summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
committerOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
commit505c19580e0f43fe5224431459cacb7c21edd93d (patch)
tree79e2634c253d60afc0cc0b2f510dc7dcbb48497b /src
parent1336a7c91e596c423a49d1194ea42d98bca0d958 (diff)
downloadgolang-505c19580e0f43fe5224431459cacb7c21edd93d.tar.gz
Imported Upstream version 1upstream/1
Diffstat (limited to 'src')
-rw-r--r--src/Make.ccmd48
-rw-r--r--src/Make.clib37
-rw-r--r--src/Make.cmd50
-rw-r--r--src/Make.common22
-rw-r--r--src/Make.dist19
-rw-r--r--src/Make.inc169
-rw-r--r--src/Make.pkg249
-rwxr-xr-xsrc/all-qemu.bash16
-rwxr-xr-xsrc/all.bash7
-rw-r--r--src/all.bat21
-rwxr-xr-xsrc/clean.bash25
-rw-r--r--src/clean.bat30
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.y2
-rw-r--r--src/cmd/5a/lex.c16
-rw-r--r--src/cmd/5a/y.tab.c2949
-rw-r--r--src/cmd/5a/y.tab.h166
-rw-r--r--src/cmd/5c/Makefile33
-rw-r--r--src/cmd/5c/gc.h5
-rw-r--r--src/cmd/5c/swt.c37
-rw-r--r--src/cmd/5c/txt.c7
-rw-r--r--src/cmd/5g/Makefile35
-rw-r--r--src/cmd/5g/cgen.c68
-rw-r--r--src/cmd/5g/cgen64.c12
-rw-r--r--src/cmd/5g/doc.go2
-rw-r--r--src/cmd/5g/galign.c2
-rw-r--r--src/cmd/5g/gg.h21
-rw-r--r--src/cmd/5g/ggen.c9
-rw-r--r--src/cmd/5g/gobj.c63
-rw-r--r--src/cmd/5g/gsubr.c94
-rw-r--r--src/cmd/5g/list.c4
-rw-r--r--src/cmd/5g/peep.c10
-rw-r--r--src/cmd/5g/reg.c177
-rw-r--r--src/cmd/5l/5.out.h3
-rw-r--r--src/cmd/5l/Makefile42
-rw-r--r--src/cmd/5l/asm.c54
-rw-r--r--src/cmd/5l/doc.go32
-rw-r--r--src/cmd/5l/l.h1
-rw-r--r--src/cmd/5l/list.c2
-rw-r--r--src/cmd/5l/noop.c3
-rw-r--r--src/cmd/5l/obj.c30
-rw-r--r--src/cmd/5l/pass.c5
-rw-r--r--src/cmd/5l/softfloat.c1
-rw-r--r--src/cmd/5l/span.c2
-rw-r--r--src/cmd/6a/Makefile25
-rw-r--r--src/cmd/6a/a.y6
-rw-r--r--src/cmd/6a/lex.c21
-rw-r--r--src/cmd/6a/y.tab.c2730
-rw-r--r--src/cmd/6a/y.tab.h135
-rw-r--r--src/cmd/6c/Makefile35
-rw-r--r--src/cmd/6c/cgen.c48
-rw-r--r--src/cmd/6c/gc.h3
-rw-r--r--src/cmd/6c/swt.c31
-rw-r--r--src/cmd/6c/txt.c4
-rw-r--r--src/cmd/6g/Makefile34
-rw-r--r--src/cmd/6g/cgen.c46
-rw-r--r--src/cmd/6g/galign.c2
-rw-r--r--src/cmd/6g/gg.h20
-rw-r--r--src/cmd/6g/ggen.c29
-rw-r--r--src/cmd/6g/gobj.c67
-rw-r--r--src/cmd/6g/gsubr.c99
-rw-r--r--src/cmd/6g/list.c4
-rw-r--r--src/cmd/6g/peep.c5
-rw-r--r--src/cmd/6g/reg.c190
-rw-r--r--src/cmd/6l/6.out.h5
-rw-r--r--src/cmd/6l/Makefile47
-rw-r--r--src/cmd/6l/asm.c75
-rw-r--r--src/cmd/6l/doc.go46
-rw-r--r--src/cmd/6l/l.h3
-rw-r--r--src/cmd/6l/obj.c47
-rw-r--r--src/cmd/6l/optab.c16
-rw-r--r--src/cmd/6l/pass.c25
-rw-r--r--src/cmd/6l/span.c33
-rw-r--r--src/cmd/8a/Makefile25
-rw-r--r--src/cmd/8a/a.y13
-rw-r--r--src/cmd/8a/lex.c28
-rw-r--r--src/cmd/8a/y.tab.c2852
-rw-r--r--src/cmd/8a/y.tab.h135
-rw-r--r--src/cmd/8c/Makefile36
-rw-r--r--src/cmd/8c/cgen.c35
-rw-r--r--src/cmd/8c/gc.h3
-rw-r--r--src/cmd/8c/swt.c36
-rw-r--r--src/cmd/8c/txt.c4
-rw-r--r--src/cmd/8g/Makefile35
-rw-r--r--src/cmd/8g/cgen.c42
-rw-r--r--src/cmd/8g/cgen64.c2
-rw-r--r--src/cmd/8g/doc.go2
-rw-r--r--src/cmd/8g/galign.c2
-rw-r--r--src/cmd/8g/gg.h24
-rw-r--r--src/cmd/8g/ggen.c26
-rw-r--r--src/cmd/8g/gobj.c66
-rw-r--r--src/cmd/8g/gsubr.c83
-rw-r--r--src/cmd/8g/list.c4
-rw-r--r--src/cmd/8g/opt.h2
-rw-r--r--src/cmd/8g/peep.c5
-rw-r--r--src/cmd/8g/reg.c188
-rw-r--r--src/cmd/8l/8.out.h14
-rw-r--r--src/cmd/8l/Makefile48
-rw-r--r--src/cmd/8l/asm.c85
-rw-r--r--src/cmd/8l/doc.go43
-rw-r--r--src/cmd/8l/l.h2
-rw-r--r--src/cmd/8l/obj.c52
-rw-r--r--src/cmd/8l/optab.c14
-rw-r--r--src/cmd/8l/pass.c27
-rw-r--r--src/cmd/8l/span.c39
-rw-r--r--src/cmd/Makefile69
-rw-r--r--src/cmd/addr2line/main.c68
-rw-r--r--src/cmd/api/goapi.go1005
-rw-r--r--src/cmd/api/goapi_test.go75
-rw-r--r--src/cmd/api/testdata/src/pkg/p1/golden.txt73
-rw-r--r--src/cmd/api/testdata/src/pkg/p1/p1.go153
-rw-r--r--src/cmd/api/testdata/src/pkg/p2/golden.txt5
-rw-r--r--src/cmd/api/testdata/src/pkg/p2/p2.go9
-rw-r--r--src/cmd/cc/Makefile36
-rw-r--r--src/cmd/cc/cc.h9
-rw-r--r--src/cmd/cc/com64.c2
-rw-r--r--src/cmd/cc/dcl.c4
-rw-r--r--src/cmd/cc/dpchk.c18
-rw-r--r--src/cmd/cc/funct.c4
-rw-r--r--src/cmd/cc/godefs.c6
-rw-r--r--src/cmd/cc/lex.c2
-rw-r--r--src/cmd/cc/lexbody7
-rw-r--r--src/cmd/cc/macbody4
-rw-r--r--src/cmd/cc/pgen.c18
-rw-r--r--src/cmd/cc/pswt.c2
-rw-r--r--src/cmd/cc/sub.c53
-rw-r--r--src/cmd/cc/y.tab.c3811
-rw-r--r--src/cmd/cc/y.tab.h228
-rw-r--r--src/cmd/cgo/Makefile15
-rw-r--r--src/cmd/cgo/ast.go33
-rw-r--r--src/cmd/cgo/doc.go45
-rw-r--r--src/cmd/cgo/gcc.go391
-rw-r--r--src/cmd/cgo/godefs.go289
-rw-r--r--src/cmd/cgo/main.go125
-rw-r--r--src/cmd/cgo/out.go324
-rw-r--r--src/cmd/cgo/util.go21
-rw-r--r--src/cmd/cov/Makefile39
-rw-r--r--src/cmd/cov/doc.go33
-rw-r--r--src/cmd/cov/main.c480
-rw-r--r--src/cmd/cov/tree.c246
-rw-r--r--src/cmd/cov/tree.h47
-rw-r--r--src/cmd/dist/README45
-rw-r--r--src/cmd/dist/a.h149
-rw-r--r--src/cmd/dist/arg.h50
-rw-r--r--src/cmd/dist/buf.c279
-rw-r--r--src/cmd/dist/build.c1530
-rw-r--r--src/cmd/dist/buildgc.c106
-rw-r--r--src/cmd/dist/buildruntime.c346
-rw-r--r--src/cmd/dist/goc2c.c (renamed from src/pkg/runtime/goc2c.c)382
-rw-r--r--src/cmd/dist/main.c41
-rw-r--r--src/cmd/dist/unix.c720
-rw-r--r--src/cmd/dist/windows.c910
-rw-r--r--src/cmd/ebnflint/Makefile15
-rw-r--r--src/cmd/ebnflint/doc.go22
-rw-r--r--src/cmd/ebnflint/ebnflint.go109
-rw-r--r--src/cmd/fix/doc.go36
-rw-r--r--src/cmd/fix/error.go353
-rw-r--r--src/cmd/fix/error_test.go240
-rw-r--r--src/cmd/fix/filepath.go (renamed from src/cmd/gofix/filepath.go)13
-rw-r--r--src/cmd/fix/filepath_test.go (renamed from src/cmd/gofix/filepath_test.go)2
-rw-r--r--src/cmd/fix/fix.go (renamed from src/cmd/gofix/fix.go)344
-rw-r--r--src/cmd/fix/go1pkgrename.go146
-rw-r--r--src/cmd/fix/go1pkgrename_test.go139
-rw-r--r--src/cmd/fix/go1rename.go167
-rw-r--r--src/cmd/fix/go1rename_test.go195
-rw-r--r--src/cmd/fix/googlecode.go41
-rw-r--r--src/cmd/fix/googlecode_test.go31
-rw-r--r--src/cmd/fix/hashsum.go94
-rw-r--r--src/cmd/fix/hashsum_test.go99
-rw-r--r--src/cmd/fix/hmacnew.go61
-rw-r--r--src/cmd/fix/hmacnew_test.go107
-rw-r--r--src/cmd/fix/htmlerr.go47
-rw-r--r--src/cmd/fix/htmlerr_test.go39
-rw-r--r--src/cmd/fix/httpfinalurl.go (renamed from src/cmd/gofix/httpfinalurl.go)9
-rw-r--r--src/cmd/fix/httpfinalurl_test.go (renamed from src/cmd/gofix/httpfinalurl_test.go)2
-rw-r--r--src/cmd/fix/httpfs.go (renamed from src/cmd/gofix/httpfs.go)19
-rw-r--r--src/cmd/fix/httpfs_test.go (renamed from src/cmd/gofix/httpfs_test.go)2
-rw-r--r--src/cmd/fix/httpheaders.go (renamed from src/cmd/gofix/httpheaders.go)15
-rw-r--r--src/cmd/fix/httpheaders_test.go (renamed from src/cmd/gofix/httpheaders_test.go)2
-rw-r--r--src/cmd/fix/httpserver.go (renamed from src/cmd/gofix/httpserver.go)9
-rw-r--r--src/cmd/fix/httpserver_test.go (renamed from src/cmd/gofix/httpserver_test.go)2
-rw-r--r--src/cmd/fix/imagecolor.go85
-rw-r--r--src/cmd/fix/imagecolor_test.go126
-rw-r--r--src/cmd/fix/imagenew.go83
-rw-r--r--src/cmd/fix/imagenew_test.go51
-rw-r--r--src/cmd/fix/imageycbcr.go64
-rw-r--r--src/cmd/fix/imageycbcr_test.go54
-rw-r--r--src/cmd/fix/import_test.go458
-rw-r--r--src/cmd/fix/iocopyn.go41
-rw-r--r--src/cmd/fix/iocopyn_test.go37
-rw-r--r--src/cmd/fix/main.go (renamed from src/cmd/gofix/main.go)111
-rw-r--r--src/cmd/fix/main_test.go (renamed from src/cmd/gofix/main_test.go)31
-rw-r--r--src/cmd/fix/mapdelete.go89
-rw-r--r--src/cmd/fix/mapdelete_test.go43
-rw-r--r--src/cmd/fix/math.go51
-rw-r--r--src/cmd/fix/math_test.go47
-rw-r--r--src/cmd/fix/netdial.go (renamed from src/cmd/gofix/netdial.go)15
-rw-r--r--src/cmd/fix/netdial_test.go (renamed from src/cmd/gofix/netdial_test.go)8
-rw-r--r--src/cmd/fix/netudpgroup.go58
-rw-r--r--src/cmd/fix/netudpgroup_test.go53
-rw-r--r--src/cmd/fix/newwriter.go90
-rw-r--r--src/cmd/fix/newwriter_test.go83
-rw-r--r--src/cmd/fix/oserrorstring.go (renamed from src/cmd/gofix/oserrorstring.go)9
-rw-r--r--src/cmd/fix/oserrorstring_test.go (renamed from src/cmd/gofix/oserrorstring_test.go)2
-rw-r--r--src/cmd/fix/osopen.go (renamed from src/cmd/gofix/osopen.go)9
-rw-r--r--src/cmd/fix/osopen_test.go (renamed from src/cmd/gofix/osopen_test.go)2
-rw-r--r--src/cmd/fix/procattr.go (renamed from src/cmd/gofix/procattr.go)9
-rw-r--r--src/cmd/fix/procattr_test.go (renamed from src/cmd/gofix/procattr_test.go)2
-rw-r--r--src/cmd/fix/reflect.go (renamed from src/cmd/gofix/reflect.go)91
-rw-r--r--src/cmd/fix/reflect_test.go (renamed from src/cmd/gofix/reflect_test.go)6
-rw-r--r--src/cmd/fix/signal.go (renamed from src/cmd/gofix/signal.go)21
-rw-r--r--src/cmd/fix/signal_test.go (renamed from src/cmd/gofix/signal_test.go)2
-rw-r--r--src/cmd/fix/sorthelpers.go (renamed from src/cmd/gofix/sorthelpers.go)13
-rw-r--r--src/cmd/fix/sorthelpers_test.go (renamed from src/cmd/gofix/sorthelpers_test.go)2
-rw-r--r--src/cmd/fix/sortslice.go (renamed from src/cmd/gofix/sortslice.go)13
-rw-r--r--src/cmd/fix/sortslice_test.go (renamed from src/cmd/gofix/sortslice_test.go)2
-rw-r--r--src/cmd/fix/strconv.go127
-rw-r--r--src/cmd/fix/strconv_test.go93
-rw-r--r--src/cmd/fix/stringssplit.go (renamed from src/cmd/gofix/stringssplit.go)9
-rw-r--r--src/cmd/fix/stringssplit_test.go (renamed from src/cmd/gofix/stringssplit_test.go)2
-rw-r--r--src/cmd/fix/template.go111
-rw-r--r--src/cmd/fix/template_test.go55
-rw-r--r--src/cmd/fix/testdata/reflect.asn1.go.in (renamed from src/cmd/gofix/testdata/reflect.asn1.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.asn1.go.out (renamed from src/cmd/gofix/testdata/reflect.asn1.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.datafmt.go.in (renamed from src/cmd/gofix/testdata/reflect.datafmt.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.datafmt.go.out (renamed from src/cmd/gofix/testdata/reflect.datafmt.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.decode.go.in (renamed from src/cmd/gofix/testdata/reflect.decode.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.decode.go.out (renamed from src/cmd/gofix/testdata/reflect.decode.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.decoder.go.in (renamed from src/cmd/gofix/testdata/reflect.decoder.go.in)6
-rw-r--r--src/cmd/fix/testdata/reflect.decoder.go.out (renamed from src/cmd/gofix/testdata/reflect.decoder.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.dnsmsg.go.in (renamed from src/cmd/gofix/testdata/reflect.dnsmsg.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.dnsmsg.go.out (renamed from src/cmd/gofix/testdata/reflect.dnsmsg.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.encode.go.in (renamed from src/cmd/gofix/testdata/reflect.encode.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.encode.go.out (renamed from src/cmd/gofix/testdata/reflect.encode.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.encoder.go.in (renamed from src/cmd/gofix/testdata/reflect.encoder.go.in)2
-rw-r--r--src/cmd/fix/testdata/reflect.encoder.go.out (renamed from src/cmd/gofix/testdata/reflect.encoder.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.export.go.in (renamed from src/cmd/gofix/testdata/reflect.export.go.in)14
-rw-r--r--src/cmd/fix/testdata/reflect.export.go.out (renamed from src/cmd/gofix/testdata/reflect.export.go.out)2
-rw-r--r--src/cmd/fix/testdata/reflect.print.go.in (renamed from src/cmd/gofix/testdata/reflect.print.go.in)2
-rw-r--r--src/cmd/fix/testdata/reflect.print.go.out (renamed from src/cmd/gofix/testdata/reflect.print.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.quick.go.in (renamed from src/cmd/gofix/testdata/reflect.quick.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.quick.go.out (renamed from src/cmd/gofix/testdata/reflect.quick.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.read.go.in (renamed from src/cmd/gofix/testdata/reflect.read.go.in)4
-rw-r--r--src/cmd/fix/testdata/reflect.read.go.out (renamed from src/cmd/gofix/testdata/reflect.read.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.scan.go.in (renamed from src/cmd/gofix/testdata/reflect.scan.go.in)8
-rw-r--r--src/cmd/fix/testdata/reflect.scan.go.out (renamed from src/cmd/gofix/testdata/reflect.scan.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.script.go.in (renamed from src/cmd/gofix/testdata/reflect.script.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.script.go.out (renamed from src/cmd/gofix/testdata/reflect.script.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.template.go.in (renamed from src/cmd/gofix/testdata/reflect.template.go.in)0
-rw-r--r--src/cmd/fix/testdata/reflect.template.go.out (renamed from src/cmd/gofix/testdata/reflect.template.go.out)0
-rw-r--r--src/cmd/fix/testdata/reflect.type.go.in (renamed from src/cmd/gofix/testdata/reflect.type.go.in)5
-rw-r--r--src/cmd/fix/testdata/reflect.type.go.out (renamed from src/cmd/gofix/testdata/reflect.type.go.out)1
-rw-r--r--src/cmd/fix/timefileinfo.go298
-rw-r--r--src/cmd/fix/timefileinfo_test.go187
-rw-r--r--src/cmd/fix/typecheck.go (renamed from src/cmd/gofix/typecheck.go)115
-rw-r--r--src/cmd/fix/url.go (renamed from src/cmd/gofix/url.go)29
-rw-r--r--src/cmd/fix/url2.go46
-rw-r--r--src/cmd/fix/url2_test.go31
-rw-r--r--src/cmd/fix/url_test.go (renamed from src/cmd/gofix/url_test.go)6
-rw-r--r--src/cmd/fix/xmlapi.go111
-rw-r--r--src/cmd/fix/xmlapi_test.go85
-rw-r--r--src/cmd/gc/Makefile72
-rw-r--r--src/cmd/gc/align.c12
-rwxr-xr-xsrc/cmd/gc/bisonerrors29
-rw-r--r--src/cmd/gc/bits.c10
-rw-r--r--src/cmd/gc/builtin.c118
-rw-r--r--src/cmd/gc/builtin.c.boot114
-rw-r--r--src/cmd/gc/closure.c9
-rw-r--r--src/cmd/gc/const.c123
-rw-r--r--src/cmd/gc/cplx.c7
-rw-r--r--src/cmd/gc/dcl.c567
-rw-r--r--src/cmd/gc/doc.go9
-rw-r--r--src/cmd/gc/esc.c805
-rw-r--r--src/cmd/gc/export.c345
-rw-r--r--src/cmd/gc/fmt.c1639
-rw-r--r--src/cmd/gc/gen.c171
-rw-r--r--src/cmd/gc/go.errors3
-rw-r--r--src/cmd/gc/go.h301
-rw-r--r--src/cmd/gc/go.y448
-rw-r--r--src/cmd/gc/init.c18
-rw-r--r--src/cmd/gc/inl.c842
-rw-r--r--src/cmd/gc/lex.c427
-rw-r--r--src/cmd/gc/md5.c2
-rwxr-xr-xsrc/cmd/gc/mkbuiltin22
-rw-r--r--src/cmd/gc/mkbuiltin1.c34
-rwxr-xr-xsrc/cmd/gc/mkopnames4
-rw-r--r--src/cmd/gc/mparith1.c12
-rw-r--r--src/cmd/gc/mparith2.c81
-rw-r--r--src/cmd/gc/mparith3.c12
-rw-r--r--src/cmd/gc/obj.c51
-rw-r--r--src/cmd/gc/order.c358
-rw-r--r--src/cmd/gc/pgen.c27
-rw-r--r--src/cmd/gc/print.c480
-rw-r--r--src/cmd/gc/range.c50
-rw-r--r--src/cmd/gc/reflect.c217
-rw-r--r--src/cmd/gc/runtime.go25
-rw-r--r--src/cmd/gc/select.c14
-rw-r--r--src/cmd/gc/sinit.c465
-rw-r--r--src/cmd/gc/subr.c1897
-rw-r--r--src/cmd/gc/swt.c63
-rw-r--r--src/cmd/gc/typecheck.c770
-rw-r--r--src/cmd/gc/unsafe.c25
-rw-r--r--src/cmd/gc/unsafe.go8
-rw-r--r--src/cmd/gc/walk.c812
-rw-r--r--src/cmd/gc/y.tab.c5540
-rw-r--r--src/cmd/gc/y.tab.h171
-rw-r--r--src/cmd/gc/yerr.h73
-rw-r--r--src/cmd/go/bootstrap.go30
-rw-r--r--src/cmd/go/build.go1566
-rw-r--r--src/cmd/go/clean.go199
-rw-r--r--src/cmd/go/discovery.go63
-rw-r--r--src/cmd/go/doc.go769
-rw-r--r--src/cmd/go/env.go89
-rw-r--r--src/cmd/go/fix.go30
-rw-r--r--src/cmd/go/fmt.go58
-rw-r--r--src/cmd/go/get.go428
-rw-r--r--src/cmd/go/help.go238
-rw-r--r--src/cmd/go/http.go87
-rw-r--r--src/cmd/go/list.go168
-rw-r--r--src/cmd/go/main.go541
-rw-r--r--src/cmd/go/match_test.go36
-rwxr-xr-xsrc/cmd/go/mkdoc.sh8
-rw-r--r--src/cmd/go/pkg.go679
-rw-r--r--src/cmd/go/run.go85
-rwxr-xr-xsrc/cmd/go/script23
-rw-r--r--src/cmd/go/script.txt352
-rw-r--r--src/cmd/go/tag_test.go (renamed from src/cmd/goinstall/tag_test.go)24
-rwxr-xr-xsrc/cmd/go/test.bash127
-rw-r--r--src/cmd/go/test.go815
-rw-r--r--src/cmd/go/testdata/errmsg/x.go3
-rw-r--r--src/cmd/go/testdata/errmsg/x1_test.go3
-rw-r--r--src/cmd/go/testdata/errmsg/x_test.go3
-rw-r--r--src/cmd/go/testdata/local/easy.go7
-rw-r--r--src/cmd/go/testdata/local/easysub/easysub.go7
-rw-r--r--src/cmd/go/testdata/local/easysub/main.go9
-rw-r--r--src/cmd/go/testdata/local/hard.go7
-rw-r--r--src/cmd/go/testdata/local/sub/sub.go12
-rw-r--r--src/cmd/go/testdata/local/sub/sub/subsub.go7
-rw-r--r--src/cmd/go/testdata/src/go-cmd-test/helloworld.go5
-rw-r--r--src/cmd/go/testdata/testimport/p.go3
-rw-r--r--src/cmd/go/testdata/testimport/p1/p1.go3
-rw-r--r--src/cmd/go/testdata/testimport/p2/p2.go3
-rw-r--r--src/cmd/go/testdata/testimport/p_test.go13
-rw-r--r--src/cmd/go/testdata/testimport/x_test.go15
-rw-r--r--src/cmd/go/testflag.go235
-rw-r--r--src/cmd/go/tool.go125
-rw-r--r--src/cmd/go/vcs.go674
-rw-r--r--src/cmd/go/version.go25
-rw-r--r--src/cmd/go/vet.go30
-rw-r--r--src/cmd/godefs/Makefile19
-rw-r--r--src/cmd/godefs/a.h104
-rw-r--r--src/cmd/godefs/doc.go99
-rw-r--r--src/cmd/godefs/main.c606
-rw-r--r--src/cmd/godefs/stabs.c456
-rwxr-xr-xsrc/cmd/godefs/test.sh45
-rw-r--r--src/cmd/godefs/testdata.c41
-rw-r--r--src/cmd/godefs/testdata_darwin_386.golden31
-rw-r--r--src/cmd/godefs/testdata_darwin_amd64.golden31
-rw-r--r--src/cmd/godefs/util.c36
-rw-r--r--src/cmd/godoc/Makefile24
-rw-r--r--src/cmd/godoc/README.godoc-app80
-rw-r--r--src/cmd/godoc/appconfig.go19
-rw-r--r--src/cmd/godoc/appinit.go74
-rw-r--r--src/cmd/godoc/codewalk.go74
-rw-r--r--src/cmd/godoc/dirtrees.go133
-rw-r--r--src/cmd/godoc/doc.go83
-rw-r--r--src/cmd/godoc/filesystem.go560
-rw-r--r--src/cmd/godoc/format.go4
-rw-r--r--src/cmd/godoc/godoc.go1042
-rw-r--r--src/cmd/godoc/httpzip.go181
-rw-r--r--src/cmd/godoc/index.go403
-rw-r--r--src/cmd/godoc/main.go328
-rw-r--r--src/cmd/godoc/mapping.go200
-rw-r--r--src/cmd/godoc/parser.go28
-rw-r--r--src/cmd/godoc/setup-godoc-app.bash121
-rw-r--r--[-rwxr-xr-x]src/cmd/godoc/snippet.go18
-rw-r--r--src/cmd/godoc/spec.go135
-rw-r--r--src/cmd/godoc/template.go182
-rw-r--r--src/cmd/godoc/throttle.go88
-rw-r--r--src/cmd/godoc/utils.go87
-rw-r--r--src/cmd/godoc/zip.go87
-rw-r--r--src/cmd/gofix/Makefile34
-rw-r--r--src/cmd/gofix/doc.go36
-rw-r--r--src/cmd/gofmt/Makefile19
-rw-r--r--src/cmd/gofmt/doc.go12
-rw-r--r--src/cmd/gofmt/gofmt.go194
-rw-r--r--src/cmd/gofmt/gofmt_test.go50
-rw-r--r--src/cmd/gofmt/long_test.go159
-rw-r--r--src/cmd/gofmt/rewrite.go13
-rw-r--r--src/cmd/gofmt/simplify.go18
-rwxr-xr-xsrc/cmd/gofmt/test.sh162
-rw-r--r--src/cmd/gofmt/testdata/comments.golden9
-rw-r--r--src/cmd/gofmt/testdata/comments.input9
-rw-r--r--src/cmd/gofmt/testdata/composites.golden98
-rw-r--r--src/cmd/gofmt/testdata/composites.input98
-rw-r--r--src/cmd/gofmt/testdata/import.golden108
-rw-r--r--src/cmd/gofmt/testdata/import.input108
-rw-r--r--src/cmd/gofmt/testdata/old.golden9
-rw-r--r--src/cmd/gofmt/testdata/old.input8
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.golden12
-rw-r--r--src/cmd/gofmt/testdata/rewrite3.input12
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.golden74
-rw-r--r--src/cmd/gofmt/testdata/rewrite4.input74
-rw-r--r--src/cmd/gofmt/testdata/stdin1.golden3
-rw-r--r--src/cmd/gofmt/testdata/stdin1.golden.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin1.input3
-rw-r--r--src/cmd/gofmt/testdata/stdin1.input.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin2.golden11
-rw-r--r--src/cmd/gofmt/testdata/stdin2.golden.gofmt10
-rw-r--r--src/cmd/gofmt/testdata/stdin2.input11
-rw-r--r--src/cmd/gofmt/testdata/stdin2.input.gofmt11
-rw-r--r--src/cmd/gofmt/testdata/stdin3.golden6
-rw-r--r--src/cmd/gofmt/testdata/stdin3.golden.gofmt7
-rw-r--r--src/cmd/gofmt/testdata/stdin3.input4
-rw-r--r--src/cmd/gofmt/testdata/stdin3.input.gofmt7
-rw-r--r--src/cmd/gofmt/testdata/stdin4.golden3
-rw-r--r--src/cmd/gofmt/testdata/stdin4.golden.gofmt3
-rw-r--r--src/cmd/gofmt/testdata/stdin4.input3
-rw-r--r--src/cmd/gofmt/testdata/stdin4.input.gofmt3
-rw-r--r--src/cmd/goinstall/Makefile19
-rw-r--r--src/cmd/goinstall/doc.go196
-rw-r--r--src/cmd/goinstall/download.go353
-rw-r--r--src/cmd/goinstall/main.go334
-rw-r--r--src/cmd/goinstall/make.go175
-rw-r--r--src/cmd/gomake/doc.go36
-rw-r--r--src/cmd/gopack/Makefile12
-rw-r--r--src/cmd/gotest/Makefile12
-rw-r--r--src/cmd/gotest/doc.go113
-rw-r--r--src/cmd/gotest/flag.go159
-rw-r--r--src/cmd/gotest/gotest.go435
-rw-r--r--src/cmd/gotry/Makefile18
-rwxr-xr-xsrc/cmd/gotry/gotry168
-rw-r--r--src/cmd/gotype/Makefile17
-rw-r--r--src/cmd/gotype/doc.go61
-rw-r--r--src/cmd/gotype/gotype.go192
-rw-r--r--src/cmd/gotype/gotype_test.go49
-rw-r--r--src/cmd/gotype/testdata/test1.go6
-rw-r--r--src/cmd/govet/Makefile14
-rw-r--r--src/cmd/goyacc/Makefile17
-rw-r--r--src/cmd/hgpatch/doc.go18
-rw-r--r--src/cmd/hgpatch/main.go358
-rw-r--r--src/cmd/ld/data.c147
-rw-r--r--src/cmd/ld/doc.go53
-rw-r--r--src/cmd/ld/dwarf.c8
-rw-r--r--src/cmd/ld/elf.c85
-rw-r--r--src/cmd/ld/elf.h6
-rw-r--r--src/cmd/ld/go.c8
-rw-r--r--src/cmd/ld/ldelf.c1
-rw-r--r--src/cmd/ld/ldpe.c26
-rw-r--r--src/cmd/ld/lib.c95
-rw-r--r--src/cmd/ld/lib.h8
-rw-r--r--src/cmd/ld/macho.c45
-rw-r--r--src/cmd/ld/pe.c104
-rw-r--r--src/cmd/ld/symtab.c17
-rw-r--r--src/cmd/nm/Makefile14
-rw-r--r--src/cmd/nm/doc.go4
-rw-r--r--src/cmd/objdump/main.c68
-rw-r--r--src/cmd/pack/Makefile5
-rw-r--r--src/cmd/pack/ar.c (renamed from src/cmd/gopack/ar.c)159
-rw-r--r--src/cmd/pack/doc.go (renamed from src/cmd/gopack/doc.go)11
-rw-r--r--src/cmd/prof/Makefile38
-rw-r--r--src/cmd/prof/doc.go48
-rwxr-xr-xsrc/cmd/prof/gopprof4975
-rw-r--r--src/cmd/prof/main.c895
-rw-r--r--src/cmd/vet/Makefile (renamed from src/pkg/http/pprof/Makefile)10
-rw-r--r--src/cmd/vet/doc.go (renamed from src/cmd/govet/doc.go)34
-rw-r--r--src/cmd/vet/main.go239
-rw-r--r--src/cmd/vet/method.go161
-rw-r--r--src/cmd/vet/print.go (renamed from src/cmd/govet/govet.go)306
-rw-r--r--src/cmd/vet/structtag.go34
-rw-r--r--src/cmd/vet/taglit.go121
-rw-r--r--src/cmd/yacc/Makefile (renamed from src/cmd/hgpatch/Makefile)11
-rw-r--r--src/cmd/yacc/doc.go (renamed from src/cmd/goyacc/doc.go)13
-rw-r--r--src/cmd/yacc/units.txt (renamed from src/cmd/goyacc/units.txt)0
-rw-r--r--src/cmd/yacc/units.y (renamed from src/cmd/goyacc/units.y)64
-rw-r--r--src/cmd/yacc/yacc.go (renamed from src/cmd/goyacc/goyacc.go)133
-rw-r--r--src/env.bash106
-rw-r--r--src/lib9/Makefile120
-rw-r--r--src/lib9/await.c2
-rw-r--r--src/lib9/ctime.c28
-rw-r--r--src/lib9/exitcode.c1
-rw-r--r--src/lib9/fmt/errfmt.c30
-rw-r--r--src/lib9/fmt/fmtprint.c26
-rw-r--r--src/lib9/fmt/fmtvprint.c28
-rw-r--r--src/lib9/fork.c46
-rw-r--r--src/lib9/getuser.c2
-rw-r--r--src/lib9/jmp.c2
-rw-r--r--src/lib9/notify.c2
-rw-r--r--src/lib9/rfork.c2
-rw-r--r--src/lib9/utf/Makefile14
-rw-r--r--src/lib9/utf/mkrunetype.c2
-rw-r--r--src/lib9/utf/runetype.c2
-rw-r--r--src/lib9/utf/runetypebody-5.0.0.c1361
-rw-r--r--src/lib9/utf/runetypebody-5.2.0.c1541
-rw-r--r--src/lib9/utf/runetypebody-6.0.0.h (renamed from src/lib9/utf/runetypebody-6.0.0.c)0
-rw-r--r--src/lib9/windows.c (renamed from src/lib9/win32.c)0
-rw-r--r--src/libbio/Makefile54
-rw-r--r--src/libmach/5db.c2
-rw-r--r--src/libmach/8db.c36
-rw-r--r--src/libmach/Makefile67
-rw-r--r--src/libmach/executable.c203
-rw-r--r--src/libmach/fakeobj.c28
-rw-r--r--src/libmach/linux.c4
-rw-r--r--src/libmach/machdata.c10
-rw-r--r--src/libmach/map.c2
-rw-r--r--src/libmach/netbsd.c46
-rw-r--r--src/libmach/plan9.c72
-rw-r--r--src/libmach/sym.c24
-rwxr-xr-xsrc/make.bash193
-rw-r--r--src/make.bat111
-rw-r--r--src/pkg/Makefile311
-rw-r--r--src/pkg/archive/tar/Makefile13
-rw-r--r--src/pkg/archive/tar/common.go52
-rw-r--r--src/pkg/archive/tar/reader.go36
-rw-r--r--src/pkg/archive/tar/reader_test.go109
-rw-r--r--src/pkg/archive/tar/testdata/writer.tarbin3072 -> 3584 bytes
-rw-r--r--src/pkg/archive/tar/writer.go59
-rw-r--r--src/pkg/archive/tar/writer_test.go45
-rw-r--r--src/pkg/archive/zip/Makefile13
-rw-r--r--src/pkg/archive/zip/example_test.go75
-rw-r--r--src/pkg/archive/zip/reader.go252
-rw-r--r--src/pkg/archive/zip/reader_test.go339
-rw-r--r--src/pkg/archive/zip/struct.go230
-rw-r--r--src/pkg/archive/zip/testdata/crc32-not-streamed.zipbin0 -> 314 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-no-datadesc-sig.zipbin0 -> 330 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-with-datadesc-sig.zipbin0 -> 242 bytes
-rw-r--r--src/pkg/archive/zip/testdata/r.zipbin440 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/symlink.zipbin0 -> 173 bytes
-rw-r--r--src/pkg/archive/zip/testdata/unix.zipbin0 -> 620 bytes
-rw-r--r--src/pkg/archive/zip/testdata/winxp.zipbin0 -> 412 bytes
-rw-r--r--src/pkg/archive/zip/writer.go202
-rw-r--r--src/pkg/archive/zip/writer_test.go82
-rw-r--r--src/pkg/archive/zip/zip_test.go50
-rw-r--r--src/pkg/asn1/Makefile13
-rw-r--r--src/pkg/big/Makefile18
-rw-r--r--src/pkg/bufio/Makefile11
-rw-r--r--src/pkg/bufio/bufio.go191
-rw-r--r--src/pkg/bufio/bufio_test.go267
-rw-r--r--src/pkg/builtin/builtin.go104
-rw-r--r--src/pkg/bytes/Makefile16
-rw-r--r--src/pkg/bytes/asm_386.s16
-rw-r--r--src/pkg/bytes/asm_amd64.s16
-rw-r--r--src/pkg/bytes/asm_arm.s3
-rw-r--r--src/pkg/bytes/buffer.go140
-rw-r--r--src/pkg/bytes/buffer_test.go36
-rw-r--r--src/pkg/bytes/bytes.go249
-rw-r--r--src/pkg/bytes/bytes_test.go342
-rw-r--r--src/pkg/bytes/example_test.go28
-rw-r--r--src/pkg/bytes/export_test.go1
-rw-r--r--src/pkg/bytes/reader.go125
-rw-r--r--src/pkg/bytes/reader_test.go88
-rw-r--r--src/pkg/cmath/Makefile25
-rw-r--r--src/pkg/compress/bzip2/Makefile14
-rw-r--r--src/pkg/compress/bzip2/bit_reader.go15
-rw-r--r--src/pkg/compress/bzip2/bzip2.go23
-rw-r--r--src/pkg/compress/bzip2/bzip2_test.go3
-rw-r--r--src/pkg/compress/bzip2/huffman.go9
-rw-r--r--src/pkg/compress/flate/Makefile17
-rw-r--r--src/pkg/compress/flate/deflate.go165
-rw-r--r--src/pkg/compress/flate/deflate_test.go173
-rw-r--r--src/pkg/compress/flate/flate_test.go12
-rw-r--r--src/pkg/compress/flate/huffman_bit_writer.go42
-rw-r--r--src/pkg/compress/flate/huffman_code.go59
-rw-r--r--src/pkg/compress/flate/inflate.go43
-rw-r--r--src/pkg/compress/flate/util.go72
-rw-r--r--src/pkg/compress/gzip/Makefile12
-rw-r--r--src/pkg/compress/gzip/gunzip.go89
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go9
-rw-r--r--src/pkg/compress/gzip/gzip.go100
-rw-r--r--src/pkg/compress/gzip/gzip_test.go207
-rw-r--r--src/pkg/compress/lzw/Makefile12
-rw-r--r--src/pkg/compress/lzw/reader.go28
-rw-r--r--src/pkg/compress/lzw/reader_test.go9
-rw-r--r--src/pkg/compress/lzw/writer.go48
-rw-r--r--src/pkg/compress/lzw/writer_test.go8
-rw-r--r--src/pkg/compress/testdata/Mark.Twain-Tom.Sawyer.txt8858
-rw-r--r--src/pkg/compress/zlib/Makefile12
-rw-r--r--src/pkg/compress/zlib/reader.go31
-rw-r--r--src/pkg/compress/zlib/reader_test.go9
-rw-r--r--src/pkg/compress/zlib/writer.go111
-rw-r--r--src/pkg/compress/zlib/writer_test.go12
-rw-r--r--src/pkg/container/heap/Makefile11
-rw-r--r--src/pkg/container/heap/example_test.go105
-rw-r--r--src/pkg/container/heap/heap.go18
-rw-r--r--src/pkg/container/heap/heap_test.go34
-rw-r--r--src/pkg/container/list/Makefile11
-rw-r--r--src/pkg/container/ring/Makefile11
-rw-r--r--src/pkg/container/vector/Makefile69
-rw-r--r--src/pkg/container/vector/defs.go43
-rw-r--r--src/pkg/container/vector/intvector.go188
-rw-r--r--src/pkg/container/vector/intvector_test.go331
-rw-r--r--src/pkg/container/vector/nogen_test.go67
-rw-r--r--src/pkg/container/vector/numbers_test.go123
-rw-r--r--src/pkg/container/vector/stringvector.go188
-rw-r--r--src/pkg/container/vector/stringvector_test.go331
-rw-r--r--src/pkg/container/vector/vector.go188
-rw-r--r--src/pkg/container/vector/vector_test.go331
-rw-r--r--src/pkg/crypto/Makefile11
-rw-r--r--src/pkg/crypto/aes/Makefile13
-rw-r--r--src/pkg/crypto/aes/aes_test.go16
-rw-r--r--src/pkg/crypto/aes/block.go18
-rw-r--r--src/pkg/crypto/aes/cipher.go41
-rw-r--r--src/pkg/crypto/aes/const.go544
-rw-r--r--src/pkg/crypto/blowfish/Makefile13
-rw-r--r--src/pkg/crypto/blowfish/block.go101
-rw-r--r--src/pkg/crypto/blowfish/blowfish_test.go192
-rw-r--r--src/pkg/crypto/blowfish/cipher.go79
-rw-r--r--src/pkg/crypto/blowfish/const.go199
-rw-r--r--src/pkg/crypto/cast5/Makefile11
-rw-r--r--src/pkg/crypto/cast5/cast5.go536
-rw-r--r--src/pkg/crypto/cast5/cast5_test.go104
-rw-r--r--src/pkg/crypto/cipher/Makefile17
-rw-r--r--src/pkg/crypto/cipher/cbc.go2
-rw-r--r--src/pkg/crypto/cipher/cbc_aes_test.go7
-rw-r--r--src/pkg/crypto/cipher/cfb_test.go7
-rw-r--r--src/pkg/crypto/cipher/common_test.go2
-rw-r--r--src/pkg/crypto/cipher/ctr_aes_test.go7
-rw-r--r--src/pkg/crypto/cipher/io.go17
-rw-r--r--src/pkg/crypto/cipher/ocfb.go138
-rw-r--r--src/pkg/crypto/cipher/ocfb_test.go44
-rw-r--r--src/pkg/crypto/cipher/ofb_test.go7
-rw-r--r--src/pkg/crypto/crypto.go30
-rw-r--r--src/pkg/crypto/des/Makefile13
-rw-r--r--src/pkg/crypto/des/block.go2
-rw-r--r--src/pkg/crypto/des/cipher.go68
-rw-r--r--src/pkg/crypto/des/des_test.go16
-rw-r--r--src/pkg/crypto/dsa/Makefile11
-rw-r--r--src/pkg/crypto/dsa/dsa.go54
-rw-r--r--src/pkg/crypto/dsa/dsa_test.go2
-rw-r--r--src/pkg/crypto/ecdsa/Makefile11
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa.go36
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa_test.go10
-rw-r--r--src/pkg/crypto/elliptic/Makefile11
-rw-r--r--src/pkg/crypto/elliptic/elliptic.go110
-rw-r--r--src/pkg/crypto/elliptic/elliptic_test.go41
-rw-r--r--src/pkg/crypto/elliptic/p224.go718
-rw-r--r--src/pkg/crypto/elliptic/p224_test.go47
-rw-r--r--src/pkg/crypto/hmac/Makefile11
-rw-r--r--src/pkg/crypto/hmac/hmac.go58
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go316
-rw-r--r--src/pkg/crypto/md4/Makefile12
-rw-r--r--src/pkg/crypto/md4/md4.go117
-rw-r--r--src/pkg/crypto/md4/md4_test.go71
-rw-r--r--src/pkg/crypto/md4/md4block.go89
-rw-r--r--src/pkg/crypto/md5/Makefile12
-rw-r--r--src/pkg/crypto/md5/md5.go30
-rw-r--r--src/pkg/crypto/md5/md5_test.go17
-rw-r--r--src/pkg/crypto/ocsp/Makefile11
-rw-r--r--src/pkg/crypto/ocsp/ocsp.go192
-rw-r--r--src/pkg/crypto/ocsp/ocsp_test.go97
-rw-r--r--src/pkg/crypto/openpgp/Makefile14
-rw-r--r--src/pkg/crypto/openpgp/armor/Makefile12
-rw-r--r--src/pkg/crypto/openpgp/armor/armor.go220
-rw-r--r--src/pkg/crypto/openpgp/armor/armor_test.go95
-rw-r--r--src/pkg/crypto/openpgp/armor/encode.go161
-rw-r--r--src/pkg/crypto/openpgp/canonical_text.go58
-rw-r--r--src/pkg/crypto/openpgp/canonical_text_test.go49
-rw-r--r--src/pkg/crypto/openpgp/elgamal/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--src/pkg/crypto/openpgp/error/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/error/error.go64
-rw-r--r--src/pkg/crypto/openpgp/keys.go545
-rw-r--r--src/pkg/crypto/openpgp/packet/Makefile22
-rw-r--r--src/pkg/crypto/openpgp/packet/compressed.go39
-rw-r--r--src/pkg/crypto/openpgp/packet/compressed_test.go41
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key.go168
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key_test.go126
-rw-r--r--src/pkg/crypto/openpgp/packet/literal.go90
-rw-r--r--src/pkg/crypto/openpgp/packet/one_pass_signature.go74
-rw-r--r--src/pkg/crypto/openpgp/packet/packet.go483
-rw-r--r--src/pkg/crypto/openpgp/packet/packet_test.go256
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key.go301
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key_test.go57
-rw-r--r--src/pkg/crypto/openpgp/packet/public_key.go393
-rw-r--r--src/pkg/crypto/openpgp/packet/public_key_test.go98
-rw-r--r--src/pkg/crypto/openpgp/packet/reader.go63
-rw-r--r--src/pkg/crypto/openpgp/packet/signature.go558
-rw-r--r--src/pkg/crypto/openpgp/packet/signature_test.go42
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go162
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go101
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go291
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go124
-rw-r--r--src/pkg/crypto/openpgp/packet/userid.go161
-rw-r--r--src/pkg/crypto/openpgp/packet/userid_test.go87
-rw-r--r--src/pkg/crypto/openpgp/read.go415
-rw-r--r--src/pkg/crypto/openpgp/read_test.go361
-rw-r--r--src/pkg/crypto/openpgp/s2k/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/s2k/s2k.go180
-rw-r--r--src/pkg/crypto/openpgp/s2k/s2k_test.go118
-rw-r--r--src/pkg/crypto/openpgp/write.go308
-rw-r--r--src/pkg/crypto/openpgp/write_test.go233
-rw-r--r--src/pkg/crypto/rand/Makefile30
-rw-r--r--src/pkg/crypto/rand/rand.go7
-rw-r--r--src/pkg/crypto/rand/rand_test.go2
-rw-r--r--src/pkg/crypto/rand/rand_unix.go11
-rw-r--r--[-rwxr-xr-x]src/pkg/crypto/rand/rand_windows.go14
-rw-r--r--src/pkg/crypto/rand/util.go12
-rw-r--r--src/pkg/crypto/rc4/Makefile11
-rw-r--r--src/pkg/crypto/rc4/rc4.go9
-rw-r--r--src/pkg/crypto/ripemd160/Makefile12
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160.go118
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160_test.go64
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160block.go161
-rw-r--r--src/pkg/crypto/rsa/Makefile12
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go40
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15_test.go6
-rw-r--r--src/pkg/crypto/rsa/rsa.go86
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go2
-rw-r--r--src/pkg/crypto/sha1/Makefile12
-rw-r--r--src/pkg/crypto/sha1/sha1.go30
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go16
-rw-r--r--src/pkg/crypto/sha256/Makefile12
-rw-r--r--src/pkg/crypto/sha256/sha256.go38
-rw-r--r--src/pkg/crypto/sha256/sha256_test.go8
-rw-r--r--src/pkg/crypto/sha512/Makefile12
-rw-r--r--src/pkg/crypto/sha512/sha512.go43
-rw-r--r--src/pkg/crypto/sha512/sha512_test.go8
-rw-r--r--src/pkg/crypto/subtle/Makefile11
-rw-r--r--src/pkg/crypto/tls/Makefile20
-rw-r--r--src/pkg/crypto/tls/alert.go4
-rw-r--r--src/pkg/crypto/tls/cipher_suites.go128
-rw-r--r--src/pkg/crypto/tls/common.go180
-rw-r--r--src/pkg/crypto/tls/conn.go191
-rw-r--r--src/pkg/crypto/tls/conn_test.go54
-rw-r--r--src/pkg/crypto/tls/generate_cert.go12
-rw-r--r--src/pkg/crypto/tls/handshake_client.go136
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go3
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go207
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go19
-rw-r--r--src/pkg/crypto/tls/handshake_server.go157
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go1165
-rw-r--r--src/pkg/crypto/tls/key_agreement.go82
-rw-r--r--src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py2
-rw-r--r--src/pkg/crypto/tls/prf.go124
-rw-r--r--src/pkg/crypto/tls/prf_test.go21
-rw-r--r--src/pkg/crypto/tls/root_test.go61
-rw-r--r--src/pkg/crypto/tls/tls.go70
-rw-r--r--src/pkg/crypto/twofish/Makefile11
-rw-r--r--src/pkg/crypto/twofish/twofish.go358
-rw-r--r--src/pkg/crypto/twofish/twofish_test.go129
-rw-r--r--src/pkg/crypto/x509/Makefile13
-rw-r--r--src/pkg/crypto/x509/cert_pool.go33
-rw-r--r--src/pkg/crypto/x509/pkcs1.go122
-rw-r--r--src/pkg/crypto/x509/pkcs8.go42
-rw-r--r--src/pkg/crypto/x509/pkcs8_test.go20
-rw-r--r--src/pkg/crypto/x509/pkix/Makefile11
-rw-r--r--src/pkg/crypto/x509/pkix/pkix.go22
-rw-r--r--src/pkg/crypto/x509/root.go17
-rw-r--r--src/pkg/crypto/x509/root_darwin.go80
-rw-r--r--src/pkg/crypto/x509/root_stub.go15
-rw-r--r--src/pkg/crypto/x509/root_unix.go35
-rw-r--r--src/pkg/crypto/x509/root_windows.go226
-rw-r--r--src/pkg/crypto/x509/verify.go104
-rw-r--r--src/pkg/crypto/x509/verify_test.go84
-rw-r--r--src/pkg/crypto/x509/x509.go307
-rw-r--r--src/pkg/crypto/x509/x509_test.go62
-rw-r--r--src/pkg/crypto/xtea/Makefile12
-rw-r--r--src/pkg/crypto/xtea/block.go66
-rw-r--r--src/pkg/crypto/xtea/cipher.go92
-rw-r--r--src/pkg/crypto/xtea/xtea_test.go246
-rw-r--r--src/pkg/csv/Makefile12
-rw-r--r--src/pkg/database/sql/convert.go158
-rw-r--r--src/pkg/database/sql/convert_test.go250
-rw-r--r--src/pkg/database/sql/doc.txt46
-rw-r--r--src/pkg/database/sql/driver/driver.go215
-rw-r--r--src/pkg/database/sql/driver/types.go252
-rw-r--r--src/pkg/database/sql/driver/types_test.go65
-rw-r--r--src/pkg/database/sql/fakedb_test.go629
-rw-r--r--src/pkg/database/sql/sql.go1063
-rw-r--r--src/pkg/database/sql/sql_test.go614
-rw-r--r--src/pkg/debug/dwarf/Makefile16
-rw-r--r--src/pkg/debug/dwarf/buf.go9
-rw-r--r--src/pkg/debug/dwarf/const.go4
-rw-r--r--src/pkg/debug/dwarf/entry.go10
-rw-r--r--src/pkg/debug/dwarf/open.go12
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.c8
-rwxr-xr-xsrc/pkg/debug/dwarf/testdata/typedef.elfbin10837 -> 12448 bytes
-rw-r--r--src/pkg/debug/dwarf/testdata/typedef.machobin5256 -> 5024 bytes
-rw-r--r--src/pkg/debug/dwarf/type.go55
-rw-r--r--src/pkg/debug/dwarf/type_test.go19
-rw-r--r--src/pkg/debug/dwarf/unit.go7
-rw-r--r--src/pkg/debug/elf/Makefile12
-rw-r--r--src/pkg/debug/elf/elf.go8
-rw-r--r--src/pkg/debug/elf/file.go57
-rw-r--r--src/pkg/debug/elf/file_test.go3
-rw-r--r--src/pkg/debug/gosym/Makefile19
-rw-r--r--src/pkg/debug/gosym/pclinetest.asm (renamed from src/pkg/debug/gosym/pclinetest.s)0
-rw-r--r--src/pkg/debug/gosym/pclinetest.h2
-rw-r--r--src/pkg/debug/gosym/pclntab_test.go36
-rw-r--r--src/pkg/debug/gosym/symtab.go19
-rw-r--r--src/pkg/debug/macho/Makefile12
-rw-r--r--src/pkg/debug/macho/file.go28
-rw-r--r--src/pkg/debug/macho/file_test.go80
-rw-r--r--src/pkg/debug/macho/macho.go6
-rw-r--r--src/pkg/debug/pe/Makefile12
-rw-r--r--src/pkg/debug/pe/file.go23
-rw-r--r--src/pkg/debug/pe/file_test.go54
-rwxr-xr-xsrc/pkg/deps.bash49
-rw-r--r--src/pkg/ebnf/Makefile12
-rw-r--r--src/pkg/ebnf/ebnf.go245
-rw-r--r--src/pkg/ebnf/ebnf_test.go87
-rw-r--r--src/pkg/ebnf/parser.go197
-rw-r--r--src/pkg/encoding/ascii85/Makefile11
-rw-r--r--src/pkg/encoding/ascii85/ascii85.go19
-rw-r--r--src/pkg/encoding/ascii85/ascii85_test.go12
-rw-r--r--src/pkg/encoding/asn1/asn1.go (renamed from src/pkg/asn1/asn1.go)64
-rw-r--r--src/pkg/encoding/asn1/asn1_test.go (renamed from src/pkg/asn1/asn1_test.go)69
-rw-r--r--src/pkg/encoding/asn1/common.go (renamed from src/pkg/asn1/common.go)5
-rw-r--r--src/pkg/encoding/asn1/marshal.go (renamed from src/pkg/asn1/marshal.go)87
-rw-r--r--src/pkg/encoding/asn1/marshal_test.go (renamed from src/pkg/asn1/marshal_test.go)26
-rw-r--r--src/pkg/encoding/base32/Makefile11
-rw-r--r--src/pkg/encoding/base32/base32.go78
-rw-r--r--src/pkg/encoding/base32/base32_test.go51
-rw-r--r--src/pkg/encoding/base64/Makefile11
-rw-r--r--src/pkg/encoding/base64/base64.go60
-rw-r--r--src/pkg/encoding/base64/base64_test.go44
-rw-r--r--src/pkg/encoding/binary/Makefile11
-rw-r--r--src/pkg/encoding/binary/binary.go71
-rw-r--r--src/pkg/encoding/binary/binary_test.go65
-rw-r--r--src/pkg/encoding/binary/example_test.go52
-rw-r--r--src/pkg/encoding/binary/varint.go134
-rw-r--r--src/pkg/encoding/binary/varint_test.go168
-rw-r--r--src/pkg/encoding/csv/reader.go (renamed from src/pkg/csv/reader.go)126
-rw-r--r--src/pkg/encoding/csv/reader_test.go (renamed from src/pkg/csv/reader_test.go)30
-rw-r--r--src/pkg/encoding/csv/writer.go (renamed from src/pkg/csv/writer.go)19
-rw-r--r--src/pkg/encoding/csv/writer_test.go (renamed from src/pkg/csv/writer_test.go)0
-rw-r--r--src/pkg/encoding/git85/Makefile11
-rw-r--r--src/pkg/encoding/git85/git.go277
-rw-r--r--src/pkg/encoding/git85/git_test.go194
-rw-r--r--src/pkg/encoding/gob/codec_test.go (renamed from src/pkg/gob/codec_test.go)101
-rw-r--r--src/pkg/encoding/gob/debug.go (renamed from src/pkg/gob/debug.go)21
-rw-r--r--src/pkg/encoding/gob/decode.go (renamed from src/pkg/gob/decode.go)237
-rw-r--r--src/pkg/encoding/gob/decoder.go (renamed from src/pkg/gob/decoder.go)36
-rw-r--r--src/pkg/encoding/gob/doc.go (renamed from src/pkg/gob/doc.go)27
-rw-r--r--src/pkg/encoding/gob/dump.go (renamed from src/pkg/gob/dump.go)11
-rw-r--r--src/pkg/encoding/gob/encode.go (renamed from src/pkg/gob/encode.go)54
-rw-r--r--src/pkg/encoding/gob/encoder.go (renamed from src/pkg/gob/encoder.go)52
-rw-r--r--src/pkg/encoding/gob/encoder_test.go (renamed from src/pkg/gob/encoder_test.go)184
-rw-r--r--src/pkg/encoding/gob/error.go (renamed from src/pkg/gob/error.go)31
-rw-r--r--src/pkg/encoding/gob/gobencdec_test.go (renamed from src/pkg/gob/gobencdec_test.go)144
-rw-r--r--src/pkg/encoding/gob/timing_test.go (renamed from src/pkg/gob/timing_test.go)20
-rw-r--r--src/pkg/encoding/gob/type.go (renamed from src/pkg/gob/type.go)66
-rw-r--r--src/pkg/encoding/gob/type_test.go (renamed from src/pkg/gob/type_test.go)10
-rw-r--r--src/pkg/encoding/hex/Makefile11
-rw-r--r--src/pkg/encoding/hex/hex.go39
-rw-r--r--src/pkg/encoding/hex/hex_test.go171
-rw-r--r--src/pkg/encoding/json/bench_test.go157
-rw-r--r--src/pkg/encoding/json/decode.go (renamed from src/pkg/json/decode.go)261
-rw-r--r--src/pkg/encoding/json/decode_test.go (renamed from src/pkg/json/decode_test.go)121
-rw-r--r--src/pkg/encoding/json/encode.go (renamed from src/pkg/json/encode.go)245
-rw-r--r--src/pkg/encoding/json/encode_test.go188
-rw-r--r--src/pkg/encoding/json/example_test.go83
-rw-r--r--src/pkg/encoding/json/indent.go (renamed from src/pkg/json/indent.go)23
-rw-r--r--src/pkg/encoding/json/scanner.go (renamed from src/pkg/json/scanner.go)53
-rw-r--r--src/pkg/encoding/json/scanner_test.go (renamed from src/pkg/json/scanner_test.go)45
-rw-r--r--src/pkg/encoding/json/stream.go (renamed from src/pkg/json/stream.go)27
-rw-r--r--src/pkg/encoding/json/stream_test.go (renamed from src/pkg/json/stream_test.go)25
-rw-r--r--src/pkg/encoding/json/tagkey_test.go (renamed from src/pkg/json/tagkey_test.go)13
-rw-r--r--src/pkg/encoding/json/tags.go (renamed from src/pkg/json/tags.go)0
-rw-r--r--src/pkg/encoding/json/tags_test.go (renamed from src/pkg/json/tags_test.go)0
-rw-r--r--src/pkg/encoding/json/testdata/code.json.gzbin0 -> 120432 bytes
-rw-r--r--src/pkg/encoding/pem/Makefile11
-rw-r--r--src/pkg/encoding/pem/pem.go11
-rw-r--r--src/pkg/encoding/pem/pem_test.go4
-rw-r--r--src/pkg/encoding/xml/atom_test.go56
-rw-r--r--src/pkg/encoding/xml/example_test.go111
-rw-r--r--src/pkg/encoding/xml/marshal.go447
-rw-r--r--src/pkg/encoding/xml/marshal_test.go793
-rw-r--r--src/pkg/encoding/xml/read.go531
-rw-r--r--src/pkg/encoding/xml/read_test.go (renamed from src/pkg/xml/read_test.go)202
-rw-r--r--src/pkg/encoding/xml/typeinfo.go329
-rw-r--r--src/pkg/encoding/xml/xml.go (renamed from src/pkg/xml/xml.go)519
-rw-r--r--src/pkg/encoding/xml/xml_test.go (renamed from src/pkg/xml/xml_test.go)299
-rw-r--r--src/pkg/errors/errors.go20
-rw-r--r--src/pkg/errors/errors_test.go53
-rw-r--r--src/pkg/errors/example_test.go34
-rw-r--r--src/pkg/exec/Makefile31
-rw-r--r--src/pkg/exp/README3
-rw-r--r--src/pkg/exp/gui/Makefile11
-rw-r--r--src/pkg/exp/gui/gui.go58
-rw-r--r--src/pkg/exp/gui/x11/Makefile12
-rw-r--r--src/pkg/exp/gui/x11/auth.go93
-rw-r--r--src/pkg/exp/gui/x11/conn.go627
-rw-r--r--src/pkg/exp/norm/Makefile44
-rw-r--r--src/pkg/exp/norm/composition.go344
-rw-r--r--src/pkg/exp/norm/composition_test.go138
-rw-r--r--src/pkg/exp/norm/forminfo.go188
-rw-r--r--src/pkg/exp/norm/maketables.go855
-rw-r--r--src/pkg/exp/norm/maketesttables.go42
-rw-r--r--src/pkg/exp/norm/norm_test.go14
-rw-r--r--src/pkg/exp/norm/normalize.go99
-rw-r--r--src/pkg/exp/norm/tables.go6580
-rw-r--r--src/pkg/exp/norm/trie.go234
-rw-r--r--src/pkg/exp/norm/trie_test.go107
-rw-r--r--src/pkg/exp/norm/triedata_test.go63
-rw-r--r--src/pkg/exp/norm/triegen.go211
-rw-r--r--src/pkg/exp/regexp/Makefile12
-rw-r--r--src/pkg/exp/regexp/all_test.go429
-rw-r--r--src/pkg/exp/regexp/find_test.go472
-rw-r--r--src/pkg/exp/regexp/regexp.go795
-rw-r--r--src/pkg/exp/regexp/syntax/Makefile16
-rw-r--r--src/pkg/exp/template/html/Makefile11
-rw-r--r--src/pkg/exp/template/html/context.go98
-rw-r--r--src/pkg/exp/template/html/escape.go105
-rw-r--r--src/pkg/exp/template/html/escape_test.go75
-rw-r--r--src/pkg/exp/wingui/Makefile29
-rw-r--r--src/pkg/exp/wingui/gui.go153
-rw-r--r--src/pkg/exp/wingui/winapi.go131
-rw-r--r--src/pkg/exp/wingui/zwinapi.go211
-rw-r--r--src/pkg/expvar/Makefile11
-rw-r--r--src/pkg/expvar/expvar.go147
-rw-r--r--src/pkg/expvar/expvar_test.go10
-rw-r--r--src/pkg/flag/Makefile11
-rw-r--r--src/pkg/flag/example_test.go83
-rw-r--r--src/pkg/flag/flag.go207
-rw-r--r--src/pkg/flag/flag_test.go54
-rw-r--r--src/pkg/fmt/Makefile14
-rw-r--r--src/pkg/fmt/doc.go35
-rw-r--r--src/pkg/fmt/export_test.go (renamed from src/pkg/syscall/syscall_386.go)6
-rw-r--r--src/pkg/fmt/fmt_test.go185
-rw-r--r--src/pkg/fmt/format.go112
-rw-r--r--src/pkg/fmt/print.go414
-rw-r--r--src/pkg/fmt/scan.go316
-rw-r--r--src/pkg/fmt/scan_test.go83
-rw-r--r--src/pkg/go/ast/Makefile16
-rw-r--r--src/pkg/go/ast/ast.go180
-rw-r--r--src/pkg/go/ast/example_test.go136
-rw-r--r--src/pkg/go/ast/filter.go348
-rw-r--r--src/pkg/go/ast/import.go134
-rw-r--r--src/pkg/go/ast/print.go38
-rw-r--r--src/pkg/go/ast/print_test.go17
-rw-r--r--src/pkg/go/ast/resolve.go16
-rw-r--r--src/pkg/go/ast/scope.go10
-rw-r--r--src/pkg/go/build/Makefile22
-rw-r--r--src/pkg/go/build/build.go1254
-rw-r--r--src/pkg/go/build/build_test.go100
-rw-r--r--src/pkg/go/build/cgotest/cgotest.go19
-rw-r--r--src/pkg/go/build/deps_test.go424
-rw-r--r--src/pkg/go/build/dir.go172
-rw-r--r--src/pkg/go/build/doc.go109
-rw-r--r--src/pkg/go/build/path.go182
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_386.s10
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_amd64.s9
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_arm.s10
-rw-r--r--src/pkg/go/build/syslist.go8
-rw-r--r--src/pkg/go/build/syslist_test.go4
-rw-r--r--src/pkg/go/build/testdata/other/file/file.go5
-rw-r--r--src/pkg/go/build/testdata/other/main.go11
-rw-r--r--src/pkg/go/doc/Makefile11
-rw-r--r--src/pkg/go/doc/comment.go376
-rw-r--r--src/pkg/go/doc/comment_test.go109
-rw-r--r--src/pkg/go/doc/doc.go668
-rw-r--r--src/pkg/go/doc/doc_test.go136
-rw-r--r--src/pkg/go/doc/example.go117
-rw-r--r--src/pkg/go/doc/exports.go199
-rw-r--r--src/pkg/go/doc/filter.go105
-rw-r--r--src/pkg/go/doc/headscan.go113
-rw-r--r--src/pkg/go/doc/reader.go774
-rw-r--r--src/pkg/go/doc/synopsis.go52
-rw-r--r--src/pkg/go/doc/synopsis_test.go44
-rw-r--r--src/pkg/go/doc/testdata/a.0.golden13
-rw-r--r--src/pkg/go/doc/testdata/a.1.golden13
-rw-r--r--src/pkg/go/doc/testdata/a.2.golden13
-rw-r--r--src/pkg/go/doc/testdata/a0.go (renamed from src/pkg/syscall/syscall_amd64.go)7
-rw-r--r--src/pkg/go/doc/testdata/a1.go (renamed from src/pkg/syscall/syscall_arm.go)7
-rw-r--r--src/pkg/go/doc/testdata/b.0.golden71
-rw-r--r--src/pkg/go/doc/testdata/b.1.golden83
-rw-r--r--src/pkg/go/doc/testdata/b.2.golden71
-rw-r--r--src/pkg/go/doc/testdata/b.go58
-rw-r--r--src/pkg/go/doc/testdata/benchmark.go293
-rw-r--r--src/pkg/go/doc/testdata/c.0.golden48
-rw-r--r--src/pkg/go/doc/testdata/c.1.golden48
-rw-r--r--src/pkg/go/doc/testdata/c.2.golden48
-rw-r--r--src/pkg/go/doc/testdata/c.go62
-rw-r--r--src/pkg/go/doc/testdata/d.0.golden104
-rw-r--r--src/pkg/go/doc/testdata/d.1.golden104
-rw-r--r--src/pkg/go/doc/testdata/d.2.golden104
-rw-r--r--src/pkg/go/doc/testdata/d1.go57
-rw-r--r--src/pkg/go/doc/testdata/d2.go45
-rw-r--r--src/pkg/go/doc/testdata/e.0.golden109
-rw-r--r--src/pkg/go/doc/testdata/e.1.golden144
-rw-r--r--src/pkg/go/doc/testdata/e.2.golden130
-rw-r--r--src/pkg/go/doc/testdata/e.go147
-rw-r--r--src/pkg/go/doc/testdata/error1.0.golden30
-rw-r--r--src/pkg/go/doc/testdata/error1.1.golden32
-rw-r--r--src/pkg/go/doc/testdata/error1.2.golden30
-rw-r--r--src/pkg/go/doc/testdata/error1.go24
-rw-r--r--src/pkg/go/doc/testdata/error2.0.golden27
-rw-r--r--src/pkg/go/doc/testdata/error2.1.golden37
-rw-r--r--src/pkg/go/doc/testdata/error2.2.golden27
-rw-r--r--src/pkg/go/doc/testdata/error2.go29
-rw-r--r--src/pkg/go/doc/testdata/example.go81
-rw-r--r--src/pkg/go/doc/testdata/f.0.golden13
-rw-r--r--src/pkg/go/doc/testdata/f.1.golden16
-rw-r--r--src/pkg/go/doc/testdata/f.2.golden13
-rw-r--r--src/pkg/go/doc/testdata/f.go14
-rw-r--r--src/pkg/go/doc/testdata/template.txt65
-rw-r--r--src/pkg/go/doc/testdata/testing.0.golden156
-rw-r--r--src/pkg/go/doc/testdata/testing.1.golden298
-rw-r--r--src/pkg/go/doc/testdata/testing.2.golden156
-rw-r--r--src/pkg/go/doc/testdata/testing.go404
-rw-r--r--src/pkg/go/parser/Makefile12
-rw-r--r--src/pkg/go/parser/error_test.go166
-rw-r--r--src/pkg/go/parser/example_test.go34
-rw-r--r--src/pkg/go/parser/interface.go183
-rw-r--r--src/pkg/go/parser/parser.go628
-rw-r--r--src/pkg/go/parser/parser_test.go193
-rw-r--r--src/pkg/go/parser/short_test.go75
-rw-r--r--src/pkg/go/parser/testdata/commas.src19
-rw-r--r--src/pkg/go/parser/testdata/issue3106.src46
-rw-r--r--src/pkg/go/printer/Makefile12
-rw-r--r--src/pkg/go/printer/example_test.go67
-rw-r--r--src/pkg/go/printer/nodes.go600
-rw-r--r--src/pkg/go/printer/performance_test.go4
-rw-r--r--src/pkg/go/printer/printer.go926
-rw-r--r--src/pkg/go/printer/printer_test.go242
-rw-r--r--src/pkg/go/printer/testdata/comments.golden174
-rw-r--r--src/pkg/go/printer/testdata/comments.input163
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden167
-rw-r--r--src/pkg/go/printer/testdata/declarations.input118
-rw-r--r--src/pkg/go/printer/testdata/expressions.golden28
-rw-r--r--src/pkg/go/printer/testdata/expressions.input22
-rw-r--r--src/pkg/go/printer/testdata/expressions.raw28
-rw-r--r--src/pkg/go/printer/testdata/linebreaks.golden52
-rw-r--r--src/pkg/go/printer/testdata/linebreaks.input48
-rw-r--r--src/pkg/go/printer/testdata/parser.go8
-rw-r--r--src/pkg/go/printer/testdata/statements.golden121
-rw-r--r--src/pkg/go/printer/testdata/statements.input119
-rw-r--r--src/pkg/go/scanner/Makefile12
-rw-r--r--src/pkg/go/scanner/errors.go142
-rw-r--r--src/pkg/go/scanner/example_test.go46
-rw-r--r--src/pkg/go/scanner/scanner.go578
-rw-r--r--src/pkg/go/scanner/scanner_test.go155
-rw-r--r--src/pkg/go/token/Makefile12
-rw-r--r--src/pkg/go/token/position.go277
-rw-r--r--src/pkg/go/token/position_test.go9
-rw-r--r--src/pkg/go/token/serialize.go56
-rw-r--r--src/pkg/go/token/serialize_test.go111
-rw-r--r--src/pkg/go/token/token.go12
-rw-r--r--src/pkg/go/typechecker/Makefile14
-rw-r--r--src/pkg/go/typechecker/scope.go69
-rw-r--r--src/pkg/go/typechecker/testdata/test0.src94
-rw-r--r--src/pkg/go/typechecker/testdata/test1.src13
-rw-r--r--src/pkg/go/typechecker/testdata/test3.src41
-rw-r--r--src/pkg/go/typechecker/testdata/test4.src11
-rw-r--r--src/pkg/go/typechecker/type.go118
-rw-r--r--src/pkg/go/typechecker/typechecker.go468
-rw-r--r--src/pkg/go/typechecker/typechecker_test.go163
-rw-r--r--src/pkg/go/typechecker/universe.go36
-rw-r--r--src/pkg/go/types/Makefile16
-rw-r--r--src/pkg/go/types/check.go226
-rw-r--r--src/pkg/go/types/check_test.go215
-rw-r--r--src/pkg/go/types/const.go332
-rw-r--r--src/pkg/go/types/exportdata.go132
-rw-r--r--src/pkg/go/types/gcimporter.go799
-rw-r--r--src/pkg/go/types/gcimporter_test.go101
-rw-r--r--src/pkg/go/types/testdata/exports.go84
-rw-r--r--src/pkg/go/types/testdata/test0.src154
-rw-r--r--src/pkg/go/types/types.go255
-rw-r--r--src/pkg/go/types/universe.go108
-rw-r--r--src/pkg/gob/Makefile25
-rw-r--r--src/pkg/hash/Makefile11
-rw-r--r--src/pkg/hash/adler32/Makefile11
-rw-r--r--src/pkg/hash/adler32/adler32.go22
-rw-r--r--src/pkg/hash/crc32/Makefile20
-rw-r--r--src/pkg/hash/crc32/crc32.go18
-rw-r--r--src/pkg/hash/crc32/crc32_generic.go2
-rw-r--r--src/pkg/hash/crc64/Makefile11
-rw-r--r--src/pkg/hash/crc64/crc64.go30
-rw-r--r--src/pkg/hash/fnv/Makefile11
-rw-r--r--src/pkg/hash/fnv/fnv.go67
-rw-r--r--src/pkg/hash/fnv/fnv_test.go12
-rw-r--r--src/pkg/hash/hash.go12
-rw-r--r--src/pkg/html/Makefile17
-rw-r--r--src/pkg/html/const.go90
-rw-r--r--src/pkg/html/doc.go110
-rw-r--r--src/pkg/html/entity.go4
-rw-r--r--src/pkg/html/entity_test.go2
-rw-r--r--src/pkg/html/escape.go46
-rw-r--r--src/pkg/html/node.go147
-rw-r--r--src/pkg/html/parse.go800
-rw-r--r--src/pkg/html/parse_test.go156
-rw-r--r--src/pkg/html/template/attr.go175
-rw-r--r--src/pkg/html/template/clone_test.go148
-rw-r--r--src/pkg/html/template/content.go129
-rw-r--r--src/pkg/html/template/content_test.go261
-rw-r--r--src/pkg/html/template/context.go339
-rw-r--r--src/pkg/html/template/css.go268
-rw-r--r--src/pkg/html/template/css_test.go281
-rw-r--r--src/pkg/html/template/doc.go191
-rw-r--r--src/pkg/html/template/error.go197
-rw-r--r--src/pkg/html/template/escape.go795
-rw-r--r--src/pkg/html/template/escape_test.go1657
-rw-r--r--src/pkg/html/template/html.go257
-rw-r--r--src/pkg/html/template/html_test.go94
-rw-r--r--src/pkg/html/template/js.go362
-rw-r--r--src/pkg/html/template/js_test.go401
-rw-r--r--src/pkg/html/template/template.go359
-rw-r--r--src/pkg/html/template/transition.go553
-rw-r--r--src/pkg/html/template/url.go105
-rw-r--r--src/pkg/html/template/url_test.go112
-rw-r--r--src/pkg/html/testdata/webkit/README28
-rw-r--r--src/pkg/html/testdata/webkit/adoption01.dat194
-rw-r--r--src/pkg/html/testdata/webkit/adoption02.dat31
-rw-r--r--src/pkg/html/testdata/webkit/comments01.dat135
-rw-r--r--src/pkg/html/testdata/webkit/doctype01.dat370
-rw-r--r--src/pkg/html/testdata/webkit/entities01.dat603
-rw-r--r--src/pkg/html/testdata/webkit/entities02.dat249
-rw-r--r--src/pkg/html/testdata/webkit/html5test-com.dat246
-rw-r--r--src/pkg/html/testdata/webkit/inbody01.dat43
-rw-r--r--src/pkg/html/testdata/webkit/isindex.dat40
-rw-r--r--src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.datbin115 -> 0 bytes
-rw-r--r--src/pkg/html/testdata/webkit/pending-spec-changes.dat28
-rw-r--r--src/pkg/html/testdata/webkit/plain-text-unsafe.dat8
-rw-r--r--src/pkg/html/testdata/webkit/scriptdata01.dat308
-rw-r--r--src/pkg/html/testdata/webkit/scripted/adoption01.dat15
-rw-r--r--src/pkg/html/testdata/webkit/scripted/webkit01.dat28
-rw-r--r--src/pkg/html/testdata/webkit/tables01.dat197
-rw-r--r--src/pkg/html/testdata/webkit/tests1.dat1952
-rw-r--r--src/pkg/html/testdata/webkit/tests10.dat799
-rw-r--r--src/pkg/html/testdata/webkit/tests11.dat482
-rw-r--r--src/pkg/html/testdata/webkit/tests12.dat62
-rw-r--r--src/pkg/html/testdata/webkit/tests14.dat74
-rw-r--r--src/pkg/html/testdata/webkit/tests15.dat208
-rw-r--r--src/pkg/html/testdata/webkit/tests16.dat2277
-rw-r--r--src/pkg/html/testdata/webkit/tests17.dat153
-rw-r--r--src/pkg/html/testdata/webkit/tests18.dat269
-rw-r--r--src/pkg/html/testdata/webkit/tests19.dat1220
-rw-r--r--src/pkg/html/testdata/webkit/tests2.dat763
-rw-r--r--src/pkg/html/testdata/webkit/tests20.dat455
-rw-r--r--src/pkg/html/testdata/webkit/tests21.dat221
-rw-r--r--src/pkg/html/testdata/webkit/tests22.dat157
-rw-r--r--src/pkg/html/testdata/webkit/tests23.dat155
-rw-r--r--src/pkg/html/testdata/webkit/tests24.dat79
-rw-r--r--src/pkg/html/testdata/webkit/tests25.dat219
-rw-r--r--src/pkg/html/testdata/webkit/tests26.dat195
-rw-r--r--src/pkg/html/testdata/webkit/tests3.dat305
-rw-r--r--src/pkg/html/testdata/webkit/tests4.dat59
-rw-r--r--src/pkg/html/testdata/webkit/tests5.dat191
-rw-r--r--src/pkg/html/testdata/webkit/tests6.dat663
-rw-r--r--src/pkg/html/testdata/webkit/tests7.dat390
-rw-r--r--src/pkg/html/testdata/webkit/tests8.dat148
-rw-r--r--src/pkg/html/testdata/webkit/tests9.dat457
-rw-r--r--src/pkg/html/testdata/webkit/tests_innerHTML_1.dat733
-rw-r--r--src/pkg/html/testdata/webkit/tricky01.dat261
-rw-r--r--src/pkg/html/testdata/webkit/webkit01.dat609
-rw-r--r--src/pkg/html/testdata/webkit/webkit02.dat104
-rw-r--r--src/pkg/html/token.go575
-rw-r--r--src/pkg/html/token_test.go340
-rw-r--r--src/pkg/http/Makefile26
-rw-r--r--src/pkg/http/cgi/Makefile12
-rw-r--r--src/pkg/http/chunked.go77
-rw-r--r--src/pkg/http/dump.go78
-rw-r--r--src/pkg/http/fcgi/Makefile12
-rw-r--r--src/pkg/http/httptest/Makefile12
-rw-r--r--src/pkg/http/reverseproxy_test.go66
-rw-r--r--src/pkg/http/spdy/Makefile13
-rw-r--r--src/pkg/http/spdy/read.go313
-rw-r--r--src/pkg/http/spdy/spdy_test.go497
-rw-r--r--src/pkg/http/spdy/types.go370
-rw-r--r--src/pkg/http/spdy/write.go286
-rw-r--r--src/pkg/image/Makefile15
-rw-r--r--src/pkg/image/bmp/Makefile11
-rw-r--r--src/pkg/image/bmp/reader.go151
-rw-r--r--src/pkg/image/color.go251
-rw-r--r--src/pkg/image/color/color.go303
-rw-r--r--src/pkg/image/color/ycbcr.go99
-rw-r--r--src/pkg/image/color/ycbcr_test.go (renamed from src/pkg/image/ycbcr/ycbcr_test.go)2
-rw-r--r--src/pkg/image/decode_example_test.go79
-rw-r--r--src/pkg/image/decode_test.go18
-rw-r--r--src/pkg/image/draw/Makefile11
-rw-r--r--src/pkg/image/draw/bench_test.go82
-rw-r--r--src/pkg/image/draw/clip_test.go6
-rw-r--r--src/pkg/image/draw/draw.go90
-rw-r--r--src/pkg/image/draw/draw_test.go134
-rw-r--r--src/pkg/image/format.go22
-rw-r--r--src/pkg/image/geom.go2
-rw-r--r--src/pkg/image/gif/Makefile11
-rw-r--r--src/pkg/image/gif/reader.go52
-rw-r--r--src/pkg/image/image.go409
-rw-r--r--src/pkg/image/image_test.go45
-rw-r--r--src/pkg/image/jpeg/Makefile15
-rw-r--r--src/pkg/image/jpeg/huffman.go13
-rw-r--r--src/pkg/image/jpeg/reader.go64
-rw-r--r--src/pkg/image/jpeg/writer.go22
-rw-r--r--src/pkg/image/jpeg/writer_test.go17
-rw-r--r--src/pkg/image/names.go71
-rw-r--r--src/pkg/image/png/Makefile12
-rw-r--r--src/pkg/image/png/reader.go362
-rw-r--r--src/pkg/image/png/reader_test.go70
-rw-r--r--src/pkg/image/png/testdata/invalid-crc32.pngbin0 -> 1289 bytes
-rw-r--r--src/pkg/image/png/testdata/invalid-noend.pngbin0 -> 1277 bytes
-rw-r--r--src/pkg/image/png/testdata/invalid-trunc.pngbin0 -> 1288 bytes
-rw-r--r--src/pkg/image/png/testdata/invalid-zlib.pngbin0 -> 1289 bytes
-rw-r--r--src/pkg/image/png/writer.go71
-rw-r--r--src/pkg/image/png/writer_test.go39
-rw-r--r--src/pkg/image/testdata/video-001.bmpbin46610 -> 0 bytes
-rw-r--r--src/pkg/image/testdata/video-001.tiffbin30810 -> 0 bytes
-rw-r--r--src/pkg/image/tiff/Makefile13
-rw-r--r--src/pkg/image/tiff/buffer.go57
-rw-r--r--src/pkg/image/tiff/buffer_test.go36
-rw-r--r--src/pkg/image/tiff/consts.go103
-rw-r--r--src/pkg/image/tiff/reader.go423
-rw-r--r--src/pkg/image/tiff/reader_test.go25
-rw-r--r--src/pkg/image/tiff/testdata/no_rps.tiffbin1294 -> 0 bytes
-rw-r--r--src/pkg/image/ycbcr.go144
-rw-r--r--src/pkg/image/ycbcr/Makefile11
-rw-r--r--src/pkg/image/ycbcr/ycbcr.go183
-rw-r--r--src/pkg/image/ycbcr_test.go106
-rw-r--r--src/pkg/index/suffixarray/Makefile12
-rw-r--r--src/pkg/index/suffixarray/qsufsort.go10
-rw-r--r--src/pkg/index/suffixarray/suffixarray.go130
-rw-r--r--src/pkg/index/suffixarray/suffixarray_test.go76
-rw-r--r--src/pkg/io/Makefile13
-rw-r--r--src/pkg/io/io.go150
-rw-r--r--src/pkg/io/io_test.go82
-rw-r--r--src/pkg/io/ioutil/Makefile12
-rw-r--r--src/pkg/io/ioutil/ioutil.go70
-rw-r--r--src/pkg/io/ioutil/ioutil_test.go33
-rw-r--r--src/pkg/io/ioutil/tempfile.go12
-rw-r--r--src/pkg/io/multi.go14
-rw-r--r--src/pkg/io/multi_test.go11
-rw-r--r--src/pkg/io/pipe.go51
-rw-r--r--src/pkg/io/pipe_test.go27
-rw-r--r--src/pkg/json/Makefile16
-rw-r--r--src/pkg/json/encode_test.go82
-rw-r--r--src/pkg/log/Makefile11
-rw-r--r--src/pkg/log/log.go81
-rw-r--r--src/pkg/log/syslog/syslog.go (renamed from src/pkg/syslog/syslog.go)79
-rw-r--r--src/pkg/log/syslog/syslog_test.go (renamed from src/pkg/syslog/syslog_test.go)10
-rw-r--r--src/pkg/log/syslog/syslog_unix.go (renamed from src/pkg/syslog/syslog_unix.go)8
-rw-r--r--src/pkg/log/syslog/syslog_windows.go8
-rw-r--r--src/pkg/mail/Makefile11
-rw-r--r--src/pkg/math/Makefile102
-rw-r--r--src/pkg/math/abs.go (renamed from src/pkg/math/fabs.go)13
-rw-r--r--src/pkg/math/abs_386.s (renamed from src/pkg/math/fabs_386.s)4
-rw-r--r--src/pkg/math/abs_amd64.s (renamed from src/pkg/math/fabs_amd64.s)4
-rw-r--r--src/pkg/math/abs_arm.s (renamed from src/pkg/go/build/cgotest/cgotest.h)3
-rw-r--r--src/pkg/math/acosh.go5
-rw-r--r--src/pkg/math/all_test.go314
-rw-r--r--src/pkg/math/asin.go10
-rw-r--r--src/pkg/math/asin_amd64.s9
-rw-r--r--src/pkg/math/asin_arm.s9
-rw-r--r--src/pkg/math/asin_decl.go8
-rw-r--r--src/pkg/math/asinh.go8
-rw-r--r--src/pkg/math/atan.go4
-rw-r--r--src/pkg/math/atan2.go18
-rw-r--r--[-rwxr-xr-x]src/pkg/math/atan2_386.s0
-rw-r--r--src/pkg/math/atan2_amd64.s (renamed from src/pkg/go/build/cgotest/cgotest.c)7
-rw-r--r--src/pkg/math/atan2_arm.s6
-rwxr-xr-xsrc/pkg/math/atan2_decl.go7
-rw-r--r--src/pkg/math/atan_amd64.s6
-rw-r--r--src/pkg/math/atan_arm.s6
-rw-r--r--src/pkg/math/atanh.go7
-rw-r--r--src/pkg/math/big/arith.go (renamed from src/pkg/big/arith.go)21
-rw-r--r--src/pkg/math/big/arith_386.s (renamed from src/pkg/big/arith_386.s)13
-rw-r--r--src/pkg/math/big/arith_amd64.s (renamed from src/pkg/big/arith_amd64.s)13
-rw-r--r--src/pkg/math/big/arith_arm.s (renamed from src/pkg/big/arith_arm.s)11
-rw-r--r--src/pkg/math/big/arith_decl.go (renamed from src/pkg/big/arith_decl.go)1
-rw-r--r--src/pkg/math/big/arith_test.go (renamed from src/pkg/big/arith_test.go)37
-rw-r--r--src/pkg/math/big/calibrate_test.go (renamed from src/pkg/big/calibrate_test.go)12
-rw-r--r--src/pkg/math/big/example_test.go51
-rw-r--r--src/pkg/math/big/hilbert_test.go (renamed from src/pkg/big/hilbert_test.go)0
-rw-r--r--[-rwxr-xr-x]src/pkg/math/big/int.go (renamed from src/pkg/big/int.go)168
-rw-r--r--[-rwxr-xr-x]src/pkg/math/big/int_test.go (renamed from src/pkg/big/int_test.go)41
-rw-r--r--[-rwxr-xr-x]src/pkg/math/big/nat.go (renamed from src/pkg/big/nat.go)282
-rw-r--r--[-rwxr-xr-x]src/pkg/math/big/nat_test.go (renamed from src/pkg/big/nat_test.go)250
-rw-r--r--src/pkg/math/big/rat.go (renamed from src/pkg/big/rat.go)269
-rw-r--r--src/pkg/math/big/rat_test.go (renamed from src/pkg/big/rat_test.go)168
-rw-r--r--src/pkg/math/bits.go2
-rw-r--r--src/pkg/math/cbrt.go17
-rw-r--r--src/pkg/math/cmplx/abs.go (renamed from src/pkg/cmath/abs.go)4
-rw-r--r--src/pkg/math/cmplx/asin.go (renamed from src/pkg/cmath/asin.go)6
-rw-r--r--src/pkg/math/cmplx/cmath_test.go (renamed from src/pkg/cmath/cmath_test.go)2
-rw-r--r--src/pkg/math/cmplx/conj.go (renamed from src/pkg/cmath/conj.go)2
-rw-r--r--src/pkg/math/cmplx/exp.go (renamed from src/pkg/cmath/exp.go)2
-rw-r--r--src/pkg/math/cmplx/isinf.go (renamed from src/pkg/cmath/isinf.go)2
-rw-r--r--src/pkg/math/cmplx/isnan.go (renamed from src/pkg/cmath/isnan.go)2
-rw-r--r--src/pkg/math/cmplx/log.go (renamed from src/pkg/cmath/log.go)2
-rw-r--r--src/pkg/math/cmplx/phase.go (renamed from src/pkg/cmath/phase.go)2
-rw-r--r--src/pkg/math/cmplx/polar.go (renamed from src/pkg/cmath/polar.go)2
-rw-r--r--src/pkg/math/cmplx/pow.go (renamed from src/pkg/cmath/pow.go)2
-rw-r--r--src/pkg/math/cmplx/rect.go (renamed from src/pkg/cmath/rect.go)2
-rw-r--r--src/pkg/math/cmplx/sin.go (renamed from src/pkg/cmath/sin.go)4
-rw-r--r--src/pkg/math/cmplx/sqrt.go (renamed from src/pkg/cmath/sqrt.go)8
-rw-r--r--src/pkg/math/cmplx/tan.go (renamed from src/pkg/cmath/tan.go)12
-rw-r--r--src/pkg/math/const.go12
-rw-r--r--src/pkg/math/dim.go72
-rw-r--r--src/pkg/math/dim_386.s12
-rw-r--r--src/pkg/math/dim_amd64.s142
-rw-r--r--src/pkg/math/dim_arm.s (renamed from src/pkg/go/build/cmdtest/main.go)12
-rw-r--r--src/pkg/math/erf.go20
-rw-r--r--src/pkg/math/exp.go179
-rw-r--r--src/pkg/math/exp2.go10
-rw-r--r--src/pkg/math/exp2_amd64.s6
-rw-r--r--src/pkg/math/exp2_arm.s6
-rw-r--r--src/pkg/math/exp2_decl.go7
-rw-r--r--src/pkg/math/exp_arm.s6
-rw-r--r--src/pkg/math/exp_port.go191
-rw-r--r--src/pkg/math/exp_test.go10
-rw-r--r--src/pkg/math/expm1.go10
-rw-r--r--src/pkg/math/expm1_amd64.s6
-rw-r--r--src/pkg/math/expm1_arm.s6
-rw-r--r--src/pkg/math/expm1_decl.go7
-rw-r--r--src/pkg/math/export_test.go11
-rw-r--r--src/pkg/math/fabs_decl.go7
-rw-r--r--src/pkg/math/fdim.go29
-rw-r--r--src/pkg/math/fdim_amd64.s26
-rw-r--r--src/pkg/math/fdim_decl.go9
-rw-r--r--src/pkg/math/floor.go34
-rw-r--r--src/pkg/math/floor_amd64.s12
-rw-r--r--src/pkg/math/floor_arm.s12
-rw-r--r--src/pkg/math/floor_decl.go9
-rw-r--r--src/pkg/math/fmod_decl.go7
-rw-r--r--src/pkg/math/frexp.go8
-rw-r--r--src/pkg/math/frexp_amd64.s6
-rw-r--r--src/pkg/math/frexp_arm.s6
-rw-r--r--src/pkg/math/frexp_decl.go7
-rw-r--r--src/pkg/math/gamma.go23
-rw-r--r--src/pkg/math/hypot.go10
-rw-r--r--src/pkg/math/hypot_arm.s6
-rw-r--r--src/pkg/math/hypot_decl.go7
-rw-r--r--src/pkg/math/hypot_port.go63
-rw-r--r--src/pkg/math/hypot_test.go9
-rw-r--r--src/pkg/math/j0.go12
-rw-r--r--src/pkg/math/j1.go12
-rw-r--r--src/pkg/math/jn.go16
-rw-r--r--src/pkg/math/ldexp.go8
-rw-r--r--src/pkg/math/ldexp_amd64.s6
-rw-r--r--src/pkg/math/ldexp_arm.s6
-rw-r--r--src/pkg/math/ldexp_decl.go7
-rw-r--r--src/pkg/math/lgamma.go165
-rw-r--r--src/pkg/math/log.go8
-rw-r--r--src/pkg/math/log10.go12
-rw-r--r--src/pkg/math/log10_amd64.s9
-rw-r--r--src/pkg/math/log10_arm.s9
-rw-r--r--src/pkg/math/log10_decl.go8
-rw-r--r--src/pkg/math/log1p.go13
-rw-r--r--src/pkg/math/log1p_amd64.s6
-rw-r--r--src/pkg/math/log1p_arm.s6
-rw-r--r--src/pkg/math/log1p_decl.go7
-rw-r--r--src/pkg/math/log_arm.s6
-rw-r--r--src/pkg/math/log_decl.go7
-rw-r--r--src/pkg/math/logb.go12
-rw-r--r--src/pkg/math/mod.go (renamed from src/pkg/math/fmod.go)17
-rw-r--r--src/pkg/math/mod_386.s (renamed from src/pkg/math/fmod_386.s)4
-rw-r--r--src/pkg/math/mod_amd64.s6
-rw-r--r--src/pkg/math/mod_arm.s6
-rw-r--r--src/pkg/math/modf.go7
-rw-r--r--src/pkg/math/modf_amd64.s6
-rw-r--r--src/pkg/math/modf_arm.s6
-rw-r--r--src/pkg/math/modf_decl.go7
-rw-r--r--src/pkg/math/nextafter.go10
-rw-r--r--src/pkg/math/pow.go10
-rw-r--r--src/pkg/math/pow10.go10
-rw-r--r--src/pkg/math/rand/exp.go (renamed from src/pkg/rand/exp.go)0
-rw-r--r--src/pkg/math/rand/normal.go (renamed from src/pkg/rand/normal.go)0
-rw-r--r--src/pkg/math/rand/rand.go (renamed from src/pkg/rand/rand.go)17
-rw-r--r--src/pkg/math/rand/rand_test.go (renamed from src/pkg/rand/rand_test.go)32
-rw-r--r--src/pkg/math/rand/rng.go (renamed from src/pkg/rand/rng.go)0
-rw-r--r--src/pkg/math/rand/zipf.go (renamed from src/pkg/rand/zipf.go)0
-rw-r--r--src/pkg/math/remainder.go20
-rw-r--r--src/pkg/math/remainder_amd64.s6
-rw-r--r--src/pkg/math/remainder_arm.s6
-rw-r--r--src/pkg/math/remainder_decl.go7
-rw-r--r--src/pkg/math/sin.go239
-rw-r--r--src/pkg/math/sin_amd64.s (renamed from src/pkg/math/atan_decl.go)6
-rw-r--r--src/pkg/math/sin_arm.s (renamed from src/pkg/math/exp_decl.go)6
-rw-r--r--src/pkg/math/sin_decl.go8
-rw-r--r--src/pkg/math/sincos.go64
-rw-r--r--src/pkg/math/sincos_arm.s6
-rw-r--r--src/pkg/math/sincos_decl.go7
-rw-r--r--src/pkg/math/sinh.go10
-rw-r--r--src/pkg/math/sqrt.go138
-rw-r--r--src/pkg/math/sqrt_decl.go7
-rw-r--r--src/pkg/math/sqrt_port.go147
-rw-r--r--src/pkg/math/sqrt_test.go9
-rw-r--r--src/pkg/math/tan.go142
-rw-r--r--src/pkg/math/tan_amd64.s6
-rw-r--r--src/pkg/math/tan_arm.s6
-rw-r--r--src/pkg/math/tan_decl.go7
-rw-r--r--src/pkg/math/tanh.go5
-rw-r--r--src/pkg/mime/Makefile13
-rw-r--r--src/pkg/mime/grammar.go27
-rw-r--r--src/pkg/mime/mediatype.go107
-rw-r--r--src/pkg/mime/mediatype_test.go40
-rw-r--r--src/pkg/mime/mime_test.go27
-rw-r--r--src/pkg/mime/multipart/Makefile13
-rw-r--r--src/pkg/mime/multipart/formdata.go35
-rw-r--r--src/pkg/mime/multipart/multipart.go60
-rw-r--r--src/pkg/mime/multipart/multipart_test.go17
-rw-r--r--src/pkg/mime/multipart/writer.go26
-rw-r--r--src/pkg/mime/type.go71
-rw-r--r--src/pkg/mime/type_test.go29
-rw-r--r--src/pkg/mime/type_unix.go61
-rw-r--r--src/pkg/mime/type_windows.go61
-rw-r--r--src/pkg/net/Makefile157
-rw-r--r--src/pkg/net/cgo_bsd.go2
-rw-r--r--src/pkg/net/cgo_stub.go12
-rw-r--r--src/pkg/net/cgo_unix.go17
-rw-r--r--src/pkg/net/dial.go249
-rw-r--r--src/pkg/net/dial_test.go224
-rw-r--r--src/pkg/net/dialgoogle_test.go21
-rw-r--r--src/pkg/net/dict/Makefile7
-rw-r--r--src/pkg/net/dict/dict.go211
-rw-r--r--src/pkg/net/dnsclient.go43
-rw-r--r--src/pkg/net/dnsclient_unix.go53
-rw-r--r--src/pkg/net/dnsconfig.go19
-rw-r--r--src/pkg/net/dnsmsg.go352
-rw-r--r--src/pkg/net/dnsmsg_test.go13
-rw-r--r--src/pkg/net/doc.go59
-rw-r--r--src/pkg/net/example_test.go35
-rw-r--r--src/pkg/net/fd.go530
-rw-r--r--src/pkg/net/fd_darwin.go37
-rw-r--r--src/pkg/net/fd_freebsd.go36
-rw-r--r--src/pkg/net/fd_linux.go51
-rw-r--r--src/pkg/net/fd_netbsd.go116
-rw-r--r--src/pkg/net/fd_openbsd.go36
-rw-r--r--src/pkg/net/fd_windows.go315
-rw-r--r--src/pkg/net/file.go41
-rw-r--r--src/pkg/net/file_plan9.go13
-rw-r--r--src/pkg/net/file_test.go130
-rw-r--r--src/pkg/net/file_windows.go6
-rw-r--r--src/pkg/net/hosts.go12
-rw-r--r--src/pkg/net/hosts_test.go2
-rw-r--r--src/pkg/net/http/cgi/child.go (renamed from src/pkg/http/cgi/child.go)34
-rw-r--r--src/pkg/net/http/cgi/child_test.go (renamed from src/pkg/http/cgi/child_test.go)6
-rw-r--r--src/pkg/net/http/cgi/host.go (renamed from src/pkg/http/cgi/host.go)67
-rw-r--r--src/pkg/net/http/cgi/host_test.go (renamed from src/pkg/http/cgi/host_test.go)62
-rw-r--r--src/pkg/net/http/cgi/matryoshka_test.go (renamed from src/pkg/http/cgi/matryoshka_test.go)23
-rwxr-xr-xsrc/pkg/net/http/cgi/testdata/test.cgi (renamed from src/pkg/http/cgi/testdata/test.cgi)0
-rw-r--r--src/pkg/net/http/chunked.go170
-rw-r--r--src/pkg/net/http/chunked_test.go39
-rw-r--r--src/pkg/net/http/client.go (renamed from src/pkg/http/client.go)114
-rw-r--r--src/pkg/net/http/client_test.go (renamed from src/pkg/http/client_test.go)180
-rw-r--r--src/pkg/net/http/cookie.go (renamed from src/pkg/http/cookie.go)21
-rw-r--r--src/pkg/net/http/cookie_test.go (renamed from src/pkg/http/cookie_test.go)59
-rw-r--r--src/pkg/net/http/doc.go80
-rw-r--r--src/pkg/net/http/example_test.go51
-rw-r--r--src/pkg/net/http/export_test.go (renamed from src/pkg/http/export_test.go)6
-rw-r--r--src/pkg/net/http/fcgi/child.go (renamed from src/pkg/http/fcgi/child.go)163
-rw-r--r--src/pkg/net/http/fcgi/fcgi.go (renamed from src/pkg/http/fcgi/fcgi.go)65
-rw-r--r--src/pkg/net/http/fcgi/fcgi_test.go (renamed from src/pkg/http/fcgi/fcgi_test.go)50
-rw-r--r--src/pkg/net/http/filetransport.go123
-rw-r--r--src/pkg/net/http/filetransport_test.go65
-rw-r--r--src/pkg/net/http/fs.go (renamed from src/pkg/http/fs.go)264
-rw-r--r--src/pkg/net/http/fs_test.go (renamed from src/pkg/http/fs_test.go)220
-rw-r--r--src/pkg/net/http/header.go (renamed from src/pkg/http/header.go)14
-rw-r--r--src/pkg/net/http/header_test.go (renamed from src/pkg/http/header_test.go)0
-rw-r--r--src/pkg/net/http/httptest/recorder.go (renamed from src/pkg/http/httptest/recorder.go)5
-rw-r--r--src/pkg/net/http/httptest/server.go (renamed from src/pkg/http/httptest/server.go)128
-rw-r--r--src/pkg/net/http/httptest/server_test.go29
-rw-r--r--src/pkg/net/http/httputil/chunked.go172
-rw-r--r--src/pkg/net/http/httputil/chunked_test.go41
-rw-r--r--src/pkg/net/http/httputil/dump.go229
-rw-r--r--src/pkg/net/http/httputil/dump_test.go152
-rw-r--r--src/pkg/net/http/httputil/persist.go (renamed from src/pkg/http/persist.go)74
-rw-r--r--src/pkg/net/http/httputil/reverseproxy.go (renamed from src/pkg/http/reverseproxy.go)71
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go109
-rw-r--r--src/pkg/net/http/jar.go30
-rw-r--r--src/pkg/net/http/lex.go (renamed from src/pkg/http/lex.go)8
-rw-r--r--src/pkg/net/http/lex_test.go (renamed from src/pkg/http/lex_test.go)0
-rw-r--r--src/pkg/net/http/pprof/pprof.go (renamed from src/pkg/http/pprof/pprof.go)94
-rw-r--r--src/pkg/net/http/proxy_test.go (renamed from src/pkg/http/proxy_test.go)0
-rw-r--r--src/pkg/net/http/range_test.go (renamed from src/pkg/http/range_test.go)0
-rw-r--r--src/pkg/net/http/readrequest_test.go (renamed from src/pkg/http/readrequest_test.go)170
-rw-r--r--src/pkg/net/http/request.go (renamed from src/pkg/http/request.go)356
-rw-r--r--src/pkg/net/http/request_test.go (renamed from src/pkg/http/request_test.go)128
-rw-r--r--src/pkg/net/http/requestwrite_test.go (renamed from src/pkg/http/requestwrite_test.go)228
-rw-r--r--src/pkg/net/http/response.go (renamed from src/pkg/http/response.go)52
-rw-r--r--src/pkg/net/http/response_test.go (renamed from src/pkg/http/response_test.go)63
-rw-r--r--src/pkg/net/http/responsewrite_test.go (renamed from src/pkg/http/responsewrite_test.go)0
-rw-r--r--src/pkg/net/http/serve_test.go (renamed from src/pkg/http/serve_test.go)393
-rw-r--r--src/pkg/net/http/server.go (renamed from src/pkg/http/server.go)401
-rw-r--r--src/pkg/net/http/sniff.go (renamed from src/pkg/http/sniff.go)50
-rw-r--r--src/pkg/net/http/sniff_test.go (renamed from src/pkg/http/sniff_test.go)62
-rw-r--r--src/pkg/net/http/status.go (renamed from src/pkg/http/status.go)2
-rw-r--r--src/pkg/net/http/testdata/file (renamed from src/pkg/http/testdata/file)0
-rw-r--r--src/pkg/net/http/testdata/index.html (renamed from src/pkg/http/testdata/index.html)0
-rw-r--r--src/pkg/net/http/testdata/style.css (renamed from src/pkg/http/testdata/style.css)0
-rw-r--r--src/pkg/net/http/transfer.go (renamed from src/pkg/http/transfer.go)178
-rw-r--r--src/pkg/net/http/transport.go (renamed from src/pkg/http/transport.go)290
-rw-r--r--src/pkg/net/http/transport_test.go (renamed from src/pkg/http/transport_test.go)269
-rw-r--r--src/pkg/net/http/triv.go (renamed from src/pkg/http/triv.go)58
-rw-r--r--src/pkg/net/interface.go52
-rw-r--r--src/pkg/net/interface_bsd.go112
-rw-r--r--src/pkg/net/interface_darwin.go35
-rw-r--r--src/pkg/net/interface_freebsd.go35
-rw-r--r--src/pkg/net/interface_linux.go164
-rw-r--r--src/pkg/net/interface_linux_test.go54
-rw-r--r--src/pkg/net/interface_netbsd.go14
-rw-r--r--src/pkg/net/interface_openbsd.go4
-rw-r--r--src/pkg/net/interface_stub.go12
-rw-r--r--src/pkg/net/interface_test.go65
-rw-r--r--src/pkg/net/interface_windows.go54
-rw-r--r--src/pkg/net/ip.go259
-rw-r--r--src/pkg/net/ip_test.go243
-rw-r--r--src/pkg/net/ipraw_test.go246
-rw-r--r--src/pkg/net/iprawsock.go8
-rw-r--r--src/pkg/net/iprawsock_plan9.go94
-rw-r--r--src/pkg/net/iprawsock_posix.go193
-rw-r--r--src/pkg/net/ipsock.go41
-rw-r--r--src/pkg/net/ipsock_plan9.go92
-rw-r--r--src/pkg/net/ipsock_posix.go114
-rw-r--r--src/pkg/net/lookup_plan9.go74
-rw-r--r--src/pkg/net/lookup_test.go70
-rw-r--r--src/pkg/net/lookup_unix.go104
-rw-r--r--src/pkg/net/lookup_windows.go89
-rw-r--r--src/pkg/net/mac.go86
-rw-r--r--src/pkg/net/mac_test.go66
-rw-r--r--src/pkg/net/mail/message.go (renamed from src/pkg/mail/message.go)67
-rw-r--r--src/pkg/net/mail/message_test.go (renamed from src/pkg/mail/message_test.go)51
-rw-r--r--src/pkg/net/multicast_test.go241
-rw-r--r--src/pkg/net/net.go190
-rw-r--r--src/pkg/net/net_test.go189
-rw-r--r--src/pkg/net/newpollserver.go17
-rw-r--r--src/pkg/net/parse.go49
-rw-r--r--src/pkg/net/parse_test.go6
-rw-r--r--src/pkg/net/pipe.go21
-rw-r--r--src/pkg/net/pipe_test.go5
-rw-r--r--src/pkg/net/port.go11
-rw-r--r--src/pkg/net/rpc/client.go (renamed from src/pkg/rpc/client.go)129
-rw-r--r--src/pkg/net/rpc/debug.go (renamed from src/pkg/rpc/debug.go)8
-rw-r--r--src/pkg/net/rpc/jsonrpc/all_test.go (renamed from src/pkg/rpc/jsonrpc/all_test.go)91
-rw-r--r--src/pkg/net/rpc/jsonrpc/client.go (renamed from src/pkg/rpc/jsonrpc/client.go)17
-rw-r--r--src/pkg/net/rpc/jsonrpc/server.go (renamed from src/pkg/rpc/jsonrpc/server.go)18
-rw-r--r--src/pkg/net/rpc/server.go (renamed from src/pkg/rpc/server.go)152
-rw-r--r--src/pkg/net/rpc/server_test.go (renamed from src/pkg/rpc/server_test.go)226
-rw-r--r--src/pkg/net/sendfile_linux.go32
-rw-r--r--src/pkg/net/sendfile_stub.go9
-rw-r--r--src/pkg/net/sendfile_windows.go12
-rw-r--r--src/pkg/net/server_test.go556
-rw-r--r--src/pkg/net/smtp/auth.go (renamed from src/pkg/smtp/auth.go)49
-rw-r--r--src/pkg/net/smtp/smtp.go (renamed from src/pkg/smtp/smtp.go)40
-rw-r--r--src/pkg/net/smtp/smtp_test.go (renamed from src/pkg/smtp/smtp_test.go)119
-rw-r--r--src/pkg/net/sock.go141
-rw-r--r--src/pkg/net/sock_bsd.go65
-rw-r--r--src/pkg/net/sock_linux.go59
-rw-r--r--src/pkg/net/sock_windows.go46
-rw-r--r--src/pkg/net/sockopt.go193
-rw-r--r--src/pkg/net/sockopt_bsd.go61
-rw-r--r--src/pkg/net/sockopt_linux.go51
-rw-r--r--src/pkg/net/sockopt_windows.go49
-rw-r--r--src/pkg/net/sockoptip.go219
-rw-r--r--src/pkg/net/sockoptip_bsd.go62
-rw-r--r--src/pkg/net/sockoptip_darwin.go90
-rw-r--r--src/pkg/net/sockoptip_freebsd.go92
-rw-r--r--src/pkg/net/sockoptip_linux.go140
-rw-r--r--src/pkg/net/sockoptip_netbsd.go39
-rw-r--r--src/pkg/net/sockoptip_openbsd.go90
-rw-r--r--src/pkg/net/sockoptip_windows.go91
-rw-r--r--src/pkg/net/tcpsock.go6
-rw-r--r--src/pkg/net/tcpsock_plan9.go44
-rw-r--r--src/pkg/net/tcpsock_posix.go188
-rw-r--r--src/pkg/net/testdata/hosts (renamed from src/pkg/net/hosts_testdata)0
-rw-r--r--src/pkg/net/testdata/igmp24
-rw-r--r--src/pkg/net/testdata/igmp618
-rw-r--r--src/pkg/net/textproto/Makefile15
-rw-r--r--src/pkg/net/textproto/header.go2
-rw-r--r--src/pkg/net/textproto/pipeline.go2
-rw-r--r--src/pkg/net/textproto/reader.go172
-rw-r--r--src/pkg/net/textproto/reader_test.go109
-rw-r--r--src/pkg/net/textproto/textproto.go14
-rw-r--r--src/pkg/net/textproto/writer.go7
-rw-r--r--src/pkg/net/timeout_test.go112
-rw-r--r--src/pkg/net/udp_test.go89
-rw-r--r--src/pkg/net/udpsock.go6
-rw-r--r--src/pkg/net/udpsock_plan9.go75
-rw-r--r--src/pkg/net/udpsock_posix.go246
-rw-r--r--src/pkg/net/unicast_test.go538
-rw-r--r--src/pkg/net/unixsock.go6
-rw-r--r--src/pkg/net/unixsock_plan9.go65
-rw-r--r--src/pkg/net/unixsock_posix.go198
-rw-r--r--src/pkg/net/url/example_test.go41
-rw-r--r--src/pkg/net/url/url.go (renamed from src/pkg/url/url.go)460
-rw-r--r--src/pkg/net/url/url_test.go (renamed from src/pkg/url/url_test.go)448
-rw-r--r--src/pkg/netchan/Makefile13
-rw-r--r--src/pkg/netchan/common.go336
-rw-r--r--src/pkg/netchan/export.go400
-rw-r--r--src/pkg/netchan/import.go287
-rw-r--r--src/pkg/netchan/netchan_test.go435
-rw-r--r--src/pkg/old/template/Makefile14
-rw-r--r--src/pkg/old/template/doc.go91
-rw-r--r--src/pkg/old/template/execute.go346
-rw-r--r--src/pkg/old/template/format.go77
-rw-r--r--src/pkg/old/template/parse.go743
-rw-r--r--src/pkg/old/template/template_test.go804
-rw-r--r--src/pkg/os/Makefile100
-rw-r--r--src/pkg/os/dir_plan9.go64
-rw-r--r--src/pkg/os/dir_unix.go23
-rw-r--r--src/pkg/os/dir_windows.go4
-rw-r--r--src/pkg/os/doc.go124
-rw-r--r--src/pkg/os/env.go40
-rw-r--r--src/pkg/os/env_plan9.go96
-rw-r--r--src/pkg/os/env_test.go11
-rw-r--r--src/pkg/os/env_unix.go109
-rw-r--r--src/pkg/os/env_windows.go127
-rw-r--r--src/pkg/os/error.go65
-rw-r--r--src/pkg/os/error_plan9.go73
-rw-r--r--src/pkg/os/error_posix.go94
-rw-r--r--src/pkg/os/error_test.go81
-rw-r--r--src/pkg/os/error_windows.go30
-rw-r--r--src/pkg/os/exec.go19
-rw-r--r--src/pkg/os/exec/example_test.go75
-rw-r--r--src/pkg/os/exec/exec.go (renamed from src/pkg/exec/exec.go)122
-rw-r--r--src/pkg/os/exec/exec_test.go (renamed from src/pkg/exec/exec_test.go)129
-rw-r--r--src/pkg/os/exec/lp_plan9.go (renamed from src/pkg/exec/lp_plan9.go)12
-rw-r--r--src/pkg/os/exec/lp_test.go (renamed from src/pkg/exec/lp_test.go)0
-rw-r--r--src/pkg/os/exec/lp_unix.go (renamed from src/pkg/exec/lp_unix.go)18
-rw-r--r--src/pkg/os/exec/lp_windows.go (renamed from src/pkg/exec/lp_windows.go)31
-rw-r--r--src/pkg/os/exec_plan9.go125
-rw-r--r--src/pkg/os/exec_posix.go122
-rw-r--r--src/pkg/os/exec_unix.go75
-rw-r--r--src/pkg/os/exec_windows.go76
-rw-r--r--src/pkg/os/export_test.go (renamed from src/pkg/go/build/pkgtest/pkgtest.go)6
-rw-r--r--src/pkg/os/file.go207
-rw-r--r--src/pkg/os/file_plan9.go191
-rw-r--r--src/pkg/os/file_posix.go198
-rw-r--r--src/pkg/os/file_unix.go216
-rw-r--r--src/pkg/os/file_windows.go248
-rw-r--r--src/pkg/os/getwd.go16
-rw-r--r--src/pkg/os/inotify/Makefile14
-rw-r--r--src/pkg/os/inotify/inotify_linux.go288
-rw-r--r--src/pkg/os/inotify/inotify_linux_test.go96
-rwxr-xr-xsrc/pkg/os/mkunixsignals.sh24
-rw-r--r--src/pkg/os/os_test.go328
-rw-r--r--src/pkg/os/os_unix_test.go76
-rw-r--r--src/pkg/os/path.go21
-rw-r--r--src/pkg/os/path_test.go37
-rw-r--r--src/pkg/os/path_unix.go2
-rw-r--r--src/pkg/os/proc.go6
-rw-r--r--src/pkg/os/signal/Makefile11
-rw-r--r--src/pkg/os/signal/sig.s16
-rw-r--r--src/pkg/os/signal/signal.go73
-rw-r--r--src/pkg/os/signal/signal_stub.go11
-rw-r--r--src/pkg/os/signal/signal_test.go50
-rw-r--r--src/pkg/os/signal/signal_unix.go38
-rw-r--r--src/pkg/os/signal/signal_windows_test.go51
-rw-r--r--src/pkg/os/stat_darwin.go71
-rw-r--r--src/pkg/os/stat_freebsd.go71
-rw-r--r--src/pkg/os/stat_linux.go71
-rw-r--r--src/pkg/os/stat_netbsd.go61
-rw-r--r--src/pkg/os/stat_openbsd.go71
-rw-r--r--src/pkg/os/stat_plan9.go126
-rw-r--r--src/pkg/os/stat_windows.go258
-rw-r--r--src/pkg/os/str.go2
-rw-r--r--src/pkg/os/sys_bsd.go11
-rw-r--r--src/pkg/os/sys_linux.go3
-rw-r--r--src/pkg/os/sys_plan9.go2
-rw-r--r--src/pkg/os/sys_windows.go4
-rw-r--r--src/pkg/os/time.go19
-rw-r--r--src/pkg/os/types.go143
-rw-r--r--src/pkg/os/user/Makefile26
-rw-r--r--src/pkg/os/user/lookup_stubs.go15
-rw-r--r--src/pkg/os/user/lookup_unix.go31
-rw-r--r--src/pkg/os/user/lookup_windows.go117
-rw-r--r--src/pkg/os/user/user.go14
-rw-r--r--src/pkg/os/user/user_test.go76
-rw-r--r--src/pkg/patch/Makefile14
-rw-r--r--src/pkg/patch/apply.go54
-rw-r--r--src/pkg/patch/git.go121
-rw-r--r--src/pkg/patch/patch.go322
-rw-r--r--src/pkg/patch/patch_test.go390
-rw-r--r--src/pkg/patch/textdiff.go175
-rw-r--r--src/pkg/path/Makefile14
-rw-r--r--src/pkg/path/example_test.go63
-rw-r--r--src/pkg/path/filepath/Makefile32
-rw-r--r--src/pkg/path/filepath/match.go51
-rw-r--r--src/pkg/path/filepath/match_test.go57
-rw-r--r--src/pkg/path/filepath/path.go289
-rw-r--r--src/pkg/path/filepath/path_plan9.go2
-rw-r--r--src/pkg/path/filepath/path_test.go515
-rw-r--r--src/pkg/path/filepath/path_unix.go4
-rw-r--r--src/pkg/path/filepath/path_windows.go42
-rw-r--r--src/pkg/path/filepath/symlink.go67
-rw-r--r--src/pkg/path/filepath/symlink_windows.go63
-rw-r--r--src/pkg/path/match.go18
-rw-r--r--src/pkg/path/match_test.go7
-rw-r--r--src/pkg/path/path.go31
-rw-r--r--src/pkg/path/path_test.go39
-rw-r--r--src/pkg/rand/Makefile15
-rw-r--r--src/pkg/reflect/Makefile13
-rw-r--r--src/pkg/reflect/all_test.go198
-rw-r--r--src/pkg/reflect/deepequal.go16
-rw-r--r--src/pkg/reflect/tostring_test.go10
-rw-r--r--src/pkg/reflect/type.go253
-rw-r--r--src/pkg/reflect/value.go1476
-rw-r--r--src/pkg/regexp/Makefile11
-rw-r--r--src/pkg/regexp/all_test.go165
-rw-r--r--src/pkg/regexp/exec.go (renamed from src/pkg/exp/regexp/exec.go)198
-rw-r--r--src/pkg/regexp/exec_test.go709
-rw-r--r--src/pkg/regexp/find_test.go32
-rw-r--r--src/pkg/regexp/regexp.go1343
-rw-r--r--src/pkg/regexp/syntax/compile.go (renamed from src/pkg/exp/regexp/syntax/compile.go)46
-rwxr-xr-xsrc/pkg/regexp/syntax/make_perl_groups.pl (renamed from src/pkg/exp/regexp/syntax/make_perl_groups.pl)2
-rw-r--r--src/pkg/regexp/syntax/parse.go (renamed from src/pkg/exp/regexp/syntax/parse.go)228
-rw-r--r--src/pkg/regexp/syntax/parse_test.go (renamed from src/pkg/exp/regexp/syntax/parse_test.go)233
-rw-r--r--src/pkg/regexp/syntax/perl_groups.go (renamed from src/pkg/exp/regexp/syntax/perl_groups.go)34
-rw-r--r--src/pkg/regexp/syntax/prog.go (renamed from src/pkg/exp/regexp/syntax/prog.go)101
-rw-r--r--src/pkg/regexp/syntax/prog_test.go (renamed from src/pkg/exp/regexp/syntax/prog_test.go)40
-rw-r--r--src/pkg/regexp/syntax/regexp.go (renamed from src/pkg/exp/regexp/syntax/regexp.go)57
-rw-r--r--src/pkg/regexp/syntax/simplify.go (renamed from src/pkg/exp/regexp/syntax/simplify.go)0
-rw-r--r--src/pkg/regexp/syntax/simplify_test.go (renamed from src/pkg/exp/regexp/syntax/simplify_test.go)12
-rw-r--r--src/pkg/regexp/testdata/README23
-rw-r--r--src/pkg/regexp/testdata/basic.dat221
-rw-r--r--src/pkg/regexp/testdata/nullsubexpr.dat79
-rw-r--r--src/pkg/regexp/testdata/re2-exhaustive.txt.bz2bin0 -> 394016 bytes
-rw-r--r--src/pkg/regexp/testdata/re2-search.txt3667
-rw-r--r--src/pkg/regexp/testdata/repetition.dat163
-rw-r--r--src/pkg/regexp/testdata/testregex.c2286
-rw-r--r--src/pkg/rpc/Makefile13
-rw-r--r--src/pkg/rpc/jsonrpc/Makefile12
-rw-r--r--src/pkg/runtime/386/arch.h3
-rw-r--r--src/pkg/runtime/Makefile165
-rw-r--r--src/pkg/runtime/alg.c484
-rw-r--r--src/pkg/runtime/amd64/arch.h3
-rw-r--r--src/pkg/runtime/arch_386.h4
-rw-r--r--src/pkg/runtime/arch_amd64.h4
-rw-r--r--src/pkg/runtime/arch_arm.h4
-rw-r--r--src/pkg/runtime/arm/arch.h3
-rw-r--r--src/pkg/runtime/asm_386.s (renamed from src/pkg/runtime/386/asm.s)81
-rw-r--r--src/pkg/runtime/asm_amd64.s (renamed from src/pkg/runtime/amd64/asm.s)76
-rw-r--r--src/pkg/runtime/asm_arm.s (renamed from src/pkg/runtime/arm/asm.s)42
-rw-r--r--src/pkg/runtime/atomic_386.c (renamed from src/pkg/runtime/386/atomic.c)0
-rw-r--r--src/pkg/runtime/atomic_amd64.c (renamed from src/pkg/runtime/amd64/atomic.c)0
-rw-r--r--src/pkg/runtime/atomic_arm.c (renamed from src/pkg/runtime/arm/atomic.c)0
-rw-r--r--src/pkg/runtime/callback_windows_386.c107
-rw-r--r--src/pkg/runtime/callback_windows_amd64.c104
-rw-r--r--src/pkg/runtime/cgo/Makefile60
-rw-r--r--src/pkg/runtime/cgo/cgo.go12
-rw-r--r--[-rwxr-xr-x]src/pkg/runtime/cgo/gcc_386.S (renamed from src/pkg/runtime/cgo/386.S)0
-rw-r--r--src/pkg/runtime/cgo/gcc_amd64.S (renamed from src/pkg/runtime/cgo/amd64.S)21
-rw-r--r--src/pkg/runtime/cgo/gcc_arm.S (renamed from src/pkg/runtime/cgo/arm.S)0
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_386.c (renamed from src/pkg/runtime/cgo/darwin_386.c)25
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_amd64.c (renamed from src/pkg/runtime/cgo/darwin_amd64.c)25
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_386.c (renamed from src/pkg/runtime/cgo/freebsd_386.c)21
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_amd64.c (renamed from src/pkg/runtime/cgo/freebsd_amd64.c)22
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c (renamed from src/pkg/runtime/cgo/linux_386.c)19
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c (renamed from src/pkg/runtime/cgo/linux_amd64.c)20
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_arm.c (renamed from src/pkg/runtime/cgo/linux_arm.c)5
-rw-r--r--src/pkg/runtime/cgo/gcc_setenv.c (renamed from src/pkg/runtime/cgo/setenv.c)2
-rw-r--r--src/pkg/runtime/cgo/gcc_util.c (renamed from src/pkg/runtime/cgo/util.c)2
-rw-r--r--[-rwxr-xr-x]src/pkg/runtime/cgo/gcc_windows_386.c (renamed from src/pkg/runtime/cgo/windows_386.c)25
-rw-r--r--[-rwxr-xr-x]src/pkg/runtime/cgo/gcc_windows_amd64.c (renamed from src/pkg/runtime/cgo/windows_amd64.c)25
-rw-r--r--src/pkg/runtime/cgo/libcgo.h2
-rw-r--r--src/pkg/runtime/cgocall.c54
-rw-r--r--src/pkg/runtime/chan.c41
-rw-r--r--src/pkg/runtime/chan_test.go60
-rw-r--r--src/pkg/runtime/closure_386.c (renamed from src/pkg/runtime/386/closure.c)0
-rw-r--r--src/pkg/runtime/closure_amd64.c (renamed from src/pkg/runtime/amd64/closure.c)0
-rw-r--r--src/pkg/runtime/closure_arm.c (renamed from src/pkg/runtime/arm/closure.c)0
-rw-r--r--src/pkg/runtime/compiler.go13
-rw-r--r--src/pkg/runtime/cpuprof.c1
-rw-r--r--src/pkg/runtime/darwin/386/defs.h289
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h305
-rw-r--r--src/pkg/runtime/darwin/defs.c159
-rw-r--r--src/pkg/runtime/darwin/signals.h51
-rw-r--r--src/pkg/runtime/debug.go62
-rw-r--r--src/pkg/runtime/debug/Makefile11
-rw-r--r--src/pkg/runtime/debug/stack_test.go21
-rw-r--r--src/pkg/runtime/defs1_linux.go37
-rw-r--r--src/pkg/runtime/defs2_linux.go126
-rw-r--r--src/pkg/runtime/defs_arm_linux.go124
-rw-r--r--src/pkg/runtime/defs_darwin.go163
-rw-r--r--src/pkg/runtime/defs_darwin_386.h366
-rw-r--r--src/pkg/runtime/defs_darwin_amd64.h369
-rw-r--r--src/pkg/runtime/defs_freebsd.go117
-rw-r--r--src/pkg/runtime/defs_freebsd_386.h (renamed from src/pkg/runtime/freebsd/386/defs.h)6
-rw-r--r--src/pkg/runtime/defs_freebsd_amd64.h (renamed from src/pkg/runtime/freebsd/amd64/defs.h)6
-rw-r--r--src/pkg/runtime/defs_linux.go104
-rw-r--r--src/pkg/runtime/defs_linux_386.h191
-rw-r--r--src/pkg/runtime/defs_linux_amd64.h234
-rw-r--r--src/pkg/runtime/defs_linux_arm.h (renamed from src/pkg/runtime/linux/arm/defs.h)3
-rw-r--r--src/pkg/runtime/defs_netbsd.go111
-rw-r--r--src/pkg/runtime/defs_netbsd_386.h146
-rw-r--r--src/pkg/runtime/defs_netbsd_amd64.h (renamed from src/pkg/runtime/openbsd/amd64/defs.h)9
-rw-r--r--src/pkg/runtime/defs_openbsd.go111
-rw-r--r--src/pkg/runtime/defs_openbsd_386.h146
-rw-r--r--src/pkg/runtime/defs_openbsd_amd64.h158
-rw-r--r--src/pkg/runtime/defs_plan9_386.h (renamed from src/pkg/runtime/plan9/386/defs.h)0
-rw-r--r--src/pkg/runtime/defs_windows.go66
-rw-r--r--src/pkg/runtime/defs_windows_386.h (renamed from src/pkg/runtime/windows/386/defs.h)18
-rw-r--r--src/pkg/runtime/defs_windows_amd64.h114
-rw-r--r--src/pkg/runtime/error.go49
-rw-r--r--src/pkg/runtime/export_test.go4
-rw-r--r--src/pkg/runtime/extern.go75
-rw-r--r--src/pkg/runtime/freebsd/defs.c108
-rw-r--r--src/pkg/runtime/freebsd/os.h12
-rw-r--r--src/pkg/runtime/freebsd/signals.h52
-rw-r--r--src/pkg/runtime/freebsd/thread.c201
-rw-r--r--src/pkg/runtime/gc_test.go41
-rw-r--r--src/pkg/runtime/hashmap.c370
-rw-r--r--src/pkg/runtime/hashmap.h5
-rw-r--r--src/pkg/runtime/iface.c178
-rw-r--r--src/pkg/runtime/linux/386/defs.h191
-rw-r--r--src/pkg/runtime/linux/amd64/defs.h236
-rw-r--r--src/pkg/runtime/linux/defs.c95
-rw-r--r--src/pkg/runtime/linux/defs1.c24
-rw-r--r--src/pkg/runtime/linux/defs2.c120
-rw-r--r--src/pkg/runtime/linux/defs_arm.c122
-rw-r--r--src/pkg/runtime/linux/signals.h51
-rw-r--r--src/pkg/runtime/lock_futex.c156
-rw-r--r--src/pkg/runtime/lock_sema.c230
-rw-r--r--src/pkg/runtime/malloc.goc125
-rw-r--r--src/pkg/runtime/malloc.h59
-rw-r--r--src/pkg/runtime/malloc1.go26
-rw-r--r--src/pkg/runtime/mallocrand.go93
-rw-r--r--src/pkg/runtime/mallocrep.go72
-rw-r--r--src/pkg/runtime/mallocrep1.go143
-rw-r--r--src/pkg/runtime/mcache.c1
-rw-r--r--src/pkg/runtime/mcentral.c1
-rw-r--r--src/pkg/runtime/mem.go35
-rw-r--r--src/pkg/runtime/mem_darwin.c (renamed from src/pkg/runtime/darwin/mem.c)14
-rw-r--r--src/pkg/runtime/mem_freebsd.c (renamed from src/pkg/runtime/freebsd/mem.c)9
-rw-r--r--src/pkg/runtime/mem_linux.c131
-rw-r--r--src/pkg/runtime/mem_netbsd.c (renamed from src/pkg/runtime/openbsd/mem.c)29
-rw-r--r--src/pkg/runtime/mem_openbsd.c (renamed from src/pkg/runtime/linux/mem.c)62
-rw-r--r--src/pkg/runtime/mem_plan9.c (renamed from src/pkg/runtime/plan9/mem.c)5
-rw-r--r--src/pkg/runtime/mem_windows.c (renamed from src/pkg/runtime/windows/mem.c)5
-rw-r--r--src/pkg/runtime/memmove_386.s (renamed from src/pkg/runtime/386/memmove.s)0
-rw-r--r--src/pkg/runtime/memmove_amd64.s (renamed from src/pkg/runtime/amd64/memmove.s)0
-rw-r--r--src/pkg/runtime/memmove_arm.s (renamed from src/pkg/runtime/arm/memmove.s)0
-rw-r--r--src/pkg/runtime/memset_arm.s (renamed from src/pkg/runtime/arm/memset.s)0
-rw-r--r--src/pkg/runtime/mfinal.c193
-rw-r--r--src/pkg/runtime/mfinal_test.go64
-rw-r--r--src/pkg/runtime/mfixalloc.c1
-rw-r--r--src/pkg/runtime/mgc0.c737
-rw-r--r--src/pkg/runtime/mheap.c89
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh44
-rwxr-xr-xsrc/pkg/runtime/mkgodefs.sh39
-rw-r--r--src/pkg/runtime/mkversion.c8
-rw-r--r--src/pkg/runtime/mprof.goc146
-rw-r--r--src/pkg/runtime/msize.c1
-rw-r--r--src/pkg/runtime/openbsd/defs.c103
-rw-r--r--src/pkg/runtime/openbsd/os.h12
-rw-r--r--src/pkg/runtime/openbsd/signals.h52
-rw-r--r--src/pkg/runtime/openbsd/thread.c156
-rw-r--r--src/pkg/runtime/os_darwin.h (renamed from src/pkg/runtime/darwin/os.h)15
-rw-r--r--src/pkg/runtime/os_freebsd.h26
-rw-r--r--src/pkg/runtime/os_linux.h (renamed from src/pkg/runtime/linux/os.h)24
-rw-r--r--src/pkg/runtime/os_netbsd.h21
-rw-r--r--src/pkg/runtime/os_openbsd.h21
-rw-r--r--src/pkg/runtime/os_plan9.h (renamed from src/pkg/runtime/plan9/os.h)30
-rw-r--r--src/pkg/runtime/os_windows.h (renamed from src/pkg/runtime/windows/os.h)12
-rw-r--r--src/pkg/runtime/plan9/thread.c174
-rw-r--r--src/pkg/runtime/pprof/Makefile11
-rw-r--r--src/pkg/runtime/pprof/pprof.go507
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go17
-rw-r--r--src/pkg/runtime/print.c62
-rw-r--r--src/pkg/runtime/proc.c481
-rw-r--r--src/pkg/runtime/rt0_darwin_386.s (renamed from src/pkg/runtime/darwin/386/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_darwin_amd64.s (renamed from src/pkg/runtime/darwin/amd64/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_freebsd_386.s (renamed from src/pkg/runtime/freebsd/386/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_freebsd_amd64.s (renamed from src/pkg/runtime/freebsd/amd64/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_linux_386.s17
-rw-r--r--src/pkg/runtime/rt0_linux_amd64.s (renamed from src/pkg/runtime/linux/amd64/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_linux_arm.s60
-rw-r--r--src/pkg/runtime/rt0_netbsd_386.s (renamed from src/pkg/runtime/linux/arm/rt0.s)4
-rw-r--r--src/pkg/runtime/rt0_netbsd_amd64.s (renamed from src/pkg/runtime/linux/386/rt0.s)9
-rw-r--r--src/pkg/runtime/rt0_openbsd_386.s6
-rw-r--r--src/pkg/runtime/rt0_openbsd_amd64.s (renamed from src/pkg/runtime/openbsd/amd64/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_plan9_386.s (renamed from src/pkg/runtime/plan9/386/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_windows_386.s (renamed from src/pkg/runtime/windows/386/rt0.s)0
-rw-r--r--src/pkg/runtime/rt0_windows_amd64.s (renamed from src/pkg/runtime/windows/amd64/rt0.s)2
-rw-r--r--src/pkg/runtime/runtime-gdb.py83
-rw-r--r--src/pkg/runtime/runtime.c401
-rw-r--r--src/pkg/runtime/runtime.h247
-rw-r--r--src/pkg/runtime/runtime1.goc4
-rw-r--r--src/pkg/runtime/runtime_linux_test.go29
-rw-r--r--src/pkg/runtime/runtime_test.go40
-rw-r--r--src/pkg/runtime/sema.goc14
-rw-r--r--src/pkg/runtime/sig.go16
-rw-r--r--src/pkg/runtime/signal_darwin_386.c (renamed from src/pkg/runtime/darwin/386/signal.c)106
-rw-r--r--src/pkg/runtime/signal_darwin_amd64.c (renamed from src/pkg/runtime/darwin/amd64/signal.c)108
-rw-r--r--src/pkg/runtime/signal_freebsd_386.c (renamed from src/pkg/runtime/freebsd/386/signal.c)93
-rw-r--r--src/pkg/runtime/signal_freebsd_amd64.c (renamed from src/pkg/runtime/freebsd/amd64/signal.c)93
-rw-r--r--src/pkg/runtime/signal_linux_386.c (renamed from src/pkg/runtime/linux/386/signal.c)98
-rw-r--r--src/pkg/runtime/signal_linux_amd64.c (renamed from src/pkg/runtime/linux/amd64/signal.c)87
-rw-r--r--src/pkg/runtime/signal_linux_arm.c (renamed from src/pkg/runtime/linux/arm/signal.c)83
-rw-r--r--src/pkg/runtime/signal_netbsd_386.c132
-rw-r--r--src/pkg/runtime/signal_netbsd_amd64.c (renamed from src/pkg/runtime/openbsd/amd64/signal.c)94
-rw-r--r--src/pkg/runtime/signal_openbsd_386.c132
-rw-r--r--src/pkg/runtime/signal_openbsd_amd64.c141
-rw-r--r--src/pkg/runtime/signal_plan9_386.c (renamed from src/pkg/runtime/plan9/386/signal.c)9
-rw-r--r--src/pkg/runtime/signal_unix.c70
-rw-r--r--src/pkg/runtime/signal_windows_386.c (renamed from src/pkg/runtime/windows/386/signal.c)29
-rw-r--r--src/pkg/runtime/signal_windows_amd64.c100
-rw-r--r--src/pkg/runtime/signals_darwin.h50
-rw-r--r--src/pkg/runtime/signals_freebsd.h51
-rw-r--r--src/pkg/runtime/signals_linux.h83
-rw-r--r--src/pkg/runtime/signals_netbsd.h51
-rw-r--r--src/pkg/runtime/signals_openbsd.h51
-rw-r--r--src/pkg/runtime/signals_plan9.h (renamed from src/pkg/runtime/plan9/signals.h)0
-rw-r--r--src/pkg/runtime/signals_windows.h (renamed from src/pkg/runtime/windows/signals.h)0
-rw-r--r--src/pkg/runtime/sigqueue.goc112
-rw-r--r--src/pkg/runtime/slice.c65
-rw-r--r--src/pkg/runtime/softfloat64.go2
-rw-r--r--src/pkg/runtime/softfloat64_test.go2
-rw-r--r--src/pkg/runtime/softfloat_arm.c (renamed from src/pkg/runtime/arm/softfloat.c)4
-rw-r--r--src/pkg/runtime/stack.h9
-rw-r--r--src/pkg/runtime/stack_test.go1528
-rw-r--r--src/pkg/runtime/string.goc58
-rw-r--r--src/pkg/runtime/symtab.c71
-rw-r--r--src/pkg/runtime/sys_darwin_386.s (renamed from src/pkg/runtime/darwin/386/sys.s)113
-rw-r--r--src/pkg/runtime/sys_darwin_amd64.s (renamed from src/pkg/runtime/darwin/amd64/sys.s)116
-rw-r--r--src/pkg/runtime/sys_freebsd_386.s (renamed from src/pkg/runtime/freebsd/386/sys.s)125
-rw-r--r--src/pkg/runtime/sys_freebsd_amd64.s (renamed from src/pkg/runtime/freebsd/amd64/sys.s)110
-rw-r--r--src/pkg/runtime/sys_linux_386.s (renamed from src/pkg/runtime/linux/386/sys.s)151
-rw-r--r--src/pkg/runtime/sys_linux_amd64.s (renamed from src/pkg/runtime/linux/amd64/sys.s)100
-rw-r--r--src/pkg/runtime/sys_linux_arm.s (renamed from src/pkg/runtime/linux/arm/sys.s)136
-rw-r--r--src/pkg/runtime/sys_netbsd_386.s325
-rw-r--r--src/pkg/runtime/sys_netbsd_amd64.s268
-rw-r--r--src/pkg/runtime/sys_openbsd_386.s325
-rw-r--r--src/pkg/runtime/sys_openbsd_amd64.s (renamed from src/pkg/runtime/openbsd/amd64/sys.s)113
-rw-r--r--src/pkg/runtime/sys_plan9_386.s (renamed from src/pkg/runtime/plan9/386/sys.s)27
-rw-r--r--src/pkg/runtime/sys_windows_386.s (renamed from src/pkg/runtime/windows/386/sys.s)212
-rw-r--r--src/pkg/runtime/sys_windows_amd64.s342
-rw-r--r--src/pkg/runtime/syscall_windows.goc145
-rw-r--r--src/pkg/runtime/syscall_windows_test.go243
-rw-r--r--src/pkg/runtime/thread_darwin.c (renamed from src/pkg/runtime/darwin/thread.c)257
-rw-r--r--src/pkg/runtime/thread_freebsd.c217
-rw-r--r--src/pkg/runtime/thread_linux.c (renamed from src/pkg/runtime/linux/thread.c)235
-rw-r--r--src/pkg/runtime/thread_netbsd.c235
-rw-r--r--src/pkg/runtime/thread_openbsd.c235
-rw-r--r--src/pkg/runtime/thread_plan9.c269
-rw-r--r--src/pkg/runtime/thread_windows.c430
-rw-r--r--src/pkg/runtime/time.goc253
-rw-r--r--src/pkg/runtime/traceback_arm.c (renamed from src/pkg/runtime/arm/traceback.c)52
-rw-r--r--src/pkg/runtime/traceback_x86.c (renamed from src/pkg/runtime/amd64/traceback.c)56
-rw-r--r--src/pkg/runtime/type.go218
-rw-r--r--src/pkg/runtime/type.h3
-rw-r--r--src/pkg/runtime/vlop_386.s (renamed from src/pkg/runtime/386/vlop.s)0
-rw-r--r--src/pkg/runtime/vlop_arm.s (renamed from src/pkg/runtime/arm/vlop.s)0
-rw-r--r--src/pkg/runtime/vlrt_386.c (renamed from src/pkg/runtime/386/vlrt.c)0
-rw-r--r--src/pkg/runtime/vlrt_arm.c (renamed from src/pkg/runtime/arm/vlrt.c)0
-rw-r--r--src/pkg/runtime/windows/amd64/defs.h40
-rw-r--r--src/pkg/runtime/windows/amd64/signal.c20
-rw-r--r--src/pkg/runtime/windows/amd64/sys.s130
-rw-r--r--src/pkg/runtime/windows/defs.c37
-rw-r--r--src/pkg/runtime/windows/syscall.goc67
-rw-r--r--src/pkg/runtime/windows/thread.c432
-rw-r--r--src/pkg/scanner/Makefile11
-rw-r--r--src/pkg/smtp/Makefile12
-rw-r--r--src/pkg/sort/Makefile12
-rw-r--r--src/pkg/sort/example_interface_test.go77
-rw-r--r--src/pkg/sort/example_reverse_test.go30
-rw-r--r--src/pkg/sort/example_test.go17
-rw-r--r--src/pkg/sort/export_test.go9
-rw-r--r--src/pkg/sort/sort.go69
-rw-r--r--src/pkg/sort/sort_test.go70
-rw-r--r--src/pkg/strconv/Makefile17
-rw-r--r--src/pkg/strconv/atob.go21
-rw-r--r--src/pkg/strconv/atob_test.go13
-rw-r--r--src/pkg/strconv/atof.go155
-rw-r--r--src/pkg/strconv/atof_test.go204
-rw-r--r--src/pkg/strconv/atoi.go151
-rw-r--r--src/pkg/strconv/atoi_test.go121
-rw-r--r--src/pkg/strconv/decimal.go71
-rw-r--r--src/pkg/strconv/decimal_test.go20
-rw-r--r--src/pkg/strconv/extfloat.go501
-rw-r--r--src/pkg/strconv/fp_test.go22
-rw-r--r--src/pkg/strconv/ftoa.go263
-rw-r--r--src/pkg/strconv/ftoa_test.go126
-rw-r--r--src/pkg/strconv/internal_test.go6
-rw-r--r--src/pkg/strconv/isprint.go521
-rw-r--r--src/pkg/strconv/itoa.go146
-rw-r--r--src/pkg/strconv/itoa_test.go154
-rw-r--r--src/pkg/strconv/makeisprint.go162
-rw-r--r--src/pkg/strconv/quote.go293
-rw-r--r--src/pkg/strconv/quote_test.go56
-rw-r--r--src/pkg/strings/Makefile12
-rw-r--r--src/pkg/strings/example_test.go182
-rw-r--r--src/pkg/strings/export_test.go9
-rw-r--r--src/pkg/strings/reader.go88
-rw-r--r--src/pkg/strings/reader_test.go88
-rw-r--r--src/pkg/strings/replace.go312
-rw-r--r--src/pkg/strings/replace_test.go174
-rw-r--r--src/pkg/strings/strings.go158
-rw-r--r--src/pkg/strings/strings_test.go313
-rw-r--r--src/pkg/sync/Makefile15
-rw-r--r--src/pkg/sync/atomic/Makefile18
-rw-r--r--src/pkg/sync/atomic/asm_386.s55
-rw-r--r--src/pkg/sync/atomic/asm_amd64.s47
-rw-r--r--src/pkg/sync/atomic/asm_arm.s24
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s39
-rw-r--r--src/pkg/sync/atomic/atomic_test.go639
-rw-r--r--src/pkg/sync/atomic/doc.go39
-rw-r--r--src/pkg/sync/cond.go15
-rw-r--r--src/pkg/sync/example_test.go54
-rw-r--r--src/pkg/sync/export_test.go9
-rw-r--r--src/pkg/sync/mutex.go11
-rw-r--r--src/pkg/sync/mutex_test.go6
-rw-r--r--src/pkg/sync/once_test.go2
-rw-r--r--src/pkg/sync/runtime.go18
-rw-r--r--src/pkg/sync/runtime_sema_test.go (renamed from src/pkg/runtime/sema_test.go)15
-rw-r--r--src/pkg/sync/rwmutex.go13
-rw-r--r--src/pkg/sync/rwmutex_test.go2
-rw-r--r--src/pkg/sync/waitgroup.go24
-rw-r--r--src/pkg/syscall/Makefile58
-rw-r--r--src/pkg/syscall/asm_linux_386.s14
-rw-r--r--src/pkg/syscall/asm_netbsd_386.s137
-rw-r--r--src/pkg/syscall/asm_netbsd_amd64.s130
-rw-r--r--src/pkg/syscall/asm_openbsd_386.s137
-rw-r--r--src/pkg/syscall/asm_openbsd_amd64.s130
-rw-r--r--src/pkg/syscall/bpf_bsd.go162
-rw-r--r--src/pkg/syscall/dll_windows.go249
-rw-r--r--src/pkg/syscall/env_plan9.go128
-rw-r--r--src/pkg/syscall/env_unix.go109
-rw-r--r--src/pkg/syscall/env_windows.go77
-rw-r--r--src/pkg/syscall/exec_bsd.go223
-rw-r--r--src/pkg/syscall/exec_linux.go234
-rw-r--r--src/pkg/syscall/exec_plan9.go37
-rw-r--r--src/pkg/syscall/exec_unix.go252
-rw-r--r--src/pkg/syscall/exec_windows.go50
-rw-r--r--src/pkg/syscall/lsf_linux.go26
-rwxr-xr-xsrc/pkg/syscall/mkall.sh98
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh177
-rwxr-xr-xsrc/pkg/syscall/mkerrors_windows.sh6
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl51
-rwxr-xr-xsrc/pkg/syscall/mksyscall_windows.pl58
-rwxr-xr-xsrc/pkg/syscall/mksysctl_openbsd.pl257
-rwxr-xr-xsrc/pkg/syscall/mksysnum_linux.pl2
-rwxr-xr-xsrc/pkg/syscall/mksysnum_netbsd.pl51
-rwxr-xr-xsrc/pkg/syscall/mksysnum_openbsd.pl43
-rw-r--r--src/pkg/syscall/netlink_linux.go49
-rw-r--r--src/pkg/syscall/route_bsd.go99
-rw-r--r--src/pkg/syscall/route_darwin.go2
-rw-r--r--src/pkg/syscall/route_freebsd.go2
-rw-r--r--src/pkg/syscall/route_netbsd.go35
-rw-r--r--src/pkg/syscall/route_openbsd.go35
-rw-r--r--src/pkg/syscall/security_windows.go359
-rw-r--r--src/pkg/syscall/sockcmsg_linux.go4
-rw-r--r--src/pkg/syscall/sockcmsg_unix.go16
-rw-r--r--src/pkg/syscall/syscall.go23
-rw-r--r--src/pkg/syscall/syscall_bsd.go329
-rw-r--r--src/pkg/syscall/syscall_darwin.go191
-rw-r--r--src/pkg/syscall/syscall_darwin_386.go6
-rw-r--r--src/pkg/syscall/syscall_darwin_amd64.go4
-rw-r--r--src/pkg/syscall/syscall_freebsd.go194
-rw-r--r--src/pkg/syscall/syscall_freebsd_386.go2
-rw-r--r--src/pkg/syscall/syscall_linux.go469
-rw-r--r--src/pkg/syscall/syscall_linux_386.go189
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go92
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go129
-rw-r--r--src/pkg/syscall/syscall_netbsd.go434
-rw-r--r--src/pkg/syscall/syscall_netbsd_386.go42
-rw-r--r--src/pkg/syscall/syscall_netbsd_amd64.go42
-rw-r--r--src/pkg/syscall/syscall_openbsd.go281
-rw-r--r--src/pkg/syscall/syscall_openbsd_386.go42
-rw-r--r--src/pkg/syscall/syscall_openbsd_amd64.go42
-rw-r--r--src/pkg/syscall/syscall_plan9.go106
-rw-r--r--src/pkg/syscall/syscall_unix.go81
-rw-r--r--src/pkg/syscall/syscall_windows.go563
-rw-r--r--src/pkg/syscall/types_darwin.c180
-rw-r--r--src/pkg/syscall/types_darwin.go228
-rw-r--r--src/pkg/syscall/types_freebsd.c190
-rw-r--r--src/pkg/syscall/types_freebsd.go240
-rw-r--r--src/pkg/syscall/types_linux.c266
-rw-r--r--src/pkg/syscall/types_linux.go452
-rw-r--r--src/pkg/syscall/types_netbsd.go229
-rw-r--r--src/pkg/syscall/types_openbsd.go229
-rw-r--r--src/pkg/syscall/types_plan9.c2
-rw-r--r--src/pkg/syscall/zerrors_darwin_386.go2289
-rw-r--r--src/pkg/syscall/zerrors_darwin_amd64.go2289
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go393
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go393
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go651
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go653
-rw-r--r--src/pkg/syscall/zerrors_linux_arm.go639
-rw-r--r--src/pkg/syscall/zerrors_netbsd_386.go1368
-rw-r--r--src/pkg/syscall/zerrors_netbsd_amd64.go1368
-rw-r--r--src/pkg/syscall/zerrors_openbsd_386.go1441
-rw-r--r--src/pkg/syscall/zerrors_openbsd_amd64.go1441
-rw-r--r--src/pkg/syscall/zerrors_plan9_386.go21
-rw-r--r--src/pkg/syscall/zerrors_windows.go8
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go594
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go594
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go582
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go582
-rw-r--r--src/pkg/syscall/zsyscall_linux_386.go710
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go806
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go830
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_386.go1086
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_amd64.go1086
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_386.go1133
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_amd64.go1133
-rw-r--r--src/pkg/syscall/zsyscall_plan9_386.go96
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go1275
-rw-r--r--src/pkg/syscall/zsyscall_windows_amd64.go1275
-rw-r--r--src/pkg/syscall/zsysctl_openbsd.go292
-rw-r--r--src/pkg/syscall/zsysnum_darwin_386.go701
-rw-r--r--src/pkg/syscall/zsysnum_darwin_amd64.go701
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go27
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go27
-rw-r--r--src/pkg/syscall/zsysnum_linux_386.go4
-rw-r--r--src/pkg/syscall/zsysnum_linux_amd64.go4
-rw-r--r--src/pkg/syscall/zsysnum_linux_arm.go680
-rw-r--r--src/pkg/syscall/zsysnum_netbsd_386.go274
-rw-r--r--src/pkg/syscall/zsysnum_netbsd_amd64.go274
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_386.go207
-rw-r--r--src/pkg/syscall/zsysnum_openbsd_amd64.go207
-rw-r--r--src/pkg/syscall/ztypes_darwin_386.go216
-rw-r--r--src/pkg/syscall/ztypes_darwin_amd64.go252
-rw-r--r--src/pkg/syscall/ztypes_freebsd_386.go231
-rw-r--r--src/pkg/syscall/ztypes_freebsd_amd64.go268
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go476
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go508
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go507
-rw-r--r--src/pkg/syscall/ztypes_netbsd_386.go406
-rw-r--r--src/pkg/syscall/ztypes_netbsd_amd64.go412
-rw-r--r--src/pkg/syscall/ztypes_openbsd_386.go405
-rw-r--r--src/pkg/syscall/ztypes_openbsd_amd64.go412
-rw-r--r--src/pkg/syscall/ztypes_windows.go364
-rw-r--r--src/pkg/syslog/Makefile12
-rw-r--r--src/pkg/tabwriter/Makefile11
-rw-r--r--src/pkg/template/Makefile15
-rw-r--r--src/pkg/template/helper.go238
-rw-r--r--src/pkg/template/parse.go85
-rw-r--r--src/pkg/template/parse/Makefile14
-rw-r--r--src/pkg/template/parse/set.go50
-rw-r--r--src/pkg/template/set.go108
-rw-r--r--src/pkg/template/set_test.go239
-rw-r--r--src/pkg/template/testdata/tmpl1.tmpl1
-rw-r--r--src/pkg/template/testdata/tmpl2.tmpl1
-rw-r--r--src/pkg/testing/Makefile12
-rw-r--r--src/pkg/testing/benchmark.go127
-rw-r--r--src/pkg/testing/example.go82
-rw-r--r--src/pkg/testing/iotest/Makefile13
-rw-r--r--src/pkg/testing/iotest/logger.go5
-rw-r--r--src/pkg/testing/iotest/reader.go14
-rw-r--r--src/pkg/testing/iotest/writer.go7
-rw-r--r--src/pkg/testing/quick/Makefile11
-rw-r--r--src/pkg/testing/quick/quick.go28
-rw-r--r--src/pkg/testing/quick/quick_test.go5
-rw-r--r--src/pkg/testing/script/Makefile11
-rw-r--r--src/pkg/testing/script/script.go359
-rw-r--r--src/pkg/testing/script/script_test.go75
-rw-r--r--src/pkg/testing/testing.go324
-rw-r--r--src/pkg/text/scanner/scanner.go (renamed from src/pkg/scanner/scanner.go)79
-rw-r--r--src/pkg/text/scanner/scanner_test.go (renamed from src/pkg/scanner/scanner_test.go)35
-rw-r--r--src/pkg/text/tabwriter/example_test.go38
-rw-r--r--src/pkg/text/tabwriter/tabwriter.go (renamed from src/pkg/tabwriter/tabwriter.go)25
-rw-r--r--src/pkg/text/tabwriter/tabwriter_test.go (renamed from src/pkg/tabwriter/tabwriter_test.go)6
-rw-r--r--src/pkg/text/template/doc.go (renamed from src/pkg/template/doc.go)123
-rw-r--r--src/pkg/text/template/example_test.go71
-rw-r--r--src/pkg/text/template/examplefiles_test.go182
-rw-r--r--src/pkg/text/template/examplefunc_test.go54
-rw-r--r--src/pkg/text/template/exec.go (renamed from src/pkg/template/exec.go)128
-rw-r--r--src/pkg/text/template/exec_test.go (renamed from src/pkg/template/exec_test.go)199
-rw-r--r--src/pkg/text/template/funcs.go (renamed from src/pkg/template/funcs.go)92
-rw-r--r--src/pkg/text/template/helper.go108
-rw-r--r--src/pkg/text/template/multi_test.go280
-rw-r--r--src/pkg/text/template/parse/lex.go (renamed from src/pkg/template/parse/lex.go)97
-rw-r--r--src/pkg/text/template/parse/lex_test.go (renamed from src/pkg/template/parse/lex_test.go)40
-rw-r--r--src/pkg/text/template/parse/node.go (renamed from src/pkg/template/parse/node.go)254
-rw-r--r--src/pkg/text/template/parse/parse.go (renamed from src/pkg/template/parse/parse.go)160
-rw-r--r--src/pkg/text/template/parse/parse_test.go (renamed from src/pkg/template/parse/parse_test.go)123
-rw-r--r--src/pkg/text/template/template.go214
-rw-r--r--src/pkg/text/template/testdata/file1.tmpl (renamed from src/pkg/template/testdata/file1.tmpl)0
-rw-r--r--src/pkg/text/template/testdata/file2.tmpl (renamed from src/pkg/template/testdata/file2.tmpl)0
-rw-r--r--src/pkg/text/template/testdata/tmpl1.tmpl3
-rw-r--r--src/pkg/text/template/testdata/tmpl2.tmpl3
-rw-r--r--src/pkg/time/Makefile46
-rw-r--r--src/pkg/time/example_test.go58
-rw-r--r--src/pkg/time/format.go712
-rw-r--r--src/pkg/time/internal_test.go13
-rw-r--r--src/pkg/time/sleep.go212
-rw-r--r--src/pkg/time/sleep_test.go130
-rw-r--r--src/pkg/time/sys.go51
-rw-r--r--src/pkg/time/sys_plan9.go66
-rw-r--r--src/pkg/time/sys_posix.go18
-rw-r--r--src/pkg/time/sys_unix.go76
-rw-r--r--src/pkg/time/sys_windows.go73
-rw-r--r--src/pkg/time/tick.go188
-rw-r--r--src/pkg/time/tick_test.go24
-rw-r--r--src/pkg/time/time.go1069
-rw-r--r--src/pkg/time/time_test.go695
-rw-r--r--src/pkg/time/zoneinfo.go204
-rw-r--r--src/pkg/time/zoneinfo_plan9.go145
-rw-r--r--src/pkg/time/zoneinfo_posix.go62
-rw-r--r--src/pkg/time/zoneinfo_read.go341
-rw-r--r--src/pkg/time/zoneinfo_unix.go227
-rw-r--r--src/pkg/time/zoneinfo_windows.go275
-rw-r--r--src/pkg/try/Makefile11
-rw-r--r--src/pkg/try/try.go174
-rw-r--r--src/pkg/try/try_test.go60
-rw-r--r--src/pkg/unicode/Makefile24
-rw-r--r--src/pkg/unicode/casetables.go4
-rw-r--r--src/pkg/unicode/digit.go8
-rw-r--r--src/pkg/unicode/digit_test.go6
-rw-r--r--src/pkg/unicode/graphic.go77
-rw-r--r--src/pkg/unicode/graphic_test.go20
-rw-r--r--src/pkg/unicode/letter.go170
-rw-r--r--src/pkg/unicode/letter_test.go29
-rw-r--r--src/pkg/unicode/maketables.go197
-rw-r--r--src/pkg/unicode/script_test.go8
-rw-r--r--src/pkg/unicode/tables.go5863
-rw-r--r--src/pkg/unicode/utf16/export_test.go11
-rw-r--r--src/pkg/unicode/utf16/utf16.go (renamed from src/pkg/utf16/utf16.go)45
-rw-r--r--src/pkg/unicode/utf16/utf16_test.go (renamed from src/pkg/utf16/utf16_test.go)63
-rw-r--r--src/pkg/unicode/utf8/utf8.go (renamed from src/pkg/utf8/utf8.go)155
-rw-r--r--src/pkg/unicode/utf8/utf8_test.go (renamed from src/pkg/utf8/utf8_test.go)140
-rw-r--r--src/pkg/unsafe/unsafe.go34
-rw-r--r--src/pkg/url/Makefile11
-rw-r--r--src/pkg/utf16/Makefile11
-rw-r--r--src/pkg/utf8/Makefile12
-rw-r--r--src/pkg/utf8/string.go211
-rw-r--r--src/pkg/utf8/string_test.go114
-rw-r--r--src/pkg/websocket/Makefile9
-rw-r--r--src/pkg/websocket/client.go323
-rw-r--r--src/pkg/websocket/server.go219
-rw-r--r--src/pkg/websocket/websocket.go192
-rw-r--r--src/pkg/websocket/websocket_test.go271
-rw-r--r--src/pkg/xml/Makefile14
-rw-r--r--src/pkg/xml/atom_test.go50
-rw-r--r--src/pkg/xml/embed_test.go124
-rw-r--r--src/pkg/xml/marshal.go228
-rw-r--r--src/pkg/xml/marshal_test.go305
-rw-r--r--src/pkg/xml/read.go631
-rwxr-xr-xsrc/quietgcc.bash44
-rwxr-xr-xsrc/run.bash103
-rw-r--r--src/run.bat76
-rwxr-xr-xsrc/sudo.bash17
-rwxr-xr-xsrc/version.bash50
2225 files changed, 189828 insertions, 128717 deletions
diff --git a/src/Make.ccmd b/src/Make.ccmd
deleted file mode 100644
index 40cc3a0e8..000000000
--- a/src/Make.ccmd
+++ /dev/null
@@ -1,48 +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.
-
-# Makefile for commands written in C.
-
-ifeq (windows,$(findstring windows, $(shell uname | tr A-Z a-z | sed 's/mingw/windows/')))
-TARG:=$(TARG).exe
-endif
-
-$(TARG): $(OFILES) $(LIB)
- $(HOST_LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lmach -lbio -l9 -lm $(HOST_LDFLAGS)
-
-$(OFILES): $(HFILES)
-
-CLEANFILES+=y.tab.[ch]
-
-clean:
- rm -f *.$(HOST_O) $(TARG) $(CLEANFILES)
-
-nuke: clean
- rm -f "$(GOBIN)/$(TARG)"
-
-ifneq ($(NOINSTALL),1)
-install: $(QUOTED_GOBIN)/$(TARG)
-endif
-
-$(QUOTED_GOBIN)/$(TARG): $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-y.tab.h: $(YFILES)
- bison -y $(HOST_YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-all: $(TARG)
-
-# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
-%.$(HOST_O): %.c
- $(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
-
-# These are used by enough different Makefiles to be
-# worth writing down in one place, even if they don't
-# apply to every command that builds with Make.ccmd
-../%l/enam.o:
- cd ../$*l; $(MAKE) enam.o
-
diff --git a/src/Make.clib b/src/Make.clib
deleted file mode 100644
index 4a7ea02d9..000000000
--- a/src/Make.clib
+++ /dev/null
@@ -1,37 +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.
-
-# Makefile included for C libraries
-
-all: $(LIB)
-
-# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
-%.$(HOST_O): %.c
- $(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
-
-$(OFILES): $(HFILES)
-
-ifneq ($(NOINSTALL),1)
-install: $(QUOTED_GOROOT)/lib/$(LIB)
-endif
-
-$(QUOTED_GOROOT)/lib/$(LIB): $(LIB)
- cp $(LIB) "$(GOROOT)/lib/$(LIB)"
-
-$(LIB): $(OFILES)
- $(HOST_AR) rsc $(LIB) $(OFILES)
-
-CLEANFILES+=y.tab.[ch] y.output a.out $(LIB)
-
-clean:
- rm -f *.$(HOST_O) $(CLEANFILES)
-
-nuke: clean
- rm -f "$(GOROOT)/lib/$(LIB)"
-
-y.tab.h: $(YFILES)
- LANG=C LANGUAGE="en_US.UTF8" bison -v -y $(HOST_YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
diff --git a/src/Make.cmd b/src/Make.cmd
deleted file mode 100644
index 27c6a2e13..000000000
--- a/src/Make.cmd
+++ /dev/null
@@ -1,50 +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.
-
-ifeq ($(GOOS),windows)
-TARG:=$(TARG).exe
-endif
-
-ifeq ($(TARGDIR),)
-TARGDIR:=$(QUOTED_GOBIN)
-endif
-
-all: $(TARG)
-
-include $(QUOTED_GOROOT)/src/Make.common
-
-PREREQ+=$(patsubst %,%.make,$(DEPS))
-
-$(TARG): _go_.$O
- $(LD) $(LDIMPORTS) -o $@ _go_.$O
-
-_go_.$O: $(GOFILES) $(PREREQ)
- $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
-
-install: $(TARGDIR)/$(TARG)
-
-$(TARGDIR)/$(TARG): $(TARG)
- mkdir -p $(TARGDIR) && cp -f $(TARG) $(TARGDIR)
-
-CLEANFILES+=$(TARG) _test _testmain.go test.out build.out
-
-nuke: clean
- rm -f $(TARGDIR)/$(TARG)
-
-# for gotest
-testpackage: _test/main.a
-
-testpackage-clean:
- rm -f _test/main.a _gotest_.$O
-
-_test/main.a: _gotest_.$O
- @mkdir -p _test
- rm -f $@
- gopack grc $@ _gotest_.$O
-
-_gotest_.$O: $(GOFILES) $(GOTESTFILES)
- $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
-
-importpath:
- echo main
diff --git a/src/Make.common b/src/Make.common
deleted file mode 100644
index 0b27d07f9..000000000
--- a/src/Make.common
+++ /dev/null
@@ -1,22 +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.
-
-clean:
- rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES)
-
-install.clean: install
- rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
-
-test.clean: test
- rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
-
-testshort.clean: testshort
- rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES) || true
-
-%.make:
- $(MAKE) -C $* install
-
-.PHONY: all clean nuke install coverage test bench testpackage-clean\
- importpath dir
-
diff --git a/src/Make.dist b/src/Make.dist
new file mode 100644
index 000000000..cae892de9
--- /dev/null
+++ b/src/Make.dist
@@ -0,0 +1,19 @@
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Run go tool dist to install a command.
+# The -v causes dist to print the name of each directory as it runs.
+# The -vv causes dist to print each build command as it runs.
+# go tool dist clean cleans all directories, not just this one,
+# but it's as close as we can get.
+
+# Default target (first).
+install:
+ go tool dist install -v
+
+verbose:
+ go tool dist install -vv
+
+clean:
+ go tool dist clean
diff --git a/src/Make.inc b/src/Make.inc
deleted file mode 100644
index 8f549f624..000000000
--- a/src/Make.inc
+++ /dev/null
@@ -1,169 +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.
-
-# Makefile included by all other Go makefiles.
-
-# Clear variables that must come from Makefiles,
-# not the environment.
-LIB:=
-TARG:=
-GOFILES:=
-HFILES:=
-OFILES:=
-YFILES:=
-
-# GOROOT must be set.
-ifeq ($(GOROOT),)
-$(error $$GOROOT is not set; use gomake or set $$GOROOT in your environment)
-endif
-
-# Set up GOROOT_FINAL, GOARCH, GOOS if needed.
-GOROOT_FINAL?=$(GOROOT)
-
-ifeq ($(GOHOSTOS),)
-GOHOSTOS:=$(shell uname | tr A-Z a-z | sed 's/mingw/windows/; s/.*windows.*/windows/')
-endif
-
-ifeq ($(GOOS),)
-GOOS:=$(GOHOSTOS)
-endif
-
-GOOS_LIST=\
- darwin\
- freebsd\
- linux\
- plan9\
- windows\
-
-GOARCH_LIST=\
- 386\
- amd64\
- arm\
-
-ifeq ($(filter $(GOOS),$(GOOS_LIST)),)
-$(error Invalid $$GOOS '$(GOOS)'; must be one of: $(GOOS_LIST))
-endif
-
-ifeq ($(GOHOSTARCH),)
-ifeq ($(GOHOSTOS),darwin)
-# Even on 64-bit platform, darwin uname -m prints i386.
-# Check for amd64 with sysctl instead.
-GOHOSTARCH:=${shell if sysctl machdep.cpu.extfeatures | grep EM64T >/dev/null; then echo amd64; else uname -m | sed 's/i386/386/'; fi}
-else
-# Ask uname -m for the processor.
-GOHOSTARCH:=${shell uname -m | sed 's/^..86$$/386/; s/^.86$$/386/; s/x86_64/amd64/; s/arm.*/arm/'}
-endif
-endif
-
-ifeq ($(GOARCH),)
-GOARCH:=$(GOHOSTARCH)
-endif
-
-# darwin requires GOHOSTARCH match GOARCH
-ifeq ($(GOOS),darwin)
-GOHOSTARCH:=$(GOARCH)
-endif
-
-ifeq ($(filter $(GOARCH),$(GOARCH_LIST)),)
-$(error Invalid $$GOARCH '$(GOARCH)'; must be one of: $(GOARCH_LIST))
-endif
-
-ifeq ($(GOARCH),386)
-O:=8
-else ifeq ($(GOARCH),amd64)
-O:=6
-else ifeq ($(GOARCH),arm)
-O:=5
-ifneq ($(GOOS),linux)
-$(error Invalid $$GOOS '$(GOOS)' for GOARCH=arm; must be linux)
-endif
-else
-$(error Missing $$O for '$(GOARCH)')
-endif
-
-# Save for recursive make to avoid recomputing.
-export GOARCH GOOS GOHOSTARCH GOHOSTOS GOARCH_LIST GOOS_LIST
-
-# ugly hack to deal with whitespaces in $GOROOT
-nullstring :=
-space := $(nullstring) # a space at the end
-QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
-
-# default GOBIN
-ifndef GOBIN
-GOBIN=$(QUOTED_GOROOT)/bin
-endif
-QUOTED_GOBIN=$(subst $(space),\ ,$(GOBIN))
-
-AS=${O}a
-CC=${O}c
-GC=${O}g
-LD=${O}l
-OS=568vq
-CFLAGS=-FVw
-
-HOST_CC=quietgcc
-HOST_LD=quietgcc
-HOST_O=o
-HOST_YFLAGS=-d
-HOST_AR?=ar
-
-# These two variables can be overridden in the environment
-# to build with other flags. They are like $CFLAGS and $LDFLAGS
-# in a more typical GNU build. We are more explicit about the names
-# here because there are different compilers being run during the
-# build (both gcc and 6c, for example).
-HOST_EXTRA_CFLAGS?=-ggdb -O2
-HOST_EXTRA_LDFLAGS?=
-
-HOST_CFLAGS=-I"$(GOROOT)/include" $(HOST_EXTRA_CFLAGS)
-HOST_LDFLAGS=$(HOST_EXTRA_LDFLAGS)
-PWD=$(shell pwd)
-
-# Decide whether use of cgo is okay.
-ifeq ($(CGO_ENABLED),)
-# Default on...
-CGO_ENABLED:=1
-ifeq ($(GOARCH),arm) # ... but not on ARM
-CGO_ENABLED:=0
-endif
-ifeq ($(GOOS),plan9) # ... and not on Plan 9
-CGO_ENABLED:=0
-endif
-ifeq ($(GOOS),openbsd) # ... and not on OpenBSD
-CGO_ENABLED:=0
-endif
-endif
-
-# Make environment more standard.
-LANG:=
-LC_ALL:=C
-LC_CTYPE:=C
-GREP_OPTIONS:=
-GREP_COLORS:=
-export LANG LC_ALL LC_CTYPE GREP_OPTIONS GREP_COLORS
-
-go-env:
- @echo export GOARCH="$(GOARCH)"
- @echo export GOOS="$(GOOS)"
- @echo export GOHOSTARCH="$(GOHOSTARCH)"
- @echo export GOHOSTOS="$(GOHOSTOS)"
- @echo export CGO_ENABLED="$(CGO_ENABLED)"
- @echo export O="$O"
- @echo export AS="$(AS)"
- @echo export CC="$(CC)"
- @echo export GC="$(GC)"
- @echo export LD="$(LD)"
- @echo export OS="$(OS)"
- @echo export CFLAGS="$(CFLAGS)"
- @echo export LANG="$(LANG)"
- @echo export LC_ALL="$(LC_ALL)"
- @echo export LC_CTYPE="$(LC_CTYPE)"
- @echo export GREP_OPTIONS="$(GREP_OPTIONS)"
- @echo export GREP_COLORS="$(GREP_COLORS)"
- @echo MAKE_GO_ENV_WORKED=1
-
-# Don't let the targets in this file be used
-# as the default make target.
-.DEFAULT_GOAL:=
diff --git a/src/Make.pkg b/src/Make.pkg
deleted file mode 100644
index fc80cf6e6..000000000
--- a/src/Make.pkg
+++ /dev/null
@@ -1,249 +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.
-
-all: package
-package: _obj/$(TARG).a
-testpackage: _test/$(TARG).a
-
-include $(QUOTED_GOROOT)/src/Make.common
-
-# The quietgcc wrapper is for our own source code
-# while building the libraries, not arbitrary source code
-# as encountered by cgo.
-ifeq ($(HOST_CC),quietgcc)
-HOST_CC:=gcc
-endif
-ifeq ($(HOST_LD),quietgcc)
-HOST_LD:=gcc
-endif
-
-# GNU Make 3.80 has a bug in lastword
-# elem=$(lastword $(subst /, ,$(TARG)))
-TARG_words=$(subst /, ,$(TARG))
-elem=$(word $(words $(TARG_words)),$(TARG_words))
-
-ifeq ($(elem),$(TARG))
-dir=
-else
-dir=$(patsubst %/$(elem),%,$(TARG))
-endif
-
-pkgdir=$(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)
-
-ifeq ($(TARGDIR),)
-TARGDIR:=$(pkgdir)
-endif
-
-INSTALLFILES+=$(TARGDIR)/$(TARG).a
-
-# The rest of the cgo rules are below, but these variable updates
-# must be done here so they apply to the main rules.
-ifdef CGOFILES
-GOFILES+=$(patsubst %.go,_obj/%.cgo1.go,$(CGOFILES)) _obj/_cgo_gotypes.go
-CGO_OFILES+=$(patsubst %.go,%.cgo2.o,$(CGOFILES)) _cgo_export.o
-OFILES+=_cgo_defun.$O _cgo_import.$O $(CGO_OFILES)
-endif
-
-ifdef SWIGFILES
-GOFILES+=$(patsubst %.swig,_obj/%.go,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
-OFILES+=$(patsubst %.swig,_obj/%_gc.$O,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
-SWIG_PREFIX=$(subst /,-,$(TARG))
-SWIG_SOS+=$(patsubst %.swig,_obj/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
-INSTALLFILES+=$(patsubst %.swig,$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so,$(patsubst %.swigcxx,%.swig,$(SWIGFILES)))
-endif
-
-PREREQ+=$(patsubst %,%.make,$(DEPS))
-
-coverage:
- gotest
- 6cov -g $(shell pwd) $O.out | grep -v '_test\.go:'
-
-CLEANFILES+=*.so _obj _test _testmain.go *.exe _cgo* test.out build.out
-
-test:
- gotest
-
-testshort:
- gotest -test.short -test.timeout=120
-
-bench:
- gotest -test.bench=. -test.run="Do not run tests"
-
-nuke: clean
- rm -f $(TARGDIR)/$(TARG).a
-
-testpackage-clean:
- rm -f _test/$(TARG).a
-
-install: $(INSTALLFILES)
-
-$(TARGDIR)/$(TARG).a: _obj/$(TARG).a
- @mkdir -p $(TARGDIR)/$(dir)
- cp _obj/$(TARG).a "$@"
-
-_go_.$O: $(GOFILES) $(PREREQ)
- $(GC) $(GCIMPORTS) -o $@ $(GOFILES)
-
-_gotest_.$O: $(GOFILES) $(GOTESTFILES) $(PREREQ)
- $(GC) $(GCIMPORTS) -o $@ $(GOFILES) $(GOTESTFILES)
-
-_obj/$(TARG).a: _go_.$O $(OFILES)
- @mkdir -p _obj/$(dir)
- rm -f _obj/$(TARG).a
- gopack grc $@ _go_.$O $(OFILES)
-
-_test/$(TARG).a: _gotest_.$O $(OFILES)
- @mkdir -p _test/$(dir)
- rm -f _test/$(TARG).a
- gopack grc $@ _gotest_.$O $(OFILES)
-
-importpath:
- @echo $(TARG)
-
-dir:
- @echo $(dir)
-
-# To use cgo in a Go package, add a line
-#
-# CGOFILES=x.go y.go
-#
-# to the main Makefile. This signals that cgo should process x.go
-# and y.go when building the package.
-# There are three optional variables to set, CGO_CFLAGS, CGO_LDFLAGS,
-# and CGO_DEPS, which specify compiler flags, linker flags, and linker
-# dependencies to use when compiling (using gcc) the C support for
-# x.go and y.go.
-
-# Cgo translates each x.go file listed in $(CGOFILES) into a basic
-# translation of x.go, called _obj/x.cgo1.go. Additionally, three other
-# files are created:
-#
-# _obj/_cgo_gotypes.go - declarations needed for all .go files in the package; imports "unsafe"
-# _obj/_cgo_defun.c - C trampoline code to be compiled with 6c and linked into the package
-# _obj/x.cgo2.c - C implementations compiled with gcc to create a dynamic library
-#
-
-ifdef CGOFILES
-_obj/_cgo_run: $(CGOFILES)
- @mkdir -p _obj
- CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES)
- touch _obj/_cgo_run
-
-# _CGO_CFLAGS and _CGO_LDFLAGS are defined via the evaluation of _cgo_flags.
-# The include happens before the commands in the recipe run,
-# so it cannot be done in the same recipe that runs cgo.
-_obj/_load_cgo_flags: _obj/_cgo_run
- $(eval include _obj/_cgo_flags)
-
-# Include any previous flags in case cgo files are up to date.
--include _obj/_cgo_flags
-
-# Ugly but necessary - cgo writes these files too.
-_obj/_cgo_gotypes.go _obj/_cgo_export.c _obj/_cgo_export.h _obj/_cgo_main.c _obj/_cgo_defun.c: _obj/_load_cgo_flags
- @true
-
-_obj/%.cgo1.go _obj/%.cgo2.c: _obj/_cgo_defun.c
- @true
-endif
-
-# Compile rules for gcc source files.
-%.o: %.c
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) $*.c
-
-%.o: _obj/%.c
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) $^
-
-# To find out which symbols are needed from external libraries
-# and which libraries are needed, we build a simple a.out that
-# links all the objects we just created and then use cgo -dynimport
-# to inspect it. That is, we make gcc tell us which dynamic symbols
-# and libraries are involved, instead of duplicating gcc's logic ourselves.
-# After main we have to define all the symbols that will be provided
-# by Go code. That's crosscall2 and any exported symbols.
-
-_cgo1_.o: _cgo_main.o $(CGO_OFILES)
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) $(_CGO_LDFLAGS)
-
-_obj/_cgo_import.c: _cgo1_.o
- @mkdir -p _obj
- cgo -dynimport _cgo1_.o >$@_ && mv -f $@_ $@
-
-# The rules above added x.cgo1.go and _cgo_gotypes.go to $(GOFILES),
-# added _cgo_defun.$O to $OFILES, and added the installed copy of
-# package_x.so (built from x.cgo2.c) to $(INSTALLFILES).
-
-# Have to run gcc with the right size argument on hybrid 32/64 machines.
-_CGO_CFLAGS_386=-m32
-_CGO_CFLAGS_amd64=-m64
-_CGO_LDFLAGS_freebsd=-shared -lpthread -lm
-_CGO_LDFLAGS_linux=-shared -lpthread -lm
-_CGO_LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup
-_CGO_LDFLAGS_windows=-shared -lm -mthreads
-
-# Have to compile the runtime header.
-RUNTIME_CFLAGS=-I$(pkgdir)
-
-# Compile _cgo_defun.c with 6c; needs access to the runtime headers.
-_cgo_defun.$O: _obj/_cgo_defun.c
- $(CC) $(CFLAGS) $(RUNTIME_CFLAGS) -I . -o "$@" _obj/_cgo_defun.c
-
-# To use swig in a Go package, add a line
-#
-# SWIGFILES=x.swig
-#
-# to the main Makefile. This signals that SWIG should process the
-#.swig file when building the package.
-#
-# To wrap C code, use an extension of .swig. To wrap C++ code, use an
-# extension of .swigcxx.
-#
-# SWIGFILES=myclib.swig mycxxlib.swigcxx
-
-ifdef SWIGFILES
-_obj/%._swig_run _obj/%.go _obj/%_gc.c _obj/%_wrap.c: %.swig
- @mkdir -p _obj
- swig -go -module $* -soname $(SWIG_PREFIX)-$*.so -o _obj/$*_wrap.c -outdir _obj $<
-
-_obj/%._swig_run _obj/%.go _obj/%_gc.c _obj/%_wrap.cxx: %.swigcxx
- @mkdir -p _obj
- swig -go -c++ -module $* -soname $(SWIG_PREFIX)-$*.so -o _obj/$*_wrap.cxx -outdir _obj $<
-
-_obj/%_gc.$O: _obj/%_gc.c
- $(CC) $(CFLAGS) -I . -I$(pkgdir) -o "$@" _obj/$*_gc.c
-
-_obj/%_wrap.o: _obj/%_wrap.c
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $^ $(SWIG_CFLAGS)
-
-HOST_CXX=g++
-
-_obj/%_wrapcxx.o: _obj/%_wrap.cxx
- $(HOST_CXX) $(_CGO_CFLAGS_$(GOARCH)) -I . -g -fPIC -O2 -o $@ -c $^ $(SWIG_CXXFLAGS)
-
-_obj/$(SWIG_PREFIX)-%.so: _obj/%_wrap.o
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -o $@ $^ $(SWIG_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) $(_SWIG_LDFLAGS_$(GOOS))
-
-_obj/$(SWIG_PREFIX)-%.so: _obj/%_wrapcxx.o
- $(HOST_CXX) $(_CGO_CFLAGS_$(GOARCH)) -o $@ $^ $(SWIG_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS)) $(_SWIG_LDFLAGS_$(GOOS))
-
-$(TARGDIR)/swig/$(SWIG_PREFIX)-%.so: _obj/$(SWIG_PREFIX)-%.so
- @mkdir -p $(TARGDIR)/swig
- cp $< "$@"
-
-all: $(SWIG_SOS)
-
-SWIG_RPATH=-r $(TARGDIR)/swig
-
-endif
-
-# Generic build rules.
-# These come last so that the rules above can override them
-# for more specific file names.
-%.$O: %.c $(HFILES)
- $(CC) $(CFLAGS) -o "$@" $*.c
-
-%.$O: _obj/%.c $(HFILES)
- $(CC) $(CFLAGS) -I . -o "$@" _obj/$*.c
-
-%.$O: %.s
- $(AS) $*.s
diff --git a/src/all-qemu.bash b/src/all-qemu.bash
deleted file mode 100755
index 6a659d6d4..000000000
--- a/src/all-qemu.bash
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2011 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Run all.bash but exclude tests that depend on functionality
-# missing in QEMU's system call emulation.
-
-export GOARCH=arm
-export NOTEST=""
-NOTEST="$NOTEST big" # just slow
-NOTEST="$NOTEST go/build" # wants to run cgo
-NOTEST="$NOTEST http http/cgi net rpc syslog websocket" # no localhost network
-NOTEST="$NOTEST os" # 64-bit seek fails
-
-./all.bash
diff --git a/src/all.bash b/src/all.bash
index 00110d2da..932b65dc0 100755
--- a/src/all.bash
+++ b/src/all.bash
@@ -8,7 +8,6 @@ if [ ! -f make.bash ]; then
echo 'all.bash must be run from $GOROOT/src' 1>&2
exit 1
fi
-. ./make.bash
-bash run.bash --no-env --no-rebuild
-installed # function defined by make.bash
-
+. ./make.bash --no-banner
+bash run.bash --no-rebuild --banner
+$GOTOOLDIR/dist banner # print build info
diff --git a/src/all.bat b/src/all.bat
new file mode 100644
index 000000000..e3b61c012
--- /dev/null
+++ b/src/all.bat
@@ -0,0 +1,21 @@
+:: Copyright 2012 The Go Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style
+:: license that can be found in the LICENSE file.
+@echo off
+
+setlocal
+
+if exist make.bat goto ok
+echo all.bat must be run from go\src
+:: cannot exit: would kill parent command interpreter
+goto end
+:ok
+
+call make.bat --no-banner --no-local
+if %GOBUILDFAIL%==1 goto end
+call run.bat --no-rebuild --no-local
+if %GOBUILDFAIL%==1 goto end
+go tool dist banner
+
+:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/clean.bash b/src/clean.bash
index 1955b583b..f36260240 100755
--- a/src/clean.bash
+++ b/src/clean.bash
@@ -5,25 +5,12 @@
set -e
-if [ ! -f env.bash ]; then
- echo 'clean.bash must be run from $GOROOT/src' 1>&2
+eval $(go tool dist env)
+
+if [ ! -x $GOTOOLDIR/dist ]; then
+ echo 'cannot find $GOTOOLDIR/dist; nothing to clean' >&2
exit 1
fi
-. ./env.bash
-if [ ! -f Make.inc ] ; then
- GOROOT_FINAL=${GOROOT_FINAL:-$GOROOT}
- sed 's!@@GOROOT@@!'"$GOROOT_FINAL"'!' Make.inc.in >Make.inc
-fi
-if [ "$1" != "--nopkg" ]; then
- rm -rf "$GOROOT"/pkg/${GOOS}_$GOARCH
-fi
-rm -f "$GOROOT"/lib/*.a
-for i in lib9 libbio libmach cmd pkg \
- ../misc/cgo/gmp ../misc/cgo/stdio \
- ../misc/cgo/life ../misc/cgo/test \
- ../test/bench ../test/garbage
-do
- # Do not use gomake here. It may not be available.
- $MAKE -C "$GOROOT/src/$i" clean
-done
+"$GOBIN/go" clean -i std
+$GOTOOLDIR/dist clean
diff --git a/src/clean.bat b/src/clean.bat
new file mode 100644
index 000000000..dcf54ea3a
--- /dev/null
+++ b/src/clean.bat
@@ -0,0 +1,30 @@
+:: Copyright 2012 The Go Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style
+:: license that can be found in the LICENSE file.
+@echo off
+
+setlocal
+
+set GOBUILDFAIL=0
+
+go tool dist env -wp >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
+if exist %GOTOOLDIR%\dist.exe goto distok
+echo cannot find %GOTOOLDIR%\dist; nothing to clean
+goto fail
+:distok
+
+"%GOBIN%\go" clean -i std
+%GOTOOLDIR%\dist clean
+
+goto end
+
+:fail
+set GOBUILDFAIL=1
+
+:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
index f4463c97b..27290ddd7 100644
--- a/src/cmd/5a/Makefile
+++ b/src/cmd/5a/Makefile
@@ -1,25 +1,10 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
+include ../../Make.dist
-TARG=5a
+install: y.tab.h
-HFILES=\
- a.h\
- y.tab.h\
- ../5l/5.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../5l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
+y.tab.h: a.y
+ LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index 9a0efd5e0..512fb5a95 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -217,7 +217,7 @@ inst:
*/
| LTYPEB name ',' imm
{
- outcode($1, Always, &$2, NREG, &$4);
+ outcode($1, Always, &$2, 0, &$4);
}
| LTYPEB name ',' con ',' imm
{
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index ad7ed05dd..4bef0219a 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -44,7 +44,11 @@ enum
int
systemtype(int sys)
{
+#ifdef _WIN32
+ return sys&Windows;
+#else
return sys&Plan9;
+#endif
}
void
@@ -643,17 +647,13 @@ outhist(void)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
new file mode 100644
index 000000000..a2fba60b3
--- /dev/null
+++ b/src/cmd/5a/y.tab.c
@@ -0,0 +1,2949 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+
+
+/* Line 189 of yacc.c */
+#line 81 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE1 = 258,
+ LTYPE2 = 259,
+ LTYPE3 = 260,
+ LTYPE4 = 261,
+ LTYPE5 = 262,
+ LTYPE6 = 263,
+ LTYPE7 = 264,
+ LTYPE8 = 265,
+ LTYPE9 = 266,
+ LTYPEA = 267,
+ LTYPEB = 268,
+ LTYPEC = 269,
+ LTYPED = 270,
+ LTYPEE = 271,
+ LTYPEF = 272,
+ LTYPEG = 273,
+ LTYPEH = 274,
+ LTYPEI = 275,
+ LTYPEJ = 276,
+ LTYPEK = 277,
+ LTYPEL = 278,
+ LTYPEM = 279,
+ LTYPEN = 280,
+ LTYPEBX = 281,
+ LCONST = 282,
+ LSP = 283,
+ LSB = 284,
+ LFP = 285,
+ LPC = 286,
+ LTYPEX = 287,
+ LR = 288,
+ LREG = 289,
+ LF = 290,
+ LFREG = 291,
+ LC = 292,
+ LCREG = 293,
+ LPSR = 294,
+ LFCR = 295,
+ LCOND = 296,
+ LS = 297,
+ LAT = 298,
+ LFCONST = 299,
+ LSCONST = 300,
+ LNAME = 301,
+ LLAB = 302,
+ LVAR = 303
+ };
+#endif
+/* Tokens. */
+#define LTYPE1 258
+#define LTYPE2 259
+#define LTYPE3 260
+#define LTYPE4 261
+#define LTYPE5 262
+#define LTYPE6 263
+#define LTYPE7 264
+#define LTYPE8 265
+#define LTYPE9 266
+#define LTYPEA 267
+#define LTYPEB 268
+#define LTYPEC 269
+#define LTYPED 270
+#define LTYPEE 271
+#define LTYPEF 272
+#define LTYPEG 273
+#define LTYPEH 274
+#define LTYPEI 275
+#define LTYPEJ 276
+#define LTYPEK 277
+#define LTYPEL 278
+#define LTYPEM 279
+#define LTYPEN 280
+#define LTYPEBX 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LTYPEX 287
+#define LR 288
+#define LREG 289
+#define LF 290
+#define LFREG 291
+#define LC 292
+#define LCREG 293
+#define LPSR 294
+#define LFCR 295
+#define LCOND 296
+#define LS 297
+#define LAT 298
+#define LFCONST 299
+#define LSCONST 300
+#define LNAME 301
+#define LLAB 302
+#define LVAR 303
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c */
+#line 38 "a.y"
+
+ Sym *sym;
+ int32 lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+
+
+
+/* Line 214 of yacc.c */
+#line 223 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 264 of yacc.c */
+#line 235 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 643
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 69
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 35
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 129
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 327
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 303
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 67, 12, 5, 2,
+ 65, 66, 10, 8, 62, 9, 2, 11, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 59, 61,
+ 6, 60, 7, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 63, 2, 64, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 2, 68, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
+ 26, 31, 33, 36, 39, 47, 54, 60, 66, 72,
+ 77, 82, 86, 90, 95, 102, 110, 118, 126, 133,
+ 140, 144, 149, 156, 163, 168, 172, 178, 184, 192,
+ 199, 212, 220, 230, 233, 234, 237, 240, 241, 244,
+ 249, 252, 255, 258, 261, 266, 269, 271, 274, 278,
+ 280, 284, 288, 290, 292, 294, 299, 301, 303, 305,
+ 307, 309, 311, 313, 317, 319, 324, 326, 331, 333,
+ 335, 337, 339, 342, 344, 350, 355, 360, 365, 370,
+ 372, 374, 376, 378, 383, 385, 387, 389, 394, 396,
+ 398, 400, 405, 410, 416, 424, 425, 428, 431, 433,
+ 435, 437, 439, 441, 444, 447, 450, 454, 455, 458,
+ 460, 464, 468, 472, 476, 480, 485, 490, 494, 498
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 70, 0, -1, -1, -1, 70, 71, 72, -1, -1,
+ 57, 59, 73, 72, -1, -1, 56, 59, 74, 72,
+ -1, 56, 60, 103, 61, -1, 58, 60, 103, 61,
+ -1, 61, -1, 75, 61, -1, 1, 61, -1, 13,
+ 76, 87, 62, 94, 62, 89, -1, 13, 76, 87,
+ 62, 94, 62, -1, 13, 76, 87, 62, 89, -1,
+ 14, 76, 87, 62, 89, -1, 15, 76, 82, 62,
+ 82, -1, 16, 76, 77, 78, -1, 16, 76, 77,
+ 83, -1, 36, 77, 84, -1, 17, 77, 78, -1,
+ 18, 76, 77, 82, -1, 19, 76, 87, 62, 94,
+ 77, -1, 20, 76, 85, 62, 63, 81, 64, -1,
+ 20, 76, 63, 81, 64, 62, 85, -1, 21, 76,
+ 89, 62, 84, 62, 89, -1, 21, 76, 89, 62,
+ 84, 77, -1, 21, 76, 77, 84, 62, 89, -1,
+ 22, 76, 77, -1, 23, 98, 62, 88, -1, 23,
+ 98, 62, 101, 62, 88, -1, 24, 98, 11, 101,
+ 62, 79, -1, 25, 76, 89, 77, -1, 29, 77,
+ 79, -1, 30, 76, 97, 62, 97, -1, 32, 76,
+ 96, 62, 97, -1, 32, 76, 96, 62, 46, 62,
+ 97, -1, 33, 76, 97, 62, 97, 77, -1, 31,
+ 76, 101, 62, 103, 62, 94, 62, 95, 62, 95,
+ 102, -1, 34, 76, 89, 62, 89, 62, 90, -1,
+ 35, 76, 89, 62, 89, 62, 89, 62, 94, -1,
+ 26, 77, -1, -1, 76, 51, -1, 76, 52, -1,
+ -1, 62, 77, -1, 101, 65, 41, 66, -1, 56,
+ 99, -1, 57, 99, -1, 67, 101, -1, 67, 86,
+ -1, 67, 10, 67, 86, -1, 67, 55, -1, 80,
+ -1, 67, 54, -1, 67, 9, 54, -1, 94, -1,
+ 94, 9, 94, -1, 94, 77, 81, -1, 89, -1,
+ 79, -1, 91, -1, 91, 65, 94, 66, -1, 49,
+ -1, 50, -1, 101, -1, 86, -1, 97, -1, 84,
+ -1, 98, -1, 65, 94, 66, -1, 84, -1, 101,
+ 65, 93, 66, -1, 98, -1, 98, 65, 93, 66,
+ -1, 85, -1, 89, -1, 88, -1, 91, -1, 67,
+ 101, -1, 94, -1, 65, 94, 62, 94, 66, -1,
+ 94, 6, 6, 92, -1, 94, 7, 7, 92, -1,
+ 94, 9, 7, 92, -1, 94, 53, 7, 92, -1,
+ 94, -1, 101, -1, 44, -1, 41, -1, 43, 65,
+ 103, 66, -1, 93, -1, 38, -1, 48, -1, 47,
+ 65, 103, 66, -1, 97, -1, 80, -1, 46, -1,
+ 45, 65, 101, 66, -1, 101, 65, 100, 66, -1,
+ 56, 99, 65, 100, 66, -1, 56, 6, 7, 99,
+ 65, 39, 66, -1, -1, 8, 101, -1, 9, 101,
+ -1, 39, -1, 38, -1, 40, -1, 37, -1, 58,
+ -1, 9, 101, -1, 8, 101, -1, 68, 101, -1,
+ 65, 103, 66, -1, -1, 62, 103, -1, 101, -1,
+ 103, 8, 103, -1, 103, 9, 103, -1, 103, 10,
+ 103, -1, 103, 11, 103, -1, 103, 12, 103, -1,
+ 103, 6, 6, 103, -1, 103, 7, 7, 103, -1,
+ 103, 5, 103, -1, 103, 4, 103, -1, 103, 3,
+ 103, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 67, 67, 69, 68, 76, 75, 83, 82, 88,
+ 93, 99, 100, 101, 107, 111, 115, 122, 129, 136,
+ 140, 147, 154, 161, 168, 175, 184, 196, 200, 204,
+ 211, 218, 222, 229, 236, 243, 250, 254, 258, 262,
+ 269, 291, 298, 307, 313, 316, 320, 325, 326, 329,
+ 335, 344, 352, 358, 363, 368, 374, 377, 383, 391,
+ 395, 404, 410, 411, 412, 413, 418, 424, 430, 436,
+ 437, 440, 441, 449, 458, 459, 468, 469, 475, 478,
+ 479, 480, 482, 490, 498, 507, 513, 519, 525, 533,
+ 539, 547, 548, 552, 560, 561, 567, 568, 576, 577,
+ 580, 586, 594, 602, 610, 620, 623, 627, 633, 634,
+ 635, 638, 639, 643, 647, 651, 655, 661, 664, 670,
+ 671, 675, 679, 683, 687, 691, 695, 699, 703, 707
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4",
+ "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB",
+ "LTYPEC", "LTYPED", "LTYPEE", "LTYPEF", "LTYPEG", "LTYPEH", "LTYPEI",
+ "LTYPEJ", "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LCONST",
+ "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LR", "LREG", "LF", "LFREG", "LC",
+ "LCREG", "LPSR", "LFCR", "LCOND", "LS", "LAT", "LFCONST", "LSCONST",
+ "LNAME", "LLAB", "LVAR", "':'", "'='", "';'", "','", "'['", "']'", "'('",
+ "')'", "'$'", "'~'", "$accept", "prog", "$@1", "line", "$@2", "$@3",
+ "inst", "cond", "comma", "rel", "ximm", "fcon", "reglist", "gen",
+ "nireg", "ireg", "ioreg", "oreg", "imsr", "imm", "reg", "regreg",
+ "shift", "rcon", "sreg", "spreg", "creg", "frcon", "freg", "name",
+ "offset", "pointer", "con", "oexpr", "expr", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
+ 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 58,
+ 61, 59, 44, 91, 93, 40, 41, 36, 126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 69, 70, 71, 70, 73, 72, 74, 72, 72,
+ 72, 72, 72, 72, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 76, 76, 76, 77, 77, 78,
+ 78, 78, 79, 79, 79, 79, 79, 80, 80, 81,
+ 81, 81, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 83, 83, 84, 85, 85, 86, 86, 86, 87,
+ 87, 87, 88, 89, 90, 91, 91, 91, 91, 92,
+ 92, 93, 93, 93, 94, 94, 95, 95, 96, 96,
+ 97, 97, 98, 98, 98, 99, 99, 99, 100, 100,
+ 100, 101, 101, 101, 101, 101, 101, 102, 102, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 0, 3, 0, 4, 0, 4, 4,
+ 4, 1, 2, 2, 7, 6, 5, 5, 5, 4,
+ 4, 3, 3, 4, 6, 7, 7, 7, 6, 6,
+ 3, 4, 6, 6, 4, 3, 5, 5, 7, 6,
+ 12, 7, 9, 2, 0, 2, 2, 0, 2, 4,
+ 2, 2, 2, 2, 4, 2, 1, 2, 3, 1,
+ 3, 3, 1, 1, 1, 4, 1, 1, 1, 1,
+ 1, 1, 1, 3, 1, 4, 1, 4, 1, 1,
+ 1, 1, 2, 1, 5, 4, 4, 4, 4, 1,
+ 1, 1, 1, 4, 1, 1, 1, 4, 1, 1,
+ 1, 4, 4, 5, 7, 0, 2, 2, 1, 1,
+ 1, 1, 1, 2, 2, 2, 3, 0, 2, 1,
+ 3, 3, 3, 3, 3, 4, 4, 3, 3, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 3, 1, 0, 0, 44, 44, 44, 44, 47,
+ 44, 44, 44, 44, 44, 0, 0, 44, 47, 47,
+ 44, 44, 44, 44, 44, 44, 47, 0, 0, 0,
+ 11, 4, 0, 13, 0, 0, 0, 47, 47, 0,
+ 47, 0, 0, 47, 47, 0, 0, 111, 105, 112,
+ 0, 0, 0, 0, 0, 0, 43, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7, 0, 5, 0, 12,
+ 95, 92, 0, 91, 45, 46, 0, 0, 80, 79,
+ 81, 94, 83, 0, 0, 100, 66, 67, 0, 0,
+ 63, 56, 0, 74, 78, 69, 62, 64, 70, 76,
+ 68, 0, 48, 105, 105, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 83, 30, 114, 113, 0, 0,
+ 0, 0, 119, 0, 115, 0, 0, 0, 47, 35,
+ 0, 0, 0, 99, 0, 98, 0, 0, 0, 0,
+ 21, 0, 0, 0, 0, 0, 82, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 57, 55, 53,
+ 52, 0, 0, 0, 0, 105, 19, 20, 71, 72,
+ 0, 50, 51, 0, 23, 0, 0, 47, 0, 0,
+ 0, 0, 105, 106, 107, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 116, 31, 0, 109,
+ 108, 110, 0, 0, 34, 0, 0, 0, 0, 0,
+ 0, 0, 8, 9, 6, 10, 0, 16, 83, 0,
+ 0, 0, 0, 17, 0, 73, 58, 0, 18, 0,
+ 0, 0, 50, 0, 0, 47, 0, 0, 0, 0,
+ 0, 47, 0, 0, 129, 128, 127, 0, 0, 120,
+ 121, 122, 123, 124, 0, 102, 0, 36, 0, 100,
+ 37, 47, 0, 0, 93, 15, 85, 89, 90, 86,
+ 87, 88, 101, 54, 0, 65, 77, 75, 49, 24,
+ 0, 60, 61, 0, 29, 47, 28, 0, 103, 125,
+ 126, 32, 33, 0, 0, 39, 0, 0, 14, 26,
+ 25, 27, 0, 0, 38, 0, 41, 0, 104, 0,
+ 0, 0, 0, 96, 0, 0, 42, 0, 0, 0,
+ 0, 117, 84, 97, 0, 40, 118
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 3, 31, 143, 141, 32, 34, 102, 105,
+ 90, 91, 176, 92, 167, 93, 94, 95, 77, 78,
+ 79, 306, 80, 266, 81, 114, 314, 134, 98, 99,
+ 121, 202, 122, 325, 123
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -147
+static const yytype_int16 yypact[] =
+{
+ -147, 19, -147, 305, -37, -147, -147, -147, -147, -40,
+ -147, -147, -147, -147, -147, 448, 448, -147, -40, -40,
+ -147, -147, -147, -147, -147, -147, -40, -8, -22, -21,
+ -147, -147, -20, -147, 102, 102, 334, 108, -40, 416,
+ 108, 102, 397, 48, 108, 482, 482, -147, 95, -147,
+ 482, 482, -19, 18, 34, 223, -147, 5, 174, 424,
+ 132, 174, 223, 223, 20, -147, 482, -147, 482, -147,
+ -147, -147, 30, -147, -147, -147, 482, 35, -147, -147,
+ -147, -147, 49, 76, 84, -147, -147, -147, 205, 339,
+ -147, -147, 93, -147, -147, -147, -147, 110, -147, 124,
+ 125, 442, -147, 98, 98, -147, 128, 373, 134, 36,
+ 144, 147, 20, 153, -147, -147, -147, -147, 60, 482,
+ 482, 175, -147, 114, -147, 249, 21, 482, -40, -147,
+ 182, 183, 12, -147, 185, -147, 188, 189, 198, 36,
+ -147, 305, 562, 305, 572, 482, -147, 36, 256, 258,
+ 261, 269, 36, 482, 212, 460, 216, -147, -147, -147,
+ 125, 373, 36, 138, 586, 95, -147, -147, -147, -147,
+ 217, -147, -147, 247, -147, 36, 226, 7, 229, 138,
+ 227, 20, 98, -147, -147, 21, 482, 482, 482, 287,
+ 301, 482, 482, 482, 482, 482, -147, -147, 248, -147,
+ -147, -147, 243, 250, -147, 66, 482, 257, 106, 66,
+ 36, 36, -147, -147, -147, -147, 225, -147, 251, 205,
+ 205, 205, 205, -147, 266, -147, -147, 478, -147, 267,
+ 278, 279, 175, 215, 280, -40, 253, 36, 36, 36,
+ 36, 297, 295, 298, 601, 345, 609, 482, 482, 190,
+ 190, -147, -147, -147, 300, -147, 5, -147, 552, 303,
+ -147, -40, 306, 307, -147, 36, -147, -147, -147, -147,
+ -147, -147, -147, -147, 125, -147, -147, -147, -147, -147,
+ 486, -147, -147, 309, -147, 130, -147, 331, -147, 121,
+ 121, -147, -147, 36, 66, -147, 322, 36, -147, -147,
+ -147, -147, 308, 326, -147, 36, -147, 327, -147, 119,
+ 329, 36, 333, -147, 338, 36, -147, 482, 119, 330,
+ 292, 341, -147, -147, 482, -147, 631
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -147, -147, -147, -114, -147, -147, -147, 579, 44, 311,
+ -49, 348, 0, -97, -147, -44, -39, -80, -9, -119,
+ -13, -147, -25, 2, -146, -34, 91, -147, -14, -3,
+ -89, 228, -11, -147, -30
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -60
+static const yytype_int16 yytable[] =
+{
+ 82, 82, 82, 110, 53, 53, 197, 82, 129, 159,
+ 174, 97, 52, 54, 171, 172, 237, 230, 231, 2,
+ 140, 207, 38, 96, 33, 100, 83, 212, 106, 214,
+ 113, 111, 108, 231, 116, 117, 142, 67, 144, 68,
+ 124, 69, 128, 125, 130, 127, 135, 136, 131, 137,
+ 138, 65, 66, 39, 154, 148, 149, 168, 150, 199,
+ 200, 201, 56, 57, 228, 146, 157, 182, 180, 38,
+ 64, -59, 89, 82, 70, 177, 232, 71, 160, 72,
+ 73, 101, 97, 126, 107, 139, 70, 112, 115, 71,
+ 170, 72, 73, 242, 96, 145, 100, 147, 169, 74,
+ 75, 118, 151, 119, 120, 154, 119, 120, 183, 184,
+ 38, 84, 85, 218, 198, 216, 203, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 82, 229, 191,
+ 192, 193, 194, 195, 217, 291, 97, 241, 152, 223,
+ 70, 235, 224, 71, 117, 72, 73, 273, 96, 153,
+ 100, 84, 259, 74, 75, 161, 244, 245, 246, 74,
+ 75, 249, 250, 251, 252, 253, 312, 313, 70, 76,
+ 38, 71, 204, 72, 73, 162, 258, 84, 85, 71,
+ 196, 72, 73, 74, 75, 267, 267, 267, 267, 163,
+ 164, 257, 38, 173, 260, 261, 175, 262, 263, 132,
+ 193, 194, 195, 281, 177, 177, 178, 292, 268, 268,
+ 268, 268, 179, 45, 46, 181, 274, 289, 290, 84,
+ 85, 238, 269, 270, 271, 74, 75, 284, 186, 187,
+ 188, 189, 190, 191, 192, 193, 194, 195, 282, 283,
+ 185, 299, 47, 70, 205, 206, 71, 208, 72, 73,
+ 209, 210, 298, 199, 200, 201, 234, 45, 46, 303,
+ 211, 70, 219, 49, 71, 220, 72, 73, 221, 111,
+ 50, 310, 301, 51, 74, 75, 222, 316, 225, 279,
+ 304, 319, 233, 227, 307, 286, 47, 320, 234, 240,
+ 236, 264, 239, 247, 326, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 295, 4, 49, 248, 255,
+ 254, 226, 256, 265, 50, 280, 76, 51, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 272, 275, 19, 20, 21, 22, 23, 24,
+ 25, 26, 45, 46, 276, 277, 278, 45, 155, 156,
+ 188, 189, 190, 191, 192, 193, 194, 195, 323, 285,
+ 287, 27, 28, 29, 288, 294, 30, 76, 296, 297,
+ 302, 47, 70, 300, 308, 71, 47, 72, 73, 84,
+ 85, 45, 46, 86, 87, 74, 75, 305, 309, 311,
+ 48, 315, 49, 157, 158, 48, 322, 49, 317, 88,
+ 318, 89, 51, 324, 88, 45, 46, 51, 133, 321,
+ 47, 70, 166, 243, 71, 0, 72, 73, 84, 85,
+ 0, 0, 86, 87, 45, 46, 0, 0, 0, 48,
+ 0, 49, 45, 46, 47, 0, 0, 0, 88, 0,
+ 89, 51, 0, 0, 0, 0, 0, 0, 74, 75,
+ 45, 46, 0, 47, 0, 49, 45, 46, 0, 0,
+ 109, 47, 88, 0, 0, 51, 0, 0, 45, 46,
+ 0, 0, 103, 104, 49, 74, 75, 0, 0, 47,
+ 0, 50, 49, 0, 51, 47, 45, 46, 0, 50,
+ 45, 46, 51, 0, 45, 46, 0, 47, 165, 104,
+ 49, 0, 0, 0, 48, 0, 49, 88, 0, 0,
+ 51, 0, 0, 50, 226, 47, 51, 0, 49, 47,
+ 0, 0, 0, 47, 0, 50, 0, 0, 51, 0,
+ 0, 0, 0, 0, 48, 0, 49, 0, 0, 0,
+ 49, 0, 0, 88, 49, 0, 51, 50, 0, 0,
+ 51, 88, 0, 0, 51, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 35, 36, 37, 0, 40,
+ 41, 42, 43, 44, 0, 0, 55, 0, 0, 58,
+ 59, 60, 61, 62, 63, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 293, 189, 190, 191, 192, 193,
+ 194, 195, 0, 213, 199, 200, 201, 71, 0, 72,
+ 73, 0, 0, 215, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 34, 35, 36, 42, 15, 16, 125, 41, 57, 89,
+ 107, 36, 15, 16, 103, 104, 9, 163, 164, 0,
+ 64, 9, 62, 36, 61, 36, 35, 141, 39, 143,
+ 43, 42, 41, 179, 45, 46, 66, 59, 68, 60,
+ 51, 61, 55, 62, 58, 11, 60, 61, 59, 62,
+ 63, 59, 60, 9, 88, 6, 7, 101, 9, 38,
+ 39, 40, 18, 19, 161, 76, 54, 7, 112, 62,
+ 26, 64, 67, 107, 38, 109, 165, 41, 89, 43,
+ 44, 37, 107, 65, 40, 65, 38, 43, 44, 41,
+ 101, 43, 44, 182, 107, 65, 107, 62, 101, 51,
+ 52, 6, 53, 8, 9, 139, 8, 9, 119, 120,
+ 62, 45, 46, 147, 125, 145, 127, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 161, 162, 8,
+ 9, 10, 11, 12, 147, 254, 161, 181, 62, 152,
+ 38, 175, 153, 41, 155, 43, 44, 227, 161, 65,
+ 161, 45, 46, 51, 52, 62, 186, 187, 188, 51,
+ 52, 191, 192, 193, 194, 195, 47, 48, 38, 67,
+ 62, 41, 128, 43, 44, 65, 206, 45, 46, 41,
+ 66, 43, 44, 51, 52, 219, 220, 221, 222, 65,
+ 65, 205, 62, 65, 208, 209, 62, 210, 211, 67,
+ 10, 11, 12, 237, 238, 239, 62, 256, 219, 220,
+ 221, 222, 65, 8, 9, 62, 227, 247, 248, 45,
+ 46, 177, 220, 221, 222, 51, 52, 240, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 238, 239,
+ 65, 280, 37, 38, 62, 62, 41, 62, 43, 44,
+ 62, 62, 265, 38, 39, 40, 41, 8, 9, 293,
+ 62, 38, 6, 58, 41, 7, 43, 44, 7, 280,
+ 65, 305, 285, 68, 51, 52, 7, 311, 66, 235,
+ 294, 315, 65, 67, 297, 241, 37, 317, 41, 62,
+ 64, 66, 63, 6, 324, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 261, 1, 58, 7, 66,
+ 62, 54, 62, 62, 65, 62, 67, 68, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 66, 66, 29, 30, 31, 32, 33, 34,
+ 35, 36, 8, 9, 66, 66, 66, 8, 9, 10,
+ 5, 6, 7, 8, 9, 10, 11, 12, 66, 62,
+ 65, 56, 57, 58, 66, 62, 61, 67, 62, 62,
+ 39, 37, 38, 64, 66, 41, 37, 43, 44, 45,
+ 46, 8, 9, 49, 50, 51, 52, 65, 62, 62,
+ 56, 62, 58, 54, 55, 56, 66, 58, 65, 65,
+ 62, 67, 68, 62, 65, 8, 9, 68, 60, 318,
+ 37, 38, 101, 185, 41, -1, 43, 44, 45, 46,
+ -1, -1, 49, 50, 8, 9, -1, -1, -1, 56,
+ -1, 58, 8, 9, 37, -1, -1, -1, 65, -1,
+ 67, 68, -1, -1, -1, -1, -1, -1, 51, 52,
+ 8, 9, -1, 37, -1, 58, 8, 9, -1, -1,
+ 63, 37, 65, -1, -1, 68, -1, -1, 8, 9,
+ -1, -1, 56, 57, 58, 51, 52, -1, -1, 37,
+ -1, 65, 58, -1, 68, 37, 8, 9, -1, 65,
+ 8, 9, 68, -1, 8, 9, -1, 37, 56, 57,
+ 58, -1, -1, -1, 56, -1, 58, 65, -1, -1,
+ 68, -1, -1, 65, 54, 37, 68, -1, 58, 37,
+ -1, -1, -1, 37, -1, 65, -1, -1, 68, -1,
+ -1, -1, -1, -1, 56, -1, 58, -1, -1, -1,
+ 58, -1, -1, 65, 58, -1, 68, 65, -1, -1,
+ 68, 65, -1, -1, 68, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 6, 7, 8, -1, 10,
+ 11, 12, 13, 14, -1, -1, 17, -1, -1, 20,
+ 21, 22, 23, 24, 25, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 62, 6, 7, 8, 9, 10,
+ 11, 12, -1, 61, 38, 39, 40, 41, -1, 43,
+ 44, -1, -1, 61, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 70, 0, 71, 1, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 29,
+ 30, 31, 32, 33, 34, 35, 36, 56, 57, 58,
+ 61, 72, 75, 61, 76, 76, 76, 76, 62, 77,
+ 76, 76, 76, 76, 76, 8, 9, 37, 56, 58,
+ 65, 68, 98, 101, 98, 76, 77, 77, 76, 76,
+ 76, 76, 76, 76, 77, 59, 60, 59, 60, 61,
+ 38, 41, 43, 44, 51, 52, 67, 87, 88, 89,
+ 91, 93, 94, 87, 45, 46, 49, 50, 65, 67,
+ 79, 80, 82, 84, 85, 86, 89, 91, 97, 98,
+ 101, 77, 77, 56, 57, 78, 101, 77, 87, 63,
+ 85, 101, 77, 89, 94, 77, 101, 101, 6, 8,
+ 9, 99, 101, 103, 101, 62, 65, 11, 89, 79,
+ 97, 101, 67, 80, 96, 97, 97, 89, 89, 65,
+ 84, 74, 103, 73, 103, 65, 101, 62, 6, 7,
+ 9, 53, 62, 65, 94, 9, 10, 54, 55, 86,
+ 101, 62, 65, 65, 65, 56, 78, 83, 84, 98,
+ 101, 99, 99, 65, 82, 62, 81, 94, 62, 65,
+ 84, 62, 7, 101, 101, 65, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 66, 88, 101, 38,
+ 39, 40, 100, 101, 77, 62, 62, 9, 62, 62,
+ 62, 62, 72, 61, 72, 61, 103, 89, 94, 6,
+ 7, 7, 7, 89, 101, 66, 54, 67, 82, 94,
+ 93, 93, 99, 65, 41, 94, 64, 9, 77, 63,
+ 62, 84, 99, 100, 103, 103, 103, 6, 7, 103,
+ 103, 103, 103, 103, 62, 66, 62, 97, 103, 46,
+ 97, 97, 89, 89, 66, 62, 92, 94, 101, 92,
+ 92, 92, 66, 86, 101, 66, 66, 66, 66, 77,
+ 62, 94, 81, 81, 89, 62, 77, 65, 66, 103,
+ 103, 88, 79, 62, 62, 77, 62, 62, 89, 85,
+ 64, 89, 39, 94, 97, 65, 90, 89, 66, 62,
+ 94, 62, 47, 48, 95, 62, 94, 65, 62, 94,
+ 103, 95, 66, 66, 62, 102, 103
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+
+/* Line 1455 of yacc.c */
+#line 69 "a.y"
+ {
+ stmtline = lineno;
+ }
+ break;
+
+ case 5:
+
+/* Line 1455 of yacc.c */
+#line 76 "a.y"
+ {
+ if((yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 7:
+
+/* Line 1455 of yacc.c */
+#line 83 "a.y"
+ {
+ (yyvsp[(1) - (2)].sym)->type = LLAB;
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 9:
+
+/* Line 1455 of yacc.c */
+#line 89 "a.y"
+ {
+ (yyvsp[(1) - (4)].sym)->type = LVAR;
+ (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 10:
+
+/* Line 1455 of yacc.c */
+#line 94 "a.y"
+ {
+ if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
+ yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
+ (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 14:
+
+/* Line 1455 of yacc.c */
+#line 108 "a.y"
+ {
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen));
+ }
+ break;
+
+ case 15:
+
+/* Line 1455 of yacc.c */
+#line 112 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen);
+ }
+ break;
+
+ case 16:
+
+/* Line 1455 of yacc.c */
+#line 116 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ }
+ break;
+
+ case 17:
+
+/* Line 1455 of yacc.c */
+#line 123 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ }
+ break;
+
+ case 18:
+
+/* Line 1455 of yacc.c */
+#line 130 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ }
+ break;
+
+ case 19:
+
+/* Line 1455 of yacc.c */
+#line 137 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ }
+ break;
+
+ case 20:
+
+/* Line 1455 of yacc.c */
+#line 141 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ }
+ break;
+
+ case 21:
+
+/* Line 1455 of yacc.c */
+#line 148 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ }
+ break;
+
+ case 22:
+
+/* Line 1455 of yacc.c */
+#line 155 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ }
+ break;
+
+ case 23:
+
+/* Line 1455 of yacc.c */
+#line 162 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].gen));
+ }
+ break;
+
+ case 24:
+
+/* Line 1455 of yacc.c */
+#line 169 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].lval), &nullgen);
+ }
+ break;
+
+ case 25:
+
+/* Line 1455 of yacc.c */
+#line 176 "a.y"
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = (yyvsp[(6) - (7)].lval);
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), NREG, &g);
+ }
+ break;
+
+ case 26:
+
+/* Line 1455 of yacc.c */
+#line 185 "a.y"
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset = (yyvsp[(4) - (7)].lval);
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].gen));
+ }
+ break;
+
+ case 27:
+
+/* Line 1455 of yacc.c */
+#line 197 "a.y"
+ {
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].gen), (yyvsp[(3) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen));
+ }
+ break;
+
+ case 28:
+
+/* Line 1455 of yacc.c */
+#line 201 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].gen), (yyvsp[(3) - (6)].gen).reg, &(yyvsp[(3) - (6)].gen));
+ }
+ break;
+
+ case 29:
+
+/* Line 1455 of yacc.c */
+#line 205 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].gen), (yyvsp[(6) - (6)].gen).reg, &(yyvsp[(6) - (6)].gen));
+ }
+ break;
+
+ case 30:
+
+/* Line 1455 of yacc.c */
+#line 212 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 31:
+
+/* Line 1455 of yacc.c */
+#line 219 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].gen), NREG, &(yyvsp[(4) - (4)].gen));
+ }
+ break;
+
+ case 32:
+
+/* Line 1455 of yacc.c */
+#line 223 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen));
+ }
+ break;
+
+ case 33:
+
+/* Line 1455 of yacc.c */
+#line 230 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].gen), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].gen));
+ }
+ break;
+
+ case 34:
+
+/* Line 1455 of yacc.c */
+#line 237 "a.y"
+ {
+ outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].gen), NREG, &nullgen);
+ }
+ break;
+
+ case 35:
+
+/* Line 1455 of yacc.c */
+#line 244 "a.y"
+ {
+ outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].gen));
+ }
+ break;
+
+ case 36:
+
+/* Line 1455 of yacc.c */
+#line 251 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ }
+ break;
+
+ case 37:
+
+/* Line 1455 of yacc.c */
+#line 255 "a.y"
+ {
+ outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].gen), NREG, &(yyvsp[(5) - (5)].gen));
+ }
+ break;
+
+ case 38:
+
+/* Line 1455 of yacc.c */
+#line 259 "a.y"
+ {
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].gen));
+ }
+ break;
+
+ case 39:
+
+/* Line 1455 of yacc.c */
+#line 263 "a.y"
+ {
+ outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].gen), (yyvsp[(5) - (6)].gen).reg, &nullgen);
+ }
+ break;
+
+ case 40:
+
+/* Line 1455 of yacc.c */
+#line 270 "a.y"
+ {
+ Gen g;
+
+ g = nullgen;
+ g.type = D_CONST;
+ g.offset =
+ (0xe << 24) | /* opcode */
+ ((yyvsp[(1) - (12)].lval) << 20) | /* MCR/MRC */
+ ((yyvsp[(2) - (12)].lval) << 28) | /* scond */
+ (((yyvsp[(3) - (12)].lval) & 15) << 8) | /* coprocessor number */
+ (((yyvsp[(5) - (12)].lval) & 7) << 21) | /* coprocessor operation */
+ (((yyvsp[(7) - (12)].lval) & 15) << 12) | /* arm register */
+ (((yyvsp[(9) - (12)].lval) & 15) << 16) | /* Crn */
+ (((yyvsp[(11) - (12)].lval) & 15) << 0) | /* Crm */
+ (((yyvsp[(12) - (12)].lval) & 7) << 5) | /* coprocessor information */
+ (1<<4); /* must be set */
+ outcode(AWORD, Always, &nullgen, NREG, &g);
+ }
+ break;
+
+ case 41:
+
+/* Line 1455 of yacc.c */
+#line 292 "a.y"
+ {
+ outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].gen), (yyvsp[(5) - (7)].gen).reg, &(yyvsp[(7) - (7)].gen));
+ }
+ break;
+
+ case 42:
+
+/* Line 1455 of yacc.c */
+#line 299 "a.y"
+ {
+ (yyvsp[(7) - (9)].gen).type = D_REGREG;
+ (yyvsp[(7) - (9)].gen).offset = (yyvsp[(9) - (9)].lval);
+ outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].gen), (yyvsp[(5) - (9)].gen).reg, &(yyvsp[(7) - (9)].gen));
+ }
+ break;
+
+ case 43:
+
+/* Line 1455 of yacc.c */
+#line 308 "a.y"
+ {
+ outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
+ }
+ break;
+
+ case 44:
+
+/* Line 1455 of yacc.c */
+#line 313 "a.y"
+ {
+ (yyval.lval) = Always;
+ }
+ break;
+
+ case 45:
+
+/* Line 1455 of yacc.c */
+#line 317 "a.y"
+ {
+ (yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 46:
+
+/* Line 1455 of yacc.c */
+#line 321 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 49:
+
+/* Line 1455 of yacc.c */
+#line 330 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ }
+ break;
+
+ case 50:
+
+/* Line 1455 of yacc.c */
+#line 336 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 51:
+
+/* Line 1455 of yacc.c */
+#line 345 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 52:
+
+/* Line 1455 of yacc.c */
+#line 353 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 53:
+
+/* Line 1455 of yacc.c */
+#line 359 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.gen).type = D_CONST;
+ }
+ break;
+
+ case 54:
+
+/* Line 1455 of yacc.c */
+#line 364 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(4) - (4)].gen);
+ (yyval.gen).type = D_OCONST;
+ }
+ break;
+
+ case 55:
+
+/* Line 1455 of yacc.c */
+#line 369 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SCONST;
+ memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ }
+ break;
+
+ case 57:
+
+/* Line 1455 of yacc.c */
+#line 378 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ }
+ break;
+
+ case 58:
+
+/* Line 1455 of yacc.c */
+#line 384 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ }
+ break;
+
+ case 59:
+
+/* Line 1455 of yacc.c */
+#line 392 "a.y"
+ {
+ (yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 60:
+
+/* Line 1455 of yacc.c */
+#line 396 "a.y"
+ {
+ int i;
+ (yyval.lval)=0;
+ for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++)
+ (yyval.lval) |= 1<<i;
+ for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++)
+ (yyval.lval) |= 1<<i;
+ }
+ break;
+
+ case 61:
+
+/* Line 1455 of yacc.c */
+#line 405 "a.y"
+ {
+ (yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 65:
+
+/* Line 1455 of yacc.c */
+#line 414 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (4)].gen);
+ (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 66:
+
+/* Line 1455 of yacc.c */
+#line 419 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_PSR;
+ (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 67:
+
+/* Line 1455 of yacc.c */
+#line 425 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FPCR;
+ (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 68:
+
+/* Line 1455 of yacc.c */
+#line 431 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 72:
+
+/* Line 1455 of yacc.c */
+#line 442 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (1)].gen);
+ if((yyvsp[(1) - (1)].gen).name != D_EXTERN && (yyvsp[(1) - (1)].gen).name != D_STATIC) {
+ }
+ }
+ break;
+
+ case 73:
+
+/* Line 1455 of yacc.c */
+#line 450 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).reg = (yyvsp[(2) - (3)].lval);
+ (yyval.gen).offset = 0;
+ }
+ break;
+
+ case 75:
+
+/* Line 1455 of yacc.c */
+#line 460 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 77:
+
+/* Line 1455 of yacc.c */
+#line 470 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (4)].gen);
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 82:
+
+/* Line 1455 of yacc.c */
+#line 483 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 83:
+
+/* Line 1455 of yacc.c */
+#line 491 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_REG;
+ (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 84:
+
+/* Line 1455 of yacc.c */
+#line 499 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_REGREG;
+ (yyval.gen).reg = (yyvsp[(2) - (5)].lval);
+ (yyval.gen).offset = (yyvsp[(4) - (5)].lval);
+ }
+ break;
+
+ case 85:
+
+/* Line 1455 of yacc.c */
+#line 508 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SHIFT;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5);
+ }
+ break;
+
+ case 86:
+
+/* Line 1455 of yacc.c */
+#line 514 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SHIFT;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5);
+ }
+ break;
+
+ case 87:
+
+/* Line 1455 of yacc.c */
+#line 520 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SHIFT;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5);
+ }
+ break;
+
+ case 88:
+
+/* Line 1455 of yacc.c */
+#line 526 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SHIFT;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5);
+ }
+ break;
+
+ case 89:
+
+/* Line 1455 of yacc.c */
+#line 534 "a.y"
+ {
+ if((yyval.lval) < 0 || (yyval.lval) >= 16)
+ print("register value out of range\n");
+ (yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4);
+ }
+ break;
+
+ case 90:
+
+/* Line 1455 of yacc.c */
+#line 540 "a.y"
+ {
+ if((yyval.lval) < 0 || (yyval.lval) >= 32)
+ print("shift value out of range\n");
+ (yyval.lval) = ((yyvsp[(1) - (1)].lval)&31) << 7;
+ }
+ break;
+
+ case 92:
+
+/* Line 1455 of yacc.c */
+#line 549 "a.y"
+ {
+ (yyval.lval) = REGPC;
+ }
+ break;
+
+ case 93:
+
+/* Line 1455 of yacc.c */
+#line 553 "a.y"
+ {
+ if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
+ print("register value out of range\n");
+ (yyval.lval) = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 95:
+
+/* Line 1455 of yacc.c */
+#line 562 "a.y"
+ {
+ (yyval.lval) = REGSP;
+ }
+ break;
+
+ case 97:
+
+/* Line 1455 of yacc.c */
+#line 569 "a.y"
+ {
+ if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
+ print("register value out of range\n");
+ (yyval.lval) = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 100:
+
+/* Line 1455 of yacc.c */
+#line 581 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FREG;
+ (yyval.gen).reg = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 101:
+
+/* Line 1455 of yacc.c */
+#line 587 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FREG;
+ (yyval.gen).reg = (yyvsp[(3) - (4)].lval);
+ }
+ break;
+
+ case 102:
+
+/* Line 1455 of yacc.c */
+#line 595 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).name = (yyvsp[(3) - (4)].lval);
+ (yyval.gen).sym = S;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 103:
+
+/* Line 1455 of yacc.c */
+#line 603 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).name = (yyvsp[(4) - (5)].lval);
+ (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ }
+ break;
+
+ case 104:
+
+/* Line 1455 of yacc.c */
+#line 611 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_OREG;
+ (yyval.gen).name = D_STATIC;
+ (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
+ (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ }
+ break;
+
+ case 105:
+
+/* Line 1455 of yacc.c */
+#line 620 "a.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 106:
+
+/* Line 1455 of yacc.c */
+#line 624 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 107:
+
+/* Line 1455 of yacc.c */
+#line 628 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 112:
+
+/* Line 1455 of yacc.c */
+#line 640 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+ }
+ break;
+
+ case 113:
+
+/* Line 1455 of yacc.c */
+#line 644 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 114:
+
+/* Line 1455 of yacc.c */
+#line 648 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 115:
+
+/* Line 1455 of yacc.c */
+#line 652 "a.y"
+ {
+ (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 116:
+
+/* Line 1455 of yacc.c */
+#line 656 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 117:
+
+/* Line 1455 of yacc.c */
+#line 661 "a.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 118:
+
+/* Line 1455 of yacc.c */
+#line 665 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 120:
+
+/* Line 1455 of yacc.c */
+#line 672 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 121:
+
+/* Line 1455 of yacc.c */
+#line 676 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 122:
+
+/* Line 1455 of yacc.c */
+#line 680 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 123:
+
+/* Line 1455 of yacc.c */
+#line 684 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 124:
+
+/* Line 1455 of yacc.c */
+#line 688 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 125:
+
+/* Line 1455 of yacc.c */
+#line 692 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 126:
+
+/* Line 1455 of yacc.c */
+#line 696 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 127:
+
+/* Line 1455 of yacc.c */
+#line 700 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 128:
+
+/* Line 1455 of yacc.c */
+#line 704 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 129:
+
+/* Line 1455 of yacc.c */
+#line 708 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+
+
+/* Line 1455 of yacc.c */
+#line 2740 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
new file mode 100644
index 000000000..28039992c
--- /dev/null
+++ b/src/cmd/5a/y.tab.h
@@ -0,0 +1,166 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE1 = 258,
+ LTYPE2 = 259,
+ LTYPE3 = 260,
+ LTYPE4 = 261,
+ LTYPE5 = 262,
+ LTYPE6 = 263,
+ LTYPE7 = 264,
+ LTYPE8 = 265,
+ LTYPE9 = 266,
+ LTYPEA = 267,
+ LTYPEB = 268,
+ LTYPEC = 269,
+ LTYPED = 270,
+ LTYPEE = 271,
+ LTYPEF = 272,
+ LTYPEG = 273,
+ LTYPEH = 274,
+ LTYPEI = 275,
+ LTYPEJ = 276,
+ LTYPEK = 277,
+ LTYPEL = 278,
+ LTYPEM = 279,
+ LTYPEN = 280,
+ LTYPEBX = 281,
+ LCONST = 282,
+ LSP = 283,
+ LSB = 284,
+ LFP = 285,
+ LPC = 286,
+ LTYPEX = 287,
+ LR = 288,
+ LREG = 289,
+ LF = 290,
+ LFREG = 291,
+ LC = 292,
+ LCREG = 293,
+ LPSR = 294,
+ LFCR = 295,
+ LCOND = 296,
+ LS = 297,
+ LAT = 298,
+ LFCONST = 299,
+ LSCONST = 300,
+ LNAME = 301,
+ LLAB = 302,
+ LVAR = 303
+ };
+#endif
+/* Tokens. */
+#define LTYPE1 258
+#define LTYPE2 259
+#define LTYPE3 260
+#define LTYPE4 261
+#define LTYPE5 262
+#define LTYPE6 263
+#define LTYPE7 264
+#define LTYPE8 265
+#define LTYPE9 266
+#define LTYPEA 267
+#define LTYPEB 268
+#define LTYPEC 269
+#define LTYPED 270
+#define LTYPEE 271
+#define LTYPEF 272
+#define LTYPEG 273
+#define LTYPEH 274
+#define LTYPEI 275
+#define LTYPEJ 276
+#define LTYPEK 277
+#define LTYPEL 278
+#define LTYPEM 279
+#define LTYPEN 280
+#define LTYPEBX 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LTYPEX 287
+#define LR 288
+#define LREG 289
+#define LF 290
+#define LFREG 291
+#define LC 292
+#define LCREG 293
+#define LPSR 294
+#define LFCR 295
+#define LCOND 296
+#define LS 297
+#define LAT 298
+#define LFCONST 299
+#define LSCONST 300
+#define LNAME 301
+#define LLAB 302
+#define LVAR 303
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1676 of yacc.c */
+#line 38 "a.y"
+
+ Sym *sym;
+ int32 lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+
+
+
+/* Line 1676 of yacc.c */
+#line 158 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
index 70b614e8a..3f528d751 100644
--- a/src/cmd/5c/Makefile
+++ b/src/cmd/5c/Makefile
@@ -1,34 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5c
-
-HFILES=\
- gc.h\
- ../5l/5.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- list.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- mul.$O\
- reg.$O\
- peep.$O\
- pgen.$O\
- pswt.$O\
- ../5l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
index ff6d51916..20652682b 100644
--- a/src/cmd/5c/gc.h
+++ b/src/cmd/5c/gc.h
@@ -181,7 +181,7 @@ EXTERN int32 maxargsafe;
EXTERN int mnstring;
EXTERN Multab multab[20];
EXTERN int retok;
-EXTERN int hintabsize;
+extern int hintabsize;
EXTERN Node* nodrat;
EXTERN Node* nodret;
EXTERN Node* nodsafe;
@@ -304,7 +304,8 @@ void gpseudo(int, Sym*, Node*);
int swcmp(const void*, const void*);
void doswit(Node*);
void swit1(C1*, int, int32, Node*);
-void cas(void);
+void swit2(C1*, int, int32, Node*);
+void newcase(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
int mulcon(Node*, Node*);
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 7cbaadba9..7268f9af2 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -28,12 +28,31 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-
#include "gc.h"
void
swit1(C1 *q, int nc, int32 def, Node *n)
{
+ Node nreg;
+
+ if(typev[n->type->etype]) {
+ regsalloc(&nreg, n);
+ nreg.type = types[TVLONG];
+ cgen(n, &nreg);
+ swit2(q, nc, def, &nreg);
+ return;
+ }
+
+ regalloc(&nreg, n, Z);
+ nreg.type = types[TLONG];
+ cgen(n, &nreg);
+ swit2(q, nc, def, &nreg);
+ regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
C1 *r;
int i;
int32 v;
@@ -65,12 +84,12 @@ swit1(C1 *q, int nc, int32 def, Node *n)
sp = p;
gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
patch(p, r->label);
- swit1(q, i, def, n);
+ swit2(q, i, def, n);
if(debug['W'])
print("case < %.8ux\n", r->val);
patch(sp, pc);
- swit1(r+1, nc-i-1, def, n);
+ swit2(r+1, nc-i-1, def, n);
return;
direct:
@@ -460,17 +479,13 @@ outhist(Biobuf *b)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index a32387bc1..1a189e3af 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -139,7 +139,9 @@ gclean(void)
continue;
if(s->type == types[TENUM])
continue;
+ textflag = s->dataflag;
gpseudo(AGLOBL, s, nodconst(s->type->width));
+ textflag = 0;
}
nextpc();
p->as = AEND;
@@ -357,7 +359,7 @@ regfree(Node *n)
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
i = n->reg;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
goto err;
if(reg[i] <= 0)
goto err;
@@ -1183,7 +1185,8 @@ gpseudo(int a, Sym *s, Node *n)
if(a == ATEXT) {
p->reg = textflag;
textflag = 0;
- }
+ } else if(a == AGLOBL)
+ p->reg = 0;
if(s->class == CSTATIC)
p->from.name = D_STATIC;
naddr(n, &p->to);
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
index b47014a4e..3f528d751 100644
--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -1,36 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5g
-
-HFILES=\
- ../gc/go.h\
- ../5l/5.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../5l/enam.$O\
- cgen.$O\
- cgen64.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 6e2fbe20f..cccef94c9 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
/*
@@ -62,6 +64,9 @@ cgen(Node *n, Node *res)
if(isslice(n->left->type))
n->addable = n->left->addable;
break;
+ case OITAB:
+ n->addable = n->left->addable;
+ break;
}
// if both are addressable, move
@@ -211,11 +216,11 @@ cgen(Node *n, Node *res)
goto ret;
case OMINUS:
+ regalloc(&n1, nl->type, N);
+ cgen(nl, &n1);
nodconst(&n3, nl->type, 0);
regalloc(&n2, nl->type, res);
- regalloc(&n1, nl->type, N);
gmove(&n3, &n2);
- cgen(nl, &n1);
gins(optoas(OSUB, nl->type), &n1, &n2);
gmove(&n2, res);
regfree(&n1);
@@ -278,6 +283,20 @@ cgen(Node *n, Node *res)
regfree(&n1);
break;
+ case OITAB:
+ // itable of interface value
+ igen(nl, &n1, res);
+ n1.op = OREGISTER; // was OINDREG
+ regalloc(&n2, n->type, &n1);
+ n1.op = OINDREG;
+ n1.type = n->type;
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n1);
+ regfree(&n2);
+ break;
+
case OLEN:
if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
// map has len in the first 32-bit word.
@@ -400,9 +419,9 @@ abop: // asymmetric binary
regalloc(&n2, nr->type, N);
cgen(nr, &n2);
} else {
- regalloc(&n2, nr->type, N);
+ regalloc(&n2, nr->type, res);
cgen(nr, &n2);
- regalloc(&n1, nl->type, res);
+ regalloc(&n1, nl->type, N);
cgen(nl, &n1);
}
gins(a, &n2, &n1);
@@ -848,8 +867,10 @@ bgen(Node *n, int true, Prog *to)
int et, a;
Node *nl, *nr, *r;
Node n1, n2, n3, n4, tmp;
+ NodeList *ll;
Prog *p1, *p2;
+ USED(n4); // in unreachable code below
if(debug['g']) {
dump("\nbgen", n);
}
@@ -860,9 +881,6 @@ bgen(Node *n, int true, Prog *to)
if(n->ninit != nil)
genlist(n->ninit);
- nl = n->left;
- nr = n->right;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -875,7 +893,6 @@ bgen(Node *n, int true, Prog *to)
patch(gins(AEND, N, N), to);
goto ret;
}
- nl = N;
nr = N;
switch(n->op) {
@@ -951,7 +968,10 @@ bgen(Node *n, int true, Prog *to)
p1 = gbranch(AB, T);
p2 = gbranch(AB, T);
patch(p1, pc);
+ ll = n->ninit;
+ n->ninit = nil;
bgen(n, 1, p2);
+ n->ninit = ll;
patch(gbranch(AB, T), to);
patch(p2, pc);
goto ret;
@@ -984,6 +1004,7 @@ bgen(Node *n, int true, Prog *to)
regfree(&n1);
break;
+#ifdef NOTDEF
a = optoas(a, types[tptr]);
regalloc(&n1, types[tptr], N);
regalloc(&n3, types[tptr], N);
@@ -1001,6 +1022,7 @@ bgen(Node *n, int true, Prog *to)
regfree(&n3);
regfree(&n1);
break;
+#endif
}
if(isinter(nl->type)) {
@@ -1019,6 +1041,7 @@ bgen(Node *n, int true, Prog *to)
regfree(&n1);
break;
+#ifdef NOTDEF
a = optoas(a, types[tptr]);
regalloc(&n1, types[tptr], N);
regalloc(&n3, types[tptr], N);
@@ -1036,6 +1059,7 @@ bgen(Node *n, int true, Prog *to)
regfree(&n3);
regfree(&n4);
break;
+#endif
}
if(iscomplex[nl->type->etype]) {
@@ -1059,7 +1083,7 @@ bgen(Node *n, int true, Prog *to)
}
if(nr->op == OLITERAL) {
- if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) {
+ if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) {
gencmp0(nl, nl->type, a, to);
break;
}
@@ -1186,7 +1210,7 @@ stkof(Node *n)
* NB: character copy assumed little endian architecture
*/
void
-sgen(Node *n, Node *res, int32 w)
+sgen(Node *n, Node *res, int64 w)
{
Node dst, src, tmp, nend;
int32 c, odst, osrc;
@@ -1194,25 +1218,34 @@ sgen(Node *n, Node *res, int32 w)
Prog *p, *ploop;
if(debug['g']) {
- print("\nsgen w=%d\n", w);
+ print("\nsgen w=%lld\n", w);
dump("r", n);
dump("res", res);
}
- if(w == 0)
- return;
- if(w < 0)
- fatal("sgen copy %d", w);
+
if(n->ullman >= UINF && res->ullman >= UINF)
fatal("sgen UINF");
+
+ if(w < 0 || (int32)w != w)
+ fatal("sgen copy %lld", w);
+
if(n->type == T)
fatal("sgen: missing type");
+ if(w == 0) {
+ // evaluate side effects only.
+ regalloc(&dst, types[tptr], N);
+ agen(res, &dst);
+ agen(n, &dst);
+ regfree(&dst);
+ return;
+ }
+
// determine alignment.
// want to avoid unaligned access, so have to use
// smaller operations for less aligned types.
// for example moving [4]byte must use 4 MOVB not 1 MOVW.
align = n->type->align;
- op = 0;
switch(align) {
default:
fatal("sgen: invalid alignment %d for %T", align, n->type);
@@ -1227,7 +1260,7 @@ sgen(Node *n, Node *res, int32 w)
break;
}
if(w%align)
- fatal("sgen: unaligned size %d (align=%d) for %T", w, align, n->type);
+ fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
c = w / align;
// offset on the stack
@@ -1313,7 +1346,6 @@ sgen(Node *n, Node *res, int32 w)
p->from.type = D_OREG;
p->from.offset = dir;
p->scond |= C_PBIT;
- ploop = p;
p = gins(op, &tmp, &dst);
p->to.type = D_OREG;
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index b56df765b..1235d1ace 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
/*
@@ -240,7 +242,7 @@ cgen64(Node *n, Node *res)
// shift is >= 1<<32
split64(r, &cl, &ch);
gmove(&ch, &s);
- p1 = gins(ATST, &s, N);
+ gins(ATST, &s, N);
p6 = gbranch(ABNE, T);
gmove(&cl, &s);
splitclean();
@@ -248,7 +250,7 @@ cgen64(Node *n, Node *res)
gmove(r, &s);
p6 = P;
}
- p1 = gins(ATST, &s, N);
+ gins(ATST, &s, N);
// shift == 0
p1 = gins(AMOVW, &bl, &al);
@@ -411,7 +413,7 @@ olsh_break:
gmove(r, &s);
p6 = P;
}
- p1 = gins(ATST, &s, N);
+ gins(ATST, &s, N);
// shift == 0
p1 = gins(AMOVW, &bl, &al);
@@ -453,9 +455,9 @@ olsh_break:
p1 = gins(AMOVW, &bh, &al);
p1->scond = C_SCOND_EQ;
if(bh.type->etype == TINT32)
- p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+ gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
- p1 = gins(AEOR, &ah, &ah);
+ gins(AEOR, &ah, &ah);
p4 = gbranch(ABEQ, T);
// check if shift is < 64
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
index e86013bdd..5a4a772fb 100644
--- a/src/cmd/5g/doc.go
+++ b/src/cmd/5g/doc.go
@@ -9,7 +9,5 @@ The $GOARCH for these tools is arm.
It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
-There is no instruction optimizer, so the -N flag is a no-op.
-
*/
package documentation
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 12766102f..070804217 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
int thechar = '5';
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index ce4558e21..7dbf3beec 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -2,16 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <u.h>
-#include <libc.h>
+#ifndef EXTERN
+#define EXTERN extern
+#endif
#include "../gc/go.h"
#include "../5l/5.out.h"
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
typedef struct Addr Addr;
struct Addr
@@ -46,27 +43,26 @@ struct Prog
uchar scond;
};
+#define TEXTFLAG reg
+
#define REGALLOC_R0 0
#define REGALLOC_RMAX REGEXT
#define REGALLOC_F0 (REGALLOC_RMAX+1)
#define REGALLOC_FMAX (REGALLOC_F0 + FREGEXT)
-EXTERN Biobuf* bout;
EXTERN int32 dynloc;
EXTERN uchar reg[REGALLOC_FMAX+1];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
extern char* anames[];
-EXTERN Hist* hist;
EXTERN Prog zprog;
-EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
-EXTERN long unmappedzero;
+extern long unmappedzero;
EXTERN int maxstksize;
/*
@@ -98,7 +94,7 @@ void igen(Node*, Node*, Node*);
void agenr(Node *n, Node *a, Node *res);
vlong fieldoffset(Type*, Node*);
void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
+void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
@@ -169,3 +165,6 @@ int Yconv(Fmt*);
void listinit(void);
void zaddr(Biobuf*, Addr*, int);
+
+#pragma varargck type "D" Addr*
+#pragma varargck type "M" Addr*
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 3f5f47e7b..de100620b 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -4,6 +4,8 @@
#undef EXTERN
#define EXTERN
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -12,7 +14,6 @@ defframe(Prog *ptxt)
{
// fill in argument size
ptxt->to.type = D_CONST2;
- ptxt->reg = 0; // flags
ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
@@ -28,10 +29,10 @@ markautoused(Prog* p)
{
for (; p; p = p->link) {
if (p->from.name == D_AUTO && p->from.node)
- p->from.node->used++;
+ p->from.node->used = 1;
if (p->to.name == D_AUTO && p->to.node)
- p->to.node->used++;
+ p->to.node->used = 1;
}
}
@@ -544,7 +545,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
}
// test for shift being 0
- p1 = gins(ATST, &n1, N);
+ gins(ATST, &n1, N);
p3 = gbranch(ABEQ, T);
// test and fix up large shifts
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index 27c8be67d..b562ba888 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
void
@@ -266,54 +268,6 @@ dumpfuncs(void)
}
}
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
int
dsname(Sym *sym, int off, char *t, int n)
{
@@ -353,6 +307,7 @@ datastring(char *s, int len, Addr *a)
a->offset = widthptr+4; // skip header
a->reg = NREG;
a->sym = sym;
+ a->node = sym->def;
}
/*
@@ -371,6 +326,7 @@ datagostring(Strlit *sval, Addr *a)
a->offset = 0; // header
a->reg = NREG;
a->sym = sym;
+ a->node = sym->def;
}
void
@@ -379,6 +335,17 @@ gdata(Node *nam, Node *nr, int wid)
Prog *p;
vlong v;
+ if(nr->op == OLITERAL) {
+ switch(nr->val.ctype) {
+ case CTCPLX:
+ gdatacomplex(nam, nr->val.u.cval);
+ return;
+ case CTSTR:
+ gdatastring(nam, nr->val.u.sval);
+ return;
+ }
+ }
+
if(wid == 8 && is64(nr->type)) {
v = mpgetfix(nr->val.u.xval);
p = gins(ADATA, nam, nodintconst(v));
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index ddaf52a88..9acf93670 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
// TODO(kaib): Can make this bigger if we move
@@ -50,6 +52,10 @@ clearp(Prog *p)
pcloc++;
}
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
/*
* generate and return proc with p->as = as,
* linked into program. pc is next instruction.
@@ -59,10 +65,23 @@ prog(int as)
{
Prog *p;
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ p->reg = 0; // used for flags
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
if(lineno == 0) {
if(debug['K'])
@@ -71,10 +90,21 @@ prog(int as)
p->as = as;
p->lineno = lineno;
- p->link = pc;
return p;
}
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
/*
* generate a branch.
* t is ignored.
@@ -84,6 +114,8 @@ gbranch(int as, Type *t)
{
Prog *p;
+ USED(t);
+
p = prog(as);
p->to.type = D_BRANCH;
p->to.branch = P;
@@ -222,6 +254,10 @@ ggloblnod(Node *nam, int32 width)
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
+ if(nam->readonly)
+ p->reg = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->reg |= NOPTR;
}
void
@@ -238,6 +274,7 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.offset = width;
if(dupok)
p->reg = DUPOK;
+ p->reg |= RODATA;
}
int
@@ -315,6 +352,8 @@ anyregalloc(void)
return 0;
}
+uintptr regpc[REGALLOC_FMAX+1];
+
/*
* allocate register of type t, leave in n.
* if o != N, o is desired fixed register.
@@ -325,7 +364,7 @@ regalloc(Node *n, Type *t, Node *o)
{
int i, et, fixfree, floatfree;
- if(debug['r']) {
+ if(0 && debug['r']) {
fixfree = 0;
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
if(reg[i] == 0)
@@ -358,9 +397,12 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
}
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
- if(reg[i] == 0)
+ if(reg[i] == 0) {
+ regpc[i] = (uintptr)getcallerpc(&n);
goto out;
-
+ }
+ for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+ print("%d %p\n", i, regpc[i]);
yyerror("out of fixed registers");
goto err;
@@ -398,7 +440,7 @@ regfree(Node *n)
{
int i, fixfree, floatfree;
- if(debug['r']) {
+ if(0 && debug['r']) {
fixfree = 0;
for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
if(reg[i] == 0)
@@ -415,11 +457,13 @@ regfree(Node *n)
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
fatal("regfree: reg not allocated");
reg[i]--;
+ if(reg[i] == 0)
+ regpc[i] = 0;
}
/*
@@ -481,8 +525,15 @@ nodarg(Type *t, int fp)
fatal("nodarg: offset not computed for %T", t);
n->xoffset = t->width;
n->addable = 1;
+ n->orig = t->nname;
fp:
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
+
switch(fp) {
default:
fatal("nodarg %T %d", t, fp);
@@ -1066,7 +1117,8 @@ gins(int as, Node *f, Node *t)
if(f != N)
naddr(f, &af, 1);
if(t != N)
- naddr(t, &at, 1); p = prog(as);
+ naddr(t, &at, 1);
+ p = prog(as);
if(f != N)
p->from = af;
if(t != N)
@@ -1232,6 +1284,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->sym = n->left->sym;
a->type = D_OREG;
a->name = D_PARAM;
+ a->node = n->left->orig;
break;
case ONAME:
@@ -1242,9 +1295,11 @@ naddr(Node *n, Addr *a, int canemitcode)
a->etype = simtype[n->type->etype];
a->width = n->type->width;
}
- a->pun = n->pun;
a->offset = n->xoffset;
a->sym = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
if(a->sym == S)
a->sym = lookup(".noname");
if(n->method) {
@@ -1263,8 +1318,6 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->name = D_AUTO;
- if (n->sym)
- a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
@@ -1287,6 +1340,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
+ case CTRUNE:
a->sym = S;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
@@ -1307,6 +1361,16 @@ naddr(Node *n, Addr *a, int canemitcode)
}
break;
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ a->etype = TINT32;
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
+
case OLEN:
// len of string or slice
naddr(n->left, a, canemitcode);
@@ -1744,7 +1808,7 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
switch(n->op) {
case OLITERAL:
- if(n->val.ctype != CTINT)
+ if(!isconst(n, CTINT))
break;
v = mpgetfix(n->val.u.xval);
if(v >= 32000 || v <= -32000)
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index 0c6dbbf71..9bc3a9a9a 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
// TODO(kaib): make 5g/list.c congruent with 5l/list.c
@@ -57,7 +59,7 @@ Pconv(Fmt *fp)
switch(p->as) {
default:
snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
- if(p->reg == NREG)
+ if(p->reg == NREG && p->as != AGLOBL)
snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
p->loc, p->lineno, str1, &p->from, &p->to);
else
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index 6cc93db12..e87f5d697 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -29,6 +29,8 @@
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -45,6 +47,9 @@ peep(void)
Reg *r, *r1, *r2;
Prog *p, *p1;
int t;
+
+ p1 = nil;
+ USED(p1); // ... in unreachable code...
/*
* complete R structure
*/
@@ -115,12 +120,14 @@ loop1:
}
break;
+#ifdef NOTDEF
if(p->scond == C_SCOND_NONE)
if(regtyp(&p->to))
if(isdconst(&p->from)) {
constprop(&p->from, &p->to, r->s1);
}
break;
+#endif
}
}
if(t)
@@ -128,6 +135,7 @@ loop1:
return;
+#ifdef NOTDEF
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
switch(p->as) {
@@ -255,6 +263,7 @@ return;
// }
predicate();
+#endif
}
Reg*
@@ -1159,7 +1168,6 @@ copyu(Prog *p, Adr *v, Adr *s)
return 3;
return 0;
}
- return 0;
}
/*
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 2d2a6d01a..93724d032 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -29,6 +29,8 @@
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -40,6 +42,9 @@
int noreturn(Prog *p);
static int first = 0;
+static void fixjmp(Prog*);
+
+
Reg*
rega(void)
{
@@ -90,8 +95,8 @@ setoutvar(void)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
+//if(bany(ovar))
+//print("ovar = %Q\n", ovar);
}
void
@@ -112,19 +117,19 @@ setaddrs(Bits bit)
{
int i, n;
Var *v;
- Sym *s;
+ Node *node;
while(bany(&bit)) {
// convert each bit to a variable
i = bnum(bit);
- s = var[i].sym;
+ node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n)
+ if(v->node == node && v->name == n)
v->addr = 2;
}
}
@@ -169,6 +174,8 @@ regopt(Prog *firstp)
if(first == 0) {
fmtinstall('Q', Qconv);
}
+
+ fixjmp(firstp);
first++;
if(debug['K']) {
@@ -202,7 +209,7 @@ regopt(Prog *firstp)
nvar = NREGVAR;
memset(var, 0, NREGVAR*sizeof var[0]);
for(i=0; i<NREGVAR; i++)
- var[i].sym = lookup(regname[i]);
+ var[i].node = newname(lookup(regname[i]));
regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
for(z=0; z<BITS; z++) {
@@ -750,9 +757,9 @@ addmove(Reg *r, int bn, int rn, int f)
v = var + bn;
a = &p1->to;
- a->sym = v->sym;
a->name = v->name;
a->node = v->node;
+ a->sym = v->node->sym;
a->offset = v->offset;
a->etype = v->etype;
a->type = D_OREG;
@@ -838,11 +845,10 @@ mkvar(Reg *r, Adr *a)
int i, t, n, et, z, w, flag;
int32 o;
Bits bit;
- Sym *s;
+ Node *node;
// mark registers used
t = a->type;
- n = D_NONE;
flag = 0;
switch(t) {
@@ -909,10 +915,13 @@ mkvar(Reg *r, Adr *a)
break;
}
- s = a->sym;
- if(s == S)
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
goto none;
- if(s->name[0] == '.')
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
@@ -920,7 +929,7 @@ mkvar(Reg *r, Adr *a)
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n) {
+ if(v->node == node && v->name == n) {
if(v->offset == o)
if(v->etype == et)
if(v->width == w)
@@ -944,7 +953,7 @@ mkvar(Reg *r, Adr *a)
}
if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
+ if(debug['w'] > 1 && node)
fatal("variable not optimized: %D", a);
goto none;
}
@@ -953,17 +962,16 @@ mkvar(Reg *r, Adr *a)
nvar++;
//print("var %d %E %D %S\n", i, et, a, s);
v = var+i;
- v->sym = s;
v->offset = o;
v->name = n;
// v->gotype = a->gotype;
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
- v->node = a->node;
+ v->node = node;
if(debug['R'])
- print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
+ print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
@@ -1021,6 +1029,13 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
+
+ default:
+ // Work around for issue 1304:
+ // flush modified globals before each instruction.
+ for(z=0; z<BITS; z++)
+ cal.b[z] |= externs.b[z];
+ break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1156,10 +1171,12 @@ loopit(Reg *r, int32 nr)
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
+ // rpo2r[r->rpo] == r protects against considering dead code,
+ // which has r->rpo == 0.
+ if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
+ if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
@@ -1570,7 +1587,7 @@ dumpone(Reg *r)
if(bany(&r->refahead))
print(" ra:%Q ", r->refahead);
if(bany(&r->calbehind))
- print("cb:%Q ", r->calbehind);
+ print(" cb:%Q ", r->calbehind);
if(bany(&r->calahead))
print(" ca:%Q ", r->calahead);
if(bany(&r->regdiff))
@@ -1605,3 +1622,123 @@ dumpit(char *str, Reg *r0)
// }
}
}
+
+/*
+ * the code generator depends on being able to write out JMP (B)
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+ int n;
+
+ n = 0;
+ while(p != P && p->as == AB && p->to.type == D_BRANCH) {
+ if(++n > 10) {
+ *jmploop = 1;
+ break;
+ }
+ p = p->to.branch;
+ }
+ return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+ Prog *p;
+
+ for(p=firstp; p; p=p->link) {
+ if(p->regp != dead)
+ break;
+ p->regp = alive;
+ if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch)
+ mark(p->to.branch);
+ if(p->as == AB || p->as == ARET || (p->as == ABL && noreturn(p)))
+ break;
+ }
+}
+
+static void
+fixjmp(Prog *firstp)
+{
+ int jmploop;
+ Prog *p, *last;
+
+ if(debug['R'] && debug['v'])
+ print("\nfixjmp\n");
+
+ // pass 1: resolve jump to B, mark all code as dead.
+ jmploop = 0;
+ for(p=firstp; p; p=p->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n", p);
+ if(p->as != ABL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AB) {
+ p->to.branch = chasejmp(p->to.branch, &jmploop);
+ if(debug['R'] && debug['v'])
+ print("->%P\n", p);
+ }
+ p->regp = dead;
+ }
+ if(debug['R'] && debug['v'])
+ print("\n");
+
+ // pass 2: mark all reachable code alive
+ mark(firstp);
+
+ // pass 3: delete dead code (mostly JMPs).
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->regp == dead) {
+ if(p->link == P && p->as == ARET && last && last->as != ARET) {
+ // This is the final ARET, and the code so far doesn't have one.
+ // Let it stay.
+ } else {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+
+ // pass 4: elide JMP to next instruction.
+ // only safe if there are no jumps to JMPs anymore.
+ if(!jmploop) {
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->as == AB && p->to.type == D_BRANCH && p->to.branch == p->link) {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+ }
+
+ if(debug['R'] && debug['v']) {
+ print("\n");
+ for(p=firstp; p; p=p->link)
+ print("%P\n", p);
+ print("\n");
+ }
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index cf86ae48b..569536ebd 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -35,7 +35,8 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
-#define ALLTHUMBS (1<<3)
+#define RODATA (1<<3)
+#define NOPTR (1<<4)
#define REGRET 0
/* -1 disables use of REGARG */
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index 8489abc64..3f528d751 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -1,43 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=5l
-
-OFILES=\
- asm.$O\
- data.$O\
- elf.$O\
- enam.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- noop.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- prof.$O\
- softfloat.$O\
- span.$O\
- symtab.$O\
- go.$O\
-
-HFILES=\
- l.h\
- 5.out.h\
- ../ld/elf.h\
-
-include ../../Make.ccmd
-
-enam.c: 5.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
+include ../../Make.dist
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 5b7f6f111..b36a982d1 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -73,6 +73,9 @@ enum {
ElfStrShstrtab,
ElfStrRelPlt,
ElfStrPlt,
+ ElfStrNoteNetbsdIdent,
+ ElfStrNoPtrData,
+ ElfStrNoPtrBss,
NElfStr
};
@@ -90,6 +93,7 @@ needlib(char *name)
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
s = lookup(p, 0);
+ free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
return 1;
@@ -162,8 +166,12 @@ doelf(void)
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
+ elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
+ if(HEADTYPE == Hnetbsd)
+ elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gosymtab");
addstring(shstrtab, ".gopclntab");
@@ -232,7 +240,7 @@ doelf(void)
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s->reachable = 1;
- s->type = SELFROSECT;
+ s->type = SELFSECT; // writable
/*
* .dynamic table
@@ -251,6 +259,7 @@ doelf(void)
elfwritedynent(s, DT_PLTREL, DT_REL);
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
+ elfwritedynent(s, DT_DEBUG, 0);
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -293,7 +302,7 @@ asmb(void)
{
int32 t;
int a, dynsym;
- uint32 fo, symo, startva;
+ uint32 fo, symo, startva, resoff;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -321,11 +330,6 @@ asmb(void)
cseek(segdata.fileoff);
datblk(segdata.vaddr, segdata.filelen);
- /* output read-only data in text segment */
- sect = segtext.sect->next;
- cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
- datblk(sect->vaddr, sect->len);
-
if(iself) {
/* index of elf text section; needed by asmelfsym, double-checked below */
/* !debug['d'] causes extra sections before the .text section */
@@ -335,6 +339,8 @@ asmb(void)
if(elfverneed)
elftextsh += 2;
}
+ if(HEADTYPE == Hnetbsd)
+ elftextsh += 1;
}
/* output symbol table */
@@ -370,7 +376,7 @@ asmb(void)
cseek(symo);
if(iself) {
if(debug['v'])
- Bprint(&bso, "%5.2f elfsym\n", cputime());
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
asmelfsym();
cflush();
cwrite(elfstrdat, elfstrsize);
@@ -454,6 +460,7 @@ asmb(void)
eh = getElfEhdr();
fo = HEADR;
startva = INITTEXT - fo; /* va of byte 0 of file */
+ resoff = ELFRESERVE;
/* This null SHdr must appear before all others */
newElfShdr(elfstr[ElfStrEmpty]);
@@ -486,7 +493,7 @@ asmb(void)
sh->addralign = 1;
if(interpreter == nil)
interpreter = linuxdynld;
- elfinterp(sh, startva, interpreter);
+ resoff -= elfinterp(sh, startva, resoff, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
@@ -494,11 +501,24 @@ asmb(void)
phsh(ph, sh);
}
+ if(HEADTYPE == Hnetbsd) {
+ sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
+ sh->type = SHT_NOTE;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 4;
+ resoff -= elfnetbsdsig(sh, startva, resoff);
+
+ ph = newElfPhdr();
+ ph->type = PT_NOTE;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
elfphload(&segtext);
elfphload(&segdata);
/* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
/* S headers for dynamic linking */
sh = newElfShdr(elfstr[ElfStrGot]);
sh->type = SHT_PROGBITS;
@@ -589,7 +609,7 @@ asmb(void)
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
- if (!debug['s']) {
+ if(!debug['s']) {
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
sh->off = symo;
@@ -631,8 +651,10 @@ asmb(void)
a += elfwritehdr();
a += elfwritephdrs();
a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
+ a += elfwriteinterp(elfstr[ElfStrInterp]);
+ if(HEADTYPE == Hnetbsd)
+ a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
+ if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
}
@@ -1827,14 +1849,20 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case STYPE:
case SSTRING:
case SGOSTRING:
+ case SNOPTRDATA:
+ case SSYMTAB:
+ case SPCLNTAB:
if(!s->reachable)
continue;
put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
continue;
case SBSS:
+ case SNOPTRBSS:
if(!s->reachable)
continue;
+ if(s->np > 0)
+ diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
continue;
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
index aa7ccebfc..969f502a7 100644
--- a/src/cmd/5l/doc.go
+++ b/src/cmd/5l/doc.go
@@ -4,36 +4,10 @@
/*
-5l is a modified version of the Plan 9 linker. The original is documented at
+5l is the linker for the ARM.
+The $GOARCH for these tools is arm.
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the ARM, referred to by these tools as arm.
-It reads files in .5 format generated by 5g, 5c, and 5a and emits
-a binary called 5.out by default.
-
-Major changes include:
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--F
- Force use of software floating point.
- Also implied by setting GOARM=5 in the environment.
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_arm.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
+The flags are documented in ../ld/doc.go.
*/
package documentation
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index dabe93d37..b1a48ded8 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -143,6 +143,7 @@ struct Sym
int32 value;
int32 sig;
int32 size;
+ int32 align; // if non-zero, required alignment in bytes
uchar special;
uchar fnptr; // used as fn ptr
Sym* hash; // in hash table
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index fa838215b..7b623d78a 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -65,7 +65,7 @@ Pconv(Fmt *fp)
switch(a) {
default:
fmtprint(fp, "(%d)", p->line);
- if(p->reg == NREG)
+ if(p->reg == NREG && p->as != AGLOBL)
fmtprint(fp, " %A%C %D,%D",
a, p->scond, &p->from, &p->to);
else
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index eb44344f4..004f9f2fa 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -226,8 +226,7 @@ noops(void)
p->as = AMOVW;
p->scond = C_SCOND_LO;
p->from.type = D_CONST;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- p->from.offset = autosize+160;
+ p->from.offset = autosize;
p->to.type = D_REG;
p->to.reg = 1;
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index fc5806aac..a3f816160 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -81,7 +81,7 @@ void
main(int argc, char *argv[])
{
int c, i;
- char *p;
+ char *p, *name, *val;
Binit(&bso, 1, OWRITE);
listinit();
@@ -92,6 +92,7 @@ main(int argc, char *argv[])
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
+ nuxiinit();
p = getenv("GOARM");
if(p != nil && strcmp(p, "5") == 0)
@@ -136,6 +137,11 @@ main(int argc, char *argv[])
case 'V':
print("%cl version %s\n", thechar, getgoversion());
errorexit();
+ case 'X':
+ name = EARGF(usage());
+ val = EARGF(usage());
+ addstrdata(name, val);
+ break;
} ARGEND
USED(argc);
@@ -235,7 +241,6 @@ main(int argc, char *argv[])
histgen = 0;
pc = 0;
dtype = 4;
- nuxiinit();
version = 0;
cbp = buf.cbuf;
@@ -535,7 +540,7 @@ loop:
s->type = SBSS;
s->value = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
diag("redefinition: %s\n%P", s->name, p);
s->type = SBSS;
s->value = 0;
@@ -544,6 +549,10 @@ loop:
s->size = p->to.offset;
if(p->reg & DUPOK)
s->dupok = 1;
+ if(p->reg & RODATA)
+ s->type = SRODATA;
+ else if(p->reg & NOPTR)
+ s->type = SNOPTRBSS;
break;
case ADATA:
@@ -553,8 +562,8 @@ loop:
// redefinitions.
s = p->from.sym;
if(s->dupok) {
- if(debug['v'])
- Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
+// if(debug['v'])
+// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s->file == nil)
@@ -585,6 +594,10 @@ loop:
errorexit();
}
cursym = s;
+ if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) {
+ skip = 1;
+ goto casedef;
+ }
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(debug['v'])
@@ -592,13 +605,8 @@ loop:
return;
}
skip = 0;
- if(s->type != 0 && s->type != SXREF) {
- if(p->reg & DUPOK) {
- skip = 1;
- goto casedef;
- }
+ if(s->type != 0 && s->type != SXREF)
diag("redefinition: %s\n%P", s->name, p);
- }
if(etextp)
etextp->next = s;
else
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index c43049459..0f2afbd85 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -213,6 +213,8 @@ patch(void)
if((a == ABL || a == ABX || a == AB || a == ARET) &&
p->to.type != D_BRANCH && p->to.sym != S) {
s = p->to.sym;
+ if(s->text == nil)
+ continue;
switch(s->type) {
default:
diag("undefined: %s", s->name);
@@ -222,7 +224,8 @@ patch(void)
case STEXT:
p->to.offset = s->value;
p->to.type = D_BRANCH;
- break;
+ p->cond = s->text;
+ continue;
}
}
if(p->to.type != D_BRANCH)
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 4f799d17e..401107178 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define EXTERN
#include "l.h"
#include "../ld/lib.h"
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 2e1232a1a..13e1848e1 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -421,6 +421,8 @@ symaddr(Sym *s)
case SDATA:
case SBSS:
case SCONST:
+ case SNOPTRDATA:
+ case SNOPTRBSS:
break;
}
return v;
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
index 30180bd24..27290ddd7 100644
--- a/src/cmd/6a/Makefile
+++ b/src/cmd/6a/Makefile
@@ -1,25 +1,10 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
+include ../../Make.dist
-TARG=6a
+install: y.tab.h
-HFILES=\
- a.h\
- y.tab.h\
- ../6l/6.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../6l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
+y.tab.h: a.y
+ LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index c0fa4106e..8459ff323 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -429,6 +429,12 @@ imm:
$$.type = D_FCONST;
$$.dval = $3;
}
+| '$' '(' '-' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$4;
+ }
| '$' '-' LFCONST
{
$$ = nullgen;
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 42f4b1d11..e013bec2a 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -44,7 +44,11 @@ enum
int
systemtype(int sys)
{
+#ifdef _WIN32
+ return sys&Windows;
+#else
return sys&Plan9;
+#endif
}
int
@@ -392,6 +396,7 @@ struct
"IMULB", LTYPEI, AIMULB,
"IMULL", LTYPEI, AIMULL,
"IMULQ", LTYPEI, AIMULQ,
+ "IMUL3Q", LTYPEX, AIMUL3Q,
"IMULW", LTYPEI, AIMULW,
"INB", LTYPE0, AINB,
"INL", LTYPE0, AINL,
@@ -456,8 +461,8 @@ struct
"JGT", LTYPER, AJGT,
"JG", LTYPER, AJGT, /* alternate */
"JNLE", LTYPER, AJGT, /* alternate */
-
- "JCXZ", LTYPER, AJCXZ,
+ "JCXZL", LTYPER, AJCXZL,
+ "JCXZQ", LTYPER, AJCXZQ,
"JMP", LTYPEC, AJMP,
"LAHF", LTYPE0, ALAHF,
"LARL", LTYPE3, ALARL,
@@ -1251,17 +1256,13 @@ outhist(void)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
new file mode 100644
index 000000000..2da8a1fac
--- /dev/null
+++ b/src/cmd/6a/y.tab.c
@@ -0,0 +1,2730 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE0 = 258,
+ LTYPE1 = 259,
+ LTYPE2 = 260,
+ LTYPE3 = 261,
+ LTYPE4 = 262,
+ LTYPEC = 263,
+ LTYPED = 264,
+ LTYPEN = 265,
+ LTYPER = 266,
+ LTYPET = 267,
+ LTYPEG = 268,
+ LTYPES = 269,
+ LTYPEM = 270,
+ LTYPEI = 271,
+ LTYPEXC = 272,
+ LTYPEX = 273,
+ LTYPERT = 274,
+ LCONST = 275,
+ LFP = 276,
+ LPC = 277,
+ LSB = 278,
+ LBREG = 279,
+ LLREG = 280,
+ LSREG = 281,
+ LFREG = 282,
+ LMREG = 283,
+ LXREG = 284,
+ LFCONST = 285,
+ LSCONST = 286,
+ LSP = 287,
+ LNAME = 288,
+ LLAB = 289,
+ LVAR = 290
+ };
+#endif
+/* Tokens. */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPEG 268
+#define LTYPES 269
+#define LTYPEM 270
+#define LTYPEI 271
+#define LTYPEXC 272
+#define LTYPEX 273
+#define LTYPERT 274
+#define LCONST 275
+#define LFP 276
+#define LPC 277
+#define LSB 278
+#define LBREG 279
+#define LLREG 280
+#define LSREG 281
+#define LFREG 282
+#define LMREG 283
+#define LXREG 284
+#define LFCONST 285
+#define LSCONST 286
+#define LSP 287
+#define LNAME 288
+#define LLAB 289
+#define LVAR 290
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 37 "a.y"
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+/* Line 193 of yacc.c. */
+#line 182 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 195 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 548
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 54
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 40
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 131
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 260
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 290
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 52, 12, 5, 2,
+ 50, 51, 10, 8, 49, 9, 2, 11, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 46, 47,
+ 6, 48, 7, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 2, 53, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
+ 23, 26, 29, 33, 37, 40, 43, 46, 49, 52,
+ 55, 58, 61, 64, 67, 70, 73, 76, 79, 82,
+ 85, 88, 89, 91, 95, 99, 102, 104, 107, 109,
+ 112, 114, 120, 124, 130, 133, 135, 137, 139, 143,
+ 149, 153, 159, 162, 164, 168, 174, 180, 181, 183,
+ 187, 193, 195, 197, 199, 201, 204, 207, 209, 211,
+ 213, 215, 220, 223, 226, 228, 230, 232, 234, 236,
+ 238, 240, 243, 246, 249, 252, 255, 260, 266, 270,
+ 272, 274, 276, 281, 286, 291, 298, 308, 312, 316,
+ 322, 331, 333, 340, 346, 354, 355, 358, 361, 363,
+ 365, 367, 369, 371, 374, 377, 380, 384, 386, 389,
+ 393, 398, 400, 404, 408, 412, 416, 420, 425, 430,
+ 434, 438
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 55, 0, -1, -1, -1, 55, 56, 57, -1, -1,
+ 44, 46, 58, 57, -1, -1, 43, 46, 59, 57,
+ -1, 47, -1, 60, 47, -1, 1, 47, -1, 43,
+ 48, 93, -1, 45, 48, 93, -1, 13, 61, -1,
+ 14, 65, -1, 15, 64, -1, 16, 62, -1, 17,
+ 63, -1, 21, 66, -1, 19, 67, -1, 22, 68,
+ -1, 18, 69, -1, 20, 70, -1, 24, 71, -1,
+ 25, 72, -1, 26, 73, -1, 27, 74, -1, 28,
+ 75, -1, 29, 76, -1, 23, 77, -1, -1, 49,
+ -1, 80, 49, 78, -1, 78, 49, 80, -1, 80,
+ 49, -1, 80, -1, 49, 78, -1, 78, -1, 49,
+ 81, -1, 81, -1, 88, 11, 91, 49, 84, -1,
+ 85, 49, 83, -1, 85, 49, 91, 49, 83, -1,
+ 49, 79, -1, 79, -1, 61, -1, 65, -1, 80,
+ 49, 78, -1, 80, 49, 78, 46, 35, -1, 80,
+ 49, 78, -1, 80, 49, 78, 46, 36, -1, 80,
+ 49, -1, 80, -1, 80, 49, 78, -1, 82, 49,
+ 78, 49, 91, -1, 84, 49, 78, 49, 82, -1,
+ -1, 84, -1, 85, 49, 84, -1, 85, 49, 91,
+ 49, 84, -1, 82, -1, 85, -1, 81, -1, 87,
+ -1, 10, 82, -1, 10, 86, -1, 82, -1, 86,
+ -1, 78, -1, 84, -1, 91, 50, 32, 51, -1,
+ 43, 89, -1, 44, 89, -1, 34, -1, 37, -1,
+ 35, -1, 38, -1, 42, -1, 36, -1, 39, -1,
+ 52, 92, -1, 52, 91, -1, 52, 88, -1, 52,
+ 41, -1, 52, 40, -1, 52, 50, 40, 51, -1,
+ 52, 50, 9, 40, 51, -1, 52, 9, 40, -1,
+ 86, -1, 87, -1, 91, -1, 91, 50, 35, 51,
+ -1, 91, 50, 42, 51, -1, 91, 50, 36, 51,
+ -1, 91, 50, 35, 10, 91, 51, -1, 91, 50,
+ 35, 51, 50, 35, 10, 91, 51, -1, 50, 35,
+ 51, -1, 50, 42, 51, -1, 50, 35, 10, 91,
+ 51, -1, 50, 35, 51, 50, 35, 10, 91, 51,
+ -1, 88, -1, 88, 50, 35, 10, 91, 51, -1,
+ 43, 89, 50, 90, 51, -1, 43, 6, 7, 89,
+ 50, 33, 51, -1, -1, 8, 91, -1, 9, 91,
+ -1, 33, -1, 42, -1, 31, -1, 30, -1, 45,
+ -1, 9, 91, -1, 8, 91, -1, 53, 91, -1,
+ 50, 93, 51, -1, 30, -1, 9, 30, -1, 30,
+ 9, 30, -1, 9, 30, 9, 30, -1, 91, -1,
+ 93, 8, 93, -1, 93, 9, 93, -1, 93, 10,
+ 93, -1, 93, 11, 93, -1, 93, 12, 93, -1,
+ 93, 6, 6, 93, -1, 93, 7, 7, 93, -1,
+ 93, 5, 93, -1, 93, 4, 93, -1, 93, 3,
+ 93, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 64, 64, 66, 65, 73, 72, 80, 79, 85,
+ 86, 87, 90, 95, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 120, 124, 131, 138, 145, 150, 157, 162, 169,
+ 174, 181, 189, 194, 202, 207, 214, 215, 218, 223,
+ 233, 238, 248, 253, 258, 265, 273, 283, 287, 294,
+ 299, 307, 308, 311, 312, 313, 317, 321, 322, 325,
+ 326, 329, 335, 344, 353, 358, 363, 368, 373, 378,
+ 383, 389, 397, 403, 414, 420, 426, 432, 438, 446,
+ 447, 450, 456, 462, 468, 474, 483, 492, 497, 502,
+ 510, 520, 524, 533, 540, 549, 552, 556, 562, 563,
+ 567, 570, 571, 575, 579, 583, 587, 593, 597, 601,
+ 606, 613, 614, 618, 622, 626, 630, 634, 638, 642,
+ 646, 650
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
+ "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPEG",
+ "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT", "LCONST",
+ "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG", "LMREG",
+ "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
+ "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
+ "line", "@2", "@3", "inst", "nonnon", "rimrem", "remrim", "rimnon",
+ "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4", "spec5", "spec6",
+ "spec7", "spec8", "spec9", "spec10", "spec11", "rem", "rom", "rim",
+ "rel", "reg", "imm2", "imm", "mem", "omem", "nmem", "nam", "offset",
+ "pointer", "con", "con2", "expr", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
+ 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 58, 59, 61, 44,
+ 40, 41, 36, 126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 54, 55, 56, 55, 58, 57, 59, 57, 57,
+ 57, 57, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 61, 61, 62, 63, 64, 64, 65, 65, 66,
+ 66, 67, 68, 68, 69, 69, 70, 70, 71, 71,
+ 72, 72, 73, 73, 73, 74, 75, 76, 76, 77,
+ 77, 78, 78, 79, 79, 79, 79, 79, 79, 80,
+ 80, 81, 81, 81, 82, 82, 82, 82, 82, 82,
+ 82, 83, 84, 84, 84, 84, 84, 84, 84, 85,
+ 85, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 87, 87, 88, 88, 89, 89, 89, 90, 90,
+ 90, 91, 91, 91, 91, 91, 91, 92, 92, 92,
+ 92, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 0, 3, 0, 4, 0, 4, 1,
+ 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 0, 1, 3, 3, 2, 1, 2, 1, 2,
+ 1, 5, 3, 5, 2, 1, 1, 1, 3, 5,
+ 3, 5, 2, 1, 3, 5, 5, 0, 1, 3,
+ 5, 1, 1, 1, 1, 2, 2, 1, 1, 1,
+ 1, 4, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 4, 5, 3, 1,
+ 1, 1, 4, 4, 4, 6, 9, 3, 3, 5,
+ 8, 1, 6, 5, 7, 0, 2, 2, 1, 1,
+ 1, 1, 1, 2, 2, 2, 3, 1, 2, 3,
+ 4, 1, 3, 3, 3, 3, 3, 4, 4, 3,
+ 3, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 3, 1, 0, 0, 31, 0, 0, 0, 0,
+ 0, 0, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 57, 0, 0, 0, 9, 4, 0, 11, 32,
+ 14, 0, 0, 111, 74, 76, 79, 75, 77, 80,
+ 78, 105, 112, 0, 0, 0, 15, 38, 61, 62,
+ 89, 90, 101, 91, 0, 16, 69, 36, 70, 17,
+ 0, 18, 0, 0, 105, 105, 0, 22, 45, 63,
+ 67, 68, 64, 91, 20, 0, 32, 46, 47, 23,
+ 105, 0, 0, 19, 40, 0, 21, 0, 30, 0,
+ 24, 0, 25, 0, 26, 53, 27, 0, 28, 0,
+ 29, 58, 7, 0, 5, 0, 10, 114, 113, 0,
+ 0, 0, 0, 37, 0, 0, 121, 0, 115, 0,
+ 0, 0, 85, 84, 0, 83, 82, 35, 0, 0,
+ 65, 66, 72, 73, 44, 0, 0, 72, 39, 0,
+ 0, 0, 0, 0, 52, 0, 0, 0, 12, 0,
+ 13, 105, 106, 107, 0, 0, 97, 98, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 116, 0,
+ 0, 0, 0, 88, 0, 0, 33, 34, 0, 0,
+ 0, 42, 0, 59, 0, 48, 50, 54, 0, 0,
+ 8, 6, 0, 110, 108, 109, 0, 0, 0, 131,
+ 130, 129, 0, 0, 122, 123, 124, 125, 126, 0,
+ 0, 92, 94, 93, 0, 86, 71, 0, 0, 117,
+ 81, 0, 0, 0, 0, 0, 0, 0, 103, 99,
+ 0, 127, 128, 0, 0, 0, 87, 41, 118, 0,
+ 43, 60, 49, 51, 55, 56, 0, 0, 102, 95,
+ 0, 0, 119, 104, 0, 0, 120, 100, 0, 96
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 3, 26, 149, 147, 27, 30, 59, 61,
+ 55, 46, 83, 74, 86, 67, 79, 90, 92, 94,
+ 96, 98, 100, 88, 56, 68, 57, 69, 48, 181,
+ 58, 49, 50, 51, 52, 112, 196, 53, 220, 117
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -97
+static const yytype_int16 yypact[] =
+{
+ -97, 29, -97, 206, -39, -36, 254, 278, 278, 326,
+ 230, 15, 302, 59, 412, 412, 278, 278, 278, 82,
+ -20, -20, -22, -6, 2, -97, -97, 12, -97, -97,
+ -97, 476, 476, -97, -97, -97, -97, -97, -97, -97,
+ -97, 88, -97, 326, 366, 476, -97, -97, -97, -97,
+ -97, -97, 14, 16, 364, -97, -97, 33, -97, -97,
+ 39, -97, 41, 350, 88, 11, 152, -97, -97, -97,
+ -97, -97, -97, 31, -97, 51, 326, -97, -97, -97,
+ 11, 382, 476, -97, -97, 42, -97, 50, -97, 56,
+ -97, 58, -97, 61, -97, 64, -97, 66, -97, 79,
+ -97, -97, -97, 476, -97, 476, -97, -97, -97, 84,
+ 476, 476, 92, -97, 18, 78, -97, 129, -97, 108,
+ -5, 414, -97, -97, 421, -97, -97, -97, 326, 278,
+ -97, -97, 92, -97, -97, 13, 476, -97, -97, 112,
+ 428, 438, 326, 326, 326, 326, 326, 206, 527, 206,
+ 527, 11, -97, -97, 10, 476, 96, -97, 476, 476,
+ 476, 141, 144, 476, 476, 476, 476, 476, -97, 142,
+ 23, 126, 127, -97, 467, 128, -97, -97, 130, 110,
+ 8, -97, 114, -97, 134, 138, 139, -97, 149, 154,
+ -97, -97, 163, -97, -97, -97, 153, 165, 179, 536,
+ 493, 159, 476, 476, 65, 65, -97, -97, -97, 476,
+ 476, 168, -97, -97, 185, -97, -97, -20, 211, 233,
+ -97, 191, -20, 209, 210, 476, 82, 214, -97, -97,
+ 238, 200, 200, 201, 203, 220, -97, -97, 247, 227,
+ -97, -97, -97, -97, -97, -97, 207, 476, -97, -97,
+ 249, 231, -97, -97, 219, 476, -97, -97, 225, -97
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -97, -97, -97, -96, -97, -97, -97, 259, -97, -97,
+ -97, 265, -97, -97, -97, -97, -97, -97, -97, -97,
+ -97, -97, -97, -97, 30, 212, -2, -11, -9, 60,
+ -16, 32, -3, -1, 7, -53, -97, -10, -97, -80
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+ 73, 70, 84, 85, 99, 101, 60, 71, 28, 72,
+ 97, 132, 133, 29, 91, 93, 95, 218, 75, 110,
+ 111, 107, 108, 148, 102, 150, 103, 137, 155, 2,
+ 170, 171, 54, 210, 116, 118, 47, 172, 219, 62,
+ 104, 193, 47, 194, 126, 178, 87, 89, 170, 171,
+ 105, 190, 195, 191, 130, 172, 73, 70, 41, 106,
+ 131, 125, 136, 71, 119, 72, 120, 31, 32, 156,
+ 138, 85, 116, 113, 211, 165, 166, 167, 199, 200,
+ 201, 135, 127, 204, 205, 206, 207, 208, 128, 33,
+ 129, 151, 139, 116, 109, 116, 110, 111, 192, 140,
+ 152, 153, 80, 65, 42, 141, 113, 142, 81, 82,
+ 143, 108, 45, 144, 116, 145, 34, 35, 36, 37,
+ 38, 39, 231, 232, 40, 183, 179, 177, 146, 157,
+ 182, 184, 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 154, 169, 178, 197, 198, 202, 116, 116,
+ 116, 203, 209, 116, 116, 116, 116, 116, 176, 217,
+ 31, 32, 63, 221, 108, 161, 162, 163, 164, 165,
+ 166, 167, 185, 186, 187, 188, 189, 212, 213, 215,
+ 168, 216, 33, 222, 223, 224, 34, 35, 36, 37,
+ 38, 39, 116, 116, 40, 64, 65, 42, 225, 233,
+ 234, 237, 44, 226, 228, 45, 241, 4, 163, 164,
+ 165, 166, 167, 227, 230, 244, 229, 245, 235, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 236, 254, 31, 32,
+ 63, 238, 239, 180, 242, 258, 243, 246, 247, 22,
+ 23, 24, 248, 25, 249, 250, 251, 252, 253, 255,
+ 33, 256, 31, 32, 34, 35, 36, 37, 38, 39,
+ 257, 77, 40, 64, 65, 42, 259, 78, 134, 66,
+ 44, 240, 0, 45, 33, 0, 31, 32, 34, 35,
+ 36, 37, 38, 39, 0, 0, 40, 41, 0, 42,
+ 0, 0, 0, 43, 44, 0, 0, 45, 33, 0,
+ 31, 32, 34, 35, 36, 37, 38, 39, 0, 0,
+ 40, 41, 0, 42, 0, 0, 0, 0, 44, 0,
+ 54, 45, 33, 0, 31, 32, 34, 35, 36, 37,
+ 38, 39, 0, 0, 40, 41, 0, 42, 0, 0,
+ 0, 76, 44, 0, 0, 45, 33, 0, 31, 32,
+ 34, 35, 36, 37, 38, 39, 0, 0, 40, 41,
+ 0, 42, 31, 121, 31, 32, 44, 0, 0, 45,
+ 33, 0, 0, 0, 34, 35, 36, 37, 38, 39,
+ 31, 32, 40, 0, 33, 42, 33, 0, 0, 0,
+ 44, 114, 0, 45, 122, 123, 0, 41, 115, 42,
+ 0, 42, 33, 0, 124, 0, 82, 45, 0, 45,
+ 31, 32, 31, 32, 0, 80, 65, 42, 0, 31,
+ 174, 0, 82, 0, 0, 45, 31, 32, 0, 0,
+ 0, 0, 33, 0, 33, 0, 31, 32, 0, 0,
+ 0, 33, 0, 0, 173, 41, 0, 42, 33, 42,
+ 0, 175, 44, 0, 82, 45, 42, 45, 33, 0,
+ 0, 82, 0, 42, 45, 31, 32, 0, 82, 0,
+ 180, 45, 0, 42, 31, 32, 0, 0, 82, 0,
+ 54, 45, 0, 0, 0, 0, 0, 33, 160, 161,
+ 162, 163, 164, 165, 166, 167, 33, 214, 0, 0,
+ 0, 0, 42, 0, 0, 0, 0, 82, 0, 0,
+ 45, 42, 0, 0, 0, 0, 82, 0, 0, 45,
+ 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 159, 160, 161, 162, 163, 164, 165, 166, 167
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 10, 10, 13, 13, 20, 21, 8, 10, 47, 10,
+ 19, 64, 65, 49, 16, 17, 18, 9, 11, 8,
+ 9, 31, 32, 103, 46, 105, 48, 80, 10, 0,
+ 35, 36, 52, 10, 44, 45, 6, 42, 30, 9,
+ 46, 31, 12, 33, 54, 32, 14, 15, 35, 36,
+ 48, 147, 42, 149, 63, 42, 66, 66, 43, 47,
+ 63, 54, 11, 66, 50, 66, 50, 8, 9, 51,
+ 81, 81, 82, 43, 51, 10, 11, 12, 158, 159,
+ 160, 50, 49, 163, 164, 165, 166, 167, 49, 30,
+ 49, 7, 50, 103, 6, 105, 8, 9, 151, 49,
+ 110, 111, 43, 44, 45, 49, 76, 49, 49, 50,
+ 49, 121, 53, 49, 124, 49, 34, 35, 36, 37,
+ 38, 39, 202, 203, 42, 141, 136, 129, 49, 51,
+ 140, 141, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 50, 35, 32, 155, 50, 6, 158, 159,
+ 160, 7, 10, 163, 164, 165, 166, 167, 128, 49,
+ 8, 9, 10, 49, 174, 6, 7, 8, 9, 10,
+ 11, 12, 142, 143, 144, 145, 146, 51, 51, 51,
+ 51, 51, 30, 49, 46, 46, 34, 35, 36, 37,
+ 38, 39, 202, 203, 42, 43, 44, 45, 49, 209,
+ 210, 217, 50, 49, 51, 53, 222, 1, 8, 9,
+ 10, 11, 12, 50, 35, 225, 51, 226, 50, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 51, 247, 8, 9,
+ 10, 30, 9, 52, 35, 255, 36, 33, 10, 43,
+ 44, 45, 51, 47, 51, 35, 9, 30, 51, 10,
+ 30, 30, 8, 9, 34, 35, 36, 37, 38, 39,
+ 51, 12, 42, 43, 44, 45, 51, 12, 66, 49,
+ 50, 221, -1, 53, 30, -1, 8, 9, 34, 35,
+ 36, 37, 38, 39, -1, -1, 42, 43, -1, 45,
+ -1, -1, -1, 49, 50, -1, -1, 53, 30, -1,
+ 8, 9, 34, 35, 36, 37, 38, 39, -1, -1,
+ 42, 43, -1, 45, -1, -1, -1, -1, 50, -1,
+ 52, 53, 30, -1, 8, 9, 34, 35, 36, 37,
+ 38, 39, -1, -1, 42, 43, -1, 45, -1, -1,
+ -1, 49, 50, -1, -1, 53, 30, -1, 8, 9,
+ 34, 35, 36, 37, 38, 39, -1, -1, 42, 43,
+ -1, 45, 8, 9, 8, 9, 50, -1, -1, 53,
+ 30, -1, -1, -1, 34, 35, 36, 37, 38, 39,
+ 8, 9, 42, -1, 30, 45, 30, -1, -1, -1,
+ 50, 35, -1, 53, 40, 41, -1, 43, 42, 45,
+ -1, 45, 30, -1, 50, -1, 50, 53, -1, 53,
+ 8, 9, 8, 9, -1, 43, 44, 45, -1, 8,
+ 9, -1, 50, -1, -1, 53, 8, 9, -1, -1,
+ -1, -1, 30, -1, 30, -1, 8, 9, -1, -1,
+ -1, 30, -1, -1, 40, 43, -1, 45, 30, 45,
+ -1, 40, 50, -1, 50, 53, 45, 53, 30, -1,
+ -1, 50, -1, 45, 53, 8, 9, -1, 50, -1,
+ 52, 53, -1, 45, 8, 9, -1, -1, 50, -1,
+ 52, 53, -1, -1, -1, -1, -1, 30, 5, 6,
+ 7, 8, 9, 10, 11, 12, 30, 40, -1, -1,
+ -1, -1, 45, -1, -1, -1, -1, 50, -1, -1,
+ 53, 45, -1, -1, -1, -1, 50, -1, -1, 53,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 55, 0, 56, 1, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 43, 44, 45, 47, 57, 60, 47, 49,
+ 61, 8, 9, 30, 34, 35, 36, 37, 38, 39,
+ 42, 43, 45, 49, 50, 53, 65, 78, 82, 85,
+ 86, 87, 88, 91, 52, 64, 78, 80, 84, 62,
+ 80, 63, 78, 10, 43, 44, 49, 69, 79, 81,
+ 82, 86, 87, 91, 67, 88, 49, 61, 65, 70,
+ 43, 49, 50, 66, 81, 91, 68, 85, 77, 85,
+ 71, 80, 72, 80, 73, 80, 74, 82, 75, 84,
+ 76, 84, 46, 48, 46, 48, 47, 91, 91, 6,
+ 8, 9, 89, 78, 35, 42, 91, 93, 91, 50,
+ 50, 9, 40, 41, 50, 88, 91, 49, 49, 49,
+ 82, 86, 89, 89, 79, 50, 11, 89, 81, 50,
+ 49, 49, 49, 49, 49, 49, 49, 59, 93, 58,
+ 93, 7, 91, 91, 50, 10, 51, 51, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 51, 35,
+ 35, 36, 42, 40, 9, 40, 78, 80, 32, 91,
+ 52, 83, 91, 84, 91, 78, 78, 78, 78, 78,
+ 57, 57, 89, 31, 33, 42, 90, 91, 50, 93,
+ 93, 93, 6, 7, 93, 93, 93, 93, 93, 10,
+ 10, 51, 51, 51, 40, 51, 51, 49, 9, 30,
+ 92, 49, 49, 46, 46, 49, 49, 50, 51, 51,
+ 35, 93, 93, 91, 91, 50, 51, 84, 30, 9,
+ 83, 84, 35, 36, 91, 82, 33, 10, 51, 51,
+ 35, 9, 30, 51, 91, 10, 30, 51, 91, 51
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+#line 66 "a.y"
+ {
+ stmtline = lineno;
+ }
+ break;
+
+ case 5:
+#line 73 "a.y"
+ {
+ if((yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 7:
+#line 80 "a.y"
+ {
+ (yyvsp[(1) - (2)].sym)->type = LLAB;
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 12:
+#line 91 "a.y"
+ {
+ (yyvsp[(1) - (3)].sym)->type = LVAR;
+ (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 13:
+#line 96 "a.y"
+ {
+ if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
+ yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
+ (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 14:
+#line 101 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 15:
+#line 102 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 16:
+#line 103 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 17:
+#line 104 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 18:
+#line 105 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 19:
+#line 106 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 20:
+#line 107 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 21:
+#line 108 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 22:
+#line 109 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 23:
+#line 110 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 24:
+#line 111 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 25:
+#line 112 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 26:
+#line 113 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 27:
+#line 114 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 28:
+#line 115 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 29:
+#line 116 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 30:
+#line 117 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 31:
+#line 120 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 32:
+#line 125 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 33:
+#line 132 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 34:
+#line 139 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 35:
+#line 146 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 36:
+#line 151 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 37:
+#line 158 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 38:
+#line 163 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 39:
+#line 170 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 40:
+#line 175 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 41:
+#line 182 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 42:
+#line 190 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 43:
+#line 195 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 44:
+#line 203 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 45:
+#line 208 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 48:
+#line 219 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 49:
+#line 224 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
+ if((yyval.gen2).from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval);
+ }
+ break;
+
+ case 50:
+#line 234 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 51:
+#line 239 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
+ if((yyval.gen2).to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval);
+ }
+ break;
+
+ case 52:
+#line 249 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 53:
+#line 254 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 54:
+#line 259 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 55:
+#line 266 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
+ (yyval.gen2).to.offset = (yyvsp[(5) - (5)].lval);
+ }
+ break;
+
+ case 56:
+#line 274 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(3) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ if((yyvsp[(1) - (5)].gen).type != D_CONST)
+ yyerror("illegal constant");
+ (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset;
+ }
+ break;
+
+ case 57:
+#line 283 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 58:
+#line 288 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 59:
+#line 295 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 60:
+#line 300 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 65:
+#line 314 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 66:
+#line 318 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 71:
+#line 330 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ }
+ break;
+
+ case 72:
+#line 336 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 73:
+#line 345 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 74:
+#line 354 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 75:
+#line 359 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 76:
+#line 364 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 77:
+#line 369 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 78:
+#line 374 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SP;
+ }
+ break;
+
+ case 79:
+#line 379 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 80:
+#line 384 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 81:
+#line 390 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 82:
+#line 398 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 83:
+#line 404 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.gen).index = (yyvsp[(2) - (2)].gen).type;
+ (yyval.gen).type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+ break;
+
+ case 84:
+#line 415 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SCONST;
+ memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ }
+ break;
+
+ case 85:
+#line 421 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ }
+ break;
+
+ case 86:
+#line 427 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = (yyvsp[(3) - (4)].dval);
+ }
+ break;
+
+ case 87:
+#line 433 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = -(yyvsp[(4) - (5)].dval);
+ }
+ break;
+
+ case 88:
+#line 439 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ }
+ break;
+
+ case 91:
+#line 451 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 92:
+#line 457 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 93:
+#line 463 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_SP;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 94:
+#line 469 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 95:
+#line 475 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).offset = (yyvsp[(1) - (6)].lval);
+ (yyval.gen).index = (yyvsp[(3) - (6)].lval);
+ (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 96:
+#line 484 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.gen).index = (yyvsp[(6) - (9)].lval);
+ (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 97:
+#line 493 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 98:
+#line 498 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_SP;
+ }
+ break;
+
+ case 99:
+#line 503 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).index = (yyvsp[(2) - (5)].lval);
+ (yyval.gen).scale = (yyvsp[(4) - (5)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 100:
+#line 511 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+ (yyval.gen).index = (yyvsp[(5) - (8)].lval);
+ (yyval.gen).scale = (yyvsp[(7) - (8)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 101:
+#line 521 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 102:
+#line 525 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (6)].gen);
+ (yyval.gen).index = (yyvsp[(3) - (6)].lval);
+ (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 103:
+#line 534 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(4) - (5)].lval);
+ (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ }
+ break;
+
+ case 104:
+#line 541 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_STATIC;
+ (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
+ (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ }
+ break;
+
+ case 105:
+#line 549 "a.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 106:
+#line 553 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 107:
+#line 557 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 109:
+#line 564 "a.y"
+ {
+ (yyval.lval) = D_AUTO;
+ }
+ break;
+
+ case 112:
+#line 572 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+ }
+ break;
+
+ case 113:
+#line 576 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 114:
+#line 580 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 115:
+#line 584 "a.y"
+ {
+ (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 116:
+#line 588 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 117:
+#line 594 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].lval) & 0xffffffffLL;
+ }
+ break;
+
+ case 118:
+#line 598 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval) & 0xffffffffLL;
+ }
+ break;
+
+ case 119:
+#line 602 "a.y"
+ {
+ (yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
+ (((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
+ }
+ break;
+
+ case 120:
+#line 607 "a.y"
+ {
+ (yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
+ (((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
+ }
+ break;
+
+ case 122:
+#line 615 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 123:
+#line 619 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 124:
+#line 623 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 125:
+#line 627 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 126:
+#line 631 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 127:
+#line 635 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 128:
+#line 639 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 129:
+#line 643 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 130:
+#line 647 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 131:
+#line 651 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 2517 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h
new file mode 100644
index 000000000..3cca766d3
--- /dev/null
+++ b/src/cmd/6a/y.tab.h
@@ -0,0 +1,135 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE0 = 258,
+ LTYPE1 = 259,
+ LTYPE2 = 260,
+ LTYPE3 = 261,
+ LTYPE4 = 262,
+ LTYPEC = 263,
+ LTYPED = 264,
+ LTYPEN = 265,
+ LTYPER = 266,
+ LTYPET = 267,
+ LTYPEG = 268,
+ LTYPES = 269,
+ LTYPEM = 270,
+ LTYPEI = 271,
+ LTYPEXC = 272,
+ LTYPEX = 273,
+ LTYPERT = 274,
+ LCONST = 275,
+ LFP = 276,
+ LPC = 277,
+ LSB = 278,
+ LBREG = 279,
+ LLREG = 280,
+ LSREG = 281,
+ LFREG = 282,
+ LMREG = 283,
+ LXREG = 284,
+ LFCONST = 285,
+ LSCONST = 286,
+ LSP = 287,
+ LNAME = 288,
+ LLAB = 289,
+ LVAR = 290
+ };
+#endif
+/* Tokens. */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPEG 268
+#define LTYPES 269
+#define LTYPEM 270
+#define LTYPEI 271
+#define LTYPEXC 272
+#define LTYPEX 273
+#define LTYPERT 274
+#define LCONST 275
+#define LFP 276
+#define LPC 277
+#define LSB 278
+#define LBREG 279
+#define LLREG 280
+#define LSREG 281
+#define LFREG 282
+#define LMREG 283
+#define LXREG 284
+#define LFCONST 285
+#define LSCONST 286
+#define LSP 287
+#define LNAME 288
+#define LLAB 289
+#define LVAR 290
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 37 "a.y"
+{
+ Sym *sym;
+ vlong lval;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+}
+/* Line 1529 of yacc.c. */
+#line 128 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
index 484e16def..3f528d751 100644
--- a/src/cmd/6c/Makefile
+++ b/src/cmd/6c/Makefile
@@ -1,36 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6c
-
-HFILES=\
- gc.h\
- ../6l/6.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- list.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- pgen.$O\
- pswt.$O\
- div.$O\
- mul.$O\
- reg.$O\
- peep.$O\
- machcap.$O\
- ../6l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
index 7f717dcbb..71822586c 100644
--- a/src/cmd/6c/cgen.c
+++ b/src/cmd/6c/cgen.c
@@ -1237,11 +1237,12 @@ void
boolgen(Node *n, int true, Node *nn)
{
int o;
- Prog *p1, *p2;
+ Prog *p1, *p2, *p3;
Node *l, *r, nod, nod1;
int32 curs;
if(debug['g']) {
+ print("boolgen %d\n", true);
prtree(nn, "boolgen lhs");
prtree(n, "boolgen");
}
@@ -1353,6 +1354,15 @@ boolgen(Node *n, int true, Node *nn)
case OLO:
case OLS:
o = n->op;
+ if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
+ // Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
+ // Jump around instead.
+ boolgen(n, 0, Z);
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ goto com;
+ }
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
@@ -1367,6 +1377,10 @@ boolgen(Node *n, int true, Node *nn)
break;
}
if(immconst(l)) {
+ // NOTE: Reversing the comparison here is wrong
+ // for floating point ordering comparisons involving NaN,
+ // but we don't have any of those yet so we don't
+ // bother worrying about it.
o = invrel[relindex(o)];
/* bad, 13 is address of external that becomes constant */
if(r->addable < INDEXED || r->addable == 13) {
@@ -1388,10 +1402,11 @@ boolgen(Node *n, int true, Node *nn)
cgen(r, &nod1);
gopcode(o, l->type, &nod, &nod1);
regfree(&nod1);
- } else
+ } else {
gopcode(o, l->type, &nod, r);
+ }
regfree(&nod);
- goto com;
+ goto fixfloat;
}
regalloc(&nod, r, nn);
cgen(r, &nod);
@@ -1406,6 +1421,33 @@ boolgen(Node *n, int true, Node *nn)
} else
gopcode(o, l->type, l, &nod);
regfree(&nod);
+ fixfloat:
+ if(typefd[l->type->etype]) {
+ switch(o) {
+ case OEQ:
+ // Already emitted AJEQ; want AJEQ and AJPC.
+ p1 = p;
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gins(AJPC, Z, Z);
+ patch(p2, pc);
+ break;
+
+ case ONE:
+ // Already emitted AJNE; want AJNE or AJPS.
+ p1 = p;
+ gins(AJPS, Z, Z);
+ p2 = p;
+ gbranch(OGOTO);
+ p3 = p;
+ patch(p1, pc);
+ patch(p2, pc);
+ gbranch(OGOTO);
+ patch(p3, pc);
+ break;
+ }
+ }
com:
if(nn != Z) {
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
index 0c23b115c..b0081abb5 100644
--- a/src/cmd/6c/gc.h
+++ b/src/cmd/6c/gc.h
@@ -299,7 +299,8 @@ void gpseudo(int, Sym*, Node*);
int swcmp(const void*, const void*);
void doswit(Node*);
void swit1(C1*, int, int32, Node*);
-void cas(void);
+void swit2(C1*, int, int32, Node*);
+void newcase(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
int32 outstring(char*, int32);
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index d7a917043..f16d0f78a 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -33,6 +33,21 @@
void
swit1(C1 *q, int nc, int32 def, Node *n)
{
+ Node nreg;
+
+ regalloc(&nreg, n, Z);
+ if(typev[n->type->etype])
+ nreg.type = types[TVLONG];
+ else
+ nreg.type = types[TLONG];
+ cgen(n, &nreg);
+ swit2(q, nc, def, &nreg);
+ regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
C1 *r;
int i;
Prog *sp;
@@ -58,12 +73,12 @@ swit1(C1 *q, int nc, int32 def, Node *n)
gbranch(OGOTO);
p->as = AJEQ;
patch(p, r->label);
- swit1(q, i, def, n);
+ swit2(q, i, def, n);
if(debug['W'])
print("case < %.8llux\n", r->val);
patch(sp, pc);
- swit1(r+1, nc-i-1, def, n);
+ swit2(r+1, nc-i-1, def, n);
}
void
@@ -331,17 +346,13 @@ outhist(Biobuf *b)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index 12fc5b498..2cb8c1585 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -158,7 +158,9 @@ gclean(void)
continue;
if(s->type == types[TENUM])
continue;
+ textflag = s->dataflag;
gpseudo(AGLOBL, s, nodconst(s->type->width));
+ textflag = 0;
}
nextpc();
p->as = AEND;
@@ -411,7 +413,7 @@ regfree(Node *n)
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
i = n->reg;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
goto err;
if(reg[i] <= 0)
goto err;
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
index 64fa15399..3f528d751 100644
--- a/src/cmd/6g/Makefile
+++ b/src/cmd/6g/Makefile
@@ -1,35 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6g
-
-HFILES=\
- ../gc/go.h\
- ../6l/6.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../6l/enam.$O\
- cgen.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 24f88a416..00334e71b 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
/*
@@ -123,6 +125,9 @@ cgen(Node *n, Node *res)
if(isslice(n->left->type))
n->addable = n->left->addable;
break;
+ case OITAB:
+ n->addable = n->left->addable;
+ break;
}
if(complexop(n, res)) {
@@ -257,6 +262,14 @@ cgen(Node *n, Node *res)
gmove(&n1, res);
regfree(&n1);
break;
+
+ case OITAB:
+ // interface table is first word of interface value
+ igen(nl, &n1, res);
+ n1.type = n->type;
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
case OLEN:
if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
@@ -385,9 +398,9 @@ abop: // asymmetric binary
regalloc(&n2, nr->type, N);
cgen(nr, &n2);
} else {
- regalloc(&n2, nr->type, N);
+ regalloc(&n2, nr->type, res);
cgen(nr, &n2);
- regalloc(&n1, nl->type, res);
+ regalloc(&n1, nl->type, N);
cgen(nl, &n1);
}
gins(a, &n2, &n1);
@@ -715,6 +728,7 @@ bgen(Node *n, int true, Prog *to)
int et, a;
Node *nl, *nr, *l, *r;
Node n1, n2, tmp;
+ NodeList *ll;
Prog *p1, *p2;
if(debug['g']) {
@@ -727,9 +741,6 @@ bgen(Node *n, int true, Prog *to)
if(n->ninit != nil)
genlist(n->ninit);
- nl = n->left;
- nr = n->right;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -742,7 +753,6 @@ bgen(Node *n, int true, Prog *to)
patch(gins(AEND, N, N), to);
goto ret;
}
- nl = N;
nr = N;
switch(n->op) {
@@ -836,7 +846,10 @@ bgen(Node *n, int true, Prog *to)
p1 = gbranch(AJMP, T);
p2 = gbranch(AJMP, T);
patch(p1, pc);
+ ll = n->ninit; // avoid re-genning ninit
+ n->ninit = nil;
bgen(n, 1, p2);
+ n->ninit = ll;
patch(gbranch(AJMP, T), to);
patch(p2, pc);
goto ret;
@@ -1021,28 +1034,35 @@ stkof(Node *n)
* memmove(&ns, &n, w);
*/
void
-sgen(Node *n, Node *ns, int32 w)
+sgen(Node *n, Node *ns, int64 w)
{
Node nodl, nodr, oldl, oldr, cx, oldcx, tmp;
int32 c, q, odst, osrc;
if(debug['g']) {
- print("\nsgen w=%d\n", w);
+ print("\nsgen w=%lld\n", w);
dump("r", n);
dump("res", ns);
}
- if(w == 0)
- return;
- if(n->ullman >= UINF && ns->ullman >= UINF) {
+
+ if(n->ullman >= UINF && ns->ullman >= UINF)
fatal("sgen UINF");
- }
if(w < 0)
- fatal("sgen copy %d", w);
+ fatal("sgen copy %lld", w);
if(w == 16)
if(componentgen(n, ns))
return;
+
+ if(w == 0) {
+ // evaluate side effects only
+ regalloc(&nodr, types[tptr], N);
+ agen(ns, &nodr);
+ agen(n, &nodr);
+ regfree(&nodr);
+ return;
+ }
// offset on the stack
osrc = stkof(n);
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index e366362b3..b03ac1ed6 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
int thechar = '6';
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 2493771a0..47a540082 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -2,16 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <u.h>
-#include <libc.h>
+#ifndef EXTERN
+#define EXTERN extern
+#endif
#include "../gc/go.h"
#include "../6l/6.out.h"
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
typedef struct Addr Addr;
struct Addr
@@ -44,22 +41,21 @@ struct Prog
void* reg; // pointer to containing Reg struct
};
-EXTERN Biobuf* bout;
+#define TEXTFLAG from.scale
+
EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
extern char* anames[];
-EXTERN Hist* hist;
EXTERN Prog zprog;
-EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
-EXTERN vlong unmappedzero;
+extern vlong unmappedzero;
/*
* gen.c
@@ -91,7 +87,7 @@ void agen(Node*, Node*);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
+void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
@@ -159,3 +155,5 @@ void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
+#pragma varargck type "D" Addr*
+#pragma varargck type "lD" Addr*
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index a5f278384..02e67d6d4 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -4,6 +4,8 @@
#undef EXTERN
#define EXTERN
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -24,10 +26,10 @@ markautoused(Prog* p)
{
for (; p; p = p->link) {
if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
+ p->from.node->used = 1;
if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
+ p->to.node->used = 1;
}
}
@@ -446,8 +448,8 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
{
int a, check;
Node n3, n4, n5;
- Type *t;
- Node ax, dx, oldax, olddx;
+ Type *t, *t0;
+ Node ax, dx, ax1, n31, oldax, olddx;
Prog *p1, *p2, *p3;
// Have to be careful about handling
@@ -459,6 +461,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
// For int32 and int64, use explicit test.
// Could use int64 hw for int32.
t = nl->type;
+ t0 = t;
check = 0;
if(issigned[t->etype]) {
check = 1;
@@ -476,18 +479,28 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
}
a = optoas(op, t);
- regalloc(&n3, t, N);
+ regalloc(&n3, t0, N);
if(nl->ullman >= nr->ullman) {
- savex(D_AX, &ax, &oldax, res, t);
+ savex(D_AX, &ax, &oldax, res, t0);
cgen(nl, &ax);
- regalloc(&ax, t, &ax); // mark ax live during cgen
+ regalloc(&ax, t0, &ax); // mark ax live during cgen
cgen(nr, &n3);
regfree(&ax);
} else {
cgen(nr, &n3);
- savex(D_AX, &ax, &oldax, res, t);
+ savex(D_AX, &ax, &oldax, res, t0);
cgen(nl, &ax);
}
+ if(t != t0) {
+ // Convert
+ ax1 = ax;
+ n31 = n3;
+ ax.type = t;
+ n3.type = t;
+ gmove(&ax1, &ax);
+ gmove(&n31, &n3);
+ }
+
p3 = P;
if(check) {
nodconst(&n4, t, -1);
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index ba8a4870e..80de2f750 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
void
@@ -278,54 +280,6 @@ dumpfuncs(void)
}
}
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
int
dsname(Sym *s, int off, char *t, int n)
{
@@ -356,6 +310,7 @@ datastring(char *s, int len, Addr *a)
sym = stringsym(s, len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = widthptr+4; // skip header
a->etype = TINT32;
}
@@ -372,6 +327,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
}
@@ -381,6 +337,16 @@ gdata(Node *nam, Node *nr, int wid)
{
Prog *p;
+ if(nr->op == OLITERAL) {
+ switch(nr->val.ctype) {
+ case CTCPLX:
+ gdatacomplex(nam, nr->val.u.cval);
+ return;
+ case CTSTR:
+ gdatastring(nam, nr->val.u.sval);
+ return;
+ }
+ }
p = gins(ADATA, nam, nr);
p->from.scale = wid;
}
@@ -537,8 +503,10 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
int c, d, o, mov, add, loaded;
Prog *p;
Type *f;
+
+ USED(iface);
- if(debug['r'])
+ if(0 && debug['r'])
print("genembedtramp %T %T %S\n", rcvr, method, newnam);
e = method->sym;
@@ -619,7 +587,6 @@ out:
// but 6l has a bug, and it can't handle
// JMP instructions too close to the top of
// a new function.
- p = pc;
gins(ANOP, N, N);
}
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index d0d6d0c96..ededcf673 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
// TODO(rsc): Can make this bigger if we move
@@ -46,6 +48,10 @@ clearp(Prog *p)
pcloc++;
}
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
/*
* generate and return proc with p->as = as,
* linked into program. pc is next instruction.
@@ -55,10 +61,22 @@ prog(int as)
{
Prog *p;
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
if(lineno == 0) {
if(debug['K'])
@@ -67,10 +85,21 @@ prog(int as)
p->as = as;
p->lineno = lineno;
- p->link = pc;
return p;
}
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
/*
* generate a branch.
* t is ignored.
@@ -79,6 +108,8 @@ Prog*
gbranch(int as, Type *t)
{
Prog *p;
+
+ USED(t);
p = prog(as);
p->to.type = D_BRANCH;
@@ -200,6 +231,8 @@ ggloblnod(Node *nam, int32 width)
p->to.offset = width;
if(nam->readonly)
p->from.scale = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->from.scale |= NOPTR;
}
void
@@ -256,8 +289,6 @@ static int resvd[] =
D_CX, // for shift
D_DX, // for divide
D_SP, // for stack
- D_R14, // reserved for m
- D_R15, // reserved for u
};
void
@@ -309,6 +340,8 @@ anyregalloc(void)
return 0;
}
+static uintptr regpc[D_R15+1 - D_AX];
+
/*
* allocate register of type t, leave in n.
* if o != N, o is desired fixed register.
@@ -341,11 +374,15 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
}
for(i=D_AX; i<=D_R15; i++)
- if(reg[i] == 0)
+ if(reg[i] == 0) {
+ regpc[i-D_AX] = (uintptr)getcallerpc(&n);
goto out;
+ }
- yyerror("out of fixed registers");
- goto err;
+ flusherrors();
+ for(i=0; i+D_AX<=D_R15; i++)
+ print("%d %p\n", i, regpc[i]);
+ fatal("out of fixed registers");
case TFLOAT32:
case TFLOAT64:
@@ -357,18 +394,14 @@ regalloc(Node *n, Type *t, Node *o)
for(i=D_X0; i<=D_X7; i++)
if(reg[i] == 0)
goto out;
- yyerror("out of floating registers");
- goto err;
+ fatal("out of floating registers");
case TCOMPLEX64:
case TCOMPLEX128:
tempname(n, t);
return;
}
- yyerror("regalloc: unknown type %T", t);
-
-err:
- nodreg(n, t, 0);
+ fatal("regalloc: unknown type %T", t);
return;
out:
@@ -388,11 +421,13 @@ regfree(Node *n)
i = n->val.u.reg;
if(i == D_SP)
return;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
fatal("regfree: reg not allocated");
reg[i]--;
+ if(reg[i] == 0 && D_AX <= i && i <= D_R15)
+ regpc[i - D_AX] = 0;
}
/*
@@ -450,12 +485,20 @@ nodarg(Type *t, int fp)
n = nod(ONAME, N, N);
n->type = t->type;
n->sym = t->sym;
+
if(t->width == BADWIDTH)
fatal("nodarg: offset not computed for %T", t);
n->xoffset = t->width;
n->addable = 1;
+ n->orig = t->nname;
fp:
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
+
switch(fp) {
case 0: // output arg
n->op = OINDREG;
@@ -522,6 +565,7 @@ int
ismem(Node *n)
{
switch(n->op) {
+ case OITAB:
case OLEN:
case OCAP:
case OINDREG:
@@ -1088,6 +1132,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->offset = n->xoffset;
a->sym = n->left->sym;
a->type = D_PARAM;
+ a->node = n->left->orig;
break;
case ONAME:
@@ -1098,9 +1143,11 @@ naddr(Node *n, Addr *a, int canemitcode)
a->width = n->type->width;
a->gotype = ngotype(n);
}
- a->pun = n->pun;
a->offset = n->xoffset;
a->sym = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
if(a->sym == S)
a->sym = lookup(".noname");
if(n->method) {
@@ -1118,8 +1165,6 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->type = D_AUTO;
- if (n->sym)
- a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
@@ -1142,6 +1187,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
+ case CTRUNE:
a->sym = S;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
@@ -1176,6 +1222,17 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
}
fatal("naddr: OADDR\n");
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // itab(nil)
+ a->etype = tptr;
+ a->width = widthptr;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
case OLEN:
// len of string or slice
@@ -1845,7 +1902,7 @@ sudoaddable(int as, Node *n, Addr *a)
switch(n->op) {
case OLITERAL:
- if(n->val.ctype != CTINT)
+ if(!isconst(n, CTINT))
break;
v = mpgetfix(n->val.u.xval);
if(v >= 32000 || v <= -32000)
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
index c8077c97a..ad63f7d29 100644
--- a/src/cmd/6g/list.c
+++ b/src/cmd/6g/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
static int sconsize;
@@ -131,7 +133,7 @@ Dconv(Fmt *fp)
if(fp->flags & FmtLong) {
d1 = a->offset & 0xffffffffLL;
d2 = (a->offset>>32) & 0xffffffffLL;
- snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
+ snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
break;
}
snprint(str, sizeof(str), "$%lld", a->offset);
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index 4432203f2..3710033b2 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -985,13 +987,12 @@ loop:
case 3: // set
if(p->as == p0->as)
if(p->from.type == p0->from.type)
- if(p->from.sym == p0->from.sym)
+ if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
if(p->from.dval == p0->from.dval)
if(p->from.index == p0->from.index) {
excise(r);
- t++;
goto loop;
}
break;
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 4d4263047..bed9f8da6 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -28,9 +28,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
-#undef EXTERN
-#define EXTERN
#include "opt.h"
#define NREGVAR 32 /* 16 general + 16 floating */
@@ -89,8 +89,8 @@ setoutvar(void)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
+//if(bany(&ovar))
+//print("ovars = %Q\n", ovar);
}
static void
@@ -98,19 +98,19 @@ setaddrs(Bits bit)
{
int i, n;
Var *v;
- Sym *s;
+ Node *node;
while(bany(&bit)) {
// convert each bit to a variable
i = bnum(bit);
- s = var[i].sym;
+ node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n)
+ if(v->node == node && v->name == n)
v->addr = 2;
}
}
@@ -151,6 +151,8 @@ static char* regname[] = {
".X15",
};
+static void fixjmp(Prog*);
+
void
regopt(Prog *firstp)
{
@@ -166,6 +168,8 @@ regopt(Prog *firstp)
first = 0;
}
+ fixjmp(firstp);
+
// count instructions
nr = 0;
for(p=firstp; p!=P; p=p->link)
@@ -179,7 +183,6 @@ regopt(Prog *firstp)
r1 = R;
firstr = R;
lastr = R;
- nvar = 0;
/*
* control flow is more complicated in generated go code
@@ -189,7 +192,7 @@ regopt(Prog *firstp)
nvar = NREGVAR;
memset(var, 0, NREGVAR*sizeof var[0]);
for(i=0; i<NREGVAR; i++)
- var[i].sym = lookup(regname[i]);
+ var[i].node = newname(lookup(regname[i]));
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
@@ -801,9 +804,9 @@ brk:
if(ostats.ndelmov)
print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4d delmov\n", ostats.nvar);
+ print(" %4d var\n", ostats.nvar);
if(ostats.naddr)
- print(" %4d delmov\n", ostats.naddr);
+ print(" %4d addr\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -832,12 +835,12 @@ addmove(Reg *r, int bn, int rn, int f)
v = var + bn;
a = &p1->to;
- a->sym = v->sym;
a->offset = v->offset;
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
a->node = v->node;
+ a->sym = v->node->sym;
// need to clean this up with wptr and
// some of the defaults
@@ -933,7 +936,7 @@ mkvar(Reg *r, Adr *a)
uint32 regu;
int32 o;
Bits bit;
- Sym *s;
+ Node *node;
/*
* mark registers used
@@ -969,10 +972,14 @@ mkvar(Reg *r, Adr *a)
n = t;
break;
}
- s = a->sym;
- if(s == S)
+
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
goto none;
- if(s->name[0] == '.')
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
@@ -981,7 +988,7 @@ mkvar(Reg *r, Adr *a)
flag = 0;
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n) {
+ if(v->node == node && v->name == n) {
if(v->offset == o)
if(v->etype == et)
if(v->width == w)
@@ -995,11 +1002,6 @@ mkvar(Reg *r, Adr *a)
}
}
}
- if(a->pun) {
-// print("disable pun %s\n", s->name);
- flag = 1;
-
- }
switch(et) {
case 0:
case TFUNC:
@@ -1007,25 +1009,24 @@ mkvar(Reg *r, Adr *a)
}
if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
- fatal("variable not optimized: %D", a);
+ if(debug['w'] > 1 && node != N)
+ fatal("variable not optimized: %#N", node);
goto none;
}
i = nvar;
nvar++;
v = var+i;
- v->sym = s;
v->offset = o;
v->name = n;
v->gotype = a->gotype;
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
- v->node = a->node;
+ v->node = node;
if(debug['R'])
- print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
+ print("bit=%2d et=%2d w=%d %#N %D\n", i, et, w, node, a);
ostats.nvar++;
bit = blsh(i);
@@ -1084,6 +1085,13 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
+
+ default:
+ // Work around for issue 1304:
+ // flush modified globals before each instruction.
+ for(z=0; z<BITS; z++)
+ cal.b[z] |= externs.b[z];
+ break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1220,10 +1228,12 @@ loopit(Reg *r, int32 nr)
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
+ // rpo2r[r->rpo] == r protects against considering dead code,
+ // which has r->rpo == 0.
+ if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
+ if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
@@ -1628,7 +1638,7 @@ dumpone(Reg *r)
if(bany(&r->refahead))
print(" ra:%Q ", r->refahead);
if(bany(&r->calbehind))
- print("cb:%Q ", r->calbehind);
+ print(" cb:%Q ", r->calbehind);
if(bany(&r->calahead))
print(" ca:%Q ", r->calahead);
if(bany(&r->regdiff))
@@ -1688,3 +1698,123 @@ noreturn(Prog *p)
return 1;
return 0;
}
+
+/*
+ * the code generator depends on being able to write out JMP
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+ int n;
+
+ n = 0;
+ while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+ if(++n > 10) {
+ *jmploop = 1;
+ break;
+ }
+ p = p->to.branch;
+ }
+ return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+ Prog *p;
+
+ for(p=firstp; p; p=p->link) {
+ if(p->reg != dead)
+ break;
+ p->reg = alive;
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch)
+ mark(p->to.branch);
+ if(p->as == AJMP || p->as == ARET || (p->as == ACALL && noreturn(p)))
+ break;
+ }
+}
+
+static void
+fixjmp(Prog *firstp)
+{
+ int jmploop;
+ Prog *p, *last;
+
+ if(debug['R'] && debug['v'])
+ print("\nfixjmp\n");
+
+ // pass 1: resolve jump to AJMP, mark all code as dead.
+ jmploop = 0;
+ for(p=firstp; p; p=p->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n", p);
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AJMP) {
+ p->to.branch = chasejmp(p->to.branch, &jmploop);
+ if(debug['R'] && debug['v'])
+ print("->%P\n", p);
+ }
+ p->reg = dead;
+ }
+ if(debug['R'] && debug['v'])
+ print("\n");
+
+ // pass 2: mark all reachable code alive
+ mark(firstp);
+
+ // pass 3: delete dead code (mostly JMPs).
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->reg == dead) {
+ if(p->link == P && p->as == ARET && last && last->as != ARET) {
+ // This is the final ARET, and the code so far doesn't have one.
+ // Let it stay.
+ } else {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+
+ // pass 4: elide JMP to next instruction.
+ // only safe if there are no jumps to JMPs anymore.
+ if(!jmploop) {
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->as == AJMP && p->to.type == D_BRANCH && p->to.branch == p->link) {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+ }
+
+ if(debug['R'] && debug['v']) {
+ print("\n");
+ for(p=firstp; p; p=p->link)
+ print("%P\n", p);
+ print("\n");
+ }
+}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 262da02ab..849915954 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -34,6 +34,7 @@
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
#define RODATA (1<<3)
+#define NOPTR (1<<4)
/*
* amd64
@@ -121,7 +122,7 @@ enum as
AIRETW,
AJCC,
AJCS,
- AJCXZ,
+ AJCXZL,
AJEQ,
AJGE,
AJGT,
@@ -487,6 +488,7 @@ enum as
AIDIVQ,
AIMULQ,
AIRETQ,
+ AJCXZQ,
ALEAQ,
ALEAVEQ,
ALODSQ,
@@ -733,6 +735,7 @@ enum as
AMODE,
ACRC32B,
ACRC32Q,
+ AIMUL3Q,
ALAST
};
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index 8ed3e1411..3f528d751 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -1,48 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=6l
-
-OFILES=\
- asm.$O\
- data.$O\
- dwarf.$O\
- elf.$O\
- enam.$O\
- go.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- macho.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- pe.$O\
- prof.$O\
- span.$O\
- symtab.$O\
-
-HFILES=\
- l.h\
- 6.out.h\
- ../ld/lib.h\
- ../ld/elf.h\
- ../ld/macho.h\
- ../ld/dwarf.h\
- ../ld/pe.h\
-
-include ../../Make.ccmd
-
-enam.c: 6.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
+include ../../Make.dist
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 3a8223e65..ee31a05cd 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -37,13 +37,12 @@
#include "../ld/macho.h"
#include "../ld/pe.h"
-#define Dbufslop 100
-
#define PADDR(a) ((uint32)(a) & ~0x80000000)
char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
char freebsddynld[] = "/libexec/ld-elf.so.1";
char openbsddynld[] = "/usr/libexec/ld.so";
+char netbsddynld[] = "/libexec/ld.elf_so";
char zeroes[32];
@@ -95,6 +94,9 @@ enum {
ElfStrPlt,
ElfStrGnuVersion,
ElfStrGnuVersionR,
+ ElfStrNoteNetbsdIdent,
+ ElfStrNoPtrData,
+ ElfStrNoPtrBss,
NElfStr
};
@@ -112,6 +114,7 @@ needlib(char *name)
/* reuse hash code in symbol table */
p = smprint(".elfload.%s", name);
s = lookup(p, 0);
+ free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
return 1;
@@ -558,7 +561,7 @@ doelf(void)
{
Sym *s, *shstrtab, *dynstr;
- if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd)
+ if(HEADTYPE != Hlinux && HEADTYPE != Hfreebsd && HEADTYPE != Hopenbsd && HEADTYPE != Hnetbsd)
return;
/* predefine strings we need for section headers */
@@ -568,8 +571,12 @@ doelf(void)
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
+ elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
+ if(HEADTYPE == Hnetbsd)
+ elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gosymtab");
@@ -649,7 +656,7 @@ doelf(void)
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s->reachable = 1;
- s->type = SELFROSECT;
+ s->type = SELFSECT; // writable
/*
* .dynamic table
@@ -670,6 +677,8 @@ doelf(void)
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
+ elfwritedynent(s, DT_DEBUG, 0);
+
// Do not write DT_NULL. elfdynhash will finish it.
}
}
@@ -701,7 +710,7 @@ asmb(void)
{
int32 magic;
int a, dynsym;
- vlong vl, startva, symo, machlink;
+ vlong vl, startva, symo, dwarfoff, machlink, resoff;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -736,8 +745,19 @@ asmb(void)
datblk(segdata.vaddr, segdata.filelen);
machlink = 0;
- if(HEADTYPE == Hdarwin)
+ if(HEADTYPE == Hdarwin) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ cseek(dwarfoff);
+
+ segdwarf.fileoff = cpos();
+ dwarfemitdebugsections();
+ segdwarf.filelen = cpos() - segdwarf.fileoff;
+
machlink = domacholink();
+ }
switch(HEADTYPE) {
default:
@@ -750,6 +770,7 @@ asmb(void)
break;
case Hlinux:
case Hfreebsd:
+ case Hnetbsd:
case Hopenbsd:
debug['8'] = 1; /* 64-bit addresses */
/* index of elf text section; needed by asmelfsym, double-checked below */
@@ -760,6 +781,8 @@ asmb(void)
if(elfverneed)
elftextsh += 2;
}
+ if(HEADTYPE == Hnetbsd)
+ elftextsh += 1;
break;
case Hwindows:
break;
@@ -785,6 +808,7 @@ asmb(void)
break;
case Hlinux:
case Hfreebsd:
+ case Hnetbsd:
case Hopenbsd:
symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
@@ -809,7 +833,6 @@ asmb(void)
dwarfemitdebugsections();
}
break;
- case Hdarwin:
case Hwindows:
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -855,11 +878,13 @@ asmb(void)
break;
case Hlinux:
case Hfreebsd:
+ case Hnetbsd:
case Hopenbsd:
/* elf amd-64 */
eh = getElfEhdr();
startva = INITTEXT - HEADR;
+ resoff = ELFRESERVE;
/* This null SHdr must appear before all others */
newElfShdr(elfstr[ElfStrEmpty]);
@@ -898,12 +923,15 @@ asmb(void)
case Hfreebsd:
interpreter = freebsddynld;
break;
+ case Hnetbsd:
+ interpreter = netbsddynld;
+ break;
case Hopenbsd:
interpreter = openbsddynld;
break;
}
}
- elfinterp(sh, startva, interpreter);
+ resoff -= elfinterp(sh, startva, resoff, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
@@ -911,11 +939,24 @@ asmb(void)
phsh(ph, sh);
}
+ if(HEADTYPE == Hnetbsd) {
+ sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
+ sh->type = SHT_NOTE;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 4;
+ resoff -= elfnetbsdsig(sh, startva, resoff);
+
+ ph = newElfPhdr();
+ ph->type = PT_NOTE;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
elfphload(&segtext);
elfphload(&segdata);
/* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
/* S headers for dynamic linking */
sh = newElfShdr(elfstr[ElfStrGot]);
sh->type = SHT_PROGBITS;
@@ -1039,7 +1080,7 @@ asmb(void)
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
- if (!debug['s']) {
+ if(!debug['s']) {
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
sh->off = symo;
@@ -1064,6 +1105,8 @@ asmb(void)
eh->ident[EI_MAG3] = 'F';
if(HEADTYPE == Hfreebsd)
eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ else if(HEADTYPE == Hnetbsd)
+ eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
else if(HEADTYPE == Hopenbsd)
eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
eh->ident[EI_CLASS] = ELFCLASS64;
@@ -1083,8 +1126,10 @@ asmb(void)
a += elfwritehdr();
a += elfwritephdrs();
a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
+ a += elfwriteinterp(elfstr[ElfStrInterp]);
+ if(HEADTYPE == Hnetbsd)
+ a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
+ if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
case Hwindows:
@@ -1125,7 +1170,10 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
switch(s->type&~SSUB) {
case SCONST:
case SRODATA:
+ case SSYMTAB:
+ case SPCLNTAB:
case SDATA:
+ case SNOPTRDATA:
case SELFROSECT:
case SMACHOGOT:
case STYPE:
@@ -1138,8 +1186,11 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
continue;
case SBSS:
+ case SNOPTRBSS:
if(!s->reachable)
continue;
+ if(s->np > 0)
+ diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
continue;
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index b8a6013d6..4d94b209b 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -4,50 +4,10 @@
/*
-6l is a modified version of the Plan 9 linker. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-It reads files in .6 format generated by 6g, 6c, and 6a and emits
-a binary called 6.out by default.
-
-Major changes include:
- - support for ELF and Mach-O binary files
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--d
- Elide the dynamic linking header. With this option, the binary
- is statically linked and does not refer to dynld. Without this option
- (the default), the binary's contents are identical but it is loaded with dynld.
--e
- Emit an extra ELF-compatible symbol table useful with tools such as
- nm, gdb, and oprofile. This option makes the binary file considerably larger.
--Hdarwin
- Write Apple Mach-O binaries (default when $GOOS is darwin)
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--Hfreebsd
- Write FreeBSD ELF binaries (default when $GOOS is freebsd)
--Hopenbsd
- Write OpenBSD ELF binaries (default when $GOOS is openbsd)
--Hwindows
- Write Windows PE32+ binaries (default when $GOOS is windows)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_amd64.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
+6l is the linker for the x86-64.
+The $GOARCH for these tools is amd64.
+The flags are documented in ../ld/doc.go.
*/
package documentation
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index b291d5f3d..5f62239a1 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -133,6 +133,7 @@ struct Sym
int32 sig;
int32 plt;
int32 got;
+ int32 align; // if non-zero, required alignment in bytes
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
Sym* next; // in text or data list
@@ -163,7 +164,7 @@ struct Optab
short as;
uchar* ytab;
uchar prefix;
- uchar op[20];
+ uchar op[22];
};
struct Movtab
{
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index a7ef58db4..692cab7b8 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -44,16 +44,17 @@ char* thestring = "amd64";
char* paramspace = "FP";
Header headers[] = {
- "plan9x32", Hplan9x32,
- "plan9", Hplan9x64,
- "elf", Helf,
- "darwin", Hdarwin,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "openbsd", Hopenbsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
+ "plan9x32", Hplan9x32,
+ "plan9", Hplan9x64,
+ "elf", Helf,
+ "darwin", Hdarwin,
+ "linux", Hlinux,
+ "freebsd", Hfreebsd,
+ "netbsd", Hnetbsd,
+ "openbsd", Hopenbsd,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
};
/*
@@ -63,6 +64,7 @@ Header headers[] = {
* -Hdarwin -Tx -Rx is apple MH-exec
* -Hlinux -Tx -Rx is linux elf-exec
* -Hfreebsd -Tx -Rx is FreeBSD elf-exec
+ * -Hnetbsd -Tx -Rx is NetBSD elf-exec
* -Hopenbsd -Tx -Rx is OpenBSD elf-exec
* -Hwindows -Tx -Rx is MS Windows PE32+
*
@@ -80,6 +82,7 @@ void
main(int argc, char *argv[])
{
int c;
+ char *name, *val;
Binit(&bso, 1, OWRITE);
listinit();
@@ -91,6 +94,7 @@ main(int argc, char *argv[])
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
+ nuxiinit();
ARGBEGIN {
default:
@@ -130,6 +134,11 @@ main(int argc, char *argv[])
case 'V':
print("%cl version %s\n", thechar, getgoversion());
errorexit();
+ case 'X':
+ name = EARGF(usage());
+ val = EARGF(usage());
+ addstrdata(name, val);
+ break;
} ARGEND
if(argc != 1)
@@ -183,7 +192,7 @@ main(int argc, char *argv[])
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from 0(GS) to our TLS.
- * Explained in ../../libcgo/darwin_amd64.c.
+ * Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c.
*/
tlsoffset = 0x8a0;
machoinit();
@@ -197,12 +206,13 @@ main(int argc, char *argv[])
break;
case Hlinux: /* elf64 executable */
case Hfreebsd: /* freebsd */
+ case Hnetbsd: /* netbsd */
case Hopenbsd: /* openbsd */
/*
* ELF uses TLS offset negative from FS.
* Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
- * Also known to ../../pkg/runtime/linux/amd64/sys.s
- * and ../../libcgo/linux_amd64.s.
+ * Also known to ../../pkg/runtime/sys_linux_amd64.s
+ * and ../../pkg/runtime/cgo/gcc_linux_amd64.c.
*/
tlsoffset = -16;
elfinit();
@@ -245,7 +255,6 @@ main(int argc, char *argv[])
zprg.mode = 64;
pcstr = "%.6llux ";
- nuxiinit();
histgen = 0;
pc = 0;
dtype = 4;
@@ -462,7 +471,7 @@ loop:
sig = 1729;
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures"
+ diag("incompatible type signatures "
"%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
@@ -546,7 +555,7 @@ loop:
s->type = SBSS;
s->size = 0;
}
- if(s->type != SBSS && !s->dupok) {
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
@@ -558,6 +567,8 @@ loop:
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
+ else if(p->from.scale & NOPTR)
+ s->type = SNOPTRBSS;
goto loop;
case ADATA:
@@ -589,6 +600,10 @@ loop:
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
diag("%s: %s: redefinition", pn, s->name);
return;
}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
index 36806ec4b..5746ded19 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -200,7 +200,8 @@ uchar ymovq[] =
Ymm, Ymr, Zm_r_xm, 1, // MMX MOVD
Ymr, Ymm, Zr_m_xm, 1, // MMX MOVD
Yxr, Ymr, Zm_r_xm_nr, 2, // MOVDQ2Q
- Yxr, Ym, Zr_m_xm_nr, 2, // MOVQ xmm store
+ Yxm, Yxr, Zm_r_xm_nr, 2, // MOVQ xmm1/m64 -> xmm2
+ Yxr, Yxm, Zr_m_xm_nr, 2, // MOVQ xmm1 -> xmm2/m64
Yml, Yxr, Zm_r_xm, 2, // MOVD xmm load
Yxr, Yml, Zr_m_xm, 2, // MOVD xmm store
Yiauto, Yrl, Zaut_r, 2, // built-in LEAQ
@@ -266,6 +267,11 @@ uchar yimul[] =
Yml, Yrl, Zm_r, 2,
0
};
+uchar yimul3[] =
+{
+ Yml, Yrl, Zibm_r, 1,
+ 0
+};
uchar ybyte[] =
{
Yi64, Ynone, Zbyte, 1,
@@ -771,6 +777,7 @@ Optab optab[] =
{ AIMULL, yimul, Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
{ AIMULQ, yimul, Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
{ AIMULW, yimul, Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+ { AIMUL3Q, yimul3, Pw, 0x6b },
{ AINB, yin, Pb, 0xe4,0xec },
{ AINCB, yincb, Pb, 0xfe,(00) },
{ AINCL, yincl, Px, 0xff,(00) },
@@ -788,7 +795,8 @@ Optab optab[] =
{ AIRETW, ynone, Pe, 0xcf },
{ AJCC, yjcond, Px, 0x73,0x83,(00) },
{ AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZ, yloop, Px, 0xe3 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZQ, yloop, Px, 0xe3 },
{ AJEQ, yjcond, Px, 0x74,0x84 },
{ AJGE, yjcond, Px, 0x7d,0x8d },
{ AJGT, yjcond, Px, 0x7f,0x8f },
@@ -861,7 +869,7 @@ Optab optab[] =
{ AMOVNTPD, yxr_ml, Pe, 0x2b },
{ AMOVNTPS, yxr_ml, Pm, 0x2b },
{ AMOVNTQ, ymr_ml, Pm, 0xe7 },
- { AMOVQ, ymovq, Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e },
+ { AMOVQ, ymovq, Pw, 0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e },
{ AMOVQOZX, ymrxr, Pf3, 0xd6,0x7e },
{ AMOVSB, ynone, Pb, 0xa4 },
{ AMOVSD, yxmov, Pf2, 0x10,0x11 },
@@ -977,7 +985,7 @@ Optab optab[] =
{ APSHUFW, ymshuf, Pm, 0x70 },
{ APSLLO, ypsdq, Pq, 0x73,(07) },
{ APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
- { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) },
+ { APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
{ APSLLW, yps, Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
{ APSRAL, yps, Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
{ APSRAW, yps, Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index d9e0b2fc1..c9b477627 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -276,7 +276,7 @@ patch(void)
// Convert
// op n(GS), reg
// to
- // MOVL 0x58(GS), reg
+ // MOVL 0x28(GS), reg
// op n(reg), reg
// The purpose of this patch is to fix some accesses
// to extern register variables (TLS) on Windows, as
@@ -291,11 +291,11 @@ patch(void)
q->as = p->as;
p->as = AMOVQ;
p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x58;
+ p->from.offset = 0x28;
}
}
if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd) {
+ || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) {
// ELF uses FS instead of GS.
if(p->from.type == D_INDIR+D_GS)
p->from.type = D_INDIR+D_FS;
@@ -421,18 +421,18 @@ dostkoff(void)
p = appendp(p); // load g into CX
p->as = AMOVQ;
if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
- || HEADTYPE == Hopenbsd) // ELF uses FS
+ || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) // ELF uses FS
p->from.type = D_INDIR+D_FS;
else
p->from.type = D_INDIR+D_GS;
p->from.offset = tlsoffset+0;
p->to.type = D_CX;
if(HEADTYPE == Hwindows) {
- // movq %gs:0x58, %rcx
+ // movq %gs:0x28, %rcx
// movq (%rcx), %rcx
p->as = AMOVQ;
p->from.type = D_INDIR+D_GS;
- p->from.offset = 0x58;
+ p->from.offset = 0x28;
p->to.type = D_CX;
@@ -501,10 +501,17 @@ dostkoff(void)
q = p;
}
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
moreconst1 = 0;
- if(autoffset+160+textarg > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
+ if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
+ moreconst1 = autoffset;
moreconst2 = textarg;
// 4 varieties varieties (const1==0 cross const2==0)
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 5d13ad44b..28eb38f40 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -88,7 +88,10 @@ span1(Sym *s)
loop++;
q->back ^= 2;
}
- s->p[q->pc+1] = v;
+ if(q->as == AJCXZL)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
} else {
bp = s->p + q->pc + q->mark - 4;
*bp++ = v;
@@ -263,10 +266,6 @@ instinit(void)
ycover[Ym*Ymax + Ymm] = 1;
ycover[Ymr*Ymax + Ymm] = 1;
- ycover[Yax*Ymax + Yxm] = 1;
- ycover[Ycx*Ymax + Yxm] = 1;
- ycover[Yrx*Ymax + Yxm] = 1;
- ycover[Yrl*Ymax + Yxm] = 1;
ycover[Ym*Ymax + Yxm] = 1;
ycover[Yxr*Ymax + Yxm] = 1;
@@ -1439,10 +1438,11 @@ found:
case Zbr:
case Zjmp:
+ case Zloop:
// TODO: jump across functions needs reloc
q = p->pcond;
if(q == nil) {
- diag("jmp/branch without target");
+ diag("jmp/branch/loop without target");
errorexit();
}
if(q->as == ATEXT) {
@@ -1466,8 +1466,12 @@ found:
if(p->back & 1) {
v = q->pc - (p->pc + 2);
if(v >= -128) {
+ if(p->as == AJCXZL)
+ *andptr++ = 0x67;
*andptr++ = op;
*andptr++ = v;
+ } else if(t[2] == Zloop) {
+ diag("loop too far: %P", p);
} else {
v -= 5-2;
if(t[2] == Zbr) {
@@ -1487,8 +1491,12 @@ found:
p->forwd = q->comefrom;
q->comefrom = p;
if(p->back & 2) { // short
+ if(p->as == AJCXZL)
+ *andptr++ = 0x67;
*andptr++ = op;
*andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ diag("loop too far: %P", p);
} else {
if(t[2] == Zbr)
*andptr++ = 0x0f;
@@ -1520,19 +1528,6 @@ found:
*/
break;
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("loop without target");
- errorexit();
- }
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
- break;
-
case Zbyte:
v = vaddr(&p->from, &rel);
if(rel.siz != 0) {
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
index 78d361dbd..27290ddd7 100644
--- a/src/cmd/8a/Makefile
+++ b/src/cmd/8a/Makefile
@@ -1,25 +1,10 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
+include ../../Make.dist
-TARG=8a
+install: y.tab.h
-HFILES=\
- a.h\
- y.tab.h\
- ../8l/8.out.h\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- ../8l/enam.$O\
-
-YFILES=\
- a.y\
-
-include ../../Make.ccmd
-
-lex.$O: ../cc/macbody ../cc/lexbody
+y.tab.h: a.y
+ LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index a8ac773da..f1881808f 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -210,6 +210,13 @@ spec3: /* JMP/CALL */
$$.from = nullgen;
$$.to = $1;
}
+| '*' nam
+ {
+ $$.from = nullgen;
+ $$.to = $2;
+ $$.to.index = $2.type;
+ $$.to.type = D_INDIR+D_ADDR;
+ }
spec4: /* NOP */
nonnon
@@ -385,6 +392,12 @@ imm:
$$.type = D_FCONST;
$$.dval = $3;
}
+| '$' '(' '-' LFCONST ')'
+ {
+ $$ = nullgen;
+ $$.type = D_FCONST;
+ $$.dval = -$4;
+ }
| '$' '-' LFCONST
{
$$ = nullgen;
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index e56460e4b..1cc6e591d 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -44,7 +44,11 @@ enum
int
systemtype(int sys)
{
+#ifdef _WIN32
+ return sys&Windows;
+#else
return sys&Plan9;
+#endif
}
int
@@ -309,8 +313,8 @@ struct
"IDIVL", LTYPE2, AIDIVL,
"IDIVW", LTYPE2, AIDIVW,
"IMULB", LTYPE2, AIMULB,
- "IMULL", LTYPE2, AIMULL,
- "IMULW", LTYPE2, AIMULW,
+ "IMULL", LTYPEI, AIMULL,
+ "IMULW", LTYPEI, AIMULW,
"INB", LTYPE0, AINB,
"INL", LTYPE0, AINL,
"INW", LTYPE0, AINW,
@@ -371,7 +375,8 @@ struct
"JG", LTYPER, AJGT, /* alternate */
"JNLE", LTYPER, AJGT, /* alternate */
- "JCXZ", LTYPER, AJCXZ,
+ "JCXZL", LTYPER, AJCXZL,
+ "JCXZW", LTYPER, AJCXZW,
"JMP", LTYPEC, AJMP,
"LAHF", LTYPE0, ALAHF,
"LARL", LTYPE3, ALARL,
@@ -440,6 +445,7 @@ struct
"RCRB", LTYPE3, ARCRB,
"RCRL", LTYPE3, ARCRL,
"RCRW", LTYPE3, ARCRW,
+ "RDTSC", LTYPE0, ARDTSC,
"REP", LTYPE0, AREP,
"REPN", LTYPE0, AREPN,
"RET", LTYPE0, ARET,
@@ -657,6 +663,10 @@ struct
"FXTRACT", LTYPE0, AFXTRACT,
"FYL2X", LTYPE0, AFYL2X,
"FYL2XP1", LTYPE0, AFYL2XP1,
+ "LFENCE", LTYPE0, ALFENCE,
+ "MFENCE", LTYPE0, AMFENCE,
+ "SFENCE", LTYPE0, ASFENCE,
+ "EMMS", LTYPE0, AEMMS,
0
};
@@ -911,17 +921,13 @@ outhist(void)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
new file mode 100644
index 000000000..ccd3a2563
--- /dev/null
+++ b/src/cmd/8a/y.tab.c
@@ -0,0 +1,2852 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+
+
+/* Line 189 of yacc.c */
+#line 81 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE0 = 258,
+ LTYPE1 = 259,
+ LTYPE2 = 260,
+ LTYPE3 = 261,
+ LTYPE4 = 262,
+ LTYPEC = 263,
+ LTYPED = 264,
+ LTYPEN = 265,
+ LTYPER = 266,
+ LTYPET = 267,
+ LTYPES = 268,
+ LTYPEM = 269,
+ LTYPEI = 270,
+ LTYPEG = 271,
+ LCONST = 272,
+ LFP = 273,
+ LPC = 274,
+ LSB = 275,
+ LBREG = 276,
+ LLREG = 277,
+ LSREG = 278,
+ LFREG = 279,
+ LFCONST = 280,
+ LSCONST = 281,
+ LSP = 282,
+ LNAME = 283,
+ LLAB = 284,
+ LVAR = 285
+ };
+#endif
+/* Tokens. */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPES 268
+#define LTYPEM 269
+#define LTYPEI 270
+#define LTYPEG 271
+#define LCONST 272
+#define LFP 273
+#define LPC 274
+#define LSB 275
+#define LBREG 276
+#define LLREG 277
+#define LSREG 278
+#define LFREG 279
+#define LFCONST 280
+#define LSCONST 281
+#define LSP 282
+#define LNAME 283
+#define LLAB 284
+#define LVAR 285
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 214 of yacc.c */
+#line 37 "a.y"
+
+ Sym *sym;
+ int32 lval;
+ struct {
+ int32 v1;
+ int32 v2;
+ } con2;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+
+
+
+/* Line 214 of yacc.c */
+#line 192 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 264 of yacc.c */
+#line 204 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 483
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 49
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 37
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 124
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 244
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 285
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 47, 12, 5, 2,
+ 45, 46, 10, 8, 44, 9, 2, 11, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 41, 42,
+ 6, 43, 7, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 2, 48, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
+ 23, 26, 29, 33, 37, 40, 43, 46, 49, 52,
+ 55, 58, 61, 64, 67, 70, 73, 76, 79, 80,
+ 82, 86, 90, 93, 95, 98, 100, 103, 105, 111,
+ 115, 121, 124, 126, 129, 131, 133, 137, 143, 147,
+ 153, 156, 158, 162, 166, 172, 174, 176, 178, 180,
+ 183, 186, 188, 190, 192, 194, 196, 201, 204, 207,
+ 209, 211, 213, 215, 217, 220, 223, 226, 229, 234,
+ 240, 244, 247, 249, 252, 256, 261, 263, 265, 267,
+ 272, 277, 284, 294, 298, 302, 307, 313, 322, 324,
+ 331, 337, 345, 346, 349, 352, 354, 356, 358, 360,
+ 362, 365, 368, 371, 375, 377, 381, 385, 389, 393,
+ 397, 402, 407, 411, 415
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 50, 0, -1, -1, -1, 50, 51, 52, -1, -1,
+ 39, 41, 53, 52, -1, -1, 38, 41, 54, 52,
+ -1, 42, -1, 55, 42, -1, 1, 42, -1, 38,
+ 43, 85, -1, 40, 43, 85, -1, 13, 56, -1,
+ 14, 60, -1, 15, 59, -1, 16, 57, -1, 17,
+ 58, -1, 21, 61, -1, 19, 62, -1, 22, 63,
+ -1, 18, 64, -1, 20, 65, -1, 23, 66, -1,
+ 24, 67, -1, 25, 68, -1, 26, 69, -1, -1,
+ 44, -1, 72, 44, 70, -1, 70, 44, 72, -1,
+ 72, 44, -1, 72, -1, 44, 70, -1, 70, -1,
+ 44, 73, -1, 73, -1, 81, 11, 84, 44, 75,
+ -1, 78, 44, 76, -1, 78, 44, 84, 44, 76,
+ -1, 44, 71, -1, 71, -1, 10, 81, -1, 56,
+ -1, 60, -1, 72, 44, 70, -1, 72, 44, 70,
+ 41, 32, -1, 72, 44, 70, -1, 72, 44, 70,
+ 41, 33, -1, 72, 44, -1, 72, -1, 72, 44,
+ 70, -1, 78, 44, 75, -1, 78, 44, 84, 44,
+ 75, -1, 74, -1, 78, -1, 73, -1, 80, -1,
+ 10, 74, -1, 10, 79, -1, 74, -1, 79, -1,
+ 75, -1, 70, -1, 75, -1, 84, 45, 29, 46,
+ -1, 38, 82, -1, 39, 82, -1, 31, -1, 34,
+ -1, 32, -1, 37, -1, 33, -1, 47, 84, -1,
+ 47, 81, -1, 47, 36, -1, 47, 35, -1, 47,
+ 45, 35, 46, -1, 47, 45, 9, 35, 46, -1,
+ 47, 9, 35, -1, 47, 77, -1, 27, -1, 9,
+ 27, -1, 27, 9, 27, -1, 9, 27, 9, 27,
+ -1, 79, -1, 80, -1, 84, -1, 84, 45, 32,
+ 46, -1, 84, 45, 37, 46, -1, 84, 45, 32,
+ 10, 84, 46, -1, 84, 45, 32, 46, 45, 32,
+ 10, 84, 46, -1, 45, 32, 46, -1, 45, 37,
+ 46, -1, 84, 45, 33, 46, -1, 45, 32, 10,
+ 84, 46, -1, 45, 32, 46, 45, 32, 10, 84,
+ 46, -1, 81, -1, 81, 45, 32, 10, 84, 46,
+ -1, 38, 82, 45, 83, 46, -1, 38, 6, 7,
+ 82, 45, 30, 46, -1, -1, 8, 84, -1, 9,
+ 84, -1, 30, -1, 37, -1, 28, -1, 27, -1,
+ 40, -1, 9, 84, -1, 8, 84, -1, 48, 84,
+ -1, 45, 85, 46, -1, 84, -1, 85, 8, 85,
+ -1, 85, 9, 85, -1, 85, 10, 85, -1, 85,
+ 11, 85, -1, 85, 12, 85, -1, 85, 6, 6,
+ 85, -1, 85, 7, 7, 85, -1, 85, 5, 85,
+ -1, 85, 4, 85, -1, 85, 3, 85, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 68, 68, 70, 69, 77, 76, 84, 83, 89,
+ 90, 91, 94, 99, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118, 121, 125,
+ 132, 139, 146, 151, 158, 163, 170, 175, 182, 190,
+ 195, 203, 208, 213, 222, 223, 226, 231, 241, 246,
+ 256, 261, 266, 273, 278, 286, 287, 290, 291, 292,
+ 296, 300, 301, 302, 305, 306, 309, 315, 324, 333,
+ 338, 343, 348, 353, 360, 366, 377, 383, 389, 395,
+ 401, 409, 418, 423, 428, 433, 440, 441, 444, 450,
+ 456, 462, 471, 480, 485, 490, 496, 504, 514, 518,
+ 527, 534, 543, 546, 550, 556, 557, 561, 564, 565,
+ 569, 573, 577, 581, 587, 588, 592, 596, 600, 604,
+ 608, 612, 616, 620, 624
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+ "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
+ "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES",
+ "LTYPEM", "LTYPEI", "LTYPEG", "LCONST", "LFP", "LPC", "LSB", "LBREG",
+ "LLREG", "LSREG", "LFREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
+ "LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'",
+ "$accept", "prog", "$@1", "line", "$@2", "$@3", "inst", "nonnon",
+ "rimrem", "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2",
+ "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "rem", "rom",
+ "rim", "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem", "nam",
+ "offset", "pointer", "con", "expr", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 124, 94, 38, 60, 62, 43, 45,
+ 42, 47, 37, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 58, 59, 61, 44, 40, 41, 36, 126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 49, 50, 51, 50, 53, 52, 54, 52, 52,
+ 52, 52, 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 56, 56,
+ 57, 58, 59, 59, 60, 60, 61, 61, 62, 63,
+ 63, 64, 64, 64, 65, 65, 66, 66, 67, 67,
+ 68, 68, 68, 69, 69, 70, 70, 71, 71, 71,
+ 71, 71, 71, 71, 72, 72, 73, 73, 73, 74,
+ 74, 74, 74, 74, 75, 75, 75, 75, 75, 75,
+ 75, 76, 77, 77, 77, 77, 78, 78, 79, 79,
+ 79, 79, 79, 79, 79, 79, 79, 79, 80, 80,
+ 81, 81, 82, 82, 82, 83, 83, 83, 84, 84,
+ 84, 84, 84, 84, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 0, 3, 0, 4, 0, 4, 1,
+ 2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 0, 1,
+ 3, 3, 2, 1, 2, 1, 2, 1, 5, 3,
+ 5, 2, 1, 2, 1, 1, 3, 5, 3, 5,
+ 2, 1, 3, 3, 5, 1, 1, 1, 1, 2,
+ 2, 1, 1, 1, 1, 1, 4, 2, 2, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 4, 5,
+ 3, 2, 1, 2, 3, 4, 1, 1, 1, 4,
+ 4, 6, 9, 3, 3, 4, 5, 8, 1, 6,
+ 5, 7, 0, 2, 2, 1, 1, 1, 1, 1,
+ 2, 2, 2, 3, 1, 3, 3, 3, 3, 3,
+ 4, 4, 3, 3, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 3, 1, 0, 0, 28, 0, 0, 0, 0,
+ 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 4, 0, 11, 29, 14, 0, 0,
+ 108, 69, 71, 73, 70, 72, 102, 109, 0, 0,
+ 0, 15, 35, 55, 56, 86, 87, 98, 88, 0,
+ 16, 64, 33, 65, 17, 0, 18, 0, 0, 102,
+ 102, 0, 22, 42, 57, 61, 63, 62, 58, 88,
+ 20, 0, 29, 44, 45, 23, 102, 0, 0, 19,
+ 37, 0, 21, 0, 24, 0, 25, 0, 26, 51,
+ 27, 0, 7, 0, 5, 0, 10, 111, 110, 0,
+ 0, 0, 0, 34, 0, 0, 114, 0, 112, 0,
+ 0, 0, 77, 76, 0, 75, 74, 32, 0, 0,
+ 59, 60, 43, 67, 68, 0, 41, 0, 0, 67,
+ 36, 0, 0, 0, 0, 50, 0, 0, 12, 0,
+ 13, 102, 103, 104, 0, 0, 93, 94, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 113, 0,
+ 0, 0, 0, 80, 0, 0, 30, 31, 0, 0,
+ 0, 39, 0, 46, 48, 52, 53, 0, 8, 6,
+ 0, 107, 105, 106, 0, 0, 0, 124, 123, 122,
+ 0, 0, 115, 116, 117, 118, 119, 0, 0, 89,
+ 95, 90, 0, 78, 66, 0, 0, 82, 81, 0,
+ 0, 0, 0, 0, 100, 96, 0, 120, 121, 0,
+ 0, 0, 79, 38, 83, 0, 40, 47, 49, 54,
+ 0, 0, 99, 91, 0, 0, 84, 101, 0, 0,
+ 85, 97, 0, 92
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 3, 23, 139, 137, 24, 27, 54, 56,
+ 50, 41, 79, 70, 82, 62, 75, 84, 86, 88,
+ 90, 51, 63, 52, 64, 43, 53, 171, 208, 44,
+ 45, 46, 47, 102, 184, 48, 107
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -107
+static const yytype_int16 yypact[] =
+{
+ -107, 9, -107, 151, -28, -19, 235, 255, 255, 302,
+ 175, 6, 282, 34, 363, 255, 255, 255, 363, -3,
+ -6, 5, -107, -107, 4, -107, -107, -107, 373, 373,
+ -107, -107, -107, -107, -107, -107, 128, -107, 302, 343,
+ 373, -107, -107, -107, -107, -107, -107, 17, 19, 115,
+ -107, -107, 15, -107, -107, 27, -107, 42, 302, 128,
+ 72, 208, -107, -107, -107, -107, -107, -107, -107, 52,
+ -107, 44, 302, -107, -107, -107, 72, 359, 373, -107,
+ -107, 55, -107, 71, -107, 76, -107, 81, -107, 84,
+ -107, 97, -107, 373, -107, 373, -107, -107, -107, 142,
+ 373, 373, 114, -107, 1, 116, -107, 102, -107, 129,
+ 66, 385, -107, -107, 387, -107, -107, -107, 302, 255,
+ -107, -107, -107, 114, -107, 329, -107, 168, 373, -107,
+ -107, 149, 18, 302, 302, 302, 397, 151, 447, 151,
+ 447, 72, -107, -107, 47, 373, 134, -107, 373, 373,
+ 373, 176, 179, 373, 373, 373, 373, 373, -107, 182,
+ 3, 148, 152, -107, 401, 153, -107, -107, 158, 166,
+ 14, -107, 167, 154, 189, -107, -107, 187, -107, -107,
+ 188, -107, -107, -107, 186, 190, 202, 456, 464, 471,
+ 373, 373, 146, 146, -107, -107, -107, 373, 373, 192,
+ -107, -107, 203, -107, -107, 191, 223, 242, -107, 205,
+ 222, 224, 191, 228, -107, -107, 249, 216, 216, 214,
+ 215, 233, -107, -107, 261, 244, -107, -107, -107, -107,
+ 230, 373, -107, -107, 264, 250, -107, -107, 232, 373,
+ -107, -107, 238, -107
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -107, -107, -107, -106, -107, -107, -107, 269, -107, -107,
+ -107, 273, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -2, 236, 0, -1, -8, -9, 85, -107, 10,
+ -4, -5, 11, -39, -107, -10, -61
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 69, 66, 65, 81, 42, 68, 67, 57, 55, 2,
+ 42, 145, 80, 198, 25, 85, 87, 89, 97, 98,
+ 123, 124, 71, 206, 83, 26, 28, 29, 91, 106,
+ 108, 178, 138, 179, 140, 94, 103, 129, 92, 116,
+ 93, 207, 28, 29, 36, 30, 96, 146, 95, 199,
+ 120, 69, 66, 65, 121, 128, 68, 67, 37, 117,
+ 115, 30, 109, 78, 110, 170, 40, 81, 106, 122,
+ 103, 118, 76, 60, 37, 181, 130, 182, 77, 78,
+ 100, 101, 40, 106, 183, 106, 119, 187, 188, 189,
+ 142, 143, 192, 193, 194, 195, 196, 127, 160, 161,
+ 131, 98, 180, 162, 106, 148, 149, 150, 151, 152,
+ 153, 154, 155, 156, 157, 132, 166, 120, 169, 167,
+ 133, 121, 172, 28, 111, 134, 177, 176, 135, 217,
+ 218, 173, 174, 175, 99, 185, 100, 101, 106, 106,
+ 106, 136, 30, 106, 106, 106, 106, 106, 158, 141,
+ 112, 113, 4, 36, 98, 37, 155, 156, 157, 144,
+ 114, 159, 147, 40, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 168, 186,
+ 106, 106, 190, 28, 29, 58, 191, 219, 220, 19,
+ 20, 21, 197, 22, 200, 210, 223, 168, 201, 203,
+ 160, 161, 30, 229, 204, 162, 31, 32, 33, 34,
+ 205, 209, 35, 59, 60, 37, 28, 29, 125, 61,
+ 39, 238, 49, 40, 153, 154, 155, 156, 157, 242,
+ 211, 212, 214, 213, 216, 30, 215, 221, 49, 31,
+ 32, 33, 34, 28, 29, 35, 59, 60, 37, 222,
+ 224, 225, 170, 39, 227, 49, 40, 228, 230, 231,
+ 232, 233, 30, 28, 29, 234, 31, 32, 33, 34,
+ 235, 236, 35, 36, 239, 37, 237, 240, 241, 38,
+ 39, 73, 30, 40, 243, 74, 31, 32, 33, 34,
+ 28, 29, 35, 36, 226, 37, 0, 126, 0, 0,
+ 39, 0, 49, 40, 0, 0, 0, 0, 0, 30,
+ 28, 29, 0, 31, 32, 33, 34, 0, 0, 35,
+ 36, 0, 37, 0, 0, 0, 72, 39, 0, 30,
+ 40, 0, 0, 31, 32, 33, 34, 28, 29, 35,
+ 36, 0, 37, 0, 0, 0, 0, 39, 0, 0,
+ 40, 28, 29, 0, 0, 0, 30, 0, 0, 0,
+ 31, 32, 33, 34, 0, 0, 35, 28, 29, 37,
+ 30, 28, 29, 0, 39, 104, 0, 40, 0, 0,
+ 105, 28, 29, 37, 0, 0, 30, 0, 78, 0,
+ 30, 40, 0, 28, 29, 28, 164, 76, 60, 37,
+ 30, 36, 0, 37, 78, 28, 29, 40, 39, 28,
+ 29, 40, 30, 37, 30, 0, 0, 0, 78, 0,
+ 163, 40, 165, 0, 30, 37, 0, 37, 30, 0,
+ 78, 0, 78, 40, 0, 40, 202, 37, 0, 0,
+ 0, 37, 78, 0, 49, 40, 78, 0, 0, 40,
+ 148, 149, 150, 151, 152, 153, 154, 155, 156, 157,
+ 149, 150, 151, 152, 153, 154, 155, 156, 157, 150,
+ 151, 152, 153, 154, 155, 156, 157, 151, 152, 153,
+ 154, 155, 156, 157
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 10, 10, 10, 13, 6, 10, 10, 9, 8, 0,
+ 12, 10, 13, 10, 42, 15, 16, 17, 28, 29,
+ 59, 60, 11, 9, 14, 44, 8, 9, 18, 39,
+ 40, 137, 93, 139, 95, 41, 38, 76, 41, 49,
+ 43, 27, 8, 9, 38, 27, 42, 46, 43, 46,
+ 58, 61, 61, 61, 58, 11, 61, 61, 40, 44,
+ 49, 27, 45, 45, 45, 47, 48, 77, 78, 58,
+ 72, 44, 38, 39, 40, 28, 77, 30, 44, 45,
+ 8, 9, 48, 93, 37, 95, 44, 148, 149, 150,
+ 100, 101, 153, 154, 155, 156, 157, 45, 32, 33,
+ 45, 111, 141, 37, 114, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 44, 118, 125, 128, 119,
+ 44, 125, 132, 8, 9, 44, 136, 136, 44, 190,
+ 191, 133, 134, 135, 6, 145, 8, 9, 148, 149,
+ 150, 44, 27, 153, 154, 155, 156, 157, 46, 7,
+ 35, 36, 1, 38, 164, 40, 10, 11, 12, 45,
+ 45, 32, 46, 48, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 29, 45,
+ 190, 191, 6, 8, 9, 10, 7, 197, 198, 38,
+ 39, 40, 10, 42, 46, 41, 205, 29, 46, 46,
+ 32, 33, 27, 212, 46, 37, 31, 32, 33, 34,
+ 44, 44, 37, 38, 39, 40, 8, 9, 10, 44,
+ 45, 231, 47, 48, 8, 9, 10, 11, 12, 239,
+ 41, 44, 46, 45, 32, 27, 46, 45, 47, 31,
+ 32, 33, 34, 8, 9, 37, 38, 39, 40, 46,
+ 27, 9, 47, 45, 32, 47, 48, 33, 30, 10,
+ 46, 46, 27, 8, 9, 32, 31, 32, 33, 34,
+ 9, 27, 37, 38, 10, 40, 46, 27, 46, 44,
+ 45, 12, 27, 48, 46, 12, 31, 32, 33, 34,
+ 8, 9, 37, 38, 209, 40, -1, 61, -1, -1,
+ 45, -1, 47, 48, -1, -1, -1, -1, -1, 27,
+ 8, 9, -1, 31, 32, 33, 34, -1, -1, 37,
+ 38, -1, 40, -1, -1, -1, 44, 45, -1, 27,
+ 48, -1, -1, 31, 32, 33, 34, 8, 9, 37,
+ 38, -1, 40, -1, -1, -1, -1, 45, -1, -1,
+ 48, 8, 9, -1, -1, -1, 27, -1, -1, -1,
+ 31, 32, 33, 34, -1, -1, 37, 8, 9, 40,
+ 27, 8, 9, -1, 45, 32, -1, 48, -1, -1,
+ 37, 8, 9, 40, -1, -1, 27, -1, 45, -1,
+ 27, 48, -1, 8, 9, 8, 9, 38, 39, 40,
+ 27, 38, -1, 40, 45, 8, 9, 48, 45, 8,
+ 9, 48, 27, 40, 27, -1, -1, -1, 45, -1,
+ 35, 48, 35, -1, 27, 40, -1, 40, 27, -1,
+ 45, -1, 45, 48, -1, 48, 35, 40, -1, -1,
+ -1, 40, 45, -1, 47, 48, 45, -1, -1, 48,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 5,
+ 6, 7, 8, 9, 10, 11, 12, 6, 7, 8,
+ 9, 10, 11, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 50, 0, 51, 1, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 38,
+ 39, 40, 42, 52, 55, 42, 44, 56, 8, 9,
+ 27, 31, 32, 33, 34, 37, 38, 40, 44, 45,
+ 48, 60, 70, 74, 78, 79, 80, 81, 84, 47,
+ 59, 70, 72, 75, 57, 72, 58, 70, 10, 38,
+ 39, 44, 64, 71, 73, 74, 75, 79, 80, 84,
+ 62, 81, 44, 56, 60, 65, 38, 44, 45, 61,
+ 73, 84, 63, 78, 66, 72, 67, 72, 68, 72,
+ 69, 78, 41, 43, 41, 43, 42, 84, 84, 6,
+ 8, 9, 82, 70, 32, 37, 84, 85, 84, 45,
+ 45, 9, 35, 36, 45, 81, 84, 44, 44, 44,
+ 74, 79, 81, 82, 82, 10, 71, 45, 11, 82,
+ 73, 45, 44, 44, 44, 44, 44, 54, 85, 53,
+ 85, 7, 84, 84, 45, 10, 46, 46, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 46, 32,
+ 32, 33, 37, 35, 9, 35, 70, 72, 29, 84,
+ 47, 76, 84, 70, 70, 70, 75, 84, 52, 52,
+ 82, 28, 30, 37, 83, 84, 45, 85, 85, 85,
+ 6, 7, 85, 85, 85, 85, 85, 10, 10, 46,
+ 46, 46, 35, 46, 46, 44, 9, 27, 77, 44,
+ 41, 41, 44, 45, 46, 46, 32, 85, 85, 84,
+ 84, 45, 46, 75, 27, 9, 76, 32, 33, 75,
+ 30, 10, 46, 46, 32, 9, 27, 46, 84, 10,
+ 27, 46, 84, 46
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3:
+
+/* Line 1455 of yacc.c */
+#line 70 "a.y"
+ {
+ stmtline = lineno;
+ }
+ break;
+
+ case 5:
+
+/* Line 1455 of yacc.c */
+#line 77 "a.y"
+ {
+ if((yyvsp[(1) - (2)].sym)->value != pc)
+ yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 7:
+
+/* Line 1455 of yacc.c */
+#line 84 "a.y"
+ {
+ (yyvsp[(1) - (2)].sym)->type = LLAB;
+ (yyvsp[(1) - (2)].sym)->value = pc;
+ }
+ break;
+
+ case 12:
+
+/* Line 1455 of yacc.c */
+#line 95 "a.y"
+ {
+ (yyvsp[(1) - (3)].sym)->type = LVAR;
+ (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 13:
+
+/* Line 1455 of yacc.c */
+#line 100 "a.y"
+ {
+ if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
+ yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
+ (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 14:
+
+/* Line 1455 of yacc.c */
+#line 105 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 15:
+
+/* Line 1455 of yacc.c */
+#line 106 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 16:
+
+/* Line 1455 of yacc.c */
+#line 107 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 17:
+
+/* Line 1455 of yacc.c */
+#line 108 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 18:
+
+/* Line 1455 of yacc.c */
+#line 109 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 19:
+
+/* Line 1455 of yacc.c */
+#line 110 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 20:
+
+/* Line 1455 of yacc.c */
+#line 111 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 21:
+
+/* Line 1455 of yacc.c */
+#line 112 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 22:
+
+/* Line 1455 of yacc.c */
+#line 113 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 23:
+
+/* Line 1455 of yacc.c */
+#line 114 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 24:
+
+/* Line 1455 of yacc.c */
+#line 115 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 25:
+
+/* Line 1455 of yacc.c */
+#line 116 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 26:
+
+/* Line 1455 of yacc.c */
+#line 117 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 27:
+
+/* Line 1455 of yacc.c */
+#line 118 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 28:
+
+/* Line 1455 of yacc.c */
+#line 121 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 29:
+
+/* Line 1455 of yacc.c */
+#line 126 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 30:
+
+/* Line 1455 of yacc.c */
+#line 133 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 31:
+
+/* Line 1455 of yacc.c */
+#line 140 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 32:
+
+/* Line 1455 of yacc.c */
+#line 147 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 33:
+
+/* Line 1455 of yacc.c */
+#line 152 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 34:
+
+/* Line 1455 of yacc.c */
+#line 159 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 35:
+
+/* Line 1455 of yacc.c */
+#line 164 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 36:
+
+/* Line 1455 of yacc.c */
+#line 171 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 37:
+
+/* Line 1455 of yacc.c */
+#line 176 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 38:
+
+/* Line 1455 of yacc.c */
+#line 183 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 39:
+
+/* Line 1455 of yacc.c */
+#line 191 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 40:
+
+/* Line 1455 of yacc.c */
+#line 196 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 41:
+
+/* Line 1455 of yacc.c */
+#line 204 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 42:
+
+/* Line 1455 of yacc.c */
+#line 209 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 43:
+
+/* Line 1455 of yacc.c */
+#line 214 "a.y"
+ {
+ (yyval.gen2).from = nullgen;
+ (yyval.gen2).to = (yyvsp[(2) - (2)].gen);
+ (yyval.gen2).to.index = (yyvsp[(2) - (2)].gen).type;
+ (yyval.gen2).to.type = D_INDIR+D_ADDR;
+ }
+ break;
+
+ case 46:
+
+/* Line 1455 of yacc.c */
+#line 227 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 47:
+
+/* Line 1455 of yacc.c */
+#line 232 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
+ if((yyval.gen2).from.index != D_NONE)
+ yyerror("dp shift with lhs index");
+ (yyval.gen2).from.index = (yyvsp[(5) - (5)].lval);
+ }
+ break;
+
+ case 48:
+
+/* Line 1455 of yacc.c */
+#line 242 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 49:
+
+/* Line 1455 of yacc.c */
+#line 247 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (5)].gen);
+ if((yyval.gen2).to.index != D_NONE)
+ yyerror("dp move with lhs index");
+ (yyval.gen2).to.index = (yyvsp[(5) - (5)].lval);
+ }
+ break;
+
+ case 50:
+
+/* Line 1455 of yacc.c */
+#line 257 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (2)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 51:
+
+/* Line 1455 of yacc.c */
+#line 262 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (1)].gen);
+ (yyval.gen2).to = nullgen;
+ }
+ break;
+
+ case 52:
+
+/* Line 1455 of yacc.c */
+#line 267 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 53:
+
+/* Line 1455 of yacc.c */
+#line 274 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (3)].gen);
+ (yyval.gen2).to = (yyvsp[(3) - (3)].gen);
+ }
+ break;
+
+ case 54:
+
+/* Line 1455 of yacc.c */
+#line 279 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(1) - (5)].gen);
+ (yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ }
+ break;
+
+ case 59:
+
+/* Line 1455 of yacc.c */
+#line 293 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 60:
+
+/* Line 1455 of yacc.c */
+#line 297 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ }
+ break;
+
+ case 66:
+
+/* Line 1455 of yacc.c */
+#line 310 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval) + pc;
+ }
+ break;
+
+ case 67:
+
+/* Line 1455 of yacc.c */
+#line 316 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ if(pass == 2)
+ yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 68:
+
+/* Line 1455 of yacc.c */
+#line 325 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_BRANCH;
+ (yyval.gen).sym = (yyvsp[(1) - (2)].sym);
+ (yyval.gen).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 69:
+
+/* Line 1455 of yacc.c */
+#line 334 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 70:
+
+/* Line 1455 of yacc.c */
+#line 339 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 71:
+
+/* Line 1455 of yacc.c */
+#line 344 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 72:
+
+/* Line 1455 of yacc.c */
+#line 349 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SP;
+ }
+ break;
+
+ case 73:
+
+/* Line 1455 of yacc.c */
+#line 354 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 74:
+
+/* Line 1455 of yacc.c */
+#line 361 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 75:
+
+/* Line 1455 of yacc.c */
+#line 367 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(2) - (2)].gen);
+ (yyval.gen).index = (yyvsp[(2) - (2)].gen).type;
+ (yyval.gen).type = D_ADDR;
+ /*
+ if($2.type == D_AUTO || $2.type == D_PARAM)
+ yyerror("constant cannot be automatic: %s",
+ $2.sym->name);
+ */
+ }
+ break;
+
+ case 76:
+
+/* Line 1455 of yacc.c */
+#line 378 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_SCONST;
+ memcpy((yyval.gen).sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.gen).sval));
+ }
+ break;
+
+ case 77:
+
+/* Line 1455 of yacc.c */
+#line 384 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = (yyvsp[(2) - (2)].dval);
+ }
+ break;
+
+ case 78:
+
+/* Line 1455 of yacc.c */
+#line 390 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = (yyvsp[(3) - (4)].dval);
+ }
+ break;
+
+ case 79:
+
+/* Line 1455 of yacc.c */
+#line 396 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = -(yyvsp[(4) - (5)].dval);
+ }
+ break;
+
+ case 80:
+
+/* Line 1455 of yacc.c */
+#line 402 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_FCONST;
+ (yyval.gen).dval = -(yyvsp[(3) - (3)].dval);
+ }
+ break;
+
+ case 81:
+
+/* Line 1455 of yacc.c */
+#line 410 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_CONST2;
+ (yyval.gen).offset = (yyvsp[(2) - (2)].con2).v1;
+ (yyval.gen).offset2 = (yyvsp[(2) - (2)].con2).v2;
+ }
+ break;
+
+ case 82:
+
+/* Line 1455 of yacc.c */
+#line 419 "a.y"
+ {
+ (yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
+ (yyval.con2).v2 = 0;
+ }
+ break;
+
+ case 83:
+
+/* Line 1455 of yacc.c */
+#line 424 "a.y"
+ {
+ (yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
+ (yyval.con2).v2 = 0;
+ }
+ break;
+
+ case 84:
+
+/* Line 1455 of yacc.c */
+#line 429 "a.y"
+ {
+ (yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
+ (yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 85:
+
+/* Line 1455 of yacc.c */
+#line 434 "a.y"
+ {
+ (yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
+ (yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 88:
+
+/* Line 1455 of yacc.c */
+#line 445 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).offset = (yyvsp[(1) - (1)].lval);
+ }
+ break;
+
+ case 89:
+
+/* Line 1455 of yacc.c */
+#line 451 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 90:
+
+/* Line 1455 of yacc.c */
+#line 457 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_SP;
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 91:
+
+/* Line 1455 of yacc.c */
+#line 463 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).offset = (yyvsp[(1) - (6)].lval);
+ (yyval.gen).index = (yyvsp[(3) - (6)].lval);
+ (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 92:
+
+/* Line 1455 of yacc.c */
+#line 472 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.gen).index = (yyvsp[(6) - (9)].lval);
+ (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 93:
+
+/* Line 1455 of yacc.c */
+#line 481 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 94:
+
+/* Line 1455 of yacc.c */
+#line 486 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_SP;
+ }
+ break;
+
+ case 95:
+
+/* Line 1455 of yacc.c */
+#line 491 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (4)].lval);
+ }
+ break;
+
+ case 96:
+
+/* Line 1455 of yacc.c */
+#line 497 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+D_NONE;
+ (yyval.gen).index = (yyvsp[(2) - (5)].lval);
+ (yyval.gen).scale = (yyvsp[(4) - (5)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 97:
+
+/* Line 1455 of yacc.c */
+#line 505 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
+ (yyval.gen).index = (yyvsp[(5) - (8)].lval);
+ (yyval.gen).scale = (yyvsp[(7) - (8)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 98:
+
+/* Line 1455 of yacc.c */
+#line 515 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (1)].gen);
+ }
+ break;
+
+ case 99:
+
+/* Line 1455 of yacc.c */
+#line 519 "a.y"
+ {
+ (yyval.gen) = (yyvsp[(1) - (6)].gen);
+ (yyval.gen).index = (yyvsp[(3) - (6)].lval);
+ (yyval.gen).scale = (yyvsp[(5) - (6)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 100:
+
+/* Line 1455 of yacc.c */
+#line 528 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = (yyvsp[(4) - (5)].lval);
+ (yyval.gen).sym = (yyvsp[(1) - (5)].sym);
+ (yyval.gen).offset = (yyvsp[(2) - (5)].lval);
+ }
+ break;
+
+ case 101:
+
+/* Line 1455 of yacc.c */
+#line 535 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_STATIC;
+ (yyval.gen).sym = (yyvsp[(1) - (7)].sym);
+ (yyval.gen).offset = (yyvsp[(4) - (7)].lval);
+ }
+ break;
+
+ case 102:
+
+/* Line 1455 of yacc.c */
+#line 543 "a.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 103:
+
+/* Line 1455 of yacc.c */
+#line 547 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 104:
+
+/* Line 1455 of yacc.c */
+#line 551 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 106:
+
+/* Line 1455 of yacc.c */
+#line 558 "a.y"
+ {
+ (yyval.lval) = D_AUTO;
+ }
+ break;
+
+ case 109:
+
+/* Line 1455 of yacc.c */
+#line 566 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+ }
+ break;
+
+ case 110:
+
+/* Line 1455 of yacc.c */
+#line 570 "a.y"
+ {
+ (yyval.lval) = -(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 111:
+
+/* Line 1455 of yacc.c */
+#line 574 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 112:
+
+/* Line 1455 of yacc.c */
+#line 578 "a.y"
+ {
+ (yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+ }
+ break;
+
+ case 113:
+
+/* Line 1455 of yacc.c */
+#line 582 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(2) - (3)].lval);
+ }
+ break;
+
+ case 115:
+
+/* Line 1455 of yacc.c */
+#line 589 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 116:
+
+/* Line 1455 of yacc.c */
+#line 593 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 117:
+
+/* Line 1455 of yacc.c */
+#line 597 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 118:
+
+/* Line 1455 of yacc.c */
+#line 601 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 119:
+
+/* Line 1455 of yacc.c */
+#line 605 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 120:
+
+/* Line 1455 of yacc.c */
+#line 609 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 121:
+
+/* Line 1455 of yacc.c */
+#line 613 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+ }
+ break;
+
+ case 122:
+
+/* Line 1455 of yacc.c */
+#line 617 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 123:
+
+/* Line 1455 of yacc.c */
+#line 621 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+ case 124:
+
+/* Line 1455 of yacc.c */
+#line 625 "a.y"
+ {
+ (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+ }
+ break;
+
+
+
+/* Line 1455 of yacc.c */
+#line 2643 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
new file mode 100644
index 000000000..69a966a4b
--- /dev/null
+++ b/src/cmd/8a/y.tab.h
@@ -0,0 +1,135 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LTYPE0 = 258,
+ LTYPE1 = 259,
+ LTYPE2 = 260,
+ LTYPE3 = 261,
+ LTYPE4 = 262,
+ LTYPEC = 263,
+ LTYPED = 264,
+ LTYPEN = 265,
+ LTYPER = 266,
+ LTYPET = 267,
+ LTYPES = 268,
+ LTYPEM = 269,
+ LTYPEI = 270,
+ LTYPEG = 271,
+ LCONST = 272,
+ LFP = 273,
+ LPC = 274,
+ LSB = 275,
+ LBREG = 276,
+ LLREG = 277,
+ LSREG = 278,
+ LFREG = 279,
+ LFCONST = 280,
+ LSCONST = 281,
+ LSP = 282,
+ LNAME = 283,
+ LLAB = 284,
+ LVAR = 285
+ };
+#endif
+/* Tokens. */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPES 268
+#define LTYPEM 269
+#define LTYPEI 270
+#define LTYPEG 271
+#define LCONST 272
+#define LFP 273
+#define LPC 274
+#define LSB 275
+#define LBREG 276
+#define LLREG 277
+#define LSREG 278
+#define LFREG 279
+#define LFCONST 280
+#define LSCONST 281
+#define LSP 282
+#define LNAME 283
+#define LLAB 284
+#define LVAR 285
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1676 of yacc.c */
+#line 37 "a.y"
+
+ Sym *sym;
+ int32 lval;
+ struct {
+ int32 v1;
+ int32 v2;
+ } con2;
+ double dval;
+ char sval[8];
+ Gen gen;
+ Gen2 gen2;
+
+
+
+/* Line 1676 of yacc.c */
+#line 127 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
index 60f46d3c9..3f528d751 100644
--- a/src/cmd/8c/Makefile
+++ b/src/cmd/8c/Makefile
@@ -1,37 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8c
-
-HFILES=\
- gc.h\
- ../8l/8.out.h\
- ../cc/cc.h\
-
-OFILES=\
- cgen.$O\
- cgen64.$O\
- div.$O\
- list.$O\
- machcap.$O\
- mul.$O\
- pgen.$O\
- pswt.$O\
- peep.$O\
- reg.$O\
- sgen.$O\
- swt.$O\
- txt.$O\
- ../8l/enam.$O\
-
-LIB=\
- ../cc/cc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../cc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
index 7f02bd96e..869d31ace 100644
--- a/src/cmd/8c/cgen.c
+++ b/src/cmd/8c/cgen.c
@@ -1221,7 +1221,7 @@ void
boolgen(Node *n, int true, Node *nn)
{
int o;
- Prog *p1, *p2;
+ Prog *p1, *p2, *p3;
Node *l, *r, nod, nod1;
int32 curs;
@@ -1346,6 +1346,15 @@ boolgen(Node *n, int true, Node *nn)
cgen64(n, Z);
goto com;
}
+ if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
+ // Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
+ // Jump around instead.
+ boolgen(n, 0, Z);
+ p1 = p;
+ gbranch(OGOTO);
+ patch(p1, pc);
+ goto com;
+ }
if(true)
o = comrel[relindex(o)];
if(l->complex >= FNX && r->complex >= FNX) {
@@ -1378,6 +1387,30 @@ boolgen(Node *n, int true, Node *nn)
} else
fgopcode(o, l, &fregnode0, 0, 1);
}
+ switch(o) {
+ case OEQ:
+ // Already emitted AJEQ; want AJEQ and AJPC.
+ p1 = p;
+ gbranch(OGOTO);
+ p2 = p;
+ patch(p1, pc);
+ gins(AJPC, Z, Z);
+ patch(p2, pc);
+ break;
+
+ case ONE:
+ // Already emitted AJNE; want AJNE or AJPS.
+ p1 = p;
+ gins(AJPS, Z, Z);
+ p2 = p;
+ gbranch(OGOTO);
+ p3 = p;
+ patch(p1, pc);
+ patch(p2, pc);
+ gbranch(OGOTO);
+ patch(p3, pc);
+ break;
+ }
goto com;
}
if(l->op == OCONST) {
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
index 32b80e995..4a57f5d3c 100644
--- a/src/cmd/8c/gc.h
+++ b/src/cmd/8c/gc.h
@@ -304,7 +304,8 @@ void gpseudo(int, Sym*, Node*);
int swcmp(const void*, const void*);
void doswit(Node*);
void swit1(C1*, int, int32, Node*);
-void cas(void);
+void swit2(C1*, int, int32, Node*);
+void newcase(void);
void bitload(Node*, Node*, Node*, Node*, Node*);
void bitstore(Node*, Node*, Node*, Node*, Node*);
int32 outstring(char*, int32);
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index 769ef2c66..f1ca4c25f 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -33,6 +33,26 @@
void
swit1(C1 *q, int nc, int32 def, Node *n)
{
+ Node nreg;
+
+ if(typev[n->type->etype]) {
+ regsalloc(&nreg, n);
+ nreg.type = types[TVLONG];
+ cgen(n, &nreg);
+ swit2(q, nc, def, &nreg);
+ return;
+ }
+
+ regalloc(&nreg, n, Z);
+ nreg.type = types[TLONG];
+ cgen(n, &nreg);
+ swit2(q, nc, def, &nreg);
+ regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
C1 *r;
int i;
Prog *sp;
@@ -58,12 +78,12 @@ swit1(C1 *q, int nc, int32 def, Node *n)
gbranch(OGOTO);
p->as = AJEQ;
patch(p, r->label);
- swit1(q, i, def, n);
+ swit2(q, i, def, n);
if(debug['W'])
print("case < %.8ux\n", r->val);
patch(sp, pc);
- swit1(r+1, nc-i-1, def, n);
+ swit2(r+1, nc-i-1, def, n);
}
void
@@ -330,17 +350,13 @@ outhist(Biobuf *b)
for(h = hist; h != H; h = h->link) {
p = h->name;
op = 0;
- /* on windows skip drive specifier in pathname */
if(systemtype(Windows) && p && p[1] == ':'){
- p += 2;
- c = *p;
- }
- if(p && p[0] != c && h->offset == 0 && pathname){
- /* on windows skip drive specifier in pathname */
+ c = p[2];
+ } else if(p && p[0] != c && h->offset == 0 && pathname){
if(systemtype(Windows) && pathname[1] == ':') {
op = p;
- p = pathname+2;
- c = *p;
+ p = pathname;
+ c = p[2];
} else if(pathname[0] == c){
op = p;
p = pathname;
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index b2e0148a0..3a08da7cd 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -146,7 +146,9 @@ gclean(void)
continue;
if(s->type == types[TENUM])
continue;
+ textflag = s->dataflag;
gpseudo(AGLOBL, s, nodconst(s->type->width));
+ textflag = 0;
}
nextpc();
p->as = AEND;
@@ -372,7 +374,7 @@ regfree(Node *n)
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
i = n->reg;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
goto err;
if(reg[i] <= 0)
goto err;
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
index b459782a3..3f528d751 100644
--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -1,36 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8g
-
-HFILES=\
- ../gc/go.h\
- ../8l/8.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../8l/enam.$O\
- cgen.$O\
- cgen64.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index b316e6e34..48619ac73 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -5,6 +5,8 @@
// TODO(rsc):
// assume CLD?
+#include <u.h>
+#include <libc.h>
#include "gg.h"
void
@@ -96,6 +98,9 @@ cgen(Node *n, Node *res)
if(isslice(n->left->type))
n->addable = n->left->addable;
break;
+ case OITAB:
+ n->addable = n->left->addable;
+ break;
}
// if both are addressable, move
@@ -250,6 +255,13 @@ cgen(Node *n, Node *res)
regfree(&n1);
break;
+ case OITAB:
+ igen(nl, &n1, res);
+ n1.type = ptrto(types[TUINTPTR]);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
case OLEN:
if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
// map has len in the first 32-bit word.
@@ -680,7 +692,6 @@ agen(Node *n, Node *res)
break;
case ODOT:
- t = nl->type;
agen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[tptr], n->xoffset);
@@ -786,6 +797,7 @@ bgen(Node *n, int true, Prog *to)
int et, a;
Node *nl, *nr, *r;
Node n1, n2, tmp, t1, t2, ax;
+ NodeList *ll;
Prog *p1, *p2;
if(debug['g']) {
@@ -798,9 +810,6 @@ bgen(Node *n, int true, Prog *to)
if(n->ninit != nil)
genlist(n->ninit);
- nl = n->left;
- nr = n->right;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -813,7 +822,6 @@ bgen(Node *n, int true, Prog *to)
patch(gins(AEND, N, N), to);
return;
}
- nl = N;
nr = N;
switch(n->op) {
@@ -905,7 +913,10 @@ bgen(Node *n, int true, Prog *to)
p1 = gbranch(AJMP, T);
p2 = gbranch(AJMP, T);
patch(p1, pc);
+ ll = n->ninit; // avoid re-genning ninit
+ n->ninit = nil;
bgen(n, 1, p2);
+ n->ninit = ll;
patch(gbranch(AJMP, T), to);
patch(p2, pc);
break;
@@ -1129,24 +1140,29 @@ stkof(Node *n)
* memmove(&res, &n, w);
*/
void
-sgen(Node *n, Node *res, int32 w)
+sgen(Node *n, Node *res, int64 w)
{
Node dst, src, tdst, tsrc;
int32 c, q, odst, osrc;
if(debug['g']) {
- print("\nsgen w=%d\n", w);
+ print("\nsgen w=%lld\n", w);
dump("r", n);
dump("res", res);
}
- if(w == 0)
- return;
- if(n->ullman >= UINF && res->ullman >= UINF) {
+ if(n->ullman >= UINF && res->ullman >= UINF)
fatal("sgen UINF");
- }
- if(w < 0)
- fatal("sgen copy %d", w);
+ if(w < 0 || (int32)w != w)
+ fatal("sgen copy %lld", w);
+
+ if(w == 0) {
+ // evaluate side effects only.
+ tempname(&tdst, types[tptr]);
+ agen(res, &tdst);
+ agen(n, &tdst);
+ return;
+ }
// offset on the stack
osrc = stkof(n);
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
index ba99cec74..8e568a0f9 100644
--- a/src/cmd/8g/cgen64.c
+++ b/src/cmd/8g/cgen64.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
/*
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
index 2d9ff9a42..6d678eac8 100644
--- a/src/cmd/8g/doc.go
+++ b/src/cmd/8g/doc.go
@@ -9,7 +9,5 @@ The $GOARCH for these tools is 386.
It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
-There is no instruction optimizer, so the -N flag is a no-op.
-
*/
package documentation
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 7734603c4..4526a2efb 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
int thechar = '8';
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 9f7a66a29..0a4f0ad2d 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -2,16 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <u.h>
-#include <libc.h>
-
-#include "../gc/go.h"
-#include "../8l/8.out.h"
-
#ifndef EXTERN
#define EXTERN extern
#endif
+#include "../gc/go.h"
+#include "../8l/8.out.h"
+
typedef struct Addr Addr;
struct Addr
@@ -46,6 +43,8 @@ struct Prog
void* reg; // pointer to containing Reg struct
};
+#define TEXTFLAG from.scale
+
// foptoas flags
enum
{
@@ -54,15 +53,12 @@ enum
Fpop2 = 1<<2,
};
-EXTERN Biobuf* bout;
EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
extern char* anames[];
-EXTERN Hist* hist;
EXTERN Prog zprog;
-EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
@@ -103,7 +99,7 @@ void agenr(Node *n, Node *a, Node *res);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
+void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
@@ -168,12 +164,6 @@ void complexgen(Node*, Node*);
void complexbool(int, Node*, Node*, int, Prog*);
/*
- * gobj.c
- */
-void data(void);
-void text(void);
-
-/*
* list.c
*/
int Aconv(Fmt*);
@@ -185,3 +175,5 @@ void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
+#pragma varargck type "D" Addr*
+#pragma varargck type "lD" Addr*
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 108c493aa..6a4570199 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -4,6 +4,8 @@
#undef EXTERN
#define EXTERN
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -26,10 +28,10 @@ markautoused(Prog* p)
{
for (; p; p = p->link) {
if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
+ p->from.node->used = 1;
if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
+ p->to.node->used = 1;
}
}
@@ -429,7 +431,6 @@ hard:
if(nr->ullman >= nl->ullman || nl->addable) {
mgen(nr, &n2, N);
nr = &n2;
- nr = &n2;
} else {
tempname(&n2, nr->type);
cgen(nr, &n2);
@@ -483,8 +484,8 @@ void
dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
{
int check;
- Node n1, t1, t2, n4, nz;
- Type *t;
+ Node n1, t1, t2, t3, t4, n4, nz;
+ Type *t, *t0;
Prog *p1, *p2, *p3;
// Have to be careful about handling
@@ -496,6 +497,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
// For int32 and int64, use explicit test.
// Could use int64 hw for int32.
t = nl->type;
+ t0 = t;
check = 0;
if(issigned[t->etype]) {
check = 1;
@@ -514,8 +516,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
tempname(&t1, t);
tempname(&t2, t);
- cgen(nl, &t1);
- cgen(nr, &t2);
+ if(t0 != t) {
+ tempname(&t3, t0);
+ tempname(&t4, t0);
+ cgen(nl, &t3);
+ cgen(nr, &t4);
+ // Convert.
+ gmove(&t3, &t1);
+ gmove(&t4, &t2);
+ } else {
+ cgen(nl, &t1);
+ cgen(nr, &t2);
+ }
if(!samereg(ax, res) && !samereg(dx, res))
regalloc(&n1, t, res);
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index 31c42a3f2..d8c8f5ab9 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
void
@@ -276,54 +278,6 @@ dumpfuncs(void)
}
}
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
int
dsname(Sym *s, int off, char *t, int n)
{
@@ -354,6 +308,7 @@ datastring(char *s, int len, Addr *a)
sym = stringsym(s, len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = widthptr+4; // skip header
a->etype = TINT32;
}
@@ -370,6 +325,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
}
@@ -380,6 +336,17 @@ gdata(Node *nam, Node *nr, int wid)
Prog *p;
vlong v;
+ if(nr->op == OLITERAL) {
+ switch(nr->val.ctype) {
+ case CTCPLX:
+ gdatacomplex(nam, nr->val.u.cval);
+ return;
+ case CTSTR:
+ gdatastring(nam, nr->val.u.sval);
+ return;
+ }
+ }
+
if(wid == 8 && is64(nr->type)) {
v = mpgetfix(nr->val.u.xval);
p = gins(ADATA, nam, nodintconst(v));
@@ -547,6 +514,8 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
Prog *p;
Type *f;
+ USED(iface);
+
e = method->sym;
for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, rcvr, d, nil, 0);
@@ -626,7 +595,6 @@ out:
// but 6l has a bug, and it can't handle
// JMP instructions too close to the top of
// a new function.
- p = pc;
gins(ANOP, N, N);
}
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index a35c81eb1..5e89af04a 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
// TODO(rsc): Can make this bigger if we move
@@ -48,6 +50,10 @@ clearp(Prog *p)
pcloc++;
}
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
/*
* generate and return proc with p->as = as,
* linked into program. pc is next instruction.
@@ -57,10 +63,22 @@ prog(int as)
{
Prog *p;
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
+ if(as == ADATA || as == AGLOBL) {
+ if(ddumped)
+ fatal("already dumped data");
+ if(dpc == nil) {
+ dpc = mal(sizeof(*dpc));
+ dfirst = dpc;
+ }
+ p = dpc;
+ dpc = mal(sizeof(*dpc));
+ p->link = dpc;
+ } else {
+ p = pc;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p->link = pc;
+ }
if(lineno == 0) {
if(debug['K'])
@@ -69,10 +87,21 @@ prog(int as)
p->as = as;
p->lineno = lineno;
- p->link = pc;
return p;
}
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
/*
* generate a branch.
* t is ignored.
@@ -82,6 +111,7 @@ gbranch(int as, Type *t)
{
Prog *p;
+ USED(t);
p = prog(as);
p->to.type = D_BRANCH;
p->to.branch = P;
@@ -202,6 +232,8 @@ ggloblnod(Node *nam, int32 width)
p->to.offset = width;
if(nam->readonly)
p->from.scale = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->from.scale |= NOPTR;
}
void
@@ -753,7 +785,7 @@ ginit(void)
reg[resvd[i]]++;
}
-ulong regpc[D_NONE];
+uintptr regpc[D_NONE];
void
gclean(void)
@@ -822,7 +854,7 @@ regalloc(Node *n, Type *t, Node *o)
fprint(2, "registers allocated at\n");
for(i=D_AX; i<=D_DI; i++)
- fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
+ fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
yyerror("out of fixed registers");
goto err;
@@ -832,7 +864,6 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
}
yyerror("regalloc: unknown type %T", t);
- i = 0;
err:
nodreg(n, t, 0);
@@ -842,7 +873,7 @@ out:
if (i == D_SP)
print("alloc SP\n");
if(reg[i] == 0) {
- regpc[i] = (ulong)__builtin_return_address(0);
+ regpc[i] = (uintptr)getcallerpc(&n);
if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
dump("regalloc-o", o);
fatal("regalloc %R", i);
@@ -864,7 +895,7 @@ regfree(Node *n)
i = n->val.u.reg;
if(i == D_SP)
return;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
fatal("regfree: reg not allocated");
@@ -935,8 +966,15 @@ nodarg(Type *t, int fp)
fatal("nodarg: offset not computed for %T", t);
n->xoffset = t->width;
n->addable = 1;
+ n->orig = t->nname;
break;
}
+
+ // Rewrite argument named _ to __,
+ // or else the assignment to _ will be
+ // discarded during code generation.
+ if(isblank(n))
+ n->sym = lookup("__");
switch(fp) {
default:
@@ -1005,6 +1043,7 @@ int
ismem(Node *n)
{
switch(n->op) {
+ case OITAB:
case OLEN:
case OCAP:
case OINDREG:
@@ -1123,6 +1162,7 @@ memname(Node *n, Type *t)
strcpy(namebuf, n->sym->name);
namebuf[0] = '.'; // keep optimizer from registerizing
n->sym = lookup(namebuf);
+ n->orig->sym = n->sym;
}
void
@@ -1799,6 +1839,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->offset = n->xoffset;
a->sym = n->left->sym;
a->type = D_PARAM;
+ a->node = n->left->orig;
break;
case ONAME:
@@ -1809,9 +1850,11 @@ naddr(Node *n, Addr *a, int canemitcode)
a->width = n->type->width;
a->gotype = ngotype(n);
}
- a->pun = n->pun;
a->offset = n->xoffset;
a->sym = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
if(a->sym == S)
a->sym = lookup(".noname");
if(n->method) {
@@ -1829,8 +1872,6 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->type = D_AUTO;
- if (n->sym)
- a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
@@ -1853,6 +1894,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
+ case CTRUNE:
a->sym = S;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
@@ -1887,6 +1929,17 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
}
fatal("naddr: OADDR\n");
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->etype = tptr;
+ a->width = widthptr;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
case OLEN:
// len of string or slice
@@ -1955,5 +2008,9 @@ sudoclean(void)
int
sudoaddable(int as, Node *n, Addr *a)
{
+ USED(as);
+ USED(n);
+ USED(a);
+
return 0;
}
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
index edb1ece84..88d3d5f7e 100644
--- a/src/cmd/8g/list.c
+++ b/src/cmd/8g/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
static int sconsize;
@@ -128,7 +130,7 @@ Dconv(Fmt *fp)
if(fp->flags & FmtLong) {
d1 = a->offset;
d2 = a->offset2;
- snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
+ snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
break;
}
snprint(str, sizeof(str), "$%d", a->offset);
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
index 8f31dec3b..ed6eb15ab 100644
--- a/src/cmd/8g/opt.h
+++ b/src/cmd/8g/opt.h
@@ -162,3 +162,5 @@ int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
+
+#pragma varargck type "D" Adr*
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index 5ad29e1b2..b8a2825e5 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -876,13 +878,12 @@ loop:
case 3: // set
if(p->as == p0->as)
if(p->from.type == p0->from.type)
- if(p->from.sym == p0->from.sym)
+ if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
if(p->from.dval == p0->from.dval)
if(p->from.index == p0->from.index) {
excise(r);
- t++;
goto loop;
}
break;
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 2b878f62a..29270c820 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -28,9 +28,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
-#undef EXTERN
-#define EXTERN
#include "opt.h"
#define NREGVAR 8
@@ -39,6 +39,8 @@
static int first = 1;
+static void fixjmp(Prog*);
+
Reg*
rega(void)
{
@@ -89,8 +91,8 @@ setoutvar(void)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
+//if(bany(ovar))
+//print("ovars = %Q\n", ovar);
}
static void
@@ -98,19 +100,19 @@ setaddrs(Bits bit)
{
int i, n;
Var *v;
- Sym *s;
+ Node *node;
while(bany(&bit)) {
// convert each bit to a variable
i = bnum(bit);
- s = var[i].sym;
+ node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n)
+ if(v->node == node && v->name == n)
v->addr = 2;
}
}
@@ -132,6 +134,8 @@ regopt(Prog *firstp)
exregoffset = D_DI; // no externals
first = 0;
}
+
+ fixjmp(firstp);
// count instructions
nr = 0;
@@ -155,7 +159,7 @@ regopt(Prog *firstp)
nvar = NREGVAR;
memset(var, 0, NREGVAR*sizeof var[0]);
for(i=0; i<NREGVAR; i++)
- var[i].sym = lookup(regname[i]);
+ var[i].node = newname(lookup(regname[i]));
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
@@ -216,6 +220,9 @@ regopt(Prog *firstp)
* funny
*/
case ALEAL:
+ case AFMOVL:
+ case AFMOVW:
+ case AFMOVV:
setaddrs(bit);
break;
@@ -694,9 +701,9 @@ brk:
if(ostats.ndelmov)
print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4d delmov\n", ostats.nvar);
+ print(" %4d var\n", ostats.nvar);
if(ostats.naddr)
- print(" %4d delmov\n", ostats.naddr);
+ print(" %4d addr\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -725,19 +732,19 @@ addmove(Reg *r, int bn, int rn, int f)
v = var + bn;
a = &p1->to;
- a->sym = v->sym;
a->offset = v->offset;
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
a->node = v->node;
+ a->sym = v->node->sym;
// need to clean this up with wptr and
// some of the defaults
p1->as = AMOVL;
switch(v->etype) {
default:
- fatal("unknown type\n");
+ fatal("unknown type %E", v->etype);
case TINT8:
case TUINT8:
case TBOOL:
@@ -810,7 +817,7 @@ mkvar(Reg *r, Adr *a)
int i, t, n, et, z, w, flag, regu;
int32 o;
Bits bit;
- Sym *s;
+ Node *node;
/*
* mark registers used
@@ -847,10 +854,13 @@ mkvar(Reg *r, Adr *a)
break;
}
- s = a->sym;
- if(s == S)
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
goto none;
- if(s->name[0] == '.')
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
@@ -859,7 +869,7 @@ mkvar(Reg *r, Adr *a)
flag = 0;
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n) {
+ if(v->node == node && v->name == n) {
if(v->offset == o)
if(v->etype == et)
if(v->width == w)
@@ -868,7 +878,7 @@ mkvar(Reg *r, Adr *a)
// if they overlap, disable both
if(overlap(v->offset, v->width, o, w)) {
if(debug['R'])
- print("disable %s\n", v->sym->name);
+ print("disable %s\n", node->sym->name);
v->addr = 1;
flag = 1;
}
@@ -882,7 +892,7 @@ mkvar(Reg *r, Adr *a)
}
if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
+ if(debug['w'] > 1 && node != N)
fatal("variable not optimized: %D", a);
goto none;
}
@@ -890,17 +900,16 @@ mkvar(Reg *r, Adr *a)
i = nvar;
nvar++;
v = var+i;
- v->sym = s;
v->offset = o;
v->name = n;
v->gotype = a->gotype;
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
- v->node = a->node;
+ v->node = node;
if(debug['R'])
- print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
+ print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
ostats.nvar++;
bit = blsh(i);
@@ -959,6 +968,13 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
+
+ default:
+ // Work around for issue 1304:
+ // flush modified globals before each instruction.
+ for(z=0; z<BITS; z++)
+ cal.b[z] |= externs.b[z];
+ break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1095,10 +1111,12 @@ loopit(Reg *r, int32 nr)
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
+ // rpo2r[r->rpo] == r protects against considering dead code,
+ // which has r->rpo == 0.
+ if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
+ if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
@@ -1482,7 +1500,7 @@ dumpone(Reg *r)
if(bany(&r->refahead))
print(" ra:%Q ", r->refahead);
if(bany(&r->calbehind))
- print("cb:%Q ", r->calbehind);
+ print(" cb:%Q ", r->calbehind);
if(bany(&r->calahead))
print(" ca:%Q ", r->calahead);
if(bany(&r->regdiff))
@@ -1542,3 +1560,123 @@ noreturn(Prog *p)
return 1;
return 0;
}
+
+/*
+ * the code generator depends on being able to write out JMP
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+ int n;
+
+ n = 0;
+ while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+ if(++n > 10) {
+ *jmploop = 1;
+ break;
+ }
+ p = p->to.branch;
+ }
+ return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+ Prog *p;
+
+ for(p=firstp; p; p=p->link) {
+ if(p->reg != dead)
+ break;
+ p->reg = alive;
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch)
+ mark(p->to.branch);
+ if(p->as == AJMP || p->as == ARET || (p->as == ACALL && noreturn(p)))
+ break;
+ }
+}
+
+static void
+fixjmp(Prog *firstp)
+{
+ int jmploop;
+ Prog *p, *last;
+
+ if(debug['R'] && debug['v'])
+ print("\nfixjmp\n");
+
+ // pass 1: resolve jump to AJMP, mark all code as dead.
+ jmploop = 0;
+ for(p=firstp; p; p=p->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n", p);
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AJMP) {
+ p->to.branch = chasejmp(p->to.branch, &jmploop);
+ if(debug['R'] && debug['v'])
+ print("->%P\n", p);
+ }
+ p->reg = dead;
+ }
+ if(debug['R'] && debug['v'])
+ print("\n");
+
+ // pass 2: mark all reachable code alive
+ mark(firstp);
+
+ // pass 3: delete dead code (mostly JMPs).
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->reg == dead) {
+ if(p->link == P && p->as == ARET && last && last->as != ARET) {
+ // This is the final ARET, and the code so far doesn't have one.
+ // Let it stay.
+ } else {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+
+ // pass 4: elide JMP to next instruction.
+ // only safe if there are no jumps to JMPs anymore.
+ if(!jmploop) {
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->as == AJMP && p->to.type == D_BRANCH && p->to.branch == p->link) {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+ }
+
+ if(debug['R'] && debug['v']) {
+ print("\n");
+ for(p=firstp; p; p=p->link)
+ print("%P\n", p);
+ print("\n");
+ }
+}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index 9a8483aaf..9d2751cf0 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -34,6 +34,7 @@
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
#define RODATA (1<<3)
+#define NOPTR (1<<4)
enum as
{
@@ -115,7 +116,8 @@ enum as
AIRETW,
AJCC,
AJCS,
- AJCXZ,
+ AJCXZL,
+ AJCXZW,
AJEQ,
AJGE,
AJGT,
@@ -394,7 +396,9 @@ enum as
ACMPXCHGL,
ACMPXCHGW,
ACMPXCHG8B,
-
+
+ ARDTSC,
+
AXADDB,
AXADDL,
AXADDW,
@@ -442,6 +446,12 @@ enum as
AFCMOVNU,
AFCMOVUN,
+ ALFENCE,
+ AMFENCE,
+ ASFENCE,
+
+ AEMMS,
+
ALAST
};
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index 7d34e1704..3f528d751 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -1,49 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8l
-
-OFILES=\
- asm.$O\
- data.$O\
- dwarf.$O\
- elf.$O\
- enam.$O\
- go.$O\
- ldelf.$O\
- ldmacho.$O\
- ldpe.$O\
- lib.$O\
- list.$O\
- macho.$O\
- obj.$O\
- optab.$O\
- pass.$O\
- pe.$O\
- prof.$O\
- span.$O\
- symtab.$O\
-
-
-HFILES=\
- l.h\
- 8.out.h\
- ../ld/dwarf.h\
- ../ld/elf.h\
- ../ld/macho.h\
- ../ld/pe.h\
-
-include ../../Make.ccmd
-
-enam.c: 8.out.h
- sh mkenam
-
-CLEANFILES+=enam.c
-
-
-%.$O: ../ld/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
+include ../../Make.dist
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 22abd8049..25ffc786f 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -37,10 +37,10 @@
#include "../ld/macho.h"
#include "../ld/pe.h"
-#define Dbufslop 100
-
char linuxdynld[] = "/lib/ld-linux.so.2";
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
+char openbsddynld[] = "/usr/libexec/ld.so";
+char netbsddynld[] = "/usr/libexec/ld.elf_so";
int32
entryvalue(void)
@@ -90,6 +90,9 @@ enum {
ElfStrPlt,
ElfStrGnuVersion,
ElfStrGnuVersionR,
+ ElfStrNoteNetbsdIdent,
+ ElfStrNoPtrData,
+ ElfStrNoPtrBss,
NElfStr
};
@@ -107,6 +110,7 @@ needlib(char *name)
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
s = lookup(p, 0);
+ free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
return 1;
@@ -416,7 +420,7 @@ adddynsym(Sym *s)
return;
if(s->dynimpname == nil)
- diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);
+ diag("adddynsym: no dynamic name for %s", s->name);
if(iself) {
s->dynid = nelfsym++;
@@ -524,8 +528,12 @@ doelf(void)
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
+ elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss");
+ if(HEADTYPE == Hnetbsd)
+ elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident");
addstring(shstrtab, ".elfdata");
addstring(shstrtab, ".rodata");
addstring(shstrtab, ".gosymtab");
@@ -606,7 +614,7 @@ doelf(void)
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s->reachable = 1;
- s->type = SELFROSECT;
+ s->type = SELFSECT; // writable
/*
* .dynamic table
@@ -626,6 +634,8 @@ doelf(void)
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
+ elfwritedynent(s, DT_DEBUG, 0);
+
// Do not write DT_NULL. elfdynhash will finish it.
}
}
@@ -657,7 +667,7 @@ asmb(void)
{
int32 v, magic;
int a, dynsym;
- uint32 symo, startva, machlink;
+ uint32 symo, startva, dwarfoff, machlink, resoff;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -688,8 +698,19 @@ asmb(void)
datblk(segdata.vaddr, segdata.filelen);
machlink = 0;
- if(HEADTYPE == Hdarwin)
+ if(HEADTYPE == Hdarwin) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ cseek(dwarfoff);
+
+ segdwarf.fileoff = cpos();
+ dwarfemitdebugsections();
+ segdwarf.filelen = cpos() - segdwarf.fileoff;
+
machlink = domacholink();
+ }
if(iself) {
/* index of elf text section; needed by asmelfsym, double-checked below */
@@ -700,6 +721,8 @@ asmb(void)
if(elfverneed)
elftextsh += 2;
}
+ if(HEADTYPE == Hnetbsd)
+ elftextsh += 1;
}
symsize = 0;
@@ -746,7 +769,7 @@ asmb(void)
default:
if(iself) {
if(debug['v'])
- Bprint(&bso, "%5.2f elfsym\n", cputime());
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
asmelfsym();
cflush();
cwrite(elfstrdat, elfstrsize);
@@ -769,7 +792,6 @@ asmb(void)
cflush();
}
break;
- case Hdarwin:
case Hwindows:
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
@@ -918,6 +940,7 @@ asmb(void)
Elfput:
eh = getElfEhdr();
startva = INITTEXT - HEADR;
+ resoff = ELFRESERVE;
/* This null SHdr must appear before all others */
newElfShdr(elfstr[ElfStrEmpty]);
@@ -956,9 +979,15 @@ asmb(void)
case Hfreebsd:
interpreter = freebsddynld;
break;
+ case Hnetbsd:
+ interpreter = netbsddynld;
+ break;
+ case Hopenbsd:
+ interpreter = openbsddynld;
+ break;
}
}
- elfinterp(sh, startva, interpreter);
+ resoff -= elfinterp(sh, startva, resoff, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
@@ -966,11 +995,27 @@ asmb(void)
phsh(ph, sh);
}
+ if(HEADTYPE == Hnetbsd) {
+ sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]);
+ sh->type = SHT_NOTE;
+ sh->flags = SHF_ALLOC;
+ sh->addralign = 4;
+ resoff -= elfnetbsdsig(sh, startva, resoff);
+
+ ph = newElfPhdr();
+ ph->type = PT_NOTE;
+ ph->flags = PF_R;
+ phsh(ph, sh);
+ }
+
+ // Additions to the reserved area must be above this line.
+ USED(resoff);
+
elfphload(&segtext);
elfphload(&segdata);
/* Dynamic linking sections */
- if (!debug['d']) { /* -d suppresses dynamic loader format */
+ if(!debug['d']) { /* -d suppresses dynamic loader format */
/* S headers for dynamic linking */
sh = newElfShdr(elfstr[ElfStrGot]);
sh->type = SHT_PROGBITS;
@@ -1094,7 +1139,7 @@ asmb(void)
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
- if (!debug['s']) {
+ if(!debug['s']) {
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
sh->off = symo;
@@ -1122,7 +1167,13 @@ asmb(void)
eh->ident[EI_VERSION] = EV_CURRENT;
switch(HEADTYPE) {
case Hfreebsd:
- eh->ident[EI_OSABI] = 9;
+ eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ break;
+ case Hnetbsd:
+ eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
+ break;
+ case Hopenbsd:
+ eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
break;
}
@@ -1141,8 +1192,10 @@ asmb(void)
a += elfwritehdr();
a += elfwritephdrs();
a += elfwriteshdrs();
- cflush();
- if(a+elfwriteinterp() > ELFRESERVE)
+ a += elfwriteinterp(elfstr[ElfStrInterp]);
+ if(HEADTYPE == Hnetbsd)
+ a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]);
+ if(a > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
@@ -1205,12 +1258,16 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case SSTRING:
case SGOSTRING:
case SWINDOWS:
+ case SNOPTRDATA:
+ case SSYMTAB:
+ case SPCLNTAB:
if(!s->reachable)
continue;
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
continue;
case SBSS:
+ case SNOPTRBSS:
if(!s->reachable)
continue;
put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
index b70888907..12301d4f2 100644
--- a/src/cmd/8l/doc.go
+++ b/src/cmd/8l/doc.go
@@ -4,47 +4,10 @@
/*
-8l is a modified version of the Plan 9 linker. The original is documented at
-
- http://plan9.bell-labs.com/magic/man2html/1/2l
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-It reads files in .8 format generated by 8g, 8c, and 8a and emits
-a binary called 8.out by default.
-
-Major changes include:
- - support for ELF and Mach-O binary files
- - support for segmented stacks (this feature is implemented here, not in the compilers).
-
-
-Original options are listed in the link above.
-
-Options new in this version:
-
--d
- Elide the dynamic linking header. With this option, the binary
- is statically linked and does not refer to dynld. Without this option
- (the default), the binary's contents are identical but it is loaded with dynld.
--Hplan9
- Write Plan 9 32-bit format binaries (default when $GOOS is plan9)
--Hdarwin
- Write Apple Mach-O binaries (default when $GOOS is darwin)
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--Hfreebsd
- Write FreeBSD ELF binaries (default when $GOOS is freebsd)
--Hwindows
- Write Windows PE32 binaries (default when $GOOS is windows)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_386.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
+8l is the linker for the 32-bit x86.
+The $GOARCH for these tools is 386.
+The flags are documented in ../ld/doc.go.
*/
package documentation
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 4ee0db967..b974f464b 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -134,6 +134,7 @@ struct Sym
int32 dynid;
int32 plt;
int32 got;
+ int32 align; // if non-zero, required alignment in bytes
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
Sym* next; // in text or data list
@@ -209,6 +210,7 @@ enum
Zbr,
Zcall,
Zcallcon,
+ Zcallind,
Zib_,
Zib_rp,
Zibo_m,
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index a8e1c34a5..af4bc844f 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -47,17 +47,19 @@ char *noname = "<none>";
char *thestring = "386";
Header headers[] = {
- "garbunix", Hgarbunix,
- "unixcoff", Hunixcoff,
- "plan9", Hplan9x32,
- "msdoscom", Hmsdoscom,
- "msdosexe", Hmsdosexe,
- "darwin", Hdarwin,
- "linux", Hlinux,
- "freebsd", Hfreebsd,
- "windows", Hwindows,
- "windowsgui", Hwindows,
- 0, 0
+ "garbunix", Hgarbunix,
+ "unixcoff", Hunixcoff,
+ "plan9", Hplan9x32,
+ "msdoscom", Hmsdoscom,
+ "msdosexe", Hmsdosexe,
+ "darwin", Hdarwin,
+ "linux", Hlinux,
+ "freebsd", Hfreebsd,
+ "netbsd", Hnetbsd,
+ "openbsd", Hopenbsd,
+ "windows", Hwindows,
+ "windowsgui", Hwindows,
+ 0, 0
};
/*
@@ -69,6 +71,8 @@ Header headers[] = {
* -Hdarwin -Tx -Rx is Apple Mach-O
* -Hlinux -Tx -Rx is Linux ELF32
* -Hfreebsd -Tx -Rx is FreeBSD ELF32
+ * -Hnetbsd -Tx -Rx is NetBSD ELF32
+ * -Hopenbsd -Tx -Rx is OpenBSD ELF32
* -Hwindows -Tx -Rx is MS Windows PE32
*/
@@ -83,6 +87,7 @@ void
main(int argc, char *argv[])
{
int c;
+ char *name, *val;
Binit(&bso, 1, OWRITE);
listinit();
@@ -94,6 +99,7 @@ main(int argc, char *argv[])
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
+ nuxiinit();
ARGBEGIN {
default:
@@ -133,6 +139,11 @@ main(int argc, char *argv[])
case 'V':
print("%cl version %s\n", thechar, getgoversion());
errorexit();
+ case 'X':
+ name = EARGF(usage());
+ val = EARGF(usage());
+ addstrdata(name, val);
+ break;
} ARGEND
if(argc != 1)
@@ -209,7 +220,7 @@ main(int argc, char *argv[])
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from %gs to our TLS.
- * Explained in ../../libcgo/darwin_386.c.
+ * Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c.
*/
tlsoffset = 0x468;
machoinit();
@@ -223,11 +234,13 @@ main(int argc, char *argv[])
break;
case Hlinux: /* elf32 executable */
case Hfreebsd:
+ case Hnetbsd:
+ case Hopenbsd:
/*
* ELF uses TLS offsets negative from %gs.
* Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
- * Also known to ../../pkg/runtime/linux/386/sys.s
- * and ../../libcgo/linux_386.c.
+ * Also known to ../../pkg/runtime/sys_linux_386.s
+ * and ../../pkg/runtime/cgo/gcc_linux_386.c.
*/
tlsoffset = -8;
elfinit();
@@ -269,7 +282,6 @@ main(int argc, char *argv[])
zprg.to = zprg.from;
pcstr = "%.6ux ";
- nuxiinit();
histgen = 0;
pc = 0;
dtype = 4;
@@ -477,7 +489,7 @@ loop:
sig = 1729;
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures"
+ diag("incompatible type signatures "
"%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
@@ -551,7 +563,7 @@ loop:
s->type = SBSS;
s->size = 0;
}
- if(s->type != SBSS && !s->dupok) {
+ if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
@@ -563,6 +575,8 @@ loop:
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
+ else if(p->from.scale & NOPTR)
+ s->type = SNOPTRBSS;
goto loop;
case ADATA:
@@ -594,6 +608,10 @@ loop:
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
+ if(p->from.scale & DUPOK) {
+ skip = 1;
+ goto casdef;
+ }
diag("%s: %s: redefinition", pn, s->name);
return;
}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index f5c195d75..856482290 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -260,6 +260,7 @@ uchar yloop[] =
uchar ycall[] =
{
Ynone, Yml, Zo_m, 2,
+ Ynone, Ycol, Zcallind, 2,
Ynone, Ybr, Zcall, 0,
Ynone, Yi32, Zcallcon, 1,
0
@@ -383,7 +384,7 @@ Optab optab[] =
{ ABTSL, yml_rl, Pm, 0xab },
{ ABTSW, yml_rl, Pq, 0xab },
{ ABYTE, ybyte, Px, 1 },
- { ACALL, ycall, Px, 0xff,(02),0xe8 },
+ { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 },
{ ACLC, ynone, Px, 0xf8 },
{ ACLD, ynone, Px, 0xfc },
{ ACLI, ynone, Px, 0xfa },
@@ -430,7 +431,8 @@ Optab optab[] =
{ AIRETW, ynone, Pe, 0xcf },
{ AJCC, yjcond, Px, 0x73,0x83,(00) },
{ AJCS, yjcond, Px, 0x72,0x82 },
- { AJCXZ, yloop, Px, 0xe3 },
+ { AJCXZL, yloop, Px, 0xe3 },
+ { AJCXZW, yloop, Px, 0xe3 },
{ AJEQ, yjcond, Px, 0x74,0x84 },
{ AJGE, yjcond, Px, 0x7d,0x8d },
{ AJGT, yjcond, Px, 0x7f,0x8f },
@@ -705,6 +707,8 @@ Optab optab[] =
{ ACMPXCHGW, yrl_ml, Pm, 0xb1 },
{ ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { ARDTSC, ynone, Pm, 0x31 },
+
{ AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
{ AXADDL, yrl_ml, Pm, 0xc1 },
{ AXADDW, yrl_ml, Pe, 0x0f,0xc1 },
@@ -751,5 +755,11 @@ Optab optab[] =
{ AFCMOVNU, yfcmv, Px, 0xdb,(03) },
{ AFCMOVUN, yfcmv, Px, 0xda,(03) },
+ { ALFENCE, ynone, Pm, 0xae,0xe8 },
+ { AMFENCE, ynone, Pm, 0xae,0xf0 },
+ { ASFENCE, ynone, Pm, 0xae,0xf8 },
+
+ { AEMMS, ynone, Pm, 0x77 },
+
0
};
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 2e0990c5a..9034fdf3a 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -259,7 +259,7 @@ patch(void)
// Convert
// op n(GS), reg
// to
- // MOVL 0x2C(FS), reg
+ // MOVL 0x14(FS), reg
// op n(reg), reg
// The purpose of this patch is to fix some accesses
// to extern register variables (TLS) on Windows, as
@@ -273,7 +273,7 @@ patch(void)
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2C;
+ p->from.offset = 0x14;
}
}
if(HEADTYPE == Hlinux) {
@@ -307,9 +307,12 @@ patch(void)
p->from.offset = 0;
}
}
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
+ if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH)) {
s = p->to.sym;
- if(s) {
+ if(p->to.type == D_INDIR+D_ADDR) {
+ /* skip check if this is an indirect call (CALL *symbol(SB)) */
+ continue;
+ } else if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
if((s->type&~SSUB) != STEXT) {
@@ -421,7 +424,7 @@ dostkoff(void)
case Hwindows:
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2c;
+ p->from.offset = 0x14;
p->to.type = D_CX;
p = appendp(p);
@@ -524,10 +527,18 @@ dostkoff(void)
p = appendp(p); // save frame size in DX
p->as = AMOVL;
p->to.type = D_DX;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
p->from.type = D_CONST;
- if(autoffset+160+cursym->text->to.offset2 > 4096)
- p->from.offset = (autoffset+160) & ~7LL;
+
+ // If we ask for more stack, we'll get a minimum of StackMin bytes.
+ // We need a stack frame large enough to hold the top-of-stack data,
+ // the function arguments+results, our caller's PC, our frame,
+ // a word for the return PC of the next call, and then the StackLimit bytes
+ // that must be available on entry to any function called from a function
+ // that did a stack check. If StackMin is enough, don't ask for a specific
+ // amount: then we can use the custom functions and save a few
+ // instructions.
+ if(StackTop + cursym->text->to.offset2 + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
+ p->from.offset = (autoffset+7) & ~7LL;
p = appendp(p); // save arg size in AX
p->as = AMOVL;
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index a4cba1257..81c1d37eb 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -83,7 +83,10 @@ span1(Sym *s)
loop++;
q->back ^= 2;
}
- s->p[q->pc+1] = v;
+ if(q->as == AJCXZW)
+ s->p[q->pc+2] = v;
+ else
+ s->p[q->pc+1] = v;
} else {
bp = s->p + q->pc + q->mark - 4;
*bp++ = v;
@@ -282,6 +285,8 @@ oclass(Adr *a)
}
return Yxxx;
}
+ //if(a->type == D_INDIR+D_ADDR)
+ // print("*Ycol\n");
return Ycol;
}
return Ym;
@@ -1056,9 +1061,10 @@ found:
case Zbr:
case Zjmp:
+ case Zloop:
q = p->pcond;
if(q == nil) {
- diag("jmp/branch without target");
+ diag("jmp/branch/loop without target");
errorexit();
}
if(q->as == ATEXT) {
@@ -1084,8 +1090,12 @@ found:
if(p->back & 1) {
v = q->pc - (p->pc + 2);
if(v >= -128) {
+ if(p->as == AJCXZW)
+ *andptr++ = 0x67;
*andptr++ = op;
*andptr++ = v;
+ } else if(t[2] == Zloop) {
+ diag("loop too far: %P", p);
} else {
v -= 5-2;
if(t[2] == Zbr) {
@@ -1105,8 +1115,12 @@ found:
p->forwd = q->comefrom;
q->comefrom = p;
if(p->back & 2) { // short
+ if(p->as == AJCXZW)
+ *andptr++ = 0x67;
*andptr++ = op;
*andptr++ = 0;
+ } else if(t[2] == Zloop) {
+ diag("loop too far: %P", p);
} else {
if(t[2] == Zbr)
*andptr++ = 0x0f;
@@ -1131,18 +1145,17 @@ found:
r->add = p->to.offset;
put4(0);
break;
-
- case Zloop:
- q = p->pcond;
- if(q == nil) {
- diag("loop without target");
- errorexit();
- }
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
+
+ case Zcallind:
*andptr++ = op;
- *andptr++ = v;
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->add = p->to.offset;
+ r->sym = p->to.sym;
+ put4(0);
break;
case Zbyte:
diff --git a/src/cmd/Makefile b/src/cmd/Makefile
deleted file mode 100644
index 5a37733de..000000000
--- a/src/cmd/Makefile
+++ /dev/null
@@ -1,69 +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.
-
-include ../Make.inc
-
-all: install
-
-# Only build tools for current architecture, and only tools written in C.
-# The tools written in Go are managed by ../pkg/Makefile.
-DIRS=\
- $(O)a\
- $(O)c\
- $(O)g\
- $(O)l\
- cc\
- cov\
- gc\
- godefs\
- gopack\
- gotry\
- nm\
- prof\
-
-# Clean applies to all directories, even for other architectures or
-# written in Go.
-CLEANDIRS=\
- $(DIRS)\
- 5a\
- 5c\
- 5g\
- 5l\
- 6a\
- 6c\
- 6g\
- 6l\
- 8a\
- 8c\
- 8g\
- 8l\
- cgo\
- ebnflint\
- godoc\
- gofix\
- gofmt\
- goinstall\
- gotest\
- gotype\
- goyacc\
- hgpatch\
-
-install: $(patsubst %,%.install,$(DIRS))
-clean: $(patsubst %,%.clean,$(CLEANDIRS))
-
-%.install:
- @echo
- @echo %%%% making $* %%%%
- @echo
- $(MAKE) -C $* install
-
-gc.install $(O)c.install: cc.install
-$(O)g.install: gc.install
-$(O)a.install $(O)c.install $(O)g.install: $(O)l.install
-
-%.clean:
- $(MAKE) -C $* clean
-
-echo-dirs:
- @echo $(DIRS)
diff --git a/src/cmd/addr2line/main.c b/src/cmd/addr2line/main.c
new file mode 100644
index 000000000..6b2fe5dfe
--- /dev/null
+++ b/src/cmd/addr2line/main.c
@@ -0,0 +1,68 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * addr2line simulation - only enough to make pprof work on Macs
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+void
+usage(void)
+{
+ fprint(2, "usage: addr2line binary\n");
+ fprint(2, "reads addresses from standard input and writes two lines for each:\n");
+ fprint(2, "\tfunction name\n");
+ fprint(2, "\tfile:line\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd;
+ char *p;
+ uvlong pc;
+ Symbol s;
+ Fhdr fhdr;
+ Biobuf bin, bout;
+ char file[1024];
+
+ ARGBEGIN{
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("open %s: %r", argv[0]);
+ if(crackhdr(fd, &fhdr) <= 0)
+ sysfatal("crackhdr: %r");
+ machbytype(fhdr.type);
+ if(syminit(fd, &fhdr) <= 0)
+ sysfatal("syminit: %r");
+
+ Binit(&bin, 0, OREAD);
+ Binit(&bout, 1, OWRITE);
+ for(;;) {
+ p = Brdline(&bin, '\n');
+ if(p == nil)
+ break;
+ p[Blinelen(&bin)-1] = '\0';
+ pc = strtoull(p, 0, 16);
+ if(!findsym(pc, CTEXT, &s))
+ s.name = "??";
+ if(!fileline(file, sizeof file, pc))
+ strcpy(file, "??:0");
+ Bprint(&bout, "%s\n%s\n", s.name, file);
+ }
+ Bflush(&bout);
+ exits(0);
+}
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
new file mode 100644
index 000000000..7363f6d82
--- /dev/null
+++ b/src/cmd/api/goapi.go
@@ -0,0 +1,1005 @@
+// 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.
+
+// Api computes the exported API of a set of Go packages.
+//
+// BUG(bradfitz): Note that this tool is only currently suitable
+// for use on the Go standard library, not arbitrary packages.
+// Once the Go AST has type information, this tool will be more
+// reliable without hard-coded hacks throughout.
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// Flags
+var (
+ checkFile = flag.String("c", "", "optional filename to check API against")
+ verbose = flag.Bool("v", false, "Verbose debugging")
+)
+
+var contexts = []*build.Context{
+ {GOOS: "linux", GOARCH: "386", CgoEnabled: true},
+ {GOOS: "linux", GOARCH: "386"},
+ {GOOS: "linux", GOARCH: "amd64", CgoEnabled: true},
+ {GOOS: "linux", GOARCH: "amd64"},
+ {GOOS: "darwin", GOARCH: "386", CgoEnabled: true},
+ {GOOS: "darwin", GOARCH: "386"},
+ {GOOS: "darwin", GOARCH: "amd64", CgoEnabled: true},
+ {GOOS: "darwin", GOARCH: "amd64"},
+ {GOOS: "windows", GOARCH: "amd64"},
+ {GOOS: "windows", GOARCH: "386"},
+}
+
+func init() {
+ for _, c := range contexts {
+ c.Compiler = build.Default.Compiler
+ }
+}
+
+func contextName(c *build.Context) string {
+ s := c.GOOS + "-" + c.GOARCH
+ if c.CgoEnabled {
+ return s + "-cgo"
+ }
+ return s
+}
+
+func main() {
+ flag.Parse()
+
+ var pkgs []string
+ if flag.NArg() > 0 {
+ pkgs = flag.Args()
+ } else {
+ stds, err := exec.Command("go", "list", "std").Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ pkgs = strings.Fields(string(stds))
+ }
+
+ var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true
+ for _, context := range contexts {
+ w := NewWalker()
+ w.context = context
+
+ for _, pkg := range pkgs {
+ w.wantedPkg[pkg] = true
+ }
+
+ for _, pkg := range pkgs {
+ if strings.HasPrefix(pkg, "cmd/") ||
+ strings.HasPrefix(pkg, "exp/") ||
+ strings.HasPrefix(pkg, "old/") {
+ continue
+ }
+ if fi, err := os.Stat(filepath.Join(w.root, pkg)); err != nil || !fi.IsDir() {
+ log.Fatalf("no source in tree for package %q", pkg)
+ }
+ w.WalkPackage(pkg)
+ }
+ ctxName := contextName(context)
+ for _, f := range w.Features() {
+ if featureCtx[f] == nil {
+ featureCtx[f] = make(map[string]bool)
+ }
+ featureCtx[f][ctxName] = true
+ }
+ }
+
+ var features []string
+ for f, cmap := range featureCtx {
+ if len(cmap) == len(contexts) {
+ features = append(features, f)
+ continue
+ }
+ comma := strings.Index(f, ",")
+ for cname := range cmap {
+ f2 := fmt.Sprintf("%s (%s)%s", f[:comma], cname, f[comma:])
+ features = append(features, f2)
+ }
+ }
+ sort.Strings(features)
+
+ bw := bufio.NewWriter(os.Stdout)
+ defer bw.Flush()
+
+ if *checkFile != "" {
+ bs, err := ioutil.ReadFile(*checkFile)
+ if err != nil {
+ log.Fatalf("Error reading file %s: %v", *checkFile, err)
+ }
+ v1 := strings.Split(strings.TrimSpace(string(bs)), "\n")
+ sort.Strings(v1)
+ v2 := features
+ take := func(sl *[]string) string {
+ s := (*sl)[0]
+ *sl = (*sl)[1:]
+ return s
+ }
+ changes := false
+ for len(v1) > 0 || len(v2) > 0 {
+ switch {
+ case len(v2) == 0 || v1[0] < v2[0]:
+ fmt.Fprintf(bw, "-%s\n", take(&v1))
+ changes = true
+ case len(v1) == 0 || v1[0] > v2[0]:
+ fmt.Fprintf(bw, "+%s\n", take(&v2))
+ changes = true
+ default:
+ take(&v1)
+ take(&v2)
+ }
+ }
+ if changes {
+ bw.Flush()
+ os.Exit(1)
+ }
+ } else {
+ for _, f := range features {
+ fmt.Fprintf(bw, "%s\n", f)
+ }
+ }
+}
+
+// pkgSymbol represents a symbol in a package
+type pkgSymbol struct {
+ pkg string // "net/http"
+ symbol string // "RoundTripper"
+}
+
+type Walker struct {
+ context *build.Context
+ root string
+ fset *token.FileSet
+ scope []string
+ features map[string]bool // set
+ lastConstType string
+ curPackageName string
+ curPackage *ast.Package
+ prevConstType map[pkgSymbol]string
+ constDep map[string]string // key's const identifier has type of future value const identifier
+ packageState map[string]loadState
+ interfaces map[pkgSymbol]*ast.InterfaceType
+ functionTypes map[pkgSymbol]string // symbol => return type
+ selectorFullPkg map[string]string // "http" => "net/http", updated by imports
+ wantedPkg map[string]bool // packages requested on the command line
+}
+
+func NewWalker() *Walker {
+ return &Walker{
+ fset: token.NewFileSet(),
+ features: make(map[string]bool),
+ packageState: make(map[string]loadState),
+ interfaces: make(map[pkgSymbol]*ast.InterfaceType),
+ functionTypes: make(map[pkgSymbol]string),
+ selectorFullPkg: make(map[string]string),
+ wantedPkg: make(map[string]bool),
+ prevConstType: make(map[pkgSymbol]string),
+ root: filepath.Join(build.Default.GOROOT, "src/pkg"),
+ }
+}
+
+// loadState is the state of a package's parsing.
+type loadState int
+
+const (
+ notLoaded loadState = iota
+ loading
+ loaded
+)
+
+// hardCodedConstantType is a hack until the type checker is sufficient for our needs.
+// Rather than litter the code with unnecessary type annotations, we'll hard-code
+// the cases we can't handle yet.
+func (w *Walker) hardCodedConstantType(name string) (typ string, ok bool) {
+ switch w.scope[0] {
+ case "pkg syscall":
+ switch name {
+ case "darwinAMD64":
+ return "bool", true
+ }
+ }
+ return "", false
+}
+
+func (w *Walker) Features() (fs []string) {
+ for f := range w.features {
+ fs = append(fs, f)
+ }
+ sort.Strings(fs)
+ return
+}
+
+// fileDeps returns the imports in a file.
+func fileDeps(f *ast.File) (pkgs []string) {
+ for _, is := range f.Imports {
+ fpkg, err := strconv.Unquote(is.Path.Value)
+ if err != nil {
+ log.Fatalf("error unquoting import string %q: %v", is.Path.Value, err)
+ }
+ if fpkg != "C" {
+ pkgs = append(pkgs, fpkg)
+ }
+ }
+ return
+}
+
+// WalkPackage walks all files in package `name'.
+// WalkPackage does nothing if the package has already been loaded.
+func (w *Walker) WalkPackage(name string) {
+ switch w.packageState[name] {
+ case loading:
+ log.Fatalf("import cycle loading package %q?", name)
+ case loaded:
+ return
+ }
+ w.packageState[name] = loading
+ defer func() {
+ w.packageState[name] = loaded
+ }()
+ dir := filepath.Join(w.root, filepath.FromSlash(name))
+
+ ctxt := w.context
+ if ctxt == nil {
+ ctxt = &build.Default
+ }
+ info, err := ctxt.ImportDir(dir, 0)
+ if err != nil {
+ if strings.Contains(err.Error(), "no Go source files") {
+ return
+ }
+ log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
+ }
+
+ apkg := &ast.Package{
+ Files: make(map[string]*ast.File),
+ }
+
+ files := append(append([]string{}, info.GoFiles...), info.CgoFiles...)
+ for _, file := range files {
+ f, err := parser.ParseFile(w.fset, filepath.Join(dir, file), nil, 0)
+ if err != nil {
+ log.Fatalf("error parsing package %s, file %s: %v", name, file, err)
+ }
+ apkg.Files[file] = f
+
+ for _, dep := range fileDeps(f) {
+ w.WalkPackage(dep)
+ }
+ }
+
+ if *verbose {
+ log.Printf("package %s", name)
+ }
+ pop := w.pushScope("pkg " + name)
+ defer pop()
+
+ w.curPackageName = name
+ w.curPackage = apkg
+ w.constDep = map[string]string{}
+
+ for _, afile := range apkg.Files {
+ w.recordTypes(afile)
+ }
+
+ // Register all function declarations first.
+ for _, afile := range apkg.Files {
+ for _, di := range afile.Decls {
+ if d, ok := di.(*ast.FuncDecl); ok {
+ w.peekFuncDecl(d)
+ }
+ }
+ }
+
+ for _, afile := range apkg.Files {
+ w.walkFile(afile)
+ }
+
+ w.resolveConstantDeps()
+
+ // Now that we're done walking types, vars and consts
+ // in the *ast.Package, use go/doc to do the rest
+ // (functions and methods). This is done here because
+ // go/doc is destructive. We can't use the
+ // *ast.Package after this.
+ dpkg := doc.New(apkg, name, doc.AllMethods)
+
+ for _, t := range dpkg.Types {
+ // Move funcs up to the top-level, not hiding in the Types.
+ dpkg.Funcs = append(dpkg.Funcs, t.Funcs...)
+
+ for _, m := range t.Methods {
+ w.walkFuncDecl(m.Decl)
+ }
+ }
+
+ for _, f := range dpkg.Funcs {
+ w.walkFuncDecl(f.Decl)
+ }
+}
+
+// pushScope enters a new scope (walking a package, type, node, etc)
+// and returns a function that will leave the scope (with sanity checking
+// for mismatched pushes & pops)
+func (w *Walker) pushScope(name string) (popFunc func()) {
+ w.scope = append(w.scope, name)
+ return func() {
+ if len(w.scope) == 0 {
+ log.Fatalf("attempt to leave scope %q with empty scope list", name)
+ }
+ if w.scope[len(w.scope)-1] != name {
+ log.Fatalf("attempt to leave scope %q, but scope is currently %#v", name, w.scope)
+ }
+ w.scope = w.scope[:len(w.scope)-1]
+ }
+}
+
+func (w *Walker) recordTypes(file *ast.File) {
+ for _, di := range file.Decls {
+ switch d := di.(type) {
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.TYPE:
+ for _, sp := range d.Specs {
+ ts := sp.(*ast.TypeSpec)
+ name := ts.Name.Name
+ if ast.IsExported(name) {
+ if it, ok := ts.Type.(*ast.InterfaceType); ok {
+ w.noteInterface(name, it)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func (w *Walker) walkFile(file *ast.File) {
+ // Not entering a scope here; file boundaries aren't interesting.
+ for _, di := range file.Decls {
+ switch d := di.(type) {
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.IMPORT:
+ for _, sp := range d.Specs {
+ is := sp.(*ast.ImportSpec)
+ fpath, err := strconv.Unquote(is.Path.Value)
+ if err != nil {
+ log.Fatal(err)
+ }
+ name := path.Base(fpath)
+ if is.Name != nil {
+ name = is.Name.Name
+ }
+ w.selectorFullPkg[name] = fpath
+ }
+ case token.CONST:
+ for _, sp := range d.Specs {
+ w.walkConst(sp.(*ast.ValueSpec))
+ }
+ case token.TYPE:
+ for _, sp := range d.Specs {
+ w.walkTypeSpec(sp.(*ast.TypeSpec))
+ }
+ case token.VAR:
+ for _, sp := range d.Specs {
+ w.walkVar(sp.(*ast.ValueSpec))
+ }
+ default:
+ log.Fatalf("unknown token type %d in GenDecl", d.Tok)
+ }
+ case *ast.FuncDecl:
+ // Ignore. Handled in subsequent pass, by go/doc.
+ default:
+ log.Printf("unhandled %T, %#v\n", di, di)
+ printer.Fprint(os.Stderr, w.fset, di)
+ os.Stderr.Write([]byte("\n"))
+ }
+ }
+}
+
+var constType = map[token.Token]string{
+ token.INT: "ideal-int",
+ token.FLOAT: "ideal-float",
+ token.STRING: "ideal-string",
+ token.CHAR: "ideal-char",
+ token.IMAG: "ideal-imag",
+}
+
+var varType = map[token.Token]string{
+ token.INT: "int",
+ token.FLOAT: "float64",
+ token.STRING: "string",
+ token.CHAR: "rune",
+ token.IMAG: "complex128",
+}
+
+var errTODO = errors.New("TODO")
+
+func (w *Walker) constValueType(vi interface{}) (string, error) {
+ switch v := vi.(type) {
+ case *ast.BasicLit:
+ litType, ok := constType[v.Kind]
+ if !ok {
+ return "", fmt.Errorf("unknown basic literal kind %#v", v)
+ }
+ return litType, nil
+ case *ast.UnaryExpr:
+ return w.constValueType(v.X)
+ case *ast.SelectorExpr:
+ lhs := w.nodeString(v.X)
+ rhs := w.nodeString(v.Sel)
+ pkg, ok := w.selectorFullPkg[lhs]
+ if !ok {
+ return "", fmt.Errorf("unknown constant reference; unknown package in expression %s.%s", lhs, rhs)
+ }
+ if t, ok := w.prevConstType[pkgSymbol{pkg, rhs}]; ok {
+ return t, nil
+ }
+ return "", fmt.Errorf("unknown constant reference to %s.%s", lhs, rhs)
+ case *ast.Ident:
+ if v.Name == "iota" {
+ return "ideal-int", nil // hack.
+ }
+ if v.Name == "false" || v.Name == "true" {
+ return "bool", nil
+ }
+ if v.Name == "intSize" && w.curPackageName == "strconv" {
+ // Hack.
+ return "ideal-int", nil
+ }
+ if t, ok := w.prevConstType[pkgSymbol{w.curPackageName, v.Name}]; ok {
+ return t, nil
+ }
+ return constDepPrefix + v.Name, nil
+ case *ast.BinaryExpr:
+ left, err := w.constValueType(v.X)
+ if err != nil {
+ return "", err
+ }
+ right, err := w.constValueType(v.Y)
+ if err != nil {
+ return "", err
+ }
+ if left != right {
+ // TODO(bradfitz): encode the real rules here,
+ // rather than this mess.
+ if left == "ideal-int" && right == "ideal-float" {
+ return "ideal-float", nil // math.Log2E
+ }
+ if left == "ideal-char" && right == "ideal-int" {
+ return "ideal-int", nil // math/big.MaxBase
+ }
+ if left == "ideal-int" && right == "ideal-char" {
+ return "ideal-int", nil // text/scanner.GoWhitespace
+ }
+ if left == "ideal-int" && right == "Duration" {
+ // Hack, for package time.
+ return "Duration", nil
+ }
+ if left == "ideal-int" && !strings.HasPrefix(right, "ideal-") {
+ return right, nil
+ }
+ if right == "ideal-int" && !strings.HasPrefix(left, "ideal-") {
+ return left, nil
+ }
+ if strings.HasPrefix(left, constDepPrefix) && strings.HasPrefix(right, constDepPrefix) {
+ // Just pick one.
+ // e.g. text/scanner GoTokens const-dependency:ScanIdents, const-dependency:ScanFloats
+ return left, nil
+ }
+ return "", fmt.Errorf("in BinaryExpr, unhandled type mismatch; left=%q, right=%q", left, right)
+ }
+ return left, nil
+ case *ast.CallExpr:
+ // Not a call, but a type conversion.
+ return w.nodeString(v.Fun), nil
+ case *ast.ParenExpr:
+ return w.constValueType(v.X)
+ }
+ return "", fmt.Errorf("unknown const value type %T", vi)
+}
+
+func (w *Walker) varValueType(vi interface{}) (string, error) {
+ switch v := vi.(type) {
+ case *ast.BasicLit:
+ litType, ok := varType[v.Kind]
+ if !ok {
+ return "", fmt.Errorf("unknown basic literal kind %#v", v)
+ }
+ return litType, nil
+ case *ast.CompositeLit:
+ return w.nodeString(v.Type), nil
+ case *ast.FuncLit:
+ return w.nodeString(w.namelessType(v.Type)), nil
+ case *ast.UnaryExpr:
+ if v.Op == token.AND {
+ typ, err := w.varValueType(v.X)
+ return "*" + typ, err
+ }
+ return "", fmt.Errorf("unknown unary expr: %#v", v)
+ case *ast.SelectorExpr:
+ return "", errTODO
+ case *ast.Ident:
+ node, _, ok := w.resolveName(v.Name)
+ if !ok {
+ return "", fmt.Errorf("unresolved identifier: %q", v.Name)
+ }
+ return w.varValueType(node)
+ case *ast.BinaryExpr:
+ left, err := w.varValueType(v.X)
+ if err != nil {
+ return "", err
+ }
+ right, err := w.varValueType(v.Y)
+ if err != nil {
+ return "", err
+ }
+ if left != right {
+ return "", fmt.Errorf("in BinaryExpr, unhandled type mismatch; left=%q, right=%q", left, right)
+ }
+ return left, nil
+ case *ast.ParenExpr:
+ return w.varValueType(v.X)
+ case *ast.CallExpr:
+ var funSym pkgSymbol
+ if selnode, ok := v.Fun.(*ast.SelectorExpr); ok {
+ // assume it is not a method.
+ pkg, ok := w.selectorFullPkg[w.nodeString(selnode.X)]
+ if !ok {
+ return "", fmt.Errorf("not a package: %s", w.nodeString(selnode.X))
+ }
+ funSym = pkgSymbol{pkg, selnode.Sel.Name}
+ if retType, ok := w.functionTypes[funSym]; ok {
+ if ast.IsExported(retType) && pkg != w.curPackageName {
+ // otherpkg.F returning an exported type from otherpkg.
+ return pkg + "." + retType, nil
+ } else {
+ return retType, nil
+ }
+ }
+ } else {
+ funSym = pkgSymbol{w.curPackageName, w.nodeString(v.Fun)}
+ if retType, ok := w.functionTypes[funSym]; ok {
+ return retType, nil
+ }
+ }
+ // maybe a function call; maybe a conversion. Need to lookup type.
+ // TODO(bradfitz): this is a hack, but arguably most of this tool is,
+ // until the Go AST has type information.
+ nodeStr := w.nodeString(v.Fun)
+ switch nodeStr {
+ case "string", "[]byte":
+ return nodeStr, nil
+ }
+ return "", fmt.Errorf("not a known function %q", nodeStr)
+ default:
+ return "", fmt.Errorf("unknown const value type %T", vi)
+ }
+ panic("unreachable")
+}
+
+// resolveName finds a top-level node named name and returns the node
+// v and its type t, if known.
+func (w *Walker) resolveName(name string) (v interface{}, t interface{}, ok bool) {
+ for _, file := range w.curPackage.Files {
+ for _, di := range file.Decls {
+ switch d := di.(type) {
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.VAR:
+ for _, sp := range d.Specs {
+ vs := sp.(*ast.ValueSpec)
+ for i, vname := range vs.Names {
+ if vname.Name == name {
+ if len(vs.Values) > i {
+ return vs.Values[i], vs.Type, true
+ }
+ return nil, vs.Type, true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nil, nil, false
+}
+
+// constDepPrefix is a magic prefix that is used by constValueType
+// and walkConst to signal that a type isn't known yet. These are
+// resolved at the end of walking of a package's files.
+const constDepPrefix = "const-dependency:"
+
+func (w *Walker) walkConst(vs *ast.ValueSpec) {
+ for _, ident := range vs.Names {
+ litType := ""
+ if vs.Type != nil {
+ litType = w.nodeString(vs.Type)
+ } else {
+ litType = w.lastConstType
+ if vs.Values != nil {
+ if len(vs.Values) != 1 {
+ log.Fatalf("const %q, values: %#v", ident.Name, vs.Values)
+ }
+ var err error
+ litType, err = w.constValueType(vs.Values[0])
+ if err != nil {
+ if t, ok := w.hardCodedConstantType(ident.Name); ok {
+ litType = t
+ err = nil
+ } else {
+ log.Fatalf("unknown kind in const %q (%T): %v", ident.Name, vs.Values[0], err)
+ }
+ }
+ }
+ }
+ if strings.HasPrefix(litType, constDepPrefix) {
+ dep := litType[len(constDepPrefix):]
+ w.constDep[ident.Name] = dep
+ continue
+ }
+ if litType == "" {
+ log.Fatalf("unknown kind in const %q", ident.Name)
+ }
+ w.lastConstType = litType
+
+ w.prevConstType[pkgSymbol{w.curPackageName, ident.Name}] = litType
+
+ if ast.IsExported(ident.Name) {
+ w.emitFeature(fmt.Sprintf("const %s %s", ident, litType))
+ }
+ }
+}
+
+func (w *Walker) resolveConstantDeps() {
+ var findConstType func(string) string
+ findConstType = func(ident string) string {
+ if dep, ok := w.constDep[ident]; ok {
+ return findConstType(dep)
+ }
+ if t, ok := w.prevConstType[pkgSymbol{w.curPackageName, ident}]; ok {
+ return t
+ }
+ return ""
+ }
+ for ident := range w.constDep {
+ if !ast.IsExported(ident) {
+ continue
+ }
+ t := findConstType(ident)
+ if t == "" {
+ log.Fatalf("failed to resolve constant %q", ident)
+ }
+ w.emitFeature(fmt.Sprintf("const %s %s", ident, t))
+ }
+}
+
+func (w *Walker) walkVar(vs *ast.ValueSpec) {
+ for i, ident := range vs.Names {
+ if !ast.IsExported(ident.Name) {
+ continue
+ }
+
+ typ := ""
+ if vs.Type != nil {
+ typ = w.nodeString(vs.Type)
+ } else {
+ if len(vs.Values) == 0 {
+ log.Fatalf("no values for var %q", ident.Name)
+ }
+ if len(vs.Values) > 1 {
+ log.Fatalf("more than 1 values in ValueSpec not handled, var %q", ident.Name)
+ }
+ var err error
+ typ, err = w.varValueType(vs.Values[i])
+ if err != nil {
+ log.Fatalf("unknown type of variable %q, type %T, error = %v\ncode: %s",
+ ident.Name, vs.Values[i], err, w.nodeString(vs.Values[i]))
+ }
+ }
+ w.emitFeature(fmt.Sprintf("var %s %s", ident, typ))
+ }
+}
+
+func (w *Walker) nodeString(node interface{}) string {
+ if node == nil {
+ return ""
+ }
+ var b bytes.Buffer
+ printer.Fprint(&b, w.fset, node)
+ return b.String()
+}
+
+func (w *Walker) nodeDebug(node interface{}) string {
+ if node == nil {
+ return ""
+ }
+ var b bytes.Buffer
+ ast.Fprint(&b, w.fset, node, nil)
+ return b.String()
+}
+
+func (w *Walker) noteInterface(name string, it *ast.InterfaceType) {
+ w.interfaces[pkgSymbol{w.curPackageName, name}] = it
+}
+
+func (w *Walker) walkTypeSpec(ts *ast.TypeSpec) {
+ name := ts.Name.Name
+ if !ast.IsExported(name) {
+ return
+ }
+ switch t := ts.Type.(type) {
+ case *ast.StructType:
+ w.walkStructType(name, t)
+ case *ast.InterfaceType:
+ w.walkInterfaceType(name, t)
+ default:
+ w.emitFeature(fmt.Sprintf("type %s %s", name, w.nodeString(ts.Type)))
+ }
+}
+
+func (w *Walker) walkStructType(name string, t *ast.StructType) {
+ typeStruct := fmt.Sprintf("type %s struct", name)
+ w.emitFeature(typeStruct)
+ pop := w.pushScope(typeStruct)
+ defer pop()
+ for _, f := range t.Fields.List {
+ typ := f.Type
+ for _, name := range f.Names {
+ if ast.IsExported(name.Name) {
+ w.emitFeature(fmt.Sprintf("%s %s", name, w.nodeString(w.namelessType(typ))))
+ }
+ }
+ if f.Names == nil {
+ switch v := typ.(type) {
+ case *ast.Ident:
+ if ast.IsExported(v.Name) {
+ w.emitFeature(fmt.Sprintf("embedded %s", v.Name))
+ }
+ case *ast.StarExpr:
+ switch vv := v.X.(type) {
+ case *ast.Ident:
+ if ast.IsExported(vv.Name) {
+ w.emitFeature(fmt.Sprintf("embedded *%s", vv.Name))
+ }
+ case *ast.SelectorExpr:
+ w.emitFeature(fmt.Sprintf("embedded %s", w.nodeString(typ)))
+ default:
+ log.Fatalf("unable to handle embedded starexpr before %T", typ)
+ }
+ case *ast.SelectorExpr:
+ w.emitFeature(fmt.Sprintf("embedded %s", w.nodeString(typ)))
+ default:
+ log.Fatalf("unable to handle embedded %T", typ)
+ }
+ }
+ }
+}
+
+// method is a method of an interface.
+type method struct {
+ name string // "Read"
+ sig string // "([]byte) (int, error)", from funcSigString
+}
+
+// interfaceMethods returns the expanded list of methods for an interface.
+// pkg is the complete package name ("net/http")
+// iname is the interface name.
+func (w *Walker) interfaceMethods(pkg, iname string) (methods []method) {
+ t, ok := w.interfaces[pkgSymbol{pkg, iname}]
+ if !ok {
+ log.Fatalf("failed to find interface %s.%s", pkg, iname)
+ }
+
+ for _, f := range t.Methods.List {
+ typ := f.Type
+ switch tv := typ.(type) {
+ case *ast.FuncType:
+ for _, mname := range f.Names {
+ if ast.IsExported(mname.Name) {
+ ft := typ.(*ast.FuncType)
+ methods = append(methods, method{
+ name: mname.Name,
+ sig: w.funcSigString(ft),
+ })
+ }
+ }
+ case *ast.Ident:
+ embedded := typ.(*ast.Ident).Name
+ if embedded == "error" {
+ methods = append(methods, method{
+ name: "Error",
+ sig: "() string",
+ })
+ continue
+ }
+ if !ast.IsExported(embedded) {
+ log.Fatalf("unexported embedded interface %q in exported interface %s.%s; confused",
+ embedded, pkg, iname)
+ }
+ methods = append(methods, w.interfaceMethods(pkg, embedded)...)
+ case *ast.SelectorExpr:
+ lhs := w.nodeString(tv.X)
+ rhs := w.nodeString(tv.Sel)
+ fpkg, ok := w.selectorFullPkg[lhs]
+ if !ok {
+ log.Fatalf("can't resolve selector %q in interface %s.%s", lhs, pkg, iname)
+ }
+ methods = append(methods, w.interfaceMethods(fpkg, rhs)...)
+ default:
+ log.Fatalf("unknown type %T in interface field", typ)
+ }
+ }
+ return
+}
+
+func (w *Walker) walkInterfaceType(name string, t *ast.InterfaceType) {
+ methNames := []string{}
+
+ pop := w.pushScope("type " + name + " interface")
+ for _, m := range w.interfaceMethods(w.curPackageName, name) {
+ methNames = append(methNames, m.name)
+ w.emitFeature(fmt.Sprintf("%s%s", m.name, m.sig))
+ }
+ pop()
+
+ sort.Strings(methNames)
+ if len(methNames) == 0 {
+ w.emitFeature(fmt.Sprintf("type %s interface {}", name))
+ } else {
+ w.emitFeature(fmt.Sprintf("type %s interface { %s }", name, strings.Join(methNames, ", ")))
+ }
+}
+
+func (w *Walker) peekFuncDecl(f *ast.FuncDecl) {
+ if f.Recv != nil {
+ return
+ }
+ // Record return type for later use.
+ if f.Type.Results != nil && len(f.Type.Results.List) == 1 {
+ retType := w.nodeString(w.namelessType(f.Type.Results.List[0].Type))
+ w.functionTypes[pkgSymbol{w.curPackageName, f.Name.Name}] = retType
+ }
+}
+
+func (w *Walker) walkFuncDecl(f *ast.FuncDecl) {
+ if !ast.IsExported(f.Name.Name) {
+ return
+ }
+ if f.Recv != nil {
+ // Method.
+ recvType := w.nodeString(f.Recv.List[0].Type)
+ keep := ast.IsExported(recvType) ||
+ (strings.HasPrefix(recvType, "*") &&
+ ast.IsExported(recvType[1:]))
+ if !keep {
+ return
+ }
+ w.emitFeature(fmt.Sprintf("method (%s) %s%s", recvType, f.Name.Name, w.funcSigString(f.Type)))
+ return
+ }
+ // Else, a function
+ w.emitFeature(fmt.Sprintf("func %s%s", f.Name.Name, w.funcSigString(f.Type)))
+}
+
+func (w *Walker) funcSigString(ft *ast.FuncType) string {
+ var b bytes.Buffer
+ b.WriteByte('(')
+ if ft.Params != nil {
+ for i, f := range ft.Params.List {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(w.nodeString(w.namelessType(f.Type)))
+ }
+ }
+ b.WriteByte(')')
+ if ft.Results != nil {
+ if nr := len(ft.Results.List); nr > 0 {
+ b.WriteByte(' ')
+ if nr > 1 {
+ b.WriteByte('(')
+ }
+ for i, f := range ft.Results.List {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(w.nodeString(w.namelessType(f.Type)))
+ }
+ if nr > 1 {
+ b.WriteByte(')')
+ }
+ }
+ }
+ return b.String()
+}
+
+// namelessType returns a type node that lacks any variable names.
+func (w *Walker) namelessType(t interface{}) interface{} {
+ ft, ok := t.(*ast.FuncType)
+ if !ok {
+ return t
+ }
+ return &ast.FuncType{
+ Params: w.namelessFieldList(ft.Params),
+ Results: w.namelessFieldList(ft.Results),
+ }
+}
+
+// namelessFieldList returns a deep clone of fl, with the cloned fields
+// lacking names.
+func (w *Walker) namelessFieldList(fl *ast.FieldList) *ast.FieldList {
+ fl2 := &ast.FieldList{}
+ if fl != nil {
+ for _, f := range fl.List {
+ fl2.List = append(fl2.List, w.namelessField(f))
+ }
+ }
+ return fl2
+}
+
+// namelessField clones f, but not preserving the names of fields.
+// (comments and tags are also ignored)
+func (w *Walker) namelessField(f *ast.Field) *ast.Field {
+ return &ast.Field{
+ Type: f.Type,
+ }
+}
+
+func (w *Walker) emitFeature(feature string) {
+ if !w.wantedPkg[w.curPackageName] {
+ return
+ }
+ f := strings.Join(w.scope, ", ") + ", " + feature
+ if _, dup := w.features[f]; dup {
+ panic("duplicate feature inserted: " + f)
+ }
+
+ if strings.Contains(f, "\n") {
+ // TODO: for now, just skip over the
+ // runtime.MemStatsType.BySize type, which this tool
+ // doesn't properly handle. It's pretty low-level,
+ // though, so not super important to protect against.
+ if strings.HasPrefix(f, "pkg runtime") && strings.Contains(f, "BySize [61]struct") {
+ return
+ }
+ panic("feature contains newlines: " + f)
+ }
+ w.features[f] = true
+ if *verbose {
+ log.Printf("feature: %s", f)
+ }
+}
+
+func strListContains(l []string, s string) bool {
+ for _, v := range l {
+ if v == s {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
new file mode 100644
index 000000000..c7cc601b1
--- /dev/null
+++ b/src/cmd/api/goapi_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 main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "testing"
+)
+
+var (
+ updateGolden = flag.Bool("updategolden", false, "update golden files")
+)
+
+func TestGolden(t *testing.T) {
+ td, err := os.Open("testdata/src/pkg")
+ if err != nil {
+ t.Fatal(err)
+ }
+ fis, err := td.Readdir(0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, fi := range fis {
+ if !fi.IsDir() {
+ continue
+ }
+ w := NewWalker()
+ w.wantedPkg[fi.Name()] = true
+
+ w.root = "testdata/src/pkg"
+ goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
+ w.WalkPackage(fi.Name())
+
+ if *updateGolden {
+ os.Remove(goldenFile)
+ f, err := os.Create(goldenFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, feat := range w.Features() {
+ fmt.Fprintf(f, "%s\n", feat)
+ }
+ f.Close()
+ }
+
+ bs, err := ioutil.ReadFile(goldenFile)
+ if err != nil {
+ t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
+ }
+ wanted := strings.Split(string(bs), "\n")
+ sort.Strings(wanted)
+ for _, feature := range wanted {
+ if feature == "" {
+ continue
+ }
+ _, ok := w.features[feature]
+ if !ok {
+ t.Errorf("package %s: missing feature %q", fi.Name(), feature)
+ }
+ delete(w.features, feature)
+ }
+
+ for _, feature := range w.Features() {
+ t.Errorf("package %s: extra feature not in golden file: %q", fi.Name(), feature)
+ }
+ }
+}
diff --git a/src/cmd/api/testdata/src/pkg/p1/golden.txt b/src/cmd/api/testdata/src/pkg/p1/golden.txt
new file mode 100644
index 000000000..e334e5776
--- /dev/null
+++ b/src/cmd/api/testdata/src/pkg/p1/golden.txt
@@ -0,0 +1,73 @@
+pkg p1, const A ideal-int
+pkg p1, const A64 int64
+pkg p1, const AIsLowerA ideal-int
+pkg p1, const B ideal-int
+pkg p1, const ConstChase2 ideal-int
+pkg p1, const ConversionConst MyInt
+pkg p1, const FloatConst ideal-float
+pkg p1, const StrConst ideal-string
+pkg p1, func Bar(int8, int16, int64)
+pkg p1, func Bar1(int8, int16, int64) uint64
+pkg p1, func Bar2(int8, int16, int64) (uint8, uint64)
+pkg p1, func BarE() Error
+pkg p1, func TakesFunc(func(int) int)
+pkg p1, method (*B) JustOnB()
+pkg p1, method (*B) OnBothTandBPtr()
+pkg p1, method (*Embedded) OnEmbedded()
+pkg p1, method (*S2) SMethod(int8, int16, int64)
+pkg p1, method (*T) JustOnT()
+pkg p1, method (*T) OnBothTandBPtr()
+pkg p1, method (B) OnBothTandBVal()
+pkg p1, method (S) StructValueMethod()
+pkg p1, method (S) StructValueMethodNamedRecv()
+pkg p1, method (S2) StructValueMethod()
+pkg p1, method (S2) StructValueMethodNamedRecv()
+pkg p1, method (T) OnBothTandBVal()
+pkg p1, method (TPtrExported) OnEmbedded()
+pkg p1, method (TPtrUnexported) OnBothTandBPtr()
+pkg p1, method (TPtrUnexported) OnBothTandBVal()
+pkg p1, type B struct
+pkg p1, type Codec struct
+pkg p1, type Codec struct, Func func(int, int) int
+pkg p1, type EmbedSelector struct
+pkg p1, type EmbedSelector struct, embedded time.Time
+pkg p1, type EmbedURLPtr struct
+pkg p1, type EmbedURLPtr struct, embedded *url.URL
+pkg p1, type Embedded struct
+pkg p1, type Error interface { Error, Temporary }
+pkg p1, type Error interface, Error() string
+pkg p1, type Error interface, Temporary() bool
+pkg p1, type I interface { Get, GetNamed, Name, PackageTwoMeth, Set }
+pkg p1, type I interface, Get(string) int64
+pkg p1, type I interface, GetNamed(string) int64
+pkg p1, type I interface, Name() string
+pkg p1, type I interface, PackageTwoMeth()
+pkg p1, type I interface, Set(string, int64)
+pkg p1, type MyInt int
+pkg p1, type Namer interface { Name }
+pkg p1, type Namer interface, Name() string
+pkg p1, type S struct
+pkg p1, type S struct, Public *int
+pkg p1, type S struct, PublicTime time.Time
+pkg p1, type S2 struct
+pkg p1, type S2 struct, Extra bool
+pkg p1, type S2 struct, embedded S
+pkg p1, type SI struct
+pkg p1, type SI struct, I int
+pkg p1, type T struct
+pkg p1, type TPtrExported struct
+pkg p1, type TPtrExported struct, embedded *Embedded
+pkg p1, type TPtrUnexported struct
+pkg p1, var ByteConv []byte
+pkg p1, var ChecksumError error
+pkg p1, var SIPtr *SI
+pkg p1, var SIPtr2 *SI
+pkg p1, var SIVal SI
+pkg p1, var StrConv string
+pkg p1, var V string
+pkg p1, var V1 uint64
+pkg p1, var V2 p2.Twoer
+pkg p1, var VError Error
+pkg p1, var X I
+pkg p1, var X int64
+pkg p1, var Y int
diff --git a/src/cmd/api/testdata/src/pkg/p1/p1.go b/src/cmd/api/testdata/src/pkg/p1/p1.go
new file mode 100644
index 000000000..d965bb75e
--- /dev/null
+++ b/src/cmd/api/testdata/src/pkg/p1/p1.go
@@ -0,0 +1,153 @@
+package p1
+
+import (
+ ptwo "p2"
+)
+
+const (
+ ConstChase2 = constChase // forward declaration to unexported ident
+ constChase = AIsLowerA // forward declaration to exported ident
+
+ A = 1
+ a = 11
+ A64 int64 = 1
+
+ AIsLowerA = a // previously declared
+)
+
+const (
+ ConversionConst = MyInt(5)
+)
+
+// Variables from function calls.
+var (
+ V = ptwo.F()
+ VError = BarE()
+ V1 = Bar1(1, 2, 3)
+ V2 = ptwo.G()
+)
+
+// Variables with conversions:
+var (
+ StrConv = string("foo")
+ ByteConv = []byte("foo")
+)
+
+var ChecksumError = ptwo.NewError("gzip checksum error")
+
+const B = 2
+const StrConst = "foo"
+const FloatConst = 1.5
+
+type myInt int
+
+type MyInt int
+
+type S struct {
+ Public *int
+ private *int
+ PublicTime time.Time
+}
+
+type EmbedURLPtr struct {
+ *url.URL
+}
+
+type S2 struct {
+ S
+ Extra bool
+}
+
+var X int64
+
+var (
+ Y int
+ X I
+)
+
+type Namer interface {
+ Name() string
+}
+
+type I interface {
+ Namer
+ ptwo.Twoer
+ Set(name string, balance int64)
+ Get(string) int64
+ GetNamed(string) (balance int64)
+ private()
+}
+
+type Error interface {
+ error
+ Temporary() bool
+}
+
+func (myInt) privateTypeMethod() {}
+func (myInt) CapitalMethodUnexportedType() {}
+
+func (s *S2) SMethod(x int8, y int16, z int64) {}
+
+type s struct{}
+
+func (s) method()
+func (s) Method()
+
+func (S) StructValueMethod()
+func (ignored S) StructValueMethodNamedRecv()
+
+func (s *S2) unexported(x int8, y int16, z int64) {}
+
+func Bar(x int8, y int16, z int64) {}
+func Bar1(x int8, y int16, z int64) uint64 {}
+func Bar2(x int8, y int16, z int64) (uint8, uint64) {}
+func BarE() Error {}
+
+func unexported(x int8, y int16, z int64) {}
+
+func TakesFunc(f func(dontWantName int) int)
+
+type Codec struct {
+ Func func(x int, y int) (z int)
+}
+
+type SI struct {
+ I int
+}
+
+var SIVal = SI{}
+var SIPtr = &SI{}
+var SIPtr2 *SI
+
+type T struct {
+ common
+}
+
+type B struct {
+ common
+}
+
+type common struct {
+ i int
+}
+
+type TPtrUnexported struct {
+ *common
+}
+
+type TPtrExported struct {
+ *Embedded
+}
+
+type Embedded struct{}
+
+func (*Embedded) OnEmbedded() {}
+
+func (*T) JustOnT() {}
+func (*B) JustOnB() {}
+func (*common) OnBothTandBPtr() {}
+func (common) OnBothTandBVal() {}
+
+type EmbedSelector struct {
+ time.Time
+}
diff --git a/src/cmd/api/testdata/src/pkg/p2/golden.txt b/src/cmd/api/testdata/src/pkg/p2/golden.txt
new file mode 100644
index 000000000..4271620c7
--- /dev/null
+++ b/src/cmd/api/testdata/src/pkg/p2/golden.txt
@@ -0,0 +1,5 @@
+pkg p2, func F() string
+pkg p2, func G() Twoer
+pkg p2, func NewError(string) error
+pkg p2, type Twoer interface { PackageTwoMeth }
+pkg p2, type Twoer interface, PackageTwoMeth()
diff --git a/src/cmd/api/testdata/src/pkg/p2/p2.go b/src/cmd/api/testdata/src/pkg/p2/p2.go
new file mode 100644
index 000000000..6b107b507
--- /dev/null
+++ b/src/cmd/api/testdata/src/pkg/p2/p2.go
@@ -0,0 +1,9 @@
+package p2
+
+type Twoer interface {
+ PackageTwoMeth()
+}
+
+func F() string {}
+func G() Twoer {}
+func NewError(s string) error {}
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
index 8327d9516..109578297 100644
--- a/src/cmd/cc/Makefile
+++ b/src/cmd/cc/Makefile
@@ -1,36 +1,10 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
+include ../../Make.dist
-LIB=cc.a
+install: y.tab.h
-HFILES=\
- cc.h\
- y.tab.h\
-
-YFILES=\
- cc.y\
-
-OFILES=\
- y.tab.$O\
- lex.$O\
- mac.$O\
- dcl.$O\
- acid.$O\
- godefs.$O\
- bits.$O\
- com.$O\
- scon.$O\
- funct.$O\
- sub.$O\
- com64.$O\
- dpchk.$O\
- omachcap.$O\
-
-NOINSTALL=1
-include ../../Make.clib
-
-install: $(LIB)
+y.tab.h: cc.y
+ LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index a38e658ce..4c527a2b3 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -31,8 +31,6 @@
#include <libc.h>
#include <bio.h>
-#pragma lib "../cc/cc.a$O"
-
#ifndef EXTERN
#define EXTERN extern
#endif
@@ -124,6 +122,7 @@ struct Sym
uchar sym;
uchar aused;
uchar sig;
+ uchar dataflag;
};
#define S ((Sym*)0)
@@ -518,14 +517,15 @@ EXTERN int thechar;
EXTERN char* thestring;
EXTERN Type* thisfn;
EXTERN int32 thunk;
-EXTERN Type* types[NTYPE];
-EXTERN Type* fntypes[NTYPE];
+EXTERN Type* types[NALLTYPES];
+EXTERN Type* fntypes[NALLTYPES];
EXTERN Node* initlist;
EXTERN Term term[NTERM];
EXTERN int nterm;
EXTERN int packflg;
EXTERN int fproundflg;
EXTERN int textflag;
+EXTERN int dataflag;
EXTERN int ncontin;
EXTERN int canreach;
EXTERN int warnreach;
@@ -768,6 +768,7 @@ void arginit(void);
void pragvararg(void);
void pragpack(void);
void pragfpround(void);
+void pragdataflag(void);
void pragtextflag(void);
void pragincomplete(void);
void pragdynimport(void);
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
index fb7a3f750..f46fedc16 100644
--- a/src/cmd/cc/com64.c
+++ b/src/cmd/cc/com64.c
@@ -96,7 +96,7 @@ Node* nodmmv;
Node* nodvasop;
-char etconv[NTYPE]; /* for _vasop */
+char etconv[NALLTYPES]; /* for _vasop */
Init initetconv[] =
{
TCHAR, 1, 0,
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index d624bf247..a3ed9772d 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -120,6 +120,10 @@ loop:
(*f)(c, t, s);
if(s->class == CLOCAL)
s = mkstatic(s);
+ if(dataflag) {
+ s->dataflag = dataflag;
+ dataflag = 0;
+ }
firstbit = 0;
n->sym = s;
n->type = s->type;
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 084aa0484..c579e20d9 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -567,13 +567,7 @@ pragfpround(void)
void
pragtextflag(void)
{
- Sym *s;
-
- textflag = 0;
- s = getsym();
- textflag = 7;
- if(s)
- textflag = atoi(s->name+1);
+ textflag = getnsn();
while(getnsc() != '\n')
;
if(debug['f'])
@@ -581,6 +575,16 @@ pragtextflag(void)
}
void
+pragdataflag(void)
+{
+ dataflag = getnsn();
+ while(getnsc() != '\n')
+ ;
+ if(debug['f'])
+ print("%4d: dataflag %d\n", lineno, dataflag);
+}
+
+void
pragincomplete(void)
{
Sym *s;
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
index 99477b2b2..057151987 100644
--- a/src/cmd/cc/funct.c
+++ b/src/cmd/cc/funct.c
@@ -46,7 +46,7 @@ struct Gtab
};
Ftab ftabinit[OEND];
-Gtab gtabinit[NTYPE];
+Gtab gtabinit[NALLTYPES];
int
isfunct(Node *n)
@@ -350,7 +350,7 @@ bad:
diag(Z, "dclfunct bad %T %s\n", t, s->name);
}
-Gtab gtabinit[NTYPE] =
+Gtab gtabinit[NALLTYPES] =
{
TCHAR, "c",
TUCHAR, "uc",
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
index 3ba979c8a..4274c5626 100644
--- a/src/cmd/cc/godefs.c
+++ b/src/cmd/cc/godefs.c
@@ -124,11 +124,11 @@ Uconv(Fmt *fp)
if(s && *s) {
if(upper)
- str[0] = toupper(*s);
+ str[0] = toupper((uchar)*s);
else
- str[0] = tolower(*s);
+ str[0] = tolower((uchar)*s);
for(i = 1; i < STRINGSZ && s[i] != 0; i++)
- str[i] = tolower(s[i]);
+ str[i] = tolower((uchar)s[i]);
str[i] = 0;
}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index 9fb2f9e4d..8aeb1a334 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -112,7 +112,7 @@ main(int argc, char *argv[])
case 'l': /* for little-endian mips */
if(thechar != 'v'){
- print("can only use -l with vc");
+ print("can only use -l with vc\n");
errorexit();
}
thechar = '0';
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index f4cc19c2e..d339cf9a2 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -75,6 +75,13 @@ pragtextflag(void)
}
void
+pragdataflag(void)
+{
+ while(getnsc() != '\n')
+ ;
+}
+
+void
pragprofile(void)
{
while(getnsc() != '\n')
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index ed66361f1..874e82d25 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -731,6 +731,10 @@ macprag(void)
pragtextflag();
return;
}
+ if(s && strcmp(s->name, "dataflag") == 0) {
+ pragdataflag();
+ return;
+ }
if(s && strcmp(s->name, "varargck") == 0) {
pragvararg();
return;
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index 0e5e8c059..3a686102f 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -266,7 +266,7 @@ loop:
if(cases == C)
diag(n, "case/default outside a switch");
if(l == Z) {
- cas();
+ newcase();
cases->val = 0;
cases->def = 1;
cases->label = pc;
@@ -278,7 +278,7 @@ loop:
goto rloop;
if(l->op == OCONST)
if(typeword[l->type->etype] && l->type->etype != TIND) {
- cas();
+ newcase();
cases->val = l->vconst;
cases->def = 0;
cases->label = pc;
@@ -293,7 +293,7 @@ loop:
complex(l);
if(l->type == T)
break;
- if(!typeword[l->type->etype] || l->type->etype == TIND) {
+ if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
diag(n, "switch expression must be integer");
break;
}
@@ -303,7 +303,7 @@ loop:
cn = cases;
cases = C;
- cas();
+ newcase();
sbc = breakpc;
breakpc = pc;
@@ -320,15 +320,7 @@ loop:
}
patch(sp, pc);
- regalloc(&nod, l, Z);
- /* always signed */
- if(typev[l->type->etype])
- nod.type = types[TVLONG];
- else
- nod.type = types[TLONG];
- cgen(l, &nod);
- doswit(&nod);
- regfree(&nod);
+ doswit(l);
patch(spb, pc);
cases = cn;
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
index 0e402dea7..b94035faa 100644
--- a/src/cmd/cc/pswt.c
+++ b/src/cmd/cc/pswt.c
@@ -92,7 +92,7 @@ doswit(Node *n)
}
void
-cas(void)
+newcase(void)
{
Case *c;
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
index e5992e213..72d671b2f 100644
--- a/src/cmd/cc/sub.c
+++ b/src/cmd/cc/sub.c
@@ -156,7 +156,10 @@ typ(int et, Type *d)
t->link = d;
t->down = T;
t->sym = S;
- t->width = ewidth[et];
+ if(et < NTYPE)
+ t->width = ewidth[et];
+ else
+ t->width = -1; // for TDOT or TOLD in prototype
t->offset = 0;
t->shift = 0;
t->nbits = 0;
@@ -1535,92 +1538,92 @@ uchar logrel[12] =
OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
};
-uchar typei[NTYPE];
+uchar typei[NALLTYPES];
int typeiinit[] =
{
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
};
-uchar typeu[NTYPE];
+uchar typeu[NALLTYPES];
int typeuinit[] =
{
TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
};
-uchar typesuv[NTYPE];
+uchar typesuv[NALLTYPES];
int typesuvinit[] =
{
TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
};
-uchar typeilp[NTYPE];
+uchar typeilp[NALLTYPES];
int typeilpinit[] =
{
TINT, TUINT, TLONG, TULONG, TIND, -1
};
-uchar typechl[NTYPE];
-uchar typechlv[NTYPE];
-uchar typechlvp[NTYPE];
+uchar typechl[NALLTYPES];
+uchar typechlv[NALLTYPES];
+uchar typechlvp[NALLTYPES];
int typechlinit[] =
{
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
};
-uchar typechlp[NTYPE];
+uchar typechlp[NALLTYPES];
int typechlpinit[] =
{
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
};
-uchar typechlpfd[NTYPE];
+uchar typechlpfd[NALLTYPES];
int typechlpfdinit[] =
{
TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
};
-uchar typec[NTYPE];
+uchar typec[NALLTYPES];
int typecinit[] =
{
TCHAR, TUCHAR, -1
};
-uchar typeh[NTYPE];
+uchar typeh[NALLTYPES];
int typehinit[] =
{
TSHORT, TUSHORT, -1,
};
-uchar typeil[NTYPE];
+uchar typeil[NALLTYPES];
int typeilinit[] =
{
TINT, TUINT, TLONG, TULONG, -1,
};
-uchar typev[NTYPE];
+uchar typev[NALLTYPES];
int typevinit[] =
{
TVLONG, TUVLONG, -1,
};
-uchar typefd[NTYPE];
+uchar typefd[NALLTYPES];
int typefdinit[] =
{
TFLOAT, TDOUBLE, -1,
};
-uchar typeaf[NTYPE];
+uchar typeaf[NALLTYPES];
int typeafinit[] =
{
TFUNC, TARRAY, -1,
};
-uchar typesu[NTYPE];
+uchar typesu[NALLTYPES];
int typesuinit[] =
{
TSTRUCT, TUNION, -1,
};
-int32 tasign[NTYPE];
+int32 tasign[NALLTYPES];
Init tasigninit[] =
{
TCHAR, BNUMBER, 0,
@@ -1641,7 +1644,7 @@ Init tasigninit[] =
-1, 0, 0,
};
-int32 tasadd[NTYPE];
+int32 tasadd[NALLTYPES];
Init tasaddinit[] =
{
TCHAR, BNUMBER, 0,
@@ -1660,7 +1663,7 @@ Init tasaddinit[] =
-1, 0, 0,
};
-int32 tcast[NTYPE];
+int32 tcast[NALLTYPES];
Init tcastinit[] =
{
TCHAR, BNUMBER|BIND|BVOID, 0,
@@ -1682,7 +1685,7 @@ Init tcastinit[] =
-1, 0, 0,
};
-int32 tadd[NTYPE];
+int32 tadd[NALLTYPES];
Init taddinit[] =
{
TCHAR, BNUMBER|BIND, 0,
@@ -1701,7 +1704,7 @@ Init taddinit[] =
-1, 0, 0,
};
-int32 tsub[NTYPE];
+int32 tsub[NALLTYPES];
Init tsubinit[] =
{
TCHAR, BNUMBER, 0,
@@ -1720,7 +1723,7 @@ Init tsubinit[] =
-1, 0, 0,
};
-int32 tmul[NTYPE];
+int32 tmul[NALLTYPES];
Init tmulinit[] =
{
TCHAR, BNUMBER, 0,
@@ -1738,7 +1741,7 @@ Init tmulinit[] =
-1, 0, 0,
};
-int32 tand[NTYPE];
+int32 tand[NALLTYPES];
Init tandinit[] =
{
TCHAR, BINTEGER, 0,
@@ -1754,7 +1757,7 @@ Init tandinit[] =
-1, 0, 0,
};
-int32 trel[NTYPE];
+int32 trel[NALLTYPES];
Init trelinit[] =
{
TCHAR, BNUMBER, 0,
diff --git a/src/cmd/cc/y.tab.c b/src/cmd/cc/y.tab.c
new file mode 100644
index 000000000..af8328abd
--- /dev/null
+++ b/src/cmd/cc/y.tab.c
@@ -0,0 +1,3811 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LORE = 258,
+ LXORE = 259,
+ LANDE = 260,
+ LLSHE = 261,
+ LRSHE = 262,
+ LMDE = 263,
+ LDVE = 264,
+ LMLE = 265,
+ LME = 266,
+ LPE = 267,
+ LOROR = 268,
+ LANDAND = 269,
+ LNE = 270,
+ LEQ = 271,
+ LGE = 272,
+ LLE = 273,
+ LRSH = 274,
+ LLSH = 275,
+ LMG = 276,
+ LPP = 277,
+ LMM = 278,
+ LNAME = 279,
+ LTYPE = 280,
+ LFCONST = 281,
+ LDCONST = 282,
+ LCONST = 283,
+ LLCONST = 284,
+ LUCONST = 285,
+ LULCONST = 286,
+ LVLCONST = 287,
+ LUVLCONST = 288,
+ LSTRING = 289,
+ LLSTRING = 290,
+ LAUTO = 291,
+ LBREAK = 292,
+ LCASE = 293,
+ LCHAR = 294,
+ LCONTINUE = 295,
+ LDEFAULT = 296,
+ LDO = 297,
+ LDOUBLE = 298,
+ LELSE = 299,
+ LEXTERN = 300,
+ LFLOAT = 301,
+ LFOR = 302,
+ LGOTO = 303,
+ LIF = 304,
+ LINT = 305,
+ LLONG = 306,
+ LREGISTER = 307,
+ LRETURN = 308,
+ LSHORT = 309,
+ LSIZEOF = 310,
+ LUSED = 311,
+ LSTATIC = 312,
+ LSTRUCT = 313,
+ LSWITCH = 314,
+ LTYPEDEF = 315,
+ LTYPESTR = 316,
+ LUNION = 317,
+ LUNSIGNED = 318,
+ LWHILE = 319,
+ LVOID = 320,
+ LENUM = 321,
+ LSIGNED = 322,
+ LCONSTNT = 323,
+ LVOLATILE = 324,
+ LSET = 325,
+ LSIGNOF = 326,
+ LRESTRICT = 327,
+ LINLINE = 328
+ };
+#endif
+/* Tokens. */
+#define LORE 258
+#define LXORE 259
+#define LANDE 260
+#define LLSHE 261
+#define LRSHE 262
+#define LMDE 263
+#define LDVE 264
+#define LMLE 265
+#define LME 266
+#define LPE 267
+#define LOROR 268
+#define LANDAND 269
+#define LNE 270
+#define LEQ 271
+#define LGE 272
+#define LLE 273
+#define LRSH 274
+#define LLSH 275
+#define LMG 276
+#define LPP 277
+#define LMM 278
+#define LNAME 279
+#define LTYPE 280
+#define LFCONST 281
+#define LDCONST 282
+#define LCONST 283
+#define LLCONST 284
+#define LUCONST 285
+#define LULCONST 286
+#define LVLCONST 287
+#define LUVLCONST 288
+#define LSTRING 289
+#define LLSTRING 290
+#define LAUTO 291
+#define LBREAK 292
+#define LCASE 293
+#define LCHAR 294
+#define LCONTINUE 295
+#define LDEFAULT 296
+#define LDO 297
+#define LDOUBLE 298
+#define LELSE 299
+#define LEXTERN 300
+#define LFLOAT 301
+#define LFOR 302
+#define LGOTO 303
+#define LIF 304
+#define LINT 305
+#define LLONG 306
+#define LREGISTER 307
+#define LRETURN 308
+#define LSHORT 309
+#define LSIZEOF 310
+#define LUSED 311
+#define LSTATIC 312
+#define LSTRUCT 313
+#define LSWITCH 314
+#define LTYPEDEF 315
+#define LTYPESTR 316
+#define LUNION 317
+#define LUNSIGNED 318
+#define LWHILE 319
+#define LVOID 320
+#define LENUM 321
+#define LSIGNED 322
+#define LCONSTNT 323
+#define LVOLATILE 324
+#define LSET 325
+#define LSIGNOF 326
+#define LRESTRICT 327
+#define LINLINE 328
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 31 "cc.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */
+#include "cc.h"
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 36 "cc.y"
+{
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ uchar c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ Type* t3;
+ uchar c;
+ } tyty;
+ struct
+ {
+ char* s;
+ int32 l;
+ } sval;
+ int32 lval;
+ double dval;
+ vlong vval;
+}
+/* Line 193 of yacc.c. */
+#line 274 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 287 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 1188
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 98
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 75
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 246
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 412
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 328
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 96, 2, 2, 2, 35, 22, 2,
+ 38, 92, 33, 31, 4, 32, 36, 34, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 17, 3,
+ 25, 5, 26, 16, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 37, 2, 93, 21, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 94, 20, 95, 97, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 18, 19,
+ 23, 24, 27, 28, 29, 30, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 10, 14, 15, 16, 23,
+ 25, 26, 31, 35, 37, 41, 43, 47, 52, 57,
+ 60, 64, 66, 67, 72, 76, 77, 82, 84, 88,
+ 89, 94, 95, 101, 102, 104, 106, 110, 112, 116,
+ 119, 120, 122, 125, 129, 131, 133, 138, 143, 146,
+ 150, 154, 156, 160, 164, 167, 170, 173, 177, 179,
+ 182, 184, 186, 189, 190, 192, 194, 197, 200, 204,
+ 208, 212, 213, 216, 219, 221, 224, 228, 231, 234,
+ 237, 239, 242, 244, 247, 250, 251, 254, 260, 268,
+ 269, 280, 286, 294, 298, 304, 307, 310, 314, 320,
+ 326, 327, 329, 330, 332, 334, 336, 340, 342, 346,
+ 350, 354, 358, 362, 366, 370, 374, 378, 382, 386,
+ 390, 394, 398, 402, 406, 410, 414, 420, 424, 428,
+ 432, 436, 440, 444, 448, 452, 456, 460, 464, 466,
+ 472, 480, 482, 485, 488, 491, 494, 497, 500, 503,
+ 506, 509, 512, 516, 522, 528, 533, 538, 542, 546,
+ 549, 552, 554, 556, 558, 560, 562, 564, 566, 568,
+ 570, 572, 574, 576, 579, 581, 584, 585, 587, 589,
+ 593, 594, 599, 600, 602, 604, 606, 608, 611, 614,
+ 618, 621, 625, 627, 629, 632, 633, 638, 641, 644,
+ 645, 650, 653, 656, 657, 658, 666, 667, 673, 675,
+ 677, 680, 681, 684, 686, 688, 690, 692, 695, 697,
+ 699, 701, 705, 708, 712, 714, 716, 718, 720, 722,
+ 724, 726, 728, 730, 732, 734, 736, 738, 740, 742,
+ 744, 746, 748, 750, 752, 754, 756
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 99, 0, -1, -1, 99, 100, -1, 151, 3, -1,
+ 151, 103, 3, -1, -1, -1, 151, 105, 101, 110,
+ 102, 128, -1, 105, -1, -1, 105, 104, 5, 122,
+ -1, 103, 4, 103, -1, 106, -1, 33, 162, 105,
+ -1, 171, -1, 38, 105, 92, -1, 106, 38, 126,
+ 92, -1, 106, 37, 138, 93, -1, 154, 3, -1,
+ 154, 108, 3, -1, 105, -1, -1, 105, 109, 5,
+ 122, -1, 108, 4, 108, -1, -1, 110, 154, 111,
+ 3, -1, 105, -1, 111, 4, 111, -1, -1, 153,
+ 113, 115, 3, -1, -1, 112, 153, 114, 115, 3,
+ -1, -1, 116, -1, 117, -1, 116, 4, 116, -1,
+ 105, -1, 171, 17, 139, -1, 17, 139, -1, -1,
+ 119, -1, 33, 162, -1, 33, 162, 119, -1, 120,
+ -1, 121, -1, 120, 38, 126, 92, -1, 120, 37,
+ 138, 93, -1, 38, 92, -1, 37, 138, 93, -1,
+ 38, 119, 92, -1, 141, -1, 94, 125, 95, -1,
+ 37, 139, 93, -1, 36, 172, -1, 123, 5, -1,
+ 122, 4, -1, 124, 122, 4, -1, 123, -1, 124,
+ 123, -1, 124, -1, 122, -1, 124, 122, -1, -1,
+ 127, -1, 170, -1, 153, 118, -1, 153, 105, -1,
+ 36, 36, 36, -1, 127, 4, 127, -1, 94, 129,
+ 95, -1, -1, 129, 107, -1, 129, 132, -1, 131,
+ -1, 130, 131, -1, 56, 141, 17, -1, 59, 17,
+ -1, 42, 17, -1, 1, 3, -1, 134, -1, 130,
+ 134, -1, 137, -1, 154, 108, -1, 137, 3, -1,
+ -1, 135, 128, -1, 67, 38, 140, 92, 132, -1,
+ 67, 38, 140, 92, 132, 62, 132, -1, -1, 136,
+ 65, 38, 133, 3, 137, 3, 137, 92, 132, -1,
+ 82, 38, 140, 92, 132, -1, 60, 132, 82, 38,
+ 140, 92, 3, -1, 71, 137, 3, -1, 77, 38,
+ 140, 92, 132, -1, 55, 3, -1, 58, 3, -1,
+ 66, 172, 3, -1, 74, 38, 147, 92, 3, -1,
+ 88, 38, 147, 92, 3, -1, -1, 140, -1, -1,
+ 139, -1, 141, -1, 141, -1, 140, 4, 140, -1,
+ 142, -1, 141, 33, 141, -1, 141, 34, 141, -1,
+ 141, 35, 141, -1, 141, 31, 141, -1, 141, 32,
+ 141, -1, 141, 29, 141, -1, 141, 30, 141, -1,
+ 141, 25, 141, -1, 141, 26, 141, -1, 141, 28,
+ 141, -1, 141, 27, 141, -1, 141, 24, 141, -1,
+ 141, 23, 141, -1, 141, 22, 141, -1, 141, 21,
+ 141, -1, 141, 20, 141, -1, 141, 19, 141, -1,
+ 141, 18, 141, -1, 141, 16, 140, 17, 141, -1,
+ 141, 5, 141, -1, 141, 15, 141, -1, 141, 14,
+ 141, -1, 141, 13, 141, -1, 141, 12, 141, -1,
+ 141, 11, 141, -1, 141, 9, 141, -1, 141, 10,
+ 141, -1, 141, 8, 141, -1, 141, 7, 141, -1,
+ 141, 6, 141, -1, 143, -1, 38, 153, 118, 92,
+ 142, -1, 38, 153, 118, 92, 94, 125, 95, -1,
+ 144, -1, 33, 142, -1, 22, 142, -1, 31, 142,
+ -1, 32, 142, -1, 96, 142, -1, 97, 142, -1,
+ 40, 142, -1, 41, 142, -1, 73, 143, -1, 89,
+ 143, -1, 38, 140, 92, -1, 73, 38, 153, 118,
+ 92, -1, 89, 38, 153, 118, 92, -1, 144, 38,
+ 147, 92, -1, 144, 37, 140, 93, -1, 144, 39,
+ 172, -1, 144, 36, 172, -1, 144, 40, -1, 144,
+ 41, -1, 170, -1, 46, -1, 47, -1, 48, -1,
+ 49, -1, 45, -1, 44, -1, 50, -1, 51, -1,
+ 145, -1, 146, -1, 52, -1, 145, 52, -1, 53,
+ -1, 146, 53, -1, -1, 148, -1, 141, -1, 148,
+ 4, 148, -1, -1, 94, 150, 112, 95, -1, -1,
+ 154, -1, 155, -1, 167, -1, 164, -1, 155, 161,
+ -1, 167, 161, -1, 164, 155, 162, -1, 164, 167,
+ -1, 164, 167, 161, -1, 152, -1, 152, -1, 76,
+ 172, -1, -1, 76, 172, 156, 149, -1, 76, 149,
+ -1, 80, 172, -1, -1, 80, 172, 157, 149, -1,
+ 80, 149, -1, 84, 172, -1, -1, -1, 84, 172,
+ 158, 94, 159, 166, 95, -1, -1, 84, 94, 160,
+ 166, 95, -1, 43, -1, 163, -1, 161, 163, -1,
+ -1, 162, 169, -1, 167, -1, 169, -1, 168, -1,
+ 165, -1, 164, 165, -1, 169, -1, 168, -1, 42,
+ -1, 42, 5, 141, -1, 166, 4, -1, 166, 4,
+ 166, -1, 57, -1, 72, -1, 68, -1, 69, -1,
+ 85, -1, 81, -1, 64, -1, 61, -1, 83, -1,
+ 54, -1, 75, -1, 63, -1, 78, -1, 79, -1,
+ 70, -1, 91, -1, 86, -1, 87, -1, 90, -1,
+ 42, -1, 172, -1, 42, -1, 43, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 101, 101, 102, 108, 112, 114, 128, 113, 143,
+ 148, 147, 155, 158, 159, 166, 167, 171, 175, 184,
+ 188, 194, 200, 199, 211, 224, 225, 228, 232, 239,
+ 238, 244, 243, 250, 254, 257, 261, 264, 269, 273,
+ 282, 285, 288, 293, 298, 301, 302, 306, 312, 316,
+ 320, 326, 327, 333, 337, 342, 345, 346, 350, 351,
+ 357, 358, 359, 365, 368, 375, 376, 381, 386, 390,
+ 396, 406, 409, 413, 419, 420, 426, 430, 434, 440,
+ 444, 445, 451, 452, 458, 459, 459, 470, 476, 484,
+ 484, 495, 499, 503, 508, 522, 526, 530, 534, 538,
+ 544, 547, 550, 553, 556, 563, 564, 570, 571, 575,
+ 579, 583, 587, 591, 595, 599, 603, 607, 611, 615,
+ 619, 623, 627, 631, 635, 639, 643, 647, 651, 655,
+ 659, 663, 667, 671, 675, 679, 683, 687, 693, 694,
+ 701, 709, 710, 714, 718, 722, 726, 730, 734, 738,
+ 742, 746, 752, 756, 762, 768, 776, 780, 785, 790,
+ 794, 798, 799, 806, 813, 820, 827, 834, 841, 848,
+ 855, 856, 859, 869, 887, 897, 915, 918, 921, 922,
+ 929, 928, 951, 955, 958, 963, 968, 974, 982, 988,
+ 994, 1000, 1008, 1016, 1023, 1029, 1028, 1040, 1048, 1054,
+ 1053, 1065, 1073, 1082, 1086, 1081, 1103, 1102, 1111, 1117,
+ 1118, 1124, 1127, 1133, 1134, 1135, 1138, 1139, 1145, 1146,
+ 1149, 1153, 1157, 1158, 1161, 1162, 1163, 1164, 1165, 1166,
+ 1167, 1168, 1169, 1172, 1173, 1174, 1175, 1176, 1177, 1178,
+ 1181, 1182, 1183, 1186, 1201, 1213, 1214
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "';'", "','", "'='", "LORE", "LXORE",
+ "LANDE", "LLSHE", "LRSHE", "LMDE", "LDVE", "LMLE", "LME", "LPE", "'?'",
+ "':'", "LOROR", "LANDAND", "'|'", "'^'", "'&'", "LNE", "LEQ", "'<'",
+ "'>'", "LGE", "LLE", "LRSH", "LLSH", "'+'", "'-'", "'*'", "'/'", "'%'",
+ "'.'", "'['", "'('", "LMG", "LPP", "LMM", "LNAME", "LTYPE", "LFCONST",
+ "LDCONST", "LCONST", "LLCONST", "LUCONST", "LULCONST", "LVLCONST",
+ "LUVLCONST", "LSTRING", "LLSTRING", "LAUTO", "LBREAK", "LCASE", "LCHAR",
+ "LCONTINUE", "LDEFAULT", "LDO", "LDOUBLE", "LELSE", "LEXTERN", "LFLOAT",
+ "LFOR", "LGOTO", "LIF", "LINT", "LLONG", "LREGISTER", "LRETURN",
+ "LSHORT", "LSIZEOF", "LUSED", "LSTATIC", "LSTRUCT", "LSWITCH",
+ "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID",
+ "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF",
+ "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'",
+ "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor",
+ "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5",
+ "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2",
+ "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist",
+ "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7",
+ "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr",
+ "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9",
+ "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12",
+ "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname",
+ "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 59, 44, 61, 258, 259, 260, 261,
+ 262, 263, 264, 265, 266, 267, 63, 58, 268, 269,
+ 124, 94, 38, 270, 271, 60, 62, 272, 273, 274,
+ 275, 43, 45, 42, 47, 37, 46, 91, 40, 276,
+ 277, 278, 279, 280, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 301, 302, 303, 304, 305, 306,
+ 307, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, 318, 319, 320, 321, 322, 323, 324, 325, 326,
+ 327, 328, 41, 93, 123, 125, 33, 126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 98, 99, 99, 100, 100, 101, 102, 100, 103,
+ 104, 103, 103, 105, 105, 106, 106, 106, 106, 107,
+ 107, 108, 109, 108, 108, 110, 110, 111, 111, 113,
+ 112, 114, 112, 115, 115, 116, 116, 117, 117, 117,
+ 118, 118, 119, 119, 119, 120, 120, 120, 121, 121,
+ 121, 122, 122, 123, 123, 123, 124, 124, 124, 124,
+ 125, 125, 125, 126, 126, 127, 127, 127, 127, 127,
+ 128, 129, 129, 129, 130, 130, 131, 131, 131, 132,
+ 132, 132, 133, 133, 134, 135, 134, 134, 134, 136,
+ 134, 134, 134, 134, 134, 134, 134, 134, 134, 134,
+ 137, 137, 138, 138, 139, 140, 140, 141, 141, 141,
+ 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
+ 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
+ 141, 141, 141, 141, 141, 141, 141, 141, 142, 142,
+ 142, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144, 144, 145, 145, 146, 146, 147, 147, 148, 148,
+ 150, 149, 151, 151, 152, 152, 152, 152, 152, 152,
+ 152, 152, 153, 154, 155, 156, 155, 155, 155, 157,
+ 155, 155, 155, 158, 159, 155, 160, 155, 155, 161,
+ 161, 162, 162, 163, 163, 163, 164, 164, 165, 165,
+ 166, 166, 166, 166, 167, 167, 167, 167, 167, 167,
+ 167, 167, 167, 168, 168, 168, 168, 168, 168, 168,
+ 169, 169, 169, 170, 171, 172, 172
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 2, 3, 0, 0, 6, 1,
+ 0, 4, 3, 1, 3, 1, 3, 4, 4, 2,
+ 3, 1, 0, 4, 3, 0, 4, 1, 3, 0,
+ 4, 0, 5, 0, 1, 1, 3, 1, 3, 2,
+ 0, 1, 2, 3, 1, 1, 4, 4, 2, 3,
+ 3, 1, 3, 3, 2, 2, 2, 3, 1, 2,
+ 1, 1, 2, 0, 1, 1, 2, 2, 3, 3,
+ 3, 0, 2, 2, 1, 2, 3, 2, 2, 2,
+ 1, 2, 1, 2, 2, 0, 2, 5, 7, 0,
+ 10, 5, 7, 3, 5, 2, 2, 3, 5, 5,
+ 0, 1, 0, 1, 1, 1, 3, 1, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 5, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 1, 5,
+ 7, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 5, 5, 4, 4, 3, 3, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 1, 2, 0, 1, 1, 3,
+ 0, 4, 0, 1, 1, 1, 1, 2, 2, 3,
+ 2, 3, 1, 1, 2, 0, 4, 2, 2, 0,
+ 4, 2, 2, 0, 0, 7, 0, 5, 1, 1,
+ 2, 0, 2, 1, 1, 1, 1, 2, 1, 1,
+ 1, 3, 2, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 182, 1, 208, 233, 224, 231, 235, 230, 226,
+ 227, 238, 225, 234, 0, 236, 237, 0, 229, 232,
+ 0, 228, 240, 241, 242, 239, 3, 0, 193, 183,
+ 184, 186, 216, 185, 219, 218, 245, 246, 180, 197,
+ 194, 201, 198, 206, 202, 4, 211, 0, 0, 6,
+ 13, 15, 244, 187, 209, 213, 215, 214, 211, 217,
+ 190, 188, 0, 0, 0, 0, 0, 0, 0, 5,
+ 0, 25, 0, 102, 63, 210, 189, 191, 0, 192,
+ 29, 196, 200, 220, 0, 204, 14, 212, 16, 12,
+ 9, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 243, 167, 166, 162, 163, 164, 165, 168, 169, 172,
+ 174, 0, 0, 0, 0, 0, 103, 104, 107, 138,
+ 141, 170, 171, 161, 0, 0, 64, 40, 65, 181,
+ 31, 33, 0, 222, 207, 0, 0, 0, 0, 11,
+ 51, 143, 144, 145, 142, 0, 105, 40, 148, 149,
+ 0, 150, 0, 151, 146, 147, 18, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 176,
+ 0, 159, 160, 173, 175, 0, 17, 0, 211, 102,
+ 0, 67, 66, 41, 44, 45, 33, 0, 37, 0,
+ 34, 35, 15, 221, 223, 0, 71, 8, 27, 0,
+ 0, 0, 61, 58, 60, 0, 0, 152, 211, 0,
+ 0, 40, 40, 127, 137, 136, 135, 133, 134, 132,
+ 131, 130, 129, 128, 0, 125, 124, 123, 122, 121,
+ 120, 119, 115, 116, 118, 117, 113, 114, 111, 112,
+ 108, 109, 110, 158, 0, 178, 0, 177, 157, 68,
+ 69, 42, 0, 48, 0, 102, 63, 0, 39, 30,
+ 0, 0, 205, 0, 26, 0, 54, 0, 56, 55,
+ 62, 59, 52, 106, 42, 0, 0, 0, 0, 156,
+ 155, 0, 43, 49, 50, 0, 0, 32, 36, 38,
+ 0, 243, 0, 0, 0, 0, 0, 0, 0, 100,
+ 0, 0, 0, 0, 70, 72, 85, 74, 73, 80,
+ 0, 0, 0, 101, 0, 28, 53, 57, 0, 139,
+ 153, 154, 126, 179, 47, 46, 79, 78, 95, 0,
+ 96, 77, 0, 0, 0, 0, 176, 0, 0, 176,
+ 75, 81, 86, 0, 84, 19, 21, 0, 0, 76,
+ 0, 97, 0, 93, 0, 0, 0, 0, 100, 0,
+ 20, 0, 140, 0, 0, 0, 0, 0, 0, 0,
+ 82, 0, 0, 24, 0, 87, 98, 94, 91, 99,
+ 100, 83, 23, 0, 0, 0, 92, 88, 100, 0,
+ 0, 90
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 26, 71, 136, 48, 72, 208, 50, 325,
+ 367, 379, 91, 219, 78, 131, 206, 209, 210, 211,
+ 202, 203, 204, 205, 222, 223, 224, 225, 125, 126,
+ 217, 283, 326, 327, 328, 389, 329, 330, 331, 332,
+ 115, 116, 333, 146, 118, 119, 120, 121, 122, 266,
+ 267, 39, 62, 27, 79, 127, 29, 30, 63, 64,
+ 66, 135, 65, 53, 67, 54, 31, 32, 84, 33,
+ 34, 35, 123, 51, 52
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -366
+static const yytype_int16 yypact[] =
+{
+ -366, 541, -366, -366, -366, -366, -366, -366, -366, -366,
+ -366, -366, -366, -366, -3, -366, -366, -3, -366, -366,
+ 140, -366, -366, -366, -366, -366, -366, 161, -366, -366,
+ 949, 914, -366, 949, -366, -366, -366, -366, -366, -366,
+ -64, -366, -60, -366, -17, -366, -366, 21, 70, 316,
+ 51, -366, -366, 949, -366, -366, -366, -366, -366, -366,
+ 949, 949, 914, -13, -13, 57, 9, 154, 54, -366,
+ 21, -366, 164, 745, 836, -366, -41, 949, 875, -366,
+ -366, -366, -366, 167, 7, -366, -366, -366, -366, -366,
+ 181, 914, 677, 745, 745, 745, 745, 607, 745, 745,
+ -366, -366, -366, -366, -366, -366, -366, -366, -366, -366,
+ -366, 779, 813, 745, 745, 95, -366, 1067, -366, -366,
+ 422, 141, 145, -366, 176, 139, 225, 128, -366, -366,
+ -366, 289, 745, 57, -366, 57, 149, 21, 169, -366,
+ 1067, -366, -366, -366, -366, 31, 1067, 130, -366, -366,
+ 607, -366, 607, -366, -366, -366, -366, 745, 745, 745,
+ 745, 745, 745, 745, 745, 745, 745, 745, 745, 745,
+ 745, 745, 745, 745, 745, 745, 745, 745, 745, 745,
+ 745, 745, 745, 745, 745, 745, 745, 53, 745, 745,
+ 53, -366, -366, -366, -366, 199, -366, 836, -366, 745,
+ 147, -366, -366, -366, 111, -366, 289, 745, -366, 243,
+ 247, -366, 235, 1067, -366, 13, -366, -366, -366, 222,
+ 53, 745, 260, 255, 169, 172, 745, -366, -366, -6,
+ 180, 130, 130, 1067, 1067, 1067, 1067, 1067, 1067, 1067,
+ 1067, 1067, 1067, 1067, 16, 1084, 1100, 1115, 1129, 1142,
+ 1153, 1153, 319, 319, 319, 319, 303, 303, 295, 295,
+ -366, -366, -366, -366, 11, 1067, 186, 269, -366, -366,
+ -366, 190, 188, -366, 187, 745, 836, 280, -366, -366,
+ 289, 745, -366, 338, -366, 21, -366, 191, -366, -366,
+ 284, 255, -366, -366, 217, 711, 202, 204, 745, -366,
+ -366, 745, -366, -366, -366, 198, 207, -366, -366, -366,
+ 309, 296, 312, 745, 320, 307, 435, 53, 302, 745,
+ 305, 306, 308, 318, -366, -366, 504, -366, -366, -366,
+ 149, 292, 342, 354, 259, -366, -366, -366, 169, -366,
+ -366, -366, 421, -366, -366, -366, -366, -366, -366, 1036,
+ -366, -366, 277, 358, 745, 359, 745, 745, 745, 745,
+ -366, -366, -366, 325, -366, -366, 361, 234, 272, -366,
+ 326, -366, 64, -366, 276, 66, 67, 281, 607, 367,
+ -366, 21, -366, 745, 435, 371, 435, 435, 372, 397,
+ -366, 21, 677, -366, 68, 368, -366, -366, -366, -366,
+ 745, 427, -366, 461, 435, 462, -366, -366, 745, 377,
+ 435, -366
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -366, -366, -366, -366, -366, 400, -366, -26, -366, -366,
+ -365, -366, -366, 189, -366, -366, -366, 266, 209, -366,
+ -122, -187, -366, -366, -82, 254, -366, 133, 216, 299,
+ 168, -366, -366, 171, -304, -366, 173, -366, -366, -227,
+ -181, -183, -83, -45, -38, 137, -366, -366, -366, -308,
+ 203, 2, -366, -366, -1, 0, -88, 472, -366, -366,
+ -366, -366, -366, -10, -51, 208, -366, 474, 22, 256,
+ 265, -24, -52, -127, -12
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -204
+static const yytype_int16 yytable[] =
+{
+ 28, 49, 40, 137, 212, 42, 57, 76, 44, 57,
+ 139, 133, 352, 274, 145, 226, 393, 133, 272, 41,
+ 226, 68, 128, 61, 278, 230, 401, 228, 117, 57,
+ -195, 199, 229, 298, -199, 226, 57, 57, 287, 36,
+ 37, 86, 274, 87, 90, 22, 23, 140, 374, 24,
+ 77, 377, 87, 57, 46, 141, 142, 143, 144, 47,
+ 148, 149, 80, 36, 37, 81, 82, 145, 226, 145,
+ 226, 226, 226, 69, 70, 154, 155, -203, 130, 212,
+ 395, 38, 397, 398, 302, 244, 273, 213, 73, 74,
+ 28, 38, 355, 140, 305, 36, 37, 147, 309, 83,
+ 407, 201, 134, 85, 299, 264, 411, 302, 282, 296,
+ 297, 218, 233, 234, 235, 236, 237, 238, 239, 240,
+ 241, 242, 243, 227, 245, 246, 247, 248, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 290, 293, 265, 128, 88, 271, 275, 276,
+ 231, 390, 232, 212, 117, 214, 384, 215, 386, 387,
+ 403, 198, 117, 228, 45, 199, 200, 199, 229, 92,
+ 36, 37, 132, 405, 68, 263, 117, 294, 268, 140,
+ 198, 409, 36, 37, 199, 200, -10, 46, 156, 36,
+ 37, 93, 47, 193, 46, 334, 36, 37, 194, 47,
+ 94, 95, 96, 36, 37, 220, 221, 97, 286, 98,
+ 99, 100, 195, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 198, 128, 284, 285, 199, 200, 197,
+ 117, 196, 36, 37, 43, 269, 117, 380, 381, 273,
+ 22, 23, 111, 216, 24, 86, 279, 87, 151, 153,
+ 228, 280, 281, 342, 199, 229, 265, 339, 112, 218,
+ 289, 75, 365, 138, 288, 113, 114, 292, 349, 75,
+ 87, 372, 295, 301, 375, 376, 22, 23, 300, 304,
+ 24, 303, 28, 307, 336, 75, 55, 60, 337, 55,
+ 391, 344, 46, 140, 340, 56, 341, 47, 56, 345,
+ 394, 36, 37, 22, 23, 353, 207, 24, 366, 55,
+ 402, 265, 346, 347, 265, 348, 55, 55, 56, -9,
+ -9, -10, 46, 350, 351, 56, 56, 47, 184, 185,
+ 186, 36, 37, 55, 182, 183, 184, 185, 186, 310,
+ 354, -100, 56, 356, 357, 364, 358, 140, 180, 181,
+ 182, 183, 184, 185, 186, 366, 359, 363, 226, 370,
+ 93, 371, 373, 378, 383, 366, -22, 382, 385, 94,
+ 95, 96, 392, 388, 396, 399, 97, 28, 98, 99,
+ 311, 3, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 4, 312, 313, 5, 314, 315, 316, 6,
+ 400, 7, 8, -89, 317, 318, 9, 10, 11, 319,
+ 12, 111, 320, 13, 14, 321, 15, 16, 17, 18,
+ 322, 19, 20, 21, 22, 23, 323, 112, 24, 25,
+ 404, 381, -85, 324, 113, 114, 310, 168, -100, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 93, 187, 188,
+ 189, 190, 191, 192, 406, 408, 94, 95, 96, 410,
+ 89, 368, 277, 97, 335, 98, 99, 311, 291, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 308,
+ 312, 313, 306, 314, 315, 316, 270, 360, 362, 361,
+ -89, 317, 318, 58, 343, 59, 319, -100, 111, 320,
+ 0, 0, 321, 0, 0, 0, 0, 322, 0, 0,
+ 0, 0, 0, 323, 112, 0, 93, 0, 0, -85,
+ 0, 113, 114, 0, 0, 94, 95, 96, 0, 0,
+ 0, 2, 97, 0, 98, 99, 311, 0, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110, 0, 312,
+ 313, 0, 314, 315, 316, 0, 0, 0, 0, -89,
+ 317, 318, 0, 0, 0, 319, 0, 111, 320, 0,
+ 0, 321, 0, 0, 3, 0, 322, 0, 0, 0,
+ 0, 0, 323, 112, 0, 4, 0, 0, 5, 0,
+ 113, 114, 6, 0, 7, 8, 0, 0, 0, 9,
+ 10, 11, 0, 12, 0, 0, 13, 14, 0, 15,
+ 16, 17, 18, 0, 19, 20, 21, 22, 23, 93,
+ 0, 24, 25, 0, 0, 0, 0, 0, 94, 95,
+ 96, 0, 0, 0, 0, 97, 0, 98, 99, 100,
+ 3, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 4, 0, 0, 5, 0, 0, 0, 6, 0,
+ 7, 8, 0, 0, 0, 9, 10, 11, 0, 12,
+ 111, 0, 13, 14, 0, 15, 16, 17, 18, 0,
+ 19, 20, 21, 22, 23, 0, 112, 24, 25, 93,
+ 0, 0, 0, 113, 114, 0, 0, 0, 94, 95,
+ 96, 0, 0, 0, 0, 97, 0, 98, 99, 100,
+ 0, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 0, 0, 93, 0, 0, 0, 0, 0, 0,
+ 0, 0, 94, 95, 96, 0, 0, 0, 0, 97,
+ 111, 98, 99, 100, 0, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 0, 112, 93, 0, 0,
+ 0, 138, 0, 113, 114, 0, 94, 95, 96, 0,
+ 0, 0, 0, 97, 111, 98, 99, 100, 0, 101,
+ 102, 103, 104, 105, 106, 107, 108, 109, 110, 0,
+ 112, 93, 0, 0, 0, 338, 0, 113, 114, 0,
+ 94, 95, 96, 0, 0, 0, 0, 150, 111, 98,
+ 99, 100, 0, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 0, 112, 93, 0, 0, 0, 0,
+ 0, 113, 114, 0, 94, 95, 96, 0, 0, 0,
+ 0, 152, 111, 98, 99, 100, 0, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 0, 112, 0,
+ 0, 0, 124, 0, 0, 113, 114, 0, 100, 3,
+ 0, 0, 0, 0, 0, 0, 111, 0, 0, 0,
+ 4, 0, 0, 5, 0, 0, 0, 6, 0, 7,
+ 8, 0, 112, 0, 9, 10, 11, 0, 12, 113,
+ 114, 13, 14, 0, 15, 16, 17, 18, 3, 19,
+ 20, 21, 22, 23, 0, 0, 24, 25, 0, 4,
+ 0, 0, 5, 0, 0, 0, 6, 0, 7, 8,
+ 0, 0, 0, 9, 10, 11, 0, 12, 0, 0,
+ 13, 14, 0, 15, 16, 17, 18, 3, 19, 20,
+ 21, 22, 23, 0, 0, 24, 25, 0, 4, 0,
+ 129, 5, 0, 0, 0, 6, 0, 7, 8, 0,
+ 0, 0, 9, 10, 11, 0, 12, 0, 0, 13,
+ 14, 0, 15, 16, 17, 18, 0, 19, 20, 21,
+ 22, 23, 0, 4, 24, 25, 5, 0, 0, 0,
+ 6, 0, 7, 8, 0, 0, 0, 9, 10, 11,
+ 0, 12, 0, 0, 13, 0, 0, 15, 16, 0,
+ 18, 0, 19, 0, 21, 22, 23, 0, 0, 24,
+ 25, 157, 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 168, 369, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 0, 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 170, 171, 172, 173, 174, 175, 176,
+ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 181, 182, 183, 184, 185, 186, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
+ 186, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 27, 14, 91, 131, 17, 30, 58, 20, 33,
+ 92, 4, 316, 200, 97, 4, 381, 4, 199, 17,
+ 4, 47, 74, 33, 207, 147, 391, 33, 73, 53,
+ 94, 37, 38, 17, 94, 4, 60, 61, 221, 42,
+ 43, 67, 229, 67, 70, 86, 87, 92, 356, 90,
+ 60, 359, 76, 77, 33, 93, 94, 95, 96, 38,
+ 98, 99, 62, 42, 43, 63, 64, 150, 4, 152,
+ 4, 4, 4, 3, 4, 113, 114, 94, 78, 206,
+ 384, 94, 386, 387, 271, 168, 92, 132, 37, 38,
+ 91, 94, 319, 138, 275, 42, 43, 97, 281, 42,
+ 404, 127, 95, 94, 93, 188, 410, 294, 95, 231,
+ 232, 137, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 92, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 224, 226, 189, 197, 92, 198, 37, 38,
+ 150, 378, 152, 280, 199, 133, 92, 135, 92, 92,
+ 92, 33, 207, 33, 3, 37, 38, 37, 38, 5,
+ 42, 43, 5, 400, 200, 187, 221, 228, 190, 224,
+ 33, 408, 42, 43, 37, 38, 5, 33, 93, 42,
+ 43, 22, 38, 52, 33, 283, 42, 43, 53, 38,
+ 31, 32, 33, 42, 43, 36, 37, 38, 220, 40,
+ 41, 42, 36, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 33, 276, 3, 4, 37, 38, 4,
+ 275, 92, 42, 43, 94, 36, 281, 3, 4, 92,
+ 86, 87, 73, 94, 90, 271, 3, 271, 111, 112,
+ 33, 4, 17, 298, 37, 38, 301, 295, 89, 285,
+ 5, 53, 3, 94, 4, 96, 97, 95, 313, 61,
+ 294, 354, 92, 4, 357, 358, 86, 87, 92, 92,
+ 90, 93, 283, 3, 93, 77, 30, 31, 4, 33,
+ 378, 93, 33, 338, 92, 30, 92, 38, 33, 92,
+ 383, 42, 43, 86, 87, 317, 17, 90, 334, 53,
+ 392, 356, 3, 17, 359, 3, 60, 61, 53, 3,
+ 4, 5, 33, 3, 17, 60, 61, 38, 33, 34,
+ 35, 42, 43, 77, 31, 32, 33, 34, 35, 1,
+ 38, 3, 77, 38, 38, 3, 38, 392, 29, 30,
+ 31, 32, 33, 34, 35, 381, 38, 65, 4, 82,
+ 22, 3, 3, 38, 38, 391, 5, 95, 92, 31,
+ 32, 33, 5, 92, 3, 3, 38, 378, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 3, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ 62, 4, 94, 95, 96, 97, 1, 16, 3, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 22, 36, 37,
+ 38, 39, 40, 41, 3, 3, 31, 32, 33, 92,
+ 70, 338, 206, 38, 285, 40, 41, 42, 224, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 280,
+ 55, 56, 276, 58, 59, 60, 197, 326, 330, 326,
+ 65, 66, 67, 31, 301, 31, 71, 3, 73, 74,
+ -1, -1, 77, -1, -1, -1, -1, 82, -1, -1,
+ -1, -1, -1, 88, 89, -1, 22, -1, -1, 94,
+ -1, 96, 97, -1, -1, 31, 32, 33, -1, -1,
+ -1, 0, 38, -1, 40, 41, 42, -1, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, -1, 55,
+ 56, -1, 58, 59, 60, -1, -1, -1, -1, 65,
+ 66, 67, -1, -1, -1, 71, -1, 73, 74, -1,
+ -1, 77, -1, -1, 43, -1, 82, -1, -1, -1,
+ -1, -1, 88, 89, -1, 54, -1, -1, 57, -1,
+ 96, 97, 61, -1, 63, 64, -1, -1, -1, 68,
+ 69, 70, -1, 72, -1, -1, 75, 76, -1, 78,
+ 79, 80, 81, -1, 83, 84, 85, 86, 87, 22,
+ -1, 90, 91, -1, -1, -1, -1, -1, 31, 32,
+ 33, -1, -1, -1, -1, 38, -1, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, -1, -1, 57, -1, -1, -1, 61, -1,
+ 63, 64, -1, -1, -1, 68, 69, 70, -1, 72,
+ 73, -1, 75, 76, -1, 78, 79, 80, 81, -1,
+ 83, 84, 85, 86, 87, -1, 89, 90, 91, 22,
+ -1, -1, -1, 96, 97, -1, -1, -1, 31, 32,
+ 33, -1, -1, -1, -1, 38, -1, 40, 41, 42,
+ -1, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ -1, -1, 31, 32, 33, -1, -1, -1, -1, 38,
+ 73, 40, 41, 42, -1, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, -1, 89, 22, -1, -1,
+ -1, 94, -1, 96, 97, -1, 31, 32, 33, -1,
+ -1, -1, -1, 38, 73, 40, 41, 42, -1, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, -1,
+ 89, 22, -1, -1, -1, 94, -1, 96, 97, -1,
+ 31, 32, 33, -1, -1, -1, -1, 38, 73, 40,
+ 41, 42, -1, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, -1, 89, 22, -1, -1, -1, -1,
+ -1, 96, 97, -1, 31, 32, 33, -1, -1, -1,
+ -1, 38, 73, 40, 41, 42, -1, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, -1, 89, -1,
+ -1, -1, 36, -1, -1, 96, 97, -1, 42, 43,
+ -1, -1, -1, -1, -1, -1, 73, -1, -1, -1,
+ 54, -1, -1, 57, -1, -1, -1, 61, -1, 63,
+ 64, -1, 89, -1, 68, 69, 70, -1, 72, 96,
+ 97, 75, 76, -1, 78, 79, 80, 81, 43, 83,
+ 84, 85, 86, 87, -1, -1, 90, 91, -1, 54,
+ -1, -1, 57, -1, -1, -1, 61, -1, 63, 64,
+ -1, -1, -1, 68, 69, 70, -1, 72, -1, -1,
+ 75, 76, -1, 78, 79, 80, 81, 43, 83, 84,
+ 85, 86, 87, -1, -1, 90, 91, -1, 54, -1,
+ 95, 57, -1, -1, -1, 61, -1, 63, 64, -1,
+ -1, -1, 68, 69, 70, -1, 72, -1, -1, 75,
+ 76, -1, 78, 79, 80, 81, -1, 83, 84, 85,
+ 86, 87, -1, 54, 90, 91, 57, -1, -1, -1,
+ 61, -1, 63, 64, -1, -1, -1, 68, 69, 70,
+ -1, 72, -1, -1, 75, -1, -1, 78, 79, -1,
+ 81, -1, 83, -1, 85, 86, 87, -1, -1, 90,
+ 91, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, -1, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 19, 20, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 99, 0, 43, 54, 57, 61, 63, 64, 68,
+ 69, 70, 72, 75, 76, 78, 79, 80, 81, 83,
+ 84, 85, 86, 87, 90, 91, 100, 151, 152, 154,
+ 155, 164, 165, 167, 168, 169, 42, 43, 94, 149,
+ 172, 149, 172, 94, 172, 3, 33, 38, 103, 105,
+ 106, 171, 172, 161, 163, 167, 168, 169, 155, 165,
+ 167, 161, 150, 156, 157, 160, 158, 162, 105, 3,
+ 4, 101, 104, 37, 38, 163, 162, 161, 112, 152,
+ 153, 149, 149, 42, 166, 94, 105, 169, 92, 103,
+ 105, 110, 5, 22, 31, 32, 33, 38, 40, 41,
+ 42, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 73, 89, 96, 97, 138, 139, 141, 142, 143,
+ 144, 145, 146, 170, 36, 126, 127, 153, 170, 95,
+ 153, 113, 5, 4, 95, 159, 102, 154, 94, 122,
+ 141, 142, 142, 142, 142, 140, 141, 153, 142, 142,
+ 38, 143, 38, 143, 142, 142, 93, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 52, 53, 36, 92, 4, 33, 37,
+ 38, 105, 118, 119, 120, 121, 114, 17, 105, 115,
+ 116, 117, 171, 141, 166, 166, 94, 128, 105, 111,
+ 36, 37, 122, 123, 124, 125, 4, 92, 33, 38,
+ 118, 153, 153, 141, 141, 141, 141, 141, 141, 141,
+ 141, 141, 141, 141, 140, 141, 141, 141, 141, 141,
+ 141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
+ 141, 141, 141, 172, 140, 141, 147, 148, 172, 36,
+ 127, 162, 138, 92, 119, 37, 38, 115, 139, 3,
+ 4, 17, 95, 129, 3, 4, 172, 139, 4, 5,
+ 122, 123, 95, 140, 162, 92, 118, 118, 17, 93,
+ 92, 4, 119, 93, 92, 138, 126, 3, 116, 139,
+ 1, 42, 55, 56, 58, 59, 60, 66, 67, 71,
+ 74, 77, 82, 88, 95, 107, 130, 131, 132, 134,
+ 135, 136, 137, 140, 154, 111, 93, 4, 94, 142,
+ 92, 92, 141, 148, 93, 92, 3, 17, 3, 141,
+ 3, 17, 132, 172, 38, 137, 38, 38, 38, 38,
+ 131, 134, 128, 65, 3, 3, 105, 108, 125, 17,
+ 82, 3, 140, 3, 147, 140, 140, 147, 38, 109,
+ 3, 4, 95, 38, 92, 92, 92, 92, 92, 133,
+ 137, 154, 5, 108, 140, 132, 3, 132, 132, 3,
+ 3, 108, 122, 92, 62, 137, 3, 132, 3, 137,
+ 92, 132
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 109 "cc.y"
+ {
+ dodecl(xdecl, lastclass, lasttype, Z);
+ }
+ break;
+
+ case 6:
+#line 114 "cc.y"
+ {
+ lastdcl = T;
+ firstarg = S;
+ dodecl(xdecl, lastclass, lasttype, (yyvsp[(2) - (2)].node));
+ if(lastdcl == T || lastdcl->etype != TFUNC) {
+ diag((yyvsp[(2) - (2)].node), "not a function");
+ lastdcl = types[TFUNC];
+ }
+ thisfn = lastdcl;
+ markdcl();
+ firstdcl = dclstack;
+ argmark((yyvsp[(2) - (2)].node), 0);
+ }
+ break;
+
+ case 7:
+#line 128 "cc.y"
+ {
+ argmark((yyvsp[(2) - (4)].node), 1);
+ }
+ break;
+
+ case 8:
+#line 132 "cc.y"
+ {
+ Node *n;
+
+ n = revertdcl();
+ if(n)
+ (yyvsp[(6) - (6)].node) = new(OLIST, n, (yyvsp[(6) - (6)].node));
+ if(!debug['a'] && !debug['Z'])
+ codgen((yyvsp[(6) - (6)].node), (yyvsp[(2) - (6)].node));
+ }
+ break;
+
+ case 9:
+#line 144 "cc.y"
+ {
+ dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 10:
+#line 148 "cc.y"
+ {
+ (yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 11:
+#line 152 "cc.y"
+ {
+ doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
+ }
+ break;
+
+ case 14:
+#line 160 "cc.y"
+ {
+ (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
+ (yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
+ }
+ break;
+
+ case 16:
+#line 168 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+ }
+ break;
+
+ case 17:
+#line 172 "cc.y"
+ {
+ (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 18:
+#line 176 "cc.y"
+ {
+ (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 19:
+#line 185 "cc.y"
+ {
+ (yyval.node) = dodecl(adecl, lastclass, lasttype, Z);
+ }
+ break;
+
+ case 20:
+#line 189 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+ }
+ break;
+
+ case 21:
+#line 195 "cc.y"
+ {
+ dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 22:
+#line 200 "cc.y"
+ {
+ (yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 23:
+#line 204 "cc.y"
+ {
+ int32 w;
+
+ w = (yyvsp[(1) - (4)].node)->sym->type->width;
+ (yyval.node) = doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
+ (yyval.node) = contig((yyvsp[(1) - (4)].node)->sym, (yyval.node), w);
+ }
+ break;
+
+ case 24:
+#line 212 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(1) - (3)].node);
+ if((yyvsp[(3) - (3)].node) != Z) {
+ (yyval.node) = (yyvsp[(3) - (3)].node);
+ if((yyvsp[(1) - (3)].node) != Z)
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ }
+ break;
+
+ case 27:
+#line 229 "cc.y"
+ {
+ dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 29:
+#line 239 "cc.y"
+ {
+ lasttype = (yyvsp[(1) - (1)].type);
+ }
+ break;
+
+ case 31:
+#line 244 "cc.y"
+ {
+ lasttype = (yyvsp[(2) - (2)].type);
+ }
+ break;
+
+ case 33:
+#line 250 "cc.y"
+ {
+ lastfield = 0;
+ edecl(CXXX, lasttype, S);
+ }
+ break;
+
+ case 35:
+#line 258 "cc.y"
+ {
+ dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 37:
+#line 265 "cc.y"
+ {
+ lastbit = 0;
+ firstbit = 1;
+ }
+ break;
+
+ case 38:
+#line 270 "cc.y"
+ {
+ (yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 39:
+#line 274 "cc.y"
+ {
+ (yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 40:
+#line 282 "cc.y"
+ {
+ (yyval.node) = (Z);
+ }
+ break;
+
+ case 42:
+#line 289 "cc.y"
+ {
+ (yyval.node) = new(OIND, (Z), Z);
+ (yyval.node)->garb = simpleg((yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 43:
+#line 294 "cc.y"
+ {
+ (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
+ (yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
+ }
+ break;
+
+ case 46:
+#line 303 "cc.y"
+ {
+ (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 47:
+#line 307 "cc.y"
+ {
+ (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 48:
+#line 313 "cc.y"
+ {
+ (yyval.node) = new(OFUNC, (Z), Z);
+ }
+ break;
+
+ case 49:
+#line 317 "cc.y"
+ {
+ (yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node));
+ }
+ break;
+
+ case 50:
+#line 321 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+ }
+ break;
+
+ case 52:
+#line 328 "cc.y"
+ {
+ (yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z);
+ }
+ break;
+
+ case 53:
+#line 334 "cc.y"
+ {
+ (yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z);
+ }
+ break;
+
+ case 54:
+#line 338 "cc.y"
+ {
+ (yyval.node) = new(OELEM, Z, Z);
+ (yyval.node)->sym = (yyvsp[(2) - (2)].sym);
+ }
+ break;
+
+ case 57:
+#line 347 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node));
+ }
+ break;
+
+ case 59:
+#line 352 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 62:
+#line 360 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 63:
+#line 365 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 64:
+#line 369 "cc.y"
+ {
+ (yyval.node) = invert((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 66:
+#line 377 "cc.y"
+ {
+ (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
+ (yyval.node)->type = (yyvsp[(1) - (2)].type);
+ }
+ break;
+
+ case 67:
+#line 382 "cc.y"
+ {
+ (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
+ (yyval.node)->type = (yyvsp[(1) - (2)].type);
+ }
+ break;
+
+ case 68:
+#line 387 "cc.y"
+ {
+ (yyval.node) = new(ODOTDOT, Z, Z);
+ }
+ break;
+
+ case 69:
+#line 391 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 70:
+#line 397 "cc.y"
+ {
+ (yyval.node) = invert((yyvsp[(2) - (3)].node));
+ // if($2 != Z)
+ // $$ = new(OLIST, $2, $$);
+ if((yyval.node) == Z)
+ (yyval.node) = new(OLIST, Z, Z);
+ }
+ break;
+
+ case 71:
+#line 406 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 72:
+#line 410 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 73:
+#line 414 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 75:
+#line 421 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 76:
+#line 427 "cc.y"
+ {
+ (yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z);
+ }
+ break;
+
+ case 77:
+#line 431 "cc.y"
+ {
+ (yyval.node) = new(OCASE, Z, Z);
+ }
+ break;
+
+ case 78:
+#line 435 "cc.y"
+ {
+ (yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z);
+ }
+ break;
+
+ case 79:
+#line 441 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 81:
+#line 446 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 83:
+#line 453 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (2)].node);
+ }
+ break;
+
+ case 85:
+#line 459 "cc.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 86:
+#line 463 "cc.y"
+ {
+ (yyval.node) = revertdcl();
+ if((yyval.node))
+ (yyval.node) = new(OLIST, (yyval.node), (yyvsp[(2) - (2)].node));
+ else
+ (yyval.node) = (yyvsp[(2) - (2)].node);
+ }
+ break;
+
+ case 87:
+#line 471 "cc.y"
+ {
+ (yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z));
+ if((yyvsp[(5) - (5)].node) == Z)
+ warn((yyvsp[(3) - (5)].node), "empty if body");
+ }
+ break;
+
+ case 88:
+#line 477 "cc.y"
+ {
+ (yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)));
+ if((yyvsp[(5) - (7)].node) == Z)
+ warn((yyvsp[(3) - (7)].node), "empty if body");
+ if((yyvsp[(7) - (7)].node) == Z)
+ warn((yyvsp[(3) - (7)].node), "empty else body");
+ }
+ break;
+
+ case 89:
+#line 484 "cc.y"
+ { markdcl(); }
+ break;
+
+ case 90:
+#line 485 "cc.y"
+ {
+ (yyval.node) = revertdcl();
+ if((yyval.node)){
+ if((yyvsp[(4) - (10)].node))
+ (yyvsp[(4) - (10)].node) = new(OLIST, (yyval.node), (yyvsp[(4) - (10)].node));
+ else
+ (yyvsp[(4) - (10)].node) = (yyval.node);
+ }
+ (yyval.node) = new(OFOR, new(OLIST, (yyvsp[(6) - (10)].node), new(OLIST, (yyvsp[(4) - (10)].node), (yyvsp[(8) - (10)].node))), (yyvsp[(10) - (10)].node));
+ }
+ break;
+
+ case 91:
+#line 496 "cc.y"
+ {
+ (yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+ }
+ break;
+
+ case 92:
+#line 500 "cc.y"
+ {
+ (yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node));
+ }
+ break;
+
+ case 93:
+#line 504 "cc.y"
+ {
+ (yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z);
+ (yyval.node)->type = thisfn->link;
+ }
+ break;
+
+ case 94:
+#line 509 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->vconst = 0;
+ (yyval.node)->type = types[TINT];
+ (yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
+
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->vconst = 0;
+ (yyval.node)->type = types[TINT];
+ (yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
+
+ (yyval.node) = new(OSWITCH, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+ }
+ break;
+
+ case 95:
+#line 523 "cc.y"
+ {
+ (yyval.node) = new(OBREAK, Z, Z);
+ }
+ break;
+
+ case 96:
+#line 527 "cc.y"
+ {
+ (yyval.node) = new(OCONTINUE, Z, Z);
+ }
+ break;
+
+ case 97:
+#line 531 "cc.y"
+ {
+ (yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z);
+ }
+ break;
+
+ case 98:
+#line 535 "cc.y"
+ {
+ (yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z);
+ }
+ break;
+
+ case 99:
+#line 539 "cc.y"
+ {
+ (yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z);
+ }
+ break;
+
+ case 100:
+#line 544 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 102:
+#line 550 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 104:
+#line 557 "cc.y"
+ {
+ (yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z);
+ (yyval.node)->type = types[TLONG];
+ }
+ break;
+
+ case 106:
+#line 565 "cc.y"
+ {
+ (yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 108:
+#line 572 "cc.y"
+ {
+ (yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 109:
+#line 576 "cc.y"
+ {
+ (yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 110:
+#line 580 "cc.y"
+ {
+ (yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 111:
+#line 584 "cc.y"
+ {
+ (yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 112:
+#line 588 "cc.y"
+ {
+ (yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 113:
+#line 592 "cc.y"
+ {
+ (yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 114:
+#line 596 "cc.y"
+ {
+ (yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 115:
+#line 600 "cc.y"
+ {
+ (yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 116:
+#line 604 "cc.y"
+ {
+ (yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 117:
+#line 608 "cc.y"
+ {
+ (yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 118:
+#line 612 "cc.y"
+ {
+ (yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 119:
+#line 616 "cc.y"
+ {
+ (yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 120:
+#line 620 "cc.y"
+ {
+ (yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 121:
+#line 624 "cc.y"
+ {
+ (yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 122:
+#line 628 "cc.y"
+ {
+ (yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 123:
+#line 632 "cc.y"
+ {
+ (yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 124:
+#line 636 "cc.y"
+ {
+ (yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 125:
+#line 640 "cc.y"
+ {
+ (yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 126:
+#line 644 "cc.y"
+ {
+ (yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)));
+ }
+ break;
+
+ case 127:
+#line 648 "cc.y"
+ {
+ (yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 128:
+#line 652 "cc.y"
+ {
+ (yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 129:
+#line 656 "cc.y"
+ {
+ (yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 130:
+#line 660 "cc.y"
+ {
+ (yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 131:
+#line 664 "cc.y"
+ {
+ (yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 132:
+#line 668 "cc.y"
+ {
+ (yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 133:
+#line 672 "cc.y"
+ {
+ (yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 134:
+#line 676 "cc.y"
+ {
+ (yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 135:
+#line 680 "cc.y"
+ {
+ (yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 136:
+#line 684 "cc.y"
+ {
+ (yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 137:
+#line 688 "cc.y"
+ {
+ (yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 139:
+#line 695 "cc.y"
+ {
+ (yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z);
+ dodecl(NODECL, CXXX, (yyvsp[(2) - (5)].type), (yyvsp[(3) - (5)].node));
+ (yyval.node)->type = lastdcl;
+ (yyval.node)->xcast = 1;
+ }
+ break;
+
+ case 140:
+#line 702 "cc.y"
+ {
+ (yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z);
+ dodecl(NODECL, CXXX, (yyvsp[(2) - (7)].type), (yyvsp[(3) - (7)].node));
+ (yyval.node)->type = lastdcl;
+ }
+ break;
+
+ case 142:
+#line 711 "cc.y"
+ {
+ (yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 143:
+#line 715 "cc.y"
+ {
+ (yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 144:
+#line 719 "cc.y"
+ {
+ (yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 145:
+#line 723 "cc.y"
+ {
+ (yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 146:
+#line 727 "cc.y"
+ {
+ (yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 147:
+#line 731 "cc.y"
+ {
+ (yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 148:
+#line 735 "cc.y"
+ {
+ (yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 149:
+#line 739 "cc.y"
+ {
+ (yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 150:
+#line 743 "cc.y"
+ {
+ (yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 151:
+#line 747 "cc.y"
+ {
+ (yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z);
+ }
+ break;
+
+ case 152:
+#line 753 "cc.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+ }
+ break;
+
+ case 153:
+#line 757 "cc.y"
+ {
+ (yyval.node) = new(OSIZE, Z, Z);
+ dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
+ (yyval.node)->type = lastdcl;
+ }
+ break;
+
+ case 154:
+#line 763 "cc.y"
+ {
+ (yyval.node) = new(OSIGN, Z, Z);
+ dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
+ (yyval.node)->type = lastdcl;
+ }
+ break;
+
+ case 155:
+#line 769 "cc.y"
+ {
+ (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z);
+ if((yyvsp[(1) - (4)].node)->op == ONAME)
+ if((yyvsp[(1) - (4)].node)->type == T)
+ dodecl(xdecl, CXXX, types[TINT], (yyval.node));
+ (yyval.node)->right = invert((yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 156:
+#line 777 "cc.y"
+ {
+ (yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z);
+ }
+ break;
+
+ case 157:
+#line 781 "cc.y"
+ {
+ (yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z);
+ (yyval.node)->sym = (yyvsp[(3) - (3)].sym);
+ }
+ break;
+
+ case 158:
+#line 786 "cc.y"
+ {
+ (yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z);
+ (yyval.node)->sym = (yyvsp[(3) - (3)].sym);
+ }
+ break;
+
+ case 159:
+#line 791 "cc.y"
+ {
+ (yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z);
+ }
+ break;
+
+ case 160:
+#line 795 "cc.y"
+ {
+ (yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z);
+ }
+ break;
+
+ case 162:
+#line 800 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TINT];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 163:
+#line 807 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TLONG];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 164:
+#line 814 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TUINT];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 165:
+#line 821 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TULONG];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 166:
+#line 828 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TDOUBLE];
+ (yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 167:
+#line 835 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TFLOAT];
+ (yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 168:
+#line 842 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TVLONG];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 169:
+#line 849 "cc.y"
+ {
+ (yyval.node) = new(OCONST, Z, Z);
+ (yyval.node)->type = types[TUVLONG];
+ (yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+ (yyval.node)->cstring = strdup(symb);
+ }
+ break;
+
+ case 172:
+#line 860 "cc.y"
+ {
+ (yyval.node) = new(OSTRING, Z, Z);
+ (yyval.node)->type = typ(TARRAY, types[TCHAR]);
+ (yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + 1;
+ (yyval.node)->cstring = (yyvsp[(1) - (1)].sval).s;
+ (yyval.node)->sym = symstring;
+ (yyval.node)->etype = TARRAY;
+ (yyval.node)->class = CSTATIC;
+ }
+ break;
+
+ case 173:
+#line 870 "cc.y"
+ {
+ char *s;
+ int n;
+
+ n = (yyvsp[(1) - (2)].node)->type->width - 1;
+ s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
+
+ memcpy(s, (yyvsp[(1) - (2)].node)->cstring, n);
+ memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
+ s[n+(yyvsp[(2) - (2)].sval).l] = 0;
+
+ (yyval.node) = (yyvsp[(1) - (2)].node);
+ (yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
+ (yyval.node)->cstring = s;
+ }
+ break;
+
+ case 174:
+#line 888 "cc.y"
+ {
+ (yyval.node) = new(OLSTRING, Z, Z);
+ (yyval.node)->type = typ(TARRAY, types[TUSHORT]);
+ (yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + sizeof(ushort);
+ (yyval.node)->rstring = (ushort*)(yyvsp[(1) - (1)].sval).s;
+ (yyval.node)->sym = symstring;
+ (yyval.node)->etype = TARRAY;
+ (yyval.node)->class = CSTATIC;
+ }
+ break;
+
+ case 175:
+#line 898 "cc.y"
+ {
+ char *s;
+ int n;
+
+ n = (yyvsp[(1) - (2)].node)->type->width - sizeof(ushort);
+ s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
+
+ memcpy(s, (yyvsp[(1) - (2)].node)->rstring, n);
+ memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
+ *(ushort*)(s+n+(yyvsp[(2) - (2)].sval).l) = 0;
+
+ (yyval.node) = (yyvsp[(1) - (2)].node);
+ (yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
+ (yyval.node)->rstring = (ushort*)s;
+ }
+ break;
+
+ case 176:
+#line 915 "cc.y"
+ {
+ (yyval.node) = Z;
+ }
+ break;
+
+ case 179:
+#line 923 "cc.y"
+ {
+ (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 180:
+#line 929 "cc.y"
+ {
+ (yyval.tyty).t1 = strf;
+ (yyval.tyty).t2 = strl;
+ (yyval.tyty).t3 = lasttype;
+ (yyval.tyty).c = lastclass;
+ strf = T;
+ strl = T;
+ lastbit = 0;
+ firstbit = 1;
+ lastclass = CXXX;
+ lasttype = T;
+ }
+ break;
+
+ case 181:
+#line 942 "cc.y"
+ {
+ (yyval.type) = strf;
+ strf = (yyvsp[(2) - (4)].tyty).t1;
+ strl = (yyvsp[(2) - (4)].tyty).t2;
+ lasttype = (yyvsp[(2) - (4)].tyty).t3;
+ lastclass = (yyvsp[(2) - (4)].tyty).c;
+ }
+ break;
+
+ case 182:
+#line 951 "cc.y"
+ {
+ lastclass = CXXX;
+ lasttype = types[TINT];
+ }
+ break;
+
+ case 184:
+#line 959 "cc.y"
+ {
+ (yyval.tycl).t = (yyvsp[(1) - (1)].type);
+ (yyval.tycl).c = CXXX;
+ }
+ break;
+
+ case 185:
+#line 964 "cc.y"
+ {
+ (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
+ (yyval.tycl).c = CXXX;
+ }
+ break;
+
+ case 186:
+#line 969 "cc.y"
+ {
+ (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
+ (yyval.tycl).c = simplec((yyvsp[(1) - (1)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (1)].lval));
+ }
+ break;
+
+ case 187:
+#line 975 "cc.y"
+ {
+ (yyval.tycl).t = (yyvsp[(1) - (2)].type);
+ (yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
+ if((yyvsp[(2) - (2)].lval) & ~BCLASS & ~BGARB)
+ diag(Z, "duplicate types given: %T and %Q", (yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 188:
+#line 983 "cc.y"
+ {
+ (yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)));
+ (yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 189:
+#line 989 "cc.y"
+ {
+ (yyval.tycl).t = (yyvsp[(2) - (3)].type);
+ (yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+ }
+ break;
+
+ case 190:
+#line 995 "cc.y"
+ {
+ (yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval));
+ (yyval.tycl).c = simplec((yyvsp[(1) - (2)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (2)].lval));
+ }
+ break;
+
+ case 191:
+#line 1001 "cc.y"
+ {
+ (yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval)));
+ (yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+ (yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+ }
+ break;
+
+ case 192:
+#line 1009 "cc.y"
+ {
+ (yyval.type) = (yyvsp[(1) - (1)].tycl).t;
+ if((yyvsp[(1) - (1)].tycl).c != CXXX)
+ diag(Z, "illegal combination of class 4: %s", cnames[(yyvsp[(1) - (1)].tycl).c]);
+ }
+ break;
+
+ case 193:
+#line 1017 "cc.y"
+ {
+ lasttype = (yyvsp[(1) - (1)].tycl).t;
+ lastclass = (yyvsp[(1) - (1)].tycl).c;
+ }
+ break;
+
+ case 194:
+#line 1024 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0);
+ (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+ }
+ break;
+
+ case 195:
+#line 1029 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn);
+ }
+ break;
+
+ case 196:
+#line 1033 "cc.y"
+ {
+ (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
+ if((yyval.type)->link != T)
+ diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
+ (yyval.type)->link = (yyvsp[(4) - (4)].type);
+ sualign((yyval.type));
+ }
+ break;
+
+ case 197:
+#line 1041 "cc.y"
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ (yyval.type) = dotag(lookup(), TSTRUCT, autobn);
+ (yyval.type)->link = (yyvsp[(2) - (2)].type);
+ sualign((yyval.type));
+ }
+ break;
+
+ case 198:
+#line 1049 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TUNION, 0);
+ (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+ }
+ break;
+
+ case 199:
+#line 1054 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TUNION, autobn);
+ }
+ break;
+
+ case 200:
+#line 1058 "cc.y"
+ {
+ (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
+ if((yyval.type)->link != T)
+ diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
+ (yyval.type)->link = (yyvsp[(4) - (4)].type);
+ sualign((yyval.type));
+ }
+ break;
+
+ case 201:
+#line 1066 "cc.y"
+ {
+ taggen++;
+ sprint(symb, "_%d_", taggen);
+ (yyval.type) = dotag(lookup(), TUNION, autobn);
+ (yyval.type)->link = (yyvsp[(2) - (2)].type);
+ sualign((yyval.type));
+ }
+ break;
+
+ case 202:
+#line 1074 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TENUM, 0);
+ (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+ if((yyval.type)->link == T)
+ (yyval.type)->link = types[TINT];
+ (yyval.type) = (yyval.type)->link;
+ }
+ break;
+
+ case 203:
+#line 1082 "cc.y"
+ {
+ dotag((yyvsp[(2) - (2)].sym), TENUM, autobn);
+ }
+ break;
+
+ case 204:
+#line 1086 "cc.y"
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ break;
+
+ case 205:
+#line 1091 "cc.y"
+ {
+ (yyval.type) = (yyvsp[(2) - (7)].sym)->suetag;
+ if((yyval.type)->link != T)
+ diag(Z, "redeclare tag: %s", (yyvsp[(2) - (7)].sym)->name);
+ if(en.tenum == T) {
+ diag(Z, "enum type ambiguous: %s", (yyvsp[(2) - (7)].sym)->name);
+ en.tenum = types[TINT];
+ }
+ (yyval.type)->link = en.tenum;
+ (yyval.type) = en.tenum;
+ }
+ break;
+
+ case 206:
+#line 1103 "cc.y"
+ {
+ en.tenum = T;
+ en.cenum = T;
+ }
+ break;
+
+ case 207:
+#line 1108 "cc.y"
+ {
+ (yyval.type) = en.tenum;
+ }
+ break;
+
+ case 208:
+#line 1112 "cc.y"
+ {
+ (yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type);
+ }
+ break;
+
+ case 210:
+#line 1119 "cc.y"
+ {
+ (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 211:
+#line 1124 "cc.y"
+ {
+ (yyval.lval) = 0;
+ }
+ break;
+
+ case 212:
+#line 1128 "cc.y"
+ {
+ (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 217:
+#line 1140 "cc.y"
+ {
+ (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+ }
+ break;
+
+ case 220:
+#line 1150 "cc.y"
+ {
+ doenum((yyvsp[(1) - (1)].sym), Z);
+ }
+ break;
+
+ case 221:
+#line 1154 "cc.y"
+ {
+ doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 224:
+#line 1161 "cc.y"
+ { (yyval.lval) = BCHAR; }
+ break;
+
+ case 225:
+#line 1162 "cc.y"
+ { (yyval.lval) = BSHORT; }
+ break;
+
+ case 226:
+#line 1163 "cc.y"
+ { (yyval.lval) = BINT; }
+ break;
+
+ case 227:
+#line 1164 "cc.y"
+ { (yyval.lval) = BLONG; }
+ break;
+
+ case 228:
+#line 1165 "cc.y"
+ { (yyval.lval) = BSIGNED; }
+ break;
+
+ case 229:
+#line 1166 "cc.y"
+ { (yyval.lval) = BUNSIGNED; }
+ break;
+
+ case 230:
+#line 1167 "cc.y"
+ { (yyval.lval) = BFLOAT; }
+ break;
+
+ case 231:
+#line 1168 "cc.y"
+ { (yyval.lval) = BDOUBLE; }
+ break;
+
+ case 232:
+#line 1169 "cc.y"
+ { (yyval.lval) = BVOID; }
+ break;
+
+ case 233:
+#line 1172 "cc.y"
+ { (yyval.lval) = BAUTO; }
+ break;
+
+ case 234:
+#line 1173 "cc.y"
+ { (yyval.lval) = BSTATIC; }
+ break;
+
+ case 235:
+#line 1174 "cc.y"
+ { (yyval.lval) = BEXTERN; }
+ break;
+
+ case 236:
+#line 1175 "cc.y"
+ { (yyval.lval) = BTYPEDEF; }
+ break;
+
+ case 237:
+#line 1176 "cc.y"
+ { (yyval.lval) = BTYPESTR; }
+ break;
+
+ case 238:
+#line 1177 "cc.y"
+ { (yyval.lval) = BREGISTER; }
+ break;
+
+ case 239:
+#line 1178 "cc.y"
+ { (yyval.lval) = 0; }
+ break;
+
+ case 240:
+#line 1181 "cc.y"
+ { (yyval.lval) = BCONSTNT; }
+ break;
+
+ case 241:
+#line 1182 "cc.y"
+ { (yyval.lval) = BVOLATILE; }
+ break;
+
+ case 242:
+#line 1183 "cc.y"
+ { (yyval.lval) = 0; }
+ break;
+
+ case 243:
+#line 1187 "cc.y"
+ {
+ (yyval.node) = new(ONAME, Z, Z);
+ if((yyvsp[(1) - (1)].sym)->class == CLOCAL)
+ (yyvsp[(1) - (1)].sym) = mkstatic((yyvsp[(1) - (1)].sym));
+ (yyval.node)->sym = (yyvsp[(1) - (1)].sym);
+ (yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
+ (yyval.node)->etype = TVOID;
+ if((yyval.node)->type != T)
+ (yyval.node)->etype = (yyval.node)->type->etype;
+ (yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
+ (yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
+ (yyvsp[(1) - (1)].sym)->aused = 1;
+ }
+ break;
+
+ case 244:
+#line 1202 "cc.y"
+ {
+ (yyval.node) = new(ONAME, Z, Z);
+ (yyval.node)->sym = (yyvsp[(1) - (1)].sym);
+ (yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
+ (yyval.node)->etype = TVOID;
+ if((yyval.node)->type != T)
+ (yyval.node)->etype = (yyval.node)->type->etype;
+ (yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
+ (yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
+ }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 3596 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 1215 "cc.y"
+
+
diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h
new file mode 100644
index 000000000..c56a1d85a
--- /dev/null
+++ b/src/cmd/cc/y.tab.h
@@ -0,0 +1,228 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LORE = 258,
+ LXORE = 259,
+ LANDE = 260,
+ LLSHE = 261,
+ LRSHE = 262,
+ LMDE = 263,
+ LDVE = 264,
+ LMLE = 265,
+ LME = 266,
+ LPE = 267,
+ LOROR = 268,
+ LANDAND = 269,
+ LNE = 270,
+ LEQ = 271,
+ LGE = 272,
+ LLE = 273,
+ LRSH = 274,
+ LLSH = 275,
+ LMG = 276,
+ LPP = 277,
+ LMM = 278,
+ LNAME = 279,
+ LTYPE = 280,
+ LFCONST = 281,
+ LDCONST = 282,
+ LCONST = 283,
+ LLCONST = 284,
+ LUCONST = 285,
+ LULCONST = 286,
+ LVLCONST = 287,
+ LUVLCONST = 288,
+ LSTRING = 289,
+ LLSTRING = 290,
+ LAUTO = 291,
+ LBREAK = 292,
+ LCASE = 293,
+ LCHAR = 294,
+ LCONTINUE = 295,
+ LDEFAULT = 296,
+ LDO = 297,
+ LDOUBLE = 298,
+ LELSE = 299,
+ LEXTERN = 300,
+ LFLOAT = 301,
+ LFOR = 302,
+ LGOTO = 303,
+ LIF = 304,
+ LINT = 305,
+ LLONG = 306,
+ LREGISTER = 307,
+ LRETURN = 308,
+ LSHORT = 309,
+ LSIZEOF = 310,
+ LUSED = 311,
+ LSTATIC = 312,
+ LSTRUCT = 313,
+ LSWITCH = 314,
+ LTYPEDEF = 315,
+ LTYPESTR = 316,
+ LUNION = 317,
+ LUNSIGNED = 318,
+ LWHILE = 319,
+ LVOID = 320,
+ LENUM = 321,
+ LSIGNED = 322,
+ LCONSTNT = 323,
+ LVOLATILE = 324,
+ LSET = 325,
+ LSIGNOF = 326,
+ LRESTRICT = 327,
+ LINLINE = 328
+ };
+#endif
+/* Tokens. */
+#define LORE 258
+#define LXORE 259
+#define LANDE 260
+#define LLSHE 261
+#define LRSHE 262
+#define LMDE 263
+#define LDVE 264
+#define LMLE 265
+#define LME 266
+#define LPE 267
+#define LOROR 268
+#define LANDAND 269
+#define LNE 270
+#define LEQ 271
+#define LGE 272
+#define LLE 273
+#define LRSH 274
+#define LLSH 275
+#define LMG 276
+#define LPP 277
+#define LMM 278
+#define LNAME 279
+#define LTYPE 280
+#define LFCONST 281
+#define LDCONST 282
+#define LCONST 283
+#define LLCONST 284
+#define LUCONST 285
+#define LULCONST 286
+#define LVLCONST 287
+#define LUVLCONST 288
+#define LSTRING 289
+#define LLSTRING 290
+#define LAUTO 291
+#define LBREAK 292
+#define LCASE 293
+#define LCHAR 294
+#define LCONTINUE 295
+#define LDEFAULT 296
+#define LDO 297
+#define LDOUBLE 298
+#define LELSE 299
+#define LEXTERN 300
+#define LFLOAT 301
+#define LFOR 302
+#define LGOTO 303
+#define LIF 304
+#define LINT 305
+#define LLONG 306
+#define LREGISTER 307
+#define LRETURN 308
+#define LSHORT 309
+#define LSIZEOF 310
+#define LUSED 311
+#define LSTATIC 312
+#define LSTRUCT 313
+#define LSWITCH 314
+#define LTYPEDEF 315
+#define LTYPESTR 316
+#define LUNION 317
+#define LUNSIGNED 318
+#define LWHILE 319
+#define LVOID 320
+#define LENUM 321
+#define LSIGNED 322
+#define LCONSTNT 323
+#define LVOLATILE 324
+#define LSET 325
+#define LSIGNOF 326
+#define LRESTRICT 327
+#define LINLINE 328
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 36 "cc.y"
+{
+ Node* node;
+ Sym* sym;
+ Type* type;
+ struct
+ {
+ Type* t;
+ uchar c;
+ } tycl;
+ struct
+ {
+ Type* t1;
+ Type* t2;
+ Type* t3;
+ uchar c;
+ } tyty;
+ struct
+ {
+ char* s;
+ int32 l;
+ } sval;
+ int32 lval;
+ double dval;
+ vlong vval;
+}
+/* Line 1529 of yacc.c. */
+#line 221 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
deleted file mode 100644
index 5458c3e4f..000000000
--- a/src/cmd/cgo/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../Make.inc
-
-TARG=cgo
-GOFILES=\
- ast.go\
- gcc.go\
- main.go\
- out.go\
- util.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 73b7313d6..381e606ef 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -9,7 +9,6 @@ package main
import (
"fmt"
"go/ast"
- "go/doc"
"go/parser"
"go/scanner"
"go/token"
@@ -17,7 +16,7 @@ import (
"strings"
)
-func parse(name string, flags uint) *ast.File {
+func parse(name string, flags parser.Mode) *ast.File {
ast1, err := parser.ParseFile(fset, name, nil, flags)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
@@ -71,7 +70,7 @@ func (f *File) ReadGo(name string) {
}
sawC = true
if s.Name != nil {
- error(s.Path.Pos(), `cannot rename import "C"`)
+ error_(s.Path.Pos(), `cannot rename import "C"`)
}
cg := s.Doc
if cg == nil && len(d.Specs) == 1 {
@@ -79,12 +78,12 @@ func (f *File) ReadGo(name string) {
}
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
- f.Preamble += doc.CommentText(cg) + "\n"
+ f.Preamble += cg.Text() + "\n"
}
}
}
if !sawC {
- error(token.NoPos, `cannot find import "C"`)
+ error_(token.NoPos, `cannot find import "C"`)
}
// In ast2, strip the import "C" line.
@@ -128,6 +127,7 @@ func (f *File) ReadGo(name string) {
f.walk(ast1, "prog", (*File).saveExport)
f.walk(ast2, "prog", (*File).saveExport2)
+ f.Comments = ast1.Comments
f.AST = ast2
}
@@ -147,9 +147,12 @@ func (f *File) saveRef(x interface{}, context string) {
if context == "as2" {
context = "expr"
}
+ if context == "embed-type" {
+ error_(sel.Pos(), "cannot embed C type")
+ }
goname := sel.Sel.Name
if goname == "errno" {
- error(sel.Pos(), "cannot refer to errno directly; see documentation")
+ error_(sel.Pos(), "cannot refer to errno directly; see documentation")
return
}
name := f.Name[goname]
@@ -186,11 +189,11 @@ func (f *File) saveExport(x interface{}, context string) {
name := strings.TrimSpace(string(c.Text[9:]))
if name == "" {
- error(c.Pos(), "export missing name")
+ error_(c.Pos(), "export missing name")
}
if name != n.Name.Name {
- error(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
+ error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
}
f.ExpFunc = append(f.ExpFunc, &ExpFunc{
@@ -225,14 +228,18 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
// everything else just recurs
default:
- error(token.NoPos, "unexpected type %T in walk", x, visit)
+ error_(token.NoPos, "unexpected type %T in walk", x, visit)
panic("unexpected type")
case nil:
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
case *ast.Field:
- f.walk(&n.Type, "type", visit)
+ if len(n.Names) == 0 && context == "field" {
+ f.walk(&n.Type, "embed-type", visit)
+ } else {
+ f.walk(&n.Type, "type", visit)
+ }
case *ast.FieldList:
for _, field := range n.List {
f.walk(field, context, visit)
@@ -289,9 +296,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
case *ast.StructType:
f.walk(n.Fields, "field", visit)
case *ast.FuncType:
- f.walk(n.Params, "field", visit)
+ f.walk(n.Params, "param", visit)
if n.Results != nil {
- f.walk(n.Results, "field", visit)
+ f.walk(n.Results, "param", visit)
}
case *ast.InterfaceType:
f.walk(n.Methods, "field", visit)
@@ -379,7 +386,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
f.walk(n.Specs, "spec", visit)
case *ast.FuncDecl:
if n.Recv != nil {
- f.walk(n.Recv, "field", visit)
+ f.walk(n.Recv, "param", visit)
}
f.walk(n.Type, "type", visit)
if n.Body != nil {
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index a4219867c..1bb48f44e 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -6,7 +6,8 @@
Cgo enables the creation of Go packages that call C code.
-Usage: cgo [compiler options] file.go
+Usage:
+ go tool cgo [compiler options] file.go
The compiler options are passed through uninterpreted when
invoking gcc to compile the C parts of the package.
@@ -16,8 +17,8 @@ the pseudo-package "C" and then refers to types such as C.size_t,
variables such as C.stdout, or functions such as C.putchar.
If the import of "C" is immediately preceded by a comment, that
-comment is used as a header when compiling the C parts of
-the package. For example:
+comment, called the preamble, is used as a header when compiling
+the C parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
@@ -43,6 +44,11 @@ For example:
// #include <png.h>
import "C"
+The CGO_CFLAGS and CGO_LDFLAGS environment variables are added
+to the flags derived from these directives. Package-specific flags should
+be set using the directives, not the environment variables, so that builds
+work in unmodified environments.
+
Within the Go file, C identifiers or field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
@@ -57,9 +63,11 @@ The C type void* is represented by Go's unsafe.Pointer.
To access a struct, union, or enum type directly, prefix it with
struct_, union_, or enum_, as in C.struct_stat.
+Go structs cannot embed fields with C types.
+
Any C function that returns a value may be called in a multiple
assignment context to retrieve both the return value and the
-C errno variable as an os.Error. For example:
+C errno variable as an error. For example:
n, err := C.atoi("abc")
@@ -73,6 +81,9 @@ A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
// Go string to C string
+ // The C string is allocated in the C heap using malloc.
+ // It is the caller's responsibility to arrange for it to be
+ // freed, such as by calling C.free.
func C.CString(string) *C.char
// C string to Go string
@@ -84,16 +95,34 @@ by making copies of the data. In pseudo-Go definitions:
// C pointer, length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
+Go functions can be exported for use by C code in the following way:
+
+ //export MyFunction
+ func MyFunction(arg1, arg2 int, arg3 string) int64 {...}
+
+ //export MyFunction2
+ func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}
+
+They will be available in the C code as:
+
+ extern int64 MyFunction(int arg1, int arg2, GoString arg3);
+ extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
+
+found in _cgo_export.h generated header, after any preambles
+copied from the cgo input files. Functions with multiple
+return values are mapped to functions returning a struct.
+Not all Go types can be mapped to C types in a useful way.
+
Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
-The standard package makefile rules in Make.pkg automate the
-process of using cgo. See $GOROOT/misc/cgo/stdio and
-$GOROOT/misc/cgo/gmp for examples.
+The standard package construction rules of the go command
+automate the process of using cgo. See $GOROOT/misc/cgo/stdio
+and $GOROOT/misc/cgo/gmp for examples.
Cgo does not yet work with gccgo.
See "C? Go? Cgo!" for an introduction to using cgo:
-http://blog.golang.org/2011/03/c-go-cgo.html
+http://golang.org/doc/articles/c_go_cgo.html
*/
package documentation
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 7ec4d8ccf..98a847e6f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -14,16 +14,17 @@ import (
"debug/macho"
"debug/pe"
"encoding/binary"
+ "errors"
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
- "runtime"
"strconv"
"strings"
"unicode"
+ "unicode/utf8"
)
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
@@ -59,6 +60,9 @@ func cname(s string) string {
if strings.HasPrefix(s, "enum_") {
return "enum " + s[len("enum_"):]
}
+ if strings.HasPrefix(s, "sizeof_") {
+ return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
+ }
return s
}
@@ -72,7 +76,7 @@ func (p *Package) ParseFlags(f *File, srcfile string) {
NextLine:
for _, line := range linesIn {
l := strings.TrimSpace(line)
- if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
+ if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
linesOut = append(linesOut, line)
continue
}
@@ -91,9 +95,9 @@ NextLine:
case 2:
k = kf[1]
switch kf[0] {
- case runtime.GOOS:
- case runtime.GOARCH:
- case runtime.GOOS + "/" + runtime.GOARCH:
+ case goos:
+ case goarch:
+ case goos + "/" + goarch:
default:
continue NextLine
}
@@ -148,10 +152,10 @@ func (p *Package) addToFlag(flag string, args []string) {
// pkgConfig runs pkg-config and extracts --libs and --cflags information
// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
+func pkgConfig(packages []string) (cflags, ldflags []string, err error) {
for _, name := range packages {
if len(name) == 0 || name[0] == '-' {
- return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name))
+ return nil, nil, errors.New(fmt.Sprintf("invalid name: %q", name))
}
}
@@ -159,7 +163,7 @@ func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
stdout, stderr, ok := run(nil, args)
if !ok {
os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
+ return nil, nil, errors.New("pkg-config failed")
}
cflags, err = splitQuoted(string(stdout))
if err != nil {
@@ -170,7 +174,7 @@ func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
stdout, stderr, ok = run(nil, args)
if !ok {
os.Stderr.Write(stderr)
- return nil, nil, os.NewError("pkg-config failed")
+ return nil, nil, errors.New("pkg-config failed")
}
ldflags, err = splitQuoted(string(stdout))
return
@@ -192,30 +196,30 @@ func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
//
// []string{"a", "b:c d", "ef", `g"`}
//
-func splitQuoted(s string) (r []string, err os.Error) {
+func splitQuoted(s string) (r []string, err error) {
var args []string
- arg := make([]int, len(s))
+ arg := make([]rune, len(s))
escaped := false
quoted := false
- quote := 0
+ quote := '\x00'
i := 0
- for _, rune := range s {
+ for _, r := range s {
switch {
case escaped:
escaped = false
- case rune == '\\':
+ case r == '\\':
escaped = true
continue
case quote != 0:
- if rune == quote {
+ if r == quote {
quote = 0
continue
}
- case rune == '"' || rune == '\'':
+ case r == '"' || r == '\'':
quoted = true
- quote = rune
+ quote = r
continue
- case unicode.IsSpace(rune):
+ case unicode.IsSpace(r):
if quoted || i > 0 {
quoted = false
args = append(args, string(arg[:i]))
@@ -223,21 +227,21 @@ func splitQuoted(s string) (r []string, err os.Error) {
}
continue
}
- arg[i] = rune
+ arg[i] = r
i++
}
if quoted || i > 0 {
args = append(args, string(arg[:i]))
}
if quote != 0 {
- err = os.NewError("unclosed quote")
+ err = errors.New("unclosed quote")
} else if escaped {
- err = os.NewError("unfinished escaping")
+ err = errors.New("unfinished escaping")
}
return args, err
}
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
func safeName(s string) bool {
if s == "" {
@@ -340,14 +344,22 @@ func (p *Package) guessKinds(f *File) []*Name {
if _, err := strconv.Atoi(n.Define); err == nil {
ok = true
} else if n.Define[0] == '"' || n.Define[0] == '\'' {
- _, err := parser.ParseExpr(fset, "", n.Define)
- if err == nil {
+ if _, err := parser.ParseExpr(n.Define); err == nil {
ok = true
}
}
if ok {
n.Kind = "const"
- n.Const = n.Define
+ // Turn decimal into hex, just for consistency
+ // with enum-derived constants. Otherwise
+ // in the cgo -godefs output half the constants
+ // are in hex and half are in whatever the #define used.
+ i, err := strconv.ParseInt(n.Define, 0, 64)
+ if err == nil {
+ n.Const = fmt.Sprintf("%#x", i)
+ } else {
+ n.Const = n.Define
+ }
continue
}
@@ -421,7 +433,7 @@ func (p *Package) guessKinds(f *File) []*Name {
case strings.Contains(line, ": statement with no effect"):
what = "not-type" // const or func or var
case strings.Contains(line, "undeclared"):
- error(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
+ error_(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
case strings.Contains(line, "is not an integer constant"):
isConst[i] = false
continue
@@ -440,6 +452,11 @@ func (p *Package) guessKinds(f *File) []*Name {
for i, b := range isConst {
if b {
names[i].Kind = "const"
+ if toSniff[i] != nil && names[i].Const == "" {
+ j := len(needType)
+ needType = needType[0 : j+1]
+ needType[j] = names[i]
+ }
}
}
for _, n := range toSniff {
@@ -449,7 +466,7 @@ func (p *Package) guessKinds(f *File) []*Name {
if n.Kind != "" {
continue
}
- error(token.NoPos, "could not determine kind of name for C.%s", n.Go)
+ error_(token.NoPos, "could not determine kind of name for C.%s", n.Go)
}
if nerrors > 0 {
fatalf("unresolved names")
@@ -507,6 +524,10 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
for i, n := range names {
nameToIndex[n] = i
}
+ nameToRef := make(map[*Name]*Ref)
+ for _, ref := range f.Ref {
+ nameToRef[ref.Name] = ref
+ }
r := d.Reader()
for {
e, err := r.Next()
@@ -577,21 +598,28 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
var conv typeConv
conv.Init(p.PtrSize)
for i, n := range names {
+ if types[i] == nil {
+ continue
+ }
+ pos := token.NoPos
+ if ref, ok := nameToRef[n]; ok {
+ pos = ref.Pos()
+ }
f, fok := types[i].(*dwarf.FuncType)
if n.Kind != "type" && fok {
n.Kind = "func"
- n.FuncType = conv.FuncType(f)
+ n.FuncType = conv.FuncType(f, pos)
} else {
- n.Type = conv.Type(types[i])
+ n.Type = conv.Type(types[i], pos)
if enums[i] != 0 && n.Type.EnumValues != nil {
k := fmt.Sprintf("__cgo_enum__%d", i)
n.Kind = "const"
- n.Const = strconv.Itoa64(n.Type.EnumValues[k])
+ n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k])
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
- n.Type.EnumValues[k] = 0, false
+ delete(n.Type.EnumValues, k)
} else if n.Kind == "const" && i < len(enumVal) {
- n.Const = strconv.Itoa64(enumVal[i])
+ n.Const = fmt.Sprintf("%#x", enumVal[i])
}
}
}
@@ -600,7 +628,8 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
// Go equivalents, now that we have figured out the meaning of all
-// the xxx.
+// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names
+// with full definitions instead of mangled names.
func (p *Package) rewriteRef(f *File) {
// Assign mangled names.
for _, n := range f.Name {
@@ -618,7 +647,7 @@ func (p *Package) rewriteRef(f *File) {
// functions are only used in calls.
for _, r := range f.Ref {
if r.Name.Kind == "const" && r.Name.Const == "" {
- error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
+ error_(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
}
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
switch r.Context {
@@ -629,12 +658,12 @@ func (p *Package) rewriteRef(f *File) {
expr = r.Name.Type.Go
break
}
- error(r.Pos(), "call of non-function C.%s", r.Name.Go)
+ error_(r.Pos(), "call of non-function C.%s", r.Name.Go)
break
}
if r.Context == "call2" {
if r.Name.FuncType.Result == nil {
- error(r.Pos(), "assignment count mismatch: 2 = 0")
+ error_(r.Pos(), "assignment count mismatch: 2 = 0")
}
// Invent new Name for the two-result function.
n := f.Name["2"+r.Name.Go]
@@ -651,7 +680,7 @@ func (p *Package) rewriteRef(f *File) {
}
case "expr":
if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
+ error_(r.Pos(), "must call C.%s", r.Name.Go)
}
if r.Name.Kind == "type" {
// Okay - might be new(T)
@@ -663,13 +692,28 @@ func (p *Package) rewriteRef(f *File) {
case "type":
if r.Name.Kind != "type" {
- error(r.Pos(), "expression C.%s used as type", r.Name.Go)
+ error_(r.Pos(), "expression C.%s used as type", r.Name.Go)
+ } else if r.Name.Type == nil {
+ // Use of C.enum_x, C.struct_x or C.union_x without C definition.
+ // GCC won't raise an error when using pointers to such unknown types.
+ error_(r.Pos(), "type C.%s: undefined C type '%s'", r.Name.Go, r.Name.C)
} else {
expr = r.Name.Type.Go
}
default:
if r.Name.Kind == "func" {
- error(r.Pos(), "must call C.%s", r.Name.Go)
+ error_(r.Pos(), "must call C.%s", r.Name.Go)
+ }
+ }
+ if *godefs || *cdefs {
+ // Substitute definition for mangled type name.
+ if id, ok := expr.(*ast.Ident); ok {
+ if t := typedef[id.Name]; t != nil {
+ expr = t.Go
+ }
+ if id.Name == r.Name.Mangle && r.Name.Const != "" {
+ expr = ast.NewIdent(r.Name.Const)
+ }
}
}
*r.Expr = expr
@@ -688,7 +732,7 @@ func (p *Package) gccName() (ret string) {
// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
func (p *Package) gccMachine() []string {
- switch runtime.GOARCH {
+ switch goarch {
case "amd64":
return []string{"-m64"}
case "386":
@@ -697,7 +741,9 @@ func (p *Package) gccMachine() []string {
return nil
}
-var gccTmp = objDir + "_cgo_.o"
+func gccTmp() string {
+ return *objDir + "_cgo_.o"
+}
// gccCmd returns the gcc command line to use for compiling
// the input.
@@ -706,7 +752,7 @@ func (p *Package) gccCmd() []string {
p.gccName(),
"-Wall", // many warnings
"-Werror", // warnings are errors
- "-o" + gccTmp, // write object to tmp
+ "-o" + gccTmp(), // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
"-c", // do not link
@@ -723,10 +769,10 @@ func (p *Package) gccCmd() []string {
func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
runGcc(stdin, p.gccCmd())
- if f, err := macho.Open(gccTmp); err == nil {
+ if f, err := macho.Open(gccTmp()); err == nil {
d, err := f.DWARF()
if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
if f.Symtab != nil {
@@ -752,23 +798,23 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
// Can skip debug data block in ELF and PE for now.
// The DWARF information is complete.
- if f, err := elf.Open(gccTmp); err == nil {
+ if f, err := elf.Open(gccTmp()); err == nil {
d, err := f.DWARF()
if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
return d, f.ByteOrder, nil
}
- if f, err := pe.Open(gccTmp); err == nil {
+ if f, err := pe.Open(gccTmp()); err == nil {
d, err := f.DWARF()
if err != nil {
- fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
return d, binary.LittleEndian, nil
}
- fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
panic("not reached")
}
@@ -848,7 +894,8 @@ type typeConv struct {
}
var tagGen int
-var typedef = make(map[string]ast.Expr)
+var typedef = make(map[string]*Type)
+var goIdent = make(map[string]*ast.Ident)
func (c *typeConv) Init(ptrSize int64) {
c.ptrSize = ptrSize
@@ -933,10 +980,10 @@ func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
// Type returns a *Type with the same memory layout as
// dtype when used as the type of a variable or a struct field.
-func (c *typeConv) Type(dtype dwarf.Type) *Type {
+func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
if t, ok := c.m[dtype]; ok {
if t.Go == nil {
- fatalf("type conversion loop at %s", dtype)
+ fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
}
return t
}
@@ -959,11 +1006,11 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
switch dt := dtype.(type) {
default:
- fatalf("unexpected type: %s", dtype)
+ fatalf("%s: unexpected type: %s", lineno(pos), dtype)
case *dwarf.AddrType:
if t.Size != c.ptrSize {
- fatalf("unexpected: %d-byte address type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.uintptr
t.Align = t.Size
@@ -978,7 +1025,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
Len: c.intExpr(dt.Count),
}
t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
+ sub := c.Type(dt.Type, pos)
t.Align = sub.Align
gt.Elt = sub.Go
t.C.Set("typeof(%s[%d])", sub.C, dt.Count)
@@ -989,7 +1036,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.CharType:
if t.Size != 1 {
- fatalf("unexpected: %d-byte char type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.int8
t.Align = 1
@@ -1009,7 +1056,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
}
switch t.Size + int64(signed) {
default:
- fatalf("unexpected: %d-byte enum type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.uint8
case 2:
@@ -1031,7 +1078,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.FloatType:
switch t.Size {
default:
- fatalf("unexpected: %d-byte float type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
case 4:
t.Go = c.float32
case 8:
@@ -1044,7 +1091,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.ComplexType:
switch t.Size {
default:
- fatalf("unexpected: %d-byte complex type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
case 8:
t.Go = c.complex64
case 16:
@@ -1062,11 +1109,11 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.IntType:
if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit int type - %s", dt.BitSize, dtype)
+ fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
}
switch t.Size {
default:
- fatalf("unexpected: %d-byte int type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.int8
case 2:
@@ -1092,13 +1139,13 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
gt := &ast.StarExpr{}
t.Go = gt // publish before recursive call
- sub := c.Type(dt.Type)
+ sub := c.Type(dt.Type, pos)
gt.X = sub.Go
t.C.Set("%s*", sub.C)
case *dwarf.QualType:
// Ignore qualifier.
- t = c.Type(dt.Type)
+ t = c.Type(dt.Type, pos)
c.m[dtype] = t
return t
@@ -1114,19 +1161,26 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
}
name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
t.Go = name // publish before recursive calls
+ goIdent[name.Name] = name
switch dt.Kind {
case "union", "class":
- typedef[name.Name] = c.Opaque(t.Size)
+ t.Go = c.Opaque(t.Size)
if t.C.Empty() {
t.C.Set("typeof(unsigned char[%d])", t.Size)
}
+ typedef[name.Name] = t
case "struct":
- g, csyntax, align := c.Struct(dt)
+ g, csyntax, align := c.Struct(dt, pos)
if t.C.Empty() {
t.C.Set(csyntax)
}
t.Align = align
- typedef[name.Name] = g
+ tt := *t
+ if tag != "" {
+ tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
+ }
+ tt.Go = g
+ typedef[name.Name] = &tt
}
case *dwarf.TypedefType:
@@ -1148,29 +1202,35 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Align = c.ptrSize
break
}
- name := c.Ident("_Ctypedef_" + dt.Name)
+ name := c.Ident("_Ctype_" + dt.Name)
+ goIdent[name.Name] = name
t.Go = name // publish before recursive call
- sub := c.Type(dt.Type)
+ sub := c.Type(dt.Type, pos)
t.Size = sub.Size
t.Align = sub.Align
if _, ok := typedef[name.Name]; !ok {
- typedef[name.Name] = sub.Go
+ tt := *t
+ tt.Go = sub.Go
+ typedef[name.Name] = &tt
+ }
+ if *godefs || *cdefs {
+ t.Go = sub.Go
}
case *dwarf.UcharType:
if t.Size != 1 {
- fatalf("unexpected: %d-byte uchar type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
}
t.Go = c.uint8
t.Align = 1
case *dwarf.UintType:
if dt.BitSize > 0 {
- fatalf("unexpected: %d-bit uint type - %s", dt.BitSize, dtype)
+ fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
}
switch t.Size {
default:
- fatalf("unexpected: %d-byte uint type - %s", t.Size, dtype)
+ fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
case 1:
t.Go = c.uint8
case 2:
@@ -1198,13 +1258,16 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
}
s = strings.Join(strings.Split(s, " "), "") // strip spaces
name := c.Ident("_Ctype_" + s)
- typedef[name.Name] = t.Go
- t.Go = name
+ tt := *t
+ typedef[name.Name] = &tt
+ if !*godefs && !*cdefs {
+ t.Go = name
+ }
}
}
if t.C.Empty() {
- fatalf("internal error: did not create C name for %s", dtype)
+ fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
}
return t
@@ -1212,8 +1275,8 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
// FuncArg returns a Go type with the same memory layout as
// dtype when used as the type of a C function argument.
-func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
- t := c.Type(dtype)
+func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
+ t := c.Type(dtype, pos)
switch dt := dtype.(type) {
case *dwarf.ArrayType:
// Arrays are passed implicitly as pointers in C.
@@ -1234,9 +1297,18 @@ func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
// Unless the typedef happens to point to void* since
// Go has special rules around using unsafe.Pointer.
- if _, void := base(ptr.Type).(*dwarf.VoidType); !void {
- return c.Type(ptr)
+ if _, void := base(ptr.Type).(*dwarf.VoidType); void {
+ break
+ }
+
+ t = c.Type(ptr, pos)
+ if t == nil {
+ return nil
}
+
+ // Remember the C spelling, in case the struct
+ // has __attribute__((unavailable)) on it. See issue 2888.
+ t.Typedef = dt.Name
}
}
return t
@@ -1244,7 +1316,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type) *Type {
// FuncType returns the Go type analogous to dtype.
// There is no guarantee about matching memory layout.
-func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
+func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
p := make([]*Type, len(dtype.ParamType))
gp := make([]*ast.Field, len(dtype.ParamType))
for i, f := range dtype.ParamType {
@@ -1257,14 +1329,14 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
p, gp = nil, nil
break
}
- p[i] = c.FuncArg(f)
+ p[i] = c.FuncArg(f, pos)
gp[i] = &ast.Field{Type: p[i].Go}
}
var r *Type
var gr []*ast.Field
if _, ok := dtype.ReturnType.(*dwarf.VoidType); !ok && dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType)
- gr = []*ast.Field{&ast.Field{Type: r.Go}}
+ r = c.Type(dtype.ReturnType, pos)
+ gr = []*ast.Field{{Type: r.Go}}
}
return &FuncType{
Params: p,
@@ -1293,7 +1365,7 @@ func (c *typeConv) Opaque(n int64) ast.Expr {
func (c *typeConv) intExpr(n int64) ast.Expr {
return &ast.BasicLit{
Kind: token.INT,
- Value: strconv.Itoa64(n),
+ Value: strconv.FormatInt(n, 10),
}
}
@@ -1306,7 +1378,7 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
}
// Struct conversion: return Go and (6g) C syntax for type.
-func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
+func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
var buf bytes.Buffer
buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
@@ -1324,38 +1396,61 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
ident[f.Name] = f.Name
used[f.Name] = true
}
- for cid, goid := range ident {
- if token.Lookup([]byte(goid)).IsKeyword() {
- // Avoid keyword
- goid = "_" + goid
- // Also avoid existing fields
- for _, exist := used[goid]; exist; _, exist = used[goid] {
+ if !*godefs && !*cdefs {
+ for cid, goid := range ident {
+ if token.Lookup(goid).IsKeyword() {
+ // Avoid keyword
goid = "_" + goid
- }
- used[goid] = true
- ident[cid] = goid
+ // Also avoid existing fields
+ for _, exist := used[goid]; exist; _, exist = used[goid] {
+ goid = "_" + goid
+ }
+
+ used[goid] = true
+ ident[cid] = goid
+ }
}
}
+ anon := 0
for _, f := range dt.Field {
- if f.BitSize > 0 && f.BitSize != f.ByteSize*8 {
- continue
- }
if f.ByteOffset > off {
fld = c.pad(fld, f.ByteOffset-off)
off = f.ByteOffset
}
- t := c.Type(f.Type)
+ t := c.Type(f.Type, pos)
+ tgo := t.Go
+ size := t.Size
+
+ if f.BitSize > 0 {
+ if f.BitSize%8 != 0 {
+ continue
+ }
+ size = f.BitSize / 8
+ name := tgo.(*ast.Ident).String()
+ if strings.HasPrefix(name, "int") {
+ name = "int"
+ } else {
+ name = "uint"
+ }
+ tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
+ }
+
n := len(fld)
fld = fld[0 : n+1]
-
- fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
- off += t.Size
+ name := f.Name
+ if name == "" {
+ name = fmt.Sprintf("anon%d", anon)
+ anon++
+ ident[name] = name
+ }
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
+ off += size
buf.WriteString(t.C.String())
buf.WriteString(" ")
- buf.WriteString(f.Name)
+ buf.WriteString(name)
buf.WriteString("; ")
if t.Align > align {
align = t.Align
@@ -1366,10 +1461,100 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
off = dt.ByteSize
}
if off != dt.ByteSize {
- fatalf("struct size calculation error")
+ fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
}
buf.WriteString("}")
csyntax = buf.String()
+
+ if *godefs || *cdefs {
+ godefsFields(fld)
+ }
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return
}
+
+func upper(s string) string {
+ if s == "" {
+ return ""
+ }
+ r, size := utf8.DecodeRuneInString(s)
+ if r == '_' {
+ return "X" + s
+ }
+ return string(unicode.ToUpper(r)) + s[size:]
+}
+
+// godefsFields rewrites field names for use in Go or C definitions.
+// It strips leading common prefixes (like tv_ in tv_sec, tv_usec)
+// converts names to upper case, and rewrites _ into Pad_godefs_n,
+// so that all fields are exported.
+func godefsFields(fld []*ast.Field) {
+ prefix := fieldPrefix(fld)
+ npad := 0
+ for _, f := range fld {
+ for _, n := range f.Names {
+ if strings.HasPrefix(n.Name, prefix) && n.Name != prefix {
+ n.Name = n.Name[len(prefix):]
+ }
+ if n.Name == "_" {
+ // Use exported name instead.
+ n.Name = "Pad_cgo_" + strconv.Itoa(npad)
+ npad++
+ }
+ if !*cdefs {
+ n.Name = upper(n.Name)
+ }
+ }
+ p := &f.Type
+ t := *p
+ if star, ok := t.(*ast.StarExpr); ok {
+ star = &ast.StarExpr{X: star.X}
+ *p = star
+ p = &star.X
+ t = *p
+ }
+ if id, ok := t.(*ast.Ident); ok {
+ if id.Name == "unsafe.Pointer" {
+ *p = ast.NewIdent("*byte")
+ }
+ }
+ }
+}
+
+// fieldPrefix returns the prefix that should be removed from all the
+// field names when generating the C or Go code. For generated
+// C, we leave the names as is (tv_sec, tv_usec), since that's what
+// people are used to seeing in C. For generated Go code, such as
+// package syscall's data structures, we drop a common prefix
+// (so sec, usec, which will get turned into Sec, Usec for exporting).
+func fieldPrefix(fld []*ast.Field) string {
+ if *cdefs {
+ return ""
+ }
+ prefix := ""
+ for _, f := range fld {
+ for _, n := range f.Names {
+ // Ignore field names that don't have the prefix we're
+ // looking for. It is common in C headers to have fields
+ // named, say, _pad in an otherwise prefixed header.
+ // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
+ // still want to remove the tv_ prefix.
+ // The check for "orig_" here handles orig_eax in the
+ // x86 ptrace register sets, which otherwise have all fields
+ // with reg_ prefixes.
+ if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
+ continue
+ }
+ i := strings.Index(n.Name, "_")
+ if i < 0 {
+ continue
+ }
+ if prefix == "" {
+ prefix = n.Name[:i+1]
+ } else if prefix != n.Name[:i+1] {
+ return ""
+ }
+ }
+ }
+ return prefix
+}
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
new file mode 100644
index 000000000..fec70a334
--- /dev/null
+++ b/src/cmd/cgo/godefs.go
@@ -0,0 +1,289 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "os"
+ "strings"
+)
+
+// godefs returns the output for -godefs mode.
+func (p *Package) godefs(f *File, srcfile string) string {
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
+ fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
+ fmt.Fprintf(&buf, "\n")
+
+ override := make(map[string]string)
+
+ // Allow source file to specify override mappings.
+ // For example, the socket data structures refer
+ // to in_addr and in_addr6 structs but we want to be
+ // able to treat them as byte arrays, so the godefs
+ // inputs in package syscall say
+ //
+ // // +godefs map struct_in_addr [4]byte
+ // // +godefs map struct_in_addr6 [16]byte
+ //
+ for _, g := range f.Comments {
+ for _, c := range g.List {
+ i := strings.Index(c.Text, "+godefs map")
+ if i < 0 {
+ continue
+ }
+ s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
+ i = strings.Index(s, " ")
+ if i < 0 {
+ fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
+ continue
+ }
+ override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
+ }
+ }
+ for _, n := range f.Name {
+ if s := override[n.Go]; s != "" {
+ override[n.Mangle] = s
+ }
+ }
+
+ // Otherwise, if the source file says type T C.whatever,
+ // use "T" as the mangling of C.whatever,
+ // except in the definition (handled at end of function).
+ refName := make(map[*ast.Expr]*Name)
+ for _, r := range f.Ref {
+ refName[r.Expr] = r.Name
+ }
+ for _, d := range f.AST.Decls {
+ d, ok := d.(*ast.GenDecl)
+ if !ok || d.Tok != token.TYPE {
+ continue
+ }
+ for _, s := range d.Specs {
+ s := s.(*ast.TypeSpec)
+ n := refName[&s.Type]
+ if n != nil && n.Mangle != "" {
+ override[n.Mangle] = s.Name.Name
+ }
+ }
+ }
+
+ // Extend overrides using typedefs:
+ // If we know that C.xxx should format as T
+ // and xxx is a typedef for yyy, make C.yyy format as T.
+ for typ, def := range typedef {
+ if new := override[typ]; new != "" {
+ if id, ok := def.Go.(*ast.Ident); ok {
+ override[id.Name] = new
+ }
+ }
+ }
+
+ // Apply overrides.
+ for old, new := range override {
+ if id := goIdent[old]; id != nil {
+ id.Name = new
+ }
+ }
+
+ // Any names still using the _C syntax are not going to compile,
+ // although in general we don't know whether they all made it
+ // into the file, so we can't warn here.
+ //
+ // The most common case is union types, which begin with
+ // _Ctype_union and for which typedef[name] is a Go byte
+ // array of the appropriate size (such as [4]byte).
+ // Substitute those union types with byte arrays.
+ for name, id := range goIdent {
+ if id.Name == name && strings.Contains(name, "_Ctype_union") {
+ if def := typedef[name]; def != nil {
+ id.Name = gofmt(def)
+ }
+ }
+ }
+
+ conf.Fprint(&buf, fset, f.AST)
+
+ return buf.String()
+}
+
+// cdefs returns the output for -cdefs mode.
+// The easiest way to do this is to translate the godefs Go to C.
+func (p *Package) cdefs(f *File, srcfile string) string {
+ godefsOutput := p.godefs(f, srcfile)
+
+ lines := strings.Split(godefsOutput, "\n")
+ lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
+
+ for i, line := range lines {
+ lines[i] = strings.TrimSpace(line)
+ }
+
+ var out bytes.Buffer
+ printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
+
+ didTypedef := false
+ for i := 0; i < len(lines); i++ {
+ line := lines[i]
+
+ // Delete
+ // package x
+ if strings.HasPrefix(line, "package ") {
+ continue
+ }
+
+ // Convert
+ // const (
+ // A = 1
+ // B = 2
+ // )
+ //
+ // to
+ //
+ // enum {
+ // A = 1,
+ // B = 2,
+ // };
+ if line == "const (" {
+ printf("enum {\n")
+ for i++; i < len(lines) && lines[i] != ")"; i++ {
+ line = lines[i]
+ if line != "" {
+ printf("\t%s,", line)
+ }
+ printf("\n")
+ }
+ printf("};\n")
+ continue
+ }
+
+ // Convert
+ // const A = 1
+ // to
+ // enum { A = 1 };
+ if strings.HasPrefix(line, "const ") {
+ printf("enum { %s };\n", line[len("const "):])
+ continue
+ }
+
+ // On first type definition, typedef all the structs
+ // in case there are dependencies between them.
+ if !didTypedef && strings.HasPrefix(line, "type ") {
+ didTypedef = true
+ for _, line := range lines {
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
+ s := line[len("type ") : len(line)-len(" struct {")]
+ printf("typedef struct %s %s;\n", s, s)
+ }
+ }
+ printf("\n")
+ printf("#pragma pack on\n")
+ printf("\n")
+ }
+
+ // Convert
+ // type T struct {
+ // X int64
+ // Y *int32
+ // Z [4]byte
+ // }
+ //
+ // to
+ //
+ // struct T {
+ // int64 X;
+ // int32 *Y;
+ // byte Z[4];
+ // }
+ if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
+ s := line[len("type ") : len(line)-len(" struct {")]
+ printf("struct %s {\n", s)
+ for i++; i < len(lines) && lines[i] != "}"; i++ {
+ line := lines[i]
+ if line != "" {
+ f := strings.Fields(line)
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
+ nerrors++
+ continue
+ }
+ printf("\t%s;", cdecl(f[0], f[1]))
+ }
+ printf("\n")
+ }
+ printf("};\n")
+ continue
+ }
+
+ // Convert
+ // type T int
+ // to
+ // typedef int T;
+ if strings.HasPrefix(line, "type ") {
+ f := strings.Fields(line[len("type "):])
+ if len(f) != 2 {
+ fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
+ nerrors++
+ continue
+ }
+ printf("typedef\t%s;\n", cdecl(f[0], f[1]))
+ continue
+ }
+
+ printf("%s\n", line)
+ }
+
+ if didTypedef {
+ printf("\n")
+ printf("#pragma pack off\n")
+ }
+
+ return out.String()
+}
+
+// cdecl returns the C declaration for the given Go name and type.
+// It only handles the specific cases necessary for converting godefs output.
+func cdecl(name, typ string) string {
+ // X *[0]byte -> X *void
+ if strings.HasPrefix(typ, "*[0]") {
+ typ = "*void"
+ }
+ // X *byte -> *X byte
+ if strings.HasPrefix(typ, "*") {
+ name = "*" + name
+ typ = typ[1:]
+ }
+ // X [4]byte -> X[4] byte
+ if strings.HasPrefix(typ, "[") {
+ i := strings.Index(typ, "]") + 1
+ name = name + typ[:i]
+ typ = typ[i:]
+ }
+ // X T -> T X
+ // Handle the special case: 'unsafe.Pointer' is 'void *'
+ if typ == "unsafe.Pointer" {
+ typ = "void"
+ name = "*" + name
+ }
+ return typ + "\t" + name
+}
+
+var gofmtBuf bytes.Buffer
+
+// gofmt returns the gofmt-formatted string for an AST node.
+func gofmt(n interface{}) string {
+ gofmtBuf.Reset()
+ err := printer.Fprint(&gofmtBuf, fset, n)
+ if err != nil {
+ return "<" + err.Error() + ">"
+ }
+ return gofmtBuf.String()
+}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index be9c2bc4f..7449f04c4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -15,11 +15,13 @@ import (
"flag"
"fmt"
"go/ast"
+ "go/printer"
"go/token"
"io"
"os"
"path/filepath"
"reflect"
+ "runtime"
"strings"
)
@@ -37,11 +39,13 @@ type Package struct {
Decl []ast.Decl
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
+ Preamble string // collected preamble for _cgo_export.h
}
// A File collects information about a single Go input file.
type File struct {
AST *ast.File // parsed AST
+ Comments []*ast.CommentGroup // comments from file
Package string // Package name
Preamble string // C preamble (doc comment on import "C")
Ref []*Ref // all references to C.xxx in AST
@@ -95,6 +99,7 @@ type Type struct {
C *TypeRepr
Go ast.Expr
EnumValues map[string]int64
+ Typedef string
}
// A FuncType collects information about a function type in both the C and Go worlds.
@@ -121,6 +126,19 @@ var cPrefix string
var fset = token.NewFileSet()
var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
+var dynout = flag.String("dynout", "", "write -dynobj output to this file")
+
+// These flags are for bootstrapping a new Go implementation,
+// to generate Go and C headers that match the data layout and
+// constant values used in the host's C libraries and system calls.
+var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
+var objDir = flag.String("objdir", "", "object directory")
+
+var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "go", "prefix of symbols generated by gccgo")
+var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
+var goarch, goos string
func main() {
flag.Usage = usage
@@ -130,7 +148,7 @@ func main() {
// cgo -dynimport is essentially a separate helper command
// built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
- // imported libraries. The Make.pkg rules for cgo prepare an
+ // imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
@@ -139,6 +157,18 @@ func main() {
return
}
+ if *godefs && *cdefs {
+ fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
+ os.Exit(2)
+ }
+
+ if *godefs || *cdefs {
+ // Generating definitions pulled from header files,
+ // to be checked into Go repositories.
+ // Line numbers are just noise.
+ conf.Mode &^= printer.SourcePos
+ }
+
args := flag.Args()
if len(args) < 1 {
usage()
@@ -156,32 +186,9 @@ func main() {
usage()
}
- // Copy it to a new slice so it can grow.
- gccOptions := make([]string, i)
- copy(gccOptions, args[0:i])
-
goFiles := args[i:]
- arch := os.Getenv("GOARCH")
- if arch == "" {
- fatalf("$GOARCH is not set")
- }
- ptrSize := ptrSizeMap[arch]
- if ptrSize == 0 {
- fatalf("unknown $GOARCH %q", arch)
- }
-
- // Clear locale variables so gcc emits English errors [sic].
- os.Setenv("LANG", "en_US.UTF-8")
- os.Setenv("LC_ALL", "C")
- os.Setenv("LC_CTYPE", "C")
-
- p := &Package{
- PtrSize: ptrSize,
- GccOptions: gccOptions,
- CgoFlags: make(map[string]string),
- Written: make(map[string]bool),
- }
+ p := newPackage(args[:i])
// Need a unique prefix for the global C symbols that
// we use to coordinate between gcc and ourselves.
@@ -197,7 +204,7 @@ func main() {
io.Copy(h, f)
f.Close()
}
- cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
+ cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
@@ -208,9 +215,13 @@ func main() {
fs[i] = f
}
- // make sure that _obj directory exists, so that we can write
- // all the output files there.
- os.Mkdir("_obj", 0777)
+ if *objDir == "" {
+ // make sure that _obj directory exists, so that we can write
+ // all the output files there.
+ os.Mkdir("_obj", 0777)
+ *objDir = "_obj"
+ }
+ *objDir += string(filepath.Separator)
for i, input := range goFiles {
f := fs[i]
@@ -232,23 +243,64 @@ func main() {
pkg = filepath.Join(dir, pkg)
}
p.PackagePath = pkg
- p.writeOutput(f, input)
-
p.Record(f)
+ if *godefs {
+ os.Stdout.WriteString(p.godefs(f, input))
+ } else if *cdefs {
+ os.Stdout.WriteString(p.cdefs(f, input))
+ } else {
+ p.writeOutput(f, input)
+ }
}
- p.writeDefs()
+ if !*godefs && !*cdefs {
+ p.writeDefs()
+ }
if nerrors > 0 {
os.Exit(2)
}
}
+// newPackage returns a new Package that will invoke
+// gcc with the additional arguments specified in args.
+func newPackage(args []string) *Package {
+ // Copy the gcc options to a new slice so the list
+ // can grow without overwriting the slice that args is in.
+ gccOptions := make([]string, len(args))
+ copy(gccOptions, args)
+
+ goarch = runtime.GOARCH
+ if s := os.Getenv("GOARCH"); s != "" {
+ goarch = s
+ }
+ goos = runtime.GOOS
+ if s := os.Getenv("GOOS"); s != "" {
+ goos = s
+ }
+ ptrSize := ptrSizeMap[goarch]
+ if ptrSize == 0 {
+ fatalf("unknown $GOARCH %q", goarch)
+ }
+
+ // Reset locale variables so gcc emits English errors [sic].
+ os.Setenv("LANG", "en_US.UTF-8")
+ os.Setenv("LC_ALL", "C")
+
+ p := &Package{
+ PtrSize: ptrSize,
+ GccOptions: gccOptions,
+ CgoFlags: make(map[string]string),
+ Written: make(map[string]bool),
+ }
+ return p
+}
+
// Record what needs to be recorded about f.
func (p *Package) Record(f *File) {
if p.PackageName == "" {
p.PackageName = f.Package
} else if p.PackageName != f.Package {
- error(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
+ error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
}
if p.Name == nil {
@@ -258,11 +310,14 @@ func (p *Package) Record(f *File) {
if p.Name[k] == nil {
p.Name[k] = v
} else if !reflect.DeepEqual(p.Name[k], v) {
- error(token.NoPos, "inconsistent definitions for C.%s", k)
+ error_(token.NoPos, "inconsistent definitions for C.%s", k)
}
}
}
- p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ if f.ExpFunc != nil {
+ p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ p.Preamble += "\n" + f.Preamble
+ }
p.Decl = append(p.Decl, f.AST.Decls...)
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 498ab1566..814250c2e 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -14,20 +14,19 @@ import (
"go/printer"
"go/token"
"os"
- "path/filepath"
"strings"
)
-var objDir = "_obj" + string(filepath.Separator)
+var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
- fgo2 := creat(objDir + "_cgo_gotypes.go")
- fc := creat(objDir + "_cgo_defun.c")
- fm := creat(objDir + "_cgo_main.c")
+ fgo2 := creat(*objDir + "_cgo_gotypes.go")
+ fc := creat(*objDir + "_cgo_defun.c")
+ fm := creat(*objDir + "_cgo_main.c")
- fflg := creat(objDir + "_cgo_flags")
+ fflg := creat(*objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
}
@@ -35,7 +34,13 @@ func (p *Package) writeDefs() {
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+ if *importRuntimeCgo {
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+ } else {
+ // If we're not importing runtime/cgo, we *are* runtime/cgo,
+ // which provides crosscall2. We just need a prototype.
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);")
+ }
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
@@ -45,19 +50,25 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
- fmt.Fprintf(fgo2, "import \"os\"\n\n")
- fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
+ fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
+ if !*gccgo && *importRuntimeCgo {
+ fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
+ }
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
- fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n")
+ fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int) { *dst = syscall.Errno(x) }\n")
for name, def := range typedef {
fmt.Fprintf(fgo2, "type %s ", name)
- printer.Fprint(fgo2, fset, def)
- fmt.Fprintf(fgo2, "\n")
+ conf.Fprint(fgo2, fset, def.Go)
+ fmt.Fprintf(fgo2, "\n\n")
}
fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
- fmt.Fprintf(fc, cProlog)
+ if *gccgo {
+ fmt.Fprintf(fc, cPrologGccgo)
+ } else {
+ fmt.Fprintf(fc, cProlog)
+ }
cVars := make(map[string]bool)
for _, n := range p.Name {
@@ -78,7 +89,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fc, "\n")
fmt.Fprintf(fgo2, "var %s ", n.Mangle)
- printer.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
+ conf.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
fmt.Fprintf(fgo2, "\n")
}
fmt.Fprintf(fc, "\n")
@@ -96,13 +107,26 @@ func (p *Package) writeDefs() {
}
}
- p.writeExports(fgo2, fc, fm)
+ if *gccgo {
+ p.writeGccgoExports(fgo2, fc, fm)
+ } else {
+ p.writeExports(fgo2, fc, fm)
+ }
fgo2.Close()
fc.Close()
}
func dynimport(obj string) {
+ stdout := os.Stdout
+ if *dynout != "" {
+ f, err := os.Create(*dynout)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ stdout = f
+ }
+
if f, err := elf.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
@@ -113,14 +137,14 @@ func dynimport(obj string) {
if s.Version != "" {
targ += "@" + s.Version
}
- fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
+ fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Printf("#pragma dynimport _ _ %q\n", l)
+ fmt.Fprintf(stdout, "#pragma dynimport _ _ %q\n", l)
}
return
}
@@ -134,14 +158,14 @@ func dynimport(obj string) {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
- fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
+ fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", s, s, "")
}
lib, err := f.ImportedLibraries()
if err != nil {
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
}
for _, l := range lib {
- fmt.Printf("#pragma dynimport _ _ %q\n", l)
+ fmt.Fprintf(stdout, "#pragma dynimport _ _ %q\n", l)
}
return
}
@@ -153,7 +177,7 @@ func dynimport(obj string) {
}
for _, s := range sym {
ss := strings.Split(s, ":")
- fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
+ fmt.Fprintf(stdout, "#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
}
return
}
@@ -176,7 +200,11 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- fmt.Fprintf(&buf, "\t\t%s p%d;\n", t.C, i)
+ c := t.Typedef
+ if c == "" {
+ c = t.C.String()
+ }
+ fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i)
off += t.Size
}
if off%p.PtrSize != 0 {
@@ -203,7 +231,7 @@ func (p *Package) structType(n *Name) (string, int64) {
off += pad
}
if n.AddError {
- fmt.Fprint(&buf, "\t\tvoid *e[2]; /* os.Error */\n")
+ fmt.Fprint(&buf, "\t\tvoid *e[2]; /* error */\n")
off += 2 * p.PtrSize
}
if off == 0 {
@@ -217,9 +245,9 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
name := n.Go
gtype := n.FuncType.Go
if n.AddError {
- // Add "os.Error" to return type list.
+ // Add "error" to return type list.
// Type list is known to be 0 or 1 element - it's a C function.
- err := &ast.Field{Type: ast.NewIdent("os.Error")}
+ err := &ast.Field{Type: ast.NewIdent("error")}
l := gtype.Results.List
if len(l) == 0 {
l = []*ast.Field{err}
@@ -237,8 +265,45 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
Name: ast.NewIdent(n.Mangle),
Type: gtype,
}
- printer.Fprint(fgo2, fset, d)
- fmt.Fprintf(fgo2, "\n")
+
+ if *gccgo {
+ // Gccgo style hooks.
+ // we hook directly into C. gccgo goes not support cgocall yet.
+ if !n.AddError {
+ fmt.Fprintf(fgo2, "//extern %s\n", n.C)
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, "\n")
+ } else {
+ // write a small wrapper to retrieve errno.
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ for i, param := range d.Type.Params.List {
+ paramName := fmt.Sprintf("p%d", i)
+ param.Names = []*ast.Ident{ast.NewIdent(paramName)}
+ paramnames = append(paramnames, paramName)
+ }
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprintf(fgo2, "{\n")
+ fmt.Fprintf(fgo2, "\tsyscall.SetErrno(0)\n")
+ fmt.Fprintf(fgo2, "\tr := %s(%s)\n", cname, strings.Join(paramnames, ", "))
+ fmt.Fprintf(fgo2, "\te := syscall.GetErrno()\n")
+ fmt.Fprintf(fgo2, "\tif e != 0 {\n")
+ fmt.Fprintf(fgo2, "\t\treturn r, e\n")
+ fmt.Fprintf(fgo2, "\t}\n")
+ fmt.Fprintf(fgo2, "\treturn r, nil\n")
+ fmt.Fprintf(fgo2, "}\n")
+ // declare the C function.
+ fmt.Fprintf(fgo2, "//extern %s\n", n.C)
+ d.Name = ast.NewIdent(cname)
+ l := d.Type.Results.List
+ d.Type.Results.List = l[:len(l)-1]
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, "\n")
+ }
+ return
+ }
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, "\n")
if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" {
// The builtins are already defined in the C prolog.
@@ -276,7 +341,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
v[0] = 0;
v[1] = 0;
} else {
- ·_Cerrno(v, e); /* fill in v as os.Error for errno e */
+ ·_Cerrno(v, e); /* fill in v as error for errno e */
}
}`)
}
@@ -292,16 +357,15 @@ func (p *Package) writeOutput(f *File, srcfile string) {
base = base[0 : len(base)-3]
}
base = strings.Map(slashToUnderscore, base)
- fgo1 := creat(objDir + base + ".cgo1.go")
- fgcc := creat(objDir + base + ".cgo2.c")
+ fgo1 := creat(*objDir + base + ".cgo1.go")
+ fgcc := creat(*objDir + base + ".cgo2.c")
p.GoFiles = append(p.GoFiles, base+".cgo1.go")
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
- printer.Fprint(fgo1, fset, f.AST)
+ conf.Fprint(fgo1, fset, f.AST)
// While we process the vars and funcs, also write 6c and gcc output.
// Gcc output starts with the preamble.
@@ -327,6 +391,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
p.Written[name] = true
+ if *gccgo {
+ // we don't use wrappers with gccgo.
+ return
+ }
+
ctype, _ := p.structType(n)
// Gcc wrapper unpacks the C argument struct
@@ -351,10 +420,20 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i := range n.FuncType.Params {
+ for i, t := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
+ // We know the type params are correct, because
+ // the Go equivalents had good type params.
+ // However, our version of the type omits the magic
+ // words const and volatile, which can provoke
+ // C compiler warnings. Silence them by casting
+ // all pointers to void*. (Eventually that will produce
+ // other warnings.)
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -368,10 +447,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
- fgcc := creat(objDir + "_cgo_export.c")
- fgcch := creat("_cgo_export.h")
+ fgcc := creat(*objDir + "_cgo_export.c")
+ fgcch := creat(*objDir + "_cgo_export.h")
fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "%s\n", p.Preamble)
fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
@@ -501,8 +581,10 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "extern void ·%s();\n", goname)
- fmt.Fprintf(fc, "\nvoid\n")
+ fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname)
+ fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+ fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
+ fmt.Fprintf(fc, "void\n")
fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
@@ -514,11 +596,11 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
// a Go wrapper function.
if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname)
- printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
+ conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
fmt.Fprintf(fgo2, ", p%d ", i)
- printer.Fprint(fgo2, fset, atype)
+ conf.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
@@ -528,7 +610,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- printer.Fprint(fgo2, fset, atype)
+ conf.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
@@ -551,6 +633,83 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
}
}
+// Write out the C header allowing C code to call exported gccgo functions.
+func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+ fgcc := creat(*objDir + "_cgo_export.c")
+ fgcch := creat(*objDir + "_cgo_export.h")
+ _ = fgcc
+
+ fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
+ fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
+
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ gccgoSymbolPrefix := strings.Map(clean, *gccgoprefix)
+
+ for _, exp := range p.ExpFunc {
+ // TODO: support functions with receivers.
+ fn := exp.Func
+ fntype := fn.Type
+
+ if !ast.IsExported(fn.Name.Name) {
+ fatalf("cannot export unexported function %s with gccgo", fn.Name)
+ }
+
+ cdeclBuf := new(bytes.Buffer)
+ resultCount := 0
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) { resultCount++ })
+ switch resultCount {
+ case 0:
+ fmt.Fprintf(cdeclBuf, "void")
+ case 1:
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s", t.C)
+ })
+ default:
+ // Declare a result struct.
+ fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
+ }
+
+ // The function name.
+ fmt.Fprintf(cdeclBuf, " "+exp.ExpName)
+ gccgoSymbol := fmt.Sprintf("%s.%s.%s", gccgoSymbolPrefix, p.PackageName, exp.Func.Name)
+ fmt.Fprintf(cdeclBuf, " (")
+ // Function parameters.
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprintf(cdeclBuf, ", ")
+ }
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
+ })
+ fmt.Fprintf(cdeclBuf, ")")
+ cdecl := cdeclBuf.String()
+
+ fmt.Fprintf(fgcch, "extern %s __asm__(\"%s\");\n", cdecl, gccgoSymbol)
+ // Dummy declaration for _cgo_main.c
+ fmt.Fprintf(fm, "%s {}\n", cdecl)
+ }
+}
+
// Call a function for each entry in an ast.FieldList, passing the
// index into the list and the type.
func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
@@ -577,22 +736,25 @@ func c(repr string, args ...interface{}) *TypeRepr {
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
- "int": &Type{Size: 4, Align: 4, C: c("int")},
- "uint": &Type{Size: 4, Align: 4, C: c("uint")},
- "int8": &Type{Size: 1, Align: 1, C: c("schar")},
- "uint8": &Type{Size: 1, Align: 1, C: c("uchar")},
- "int16": &Type{Size: 2, Align: 2, C: c("short")},
- "uint16": &Type{Size: 2, Align: 2, C: c("ushort")},
- "int32": &Type{Size: 4, Align: 4, C: c("int")},
- "uint32": &Type{Size: 4, Align: 4, C: c("uint")},
- "int64": &Type{Size: 8, Align: 8, C: c("int64")},
- "uint64": &Type{Size: 8, Align: 8, C: c("uint64")},
- "float": &Type{Size: 4, Align: 4, C: c("float")},
- "float32": &Type{Size: 4, Align: 4, C: c("float")},
- "float64": &Type{Size: 8, Align: 8, C: c("double")},
- "complex": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex64": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex128": &Type{Size: 16, Align: 16, C: c("__complex double")},
+ "bool": {Size: 1, Align: 1, C: c("uchar")},
+ "byte": {Size: 1, Align: 1, C: c("uchar")},
+ "int": {Size: 4, Align: 4, C: c("int")},
+ "uint": {Size: 4, Align: 4, C: c("uint")},
+ "rune": {Size: 4, Align: 4, C: c("int")},
+ "int8": {Size: 1, Align: 1, C: c("schar")},
+ "uint8": {Size: 1, Align: 1, C: c("uchar")},
+ "int16": {Size: 2, Align: 2, C: c("short")},
+ "uint16": {Size: 2, Align: 2, C: c("ushort")},
+ "int32": {Size: 4, Align: 4, C: c("int")},
+ "uint32": {Size: 4, Align: 4, C: c("uint")},
+ "int64": {Size: 8, Align: 8, C: c("int64")},
+ "uint64": {Size: 8, Align: 8, C: c("uint64")},
+ "float": {Size: 4, Align: 4, C: c("float")},
+ "float32": {Size: 4, Align: 4, C: c("float")},
+ "float64": {Size: 8, Align: 8, C: c("double")},
+ "complex": {Size: 8, Align: 8, C: c("__complex float")},
+ "complex64": {Size: 8, Align: 8, C: c("__complex float")},
+ "complex128": {Size: 16, Align: 16, C: c("__complex double")},
}
// Map an ast type to a Type.
@@ -610,7 +772,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
case *ast.FuncType:
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
case *ast.InterfaceType:
- return &Type{Size: 3 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
case *ast.MapType:
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")}
case *ast.ChanType:
@@ -633,10 +795,8 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
}
}
- for name, def := range typedef {
- if name == t.Name {
- return p.cgoType(def)
- }
+ if def := typedef[t.Name]; def != nil {
+ return def
}
if t.Name == "uintptr" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("uintptr")}
@@ -644,13 +804,16 @@ func (p *Package) cgoType(e ast.Expr) *Type {
if t.Name == "string" {
return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: c("GoString")}
}
+ if t.Name == "error" {
+ return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
+ }
if r, ok := goTypes[t.Name]; ok {
if r.Align > p.PtrSize {
r.Align = p.PtrSize
}
return r
}
- error(e.Pos(), "unrecognized Go type %s", t.Name)
+ error_(e.Pos(), "unrecognized Go type %s", t.Name)
return &Type{Size: 4, Align: 4, C: c("int")}
case *ast.SelectorExpr:
id, ok := t.X.(*ast.Ident)
@@ -658,7 +821,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")}
}
}
- error(e.Pos(), "unrecognized Go type %T", e)
+ error_(e.Pos(), "Go type not supported in export: %s", gofmt(e))
return &Type{Size: 4, Align: 4, C: c("int")}
}
@@ -729,6 +892,43 @@ void
}
`
+const cPrologGccgo = `
+#include <stdint.h>
+#include <string.h>
+
+struct __go_string {
+ const unsigned char *__data;
+ int __length;
+};
+
+typedef struct __go_open_array {
+ void* __values;
+ int __count;
+ int __capacity;
+} Slice;
+
+struct __go_string __go_byte_array_to_string(const void* p, int len);
+struct __go_open_array __go_string_to_byte_array (struct __go_string str);
+
+const char *CString(struct __go_string s) {
+ return strndup((const char*)s.__data, s.__length);
+}
+
+struct __go_string GoString(char *p) {
+ int len = (p != NULL) ? strlen(p) : 0;
+ return __go_byte_array_to_string(p, len);
+}
+
+struct __go_string GoStringN(char *p, int n) {
+ return __go_byte_array_to_string(p, n);
+}
+
+Slice GoBytes(char *p, int n) {
+ struct __go_string s = { (const unsigned char *)p, n };
+ return __go_string_to_byte_array(s);
+}
+`
+
const gccExportHeaderProlog = `
typedef unsigned int uint;
typedef signed char schar;
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index e79b0e1bf..a0f216614 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -5,11 +5,11 @@
package main
import (
- "exec"
"fmt"
"go/token"
"io/ioutil"
"os"
+ "os/exec"
)
// run runs the command argv, feeding in stdin on standard input.
@@ -36,7 +36,6 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
if err != nil {
fatalf("%s", err)
}
- defer p.Release()
r0.Close()
w1.Close()
w2.Close()
@@ -56,23 +55,31 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
<-c
<-c
- w, err := p.Wait(0)
+ state, err := p.Wait()
if err != nil {
fatalf("%s", err)
}
- ok = w.Exited() && w.ExitStatus() == 0
+ ok = state.Success()
return
}
+func lineno(pos token.Pos) string {
+ return fset.Position(pos).String()
+}
+
// Die with an error message.
func fatalf(msg string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, msg+"\n", args...)
+ // If we've already printed other errors, they might have
+ // caused the fatal condition. Assume they're enough.
+ if nerrors == 0 {
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
+ }
os.Exit(2)
}
var nerrors int
-func error(pos token.Pos, msg string, args ...interface{}) {
+func error_(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
@@ -102,7 +109,7 @@ func creat(name string) *os.File {
return f
}
-func slashToUnderscore(c int) int {
+func slashToUnderscore(c rune) rune {
if c == '/' || c == '\\' || c == ':' {
c = '_'
}
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
deleted file mode 100644
index 95dba9c60..000000000
--- a/src/cmd/cov/Makefile
+++ /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.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is cov because the source is portable and general.
-# We call the binary 6cov to avoid confusion and because this binary
-# is linked only with amd64 and x86 support.
-
-TARG=6cov
-OFILES=\
- main.$O\
- tree.$O\
-
-HFILES=\
- tree.h\
-
-NOINSTALL=1
-include ../../Make.ccmd
-
-ifeq ($(GOOS),windows)
-NAME=windows
-else
-NAME=$(shell uname | tr A-Z a-z)
-endif
-
-install: install-$(NAME)
-install-linux: install-default
-install-freebsd: install-default
-install-windows: install-default
-
-# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
-install-darwin: $(TARG)
- @true
-
-install-default: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/cov/doc.go b/src/cmd/cov/doc.go
deleted file mode 100644
index 5de00e19c..000000000
--- a/src/cmd/cov/doc.go
+++ /dev/null
@@ -1,33 +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.
-
-/*
-
-Cov is a rudimentary code coverage tool.
-
-Given a command to run, it runs the command while tracking which
-sections of code have been executed. When the command finishes,
-cov prints the line numbers of sections of code in the binary that
-were not executed. With no arguments it assumes the command "6.out".
-
-Usage: cov [-lsv] [-g substring] [-m minlines] [6.out args]
-
-The options are:
-
- -l
- print full path names instead of paths relative to the current directory
- -s
- show the source code that didn't execute, in addition to the line numbers.
- -v
- print debugging information during the run.
- -g substring
- restrict the coverage analysis to functions or files whose names contain substring
- -m minlines
- only report uncovered sections of code larger than minlines lines
-
-For reasons of disambiguation it is installed as 6cov although it also serves
-as an 8cov and a 5cov.
-
-*/
-package documentation
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
deleted file mode 100644
index 5ff22c00a..000000000
--- a/src/cmd/cov/main.c
+++ /dev/null
@@ -1,480 +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.
-
-/*
- * code coverage
- */
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-#include "tree.h"
-
-#include <ureg_amd64.h>
-#include <mach.h>
-typedef struct Ureg Ureg;
-
-void
-usage(void)
-{
- fprint(2, "usage: cov [-lsv] [-g substring] [-m minlines] [6.out args...]\n");
- fprint(2, "-g specifies pattern of interesting functions or files\n");
- exits("usage");
-}
-
-typedef struct Range Range;
-struct Range
-{
- uvlong pc;
- uvlong epc;
-};
-
-int chatty;
-int fd;
-int longnames;
-int pid;
-int doshowsrc;
-Map *mem;
-Map *text;
-Fhdr fhdr;
-char *substring;
-char cwd[1000];
-int ncwd;
-int minlines = -1000;
-
-Tree breakpoints; // code ranges not run
-
-/*
- * comparison for Range structures
- * they are "equal" if they overlap, so
- * that a search for [pc, pc+1) finds the
- * Range containing pc.
- */
-int
-rangecmp(void *va, void *vb)
-{
- Range *a = va, *b = vb;
- if(a->epc <= b->pc)
- return 1;
- if(b->epc <= a->pc)
- return -1;
- return 0;
-}
-
-/*
- * remember that we ran the section of code [pc, epc).
- */
-void
-ran(uvlong pc, uvlong epc)
-{
- Range key;
- Range *r;
- uvlong oldepc;
-
- if(chatty)
- print("run %#llux-%#llux\n", pc, epc);
-
- key.pc = pc;
- key.epc = pc+1;
- r = treeget(&breakpoints, &key);
- if(r == nil)
- sysfatal("unchecked breakpoint at %#llux+%d", pc, (int)(epc-pc));
-
- // Might be that the tail of the sequence
- // was run already, so r->epc is before the end.
- // Adjust len.
- if(epc > r->epc)
- epc = r->epc;
-
- if(r->pc == pc) {
- r->pc = epc;
- } else {
- // Chop r to before pc;
- // add new entry for after if needed.
- // Changing r->epc does not affect r's position in the tree.
- oldepc = r->epc;
- r->epc = pc;
- if(epc < oldepc) {
- Range *n;
- n = malloc(sizeof *n);
- n->pc = epc;
- n->epc = oldepc;
- treeput(&breakpoints, n, n);
- }
- }
-}
-
-void
-showsrc(char *file, int line1, int line2)
-{
- Biobuf *b;
- char *p;
- int n, stop;
-
- if((b = Bopen(file, OREAD)) == nil) {
- print("\topen %s: %r\n", file);
- return;
- }
-
- for(n=1; n<line1 && (p = Brdstr(b, '\n', 1)) != nil; n++)
- free(p);
-
- // print up to five lines (this one and 4 more).
- // if there are more than five lines, print 4 and "..."
- stop = n+4;
- if(stop > line2)
- stop = line2;
- if(stop < line2)
- stop--;
- for(; n<=stop && (p = Brdstr(b, '\n', 1)) != nil; n++) {
- print(" %d %s\n", n, p);
- free(p);
- }
- if(n < line2)
- print(" ...\n");
- Bterm(b);
-}
-
-/*
- * if s is in the current directory or below,
- * return the relative path.
- */
-char*
-shortname(char *s)
-{
- if(!longnames && strlen(s) > ncwd && memcmp(s, cwd, ncwd) == 0 && s[ncwd] == '/')
- return s+ncwd+1;
- return s;
-}
-
-/*
- * we've decided that [pc, epc) did not run.
- * do something about it.
- */
-void
-missing(uvlong pc, uvlong epc)
-{
- char file[1000];
- int line1, line2;
- char buf[100];
- Symbol s;
- char *p;
- uvlong uv;
-
- if(!findsym(pc, CTEXT, &s) || !fileline(file, sizeof file, pc)) {
- notfound:
- print("%#llux-%#llux\n", pc, epc);
- return;
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line1 = atoi(p);
- for(uv=pc; uv<epc; ) {
- if(!fileline(file, sizeof file, epc-2))
- goto notfound;
- uv += machdata->instsize(text, uv);
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line2 = atoi(p);
-
- if(line2+1-line2 < minlines)
- return;
-
- if(pc == s.value) {
- // never entered function
- print("%s:%d %s never called (%#llux-%#llux)\n", shortname(file), line1, s.name, pc, epc);
- return;
- }
- if(pc <= s.value+13) {
- // probably stub for stack growth.
- // check whether last instruction is call to morestack.
- // the -5 below is the length of
- // CALL sys.morestack.
- buf[0] = 0;
- machdata->das(text, epc-5, 0, buf, sizeof buf);
- if(strstr(buf, "morestack"))
- return;
- }
-
- if(epc - pc == 5) {
- // check for CALL sys.panicindex
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strstr(buf, "panicindex"))
- return;
- }
-
- if(epc - pc == 2 || epc -pc == 3) {
- // check for XORL inside shift.
- // (on x86 have to implement large left or unsigned right shift with explicit zeroing).
- // f+90 0x00002c9f CMPL CX,$20
- // f+93 0x00002ca2 JCS f+97(SB)
- // f+95 0x00002ca4 XORL AX,AX <<<
- // f+97 0x00002ca6 SHLL CL,AX
- // f+99 0x00002ca8 MOVL $1,CX
- //
- // f+c8 0x00002cd7 CMPL CX,$40
- // f+cb 0x00002cda JCS f+d0(SB)
- // f+cd 0x00002cdc XORQ AX,AX <<<
- // f+d0 0x00002cdf SHLQ CL,AX
- // f+d3 0x00002ce2 MOVQ $1,CX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "XOR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SHL", 3) == 0 || strncmp(buf, "SHR", 3) == 0)
- return;
- }
- }
-
- if(epc - pc == 3) {
- // check for SAR inside shift.
- // (on x86 have to implement large signed right shift as >>31).
- // f+36 0x00016216 CMPL CX,$20
- // f+39 0x00016219 JCS f+3e(SB)
- // f+3b 0x0001621b SARL $1f,AX <<<
- // f+3e 0x0001621e SARL CL,AX
- // f+40 0x00016220 XORL CX,CX
- // f+42 0x00016222 CMPL CX,AX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0)
- return;
- }
- }
-
- // show first instruction to make clear where we were.
- machdata->das(text, pc, 0, buf, sizeof buf);
-
- if(line1 != line2)
- print("%s:%d,%d %#llux-%#llux %s\n",
- shortname(file), line1, line2, pc, epc, buf);
- else
- print("%s:%d %#llux-%#llux %s\n",
- shortname(file), line1, pc, epc, buf);
- if(doshowsrc)
- showsrc(file, line1, line2);
-}
-
-/*
- * walk the tree, calling missing for each non-empty
- * section of missing code.
- */
-void
-walktree(TreeNode *t)
-{
- Range *n;
-
- if(t == nil)
- return;
- walktree(t->left);
- n = t->key;
- if(n->pc < n->epc)
- missing(n->pc, n->epc);
- walktree(t->right);
-}
-
-/*
- * set a breakpoint all over [pc, epc)
- * and remember that we did.
- */
-void
-breakpoint(uvlong pc, uvlong epc)
-{
- Range *r;
-
- r = malloc(sizeof *r);
- r->pc = pc;
- r->epc = epc;
- treeput(&breakpoints, r, r);
-
- for(; pc < epc; pc+=machdata->bpsize)
- put1(mem, pc, machdata->bpinst, machdata->bpsize);
-}
-
-/*
- * install breakpoints over all text symbols
- * that match the pattern.
- */
-void
-cover(void)
-{
- Symbol s;
- char *lastfn;
- uvlong lastpc;
- int i;
- char buf[200];
-
- lastfn = nil;
- lastpc = 0;
- for(i=0; textsym(&s, i); i++) {
- switch(s.type) {
- case 'T':
- case 't':
- if(lastpc != 0) {
- breakpoint(lastpc, s.value);
- lastpc = 0;
- }
- // Ignore second entry for a given name;
- // that's the debugging blob.
- if(lastfn && strcmp(s.name, lastfn) == 0)
- break;
- lastfn = s.name;
- buf[0] = 0;
- fileline(buf, sizeof buf, s.value);
- if(substring == nil || strstr(buf, substring) || strstr(s.name, substring))
- lastpc = s.value;
- }
- }
-}
-
-uvlong
-rgetzero(Map *map, char *reg)
-{
- return 0;
-}
-
-/*
- * remove the breakpoints at pc and successive instructions,
- * up to and including the first jump or other control flow transfer.
- */
-void
-uncover(uvlong pc)
-{
- uchar buf[1000];
- int n, n1, n2;
- uvlong foll[2];
-
- // Double-check that we stopped at a breakpoint.
- if(get1(mem, pc, buf, machdata->bpsize) < 0)
- sysfatal("read mem inst at %#llux: %r", pc);
- if(memcmp(buf, machdata->bpinst, machdata->bpsize) != 0)
- sysfatal("stopped at %#llux; not at breakpoint %d", pc, machdata->bpsize);
-
- // Figure out how many bytes of straight-line code
- // there are in the text starting at pc.
- n = 0;
- while(n < sizeof buf) {
- n1 = machdata->instsize(text, pc+n);
- if(n+n1 > sizeof buf)
- break;
- n2 = machdata->foll(text, pc+n, rgetzero, foll);
- n += n1;
- if(n2 != 1 || foll[0] != pc+n)
- break;
- }
-
- // Record that this section of code ran.
- ran(pc, pc+n);
-
- // Put original instructions back.
- if(get1(text, pc, buf, n) < 0)
- sysfatal("get1: %r");
- if(put1(mem, pc, buf, n) < 0)
- sysfatal("put1: %r");
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) < 0)
- sysfatal("fork: %r");
- if(pid == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0)
- sysfatal("ctlproc hang: %r");
- execv(argv[0], argv);
- sysfatal("exec %s: %r", argv[0]);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0)
- sysfatal("attach %d %s: %r", pid, argv[0]);
- return pid;
-}
-
-int
-go(void)
-{
- uvlong pc;
- char buf[100];
- int n;
-
- for(n = 0;; n++) {
- ctlproc(pid, "startstop");
- if(get8(mem, offsetof(Ureg, ip), &pc) < 0) {
- rerrstr(buf, sizeof buf);
- if(strstr(buf, "exited") || strstr(buf, "No such process"))
- return n;
- sysfatal("cannot read pc: %r");
- }
- pc--;
- if(put8(mem, offsetof(Ureg, ip), pc) < 0)
- sysfatal("cannot write pc: %r");
- uncover(pc);
- }
-}
-
-void
-main(int argc, char **argv)
-{
- int n;
-
- ARGBEGIN{
- case 'g':
- substring = EARGF(usage());
- break;
- case 'l':
- longnames++;
- break;
- case 'n':
- minlines = atoi(EARGF(usage()));
- break;
- case 's':
- doshowsrc = 1;
- break;
- case 'v':
- chatty++;
- break;
- default:
- usage();
- }ARGEND
-
- getwd(cwd, sizeof cwd);
- ncwd = strlen(cwd);
-
- if(argc == 0) {
- *--argv = "6.out";
- argc++;
- }
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
- text = loadmap(nil, fd, &fhdr);
- if(text == nil)
- sysfatal("loadmap: %r");
- pid = startprocess(argv);
- mem = attachproc(pid, &fhdr);
- if(mem == nil)
- sysfatal("attachproc: %r");
- breakpoints.cmp = rangecmp;
- cover();
- n = go();
- walktree(breakpoints.root);
- if(chatty)
- print("%d breakpoints\n", n);
- detachproc(mem);
- exits(0);
-}
-
diff --git a/src/cmd/cov/tree.c b/src/cmd/cov/tree.c
deleted file mode 100644
index 116772e42..000000000
--- a/src/cmd/cov/tree.c
+++ /dev/null
@@ -1,246 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-// Mutable map structure, but still based on
-// Okasaki, Red Black Trees in a Functional Setting, JFP 1999,
-// which is a lot easier than the traditional red-black
-// and plenty fast enough for me. (Also I could copy
-// and edit fmap.c.)
-
-#include <u.h>
-#include <libc.h>
-#include "tree.h"
-
-#define TreeNode TreeNode
-#define Tree Tree
-
-enum
-{
- Red = 0,
- Black = 1
-};
-
-
-// Red-black trees are binary trees with this property:
-// 1. No red node has a red parent.
-// 2. Every path from the root to a leaf contains the
-// same number of black nodes.
-
-static TreeNode*
-rwTreeNode(TreeNode *p, int color, TreeNode *left, void *key, void *value, TreeNode *right)
-{
- if(p == nil)
- p = malloc(sizeof *p);
- p->color = color;
- p->left = left;
- p->key = key;
- p->value = value;
- p->right = right;
- return p;
-}
-
-static TreeNode*
-balance(TreeNode *m0)
-{
- void *xk, *xv, *yk, *yv, *zk, *zv;
- TreeNode *a, *b, *c, *d;
- TreeNode *m1, *m2;
- int color;
- TreeNode *left, *right;
- void *key, *value;
-
- color = m0->color;
- left = m0->left;
- key = m0->key;
- value = m0->value;
- right = m0->right;
-
- // Okasaki notation: (T is mkTreeNode, B is Black, R is Red, x, y, z are key-value.
- //
- // balance B (T R (T R a x b) y c) z d
- // balance B (T R a x (T R b y c)) z d
- // balance B a x (T R (T R b y c) z d)
- // balance B a x (T R b y (T R c z d))
- //
- // = T R (T B a x b) y (T B c z d)
-
- if(color == Black){
- if(left && left->color == Red){
- if(left->left && left->left->color == Red){
- a = left->left->left;
- xk = left->left->key;
- xv = left->left->value;
- b = left->left->right;
- yk = left->key;
- yv = left->value;
- c = left->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->left;
- goto hard;
- }else if(left->right && left->right->color == Red){
- a = left->left;
- xk = left->key;
- xv = left->value;
- b = left->right->left;
- yk = left->right->key;
- yv = left->right->value;
- c = left->right->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->right;
- goto hard;
- }
- }else if(right && right->color == Red){
- if(right->left && right->left->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left->left;
- yk = right->left->key;
- yv = right->left->value;
- c = right->left->right;
- zk = right->key;
- zv = right->value;
- d = right->right;
- m1 = right;
- m2 = right->left;
- goto hard;
- }else if(right->right && right->right->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left;
- yk = right->key;
- yv = right->value;
- c = right->right->left;
- zk = right->right->key;
- zv = right->right->value;
- d = right->right->right;
- m1 = right;
- m2 = right->right;
- goto hard;
- }
- }
- }
- return rwTreeNode(m0, color, left, key, value, right);
-
-hard:
- return rwTreeNode(m0, Red, rwTreeNode(m1, Black, a, xk, xv, b),
- yk, yv, rwTreeNode(m2, Black, c, zk, zv, d));
-}
-
-static TreeNode*
-ins0(TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- if(p->key == k){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(p->key < k)
- p->left = ins0(p->left, k, v, rw);
- else
- p->right = ins0(p->right, k, v, rw);
- return balance(p);
-}
-
-static TreeNode*
-ins1(Tree *m, TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- int i;
-
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- i = m->cmp(p->key, k);
- if(i == 0){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(i < 0)
- p->left = ins1(m, p->left, k, v, rw);
- else
- p->right = ins1(m, p->right, k, v, rw);
- return balance(p);
-}
-
-void
-treeputelem(Tree *m, void *key, void *val, TreeNode *rw)
-{
- if(m->cmp)
- m->root = ins1(m, m->root, key, val, rw);
- else
- m->root = ins0(m->root, key, val, rw);
-}
-
-void
-treeput(Tree *m, void *key, void *val)
-{
- treeputelem(m, key, val, nil);
-}
-
-void*
-treeget(Tree *m, void *key)
-{
- int i;
- TreeNode *p;
-
- p = m->root;
- if(m->cmp){
- for(;;){
- if(p == nil)
- return nil;
- i = m->cmp(p->key, key);
- if(i < 0)
- p = p->left;
- else if(i > 0)
- p = p->right;
- else
- return p->value;
- }
- }else{
- for(;;){
- if(p == nil)
- return nil;
- if(p->key == key)
- return p->value;
- if(p->key < key)
- p = p->left;
- else
- p = p->right;
- }
- }
-}
diff --git a/src/cmd/cov/tree.h b/src/cmd/cov/tree.h
deleted file mode 100644
index a716d83ad..000000000
--- a/src/cmd/cov/tree.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-typedef struct Tree Tree;
-typedef struct TreeNode TreeNode;
-struct Tree
-{
- int (*cmp)(void*, void*);
- TreeNode *root;
-};
-
-struct TreeNode
-{
- int color;
- TreeNode *left;
- void *key;
- void *value;
- TreeNode *right;
-};
-
-void *treeget(Tree*, void*);
-void treeput(Tree*, void*, void*);
-void treeputelem(Tree*, void*, void*, TreeNode*);
diff --git a/src/cmd/dist/README b/src/cmd/dist/README
new file mode 100644
index 000000000..cf194faf0
--- /dev/null
+++ b/src/cmd/dist/README
@@ -0,0 +1,45 @@
+This program, dist, is the bootstrapping tool for the Go distribution.
+It takes care of building the C programs (like the Go compiler) and
+the initial bootstrap copy of the go tool. It also serves as a catch-all
+to replace odd jobs previously done with shell scripts.
+
+Dist is itself written in very simple C. All interaction with C libraries,
+even standard C libraries, is confined to a single system-specific file
+(plan9.c, unix.c, windows.c), to aid portability. Functionality needed
+by other files should be exposed via the portability layer. Functions
+in the portability layer begin with an x prefix when they would otherwise
+use the same name as or be confused for an existing function.
+For example, xprintf is the portable printf.
+
+By far the most common data types in dist are strings and arrays of
+strings. Instead of using char* and char**, though, dist uses two named
+data structures, Buf and Vec, which own all the data they point at.
+The Buf operations are functions beginning with b; the Vec operations
+are functions beginning with v. The basic form of any function declaring
+Bufs or Vecs on the stack should be
+
+ void
+ myfunc(void)
+ {
+ Buf b1, b2;
+ Vec v1;
+
+ binit(&b1);
+ binit(&b2);
+ vinit(&v1);
+
+ ... main code ...
+ bprintf(&b1, "hello, world");
+ vadd(&v1, bstr(&b1)); // v1 takes a copy of its argument
+ bprintf(&b1, "another string");
+ vadd(&v1, bstr(&b1)); // v1 now has two strings
+
+ bfree(&b1);
+ bfree(&b2);
+ vfree(&v1);
+ }
+
+The binit/vinit calls prepare a buffer or vector for use, initializing the
+data structures, and the bfree/vfree calls free any memory they are still
+holding onto. Use of this idiom gives us lexically scoped allocations.
+
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
new file mode 100644
index 000000000..c19b1f468
--- /dev/null
+++ b/src/cmd/dist/a.h
@@ -0,0 +1,149 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+typedef int bool;
+
+// The Time unit is unspecified; we just need to
+// be able to compare whether t1 is older than t2 with t1 < t2.
+typedef long long Time;
+
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define USED(x) ((void)(x))
+
+// A Buf is a byte buffer, like Go's []byte.
+typedef struct Buf Buf;
+struct Buf
+{
+ char *p;
+ int len;
+ int cap;
+};
+
+// A Vec is a string vector, like Go's []string.
+typedef struct Vec Vec;
+struct Vec
+{
+ char **p;
+ int len;
+ int cap;
+};
+
+// Modes for run.
+enum {
+ CheckExit = 1,
+};
+
+// buf.c
+bool bequal(Buf *s, Buf *t);
+void bsubst(Buf *b, char *x, char *y);
+void bfree(Buf *b);
+void bgrow(Buf *b, int n);
+void binit(Buf *b);
+char* bpathf(Buf *b, char *fmt, ...);
+char* bprintf(Buf *b, char *fmt, ...);
+void bwritef(Buf *b, char *fmt, ...);
+void breset(Buf *b);
+char* bstr(Buf *b);
+char* btake(Buf *b);
+void bwrite(Buf *b, void *v, int n);
+void bwriteb(Buf *dst, Buf *src);
+void bwritestr(Buf *b, char *p);
+void bswap(Buf *b, Buf *b1);
+void vadd(Vec *v, char *p);
+void vcopy(Vec *dst, char **src, int n);
+void vfree(Vec *v);
+void vgrow(Vec *v, int n);
+void vinit(Vec *v);
+void vreset(Vec *v);
+void vuniq(Vec *v);
+void splitlines(Vec*, char*);
+void splitfields(Vec*, char*);
+
+// build.c
+extern char *goarch;
+extern char *gobin;
+extern char *gochar;
+extern char *gohostarch;
+extern char *gohostos;
+extern char *goos;
+extern char *goroot;
+extern char *goroot_final;
+extern char *goversion;
+extern char *workdir;
+extern char *tooldir;
+extern char *slash;
+extern bool rebuildall;
+
+int find(char*, char**, int);
+void init(void);
+void cmdbanner(int, char**);
+void cmdbootstrap(int, char**);
+void cmdclean(int, char**);
+void cmdenv(int, char**);
+void cmdinstall(int, char**);
+void cmdversion(int, char**);
+
+// buildgc.c
+void gcopnames(char*, char*);
+void mkenam(char*, char*);
+
+// buildruntime.c
+void mkzasm(char*, char*);
+void mkzgoarch(char*, char*);
+void mkzgoos(char*, char*);
+void mkzruntimedefs(char*, char*);
+void mkzversion(char*, char*);
+
+// goc2c.c
+void goc2c(char*, char*);
+
+// main.c
+extern int vflag;
+void usage(void);
+void xmain(int argc, char **argv);
+
+// portability layer (plan9.c, unix.c, windows.c)
+bool contains(char *p, char *sep);
+void fatal(char *msg, ...);
+bool hasprefix(char *p, char *prefix);
+bool hassuffix(char *p, char *suffix);
+bool isabs(char*);
+bool isdir(char *p);
+bool isfile(char *p);
+char* lastelem(char*);
+Time mtime(char*);
+void readfile(Buf*, char*);
+void run(Buf *b, char *dir, int mode, char *cmd, ...);
+void runv(Buf *b, char *dir, int mode, Vec *argv);
+void bgrunv(char *dir, int mode, Vec *argv);
+void bgwait(void);
+bool streq(char*, char*);
+void writefile(Buf*, char*, int);
+void xatexit(void (*f)(void));
+void xexit(int);
+void xfree(void*);
+void xgetenv(Buf *b, char *name);
+void xgetwd(Buf *b);
+void* xmalloc(int n);
+void* xmalloc(int);
+int xmemcmp(void*, void*, int);
+void xmemmove(void*, void*, int);
+void xmkdir(char *p);
+void xmkdirall(char*);
+Time xmtime(char *p);
+void xprintf(char*, ...);
+void xqsort(void*, int, int, int(*)(const void*, const void*));
+void xreaddir(Vec *dst, char *dir);
+void* xrealloc(void*, int);
+void xrealwd(Buf *b, char *path);
+void xremove(char *p);
+void xremoveall(char *p);
+void xsetenv(char*, char*);
+int xstrcmp(char*, char*);
+char* xstrdup(char *p);
+int xstrlen(char*);
+char* xstrrchr(char*, int);
+char* xstrstr(char*, char*);
+char* xworkdir(void);
diff --git a/src/cmd/dist/arg.h b/src/cmd/dist/arg.h
new file mode 100644
index 000000000..6eef0353b
--- /dev/null
+++ b/src/cmd/dist/arg.h
@@ -0,0 +1,50 @@
+/*
+Derived from Inferno include/kern.h.
+
+http://code.google.com/p/inferno-os/source/browse/include/kern.h
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+ Portions Copyright © 2009 The Go Authors. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* command line */
+extern char *argv0;
+#define ARGBEGIN for((argv0?0:(argv0=(*argv))),argv++,argc--;\
+ argv[0] && argv[0][0]=='-' && argv[0][1];\
+ argc--, argv++) {\
+ char *_args, *_argt;\
+ char _argc;\
+ _args = &argv[0][1];\
+ if(_args[0]=='-' && _args[1]==0){\
+ argc--; argv++; break;\
+ }\
+ _argc = 0;\
+ while((_argc = *_args++) != 0)\
+ switch(_argc)
+#define ARGEND _argt=0;USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
+#define ARGF() (_argt=_args, _args="",\
+ (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define EARGF(x) (_argt=_args, _args="",\
+ (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), fatal("usage"), (char*)0)))
+
+#define ARGC() _argc
+
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
new file mode 100644
index 000000000..45fb1954d
--- /dev/null
+++ b/src/cmd/dist/buf.c
@@ -0,0 +1,279 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Byte buffers and string vectors.
+
+#include "a.h"
+
+// binit prepares an uninitialized buffer for use.
+void
+binit(Buf *b)
+{
+ b->p = nil;
+ b->len = 0;
+ b->cap = 0;
+}
+
+// breset truncates the buffer back to zero length.
+void
+breset(Buf *b)
+{
+ b->len = 0;
+}
+
+// bfree frees the storage associated with a buffer.
+void
+bfree(Buf *b)
+{
+ xfree(b->p);
+ binit(b);
+}
+
+// bgrow ensures that the buffer has at least n more bytes
+// between its len and cap.
+void
+bgrow(Buf *b, int n)
+{
+ int want;
+
+ want = b->len+n;
+ if(want > b->cap) {
+ b->cap = 2*want;
+ if(b->cap < 64)
+ b->cap = 64;
+ b->p = xrealloc(b->p, b->cap);
+ }
+}
+
+// bwrite appends the n bytes at v to the buffer.
+void
+bwrite(Buf *b, void *v, int n)
+{
+ bgrow(b, n);
+ xmemmove(b->p+b->len, v, n);
+ b->len += n;
+}
+
+// bwritestr appends the string p to the buffer.
+void
+bwritestr(Buf *b, char *p)
+{
+ bwrite(b, p, xstrlen(p));
+}
+
+// bstr returns a pointer to a NUL-terminated string of the
+// buffer contents. The pointer points into the buffer.
+char*
+bstr(Buf *b)
+{
+ bgrow(b, 1);
+ b->p[b->len] = '\0';
+ return b->p;
+}
+
+// btake takes ownership of the string form of the buffer.
+// After this call, the buffer has zero length and does not
+// refer to the memory that btake returned.
+char*
+btake(Buf *b)
+{
+ char *p;
+
+ p = bstr(b);
+ binit(b);
+ return p;
+}
+
+// bwriteb appends the src buffer to the dst buffer.
+void
+bwriteb(Buf *dst, Buf *src)
+{
+ bwrite(dst, src->p, src->len);
+}
+
+// bequal reports whether the buffers have the same content.
+bool
+bequal(Buf *s, Buf *t)
+{
+ return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
+}
+
+// bsubst rewites b to replace all occurrences of x with y.
+void
+bsubst(Buf *b, char *x, char *y)
+{
+ char *p;
+ int nx, ny, pos;
+
+ nx = xstrlen(x);
+ ny = xstrlen(y);
+
+ pos = 0;
+ for(;;) {
+ p = xstrstr(bstr(b)+pos, x);
+ if(p == nil)
+ break;
+ if(nx != ny) {
+ if(nx < ny) {
+ pos = p - b->p;
+ bgrow(b, ny-nx);
+ p = b->p + pos;
+ }
+ xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
+ }
+ xmemmove(p, y, ny);
+ pos = p+ny - b->p;
+ b->len += ny - nx;
+ }
+}
+
+// The invariant with the vectors is that v->p[0:v->len] is allocated
+// strings that are owned by the vector. The data beyond v->len may
+// be garbage.
+
+// vinit prepares an uninitialized vector for use.
+void
+vinit(Vec *v)
+{
+ v->p = nil;
+ v->len = 0;
+ v->cap = 0;
+}
+
+// vreset truncates the vector back to zero length.
+void
+vreset(Vec *v)
+{
+ int i;
+
+ for(i=0; i<v->len; i++) {
+ xfree(v->p[i]);
+ v->p[i] = nil;
+ }
+ v->len = 0;
+}
+
+// vfree frees the storage associated with the vector.
+void
+vfree(Vec *v)
+{
+ vreset(v);
+ xfree(v->p);
+ vinit(v);
+}
+
+
+// vgrow ensures that the vector has room for at least
+// n more entries between len and cap.
+void
+vgrow(Vec *v, int n)
+{
+ int want;
+
+ want = v->len+n;
+ if(want > v->cap) {
+ v->cap = 2*want;
+ if(v->cap < 64)
+ v->cap = 64;
+ v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
+ }
+}
+
+// vcopy copies the srclen strings at src into the vector.
+void
+vcopy(Vec *dst, char **src, int srclen)
+{
+ int i;
+
+ // use vadd, to make copies of strings
+ for(i=0; i<srclen; i++)
+ vadd(dst, src[i]);
+}
+
+// vadd adds a copy of the string p to the vector.
+void
+vadd(Vec *v, char *p)
+{
+ vgrow(v, 1);
+ if(p != nil)
+ p = xstrdup(p);
+ v->p[v->len++] = p;
+}
+
+// vaddn adds a string consisting of the n bytes at p to the vector.
+void
+vaddn(Vec *v, char *p, int n)
+{
+ char *q;
+
+ vgrow(v, 1);
+ q = xmalloc(n+1);
+ xmemmove(q, p, n);
+ q[n] = '\0';
+ v->p[v->len++] = q;
+}
+
+static int
+strpcmp(const void *a, const void *b)
+{
+ return xstrcmp(*(char**)a, *(char**)b);
+}
+
+// vuniq sorts the vector and then discards duplicates,
+// in the manner of sort | uniq.
+void
+vuniq(Vec *v)
+{
+ int i, n;
+
+ xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
+ n = 0;
+ for(i=0; i<v->len; i++) {
+ if(n>0 && streq(v->p[i], v->p[n-1]))
+ xfree(v->p[i]);
+ else
+ v->p[n++] = v->p[i];
+ }
+ v->len = n;
+}
+
+// splitlines replaces the vector v with the result of splitting
+// the input p after each \n.
+void
+splitlines(Vec *v, char *p)
+{
+ int i;
+ char *start;
+
+ vreset(v);
+ start = p;
+ for(i=0; p[i]; i++) {
+ if(p[i] == '\n') {
+ vaddn(v, start, (p+i+1)-start);
+ start = p+i+1;
+ }
+ }
+ if(*start != '\0')
+ vadd(v, start);
+}
+
+// splitfields replaces the vector v with the result of splitting
+// the input p into non-empty fields containing no spaces.
+void
+splitfields(Vec *v, char *p)
+{
+ char *start;
+
+ vreset(v);
+ for(;;) {
+ while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+ p++;
+ if(*p == '\0')
+ break;
+ start = p;
+ while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
+ p++;
+ vaddn(v, start, p-start);
+ }
+}
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
new file mode 100644
index 000000000..567c9f336
--- /dev/null
+++ b/src/cmd/dist/build.c
@@ -0,0 +1,1530 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+#include "arg.h"
+
+/*
+ * Initialization for any invocation.
+ */
+
+// The usual variables.
+char *goarch;
+char *gobin;
+char *gohostarch;
+char *gohostchar;
+char *gohostos;
+char *goos;
+char *goroot = GOROOT_FINAL;
+char *goroot_final = GOROOT_FINAL;
+char *workdir;
+char *tooldir;
+char *gochar;
+char *goversion;
+char *slash; // / for unix, \ for windows
+
+bool rebuildall = 0;
+
+static bool shouldbuild(char*, char*);
+static void copy(char*, char*, int);
+static char *findgoversion(void);
+
+// The known architecture letters.
+static char *gochars = "568";
+
+// The known architectures.
+static char *okgoarch[] = {
+ // same order as gochars
+ "arm",
+ "amd64",
+ "386",
+};
+
+// The known operating systems.
+static char *okgoos[] = {
+ "darwin",
+ "linux",
+ "freebsd",
+ "netbsd",
+ "openbsd",
+ "plan9",
+ "windows",
+};
+
+static void rmworkdir(void);
+
+// find reports the first index of p in l[0:n], or else -1.
+int
+find(char *p, char **l, int n)
+{
+ int i;
+
+ for(i=0; i<n; i++)
+ if(streq(p, l[i]))
+ return i;
+ return -1;
+}
+
+// init handles initialization of the various global state, like goroot and goarch.
+void
+init(void)
+{
+ char *p;
+ int i;
+ Buf b;
+
+ binit(&b);
+
+ xgetenv(&b, "GOROOT");
+ if(b.len > 0) {
+ // if not "/", then strip trailing path separator
+ if(b.len >= 2 && b.p[b.len - 1] == slash[0])
+ b.len--;
+ goroot = btake(&b);
+ }
+
+ xgetenv(&b, "GOBIN");
+ if(b.len == 0)
+ bprintf(&b, "%s%sbin", goroot, slash);
+ gobin = btake(&b);
+
+ xgetenv(&b, "GOOS");
+ if(b.len == 0)
+ bwritestr(&b, gohostos);
+ goos = btake(&b);
+ if(find(goos, okgoos, nelem(okgoos)) < 0)
+ fatal("unknown $GOOS %s", goos);
+
+ p = bpathf(&b, "%s/include/u.h", goroot);
+ if(!isfile(p)) {
+ fatal("$GOROOT is not set correctly or not exported\n"
+ "\tGOROOT=%s\n"
+ "\t%s does not exist", goroot, p);
+ }
+
+ xgetenv(&b, "GOHOSTARCH");
+ if(b.len > 0)
+ gohostarch = btake(&b);
+
+ i = find(gohostarch, okgoarch, nelem(okgoarch));
+ if(i < 0)
+ fatal("unknown $GOHOSTARCH %s", gohostarch);
+ bprintf(&b, "%c", gochars[i]);
+ gohostchar = btake(&b);
+
+ xgetenv(&b, "GOARCH");
+ if(b.len == 0)
+ bwritestr(&b, gohostarch);
+ goarch = btake(&b);
+ i = find(goarch, okgoarch, nelem(okgoarch));
+ if(i < 0)
+ fatal("unknown $GOARCH %s", goarch);
+ bprintf(&b, "%c", gochars[i]);
+ gochar = btake(&b);
+
+ xsetenv("GOROOT", goroot);
+ xsetenv("GOARCH", goarch);
+ xsetenv("GOOS", goos);
+
+ // Make the environment more predictable.
+ xsetenv("LANG", "C");
+ xsetenv("LANGUAGE", "en_US.UTF8");
+
+ goversion = findgoversion();
+
+ workdir = xworkdir();
+ xatexit(rmworkdir);
+
+ bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch);
+ tooldir = btake(&b);
+
+ bfree(&b);
+}
+
+// rmworkdir deletes the work directory.
+static void
+rmworkdir(void)
+{
+ if(vflag > 1)
+ xprintf("rm -rf %s\n", workdir);
+ xremoveall(workdir);
+}
+
+// Remove trailing spaces.
+static void
+chomp(Buf *b)
+{
+ int c;
+
+ while(b->len > 0 && ((c=b->p[b->len-1]) == ' ' || c == '\t' || c == '\r' || c == '\n'))
+ b->len--;
+}
+
+
+// findgoversion determines the Go version to use in the version string.
+static char*
+findgoversion(void)
+{
+ char *tag, *rev, *p;
+ int i, nrev;
+ Buf b, path, bmore, branch;
+ Vec tags;
+
+ binit(&b);
+ binit(&path);
+ binit(&bmore);
+ binit(&branch);
+ vinit(&tags);
+
+ // The $GOROOT/VERSION file takes priority, for distributions
+ // without the Mercurial repo.
+ bpathf(&path, "%s/VERSION", goroot);
+ if(isfile(bstr(&path))) {
+ readfile(&b, bstr(&path));
+ chomp(&b);
+ // Commands such as "dist version > VERSION" will cause
+ // the shell to create an empty VERSION file and set dist's
+ // stdout to its fd. dist in turn looks at VERSION and uses
+ // its content if available, which is empty at this point.
+ if(b.len > 0)
+ goto done;
+ }
+
+ // The $GOROOT/VERSION.cache file is a cache to avoid invoking
+ // hg every time we run this command. Unlike VERSION, it gets
+ // deleted by the clean command.
+ bpathf(&path, "%s/VERSION.cache", goroot);
+ if(isfile(bstr(&path))) {
+ readfile(&b, bstr(&path));
+ chomp(&b);
+ goto done;
+ }
+
+ // Otherwise, use Mercurial.
+ // What is the current branch?
+ run(&branch, goroot, CheckExit, "hg", "identify", "-b", nil);
+ chomp(&branch);
+
+ // What are the tags along the current branch?
+ tag = "";
+ rev = ".";
+ run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "-r", ".:0", "--template", "{tags} + ", nil);
+ splitfields(&tags, bstr(&b));
+ nrev = 0;
+ for(i=0; i<tags.len; i++) {
+ p = tags.p[i];
+ if(streq(p, "+"))
+ nrev++;
+ if(hasprefix(p, "release.") || hasprefix(p, "weekly.") || hasprefix(p, "go")) {
+ tag = xstrdup(p);
+ // If this tag matches the current checkout
+ // exactly (no "+" yet), don't show extra
+ // revision information.
+ if(nrev == 0)
+ rev = "";
+ break;
+ }
+ }
+
+ if(tag[0] == '\0') {
+ // Did not find a tag; use branch name.
+ bprintf(&b, "branch.%s", bstr(&branch));
+ tag = btake(&b);
+ }
+
+ if(rev[0]) {
+ // Tag is before the revision we're building.
+ // Add extra information.
+ run(&bmore, goroot, CheckExit, "hg", "log", "--template", " +{node|short}", "-r", rev, nil);
+ chomp(&bmore);
+ }
+
+ bprintf(&b, "%s", tag);
+ if(bmore.len > 0)
+ bwriteb(&b, &bmore);
+
+ // Cache version.
+ writefile(&b, bstr(&path), 0);
+
+done:
+ p = btake(&b);
+
+
+ bfree(&b);
+ bfree(&path);
+ bfree(&bmore);
+ bfree(&branch);
+ vfree(&tags);
+
+ return p;
+}
+
+/*
+ * Initial tree setup.
+ */
+
+// The old tools that no longer live in $GOBIN or $GOROOT/bin.
+static char *oldtool[] = {
+ "5a", "5c", "5g", "5l",
+ "6a", "6c", "6g", "6l",
+ "8a", "8c", "8g", "8l",
+ "6cov",
+ "6nm",
+ "6prof",
+ "cgo",
+ "ebnflint",
+ "goapi",
+ "gofix",
+ "goinstall",
+ "gomake",
+ "gopack",
+ "gopprof",
+ "gotest",
+ "gotype",
+ "govet",
+ "goyacc",
+ "quietgcc",
+};
+
+// Unreleased directories (relative to $GOROOT) that should
+// not be in release branches.
+static char *unreleased[] = {
+ "src/cmd/cov",
+ "src/cmd/prof",
+ "src/pkg/old",
+ "src/pkg/exp",
+};
+
+// setup sets up the tree for the initial build.
+static void
+setup(void)
+{
+ int i;
+ Buf b;
+ char *p;
+
+ binit(&b);
+
+ // Create bin directory.
+ p = bpathf(&b, "%s/bin", goroot);
+ if(!isdir(p))
+ xmkdir(p);
+
+ // Create package directory.
+ p = bpathf(&b, "%s/pkg", goroot);
+ if(!isdir(p))
+ xmkdir(p);
+ p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch);
+ if(rebuildall)
+ xremoveall(p);
+ xmkdirall(p);
+ if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) {
+ p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);
+ if(rebuildall)
+ xremoveall(p);
+ xmkdirall(p);
+ }
+
+ // Create object directory.
+ // We keep it in pkg/ so that all the generated binaries
+ // are in one tree. If pkg/obj/libgc.a exists, it is a dreg from
+ // before we used subdirectories of obj. Delete all of obj
+ // to clean up.
+ bpathf(&b, "%s/pkg/obj/libgc.a", goroot);
+ if(isfile(bstr(&b)))
+ xremoveall(bpathf(&b, "%s/pkg/obj", goroot));
+ p = bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch);
+ if(rebuildall)
+ xremoveall(p);
+ xmkdirall(p);
+
+ // Create tool directory.
+ // We keep it in pkg/, just like the object directory above.
+ if(rebuildall)
+ xremoveall(tooldir);
+ xmkdirall(tooldir);
+
+ // Remove tool binaries from before the tool/gohostos_gohostarch
+ xremoveall(bpathf(&b, "%s/bin/tool", goroot));
+
+ // Remove old pre-tool binaries.
+ for(i=0; i<nelem(oldtool); i++)
+ xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i]));
+
+ // If $GOBIN is set and has a Go compiler, it must be cleaned.
+ for(i=0; gochars[i]; i++) {
+ if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
+ for(i=0; i<nelem(oldtool); i++)
+ xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
+ break;
+ }
+ }
+
+ // For release, make sure excluded things are excluded.
+ if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) {
+ for(i=0; i<nelem(unreleased); i++)
+ if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
+ fatal("%s should not exist in release build", bstr(&b));
+ }
+
+ bfree(&b);
+}
+
+/*
+ * C library and tool building
+ */
+
+// gccargs is the gcc command line to use for compiling a single C file.
+static char *proto_gccargs[] = {
+ "-Wall",
+ "-Wno-sign-compare",
+ "-Wno-missing-braces",
+ "-Wno-parentheses",
+ "-Wno-unknown-pragmas",
+ "-Wno-switch",
+ "-Wno-comment",
+ "-Werror",
+ "-fno-common",
+ "-ggdb",
+ "-O2",
+};
+
+static Vec gccargs;
+
+// deptab lists changes to the default dependencies for a given prefix.
+// deps ending in /* read the whole directory; deps beginning with -
+// exclude files with that prefix.
+static struct {
+ char *prefix; // prefix of target
+ char *dep[20]; // dependency tweaks for targets with that prefix
+} deptab[] = {
+ {"lib9", {
+ "$GOROOT/include/u.h",
+ "$GOROOT/include/utf.h",
+ "$GOROOT/include/fmt.h",
+ "$GOROOT/include/libc.h",
+ "fmt/*",
+ "utf/*",
+ }},
+ {"libbio", {
+ "$GOROOT/include/u.h",
+ "$GOROOT/include/utf.h",
+ "$GOROOT/include/fmt.h",
+ "$GOROOT/include/libc.h",
+ "$GOROOT/include/bio.h",
+ }},
+ {"libmach", {
+ "$GOROOT/include/u.h",
+ "$GOROOT/include/utf.h",
+ "$GOROOT/include/fmt.h",
+ "$GOROOT/include/libc.h",
+ "$GOROOT/include/bio.h",
+ "$GOROOT/include/ar.h",
+ "$GOROOT/include/bootexec.h",
+ "$GOROOT/include/mach.h",
+ "$GOROOT/include/ureg_amd64.h",
+ "$GOROOT/include/ureg_arm.h",
+ "$GOROOT/include/ureg_x86.h",
+ }},
+ {"cmd/cc", {
+ "-pgen.c",
+ "-pswt.c",
+ }},
+ {"cmd/gc", {
+ "-cplx.c",
+ "-pgen.c",
+ "-y1.tab.c", // makefile dreg
+ "opnames.h",
+ }},
+ {"cmd/5c", {
+ "../cc/pgen.c",
+ "../cc/pswt.c",
+ "../5l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ }},
+ {"cmd/6c", {
+ "../cc/pgen.c",
+ "../cc/pswt.c",
+ "../6l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ }},
+ {"cmd/8c", {
+ "../cc/pgen.c",
+ "../cc/pswt.c",
+ "../8l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+ }},
+ {"cmd/5g", {
+ "../gc/cplx.c",
+ "../gc/pgen.c",
+ "../5l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ }},
+ {"cmd/6g", {
+ "../gc/cplx.c",
+ "../gc/pgen.c",
+ "../6l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ }},
+ {"cmd/8g", {
+ "../gc/cplx.c",
+ "../gc/pgen.c",
+ "../8l/enam.c",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+ }},
+ {"cmd/5l", {
+ "../ld/data.c",
+ "../ld/elf.c",
+ "../ld/go.c",
+ "../ld/ldelf.c",
+ "../ld/ldmacho.c",
+ "../ld/ldpe.c",
+ "../ld/lib.c",
+ "../ld/symtab.c",
+ "enam.c",
+ }},
+ {"cmd/6l", {
+ "../ld/*",
+ "enam.c",
+ }},
+ {"cmd/8l", {
+ "../ld/*",
+ "enam.c",
+ }},
+ {"cmd/", {
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libmach.a",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/libbio.a",
+ "$GOROOT/pkg/obj/$GOOS_$GOARCH/lib9.a",
+ }},
+ {"pkg/runtime", {
+ "zasm_$GOOS_$GOARCH.h",
+ "zgoarch_$GOARCH.go",
+ "zgoos_$GOOS.go",
+ "zruntime_defs_$GOOS_$GOARCH.go",
+ "zversion.go",
+ }},
+};
+
+// depsuffix records the allowed suffixes for source files.
+char *depsuffix[] = {
+ ".c",
+ ".h",
+ ".s",
+ ".go",
+ ".goc",
+};
+
+// gentab records how to generate some trivial files.
+static struct {
+ char *nameprefix;
+ void (*gen)(char*, char*);
+} gentab[] = {
+ {"opnames.h", gcopnames},
+ {"enam.c", mkenam},
+ {"zasm_", mkzasm},
+ {"zgoarch_", mkzgoarch},
+ {"zgoos_", mkzgoos},
+ {"zruntime_defs_", mkzruntimedefs},
+ {"zversion.go", mkzversion},
+};
+
+// install installs the library, package, or binary associated with dir,
+// which is relative to $GOROOT/src.
+static void
+install(char *dir)
+{
+ char *name, *p, *elem, *prefix, *exe;
+ bool islib, ispkg, isgo, stale;
+ Buf b, b1, path;
+ Vec compile, files, link, go, missing, clean, lib, extra;
+ Time ttarg, t;
+ int i, j, k, n, doclean, targ;
+
+ if(vflag) {
+ if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
+ xprintf("%s (%s/%s)\n", dir, goos, goarch);
+ else
+ xprintf("%s\n", dir);
+ }
+
+ binit(&b);
+ binit(&b1);
+ binit(&path);
+ vinit(&compile);
+ vinit(&files);
+ vinit(&link);
+ vinit(&go);
+ vinit(&missing);
+ vinit(&clean);
+ vinit(&lib);
+ vinit(&extra);
+
+ // path = full path to dir.
+ bpathf(&path, "%s/src/%s", goroot, dir);
+ name = lastelem(dir);
+
+ // For misc/prof, copy into the tool directory and we're done.
+ if(hasprefix(dir, "misc/")) {
+ copy(bpathf(&b, "%s/%s", tooldir, name),
+ bpathf(&b1, "%s/misc/%s", goroot, name), 1);
+ goto out;
+ }
+
+ // For release, cmd/prof and cmd/cov are not included.
+ if((streq(dir, "cmd/cov") || streq(dir, "cmd/prof")) && !isdir(bstr(&path))) {
+ if(vflag > 1)
+ xprintf("skipping %s - does not exist\n", dir);
+ goto out;
+ }
+
+ // set up gcc command line on first run.
+ if(gccargs.len == 0) {
+ xgetenv(&b, "CC");
+ if(b.len == 0)
+ bprintf(&b, "gcc");
+ splitfields(&gccargs, bstr(&b));
+ for(i=0; i<nelem(proto_gccargs); i++)
+ vadd(&gccargs, proto_gccargs[i]);
+ if(xstrstr(bstr(&b), "clang") != nil) {
+ vadd(&gccargs, "-Wno-dangling-else");
+ vadd(&gccargs, "-Wno-unused-value");
+ }
+ }
+
+ islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
+ ispkg = hasprefix(dir, "pkg");
+ isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
+
+ exe = "";
+ if(streq(gohostos, "windows"))
+ exe = ".exe";
+
+ // Start final link command line.
+ // Note: code below knows that link.p[targ] is the target.
+ if(islib) {
+ // C library.
+ vadd(&link, "ar");
+ vadd(&link, "rsc");
+ prefix = "";
+ if(!hasprefix(name, "lib"))
+ prefix = "lib";
+ targ = link.len;
+ vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
+ } else if(ispkg) {
+ // Go library (package).
+ vadd(&link, bpathf(&b, "%s/pack", tooldir));
+ vadd(&link, "grc");
+ p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
+ *xstrrchr(p, '/') = '\0';
+ xmkdirall(p);
+ targ = link.len;
+ vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4));
+ } else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
+ // Go command.
+ vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
+ vadd(&link, "-o");
+ elem = name;
+ if(streq(elem, "go"))
+ elem = "go_bootstrap";
+ targ = link.len;
+ vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
+ } else {
+ // C command. Use gccargs.
+ vcopy(&link, gccargs.p, gccargs.len);
+ vadd(&link, "-o");
+ targ = link.len;
+ vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
+ if(streq(gohostarch, "amd64"))
+ vadd(&link, "-m64");
+ else if(streq(gohostarch, "386"))
+ vadd(&link, "-m32");
+ }
+ ttarg = mtime(link.p[targ]);
+
+ // Gather files that are sources for this target.
+ // Everything in that directory, and any target-specific
+ // additions.
+ xreaddir(&files, bstr(&path));
+
+ // Remove files beginning with . or _,
+ // which are likely to be editor temporary files.
+ // This is the same heuristic build.ScanDir uses.
+ // There do exist real C files beginning with _,
+ // so limit that check to just Go files.
+ n = 0;
+ for(i=0; i<files.len; i++) {
+ p = files.p[i];
+ if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go")))
+ xfree(p);
+ else
+ files.p[n++] = p;
+ }
+ files.len = n;
+
+ for(i=0; i<nelem(deptab); i++) {
+ if(hasprefix(dir, deptab[i].prefix)) {
+ for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
+ breset(&b1);
+ bwritestr(&b1, p);
+ bsubst(&b1, "$GOROOT", goroot);
+ bsubst(&b1, "$GOOS", goos);
+ bsubst(&b1, "$GOARCH", goarch);
+ p = bstr(&b1);
+ if(hassuffix(p, ".a")) {
+ vadd(&lib, bpathf(&b, "%s", p));
+ continue;
+ }
+ if(hassuffix(p, "/*")) {
+ bpathf(&b, "%s/%s", bstr(&path), p);
+ b.len -= 2;
+ xreaddir(&extra, bstr(&b));
+ bprintf(&b, "%s", p);
+ b.len -= 2;
+ for(k=0; k<extra.len; k++)
+ vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k]));
+ continue;
+ }
+ if(hasprefix(p, "-")) {
+ p++;
+ n = 0;
+ for(k=0; k<files.len; k++) {
+ if(hasprefix(files.p[k], p))
+ xfree(files.p[k]);
+ else
+ files.p[n++] = files.p[k];
+ }
+ files.len = n;
+ continue;
+ }
+ vadd(&files, p);
+ }
+ }
+ }
+ vuniq(&files);
+
+ // Convert to absolute paths.
+ for(i=0; i<files.len; i++) {
+ if(!isabs(files.p[i])) {
+ bpathf(&b, "%s/%s", bstr(&path), files.p[i]);
+ xfree(files.p[i]);
+ files.p[i] = btake(&b);
+ }
+ }
+
+ // Is the target up-to-date?
+ stale = rebuildall;
+ n = 0;
+ for(i=0; i<files.len; i++) {
+ p = files.p[i];
+ for(j=0; j<nelem(depsuffix); j++)
+ if(hassuffix(p, depsuffix[j]))
+ goto ok;
+ xfree(files.p[i]);
+ continue;
+ ok:
+ t = mtime(p);
+ if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) {
+ xfree(files.p[i]);
+ continue;
+ }
+ if(hassuffix(p, ".go"))
+ vadd(&go, p);
+ if(t > ttarg)
+ stale = 1;
+ if(t == 0) {
+ vadd(&missing, p);
+ files.p[n++] = files.p[i];
+ continue;
+ }
+ files.p[n++] = files.p[i];
+ }
+ files.len = n;
+
+ for(i=0; i<lib.len && !stale; i++)
+ if(mtime(lib.p[i]) > ttarg)
+ stale = 1;
+
+ if(!stale)
+ goto out;
+
+ // For package runtime, copy some files into the work space.
+ if(streq(dir, "pkg/runtime")) {
+ copy(bpathf(&b, "%s/arch_GOARCH.h", workdir),
+ bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
+ copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
+ bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
+ copy(bpathf(&b, "%s/os_GOOS.h", workdir),
+ bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
+ copy(bpathf(&b, "%s/signals_GOOS.h", workdir),
+ bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
+ }
+
+ // Generate any missing files; regenerate existing ones.
+ for(i=0; i<files.len; i++) {
+ p = files.p[i];
+ elem = lastelem(p);
+ for(j=0; j<nelem(gentab); j++) {
+ if(hasprefix(elem, gentab[j].nameprefix)) {
+ if(vflag > 1)
+ xprintf("generate %s\n", p);
+ gentab[j].gen(bstr(&path), p);
+ // Do not add generated file to clean list.
+ // In pkg/runtime, we want to be able to
+ // build the package with the go tool,
+ // and it assumes these generated files already
+ // exist (it does not know how to build them).
+ // The 'clean' command can remove
+ // the generated files.
+ goto built;
+ }
+ }
+ // Did not rebuild p.
+ if(find(p, missing.p, missing.len) >= 0)
+ fatal("missing file %s", p);
+ built:;
+ }
+
+ // One more copy for package runtime.
+ // The last batch was required for the generators.
+ // This one is generated.
+ if(streq(dir, "pkg/runtime")) {
+ copy(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
+ bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
+ }
+
+ // Generate .c files from .goc files.
+ if(streq(dir, "pkg/runtime")) {
+ for(i=0; i<files.len; i++) {
+ p = files.p[i];
+ if(!hassuffix(p, ".goc"))
+ continue;
+ // b = path/zp but with _goarch.c instead of .goc
+ bprintf(&b, "%s%sz%s", bstr(&path), slash, lastelem(p));
+ b.len -= 4;
+ bwritef(&b, "_%s.c", goarch);
+ goc2c(p, bstr(&b));
+ vadd(&files, bstr(&b));
+ }
+ vuniq(&files);
+ }
+
+ if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
+ // We've generated the right files; the go command can do the build.
+ if(vflag > 1)
+ xprintf("skip build for cross-compile %s\n", dir);
+ goto nobuild;
+ }
+
+ // Compile the files.
+ for(i=0; i<files.len; i++) {
+ if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
+ continue;
+ name = lastelem(files.p[i]);
+
+ vreset(&compile);
+ if(!isgo) {
+ // C library or tool.
+ vcopy(&compile, gccargs.p, gccargs.len);
+ vadd(&compile, "-c");
+ if(streq(gohostarch, "amd64"))
+ vadd(&compile, "-m64");
+ else if(streq(gohostarch, "386"))
+ vadd(&compile, "-m32");
+ if(streq(dir, "lib9"))
+ vadd(&compile, "-DPLAN9PORT");
+
+ vadd(&compile, "-I");
+ vadd(&compile, bpathf(&b, "%s/include", goroot));
+
+ vadd(&compile, "-I");
+ vadd(&compile, bstr(&path));
+
+ // lib9/goos.c gets the default constants hard-coded.
+ if(streq(name, "goos.c")) {
+ vadd(&compile, bprintf(&b, "-DGOOS=\"%s\"", goos));
+ vadd(&compile, bprintf(&b, "-DGOARCH=\"%s\"", goarch));
+ bprintf(&b1, "%s", goroot_final);
+ bsubst(&b1, "\\", "\\\\"); // turn into C string
+ vadd(&compile, bprintf(&b, "-DGOROOT=\"%s\"", bstr(&b1)));
+ vadd(&compile, bprintf(&b, "-DGOVERSION=\"%s\"", goversion));
+ }
+
+ // gc/lex.c records the GOEXPERIMENT setting used during the build.
+ if(streq(name, "lex.c")) {
+ xgetenv(&b, "GOEXPERIMENT");
+ vadd(&compile, bprintf(&b1, "-DGOEXPERIMENT=\"%s\"", bstr(&b)));
+ }
+ } else {
+ // Supporting files for a Go package.
+ if(hassuffix(files.p[i], ".s"))
+ vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar));
+ else {
+ vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar));
+ vadd(&compile, "-FVw");
+ }
+ vadd(&compile, "-I");
+ vadd(&compile, workdir);
+ vadd(&compile, bprintf(&b, "-DGOOS_%s", goos));
+ vadd(&compile, bprintf(&b, "-DGOARCH_%s", goarch));
+ }
+
+ bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));
+ doclean = 1;
+ if(!isgo && streq(gohostos, "darwin")) {
+ // To debug C programs on OS X, it is not enough to say -ggdb
+ // on the command line. You have to leave the object files
+ // lying around too. Leave them in pkg/obj/, which does not
+ // get removed when this tool exits.
+ bpathf(&b1, "%s/pkg/obj/%s", goroot, dir);
+ xmkdirall(bstr(&b1));
+ bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i]));
+ doclean = 0;
+ }
+
+ b.p[b.len-1] = 'o'; // was c or s
+ vadd(&compile, "-o");
+ vadd(&compile, bstr(&b));
+ vadd(&compile, files.p[i]);
+ bgrunv(bstr(&path), CheckExit, &compile);
+
+ vadd(&link, bstr(&b));
+ if(doclean)
+ vadd(&clean, bstr(&b));
+ }
+ bgwait();
+
+ if(isgo) {
+ // The last loop was compiling individual files.
+ // Hand the Go files to the compiler en masse.
+ vreset(&compile);
+ vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
+
+ bpathf(&b, "%s/_go_.%s", workdir, gochar);
+ vadd(&compile, "-o");
+ vadd(&compile, bstr(&b));
+ vadd(&clean, bstr(&b));
+ vadd(&link, bstr(&b));
+
+ vadd(&compile, "-p");
+ if(hasprefix(dir, "pkg/"))
+ vadd(&compile, dir+4);
+ else
+ vadd(&compile, "main");
+
+ if(streq(dir, "pkg/runtime"))
+ vadd(&compile, "-+");
+
+ vcopy(&compile, go.p, go.len);
+
+ runv(nil, bstr(&path), CheckExit, &compile);
+ }
+
+ if(!islib && !isgo) {
+ // C binaries need the libraries explicitly, and -lm.
+ vcopy(&link, lib.p, lib.len);
+ vadd(&link, "-lm");
+ }
+
+ // Remove target before writing it.
+ xremove(link.p[targ]);
+
+ runv(nil, nil, CheckExit, &link);
+
+nobuild:
+ // In package runtime, we install runtime.h and cgocall.h too,
+ // for use by cgo compilation.
+ if(streq(dir, "pkg/runtime")) {
+ copy(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
+ bpathf(&b1, "%s/src/pkg/runtime/cgocall.h", goroot), 0);
+ copy(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
+ bpathf(&b1, "%s/src/pkg/runtime/runtime.h", goroot), 0);
+ }
+
+
+out:
+ for(i=0; i<clean.len; i++)
+ xremove(clean.p[i]);
+
+ bfree(&b);
+ bfree(&b1);
+ bfree(&path);
+ vfree(&compile);
+ vfree(&files);
+ vfree(&link);
+ vfree(&go);
+ vfree(&missing);
+ vfree(&clean);
+ vfree(&lib);
+ vfree(&extra);
+}
+
+// matchfield reports whether the field matches this build.
+static bool
+matchfield(char *f)
+{
+ return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap");
+}
+
+// shouldbuild reports whether we should build this file.
+// It applies the same rules that are used with context tags
+// in package go/build, except that the GOOS and GOARCH
+// can appear anywhere in the file name, not just after _.
+// In particular, they can be the entire file name (like windows.c).
+// We also allow the special tag cmd_go_bootstrap.
+// See ../go/bootstrap.go and package go/build.
+static bool
+shouldbuild(char *file, char *dir)
+{
+ char *name, *p;
+ int i, j, ret;
+ Buf b;
+ Vec lines, fields;
+
+ // Check file name for GOOS or GOARCH.
+ name = lastelem(file);
+ for(i=0; i<nelem(okgoos); i++)
+ if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
+ return 0;
+ for(i=0; i<nelem(okgoarch); i++)
+ if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
+ return 0;
+
+ // Omit test files.
+ if(contains(name, "_test"))
+ return 0;
+
+ // cmd/go/doc.go has a giant /* */ comment before
+ // it gets to the important detail that it is not part of
+ // package main. We don't parse those comments,
+ // so special case that file.
+ if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go"))
+ return 0;
+ if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go"))
+ return 0;
+
+ // Check file contents for // +build lines.
+ binit(&b);
+ vinit(&lines);
+ vinit(&fields);
+
+ ret = 1;
+ readfile(&b, file);
+ splitlines(&lines, bstr(&b));
+ for(i=0; i<lines.len; i++) {
+ p = lines.p[i];
+ while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+ p++;
+ if(*p == '\0')
+ continue;
+ if(contains(p, "package documentation")) {
+ ret = 0;
+ goto out;
+ }
+ if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) {
+ ret = 0;
+ goto out;
+ }
+ if(!hasprefix(p, "//"))
+ break;
+ if(!contains(p, "+build"))
+ continue;
+ splitfields(&fields, lines.p[i]);
+ if(fields.len < 2 || !streq(fields.p[1], "+build"))
+ continue;
+ for(j=2; j<fields.len; j++) {
+ p = fields.p[j];
+ if((*p == '!' && !matchfield(p+1)) || matchfield(p))
+ goto fieldmatch;
+ }
+ ret = 0;
+ goto out;
+ fieldmatch:;
+ }
+
+out:
+ bfree(&b);
+ vfree(&lines);
+ vfree(&fields);
+
+ return ret;
+}
+
+// copy copies the file src to dst, via memory (so only good for small files).
+static void
+copy(char *dst, char *src, int exec)
+{
+ Buf b;
+
+ if(vflag > 1)
+ xprintf("cp %s %s\n", src, dst);
+
+ binit(&b);
+ readfile(&b, src);
+ writefile(&b, dst, exec);
+ bfree(&b);
+}
+
+// buildorder records the order of builds for the 'go bootstrap' command.
+static char *buildorder[] = {
+ "lib9",
+ "libbio",
+ "libmach",
+
+ "misc/pprof",
+
+ "cmd/addr2line",
+ "cmd/cov",
+ "cmd/nm",
+ "cmd/objdump",
+ "cmd/pack",
+ "cmd/prof",
+
+ "cmd/cc", // must be before c
+ "cmd/gc", // must be before g
+ "cmd/%sl", // must be before a, c, g
+ "cmd/%sa",
+ "cmd/%sc",
+ "cmd/%sg",
+
+ // The dependency order here was copied from a buildscript
+ // back when there were build scripts. Will have to
+ // be maintained by hand, but shouldn't change very
+ // often.
+ "pkg/runtime",
+ "pkg/errors",
+ "pkg/sync/atomic",
+ "pkg/sync",
+ "pkg/io",
+ "pkg/unicode",
+ "pkg/unicode/utf8",
+ "pkg/unicode/utf16",
+ "pkg/bytes",
+ "pkg/math",
+ "pkg/strings",
+ "pkg/strconv",
+ "pkg/bufio",
+ "pkg/sort",
+ "pkg/container/heap",
+ "pkg/encoding/base64",
+ "pkg/syscall",
+ "pkg/time",
+ "pkg/os",
+ "pkg/reflect",
+ "pkg/fmt",
+ "pkg/encoding/json",
+ "pkg/flag",
+ "pkg/path/filepath",
+ "pkg/path",
+ "pkg/io/ioutil",
+ "pkg/log",
+ "pkg/regexp/syntax",
+ "pkg/regexp",
+ "pkg/go/token",
+ "pkg/go/scanner",
+ "pkg/go/ast",
+ "pkg/go/parser",
+ "pkg/os/exec",
+ "pkg/net/url",
+ "pkg/text/template/parse",
+ "pkg/text/template",
+ "pkg/go/doc",
+ "pkg/go/build",
+ "cmd/go",
+};
+
+// cleantab records the directories to clean in 'go clean'.
+// It is bigger than the buildorder because we clean all the
+// compilers but build only the $GOARCH ones.
+static char *cleantab[] = {
+ "cmd/5a",
+ "cmd/5c",
+ "cmd/5g",
+ "cmd/5l",
+ "cmd/6a",
+ "cmd/6c",
+ "cmd/6g",
+ "cmd/6l",
+ "cmd/8a",
+ "cmd/8c",
+ "cmd/8g",
+ "cmd/8l",
+ "cmd/addr2line",
+ "cmd/cc",
+ "cmd/cov",
+ "cmd/gc",
+ "cmd/go",
+ "cmd/nm",
+ "cmd/objdump",
+ "cmd/pack",
+ "cmd/prof",
+ "lib9",
+ "libbio",
+ "libmach",
+ "pkg/bufio",
+ "pkg/bytes",
+ "pkg/container/heap",
+ "pkg/encoding/base64",
+ "pkg/encoding/json",
+ "pkg/errors",
+ "pkg/flag",
+ "pkg/fmt",
+ "pkg/go/ast",
+ "pkg/go/build",
+ "pkg/go/doc",
+ "pkg/go/parser",
+ "pkg/go/scanner",
+ "pkg/go/token",
+ "pkg/io",
+ "pkg/io/ioutil",
+ "pkg/log",
+ "pkg/math",
+ "pkg/net/url",
+ "pkg/os",
+ "pkg/os/exec",
+ "pkg/path",
+ "pkg/path/filepath",
+ "pkg/reflect",
+ "pkg/regexp",
+ "pkg/regexp/syntax",
+ "pkg/runtime",
+ "pkg/sort",
+ "pkg/strconv",
+ "pkg/strings",
+ "pkg/sync",
+ "pkg/sync/atomic",
+ "pkg/syscall",
+ "pkg/text/template",
+ "pkg/text/template/parse",
+ "pkg/time",
+ "pkg/unicode",
+ "pkg/unicode/utf16",
+ "pkg/unicode/utf8",
+};
+
+static void
+clean(void)
+{
+ int i, j, k;
+ Buf b, path;
+ Vec dir;
+
+ binit(&b);
+ binit(&path);
+ vinit(&dir);
+
+ for(i=0; i<nelem(cleantab); i++) {
+ if((streq(cleantab[i], "cmd/cov") || streq(cleantab[i], "cmd/prof")) && !isdir(cleantab[i]))
+ continue;
+ bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
+ xreaddir(&dir, bstr(&path));
+ // Remove generated files.
+ for(j=0; j<dir.len; j++) {
+ for(k=0; k<nelem(gentab); k++) {
+ if(hasprefix(dir.p[j], gentab[k].nameprefix))
+ xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
+ }
+ }
+ // Remove generated binary named for directory.
+ if(hasprefix(cleantab[i], "cmd/"))
+ xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
+ }
+
+ if(rebuildall) {
+ // Remove object tree.
+ xremoveall(bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch));
+
+ // Remove installed packages and tools.
+ xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch));
+ xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
+ xremoveall(tooldir);
+
+ // Remove cached version info.
+ xremove(bpathf(&b, "%s/VERSION.cache", goroot));
+ }
+
+ bfree(&b);
+ bfree(&path);
+ vfree(&dir);
+}
+
+/*
+ * command implementations
+ */
+
+void
+usage(void)
+{
+ xprintf("usage: go tool dist [command]\n"
+ "Commands are:\n"
+ "\n"
+ "banner print installation banner\n"
+ "bootstrap rebuild everything\n"
+ "clean deletes all built files\n"
+ "env [-p] print environment (-p: include $PATH)\n"
+ "install [dir] install individual directory\n"
+ "version print Go version\n"
+ "\n"
+ "All commands take -v flags to emit extra information.\n"
+ );
+ xexit(2);
+}
+
+// The env command prints the default environment.
+void
+cmdenv(int argc, char **argv)
+{
+ bool pflag;
+ char *sep;
+ Buf b, b1;
+ char *format;
+
+ binit(&b);
+ binit(&b1);
+
+ format = "%s=\"%s\"\n";
+ pflag = 0;
+ ARGBEGIN{
+ case 'p':
+ pflag = 1;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'w':
+ format = "set %s=%s\n";
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0)
+ usage();
+
+ xprintf(format, "GOROOT", goroot);
+ xprintf(format, "GOBIN", gobin);
+ xprintf(format, "GOARCH", goarch);
+ xprintf(format, "GOOS", goos);
+ xprintf(format, "GOHOSTARCH", gohostarch);
+ xprintf(format, "GOHOSTOS", gohostos);
+ xprintf(format, "GOTOOLDIR", tooldir);
+ xprintf(format, "GOCHAR", gochar);
+
+ if(pflag) {
+ sep = ":";
+ if(streq(gohostos, "windows"))
+ sep = ";";
+ xgetenv(&b, "PATH");
+ bprintf(&b1, "%s%s%s", gobin, sep, bstr(&b));
+ xprintf(format, "PATH", bstr(&b1));
+ }
+
+ bfree(&b);
+ bfree(&b1);
+}
+
+// The bootstrap command runs a build from scratch,
+// stopping at having installed the go_bootstrap command.
+void
+cmdbootstrap(int argc, char **argv)
+{
+ int i;
+ Buf b;
+ char *oldgoos, *oldgoarch, *oldgochar;
+
+ binit(&b);
+
+ ARGBEGIN{
+ case 'a':
+ rebuildall = 1;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0)
+ usage();
+
+ if(rebuildall)
+ clean();
+ goversion = findgoversion();
+ setup();
+
+ xsetenv("GOROOT", goroot);
+ xsetenv("GOROOT_FINAL", goroot_final);
+
+ // For the main bootstrap, building for host os/arch.
+ oldgoos = goos;
+ oldgoarch = goarch;
+ oldgochar = gochar;
+ goos = gohostos;
+ goarch = gohostarch;
+ gochar = gohostchar;
+ xsetenv("GOARCH", goarch);
+ xsetenv("GOOS", goos);
+
+ for(i=0; i<nelem(buildorder); i++) {
+ install(bprintf(&b, buildorder[i], gohostchar));
+ if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s"))
+ install(bprintf(&b, buildorder[i], oldgochar));
+ }
+
+ goos = oldgoos;
+ goarch = oldgoarch;
+ gochar = oldgochar;
+ xsetenv("GOARCH", goarch);
+ xsetenv("GOOS", goos);
+
+ // Build pkg/runtime for actual goos/goarch too.
+ if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
+ install("pkg/runtime");
+
+ bfree(&b);
+}
+
+static char*
+defaulttarg(void)
+{
+ char *p;
+ Buf pwd, src, real_src;
+
+ binit(&pwd);
+ binit(&src);
+ binit(&real_src);
+
+ // xgetwd might return a path with symlinks fully resolved, and if
+ // there happens to be symlinks in goroot, then the hasprefix test
+ // will never succeed. Instead, we use xrealwd to get a canonical
+ // goroot/src before the comparison to avoid this problem.
+ xgetwd(&pwd);
+ p = btake(&pwd);
+ bpathf(&src, "%s/src/", goroot);
+ xrealwd(&real_src, bstr(&src));
+ if(!hasprefix(p, bstr(&real_src)))
+ fatal("current directory %s is not under %s", p, bstr(&real_src));
+ p += real_src.len;
+ // guard againt xrealwd return the directory without the trailing /
+ if(*p == slash[0])
+ p++;
+
+ bfree(&pwd);
+ bfree(&src);
+ bfree(&real_src);
+
+ return p;
+}
+
+// Install installs the list of packages named on the command line.
+void
+cmdinstall(int argc, char **argv)
+{
+ int i;
+
+ ARGBEGIN{
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc == 0)
+ install(defaulttarg());
+
+ for(i=0; i<argc; i++)
+ install(argv[i]);
+}
+
+// Clean deletes temporary objects.
+// Clean -i deletes the installed objects too.
+void
+cmdclean(int argc, char **argv)
+{
+ ARGBEGIN{
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0)
+ usage();
+
+ clean();
+}
+
+// Banner prints the 'now you've installed Go' banner.
+void
+cmdbanner(int argc, char **argv)
+{
+ char *pathsep;
+ Buf b, b1, search;
+
+ ARGBEGIN{
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0)
+ usage();
+
+ binit(&b);
+ binit(&b1);
+ binit(&search);
+
+ xprintf("\n");
+ xprintf("---\n");
+ xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
+ xprintf("Installed commands in %s\n", gobin);
+
+ // Check that gobin appears in $PATH.
+ xgetenv(&b, "PATH");
+ pathsep = ":";
+ if(streq(gohostos, "windows"))
+ pathsep = ";";
+ bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
+ bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
+ if(xstrstr(bstr(&b1), bstr(&search)) == nil)
+ xprintf("*** You need to add %s to your PATH.\n", gobin);
+
+ if(streq(gohostos, "darwin")) {
+ xprintf("\n"
+ "On OS X the debuggers must be installed setgid procmod.\n"
+ "Read and run ./sudo.bash to install the debuggers.\n");
+ }
+
+ if(!streq(goroot_final, goroot)) {
+ xprintf("\n"
+ "The binaries expect %s to be copied or moved to %s\n",
+ goroot, goroot_final);
+ }
+
+ bfree(&b);
+ bfree(&b1);
+ bfree(&search);
+}
+
+// Version prints the Go version.
+void
+cmdversion(int argc, char **argv)
+{
+ ARGBEGIN{
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0)
+ usage();
+
+ xprintf("%s\n", goversion);
+}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
new file mode 100644
index 000000000..da38760c6
--- /dev/null
+++ b/src/cmd/dist/buildgc.c
@@ -0,0 +1,106 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+#include <stdio.h>
+
+/*
+ * Helpers for building cmd/gc.
+ */
+
+// gcopnames creates opnames.h from go.h.
+// It finds the OXXX enum, pulls out all the constants
+// from OXXX to OEND, and writes a table mapping
+// op to string.
+void
+gcopnames(char *dir, char *file)
+{
+ char *p, *q;
+ int i, j, end;
+ Buf in, b, out;
+ Vec lines, fields;
+
+ binit(&in);
+ binit(&b);
+ binit(&out);
+ vinit(&lines);
+ vinit(&fields);
+
+ bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
+ bwritestr(&out, bprintf(&b, "static char *opnames[] = {\n"));
+
+ readfile(&in, bprintf(&b, "%s/go.h", dir));
+ splitlines(&lines, bstr(&in));
+ i = 0;
+ while(i<lines.len && !contains(lines.p[i], "OXXX"))
+ i++;
+ end = 0;
+ for(; i<lines.len && !end; i++) {
+ p = xstrstr(lines.p[i], "//");
+ if(p != nil)
+ *p = '\0';
+ end = contains(lines.p[i], "OEND");
+ splitfields(&fields, lines.p[i]);
+ for(j=0; j<fields.len; j++) {
+ q = fields.p[j];
+ if(*q == 'O')
+ q++;
+ p = q+xstrlen(q)-1;
+ if(*p == ',')
+ *p = '\0';
+ bwritestr(&out, bprintf(&b, " [O%s] = \"%s\",\n", q, q));
+ }
+ }
+
+ bwritestr(&out, bprintf(&b, "};\n"));
+
+ writefile(&out, file, 0);
+
+ bfree(&in);
+ bfree(&b);
+ bfree(&out);
+ vfree(&lines);
+ vfree(&fields);
+}
+
+// mkenam reads [568].out.h and writes enam.c
+// The format is much the same as the Go opcodes above.
+void
+mkenam(char *dir, char *file)
+{
+ int i, ch;
+ Buf in, b, out;
+ Vec lines;
+ char *p;
+
+ binit(&b);
+ binit(&in);
+ binit(&out);
+ vinit(&lines);
+
+ ch = dir[xstrlen(dir)-2];
+ bprintf(&b, "%s/../%cl/%c.out.h", dir, ch, ch);
+ readfile(&in, bstr(&b));
+ splitlines(&lines, bstr(&in));
+ bwritestr(&out, "char* anames[] = {\n");
+ for(i=0; i<lines.len; i++) {
+ if(hasprefix(lines.p[i], "\tA")) {
+ p = xstrstr(lines.p[i], ",");
+ if(p)
+ *p = '\0';
+ p = xstrstr(lines.p[i], "\n");
+ if(p)
+ *p = '\0';
+ p = lines.p[i] + 2;
+ bwritestr(&out, bprintf(&b, "\t\"%s\",\n", p));
+ }
+ }
+ bwritestr(&out, "};\n");
+ writefile(&out, file, 0);
+
+ bfree(&b);
+ bfree(&in);
+ bfree(&out);
+ vfree(&lines);
+}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
new file mode 100644
index 000000000..a0c62010d
--- /dev/null
+++ b/src/cmd/dist/buildruntime.c
@@ -0,0 +1,346 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+#include <stdio.h>
+
+/*
+ * Helpers for building pkg/runtime.
+ */
+
+// mkzversion writes zversion.go:
+//
+// package runtime
+// const defaultGoroot = <goroot>
+// const theVersion = <version>
+//
+void
+mkzversion(char *dir, char *file)
+{
+ Buf b, out;
+
+ binit(&b);
+ binit(&out);
+
+ bwritestr(&out, bprintf(&b,
+ "// auto generated by go tool dist\n"
+ "\n"
+ "package runtime\n"
+ "\n"
+ "const defaultGoroot = `%s`\n"
+ "const theVersion = `%s`\n", goroot_final, goversion));
+
+ writefile(&out, file, 0);
+
+ bfree(&b);
+ bfree(&out);
+}
+
+// mkzgoarch writes zgoarch_$GOARCH.go:
+//
+// package runtime
+// const theGoarch = <goarch>
+//
+void
+mkzgoarch(char *dir, char *file)
+{
+ Buf b, out;
+
+ binit(&b);
+ binit(&out);
+
+ bwritestr(&out, bprintf(&b,
+ "// auto generated by go tool dist\n"
+ "\n"
+ "package runtime\n"
+ "\n"
+ "const theGoarch = `%s`\n", goarch));
+
+ writefile(&out, file, 0);
+
+ bfree(&b);
+ bfree(&out);
+}
+
+// mkzgoos writes zgoos_$GOOS.go:
+//
+// package runtime
+// const theGoos = <goos>
+//
+void
+mkzgoos(char *dir, char *file)
+{
+ Buf b, out;
+
+ binit(&b);
+ binit(&out);
+
+ bwritestr(&out, bprintf(&b,
+ "// auto generated by go tool dist\n"
+ "\n"
+ "package runtime\n"
+ "\n"
+ "const theGoos = `%s`\n", goos));
+
+ writefile(&out, file, 0);
+
+ bfree(&b);
+ bfree(&out);
+}
+
+static struct {
+ char *goarch;
+ char *goos;
+ char *hdr;
+} zasmhdr[] = {
+ {"386", "windows",
+ "#define get_tls(r) MOVL 0x14(FS), r\n"
+ "#define g(r) 0(r)\n"
+ "#define m(r) 4(r)\n"
+ },
+ {"386", "plan9",
+ "#define get_tls(r) MOVL _tos(SB), r \n"
+ "#define g(r) -8(r)\n"
+ "#define m(r) -4(r)\n"
+ },
+ {"386", "linux",
+ "// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n"
+ "// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n"
+ "// what the machine sees as opposed to 8l input).\n"
+ "// 8l rewrites 0(GS) and 4(GS) into these.\n"
+ "//\n"
+ "// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n"
+ "// directly. Instead, we have to store %gs:0 into a temporary\n"
+ "// register and then use -8(%reg) and -4(%reg). This kind\n"
+ "// of addressing is correct even when not running Xen.\n"
+ "//\n"
+ "// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n"
+ "// of mov instructions, using CX as the intermediate register\n"
+ "// (safe because CX is about to be written to anyway).\n"
+ "// But 8l cannot handle other instructions, like storing into 0(GS),\n"
+ "// which is where these macros come into play.\n"
+ "// get_tls sets up the temporary and then g and r use it.\n"
+ "//\n"
+ "// The final wrinkle is that get_tls needs to read from %gs:0,\n"
+ "// but in 8l input it's called 8(GS), because 8l is going to\n"
+ "// subtract 8 from all the offsets, as described above.\n"
+ "#define get_tls(r) MOVL 8(GS), r\n"
+ "#define g(r) -8(r)\n"
+ "#define m(r) -4(r)\n"
+ },
+ {"386", "",
+ "#define get_tls(r)\n"
+ "#define g(r) 0(GS)\n"
+ "#define m(r) 4(GS)\n"
+ },
+
+ {"amd64", "windows",
+ "#define get_tls(r) MOVQ 0x28(GS), r\n"
+ "#define g(r) 0(r)\n"
+ "#define m(r) 8(r)\n"
+ },
+ {"amd64", "",
+ "// The offsets 0 and 8 are known to:\n"
+ "// ../../cmd/6l/pass.c:/D_GS\n"
+ "// cgo/gcc_linux_amd64.c:/^threadentry\n"
+ "// cgo/gcc_darwin_amd64.c:/^threadentry\n"
+ "//\n"
+ "#define get_tls(r)\n"
+ "#define g(r) 0(GS)\n"
+ "#define m(r) 8(GS)\n"
+ },
+
+ {"arm", "",
+ "#define g R10\n"
+ "#define m R9\n"
+ "#define LR R14\n"
+ },
+};
+
+// mkzasm writes zasm_$GOOS_$GOARCH.h,
+// which contains struct offsets for use by
+// assembly files. It also writes a copy to the work space
+// under the name zasm_GOOS_GOARCH.h (no expansion).
+//
+void
+mkzasm(char *dir, char *file)
+{
+ int i, n;
+ char *aggr, *p;
+ Buf in, b, out;
+ Vec argv, lines, fields;
+
+ binit(&in);
+ binit(&b);
+ binit(&out);
+ vinit(&argv);
+ vinit(&lines);
+ vinit(&fields);
+
+ bwritestr(&out, "// auto generated by go tool dist\n\n");
+ for(i=0; i<nelem(zasmhdr); i++) {
+ if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
+ bwritestr(&out, zasmhdr[i].hdr);
+ goto ok;
+ }
+ }
+ fatal("unknown $GOOS/$GOARCH in mkzasm");
+ok:
+
+ // Run 6c -DGOOS_goos -DGOARCH_goarch -Iworkdir -a proc.c
+ // to get acid [sic] output.
+ vreset(&argv);
+ vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
+ vadd(&argv, bprintf(&b, "-DGOOS_%s", goos));
+ vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch));
+ vadd(&argv, bprintf(&b, "-I%s", workdir));
+ vadd(&argv, "-a");
+ vadd(&argv, "proc.c");
+ runv(&in, dir, CheckExit, &argv);
+
+ // Convert input like
+ // aggr G
+ // {
+ // Gobuf 24 sched;
+ // 'Y' 48 stack0;
+ // }
+ // into output like
+ // #define g_sched 24
+ // #define g_stack0 48
+ //
+ aggr = nil;
+ splitlines(&lines, bstr(&in));
+ for(i=0; i<lines.len; i++) {
+ splitfields(&fields, lines.p[i]);
+ if(fields.len == 2 && streq(fields.p[0], "aggr")) {
+ if(streq(fields.p[1], "G"))
+ aggr = "g";
+ else if(streq(fields.p[1], "M"))
+ aggr = "m";
+ else if(streq(fields.p[1], "Gobuf"))
+ aggr = "gobuf";
+ else if(streq(fields.p[1], "WinCall"))
+ aggr = "wincall";
+ }
+ if(hasprefix(lines.p[i], "}"))
+ aggr = nil;
+ if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) {
+ n = fields.len;
+ p = fields.p[n-1];
+ if(p[xstrlen(p)-1] == ';')
+ p[xstrlen(p)-1] = '\0';
+ bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2]));
+ }
+ }
+
+ // Write both to file and to workdir/zasm_GOOS_GOARCH.h.
+ writefile(&out, file, 0);
+ writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
+
+ bfree(&in);
+ bfree(&b);
+ bfree(&out);
+ vfree(&argv);
+ vfree(&lines);
+ vfree(&fields);
+}
+
+static char *runtimedefs[] = {
+ "proc.c",
+ "iface.c",
+ "hashmap.c",
+ "chan.c",
+};
+
+// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
+// which contains Go struct definitions equivalent to the C ones.
+// Mostly we just write the output of 6c -q to the file.
+// However, we run it on multiple files, so we have to delete
+// the duplicated definitions, and we don't care about the funcs
+// and consts, so we delete those too.
+//
+void
+mkzruntimedefs(char *dir, char *file)
+{
+ int i, skip;
+ char *p;
+ Buf in, b, out;
+ Vec argv, lines, fields, seen;
+
+ binit(&in);
+ binit(&b);
+ binit(&out);
+ vinit(&argv);
+ vinit(&lines);
+ vinit(&fields);
+ vinit(&seen);
+
+ bwritestr(&out, "// auto generated by go tool dist\n"
+ "\n"
+ "package runtime\n"
+ "import \"unsafe\"\n"
+ "var _ unsafe.Pointer\n"
+ "\n"
+ );
+
+
+ // Run 6c -DGOOS_goos -DGOARCH_goarch -Iworkdir -q
+ // on each of the runtimedefs C files.
+ vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
+ vadd(&argv, bprintf(&b, "-DGOOS_%s", goos));
+ vadd(&argv, bprintf(&b, "-DGOARCH_%s", goarch));
+ vadd(&argv, bprintf(&b, "-I%s", workdir));
+ vadd(&argv, "-q");
+ vadd(&argv, "");
+ p = argv.p[argv.len-1];
+ for(i=0; i<nelem(runtimedefs); i++) {
+ argv.p[argv.len-1] = runtimedefs[i];
+ runv(&b, dir, CheckExit, &argv);
+ bwriteb(&in, &b);
+ }
+ argv.p[argv.len-1] = p;
+
+ // Process the aggregate output.
+ skip = 0;
+ splitlines(&lines, bstr(&in));
+ for(i=0; i<lines.len; i++) {
+ p = lines.p[i];
+ // Drop comment, func, and const lines.
+ if(hasprefix(p, "//") || hasprefix(p, "const") || hasprefix(p, "func"))
+ continue;
+
+ // Note beginning of type or var decl, which can be multiline.
+ // Remove duplicates. The linear check of seen here makes the
+ // whole processing quadratic in aggregate, but there are only
+ // about 100 declarations, so this is okay (and simple).
+ if(hasprefix(p, "type ") || hasprefix(p, "var ")) {
+ splitfields(&fields, p);
+ if(fields.len < 2)
+ continue;
+ if(find(fields.p[1], seen.p, seen.len) >= 0) {
+ if(streq(fields.p[fields.len-1], "{"))
+ skip = 1; // skip until }
+ continue;
+ }
+ vadd(&seen, fields.p[1]);
+ }
+ if(skip) {
+ if(hasprefix(p, "}"))
+ skip = 0;
+ continue;
+ }
+
+ bwritestr(&out, p);
+ }
+
+ writefile(&out, file, 0);
+
+ bfree(&in);
+ bfree(&b);
+ bfree(&out);
+ vfree(&argv);
+ vfree(&lines);
+ vfree(&fields);
+ vfree(&seen);
+}
diff --git a/src/pkg/runtime/goc2c.c b/src/cmd/dist/goc2c.c
index 61236e226..22f72f8b5 100644
--- a/src/pkg/runtime/goc2c.c
+++ b/src/cmd/dist/goc2c.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include "a.h"
+
/*
* Translate a .goc file into a .c file. A .goc file is a combination
* of a limited form of Go with C.
@@ -20,9 +22,39 @@
* be called from Go and executes the C code.
*/
-#include <u.h>
-#include <stdio.h>
-#include <libc.h>
+static char *input;
+static Buf *output;
+#define EOF -1
+
+static int
+xgetchar(void)
+{
+ int c;
+
+ c = *input;
+ if(c == 0)
+ return EOF;
+ input++;
+ return c;
+}
+
+static void
+xungetc(void)
+{
+ input--;
+}
+
+static void
+xputchar(char c)
+{
+ bwrite(output, &c, 1);
+}
+
+static int
+xisspace(int c)
+{
+ return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+}
/* Whether we're emitting for gcc */
static int gcc;
@@ -57,29 +89,29 @@ static struct {
/* variable sized first, for easy replacement */
/* order matches enum above */
/* default is 32-bit architecture sizes */
- "bool", 1,
- "float", 4,
- "int", 4,
- "uint", 4,
- "uintptr", 4,
- "String", 8,
- "Slice", 12,
- "Eface", 8,
+ {"bool", 1},
+ {"float", 4},
+ {"int", 4},
+ {"uint", 4},
+ {"uintptr", 4},
+ {"String", 8},
+ {"Slice", 12},
+ {"Eface", 8},
/* fixed size */
- "float32", 4,
- "float64", 8,
- "byte", 1,
- "int8", 1,
- "uint8", 1,
- "int16", 2,
- "uint16", 2,
- "int32", 4,
- "uint32", 4,
- "int64", 8,
- "uint64", 8,
-
- NULL,
+ {"float32", 4},
+ {"float64", 8},
+ {"byte", 1},
+ {"int8", 1},
+ {"uint8", 1},
+ {"int16", 2},
+ {"uint16", 2},
+ {"int32", 4},
+ {"uint32", 4},
+ {"int64", 8},
+ {"uint64", 8},
+
+ {nil},
};
/* Fixed structure alignment (non-gcc only) */
@@ -89,47 +121,20 @@ int structround = 4;
static void
bad_eof(void)
{
- sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
-}
-
-/* Out of memory. */
-static void
-bad_mem(void)
-{
- sysfatal("%s:%ud: out of memory\n", file, lineno);
-}
-
-/* Allocate memory without fail. */
-static void *
-xmalloc(unsigned int size)
-{
- void *ret = malloc(size);
- if (ret == NULL)
- bad_mem();
- return ret;
-}
-
-/* Reallocate memory without fail. */
-static void*
-xrealloc(void *buf, unsigned int size)
-{
- void *ret = realloc(buf, size);
- if (ret == NULL)
- bad_mem();
- return ret;
+ fatal("%s:%ud: unexpected EOF\n", file, lineno);
}
/* Free a list of parameters. */
static void
free_params(struct params *p)
{
- while (p != NULL) {
+ while (p != nil) {
struct params *next;
next = p->next;
- free(p->name);
- free(p->type);
- free(p);
+ xfree(p->name);
+ xfree(p->type);
+ xfree(p);
p = next;
}
}
@@ -140,7 +145,7 @@ getchar_update_lineno(void)
{
int c;
- c = getchar();
+ c = xgetchar();
if (c == '\n')
++lineno;
return c;
@@ -169,7 +174,7 @@ getchar_skipping_comments(void)
if (c != '/')
return c;
- c = getchar();
+ c = xgetchar();
if (c == '/') {
do {
c = getchar_update_lineno();
@@ -189,35 +194,55 @@ getchar_skipping_comments(void)
}
}
} else {
- ungetc(c, stdin);
+ xungetc();
return '/';
}
}
}
/*
- * 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 string or character literals
+ * or else delimited by whitespace or by [(),{}].
+ * The latter are all returned as single characters.
*/
static char *
read_token(void)
{
- int c;
+ int c, q;
char *buf;
unsigned int alc, off;
- const char* delims = "(),{}";
+ char* delims = "(),{}";
while (1) {
c = getchar_skipping_comments();
if (c == EOF)
- return NULL;
- if (!isspace(c))
+ return nil;
+ if (!xisspace(c))
break;
}
alc = 16;
buf = xmalloc(alc + 1);
off = 0;
- if (strchr(delims, c) != NULL) {
+ if(c == '"' || c == '\'') {
+ q = c;
+ buf[off] = c;
+ ++off;
+ while (1) {
+ if (off+2 >= alc) { // room for c and maybe next char
+ alc *= 2;
+ buf = xrealloc(buf, alc + 1);
+ }
+ c = getchar_no_eof();
+ buf[off] = c;
+ ++off;
+ if(c == q)
+ break;
+ if(c == '\\') {
+ buf[off] = getchar_no_eof();
+ ++off;
+ }
+ }
+ } else if (xstrrchr(delims, c) != nil) {
buf[off] = c;
++off;
} else {
@@ -231,10 +256,10 @@ read_token(void)
c = getchar_skipping_comments();
if (c == EOF)
break;
- if (isspace(c) || strchr(delims, c) != NULL) {
+ if (xisspace(c) || xstrrchr(delims, c) != nil) {
if (c == '\n')
lineno--;
- ungetc(c, stdin);
+ xungetc();
break;
}
}
@@ -248,7 +273,7 @@ static char *
read_token_no_eof(void)
{
char *token = read_token();
- if (token == NULL)
+ if (token == nil)
bad_eof();
return token;
}
@@ -261,9 +286,9 @@ read_package(void)
token = read_token_no_eof();
if (token == nil)
- sysfatal("%s:%ud: no token\n", file, lineno);
- if (strcmp(token, "package") != 0) {
- sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
+ fatal("%s:%ud: no token\n", file, lineno);
+ if (!streq(token, "package")) {
+ fatal("%s:%ud: expected \"package\", got \"%s\"\n",
file, lineno, token);
}
return read_token_no_eof();
@@ -278,15 +303,15 @@ read_preprocessor_lines(void)
do {
c = getchar_skipping_comments();
- } while (isspace(c));
+ } while (xisspace(c));
if (c != '#') {
- ungetc(c, stdin);
+ xungetc();
break;
}
- putchar(c);
+ xputchar(c);
do {
c = getchar_update_lineno();
- putchar(c);
+ xputchar(c);
} while (c != '\n');
}
}
@@ -311,16 +336,16 @@ read_type(void)
++pointer_count;
++p;
}
- len = strlen(p);
+ len = xstrlen(p);
q = xmalloc(len + pointer_count + 1);
- memcpy(q, p, len);
+ xmemmove(q, p, len);
while (pointer_count > 0) {
q[len] = '*';
++len;
--pointer_count;
}
q[len] = '\0';
- free(op);
+ xfree(op);
return q;
}
@@ -330,13 +355,13 @@ type_size(char *p)
{
int i;
- if(p[strlen(p)-1] == '*')
+ if(p[xstrlen(p)-1] == '*')
return type_table[Uintptr].size;
for(i=0; type_table[i].name; i++)
- if(strcmp(type_table[i].name, p) == 0)
+ if(streq(type_table[i].name, p))
return type_table[i].size;
- sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
+ fatal("%s:%ud: unknown type %s\n", file, lineno, p);
return 0;
}
@@ -351,16 +376,16 @@ read_params(int *poffset)
struct params *ret, **pp, *p;
int offset, size, rnd;
- ret = NULL;
+ ret = nil;
pp = &ret;
token = read_token_no_eof();
offset = 0;
- if (strcmp(token, ")") != 0) {
+ if (!streq(token, ")")) {
while (1) {
p = xmalloc(sizeof(struct params));
p->name = token;
p->type = read_type();
- p->next = NULL;
+ p->next = nil;
*pp = p;
pp = &p->next;
@@ -373,16 +398,16 @@ read_params(int *poffset)
offset += size;
token = read_token_no_eof();
- if (strcmp(token, ",") != 0)
+ if (!streq(token, ","))
break;
token = read_token_no_eof();
}
}
- if (strcmp(token, ")") != 0) {
- sysfatal("%s:%ud: expected '('\n",
+ if (!streq(token, ")")) {
+ fatal("%s:%ud: expected '('\n",
file, lineno);
}
- if (poffset != NULL)
+ if (poffset != nil)
*poffset = offset;
return ret;
}
@@ -400,41 +425,41 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
lastline = -1;
while (1) {
token = read_token();
- if (token == NULL)
+ if (token == nil)
return 0;
- if (strcmp(token, "func") == 0) {
+ if (streq(token, "func")) {
if(lastline != -1)
- printf("\n");
+ bwritef(output, "\n");
break;
}
if (lastline != lineno) {
if (lastline == lineno-1)
- printf("\n");
+ bwritef(output, "\n");
else
- printf("\n#line %d \"%s\"\n", lineno, file);
+ bwritef(output, "\n#line %d \"%s\"\n", lineno, file);
lastline = lineno;
}
- printf("%s ", token);
+ bwritef(output, "%s ", token);
}
*name = read_token_no_eof();
token = read_token();
- if (token == NULL || strcmp(token, "(") != 0) {
- sysfatal("%s:%ud: expected \"(\"\n",
+ if (token == nil || !streq(token, "(")) {
+ fatal("%s:%ud: expected \"(\"\n",
file, lineno);
}
*params = read_params(paramwid);
token = read_token();
- if (token == NULL || strcmp(token, "(") != 0)
- *rets = NULL;
+ if (token == nil || !streq(token, "("))
+ *rets = nil;
else {
- *rets = read_params(NULL);
+ *rets = read_params(nil);
token = read_token();
}
- if (token == NULL || strcmp(token, "{") != 0) {
- sysfatal("%s:%ud: expected \"{\"\n",
+ if (token == nil || !streq(token, "{")) {
+ fatal("%s:%ud: expected \"{\"\n",
file, lineno);
}
return 1;
@@ -446,12 +471,12 @@ write_params(struct params *params, int *first)
{
struct params *p;
- for (p = params; p != NULL; p = p->next) {
+ for (p = params; p != nil; p = p->next) {
if (*first)
*first = 0;
else
- printf(", ");
- printf("%s %s", p->type, p->name);
+ bwritef(output, ", ");
+ bwritef(output, "%s %s", p->type, p->name);
}
}
@@ -462,23 +487,23 @@ write_6g_func_header(char *package, char *name, struct params *params,
{
int first, n;
- printf("void\n%s·%s(", package, name);
+ bwritef(output, "void\n%s·%s(", package, name);
first = 1;
write_params(params, &first);
/* insert padding to align output struct */
- if(rets != NULL && paramwid%structround != 0) {
+ if(rets != nil && paramwid%structround != 0) {
n = structround - paramwid%structround;
if(n & 1)
- printf(", uint8");
+ bwritef(output, ", uint8");
if(n & 2)
- printf(", uint16");
+ bwritef(output, ", uint16");
if(n & 4)
- printf(", uint32");
+ bwritef(output, ", uint32");
}
write_params(rets, &first);
- printf(")\n{\n");
+ bwritef(output, ")\n{\n");
}
/* Write a 6g function trailer. */
@@ -487,9 +512,9 @@ write_6g_func_trailer(struct params *rets)
{
struct params *p;
- for (p = rets; p != NULL; p = p->next)
- printf("\tFLUSH(&%s);\n", p->name);
- printf("}\n");
+ for (p = rets; p != nil; p = p->next)
+ bwritef(output, "\tFLUSH(&%s);\n", p->name);
+ bwritef(output, "}\n");
}
/* Define the gcc function return type if necessary. */
@@ -498,24 +523,24 @@ define_gcc_return_type(char *package, char *name, struct params *rets)
{
struct params *p;
- if (rets == NULL || rets->next == NULL)
+ if (rets == nil || rets->next == nil)
return;
- printf("struct %s_%s_ret {\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
- printf("};\n");
+ bwritef(output, "struct %s_%s_ret {\n", package, name);
+ for (p = rets; p != nil; p = p->next)
+ bwritef(output, " %s %s;\n", p->type, p->name);
+ bwritef(output, "};\n");
}
/* Write out the gcc function return type. */
static void
write_gcc_return_type(char *package, char *name, struct params *rets)
{
- if (rets == NULL)
- printf("void");
- else if (rets->next == NULL)
- printf("%s", rets->type);
+ if (rets == nil)
+ bwritef(output, "void");
+ else if (rets->next == nil)
+ bwritef(output, "%s", rets->type);
else
- printf("struct %s_%s_ret", package, name);
+ bwritef(output, "struct %s_%s_ret", package, name);
}
/* Write out a gcc function header. */
@@ -528,36 +553,36 @@ write_gcc_func_header(char *package, char *name, struct params *params,
define_gcc_return_type(package, name, rets);
write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
+ bwritef(output, " %s_%s(", package, name);
first = 1;
write_params(params, &first);
- printf(") asm (\"%s.%s\");\n", package, name);
+ bwritef(output, ") asm (\"%s.%s\");\n", package, name);
write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
+ bwritef(output, " %s_%s(", package, name);
first = 1;
write_params(params, &first);
- printf(")\n{\n");
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
+ bwritef(output, ")\n{\n");
+ for (p = rets; p != nil; p = p->next)
+ bwritef(output, " %s %s;\n", p->type, p->name);
}
/* Write out a gcc function trailer. */
static void
write_gcc_func_trailer(char *package, char *name, struct params *rets)
{
- if (rets == NULL)
+ if (rets == nil)
;
- else if (rets->next == NULL)
- printf("return %s;\n", rets->name);
+ else if (rets->next == nil)
+ bwritef(output, "return %s;\n", rets->name);
else {
struct params *p;
- printf(" {\n struct %s_%s_ret __ret;\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" __ret.%s = %s;\n", p->name, p->name);
- printf(" return __ret;\n }\n");
+ bwritef(output, " {\n struct %s_%s_ret __ret;\n", package, name);
+ for (p = rets; p != nil; p = p->next)
+ bwritef(output, " __ret.%s = %s;\n", p->name, p->name);
+ bwritef(output, " return __ret;\n }\n");
}
- printf("}\n");
+ bwritef(output, "}\n");
}
/* Write out a function header. */
@@ -570,7 +595,7 @@ write_func_header(char *package, char *name,
write_gcc_func_header(package, name, params, rets);
else
write_6g_func_header(package, name, params, paramwid, rets);
- printf("#line %d \"%s\"\n", lineno, file);
+ bwritef(output, "#line %d \"%s\"\n", lineno, file);
}
/* Write out a function trailer. */
@@ -598,7 +623,7 @@ copy_body(void)
c = getchar_no_eof();
if (c == '}' && nesting == 0)
return;
- putchar(c);
+ xputchar(c);
switch (c) {
default:
break;
@@ -610,20 +635,20 @@ copy_body(void)
break;
case '/':
c = getchar_update_lineno();
- putchar(c);
+ xputchar(c);
if (c == '/') {
do {
c = getchar_no_eof();
- putchar(c);
+ xputchar(c);
} while (c != '\n');
} else if (c == '*') {
while (1) {
c = getchar_no_eof();
- putchar(c);
+ xputchar(c);
if (c == '*') {
do {
c = getchar_no_eof();
- putchar(c);
+ xputchar(c);
} while (c == '*');
if (c == '/')
break;
@@ -637,10 +662,10 @@ copy_body(void)
int delim = c;
do {
c = getchar_no_eof();
- putchar(c);
+ xputchar(c);
if (c == '\\') {
c = getchar_no_eof();
- putchar(c);
+ xputchar(c);
c = '\0';
}
} while (c != delim);
@@ -664,64 +689,47 @@ process_file(void)
write_func_header(package, name, params, paramwid, rets);
copy_body();
write_func_trailer(package, name, rets);
- free(name);
+ xfree(name);
free_params(params);
free_params(rets);
}
- free(package);
-}
-
-static void
-usage(void)
-{
- sysfatal("Usage: goc2c [--6g | --gc] [file]\n");
+ xfree(package);
}
void
-main(int argc, char **argv)
+goc2c(char *goc, char *c)
{
- char *goarch;
-
- argv0 = argv[0];
- while(argc > 1 && argv[1][0] == '-') {
- if(strcmp(argv[1], "-") == 0)
- break;
- if(strcmp(argv[1], "--6g") == 0)
- gcc = 0;
- else if(strcmp(argv[1], "--gcc") == 0)
- gcc = 1;
- else
- usage();
- argc--;
- argv++;
- }
-
- if(argc <= 1 || strcmp(argv[1], "-") == 0) {
- file = "<stdin>";
- process_file();
- exits(0);
- }
+ Buf in, out;
+
+ binit(&in);
+ binit(&out);
+
+ file = goc;
+ readfile(&in, goc);
- if(argc > 2)
- usage();
-
- file = argv[1];
- if(freopen(file, "r", stdin) == 0) {
- sysfatal("open %s: %r\n", file);
- }
+ // TODO: set gcc=1 when using gcc
if(!gcc) {
- // 6g etc; update size table
- goarch = getenv("GOARCH");
- if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
+ if(streq(goarch, "amd64")) {
type_table[Uintptr].size = 8;
type_table[String].size = 16;
type_table[Slice].size = 8+4+4;
type_table[Eface].size = 8+8;
structround = 8;
+ } else {
+ type_table[Uintptr].size = 4;
+ type_table[String].size = 8;
+ type_table[Slice].size = 16;
+ type_table[Eface].size = 4+4;
+ structround = 4;
}
}
+ bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
+ input = bstr(&in);
+ output = &out;
+
process_file();
- exits(0);
+
+ writefile(&out, c, 0);
}
diff --git a/src/cmd/dist/main.c b/src/cmd/dist/main.c
new file mode 100644
index 000000000..72a7579d1
--- /dev/null
+++ b/src/cmd/dist/main.c
@@ -0,0 +1,41 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "a.h"
+
+int vflag;
+char *argv0;
+
+// cmdtab records the available commands.
+static struct {
+ char *name;
+ void (*f)(int, char**);
+} cmdtab[] = {
+ {"banner", cmdbanner},
+ {"bootstrap", cmdbootstrap},
+ {"clean", cmdclean},
+ {"env", cmdenv},
+ {"install", cmdinstall},
+ {"version", cmdversion},
+};
+
+// The OS-specific main calls into the portable code here.
+void
+xmain(int argc, char **argv)
+{
+ int i;
+
+ if(argc <= 1)
+ usage();
+
+ for(i=0; i<nelem(cmdtab); i++) {
+ if(streq(cmdtab[i].name, argv[1])) {
+ cmdtab[i].f(argc-1, argv+1);
+ return;
+ }
+ }
+
+ xprintf("unknown command %s\n", argv[1]);
+ usage();
+}
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
new file mode 100644
index 000000000..e6d82e14e
--- /dev/null
+++ b/src/cmd/dist/unix.c
@@ -0,0 +1,720 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// These #ifdefs are being used as a substitute for
+// build configuration, so that on any system, this
+// tool can be built with the local equivalent of
+// cc *.c
+//
+#ifndef WIN32
+#ifndef PLAN9
+
+#include "a.h"
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+// bprintf replaces the buffer with the result of the printf formatting
+// and returns a pointer to the NUL-terminated buffer contents.
+char*
+bprintf(Buf *b, char *fmt, ...)
+{
+ va_list arg;
+ char buf[4096];
+
+ breset(b);
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+ return bstr(b);
+}
+
+// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
+// It returns a pointer to the NUL-terminated buffer contents.
+char*
+bpathf(Buf *b, char *fmt, ...)
+{
+ va_list arg;
+ char buf[4096];
+
+ breset(b);
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+ return bstr(b);
+}
+
+// bwritef is like bprintf but does not reset the buffer
+// and does not return the NUL-terminated string.
+void
+bwritef(Buf *b, char *fmt, ...)
+{
+ va_list arg;
+ char buf[4096];
+
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+}
+
+// breadfrom appends to b all the data that can be read from fd.
+static void
+breadfrom(Buf *b, int fd)
+{
+ int n;
+
+ for(;;) {
+ bgrow(b, 4096);
+ n = read(fd, b->p+b->len, 4096);
+ if(n < 0)
+ fatal("read: %s", strerror(errno));
+ if(n == 0)
+ break;
+ b->len += n;
+ }
+}
+
+// xgetenv replaces b with the value of the named environment variable.
+void
+xgetenv(Buf *b, char *name)
+{
+ char *p;
+
+ breset(b);
+ p = getenv(name);
+ if(p != NULL)
+ bwritestr(b, p);
+}
+
+static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
+
+// run runs the command named by cmd.
+// If b is not nil, run replaces b with the output of the command.
+// If dir is not nil, run runs the command in that directory.
+// If mode is CheckExit, run calls fatal if the command is not successful.
+void
+run(Buf *b, char *dir, int mode, char *cmd, ...)
+{
+ va_list arg;
+ Vec argv;
+ char *p;
+
+ vinit(&argv);
+ vadd(&argv, cmd);
+ va_start(arg, cmd);
+ while((p = va_arg(arg, char*)) != nil)
+ vadd(&argv, p);
+ va_end(arg);
+
+ runv(b, dir, mode, &argv);
+
+ vfree(&argv);
+}
+
+// runv is like run but takes a vector.
+void
+runv(Buf *b, char *dir, int mode, Vec *argv)
+{
+ genrun(b, dir, mode, argv, 1);
+}
+
+// bgrunv is like run but runs the command in the background.
+// bgwait waits for pending bgrunv to finish.
+void
+bgrunv(char *dir, int mode, Vec *argv)
+{
+ genrun(nil, dir, mode, argv, 0);
+}
+
+#define MAXBG 4 /* maximum number of jobs to run at once */
+
+static struct {
+ int pid;
+ int mode;
+ char *cmd;
+ Buf *b;
+} bg[MAXBG];
+static int nbg;
+static int maxnbg = nelem(bg);
+
+static void bgwait1(void);
+
+// genrun is the generic run implementation.
+static void
+genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
+{
+ int i, p[2], pid;
+ Buf cmd;
+ char *q;
+
+ while(nbg >= maxnbg)
+ bgwait1();
+
+ // Generate a copy of the command to show in a log.
+ // Substitute $WORK for the work directory.
+ binit(&cmd);
+ for(i=0; i<argv->len; i++) {
+ if(i > 0)
+ bwritestr(&cmd, " ");
+ q = argv->p[i];
+ if(workdir != nil && hasprefix(q, workdir)) {
+ bwritestr(&cmd, "$WORK");
+ q += strlen(workdir);
+ }
+ bwritestr(&cmd, q);
+ }
+ if(vflag > 1)
+ xprintf("%s\n", bstr(&cmd));
+
+ if(b != nil) {
+ breset(b);
+ if(pipe(p) < 0)
+ fatal("pipe: %s", strerror(errno));
+ }
+
+ switch(pid = fork()) {
+ case -1:
+ fatal("fork: %s", strerror(errno));
+ case 0:
+ if(b != nil) {
+ close(0);
+ close(p[0]);
+ dup2(p[1], 1);
+ dup2(p[1], 2);
+ if(p[1] > 2)
+ close(p[1]);
+ }
+ if(dir != nil) {
+ if(chdir(dir) < 0) {
+ fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
+ _exit(1);
+ }
+ }
+ vadd(argv, nil);
+ execvp(argv->p[0], argv->p);
+ fprintf(stderr, "%s\n", bstr(&cmd));
+ fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
+ _exit(1);
+ }
+ if(b != nil) {
+ close(p[1]);
+ breadfrom(b, p[0]);
+ close(p[0]);
+ }
+
+ if(nbg < 0)
+ fatal("bad bookkeeping");
+ bg[nbg].pid = pid;
+ bg[nbg].mode = mode;
+ bg[nbg].cmd = btake(&cmd);
+ bg[nbg].b = b;
+ nbg++;
+
+ if(wait)
+ bgwait();
+
+ bfree(&cmd);
+}
+
+// bgwait1 waits for a single background job.
+static void
+bgwait1(void)
+{
+ int i, pid, status, mode;
+ char *cmd;
+ Buf *b;
+
+ errno = 0;
+ while((pid = wait(&status)) < 0) {
+ if(errno != EINTR)
+ fatal("waitpid: %s", strerror(errno));
+ }
+ for(i=0; i<nbg; i++)
+ if(bg[i].pid == pid)
+ goto ok;
+ fatal("waitpid: unexpected pid");
+
+ok:
+ cmd = bg[i].cmd;
+ mode = bg[i].mode;
+ bg[i].pid = 0;
+ b = bg[i].b;
+ bg[i].b = nil;
+ bg[i] = bg[--nbg];
+
+ if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
+ if(b != nil)
+ xprintf("%s\n", bstr(b));
+ fatal("FAILED: %s", cmd);
+ }
+ xfree(cmd);
+}
+
+// bgwait waits for all the background jobs.
+void
+bgwait(void)
+{
+ while(nbg > 0)
+ bgwait1();
+}
+
+// xgetwd replaces b with the current directory.
+void
+xgetwd(Buf *b)
+{
+ char buf[MAXPATHLEN];
+
+ breset(b);
+ if(getcwd(buf, MAXPATHLEN) == nil)
+ fatal("getcwd: %s", strerror(errno));
+ bwritestr(b, buf);
+}
+
+// xrealwd replaces b with the 'real' name for the given path.
+// real is defined as what getcwd returns in that directory.
+void
+xrealwd(Buf *b, char *path)
+{
+ int fd;
+
+ fd = open(".", 0);
+ if(fd < 0)
+ fatal("open .: %s", strerror(errno));
+ if(chdir(path) < 0)
+ fatal("chdir %s: %s", path, strerror(errno));
+ xgetwd(b);
+ if(fchdir(fd) < 0)
+ fatal("fchdir: %s", strerror(errno));
+ close(fd);
+}
+
+// isdir reports whether p names an existing directory.
+bool
+isdir(char *p)
+{
+ struct stat st;
+
+ return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
+}
+
+// isfile reports whether p names an existing file.
+bool
+isfile(char *p)
+{
+ struct stat st;
+
+ return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
+}
+
+// mtime returns the modification time of the file p.
+Time
+mtime(char *p)
+{
+ struct stat st;
+
+ if(stat(p, &st) < 0)
+ return 0;
+ return (Time)st.st_mtime*1000000000LL;
+}
+
+// isabs reports whether p is an absolute path.
+bool
+isabs(char *p)
+{
+ return hasprefix(p, "/");
+}
+
+// readfile replaces b with the content of the named file.
+void
+readfile(Buf *b, char *file)
+{
+ int fd;
+
+ breset(b);
+ fd = open(file, 0);
+ if(fd < 0)
+ fatal("open %s: %s", file, strerror(errno));
+ breadfrom(b, fd);
+ close(fd);
+}
+
+// writefile writes b to the named file, creating it if needed. if
+// exec is non-zero, marks the file as executable.
+void
+writefile(Buf *b, char *file, int exec)
+{
+ int fd;
+
+ fd = creat(file, 0666);
+ if(fd < 0)
+ fatal("create %s: %s", file, strerror(errno));
+ if(write(fd, b->p, b->len) != b->len)
+ fatal("short write: %s", strerror(errno));
+ if(exec)
+ fchmod(fd, 0755);
+ close(fd);
+}
+
+// xmkdir creates the directory p.
+void
+xmkdir(char *p)
+{
+ if(mkdir(p, 0777) < 0)
+ fatal("mkdir %s: %s", p, strerror(errno));
+}
+
+// xmkdirall creates the directory p and its parents, as needed.
+void
+xmkdirall(char *p)
+{
+ char *q;
+
+ if(isdir(p))
+ return;
+ q = strrchr(p, '/');
+ if(q != nil) {
+ *q = '\0';
+ xmkdirall(p);
+ *q = '/';
+ }
+ xmkdir(p);
+}
+
+// xremove removes the file p.
+void
+xremove(char *p)
+{
+ if(vflag > 2)
+ xprintf("rm %s\n", p);
+ unlink(p);
+}
+
+// xremoveall removes the file or directory tree rooted at p.
+void
+xremoveall(char *p)
+{
+ int i;
+ Buf b;
+ Vec dir;
+
+ binit(&b);
+ vinit(&dir);
+
+ if(isdir(p)) {
+ xreaddir(&dir, p);
+ for(i=0; i<dir.len; i++) {
+ bprintf(&b, "%s/%s", p, dir.p[i]);
+ xremoveall(bstr(&b));
+ }
+ if(vflag > 2)
+ xprintf("rm %s\n", p);
+ rmdir(p);
+ } else {
+ if(vflag > 2)
+ xprintf("rm %s\n", p);
+ unlink(p);
+ }
+
+ bfree(&b);
+ vfree(&dir);
+}
+
+// xreaddir replaces dst with a list of the names of the files in dir.
+// The names are relative to dir; they are not full paths.
+void
+xreaddir(Vec *dst, char *dir)
+{
+ DIR *d;
+ struct dirent *dp;
+
+ vreset(dst);
+ d = opendir(dir);
+ if(d == nil)
+ fatal("opendir %s: %s", dir, strerror(errno));
+ while((dp = readdir(d)) != nil) {
+ if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+ continue;
+ vadd(dst, dp->d_name);
+ }
+ closedir(d);
+}
+
+// xworkdir creates a new temporary directory to hold object files
+// and returns the name of that directory.
+char*
+xworkdir(void)
+{
+ Buf b;
+ char *p;
+
+ binit(&b);
+
+ xgetenv(&b, "TMPDIR");
+ if(b.len == 0)
+ bwritestr(&b, "/var/tmp");
+ bwritestr(&b, "/go-cbuild-XXXXXX");
+ if(mkdtemp(bstr(&b)) == nil)
+ fatal("mkdtemp: %s", strerror(errno));
+ p = btake(&b);
+
+ bfree(&b);
+
+ return p;
+}
+
+// fatal prints an error message to standard error and exits.
+void
+fatal(char *msg, ...)
+{
+ va_list arg;
+
+ fflush(stdout);
+ fprintf(stderr, "go tool dist: ");
+ va_start(arg, msg);
+ vfprintf(stderr, msg, arg);
+ va_end(arg);
+ fprintf(stderr, "\n");
+
+ bgwait();
+ exit(1);
+}
+
+// xmalloc returns a newly allocated zeroed block of n bytes of memory.
+// It calls fatal if it runs out of memory.
+void*
+xmalloc(int n)
+{
+ void *p;
+
+ p = malloc(n);
+ if(p == nil)
+ fatal("out of memory");
+ memset(p, 0, n);
+ return p;
+}
+
+// xstrdup returns a newly allocated copy of p.
+// It calls fatal if it runs out of memory.
+char*
+xstrdup(char *p)
+{
+ p = strdup(p);
+ if(p == nil)
+ fatal("out of memory");
+ return p;
+}
+
+// xrealloc grows the allocation p to n bytes and
+// returns the new (possibly moved) pointer.
+// It calls fatal if it runs out of memory.
+void*
+xrealloc(void *p, int n)
+{
+ p = realloc(p, n);
+ if(p == nil)
+ fatal("out of memory");
+ return p;
+}
+
+// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
+void
+xfree(void *p)
+{
+ free(p);
+}
+
+// hassuffix reports whether p ends with suffix.
+bool
+hassuffix(char *p, char *suffix)
+{
+ int np, ns;
+
+ np = strlen(p);
+ ns = strlen(suffix);
+ return np >= ns && strcmp(p+np-ns, suffix) == 0;
+}
+
+// hasprefix reports whether p begins wtih prefix.
+bool
+hasprefix(char *p, char *prefix)
+{
+ return strncmp(p, prefix, strlen(prefix)) == 0;
+}
+
+// contains reports whether sep appears in p.
+bool
+contains(char *p, char *sep)
+{
+ return strstr(p, sep) != nil;
+}
+
+// streq reports whether p and q are the same string.
+bool
+streq(char *p, char *q)
+{
+ return strcmp(p, q) == 0;
+}
+
+// lastelem returns the final path element in p.
+char*
+lastelem(char *p)
+{
+ char *out;
+
+ out = p;
+ for(; *p; p++)
+ if(*p == '/')
+ out = p+1;
+ return out;
+}
+
+// xmemmove copies n bytes from src to dst.
+void
+xmemmove(void *dst, void *src, int n)
+{
+ memmove(dst, src, n);
+}
+
+// xmemcmp compares the n-byte regions starting at a and at b.
+int
+xmemcmp(void *a, void *b, int n)
+{
+ return memcmp(a, b, n);
+}
+
+// xstrlen returns the length of the NUL-terminated string at p.
+int
+xstrlen(char *p)
+{
+ return strlen(p);
+}
+
+// xexit exits the process with return code n.
+void
+xexit(int n)
+{
+ exit(n);
+}
+
+// xatexit schedules the exit-handler f to be run when the program exits.
+void
+xatexit(void (*f)(void))
+{
+ atexit(f);
+}
+
+// xprintf prints a message to standard output.
+void
+xprintf(char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vprintf(fmt, arg);
+ va_end(arg);
+}
+
+// xsetenv sets the environment variable $name to the given value.
+void
+xsetenv(char *name, char *value)
+{
+ setenv(name, value, 1);
+}
+
+// main takes care of OS-specific startup and dispatches to xmain.
+int
+main(int argc, char **argv)
+{
+ Buf b;
+ struct utsname u;
+
+ setvbuf(stdout, nil, _IOLBF, 0);
+ setvbuf(stderr, nil, _IOLBF, 0);
+
+ binit(&b);
+
+ slash = "/";
+
+#if defined(__APPLE__)
+ gohostos = "darwin";
+ // Even on 64-bit platform, darwin uname -m prints i386.
+ run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
+ if(contains(bstr(&b), "EM64T"))
+ gohostarch = "amd64";
+#elif defined(__linux__)
+ gohostos = "linux";
+#elif defined(__FreeBSD__)
+ gohostos = "freebsd";
+#elif defined(__OpenBSD__)
+ gohostos = "openbsd";
+#elif defined(__NetBSD__)
+ gohostos = "netbsd";
+#else
+ fatal("unknown operating system");
+#endif
+
+ if(gohostarch == nil) {
+ if(uname(&u) < 0)
+ fatal("uname: %s", strerror(errno));
+ if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
+ gohostarch = "amd64";
+ else if(hassuffix(u.machine, "86"))
+ gohostarch = "386";
+ else if(contains(u.machine, "arm"))
+ gohostarch = "arm";
+ else
+ fatal("unknown architecture: %s", u.machine);
+ }
+
+ if(strcmp(gohostarch, "arm") == 0)
+ maxnbg = 1;
+
+ init();
+ xmain(argc, argv);
+ bfree(&b);
+ return 0;
+}
+
+// xqsort is a wrapper for the C standard qsort.
+void
+xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
+{
+ qsort(data, n, elemsize, cmp);
+}
+
+// xstrcmp compares the NUL-terminated strings a and b.
+int
+xstrcmp(char *a, char *b)
+{
+ return strcmp(a, b);
+}
+
+// xstrstr returns a pointer to the first occurrence of b in a.
+char*
+xstrstr(char *a, char *b)
+{
+ return strstr(a, b);
+}
+
+// xstrrchr returns a pointer to the final occurrence of c in p.
+char*
+xstrrchr(char *p, int c)
+{
+ return strrchr(p, c);
+}
+
+#endif // PLAN9
+#endif // __WINDOWS__
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
new file mode 100644
index 000000000..557e4b003
--- /dev/null
+++ b/src/cmd/dist/windows.c
@@ -0,0 +1,910 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// These #ifdefs are being used as a substitute for
+// build configuration, so that on any system, this
+// tool can be built with the local equivalent of
+// cc *.c
+//
+#ifdef WIN32
+
+// Portability layer implemented for Windows.
+// See unix.c for doc comments about exported functions.
+
+#include "a.h"
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/*
+ * Windows uses 16-bit rune strings in the APIs.
+ * Define conversions between Rune* and UTF-8 char*.
+ */
+
+typedef unsigned char uchar;
+typedef unsigned short Rune; // same as Windows
+
+// encoderune encodes the rune r into buf and returns
+// the number of bytes used.
+static int
+encoderune(char *buf, Rune r)
+{
+ if(r < 0x80) { // 7 bits
+ buf[0] = r;
+ return 1;
+ }
+ if(r < 0x800) { // 5+6 bits
+ buf[0] = 0xc0 | (r>>6);
+ buf[1] = 0x80 | (r&0x3f);
+ return 2;
+ }
+ buf[0] = 0xe0 | (r>>12);
+ buf[1] = 0x80 | ((r>>6)&0x3f);
+ buf[2] = 0x80 | (r&0x3f);
+ return 3;
+}
+
+// decoderune decodes the rune encoding at sbuf into r
+// and returns the number of bytes used.
+static int
+decoderune(Rune *r, char *sbuf)
+{
+ uchar *buf;
+
+ buf = (uchar*)sbuf;
+ if(buf[0] < 0x80) {
+ *r = buf[0];
+ return 1;
+ }
+ if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
+ *r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
+ if(*r < 0x80)
+ goto err;
+ return 2;
+ }
+ if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
+ *r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
+ if(*r < 0x800)
+ goto err;
+ return 3;
+ }
+err:
+ *r = 0xfffd;
+ return 1;
+}
+
+// toutf replaces b with the UTF-8 encoding of the rune string r.
+static void
+toutf(Buf *b, Rune *r)
+{
+ int i, n;
+ char buf[4];
+
+ breset(b);
+ for(i=0; r[i]; i++) {
+ n = encoderune(buf, r[i]);
+ bwrite(b, buf, n);
+ }
+}
+
+// torune replaces *rp with a pointer to a newly allocated
+// rune string equivalent of the UTF-8 string p.
+static void
+torune(Rune **rp, char *p)
+{
+ Rune *r, *w;
+
+ r = xmalloc((strlen(p)+1) * sizeof r[0]);
+ w = r;
+ while(*p)
+ p += decoderune(w++, p);
+ *w = 0;
+ *rp = r;
+}
+
+// errstr returns the most recent Windows error, in string form.
+static char*
+errstr(void)
+{
+ DWORD code;
+ Rune *r;
+ Buf b;
+
+ binit(&b);
+ code = GetLastError();
+ r = nil;
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+ nil, code, 0, (Rune*)&r, 0, nil);
+ toutf(&b, r);
+ return bstr(&b); // leak but we're dying anyway
+}
+
+void
+xgetenv(Buf *b, char *name)
+{
+ Rune *buf;
+ int n;
+ Rune *r;
+
+ breset(b);
+ torune(&r, name);
+ n = GetEnvironmentVariableW(r, NULL, 0);
+ if(n > 0) {
+ buf = xmalloc((n+1)*sizeof buf[0]);
+ GetEnvironmentVariableW(r, buf, n+1);
+ buf[n] = '\0';
+ toutf(b, buf);
+ xfree(buf);
+ }
+ xfree(r);
+}
+
+void
+xsetenv(char *name, char *value)
+{
+ Rune *rname, *rvalue;
+
+ torune(&rname, name);
+ torune(&rvalue, value);
+ SetEnvironmentVariableW(rname, rvalue);
+ xfree(rname);
+ xfree(rvalue);
+}
+
+char*
+bprintf(Buf *b, char *fmt, ...)
+{
+ va_list arg;
+ char buf[4096];
+
+ breset(b);
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+ return bstr(b);
+}
+
+void
+bwritef(Buf *b, char *fmt, ...)
+{
+ va_list arg;
+ char buf[4096];
+
+ // no reset
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+}
+
+// bpathf is like bprintf but replaces / with \ in the result,
+// to make it a canonical windows file path.
+char*
+bpathf(Buf *b, char *fmt, ...)
+{
+ int i;
+ va_list arg;
+ char buf[4096];
+
+ breset(b);
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+ bwritestr(b, buf);
+
+ for(i=0; i<b->len; i++)
+ if(b->p[i] == '/')
+ b->p[i] = '\\';
+
+ return bstr(b);
+}
+
+
+static void
+breadfrom(Buf *b, HANDLE h)
+{
+ DWORD n;
+
+ for(;;) {
+ if(b->len > 1<<22)
+ fatal("unlikely file size in readfrom");
+ bgrow(b, 4096);
+ n = 0;
+ if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
+ // Happens for pipe reads.
+ break;
+ }
+ if(n == 0)
+ break;
+ b->len += n;
+ }
+}
+
+void
+run(Buf *b, char *dir, int mode, char *cmd, ...)
+{
+ va_list arg;
+ Vec argv;
+ char *p;
+
+ vinit(&argv);
+ vadd(&argv, cmd);
+ va_start(arg, cmd);
+ while((p = va_arg(arg, char*)) != nil)
+ vadd(&argv, p);
+ va_end(arg);
+
+ runv(b, dir, mode, &argv);
+
+ vfree(&argv);
+}
+
+static void genrun(Buf*, char*, int, Vec*, int);
+
+void
+runv(Buf *b, char *dir, int mode, Vec *argv)
+{
+ genrun(b, dir, mode, argv, 1);
+}
+
+void
+bgrunv(char *dir, int mode, Vec *argv)
+{
+ genrun(nil, dir, mode, argv, 0);
+}
+
+#define MAXBG 4 /* maximum number of jobs to run at once */
+
+static struct {
+ PROCESS_INFORMATION pi;
+ int mode;
+ char *cmd;
+} bg[MAXBG];
+
+static int nbg;
+
+static void bgwait1(void);
+
+static void
+genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
+{
+ int i, j, nslash;
+ Buf cmd;
+ char *q;
+ Rune *rcmd, *rexe, *rdir;
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ HANDLE p[2];
+
+ while(nbg >= nelem(bg))
+ bgwait1();
+
+ binit(&cmd);
+
+ for(i=0; i<argv->len; i++) {
+ if(i > 0)
+ bwritestr(&cmd, " ");
+ q = argv->p[i];
+ if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
+ bwritestr(&cmd, "\"");
+ nslash = 0;
+ for(; *q; q++) {
+ if(*q == '\\') {
+ nslash++;
+ continue;
+ }
+ if(*q == '"') {
+ for(j=0; j<2*nslash+1; j++)
+ bwritestr(&cmd, "\\");
+ nslash = 0;
+ }
+ for(j=0; j<nslash; j++)
+ bwritestr(&cmd, "\\");
+ nslash = 0;
+ bwrite(&cmd, q, 1);
+ }
+ for(j=0; j<2*nslash; j++)
+ bwritestr(&cmd, "\\");
+ bwritestr(&cmd, "\"");
+ } else {
+ bwritestr(&cmd, q);
+ }
+ }
+ if(vflag > 1)
+ xprintf("%s\n", bstr(&cmd));
+
+ torune(&rcmd, bstr(&cmd));
+ rexe = nil;
+ rdir = nil;
+ if(dir != nil)
+ torune(&rdir, dir);
+
+ memset(&si, 0, sizeof si);
+ si.cb = sizeof si;
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = INVALID_HANDLE_VALUE;
+ if(b == nil) {
+ si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ } else {
+ SECURITY_ATTRIBUTES seci;
+
+ memset(&seci, 0, sizeof seci);
+ seci.nLength = sizeof seci;
+ seci.bInheritHandle = 1;
+ breset(b);
+ if(!CreatePipe(&p[0], &p[1], &seci, 0))
+ fatal("CreatePipe: %s", errstr());
+ si.hStdOutput = p[1];
+ si.hStdError = p[1];
+ }
+
+ if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
+ if(mode!=CheckExit)
+ return;
+ fatal("%s: %s", argv->p[0], errstr());
+ }
+ if(rexe != nil)
+ xfree(rexe);
+ xfree(rcmd);
+ if(rdir != nil)
+ xfree(rdir);
+ if(b != nil) {
+ CloseHandle(p[1]);
+ breadfrom(b, p[0]);
+ CloseHandle(p[0]);
+ }
+
+ if(nbg < 0)
+ fatal("bad bookkeeping");
+ bg[nbg].pi = pi;
+ bg[nbg].mode = mode;
+ bg[nbg].cmd = btake(&cmd);
+ nbg++;
+
+ if(wait)
+ bgwait();
+
+ bfree(&cmd);
+}
+
+// closes the background job for bgwait1
+static void
+bgwaitclose(int i)
+{
+ if(i < 0 || i >= nbg)
+ return;
+
+ CloseHandle(bg[i].pi.hProcess);
+ CloseHandle(bg[i].pi.hThread);
+
+ bg[i] = bg[--nbg];
+}
+
+// bgwait1 waits for a single background job
+static void
+bgwait1(void)
+{
+ int i, mode;
+ char *cmd;
+ HANDLE bgh[MAXBG];
+ DWORD code;
+
+ if(nbg == 0)
+ fatal("bgwait1: nothing left");
+
+ for(i=0; i<nbg; i++)
+ bgh[i] = bg[i].pi.hProcess;
+ i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
+ if(i < 0 || i >= nbg)
+ fatal("WaitForMultipleObjects: %s", errstr());
+
+ cmd = bg[i].cmd;
+ mode = bg[i].mode;
+ if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
+ bgwaitclose(i);
+ fatal("GetExitCodeProcess: %s", errstr());
+ return;
+ }
+
+ if(mode==CheckExit && code != 0) {
+ bgwaitclose(i);
+ fatal("FAILED: %s", cmd);
+ return;
+ }
+
+ bgwaitclose(i);
+}
+
+void
+bgwait(void)
+{
+ while(nbg > 0)
+ bgwait1();
+}
+
+// rgetwd returns a rune string form of the current directory's path.
+static Rune*
+rgetwd(void)
+{
+ int n;
+ Rune *r;
+
+ n = GetCurrentDirectoryW(0, nil);
+ r = xmalloc((n+1)*sizeof r[0]);
+ GetCurrentDirectoryW(n+1, r);
+ r[n] = '\0';
+ return r;
+}
+
+void
+xgetwd(Buf *b)
+{
+ Rune *r;
+
+ r = rgetwd();
+ breset(b);
+ toutf(b, r);
+ xfree(r);
+}
+
+void
+xrealwd(Buf *b, char *path)
+{
+ Rune *old;
+ Rune *rnew;
+
+ old = rgetwd();
+ torune(&rnew, path);
+ if(!SetCurrentDirectoryW(rnew))
+ fatal("chdir %s: %s", path, errstr());
+ free(rnew);
+ xgetwd(b);
+ if(!SetCurrentDirectoryW(old)) {
+ breset(b);
+ toutf(b, old);
+ fatal("chdir %s: %s", bstr(b), errstr());
+ }
+}
+
+bool
+isdir(char *p)
+{
+ DWORD attr;
+ Rune *r;
+
+ torune(&r, p);
+ attr = GetFileAttributesW(r);
+ xfree(r);
+ return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+bool
+isfile(char *p)
+{
+ DWORD attr;
+ Rune *r;
+
+ torune(&r, p);
+ attr = GetFileAttributesW(r);
+ xfree(r);
+ return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+Time
+mtime(char *p)
+{
+ HANDLE h;
+ WIN32_FIND_DATAW data;
+ Rune *r;
+ FILETIME *ft;
+
+ torune(&r, p);
+ h = FindFirstFileW(r, &data);
+ xfree(r);
+ if(h == INVALID_HANDLE_VALUE)
+ return 0;
+ FindClose(h);
+ ft = &data.ftLastWriteTime;
+ return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
+}
+
+bool
+isabs(char *p)
+{
+ // c:/ or c:\ at beginning
+ if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
+ return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
+ // / or \ at beginning
+ return p[0] == '/' || p[0] == '\\';
+}
+
+void
+readfile(Buf *b, char *file)
+{
+ HANDLE h;
+ Rune *r;
+
+ if(vflag > 2)
+ xprintf("read %s\n", file);
+ torune(&r, file);
+ h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
+ if(h == INVALID_HANDLE_VALUE)
+ fatal("open %s: %s", file, errstr());
+ breadfrom(b, h);
+ CloseHandle(h);
+}
+
+void
+writefile(Buf *b, char *file, int exec)
+{
+ HANDLE h;
+ Rune *r;
+ DWORD n;
+
+ USED(exec);
+
+ if(vflag > 2)
+ xprintf("write %s\n", file);
+ torune(&r, file);
+ h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
+ if(h == INVALID_HANDLE_VALUE)
+ fatal("create %s: %s", file, errstr());
+ n = 0;
+ if(!WriteFile(h, b->p, b->len, &n, 0))
+ fatal("write %s: %s", file, errstr());
+ CloseHandle(h);
+}
+
+
+void
+xmkdir(char *p)
+{
+ Rune *r;
+
+ torune(&r, p);
+ if(!CreateDirectoryW(r, nil))
+ fatal("mkdir %s: %s", p, errstr());
+ xfree(r);
+}
+
+void
+xmkdirall(char *p)
+{
+ int c;
+ char *q, *q2;
+
+ if(isdir(p))
+ return;
+ q = strrchr(p, '/');
+ q2 = strrchr(p, '\\');
+ if(q2 != nil && (q == nil || q < q2))
+ q = q2;
+ if(q != nil) {
+ c = *q;
+ *q = '\0';
+ xmkdirall(p);
+ *q = c;
+ }
+ xmkdir(p);
+}
+
+void
+xremove(char *p)
+{
+ int attr;
+ Rune *r;
+
+ torune(&r, p);
+ attr = GetFileAttributesW(r);
+ if(attr >= 0) {
+ if(attr & FILE_ATTRIBUTE_DIRECTORY)
+ RemoveDirectoryW(r);
+ else
+ DeleteFileW(r);
+ }
+ xfree(r);
+}
+
+void
+xreaddir(Vec *dst, char *dir)
+{
+ Rune *r;
+ Buf b;
+ HANDLE h;
+ WIN32_FIND_DATAW data;
+ char *p, *q;
+
+ binit(&b);
+ vreset(dst);
+
+ bwritestr(&b, dir);
+ bwritestr(&b, "\\*");
+ torune(&r, bstr(&b));
+
+ h = FindFirstFileW(r, &data);
+ xfree(r);
+ if(h == INVALID_HANDLE_VALUE)
+ goto out;
+ do{
+ toutf(&b, data.cFileName);
+ p = bstr(&b);
+ q = xstrrchr(p, '\\');
+ if(q != nil)
+ p = q+1;
+ if(!streq(p, ".") && !streq(p, ".."))
+ vadd(dst, p);
+ }while(FindNextFileW(h, &data));
+ FindClose(h);
+
+out:
+ bfree(&b);
+}
+
+char*
+xworkdir(void)
+{
+ Rune buf[1024];
+ Rune tmp[MAX_PATH];
+ Rune go[3] = {'g', 'o', '\0'};
+ int n;
+ Buf b;
+
+ n = GetTempPathW(nelem(buf), buf);
+ if(n <= 0)
+ fatal("GetTempPath: %s", errstr());
+ buf[n] = '\0';
+
+ if(GetTempFileNameW(buf, go, 0, tmp) == 0)
+ fatal("GetTempFileName: %s", errstr());
+ DeleteFileW(tmp);
+ if(!CreateDirectoryW(tmp, nil))
+ fatal("create tempdir: %s", errstr());
+
+ binit(&b);
+ toutf(&b, tmp);
+ return btake(&b);
+}
+
+void
+xremoveall(char *p)
+{
+ int i;
+ Buf b;
+ Vec dir;
+ Rune *r;
+
+ binit(&b);
+ vinit(&dir);
+
+ torune(&r, p);
+ if(isdir(p)) {
+ xreaddir(&dir, p);
+ for(i=0; i<dir.len; i++) {
+ bprintf(&b, "%s/%s", p, dir.p[i]);
+ xremoveall(bstr(&b));
+ }
+ RemoveDirectoryW(r);
+ } else {
+ DeleteFileW(r);
+ }
+ xfree(r);
+
+ bfree(&b);
+ vfree(&dir);
+}
+
+void
+fatal(char *msg, ...)
+{
+ static char buf1[1024];
+ va_list arg;
+
+ va_start(arg, msg);
+ vsnprintf(buf1, sizeof buf1, msg, arg);
+ va_end(arg);
+
+ xprintf("go tool dist: %s\n", buf1);
+
+ bgwait();
+ ExitProcess(1);
+}
+
+// HEAP is the persistent handle to the default process heap.
+static HANDLE HEAP = INVALID_HANDLE_VALUE;
+
+void*
+xmalloc(int n)
+{
+ void *p;
+
+ if(HEAP == INVALID_HANDLE_VALUE)
+ HEAP = GetProcessHeap();
+ p = HeapAlloc(HEAP, 0, n);
+ if(p == nil)
+ fatal("out of memory allocating %d: %s", n, errstr());
+ memset(p, 0, n);
+ return p;
+}
+
+char*
+xstrdup(char *p)
+{
+ char *q;
+
+ q = xmalloc(strlen(p)+1);
+ strcpy(q, p);
+ return q;
+}
+
+void
+xfree(void *p)
+{
+ if(HEAP == INVALID_HANDLE_VALUE)
+ HEAP = GetProcessHeap();
+ HeapFree(HEAP, 0, p);
+}
+
+void*
+xrealloc(void *p, int n)
+{
+ if(p == nil)
+ return xmalloc(n);
+ if(HEAP == INVALID_HANDLE_VALUE)
+ HEAP = GetProcessHeap();
+ p = HeapReAlloc(HEAP, 0, p, n);
+ if(p == nil)
+ fatal("out of memory reallocating %d", n);
+ return p;
+}
+
+bool
+hassuffix(char *p, char *suffix)
+{
+ int np, ns;
+
+ np = strlen(p);
+ ns = strlen(suffix);
+ return np >= ns && strcmp(p+np-ns, suffix) == 0;
+}
+
+bool
+hasprefix(char *p, char *prefix)
+{
+ return strncmp(p, prefix, strlen(prefix)) == 0;
+}
+
+bool
+contains(char *p, char *sep)
+{
+ return strstr(p, sep) != nil;
+}
+
+bool
+streq(char *p, char *q)
+{
+ return strcmp(p, q) == 0;
+}
+
+char*
+lastelem(char *p)
+{
+ char *out;
+
+ out = p;
+ for(; *p; p++)
+ if(*p == '/' || *p == '\\')
+ out = p+1;
+ return out;
+}
+
+void
+xmemmove(void *dst, void *src, int n)
+{
+ memmove(dst, src, n);
+}
+
+int
+xmemcmp(void *a, void *b, int n)
+{
+ return memcmp(a, b, n);
+}
+
+int
+xstrlen(char *p)
+{
+ return strlen(p);
+}
+
+void
+xexit(int n)
+{
+ ExitProcess(n);
+}
+
+void
+xatexit(void (*f)(void))
+{
+ atexit(f);
+}
+
+void
+xprintf(char *fmt, ...)
+{
+ va_list arg;
+ char *p;
+ DWORD n, w;
+
+ va_start(arg, fmt);
+ n = vsnprintf(NULL, 0, fmt, arg);
+ p = xmalloc(n+1);
+ vsnprintf(p, n+1, fmt, arg);
+ va_end(arg);
+ w = 0;
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), p, n, &w, 0);
+ xfree(p);
+}
+
+int
+main(int argc, char **argv)
+{
+ SYSTEM_INFO si;
+
+ setvbuf(stdout, nil, _IOLBF, 0);
+ setvbuf(stderr, nil, _IOLBF, 0);
+
+ slash = "\\";
+ gohostos = "windows";
+
+ GetSystemInfo(&si);
+ switch(si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ gohostarch = "amd64";
+ break;
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ gohostarch = "386";
+ break;
+ default:
+ fatal("unknown processor architecture");
+ }
+
+ init();
+
+ xmain(argc, argv);
+ return 0;
+}
+
+void
+xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
+{
+ qsort(data, n, elemsize, cmp);
+}
+
+int
+xstrcmp(char *a, char *b)
+{
+ return strcmp(a, b);
+}
+
+char*
+xstrstr(char *a, char *b)
+{
+ return strstr(a, b);
+}
+
+char*
+xstrrchr(char *p, int c)
+{
+ char *ep;
+
+ ep = p+strlen(p);
+ for(ep=p+strlen(p); ep >= p; ep--)
+ if(*ep == c)
+ return ep;
+ return nil;
+}
+
+#endif // __WINDOWS__
diff --git a/src/cmd/ebnflint/Makefile b/src/cmd/ebnflint/Makefile
deleted file mode 100644
index 8f030aaef..000000000
--- a/src/cmd/ebnflint/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../Make.inc
-
-TARG=ebnflint
-GOFILES=\
- ebnflint.go\
-
-include ../../Make.cmd
-
-test: $(TARG)
- $(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
-
diff --git a/src/cmd/ebnflint/doc.go b/src/cmd/ebnflint/doc.go
deleted file mode 100644
index f35976eea..000000000
--- a/src/cmd/ebnflint/doc.go
+++ /dev/null
@@ -1,22 +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.
-
-/*
-
-Ebnflint verifies that EBNF productions are consistent and gramatically correct.
-It reads them from an HTML document such as the Go specification.
-
-Grammar productions are grouped in boxes demarcated by the HTML elements
- <pre class="ebnf">
- </pre>
-
-
-Usage:
- ebnflint [--start production] [file]
-
-The --start flag specifies the name of the start production for
-the grammar; it defaults to "Start".
-
-*/
-package documentation
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
deleted file mode 100644
index 009b336f3..000000000
--- a/src/cmd/ebnflint/ebnflint.go
+++ /dev/null
@@ -1,109 +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 (
- "bytes"
- "ebnf"
- "flag"
- "fmt"
- "go/scanner"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
-)
-
-var fset = token.NewFileSet()
-var start = flag.String("start", "Start", "name of start production")
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
- flag.PrintDefaults()
- os.Exit(1)
-}
-
-// Markers around EBNF sections in .html files
-var (
- open = []byte(`<pre class="ebnf">`)
- close = []byte(`</pre>`)
-)
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- os.Exit(1)
-}
-
-func extractEBNF(src []byte) []byte {
- var buf bytes.Buffer
-
- for {
- // i = beginning of EBNF text
- i := bytes.Index(src, open)
- if i < 0 {
- break // no EBNF found - we are done
- }
- i += len(open)
-
- // write as many newlines as found in the excluded text
- // to maintain correct line numbers in error messages
- for _, ch := range src[0:i] {
- if ch == '\n' {
- buf.WriteByte('\n')
- }
- }
-
- // j = end of EBNF text (or end of source)
- j := bytes.Index(src[i:], close) // close marker
- if j < 0 {
- j = len(src) - i
- }
- j += i
-
- // copy EBNF text
- buf.Write(src[i:j])
-
- // advance
- src = src[j:]
- }
-
- return buf.Bytes()
-}
-
-func main() {
- flag.Parse()
-
- var (
- filename string
- src []byte
- err os.Error
- )
- switch flag.NArg() {
- case 0:
- filename = "<stdin>"
- src, err = ioutil.ReadAll(os.Stdin)
- case 1:
- filename = flag.Arg(0)
- src, err = ioutil.ReadFile(filename)
- default:
- usage()
- }
- if err != nil {
- report(err)
- }
-
- if filepath.Ext(filename) == ".html" || bytes.Index(src, open) >= 0 {
- src = extractEBNF(src)
- }
-
- grammar, err := ebnf.Parse(fset, filename, src)
- if err != nil {
- report(err)
- }
-
- if err = ebnf.Verify(fset, grammar, *start); err != nil {
- report(err)
- }
-}
diff --git a/src/cmd/fix/doc.go b/src/cmd/fix/doc.go
new file mode 100644
index 000000000..a92e0fc06
--- /dev/null
+++ b/src/cmd/fix/doc.go
@@ -0,0 +1,36 @@
+// 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.
+
+/*
+Fix finds Go programs that use old APIs and rewrites them to use
+newer ones. After you update to a new Go release, fix helps make
+the necessary changes to your programs.
+
+Usage:
+ go tool fix [-r name,...] [path ...]
+
+Without an explicit path, fix reads standard input and writes the
+result to standard output.
+
+If the named path is a file, fix rewrites the named files in place.
+If the named path is a directory, fix rewrites all .go files in that
+directory tree. When fix rewrites a file, it prints a line to standard
+error giving the name of the file and the rewrite applied.
+
+If the -diff flag is set, no files are rewritten. Instead fix prints
+the differences a rewrite would introduce.
+
+The -r flag restricts the set of rewrites considered to those in the
+named list. By default fix considers all known rewrites. Fix's
+rewrites are idempotent, so that it is safe to apply fix to updated
+or partially updated code even without using the -r flag.
+
+Fix prints the full list of fixes it can apply in its help output;
+to see them, run go tool fix -?.
+
+Fix does not make backup copies of the files that it edits.
+Instead, use a version control system's ``diff'' functionality to inspect
+the changes that fix makes before committing them.
+*/
+package documentation
diff --git a/src/cmd/fix/error.go b/src/cmd/fix/error.go
new file mode 100644
index 000000000..55613210a
--- /dev/null
+++ b/src/cmd/fix/error.go
@@ -0,0 +1,353 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "regexp"
+ "strings"
+)
+
+func init() {
+ register(errorFix)
+}
+
+var errorFix = fix{
+ "error",
+ "2011-11-02",
+ errorFn,
+ `Use error instead of os.Error.
+
+This fix rewrites code using os.Error to use error:
+
+ os.Error -> error
+ os.NewError -> errors.New
+ os.EOF -> io.EOF
+
+Seeing the old names above (os.Error and so on) triggers the following
+heuristic rewrites. The heuristics can be forced using the -force=error flag.
+
+A top-level function, variable, or constant named error is renamed error_.
+
+Error implementations—those types used as os.Error or named
+XxxError—have their String methods renamed to Error. Any existing
+Error field or method is renamed to Err.
+
+Error values—those with type os.Error or named e, err, error, err1,
+and so on—have method calls and field references rewritten just
+as the types do (String to Error, Error to Err). Also, a type assertion
+of the form err.(*os.Waitmsg) becomes err.(*exec.ExitError).
+
+http://codereview.appspot.com/5305066
+`,
+}
+
+// At minimum, this fix applies the following rewrites:
+//
+// os.Error -> error
+// os.NewError -> errors.New
+// os.EOF -> io.EOF
+//
+// However, if can apply any of those rewrites, it assumes that the
+// file predates the error type and tries to update the code to use
+// the new definition for error - an Error method, not a String method.
+// This more heuristic procedure may not be 100% accurate, so it is
+// only run when the file needs updating anyway. The heuristic can
+// be forced to run using -force=error.
+//
+// First, we must identify the implementations of os.Error.
+// These include the type of any value returned as or assigned to an os.Error.
+// To that set we add any type whose name contains "Error" or "error".
+// The heuristic helps for implementations that are not used as os.Error
+// in the file in which they are defined.
+//
+// In any implementation of os.Error, we rename an existing struct field
+// or method named Error to Err and rename the String method to Error.
+//
+// Second, we must identify the values of type os.Error.
+// These include any value that obviously has type os.Error.
+// To that set we add any variable whose name is e or err or error
+// possibly followed by _ or a numeric or capitalized suffix.
+// The heuristic helps for variables that are initialized using calls
+// to functions in other packages. The type checker does not have
+// information about those packages available, and in general cannot
+// (because the packages may themselves not compile).
+//
+// For any value of type os.Error, we replace a call to String with a call to Error.
+// We also replace type assertion err.(*os.Waitmsg) with err.(*exec.ExitError).
+
+// Variables matching this regexp are assumed to have type os.Error.
+var errVar = regexp.MustCompile(`^(e|err|error)_?([A-Z0-9].*)?$`)
+
+// Types matching this regexp are assumed to be implementations of os.Error.
+var errType = regexp.MustCompile(`^\*?([Ee]rror|.*Error)$`)
+
+// Type-checking configuration: tell the type-checker this basic
+// information about types, functions, and variables in external packages.
+var errorTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "os.Error": {},
+ },
+ Func: map[string]string{
+ "fmt.Errorf": "os.Error",
+ "os.NewError": "os.Error",
+ },
+ Var: map[string]string{
+ "os.EPERM": "os.Error",
+ "os.ENOENT": "os.Error",
+ "os.ESRCH": "os.Error",
+ "os.EINTR": "os.Error",
+ "os.EIO": "os.Error",
+ "os.ENXIO": "os.Error",
+ "os.E2BIG": "os.Error",
+ "os.ENOEXEC": "os.Error",
+ "os.EBADF": "os.Error",
+ "os.ECHILD": "os.Error",
+ "os.EDEADLK": "os.Error",
+ "os.ENOMEM": "os.Error",
+ "os.EACCES": "os.Error",
+ "os.EFAULT": "os.Error",
+ "os.EBUSY": "os.Error",
+ "os.EEXIST": "os.Error",
+ "os.EXDEV": "os.Error",
+ "os.ENODEV": "os.Error",
+ "os.ENOTDIR": "os.Error",
+ "os.EISDIR": "os.Error",
+ "os.EINVAL": "os.Error",
+ "os.ENFILE": "os.Error",
+ "os.EMFILE": "os.Error",
+ "os.ENOTTY": "os.Error",
+ "os.EFBIG": "os.Error",
+ "os.ENOSPC": "os.Error",
+ "os.ESPIPE": "os.Error",
+ "os.EROFS": "os.Error",
+ "os.EMLINK": "os.Error",
+ "os.EPIPE": "os.Error",
+ "os.EAGAIN": "os.Error",
+ "os.EDOM": "os.Error",
+ "os.ERANGE": "os.Error",
+ "os.EADDRINUSE": "os.Error",
+ "os.ECONNREFUSED": "os.Error",
+ "os.ENAMETOOLONG": "os.Error",
+ "os.EAFNOSUPPORT": "os.Error",
+ "os.ETIMEDOUT": "os.Error",
+ "os.ENOTCONN": "os.Error",
+ },
+}
+
+func errorFn(f *ast.File) bool {
+ if !imports(f, "os") && !force["error"] {
+ return false
+ }
+
+ // Fix gets called once to run the heuristics described above
+ // when we notice that this file definitely needs fixing
+ // (it mentions os.Error or something similar).
+ var fixed bool
+ var didHeuristic bool
+ heuristic := func() {
+ if didHeuristic {
+ return
+ }
+ didHeuristic = true
+
+ // We have identified a necessary fix (like os.Error -> error)
+ // but have not applied it or any others yet. Prepare the file
+ // for fixing and apply heuristic fixes.
+
+ // Rename error to error_ to make room for error.
+ fixed = renameTop(f, "error", "error_") || fixed
+
+ // Use type checker to build list of error implementations.
+ typeof, assign := typecheck(errorTypeConfig, f)
+
+ isError := map[string]bool{}
+ for _, val := range assign["os.Error"] {
+ t := typeof[val]
+ if strings.HasPrefix(t, "*") {
+ t = t[1:]
+ }
+ if t != "" && !strings.HasPrefix(t, "func(") {
+ isError[t] = true
+ }
+ }
+
+ // We use both the type check results and the "Error" name heuristic
+ // to identify implementations of os.Error.
+ isErrorImpl := func(typ string) bool {
+ return isError[typ] || errType.MatchString(typ)
+ }
+
+ isErrorVar := func(x ast.Expr) bool {
+ if typ := typeof[x]; typ != "" {
+ return isErrorImpl(typ) || typ == "os.Error"
+ }
+ if sel, ok := x.(*ast.SelectorExpr); ok {
+ return sel.Sel.Name == "Error" || sel.Sel.Name == "Err"
+ }
+ if id, ok := x.(*ast.Ident); ok {
+ return errVar.MatchString(id.Name)
+ }
+ return false
+ }
+
+ walk(f, func(n interface{}) {
+ // In method declaration on error implementation type,
+ // rename String() to Error() and Error() to Err().
+ fn, ok := n.(*ast.FuncDecl)
+ if ok &&
+ fn.Recv != nil &&
+ len(fn.Recv.List) == 1 &&
+ isErrorImpl(typeName(fn.Recv.List[0].Type)) {
+ // Rename.
+ switch fn.Name.Name {
+ case "String":
+ fn.Name.Name = "Error"
+ fixed = true
+ case "Error":
+ fn.Name.Name = "Err"
+ fixed = true
+ }
+ return
+ }
+
+ // In type definition of an error implementation type,
+ // rename Error field to Err to make room for method.
+ // Given type XxxError struct { ... Error T } rename field to Err.
+ d, ok := n.(*ast.GenDecl)
+ if ok {
+ for _, s := range d.Specs {
+ switch s := s.(type) {
+ case *ast.TypeSpec:
+ if isErrorImpl(typeName(s.Name)) {
+ st, ok := s.Type.(*ast.StructType)
+ if ok {
+ for _, f := range st.Fields.List {
+ for _, n := range f.Names {
+ if n.Name == "Error" {
+ n.Name = "Err"
+ fixed = true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // For values that are an error implementation type,
+ // rename .Error to .Err and .String to .Error
+ sel, selok := n.(*ast.SelectorExpr)
+ if selok && isErrorImpl(typeof[sel.X]) {
+ switch sel.Sel.Name {
+ case "Error":
+ sel.Sel.Name = "Err"
+ fixed = true
+ case "String":
+ sel.Sel.Name = "Error"
+ fixed = true
+ }
+ }
+
+ // Assume x.Err is an error value and rename .String to .Error
+ // Children have been processed so the rewrite from Error to Err
+ // has already happened there.
+ if selok {
+ if subsel, ok := sel.X.(*ast.SelectorExpr); ok && subsel.Sel.Name == "Err" && sel.Sel.Name == "String" {
+ sel.Sel.Name = "Error"
+ fixed = true
+ }
+ }
+
+ // For values that are an error variable, rename .String to .Error.
+ if selok && isErrorVar(sel.X) && sel.Sel.Name == "String" {
+ sel.Sel.Name = "Error"
+ fixed = true
+ }
+
+ // Rewrite composite literal of error type to turn Error: into Err:.
+ lit, ok := n.(*ast.CompositeLit)
+ if ok && isErrorImpl(typeof[lit]) {
+ for _, e := range lit.Elts {
+ if kv, ok := e.(*ast.KeyValueExpr); ok && isName(kv.Key, "Error") {
+ kv.Key.(*ast.Ident).Name = "Err"
+ fixed = true
+ }
+ }
+ }
+
+ // Rename os.Waitmsg to exec.ExitError
+ // when used in a type assertion on an error.
+ ta, ok := n.(*ast.TypeAssertExpr)
+ if ok && isErrorVar(ta.X) && isPtrPkgDot(ta.Type, "os", "Waitmsg") {
+ addImport(f, "exec")
+ sel := ta.Type.(*ast.StarExpr).X.(*ast.SelectorExpr)
+ sel.X.(*ast.Ident).Name = "exec"
+ sel.Sel.Name = "ExitError"
+ fixed = true
+ }
+
+ })
+ }
+
+ fix := func() {
+ if fixed {
+ return
+ }
+ fixed = true
+ heuristic()
+ }
+
+ if force["error"] {
+ heuristic()
+ }
+
+ walk(f, func(n interface{}) {
+ p, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ sel, ok := (*p).(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ switch {
+ case isPkgDot(sel, "os", "Error"):
+ fix()
+ *p = &ast.Ident{NamePos: sel.Pos(), Name: "error"}
+ case isPkgDot(sel, "os", "NewError"):
+ fix()
+ addImport(f, "errors")
+ sel.X.(*ast.Ident).Name = "errors"
+ sel.Sel.Name = "New"
+ case isPkgDot(sel, "os", "EOF"):
+ fix()
+ addImport(f, "io")
+ sel.X.(*ast.Ident).Name = "io"
+ }
+ })
+
+ if fixed && !usesImport(f, "os") {
+ deleteImport(f, "os")
+ }
+
+ return fixed
+}
+
+func typeName(typ ast.Expr) string {
+ if p, ok := typ.(*ast.StarExpr); ok {
+ typ = p.X
+ }
+ id, ok := typ.(*ast.Ident)
+ if ok {
+ return id.Name
+ }
+ sel, ok := typ.(*ast.SelectorExpr)
+ if ok {
+ return typeName(sel.X) + "." + sel.Sel.Name
+ }
+ return ""
+}
diff --git a/src/cmd/fix/error_test.go b/src/cmd/fix/error_test.go
new file mode 100644
index 000000000..027eed24f
--- /dev/null
+++ b/src/cmd/fix/error_test.go
@@ -0,0 +1,240 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(errorTests, errorFn)
+}
+
+var errorTests = []testCase{
+ {
+ Name: "error.0",
+ In: `package main
+
+func error() {}
+
+var error int
+`,
+ Out: `package main
+
+func error() {}
+
+var error int
+`,
+ },
+ {
+ Name: "error.1",
+ In: `package main
+
+import "os"
+
+func f() os.Error {
+ return os.EOF
+}
+
+func error() {}
+
+var error int
+
+func g() {
+ error := 1
+ _ = error
+}
+
+func h(os.Error) {}
+
+func i(...os.Error) {}
+`,
+ Out: `package main
+
+import "io"
+
+func f() error {
+ return io.EOF
+}
+
+func error_() {}
+
+var error_ int
+
+func g() {
+ error := 1
+ _ = error
+}
+
+func h(error) {}
+
+func i(...error) {}
+`,
+ },
+ {
+ Name: "error.2",
+ In: `package main
+
+import "os"
+
+func f() os.Error {
+ return os.EOF
+}
+
+func g() string {
+ // these all convert because f is known
+ if err := f(); err != nil {
+ return err.String()
+ }
+ if err1 := f(); err1 != nil {
+ return err1.String()
+ }
+ if e := f(); e != nil {
+ return e.String()
+ }
+ if x := f(); x != nil {
+ return x.String()
+ }
+
+ // only the error names (err, err1, e) convert; u is not known
+ if err := u(); err != nil {
+ return err.String()
+ }
+ if err1 := u(); err1 != nil {
+ return err1.String()
+ }
+ if e := u(); e != nil {
+ return e.String()
+ }
+ if x := u(); x != nil {
+ return x.String()
+ }
+ return ""
+}
+
+type T int
+
+func (t T) String() string { return "t" }
+
+type PT int
+
+func (p *PT) String() string { return "pt" }
+
+type MyError int
+
+func (t MyError) String() string { return "myerror" }
+
+type PMyError int
+
+func (p *PMyError) String() string { return "pmyerror" }
+
+func error() {}
+
+var error int
+`,
+ Out: `package main
+
+import "io"
+
+func f() error {
+ return io.EOF
+}
+
+func g() string {
+ // these all convert because f is known
+ if err := f(); err != nil {
+ return err.Error()
+ }
+ if err1 := f(); err1 != nil {
+ return err1.Error()
+ }
+ if e := f(); e != nil {
+ return e.Error()
+ }
+ if x := f(); x != nil {
+ return x.Error()
+ }
+
+ // only the error names (err, err1, e) convert; u is not known
+ if err := u(); err != nil {
+ return err.Error()
+ }
+ if err1 := u(); err1 != nil {
+ return err1.Error()
+ }
+ if e := u(); e != nil {
+ return e.Error()
+ }
+ if x := u(); x != nil {
+ return x.String()
+ }
+ return ""
+}
+
+type T int
+
+func (t T) String() string { return "t" }
+
+type PT int
+
+func (p *PT) String() string { return "pt" }
+
+type MyError int
+
+func (t MyError) Error() string { return "myerror" }
+
+type PMyError int
+
+func (p *PMyError) Error() string { return "pmyerror" }
+
+func error_() {}
+
+var error_ int
+`,
+ },
+ {
+ Name: "error.3",
+ In: `package main
+
+import "os"
+
+func f() os.Error {
+ return os.EOF
+}
+
+type PathError struct {
+ Name string
+ Error os.Error
+}
+
+func (p *PathError) String() string {
+ return p.Name + ": " + p.Error.String()
+}
+
+func (p *PathError) Error1() string {
+ p = &PathError{Error: nil}
+ return fmt.Sprint(p.Name, ": ", p.Error)
+}
+`,
+ Out: `package main
+
+import "io"
+
+func f() error {
+ return io.EOF
+}
+
+type PathError struct {
+ Name string
+ Err error
+}
+
+func (p *PathError) Error() string {
+ return p.Name + ": " + p.Err.Error()
+}
+
+func (p *PathError) Error1() string {
+ p = &PathError{Err: nil}
+ return fmt.Sprint(p.Name, ": ", p.Err)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/filepath.go b/src/cmd/fix/filepath.go
index 1d0ad6879..f31226018 100644
--- a/src/cmd/gofix/filepath.go
+++ b/src/cmd/fix/filepath.go
@@ -9,14 +9,17 @@ import (
)
func init() {
- register(fix{
- "filepath",
- filepathFunc,
- `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
+ register(filepathFix)
+}
+
+var filepathFix = fix{
+ "filepath",
+ "2011-06-26",
+ filepathFunc,
+ `Adapt code from filepath.[List]SeparatorString to string(filepath.[List]Separator).
http://codereview.appspot.com/4527090
`,
- })
}
func filepathFunc(f *ast.File) (fixed bool) {
diff --git a/src/cmd/gofix/filepath_test.go b/src/cmd/fix/filepath_test.go
index d170c3ae3..37a2f5d9f 100644
--- a/src/cmd/gofix/filepath_test.go
+++ b/src/cmd/fix/filepath_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(filepathTests)
+ addTestCases(filepathTests, filepathFunc)
}
var filepathTests = []testCase{
diff --git a/src/cmd/gofix/fix.go b/src/cmd/fix/fix.go
index cc85ceafa..a100be794 100644
--- a/src/cmd/gofix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -7,26 +7,37 @@ package main
import (
"fmt"
"go/ast"
+ "go/parser"
"go/token"
"os"
+ "path"
+ "reflect"
"strconv"
"strings"
)
type fix struct {
name string
+ date string // date that fix was introduced, in YYYY-MM-DD format
f func(*ast.File) bool
desc string
}
-// main runs sort.Sort(fixes) after init process is done.
-type fixlist []fix
+// main runs sort.Sort(byName(fixes)) before printing list of fixes.
+type byName []fix
-func (f fixlist) Len() int { return len(f) }
-func (f fixlist) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f fixlist) Less(i, j int) bool { return f[i].name < f[j].name }
+func (f byName) Len() int { return len(f) }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f byName) Less(i, j int) bool { return f[i].name < f[j].name }
-var fixes fixlist
+// main runs sort.Sort(byDate(fixes)) before applying fixes.
+type byDate []fix
+
+func (f byDate) Len() int { return len(f) }
+func (f byDate) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f byDate) Less(i, j int) bool { return f[i].date < f[j].date }
+
+var fixes []fix
func register(f fix) {
fixes = append(fixes, f)
@@ -73,6 +84,8 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
walkBeforeAfter(*n, before, after)
case **ast.Ident:
walkBeforeAfter(*n, before, after)
+ case **ast.BasicLit:
+ walkBeforeAfter(*n, before, after)
// pointers to slices
case *[]ast.Decl:
@@ -90,7 +103,9 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
case *ast.Field:
+ walkBeforeAfter(&n.Names, before, after)
walkBeforeAfter(&n.Type, before, after)
+ walkBeforeAfter(&n.Tag, before, after)
case *ast.FieldList:
for _, field := range n.List {
walkBeforeAfter(field, before, after)
@@ -98,6 +113,7 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
+ walkBeforeAfter(&n.Elt, before, after)
case *ast.BasicLit:
case *ast.FuncLit:
walkBeforeAfter(&n.Type, before, after)
@@ -292,6 +308,20 @@ func importPath(s *ast.ImportSpec) string {
return ""
}
+// declImports reports whether gen contains an import of path.
+func declImports(gen *ast.GenDecl, path string) bool {
+ if gen.Tok != token.IMPORT {
+ return false
+ }
+ for _, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ if importPath(impspec) == path {
+ return true
+ }
+ }
+ return false
+}
+
// isPkgDot returns true if t is the expression "pkg.name"
// where pkg is an imported identifier.
func isPkgDot(t ast.Expr, pkg, name string) bool {
@@ -446,66 +476,172 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
}
}
+// renameTop renames all references to the top-level name old.
+// It returns true if it makes any changes.
+func renameTop(f *ast.File, old, new string) bool {
+ var fixed bool
+
+ // Rename any conflicting imports
+ // (assuming package name is last element of path).
+ for _, s := range f.Imports {
+ if s.Name != nil {
+ if s.Name.Name == old {
+ s.Name.Name = new
+ fixed = true
+ }
+ } else {
+ _, thisName := path.Split(importPath(s))
+ if thisName == old {
+ s.Name = ast.NewIdent(new)
+ fixed = true
+ }
+ }
+ }
+
+ // Rename any top-level declarations.
+ for _, d := range f.Decls {
+ switch d := d.(type) {
+ case *ast.FuncDecl:
+ if d.Recv == nil && d.Name.Name == old {
+ d.Name.Name = new
+ d.Name.Obj.Name = new
+ fixed = true
+ }
+ case *ast.GenDecl:
+ for _, s := range d.Specs {
+ switch s := s.(type) {
+ case *ast.TypeSpec:
+ if s.Name.Name == old {
+ s.Name.Name = new
+ s.Name.Obj.Name = new
+ fixed = true
+ }
+ case *ast.ValueSpec:
+ for _, n := range s.Names {
+ if n.Name == old {
+ n.Name = new
+ n.Obj.Name = new
+ fixed = true
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Rename top-level old to new, both unresolved names
+ // (probably defined in another file) and names that resolve
+ // to a declaration we renamed.
+ walk(f, func(n interface{}) {
+ id, ok := n.(*ast.Ident)
+ if ok && isTopName(id, old) {
+ id.Name = new
+ fixed = true
+ }
+ if ok && id.Obj != nil && id.Name == old && id.Obj.Name == new {
+ id.Name = id.Obj.Name
+ fixed = true
+ }
+ })
+
+ return fixed
+}
+
+// matchLen returns the length of the longest prefix shared by x and y.
+func matchLen(x, y string) int {
+ i := 0
+ for i < len(x) && i < len(y) && x[i] == y[i] {
+ i++
+ }
+ return i
+}
+
// addImport adds the import path to the file f, if absent.
-func addImport(f *ast.File, path string) {
- if imports(f, path) {
- return
+func addImport(f *ast.File, ipath string) (added bool) {
+ if imports(f, ipath) {
+ return false
}
+ // Determine name of import.
+ // Assume added imports follow convention of using last element.
+ _, name := path.Split(ipath)
+
+ // Rename any conflicting top-level references from name to name_.
+ renameTop(f, name, name+"_")
+
newImport := &ast.ImportSpec{
Path: &ast.BasicLit{
Kind: token.STRING,
- Value: strconv.Quote(path),
+ Value: strconv.Quote(ipath),
},
}
- var impdecl *ast.GenDecl
-
// Find an import decl to add to.
- for _, decl := range f.Decls {
+ var (
+ bestMatch = -1
+ lastImport = -1
+ impDecl *ast.GenDecl
+ impIndex = -1
+ )
+ for i, decl := range f.Decls {
gen, ok := decl.(*ast.GenDecl)
-
if ok && gen.Tok == token.IMPORT {
- impdecl = gen
- break
+ lastImport = i
+ // Do not add to import "C", to avoid disrupting the
+ // association with its doc comment, breaking cgo.
+ if declImports(gen, "C") {
+ continue
+ }
+
+ // Compute longest shared prefix with imports in this block.
+ for j, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ n := matchLen(importPath(impspec), ipath)
+ if n > bestMatch {
+ bestMatch = n
+ impDecl = gen
+ impIndex = j
+ }
+ }
}
}
- // No import decl found. Add one.
- if impdecl == nil {
- impdecl = &ast.GenDecl{
+ // If no import decl found, add one after the last import.
+ if impDecl == nil {
+ impDecl = &ast.GenDecl{
Tok: token.IMPORT,
}
f.Decls = append(f.Decls, nil)
- copy(f.Decls[1:], f.Decls)
- f.Decls[0] = impdecl
+ copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
+ f.Decls[lastImport+1] = impDecl
}
// Ensure the import decl has parentheses, if needed.
- if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
- impdecl.Lparen = impdecl.Pos()
+ if len(impDecl.Specs) > 0 && !impDecl.Lparen.IsValid() {
+ impDecl.Lparen = impDecl.Pos()
}
- // Assume the import paths are alphabetically ordered.
- // If they are not, the result is ugly, but legal.
- insertAt := len(impdecl.Specs) // default to end of specs
- for i, spec := range impdecl.Specs {
- impspec := spec.(*ast.ImportSpec)
- if importPath(impspec) > path {
- insertAt = i
- break
- }
+ insertAt := impIndex + 1
+ if insertAt == 0 {
+ insertAt = len(impDecl.Specs)
+ }
+ impDecl.Specs = append(impDecl.Specs, nil)
+ copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
+ impDecl.Specs[insertAt] = newImport
+ if insertAt > 0 {
+ // Assign same position as the previous import,
+ // so that the sorter sees it as being in the same block.
+ prev := impDecl.Specs[insertAt-1]
+ newImport.Path.ValuePos = prev.Pos()
+ newImport.EndPos = prev.Pos()
}
-
- impdecl.Specs = append(impdecl.Specs, nil)
- copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
- impdecl.Specs[insertAt] = newImport
f.Imports = append(f.Imports, newImport)
+ return true
}
// deleteImport deletes the import path from the file f, if present.
-func deleteImport(f *ast.File, path string) {
+func deleteImport(f *ast.File, path string) (deleted bool) {
oldImport := importSpec(f, path)
// Find the import node that imports path, if any.
@@ -516,13 +652,13 @@ func deleteImport(f *ast.File, path string) {
}
for j, spec := range gen.Specs {
impspec := spec.(*ast.ImportSpec)
-
if oldImport != impspec {
continue
}
// We found an import spec that imports path.
// Delete it.
+ deleted = true
copy(gen.Specs[j:], gen.Specs[j+1:])
gen.Specs = gen.Specs[:len(gen.Specs)-1]
@@ -534,7 +670,13 @@ func deleteImport(f *ast.File, path string) {
} else if len(gen.Specs) == 1 {
gen.Lparen = token.NoPos // drop parens
}
-
+ if j > 0 {
+ // We deleted an entry but now there will be
+ // a blank line-sized hole where the import was.
+ // Close the hole by making the previous
+ // import appear to "end" where this one did.
+ gen.Specs[j-1].(*ast.ImportSpec).EndPos = impspec.End()
+ }
break
}
}
@@ -547,6 +689,22 @@ func deleteImport(f *ast.File, path string) {
break
}
}
+
+ return
+}
+
+// rewriteImport rewrites any import of path oldPath to path newPath.
+func rewriteImport(f *ast.File, oldPath, newPath string) (rewrote bool) {
+ for _, imp := range f.Imports {
+ if importPath(imp) == oldPath {
+ rewrote = true
+ // record old End, because the default is to compute
+ // it using the length of imp.Path.Value.
+ imp.EndPos = imp.End()
+ imp.Path.Value = strconv.Quote(newPath)
+ }
+ }
+ return
}
func usesImport(f *ast.File, path string) (used bool) {
@@ -580,3 +738,111 @@ func usesImport(f *ast.File, path string) (used bool) {
return
}
+
+func expr(s string) ast.Expr {
+ x, err := parser.ParseExpr(s)
+ if err != nil {
+ panic("parsing " + s + ": " + err.Error())
+ }
+ // Remove position information to avoid spurious newlines.
+ killPos(reflect.ValueOf(x))
+ return x
+}
+
+var posType = reflect.TypeOf(token.Pos(0))
+
+func killPos(v reflect.Value) {
+ switch v.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ if !v.IsNil() {
+ killPos(v.Elem())
+ }
+ case reflect.Slice:
+ n := v.Len()
+ for i := 0; i < n; i++ {
+ killPos(v.Index(i))
+ }
+ case reflect.Struct:
+ n := v.NumField()
+ for i := 0; i < n; i++ {
+ f := v.Field(i)
+ if f.Type() == posType {
+ f.SetInt(0)
+ continue
+ }
+ killPos(f)
+ }
+ }
+}
+
+// A Rename describes a single renaming.
+type rename struct {
+ OldImport string // only apply rename if this import is present
+ NewImport string // add this import during rewrite
+ Old string // old name: p.T or *p.T
+ New string // new name: p.T or *p.T
+}
+
+func renameFix(tab []rename) func(*ast.File) bool {
+ return func(f *ast.File) bool {
+ return renameFixTab(f, tab)
+ }
+}
+
+func parseName(s string) (ptr bool, pkg, nam string) {
+ i := strings.Index(s, ".")
+ if i < 0 {
+ panic("parseName: invalid name " + s)
+ }
+ if strings.HasPrefix(s, "*") {
+ ptr = true
+ s = s[1:]
+ i--
+ }
+ pkg = s[:i]
+ nam = s[i+1:]
+ return
+}
+
+func renameFixTab(f *ast.File, tab []rename) bool {
+ fixed := false
+ added := map[string]bool{}
+ check := map[string]bool{}
+ for _, t := range tab {
+ if !imports(f, t.OldImport) {
+ continue
+ }
+ optr, opkg, onam := parseName(t.Old)
+ walk(f, func(n interface{}) {
+ np, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ x := *np
+ if optr {
+ p, ok := x.(*ast.StarExpr)
+ if !ok {
+ return
+ }
+ x = p.X
+ }
+ if !isPkgDot(x, opkg, onam) {
+ return
+ }
+ if t.NewImport != "" && !added[t.NewImport] {
+ addImport(f, t.NewImport)
+ added[t.NewImport] = true
+ }
+ *np = expr(t.New)
+ check[t.OldImport] = true
+ fixed = true
+ })
+ }
+
+ for ipath := range check {
+ if !usesImport(f, ipath) {
+ deleteImport(f, ipath)
+ }
+ }
+ return fixed
+}
diff --git a/src/cmd/fix/go1pkgrename.go b/src/cmd/fix/go1pkgrename.go
new file mode 100644
index 000000000..f701f62f0
--- /dev/null
+++ b/src/cmd/fix/go1pkgrename.go
@@ -0,0 +1,146 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "strings"
+)
+
+func init() {
+ register(go1pkgrenameFix)
+}
+
+var go1pkgrenameFix = fix{
+ "go1rename",
+ "2011-11-08",
+ go1pkgrename,
+ `Rewrite imports for packages moved during transition to Go 1.
+
+http://codereview.appspot.com/5316078
+`,
+}
+
+var go1PackageRenames = []struct{ old, new string }{
+ {"asn1", "encoding/asn1"},
+ {"big", "math/big"},
+ {"cmath", "math/cmplx"},
+ {"csv", "encoding/csv"},
+ {"exec", "os/exec"},
+ {"exp/template/html", "html/template"},
+ {"gob", "encoding/gob"},
+ {"http", "net/http"},
+ {"http/cgi", "net/http/cgi"},
+ {"http/fcgi", "net/http/fcgi"},
+ {"http/httptest", "net/http/httptest"},
+ {"http/pprof", "net/http/pprof"},
+ {"json", "encoding/json"},
+ {"mail", "net/mail"},
+ {"rpc", "net/rpc"},
+ {"rpc/jsonrpc", "net/rpc/jsonrpc"},
+ {"scanner", "text/scanner"},
+ {"smtp", "net/smtp"},
+ {"syslog", "log/syslog"},
+ {"tabwriter", "text/tabwriter"},
+ {"template", "text/template"},
+ {"template/parse", "text/template/parse"},
+ {"rand", "math/rand"},
+ {"url", "net/url"},
+ {"utf16", "unicode/utf16"},
+ {"utf8", "unicode/utf8"},
+ {"xml", "encoding/xml"},
+
+ // go.crypto sub-repository
+ {"crypto/bcrypt", "code.google.com/p/go.crypto/bcrypt"},
+ {"crypto/blowfish", "code.google.com/p/go.crypto/blowfish"},
+ {"crypto/cast5", "code.google.com/p/go.crypto/cast5"},
+ {"crypto/md4", "code.google.com/p/go.crypto/md4"},
+ {"crypto/ocsp", "code.google.com/p/go.crypto/ocsp"},
+ {"crypto/openpgp", "code.google.com/p/go.crypto/openpgp"},
+ {"crypto/openpgp/armor", "code.google.com/p/go.crypto/openpgp/armor"},
+ {"crypto/openpgp/elgamal", "code.google.com/p/go.crypto/openpgp/elgamal"},
+ {"crypto/openpgp/errors", "code.google.com/p/go.crypto/openpgp/errors"},
+ {"crypto/openpgp/packet", "code.google.com/p/go.crypto/openpgp/packet"},
+ {"crypto/openpgp/s2k", "code.google.com/p/go.crypto/openpgp/s2k"},
+ {"crypto/ripemd160", "code.google.com/p/go.crypto/ripemd160"},
+ {"crypto/twofish", "code.google.com/p/go.crypto/twofish"},
+ {"crypto/xtea", "code.google.com/p/go.crypto/xtea"},
+ {"exp/ssh", "code.google.com/p/go.crypto/ssh"},
+
+ // go.image sub-repository
+ {"image/bmp", "code.google.com/p/go.image/bmp"},
+ {"image/tiff", "code.google.com/p/go.image/tiff"},
+
+ // go.net sub-repository
+ {"net/dict", "code.google.com/p/go.net/dict"},
+ {"net/websocket", "code.google.com/p/go.net/websocket"},
+ {"exp/spdy", "code.google.com/p/go.net/spdy"},
+ {"http/spdy", "code.google.com/p/go.net/spdy"},
+
+ // go.codereview sub-repository
+ {"encoding/git85", "code.google.com/p/go.codereview/git85"},
+ {"patch", "code.google.com/p/go.codereview/patch"},
+
+ // exp
+ {"ebnf", "exp/ebnf"},
+ {"go/types", "exp/types"},
+
+ // deleted
+ {"container/vector", ""},
+ {"exp/datafmt", ""},
+ {"go/typechecker", ""},
+ {"old/netchan", ""},
+ {"old/regexp", ""},
+ {"old/template", ""},
+ {"try", ""},
+}
+
+var go1PackageNameRenames = []struct{ newPath, old, new string }{
+ {"html/template", "html", "template"},
+ {"math/cmplx", "cmath", "cmplx"},
+}
+
+func go1pkgrename(f *ast.File) bool {
+ fixed := false
+
+ // First update the imports.
+ for _, rename := range go1PackageRenames {
+ spec := importSpec(f, rename.old)
+ if spec == nil {
+ continue
+ }
+ if rename.new == "" {
+ warn(spec.Pos(), "package %q has been deleted in Go 1", rename.old)
+ continue
+ }
+ if rewriteImport(f, rename.old, rename.new) {
+ fixed = true
+ }
+ if strings.HasPrefix(rename.new, "exp/") {
+ warn(spec.Pos(), "package %q is not part of Go 1", rename.new)
+ }
+ }
+ if !fixed {
+ return false
+ }
+
+ // Now update the package names used by importers.
+ for _, rename := range go1PackageNameRenames {
+ // These are rare packages, so do the import test before walking.
+ if imports(f, rename.newPath) {
+ walk(f, func(n interface{}) {
+ if sel, ok := n.(*ast.SelectorExpr); ok {
+ if isTopName(sel.X, rename.old) {
+ // We know Sel.X is an Ident.
+ sel.X.(*ast.Ident).Name = rename.new
+ return
+ }
+ }
+ })
+ }
+ }
+
+ return fixed
+}
diff --git a/src/cmd/fix/go1pkgrename_test.go b/src/cmd/fix/go1pkgrename_test.go
new file mode 100644
index 000000000..840e443b0
--- /dev/null
+++ b/src/cmd/fix/go1pkgrename_test.go
@@ -0,0 +1,139 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(go1pkgrenameTests, go1pkgrename)
+}
+
+var go1pkgrenameTests = []testCase{
+ {
+ Name: "go1rename.0",
+ In: `package main
+
+import (
+ "asn1"
+ "big"
+ "cmath"
+ "csv"
+ "exec"
+ "exp/template/html"
+ "gob"
+ "http"
+ "http/cgi"
+ "http/fcgi"
+ "http/httptest"
+ "http/pprof"
+ "json"
+ "mail"
+ "rand"
+ "rpc"
+ "rpc/jsonrpc"
+ "scanner"
+ "smtp"
+ "syslog"
+ "tabwriter"
+ "template"
+ "template/parse"
+ "url"
+ "utf16"
+ "utf8"
+ "xml"
+
+ "crypto/bcrypt"
+)
+`,
+ Out: `package main
+
+import (
+ "encoding/asn1"
+ "encoding/csv"
+ "encoding/gob"
+ "encoding/json"
+ "encoding/xml"
+ "html/template"
+ "log/syslog"
+ "math/big"
+ "math/cmplx"
+ "math/rand"
+ "net/http"
+ "net/http/cgi"
+ "net/http/fcgi"
+ "net/http/httptest"
+ "net/http/pprof"
+ "net/mail"
+ "net/rpc"
+ "net/rpc/jsonrpc"
+ "net/smtp"
+ "net/url"
+ "os/exec"
+ "text/scanner"
+ "text/tabwriter"
+ "text/template"
+ "text/template/parse"
+ "unicode/utf16"
+ "unicode/utf8"
+
+ "code.google.com/p/go.crypto/bcrypt"
+)
+`,
+ },
+ {
+ Name: "go1rename.1",
+ In: `package main
+
+import "cmath"
+import poot "exp/template/html"
+
+import (
+ "ebnf"
+ "old/regexp"
+)
+
+var _ = cmath.Sin
+var _ = poot.Poot
+`,
+ Out: `package main
+
+import "math/cmplx"
+import poot "html/template"
+
+import (
+ "exp/ebnf"
+ "old/regexp"
+)
+
+var _ = cmplx.Sin
+var _ = poot.Poot
+`,
+ },
+ {
+ Name: "go1rename.2",
+ In: `package foo
+
+import (
+ "fmt"
+ "http"
+ "url"
+
+ "google/secret/project/go"
+)
+
+func main() {}
+`,
+ Out: `package foo
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+
+ "google/secret/project/go"
+)
+
+func main() {}
+`,
+ },
+}
diff --git a/src/cmd/fix/go1rename.go b/src/cmd/fix/go1rename.go
new file mode 100644
index 000000000..9266c749c
--- /dev/null
+++ b/src/cmd/fix/go1rename.go
@@ -0,0 +1,167 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ register(go1renameFix)
+}
+
+var go1renameFix = fix{
+ "go1rename",
+ "2012-02-12",
+ renameFix(go1renameReplace),
+ `Rewrite package-level names that have been renamed in Go 1.
+
+http://codereview.appspot.com/5625045/
+http://codereview.appspot.com/5672072/
+`,
+}
+
+var go1renameReplace = []rename{
+ {
+ OldImport: "crypto/aes",
+ NewImport: "crypto/cipher",
+ Old: "*aes.Cipher",
+ New: "cipher.Block",
+ },
+ {
+ OldImport: "crypto/des",
+ NewImport: "crypto/cipher",
+ Old: "*des.Cipher",
+ New: "cipher.Block",
+ },
+ {
+ OldImport: "crypto/des",
+ NewImport: "crypto/cipher",
+ Old: "*des.TripleDESCipher",
+ New: "cipher.Block",
+ },
+ {
+ OldImport: "encoding/json",
+ NewImport: "",
+ Old: "json.MarshalForHTML",
+ New: "json.Marshal",
+ },
+ {
+ OldImport: "net/url",
+ NewImport: "",
+ Old: "url.ParseWithReference",
+ New: "url.Parse",
+ },
+ {
+ OldImport: "net/url",
+ NewImport: "",
+ Old: "url.ParseRequest",
+ New: "url.ParseRequestURI",
+ },
+ {
+ OldImport: "os",
+ NewImport: "syscall",
+ Old: "os.Exec",
+ New: "syscall.Exec",
+ },
+ {
+ OldImport: "runtime",
+ NewImport: "",
+ Old: "runtime.Cgocalls",
+ New: "runtime.NumCgoCall",
+ },
+ {
+ OldImport: "runtime",
+ NewImport: "",
+ Old: "runtime.Goroutines",
+ New: "runtime.NumGoroutine",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrPersistEOF",
+ New: "httputil.ErrPersistEOF",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrPipeline",
+ New: "httputil.ErrPipeline",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrClosed",
+ New: "httputil.ErrClosed",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ServerConn",
+ New: "httputil.ServerConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ClientConn",
+ New: "httputil.ClientConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewChunkedReader",
+ New: "httputil.NewChunkedReader",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewChunkedWriter",
+ New: "httputil.NewChunkedWriter",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ReverseProxy",
+ New: "httputil.ReverseProxy",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewSingleHostReverseProxy",
+ New: "httputil.NewSingleHostReverseProxy",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpRequest",
+ New: "httputil.DumpRequest",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpRequestOut",
+ New: "httputil.DumpRequestOut",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpResponse",
+ New: "httputil.DumpResponse",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewClientConn",
+ New: "httputil.NewClientConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewServerConn",
+ New: "httputil.NewServerConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewProxyClientConn",
+ New: "httputil.NewProxyClientConn",
+ },
+}
diff --git a/src/cmd/fix/go1rename_test.go b/src/cmd/fix/go1rename_test.go
new file mode 100644
index 000000000..90219ba71
--- /dev/null
+++ b/src/cmd/fix/go1rename_test.go
@@ -0,0 +1,195 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(go1renameTests, go1renameFix.f)
+}
+
+var go1renameTests = []testCase{
+ {
+ Name: "go1rename.0",
+ In: `package main
+
+import (
+ "crypto/aes"
+ "crypto/des"
+ "encoding/json"
+ "net/http"
+ "net/url"
+ "os"
+ "runtime"
+)
+
+var (
+ _ *aes.Cipher
+ _ *des.Cipher
+ _ *des.TripleDESCipher
+ _ = json.MarshalForHTML
+ _ = aes.New()
+ _ = url.Parse
+ _ = url.ParseWithReference
+ _ = url.ParseRequest
+ _ = os.Exec
+ _ = runtime.Cgocalls
+ _ = runtime.Goroutines
+ _ = http.ErrPersistEOF
+ _ = http.ErrPipeline
+ _ = http.ErrClosed
+ _ = http.NewSingleHostReverseProxy
+ _ = http.NewChunkedReader
+ _ = http.NewChunkedWriter
+ _ *http.ReverseProxy
+ _ *http.ClientConn
+ _ *http.ServerConn
+)
+`,
+ Out: `package main
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "encoding/json"
+ "net/http/httputil"
+ "net/url"
+ "runtime"
+ "syscall"
+)
+
+var (
+ _ cipher.Block
+ _ cipher.Block
+ _ cipher.Block
+ _ = json.Marshal
+ _ = aes.New()
+ _ = url.Parse
+ _ = url.Parse
+ _ = url.ParseRequestURI
+ _ = syscall.Exec
+ _ = runtime.NumCgoCall
+ _ = runtime.NumGoroutine
+ _ = httputil.ErrPersistEOF
+ _ = httputil.ErrPipeline
+ _ = httputil.ErrClosed
+ _ = httputil.NewSingleHostReverseProxy
+ _ = httputil.NewChunkedReader
+ _ = httputil.NewChunkedWriter
+ _ *httputil.ReverseProxy
+ _ *httputil.ClientConn
+ _ *httputil.ServerConn
+)
+`,
+ },
+ {
+ Name: "httputil.0",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+}
+`,
+ Out: `package main
+
+import "net/http/httputil"
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+}
+`,
+ },
+ {
+ Name: "httputil.1",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+}
+`,
+ Out: `package main
+
+import "net/http/httputil"
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+}
+`,
+ },
+ {
+ Name: "httputil.2",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+ http.Get("")
+}
+`,
+ Out: `package main
+
+import (
+ "net/http"
+ "net/http/httputil"
+)
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+ http.Get("")
+}
+`,
+ },
+}
diff --git a/src/cmd/fix/googlecode.go b/src/cmd/fix/googlecode.go
new file mode 100644
index 000000000..143781a74
--- /dev/null
+++ b/src/cmd/fix/googlecode.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "regexp"
+)
+
+func init() {
+ register(googlecodeFix)
+}
+
+var googlecodeFix = fix{
+ "googlecode",
+ "2011-11-21",
+ googlecode,
+ `Rewrite Google Code imports from the deprecated form
+"foo.googlecode.com/vcs/path" to "code.google.com/p/foo/path".
+`,
+}
+
+var googlecodeRe = regexp.MustCompile(`^([a-z0-9\-]+)\.googlecode\.com/(svn|git|hg)(/[a-z0-9A-Z_.\-/]+)?$`)
+
+func googlecode(f *ast.File) bool {
+ fixed := false
+
+ for _, s := range f.Imports {
+ old := importPath(s)
+ if m := googlecodeRe.FindStringSubmatch(old); m != nil {
+ new := "code.google.com/p/" + m[1] + m[3]
+ if rewriteImport(f, old, new) {
+ fixed = true
+ }
+ }
+ }
+
+ return fixed
+}
diff --git a/src/cmd/fix/googlecode_test.go b/src/cmd/fix/googlecode_test.go
new file mode 100644
index 000000000..c62ee4f32
--- /dev/null
+++ b/src/cmd/fix/googlecode_test.go
@@ -0,0 +1,31 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(googlecodeTests, googlecode)
+}
+
+var googlecodeTests = []testCase{
+ {
+ Name: "googlecode.0",
+ In: `package main
+
+import (
+ "foo.googlecode.com/hg/bar"
+ "go-qux-23.googlecode.com/svn"
+ "zap.googlecode.com/git/some/path"
+)
+`,
+ Out: `package main
+
+import (
+ "code.google.com/p/foo/bar"
+ "code.google.com/p/go-qux-23"
+ "code.google.com/p/zap/some/path"
+)
+`,
+ },
+}
diff --git a/src/cmd/fix/hashsum.go b/src/cmd/fix/hashsum.go
new file mode 100644
index 000000000..0df6ad749
--- /dev/null
+++ b/src/cmd/fix/hashsum.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(hashSumFix)
+}
+
+var hashSumFix = fix{
+ "hashsum",
+ "2011-11-30",
+ hashSumFn,
+ `Pass a nil argument to calls to hash.Sum
+
+This fix rewrites code so that it passes a nil argument to hash.Sum.
+The additional argument will allow callers to avoid an
+allocation in the future.
+
+http://codereview.appspot.com/5448065
+`,
+}
+
+// Type-checking configuration: tell the type-checker this basic
+// information about types, functions, and variables in external packages.
+var hashSumTypeConfig = &TypeConfig{
+ Var: map[string]string{
+ "crypto.MD4": "crypto.Hash",
+ "crypto.MD5": "crypto.Hash",
+ "crypto.SHA1": "crypto.Hash",
+ "crypto.SHA224": "crypto.Hash",
+ "crypto.SHA256": "crypto.Hash",
+ "crypto.SHA384": "crypto.Hash",
+ "crypto.SHA512": "crypto.Hash",
+ "crypto.MD5SHA1": "crypto.Hash",
+ "crypto.RIPEMD160": "crypto.Hash",
+ },
+
+ Func: map[string]string{
+ "adler32.New": "hash.Hash",
+ "crc32.New": "hash.Hash",
+ "crc32.NewIEEE": "hash.Hash",
+ "crc64.New": "hash.Hash",
+ "fnv.New32a": "hash.Hash",
+ "fnv.New32": "hash.Hash",
+ "fnv.New64a": "hash.Hash",
+ "fnv.New64": "hash.Hash",
+ "hmac.New": "hash.Hash",
+ "hmac.NewMD5": "hash.Hash",
+ "hmac.NewSHA1": "hash.Hash",
+ "hmac.NewSHA256": "hash.Hash",
+ "md4.New": "hash.Hash",
+ "md5.New": "hash.Hash",
+ "ripemd160.New": "hash.Hash",
+ "sha1.New224": "hash.Hash",
+ "sha1.New": "hash.Hash",
+ "sha256.New224": "hash.Hash",
+ "sha256.New": "hash.Hash",
+ "sha512.New384": "hash.Hash",
+ "sha512.New": "hash.Hash",
+ },
+
+ Type: map[string]*Type{
+ "crypto.Hash": {
+ Method: map[string]string{
+ "New": "func() hash.Hash",
+ },
+ },
+ },
+}
+
+func hashSumFn(f *ast.File) bool {
+ typeof, _ := typecheck(hashSumTypeConfig, f)
+
+ fixed := false
+
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if ok && len(call.Args) == 0 {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if ok && sel.Sel.Name == "Sum" && typeof[sel.X] == "hash.Hash" {
+ call.Args = append(call.Args, ast.NewIdent("nil"))
+ fixed = true
+ }
+ }
+ })
+
+ return fixed
+}
diff --git a/src/cmd/fix/hashsum_test.go b/src/cmd/fix/hashsum_test.go
new file mode 100644
index 000000000..241af2020
--- /dev/null
+++ b/src/cmd/fix/hashsum_test.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 main
+
+func init() {
+ addTestCases(hashSumTests, hashSumFn)
+}
+
+var hashSumTests = []testCase{
+ {
+ Name: "hashsum.0",
+ In: `package main
+
+import "crypto/sha256"
+
+func f() []byte {
+ h := sha256.New()
+ return h.Sum()
+}
+`,
+ Out: `package main
+
+import "crypto/sha256"
+
+func f() []byte {
+ h := sha256.New()
+ return h.Sum(nil)
+}
+`,
+ },
+
+ {
+ Name: "hashsum.1",
+ In: `package main
+
+func f(h hash.Hash) []byte {
+ return h.Sum()
+}
+`,
+ Out: `package main
+
+func f(h hash.Hash) []byte {
+ return h.Sum(nil)
+}
+`,
+ },
+
+ {
+ Name: "hashsum.0",
+ In: `package main
+
+import "crypto/sha256"
+
+func f() []byte {
+ h := sha256.New()
+ h.Write([]byte("foo"))
+ digest := h.Sum()
+}
+`,
+ Out: `package main
+
+import "crypto/sha256"
+
+func f() []byte {
+ h := sha256.New()
+ h.Write([]byte("foo"))
+ digest := h.Sum(nil)
+}
+`,
+ },
+
+ {
+ Name: "hashsum.0",
+ In: `package main
+
+import _ "crypto/sha256"
+import "crypto"
+
+func f() []byte {
+ hashType := crypto.SHA256
+ h := hashType.New()
+ digest := h.Sum()
+}
+`,
+ Out: `package main
+
+import _ "crypto/sha256"
+import "crypto"
+
+func f() []byte {
+ hashType := crypto.SHA256
+ h := hashType.New()
+ digest := h.Sum(nil)
+}
+`,
+ },
+}
diff --git a/src/cmd/fix/hmacnew.go b/src/cmd/fix/hmacnew.go
new file mode 100644
index 000000000..c0c44ef3e
--- /dev/null
+++ b/src/cmd/fix/hmacnew.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 main
+
+import "go/ast"
+
+func init() {
+ register(hmacNewFix)
+}
+
+var hmacNewFix = fix{
+ "hmacnew",
+ "2012-01-19",
+ hmacnew,
+ `Deprecate hmac.NewMD5, hmac.NewSHA1 and hmac.NewSHA256.
+
+This fix rewrites code using hmac.NewMD5, hmac.NewSHA1 and hmac.NewSHA256 to
+use hmac.New:
+
+ hmac.NewMD5(key) -> hmac.New(md5.New, key)
+ hmac.NewSHA1(key) -> hmac.New(sha1.New, key)
+ hmac.NewSHA256(key) -> hmac.New(sha256.New, key)
+
+`,
+}
+
+func hmacnew(f *ast.File) (fixed bool) {
+ if !imports(f, "crypto/hmac") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ ce, ok := n.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ var pkg string
+ switch {
+ case isPkgDot(ce.Fun, "hmac", "NewMD5"):
+ pkg = "md5"
+ case isPkgDot(ce.Fun, "hmac", "NewSHA1"):
+ pkg = "sha1"
+ case isPkgDot(ce.Fun, "hmac", "NewSHA256"):
+ pkg = "sha256"
+ default:
+ return
+ }
+
+ addImport(f, "crypto/"+pkg)
+
+ ce.Fun = ast.NewIdent("hmac.New")
+ ce.Args = append([]ast.Expr{ast.NewIdent(pkg + ".New")}, ce.Args...)
+
+ fixed = true
+ })
+
+ return
+}
diff --git a/src/cmd/fix/hmacnew_test.go b/src/cmd/fix/hmacnew_test.go
new file mode 100644
index 000000000..5aeee8573
--- /dev/null
+++ b/src/cmd/fix/hmacnew_test.go
@@ -0,0 +1,107 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(hmacNewTests, hmacnew)
+}
+
+var hmacNewTests = []testCase{
+ {
+ Name: "hmacnew.0",
+ In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewSHA1([]byte("some key"))
+`,
+ Out: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+ },
+ {
+ Name: "hmacnew.1",
+ In: `package main
+
+import "crypto/hmac"
+
+var key = make([]byte, 8)
+var f = hmac.NewSHA1(key)
+`,
+ Out: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+)
+
+var key = make([]byte, 8)
+var f = hmac.New(sha1.New, key)
+`,
+ },
+ {
+ Name: "hmacnew.2",
+ In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewMD5([]byte("some key"))
+`,
+ Out: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/md5"
+)
+
+var f = hmac.New(md5.New, []byte("some key"))
+`,
+ },
+ {
+ Name: "hmacnew.3",
+ In: `package main
+
+import "crypto/hmac"
+
+var f = hmac.NewSHA256([]byte("some key"))
+`,
+ Out: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+)
+
+var f = hmac.New(sha256.New, []byte("some key"))
+`,
+ },
+ {
+ Name: "hmacnew.4",
+ In: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+ Out: `package main
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+)
+
+var f = hmac.New(sha1.New, []byte("some key"))
+`,
+ },
+}
diff --git a/src/cmd/fix/htmlerr.go b/src/cmd/fix/htmlerr.go
new file mode 100644
index 000000000..b5105c822
--- /dev/null
+++ b/src/cmd/fix/htmlerr.go
@@ -0,0 +1,47 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(htmlerrFix)
+}
+
+var htmlerrFix = fix{
+ "htmlerr",
+ "2011-11-04",
+ htmlerr,
+ `Rename html's Tokenizer.Error method to Err.
+
+http://codereview.appspot.com/5327064/
+`,
+}
+
+var htmlerrTypeConfig = &TypeConfig{
+ Func: map[string]string{
+ "html.NewTokenizer": "html.Tokenizer",
+ },
+}
+
+func htmlerr(f *ast.File) bool {
+ if !imports(f, "html") {
+ return false
+ }
+
+ typeof, _ := typecheck(htmlerrTypeConfig, f)
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if ok && typeof[s.X] == "html.Tokenizer" && s.Sel.Name == "Error" {
+ s.Sel.Name = "Err"
+ fixed = true
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/fix/htmlerr_test.go b/src/cmd/fix/htmlerr_test.go
new file mode 100644
index 000000000..043abc42a
--- /dev/null
+++ b/src/cmd/fix/htmlerr_test.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(htmlerrTests, htmlerr)
+}
+
+var htmlerrTests = []testCase{
+ {
+ Name: "htmlerr.0",
+ In: `package main
+
+import (
+ "html"
+)
+
+func f() {
+ e := errors.New("")
+ t := html.NewTokenizer(r)
+ _, _ = e.Error(), t.Error()
+}
+`,
+ Out: `package main
+
+import (
+ "html"
+)
+
+func f() {
+ e := errors.New("")
+ t := html.NewTokenizer(r)
+ _, _ = e.Error(), t.Err()
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/fix/httpfinalurl.go
index 9e6cbf6bc..49b9f1c51 100644
--- a/src/cmd/gofix/httpfinalurl.go
+++ b/src/cmd/fix/httpfinalurl.go
@@ -8,8 +8,13 @@ import (
"go/ast"
)
+func init() {
+ register(httpFinalURLFix)
+}
+
var httpFinalURLFix = fix{
"httpfinalurl",
+ "2011-05-13",
httpfinalurl,
`Adapt http Get calls to not have a finalURL result parameter.
@@ -17,10 +22,6 @@ http://codereview.appspot.com/4535056/
`,
}
-func init() {
- register(httpFinalURLFix)
-}
-
func httpfinalurl(f *ast.File) bool {
if !imports(f, "http") {
return false
diff --git a/src/cmd/gofix/httpfinalurl_test.go b/src/cmd/fix/httpfinalurl_test.go
index 9e7d6242d..9249f7e18 100644
--- a/src/cmd/gofix/httpfinalurl_test.go
+++ b/src/cmd/fix/httpfinalurl_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(httpfinalurlTests)
+ addTestCases(httpfinalurlTests, httpfinalurl)
}
var httpfinalurlTests = []testCase{
diff --git a/src/cmd/gofix/httpfs.go b/src/cmd/fix/httpfs.go
index 7f2765680..d87b30f9d 100644
--- a/src/cmd/gofix/httpfs.go
+++ b/src/cmd/fix/httpfs.go
@@ -9,8 +9,13 @@ import (
"go/token"
)
+func init() {
+ register(httpFileSystemFix)
+}
+
var httpFileSystemFix = fix{
"httpfs",
+ "2011-06-27",
httpfs,
`Adapt http FileServer to take a FileSystem.
@@ -18,10 +23,6 @@ http://codereview.appspot.com/4629047 http FileSystem interface
`,
}
-func init() {
- register(httpFileSystemFix)
-}
-
func httpfs(f *ast.File) bool {
if !imports(f, "http") {
return false
@@ -38,7 +39,10 @@ func httpfs(f *ast.File) bool {
}
dir, prefix := call.Args[0], call.Args[1]
call.Args = []ast.Expr{&ast.CallExpr{
- Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("Dir")},
+ Fun: &ast.SelectorExpr{
+ X: ast.NewIdent("http"),
+ Sel: ast.NewIdent("Dir"),
+ },
Args: []ast.Expr{dir},
}}
wrapInStripHandler := true
@@ -52,7 +56,10 @@ func httpfs(f *ast.File) bool {
call.Args = []ast.Expr{
prefix,
&ast.CallExpr{
- Fun: &ast.SelectorExpr{ast.NewIdent("http"), ast.NewIdent("FileServer")},
+ Fun: &ast.SelectorExpr{
+ X: ast.NewIdent("http"),
+ Sel: ast.NewIdent("FileServer"),
+ },
Args: call.Args,
},
}
diff --git a/src/cmd/gofix/httpfs_test.go b/src/cmd/fix/httpfs_test.go
index d1804e93b..dd8ef2cfd 100644
--- a/src/cmd/gofix/httpfs_test.go
+++ b/src/cmd/fix/httpfs_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(httpFileSystemTests)
+ addTestCases(httpFileSystemTests, httpfs)
}
var httpFileSystemTests = []testCase{
diff --git a/src/cmd/gofix/httpheaders.go b/src/cmd/fix/httpheaders.go
index 8a9080e8e..15c21ac86 100644
--- a/src/cmd/gofix/httpheaders.go
+++ b/src/cmd/fix/httpheaders.go
@@ -8,8 +8,13 @@ import (
"go/ast"
)
+func init() {
+ register(httpHeadersFix)
+}
+
var httpHeadersFix = fix{
"httpheaders",
+ "2011-06-16",
httpheaders,
`Rename http Referer, UserAgent, Cookie, SetCookie, which are now methods.
@@ -17,10 +22,6 @@ http://codereview.appspot.com/4620049/
`,
}
-func init() {
- register(httpHeadersFix)
-}
-
func httpheaders(f *ast.File) bool {
if !imports(f, "http") {
return false
@@ -35,7 +36,7 @@ func httpheaders(f *ast.File) bool {
})
fixed := false
- typeof := typecheck(headerTypeConfig, f)
+ typeof, _ := typecheck(headerTypeConfig, f)
walk(f, func(ni interface{}) {
switch n := ni.(type) {
case *ast.SelectorExpr:
@@ -60,7 +61,7 @@ func httpheaders(f *ast.File) bool {
var headerTypeConfig = &TypeConfig{
Type: map[string]*Type{
- "*http.Request": &Type{},
- "*http.Response": &Type{},
+ "*http.Request": {},
+ "*http.Response": {},
},
}
diff --git a/src/cmd/gofix/httpheaders_test.go b/src/cmd/fix/httpheaders_test.go
index cc82b5893..37506b82d 100644
--- a/src/cmd/gofix/httpheaders_test.go
+++ b/src/cmd/fix/httpheaders_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(httpHeadersTests)
+ addTestCases(httpHeadersTests, httpheaders)
}
var httpHeadersTests = []testCase{
diff --git a/src/cmd/gofix/httpserver.go b/src/cmd/fix/httpserver.go
index 37866e88b..7aa651786 100644
--- a/src/cmd/gofix/httpserver.go
+++ b/src/cmd/fix/httpserver.go
@@ -9,8 +9,13 @@ import (
"go/token"
)
+func init() {
+ register(httpserverFix)
+}
+
var httpserverFix = fix{
"httpserver",
+ "2011-03-15",
httpserver,
`Adapt http server methods and functions to changes
made to the http ResponseWriter interface.
@@ -22,10 +27,6 @@ http://codereview.appspot.com/4248075 RemoteAddr, UsingTLS
`,
}
-func init() {
- register(httpserverFix)
-}
-
func httpserver(f *ast.File) bool {
if !imports(f, "http") {
return false
diff --git a/src/cmd/gofix/httpserver_test.go b/src/cmd/fix/httpserver_test.go
index 89bb4fa71..b6ddff27e 100644
--- a/src/cmd/gofix/httpserver_test.go
+++ b/src/cmd/fix/httpserver_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(httpserverTests)
+ addTestCases(httpserverTests, httpserver)
}
var httpserverTests = []testCase{
diff --git a/src/cmd/fix/imagecolor.go b/src/cmd/fix/imagecolor.go
new file mode 100644
index 000000000..1aac40a6f
--- /dev/null
+++ b/src/cmd/fix/imagecolor.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 main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(imagecolorFix)
+}
+
+var imagecolorFix = fix{
+ "imagecolor",
+ "2011-10-04",
+ imagecolor,
+ `Adapt code to types moved from image to color.
+
+http://codereview.appspot.com/5132048
+`,
+}
+
+var colorRenames = []struct{ in, out string }{
+ {"Color", "Color"},
+ {"ColorModel", "Model"},
+ {"ColorModelFunc", "ModelFunc"},
+ {"PalettedColorModel", "Palette"},
+
+ {"RGBAColor", "RGBA"},
+ {"RGBA64Color", "RGBA64"},
+ {"NRGBAColor", "NRGBA"},
+ {"NRGBA64Color", "NRGBA64"},
+ {"AlphaColor", "Alpha"},
+ {"Alpha16Color", "Alpha16"},
+ {"GrayColor", "Gray"},
+ {"Gray16Color", "Gray16"},
+
+ {"RGBAColorModel", "RGBAModel"},
+ {"RGBA64ColorModel", "RGBA64Model"},
+ {"NRGBAColorModel", "NRGBAModel"},
+ {"NRGBA64ColorModel", "NRGBA64Model"},
+ {"AlphaColorModel", "AlphaModel"},
+ {"Alpha16ColorModel", "Alpha16Model"},
+ {"GrayColorModel", "GrayModel"},
+ {"Gray16ColorModel", "Gray16Model"},
+}
+
+func imagecolor(f *ast.File) (fixed bool) {
+ if !imports(f, "image") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+
+ if !ok || !isTopName(s.X, "image") {
+ return
+ }
+
+ switch sel := s.Sel.String(); {
+ case sel == "ColorImage":
+ s.Sel = &ast.Ident{Name: "Uniform"}
+ fixed = true
+ case sel == "NewColorImage":
+ s.Sel = &ast.Ident{Name: "NewUniform"}
+ fixed = true
+ default:
+ for _, rename := range colorRenames {
+ if sel == rename.in {
+ addImport(f, "image/color")
+ s.X.(*ast.Ident).Name = "color"
+ s.Sel.Name = rename.out
+ fixed = true
+ }
+ }
+ }
+ })
+
+ if fixed && !usesImport(f, "image") {
+ deleteImport(f, "image")
+ }
+ return
+}
diff --git a/src/cmd/fix/imagecolor_test.go b/src/cmd/fix/imagecolor_test.go
new file mode 100644
index 000000000..c62365481
--- /dev/null
+++ b/src/cmd/fix/imagecolor_test.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(colorTests, imagecolor)
+}
+
+var colorTests = []testCase{
+ {
+ Name: "color.0",
+ In: `package main
+
+import (
+ "image"
+)
+
+var (
+ _ image.Image
+ _ image.RGBA
+ _ image.Black
+ _ image.Color
+ _ image.ColorModel
+ _ image.ColorModelFunc
+ _ image.PalettedColorModel
+ _ image.RGBAColor
+ _ image.RGBA64Color
+ _ image.NRGBAColor
+ _ image.NRGBA64Color
+ _ image.AlphaColor
+ _ image.Alpha16Color
+ _ image.GrayColor
+ _ image.Gray16Color
+)
+
+func f() {
+ _ = image.RGBAColorModel
+ _ = image.RGBA64ColorModel
+ _ = image.NRGBAColorModel
+ _ = image.NRGBA64ColorModel
+ _ = image.AlphaColorModel
+ _ = image.Alpha16ColorModel
+ _ = image.GrayColorModel
+ _ = image.Gray16ColorModel
+}
+`,
+ Out: `package main
+
+import (
+ "image"
+ "image/color"
+)
+
+var (
+ _ image.Image
+ _ image.RGBA
+ _ image.Black
+ _ color.Color
+ _ color.Model
+ _ color.ModelFunc
+ _ color.Palette
+ _ color.RGBA
+ _ color.RGBA64
+ _ color.NRGBA
+ _ color.NRGBA64
+ _ color.Alpha
+ _ color.Alpha16
+ _ color.Gray
+ _ color.Gray16
+)
+
+func f() {
+ _ = color.RGBAModel
+ _ = color.RGBA64Model
+ _ = color.NRGBAModel
+ _ = color.NRGBA64Model
+ _ = color.AlphaModel
+ _ = color.Alpha16Model
+ _ = color.GrayModel
+ _ = color.Gray16Model
+}
+`,
+ },
+ {
+ Name: "color.1",
+ In: `package main
+
+import (
+ "fmt"
+ "image"
+)
+
+func f() {
+ fmt.Println(image.RGBAColor{1, 2, 3, 4}.RGBA())
+}
+`,
+ Out: `package main
+
+import (
+ "fmt"
+ "image/color"
+)
+
+func f() {
+ fmt.Println(color.RGBA{1, 2, 3, 4}.RGBA())
+}
+`,
+ },
+ {
+ Name: "color.2",
+ In: `package main
+
+import "image"
+
+var c *image.ColorImage = image.NewColorImage(nil)
+`,
+ Out: `package main
+
+import "image"
+
+var c *image.Uniform = image.NewUniform(nil)
+`,
+ },
+}
diff --git a/src/cmd/fix/imagenew.go b/src/cmd/fix/imagenew.go
new file mode 100644
index 000000000..b4e36d4f0
--- /dev/null
+++ b/src/cmd/fix/imagenew.go
@@ -0,0 +1,83 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(imagenewFix)
+}
+
+var imagenewFix = fix{
+ "imagenew",
+ "2011-09-14",
+ imagenew,
+ `Adapt image.NewXxx calls to pass an image.Rectangle instead of (w, h int).
+
+http://codereview.appspot.com/4964073
+`,
+}
+
+var imagenewFuncs = map[string]bool{
+ "NewRGBA": true,
+ "NewRGBA64": true,
+ "NewNRGBA": true,
+ "NewNRGBA64": true,
+ "NewAlpha": true,
+ "NewAlpha16": true,
+ "NewGray": true,
+ "NewGray16": true,
+}
+
+func imagenew(f *ast.File) bool {
+ if !imports(f, "image") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ call, ok := n.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+ isNewFunc := false
+ for newFunc := range imagenewFuncs {
+ if len(call.Args) == 2 && isPkgDot(call.Fun, "image", newFunc) {
+ isNewFunc = true
+ break
+ }
+ }
+ if len(call.Args) == 3 && isPkgDot(call.Fun, "image", "NewPaletted") {
+ isNewFunc = true
+ }
+ if !isNewFunc {
+ return
+ }
+ // Replace image.NewXxx(w, h) with image.NewXxx(image.Rect(0, 0, w, h)).
+ rectArgs := []ast.Expr{
+ &ast.BasicLit{Value: "0"},
+ &ast.BasicLit{Value: "0"},
+ }
+ rectArgs = append(rectArgs, call.Args[:2]...)
+ rect := []ast.Expr{
+ &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: &ast.Ident{
+ Name: "image",
+ },
+ Sel: &ast.Ident{
+ Name: "Rect",
+ },
+ },
+ Args: rectArgs,
+ },
+ }
+ call.Args = append(rect, call.Args[2:]...)
+ fixed = true
+ })
+ return fixed
+}
diff --git a/src/cmd/fix/imagenew_test.go b/src/cmd/fix/imagenew_test.go
new file mode 100644
index 000000000..30abed23c
--- /dev/null
+++ b/src/cmd/fix/imagenew_test.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 main
+
+func init() {
+ addTestCases(imagenewTests, imagenew)
+}
+
+var imagenewTests = []testCase{
+ {
+ Name: "imagenew.0",
+ In: `package main
+
+import (
+ "image"
+)
+
+func f() {
+ image.NewRGBA(1, 2)
+ image.NewRGBA64(1, 2)
+ image.NewNRGBA(1, 2)
+ image.NewNRGBA64(1, 2)
+ image.NewAlpha(1, 2)
+ image.NewAlpha16(1, 2)
+ image.NewGray(1, 2)
+ image.NewGray16(1, 2)
+ image.NewPaletted(1, 2, nil)
+}
+`,
+ Out: `package main
+
+import (
+ "image"
+)
+
+func f() {
+ image.NewRGBA(image.Rect(0, 0, 1, 2))
+ image.NewRGBA64(image.Rect(0, 0, 1, 2))
+ image.NewNRGBA(image.Rect(0, 0, 1, 2))
+ image.NewNRGBA64(image.Rect(0, 0, 1, 2))
+ image.NewAlpha(image.Rect(0, 0, 1, 2))
+ image.NewAlpha16(image.Rect(0, 0, 1, 2))
+ image.NewGray(image.Rect(0, 0, 1, 2))
+ image.NewGray16(image.Rect(0, 0, 1, 2))
+ image.NewPaletted(image.Rect(0, 0, 1, 2), nil)
+}
+`,
+ },
+}
diff --git a/src/cmd/fix/imageycbcr.go b/src/cmd/fix/imageycbcr.go
new file mode 100644
index 000000000..41b96d18d
--- /dev/null
+++ b/src/cmd/fix/imageycbcr.go
@@ -0,0 +1,64 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(imageycbcrFix)
+}
+
+var imageycbcrFix = fix{
+ "imageycbcr",
+ "2011-12-20",
+ imageycbcr,
+ `Adapt code to types moved from image/ycbcr to image and image/color.
+
+http://codereview.appspot.com/5493084
+`,
+}
+
+func imageycbcr(f *ast.File) (fixed bool) {
+ if !imports(f, "image/ycbcr") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+
+ if !ok || !isTopName(s.X, "ycbcr") {
+ return
+ }
+
+ switch s.Sel.String() {
+ case "RGBToYCbCr", "YCbCrToRGB":
+ addImport(f, "image/color")
+ s.X.(*ast.Ident).Name = "color"
+ case "YCbCrColor":
+ addImport(f, "image/color")
+ s.X.(*ast.Ident).Name = "color"
+ s.Sel.Name = "YCbCr"
+ case "YCbCrColorModel":
+ addImport(f, "image/color")
+ s.X.(*ast.Ident).Name = "color"
+ s.Sel.Name = "YCbCrModel"
+ case "SubsampleRatio", "SubsampleRatio444", "SubsampleRatio422", "SubsampleRatio420":
+ addImport(f, "image")
+ s.X.(*ast.Ident).Name = "image"
+ s.Sel.Name = "YCbCr" + s.Sel.Name
+ case "YCbCr":
+ addImport(f, "image")
+ s.X.(*ast.Ident).Name = "image"
+ default:
+ return
+ }
+ fixed = true
+ })
+
+ deleteImport(f, "image/ycbcr")
+ return
+}
diff --git a/src/cmd/fix/imageycbcr_test.go b/src/cmd/fix/imageycbcr_test.go
new file mode 100644
index 000000000..23b599dcd
--- /dev/null
+++ b/src/cmd/fix/imageycbcr_test.go
@@ -0,0 +1,54 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(ycbcrTests, imageycbcr)
+}
+
+var ycbcrTests = []testCase{
+ {
+ Name: "ycbcr.0",
+ In: `package main
+
+import (
+ "image/ycbcr"
+)
+
+func f() {
+ _ = ycbcr.RGBToYCbCr
+ _ = ycbcr.YCbCrToRGB
+ _ = ycbcr.YCbCrColorModel
+ var _ ycbcr.YCbCrColor
+ var _ ycbcr.YCbCr
+ var (
+ _ ycbcr.SubsampleRatio = ycbcr.SubsampleRatio444
+ _ ycbcr.SubsampleRatio = ycbcr.SubsampleRatio422
+ _ ycbcr.SubsampleRatio = ycbcr.SubsampleRatio420
+ )
+}
+`,
+ Out: `package main
+
+import (
+ "image"
+ "image/color"
+)
+
+func f() {
+ _ = color.RGBToYCbCr
+ _ = color.YCbCrToRGB
+ _ = color.YCbCrModel
+ var _ color.YCbCr
+ var _ image.YCbCr
+ var (
+ _ image.YCbCrSubsampleRatio = image.YCbCrSubsampleRatio444
+ _ image.YCbCrSubsampleRatio = image.YCbCrSubsampleRatio422
+ _ image.YCbCrSubsampleRatio = image.YCbCrSubsampleRatio420
+ )
+}
+`,
+ },
+}
diff --git a/src/cmd/fix/import_test.go b/src/cmd/fix/import_test.go
new file mode 100644
index 000000000..730119205
--- /dev/null
+++ b/src/cmd/fix/import_test.go
@@ -0,0 +1,458 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+ addTestCases(importTests, nil)
+}
+
+var importTests = []testCase{
+ {
+ Name: "import.0",
+ Fn: addImportFn("os"),
+ In: `package main
+
+import (
+ "os"
+)
+`,
+ Out: `package main
+
+import (
+ "os"
+)
+`,
+ },
+ {
+ Name: "import.1",
+ Fn: addImportFn("os"),
+ In: `package main
+`,
+ Out: `package main
+
+import "os"
+`,
+ },
+ {
+ Name: "import.2",
+ Fn: addImportFn("os"),
+ In: `package main
+
+// Comment
+import "C"
+`,
+ Out: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+ },
+ {
+ Name: "import.3",
+ Fn: addImportFn("os"),
+ In: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ Out: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ },
+ {
+ Name: "import.4",
+ Fn: deleteImportFn("os"),
+ In: `package main
+
+import (
+ "os"
+)
+`,
+ Out: `package main
+`,
+ },
+ {
+ Name: "import.5",
+ Fn: deleteImportFn("os"),
+ In: `package main
+
+// Comment
+import "C"
+import "os"
+`,
+ Out: `package main
+
+// Comment
+import "C"
+`,
+ },
+ {
+ Name: "import.6",
+ Fn: deleteImportFn("os"),
+ In: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ Out: `package main
+
+// Comment
+import "C"
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ },
+ {
+ Name: "import.7",
+ Fn: deleteImportFn("io"),
+ In: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ Out: `package main
+
+import (
+ // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ },
+ {
+ Name: "import.8",
+ Fn: deleteImportFn("os"),
+ In: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ Out: `package main
+
+import (
+ "io" // a
+ // b
+ "utf8" // c
+)
+`,
+ },
+ {
+ Name: "import.9",
+ Fn: deleteImportFn("utf8"),
+ In: `package main
+
+import (
+ "io" // a
+ "os" // b
+ "utf8" // c
+)
+`,
+ Out: `package main
+
+import (
+ "io" // a
+ "os" // b
+ // c
+)
+`,
+ },
+ {
+ Name: "import.10",
+ Fn: deleteImportFn("io"),
+ In: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ Out: `package main
+
+import (
+ "os"
+ "utf8"
+)
+`,
+ },
+ {
+ Name: "import.11",
+ Fn: deleteImportFn("os"),
+ In: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ Out: `package main
+
+import (
+ "io"
+ "utf8"
+)
+`,
+ },
+ {
+ Name: "import.12",
+ Fn: deleteImportFn("utf8"),
+ In: `package main
+
+import (
+ "io"
+ "os"
+ "utf8"
+)
+`,
+ Out: `package main
+
+import (
+ "io"
+ "os"
+)
+`,
+ },
+ {
+ Name: "import.13",
+ Fn: rewriteImportFn("utf8", "encoding/utf8"),
+ In: `package main
+
+import (
+ "io"
+ "os"
+ "utf8" // thanks ken
+)
+`,
+ Out: `package main
+
+import (
+ "encoding/utf8" // thanks ken
+ "io"
+ "os"
+)
+`,
+ },
+ {
+ Name: "import.14",
+ Fn: rewriteImportFn("asn1", "encoding/asn1"),
+ In: `package main
+
+import (
+ "asn1"
+ "crypto"
+ "crypto/rsa"
+ _ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "time"
+)
+
+var x = 1
+`,
+ Out: `package main
+
+import (
+ "crypto"
+ "crypto/rsa"
+ _ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "time"
+)
+
+var x = 1
+`,
+ },
+ {
+ Name: "import.15",
+ Fn: rewriteImportFn("url", "net/url"),
+ In: `package main
+
+import (
+ "bufio"
+ "net"
+ "path"
+ "url"
+)
+
+var x = 1 // comment on x, not on url
+`,
+ Out: `package main
+
+import (
+ "bufio"
+ "net"
+ "net/url"
+ "path"
+)
+
+var x = 1 // comment on x, not on url
+`,
+ },
+ {
+ Name: "import.16",
+ Fn: rewriteImportFn("http", "net/http", "template", "text/template"),
+ In: `package main
+
+import (
+ "flag"
+ "http"
+ "log"
+ "template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+ Out: `package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "text/template"
+)
+
+var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
+`,
+ },
+ {
+ Name: "import.17",
+ Fn: addImportFn("x/y/z", "x/a/c"),
+ In: `package main
+
+// Comment
+import "C"
+
+import (
+ "a"
+ "b"
+
+ "x/w"
+
+ "d/f"
+)
+`,
+ Out: `package main
+
+// Comment
+import "C"
+
+import (
+ "a"
+ "b"
+
+ "x/a/c"
+ "x/w"
+ "x/y/z"
+
+ "d/f"
+)
+`,
+ },
+ {
+ Name: "import.18",
+ Fn: addDelImportFn("e", "o"),
+ In: `package main
+
+import (
+ "f"
+ "o"
+ "z"
+)
+`,
+ Out: `package main
+
+import (
+ "e"
+ "f"
+ "z"
+)
+`,
+ },
+}
+
+func addImportFn(path ...string) func(*ast.File) bool {
+ return func(f *ast.File) bool {
+ fixed := false
+ for _, p := range path {
+ if !imports(f, p) {
+ addImport(f, p)
+ fixed = true
+ }
+ }
+ return fixed
+ }
+}
+
+func deleteImportFn(path string) func(*ast.File) bool {
+ return func(f *ast.File) bool {
+ if imports(f, path) {
+ deleteImport(f, path)
+ return true
+ }
+ return false
+ }
+}
+
+func addDelImportFn(p1 string, p2 string) func(*ast.File) bool {
+ return func(f *ast.File) bool {
+ fixed := false
+ if !imports(f, p1) {
+ addImport(f, p1)
+ fixed = true
+ }
+ if imports(f, p2) {
+ deleteImport(f, p2)
+ fixed = true
+ }
+ return fixed
+ }
+}
+
+func rewriteImportFn(oldnew ...string) func(*ast.File) bool {
+ return func(f *ast.File) bool {
+ fixed := false
+ for i := 0; i < len(oldnew); i += 2 {
+ if imports(f, oldnew[i]) {
+ rewriteImport(f, oldnew[i], oldnew[i+1])
+ fixed = true
+ }
+ }
+ return fixed
+ }
+}
diff --git a/src/cmd/fix/iocopyn.go b/src/cmd/fix/iocopyn.go
new file mode 100644
index 000000000..720f3c689
--- /dev/null
+++ b/src/cmd/fix/iocopyn.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(ioCopyNFix)
+}
+
+var ioCopyNFix = fix{
+ "iocopyn",
+ "2011-09-30",
+ ioCopyN,
+ `Rename io.Copyn to io.CopyN.
+
+http://codereview.appspot.com/5157045
+`,
+}
+
+func ioCopyN(f *ast.File) bool {
+ if !imports(f, "io") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ if expr, ok := n.(ast.Expr); ok {
+ if isPkgDot(expr, "io", "Copyn") {
+ expr.(*ast.SelectorExpr).Sel.Name = "CopyN"
+ fixed = true
+ return
+ }
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/fix/iocopyn_test.go b/src/cmd/fix/iocopyn_test.go
new file mode 100644
index 000000000..f86fad763
--- /dev/null
+++ b/src/cmd/fix/iocopyn_test.go
@@ -0,0 +1,37 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(ioCopyNTests, ioCopyN)
+}
+
+var ioCopyNTests = []testCase{
+ {
+ Name: "io.CopyN.0",
+ In: `package main
+
+import (
+ "io"
+)
+
+func f() {
+ io.Copyn(dst, src)
+ foo.Copyn(dst, src)
+}
+`,
+ Out: `package main
+
+import (
+ "io"
+)
+
+func f() {
+ io.CopyN(dst, src)
+ foo.Copyn(dst, src)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/fix/main.go
index e7e7013c5..b151408d7 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/fix/main.go
@@ -6,15 +6,16 @@ package main
import (
"bytes"
- "exec"
"flag"
"fmt"
+ "go/ast"
"go/parser"
"go/printer"
"go/scanner"
"go/token"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"sort"
"strings"
@@ -28,14 +29,21 @@ var (
var allowedRewrites = flag.String("r", "",
"restrict the rewrites to this comma-separated list")
-var allowed map[string]bool
+var forceRewrites = flag.String("force", "",
+ "force these fixes to run even if the code looks updated")
+
+var allowed, force map[string]bool
var doDiff = flag.Bool("diff", false, "display diffs instead of rewriting files")
+// enable for debugging fix failures
+const debug = false // display incorrectly reformatted source and exit
+
func usage() {
- fmt.Fprintf(os.Stderr, "usage: gofix [-diff] [-r fixname,...] [path ...]\n")
+ fmt.Fprintf(os.Stderr, "usage: go tool fix [-diff] [-r fixname,...] [-force fixname,...] [path ...]\n")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\nAvailable rewrites are:\n")
+ sort.Sort(byName(fixes))
for _, f := range fixes {
fmt.Fprintf(os.Stderr, "\n%s\n", f.name)
desc := strings.TrimSpace(f.desc)
@@ -46,11 +54,11 @@ func usage() {
}
func main() {
- sort.Sort(fixes)
-
flag.Usage = usage
flag.Parse()
+ sort.Sort(byDate(fixes))
+
if *allowedRewrites != "" {
allowed = make(map[string]bool)
for _, f := range strings.Split(*allowedRewrites, ",") {
@@ -58,6 +66,13 @@ func main() {
}
}
+ if *forceRewrites != "" {
+ force = make(map[string]bool)
+ for _, f := range strings.Split(*forceRewrites, ",") {
+ force[f] = true
+ }
+ }
+
if flag.NArg() == 0 {
if err := processFile("standard input", true); err != nil {
report(err)
@@ -70,12 +85,12 @@ func main() {
switch dir, err := os.Stat(path); {
case err != nil:
report(err)
- case dir.IsRegular():
+ case dir.IsDir():
+ walkDir(path)
+ default:
if err := processFile(path, false); err != nil {
report(err)
}
- case dir.IsDirectory():
- walkDir(path)
}
}
@@ -89,15 +104,25 @@ const (
)
var printConfig = &printer.Config{
- printerMode,
- tabWidth,
+ Mode: printerMode,
+ Tabwidth: tabWidth,
}
-func processFile(filename string, useStdin bool) os.Error {
+func gofmtFile(f *ast.File) ([]byte, error) {
+ var buf bytes.Buffer
+
+ ast.SortImports(fset, f)
+ err := printConfig.Fprint(&buf, fset, f)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func processFile(filename string, useStdin bool) error {
var f *os.File
- var err os.Error
+ var err error
var fixlog bytes.Buffer
- var buf bytes.Buffer
if useStdin {
f = os.Stdin
@@ -133,14 +158,17 @@ func processFile(filename string, useStdin bool) os.Error {
// AST changed.
// Print and parse, to update any missing scoping
// or position information for subsequent fixers.
- buf.Reset()
- _, err = printConfig.Fprint(&buf, fset, newFile)
+ newSrc, err := gofmtFile(newFile)
if err != nil {
return err
}
- newSrc := buf.Bytes()
newFile, err = parser.ParseFile(fset, filename, newSrc, parserMode)
if err != nil {
+ if debug {
+ fmt.Printf("%s", newSrc)
+ report(err)
+ os.Exit(exitCode)
+ }
return err
}
}
@@ -156,12 +184,10 @@ func processFile(filename string, useStdin bool) os.Error {
// output of the printer run on a standard AST generated by the parser,
// but the source we generated inside the loop above is the
// output of the printer run on a mangled AST generated by a fixer.
- buf.Reset()
- _, err = printConfig.Fprint(&buf, fset, newFile)
+ newSrc, err := gofmtFile(newFile)
if err != nil {
return err
}
- newSrc := buf.Bytes()
if *doDiff {
data, err := diff(src, newSrc)
@@ -185,60 +211,47 @@ var gofmtBuf bytes.Buffer
func gofmt(n interface{}) string {
gofmtBuf.Reset()
- _, err := printConfig.Fprint(&gofmtBuf, fset, n)
+ err := printConfig.Fprint(&gofmtBuf, fset, n)
if err != nil {
- return "<" + err.String() + ">"
+ return "<" + err.Error() + ">"
}
return gofmtBuf.String()
}
-func report(err os.Error) {
+func report(err error) {
scanner.PrintError(os.Stderr, err)
exitCode = 2
}
func walkDir(path string) {
- v := make(fileVisitor)
- go func() {
- filepath.Walk(path, v, v)
- close(v)
- }()
- for err := range v {
- if err != nil {
- report(err)
- }
- }
+ filepath.Walk(path, visitFile)
}
-type fileVisitor chan os.Error
-
-func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
- if isGoFile(f) {
- v <- nil // synchronize error handler
- if err := processFile(path, false); err != nil {
- v <- err
- }
+func visitFile(path string, f os.FileInfo, err error) error {
+ if err == nil && isGoFile(f) {
+ err = processFile(path, false)
+ }
+ if err != nil {
+ report(err)
}
+ return nil
}
-func isGoFile(f *os.FileInfo) bool {
+func isGoFile(f os.FileInfo) bool {
// ignore non-Go files
- return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
+ name := f.Name()
+ return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
-func diff(b1, b2 []byte) (data []byte, err os.Error) {
- f1, err := ioutil.TempFile("", "gofix")
+func diff(b1, b2 []byte) (data []byte, err error) {
+ f1, err := ioutil.TempFile("", "go-fix")
if err != nil {
return nil, err
}
defer os.Remove(f1.Name())
defer f1.Close()
- f2, err := ioutil.TempFile("", "gofix")
+ f2, err := ioutil.TempFile("", "go-fix")
if err != nil {
return nil, err
}
diff --git a/src/cmd/gofix/main_test.go b/src/cmd/fix/main_test.go
index 275778e5b..2151bf29e 100644
--- a/src/cmd/gofix/main_test.go
+++ b/src/cmd/fix/main_test.go
@@ -5,10 +5,8 @@
package main
import (
- "bytes"
"go/ast"
"go/parser"
- "go/printer"
"strings"
"testing"
)
@@ -22,27 +20,33 @@ type testCase struct {
var testCases []testCase
-func addTestCases(t []testCase) {
+func addTestCases(t []testCase, fn func(*ast.File) bool) {
+ // Fill in fn to avoid repetition in definitions.
+ if fn != nil {
+ for i := range t {
+ if t[i].Fn == nil {
+ t[i].Fn = fn
+ }
+ }
+ }
testCases = append(testCases, t...)
}
func fnop(*ast.File) bool { return false }
-func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out string, fixed, ok bool) {
+func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string, mustBeGofmt bool) (out string, fixed, ok bool) {
file, err := parser.ParseFile(fset, desc, in, parserMode)
if err != nil {
t.Errorf("%s: parsing: %v", desc, err)
return
}
- var buf bytes.Buffer
- buf.Reset()
- _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
+ outb, err := gofmtFile(file)
if err != nil {
t.Errorf("%s: printing: %v", desc, err)
return
}
- if s := buf.String(); in != s && fn != fnop {
+ if s := string(outb); in != s && mustBeGofmt {
t.Errorf("%s: not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s",
desc, desc, in, desc, s)
tdiff(t, in, s)
@@ -59,26 +63,25 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string) (out
fixed = fn(file)
}
- buf.Reset()
- _, err = (&printer.Config{printerMode, tabWidth}).Fprint(&buf, fset, file)
+ outb, err = gofmtFile(file)
if err != nil {
t.Errorf("%s: printing: %v", desc, err)
return
}
- return buf.String(), fixed, true
+ return string(outb), fixed, true
}
func TestRewrite(t *testing.T) {
for _, tt := range testCases {
// Apply fix: should get tt.Out.
- out, fixed, ok := parseFixPrint(t, tt.Fn, tt.Name, tt.In)
+ out, fixed, ok := parseFixPrint(t, tt.Fn, tt.Name, tt.In, true)
if !ok {
continue
}
// reformat to get printing right
- out, _, ok = parseFixPrint(t, fnop, tt.Name, out)
+ out, _, ok = parseFixPrint(t, fnop, tt.Name, out, false)
if !ok {
continue
}
@@ -98,7 +101,7 @@ func TestRewrite(t *testing.T) {
}
// Should not change if run again.
- out2, fixed2, ok := parseFixPrint(t, tt.Fn, tt.Name+" output", out)
+ out2, fixed2, ok := parseFixPrint(t, tt.Fn, tt.Name+" output", out, true)
if !ok {
continue
}
diff --git a/src/cmd/fix/mapdelete.go b/src/cmd/fix/mapdelete.go
new file mode 100644
index 000000000..db89c7bf4
--- /dev/null
+++ b/src/cmd/fix/mapdelete.go
@@ -0,0 +1,89 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+ register(mapdeleteFix)
+}
+
+var mapdeleteFix = fix{
+ "mapdelete",
+ "2011-10-18",
+ mapdelete,
+ `Use delete(m, k) instead of m[k] = 0, false.
+
+http://codereview.appspot.com/5272045
+`,
+}
+
+func mapdelete(f *ast.File) bool {
+ fixed := false
+ walk(f, func(n interface{}) {
+ stmt, ok := n.(*ast.Stmt)
+ if !ok {
+ return
+ }
+ as, ok := (*stmt).(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 1 || len(as.Rhs) != 2 {
+ return
+ }
+ ix, ok := as.Lhs[0].(*ast.IndexExpr)
+ if !ok {
+ return
+ }
+ if !isTopName(as.Rhs[1], "false") {
+ warn(as.Pos(), "two-element map assignment with non-false second value")
+ return
+ }
+ if !canDrop(as.Rhs[0]) {
+ warn(as.Pos(), "two-element map assignment with non-trivial first value")
+ return
+ }
+ *stmt = &ast.ExprStmt{
+ X: &ast.CallExpr{
+ Fun: &ast.Ident{
+ NamePos: as.Pos(),
+ Name: "delete",
+ },
+ Args: []ast.Expr{ix.X, ix.Index},
+ },
+ }
+ fixed = true
+ })
+ return fixed
+}
+
+// canDrop reports whether it is safe to drop the
+// evaluation of n from the program.
+// It is very conservative.
+func canDrop(n ast.Expr) bool {
+ switch n := n.(type) {
+ case *ast.Ident, *ast.BasicLit:
+ return true
+ case *ast.ParenExpr:
+ return canDrop(n.X)
+ case *ast.SelectorExpr:
+ return canDrop(n.X)
+ case *ast.CompositeLit:
+ if !canDrop(n.Type) {
+ return false
+ }
+ for _, e := range n.Elts {
+ if !canDrop(e) {
+ return false
+ }
+ }
+ return true
+ case *ast.StarExpr:
+ // Dropping *x is questionable,
+ // but we have to be able to drop (*T)(nil).
+ return canDrop(n.X)
+ case *ast.ArrayType, *ast.ChanType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.StructType:
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/fix/mapdelete_test.go b/src/cmd/fix/mapdelete_test.go
new file mode 100644
index 000000000..8ed50328e
--- /dev/null
+++ b/src/cmd/fix/mapdelete_test.go
@@ -0,0 +1,43 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(mapdeleteTests, mapdelete)
+}
+
+var mapdeleteTests = []testCase{
+ {
+ Name: "mapdelete.0",
+ In: `package main
+
+func f() {
+ m[x] = 0, false
+ m[x] = g(), false
+ m[x] = 1
+ delete(m, x)
+ m[x] = 0, b
+}
+
+func g(false bool) {
+ m[x] = 0, false
+}
+`,
+ Out: `package main
+
+func f() {
+ delete(m, x)
+ m[x] = g(), false
+ m[x] = 1
+ delete(m, x)
+ m[x] = 0, b
+}
+
+func g(false bool) {
+ m[x] = 0, false
+}
+`,
+ },
+}
diff --git a/src/cmd/fix/math.go b/src/cmd/fix/math.go
new file mode 100644
index 000000000..2ec837eb0
--- /dev/null
+++ b/src/cmd/fix/math.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 main
+
+import "go/ast"
+
+func init() {
+ register(mathFix)
+}
+
+var mathFix = fix{
+ "math",
+ "2011-09-29",
+ math,
+ `Remove the leading F from math functions such as Fabs.
+
+http://codereview.appspot.com/5158043
+`,
+}
+
+var mathRenames = []struct{ in, out string }{
+ {"Fabs", "Abs"},
+ {"Fdim", "Dim"},
+ {"Fmax", "Max"},
+ {"Fmin", "Min"},
+ {"Fmod", "Mod"},
+}
+
+func math(f *ast.File) bool {
+ if !imports(f, "math") {
+ return false
+ }
+
+ fixed := false
+
+ walk(f, func(n interface{}) {
+ // Rename functions.
+ if expr, ok := n.(ast.Expr); ok {
+ for _, s := range mathRenames {
+ if isPkgDot(expr, "math", s.in) {
+ expr.(*ast.SelectorExpr).Sel.Name = s.out
+ fixed = true
+ return
+ }
+ }
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/fix/math_test.go b/src/cmd/fix/math_test.go
new file mode 100644
index 000000000..b8d69d2f2
--- /dev/null
+++ b/src/cmd/fix/math_test.go
@@ -0,0 +1,47 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(mathTests, math)
+}
+
+var mathTests = []testCase{
+ {
+ Name: "math.0",
+ In: `package main
+
+import (
+ "math"
+)
+
+func f() {
+ math.Fabs(1)
+ math.Fdim(1)
+ math.Fmax(1)
+ math.Fmin(1)
+ math.Fmod(1)
+ math.Abs(1)
+ foo.Fabs(1)
+}
+`,
+ Out: `package main
+
+import (
+ "math"
+)
+
+func f() {
+ math.Abs(1)
+ math.Dim(1)
+ math.Max(1)
+ math.Min(1)
+ math.Mod(1)
+ math.Abs(1)
+ foo.Fabs(1)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/netdial.go b/src/cmd/fix/netdial.go
index afa98953b..2de994cff 100644
--- a/src/cmd/gofix/netdial.go
+++ b/src/cmd/fix/netdial.go
@@ -8,8 +8,15 @@ import (
"go/ast"
)
+func init() {
+ register(netdialFix)
+ register(tlsdialFix)
+ register(netlookupFix)
+}
+
var netdialFix = fix{
"netdial",
+ "2011-03-28",
netdial,
`Adapt 3-argument calls of net.Dial to use 2-argument form.
@@ -19,6 +26,7 @@ http://codereview.appspot.com/4244055
var tlsdialFix = fix{
"tlsdial",
+ "2011-03-28",
tlsdial,
`Adapt 4-argument calls of tls.Dial to use 3-argument form.
@@ -28,6 +36,7 @@ http://codereview.appspot.com/4244055
var netlookupFix = fix{
"netlookup",
+ "2011-03-28",
netlookup,
`Adapt 3-result calls to net.LookupHost to use 2-result form.
@@ -35,12 +44,6 @@ http://codereview.appspot.com/4244055
`,
}
-func init() {
- register(netdialFix)
- register(tlsdialFix)
- register(netlookupFix)
-}
-
func netdial(f *ast.File) bool {
if !imports(f, "net") {
return false
diff --git a/src/cmd/gofix/netdial_test.go b/src/cmd/fix/netdial_test.go
index 272aa526a..fff00b4ad 100644
--- a/src/cmd/gofix/netdial_test.go
+++ b/src/cmd/fix/netdial_test.go
@@ -1,12 +1,17 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package main
func init() {
- addTestCases(netdialTests)
+ addTestCases(netdialTests, nil)
}
var netdialTests = []testCase{
{
Name: "netdial.0",
+ Fn: netdial,
In: `package main
import "net"
@@ -29,6 +34,7 @@ func f() {
{
Name: "netlookup.0",
+ Fn: netlookup,
In: `package main
import "net"
diff --git a/src/cmd/fix/netudpgroup.go b/src/cmd/fix/netudpgroup.go
new file mode 100644
index 000000000..b54beb0de
--- /dev/null
+++ b/src/cmd/fix/netudpgroup.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(netudpgroupFix)
+}
+
+var netudpgroupFix = fix{
+ "netudpgroup",
+ "2011-08-18",
+ netudpgroup,
+ `Adapt 1-argument calls of net.(*UDPConn).JoinGroup, LeaveGroup to use 2-argument form.
+
+http://codereview.appspot.com/4815074
+`,
+}
+
+func netudpgroup(f *ast.File) bool {
+ if !imports(f, "net") {
+ return false
+ }
+
+ fixed := false
+ for _, d := range f.Decls {
+ fd, ok := d.(*ast.FuncDecl)
+ if !ok || fd.Body == nil {
+ continue
+ }
+ walk(fd.Body, func(n interface{}) {
+ ce, ok := n.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+ se, ok := ce.Fun.(*ast.SelectorExpr)
+ if !ok || len(ce.Args) != 1 {
+ return
+ }
+ switch se.Sel.String() {
+ case "JoinGroup", "LeaveGroup":
+ // c.JoinGroup(a) -> c.JoinGroup(nil, a)
+ // c.LeaveGroup(a) -> c.LeaveGroup(nil, a)
+ arg := ce.Args[0]
+ ce.Args = make([]ast.Expr, 2)
+ ce.Args[0] = ast.NewIdent("nil")
+ ce.Args[1] = arg
+ fixed = true
+ }
+ })
+ }
+ return fixed
+}
diff --git a/src/cmd/fix/netudpgroup_test.go b/src/cmd/fix/netudpgroup_test.go
new file mode 100644
index 000000000..88c0e093f
--- /dev/null
+++ b/src/cmd/fix/netudpgroup_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 main
+
+func init() {
+ addTestCases(netudpgroupTests, netudpgroup)
+}
+
+var netudpgroupTests = []testCase{
+ {
+ Name: "netudpgroup.0",
+ In: `package main
+
+import "net"
+
+func f() {
+ err := x.JoinGroup(gaddr)
+ err = y.LeaveGroup(gaddr)
+}
+`,
+ Out: `package main
+
+import "net"
+
+func f() {
+ err := x.JoinGroup(nil, gaddr)
+ err = y.LeaveGroup(nil, gaddr)
+}
+`,
+ },
+ // Innocent function with no body.
+ {
+ Name: "netudpgroup.1",
+ In: `package main
+
+import "net"
+
+func f()
+
+var _ net.IP
+`,
+ Out: `package main
+
+import "net"
+
+func f()
+
+var _ net.IP
+`,
+ },
+}
diff --git a/src/cmd/fix/newwriter.go b/src/cmd/fix/newwriter.go
new file mode 100644
index 000000000..4befe24fb
--- /dev/null
+++ b/src/cmd/fix/newwriter.go
@@ -0,0 +1,90 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(newWriterFix)
+}
+
+var newWriterFix = fix{
+ "newWriter",
+ "2012-02-14",
+ newWriter,
+ `Adapt bufio, gzip and zlib NewWriterXxx calls for whether they return errors.
+
+Also rename gzip.Compressor and gzip.Decompressor to gzip.Writer and gzip.Reader.
+
+http://codereview.appspot.com/5639057 and
+http://codereview.appspot.com/5642054
+`,
+}
+
+func newWriter(f *ast.File) bool {
+ if !imports(f, "bufio") && !imports(f, "compress/gzip") && !imports(f, "compress/zlib") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ switch n := n.(type) {
+ case *ast.SelectorExpr:
+ if isTopName(n.X, "gzip") {
+ switch n.Sel.String() {
+ case "Compressor":
+ n.Sel = &ast.Ident{Name: "Writer"}
+ fixed = true
+ case "Decompressor":
+ n.Sel = &ast.Ident{Name: "Reader"}
+ fixed = true
+ }
+ } else if isTopName(n.X, "zlib") {
+ if n.Sel.String() == "NewWriterDict" {
+ n.Sel = &ast.Ident{Name: "NewWriterLevelDict"}
+ fixed = true
+ }
+ }
+
+ case *ast.AssignStmt:
+ // Drop the ", _" in assignments of the form:
+ // w0, _ = gzip.NewWriter(w1)
+ if len(n.Lhs) != 2 || len(n.Rhs) != 1 {
+ return
+ }
+ i, ok := n.Lhs[1].(*ast.Ident)
+ if !ok {
+ return
+ }
+ if i.String() != "_" {
+ return
+ }
+ c, ok := n.Rhs[0].(*ast.CallExpr)
+ if !ok {
+ return
+ }
+ s, ok := c.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ sel := s.Sel.String()
+ switch {
+ case isTopName(s.X, "bufio") && (sel == "NewReaderSize" || sel == "NewWriterSize"):
+ // No-op.
+ case isTopName(s.X, "gzip") && sel == "NewWriter":
+ // No-op.
+ case isTopName(s.X, "zlib") && sel == "NewWriter":
+ // No-op.
+ default:
+ return
+ }
+ n.Lhs = n.Lhs[:1]
+ fixed = true
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/fix/newwriter_test.go b/src/cmd/fix/newwriter_test.go
new file mode 100644
index 000000000..1f59628a0
--- /dev/null
+++ b/src/cmd/fix/newwriter_test.go
@@ -0,0 +1,83 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(newWriterTests, newWriter)
+}
+
+var newWriterTests = []testCase{
+ {
+ Name: "newWriter.0",
+ In: `package main
+
+import (
+ "bufio"
+ "compress/gzip"
+ "compress/zlib"
+ "io"
+
+ "foo"
+)
+
+func f() *gzip.Compressor {
+ var (
+ _ gzip.Compressor
+ _ *gzip.Decompressor
+ _ struct {
+ W *gzip.Compressor
+ R gzip.Decompressor
+ }
+ )
+
+ var w io.Writer
+ br := bufio.NewReader(nil)
+ br, _ = bufio.NewReaderSize(nil, 256)
+ bw, err := bufio.NewWriterSize(w, 256) // Unfixable, as it declares an err variable.
+ bw, _ = bufio.NewWriterSize(w, 256)
+ fw, _ := foo.NewWriter(w)
+ gw, _ := gzip.NewWriter(w)
+ gw, _ = gzip.NewWriter(w)
+ zw, _ := zlib.NewWriter(w)
+ _ = zlib.NewWriterDict(zw, 0, nil)
+ return gw
+}
+`,
+ Out: `package main
+
+import (
+ "bufio"
+ "compress/gzip"
+ "compress/zlib"
+ "io"
+
+ "foo"
+)
+
+func f() *gzip.Writer {
+ var (
+ _ gzip.Writer
+ _ *gzip.Reader
+ _ struct {
+ W *gzip.Writer
+ R gzip.Reader
+ }
+ )
+
+ var w io.Writer
+ br := bufio.NewReader(nil)
+ br = bufio.NewReaderSize(nil, 256)
+ bw, err := bufio.NewWriterSize(w, 256) // Unfixable, as it declares an err variable.
+ bw = bufio.NewWriterSize(w, 256)
+ fw, _ := foo.NewWriter(w)
+ gw := gzip.NewWriter(w)
+ gw = gzip.NewWriter(w)
+ zw := zlib.NewWriter(w)
+ _ = zlib.NewWriterLevelDict(zw, 0, nil)
+ return gw
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/fix/oserrorstring.go
index db39ee9dc..a75a2c12d 100644
--- a/src/cmd/gofix/oserrorstring.go
+++ b/src/cmd/fix/oserrorstring.go
@@ -8,8 +8,13 @@ import (
"go/ast"
)
+func init() {
+ register(oserrorstringFix)
+}
+
var oserrorstringFix = fix{
"oserrorstring",
+ "2011-06-22",
oserrorstring,
`Replace os.ErrorString() conversions with calls to os.NewError().
@@ -17,10 +22,6 @@ http://codereview.appspot.com/4607052
`,
}
-func init() {
- register(oserrorstringFix)
-}
-
func oserrorstring(f *ast.File) bool {
if !imports(f, "os") {
return false
diff --git a/src/cmd/gofix/oserrorstring_test.go b/src/cmd/fix/oserrorstring_test.go
index 070d9222b..75551480c 100644
--- a/src/cmd/gofix/oserrorstring_test.go
+++ b/src/cmd/fix/oserrorstring_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(oserrorstringTests)
+ addTestCases(oserrorstringTests, oserrorstring)
}
var oserrorstringTests = []testCase{
diff --git a/src/cmd/gofix/osopen.go b/src/cmd/fix/osopen.go
index 19c19b5b6..af2796ac2 100644
--- a/src/cmd/gofix/osopen.go
+++ b/src/cmd/fix/osopen.go
@@ -8,8 +8,13 @@ import (
"go/ast"
)
+func init() {
+ register(osopenFix)
+}
+
var osopenFix = fix{
"osopen",
+ "2011-04-04",
osopen,
`Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
@@ -17,10 +22,6 @@ http://codereview.appspot.com/4357052
`,
}
-func init() {
- register(osopenFix)
-}
-
func osopen(f *ast.File) bool {
if !imports(f, "os") {
return false
diff --git a/src/cmd/gofix/osopen_test.go b/src/cmd/fix/osopen_test.go
index a33bcd4fb..5797adb7b 100644
--- a/src/cmd/gofix/osopen_test.go
+++ b/src/cmd/fix/osopen_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(osopenTests)
+ addTestCases(osopenTests, osopen)
}
var osopenTests = []testCase{
diff --git a/src/cmd/gofix/procattr.go b/src/cmd/fix/procattr.go
index 0e2190b1f..ea375ec9d 100644
--- a/src/cmd/gofix/procattr.go
+++ b/src/cmd/fix/procattr.go
@@ -9,8 +9,13 @@ import (
"go/token"
)
+func init() {
+ register(procattrFix)
+}
+
var procattrFix = fix{
"procattr",
+ "2011-03-15",
procattr,
`Adapt calls to os.StartProcess to use new ProcAttr type.
@@ -18,10 +23,6 @@ http://codereview.appspot.com/4253052
`,
}
-func init() {
- register(procattrFix)
-}
-
func procattr(f *ast.File) bool {
if !imports(f, "os") && !imports(f, "syscall") {
return false
diff --git a/src/cmd/gofix/procattr_test.go b/src/cmd/fix/procattr_test.go
index b973b9684..9e2b86e74 100644
--- a/src/cmd/gofix/procattr_test.go
+++ b/src/cmd/fix/procattr_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(procattrTests)
+ addTestCases(procattrTests, procattr)
}
var procattrTests = []testCase{
diff --git a/src/cmd/gofix/reflect.go b/src/cmd/fix/reflect.go
index 3c8becaef..151da569d 100644
--- a/src/cmd/gofix/reflect.go
+++ b/src/cmd/fix/reflect.go
@@ -15,8 +15,13 @@ import (
"strings"
)
+func init() {
+ register(reflectFix)
+}
+
var reflectFix = fix{
"reflect",
+ "2011-04-08",
reflectFn,
`Adapt code to new reflect API.
@@ -25,10 +30,6 @@ http://codereview.appspot.com/4433066
`,
}
-func init() {
- register(reflectFix)
-}
-
// The reflect API change dropped the concrete types *reflect.ArrayType etc.
// Any type assertions prior to method calls can be deleted:
// x.(*reflect.ArrayType).Len() -> x.Len()
@@ -48,7 +49,7 @@ func init() {
//
// Not all type checks result in a single Kind check. The rewrite of the type check for
// reflect.ArrayOrSliceType checks x.Kind() against reflect.Array and reflect.Slice.
-// The rewrite for *reflect.IntType checks againt Int, Int8, Int16, Int32, Int64.
+// The rewrite for *reflect.IntType checks against Int, Int8, Int16, Int32, Int64.
// The rewrite for *reflect.UintType adds Uintptr.
//
// A type switch turns into an assignment and a switch on Kind:
@@ -86,8 +87,8 @@ func init() {
// x.(*reflect.MapValue).Elem(v) becomes x.MapIndex(v).
// In general, reflectFn needs to know the type of the receiver expression.
// In most cases (and in all the cases in the Go source tree), the toy
-// type checker in typecheck.go provides enough information for gofix
-// to make the rewrite. If gofix misses a rewrite, the code that is left over
+// type checker in typecheck.go provides enough information for fix
+// to make the rewrite. If fix misses a rewrite, the code that is left over
// will not compile, so it will be noticed immediately.
func reflectFn(f *ast.File) bool {
@@ -99,7 +100,7 @@ func reflectFn(f *ast.File) bool {
// Rewrite names in method calls.
// Needs basic type information (see above).
- typeof := typecheck(reflectTypeConfig, f)
+ typeof, _ := typecheck(reflectTypeConfig, f)
walk(f, func(n interface{}) {
switch n := n.(type) {
case *ast.SelectorExpr:
@@ -187,7 +188,7 @@ func reflectFn(f *ast.File) bool {
}
*n = v
case *ast.IfStmt:
- x := &ast.ExprStmt{n.Cond}
+ x := &ast.ExprStmt{X: n.Cond}
if reflectFixTypecheck(&n.Init, nil, []ast.Stmt{x, n.Body, n.Else}) {
n.Cond = x.X
fixed = true
@@ -616,75 +617,75 @@ func reflectFixAssert(n interface{}) bool {
// which implements Type.)
var reflectTypeConfig = &TypeConfig{
Type: map[string]*Type{
- "reflect.ArrayOrSliceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ArrayOrSliceValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.ArrayType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ArrayValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.BoolType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.BoolValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.ChanType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ChanValue": &Type{
+ "reflect.ArrayOrSliceType": {Embed: []string{"reflect.Type"}},
+ "reflect.ArrayOrSliceValue": {Embed: []string{"reflect.Value"}},
+ "reflect.ArrayType": {Embed: []string{"reflect.Type"}},
+ "reflect.ArrayValue": {Embed: []string{"reflect.Value"}},
+ "reflect.BoolType": {Embed: []string{"reflect.Type"}},
+ "reflect.BoolValue": {Embed: []string{"reflect.Value"}},
+ "reflect.ChanType": {Embed: []string{"reflect.Type"}},
+ "reflect.ChanValue": {
Method: map[string]string{
"Recv": "func() (reflect.Value, bool)",
"TryRecv": "func() (reflect.Value, bool)",
},
Embed: []string{"reflect.Value"},
},
- "reflect.ComplexType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.ComplexValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.FloatType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.FloatValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.FuncType": &Type{
+ "reflect.ComplexType": {Embed: []string{"reflect.Type"}},
+ "reflect.ComplexValue": {Embed: []string{"reflect.Value"}},
+ "reflect.FloatType": {Embed: []string{"reflect.Type"}},
+ "reflect.FloatValue": {Embed: []string{"reflect.Value"}},
+ "reflect.FuncType": {
Method: map[string]string{
"In": "func(int) reflect.Type",
"Out": "func(int) reflect.Type",
},
Embed: []string{"reflect.Type"},
},
- "reflect.FuncValue": &Type{
+ "reflect.FuncValue": {
Method: map[string]string{
"Call": "func([]reflect.Value) []reflect.Value",
},
},
- "reflect.IntType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.IntValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.InterfaceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.InterfaceValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.MapType": &Type{
+ "reflect.IntType": {Embed: []string{"reflect.Type"}},
+ "reflect.IntValue": {Embed: []string{"reflect.Value"}},
+ "reflect.InterfaceType": {Embed: []string{"reflect.Type"}},
+ "reflect.InterfaceValue": {Embed: []string{"reflect.Value"}},
+ "reflect.MapType": {
Method: map[string]string{
"Key": "func() reflect.Type",
},
Embed: []string{"reflect.Type"},
},
- "reflect.MapValue": &Type{
+ "reflect.MapValue": {
Method: map[string]string{
"Keys": "func() []reflect.Value",
},
Embed: []string{"reflect.Value"},
},
- "reflect.Method": &Type{
+ "reflect.Method": {
Field: map[string]string{
"Type": "*reflect.FuncType",
"Func": "*reflect.FuncValue",
},
},
- "reflect.PtrType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.PtrValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.SliceType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.SliceValue": &Type{
+ "reflect.PtrType": {Embed: []string{"reflect.Type"}},
+ "reflect.PtrValue": {Embed: []string{"reflect.Value"}},
+ "reflect.SliceType": {Embed: []string{"reflect.Type"}},
+ "reflect.SliceValue": {
Method: map[string]string{
"Slice": "func(int, int) *reflect.SliceValue",
},
Embed: []string{"reflect.Value"},
},
- "reflect.StringType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.StringValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.StructField": &Type{
+ "reflect.StringType": {Embed: []string{"reflect.Type"}},
+ "reflect.StringValue": {Embed: []string{"reflect.Value"}},
+ "reflect.StructField": {
Field: map[string]string{
"Type": "reflect.Type",
},
},
- "reflect.StructType": &Type{
+ "reflect.StructType": {
Method: map[string]string{
"Field": "func() reflect.StructField",
"FieldByIndex": "func() reflect.StructField",
@@ -693,7 +694,7 @@ var reflectTypeConfig = &TypeConfig{
},
Embed: []string{"reflect.Type"},
},
- "reflect.StructValue": &Type{
+ "reflect.StructValue": {
Method: map[string]string{
"Field": "func() reflect.Value",
"FieldByIndex": "func() reflect.Value",
@@ -702,17 +703,17 @@ var reflectTypeConfig = &TypeConfig{
},
Embed: []string{"reflect.Value"},
},
- "reflect.Type": &Type{
+ "reflect.Type": {
Method: map[string]string{
"Elem": "func() reflect.Type",
"Method": "func() reflect.Method",
},
},
- "reflect.UintType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.UintValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.UnsafePointerType": &Type{Embed: []string{"reflect.Type"}},
- "reflect.UnsafePointerValue": &Type{Embed: []string{"reflect.Value"}},
- "reflect.Value": &Type{
+ "reflect.UintType": {Embed: []string{"reflect.Type"}},
+ "reflect.UintValue": {Embed: []string{"reflect.Value"}},
+ "reflect.UnsafePointerType": {Embed: []string{"reflect.Type"}},
+ "reflect.UnsafePointerValue": {Embed: []string{"reflect.Value"}},
+ "reflect.Value": {
Method: map[string]string{
"Addr": "func() *reflect.PtrValue",
"Elem": "func() reflect.Value",
diff --git a/src/cmd/gofix/reflect_test.go b/src/cmd/fix/reflect_test.go
index 00edf30e9..032cbc745 100644
--- a/src/cmd/gofix/reflect_test.go
+++ b/src/cmd/fix/reflect_test.go
@@ -1,3 +1,7 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
package main
import (
@@ -7,7 +11,7 @@ import (
)
func init() {
- addTestCases(reflectTests())
+ addTestCases(reflectTests(), reflectFn)
}
func reflectTests() []testCase {
diff --git a/src/cmd/gofix/signal.go b/src/cmd/fix/signal.go
index 53c338851..5a583d41e 100644
--- a/src/cmd/gofix/signal.go
+++ b/src/cmd/fix/signal.go
@@ -10,14 +10,17 @@ import (
)
func init() {
- register(fix{
- "signal",
- signal,
- `Adapt code to types moved from os/signal to signal.
+ register(signalFix)
+}
+
+var signalFix = fix{
+ "signal",
+ "2011-06-29",
+ signal,
+ `Adapt code to types moved from os/signal to signal.
http://codereview.appspot.com/4437091
`,
- })
}
func signal(f *ast.File) (fixed bool) {
@@ -34,16 +37,14 @@ func signal(f *ast.File) (fixed bool) {
sel := s.Sel.String()
if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
+ addImport(f, "os")
s.X = &ast.Ident{Name: "os"}
fixed = true
}
})
- if fixed {
- addImport(f, "os")
- if !usesImport(f, "os/signal") {
- deleteImport(f, "os/signal")
- }
+ if fixed && !usesImport(f, "os/signal") {
+ deleteImport(f, "os/signal")
}
return
}
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/fix/signal_test.go
index 4abba3534..7bca7d5c4 100644
--- a/src/cmd/gofix/signal_test.go
+++ b/src/cmd/fix/signal_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(signalTests)
+ addTestCases(signalTests, signal)
}
var signalTests = []testCase{
diff --git a/src/cmd/gofix/sorthelpers.go b/src/cmd/fix/sorthelpers.go
index 4e89fa88f..fa549313e 100644
--- a/src/cmd/gofix/sorthelpers.go
+++ b/src/cmd/fix/sorthelpers.go
@@ -9,12 +9,15 @@ import (
)
func init() {
- register(fix{
- "sorthelpers",
- sorthelpers,
- `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
+ register(sorthelpersFix)
+}
+
+var sorthelpersFix = fix{
+ "sorthelpers",
+ "2011-07-08",
+ sorthelpers,
+ `Adapt code from sort.Sort[Ints|Float64s|Strings] to sort.[Ints|Float64s|Strings].
`,
- })
}
func sorthelpers(f *ast.File) (fixed bool) {
diff --git a/src/cmd/gofix/sorthelpers_test.go b/src/cmd/fix/sorthelpers_test.go
index 6c37858fd..dd6b58e03 100644
--- a/src/cmd/gofix/sorthelpers_test.go
+++ b/src/cmd/fix/sorthelpers_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(sorthelpersTests)
+ addTestCases(sorthelpersTests, sorthelpers)
}
var sorthelpersTests = []testCase{
diff --git a/src/cmd/gofix/sortslice.go b/src/cmd/fix/sortslice.go
index 7cfa1696b..89267b847 100644
--- a/src/cmd/gofix/sortslice.go
+++ b/src/cmd/fix/sortslice.go
@@ -9,15 +9,18 @@ import (
)
func init() {
- register(fix{
- "sortslice",
- sortslice,
- `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice.
+ register(sortsliceFix)
+}
+
+var sortsliceFix = fix{
+ "sortslice",
+ "2011-06-26",
+ sortslice,
+ `Adapt code from sort.[Float64|Int|String]Array to sort.[Float64|Int|String]Slice.
http://codereview.appspot.com/4602054
http://codereview.appspot.com/4639041
`,
- })
}
func sortslice(f *ast.File) (fixed bool) {
diff --git a/src/cmd/gofix/sortslice_test.go b/src/cmd/fix/sortslice_test.go
index 404feb26f..7b745a232 100644
--- a/src/cmd/gofix/sortslice_test.go
+++ b/src/cmd/fix/sortslice_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(sortsliceTests)
+ addTestCases(sortsliceTests, sortslice)
}
var sortsliceTests = []testCase{
diff --git a/src/cmd/fix/strconv.go b/src/cmd/fix/strconv.go
new file mode 100644
index 000000000..6cd69020b
--- /dev/null
+++ b/src/cmd/fix/strconv.go
@@ -0,0 +1,127 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+ register(strconvFix)
+}
+
+var strconvFix = fix{
+ "strconv",
+ "2011-12-01",
+ strconvFn,
+ `Convert to new strconv API.
+
+http://codereview.appspot.com/5434095
+http://codereview.appspot.com/5434069
+`,
+}
+
+func strconvFn(f *ast.File) bool {
+ if !imports(f, "strconv") {
+ return false
+ }
+
+ fixed := false
+
+ walk(f, func(n interface{}) {
+ // Rename functions.
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) < 1 {
+ return
+ }
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok || !isTopName(sel.X, "strconv") {
+ return
+ }
+ change := func(name string) {
+ fixed = true
+ sel.Sel.Name = name
+ }
+ add := func(s string) {
+ call.Args = append(call.Args, expr(s))
+ }
+ switch sel.Sel.Name {
+ case "Atob":
+ change("ParseBool")
+ case "Atof32":
+ change("ParseFloat")
+ add("32") // bitSize
+ warn(call.Pos(), "rewrote strconv.Atof32(_) to strconv.ParseFloat(_, 32) but return value must be converted to float32")
+ case "Atof64":
+ change("ParseFloat")
+ add("64") // bitSize
+ case "AtofN":
+ change("ParseFloat")
+ case "Atoi":
+ // Atoi stayed as a convenience wrapper.
+ case "Atoi64":
+ change("ParseInt")
+ add("10") // base
+ add("64") // bitSize
+ case "Atoui":
+ change("ParseUint")
+ add("10") // base
+ add("0") // bitSize
+ warn(call.Pos(), "rewrote strconv.Atoui(_) to strconv.ParseUint(_, 10, 0) but return value must be converted to uint")
+ case "Atoui64":
+ change("ParseUint")
+ add("10") // base
+ add("64") // bitSize
+ case "Btoa":
+ change("FormatBool")
+ case "Btoi64":
+ change("ParseInt")
+ add("64") // bitSize
+ case "Btoui64":
+ change("ParseUint")
+ add("64") // bitSize
+ case "Ftoa32":
+ change("FormatFloat")
+ call.Args[0] = strconvRewrite("float32", "float64", call.Args[0])
+ add("32") // bitSize
+ case "Ftoa64":
+ change("FormatFloat")
+ add("64") // bitSize
+ case "FtoaN":
+ change("FormatFloat")
+ case "Itoa":
+ // Itoa stayed as a convenience wrapper.
+ case "Itoa64":
+ change("FormatInt")
+ add("10") // base
+ case "Itob":
+ change("FormatInt")
+ call.Args[0] = strconvRewrite("int", "int64", call.Args[0])
+ case "Itob64":
+ change("FormatInt")
+ case "Uitoa":
+ change("FormatUint")
+ call.Args[0] = strconvRewrite("uint", "uint64", call.Args[0])
+ add("10") // base
+ case "Uitoa64":
+ change("FormatUint")
+ add("10") // base
+ case "Uitob":
+ change("FormatUint")
+ call.Args[0] = strconvRewrite("uint", "uint64", call.Args[0])
+ case "Uitob64":
+ change("FormatUint")
+ }
+ })
+ return fixed
+}
+
+// rewrite from type t1 to type t2
+// If the expression x is of the form t1(_), use t2(_). Otherwise use t2(x).
+func strconvRewrite(t1, t2 string, x ast.Expr) ast.Expr {
+ if call, ok := x.(*ast.CallExpr); ok && isTopName(call.Fun, t1) {
+ call.Fun.(*ast.Ident).Name = t2
+ return x
+ }
+ return &ast.CallExpr{Fun: ast.NewIdent(t2), Args: []ast.Expr{x}}
+}
diff --git a/src/cmd/fix/strconv_test.go b/src/cmd/fix/strconv_test.go
new file mode 100644
index 000000000..7fbd4e42e
--- /dev/null
+++ b/src/cmd/fix/strconv_test.go
@@ -0,0 +1,93 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(strconvTests, strconvFn)
+}
+
+var strconvTests = []testCase{
+ {
+ Name: "strconv.0",
+ In: `package main
+
+import "strconv"
+
+func f() {
+ foo.Atob("abc")
+
+ strconv.Atob("true")
+ strconv.Btoa(false)
+
+ strconv.Atof32("1.2")
+ strconv.Atof64("1.2")
+ strconv.AtofN("1.2", 64)
+ strconv.Ftoa32(1.2, 'g', 17)
+ strconv.Ftoa64(1.2, 'g', 17)
+ strconv.FtoaN(1.2, 'g', 17, 64)
+
+ strconv.Atoi("3")
+ strconv.Atoi64("3")
+ strconv.Btoi64("1234", 5)
+
+ strconv.Atoui("3")
+ strconv.Atoui64("3")
+ strconv.Btoui64("1234", 5)
+
+ strconv.Itoa(123)
+ strconv.Itoa64(1234)
+ strconv.Itob(123, 5)
+ strconv.Itob64(1234, 5)
+
+ strconv.Uitoa(123)
+ strconv.Uitoa64(1234)
+ strconv.Uitob(123, 5)
+ strconv.Uitob64(1234, 5)
+
+ strconv.Uitoa(uint(x))
+ strconv.Uitoa(f(x))
+}
+`,
+ Out: `package main
+
+import "strconv"
+
+func f() {
+ foo.Atob("abc")
+
+ strconv.ParseBool("true")
+ strconv.FormatBool(false)
+
+ strconv.ParseFloat("1.2", 32)
+ strconv.ParseFloat("1.2", 64)
+ strconv.ParseFloat("1.2", 64)
+ strconv.FormatFloat(float64(1.2), 'g', 17, 32)
+ strconv.FormatFloat(1.2, 'g', 17, 64)
+ strconv.FormatFloat(1.2, 'g', 17, 64)
+
+ strconv.Atoi("3")
+ strconv.ParseInt("3", 10, 64)
+ strconv.ParseInt("1234", 5, 64)
+
+ strconv.ParseUint("3", 10, 0)
+ strconv.ParseUint("3", 10, 64)
+ strconv.ParseUint("1234", 5, 64)
+
+ strconv.Itoa(123)
+ strconv.FormatInt(1234, 10)
+ strconv.FormatInt(int64(123), 5)
+ strconv.FormatInt(1234, 5)
+
+ strconv.FormatUint(uint64(123), 10)
+ strconv.FormatUint(1234, 10)
+ strconv.FormatUint(uint64(123), 5)
+ strconv.FormatUint(1234, 5)
+
+ strconv.FormatUint(uint64(x), 10)
+ strconv.FormatUint(uint64(f(x)), 10)
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/stringssplit.go b/src/cmd/fix/stringssplit.go
index 4a1fe93d3..d89ecf039 100644
--- a/src/cmd/gofix/stringssplit.go
+++ b/src/cmd/fix/stringssplit.go
@@ -9,8 +9,13 @@ import (
"go/token"
)
+func init() {
+ register(stringssplitFix)
+}
+
var stringssplitFix = fix{
"stringssplit",
+ "2011-06-28",
stringssplit,
`Restore strings.Split to its original meaning and add strings.SplitN. Bytes too.
@@ -18,10 +23,6 @@ http://codereview.appspot.com/4661051
`,
}
-func init() {
- register(stringssplitFix)
-}
-
func stringssplit(f *ast.File) bool {
if !imports(f, "bytes") && !imports(f, "strings") {
return false
diff --git a/src/cmd/gofix/stringssplit_test.go b/src/cmd/fix/stringssplit_test.go
index b925722af..fa42b1bea 100644
--- a/src/cmd/gofix/stringssplit_test.go
+++ b/src/cmd/fix/stringssplit_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(stringssplitTests)
+ addTestCases(stringssplitTests, stringssplit)
}
var stringssplitTests = []testCase{
diff --git a/src/cmd/fix/template.go b/src/cmd/fix/template.go
new file mode 100644
index 000000000..a3dd1440b
--- /dev/null
+++ b/src/cmd/fix/template.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 main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(templateFix)
+}
+
+var templateFix = fix{
+ "template",
+ "2011-11-22",
+ template,
+ `Rewrite calls to template.ParseFile to template.ParseFiles
+
+http://codereview.appspot.com/5433048
+`,
+}
+
+var templateSetGlobals = []string{
+ "ParseSetFiles",
+ "ParseSetGlob",
+ "ParseTemplateFiles",
+ "ParseTemplateGlob",
+ "Set",
+ "SetMust",
+}
+
+var templateSetMethods = []string{
+ "ParseSetFiles",
+ "ParseSetGlob",
+ "ParseTemplateFiles",
+ "ParseTemplateGlob",
+}
+
+var templateTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "template.Template": {
+ Method: map[string]string{
+ "Funcs": "func() *template.Template",
+ "Delims": "func() *template.Template",
+ "Parse": "func() (*template.Template, error)",
+ "ParseFile": "func() (*template.Template, error)",
+ "ParseInSet": "func() (*template.Template, error)",
+ },
+ },
+ "template.Set": {
+ Method: map[string]string{
+ "ParseSetFiles": "func() (*template.Set, error)",
+ "ParseSetGlob": "func() (*template.Set, error)",
+ "ParseTemplateFiles": "func() (*template.Set, error)",
+ "ParseTemplateGlob": "func() (*template.Set, error)",
+ },
+ },
+ },
+
+ Func: map[string]string{
+ "template.New": "*template.Template",
+ "template.Must": "(*template.Template, error)",
+ "template.SetMust": "(*template.Set, error)",
+ },
+}
+
+func template(f *ast.File) bool {
+ if !imports(f, "text/template") && !imports(f, "html/template") {
+ return false
+ }
+
+ fixed := false
+
+ typeof, _ := typecheck(templateTypeConfig, f)
+
+ // Now update the names used by importers.
+ walk(f, func(n interface{}) {
+ if sel, ok := n.(*ast.SelectorExpr); ok {
+ // Reference to top-level function ParseFile.
+ if isPkgDot(sel, "template", "ParseFile") {
+ sel.Sel.Name = "ParseFiles"
+ fixed = true
+ return
+ }
+ // Reference to ParseFiles method.
+ if typeof[sel.X] == "*template.Template" && sel.Sel.Name == "ParseFile" {
+ sel.Sel.Name = "ParseFiles"
+ fixed = true
+ return
+ }
+ // The Set type and its functions are now gone.
+ for _, name := range templateSetGlobals {
+ if isPkgDot(sel, "template", name) {
+ warn(sel.Pos(), "reference to template.%s must be fixed manually", name)
+ return
+ }
+ }
+ // The methods of Set are now gone.
+ for _, name := range templateSetMethods {
+ if typeof[sel.X] == "*template.Set" && sel.Sel.Name == name {
+ warn(sel.Pos(), "reference to template.*Set.%s must be fixed manually", name)
+ return
+ }
+ }
+ }
+ })
+
+ return fixed
+}
diff --git a/src/cmd/fix/template_test.go b/src/cmd/fix/template_test.go
new file mode 100644
index 000000000..f713a2901
--- /dev/null
+++ b/src/cmd/fix/template_test.go
@@ -0,0 +1,55 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(templateTests, template)
+}
+
+var templateTests = []testCase{
+ {
+ Name: "template.0",
+ In: `package main
+
+import (
+ "text/template"
+)
+
+func f() {
+ template.ParseFile(a)
+ var t template.Template
+ x, y := template.ParseFile()
+ template.New("x").Funcs(m).ParseFile(a) // chained method
+ // Output should complain about these as functions or methods.
+ var s *template.Set
+ s.ParseSetFiles(a)
+ template.ParseSetGlob(a)
+ s.ParseTemplateFiles(a)
+ template.ParseTemplateGlob(a)
+ x := template.SetMust(a())
+}
+`,
+ Out: `package main
+
+import (
+ "text/template"
+)
+
+func f() {
+ template.ParseFiles(a)
+ var t template.Template
+ x, y := template.ParseFiles()
+ template.New("x").Funcs(m).ParseFiles(a) // chained method
+ // Output should complain about these as functions or methods.
+ var s *template.Set
+ s.ParseSetFiles(a)
+ template.ParseSetGlob(a)
+ s.ParseTemplateFiles(a)
+ template.ParseTemplateGlob(a)
+ x := template.SetMust(a())
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.in b/src/cmd/fix/testdata/reflect.asn1.go.in
index 43128f6b2..43128f6b2 100644
--- a/src/cmd/gofix/testdata/reflect.asn1.go.in
+++ b/src/cmd/fix/testdata/reflect.asn1.go.in
diff --git a/src/cmd/gofix/testdata/reflect.asn1.go.out b/src/cmd/fix/testdata/reflect.asn1.go.out
index ba6224e6d..ba6224e6d 100644
--- a/src/cmd/gofix/testdata/reflect.asn1.go.out
+++ b/src/cmd/fix/testdata/reflect.asn1.go.out
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.in b/src/cmd/fix/testdata/reflect.datafmt.go.in
index 91f885f9a..91f885f9a 100644
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.in
+++ b/src/cmd/fix/testdata/reflect.datafmt.go.in
diff --git a/src/cmd/gofix/testdata/reflect.datafmt.go.out b/src/cmd/fix/testdata/reflect.datafmt.go.out
index fd447588b..fd447588b 100644
--- a/src/cmd/gofix/testdata/reflect.datafmt.go.out
+++ b/src/cmd/fix/testdata/reflect.datafmt.go.out
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.in b/src/cmd/fix/testdata/reflect.decode.go.in
index f831abee3..f831abee3 100644
--- a/src/cmd/gofix/testdata/reflect.decode.go.in
+++ b/src/cmd/fix/testdata/reflect.decode.go.in
diff --git a/src/cmd/gofix/testdata/reflect.decode.go.out b/src/cmd/fix/testdata/reflect.decode.go.out
index fb7910ee3..fb7910ee3 100644
--- a/src/cmd/gofix/testdata/reflect.decode.go.out
+++ b/src/cmd/fix/testdata/reflect.decode.go.out
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.in b/src/cmd/fix/testdata/reflect.decoder.go.in
index 34364161a..0ce9b06fd 100644
--- a/src/cmd/gofix/testdata/reflect.decoder.go.in
+++ b/src/cmd/fix/testdata/reflect.decoder.go.in
@@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder {
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
@@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
@@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.out b/src/cmd/fix/testdata/reflect.decoder.go.out
index ece88ecbe..ece88ecbe 100644
--- a/src/cmd/gofix/testdata/reflect.decoder.go.out
+++ b/src/cmd/fix/testdata/reflect.decoder.go.out
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in b/src/cmd/fix/testdata/reflect.dnsmsg.go.in
index 3d9c312f2..3d9c312f2 100644
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.in
+++ b/src/cmd/fix/testdata/reflect.dnsmsg.go.in
diff --git a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out b/src/cmd/fix/testdata/reflect.dnsmsg.go.out
index c777fe27c..c777fe27c 100644
--- a/src/cmd/gofix/testdata/reflect.dnsmsg.go.out
+++ b/src/cmd/fix/testdata/reflect.dnsmsg.go.out
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.in b/src/cmd/fix/testdata/reflect.encode.go.in
index 26ce47039..26ce47039 100644
--- a/src/cmd/gofix/testdata/reflect.encode.go.in
+++ b/src/cmd/fix/testdata/reflect.encode.go.in
diff --git a/src/cmd/gofix/testdata/reflect.encode.go.out b/src/cmd/fix/testdata/reflect.encode.go.out
index 9a13a75ab..9a13a75ab 100644
--- a/src/cmd/gofix/testdata/reflect.encode.go.out
+++ b/src/cmd/fix/testdata/reflect.encode.go.out
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.in b/src/cmd/fix/testdata/reflect.encoder.go.in
index e52a4de29..0202d79ac 100644
--- a/src/cmd/gofix/testdata/reflect.encoder.go.in
+++ b/src/cmd/fix/testdata/reflect.encoder.go.in
@@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.out b/src/cmd/fix/testdata/reflect.encoder.go.out
index 925d39301..925d39301 100644
--- a/src/cmd/gofix/testdata/reflect.encoder.go.out
+++ b/src/cmd/fix/testdata/reflect.encoder.go.out
diff --git a/src/cmd/gofix/testdata/reflect.export.go.in b/src/cmd/fix/testdata/reflect.export.go.in
index e91e777e3..ce7940b29 100644
--- a/src/cmd/gofix/testdata/reflect.export.go.in
+++ b/src/cmd/fix/testdata/reflect.export.go.in
@@ -22,8 +22,8 @@ package netchan
// BUG: can't use range clause to receive when using ImportNValues to limit the count.
import (
- "log"
"io"
+ "log"
"net"
"os"
"reflect"
@@ -343,20 +343,20 @@ func (exp *Exporter) Sync(timeout int64) os.Error {
func checkChan(chT interface{}, dir Dir) (*reflect.ChanValue, os.Error) {
chanType, ok := reflect.Typeof(chT).(*reflect.ChanType)
if !ok {
- return nil, os.ErrorString("not a channel")
+ return nil, os.NewError("not a channel")
}
if dir != Send && dir != Recv {
- return nil, os.ErrorString("unknown channel direction")
+ return nil, os.NewError("unknown channel direction")
}
switch chanType.Dir() {
case reflect.BothDir:
case reflect.SendDir:
if dir != Recv {
- return nil, os.ErrorString("to import/export with Send, must provide <-chan")
+ return nil, os.NewError("to import/export with Send, must provide <-chan")
}
case reflect.RecvDir:
if dir != Send {
- return nil, os.ErrorString("to import/export with Recv, must provide chan<-")
+ return nil, os.NewError("to import/export with Recv, must provide chan<-")
}
}
return reflect.NewValue(chT).(*reflect.ChanValue), nil
@@ -376,7 +376,7 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
defer exp.mu.Unlock()
_, present := exp.names[name]
if present {
- return os.ErrorString("channel name already being exported:" + name)
+ return os.NewError("channel name already being exported:" + name)
}
exp.names[name] = &chanDir{ch, dir}
return nil
@@ -393,7 +393,7 @@ func (exp *Exporter) Hangup(name string) os.Error {
// TODO drop all instances of channel from client sets
exp.mu.Unlock()
if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ return os.NewError("netchan export: hangup: no such channel: " + name)
}
chDir.ch.Close()
return nil
diff --git a/src/cmd/gofix/testdata/reflect.export.go.out b/src/cmd/fix/testdata/reflect.export.go.out
index 460edb40b..7bd73c5e7 100644
--- a/src/cmd/gofix/testdata/reflect.export.go.out
+++ b/src/cmd/fix/testdata/reflect.export.go.out
@@ -22,8 +22,8 @@ package netchan
// BUG: can't use range clause to receive when using ImportNValues to limit the count.
import (
- "log"
"io"
+ "log"
"net"
"os"
"reflect"
diff --git a/src/cmd/gofix/testdata/reflect.print.go.in b/src/cmd/fix/testdata/reflect.print.go.in
index cba1df296..6c9b8e4f9 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.in
+++ b/src/cmd/fix/testdata/reflect.print.go.in
@@ -185,7 +185,7 @@ func Sprintf(format string, a ...interface{}) string {
// Errorf formats according to a format specifier and returns the string
// converted to an os.ErrorString, which satisfies the os.Error interface.
func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/fix/testdata/reflect.print.go.out
index b475a2ae1..b475a2ae1 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.out
+++ b/src/cmd/fix/testdata/reflect.print.go.out
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.in b/src/cmd/fix/testdata/reflect.quick.go.in
index a5568b048..a5568b048 100644
--- a/src/cmd/gofix/testdata/reflect.quick.go.in
+++ b/src/cmd/fix/testdata/reflect.quick.go.in
diff --git a/src/cmd/gofix/testdata/reflect.quick.go.out b/src/cmd/fix/testdata/reflect.quick.go.out
index c62305b83..c62305b83 100644
--- a/src/cmd/gofix/testdata/reflect.quick.go.out
+++ b/src/cmd/fix/testdata/reflect.quick.go.out
diff --git a/src/cmd/gofix/testdata/reflect.read.go.in b/src/cmd/fix/testdata/reflect.read.go.in
index 9ae3bb8ee..487994ac6 100644
--- a/src/cmd/gofix/testdata/reflect.read.go.in
+++ b/src/cmd/fix/testdata/reflect.read.go.in
@@ -244,7 +244,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch v := val.(type) {
default:
- return os.ErrorString("unknown type " + v.Type().String())
+ return os.NewError("unknown type " + v.Type().String())
case *reflect.SliceValue:
typ := v.Type().(*reflect.SliceType)
@@ -483,7 +483,7 @@ Loop:
case nil:
// 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.IntValue:
if !getInt64() {
return err
diff --git a/src/cmd/gofix/testdata/reflect.read.go.out b/src/cmd/fix/testdata/reflect.read.go.out
index a6b126744..a6b126744 100644
--- a/src/cmd/gofix/testdata/reflect.read.go.out
+++ b/src/cmd/fix/testdata/reflect.read.go.out
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.in b/src/cmd/fix/testdata/reflect.scan.go.in
index 83650e605..51898181f 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.in
+++ b/src/cmd/fix/testdata/reflect.scan.go.in
@@ -167,7 +167,7 @@ type ssave struct {
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -240,7 +240,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -424,8 +424,8 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
}
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/fix/testdata/reflect.scan.go.out
index 956c13bde..956c13bde 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.out
+++ b/src/cmd/fix/testdata/reflect.scan.go.out
diff --git a/src/cmd/gofix/testdata/reflect.script.go.in b/src/cmd/fix/testdata/reflect.script.go.in
index b341b1f89..b341b1f89 100644
--- a/src/cmd/gofix/testdata/reflect.script.go.in
+++ b/src/cmd/fix/testdata/reflect.script.go.in
diff --git a/src/cmd/gofix/testdata/reflect.script.go.out b/src/cmd/fix/testdata/reflect.script.go.out
index bc5a6a41d..bc5a6a41d 100644
--- a/src/cmd/gofix/testdata/reflect.script.go.out
+++ b/src/cmd/fix/testdata/reflect.script.go.out
diff --git a/src/cmd/gofix/testdata/reflect.template.go.in b/src/cmd/fix/testdata/reflect.template.go.in
index 1f5a8128f..1f5a8128f 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.in
+++ b/src/cmd/fix/testdata/reflect.template.go.in
diff --git a/src/cmd/gofix/testdata/reflect.template.go.out b/src/cmd/fix/testdata/reflect.template.go.out
index f2f56ef3c..f2f56ef3c 100644
--- a/src/cmd/gofix/testdata/reflect.template.go.out
+++ b/src/cmd/fix/testdata/reflect.template.go.out
diff --git a/src/cmd/gofix/testdata/reflect.type.go.in b/src/cmd/fix/testdata/reflect.type.go.in
index 305d41980..34963bef9 100644
--- a/src/cmd/gofix/testdata/reflect.type.go.in
+++ b/src/cmd/fix/testdata/reflect.type.go.in
@@ -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.(*reflect.PtrType).Elem()
@@ -150,6 +150,7 @@ func userType(rt reflect.Type) *userTypeInfo {
}
return ut
}
+
// A typeId represents a gob Type as an integer that can be passed on the wire.
// Internally, typeIds are used as keys to a map to recover the underlying type info.
type typeId int32
@@ -524,7 +525,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
return st, nil
default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
diff --git a/src/cmd/gofix/testdata/reflect.type.go.out b/src/cmd/fix/testdata/reflect.type.go.out
index 9cd78296d..d729ea471 100644
--- a/src/cmd/gofix/testdata/reflect.type.go.out
+++ b/src/cmd/fix/testdata/reflect.type.go.out
@@ -150,6 +150,7 @@ func userType(rt reflect.Type) *userTypeInfo {
}
return ut
}
+
// A typeId represents a gob Type as an integer that can be passed on the wire.
// Internally, typeIds are used as keys to a map to recover the underlying type info.
type typeId int32
diff --git a/src/cmd/fix/timefileinfo.go b/src/cmd/fix/timefileinfo.go
new file mode 100644
index 000000000..b2ea23d8f
--- /dev/null
+++ b/src/cmd/fix/timefileinfo.go
@@ -0,0 +1,298 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+ "strings"
+)
+
+func init() {
+ register(timefileinfoFix)
+}
+
+var timefileinfoFix = fix{
+ "time+fileinfo",
+ "2011-11-29",
+ timefileinfo,
+ `Rewrite for new time and os.FileInfo APIs.
+
+This fix applies some of the more mechanical changes,
+but most code will still need manual cleanup.
+
+http://codereview.appspot.com/5392041
+http://codereview.appspot.com/5416060
+`,
+}
+
+var timefileinfoTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "os.File": {
+ Method: map[string]string{
+ "Readdir": "func() []*os.FileInfo",
+ "Stat": "func() (*os.FileInfo, error)",
+ },
+ },
+ "time.Time": {
+ Method: map[string]string{
+ "Seconds": "time.raw",
+ "Nanoseconds": "time.raw",
+ },
+ },
+ },
+ Func: map[string]string{
+ "ioutil.ReadDir": "([]*os.FileInfo, error)",
+ "os.Stat": "(*os.FileInfo, error)",
+ "os.Lstat": "(*os.FileInfo, error)",
+ "time.LocalTime": "*time.Time",
+ "time.UTC": "*time.Time",
+ "time.SecondsToLocalTime": "*time.Time",
+ "time.SecondsToUTC": "*time.Time",
+ "time.NanosecondsToLocalTime": "*time.Time",
+ "time.NanosecondsToUTC": "*time.Time",
+ "time.Parse": "(*time.Time, error)",
+ "time.Nanoseconds": "time.raw",
+ "time.Seconds": "time.raw",
+ },
+}
+
+// timefileinfoIsOld reports whether f has evidence of being
+// "old code", from before the API changes. Evidence means:
+//
+// a mention of *os.FileInfo (the pointer)
+// a mention of *time.Time (the pointer)
+// a mention of old functions from package time
+// an attempt to call time.UTC
+//
+func timefileinfoIsOld(f *ast.File, typeof map[interface{}]string) bool {
+ old := false
+
+ // called records the expressions that appear as
+ // the function part of a function call, so that
+ // we can distinguish a ref to the possibly new time.UTC
+ // from the definitely old time.UTC() function call.
+ called := make(map[interface{}]bool)
+
+ before := func(n interface{}) {
+ if old {
+ return
+ }
+ if star, ok := n.(*ast.StarExpr); ok {
+ if isPkgDot(star.X, "os", "FileInfo") || isPkgDot(star.X, "time", "Time") {
+ old = true
+ return
+ }
+ }
+ if sel, ok := n.(*ast.SelectorExpr); ok {
+ if isTopName(sel.X, "time") {
+ if timefileinfoOldTimeFunc[sel.Sel.Name] {
+ old = true
+ return
+ }
+ }
+ if typeof[sel.X] == "os.FileInfo" || typeof[sel.X] == "*os.FileInfo" {
+ switch sel.Sel.Name {
+ case "Mtime_ns", "IsDirectory", "IsRegular":
+ old = true
+ return
+ case "Name", "Mode", "Size":
+ if !called[sel] {
+ old = true
+ return
+ }
+ }
+ }
+ }
+ call, ok := n.(*ast.CallExpr)
+ if ok && isPkgDot(call.Fun, "time", "UTC") {
+ old = true
+ return
+ }
+ if ok {
+ called[call.Fun] = true
+ }
+ }
+ walkBeforeAfter(f, before, nop)
+ return old
+}
+
+var timefileinfoOldTimeFunc = map[string]bool{
+ "LocalTime": true,
+ "SecondsToLocalTime": true,
+ "SecondsToUTC": true,
+ "NanosecondsToLocalTime": true,
+ "NanosecondsToUTC": true,
+ "Seconds": true,
+ "Nanoseconds": true,
+}
+
+var isTimeNow = map[string]bool{
+ "LocalTime": true,
+ "UTC": true,
+ "Seconds": true,
+ "Nanoseconds": true,
+}
+
+func timefileinfo(f *ast.File) bool {
+ if !imports(f, "os") && !imports(f, "time") && !imports(f, "io/ioutil") {
+ return false
+ }
+
+ typeof, _ := typecheck(timefileinfoTypeConfig, f)
+
+ if !timefileinfoIsOld(f, typeof) {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ p, ok := n.(*ast.Expr)
+ if !ok {
+ return
+ }
+ nn := *p
+
+ // Rewrite *os.FileInfo and *time.Time to drop the pointer.
+ if star, ok := nn.(*ast.StarExpr); ok {
+ if isPkgDot(star.X, "os", "FileInfo") || isPkgDot(star.X, "time", "Time") {
+ fixed = true
+ *p = star.X
+ return
+ }
+ }
+
+ // Rewrite old time API calls to new calls.
+ // The code will still not compile after this edit,
+ // but the compiler will catch that, and the replacement
+ // code will be the correct functions to use in the new API.
+ if sel, ok := nn.(*ast.SelectorExpr); ok && isTopName(sel.X, "time") {
+ fn := sel.Sel.Name
+ if fn == "LocalTime" || fn == "Seconds" || fn == "Nanoseconds" {
+ fixed = true
+ sel.Sel.Name = "Now"
+ return
+ }
+ }
+
+ if call, ok := nn.(*ast.CallExpr); ok {
+ if sel, ok := call.Fun.(*ast.SelectorExpr); ok {
+ // Rewrite time.UTC but only when called (there's a new time.UTC var now).
+ if isPkgDot(sel, "time", "UTC") {
+ fixed = true
+ sel.Sel.Name = "Now"
+ // rewrite time.Now() into time.Now().UTC()
+ *p = &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: call,
+ Sel: ast.NewIdent("UTC"),
+ },
+ }
+ return
+ }
+
+ // Rewrite conversions.
+ if ok && isTopName(sel.X, "time") && len(call.Args) == 1 {
+ fn := sel.Sel.Name
+ switch fn {
+ case "SecondsToLocalTime", "SecondsToUTC",
+ "NanosecondsToLocalTime", "NanosecondsToUTC":
+ fixed = true
+ sel.Sel.Name = "Unix"
+ call.Args = append(call.Args, nil)
+ if strings.HasPrefix(fn, "Seconds") {
+ // Unix(sec, 0)
+ call.Args[1] = ast.NewIdent("0")
+ } else {
+ // Unix(0, nsec)
+ call.Args[1] = call.Args[0]
+ call.Args[0] = ast.NewIdent("0")
+ }
+ if strings.HasSuffix(fn, "ToUTC") {
+ // rewrite call into call.UTC()
+ *p = &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: call,
+ Sel: ast.NewIdent("UTC"),
+ },
+ }
+ }
+ return
+ }
+ }
+
+ // Rewrite method calls.
+ switch typeof[sel.X] {
+ case "*time.Time", "time.Time":
+ switch sel.Sel.Name {
+ case "Seconds":
+ fixed = true
+ sel.Sel.Name = "Unix"
+ return
+ case "Nanoseconds":
+ fixed = true
+ sel.Sel.Name = "UnixNano"
+ return
+ }
+
+ case "*os.FileInfo", "os.FileInfo":
+ switch sel.Sel.Name {
+ case "IsDirectory":
+ fixed = true
+ sel.Sel.Name = "IsDir"
+ return
+ case "IsRegular":
+ fixed = true
+ sel.Sel.Name = "IsDir"
+ *p = &ast.UnaryExpr{
+ Op: token.NOT,
+ X: call,
+ }
+ return
+ }
+ }
+ }
+ }
+
+ // Rewrite subtraction of two times.
+ // Cannot handle +=/-=.
+ if bin, ok := nn.(*ast.BinaryExpr); ok &&
+ bin.Op == token.SUB &&
+ (typeof[bin.X] == "time.raw" || typeof[bin.Y] == "time.raw") {
+ fixed = true
+ *p = &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: bin.X,
+ Sel: ast.NewIdent("Sub"),
+ },
+ Args: []ast.Expr{bin.Y},
+ }
+ }
+
+ // Rewrite field references for os.FileInfo.
+ if sel, ok := nn.(*ast.SelectorExpr); ok {
+ if typ := typeof[sel.X]; typ == "*os.FileInfo" || typ == "os.FileInfo" {
+ addCall := false
+ switch sel.Sel.Name {
+ case "Name", "Size", "Mode":
+ fixed = true
+ addCall = true
+ case "Mtime_ns":
+ fixed = true
+ sel.Sel.Name = "ModTime"
+ addCall = true
+ }
+ if addCall {
+ *p = &ast.CallExpr{
+ Fun: sel,
+ }
+ return
+ }
+ }
+ }
+ })
+
+ return true
+}
diff --git a/src/cmd/fix/timefileinfo_test.go b/src/cmd/fix/timefileinfo_test.go
new file mode 100644
index 000000000..6573b8545
--- /dev/null
+++ b/src/cmd/fix/timefileinfo_test.go
@@ -0,0 +1,187 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(timefileinfoTests, timefileinfo)
+}
+
+var timefileinfoTests = []testCase{
+ {
+ Name: "timefileinfo.0",
+ In: `package main
+
+import "os"
+
+func main() {
+ st, _ := os.Stat("/etc/passwd")
+ _ = st.Name
+}
+`,
+ Out: `package main
+
+import "os"
+
+func main() {
+ st, _ := os.Stat("/etc/passwd")
+ _ = st.Name()
+}
+`,
+ },
+ {
+ Name: "timefileinfo.1",
+ In: `package main
+
+import "os"
+
+func main() {
+ st, _ := os.Stat("/etc/passwd")
+ _ = st.Size
+ _ = st.Mode
+ _ = st.Mtime_ns
+ _ = st.IsDirectory()
+ _ = st.IsRegular()
+}
+`,
+ Out: `package main
+
+import "os"
+
+func main() {
+ st, _ := os.Stat("/etc/passwd")
+ _ = st.Size()
+ _ = st.Mode()
+ _ = st.ModTime()
+ _ = st.IsDir()
+ _ = !st.IsDir()
+}
+`,
+ },
+ {
+ Name: "timefileinfo.2",
+ In: `package main
+
+import "os"
+
+func f(st *os.FileInfo) {
+ _ = st.Name
+ _ = st.Size
+ _ = st.Mode
+ _ = st.Mtime_ns
+ _ = st.IsDirectory()
+ _ = st.IsRegular()
+}
+`,
+ Out: `package main
+
+import "os"
+
+func f(st os.FileInfo) {
+ _ = st.Name()
+ _ = st.Size()
+ _ = st.Mode()
+ _ = st.ModTime()
+ _ = st.IsDir()
+ _ = !st.IsDir()
+}
+`,
+ },
+ {
+ Name: "timefileinfo.3",
+ In: `package main
+
+import "time"
+
+func main() {
+ _ = time.Seconds()
+ _ = time.Nanoseconds()
+ _ = time.LocalTime()
+ _ = time.UTC()
+ _ = time.SecondsToLocalTime(sec)
+ _ = time.SecondsToUTC(sec)
+ _ = time.NanosecondsToLocalTime(nsec)
+ _ = time.NanosecondsToUTC(nsec)
+}
+`,
+ Out: `package main
+
+import "time"
+
+func main() {
+ _ = time.Now()
+ _ = time.Now()
+ _ = time.Now()
+ _ = time.Now().UTC()
+ _ = time.Unix(sec, 0)
+ _ = time.Unix(sec, 0).UTC()
+ _ = time.Unix(0, nsec)
+ _ = time.Unix(0, nsec).UTC()
+}
+`,
+ },
+ {
+ Name: "timefileinfo.4",
+ In: `package main
+
+import "time"
+
+func f(*time.Time)
+
+func main() {
+ t := time.LocalTime()
+ _ = t.Seconds()
+ _ = t.Nanoseconds()
+
+ t1 := time.Nanoseconds()
+ f(nil)
+ t2 := time.Nanoseconds()
+ dt := t2 - t1
+}
+`,
+ Out: `package main
+
+import "time"
+
+func f(time.Time)
+
+func main() {
+ t := time.Now()
+ _ = t.Unix()
+ _ = t.UnixNano()
+
+ t1 := time.Now()
+ f(nil)
+ t2 := time.Now()
+ dt := t2.Sub(t1)
+}
+`,
+ },
+ {
+ Name: "timefileinfo.5", // test for issues 1505, 2636
+ In: `package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func main() {
+ fmt.Println(time.SecondsToUTC(now)) // this comment must not introduce an illegal linebreak
+}
+`,
+ Out: `package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func main() {
+ fmt.Println(time.Unix(now, 0).UTC( // this comment must not introduce an illegal linebreak
+ ))
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/typecheck.go b/src/cmd/fix/typecheck.go
index 2d81b9710..8e54314d1 100644
--- a/src/cmd/gofix/typecheck.go
+++ b/src/cmd/fix/typecheck.go
@@ -97,8 +97,9 @@ func (cfg *TypeConfig) typeof(name string) string {
// looked for in the Embed list.
type Type struct {
Field map[string]string // map field name to type
- Method map[string]string // map method name to comma-separated return types
+ Method map[string]string // map method name to comma-separated return types (should start with "func ")
Embed []string // list of types this type embeds (for extra methods)
+ Def string // definition of named type
}
// dot returns the type of "typ.name", making its decision
@@ -128,9 +129,16 @@ func (typ *Type) dot(cfg *TypeConfig, name string) string {
}
// typecheck type checks the AST f assuming the information in cfg.
-// It returns a map from AST nodes to type information in gofmt string form.
-func typecheck(cfg *TypeConfig, f *ast.File) map[interface{}]string {
- typeof := make(map[interface{}]string)
+// It returns two maps with type information:
+// typeof maps AST nodes to type information in gofmt string form.
+// assign maps type strings to lists of expressions that were assigned
+// to values of another type that were assigned to that type.
+func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, assign map[string][]interface{}) {
+ typeof = make(map[interface{}]string)
+ assign = make(map[string][]interface{})
+ cfg1 := &TypeConfig{}
+ *cfg1 = *cfg // make copy so we can add locally
+ copied := false
// gather function declarations
for _, decl := range f.Decls {
@@ -138,7 +146,7 @@ func typecheck(cfg *TypeConfig, f *ast.File) map[interface{}]string {
if !ok {
continue
}
- typecheck1(cfg, fn.Type, typeof)
+ typecheck1(cfg, fn.Type, typeof, assign)
t := typeof[fn.Type]
if fn.Recv != nil {
// The receiver must be a type.
@@ -168,8 +176,43 @@ func typecheck(cfg *TypeConfig, f *ast.File) map[interface{}]string {
}
}
- typecheck1(cfg, f, typeof)
- return typeof
+ // gather struct declarations
+ for _, decl := range f.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if ok {
+ for _, s := range d.Specs {
+ switch s := s.(type) {
+ case *ast.TypeSpec:
+ if cfg1.Type[s.Name.Name] != nil {
+ break
+ }
+ if !copied {
+ copied = true
+ // Copy map lazily: it's time.
+ cfg1.Type = make(map[string]*Type)
+ for k, v := range cfg.Type {
+ cfg1.Type[k] = v
+ }
+ }
+ t := &Type{Field: map[string]string{}}
+ cfg1.Type[s.Name.Name] = t
+ switch st := s.Type.(type) {
+ case *ast.StructType:
+ for _, f := range st.Fields.List {
+ for _, n := range f.Names {
+ t.Field[n.Name] = gofmt(f.Type)
+ }
+ }
+ case *ast.ArrayType, *ast.StarExpr, *ast.MapType:
+ t.Def = gofmt(st)
+ }
+ }
+ }
+ }
+ }
+
+ typecheck1(cfg1, f, typeof, assign)
+ return typeof, assign
}
func makeExprList(a []*ast.Ident) []ast.Expr {
@@ -183,11 +226,14 @@ func makeExprList(a []*ast.Ident) []ast.Expr {
// Typecheck1 is the recursive form of typecheck.
// It is like typecheck but adds to the information in typeof
// instead of allocating a new map.
-func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
+func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, assign map[string][]interface{}) {
// set sets the type of n to typ.
// If isDecl is true, n is being declared.
set := func(n ast.Expr, typ string, isDecl bool) {
if typeof[n] != "" || typ == "" {
+ if typeof[n] != typ {
+ assign[typ] = append(assign[typ], n)
+ }
return
}
typeof[n] = typ
@@ -236,6 +282,14 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
}
}
+ expand := func(s string) string {
+ typ := cfg.Type[s]
+ if typ != nil && typ.Def != "" {
+ return typ.Def
+ }
+ return s
+ }
+
// The main type check is a recursive algorithm implemented
// by walkBeforeAfter(n, before, after).
// Most of it is bottom-up, but in a few places we need
@@ -263,7 +317,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
defer func() {
if t := typeof[n]; t != "" {
pos := fset.Position(n.(ast.Node).Pos())
- fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos.String(), gofmt(n), t)
+ fmt.Fprintf(os.Stderr, "%s: typeof[%s] = %s\n", pos, gofmt(n), t)
}
}()
}
@@ -405,6 +459,8 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
// x.(T) has type T.
if t := typeof[n.Type]; isType(t) {
typeof[n] = getType(t)
+ } else {
+ typeof[n] = gofmt(n.Type)
}
case *ast.SliceExpr:
@@ -413,7 +469,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
case *ast.IndexExpr:
// x[i] has key type of x's type.
- t := typeof[n.X]
+ t := expand(typeof[n.X])
if strings.HasPrefix(t, "[") || strings.HasPrefix(t, "map[") {
// Lazy: assume there are no nested [] in the array
// length or map key type.
@@ -426,7 +482,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
// *x for x of type *T has type T when x is an expr.
// We don't use the result when *x is a type, but
// compute it anyway.
- t := typeof[n.X]
+ t := expand(typeof[n.X])
if isType(t) {
typeof[n] = "type *" + getType(t)
} else if strings.HasPrefix(t, "*") {
@@ -437,7 +493,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
// &x for x of type T has type *T.
t := typeof[n.X]
if t != "" && n.Op == token.AND {
- typeof[n] = "&" + t
+ typeof[n] = "*" + t
}
case *ast.CompositeLit:
@@ -448,6 +504,39 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
// (x) has type of x.
typeof[n] = typeof[n.X]
+ case *ast.RangeStmt:
+ t := expand(typeof[n.X])
+ if t == "" {
+ return
+ }
+ var key, value string
+ if t == "string" {
+ key, value = "int", "rune"
+ } else if strings.HasPrefix(t, "[") {
+ key = "int"
+ if i := strings.Index(t, "]"); i >= 0 {
+ value = t[i+1:]
+ }
+ } else if strings.HasPrefix(t, "map[") {
+ if i := strings.Index(t, "]"); i >= 0 {
+ key, value = t[4:i], t[i+1:]
+ }
+ }
+ changed := false
+ if n.Key != nil && key != "" {
+ changed = true
+ set(n.Key, key, n.Tok == token.DEFINE)
+ }
+ if n.Value != nil && value != "" {
+ changed = true
+ set(n.Value, value, n.Tok == token.DEFINE)
+ }
+ // Ugly failure of vision: already type-checked body.
+ // Do it again now that we have that type info.
+ if changed {
+ typecheck1(cfg, n.Body, typeof, assign)
+ }
+
case *ast.TypeSwitchStmt:
// Type of variable changes for each case in type switch,
// but go/parser generates just one variable.
@@ -471,7 +560,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string) {
tt = getType(tt)
typeof[varx] = tt
typeof[varx.Obj] = tt
- typecheck1(cfg, cas.Body, typeof)
+ typecheck1(cfg, cas.Body, typeof, assign)
}
}
}
diff --git a/src/cmd/gofix/url.go b/src/cmd/fix/url.go
index 7135d8edf..49aac739b 100644
--- a/src/cmd/gofix/url.go
+++ b/src/cmd/fix/url.go
@@ -4,17 +4,15 @@
package main
-import (
- "fmt"
- "os"
- "go/ast"
-)
+import "go/ast"
-var _ fmt.Stringer
-var _ os.Error
+func init() {
+ register(urlFix)
+}
var urlFix = fix{
"url",
+ "2011-08-17",
url,
`Move the URL pieces of package http into a new package, url.
@@ -22,10 +20,6 @@ http://codereview.appspot.com/4893043
`,
}
-func init() {
- register(urlFix)
-}
-
var urlRenames = []struct{ in, out string }{
{"URL", "URL"},
{"ParseURL", "Parse"},
@@ -46,12 +40,7 @@ func url(f *ast.File) bool {
fixed := false
// Update URL code.
- var skip interface{}
urlWalk := func(n interface{}) {
- if n == skip {
- skip = nil
- return
- }
// Is it an identifier?
if ident, ok := n.(*ast.Ident); ok && ident.Name == "url" {
ident.Name = "url_"
@@ -62,12 +51,6 @@ func url(f *ast.File) bool {
fixed = urlDoFields(fn.Params) || fixed
fixed = urlDoFields(fn.Results) || fixed
}
- // U{url: ...} is likely a struct field.
- if kv, ok := n.(*ast.KeyValueExpr); ok {
- if ident, ok := kv.Key.(*ast.Ident); ok && ident.Name == "url" {
- skip = ident
- }
- }
}
// Fix up URL code and add import, at most once.
@@ -75,8 +58,8 @@ func url(f *ast.File) bool {
if fixed {
return
}
- walkBeforeAfter(f, urlWalk, nop)
addImport(f, "url")
+ walkBeforeAfter(f, urlWalk, nop)
fixed = true
}
diff --git a/src/cmd/fix/url2.go b/src/cmd/fix/url2.go
new file mode 100644
index 000000000..5fd05ad2a
--- /dev/null
+++ b/src/cmd/fix/url2.go
@@ -0,0 +1,46 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/ast"
+
+func init() {
+ register(url2Fix)
+}
+
+var url2Fix = fix{
+ "url2",
+ "2012-02-16",
+ url2,
+ `Rename some functions in net/url.
+
+http://codereview.appspot.com/5671061
+`,
+}
+
+func url2(f *ast.File) bool {
+ if !imports(f, "net/url") {
+ return false
+ }
+
+ fixed := false
+
+ walk(f, func(n interface{}) {
+ // Rename functions and methods.
+ sel, ok := n.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ if !isTopName(sel.X, "url") {
+ return
+ }
+ if sel.Sel.Name == "ParseWithReference" {
+ sel.Sel.Name = "ParseWithFragment"
+ fixed = true
+ }
+ })
+
+ return fixed
+}
diff --git a/src/cmd/fix/url2_test.go b/src/cmd/fix/url2_test.go
new file mode 100644
index 000000000..c68dd88f1
--- /dev/null
+++ b/src/cmd/fix/url2_test.go
@@ -0,0 +1,31 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(url2Tests, url2)
+}
+
+var url2Tests = []testCase{
+ {
+ Name: "url2.0",
+ In: `package main
+
+import "net/url"
+
+func f() {
+ url.ParseWithReference("foo")
+}
+`,
+ Out: `package main
+
+import "net/url"
+
+func f() {
+ url.ParseWithFragment("foo")
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/url_test.go b/src/cmd/fix/url_test.go
index 8d9542cbc..39827f780 100644
--- a/src/cmd/gofix/url_test.go
+++ b/src/cmd/fix/url_test.go
@@ -5,7 +5,7 @@
package main
func init() {
- addTestCases(urlTests)
+ addTestCases(urlTests, url)
}
var urlTests = []testCase{
@@ -103,14 +103,14 @@ func h() (url string) {
import "url"
-type U struct{ url int }
+type U struct{ url_ int }
type M map[int]int
func f() {
url.Parse(a)
var url_ = 23
url_, x := 45, y
- _ = U{url: url_}
+ _ = U{url_: url_}
_ = M{url_ + 1: url_}
}
diff --git a/src/cmd/fix/xmlapi.go b/src/cmd/fix/xmlapi.go
new file mode 100644
index 000000000..e74425914
--- /dev/null
+++ b/src/cmd/fix/xmlapi.go
@@ -0,0 +1,111 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+)
+
+func init() {
+ register(xmlapiFix)
+}
+
+var xmlapiFix = fix{
+ "xmlapi",
+ "2012-01-23",
+ xmlapi,
+ `
+ Make encoding/xml's API look more like the rest of the encoding packages.
+
+http://codereview.appspot.com/5574053
+`,
+}
+
+var xmlapiTypeConfig = &TypeConfig{
+ Func: map[string]string{
+ "xml.NewParser": "*xml.Parser",
+ "os.Open": "*os.File",
+ "os.OpenFile": "*os.File",
+ "bytes.NewBuffer": "*bytes.Buffer",
+ "bytes.NewBufferString": "*bytes.Buffer",
+ "bufio.NewReader": "*bufio.Reader",
+ "bufio.NewReadWriter": "*bufio.ReadWriter",
+ },
+}
+
+var isReader = map[string]bool{
+ "*os.File": true,
+ "*bytes.Buffer": true,
+ "*bufio.Reader": true,
+ "*bufio.ReadWriter": true,
+ "io.Reader": true,
+}
+
+func xmlapi(f *ast.File) bool {
+ if !imports(f, "encoding/xml") {
+ return false
+ }
+
+ typeof, _ := typecheck(xmlapiTypeConfig, f)
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+ if ok && typeof[s.X] == "*xml.Parser" && s.Sel.Name == "Unmarshal" {
+ s.Sel.Name = "DecodeElement"
+ fixed = true
+ return
+ }
+ if ok && isPkgDot(s, "xml", "Parser") {
+ s.Sel.Name = "Decoder"
+ fixed = true
+ return
+ }
+
+ call, ok := n.(*ast.CallExpr)
+ if !ok {
+ return
+ }
+ switch {
+ case len(call.Args) == 2 && isPkgDot(call.Fun, "xml", "Marshal"):
+ *call = xmlMarshal(call.Args)
+ fixed = true
+ case len(call.Args) == 2 && isPkgDot(call.Fun, "xml", "Unmarshal"):
+ if isReader[typeof[call.Args[0]]] {
+ *call = xmlUnmarshal(call.Args)
+ fixed = true
+ }
+ case len(call.Args) == 1 && isPkgDot(call.Fun, "xml", "NewParser"):
+ sel := call.Fun.(*ast.SelectorExpr).Sel
+ sel.Name = "NewDecoder"
+ fixed = true
+ }
+ })
+ return fixed
+}
+
+func xmlMarshal(args []ast.Expr) ast.CallExpr {
+ return xmlCallChain("NewEncoder", "Encode", args)
+}
+
+func xmlUnmarshal(args []ast.Expr) ast.CallExpr {
+ return xmlCallChain("NewDecoder", "Decode", args)
+}
+
+func xmlCallChain(first, second string, args []ast.Expr) ast.CallExpr {
+ return ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: &ast.CallExpr{
+ Fun: &ast.SelectorExpr{
+ X: ast.NewIdent("xml"),
+ Sel: ast.NewIdent(first),
+ },
+ Args: args[:1],
+ },
+ Sel: ast.NewIdent(second),
+ },
+ Args: args[1:2],
+ }
+}
diff --git a/src/cmd/fix/xmlapi_test.go b/src/cmd/fix/xmlapi_test.go
new file mode 100644
index 000000000..6486c8124
--- /dev/null
+++ b/src/cmd/fix/xmlapi_test.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(xmlapiTests, xmlapi)
+}
+
+var xmlapiTests = []testCase{
+ {
+ Name: "xmlapi.0",
+ In: `package main
+
+import "encoding/xml"
+
+func f() {
+ xml.Marshal(a, b)
+ xml.Unmarshal(a, b)
+
+ var buf1 bytes.Buffer
+ buf2 := &bytes.Buffer{}
+ buf3 := bytes.NewBuffer(data)
+ buf4 := bytes.NewBufferString(data)
+ buf5 := bufio.NewReader(r)
+ xml.Unmarshal(&buf1, v)
+ xml.Unmarshal(buf2, v)
+ xml.Unmarshal(buf3, v)
+ xml.Unmarshal(buf4, v)
+ xml.Unmarshal(buf5, v)
+
+ f := os.Open("foo.xml")
+ xml.Unmarshal(f, v)
+
+ p1 := xml.NewParser(stream)
+ p1.Unmarshal(v, start)
+
+ var p2 *xml.Parser
+ p2.Unmarshal(v, start)
+}
+
+func g(r io.Reader, f *os.File, b []byte) {
+ xml.Unmarshal(r, v)
+ xml.Unmarshal(f, v)
+ xml.Unmarshal(b, v)
+}
+`,
+ Out: `package main
+
+import "encoding/xml"
+
+func f() {
+ xml.NewEncoder(a).Encode(b)
+ xml.Unmarshal(a, b)
+
+ var buf1 bytes.Buffer
+ buf2 := &bytes.Buffer{}
+ buf3 := bytes.NewBuffer(data)
+ buf4 := bytes.NewBufferString(data)
+ buf5 := bufio.NewReader(r)
+ xml.NewDecoder(&buf1).Decode(v)
+ xml.NewDecoder(buf2).Decode(v)
+ xml.NewDecoder(buf3).Decode(v)
+ xml.NewDecoder(buf4).Decode(v)
+ xml.NewDecoder(buf5).Decode(v)
+
+ f := os.Open("foo.xml")
+ xml.NewDecoder(f).Decode(v)
+
+ p1 := xml.NewDecoder(stream)
+ p1.DecodeElement(v, start)
+
+ var p2 *xml.Decoder
+ p2.DecodeElement(v, start)
+}
+
+func g(r io.Reader, f *os.File, b []byte) {
+ xml.NewDecoder(r).Decode(v)
+ xml.NewDecoder(f).Decode(v)
+ xml.Unmarshal(b, v)
+}
+`,
+ },
+}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index 0af7659e4..58e25faaf 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -1,71 +1,17 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
+include ../../Make.dist
-LIB=gc.a
+install: y.tab.h builtin.c
-HFILES=\
- go.h\
- y.tab.h\
- md5.h\
-
-YFILES=\
- go.y\
-
-OFILES=\
- align.$O\
- bits.$O\
- builtin.$O\
- closure.$O\
- const.$O\
- dcl.$O\
- export.$O\
- gen.$O\
- init.$O\
- lex.$O\
- md5.$O\
- mparith1.$O\
- mparith2.$O\
- mparith3.$O\
- obj.$O\
- print.$O\
- range.$O\
- reflect.$O\
- select.$O\
- sinit.$O\
- subr.$O\
- swt.$O\
- typecheck.$O\
- unsafe.$O\
- walk.$O\
- y1.tab.$O\
-
-NOINSTALL=1
-include ../../Make.clib
-
-install: $(LIB)
-
-y1.tab.c: y.tab.c # make yystate global, yytname mutable
+y.tab.h: go.y go.errors bisonerrors
+ bison -v -y -d go.y
+ # make yystate global, yytname mutable
cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
-
-yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too
+ mv y1.tab.c y.tab.c
awk -f bisonerrors y.output go.errors >yerr.h
-subr.$O: yerr.h
-
-builtin.c: builtin.c.boot
- cp builtin.c.boot builtin.c
-
-subr.$O: opnames.h
-
-opnames.h: mkopnames go.h
- ./mkopnames go.h >opnames.h
-
-CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
-
-mkbuiltin1: mkbuiltin1.$O
- $(HOST_LD) -o $@ mkbuiltin1.$O -L"$(GOROOT)"/lib -lbio -l9 -lm $(HOST_LDFLAGS)
-
+builtin.c: runtime.go unsafe.go
+ ./mkbuiltin
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 14c1c4a8d..6982bbe56 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -283,6 +285,9 @@ dowidth(Type *t)
break;
}
+ if(widthptr == 4 && w != (int32)w)
+ yyerror("type %T too large", t);
+
t->width = w;
if(t->align == 0) {
if(w > 8 || (w&(w-1)) != 0)
@@ -489,12 +494,13 @@ typeinit(void)
okforeq[TPTR64] = 1;
okforeq[TUNSAFEPTR] = 1;
okforeq[TINTER] = 1;
- okforeq[TMAP] = 1;
okforeq[TCHAN] = 1;
- okforeq[TFUNC] = 1;
okforeq[TSTRING] = 1;
okforeq[TBOOL] = 1;
- okforeq[TARRAY] = 1; // refined in typecheck
+ okforeq[TMAP] = 1; // nil only; refined in typecheck
+ okforeq[TFUNC] = 1; // nil only; refined in typecheck
+ okforeq[TARRAY] = 1; // nil slice only; refined in typecheck
+ okforeq[TSTRUCT] = 1; // it's complicated; refined in typecheck
okforcmp[TSTRING] = 1;
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
index 5110f5350..0f865d086 100755
--- a/src/cmd/gc/bisonerrors
+++ b/src/cmd/gc/bisonerrors
@@ -46,24 +46,36 @@ bison && /^state 0/ { grammar = 0; states = 1 }
states && /^state / { state = $2 }
states { statetext[state] = statetext[state] $0 "\n" }
-states && / shift, and go to state/ {
+states && / shift/ {
n = nshift[state]++
- shift[state,n] = $7
+ if($0 ~ /and go to/)
+ shift[state,n] = $7 # GNU Bison
+ else
+ shift[state,n] = $3 # Plan 9 Yacc
shifttoken[state,n] = $1
next
}
-states && / go to state/ {
+states && / (go to|goto)/ {
n = nshift[state]++
- shift[state,n] = $5
+ if($0 ~ /go to/)
+ shift[state,n] = $5 # GNU Bison
+ else
+ shift[state,n] = $3 # Plan 9 Yacc
shifttoken[state,n] = $1
next
}
-states && / reduce using rule/ {
+states && / reduce/ {
n = nreduce[state]++
- reduce[state,n] = $5
+ if($0 ~ /reduce using rule/)
+ reduce[state,n] = $5 # GNU Bison
+ else
+ reduce[state,n] = $3 # Plan 9 yacc
reducetoken[state,n] = $1
next
-}
+}
+
+# Skip over the summary information printed by Plan 9 yacc.
+/nonterminals$/,/^maximum spread/ { next }
# First // comment marks the beginning of the pattern file.
/^\/\// { bison = 0; grammar = 0; state = 0 }
@@ -96,7 +108,8 @@ $1 == "%" {
if(found)
continue
for(j=0; j<nreduce[state]; j++) {
- if(reducetoken[state,j] == tok || reducetoken[state,j] == "$default") {
+ t = reducetoken[state,j]
+ if(t == tok || t == "$default" || t == ".") {
stack[nstack++] = state
rule = reduce[state,j]
nstack -= rulesize[rule]
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
index 7188ac411..c0fd4d85e 100644
--- a/src/cmd/gc/bits.c
+++ b/src/cmd/gc/bits.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -148,12 +150,12 @@ Qconv(Fmt *fp)
first = 0;
else
fmtprint(fp, " ");
- if(var[i].sym == S)
- fmtprint(fp, "$%lld", var[i].offset);
+ if(var[i].node == N || var[i].node->sym == S)
+ fmtprint(fp, "$%d", i);
else {
- fmtprint(fp, var[i].sym->name);
+ fmtprint(fp, "%s", var[i].node->sym->name);
if(var[i].offset != 0)
- fmtprint(fp, "%+d", var[i].offset);
+ fmtprint(fp, "%+lld", (vlong)var[i].offset);
}
bits.b[i/32] &= ~(1L << (i%32));
}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
new file mode 100644
index 000000000..ca3d6670d
--- /dev/null
+++ b/src/cmd/gc/builtin.c
@@ -0,0 +1,118 @@
+char *runtimeimport =
+ "package runtime\n"
+ "import runtime \"runtime\"\n"
+ "func @\"\".new(@\"\".typ *byte) (? *any)\n"
+ "func @\"\".panicindex()\n"
+ "func @\"\".panicslice()\n"
+ "func @\"\".throwreturn()\n"
+ "func @\"\".throwinit()\n"
+ "func @\"\".panicwrap(? string, ? string, ? string)\n"
+ "func @\"\".panic(? interface {})\n"
+ "func @\"\".recover(? *int32) (? interface {})\n"
+ "func @\"\".printbool(? bool)\n"
+ "func @\"\".printfloat(? float64)\n"
+ "func @\"\".printint(? int64)\n"
+ "func @\"\".printuint(? uint64)\n"
+ "func @\"\".printcomplex(? complex128)\n"
+ "func @\"\".printstring(? string)\n"
+ "func @\"\".printpointer(? any)\n"
+ "func @\"\".printiface(? any)\n"
+ "func @\"\".printeface(? any)\n"
+ "func @\"\".printslice(? any)\n"
+ "func @\"\".printnl()\n"
+ "func @\"\".printsp()\n"
+ "func @\"\".goprintf()\n"
+ "func @\"\".concatstring()\n"
+ "func @\"\".append()\n"
+ "func @\"\".appendslice(@\"\".typ *byte, @\"\".x any, @\"\".y []any) (? any)\n"
+ "func @\"\".appendstr(@\"\".typ *byte, @\"\".x []byte, @\"\".y string) (? []byte)\n"
+ "func @\"\".cmpstring(? string, ? string) (? int)\n"
+ "func @\"\".slicestring(? string, ? int, ? int) (? string)\n"
+ "func @\"\".slicestring1(? string, ? int) (? string)\n"
+ "func @\"\".intstring(? int64) (? string)\n"
+ "func @\"\".slicebytetostring(? []byte) (? string)\n"
+ "func @\"\".slicerunetostring(? []rune) (? string)\n"
+ "func @\"\".stringtoslicebyte(? string) (? []byte)\n"
+ "func @\"\".stringtoslicerune(? string) (? []rune)\n"
+ "func @\"\".stringiter(? string, ? int) (? int)\n"
+ "func @\"\".stringiter2(? string, ? int) (@\"\".retk int, @\"\".retv rune)\n"
+ "func @\"\".copy(@\"\".to any, @\"\".fr any, @\"\".wid uint32) (? int)\n"
+ "func @\"\".slicestringcopy(@\"\".to any, @\"\".fr any) (? int)\n"
+ "func @\"\".convI2E(@\"\".elem any) (@\"\".ret any)\n"
+ "func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
+ "func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n"
+ "func @\"\".convT2I(@\"\".typ *byte, @\"\".typ2 *byte, @\"\".elem any) (@\"\".ret any)\n"
+ "func @\"\".assertE2E(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertE2E2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".assertE2I(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertE2I2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".assertE2T(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertE2T2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".assertI2E(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertI2E2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".assertI2I(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertI2I2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".assertI2T(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n"
+ "func @\"\".assertI2T2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n"
+ "func @\"\".ifaceeq(@\"\".i1 any, @\"\".i2 any) (@\"\".ret bool)\n"
+ "func @\"\".efaceeq(@\"\".i1 any, @\"\".i2 any) (@\"\".ret bool)\n"
+ "func @\"\".ifacethash(@\"\".i1 any) (@\"\".ret uint32)\n"
+ "func @\"\".efacethash(@\"\".i1 any) (@\"\".ret uint32)\n"
+ "func @\"\".equal(@\"\".typ *byte, @\"\".x1 any, @\"\".x2 any) (@\"\".ret bool)\n"
+ "func @\"\".makemap(@\"\".mapType *byte, @\"\".hint int64) (@\"\".hmap map[any]any)\n"
+ "func @\"\".mapaccess1(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any) (@\"\".val any)\n"
+ "func @\"\".mapaccess2(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any) (@\"\".val any, @\"\".pres bool)\n"
+ "func @\"\".mapassign1(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any, @\"\".val any)\n"
+ "func @\"\".mapassign2(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any, @\"\".val any, @\"\".pres bool)\n"
+ "func @\"\".mapiterinit(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".hiter *any)\n"
+ "func @\"\".mapdelete(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any)\n"
+ "func @\"\".mapiternext(@\"\".hiter *any)\n"
+ "func @\"\".mapiter1(@\"\".hiter *any) (@\"\".key any)\n"
+ "func @\"\".mapiter2(@\"\".hiter *any) (@\"\".key any, @\"\".val any)\n"
+ "func @\"\".makechan(@\"\".chanType *byte, @\"\".hint int64) (@\"\".hchan chan any)\n"
+ "func @\"\".chanrecv1(@\"\".chanType *byte, @\"\".hchan <-chan any) (@\"\".elem any)\n"
+ "func @\"\".chanrecv2(@\"\".chanType *byte, @\"\".hchan <-chan any) (@\"\".elem any, @\"\".received bool)\n"
+ "func @\"\".chansend1(@\"\".chanType *byte, @\"\".hchan chan<- any, @\"\".elem any)\n"
+ "func @\"\".closechan(@\"\".hchan any)\n"
+ "func @\"\".selectnbsend(@\"\".chanType *byte, @\"\".hchan chan<- any, @\"\".elem any) (? bool)\n"
+ "func @\"\".selectnbrecv(@\"\".chanType *byte, @\"\".elem *any, @\"\".hchan <-chan any) (? bool)\n"
+ "func @\"\".selectnbrecv2(@\"\".chanType *byte, @\"\".elem *any, @\"\".received *bool, @\"\".hchan <-chan any) (? bool)\n"
+ "func @\"\".newselect(@\"\".size int) (@\"\".sel *byte)\n"
+ "func @\"\".selectsend(@\"\".sel *byte, @\"\".hchan chan<- any, @\"\".elem *any) (@\"\".selected bool)\n"
+ "func @\"\".selectrecv(@\"\".sel *byte, @\"\".hchan <-chan any, @\"\".elem *any) (@\"\".selected bool)\n"
+ "func @\"\".selectrecv2(@\"\".sel *byte, @\"\".hchan <-chan any, @\"\".elem *any, @\"\".received *bool) (@\"\".selected bool)\n"
+ "func @\"\".selectdefault(@\"\".sel *byte) (@\"\".selected bool)\n"
+ "func @\"\".selectgo(@\"\".sel *byte)\n"
+ "func @\"\".block()\n"
+ "func @\"\".makeslice(@\"\".typ *byte, @\"\".nel int64, @\"\".cap int64) (@\"\".ary []any)\n"
+ "func @\"\".growslice(@\"\".typ *byte, @\"\".old []any, @\"\".n int64) (@\"\".ary []any)\n"
+ "func @\"\".sliceslice1(@\"\".old []any, @\"\".lb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
+ "func @\"\".sliceslice(@\"\".old []any, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
+ "func @\"\".slicearray(@\"\".old *any, @\"\".nel uint64, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n"
+ "func @\"\".closure()\n"
+ "func @\"\".memequal(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".memequal8(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".memequal16(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".memequal32(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".memequal64(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".memequal128(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n"
+ "func @\"\".int64div(? int64, ? int64) (? int64)\n"
+ "func @\"\".uint64div(? uint64, ? uint64) (? uint64)\n"
+ "func @\"\".int64mod(? int64, ? int64) (? int64)\n"
+ "func @\"\".uint64mod(? uint64, ? uint64) (? uint64)\n"
+ "func @\"\".float64toint64(? float64) (? int64)\n"
+ "func @\"\".float64touint64(? float64) (? uint64)\n"
+ "func @\"\".int64tofloat64(? int64) (? float64)\n"
+ "func @\"\".uint64tofloat64(? uint64) (? float64)\n"
+ "func @\"\".complex128div(@\"\".num complex128, @\"\".den complex128) (@\"\".quo complex128)\n"
+ "\n"
+ "$$\n";
+char *unsafeimport =
+ "package unsafe\n"
+ "import runtime \"runtime\"\n"
+ "type @\"\".Pointer uintptr\n"
+ "func @\"\".Offsetof(? any) (? uintptr)\n"
+ "func @\"\".Sizeof(? any) (? uintptr)\n"
+ "func @\"\".Alignof(? any) (? uintptr)\n"
+ "\n"
+ "$$\n";
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
deleted file mode 100644
index 190c56008..000000000
--- a/src/cmd/gc/builtin.c.boot
+++ /dev/null
@@ -1,114 +0,0 @@
-char *runtimeimport =
- "package runtime\n"
- "import runtime \"runtime\"\n"
- "func \"\".new (? int32) *any\n"
- "func \"\".panicindex ()\n"
- "func \"\".panicslice ()\n"
- "func \"\".throwreturn ()\n"
- "func \"\".throwinit ()\n"
- "func \"\".panicwrap (? string, ? string, ? string)\n"
- "func \"\".panic (? interface { })\n"
- "func \"\".recover (? *int32) interface { }\n"
- "func \"\".printbool (? bool)\n"
- "func \"\".printfloat (? float64)\n"
- "func \"\".printint (? int64)\n"
- "func \"\".printuint (? uint64)\n"
- "func \"\".printcomplex (? complex128)\n"
- "func \"\".printstring (? string)\n"
- "func \"\".printpointer (? any)\n"
- "func \"\".printiface (? any)\n"
- "func \"\".printeface (? any)\n"
- "func \"\".printslice (? any)\n"
- "func \"\".printnl ()\n"
- "func \"\".printsp ()\n"
- "func \"\".goprintf ()\n"
- "func \"\".concatstring ()\n"
- "func \"\".append ()\n"
- "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
- "func \"\".cmpstring (? string, ? string) int\n"
- "func \"\".slicestring (? string, ? int, ? int) string\n"
- "func \"\".slicestring1 (? string, ? int) string\n"
- "func \"\".intstring (? int64) string\n"
- "func \"\".slicebytetostring (? []uint8) string\n"
- "func \"\".sliceinttostring (? []int) string\n"
- "func \"\".stringtoslicebyte (? string) []uint8\n"
- "func \"\".stringtosliceint (? string) []int\n"
- "func \"\".stringiter (? string, ? int) int\n"
- "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
- "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
- "func \"\".slicestringcopy (to any, fr any) int\n"
- "func \"\".convI2E (elem any) any\n"
- "func \"\".convI2I (typ *uint8, elem any) any\n"
- "func \"\".convT2E (typ *uint8, elem any) any\n"
- "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
- "func \"\".assertE2E (typ *uint8, iface any) any\n"
- "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2I (typ *uint8, iface any) any\n"
- "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertE2T (typ *uint8, iface any) any\n"
- "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2E (typ *uint8, iface any) any\n"
- "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2I (typ *uint8, iface any) any\n"
- "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".assertI2T (typ *uint8, iface any) any\n"
- "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
- "func \"\".ifaceeq (i1 any, i2 any) bool\n"
- "func \"\".efaceeq (i1 any, i2 any) bool\n"
- "func \"\".ifacethash (i1 any) uint32\n"
- "func \"\".efacethash (i1 any) uint32\n"
- "func \"\".makemap (mapType *uint8, hint int64) map[any] any\n"
- "func \"\".mapaccess1 (mapType *uint8, hmap map[any] any, key any) any\n"
- "func \"\".mapaccess2 (mapType *uint8, hmap map[any] any, key any) (val any, pres bool)\n"
- "func \"\".mapassign1 (mapType *uint8, hmap map[any] any, key any, val any)\n"
- "func \"\".mapassign2 (mapType *uint8, hmap map[any] any, key any, val any, pres bool)\n"
- "func \"\".mapiterinit (mapType *uint8, hmap map[any] any, hiter *any)\n"
- "func \"\".mapiternext (hiter *any)\n"
- "func \"\".mapiter1 (hiter *any) any\n"
- "func \"\".mapiter2 (hiter *any) (key any, val any)\n"
- "func \"\".makechan (chanType *uint8, hint int64) chan any\n"
- "func \"\".chanrecv1 (chanType *uint8, hchan <-chan any) any\n"
- "func \"\".chanrecv2 (chanType *uint8, hchan <-chan any) (elem any, received bool)\n"
- "func \"\".chansend1 (chanType *uint8, hchan chan<- any, elem any)\n"
- "func \"\".closechan (hchan any)\n"
- "func \"\".selectnbsend (chanType *uint8, hchan chan<- any, elem any) bool\n"
- "func \"\".selectnbrecv (chanType *uint8, elem *any, hchan <-chan any) bool\n"
- "func \"\".selectnbrecv2 (chanType *uint8, elem *any, received *bool, hchan <-chan any) bool\n"
- "func \"\".newselect (size int) *uint8\n"
- "func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n"
- "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
- "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n"
- "func \"\".selectdefault (sel *uint8) bool\n"
- "func \"\".selectgo (sel *uint8)\n"
- "func \"\".block ()\n"
- "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".growslice (typ *uint8, old []any, n int64) []any\n"
- "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
- "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
- "func \"\".closure ()\n"
- "func \"\".int64div (? int64, ? int64) int64\n"
- "func \"\".uint64div (? uint64, ? uint64) uint64\n"
- "func \"\".int64mod (? int64, ? int64) int64\n"
- "func \"\".uint64mod (? uint64, ? uint64) uint64\n"
- "func \"\".float64toint64 (? float64) int64\n"
- "func \"\".float64touint64 (? float64) uint64\n"
- "func \"\".int64tofloat64 (? int64) float64\n"
- "func \"\".uint64tofloat64 (? uint64) float64\n"
- "func \"\".complex128div (num complex128, den complex128) complex128\n"
- "\n"
- "$$\n";
-char *unsafeimport =
- "package unsafe\n"
- "import runtime \"runtime\"\n"
- "type \"\".Pointer uintptr\n"
- "func \"\".Offsetof (? any) uintptr\n"
- "func \"\".Sizeof (? any) uintptr\n"
- "func \"\".Alignof (? any) uintptr\n"
- "func \"\".Typeof (i interface { }) interface { }\n"
- "func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
- "func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n"
- "func \"\".New (typ interface { }) \"\".Pointer\n"
- "func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n"
- "\n"
- "$$\n";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 1261eefb7..fa44e40fa 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -6,6 +6,8 @@
* function literals aka closures
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
void
@@ -57,7 +59,6 @@ closurebody(NodeList *body)
body = list1(nod(OEMPTY, N, N));
func = curfn;
- l = func->dcl;
func->nbody = body;
funcbody(func);
@@ -129,6 +130,8 @@ makeclosure(Node *func, NodeList **init, int nowrap)
static int closgen;
char *p;
+ USED(init);
+
/*
* wrap body in external function
* with extra closure parameters.
@@ -189,6 +192,10 @@ walkclosure(Node *func, NodeList **init)
Node *xtype, *xfunc, *call, *clos;
NodeList *l, *in;
+ // no closure vars, don't bother wrapping
+ if(func->cvars == nil)
+ return makeclosure(func, init, 1)->nname;
+
/*
* wrap body in external function
* with extra closure parameters.
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 36a64cb97..e27c88338 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#define TUP(x,y) (((x)<<16)|(y))
@@ -85,6 +87,8 @@ convlit1(Node **np, Type *t, int explicit)
switch(n->op) {
default:
+ if(n->type == idealbool)
+ n->type = types[TBOOL];
if(n->type->etype == TIDEAL) {
convlit(&n->left, t);
convlit(&n->right, t);
@@ -106,7 +110,7 @@ convlit1(Node **np, Type *t, int explicit)
if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
n->val = toint(n->val);
if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ yyerror("invalid operation: %N (shift of type %T)", n, t);
t = T;
}
n->type = t;
@@ -168,6 +172,7 @@ convlit1(Node **np, Type *t, int explicit)
break;
case CTINT:
+ case CTRUNE:
case CTFLT:
case CTCPLX:
ct = n->val.ctype;
@@ -177,6 +182,7 @@ convlit1(Node **np, Type *t, int explicit)
goto bad;
case CTCPLX:
case CTFLT:
+ case CTRUNE:
n->val = toint(n->val);
// flowthrough
case CTINT:
@@ -190,6 +196,7 @@ convlit1(Node **np, Type *t, int explicit)
goto bad;
case CTCPLX:
case CTINT:
+ case CTRUNE:
n->val = toflt(n->val);
// flowthrough
case CTFLT:
@@ -204,6 +211,7 @@ convlit1(Node **np, Type *t, int explicit)
goto bad;
case CTFLT:
case CTINT:
+ case CTRUNE:
n->val = tocplx(n->val);
break;
case CTCPLX:
@@ -211,7 +219,7 @@ convlit1(Node **np, Type *t, int explicit)
break;
}
} else
- if(et == TSTRING && ct == CTINT && explicit)
+ if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
n->val = tostr(n->val);
else
goto bad;
@@ -222,7 +230,7 @@ convlit1(Node **np, Type *t, int explicit)
bad:
if(!n->diag) {
- yyerror("cannot convert %#N to type %T", n, t);
+ yyerror("cannot convert %N to type %T", n, t);
n->diag = 1;
}
if(isideal(n->type)) {
@@ -241,6 +249,7 @@ copyval(Val v)
switch(v.ctype) {
case CTINT:
+ case CTRUNE:
i = mal(sizeof(*i));
mpmovefixfix(i, v.u.xval);
v.u.xval = i;
@@ -267,6 +276,7 @@ tocplx(Val v)
switch(v.ctype) {
case CTINT:
+ case CTRUNE:
c = mal(sizeof(*c));
mpmovefixflt(&c->real, v.u.xval);
mpmovecflt(&c->imag, 0.0);
@@ -291,6 +301,7 @@ toflt(Val v)
switch(v.ctype) {
case CTINT:
+ case CTRUNE:
f = mal(sizeof(*f));
mpmovefixflt(f, v.u.xval);
v.ctype = CTFLT;
@@ -314,6 +325,9 @@ toint(Val v)
Mpint *i;
switch(v.ctype) {
+ case CTRUNE:
+ v.ctype = CTINT;
+ break;
case CTFLT:
i = mal(sizeof(*i));
if(mpmovefltfix(i, v.u.fval) < 0)
@@ -343,6 +357,7 @@ overflow(Val v, Type *t)
return;
switch(v.ctype) {
case CTINT:
+ case CTRUNE:
if(!isint[t->etype])
fatal("overflow: %T integer constant", t);
if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
@@ -377,6 +392,7 @@ tostr(Val v)
switch(v.ctype) {
case CTINT:
+ case CTRUNE:
if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
yyerror("overflow in int -> string");
@@ -413,7 +429,12 @@ consttype(Node *n)
int
isconst(Node *n, int ct)
{
- return consttype(n) == ct;
+ int t;
+
+ t = consttype(n);
+ // If the caller is asking for CTINT, allow CTRUNE too.
+ // Makes life easier for back ends.
+ return t == ct || (ct == CTINT && t == CTRUNE);
}
/*
@@ -422,7 +443,7 @@ isconst(Node *n, int ct)
void
evconst(Node *n)
{
- Node *nl, *nr;
+ Node *nl, *nr, *norig;
int32 len;
Strlit *str;
int wl, wr, lno, et;
@@ -516,7 +537,8 @@ evconst(Node *n)
n->right = nr;
if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
goto illegal;
- nl->val = toint(nl->val);
+ if(nl->val.ctype != CTRUNE)
+ nl->val = toint(nl->val);
nr->val = toint(nr->val);
break;
}
@@ -538,6 +560,17 @@ evconst(Node *n)
v = toflt(v);
rv = toflt(rv);
}
+
+ // Rune and int turns into rune.
+ if(v.ctype == CTRUNE && rv.ctype == CTINT)
+ rv.ctype = CTRUNE;
+ if(v.ctype == CTINT && rv.ctype == CTRUNE) {
+ if(n->op == OLSH || n->op == ORSH)
+ rv.ctype = CTINT;
+ else
+ v.ctype = CTRUNE;
+ }
+
if(v.ctype != rv.ctype) {
// Use of undefined name as constant?
if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
@@ -557,15 +590,19 @@ evconst(Node *n)
return;
case TUP(OADD, CTINT):
- mpaddfixfix(v.u.xval, rv.u.xval);
+ case TUP(OADD, CTRUNE):
+ mpaddfixfix(v.u.xval, rv.u.xval, 0);
break;
case TUP(OSUB, CTINT):
+ case TUP(OSUB, CTRUNE):
mpsubfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OMUL, CTINT):
+ case TUP(OMUL, CTRUNE):
mpmulfixfix(v.u.xval, rv.u.xval);
break;
case TUP(ODIV, CTINT):
+ case TUP(ODIV, CTRUNE):
if(mpcmpfixc(rv.u.xval, 0) == 0) {
yyerror("division by zero");
mpmovecfix(v.u.xval, 1);
@@ -574,6 +611,7 @@ evconst(Node *n)
mpdivfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OMOD, CTINT):
+ case TUP(OMOD, CTRUNE):
if(mpcmpfixc(rv.u.xval, 0) == 0) {
yyerror("division by zero");
mpmovecfix(v.u.xval, 1);
@@ -583,21 +621,27 @@ evconst(Node *n)
break;
case TUP(OLSH, CTINT):
+ case TUP(OLSH, CTRUNE):
mplshfixfix(v.u.xval, rv.u.xval);
break;
case TUP(ORSH, CTINT):
+ case TUP(ORSH, CTRUNE):
mprshfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OOR, CTINT):
+ case TUP(OOR, CTRUNE):
mporfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OAND, CTINT):
+ case TUP(OAND, CTRUNE):
mpandfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OANDNOT, CTINT):
+ case TUP(OANDNOT, CTRUNE):
mpandnotfixfix(v.u.xval, rv.u.xval);
break;
case TUP(OXOR, CTINT):
+ case TUP(OXOR, CTRUNE):
mpxorfixfix(v.u.xval, rv.u.xval);
break;
@@ -618,6 +662,14 @@ evconst(Node *n)
}
mpdivfltflt(v.u.fval, rv.u.fval);
break;
+ case TUP(OMOD, CTFLT):
+ // The default case above would print 'ideal % ideal',
+ // which is not quite an ideal error.
+ if(!n->diag) {
+ yyerror("illegal constant expression: floating-point %% operation");
+ n->diag = 1;
+ }
+ return;
case TUP(OADD, CTCPLX):
mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
@@ -647,26 +699,32 @@ evconst(Node *n)
goto setfalse;
case TUP(OEQ, CTINT):
+ case TUP(OEQ, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
goto settrue;
goto setfalse;
case TUP(ONE, CTINT):
+ case TUP(ONE, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
goto settrue;
goto setfalse;
case TUP(OLT, CTINT):
+ case TUP(OLT, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
goto settrue;
goto setfalse;
case TUP(OLE, CTINT):
+ case TUP(OLE, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
goto settrue;
goto setfalse;
case TUP(OGE, CTINT):
+ case TUP(OGE, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
goto settrue;
goto setfalse;
case TUP(OGT, CTINT):
+ case TUP(OGT, CTRUNE):
if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
goto settrue;
goto setfalse;
@@ -784,17 +842,21 @@ unary:
}
// fall through
case TUP(OCONV, CTINT):
+ case TUP(OCONV, CTRUNE):
case TUP(OCONV, CTFLT):
case TUP(OCONV, CTSTR):
convlit1(&nl, n->type, 1);
break;
case TUP(OPLUS, CTINT):
+ case TUP(OPLUS, CTRUNE):
break;
case TUP(OMINUS, CTINT):
+ case TUP(OMINUS, CTRUNE):
mpnegfix(v.u.xval);
break;
case TUP(OCOM, CTINT):
+ case TUP(OCOM, CTRUNE):
et = Txxx;
if(nl->type != T)
et = nl->type->etype;
@@ -840,8 +902,15 @@ unary:
}
ret:
- // rewrite n in place.
+ if(n == n->orig) {
+ // duplicate node for n->orig.
+ norig = nod(OLITERAL, N, N);
+ *norig = *n;
+ } else
+ norig = n->orig;
*n = *nl;
+ // restore value of n->orig.
+ n->orig = norig;
n->val = v;
// check range.
@@ -880,6 +949,7 @@ nodlit(Val v)
n->type = idealbool;
break;
case CTINT:
+ case CTRUNE:
case CTFLT:
case CTCPLX:
n->type = types[TIDEAL];
@@ -937,11 +1007,15 @@ defaultlit(Node **np, Type *t)
defaultlit(&n->left, t);
t = n->left->type;
if(t != T && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ yyerror("invalid operation: %N (shift of type %T)", n, t);
t = T;
}
n->type = t;
return;
+ case ONOT:
+ defaultlit(&n->left, t);
+ n->type = n->left->type;
+ return;
default:
if(n->left == N) {
dump("defaultlit", n);
@@ -961,13 +1035,18 @@ defaultlit(Node **np, Type *t)
} else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) {
defaultlit(&n->right, T);
defaultlit(&n->left, n->right->type);
+ } else if(iscmp[n->op]) {
+ defaultlit2(&n->left, &n->right, 1);
} else {
defaultlit(&n->left, t);
defaultlit(&n->right, t);
}
- if(n->type == idealbool || n->type == idealstring)
- n->type = types[n->type->etype];
- else
+ if(n->type == idealbool || n->type == idealstring) {
+ if(t != T && t->etype == n->type->etype)
+ n->type = t;
+ else
+ n->type = types[n->type->etype];
+ } else
n->type = n->left->type;
return;
}
@@ -989,7 +1068,7 @@ defaultlit(Node **np, Type *t)
n->type = types[TSTRING];
break;
}
- yyerror("defaultlit: unknown literal: %#N", n);
+ yyerror("defaultlit: unknown literal: %N", n);
break;
case CTBOOL:
n->type = types[TBOOL];
@@ -999,6 +1078,9 @@ defaultlit(Node **np, Type *t)
case CTINT:
n->type = types[TINT];
goto num;
+ case CTRUNE:
+ n->type = runetype;
+ goto num;
case CTFLT:
n->type = types[TFLOAT64];
goto num;
@@ -1053,6 +1135,10 @@ defaultlit2(Node **lp, Node **rp, int force)
}
if(!force)
return;
+ if(l->type->etype == TBOOL) {
+ convlit(lp, types[TBOOL]);
+ convlit(rp, types[TBOOL]);
+ }
if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
convlit(lp, types[TCOMPLEX128]);
convlit(rp, types[TCOMPLEX128]);
@@ -1063,6 +1149,13 @@ defaultlit2(Node **lp, Node **rp, int force)
convlit(rp, types[TFLOAT64]);
return;
}
+
+ if(isconst(l, CTRUNE) || isconst(r, CTRUNE)) {
+ convlit(lp, runetype);
+ convlit(rp, runetype);
+ return;
+ }
+
convlit(lp, types[TINT]);
convlit(rp, types[TINT]);
}
@@ -1099,7 +1192,7 @@ cmpslit(Node *l, Node *r)
int
smallintconst(Node *n)
{
- if(n->op == OLITERAL && n->type != T)
+ if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T)
switch(simtype[n->type->etype]) {
case TINT8:
case TUINT8:
@@ -1110,6 +1203,7 @@ smallintconst(Node *n)
case TBOOL:
case TPTR32:
return 1;
+ case TIDEAL:
case TINT64:
case TUINT64:
if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
@@ -1200,6 +1294,7 @@ convconst(Node *con, Type *t, Val *val)
default:
fatal("convconst ctype=%d %lT", val->ctype, t);
case CTINT:
+ case CTRUNE:
i = mpgetfix(val->u.xval);
break;
case CTBOOL:
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
index 890cf7f10..dea7bc3bb 100644
--- a/src/cmd/gc/cplx.c
+++ b/src/cmd/gc/cplx.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
static void subnode(Node *nr, Node *ni, Node *nc);
@@ -131,6 +133,9 @@ complexgen(Node *n, Node *res)
dump("\ncomplexgen-n", n);
dump("complexgen-res", res);
}
+
+ while(n->op == OCONVNOP)
+ n = n->left;
// pick off float/complex opcodes
switch(n->op) {
@@ -199,6 +204,8 @@ complexgen(Node *n, Node *res)
case OIND:
case ONAME: // PHEAP or PPARAMREF var
case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
igen(n, &n1, res);
complexmove(&n1, res);
regfree(&n1);
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 5bfeeb97a..4121a45ab 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "y.tab.h"
static void funcargs(Node*);
+static void funcargs2(Type*);
static int
dflag(void)
@@ -115,6 +118,8 @@ dumpdcl(char *st)
Sym *s, *d;
int i;
+ USED(st);
+
i = 0;
for(d=dclstack; d!=S; d=d->link) {
i++;
@@ -170,6 +175,11 @@ declare(Node *n, int ctxt)
n->lineno = parserline();
s = n->sym;
+
+ // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+ if(importpkg == nil && !typecheckok && s->pkg != localpkg)
+ yyerror("cannot declare name %S", s);
+
gen = 0;
if(ctxt == PEXTERN) {
externdcl = list(externdcl, n);
@@ -188,7 +198,7 @@ declare(Node *n, int ctxt)
n->curfn = curfn;
}
if(ctxt == PAUTO)
- n->xoffset = BADWIDTH;
+ n->xoffset = 0;
if(s->block == block)
redeclare(s, "in this block");
@@ -411,6 +421,7 @@ oldname(Sym *s)
c->funcdepth = funcdepth;
c->outer = n->closure;
n->closure = c;
+ n->addrtaken = 1;
c->closure = n;
c->xoffset = 0;
curfn->cvars = list(curfn->cvars, c);
@@ -468,7 +479,7 @@ colasdefn(NodeList *left, Node *defn)
if(isblank(n))
continue;
if(!colasname(n)) {
- yyerror("non-name %#N on left side of :=", n);
+ yyerror("non-name %N on left side of :=", n);
nerr++;
continue;
}
@@ -542,13 +553,6 @@ ifacedcl(Node *n)
void
funchdr(Node *n)
{
-
- if(n->nname != N) {
- n->nname->op = ONAME;
- declare(n->nname, PFUNC);
- n->nname->defn = n;
- }
-
// change the declaration context from extern to auto
if(funcdepth == 0 && dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
@@ -559,16 +563,19 @@ funchdr(Node *n)
n->outer = curfn;
curfn = n;
+
if(n->nname)
funcargs(n->nname->ntype);
- else
+ else if (n->ntype)
funcargs(n->ntype);
+ else
+ funcargs2(n->type);
}
static void
funcargs(Node *nt)
{
- Node *n;
+ Node *n, *nn;
NodeList *l;
int gen;
@@ -577,11 +584,11 @@ funcargs(Node *nt)
// declare the receiver and in arguments.
// no n->defn because type checking of func header
- // will fill in the types before we can demand them.
+ // will not fill in the types until later
if(nt->left != N) {
n = nt->left;
if(n->op != ODCLFIELD)
- fatal("funcargs1 %O", n->op);
+ fatal("funcargs receiver %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
@@ -591,7 +598,7 @@ funcargs(Node *nt)
for(l=nt->list; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
- fatal("funcargs2 %O", n->op);
+ fatal("funcargs in %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
@@ -604,12 +611,16 @@ funcargs(Node *nt)
for(l=nt->rlist; l; l=l->next) {
n = l->n;
if(n->op != ODCLFIELD)
- fatal("funcargs3 %O", n->op);
+ fatal("funcargs out %O", n->op);
if(n->left != N) {
n->left->op = ONAME;
n->left->ntype = n->right;
if(isblank(n->left)) {
// Give it a name so we can assign to it during return.
+ // preserve the original in ->orig
+ nn = nod(OXXX, N, N);
+ *nn = *n->left;
+ n->left = nn;
snprint(namebuf, sizeof(namebuf), ".anon%d", gen++);
n->left->sym = lookup(namebuf);
}
@@ -619,6 +630,48 @@ funcargs(Node *nt)
}
/*
+ * Same as funcargs, except run over an already constructed TFUNC.
+ * This happens during import, where the hidden_fndcl rule has
+ * used functype directly to parse the function's type.
+ */
+static void
+funcargs2(Type *t)
+{
+ Type *ft;
+ Node *n;
+
+ if(t->etype != TFUNC)
+ fatal("funcargs2 %T", t);
+
+ if(t->thistuple)
+ for(ft=getthisx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname; // no need for newname(ft->nname->sym)
+ n->type = ft->type;
+ declare(n, PPARAM);
+ }
+
+ if(t->intuple)
+ for(ft=getinargx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname;
+ n->type = ft->type;
+ declare(n, PPARAM);
+ }
+
+ if(t->outtuple)
+ for(ft=getoutargx(t)->type; ft; ft=ft->down) {
+ if(!ft->nname || !ft->nname->sym)
+ continue;
+ n = ft->nname;
+ n->type = ft->type;
+ declare(n, PPARAMOUT);
+ }
+}
+
+/*
* finish the body.
* called in auto-declaration context.
* returns in extern-declaration context.
@@ -645,7 +698,7 @@ typedcl0(Sym *s)
{
Node *n;
- n = dclname(s);
+ n = newname(s);
n->op = OTYPE;
declare(n, dclcontext);
return n;
@@ -665,217 +718,265 @@ typedcl1(Node *n, Node *t, int local)
}
/*
- * typedcl1 but during imports
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
*/
-void
-typedcl2(Type *pt, Type *t)
+
+static void
+checkembeddedtype(Type *t)
{
- Node *n;
+ if (t == T)
+ return;
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if(incannedimport &&
- strcmp(importpkg->name, "unsafe") == 0 &&
- strcmp(pt->nod->sym->name, "Pointer") == 0) {
- t = types[TUNSAFEPTR];
+ if(t->sym == S && isptr[t->etype]) {
+ t = t->type;
+ if(t->etype == TINTER)
+ yyerror("embedded type cannot be a pointer to interface");
}
+ if(isptr[t->etype])
+ yyerror("embedded type cannot be a pointer");
+ else if(t->etype == TFORW && t->embedlineno == 0)
+ t->embedlineno = lineno;
+}
- if(pt->etype == TFORW)
- goto ok;
- if(!eqtype(pt->orig, t))
- yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
- return;
+static Type*
+structfield(Node *n)
+{
+ Type *f;
+ int lno;
-ok:
- n = pt->nod;
- copytype(pt->nod, t);
- // unzero nod
- pt->nod = n;
+ lno = lineno;
+ lineno = n->lineno;
+
+ if(n->op != ODCLFIELD)
+ fatal("structfield: oops %N\n", n);
+
+ f = typ(TFIELD);
+ f->isddd = n->isddd;
+
+ if(n->right != N) {
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+ if(n->left != N)
+ n->left->type = n->type;
+ if(n->embedded)
+ checkembeddedtype(n->type);
+ }
+ n->right = N;
+
+ f->type = n->type;
+ if(f->type == T)
+ f->broke = 1;
+
+ switch(n->val.ctype) {
+ case CTSTR:
+ f->note = n->val.u.sval;
+ break;
+ default:
+ yyerror("field annotation must be string");
+ // fallthrough
+ case CTxxx:
+ f->note = nil;
+ break;
+ }
- pt->sym->lastlineno = parserline();
- declare(n, PEXTERN);
+ if(n->left && n->left->op == ONAME) {
+ f->nname = n->left;
+ f->embedded = n->embedded;
+ f->sym = f->nname->sym;
+ }
- checkwidth(pt);
+ lineno = lno;
+ return f;
}
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
+static void
+checkdupfields(Type *t, char* what)
+{
+ Type* t1;
+ int lno;
+ lno = lineno;
+
+ for( ; t; t=t->down)
+ if(t->sym && t->nname && !isblank(t->nname))
+ for(t1=t->down; t1; t1=t1->down)
+ if(t1->sym == t->sym) {
+ lineno = t->nname->lineno;
+ yyerror("duplicate %s %s", what, t->sym->name);
+ break;
+ }
+
+ lineno = lno;
+}
/*
- * turn a parsed struct into a type
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
*/
-static Type**
-stotype(NodeList *l, int et, Type **t, int funarg)
+Type*
+tostruct(NodeList *l)
{
- Type *f, *t1, *t2, **t0;
- Strlit *note;
+ Type *t, *f, **tp;
+ t = typ(TSTRUCT);
+
+ for(tp = &t->type; l; l=l->next) {
+ f = structfield(l->n);
+
+ *tp = f;
+ tp = &f->down;
+ }
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "field");
+
+ if (!t->broke)
+ checkwidth(t);
+
+ return t;
+}
+
+static Type*
+tofunargs(NodeList *l)
+{
+ Type *t, *f, **tp;
+
+ t = typ(TSTRUCT);
+ t->funarg = 1;
+
+ for(tp = &t->type; l; l=l->next) {
+ f = structfield(l->n);
+ f->funarg = 1;
+
+ // esc.c needs to find f given a PPARAM to add the tag.
+ if(l->n->left && l->n->left->class == PPARAM)
+ l->n->left->paramfld = f;
+
+ *tp = f;
+ tp = &f->down;
+ }
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "argument");
+ return t;
+}
+
+static Type*
+interfacefield(Node *n)
+{
+ Type *f;
int lno;
- Node *n, *left;
- char *what;
- t0 = t;
lno = lineno;
- what = "field";
- if(et == TINTER)
- what = "method";
+ lineno = n->lineno;
- for(; l; l=l->next) {
- n = l->n;
- lineno = n->lineno;
- note = nil;
+ if(n->op != ODCLFIELD)
+ fatal("interfacefield: oops %N\n", n);
- if(n->op != ODCLFIELD)
- fatal("stotype: oops %N\n", n);
- left = n->left;
- if(funarg && isblank(left))
- left = N;
- if(n->right != N) {
- if(et == TINTER && left != N) {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n->type = typ(TINTERMETH);
- n->type->nname = n->right;
- n->right = N;
- left->type = n->type;
- queuemethod(n);
- } else {
- typecheck(&n->right, Etype);
- n->type = n->right->type;
- if(n->type == T)
- continue;
- if(left != N)
- left->type = n->type;
- n->right = N;
- if(n->embedded && n->type != T) {
- t1 = n->type;
- if(t1->sym == S && isptr[t1->etype]) {
- t1 = t1->type;
- if(t1->etype == TINTER)
- yyerror("embedded type cannot be a pointer to interface");
- }
- if(isptr[t1->etype])
- yyerror("embedded type cannot be a pointer");
- else if(t1->etype == TFORW && t1->embedlineno == 0)
- t1->embedlineno = lineno;
- }
+ if (n->val.ctype != CTxxx)
+ yyerror("interface method cannot have annotation");
+
+ f = typ(TFIELD);
+ f->isddd = n->isddd;
+
+ if(n->right != N) {
+ if(n->left != N) {
+ // queue resolution of method type for later.
+ // right now all we need is the name list.
+ // avoids cycles for recursive interface types.
+ n->type = typ(TINTERMETH);
+ n->type->nname = n->right;
+ n->left->type = n->type;
+ queuemethod(n);
+
+ if(n->left->op == ONAME) {
+ f->nname = n->left;
+ f->embedded = n->embedded;
+ f->sym = f->nname->sym;
+ if(importpkg && !exportname(f->sym->name))
+ f->sym = pkglookup(f->sym->name, structpkg);
}
- }
- if(n->type == T) {
- // assume error already printed
- continue;
- }
+ } else {
- switch(n->val.ctype) {
- case CTSTR:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- note = n->val.u.sval;
- break;
- default:
- if(et != TSTRUCT)
- yyerror("interface method cannot have annotation");
- else
- yyerror("field annotation must be string");
- case CTxxx:
- note = nil;
- break;
- }
+ typecheck(&n->right, Etype);
+ n->type = n->right->type;
+
+ if(n->embedded)
+ checkembeddedtype(n->type);
- if(et == TINTER && left == N) {
- // embedded interface - inline the methods
- if(n->type->etype != TINTER) {
- if(n->type->etype == TFORW)
+ if(n->type)
+ switch(n->type->etype) {
+ case TINTER:
+ break;
+ case TFORW:
yyerror("interface type loop involving %T", n->type);
- else
+ f->broke = 1;
+ break;
+ default:
yyerror("interface contains embedded non-interface %T", n->type);
- continue;
- }
- for(t1=n->type->type; t1!=T; t1=t1->down) {
- f = typ(TFIELD);
- f->type = t1->type;
- f->width = BADWIDTH;
- f->nname = newname(t1->sym);
- f->sym = t1->sym;
- for(t2=*t0; t2!=T; t2=t2->down) {
- if(t2->sym == f->sym) {
- yyerror("duplicate method %s", t2->sym->name);
- break;
- }
+ f->broke = 1;
+ break;
}
- *t = f;
- t = &f->down;
- }
- continue;
}
-
- f = typ(TFIELD);
- f->type = n->type;
- f->note = note;
- f->width = BADWIDTH;
- f->isddd = n->isddd;
-
- if(left != N && left->op == ONAME) {
- f->nname = left;
- f->embedded = n->embedded;
- f->sym = f->nname->sym;
- if(importpkg && !exportname(f->sym->name))
- f->sym = pkglookup(f->sym->name, structpkg);
- if(f->sym && !isblank(f->nname)) {
- for(t1=*t0; t1!=T; t1=t1->down) {
- if(t1->sym == f->sym) {
- yyerror("duplicate %s %s", what, t1->sym->name);
- break;
- }
- }
- }
- }
-
- *t = f;
- t = &f->down;
}
- *t = T;
+ n->right = N;
+
+ f->type = n->type;
+ if(f->type == T)
+ f->broke = 1;
+
lineno = lno;
- return t;
+ return f;
}
Type*
-dostruct(NodeList *l, int et)
+tointerface(NodeList *l)
{
- Type *t;
- int funarg;
+ Type *t, *f, **tp, *t1;
- /*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
+ t = typ(TINTER);
- funarg = 0;
- if(et == TFUNC) {
- funarg = 1;
- et = TSTRUCT;
- }
- t = typ(et);
- t->funarg = funarg;
- stotype(l, et, &t->type, funarg);
- if(t->type == T && l != nil) {
- t->broke = 1;
- return t;
+ tp = &t->type;
+ for(; l; l=l->next) {
+ f = interfacefield(l->n);
+
+ if (l->n->left == N && f->type->etype == TINTER) {
+ // embedded interface, inline methods
+ for(t1=f->type->type; t1; t1=t1->down) {
+ f = typ(TFIELD);
+ f->type = t1->type;
+ f->broke = t1->broke;
+ f->sym = t1->sym;
+ if(f->sym)
+ f->nname = newname(f->sym);
+ *tp = f;
+ tp = &f->down;
+ }
+ } else {
+ *tp = f;
+ tp = &f->down;
+ }
}
- if(et == TINTER)
- t = sortinter(t);
- if(!funarg)
- checkwidth(t);
+
+ for(f=t->type; f && !t->broke; f=f->down)
+ if(f->broke)
+ t->broke = 1;
+
+ checkdupfields(t->type, "method");
+ t = sortinter(t);
+ checkwidth(t);
+
return t;
}
-
Node*
embedded(Sym *s)
{
@@ -892,7 +993,10 @@ embedded(Sym *s)
*utfrune(name, CenterDot) = 0;
}
- n = newname(lookup(name));
+ if(exportname(name) || s->pkg == builtinpkg) // old behaviour, tests pass, but is it correct?
+ n = newname(lookup(name));
+ else
+ n = newname(pkglookup(name, s->pkg));
n = nod(ODCLFIELD, n, oldname(s));
n->embedded = 1;
return n;
@@ -957,6 +1061,17 @@ checkarglist(NodeList *all, int input)
t = n;
n = N;
}
+
+ // during import l->n->op is OKEY, but l->n->left->sym == S
+ // means it was a '?', not that it was
+ // a lone type This doesn't matter for the exported
+ // declarations, which are parsed by rules that don't
+ // use checkargs, but can happen for func literals in
+ // the inline bodies.
+ // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
+ if(importpkg && n->sym == S)
+ n = N;
+
if(n != N && n->sym == S) {
t = n;
n = N;
@@ -1030,9 +1145,12 @@ functype(Node *this, NodeList *in, NodeList *out)
rcvr = nil;
if(this)
rcvr = list1(this);
- t->type = dostruct(rcvr, TFUNC);
- t->type->down = dostruct(out, TFUNC);
- t->type->down->down = dostruct(in, TFUNC);
+ t->type = tofunargs(rcvr);
+ t->type->down = tofunargs(out);
+ t->type->down->down = tofunargs(in);
+
+ if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
+ t->broke = 1;
if(this)
t->thistuple = 1;
@@ -1050,21 +1168,22 @@ methodsym(Sym *nsym, Type *t0, int iface)
char *p;
Type *t;
char *suffix;
+ Pkg *spkg;
+ static Pkg *toppkg;
t = t0;
if(t == T)
goto bad;
s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
+ if(s == S && isptr[t->etype]) {
t = t->type;
if(t == T)
goto bad;
s = t->sym;
- if(s == S)
- goto bad;
}
+ spkg = nil;
+ if(s != S)
+ spkg = s->pkg;
// if t0 == *t and t0 has a sym,
// we want to see *t, not t0, in the method name.
@@ -1077,11 +1196,23 @@ methodsym(Sym *nsym, Type *t0, int iface)
if(t0->width < types[tptr]->width)
suffix = "·i";
}
- if(t0->sym == S && isptr[t0->etype])
- p = smprint("(%#hT).%s%s", t0, nsym->name, suffix);
- else
- p = smprint("%#hT.%s%s", t0, nsym->name, suffix);
- s = pkglookup(p, s->pkg);
+ if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ } else {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
+ }
+ if(spkg == nil) {
+ if(toppkg == nil)
+ toppkg = mkpkg(strlit("go"));
+ spkg = toppkg;
+ }
+ s = pkglookup(p, spkg);
free(p);
return s;
@@ -1114,11 +1245,16 @@ methodname1(Node *n, Node *t)
}
if(t->sym == S || isblank(n))
return newname(n->sym);
+
if(star)
p = smprint("(%s%S).%S", star, t->sym, n->sym);
else
p = smprint("%S.%S", t->sym, n->sym);
- n = newname(pkglookup(p, t->sym->pkg));
+
+ if(exportname(t->sym->name))
+ n = newname(lookup(p));
+ else
+ n = newname(pkglookup(p, t->sym->pkg));
free(p);
return n;
}
@@ -1133,8 +1269,6 @@ addmethod(Sym *sf, Type *t, int local)
Type *f, *d, *pa;
Node *n;
- pa = nil;
-
// get field sym
if(sf == S)
fatal("no method symbol");
@@ -1147,7 +1281,7 @@ addmethod(Sym *sf, Type *t, int local)
}
pa = pa->type;
- f = methtype(pa);
+ f = methtype(pa, 1);
if(f == T) {
t = pa;
if(t != T) {
@@ -1159,6 +1293,8 @@ addmethod(Sym *sf, Type *t, int local)
t = t->type;
}
}
+ if(t->broke) // rely on typecheck having complained before
+ return;
if(t != T) {
if(t->sym == S) {
yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
@@ -1180,8 +1316,14 @@ addmethod(Sym *sf, Type *t, int local)
}
pa = f;
- if(importpkg && !exportname(sf->name))
- sf = pkglookup(sf->name, importpkg);
+ if(pa->etype == TSTRUCT) {
+ for(f=pa->type; f; f=f->down) {
+ if(f->sym == sf) {
+ yyerror("type %T has both field and method named %S", pa, sf);
+ return;
+ }
+ }
+ }
n = nod(ODCLFIELD, newname(sf), N);
n->type = t;
@@ -1204,10 +1346,16 @@ addmethod(Sym *sf, Type *t, int local)
return;
}
+ f = structfield(n);
+
+ // during import unexported method names should be in the type's package
+ if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
+ fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
+
if(d == T)
- stotype(list1(n), 0, &pa->method, 0);
+ pa->method = f;
else
- stotype(list1(n), 0, &d->down, 0);
+ d->down = f;
return;
}
@@ -1249,6 +1397,3 @@ funccompile(Node *n, int isclosure)
funcdepth = 0;
dclcontext = PEXTERN;
}
-
-
-
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 3fe7fafdd..163d3862c 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -26,7 +26,7 @@ package P to read the files of P's dependencies, only the compiled output
of P.
Usage:
- 6g [flags] file...
+ go tool 6g [flags] file...
The specified files must be Go source files and all part of the same package.
Substitute 6g with 8g or 5g where appropriate.
@@ -35,12 +35,17 @@ Flags:
output file, default file.6 for 6g, etc.
-e
normally the compiler quits after 10 errors; -e prints all errors
+ -p path
+ assume that path is the eventual import path for this code,
+ and diagnose any attempt to import a package that depends on it.
+ -D path
+ treat a relative import as relative to path
-L
show entire file path when printing line numbers in errors
-I dir1 -I dir2
add dir1 and dir2 to the list of paths to check for imported packages
-N
- disable optimization
+ disable optimizations
-S
write assembly language text to standard output
-u
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
new file mode 100644
index 000000000..2614b5f35
--- /dev/null
+++ b/src/cmd/gc/esc.c
@@ -0,0 +1,805 @@
+// 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.
+//
+// Escape analysis.
+//
+// First escfunc, esc and escassign recurse over the ast of each
+// function to dig out flow(dst,src) edges between any
+// pointer-containing nodes and store them in dst->escflowsrc. For
+// variables assigned to a variable in an outer scope or used as a
+// return value, they store a flow(theSink, src) edge to a fake node
+// 'the Sink'. For variables referenced in closures, an edge
+// flow(closure, &var) is recorded and the flow of a closure itself to
+// an outer scope is tracked the same way as other variables.
+//
+// Then escflood walks the graph starting at theSink and tags all
+// variables of it can reach an & node as escaping and all function
+// parameters it can reach as leaking.
+//
+// If a value's address is taken but the address does not escape,
+// then the value can stay on the stack. If the value new(T) does
+// not escape, then new(T) can be rewritten into a stack allocation.
+// The same is true of slice literals.
+//
+// If escape analysis is disabled (-s), this code is not used.
+// Instead, the compiler assumes that any value whose address
+// is taken without being immediately dereferenced
+// needs to be moved to the heap, and new(T) and slice
+// literals are always real allocations.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+static void escfunc(Node *func);
+static void esclist(NodeList *l);
+static void esc(Node *n);
+static void escloopdepthlist(NodeList *l);
+static void escloopdepth(Node *n);
+static void escassign(Node *dst, Node *src);
+static void esccall(Node*);
+static void escflows(Node *dst, Node *src);
+static void escflood(Node *dst);
+static void escwalk(int level, Node *dst, Node *src);
+static void esctag(Node *func);
+
+// Fake node that all
+// - return values and output variables
+// - parameters on imported functions not marked 'safe'
+// - assignments to global variables
+// flow to.
+static Node theSink;
+
+static NodeList* dsts; // all dst nodes
+static int loopdepth; // for detecting nested loop scopes
+static int pdepth; // for debug printing in recursions.
+static Strlit* safetag; // gets slapped on safe parameters' field types for export
+static int dstcount, edgecount; // diagnostic
+static NodeList* noesc; // list of possible non-escaping nodes, for printing
+
+void
+escapes(NodeList *all)
+{
+ NodeList *l;
+
+ theSink.op = ONAME;
+ theSink.orig = &theSink;
+ theSink.class = PEXTERN;
+ theSink.sym = lookup(".sink");
+ theSink.escloopdepth = -1;
+
+ safetag = strlit("noescape");
+ noesc = nil;
+
+ // flow-analyze functions
+ for(l=all; l; l=l->next)
+ if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE)
+ escfunc(l->n);
+
+ // print("escapes: %d dsts, %d edges\n", dstcount, edgecount);
+
+ // visit the updstream of each dst, mark address nodes with
+ // addrescapes, mark parameters unsafe
+ for(l = dsts; l; l=l->next)
+ escflood(l->n);
+
+ // for all top level functions, tag the typenodes corresponding to the param nodes
+ for(l=all; l; l=l->next)
+ if(l->n->op == ODCLFUNC)
+ esctag(l->n);
+
+ if(debug['m']) {
+ for(l=noesc; l; l=l->next)
+ if(l->n->esc == EscNone)
+ warnl(l->n->lineno, "%S %hN does not escape",
+ (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
+ l->n);
+ }
+}
+
+
+static void
+escfunc(Node *func)
+{
+ Node *savefn, *n;
+ NodeList *ll;
+ int saveld;
+
+ saveld = loopdepth;
+ loopdepth = 1;
+ savefn = curfn;
+ curfn = func;
+
+ for(ll=curfn->dcl; ll; ll=ll->next) {
+ if(ll->n->op != ONAME)
+ continue;
+ switch (ll->n->class) {
+ case PPARAMOUT:
+ // output parameters flow to the sink
+ escflows(&theSink, ll->n);
+ ll->n->escloopdepth = loopdepth;
+ break;
+ case PPARAM:
+ if(ll->n->type && !haspointers(ll->n->type))
+ break;
+ ll->n->esc = EscNone; // prime for escflood later
+ noesc = list(noesc, ll->n);
+ ll->n->escloopdepth = loopdepth;
+ break;
+ }
+ }
+
+ // walk will take the address of cvar->closure later and assign it to cvar.
+ // handle that here by linking a fake oaddr node directly to the closure.
+ for(ll=curfn->cvars; ll; ll=ll->next) {
+ if(ll->n->op == OXXX) // see dcl.c:398
+ continue;
+
+ n = nod(OADDR, ll->n->closure, N);
+ n->lineno = ll->n->lineno;
+ typecheck(&n, Erv);
+ escassign(curfn, n);
+ }
+
+ escloopdepthlist(curfn->nbody);
+ esclist(curfn->nbody);
+ curfn = savefn;
+ loopdepth = saveld;
+}
+
+// Mark labels that have no backjumps to them as not increasing loopdepth.
+// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
+// and set it to one of the following two. Then in esc we'll clear it again.
+static Label looping;
+static Label nonlooping;
+
+static void
+escloopdepthlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ escloopdepth(l->n);
+}
+
+static void
+escloopdepth(Node *n)
+{
+ if(n == N)
+ return;
+
+ escloopdepthlist(n->ninit);
+
+ switch(n->op) {
+ case OLABEL:
+ if(!n->left || !n->left->sym)
+ fatal("esc:label without label: %+N", n);
+ // Walk will complain about this label being already defined, but that's not until
+ // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
+ // if(n->left->sym->label != nil)
+ // fatal("escape analysis messed up analyzing label: %+N", n);
+ n->left->sym->label = &nonlooping;
+ break;
+ case OGOTO:
+ if(!n->left || !n->left->sym)
+ fatal("esc:goto without label: %+N", n);
+ // If we come past one that's uninitialized, this must be a (harmless) forward jump
+ // but if it's set to nonlooping the label must have preceded this goto.
+ if(n->left->sym->label == &nonlooping)
+ n->left->sym->label = &looping;
+ break;
+ }
+
+ escloopdepth(n->left);
+ escloopdepth(n->right);
+ escloopdepthlist(n->list);
+ escloopdepth(n->ntest);
+ escloopdepth(n->nincr);
+ escloopdepthlist(n->nbody);
+ escloopdepthlist(n->nelse);
+ escloopdepthlist(n->rlist);
+
+}
+
+static void
+esclist(NodeList *l)
+{
+ for(; l; l=l->next)
+ esc(l->n);
+}
+
+static void
+esc(Node *n)
+{
+ int lno;
+ NodeList *ll, *lr;
+
+ if(n == N)
+ return;
+
+ lno = setlineno(n);
+
+ if(n->op == OFOR || n->op == ORANGE)
+ loopdepth++;
+
+ esc(n->left);
+ esc(n->right);
+ esc(n->ntest);
+ esc(n->nincr);
+ esclist(n->ninit);
+ esclist(n->nbody);
+ esclist(n->nelse);
+ esclist(n->list);
+ esclist(n->rlist);
+
+ if(n->op == OFOR || n->op == ORANGE)
+ loopdepth--;
+
+ if(debug['m'] > 1)
+ print("%L:[%d] %S esc: %N\n", lineno, loopdepth,
+ (curfn && curfn->nname) ? curfn->nname->sym : S, n);
+
+ switch(n->op) {
+ case ODCL:
+ // Record loop depth at declaration.
+ if(n->left)
+ n->left->escloopdepth = loopdepth;
+ break;
+
+ case OLABEL:
+ if(n->left->sym->label == &nonlooping) {
+ if(debug['m'] > 1)
+ print("%L:%N non-looping label\n", lineno, n);
+ } else if(n->left->sym->label == &looping) {
+ if(debug['m'] > 1)
+ print("%L: %N looping label\n", lineno, n);
+ loopdepth++;
+ }
+ // See case OLABEL in escloopdepth above
+ // else if(n->left->sym->label == nil)
+ // fatal("escape anaylysis missed or messed up a label: %+N", n);
+
+ n->left->sym->label = nil;
+
+ case ORANGE:
+ // Everything but fixed array is a dereference.
+ if(isfixedarray(n->type) && n->list->next)
+ escassign(n->list->next->n, n->right);
+ break;
+
+ case OSWITCH:
+ if(n->ntest && n->ntest->op == OTYPESW) {
+ for(ll=n->list; ll; ll=ll->next) { // cases
+ // ntest->right is the argument of the .(type),
+ // ll->n->nname is the variable per case
+ escassign(ll->n->nname, n->ntest->right);
+ }
+ }
+ break;
+
+ case OAS:
+ case OASOP:
+ escassign(n->left, n->right);
+ break;
+
+ case OAS2: // x,y = a,b
+ if(count(n->list) == count(n->rlist))
+ for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
+ escassign(ll->n, lr->n);
+ break;
+
+ case OAS2RECV: // v, ok = <-ch
+ case OAS2MAPR: // v, ok = m[k]
+ case OAS2DOTTYPE: // v, ok = x.(type)
+ escassign(n->list->n, n->rlist->n);
+ break;
+
+ case OSEND: // ch <- x
+ escassign(&theSink, n->right);
+ break;
+
+ case ODEFER:
+ if(loopdepth == 1) // top level
+ break;
+ // arguments leak out of scope
+ // TODO: leak to a dummy node instead
+ // fallthrough
+ case OPROC:
+ // go f(x) - f and x escape
+ escassign(&theSink, n->left->left);
+ escassign(&theSink, n->left->right); // ODDDARG for call
+ for(ll=n->left->list; ll; ll=ll->next)
+ escassign(&theSink, ll->n);
+ break;
+
+ case ORETURN:
+ for(ll=n->list; ll; ll=ll->next)
+ escassign(&theSink, ll->n);
+ break;
+
+ case OPANIC:
+ // Argument could leak through recover.
+ escassign(&theSink, n->left);
+ break;
+
+ case OAPPEND:
+ if(!n->isddd)
+ for(ll=n->list->next; ll; ll=ll->next)
+ escassign(&theSink, ll->n); // lose track of assign to dereference
+ break;
+
+ case OCALLMETH:
+ case OCALLFUNC:
+ case OCALLINTER:
+ esccall(n);
+ break;
+
+ case OCONV:
+ case OCONVNOP:
+ case OCONVIFACE:
+ escassign(n, n->left);
+ break;
+
+ case OARRAYLIT:
+ if(isslice(n->type)) {
+ n->esc = EscNone; // until proven otherwise
+ noesc = list(noesc, n);
+ n->escloopdepth = loopdepth;
+ // Values make it to memory, lose track.
+ for(ll=n->list; ll; ll=ll->next)
+ escassign(&theSink, ll->n->right);
+ } else {
+ // Link values to array.
+ for(ll=n->list; ll; ll=ll->next)
+ escassign(n, ll->n->right);
+ }
+ break;
+
+ case OSTRUCTLIT:
+ // Link values to struct.
+ for(ll=n->list; ll; ll=ll->next)
+ escassign(n, ll->n->right);
+ break;
+
+ case OPTRLIT:
+ n->esc = EscNone; // until proven otherwise
+ noesc = list(noesc, n);
+ n->escloopdepth = loopdepth;
+ // Contents make it to memory, lose track.
+ escassign(&theSink, n->left);
+ break;
+
+ case OMAPLIT:
+ n->esc = EscNone; // until proven otherwise
+ noesc = list(noesc, n);
+ n->escloopdepth = loopdepth;
+ // Keys and values make it to memory, lose track.
+ for(ll=n->list; ll; ll=ll->next) {
+ escassign(&theSink, ll->n->left);
+ escassign(&theSink, ll->n->right);
+ }
+ break;
+
+ case OADDR:
+ case OCLOSURE:
+ case OMAKECHAN:
+ case OMAKEMAP:
+ case OMAKESLICE:
+ case ONEW:
+ n->escloopdepth = loopdepth;
+ n->esc = EscNone; // until proven otherwise
+ noesc = list(noesc, n);
+ break;
+ }
+
+ lineno = lno;
+}
+
+// Assert that expr somehow gets assigned to dst, if non nil. for
+// dst==nil, any name node expr still must be marked as being
+// evaluated in curfn. For expr==nil, dst must still be examined for
+// evaluations inside it (e.g *f(x) = y)
+static void
+escassign(Node *dst, Node *src)
+{
+ int lno;
+
+ if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
+ return;
+
+ if(debug['m'] > 1)
+ print("%L:[%d] %S escassign: %hN = %hN\n", lineno, loopdepth,
+ (curfn && curfn->nname) ? curfn->nname->sym : S, dst, src);
+
+ setlineno(dst);
+
+ // Analyze lhs of assignment.
+ // Replace dst with theSink if we can't track it.
+ switch(dst->op) {
+ default:
+ dump("dst", dst);
+ fatal("escassign: unexpected dst");
+
+ case OARRAYLIT:
+ case OCLOSURE:
+ case OCONV:
+ case OCONVIFACE:
+ case OCONVNOP:
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ break;
+
+ case ONAME:
+ if(dst->class == PEXTERN)
+ dst = &theSink;
+ break;
+ case ODOT: // treat "dst.x = src" as "dst = src"
+ escassign(dst->left, src);
+ return;
+ case OINDEX:
+ if(isfixedarray(dst->left->type)) {
+ escassign(dst->left, src);
+ return;
+ }
+ dst = &theSink; // lose track of dereference
+ break;
+ case OIND:
+ case ODOTPTR:
+ dst = &theSink; // lose track of dereference
+ break;
+ case OINDEXMAP:
+ // lose track of key and value
+ escassign(&theSink, dst->right);
+ dst = &theSink;
+ break;
+ }
+
+ lno = setlineno(src);
+ pdepth++;
+
+ switch(src->op) {
+ case OADDR: // dst = &x
+ case OIND: // dst = *x
+ case ODOTPTR: // dst = (*x).f
+ case ONAME:
+ case OPARAM:
+ case ODDDARG:
+ case OPTRLIT:
+ case OARRAYLIT:
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ // loopdepth was set in the defining statement or function header
+ escflows(dst, src);
+ break;
+
+ case ODOT:
+ // A non-pointer escaping from a struct does not concern us.
+ if(src->type && !haspointers(src->type))
+ break;
+ // fallthrough
+ case OCONV:
+ case OCONVIFACE:
+ case OCONVNOP:
+ case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
+ // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ case OSLICE:
+ case OSLICEARR:
+ // Conversions, field access, slice all preserve the input value.
+ escassign(dst, src->left);
+ break;
+
+ case OAPPEND:
+ // Append returns first argument.
+ escassign(dst, src->list->n);
+ break;
+
+ case OINDEX:
+ // Index of array preserves input value.
+ if(isfixedarray(src->left->type))
+ escassign(dst, src->left);
+ break;
+
+ case OMAKECHAN:
+ case OMAKEMAP:
+ case OMAKESLICE:
+ case ONEW:
+ escflows(dst, src);
+ break;
+
+ case OCLOSURE:
+ escflows(dst, src);
+ escfunc(src);
+ break;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OANDNOT:
+ case OPLUS:
+ case OMINUS:
+ case OCOM:
+ // Might be pointer arithmetic, in which case
+ // the operands flow into the result.
+ // TODO(rsc): Decide what the story is here. This is unsettling.
+ escassign(dst, src->left);
+ escassign(dst, src->right);
+ break;
+
+ }
+
+ pdepth--;
+ lineno = lno;
+}
+
+
+// This is a bit messier than fortunate, pulled out of escassign's big
+// switch for clarity. We either have the paramnodes, which may be
+// connected to other things throug flows or we have the parameter type
+// nodes, which may be marked 'n(ofloworescape)'. Navigating the ast is slightly
+// different for methods vs plain functions and for imported vs
+// this-package
+static void
+esccall(Node *n)
+{
+ NodeList *ll, *lr;
+ Node *a, *fn, *src;
+ Type *t, *fntype;
+
+ fn = N;
+ switch(n->op) {
+ default:
+ fatal("esccall");
+
+ case OCALLFUNC:
+ fn = n->left;
+ fntype = fn->type;
+ break;
+
+ case OCALLMETH:
+ fn = n->left->right->sym->def;
+ if(fn)
+ fntype = fn->type;
+ else
+ fntype = n->left->type;
+ break;
+
+ case OCALLINTER:
+ fntype = n->left->type;
+ break;
+ }
+
+ ll = n->list;
+ if(n->list != nil && n->list->next == nil) {
+ a = n->list->n;
+ if(a->type->etype == TSTRUCT && a->type->funarg) {
+ // f(g()).
+ // Since f's arguments are g's results and
+ // all function results escape, we're done.
+ ll = nil;
+ }
+ }
+
+ if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype) {
+ // Local function. Incorporate into flow graph.
+
+ // Receiver.
+ if(n->op != OCALLFUNC)
+ escassign(fn->ntype->left->left, n->left->left);
+
+ for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
+ src = ll->n;
+ if(lr->n->isddd && !n->isddd) {
+ // Introduce ODDDARG node to represent ... allocation.
+ src = nod(ODDDARG, N, N);
+ src->escloopdepth = loopdepth;
+ src->lineno = n->lineno;
+ src->esc = EscNone; // until we find otherwise
+ noesc = list(noesc, src);
+ n->right = src;
+ }
+ if(lr->n->left != N)
+ escassign(lr->n->left, src);
+ if(src != ll->n)
+ break;
+ }
+ // "..." arguments are untracked
+ for(; ll; ll=ll->next)
+ escassign(&theSink, ll->n);
+ return;
+ }
+
+ // Imported function. Use the escape tags.
+ if(n->op != OCALLFUNC) {
+ t = getthisx(fntype)->type;
+ if(!t->note || strcmp(t->note->s, safetag->s) != 0)
+ escassign(&theSink, n->left->left);
+ }
+ for(t=getinargx(fntype)->type; ll; ll=ll->next) {
+ src = ll->n;
+ if(t->isddd && !n->isddd) {
+ // Introduce ODDDARG node to represent ... allocation.
+ src = nod(ODDDARG, N, N);
+ src->escloopdepth = loopdepth;
+ src->lineno = n->lineno;
+ src->esc = EscNone; // until we find otherwise
+ noesc = list(noesc, src);
+ n->right = src;
+ }
+ if(!t->note || strcmp(t->note->s, safetag->s) != 0)
+ escassign(&theSink, src);
+ if(src != ll->n)
+ break;
+ t = t->down;
+ }
+ // "..." arguments are untracked
+ for(; ll; ll=ll->next)
+ escassign(&theSink, ll->n);
+}
+
+// Store the link src->dst in dst, throwing out some quick wins.
+static void
+escflows(Node *dst, Node *src)
+{
+ if(dst == nil || src == nil || dst == src)
+ return;
+
+ // Don't bother building a graph for scalars.
+ if(src->type && !haspointers(src->type))
+ return;
+
+ if(debug['m']>2)
+ print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
+
+ if(dst->escflowsrc == nil) {
+ dsts = list(dsts, dst);
+ dstcount++;
+ }
+ edgecount++;
+
+ dst->escflowsrc = list(dst->escflowsrc, src);
+}
+
+// Whenever we hit a reference node, the level goes up by one, and whenever
+// we hit an OADDR, the level goes down by one. as long as we're on a level > 0
+// finding an OADDR just means we're following the upstream of a dereference,
+// so this address doesn't leak (yet).
+// If level == 0, it means the /value/ of this node can reach the root of this flood.
+// so if this node is an OADDR, it's argument should be marked as escaping iff
+// it's currfn/loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of it's upstream should be considered
+// escaping to the global scope.
+static void
+escflood(Node *dst)
+{
+ NodeList *l;
+
+ switch(dst->op) {
+ case ONAME:
+ case OCLOSURE:
+ break;
+ default:
+ return;
+ }
+
+ if(debug['m']>1)
+ print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
+ (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
+ dst->escloopdepth);
+
+ for(l = dst->escflowsrc; l; l=l->next) {
+ walkgen++;
+ escwalk(0, dst, l->n);
+ }
+}
+
+static void
+escwalk(int level, Node *dst, Node *src)
+{
+ NodeList *ll;
+ int leaks;
+
+ if(src->walkgen == walkgen)
+ return;
+ src->walkgen = walkgen;
+
+ if(debug['m']>1)
+ print("escwalk: level:%d depth:%d %.*s %hN scope:%S[%d]\n",
+ level, pdepth, pdepth, "\t\t\t\t\t\t\t\t\t\t", src,
+ (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
+
+ pdepth++;
+
+ leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth);
+
+ switch(src->op) {
+ case ONAME:
+ if(src->class == PPARAM && leaks && src->esc == EscNone) {
+ src->esc = EscScope;
+ if(debug['m'])
+ warnl(src->lineno, "leaking param: %hN", src);
+ }
+ break;
+
+ case OPTRLIT:
+ case OADDR:
+ if(leaks) {
+ src->esc = EscHeap;
+ addrescapes(src->left);
+ if(debug['m'])
+ warnl(src->lineno, "%hN escapes to heap", src);
+ }
+ escwalk(level-1, dst, src->left);
+ break;
+
+ case OARRAYLIT:
+ if(isfixedarray(src->type))
+ break;
+ // fall through
+ case ODDDARG:
+ case OMAKECHAN:
+ case OMAKEMAP:
+ case OMAKESLICE:
+ case OMAPLIT:
+ case ONEW:
+ case OCLOSURE:
+ if(leaks) {
+ src->esc = EscHeap;
+ if(debug['m'])
+ warnl(src->lineno, "%hN escapes to heap", src);
+ }
+ break;
+
+ case OINDEX:
+ if(isfixedarray(src->type))
+ break;
+ // fall through
+ case OSLICE:
+ case ODOTPTR:
+ case OINDEXMAP:
+ case OIND:
+ escwalk(level+1, dst, src->left);
+ }
+
+ for(ll=src->escflowsrc; ll; ll=ll->next)
+ escwalk(level, dst, ll->n);
+
+ pdepth--;
+}
+
+static void
+esctag(Node *func)
+{
+ Node *savefn;
+ NodeList *ll;
+
+ // External functions must be assumed unsafe.
+ if(func->nbody == nil)
+ return;
+
+ savefn = curfn;
+ curfn = func;
+
+ for(ll=curfn->dcl; ll; ll=ll->next) {
+ if(ll->n->op != ONAME || ll->n->class != PPARAM)
+ continue;
+
+ switch (ll->n->esc) {
+ case EscNone: // not touched by escflood
+ if(haspointers(ll->n->type)) // don't bother tagging for scalars
+ ll->n->paramfld->note = safetag;
+ case EscHeap: // touched by escflood, moved to heap
+ case EscScope: // touched by escflood, value leaves scope
+ break;
+ }
+ }
+
+ curfn = savefn;
+}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 014f0c5f0..bbed8ae36 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "y.tab.h"
-static void dumpsym(Sym*);
-static void dumpexporttype(Sym*);
-static void dumpexportvar(Sym*);
-static void dumpexportconst(Sym*);
+static void dumpexporttype(Type *t);
+// Mark n's symbol as exported
void
exportsym(Node *n)
{
@@ -25,6 +25,7 @@ exportsym(Node *n)
exportlist = list(exportlist, n);
}
+// Mark n's symbol as package-local
static void
packagesym(Node *n)
{
@@ -77,7 +78,7 @@ dumppkg(Pkg *p)
{
char *suffix;
- if(p == nil || p == localpkg || p->exported)
+ if(p == nil || p == localpkg || p->exported || p == builtinpkg)
return;
p->exported = 1;
suffix = "";
@@ -86,25 +87,84 @@ dumppkg(Pkg *p)
Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
}
+// Look for anything we need for the inline body
+static void reexportdep(Node *n);
static void
-dumpprereq(Type *t)
+reexportdeplist(NodeList *ll)
{
- if(t == T)
- return;
+ for(; ll ;ll=ll->next)
+ reexportdep(ll->n);
+}
+
+static void
+reexportdep(Node *n)
+{
+ Type *t;
- if(t->printed || t == types[t->etype])
+ if(!n)
return;
- t->printed = 1;
- if(t->sym != S) {
- dumppkg(t->sym->pkg);
- if(t->etype != TFIELD)
- dumpsym(t->sym);
+// print("reexportdep %+hN\n", n);
+ switch(n->op) {
+ case ONAME:
+ switch(n->class&~PHEAP) {
+ case PFUNC:
+ // methods will be printed along with their type
+ if(!n->type || n->type->thistuple > 0)
+ break;
+ // fallthrough
+ case PEXTERN:
+ if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
+ exportlist = list(exportlist, n);
+ }
+ break;
+
+
+ case OLITERAL:
+ t = n->type;
+ if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
+ if(isptr[t->etype])
+ t = t->type;
+ if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) {
+// print("reexport literal type %+hN\n", t->sym->def);
+ exportlist = list(exportlist, t->sym->def);
+ }
+ }
+ // fallthrough
+ case OTYPE:
+ if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg)
+ exportlist = list(exportlist, n);
+ break;
+
+ // for operations that need a type when rendered, put the type on the export list.
+ case OCONV:
+ case OCONVIFACE:
+ case OCONVNOP:
+ case ODOTTYPE:
+ case OSTRUCTLIT:
+ case OPTRLIT:
+ t = n->type;
+ if(!t->sym && t->type)
+ t = t->type;
+ if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) {
+// print("reexport convnop %+hN\n", t->sym->def);
+ exportlist = list(exportlist, t->sym->def);
+ }
+ break;
}
- dumpprereq(t->type);
- dumpprereq(t->down);
+
+ reexportdep(n->left);
+ reexportdep(n->right);
+ reexportdeplist(n->list);
+ reexportdeplist(n->rlist);
+ reexportdeplist(n->ninit);
+ reexportdep(n->ntest);
+ reexportdep(n->nincr);
+ reexportdeplist(n->nbody);
+ reexportdeplist(n->nelse);
}
+
static void
dumpexportconst(Sym *s)
{
@@ -117,37 +177,12 @@ dumpexportconst(Sym *s)
fatal("dumpexportconst: oconst nil: %S", s);
t = n->type; // may or may not be specified
- if(t != T)
- dumpprereq(t);
+ dumpexporttype(t);
- Bprint(bout, "\t");
- Bprint(bout, "const %#S", s);
if(t != T && !isideal(t))
- Bprint(bout, " %#T", t);
- Bprint(bout, " = ");
-
- switch(n->val.ctype) {
- default:
- fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);
- case CTINT:
- Bprint(bout, "%B\n", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- Bprint(bout, "true\n");
- else
- Bprint(bout, "false\n");
- break;
- case CTFLT:
- Bprint(bout, "%F\n", n->val.u.fval);
- break;
- case CTCPLX:
- Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag);
- break;
- case CTSTR:
- Bprint(bout, "\"%Z\"\n", n->val.u.sval);
- break;
- }
+ Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
+ else
+ Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
}
static void
@@ -157,38 +192,27 @@ dumpexportvar(Sym *s)
Type *t;
n = s->def;
- typecheck(&n, Erv);
+ typecheck(&n, Erv|Ecall);
if(n == N || n->type == T) {
yyerror("variable exported but not defined: %S", s);
return;
}
t = n->type;
- dumpprereq(t);
-
- Bprint(bout, "\t");
- if(t->etype == TFUNC && n->class == PFUNC)
- Bprint(bout, "func %#S %#hhT", s, t);
- else
- Bprint(bout, "var %#S %#T", s, t);
- Bprint(bout, "\n");
-}
-
-static void
-dumpexporttype(Sym *s)
-{
- Type *t;
-
- t = s->def->type;
- dumpprereq(t);
- Bprint(bout, "\t");
- switch (t->etype) {
- case TFORW:
- yyerror("export of incomplete type %T", t);
- return;
- }
- if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
- fatal("Bprint failed for %T", t);
+ dumpexporttype(t);
+
+ if(t->etype == TFUNC && n->class == PFUNC) {
+ if (n->inl) {
+ // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+ // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+ if(debug['l'] < 2)
+ typecheckinl(n);
+ Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl);
+ reexportdeplist(n->inl);
+ } else
+ Bprint(bout, "\tfunc %#S%#hT\n", s, t);
+ } else
+ Bprint(bout, "\tvar %#S %#T\n", s, t);
}
static int
@@ -202,12 +226,57 @@ methcmp(const void *va, const void *vb)
}
static void
-dumpsym(Sym *s)
+dumpexporttype(Type *t)
{
- Type *f, *t;
+ Type *f;
Type **m;
int i, n;
+ if(t == T)
+ return;
+ if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
+ return;
+ t->printed = 1;
+
+ if(t->sym != S && t->etype != TFIELD)
+ dumppkg(t->sym->pkg);
+
+ dumpexporttype(t->type);
+ dumpexporttype(t->down);
+
+ if (t->sym == S || t->etype == TFIELD)
+ return;
+
+ n = 0;
+ for(f=t->method; f!=T; f=f->down) {
+ dumpexporttype(f);
+ n++;
+ }
+
+ m = mal(n*sizeof m[0]);
+ i = 0;
+ for(f=t->method; f!=T; f=f->down)
+ m[i++] = f;
+ qsort(m, n, sizeof m[0], methcmp);
+
+ Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
+ for(i=0; i<n; i++) {
+ f = m[i];
+ if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
+ // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+ // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+ if(debug['l'] < 2)
+ typecheckinl(f->type->nname);
+ Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
+ reexportdeplist(f->type->nname->inl);
+ } else
+ Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type);
+ }
+}
+
+static void
+dumpsym(Sym *s)
+{
if(s->flags & SymExported)
return;
s->flags |= SymExported;
@@ -216,56 +285,31 @@ dumpsym(Sym *s)
yyerror("unknown export symbol: %S", s);
return;
}
-
+// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg(s->pkg);
switch(s->def->op) {
default:
yyerror("unexpected export symbol: %O %S", s->def->op, s);
break;
+
case OLITERAL:
dumpexportconst(s);
break;
+
case OTYPE:
- t = s->def->type;
- n = 0;
- for(f=t->method; f!=T; f=f->down) {
- dumpprereq(f);
- n++;
- }
- m = mal(n*sizeof m[0]);
- i = 0;
- for(f=t->method; f!=T; f=f->down)
- m[i++] = f;
- qsort(m, n, sizeof m[0], methcmp);
-
- dumpexporttype(s);
- for(i=0; i<n; i++) {
- f = m[i];
- Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
- f->type->type->type, f->sym, f->type);
- }
+ if(s->def->type->etype == TFORW)
+ yyerror("export of incomplete type %S", s);
+ else
+ dumpexporttype(s->def->type);
break;
+
case ONAME:
dumpexportvar(s);
break;
}
}
-static void
-dumptype(Type *t)
-{
- // no need to re-dump type if already exported
- if(t->printed)
- return;
-
- // no need to dump type if it's not ours (was imported)
- if(t->sym != S && t->sym->def == typenod(t) && !t->local)
- return;
-
- Bprint(bout, "type %#T %l#T\n", t, t);
-}
-
void
dumpexport(void)
{
@@ -275,10 +319,7 @@ dumpexport(void)
lno = lineno;
- packagequotes = 1;
- Bprint(bout, "\n$$ // exports\n");
-
- Bprint(bout, " package %s", localpkg->name);
+ Bprint(bout, "\n$$ // exports\n package %s", localpkg->name);
if(safemode)
Bprint(bout, " safe");
Bprint(bout, "\n");
@@ -293,15 +334,7 @@ dumpexport(void)
dumpsym(l->n->sym);
}
- Bprint(bout, "\n$$ // local types\n");
-
- for(l=typelist; l; l=l->next) {
- lineno = l->n->lineno;
- dumptype(l->n->type);
- }
-
- Bprint(bout, "\n$$\n");
- packagequotes = 0;
+ Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c)
lineno = lno;
}
@@ -344,16 +377,29 @@ pkgtype(Sym *s)
s->def = typenod(t);
}
if(s->def->type == T)
- yyerror("pkgtype %lS", s);
+ yyerror("pkgtype %S", s);
return s->def->type;
}
-static int
-mypackage(Sym *s)
+void
+importimport(Sym *s, Strlit *z)
{
- // we import all definitions for runtime.
- // lowercase ones can only be used by the compiler.
- return s->pkg == localpkg || s->pkg == runtimepkg;
+ // Informational: record package name
+ // associated with import path, for use in
+ // human-readable messages.
+ Pkg *p;
+
+ p = mkpkg(z);
+ if(p->name == nil) {
+ p->name = s->name;
+ pkglookup(s->name, nil)->npkg++;
+ } else if(strcmp(p->name, s->name) != 0)
+ yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
+
+ if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
+ yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
+ errorexit();
+ }
}
void
@@ -361,24 +407,23 @@ importconst(Sym *s, Type *t, Node *n)
{
Node *n1;
- if(!exportname(s->name) && !mypackage(s))
- return;
importsym(s, OLITERAL);
convlit(&n, t);
- if(s->def != N) {
- // TODO: check if already the same.
+
+ if(s->def != N) // TODO: check if already the same.
return;
- }
if(n->op != OLITERAL) {
yyerror("expression must be a constant");
return;
}
+
if(n->sym != S) {
n1 = nod(OXXX, N, N);
*n1 = *n;
n = n1;
}
+ n->orig = newname(s);
n->sym = s;
declare(n, PEXTERN);
@@ -387,23 +432,19 @@ importconst(Sym *s, Type *t, Node *n)
}
void
-importvar(Sym *s, Type *t, int ctxt)
+importvar(Sym *s, Type *t)
{
Node *n;
- if(!exportname(s->name) && !initname(s->name) && !mypackage(s))
- return;
-
importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) {
if(eqtype(t, s->def->type))
return;
- yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
- s, s->def->type, t);
+ yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", s, s->def->type, t);
}
n = newname(s);
n->type = t;
- declare(n, ctxt);
+ declare(n, PEXTERN);
if(debug['E'])
print("import var %S %lT\n", s, t);
@@ -412,17 +453,27 @@ importvar(Sym *s, Type *t, int ctxt)
void
importtype(Type *pt, Type *t)
{
- if(pt != T && t != T)
- typedcl2(pt, t);
+ Node *n;
+
+ // override declaration in unsafe.go for Pointer.
+ // there is no way in Go code to define unsafe.Pointer
+ // so we have to supply it.
+ if(incannedimport &&
+ strcmp(importpkg->name, "unsafe") == 0 &&
+ strcmp(pt->nod->sym->name, "Pointer") == 0) {
+ t = types[TUNSAFEPTR];
+ }
+
+ if(pt->etype == TFORW) {
+ n = pt->nod;
+ copytype(pt->nod, t);
+ pt->nod = n; // unzero nod
+ pt->sym->lastlineno = parserline();
+ declare(n, PEXTERN);
+ checkwidth(pt);
+ } else if(!eqtype(pt->orig, t))
+ yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
if(debug['E'])
print("import type %T %lT\n", pt, t);
}
-
-void
-importmethod(Sym *s, Type *t)
-{
- checkwidth(t);
- addmethod(s, t, 0);
-}
-
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
new file mode 100644
index 000000000..5672c0010
--- /dev/null
+++ b/src/cmd/gc/fmt.c
@@ -0,0 +1,1639 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+#include "opnames.h"
+
+//
+// Format conversions
+// %L int Line numbers
+//
+// %E int etype values (aka 'Kind')
+//
+// %O int Node Opcodes
+// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
+//
+// %J Node* Node details
+// Flags: "%hJ" supresses things not relevant until walk.
+//
+// %V Val* Constant values
+//
+// %S Sym* Symbols
+// Flags: +,- #: mode (see below)
+// "%hS" unqualified identifier in any mode
+// "%hhS" in export mode: unqualified identifier if exported, qualified if not
+//
+// %T Type* Types
+// Flags: +,- #: mode (see below)
+// 'l' definition instead of name.
+// 'h' omit "func" and receiver in function types
+// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
+//
+// %N Node* Nodes
+// Flags: +,- #: mode (see below)
+// 'h' (only in +/debug mode) suppress recursion
+// 'l' (only in Error mode) print "foo (type Bar)"
+//
+// %H NodeList* NodeLists
+// Flags: those of %N
+// ',' separate items with ',' instead of ';'
+//
+// %Z Strlit* String literals
+//
+// In mparith1.c:
+// %B Mpint* Big integers
+// %F Mpflt* Big floats
+//
+// %S, %T and %N obey use the following flags to set the format mode:
+enum {
+ FErr, // error mode (default)
+ FDbg, // "%+N" debug mode
+ FExp, // "%#N" export mode
+ FTypeId, // "%-N" turning-types-into-symbols-mode: identical types give identical strings
+};
+static int fmtmode;
+static int fmtpkgpfx; // %uT stickyness
+//
+// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
+//
+// The mode flags +, - and # are sticky, meaning they persist through
+// recursions of %N, %T and %S, but not the h and l flags. The u flag is
+// sticky only on %T recursions and only used in %-/Sym mode.
+
+//
+// Useful format combinations:
+//
+// %+N %+H multiline recursive debug dump of node/nodelist
+// %+hN %+hH non recursive debug dump
+//
+// %#N %#T export format
+// %#lT type definition instead of name
+// %#hT omit"func" and receiver in function signature
+//
+// %lN "foo (type Bar)" for error messages
+//
+// %-T type identifiers
+// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
+// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
+//
+
+
+static int
+setfmode(unsigned long *flags)
+{
+ int fm;
+
+ fm = fmtmode;
+ if(*flags & FmtSign)
+ fmtmode = FDbg;
+ else if(*flags & FmtSharp)
+ fmtmode = FExp;
+ else if(*flags & FmtLeft)
+ fmtmode = FTypeId;
+
+ *flags &= ~(FmtSharp|FmtLeft|FmtSign);
+ return fm;
+}
+
+// Fmt "%L": Linenumbers
+static int
+Lconv(Fmt *fp)
+{
+ struct
+ {
+ Hist* incl; /* start of this include file */
+ int32 idel; /* delta line number to apply to include */
+ Hist* line; /* start of this #line directive */
+ int32 ldel; /* delta line number to apply to #line */
+ } a[HISTSZ];
+ int32 lno, d;
+ int i, n;
+ Hist *h;
+
+ lno = va_arg(fp->args, int32);
+
+ n = 0;
+ for(h=hist; h!=H; h=h->link) {
+ if(h->offset < 0)
+ continue;
+ if(lno < h->line)
+ break;
+ if(h->name) {
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
+ }
+ continue;
+ }
+ n--;
+ if(n > 0 && n < HISTSZ) {
+ d = h->line - a[n].incl->line;
+ a[n-1].ldel += d;
+ a[n-1].idel += d;
+ }
+ }
+
+ if(n > HISTSZ)
+ n = HISTSZ;
+
+ for(i=n-1; i>=0; i--) {
+ if(i != n-1) {
+ if(fp->flags & ~(FmtWidth|FmtPrec))
+ break;
+ fmtprint(fp, " ");
+ }
+ if(debug['L'] || (fp->flags&FmtLong))
+ fmtprint(fp, "%s/", pathname);
+ if(a[i].line)
+ fmtprint(fp, "%s:%d[%s:%d]",
+ a[i].line->name, lno-a[i].ldel+1,
+ a[i].incl->name, lno-a[i].idel+1);
+ else
+ fmtprint(fp, "%s:%d",
+ a[i].incl->name, lno-a[i].idel+1);
+ lno = a[i].incl->line - 1; // now print out start of this file
+ }
+ if(n == 0)
+ fmtprint(fp, "<epoch>");
+
+ return 0;
+}
+
+static char*
+goopnames[] =
+{
+ [OADDR] = "&",
+ [OADD] = "+",
+ [OADDSTR] = "+",
+ [OANDAND] = "&&",
+ [OANDNOT] = "&^",
+ [OAND] = "&",
+ [OAPPEND] = "append",
+ [OAS] = "=",
+ [OAS2] = "=",
+ [OBREAK] = "break",
+ [OCALL] = "function call", // not actual syntax
+ [OCAP] = "cap",
+ [OCASE] = "case",
+ [OCLOSE] = "close",
+ [OCOMPLEX] = "complex",
+ [OCOM] = "^",
+ [OCONTINUE] = "continue",
+ [OCOPY] = "copy",
+ [ODEC] = "--",
+ [ODELETE] = "delete",
+ [ODEFER] = "defer",
+ [ODIV] = "/",
+ [OEQ] = "==",
+ [OFALL] = "fallthrough",
+ [OFOR] = "for",
+ [OGE] = ">=",
+ [OGOTO] = "goto",
+ [OGT] = ">",
+ [OIF] = "if",
+ [OIMAG] = "imag",
+ [OINC] = "++",
+ [OIND] = "*",
+ [OLEN] = "len",
+ [OLE] = "<=",
+ [OLSH] = "<<",
+ [OLT] = "<",
+ [OMAKE] = "make",
+ [OMINUS] = "-",
+ [OMOD] = "%",
+ [OMUL] = "*",
+ [ONEW] = "new",
+ [ONE] = "!=",
+ [ONOT] = "!",
+ [OOROR] = "||",
+ [OOR] = "|",
+ [OPANIC] = "panic",
+ [OPLUS] = "+",
+ [OPRINTN] = "println",
+ [OPRINT] = "print",
+ [ORANGE] = "range",
+ [OREAL] = "real",
+ [ORECV] = "<-",
+ [ORETURN] = "return",
+ [ORSH] = ">>",
+ [OSELECT] = "select",
+ [OSEND] = "<-",
+ [OSUB] = "-",
+ [OSWITCH] = "switch",
+ [OXOR] = "^",
+};
+
+// Fmt "%O": Node opcodes
+static int
+Oconv(Fmt *fp)
+{
+ int o;
+
+ o = va_arg(fp->args, int);
+ if((fp->flags & FmtSharp) || fmtmode != FDbg)
+ if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
+ return fmtstrcpy(fp, goopnames[o]);
+
+ if(o >= 0 && o < nelem(opnames) && opnames[o] != nil)
+ return fmtstrcpy(fp, opnames[o]);
+
+ return fmtprint(fp, "O-%d", o);
+}
+
+static const char* classnames[] = {
+ "Pxxx",
+ "PEXTERN",
+ "PAUTO",
+ "PPARAM",
+ "PPARAMOUT",
+ "PPARAMREF",
+ "PFUNC",
+};
+
+// Fmt "%J": Node details.
+static int
+Jconv(Fmt *fp)
+{
+ Node *n;
+ char *s;
+ int c;
+
+ n = va_arg(fp->args, Node*);
+
+ c = fp->flags&FmtShort;
+
+ if(!c && n->ullman != 0)
+ fmtprint(fp, " u(%d)", n->ullman);
+
+ if(!c && n->addable != 0)
+ fmtprint(fp, " a(%d)", n->addable);
+
+ if(!c && n->vargen != 0)
+ fmtprint(fp, " g(%d)", n->vargen);
+
+ if(n->lineno != 0)
+ fmtprint(fp, " l(%d)", n->lineno);
+
+ if(!c && n->xoffset != BADWIDTH)
+ fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
+
+ if(n->class != 0) {
+ s = "";
+ if(n->class & PHEAP) s = ",heap";
+ if((n->class & ~PHEAP) < nelem(classnames))
+ fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
+ else
+ fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
+ }
+
+ if(n->colas != 0)
+ fmtprint(fp, " colas(%d)", n->colas);
+
+ if(n->funcdepth != 0)
+ fmtprint(fp, " f(%d)", n->funcdepth);
+
+ switch(n->esc) {
+ case EscUnknown:
+ break;
+ case EscHeap:
+ fmtprint(fp, " esc(h)");
+ break;
+ case EscScope:
+ fmtprint(fp, " esc(s)");
+ break;
+ case EscNone:
+ fmtprint(fp, " esc(no)");
+ break;
+ case EscNever:
+ if(!c)
+ fmtprint(fp, " esc(N)");
+ break;
+ default:
+ fmtprint(fp, " esc(%d)", n->esc);
+ break;
+ }
+
+ if(n->escloopdepth)
+ fmtprint(fp, " ld(%d)", n->escloopdepth);
+
+ if(!c && n->typecheck != 0)
+ fmtprint(fp, " tc(%d)", n->typecheck);
+
+ if(!c && n->dodata != 0)
+ fmtprint(fp, " dd(%d)", n->dodata);
+
+ if(n->isddd != 0)
+ fmtprint(fp, " isddd(%d)", n->isddd);
+
+ if(n->implicit != 0)
+ fmtprint(fp, " implicit(%d)", n->implicit);
+
+ if(n->embedded != 0)
+ fmtprint(fp, " embedded(%d)", n->embedded);
+
+ if(!c && n->used != 0)
+ fmtprint(fp, " used(%d)", n->used);
+ return 0;
+}
+
+// Fmt "%V": Values
+static int
+Vconv(Fmt *fp)
+{
+ Val *v;
+ vlong x;
+
+ v = va_arg(fp->args, Val*);
+
+ switch(v->ctype) {
+ case CTINT:
+ return fmtprint(fp, "%B", v->u.xval);
+ case CTRUNE:
+ x = mpgetfix(v->u.xval);
+ if(' ' <= x && x < 0x80 && x != '\\' && x != '\'')
+ return fmtprint(fp, "'%c'", (int)x);
+ if(0 <= x && x < (1<<16))
+ return fmtprint(fp, "'\\u%04ux'", (int)x);
+ if(0 <= x && x <= Runemax)
+ return fmtprint(fp, "'\\U%08llux'", x);
+ return fmtprint(fp, "('\\x00' + %B)", v->u.xval);
+ case CTFLT:
+ if((fp->flags & FmtSharp) || fmtmode == FExp)
+ return fmtprint(fp, "%F", v->u.fval);
+ return fmtprint(fp, "%#F", v->u.fval);
+ case CTCPLX:
+ if((fp->flags & FmtSharp) || fmtmode == FExp)
+ return fmtprint(fp, "(%F+%F)", &v->u.cval->real, &v->u.cval->imag);
+ return fmtprint(fp, "(%#F + %#Fi)", &v->u.cval->real, &v->u.cval->imag);
+ case CTSTR:
+ return fmtprint(fp, "\"%Z\"", v->u.sval);
+ case CTBOOL:
+ if( v->u.bval)
+ return fmtstrcpy(fp, "true");
+ return fmtstrcpy(fp, "false");
+ case CTNIL:
+ return fmtstrcpy(fp, "nil");
+ }
+ return fmtprint(fp, "<%d>", v->ctype);
+}
+
+// Fmt "%Z": escaped string literals
+static int
+Zconv(Fmt *fp)
+{
+ Rune r;
+ Strlit *sp;
+ char *s, *se;
+ int n;
+
+ sp = va_arg(fp->args, Strlit*);
+ if(sp == nil)
+ return fmtstrcpy(fp, "<nil>");
+
+ s = sp->s;
+ se = s + sp->len;
+ while(s < se) {
+ n = chartorune(&r, s);
+ s += n;
+ switch(r) {
+ case Runeerror:
+ if(n == 1) {
+ fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+ break;
+ }
+ // fall through
+ default:
+ if(r < ' ') {
+ fmtprint(fp, "\\x%02x", r);
+ break;
+ }
+ fmtrune(fp, r);
+ break;
+ case '\t':
+ fmtstrcpy(fp, "\\t");
+ break;
+ case '\n':
+ fmtstrcpy(fp, "\\n");
+ break;
+ case '\"':
+ case '\\':
+ fmtrune(fp, '\\');
+ fmtrune(fp, r);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ ]*T%%g
+s%,.*%%g
+s%.+% [T&] = "&",%g
+s%^ ........*\]%&~%g
+s%~ %%g
+*/
+
+static char*
+etnames[] =
+{
+ [TINT] = "INT",
+ [TUINT] = "UINT",
+ [TINT8] = "INT8",
+ [TUINT8] = "UINT8",
+ [TINT16] = "INT16",
+ [TUINT16] = "UINT16",
+ [TINT32] = "INT32",
+ [TUINT32] = "UINT32",
+ [TINT64] = "INT64",
+ [TUINT64] = "UINT64",
+ [TUINTPTR] = "UINTPTR",
+ [TFLOAT32] = "FLOAT32",
+ [TFLOAT64] = "FLOAT64",
+ [TCOMPLEX64] = "COMPLEX64",
+ [TCOMPLEX128] = "COMPLEX128",
+ [TBOOL] = "BOOL",
+ [TPTR32] = "PTR32",
+ [TPTR64] = "PTR64",
+ [TFUNC] = "FUNC",
+ [TARRAY] = "ARRAY",
+ [TSTRUCT] = "STRUCT",
+ [TCHAN] = "CHAN",
+ [TMAP] = "MAP",
+ [TINTER] = "INTER",
+ [TFORW] = "FORW",
+ [TFIELD] = "FIELD",
+ [TSTRING] = "STRING",
+ [TANY] = "ANY",
+};
+
+// Fmt "%E": etype
+static int
+Econv(Fmt *fp)
+{
+ int et;
+
+ et = va_arg(fp->args, int);
+ if(et >= 0 && et < nelem(etnames) && etnames[et] != nil)
+ return fmtstrcpy(fp, etnames[et]);
+ return fmtprint(fp, "E-%d", et);
+}
+
+// Fmt "%S": syms
+static int
+symfmt(Fmt *fp, Sym *s)
+{
+ char *p;
+
+ if(s->pkg && !(fp->flags&FmtShort)) {
+ switch(fmtmode) {
+ case FErr: // This is for the user
+ if(s->pkg == localpkg)
+ return fmtstrcpy(fp, s->name);
+ // If the name was used by multiple packages, display the full path,
+ if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
+ return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
+ return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
+ case FDbg:
+ return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
+ case FTypeId:
+ if(fp->flags&FmtUnsigned)
+ return fmtprint(fp, "%s.%s", s->pkg->name, s->name); // dcommontype, typehash
+ return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name); // (methodsym), typesym, weaksym
+ case FExp:
+ if(s->pkg != builtinpkg)
+ return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
+ }
+ }
+
+ if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h)
+ // skip leading "type." in method name
+ p = utfrrune(s->name, '.');
+ if(p)
+ p++;
+ else
+ p = s->name;
+
+ // exportname needs to see the name without the prefix too.
+ if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
+ return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
+
+ return fmtstrcpy(fp, p);
+ }
+
+ return fmtstrcpy(fp, s->name);
+}
+
+static char*
+basicnames[] =
+{
+ [TINT] = "int",
+ [TUINT] = "uint",
+ [TINT8] = "int8",
+ [TUINT8] = "uint8",
+ [TINT16] = "int16",
+ [TUINT16] = "uint16",
+ [TINT32] = "int32",
+ [TUINT32] = "uint32",
+ [TINT64] = "int64",
+ [TUINT64] = "uint64",
+ [TUINTPTR] = "uintptr",
+ [TFLOAT32] = "float32",
+ [TFLOAT64] = "float64",
+ [TCOMPLEX64] = "complex64",
+ [TCOMPLEX128] = "complex128",
+ [TBOOL] = "bool",
+ [TANY] = "any",
+ [TSTRING] = "string",
+ [TNIL] = "nil",
+ [TIDEAL] = "ideal",
+ [TBLANK] = "blank",
+};
+
+static int
+typefmt(Fmt *fp, Type *t)
+{
+ Type *t1;
+ Sym *s;
+
+ if(t == T)
+ return fmtstrcpy(fp, "<T>");
+
+ if (t == bytetype || t == runetype) {
+ // in %-T mode collapse rune and byte with their originals.
+ if(fmtmode != FTypeId)
+ return fmtprint(fp, "%hS", t->sym);
+ t = types[t->etype];
+ }
+
+ if(t == errortype)
+ return fmtstrcpy(fp, "error");
+
+ // Unless the 'l' flag was specified, if the type has a name, just print that name.
+ if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) {
+ switch(fmtmode) {
+ case FTypeId:
+ if(fp->flags&FmtShort)
+ return fmtprint(fp, "%hS", t->sym);
+ if(fp->flags&FmtUnsigned)
+ return fmtprint(fp, "%uS", t->sym);
+ // fallthrough
+ case FExp:
+ if(t->sym->pkg == localpkg && t->vargen)
+ return fmtprint(fp, "%S·%d", t->sym, t->vargen);
+ break;
+ }
+ return fmtprint(fp, "%S", t->sym);
+ }
+
+ if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
+ if(fmtmode == FErr && (t == idealbool || t == idealstring))
+ fmtstrcpy(fp, "ideal ");
+ return fmtstrcpy(fp, basicnames[t->etype]);
+ }
+
+ if(fmtmode == FDbg)
+ fmtprint(fp, "%E-", t->etype);
+
+ switch(t->etype) {
+ case TPTR32:
+ case TPTR64:
+ if(fmtmode == FTypeId && (fp->flags&FmtShort))
+ return fmtprint(fp, "*%hT", t->type);
+ return fmtprint(fp, "*%T", t->type);
+
+ case TARRAY:
+ if(t->bound >= 0)
+ return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
+ if(t->bound == -100)
+ return fmtprint(fp, "[...]%T", t->type);
+ return fmtprint(fp, "[]%T", t->type);
+
+ case TCHAN:
+ switch(t->chan) {
+ case Crecv:
+ return fmtprint(fp, "<-chan %T", t->type);
+ case Csend:
+ return fmtprint(fp, "chan<- %T", t->type);
+ }
+
+ if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
+ return fmtprint(fp, "chan (%T)", t->type);
+ return fmtprint(fp, "chan %T", t->type);
+
+ case TMAP:
+ return fmtprint(fp, "map[%T]%T", t->down, t->type);
+
+ case TINTER:
+ fmtstrcpy(fp, "interface {");
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(exportname(t1->sym->name)) {
+ if(t1->down)
+ fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
+ else
+ fmtprint(fp, " %hS%hT ", t1->sym, t1->type);
+ } else {
+ // non-exported method names must be qualified
+ if(t1->down)
+ fmtprint(fp, " %uS%hT;", t1->sym, t1->type);
+ else
+ fmtprint(fp, " %uS%hT ", t1->sym, t1->type);
+ }
+ fmtstrcpy(fp, "}");
+ return 0;
+
+ case TFUNC:
+ if(fp->flags & FmtShort) {
+ fmtprint(fp, "%T", getinargx(t));
+ } else {
+ if(t->thistuple)
+ fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t));
+ else
+ fmtprint(fp, "func%T", getinargx(t));
+ }
+ switch(t->outtuple) {
+ case 0:
+ break;
+ case 1:
+ if(fmtmode != FExp) {
+ fmtprint(fp, " %T", getoutargx(t)->type->type); // struct->field->field's type
+ break;
+ }
+ default:
+ fmtprint(fp, " %T", getoutargx(t));
+ break;
+ }
+ return 0;
+
+ case TSTRUCT:
+ if(t->funarg) {
+ fmtstrcpy(fp, "(");
+ if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape" tags
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(t1->down)
+ fmtprint(fp, "%hT, ", t1);
+ else
+ fmtprint(fp, "%hT", t1);
+ } else {
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(t1->down)
+ fmtprint(fp, "%T, ", t1);
+ else
+ fmtprint(fp, "%T", t1);
+ }
+ fmtstrcpy(fp, ")");
+ } else {
+ fmtstrcpy(fp, "struct {");
+ for(t1=t->type; t1!=T; t1=t1->down)
+ if(t1->down)
+ fmtprint(fp, " %lT;", t1);
+ else
+ fmtprint(fp, " %lT ", t1);
+ fmtstrcpy(fp, "}");
+ }
+ return 0;
+
+ case TFIELD:
+ if(!(fp->flags&FmtShort)) {
+ s = t->sym;
+ // Take the name from the original, lest we substituted it with .anon%d
+ if (t->nname && (fmtmode == FErr || fmtmode == FExp))
+ s = t->nname->orig->sym;
+
+ if(s != S && !t->embedded) {
+ if(fp->flags&FmtLong)
+ fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg)
+ else
+ fmtprint(fp, "%S ", s);
+ } else if(fmtmode == FExp) {
+ // TODO(rsc) this breaks on the eliding of unused arguments in the backend
+ // when this is fixed, the special case in dcl.c checkarglist can go.
+ //if(t->funarg)
+ // fmtstrcpy(fp, "_ ");
+ //else
+ fmtstrcpy(fp, "? ");
+ }
+ }
+
+ if(t->isddd)
+ fmtprint(fp, "...%T", t->type->type);
+ else
+ fmtprint(fp, "%T", t->type);
+
+ if(!(fp->flags&FmtShort) && t->note)
+ fmtprint(fp, " \"%Z\"", t->note);
+ return 0;
+
+ case TFORW:
+ if(t->sym)
+ return fmtprint(fp, "undefined %S", t->sym);
+ return fmtstrcpy(fp, "undefined");
+
+ case TUNSAFEPTR:
+ if(fmtmode == FExp)
+ return fmtprint(fp, "@\"unsafe\".Pointer");
+ return fmtprint(fp, "unsafe.Pointer");
+ }
+
+ if(fmtmode == FExp)
+ fatal("missing %E case during export", t->etype);
+ // Don't know how to handle - fall back to detailed prints.
+ return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type);
+}
+
+// Statements which may be rendered with a simplestmt as init.
+static int
+stmtwithinit(int op)
+{
+ switch(op) {
+ case OIF:
+ case OFOR:
+ case OSWITCH:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+stmtfmt(Fmt *f, Node *n)
+{
+ int complexinit, simpleinit, extrablock;
+
+ // some statements allow for an init, but at most one,
+ // but we may have an arbitrary number added, eg by typecheck
+ // and inlining. If it doesn't fit the syntax, emit an enclosing
+ // block starting with the init statements.
+
+ // if we can just say "for" n->ninit; ... then do so
+ simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op);
+ // otherwise, print the inits as separate statements
+ complexinit = n->ninit && !simpleinit && (fmtmode != FErr);
+ // but if it was for if/for/switch, put in an extra surrounding block to limit the scope
+ extrablock = complexinit && stmtwithinit(n->op);
+
+ if(extrablock)
+ fmtstrcpy(f, "{");
+
+ if(complexinit)
+ fmtprint(f, " %H; ", n->ninit);
+
+ switch(n->op){
+ case ODCL:
+ fmtprint(f, "var %S %T", n->left->sym, n->left->type);
+ break;
+
+ case ODCLFIELD:
+ if(n->left)
+ fmtprint(f, "%N %N", n->left, n->right);
+ else
+ fmtprint(f, "%N", n->right);
+ break;
+
+ case OAS:
+ if(n->colas && !complexinit)
+ fmtprint(f, "%N := %N", n->left, n->right);
+ else
+ fmtprint(f, "%N = %N", n->left, n->right);
+ break;
+
+ case OASOP:
+ fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
+ break;
+
+ case OAS2:
+ if(n->colas && !complexinit) {
+ fmtprint(f, "%,H := %,H", n->list, n->rlist);
+ break;
+ }
+ // fallthrough
+ case OAS2DOTTYPE:
+ case OAS2FUNC:
+ case OAS2MAPR:
+ case OAS2RECV:
+ fmtprint(f, "%,H = %,H", n->list, n->rlist);
+ break;
+
+ case ORETURN:
+ fmtprint(f, "return %,H", n->list);
+ break;
+
+ case OPROC:
+ fmtprint(f, "go %N", n->left);
+ break;
+
+ case ODEFER:
+ fmtprint(f, "defer %N", n->left);
+ break;
+
+ case OIF:
+ if(simpleinit)
+ fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody);
+ else
+ fmtprint(f, "if %N { %H }", n->ntest, n->nbody);
+ if(n->nelse)
+ fmtprint(f, " else { %H }", n->nelse);
+ break;
+
+ case OFOR:
+ if(fmtmode == FErr) { // TODO maybe only if FmtShort, same below
+ fmtstrcpy(f, "for loop");
+ break;
+ }
+
+ fmtstrcpy(f, "for");
+ if(simpleinit)
+ fmtprint(f, " %N;", n->ninit->n);
+ else if(n->nincr)
+ fmtstrcpy(f, " ;");
+
+ if(n->ntest)
+ fmtprint(f, " %N", n->ntest);
+
+ if(n->nincr)
+ fmtprint(f, "; %N", n->nincr);
+ else if(simpleinit)
+ fmtstrcpy(f, ";");
+
+
+ fmtprint(f, " { %H }", n->nbody);
+ break;
+
+ case ORANGE:
+ if(fmtmode == FErr) {
+ fmtstrcpy(f, "for loop");
+ break;
+ }
+
+ fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
+ break;
+
+ case OSELECT:
+ case OSWITCH:
+ if(fmtmode == FErr) {
+ fmtprint(f, "%O statement", n->op);
+ break;
+ }
+
+ fmtprint(f, "%#O", n->op);
+ if(simpleinit)
+ fmtprint(f, " %N;", n->ninit->n);
+ if(n->ntest)
+ fmtprint(f, "%N", n->ntest);
+
+ fmtprint(f, " { %H }", n->list);
+ break;
+
+ case OCASE:
+ case OXCASE:
+ if(n->list)
+ fmtprint(f, "case %,H: %H", n->list, n->nbody);
+ else
+ fmtprint(f, "default: %H", n->nbody);
+ break;
+
+ case OBREAK:
+ case OCONTINUE:
+ case OGOTO:
+ case OFALL:
+ case OXFALL:
+ if(n->left)
+ fmtprint(f, "%#O %N", n->op, n->left);
+ else
+ fmtprint(f, "%#O", n->op);
+ break;
+
+ case OEMPTY:
+ break;
+
+ case OLABEL:
+ fmtprint(f, "%N: ", n->left);
+ break;
+
+ }
+
+ if(extrablock)
+ fmtstrcpy(f, "}");
+
+ return 0;
+}
+
+
+static int opprec[] = {
+ [OAPPEND] = 8,
+ [OARRAYBYTESTR] = 8,
+ [OARRAYLIT] = 8,
+ [OARRAYRUNESTR] = 8,
+ [OCALLFUNC] = 8,
+ [OCALLINTER] = 8,
+ [OCALLMETH] = 8,
+ [OCALL] = 8,
+ [OCAP] = 8,
+ [OCLOSE] = 8,
+ [OCONVIFACE] = 8,
+ [OCONVNOP] = 8,
+ [OCONV] = 8,
+ [OCOPY] = 8,
+ [ODELETE] = 8,
+ [OLEN] = 8,
+ [OLITERAL] = 8,
+ [OMAKESLICE] = 8,
+ [OMAKE] = 8,
+ [OMAPLIT] = 8,
+ [ONAME] = 8,
+ [ONEW] = 8,
+ [ONONAME] = 8,
+ [OPACK] = 8,
+ [OPANIC] = 8,
+ [OPAREN] = 8,
+ [OPRINTN] = 8,
+ [OPRINT] = 8,
+ [ORECV] = 8,
+ [ORUNESTR] = 8,
+ [OSTRARRAYBYTE] = 8,
+ [OSTRARRAYRUNE] = 8,
+ [OSTRUCTLIT] = 8,
+ [OTARRAY] = 8,
+ [OTCHAN] = 8,
+ [OTFUNC] = 8,
+ [OTINTER] = 8,
+ [OTMAP] = 8,
+ [OTPAREN] = 8,
+ [OTSTRUCT] = 8,
+
+ [OINDEXMAP] = 8,
+ [OINDEX] = 8,
+ [OSLICE] = 8,
+ [OSLICESTR] = 8,
+ [OSLICEARR] = 8,
+ [ODOTINTER] = 8,
+ [ODOTMETH] = 8,
+ [ODOTPTR] = 8,
+ [ODOTTYPE2] = 8,
+ [ODOTTYPE] = 8,
+ [ODOT] = 8,
+ [OXDOT] = 8,
+
+ [OPLUS] = 7,
+ [ONOT] = 7,
+ [OCOM] = 7,
+ [OMINUS] = 7,
+ [OADDR] = 7,
+ [OIND] = 7,
+
+ [OMUL] = 6,
+ [ODIV] = 6,
+ [OMOD] = 6,
+ [OLSH] = 6,
+ [ORSH] = 6,
+ [OAND] = 6,
+ [OANDNOT] = 6,
+
+ [OADD] = 5,
+ [OSUB] = 5,
+ [OOR] = 5,
+ [OXOR] = 5,
+
+ [OEQ] = 4,
+ [OLT] = 4,
+ [OLE] = 4,
+ [OGE] = 4,
+ [OGT] = 4,
+ [ONE] = 4,
+ [OCMPSTR] = 4,
+ [OCMPIFACE] = 4,
+
+ [OSEND] = 3,
+ [OANDAND] = 2,
+ [OOROR] = 1,
+
+ // Statements handled by stmtfmt
+ [OAS] = -1,
+ [OAS2] = -1,
+ [OAS2DOTTYPE] = -1,
+ [OAS2FUNC] = -1,
+ [OAS2MAPR] = -1,
+ [OAS2RECV] = -1,
+ [OASOP] = -1,
+ [OBREAK] = -1,
+ [OCASE] = -1,
+ [OCONTINUE] = -1,
+ [ODCL] = -1,
+ [ODCLFIELD] = -1,
+ [ODEFER] = -1,
+ [OEMPTY] = -1,
+ [OFALL] = -1,
+ [OFOR] = -1,
+ [OIF] = -1,
+ [OLABEL] = -1,
+ [OPROC] = -1,
+ [ORANGE] = -1,
+ [ORETURN] = -1,
+ [OSELECT] = -1,
+ [OSWITCH] = -1,
+ [OXCASE] = -1,
+ [OXFALL] = -1,
+
+ [OEND] = 0
+};
+
+static int
+exprfmt(Fmt *f, Node *n, int prec)
+{
+ int nprec;
+ NodeList *l;
+ Type *t;
+
+ while(n && n->implicit && (n->op == OIND || n->op == OADDR))
+ n = n->left;
+
+ if(n == N)
+ return fmtstrcpy(f, "<N>");
+
+ nprec = opprec[n->op];
+ if(n->op == OTYPE && n->sym != S)
+ nprec = 8;
+
+ if(prec > nprec)
+ return fmtprint(f, "(%N)", n);
+
+ switch(n->op) {
+ case OPAREN:
+ return fmtprint(f, "(%N)", n->left);
+
+ case ODDDARG:
+ return fmtprint(f, "... argument");
+
+ case OREGISTER:
+ return fmtprint(f, "%R", n->val.u.reg);
+
+ case OLITERAL: // this is a bit of a mess
+ if(fmtmode == FErr && n->sym != S)
+ return fmtprint(f, "%S", n->sym);
+ if(n->val.ctype == CTNIL)
+ n = n->orig; // if this node was a nil decorated with at type, print the original naked nil
+ if(n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) {
+ // Need parens when type begins with what might
+ // be misinterpreted as a unary operator: * or <-.
+ if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv))
+ return fmtprint(f, "(%T)(%V)", n->type, &n->val);
+ else
+ return fmtprint(f, "%T(%V)", n->type, &n->val);
+ }
+ return fmtprint(f, "%V", &n->val);
+
+ case ONAME:
+ // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
+ // but for export, this should be rendered as (*pkg.T).meth.
+ // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
+ if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) {
+ if(isptr[n->left->type->etype])
+ return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym);
+ else
+ return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym);
+ }
+ //fallthrough
+ case OPACK:
+ case ONONAME:
+ return fmtprint(f, "%S", n->sym);
+
+ case OTYPE:
+ if(n->type == T && n->sym != S)
+ return fmtprint(f, "%S", n->sym);
+ return fmtprint(f, "%T", n->type);
+
+ case OTARRAY:
+ if(n->left)
+ return fmtprint(f, "[]%N", n->left);
+ return fmtprint(f, "[]%N", n->right); // happens before typecheck
+
+ case OTPAREN:
+ return fmtprint(f, "(%N)", n->left);
+
+ case OTMAP:
+ return fmtprint(f, "map[%N]%N", n->left, n->right);
+
+ case OTCHAN:
+ switch(n->etype) {
+ case Crecv:
+ return fmtprint(f, "<-chan %N", n->left);
+ case Csend:
+ return fmtprint(f, "chan<- %N", n->left);
+ default:
+ if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv)
+ return fmtprint(f, "chan (%N)", n->left);
+ else
+ return fmtprint(f, "chan %N", n->left);
+ }
+
+ case OTSTRUCT:
+ return fmtprint(f, "<struct>");
+
+ case OTINTER:
+ return fmtprint(f, "<inter>");
+
+ case OTFUNC:
+ return fmtprint(f, "<func>");
+
+ case OCLOSURE:
+ if(fmtmode == FErr)
+ return fmtstrcpy(f, "func literal");
+ return fmtprint(f, "%T { %H }", n->type, n->nbody);
+
+ case OCOMPLIT:
+ if(fmtmode == FErr)
+ return fmtstrcpy(f, "composite literal");
+ return fmtprint(f, "%N{ %,H }", n->right, n->list);
+
+ case OPTRLIT:
+ if(fmtmode == FExp && n->left->implicit)
+ return fmtprint(f, "%N", n->left);
+ return fmtprint(f, "&%N", n->left);
+
+ case OSTRUCTLIT:
+ if(fmtmode == FExp) { // requires special handling of field names
+ if(n->implicit)
+ fmtstrcpy(f, "{");
+ else
+ fmtprint(f, "%T{", n->type);
+ for(l=n->list; l; l=l->next) {
+ // another special case: if n->left is an embedded field of builtin type,
+ // it needs to be non-qualified. Can't figure that out in %S, so do it here
+ if(l->n->left->type->embedded) {
+ t = l->n->left->type->type;
+ if(t->sym == S)
+ t = t->type;
+ fmtprint(f, " %T:%N", t, l->n->right);
+ } else
+ fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right);
+
+ if(l->next)
+ fmtstrcpy(f, ",");
+ else
+ fmtstrcpy(f, " ");
+ }
+ return fmtstrcpy(f, "}");
+ }
+ // fallthrough
+
+ case OARRAYLIT:
+ case OMAPLIT:
+ if(fmtmode == FErr)
+ return fmtprint(f, "%T literal", n->type);
+ if(fmtmode == FExp && n->implicit)
+ return fmtprint(f, "{ %,H }", n->list);
+ return fmtprint(f, "%T{ %,H }", n->type, n->list);
+
+ case OKEY:
+ if(n->left && n->right)
+ return fmtprint(f, "%N:%N", n->left, n->right);
+ if(!n->left && n->right)
+ return fmtprint(f, ":%N", n->right);
+ if(n->left && !n->right)
+ return fmtprint(f, "%N:", n->left);
+ return fmtstrcpy(f, ":");
+
+ case OXDOT:
+ case ODOT:
+ case ODOTPTR:
+ case ODOTINTER:
+ case ODOTMETH:
+ exprfmt(f, n->left, nprec);
+ if(n->right == N || n->right->sym == S)
+ fmtstrcpy(f, ".<nil>");
+ return fmtprint(f, ".%hhS", n->right->sym);
+
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ exprfmt(f, n->left, nprec);
+ if(n->right != N)
+ return fmtprint(f, ".(%N)", n->right);
+ return fmtprint(f, ".(%T)", n->type);
+
+ case OINDEX:
+ case OINDEXMAP:
+ case OSLICE:
+ case OSLICESTR:
+ case OSLICEARR:
+ exprfmt(f, n->left, nprec);
+ return fmtprint(f, "[%N]", n->right);
+
+ case OCOPY:
+ case OCOMPLEX:
+ return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right);
+
+ case OCONV:
+ case OCONVIFACE:
+ case OCONVNOP:
+ case OARRAYBYTESTR:
+ case OARRAYRUNESTR:
+ case OSTRARRAYBYTE:
+ case OSTRARRAYRUNE:
+ case ORUNESTR:
+ if(n->type == T || n->type->sym == S)
+ return fmtprint(f, "(%T)(%N)", n->type, n->left);
+ if(n->left)
+ return fmtprint(f, "%T(%N)", n->type, n->left);
+ return fmtprint(f, "%T(%,H)", n->type, n->list);
+
+ case OREAL:
+ case OIMAG:
+ case OAPPEND:
+ case OCAP:
+ case OCLOSE:
+ case ODELETE:
+ case OLEN:
+ case OMAKE:
+ case ONEW:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ if(n->left)
+ return fmtprint(f, "%#O(%N)", n->op, n->left);
+ if(n->isddd)
+ return fmtprint(f, "%#O(%,H...)", n->op, n->list);
+ return fmtprint(f, "%#O(%,H)", n->op, n->list);
+
+ case OCALL:
+ case OCALLFUNC:
+ case OCALLINTER:
+ case OCALLMETH:
+ exprfmt(f, n->left, nprec);
+ if(n->isddd)
+ return fmtprint(f, "(%,H...)", n->list);
+ return fmtprint(f, "(%,H)", n->list);
+
+ case OMAKEMAP:
+ case OMAKECHAN:
+ case OMAKESLICE:
+ if(n->list) // pre-typecheck
+ return fmtprint(f, "make(%T, %,H)", n->type, n->list);
+ if(n->right)
+ return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
+ if(n->left)
+ return fmtprint(f, "make(%T, %N)", n->type, n->left);
+ return fmtprint(f, "make(%T)", n->type);
+
+ // Unary
+ case OPLUS:
+ case OMINUS:
+ case OADDR:
+ case OCOM:
+ case OIND:
+ case ONOT:
+ case ORECV:
+ if(n->left->op == n->op)
+ fmtprint(f, "%#O ", n->op);
+ else
+ fmtprint(f, "%#O", n->op);
+ return exprfmt(f, n->left, nprec+1);
+
+ // Binary
+ case OADD:
+ case OADDSTR:
+ case OAND:
+ case OANDAND:
+ case OANDNOT:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLT:
+ case OLSH:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case OOR:
+ case OOROR:
+ case ORSH:
+ case OSEND:
+ case OSUB:
+ case OXOR:
+ exprfmt(f, n->left, nprec);
+ fmtprint(f, " %#O ", n->op);
+ exprfmt(f, n->right, nprec+1);
+ return 0;
+
+ case OCMPSTR:
+ case OCMPIFACE:
+ exprfmt(f, n->left, nprec);
+ fmtprint(f, " %#O ", n->etype);
+ exprfmt(f, n->right, nprec+1);
+ return 0;
+ }
+
+ return fmtprint(f, "<node %O>", n->op);
+}
+
+static int
+nodefmt(Fmt *f, Node *n)
+{
+ Type *t;
+
+ t = n->type;
+
+ // we almost always want the original, except in export mode for literals
+ // this saves the importer some work, and avoids us having to redo some
+ // special casing for package unsafe
+ if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N)
+ n = n->orig;
+
+ if(f->flags&FmtLong && t != T) {
+ if(t->etype == TNIL)
+ return fmtprint(f, "nil");
+ else
+ return fmtprint(f, "%N (type %T)", n, t);
+ }
+
+ // TODO inlining produces expressions with ninits. we can't print these yet.
+
+ if(opprec[n->op] < 0)
+ return stmtfmt(f, n);
+
+ return exprfmt(f, n, 0);
+}
+
+static int dumpdepth;
+
+static void
+indent(Fmt *fp)
+{
+ int i;
+
+ fmtstrcpy(fp, "\n");
+ for(i = 0; i < dumpdepth; ++i)
+ fmtstrcpy(fp, ". ");
+}
+
+static int
+nodedump(Fmt *fp, Node *n)
+{
+ int recur;
+
+ if(n == N)
+ return 0;
+
+ recur = !(fp->flags&FmtShort);
+
+ if(recur) {
+ indent(fp);
+ if(dumpdepth > 10)
+ return fmtstrcpy(fp, "...");
+
+ if(n->ninit != nil) {
+ fmtprint(fp, "%O-init%H", n->op, n->ninit);
+ indent(fp);
+ }
+ }
+
+// fmtprint(fp, "[%p]", n);
+
+ switch(n->op) {
+ default:
+ fmtprint(fp, "%O%J", n->op, n);
+ break;
+ case OREGISTER:
+ fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
+ break;
+ case OLITERAL:
+ fmtprint(fp, "%O-%V%J", n->op, &n->val, n);
+ break;
+ case ONAME:
+ case ONONAME:
+ if(n->sym != S)
+ fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
+ else
+ fmtprint(fp, "%O%J", n->op, n);
+ break;
+ case OASOP:
+ fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
+ break;
+ case OTYPE:
+ fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type);
+ if(recur && n->type == T && n->ntype) {
+ indent(fp);
+ fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
+ }
+ break;
+ }
+
+ if(n->sym != S && n->op != ONAME)
+ fmtprint(fp, " %S G%d", n->sym, n->vargen);
+
+ if(n->type != T)
+ fmtprint(fp, " %T", n->type);
+
+ if(recur) {
+ if(n->left)
+ fmtprint(fp, "%N", n->left);
+ if(n->right)
+ fmtprint(fp, "%N", n->right);
+ if(n->list) {
+ indent(fp);
+ fmtprint(fp, "%O-list%H", n->op, n->list);
+ }
+ if(n->rlist) {
+ indent(fp);
+ fmtprint(fp, "%O-rlist%H", n->op, n->rlist);
+ }
+ if(n->ntest) {
+ indent(fp);
+ fmtprint(fp, "%O-test%N", n->op, n->ntest);
+ }
+ if(n->nbody) {
+ indent(fp);
+ fmtprint(fp, "%O-body%H", n->op, n->nbody);
+ }
+ if(n->nelse) {
+ indent(fp);
+ fmtprint(fp, "%O-else%H", n->op, n->nelse);
+ }
+ if(n->nincr) {
+ indent(fp);
+ fmtprint(fp, "%O-incr%N", n->op, n->nincr);
+ }
+ }
+
+ return 0;
+}
+
+// Fmt "%S": syms
+// Flags: "%hS" suppresses qualifying with package
+static int
+Sconv(Fmt *fp)
+{
+ Sym *s;
+ int r, sm;
+ unsigned long sf;
+
+ s = va_arg(fp->args, Sym*);
+ if(s == S)
+ return fmtstrcpy(fp, "<S>");
+
+ if(s->name && s->name[0] == '_' && s->name[1] == '\0')
+ return fmtstrcpy(fp, "_");
+
+ sf = fp->flags;
+ sm = setfmode(&fp->flags);
+ r = symfmt(fp, s);
+ fp->flags = sf;
+ fmtmode = sm;
+ return r;
+}
+
+// Fmt "%T": types.
+// Flags: 'l' print definition, not name
+// 'h' omit 'func' and receiver from function types, short type names
+// 'u' package name, not prefix (FTypeId mode, sticky)
+static int
+Tconv(Fmt *fp)
+{
+ Type *t;
+ int r, sm;
+ unsigned long sf;
+
+ t = va_arg(fp->args, Type*);
+ if(t == T)
+ return fmtstrcpy(fp, "<T>");
+
+ if(t->trecur > 4)
+ return fmtstrcpy(fp, "<...>");
+
+ t->trecur++;
+ sf = fp->flags;
+ sm = setfmode(&fp->flags);
+
+ if(fmtmode == FTypeId && (sf&FmtUnsigned))
+ fmtpkgpfx++;
+ if(fmtpkgpfx)
+ fp->flags |= FmtUnsigned;
+
+ r = typefmt(fp, t);
+
+ if(fmtmode == FTypeId && (sf&FmtUnsigned))
+ fmtpkgpfx--;
+
+ fp->flags = sf;
+ fmtmode = sm;
+ t->trecur--;
+ return r;
+}
+
+// Fmt '%N': Nodes.
+// Flags: 'l' suffix with "(type %T)" where possible
+// '+h' in debug mode, don't recurse, no multiline output
+static int
+Nconv(Fmt *fp)
+{
+ Node *n;
+ int r, sm;
+ unsigned long sf;
+
+ n = va_arg(fp->args, Node*);
+ if(n == N)
+ return fmtstrcpy(fp, "<N>");
+ sf = fp->flags;
+ sm = setfmode(&fp->flags);
+
+ r = -1;
+ switch(fmtmode) {
+ case FErr:
+ case FExp:
+ r = nodefmt(fp, n);
+ break;
+ case FDbg:
+ dumpdepth++;
+ r = nodedump(fp, n);
+ dumpdepth--;
+ break;
+ default:
+ fatal("unhandled %%N mode");
+ }
+
+ fp->flags = sf;
+ fmtmode = sm;
+ return r;
+}
+
+// Fmt '%H': NodeList.
+// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
+static int
+Hconv(Fmt *fp)
+{
+ NodeList *l;
+ int r, sm;
+ unsigned long sf;
+ char *sep;
+
+ l = va_arg(fp->args, NodeList*);
+
+ if(l == nil && fmtmode == FDbg)
+ return fmtstrcpy(fp, "<nil>");
+
+ sf = fp->flags;
+ sm = setfmode(&fp->flags);
+ r = 0;
+ sep = "; ";
+ if(fmtmode == FDbg)
+ sep = "\n";
+ else if(fp->flags & FmtComma)
+ sep = ", ";
+
+ for(;l; l=l->next) {
+ r += fmtprint(fp, "%N", l->n);
+ if(l->next)
+ r += fmtstrcpy(fp, sep);
+ }
+
+ fp->flags = sf;
+ fmtmode = sm;
+ return r;
+}
+
+void
+fmtinstallgo(void)
+{
+ fmtmode = FErr;
+ fmtinstall('E', Econv); // etype opcodes
+ fmtinstall('J', Jconv); // all the node flags
+ fmtinstall('H', Hconv); // node lists
+ fmtinstall('L', Lconv); // line number
+ fmtinstall('N', Nconv); // node pointer
+ fmtinstall('O', Oconv); // node opcodes
+ fmtinstall('S', Sconv); // sym pointer
+ fmtinstall('T', Tconv); // type pointer
+ fmtinstall('V', Vconv); // val pointer
+ fmtinstall('Z', Zconv); // escaped string
+
+ // These are in mparith1.c
+ fmtinstall('B', Bconv); // big numbers
+ fmtinstall('F', Fconv); // big float numbers
+
+}
+
+void
+dumplist(char *s, NodeList *l)
+{
+ print("%s\n%+H\n", s, l);
+}
+
+void
+dump(char *s, Node *n)
+{
+ print("%s [%p]\n%+N\n", s, n, n);
+}
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index cb66921ba..694a10ab5 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -7,11 +7,13 @@
* mainly statements and control flow.
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
static void cgen_dcl(Node *n);
static void cgen_proc(Node *n, int proc);
-static void checkgoto(Node*, Node*);
+static void checkgoto(Node*, Node*);
static Label *labellist;
static Label *lastlabel;
@@ -26,50 +28,93 @@ sysfunc(char *name)
return n;
}
+/*
+ * the address of n has been taken and might be used after
+ * the current function returns. mark any local vars
+ * as needing to move to the heap.
+ */
void
-allocparams(void)
+addrescapes(Node *n)
{
- NodeList *l;
- Node *n;
- uint32 w;
- Sym *s;
- int lno;
+ char buf[100];
+ Node *oldfn;
+
+ switch(n->op) {
+ default:
+ // probably a type error already.
+ // dump("addrescapes", n);
+ break;
+
+ case ONAME:
+ if(n == nodfp)
+ break;
+
+ // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+ // on PPARAM it means something different.
+ if(n->class == PAUTO && n->esc == EscNever)
+ break;
+
+ if(debug['N'] && n->esc != EscUnknown)
+ fatal("without escape analysis, only PAUTO's should have esc: %N", n);
- if(stksize < 0)
- fatal("allocparams not during code generation");
-
- /*
- * allocate (set xoffset) the stack
- * slots for all automatics.
- * allocated starting at -w down.
- */
- lno = lineno;
- for(l=curfn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op == ONAME && n->class == PHEAP-1) {
- // heap address variable; finish the job
- // started in addrescapes.
- s = n->sym;
- tempname(n, n->type);
- n->sym = s;
+ switch(n->class) {
+ case PPARAMREF:
+ addrescapes(n->defn);
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ // if func param, need separate temporary
+ // to hold heap pointer.
+ // the function type has already been checked
+ // (we're in the function body)
+ // so the param already has a valid xoffset.
+
+ // expression to refer to stack copy
+ n->stackparam = nod(OPARAM, n, N);
+ n->stackparam->type = n->type;
+ n->stackparam->addable = 1;
+ if(n->xoffset == BADWIDTH)
+ fatal("addrescapes before param assignment");
+ n->stackparam->xoffset = n->xoffset;
+ // fallthrough
+
+ case PAUTO:
+ n->class |= PHEAP;
+ n->addable = 0;
+ n->ullman = 2;
+ n->xoffset = 0;
+
+ // create stack variable to hold pointer to heap
+ oldfn = curfn;
+ curfn = n->curfn;
+ n->heapaddr = temp(ptrto(n->type));
+ snprint(buf, sizeof buf, "&%S", n->sym);
+ n->heapaddr->sym = lookup(buf);
+ n->heapaddr->orig->sym = n->heapaddr->sym;
+ if(!debug['N'])
+ n->esc = EscHeap;
+ if(debug['m'])
+ print("%L: moved to heap: %N\n", n->lineno, n);
+ curfn = oldfn;
+ break;
}
- if(n->op != ONAME || n->class != PAUTO)
- continue;
- if (n->xoffset != BADWIDTH)
- continue;
- if(n->type == T)
- continue;
- dowidth(n->type);
- w = n->type->width;
- if(w >= MAXWIDTH)
- fatal("bad width");
- stksize += w;
- stksize = rnd(stksize, n->type->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
+ break;
+
+ case OIND:
+ case ODOTPTR:
+ break;
+
+ case ODOT:
+ case OINDEX:
+ // ODOTPTR has already been introduced,
+ // so these are the non-pointer ODOT and OINDEX.
+ // In &x[0], if x is a slice, then x does not
+ // escape--the pointer inside x does, but that
+ // is always a heap pointer anyway.
+ if(!isslice(n->left->type))
+ addrescapes(n->left);
+ break;
}
- lineno = lno;
}
void
@@ -197,7 +242,7 @@ stmtlabel(Node *n)
if(n->sym != S)
if((lab = n->sym->label) != L)
if(lab->def != N)
- if(lab->def->right == n)
+ if(lab->def->defn == n)
return lab;
return L;
}
@@ -227,7 +272,6 @@ gen(Node *n)
if(n == N)
goto ret;
- p3 = pc; // save pc for loop labels
if(n->ninit)
genlist(n->ninit);
@@ -266,13 +310,13 @@ gen(Node *n)
if(lab->labelpc == P)
lab->labelpc = pc;
- if(n->right) {
- switch(n->right->op) {
+ if(n->defn) {
+ switch(n->defn->op) {
case OFOR:
case OSWITCH:
case OSELECT:
// so stmtlabel can find the label
- n->right->sym = lab->sym;
+ n->defn->sym = lab->sym;
}
}
break;
@@ -486,7 +530,7 @@ cgen_callmeth(Node *n, int proc)
/*
* generate code to start new proc running call n.
*/
-void
+static void
cgen_proc(Node *n, int proc)
{
switch(n->left->op) {
@@ -598,15 +642,12 @@ cgen_as(Node *nl, Node *nr)
Type *tl;
int iszer;
- if(nl == N)
- return;
-
if(debug['g']) {
dump("cgen_as", nl);
dump("cgen_as = ", nr);
}
- if(isblank(nl)) {
+ if(nl == N || isblank(nl)) {
cgen_discard(nr);
return;
}
@@ -748,12 +789,8 @@ tempname(Node *nn, Type *t)
{
Node *n;
Sym *s;
- uint32 w;
- if(stksize < 0)
- fatal("tempname not during code generation");
-
- if (curfn == N)
+ if(curfn == N)
fatal("no curfn for tempname");
if(t == T) {
@@ -768,23 +805,27 @@ tempname(Node *nn, Type *t)
s = lookup(namebuf);
n = nod(ONAME, N, N);
n->sym = s;
+ s->def = n;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
- n->noescape = 1;
+ n->esc = EscNever;
n->curfn = curfn;
curfn->dcl = list(curfn->dcl, n);
dowidth(t);
- w = t->width;
- stksize += w;
- stksize = rnd(stksize, t->align);
- if(thechar == '5')
- stksize = rnd(stksize, widthptr);
- n->xoffset = -stksize;
-
- // print("\ttmpname (%d): %N\n", stksize, n);
-
+ n->xoffset = 0;
*nn = *n;
}
+
+Node*
+temp(Type *t)
+{
+ Node *n;
+
+ n = nod(OXXX, N, N);
+ tempname(n, t);
+ n->sym->def->used = 1;
+ return n;
+}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
index b5af4678c..e29cfff5b 100644
--- a/src/cmd/gc/go.errors
+++ b/src/cmd/gc/go.errors
@@ -67,4 +67,7 @@ static struct {
% loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
"nested func not allowed",
+
+ % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
+ "else must be followed by if or statement block"
};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index da0fb5146..8c4fff15a 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <u.h>
-#include <libc.h>
#include <bio.h>
#undef OAPPEND
@@ -18,6 +16,12 @@
#undef BUFSIZ
+// The parser's maximum stack size.
+// We have to use a #define macro here since yacc
+// or bison will check for its definition and use
+// a potentially smaller value if it is undefined.
+#define YYMAXDEPTH 500
+
enum
{
NHUNK = 50000,
@@ -25,7 +29,6 @@ enum
NSYMB = 500,
NHASH = 1024,
STRINGSZ = 200,
- YYMAXDEPTH = 500,
MAXALIGN = 7,
UINF = 100,
HISTSZ = 10,
@@ -34,23 +37,30 @@ enum
AUNK = 100,
- // these values are known by runtime
+ // These values are known by runtime.
+ // The MEMx and NOEQx values must run in parallel. See algtype.
AMEM = 0,
- ANOEQ,
- ASTRING,
- AINTER,
- ANILINTER,
- ASLICE,
+ AMEM0,
AMEM8,
AMEM16,
AMEM32,
AMEM64,
AMEM128,
+ ANOEQ,
+ ANOEQ0,
ANOEQ8,
ANOEQ16,
ANOEQ32,
ANOEQ64,
ANOEQ128,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ ASLICE,
+ AFLOAT32,
+ AFLOAT64,
+ ACPLX64,
+ ACPLX128,
BADWIDTH = -1000000000,
};
@@ -69,33 +79,6 @@ struct Strlit
char s[3]; // variable
};
-/*
- * note this is the runtime representation
- * of hashmap iterator. it is probably
- * insafe to use it this way, but it puts
- * all the changes in one place.
- * only flag is referenced from go.
- * actual placement does not matter as long
- * as the size is >= actual size.
- */
-typedef struct Hiter Hiter;
-struct Hiter
-{
- uchar data[8]; // return val from next
- int32 elemsize; // size of elements in table */
- int32 changes; // number of changes observed last time */
- int32 i; // stack pointer in subtable_state */
- uchar last[8]; // last hash value returned */
- uchar h[8]; // the hash table */
- struct
- {
- uchar sub[8]; // pointer into subtable */
- uchar start[8]; // pointer into start of subtable */
- uchar end[8]; // pointer into end of subtable */
- uchar pad[8];
- } sub[4];
-};
-
enum
{
Mpscale = 29, // safely smaller than bits in a long
@@ -137,7 +120,7 @@ struct Val
{
short reg; // OREGISTER
short bval; // bool value CTBOOL
- Mpint* xval; // int CTINT
+ Mpint* xval; // int CTINT, rune CTRUNE
Mpflt* fval; // float CTFLT
Mpcplx* cval; // float CTCPLX
Strlit* sval; // string CTSTR
@@ -155,17 +138,16 @@ struct Type
{
uchar etype;
uchar chan;
- uchar recur; // to detect loops
uchar trecur; // to detect loops
uchar printed;
uchar embedded; // TFIELD embedded type
uchar siggen;
- uchar funarg;
+ uchar funarg; // on TSTRUCT and TFIELD
uchar copyany;
uchar local; // created in this file
uchar deferwidth;
uchar broke;
- uchar isddd; // TFIELD is ... argument
+ uchar isddd; // TFIELD is ... argument
uchar align;
Node* nod; // canonical OTYPE node
@@ -203,8 +185,50 @@ struct Type
};
#define T ((Type*)0)
+typedef struct InitEntry InitEntry;
+typedef struct InitPlan InitPlan;
+
+struct InitEntry
+{
+ vlong xoffset; // struct, array only
+ Node *key; // map only
+ Node *expr;
+};
+
+struct InitPlan
+{
+ vlong lit; // bytes of initialized non-zero literals
+ vlong zero; // bytes of zeros
+ vlong expr; // bytes of run-time computed expressions
+
+ InitEntry *e;
+ int len;
+ int cap;
+};
+
+enum
+{
+ EscUnknown,
+ EscHeap,
+ EscScope,
+ EscNone,
+ EscNever,
+};
+
struct Node
{
+ // Tree structure.
+ // Generic recursive walks should follow these fields.
+ Node* left;
+ Node* right;
+ Node* ntest;
+ Node* nincr;
+ NodeList* ninit;
+ NodeList* nbody;
+ NodeList* nelse;
+ NodeList* list;
+ NodeList* rlist;
+
uchar op;
uchar ullman; // sethi/ullman number
uchar addable; // type of addressability - 0 is not addressable
@@ -215,41 +239,26 @@ struct Node
uchar embedded; // ODCLFIELD embedded type
uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this
- uchar noescape; // ONAME never move to heap
+ uchar esc; // EscXXX
uchar funcdepth;
uchar builtin; // built-in name, like len or close
uchar walkdef;
uchar typecheck;
uchar local;
+ uchar dodata;
uchar initorder;
- uchar dodata; // compile literal assignment as data statement
uchar used;
uchar isddd;
- uchar pun; // don't registerize variable ONAME
uchar readonly;
- uchar implicit; // don't show in printout
+ uchar implicit;
+ uchar addrtaken; // address taken, even if not moved to heap
+ uchar dupok; // duplicate definitions ok (for func)
// most nodes
- Node* left;
- Node* right;
Type* type;
Type* realtype; // as determined by typecheck
- NodeList* list;
- NodeList* rlist;
Node* orig; // original form, for printing, and tracking copies of ONAMEs
- // for-body
- NodeList* ninit;
- Node* ntest;
- Node* nincr;
- NodeList* nbody;
-
- // if-body
- NodeList* nelse;
-
- // cases
- Node* ncase;
-
// func
Node* nname;
Node* shortname;
@@ -257,15 +266,17 @@ struct Node
NodeList* exit;
NodeList* cvars; // closure params
NodeList* dcl; // autodcl for this func/closure
+ NodeList* inl; // copy of the body for use in inlining
// OLITERAL/OREGISTER
Val val;
// ONAME
Node* ntype;
- Node* defn;
+ Node* defn; // ONAME: initializing assignment; OLABEL: labeled statement
Node* pack; // real package for import . names
Node* curfn; // function for local variables
+ Type* paramfld; // TFIELD for this PPARAM
// ONAME func param with PHEAP
Node* heapaddr; // temp holding heap address of param
@@ -276,8 +287,18 @@ struct Node
Node* outer; // outer PPARAMREF in nested closure
Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF
+ // ONAME substitute while inlining
+ Node* inlvar;
+
// OPACK
Pkg* pkg;
+
+ // OARRAYLIT, OMAPLIT, OSTRUCTLIT.
+ InitPlan* initplan;
+
+ // Escape analysis.
+ NodeList* escflowsrc; // flow(this, src)
+ int escloopdepth; // -1: global, 0: not set, function top level:1, increased inside function for every loop or label to mark scopes
Sym* sym; // various
int32 vargen; // unique name for OTYPE/ONAME
@@ -287,9 +308,25 @@ struct Node
int32 stkdelta; // offset added by stack frame compaction phase.
int32 ostk;
int32 iota;
+ uint32 walkgen;
};
#define N ((Node*)0)
-EXTERN int32 walkgen;
+
+/*
+ * Every node has a walkgen field.
+ * If you want to do a traversal of a node graph that
+ * might contain duplicates and want to avoid
+ * visiting the same nodes twice, increment walkgen
+ * before starting. Then before processing a node, do
+ *
+ * if(n->walkgen == walkgen)
+ * return;
+ * n->walkgen = walkgen;
+ *
+ * Such a walk cannot call another such walk recursively,
+ * because of the use of the global walkgen.
+ */
+EXTERN uint32 walkgen;
struct NodeList
{
@@ -300,9 +337,9 @@ struct NodeList
enum
{
- SymExport = 1<<0,
+ SymExport = 1<<0, // to be exported
SymPackage = 1<<1,
- SymExported = 1<<2,
+ SymExported = 1<<2, // already written out by export
SymUniq = 1<<3,
SymSiggen = 1<<4,
};
@@ -329,10 +366,10 @@ EXTERN Sym* dclstack;
struct Pkg
{
- char* name;
- Strlit* path;
+ char* name; // package name
+ Strlit* path; // string literal used in import statement
Sym* pathsym;
- char* prefix;
+ char* prefix; // escaped path for use in symbol table
Pkg* link;
char exported; // import line written in export data
char direct; // imported directly
@@ -374,20 +411,21 @@ enum
OADDR,
OANDAND,
OAPPEND,
- OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
- OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
+ OAS, OAS2, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE,
+ OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,
OCLOSE,
OCLOSURE,
OCMPIFACE, OCMPSTR,
- OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
+ OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OPTRLIT,
OCONV, OCONVIFACE, OCONVNOP,
OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
+ ODELETE,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE,
ODOTTYPE2,
@@ -444,6 +482,9 @@ enum
// misc
ODDD,
+ ODDDARG,
+ OINLCALL, // intermediary representation of an inlined call
+ OITAB, // itable word of interface value
// for back ends
OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG,
@@ -500,6 +541,7 @@ enum
CTxxx,
CTINT,
+ CTRUNE,
CTFLT,
CTCPLX,
CTSTR,
@@ -561,7 +603,6 @@ typedef struct Var Var;
struct Var
{
vlong offset;
- Sym* sym;
Sym* gotype;
Node* node;
int width;
@@ -644,6 +685,7 @@ struct Magic
};
typedef struct Prog Prog;
+#pragma incomplete Prog
struct Label
{
@@ -722,16 +764,22 @@ EXTERN Pkg* gostringpkg; // fake pkg for Go strings
EXTERN Pkg* runtimepkg; // package runtime
EXTERN Pkg* stringpkg; // fake package for C strings
EXTERN Pkg* typepkg; // fake package for runtime type info
+EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* phash[128];
EXTERN int tptr; // either TPTR32 or TPTR64
extern char* runtimeimport;
extern char* unsafeimport;
+EXTERN char* myimportpath;
EXTERN Idir* idirs;
+EXTERN char* localimport;
EXTERN Type* types[NTYPE];
EXTERN Type* idealstring;
EXTERN Type* idealbool;
+EXTERN Type* bytetype;
+EXTERN Type* runetype;
+EXTERN Type* errortype;
EXTERN uchar simtype[NTYPE];
EXTERN uchar isptr[NTYPE];
EXTERN uchar isforw[NTYPE];
@@ -763,7 +811,7 @@ EXTERN NodeList* xtop;
EXTERN NodeList* externdcl;
EXTERN NodeList* closures;
EXTERN NodeList* exportlist;
-EXTERN NodeList* typelist;
+EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies
EXTERN int dclcontext; // PEXTERN/PAUTO
EXTERN int incannedimport;
EXTERN int statuniqgen; // name generator for static temps
@@ -787,18 +835,13 @@ EXTERN Node* nblank;
extern int thechar;
extern char* thestring;
+
EXTERN char* hunk;
EXTERN int32 nhunk;
EXTERN int32 thunk;
-EXTERN int exporting;
-EXTERN int erroring;
-EXTERN int noargnames;
-
EXTERN int funcdepth;
EXTERN int typecheckok;
-EXTERN int packagequotes;
-EXTERN int longsymnames;
EXTERN int compiling_runtime;
/*
@@ -883,7 +926,6 @@ void colasdefn(NodeList *left, Node *defn);
NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
Node* dclname(Sym *s);
void declare(Node *n, int ctxt);
-Type* dostruct(NodeList *l, int et);
void dumpdcl(char *st);
Node* embedded(Sym *s);
Node* fakethis(void);
@@ -904,30 +946,43 @@ void popdcl(void);
void poptodcl(void);
void redeclare(Sym *s, char *where);
void testdclstack(void);
+Type* tointerface(NodeList *l);
+Type* tostruct(NodeList *l);
Node* typedcl0(Sym *s);
Node* typedcl1(Node *n, Node *t, int local);
-void typedcl2(Type *pt, Type *t);
Node* typenod(Type *t);
NodeList* variter(NodeList *vl, Node *t, NodeList *el);
/*
+ * esc.c
+ */
+void escapes(NodeList*);
+
+/*
* export.c
*/
void autoexport(Node *n, int ctxt);
void dumpexport(void);
int exportname(char *s);
void exportsym(Node *n);
-void importconst(Sym *s, Type *t, Node *n);
-void importmethod(Sym *s, Type *t);
-Sym* importsym(Sym *s, int op);
-void importtype(Type *pt, Type *t);
-void importvar(Sym *s, Type *t, int ctxt);
+void importconst(Sym *s, Type *t, Node *n);
+void importimport(Sym *s, Strlit *z);
+Sym* importsym(Sym *s, int op);
+void importtype(Type *pt, Type *t);
+void importvar(Sym *s, Type *t);
Type* pkgtype(Sym *s);
/*
+ * fmt.c
+ */
+void fmtinstallgo(void);
+void dump(char *s, Node *n);
+void dumplist(char *s, NodeList *l);
+
+/*
* gen.c
*/
-void allocparams(void);
+void addrescapes(Node *n);
void cgen_as(Node *nl, Node *nr);
void cgen_callmeth(Node *n, int proc);
void clearlabels(void);
@@ -937,12 +992,20 @@ void gen(Node *n);
void genlist(NodeList *l);
Node* sysfunc(char *name);
void tempname(Node *n, Type *t);
+Node* temp(Type*);
/*
* init.c
*/
void fninit(NodeList *n);
-Node* renameinit(Node *n);
+Sym* renameinit(void);
+
+/*
+ * inl.c
+ */
+void caninl(Node *fn);
+void inlcalls(Node *fn);
+void typecheckinl(Node *fn);
/*
* lex.c
@@ -950,6 +1013,7 @@ Node* renameinit(Node *n);
void cannedimports(char *file, char *cp);
void importfile(Val *f, int line);
char* lexname(int lex);
+char* expstring(void);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);
@@ -987,7 +1051,7 @@ void mpsubfltflt(Mpflt *a, Mpflt *b);
/*
* mparith2.c
*/
-void mpaddfixfix(Mpint *a, Mpint *b);
+void mpaddfixfix(Mpint *a, Mpint *b, int);
void mpandfixfix(Mpint *a, Mpint *b);
void mpandnotfixfix(Mpint *a, Mpint *b);
void mpdivfract(Mpint *a, Mpint *b);
@@ -1032,10 +1096,9 @@ void ieeedtod(uint64 *ieee, double native);
Sym* stringsym(char*, int);
/*
- * print.c
+ * order.c
*/
-void exprfmt(Fmt *f, Node *n, int prec);
-void exprlistfmt(Fmt *f, NodeList *l);
+void order(Node *fn);
/*
* range.c
@@ -1050,6 +1113,8 @@ void dumptypestructs(void);
Type* methodfunc(Type *f, Type*);
Node* typename(Type *t);
Sym* typesym(Type *t);
+Sym* typesymprefix(char *prefix, Type *t);
+int haspointers(Type *t);
/*
* select.c
@@ -1069,19 +1134,12 @@ int stataddr(Node *nam, Node *n);
/*
* subr.c
*/
-int Econv(Fmt *fp);
-int Jconv(Fmt *fp);
-int Lconv(Fmt *fp);
-int Nconv(Fmt *fp);
-int Oconv(Fmt *fp);
-int Sconv(Fmt *fp);
-int Tconv(Fmt *fp);
-int Tpretty(Fmt *fp, Type *t);
-int Zconv(Fmt *fp);
Node* adddot(Node *n);
int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
+void addinit(Node**, NodeList*);
Type* aindex(Node *b, Type *t);
int algtype(Type *t);
+int algtype1(Type *t, Type **bad);
void argtype(Node *on, Type *t);
Node* assignconv(Node *n, Type *t, char *context);
int assignop(Type *src, Type *dst, char **why);
@@ -1090,20 +1148,21 @@ int brcom(int a);
int brrev(int a);
NodeList* concat(NodeList *a, NodeList *b);
int convertop(Type *src, Type *dst, char **why);
+Node* copyexpr(Node*, Type*, NodeList**);
int count(NodeList *l);
int cplxsubtype(int et);
-void dump(char *s, Node *n);
-void dumplist(char *s, NodeList *l);
int eqtype(Type *t1, Type *t2);
int eqtypenoname(Type *t1, Type *t2);
void errorexit(void);
-void expandmeth(Sym *s, Type *t);
+void expandmeth(Type *t);
void fatal(char *fmt, ...);
void flusherrors(void);
void frame(int context);
Type* funcfirst(Iter *s, Type *t);
Type* funcnext(Iter *s);
void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
+void genhash(Sym *sym, Type *t);
+void geneq(Sym *sym, Type *t);
Type** getinarg(Type *t);
Type* getinargx(Type *t);
Type** getoutarg(Type *t);
@@ -1113,7 +1172,9 @@ Type* getthisx(Type *t);
int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
void importdot(Pkg *opkg, Node *pack);
int is64(Type *t);
+int isbadimport(Strlit *s);
int isblank(Node *n);
+int isblanksym(Sym *s);
int isfixedarray(Type *t);
int isideal(Type *t);
int isinter(Type *t);
@@ -1131,7 +1192,7 @@ NodeList* listtreecopy(NodeList *l);
Sym* lookup(char *name);
void* mal(int32 n);
Type* maptype(Type *key, Type *val);
-Type* methtype(Type *t);
+Type* methtype(Type *t, int mustname);
Pkg* mkpkg(Strlit *path);
Sym* ngotype(Node *n);
int noconv(Type *t1, Type *t2);
@@ -1170,6 +1231,7 @@ uint32 typehash(Type *t);
void ullmancalc(Node *n);
void umagic(Magic *m);
void warn(char *fmt, ...);
+void warnl(int line, char *fmt, ...);
void yyerror(char *fmt, ...);
void yyerrorl(int line, char *fmt, ...);
@@ -1182,7 +1244,6 @@ void walkswitch(Node *sw);
/*
* typecheck.c
*/
-int exportassignok(Type *t, char *desc);
int islvalue(Node *n);
Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
@@ -1195,6 +1256,7 @@ void queuemethod(Node *n);
/*
* unsafe.c
*/
+int isunsafebuiltin(Node *n);
Node* unsafenmagic(Node *n);
/*
@@ -1211,6 +1273,7 @@ void walkexprlist(NodeList *l, NodeList **init);
void walkexprlistsafe(NodeList *l, NodeList **init);
void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
+Node* conv(Node*, Type*);
/*
* arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
@@ -1274,6 +1337,30 @@ Prog* unpatch(Prog*);
void zfile(Biobuf *b, char *p, int n);
void zhist(Biobuf *b, int line, vlong offset);
void zname(Biobuf *b, Sym *s, int t);
-void data(void);
-void text(void);
+#pragma varargck type "A" int
+#pragma varargck type "B" Mpint*
+#pragma varargck type "D" Addr*
+#pragma varargck type "lD" Addr*
+#pragma varargck type "E" int
+#pragma varargck type "E" uint
+#pragma varargck type "F" Mpflt*
+#pragma varargck type "H" NodeList*
+#pragma varargck type "J" Node*
+#pragma varargck type "lL" int
+#pragma varargck type "lL" uint
+#pragma varargck type "L" int
+#pragma varargck type "L" uint
+#pragma varargck type "N" Node*
+#pragma varargck type "lN" Node*
+#pragma varargck type "O" uint
+#pragma varargck type "P" Prog*
+#pragma varargck type "Q" Bits
+#pragma varargck type "R" int
+#pragma varargck type "S" Sym*
+#pragma varargck type "lS" Sym*
+#pragma varargck type "T" Type*
+#pragma varargck type "lT" Type*
+#pragma varargck type "V" Val*
+#pragma varargck type "Y" char*
+#pragma varargck type "Z" Strlit*
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 4c7fe6068..f95058721 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -18,7 +18,9 @@
*/
%{
+#include <u.h>
#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
+#include <libc.h>
#include "go.h"
static void fixlbrace(int);
@@ -29,13 +31,13 @@ static void fixlbrace(int);
Type* type;
Sym* sym;
struct Val val;
- int lint;
+ int i;
}
// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /'
%token <val> LLITERAL
-%token <lint> LASOP
+%token <i> LASOP
%token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD
%token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
%token <sym> LIF LIMPORT LINTERFACE LMAP LNAME
@@ -45,7 +47,7 @@ static void fixlbrace(int);
%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
-%type <lint> lbrace import_here
+%type <i> lbrace import_here
%type <sym> sym packname
%type <val> oliteral
@@ -54,8 +56,8 @@ static void fixlbrace(int);
%type <node> case caseblock
%type <node> compound_stmt dotname embed expr complitexpr
%type <node> expr_or_type
-%type <node> fndcl fnliteral
-%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
+%type <node> fndcl hidden_fndcl fnliteral
+%type <node> for_body for_header for_stmt if_header if_stmt else non_dcl_stmt
%type <node> interfacedcl keyval labelname name
%type <node> name_or_type non_expr_type
%type <node> new_name dcl_name oexpr typedclname
@@ -64,7 +66,7 @@ static void fixlbrace(int);
%type <node> pseudocall range_stmt select_stmt
%type <node> simple_stmt
%type <node> switch_stmt uexpr
-%type <node> xfndcl typedcl
+%type <node> xfndcl typedcl start_complit
%type <list> xdcl fnbody fnres loop_body dcl_name_list
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
@@ -76,12 +78,10 @@ static void fixlbrace(int);
%type <node> indcl interfacetype structtype ptrtype
%type <node> recvchantype non_recvchantype othertype fnret_type fntype
-%type <val> hidden_tag
-
%type <sym> hidden_importsym hidden_pkg_importsym
-%type <node> hidden_constant hidden_literal hidden_dcl
-%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym
+%type <node> hidden_constant hidden_literal hidden_funarg
+%type <node> hidden_interfacedcl hidden_structdcl
%type <list> hidden_funres
%type <list> ohidden_funres
@@ -205,7 +205,15 @@ import_stmt:
my->lastlineno = $1;
my->block = 1; // at top level
}
-
+| import_here import_there
+ {
+ // When an invalid import path is passed to importfile,
+ // it calls yyerror and then sets up a fake import with
+ // no package statement. This allows us to test more
+ // than one invalid import statement in a single file.
+ if(nerrors == 0)
+ fatal("phase error in import");
+ }
import_stmt_list:
import_stmt
@@ -235,17 +243,17 @@ import_here:
}
import_package:
- LPACKAGE sym import_safety ';'
+ LPACKAGE LNAME import_safety ';'
{
if(importpkg->name == nil) {
importpkg->name = $2->name;
pkglookup($2->name, nil)->npkg++;
} else if(strcmp(importpkg->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path);
+ yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path);
importpkg->direct = 1;
if(safemode && !curio.importsafe)
- yyerror("cannot import unsafe package %Z", importpkg->path);
+ yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
}
import_safety:
@@ -418,18 +426,15 @@ simple_stmt:
| expr_list LCOLAS expr_list
{
if($3->n->op == OTYPESW) {
- Node *n;
-
- n = N;
+ $$ = nod(OTYPESW, N, $3->n->right);
if($3->next != nil)
yyerror("expr.(type) must be alone in list");
if($1->next != nil)
yyerror("argument count mismatch: %d = %d", count($1), 1);
- else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
- yyerror("invalid variable name %#N in type switch", $1->n);
+ else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n))
+ yyerror("invalid variable name %N in type switch", $1->n);
else
- n = $1->n;
- $$ = nod(OTYPESW, n, $3->n->right);
+ $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname.
break;
}
$$ = colas($1, $3);
@@ -448,7 +453,7 @@ simple_stmt:
case:
LCASE expr_or_type_list ':'
{
- Node *n;
+ Node *n, *nn;
// will be converted to OCASE
// right will point to next case
@@ -458,12 +463,13 @@ case:
$$->list = $2;
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
// type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
+ nn = newname(n->sym);
+ declare(nn, dclcontext);
+ $$->nname = nn;
+
+ // keep track of the instances for reporting unused
+ nn->defn = typesw->right;
}
- break;
}
| LCASE expr_or_type_list '=' expr ':'
{
@@ -494,16 +500,18 @@ case:
}
| LDEFAULT ':'
{
- Node *n;
+ Node *n, *nn;
markdcl();
$$ = nod(OXCASE, N, N);
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
// type switch - declare variable
- n = newname(n->sym);
- n->used = 1; // TODO(rsc): better job here
- declare(n, dclcontext);
- $$->nname = n;
+ nn = newname(n->sym);
+ declare(nn, dclcontext);
+ $$->nname = nn;
+
+ // keep track of the instances for reporting unused
+ nn->defn = typesw->right;
}
}
@@ -638,6 +646,7 @@ if_header:
$$->ntest = $3;
}
+/* IF cond body (ELSE IF cond body)* (ELSE block)? */
if_stmt:
LIF
{
@@ -650,9 +659,27 @@ if_stmt:
}
loop_body
{
+ $3->nbody = $5;
+ }
+ else
+ {
+ popdcl();
$$ = $3;
- $$->nbody = $5;
- // no popdcl; maybe there's an LELSE
+ if($7 != N)
+ $$->nelse = list1($7);
+ }
+
+else:
+ {
+ $$ = N;
+ }
+| LELSE if_stmt
+ {
+ $$ = $2;
+ }
+| LELSE compound_stmt
+ {
+ $$ = $2;
}
switch_stmt:
@@ -785,7 +812,14 @@ uexpr:
}
| '&' uexpr
{
- $$ = nod(OADDR, $2, N);
+ if($2->op == OCOMPLIT) {
+ // Special case for &T{...}: turn into (*T){...}.
+ $$ = $2;
+ $$->right = nod(OIND, $$->right, N);
+ $$->right->implicit = 1;
+ } else {
+ $$ = nod(OADDR, $2, N);
+ }
}
| '+' uexpr
{
@@ -874,29 +908,35 @@ pexpr_no_paren:
$$ = nod(OCALL, $1, N);
$$->list = list1($3);
}
-| comptype lbrace braced_keyval_list '}'
+| comptype lbrace start_complit braced_keyval_list '}'
{
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
-
+ $$ = $3;
+ $$->right = $1;
+ $$->list = $4;
fixlbrace($2);
}
-| pexpr_no_paren '{' braced_keyval_list '}'
+| pexpr_no_paren '{' start_complit braced_keyval_list '}'
{
- // composite expression
- $$ = nod(OCOMPLIT, N, $1);
- $$->list = $3;
+ $$ = $3;
+ $$->right = $1;
+ $$->list = $4;
}
-| '(' expr_or_type ')' '{' braced_keyval_list '}'
+| '(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
{
yyerror("cannot parenthesize type in composite literal");
- // composite expression
- $$ = nod(OCOMPLIT, N, $2);
- $$->list = $5;
+ $$ = $5;
+ $$->right = $2;
+ $$->list = $6;
}
| fnliteral
+start_complit:
+ {
+ // composite expression.
+ // make node early so we get the right line number.
+ $$ = nod(OCOMPLIT, N, N);
+ }
+
keyval:
expr ':' complitexpr
{
@@ -905,10 +945,10 @@ keyval:
complitexpr:
expr
-| '{' braced_keyval_list '}'
+| '{' start_complit braced_keyval_list '}'
{
- $$ = nod(OCOMPLIT, N, N);
- $$->list = $2;
+ $$ = $2;
+ $$->list = $3;
}
pexpr:
@@ -955,7 +995,10 @@ lbrace:
new_name:
sym
{
- $$ = newname($1);
+ if($1 == S)
+ $$ = N;
+ else
+ $$ = newname($1);
}
dcl_name:
@@ -972,6 +1015,26 @@ onew_name:
sym:
LNAME
+ {
+ $$ = $1;
+ // during imports, unqualified non-exported identifiers are from builtinpkg
+ if(importpkg != nil && !exportname($1->name))
+ $$ = pkglookup($1->name, builtinpkg);
+ }
+| hidden_importsym
+| '?'
+ {
+ $$ = S;
+ }
+
+hidden_importsym:
+ '@' LLITERAL '.' LNAME
+ {
+ if($2.u.sval->len == 0)
+ $$ = pkglookup($4->name, importpkg);
+ else
+ $$ = pkglookup($4->name, mkpkg($2.u.sval));
+ }
name:
sym %prec NotParen
@@ -1144,38 +1207,43 @@ xfndcl:
}
fndcl:
- dcl_name '(' oarg_type_list_ocomma ')' fnres
+ sym '(' oarg_type_list_ocomma ')' fnres
{
- Node *n;
+ Node *t;
+ $$ = N;
$3 = checkarglist($3, 1);
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = $1;
- n = nod(OTFUNC, N, N);
- n->list = $3;
- n->rlist = $5;
- if(strcmp($1->sym->name, "init") == 0) {
- $$->nname = renameinit($1);
+
+ if(strcmp($1->name, "init") == 0) {
+ $1 = renameinit();
if($3 != nil || $5 != nil)
yyerror("func init must have no arguments and no return values");
}
- if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) {
+ if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
if($3 != nil || $5 != nil)
yyerror("func main must have no arguments and no return values");
}
- // TODO: check if nname already has an ntype
- $$->nname->ntype = n;
+
+ t = nod(OTFUNC, N, N);
+ t->list = $3;
+ t->rlist = $5;
+
+ $$ = nod(ODCLFUNC, N, N);
+ $$->nname = newname($1);
+ $$->nname->defn = $$;
+ $$->nname->ntype = t; // TODO: check if nname already has an ntype
+ declare($$->nname, PFUNC);
+
funchdr($$);
}
| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
{
Node *rcvr, *t;
- Node *name;
-
- name = newname($4);
+
+ $$ = N;
$2 = checkarglist($2, 0);
$6 = checkarglist($6, 1);
- $$ = N;
+
if($2 == nil) {
yyerror("method has no receiver");
break;
@@ -1192,16 +1260,60 @@ fndcl:
if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
yyerror("cannot parenthesize receiver type");
- $$ = nod(ODCLFUNC, N, N);
- $$->nname = methodname1(name, rcvr->right);
t = nod(OTFUNC, rcvr, N);
t->list = $6;
t->rlist = $8;
+
+ $$ = nod(ODCLFUNC, N, N);
+ $$->shortname = newname($4);
+ $$->nname = methodname1($$->shortname, rcvr->right);
+ $$->nname->defn = $$;
$$->nname->ntype = t;
- $$->shortname = name;
+ declare($$->nname, PFUNC);
+
funchdr($$);
}
+hidden_fndcl:
+ hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
+ {
+ Sym *s;
+ Type *t;
+
+ $$ = N;
+
+ s = $1;
+ t = functype(N, $3, $5);
+
+ importsym(s, ONAME);
+ if(s->def != N && s->def->op == ONAME) {
+ if(eqtype(t, s->def->type))
+ break;
+ yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
+ }
+
+ $$ = newname(s);
+ $$->type = t;
+ declare($$, PFUNC);
+
+ funchdr($$);
+ }
+| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
+ {
+ $$ = methodname1(newname($4), $2->n->right);
+ $$->type = functype($2->n, $6, $8);
+
+ checkwidth($$->type);
+ addmethod($4, $$->type, 0);
+ funchdr($$);
+
+ // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
+ // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
+ // out by typecheck's lookdot as this $$->ttype. So by providing
+ // this back link here we avoid special casing there.
+ $$->type->nname = $$;
+ }
+
fntype:
LFUNC '(' oarg_type_list_ocomma ')' fnres
{
@@ -1317,6 +1429,20 @@ structdcl:
{
NodeList *l;
+ Node *n;
+ l = $1;
+ if(l != nil && l->next == nil && l->n == nil) {
+ // ? symbol, during import
+ n = $2;
+ if(n->op == OIND)
+ n = n->left;
+ n = embedded(n->sym);
+ n->right = $2;
+ n->val = $3;
+ $$ = list1(n);
+ break;
+ }
+
for(l=$1; l; l=l->next) {
l->n = nod(ODCLFIELD, l->n, $2);
l->n->val = $3;
@@ -1472,19 +1598,6 @@ non_dcl_stmt:
| switch_stmt
| select_stmt
| if_stmt
- {
- popdcl();
- $$ = $1;
- }
-| if_stmt LELSE stmt
- {
- if($3->op != OIF && $3->op != OBLOCK)
- yyerror("missing { } after else");
-
- popdcl();
- $$ = $1;
- $$->nelse = list1($3);
- }
| labelname ':'
{
$1 = nod(OLABEL, $1, N);
@@ -1494,7 +1607,7 @@ non_dcl_stmt:
{
NodeList *l;
- $1->right = $4;
+ $1->defn = $4;
l = list1($1);
if($4)
l = list(l, $4);
@@ -1530,6 +1643,18 @@ non_dcl_stmt:
{
$$ = nod(ORETURN, N, N);
$$->list = $2;
+ if($$->list == nil && curfn != N) {
+ NodeList *l;
+
+ for(l=curfn->dcl; l; l=l->next) {
+ if(l->n->class == PPARAM)
+ continue;
+ if(l->n->class != PPARAMOUT)
+ break;
+ if(l->n->sym->def != l->n)
+ yyerror("%s is shadowed during return", l->n->sym->name);
+ }
+ }
}
stmt_list:
@@ -1668,27 +1793,16 @@ oliteral:
| LLITERAL
/*
- * import syntax from header of
- * an output package
+ * import syntax from package header
*/
hidden_import:
- LIMPORT sym LLITERAL ';'
+ LIMPORT LNAME LLITERAL ';'
{
- // Informational: record package name
- // associated with import path, for use in
- // human-readable messages.
- Pkg *p;
-
- p = mkpkg($3.u.sval);
- if(p->name == nil) {
- p->name = $2->name;
- pkglookup($2->name, nil)->npkg++;
- } else if(strcmp(p->name, $2->name) != 0)
- yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path);
+ importimport($2, $3.u.sval);
}
| LVAR hidden_pkg_importsym hidden_type ';'
{
- importvar($2, $3, PEXTERN);
+ importvar($2, $3);
}
| LCONST hidden_pkg_importsym '=' hidden_constant ';'
{
@@ -1702,17 +1816,28 @@ hidden_import:
{
importtype($2, $3);
}
-| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';'
+| LFUNC hidden_fndcl fnbody ';'
{
- importvar($2, functype(N, $4, $6), PFUNC);
+ if($2 == N)
+ break;
+
+ $2->inl = $3;
+
+ funcbody($2);
+ importlist = list(importlist, $2);
+
+ if(debug['E']) {
+ print("import [%Z] func %lN \n", importpkg->path, $2);
+ if(debug['l'] > 2 && $2->inl)
+ print("inl body:%+H\n", $2->inl);
+ }
}
-| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';'
+
+hidden_pkg_importsym:
+ hidden_importsym
{
- if($3->next != nil || $3->n->op != ODCLFIELD) {
- yyerror("bad receiver in method");
- YYERROR;
- }
- importmethod($5, functype($3->n, $7, $9));
+ $$ = $1;
+ structpkg = $$->pkg;
}
hidden_pkgtype:
@@ -1722,6 +1847,10 @@ hidden_pkgtype:
importsym($1, OTYPE);
}
+/*
+ * importing types
+ */
+
hidden_type:
hidden_type_misc
| hidden_type_recv_chan
@@ -1760,11 +1889,11 @@ hidden_type_misc:
}
| LSTRUCT '{' ohidden_structdcl_list '}'
{
- $$ = dostruct($3, TSTRUCT);
+ $$ = tostruct($3);
}
| LINTERFACE '{' ohidden_interfacedcl_list '}'
{
- $$ = dostruct($3, TINTER);
+ $$ = tointerface($3);
}
| '*' hidden_type
{
@@ -1803,61 +1932,45 @@ hidden_type_func:
$$ = functype(nil, $3, $5);
}
-hidden_opt_sym:
- sym
- {
- $$ = newname($1);
- }
-| '?'
- {
- $$ = N;
- }
-
-hidden_dcl:
- hidden_opt_sym hidden_type hidden_tag
+hidden_funarg:
+ sym hidden_type oliteral
{
- $$ = nod(ODCLFIELD, $1, typenod($2));
+ $$ = nod(ODCLFIELD, N, typenod($2));
+ if($1)
+ $$->left = newname($1);
$$->val = $3;
}
-| hidden_opt_sym LDDD hidden_type hidden_tag
+| sym LDDD hidden_type oliteral
{
Type *t;
-
+
t = typ(TARRAY);
t->bound = -1;
t->type = $3;
- $$ = nod(ODCLFIELD, $1, typenod(t));
+
+ $$ = nod(ODCLFIELD, N, typenod(t));
+ if($1)
+ $$->left = newname($1);
$$->isddd = 1;
$$->val = $4;
}
hidden_structdcl:
- sym hidden_type hidden_tag
- {
- $$ = nod(ODCLFIELD, newname($1), typenod($2));
- $$->val = $3;
- }
-| '?' hidden_type hidden_tag
+ sym hidden_type oliteral
{
Sym *s;
- s = $2->sym;
- if(s == S && isptr[$2->etype])
- s = $2->type->sym;
- if(s && s->pkg == builtinpkg)
- s = lookup(s->name);
- $$ = embedded(s);
- $$->right = typenod($2);
- $$->val = $3;
- }
-
-hidden_tag:
- {
- $$.ctype = CTxxx;
- }
-| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename
- {
- $$ = $2;
+ if($1 != S) {
+ $$ = nod(ODCLFIELD, newname($1), typenod($2));
+ $$->val = $3;
+ } else {
+ s = $2->sym;
+ if(s == S && isptr[$2->etype])
+ s = $2->type->sym;
+ $$ = embedded(s);
+ $$->right = typenod($2);
+ $$->val = $3;
+ }
}
hidden_interfacedcl:
@@ -1865,9 +1978,9 @@ hidden_interfacedcl:
{
$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
}
-| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres
+| hidden_type
{
- $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
+ $$ = nod(ODCLFIELD, N, typenod($1));
}
ohidden_funres:
@@ -1886,6 +1999,10 @@ hidden_funres:
$$ = list1(nod(ODCLFIELD, N, typenod($1)));
}
+/*
+ * importing constants
+ */
+
hidden_literal:
LLITERAL
{
@@ -1896,6 +2013,7 @@ hidden_literal:
$$ = nodlit($2);
switch($$->val.ctype){
case CTINT:
+ case CTRUNE:
mpnegfix($$->val.u.xval);
break;
case CTFLT:
@@ -1916,37 +2034,23 @@ hidden_constant:
hidden_literal
| '(' hidden_literal '+' hidden_literal ')'
{
+ if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) {
+ $$ = $2;
+ mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0);
+ break;
+ }
$$ = nodcplxlit($2->val, $4->val);
}
-hidden_importsym:
- LLITERAL '.' sym
- {
- Pkg *p;
-
- if($1.u.sval->len == 0)
- p = importpkg;
- else
- p = mkpkg($1.u.sval);
- $$ = pkglookup($3->name, p);
- }
-
-hidden_pkg_importsym:
- hidden_importsym
- {
- $$ = $1;
- structpkg = $$->pkg;
- }
-
hidden_import_list:
| hidden_import_list hidden_import
hidden_funarg_list:
- hidden_dcl
+ hidden_funarg
{
$$ = list1($1);
}
-| hidden_funarg_list ',' hidden_dcl
+| hidden_funarg_list ',' hidden_funarg
{
$$ = list($1, $3);
}
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
index 8818db08c..be402cc0c 100644
--- a/src/cmd/gc/init.c
+++ b/src/cmd/gc/init.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -11,21 +13,13 @@
* package and also uncallable, the name,
* normally "pkg.init", is altered to "pkg.init·1".
*/
-Node*
-renameinit(Node *n)
+Sym*
+renameinit(void)
{
- Sym *s;
static int initgen;
- s = n->sym;
- if(s == S)
- return n;
- if(strcmp(s->name, "init") != 0)
- return n;
-
snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
- s = lookup(namebuf);
- return newname(s);
+ return lookup(namebuf);
}
/*
@@ -123,7 +117,9 @@ fninit(NodeList *n)
fn = nod(ODCLFUNC, N, N);
initsym = lookup(namebuf);
fn->nname = newname(initsym);
+ fn->nname->defn = fn;
fn->nname->ntype = nod(OTFUNC, N, N);
+ declare(fn->nname, PFUNC);
funchdr(fn);
// (3)
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
new file mode 100644
index 000000000..efce56057
--- /dev/null
+++ b/src/cmd/gc/inl.c
@@ -0,0 +1,842 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// The inlining facility makes 2 passes: first caninl determines which
+// functions are suitable for inlining, and for those that are it
+// saves a copy of the body. Then inlcalls walks each function body to
+// expand calls to inlinable functions.
+//
+// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
+// making 1 the default and -l disable. -ll and more is useful to flush out bugs.
+// These additional levels (beyond -l) may be buggy and are not supported.
+// 0: disabled
+// 1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
+// 2: early typechecking of all imported bodies
+// 3:
+// 4: allow non-leaf functions , (breaks runtime.Caller)
+// 5: transitive inlining
+//
+// At some point this may get another default and become switch-offable with -N.
+//
+// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying
+// which calls get inlined or not, more is for debugging, and may go away at any point.
+//
+// TODO:
+// - inline functions with ... args
+// - handle T.meth(f()) with func f() (t T, arg, arg, )
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+// Used by caninl.
+static Node* inlcopy(Node *n);
+static NodeList* inlcopylist(NodeList *ll);
+static int ishairy(Node *n, int *budget);
+static int ishairylist(NodeList *ll, int *budget);
+
+// Used by inlcalls
+static void inlnodelist(NodeList *l);
+static void inlnode(Node **np);
+static void mkinlcall(Node **np, Node *fn);
+static Node* inlvar(Node *n);
+static Node* retvar(Type *n, int i);
+static Node* newlabel(void);
+static Node* inlsubst(Node *n);
+static NodeList* inlsubstlist(NodeList *l);
+
+static void setlno(Node*, int);
+
+// Used during inlsubst[list]
+static Node *inlfn; // function currently being inlined
+static Node *inlretlabel; // target of the goto substituted in place of a return
+static NodeList *inlretvars; // temp out variables
+
+// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
+// the ->sym can be re-used in the local package, so peel it off the receiver's type.
+static Pkg*
+fnpkg(Node *fn)
+{
+ Type *rcvr;
+
+ if(fn->type->thistuple) {
+ // method
+ rcvr = getthisx(fn->type)->type->type;
+ if(isptr[rcvr->etype])
+ rcvr = rcvr->type;
+ if(!rcvr->sym)
+ fatal("receiver with no sym: [%S] %lN (%T)", fn->sym, fn, rcvr);
+ return rcvr->sym->pkg;
+ }
+ // non-method
+ return fn->sym->pkg;
+}
+
+// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body.
+void
+typecheckinl(Node *fn)
+{
+ Node *savefn;
+ Pkg *pkg;
+ int save_safemode, lno;
+
+ if(fn->typecheck)
+ return;
+
+ lno = setlineno(fn);
+
+ if (debug['m']>2)
+ print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl);
+
+ // typecheckinl is only used for imported functions;
+ // their bodies may refer to unsafe as long as the package
+ // was marked safe during import (which was checked then).
+ pkg = fnpkg(fn);
+ if (pkg == localpkg || pkg == nil)
+ fatal("typecheckinl on local function %lN", fn);
+
+ save_safemode = safemode;
+ safemode = 0;
+
+ savefn = curfn;
+ curfn = fn;
+ typechecklist(fn->inl, Etop);
+ fn->typecheck = 1;
+ curfn = savefn;
+
+ safemode = save_safemode;
+
+ lineno = lno;
+}
+
+// Caninl determines whether fn is inlineable. Currently that means:
+// fn is exactly 1 statement, either a return or an assignment, and
+// some temporary constraints marked TODO. If fn is inlineable, saves
+// fn->nbody in fn->inl and substitutes it with a copy.
+void
+caninl(Node *fn)
+{
+ Node *savefn;
+ Type *t;
+ int budget;
+
+ if(fn->op != ODCLFUNC)
+ fatal("caninl %N", fn);
+ if(!fn->nname)
+ fatal("caninl no nname %+N", fn);
+
+ // If fn has no body (is defined outside of Go), cannot inline it.
+ if(fn->nbody == nil)
+ return;
+
+ // can't handle ... args yet
+ for(t=fn->type->type->down->down->type; t; t=t->down)
+ if(t->isddd)
+ return;
+
+ budget = 40; // allowed hairyness
+ if(ishairylist(fn->nbody, &budget))
+ return;
+
+ savefn = curfn;
+ curfn = fn;
+
+ fn->nname->inl = fn->nbody;
+ fn->nbody = inlcopylist(fn->nname->inl);
+ // nbody will have been typechecked, so we can set this:
+ fn->typecheck = 1;
+
+ // hack, TODO, check for better way to link method nodes back to the thing with the ->inl
+ // this is so export can find the body of a method
+ fn->type->nname = fn->nname;
+
+ if(debug['m'] > 1)
+ print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl);
+ else if(debug['m'])
+ print("%L: can inline %N\n", fn->lineno, fn->nname);
+
+ curfn = savefn;
+}
+
+// Look for anything we want to punt on.
+static int
+ishairylist(NodeList *ll, int* budget)
+{
+ for(;ll;ll=ll->next)
+ if(ishairy(ll->n, budget))
+ return 1;
+ return 0;
+}
+
+static int
+ishairy(Node *n, int *budget)
+{
+ if(!n)
+ return 0;
+
+ // Things that are too hairy, irrespective of the budget
+ switch(n->op) {
+ case OCALL:
+ case OCALLFUNC:
+ case OCALLINTER:
+ case OCALLMETH:
+ case OPANIC:
+ case ORECOVER:
+ if(debug['l'] < 4)
+ return 1;
+ break;
+
+ case OCLOSURE:
+ case ORANGE:
+ case OFOR:
+ case OSELECT:
+ case OSWITCH:
+ case OPROC:
+ case ODEFER:
+ case ODCL: // declares locals as globals b/c of @"". qualification
+ case ODCLTYPE: // can't print yet
+ case ODCLCONST: // can't print yet
+ return 1;
+
+ break;
+ case OAS:
+ // x = <N> zero initializing assignments aren't representible in export yet.
+ // alternatively we may just skip them in printing and hope their DCL printed
+ // as a var will regenerate it
+ if(n->right == N)
+ return 1;
+ break;
+ }
+
+ (*budget)--;
+
+ return *budget < 0 ||
+ ishairy(n->left, budget) ||
+ ishairy(n->right, budget) ||
+ ishairylist(n->list, budget) ||
+ ishairylist(n->rlist, budget) ||
+ ishairylist(n->ninit, budget) ||
+ ishairy(n->ntest, budget) ||
+ ishairy(n->nincr, budget) ||
+ ishairylist(n->nbody, budget) ||
+ ishairylist(n->nelse, budget);
+}
+
+// Inlcopy and inlcopylist recursively copy the body of a function.
+// Any name-like node of non-local class is marked for re-export by adding it to
+// the exportlist.
+static NodeList*
+inlcopylist(NodeList *ll)
+{
+ NodeList *l;
+
+ l = nil;
+ for(; ll; ll=ll->next)
+ l = list(l, inlcopy(ll->n));
+ return l;
+}
+
+static Node*
+inlcopy(Node *n)
+{
+ Node *m;
+
+ if(n == N)
+ return N;
+
+ switch(n->op) {
+ case ONAME:
+ case OTYPE:
+ case OLITERAL:
+ return n;
+ }
+
+ m = nod(OXXX, N, N);
+ *m = *n;
+ m->inl = nil;
+ m->left = inlcopy(n->left);
+ m->right = inlcopy(n->right);
+ m->list = inlcopylist(n->list);
+ m->rlist = inlcopylist(n->rlist);
+ m->ninit = inlcopylist(n->ninit);
+ m->ntest = inlcopy(n->ntest);
+ m->nincr = inlcopy(n->nincr);
+ m->nbody = inlcopylist(n->nbody);
+ m->nelse = inlcopylist(n->nelse);
+
+ return m;
+}
+
+
+// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
+// calls made to inlineable functions. This is the external entry point.
+void
+inlcalls(Node *fn)
+{
+ Node *savefn;
+
+ savefn = curfn;
+ curfn = fn;
+ inlnode(&fn);
+ if(fn != curfn)
+ fatal("inlnode replaced curfn");
+ curfn = savefn;
+}
+
+// Turn an OINLCALL into a statement.
+static void
+inlconv2stmt(Node *n)
+{
+ n->op = OBLOCK;
+ // n->ninit stays
+ n->list = n->nbody;
+ n->nbody = nil;
+ n->rlist = nil;
+}
+
+// Turn an OINLCALL into a single valued expression.
+static void
+inlconv2expr(Node **np)
+{
+ Node *n, *r;
+ n = *np;
+ r = n->rlist->n;
+ addinit(&r, concat(n->ninit, n->nbody));
+ *np = r;
+}
+
+// Turn the rlist (with the return values) of the OINLCALL in
+// n into an expression list lumping the ninit and body
+// containing the inlined statements on the first list element so
+// order will be preserved Used in return, oas2func and call
+// statements.
+static NodeList*
+inlconv2list(Node *n)
+{
+ NodeList *l;
+
+ if(n->op != OINLCALL || n->rlist == nil)
+ fatal("inlconv2list %+N\n", n);
+
+ l = n->rlist;
+ addinit(&l->n, concat(n->ninit, n->nbody));
+ return l;
+}
+
+static void
+inlnodelist(NodeList *l)
+{
+ for(; l; l=l->next)
+ inlnode(&l->n);
+}
+
+// inlnode recurses over the tree to find inlineable calls, which will
+// be turned into OINLCALLs by mkinlcall. When the recursion comes
+// back up will examine left, right, list, rlist, ninit, ntest, nincr,
+// nbody and nelse and use one of the 4 inlconv/glue functions above
+// to turn the OINLCALL into an expression, a statement, or patch it
+// in to this nodes list or rlist as appropriate.
+// NOTE it makes no sense to pass the glue functions down the
+// recursion to the level where the OINLCALL gets created because they
+// have to edit /this/ n, so you'd have to push that one down as well,
+// but then you may as well do it here. so this is cleaner and
+// shorter and less complicated.
+static void
+inlnode(Node **np)
+{
+ Node *n;
+ NodeList *l;
+ int lno;
+
+ if(*np == nil)
+ return;
+
+ n = *np;
+
+ switch(n->op) {
+ case ODEFER:
+ case OPROC:
+ // inhibit inlining of their argument
+ switch(n->left->op) {
+ case OCALLFUNC:
+ case OCALLMETH:
+ n->left->etype = n->op;
+ }
+
+ case OCLOSURE:
+ // TODO do them here instead of in lex.c phase 6b, so escape analysis
+ // can avoid more heapmoves.
+ return;
+ }
+
+ lno = setlineno(n);
+
+ inlnodelist(n->ninit);
+ for(l=n->ninit; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2stmt(l->n);
+
+ inlnode(&n->left);
+ if(n->left && n->left->op == OINLCALL)
+ inlconv2expr(&n->left);
+
+ inlnode(&n->right);
+ if(n->right && n->right->op == OINLCALL)
+ inlconv2expr(&n->right);
+
+ inlnodelist(n->list);
+ switch(n->op) {
+ case OBLOCK:
+ for(l=n->list; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2stmt(l->n);
+ break;
+
+ case ORETURN:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ // if we just replaced arg in f(arg()) or return arg with an inlined call
+ // and arg returns multiple values, glue as list
+ if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
+ n->list = inlconv2list(n->list->n);
+ break;
+ }
+
+ // fallthrough
+ default:
+ for(l=n->list; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2expr(&l->n);
+ }
+
+ inlnodelist(n->rlist);
+ switch(n->op) {
+ case OAS2FUNC:
+ if(n->rlist->n->op == OINLCALL) {
+ n->rlist = inlconv2list(n->rlist->n);
+ n->op = OAS2;
+ n->typecheck = 0;
+ typecheck(np, Etop);
+ break;
+ }
+
+ // fallthrough
+ default:
+ for(l=n->rlist; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2expr(&l->n);
+
+ }
+
+ inlnode(&n->ntest);
+ if(n->ntest && n->ntest->op == OINLCALL)
+ inlconv2expr(&n->ntest);
+
+ inlnode(&n->nincr);
+ if(n->nincr && n->nincr->op == OINLCALL)
+ inlconv2stmt(n->nincr);
+
+ inlnodelist(n->nbody);
+ for(l=n->nbody; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2stmt(l->n);
+
+ inlnodelist(n->nelse);
+ for(l=n->nelse; l; l=l->next)
+ if(l->n->op == OINLCALL)
+ inlconv2stmt(l->n);
+
+ // with all the branches out of the way, it is now time to
+ // transmogrify this node itself unless inhibited by the
+ // switch at the top of this function.
+ switch(n->op) {
+ case OCALLFUNC:
+ case OCALLMETH:
+ if (n->etype == OPROC || n->etype == ODEFER)
+ return;
+ }
+
+ switch(n->op) {
+ case OCALLFUNC:
+ if(debug['m']>3)
+ print("%L:call to func %+N\n", n->lineno, n->left);
+ if(n->left->inl) // normal case
+ mkinlcall(np, n->left);
+ else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right && n->left->right->op == ONAME) // methods called as functions
+ if(n->left->sym->def)
+ mkinlcall(np, n->left->sym->def);
+ break;
+
+ case OCALLMETH:
+ if(debug['m']>3)
+ print("%L:call to meth %lN\n", n->lineno, n->left->right);
+ // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
+ if(n->left->type == T)
+ fatal("no function type for [%p] %+N\n", n->left, n->left);
+
+ if(n->left->type->nname == N)
+ fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type);
+
+ mkinlcall(np, n->left->type->nname);
+
+ break;
+ }
+
+ lineno = lno;
+}
+
+static void mkinlcall1(Node **np, Node *fn);
+
+static void
+mkinlcall(Node **np, Node *fn)
+{
+ int save_safemode;
+ Pkg *pkg;
+
+ save_safemode = safemode;
+
+ // imported functions may refer to unsafe as long as the
+ // package was marked safe during import (already checked).
+ pkg = fnpkg(fn);
+ if(pkg != localpkg && pkg != nil)
+ safemode = 0;
+ mkinlcall1(np, fn);
+ safemode = save_safemode;
+}
+// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
+// On return ninit has the parameter assignments, the nbody is the
+// inlined function body and list, rlist contain the input, output
+// parameters.
+static void
+mkinlcall1(Node **np, Node *fn)
+{
+ int i;
+ Node *n, *call, *saveinlfn, *as, *m;
+ NodeList *dcl, *ll, *ninit, *body;
+ Type *t;
+
+ if (fn->inl == nil)
+ return;
+
+ if (fn == curfn || fn->defn == curfn)
+ return;
+
+ if(debug['l']<2)
+ typecheckinl(fn);
+
+ n = *np;
+
+ // Bingo, we have a function node, and it has an inlineable body
+ if(debug['m']>1)
+ print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl);
+ else if(debug['m'])
+ print("%L: inlining call to %N\n", n->lineno, fn);
+
+ if(debug['m']>2)
+ print("%L: Before inlining: %+N\n", n->lineno, n);
+
+ saveinlfn = inlfn;
+ inlfn = fn;
+
+ ninit = n->ninit;
+
+ if (fn->defn) // local function
+ dcl = fn->defn->dcl;
+ else // imported function
+ dcl = fn->dcl;
+
+ inlretvars = nil;
+ i = 0;
+ // Make temp names to use instead of the originals
+ for(ll = dcl; ll; ll=ll->next)
+ if(ll->n->op == ONAME) {
+ ll->n->inlvar = inlvar(ll->n);
+ ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs
+ if (ll->n->class == PPARAMOUT) // we rely on the order being correct here
+ inlretvars = list(inlretvars, ll->n->inlvar);
+ }
+
+ // anonymous return values, synthesize names for use in assignment that replaces return
+ if(inlretvars == nil && fn->type->outtuple > 0)
+ for(t = getoutargx(fn->type)->type; t; t = t->down) {
+ m = retvar(t, i++);
+ ninit = list(ninit, nod(ODCL, m, N));
+ inlretvars = list(inlretvars, m);
+ }
+
+ // assign arguments to the parameters' temp names
+ as = N;
+ if(fn->type->thistuple) {
+ t = getthisx(fn->type)->type;
+ if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
+ fatal("missing inlvar for %N\n", t->nname);
+
+ if(n->left->op == ODOTMETH) {
+ if(!n->left->left)
+ fatal("method call without receiver: %+N", n);
+ if(t == T)
+ fatal("method call unknown receiver type: %+N", n);
+ if(t->nname != N && !isblank(t->nname))
+ as = nod(OAS, t->nname->inlvar, n->left->left);
+ else
+ as = nod(OAS, temp(t->type), n->left->left);
+ } else { // non-method call to method
+ if (!n->list)
+ fatal("non-method call to method without first arg: %+N", n);
+ if(t != T && t->nname != N && !isblank(t->nname))
+ as = nod(OAS, t->nname->inlvar, n->list->n);
+ }
+
+ if(as != N) {
+ typecheck(&as, Etop);
+ ninit = list(ninit, as);
+ }
+ }
+
+ as = nod(OAS2, N, N);
+ if(fn->type->intuple > 1 && n->list && !n->list->next) {
+ // TODO check that n->list->n is a call?
+ // TODO: non-method call to T.meth(f()) where f returns t, args...
+ as->rlist = n->list;
+ for(t = getinargx(fn->type)->type; t; t=t->down) {
+ if(t->nname && !isblank(t->nname)) {
+ if(!t->nname->inlvar)
+ fatal("missing inlvar for %N\n", t->nname);
+ as->list = list(as->list, t->nname->inlvar);
+ } else {
+ as->list = list(as->list, temp(t->type));
+ }
+ }
+ } else {
+ ll = n->list;
+ if(fn->type->thistuple && n->left->op != ODOTMETH) // non method call to method
+ ll=ll->next; // was handled above in if(thistuple)
+
+ for(t = getinargx(fn->type)->type; t && ll; t=t->down) {
+ if(t->nname && !isblank(t->nname)) {
+ if(!t->nname->inlvar)
+ fatal("missing inlvar for %N\n", t->nname);
+ as->list = list(as->list, t->nname->inlvar);
+ as->rlist = list(as->rlist, ll->n);
+ }
+ ll=ll->next;
+ }
+ if(ll || t)
+ fatal("arg count mismatch: %#T vs %,H\n", getinargx(fn->type), n->list);
+ }
+
+ if (as->rlist) {
+ typecheck(&as, Etop);
+ ninit = list(ninit, as);
+ }
+
+ // zero the outparams
+ for(ll = inlretvars; ll; ll=ll->next) {
+ as = nod(OAS, ll->n, N);
+ typecheck(&as, Etop);
+ ninit = list(ninit, as);
+ }
+
+ inlretlabel = newlabel();
+ body = inlsubstlist(fn->inl);
+
+ body = list(body, nod(OGOTO, inlretlabel, N)); // avoid 'not used' when function doesnt have return
+ body = list(body, nod(OLABEL, inlretlabel, N));
+
+ typechecklist(body, Etop);
+
+ call = nod(OINLCALL, N, N);
+ call->ninit = ninit;
+ call->nbody = body;
+ call->rlist = inlretvars;
+ call->type = n->type;
+ call->typecheck = 1;
+
+ setlno(call, n->lineno);
+
+ *np = call;
+
+ inlfn = saveinlfn;
+
+ // transitive inlining
+ // TODO do this pre-expansion on fn->inl directly. requires
+ // either supporting exporting statemetns with complex ninits
+ // or saving inl and making inlinl
+ if(debug['l'] >= 5) {
+ body = fn->inl;
+ fn->inl = nil; // prevent infinite recursion
+ inlnodelist(call->nbody);
+ for(ll=call->nbody; ll; ll=ll->next)
+ if(ll->n->op == OINLCALL)
+ inlconv2stmt(ll->n);
+ fn->inl = body;
+ }
+
+ if(debug['m']>2)
+ print("%L: After inlining %+N\n\n", n->lineno, *np);
+
+}
+
+// Every time we expand a function we generate a new set of tmpnames,
+// PAUTO's in the calling functions, and link them off of the
+// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
+static Node*
+inlvar(Node *var)
+{
+ Node *n;
+
+ if(debug['m']>3)
+ print("inlvar %+N\n", var);
+
+ n = newname(var->sym);
+ n->type = var->type;
+ n->class = PAUTO;
+ n->used = 1;
+ n->curfn = curfn; // the calling function, not the called one
+ curfn->dcl = list(curfn->dcl, n);
+ return n;
+}
+
+// Synthesize a variable to store the inlined function's results in.
+static Node*
+retvar(Type *t, int i)
+{
+ Node *n;
+
+ snprint(namebuf, sizeof(namebuf), ".r%d", i);
+ n = newname(lookup(namebuf));
+ n->type = t->type;
+ n->class = PAUTO;
+ n->used = 1;
+ n->curfn = curfn; // the calling function, not the called one
+ curfn->dcl = list(curfn->dcl, n);
+ return n;
+}
+
+static Node*
+newlabel(void)
+{
+ Node *n;
+ static int label;
+
+ label++;
+ snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label);
+ n = newname(lookup(namebuf));
+ n->etype = 1; // flag 'safe' for escape analysis (no backjumps)
+ return n;
+}
+
+// inlsubst and inlsubstlist recursively copy the body of the saved
+// pristine ->inl body of the function while substituting references
+// to input/output parameters with ones to the tmpnames, and
+// substituting returns with assignments to the output.
+static NodeList*
+inlsubstlist(NodeList *ll)
+{
+ NodeList *l;
+
+ l = nil;
+ for(; ll; ll=ll->next)
+ l = list(l, inlsubst(ll->n));
+ return l;
+}
+
+static Node*
+inlsubst(Node *n)
+{
+ Node *m, *as;
+ NodeList *ll;
+
+ if(n == N)
+ return N;
+
+ switch(n->op) {
+ case ONAME:
+ if(n->inlvar) { // These will be set during inlnode
+ if (debug['m']>2)
+ print ("substituting name %+N -> %+N\n", n, n->inlvar);
+ return n->inlvar;
+ }
+ if (debug['m']>2)
+ print ("not substituting name %+N\n", n);
+ return n;
+
+ case OLITERAL:
+ case OTYPE:
+ return n;
+
+ case ORETURN:
+ // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
+
+// dump("Return before substitution", n);
+ m = nod(OGOTO, inlretlabel, N);
+ m->ninit = inlsubstlist(n->ninit);
+
+ if(inlretvars && n->list) {
+ as = nod(OAS2, N, N);
+ // shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
+ for(ll=inlretvars; ll; ll=ll->next)
+ as->list = list(as->list, ll->n);
+ as->rlist = inlsubstlist(n->list);
+ typecheck(&as, Etop);
+ m->ninit = list(m->ninit, as);
+ }
+
+ typechecklist(m->ninit, Etop);
+ typecheck(&m, Etop);
+// dump("Return after substitution", m);
+ return m;
+ }
+
+
+ m = nod(OXXX, N, N);
+ *m = *n;
+ m->ninit = nil;
+
+ if(n->op == OCLOSURE)
+ fatal("cannot inline function containing closure: %+N", n);
+
+ m->left = inlsubst(n->left);
+ m->right = inlsubst(n->right);
+ m->list = inlsubstlist(n->list);
+ m->rlist = inlsubstlist(n->rlist);
+ m->ninit = concat(m->ninit, inlsubstlist(n->ninit));
+ m->ntest = inlsubst(n->ntest);
+ m->nincr = inlsubst(n->nincr);
+ m->nbody = inlsubstlist(n->nbody);
+ m->nelse = inlsubstlist(n->nelse);
+
+ return m;
+}
+
+// Plaster over linenumbers
+static void
+setlnolist(NodeList *ll, int lno)
+{
+ for(;ll;ll=ll->next)
+ setlno(ll->n, lno);
+}
+
+static void
+setlno(Node *n, int lno)
+{
+ if(!n)
+ return;
+
+ // don't clobber names, unless they're freshly synthesized
+ if(n->op != ONAME || n->lineno == 0)
+ n->lineno = lno;
+
+ setlno(n->left, lno);
+ setlno(n->right, lno);
+ setlnolist(n->list, lno);
+ setlnolist(n->rlist, lno);
+ setlnolist(n->ninit, lno);
+ setlno(n->ntest, lno);
+ setlno(n->nincr, lno);
+ setlnolist(n->nbody, lno);
+ setlnolist(n->nelse, lno);
+}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 29b6d27ff..e71fd3848 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define EXTERN
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "y.tab.h"
#include <ar.h>
@@ -18,6 +19,7 @@ int yyprev;
int yylast;
static void lexinit(void);
+static void lexinit1(void);
static void lexfini(void);
static void yytinit(void);
static int getc(void);
@@ -28,6 +30,61 @@ static void addidir(char*);
static int getlinepragma(void);
static char *goos, *goarch, *goroot;
+// Compiler experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the compiler is built.
+static struct {
+ char *name;
+ int *val;
+} exper[] = {
+// {"rune32", &rune32},
+ {nil, nil},
+};
+
+static void
+addexp(char *s)
+{
+ int i;
+
+ for(i=0; exper[i].name != nil; i++) {
+ if(strcmp(exper[i].name, s) == 0) {
+ *exper[i].val = 1;
+ return;
+ }
+ }
+
+ print("unknown experiment %s\n", s);
+ exits("unknown experiment");
+}
+
+static void
+setexp(void)
+{
+ char *f[20];
+ int i, nf;
+
+ // The makefile #defines GOEXPERIMENT for us.
+ nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
+ for(i=0; i<nf; i++)
+ addexp(f[i]);
+}
+
+char*
+expstring(void)
+{
+ int i;
+ static char buf[512];
+
+ strcpy(buf, "X");
+ for(i=0; exper[i].name != nil; i++)
+ if(*exper[i].val)
+ seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
+ if(strlen(buf) == 1)
+ strcpy(buf, "X,none");
+ buf[1] = ':';
+ return buf;
+}
+
// Our own isdigit, isspace, isalpha, isalnum that take care
// of EOF and other out of range arguments.
static int
@@ -64,7 +121,7 @@ yy_isalnum(int c)
#define isalpha use_yy_isalpha_instead_of_isalpha
#define isalnum use_yy_isalnum_instead_of_isalnum
-#define DBG if(!debug['x']);else print
+#define DBG if(!debug['x']){}else print
enum
{
EOF = -1,
@@ -75,24 +132,48 @@ usage(void)
{
print("gc: usage: %cg [flags] file.go...\n", thechar);
print("flags:\n");
- // -A is allow use of "any" type, for bootstrapping
+ // -A allow use of "any" type, for bootstrapping
+ // -B disable bounds checking
+ // -E print imported declarations
+ // -K warn when lineno is zero
+ // -M print arguments to gmove
+ // -P print peephole diagnostics
+ // -R print optimizer diagnostics
+ // -g print code generation diagnostics
+ // -i print line history
+ // -j print variables to be initialized at runtime
+ // -r print generated helper functions
+ // -s print redundant types in composite literals
+ // -v print more information with -P or -R
+ // -y print declarations in cannedimports (used with -d)
+ // -% print non-static initializers
+ // -+ indicate that the runtime is being compiled
+ print(" -D PATH interpret local imports relative to this import path\n");
print(" -I DIR search for packages in DIR\n");
+ print(" -L show full path in file:line prints\n");
+ print(" -N disable optimizations\n");
+ print(" -S print the assembly language\n");
+ print(" -V print the compiler version\n");
+ print(" -W print the parse tree after typing\n");
print(" -d print declarations\n");
print(" -e no limit on number of errors printed\n");
print(" -f print stack frame structure\n");
print(" -h panic on an error\n");
+ print(" -l disable inlining\n");
+ print(" -m print optimization decisions\n");
print(" -o file specify output file\n");
- print(" -S print the assembly language\n");
- print(" -V print the compiler version\n");
+ print(" -p assumed import path for this code\n");
print(" -u disable package unsafe\n");
- print(" -w print the parse tree after typing\n");
+ print(" -w print type checking details\n");
print(" -x print lex tokens\n");
- exit(0);
+ exits("usage");
}
void
fault(int s)
{
+ USED(s);
+
// If we've already complained about things
// in the program, don't bother complaining
// about the seg fault too; let the user clean up
@@ -106,11 +187,13 @@ int
main(int argc, char *argv[])
{
int i, c;
- NodeList *l;
+ NodeList *l, *batch;
char *p;
-
+
+#ifdef SIGBUS
signal(SIGBUS, fault);
signal(SIGSEGV, fault);
+#endif
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
@@ -127,12 +210,18 @@ main(int argc, char *argv[])
typepkg = mkpkg(strlit("type"));
typepkg->name = "type";
+ weaktypepkg = mkpkg(strlit("weak.type"));
+ weaktypepkg->name = "weak.type";
+ weaktypepkg->prefix = "weak.type"; // not weak%2etype
+
unsafepkg = mkpkg(strlit("unsafe"));
unsafepkg->name = "unsafe";
goroot = getgoroot();
goos = getgoos();
goarch = thestring;
+
+ setexp();
outfile = nil;
ARGBEGIN {
@@ -145,19 +234,37 @@ main(int argc, char *argv[])
case 'o':
outfile = EARGF(usage());
break;
-
- case 'I':
- addidir(EARGF(usage()));
- break;
+ case 'p':
+ myimportpath = EARGF(usage());
+ break;
+
case 'u':
safemode = 1;
break;
+ case 'D':
+ localimport = EARGF(usage());
+ break;
+
+ case 'I':
+ addidir(EARGF(usage()));
+ break;
+
case 'V':
- print("%cg version %s\n", thechar, getgoversion());
- exit(0);
+ p = expstring();
+ if(strcmp(p, "X:none") == 0)
+ p = "";
+ print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
+ exits(0);
} ARGEND
+
+ // enable inlining. for now:
+ // default: inlining on. (debug['l'] == 1)
+ // -l: inlining off (debug['l'] == 0)
+ // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
+ if(debug['l'] <= 1)
+ debug['l'] = 1 - debug['l'];
if(argc < 1)
usage();
@@ -179,23 +286,14 @@ main(int argc, char *argv[])
*p = '/';
}
- fmtinstall('O', Oconv); // node opcodes
- fmtinstall('E', Econv); // etype opcodes
- fmtinstall('J', Jconv); // all the node flags
- fmtinstall('S', Sconv); // sym pointer
- fmtinstall('T', Tconv); // type pointer
- fmtinstall('N', Nconv); // node pointer
- fmtinstall('Z', Zconv); // escaped string
- fmtinstall('L', Lconv); // line number
- fmtinstall('B', Bconv); // big numbers
- fmtinstall('F', Fconv); // big float numbers
-
+ fmtinstallgo();
betypeinit();
if(widthptr == 0)
fatal("betypeinit failed");
lexinit();
typeinit();
+ lexinit1();
yytinit();
blockgen = 1;
@@ -236,24 +334,24 @@ main(int argc, char *argv[])
if(debug['f'])
frame(1);
- // Process top-level declarations in four phases.
+ // Process top-level declarations in phases.
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
- // Phase 3: Type check function bodies.
- // Phase 4: Compile function bodies.
defercheckwidth();
for(l=xtop; l; l=l->next)
if(l->n->op != ODCL && l->n->op != OAS)
typecheck(&l->n, Etop);
+
+ // Phase 2: Variable assignments.
+ // To check interface assignments, depends on phase 1.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCL || l->n->op == OAS)
typecheck(&l->n, Etop);
resumetypecopy();
resumecheckwidth();
+ // Phase 3: Type check function bodies.
for(l=xtop; l; l=l->next) {
if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
curfn = l->n;
@@ -269,6 +367,37 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors)
errorexit();
+ // Phase 4: Inlining
+ if (debug['l'] > 1) {
+ // Typecheck imported function bodies if debug['l'] > 1,
+ // otherwise lazily when used or re-exported.
+ for(l=importlist; l; l=l->next)
+ if (l->n->inl) {
+ saveerrors();
+ typecheckinl(l->n);
+ }
+
+ if(nsavederrors+nerrors)
+ errorexit();
+ }
+
+ if (debug['l']) {
+ // Find functions that can be inlined and clone them before walk expands them.
+ for(l=xtop; l; l=l->next)
+ if(l->n->op == ODCLFUNC)
+ caninl(l->n);
+
+ // Expand inlineable calls in all functions
+ for(l=xtop; l; l=l->next)
+ if(l->n->op == ODCLFUNC)
+ inlcalls(l->n);
+ }
+
+ // Phase 5: escape analysis.
+ if(!debug['N'])
+ escapes(xtop);
+
+ // Phase 6: Compile top level functions.
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
funccompile(l->n, 0);
@@ -276,14 +405,21 @@ main(int argc, char *argv[])
if(nsavederrors+nerrors == 0)
fninit(xtop);
+ // Phase 6b: Compile all closures.
+ // Can generate more closures, so run in batches.
while(closures) {
- l = closures;
+ batch = closures;
closures = nil;
- for(; l; l=l->next) {
+ if(debug['l'])
+ for(l=batch; l; l=l->next)
+ inlcalls(l->n);
+ if(!debug['N'])
+ escapes(batch);
+ for(l=batch; l; l=l->next)
funccompile(l->n, 1);
- }
}
+ // Phase 7: check external declarations.
for(l=externdcl; l; l=l->next)
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
@@ -297,7 +433,7 @@ main(int argc, char *argv[])
errorexit();
flusherrors();
- exit(0);
+ exits(0);
return 0;
}
@@ -308,18 +444,30 @@ saveerrors(void)
nerrors = 0;
}
+/*
+ * macro to portably read/write archive header.
+ * 'cmd' is read/write/Bread/Bwrite, etc.
+ */
+#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
+ || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
+ || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
+ || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
+ || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
+ || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
+ || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
+
static int
arsize(Biobuf *b, char *name)
{
- struct ar_hdr *a;
+ struct ar_hdr a;
- if((a = Brdline(b, '\n')) == nil)
+ if (HEADER_IO(Bread, b, a))
return -1;
- if(Blinelen(b) != sizeof(struct ar_hdr))
- return -1;
- if(strncmp(a->name, name, strlen(name)) != 0)
+
+ if(strncmp(a.name, name, strlen(name)) != 0)
return -1;
- return atoi(a->size);
+
+ return atoi(a.size);
}
static int
@@ -366,15 +514,19 @@ addidir(char* dir)
static int
islocalname(Strlit *name)
{
- if(!windows && name->len >= 1 && name->s[0] == '/')
+ if(name->len >= 1 && name->s[0] == '/')
return 1;
if(windows && name->len >= 3 &&
yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
return 1;
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
return 1;
+ if(name->len == 1 && strncmp(name->s, ".", 1) == 0)
+ return 1;
if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
return 1;
+ if(name->len == 2 && strncmp(name->s, "..", 2) == 0)
+ return 1;
return 0;
}
@@ -400,8 +552,8 @@ findpkg(Strlit *name)
}
// local imports should be canonicalized already.
- // don't want to see "container/../container/vector"
- // as different from "container/vector".
+ // don't want to see "encoding/../encoding/base64"
+ // as different from "encoding/base64".
q = mal(name->len+1);
memmove(q, name->s, name->len);
q[name->len] = '\0';
@@ -430,6 +582,13 @@ findpkg(Strlit *name)
return 0;
}
+static void
+fakeimport(void)
+{
+ importpkg = mkpkg(strlit("fake"));
+ cannedimports("fake.6", "$$\n");
+}
+
void
importfile(Val *f, int line)
{
@@ -438,18 +597,27 @@ importfile(Val *f, int line)
int32 c;
int len;
Strlit *path;
- char *cleanbuf;
+ char *cleanbuf, *prefix;
+
+ USED(line);
// TODO(rsc): don't bother reloading imports more than once?
if(f->ctype != CTSTR) {
yyerror("import statement not a string");
+ fakeimport();
return;
}
- if(strlen(f->u.sval->s) != f->u.sval->len) {
- yyerror("import path contains NUL");
- errorexit();
+ if(f->u.sval->len == 0) {
+ yyerror("import path is empty");
+ fakeimport();
+ return;
+ }
+
+ if(isbadimport(f->u.sval)) {
+ fakeimport();
+ return;
}
// The package name main is no longer reserved,
@@ -461,6 +629,11 @@ importfile(Val *f, int line)
errorexit();
}
+ if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) {
+ yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval);
+ errorexit();
+ }
+
if(strcmp(f->u.sval->s, "unsafe") == 0) {
if(safemode) {
yyerror("cannot import package unsafe");
@@ -473,8 +646,16 @@ importfile(Val *f, int line)
path = f->u.sval;
if(islocalname(path)) {
- cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
- strcpy(cleanbuf, pathname);
+ if(path->s[0] == '/') {
+ yyerror("import path cannot be absolute path");
+ fakeimport();
+ return;
+ }
+ prefix = pathname;
+ if(localimport != nil)
+ prefix = localimport;
+ cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
+ strcpy(cleanbuf, prefix);
strcat(cleanbuf, "/");
strcat(cleanbuf, path->s);
cleanname(cleanbuf);
@@ -482,14 +663,14 @@ importfile(Val *f, int line)
}
if(!findpkg(path)) {
- yyerror("can't find import: %Z", f->u.sval);
+ yyerror("can't find import: \"%Z\"", f->u.sval);
errorexit();
}
importpkg = mkpkg(path);
imp = Bopen(namebuf, OREAD);
if(imp == nil) {
- yyerror("can't open import: %Z: %r", f->u.sval);
+ yyerror("can't open import: \"%Z\": %r", f->u.sval);
errorexit();
}
file = strdup(namebuf);
@@ -509,7 +690,7 @@ importfile(Val *f, int line)
yyerror("import %s: not a go object file", file);
errorexit();
}
- q = smprint("%s %s %s", getgoos(), thestring, getgoversion());
+ q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
if(strcmp(p+10, q) != 0) {
yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
errorexit();
@@ -546,7 +727,7 @@ importfile(Val *f, int line)
continue;
return;
}
- yyerror("no import in: %Z", f->u.sval);
+ yyerror("no import in \"%Z\"", f->u.sval);
unimportfile();
}
@@ -665,7 +846,6 @@ l0:
ep = lexbuf+sizeof lexbuf;
*cp++ = c;
c = c1;
- c1 = 0;
goto casedot;
}
if(c1 == '.') {
@@ -717,6 +897,8 @@ l0:
ncp += ncp;
}
c = getr();
+ if(c == '\r')
+ continue;
if(c == EOF) {
yyerror("eof in string");
break;
@@ -750,7 +932,7 @@ l0:
}
yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
mpmovecfix(yylval.val.u.xval, v);
- yylval.val.ctype = CTINT;
+ yylval.val.ctype = CTRUNE;
DBG("lex: codepoint literal\n");
strcpy(litbuf, "string literal");
return LLITERAL;
@@ -1008,7 +1190,7 @@ lx:
return c;
asop:
- yylval.lint = c; // rathole to hold which asop
+ yylval.i = c; // rathole to hold which asop
DBG("lex: TOKEN ASOP %c\n", c);
return LASOP;
@@ -1056,7 +1238,6 @@ talph:
return s->lexical;
tnum:
- c1 = 0;
cp = lexbuf;
ep = lexbuf+sizeof lexbuf;
if(c != '0') {
@@ -1247,7 +1428,7 @@ static int
getlinepragma(void)
{
int i, c, n;
- char *cp, *ep;
+ char *cp, *ep, *linep;
Hist *h;
for(i=0; i<5; i++) {
@@ -1258,32 +1439,36 @@ getlinepragma(void)
cp = lexbuf;
ep = lexbuf+sizeof(lexbuf)-5;
+ linep = nil;
for(;;) {
c = getr();
- if(c == '\n' || c == EOF)
+ if(c == EOF)
goto out;
+ if(c == '\n')
+ break;
if(c == ' ')
continue;
if(c == ':')
- break;
+ linep = cp;
if(cp < ep)
*cp++ = c;
}
*cp = 0;
+ if(linep == nil || linep >= ep)
+ goto out;
+ *linep++ = '\0';
n = 0;
- for(;;) {
- c = getr();
- if(!yy_isdigit(c))
- break;
- n = n*10 + (c-'0');
+ for(cp=linep; *cp; cp++) {
+ if(*cp < '0' || *cp > '9')
+ goto out;
+ n = n*10 + *cp - '0';
if(n > 1e8) {
yyerror("line number out of range");
errorexit();
}
}
-
- if(c != '\n' || n <= 0)
+ if(n <= 0)
goto out;
// try to avoid allocating file name over and over
@@ -1334,7 +1519,7 @@ yylex(void)
// Track last two tokens returned by yylex.
yyprev = yylast;
yylast = lx;
- return lx;
+ return lx;
}
static int
@@ -1561,7 +1746,6 @@ static struct
"complex128", LNAME, TCOMPLEX128, OXXX,
"bool", LNAME, TBOOL, OXXX,
- "byte", LNAME, TUINT8, OXXX,
"string", LNAME, TSTRING, OXXX,
"any", LNAME, TANY, OXXX,
@@ -1592,11 +1776,12 @@ static struct
"type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX,
- "append", LNAME, Txxx, OAPPEND,
+ "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"complex", LNAME, Txxx, OCOMPLEX,
"copy", LNAME, Txxx, OCOPY,
+ "delete", LNAME, Txxx, ODELETE,
"imag", LNAME, Txxx, OIMAG,
"len", LNAME, Txxx, OLEN,
"make", LNAME, Txxx, OMAKE,
@@ -1621,6 +1806,7 @@ lexinit(void)
Sym *s, *s1;
Type *t;
int etype;
+ Val v;
/*
* initialize basic types array
@@ -1649,6 +1835,16 @@ lexinit(void)
s1->def = typenod(t);
continue;
}
+
+ etype = syms[i].op;
+ if(etype != OXXX) {
+ s1 = pkglookup(syms[i].name, builtinpkg);
+ s1->lexical = LNAME;
+ s1->def = nod(ONAME, N, N);
+ s1->def->sym = s1;
+ s1->def->etype = etype;
+ s1->def->builtin = 1;
+ }
}
// logically, the type of a string literal.
@@ -1676,6 +1872,77 @@ lexinit(void)
types[TBLANK] = typ(TBLANK);
s->def->type = types[TBLANK];
nblank = s->def;
+
+ s = pkglookup("_", builtinpkg);
+ s->block = -100;
+ s->def = nod(ONAME, N, N);
+ s->def->sym = s;
+ types[TBLANK] = typ(TBLANK);
+ s->def->type = types[TBLANK];
+
+ types[TNIL] = typ(TNIL);
+ s = pkglookup("nil", builtinpkg);
+ v.ctype = CTNIL;
+ s->def = nodlit(v);
+ s->def->sym = s;
+}
+
+static void
+lexinit1(void)
+{
+ Sym *s, *s1;
+ Type *t, *f, *rcvr, *in, *out;
+
+ // t = interface { Error() string }
+ rcvr = typ(TSTRUCT);
+ rcvr->type = typ(TFIELD);
+ rcvr->type->type = ptrto(typ(TSTRUCT));
+ rcvr->funarg = 1;
+ in = typ(TSTRUCT);
+ in->funarg = 1;
+ out = typ(TSTRUCT);
+ out->type = typ(TFIELD);
+ out->type->type = types[TSTRING];
+ out->funarg = 1;
+ f = typ(TFUNC);
+ *getthis(f) = rcvr;
+ *getoutarg(f) = out;
+ *getinarg(f) = in;
+ f->thistuple = 1;
+ f->intuple = 0;
+ f->outnamed = 0;
+ f->outtuple = 1;
+ t = typ(TINTER);
+ t->type = typ(TFIELD);
+ t->type->sym = lookup("Error");
+ t->type->type = f;
+
+ // error type
+ s = lookup("error");
+ s->lexical = LNAME;
+ errortype = t;
+ errortype->sym = s;
+ s1 = pkglookup("error", builtinpkg);
+ s1->lexical = LNAME;
+ s1->def = typenod(errortype);
+
+ // byte alias
+ s = lookup("byte");
+ s->lexical = LNAME;
+ bytetype = typ(TUINT8);
+ bytetype->sym = s;
+ s1 = pkglookup("byte", builtinpkg);
+ s1->lexical = LNAME;
+ s1->def = typenod(bytetype);
+
+ // rune alias
+ s = lookup("rune");
+ s->lexical = LNAME;
+ runetype = typ(TINT32);
+ runetype->sym = s;
+ s1 = pkglookup("rune", builtinpkg);
+ s1->lexical = LNAME;
+ s1->def = typenod(runetype);
}
static void
@@ -1713,7 +1980,18 @@ lexfini(void)
// there's only so much table-driven we can handle.
// these are special cases.
- types[TNIL] = typ(TNIL);
+ s = lookup("byte");
+ if(s->def == N)
+ s->def = typenod(bytetype);
+
+ s = lookup("error");
+ if(s->def == N)
+ s->def = typenod(errortype);
+
+ s = lookup("rune");
+ if(s->def == N)
+ s->def = typenod(runetype);
+
s = lookup("nil");
if(s->def == N) {
v.ctype = CTNIL;
@@ -1740,7 +2018,6 @@ lexfini(void)
}
nodfp = nod(ONAME, N, N);
- nodfp->noescape = 1;
nodfp->type = types[TINT32];
nodfp->xoffset = 0;
nodfp->class = PPARAM;
@@ -1923,7 +2200,7 @@ mkpackage(char* pkgname)
// errors if a conflicting top-level name is
// introduced by a different file.
if(!s->def->used && !nsyntaxerrors)
- yyerrorl(s->def->lineno, "imported and not used: %Z", s->def->pkg->path);
+ yyerrorl(s->def->lineno, "imported and not used: \"%Z\"", s->def->pkg->path);
s->def = N;
continue;
}
@@ -1931,7 +2208,7 @@ mkpackage(char* pkgname)
// throw away top-level name left over
// from previous import . "x"
if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
- yyerrorl(s->def->pack->lineno, "imported and not used: %Z", s->def->pack->pkg->path);
+ yyerrorl(s->def->pack->lineno, "imported and not used: \"%Z\"", s->def->pack->pkg->path);
s->def->pack->used = 1;
}
s->def = N;
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
index 7cea1a6cf..5856aab51 100644
--- a/src/cmd/gc/md5.c
+++ b/src/cmd/gc/md5.c
@@ -5,6 +5,8 @@
// 64-bit MD5 (does full MD5 but returns 64 bits only).
// Translation of ../../pkg/crypto/md5/md5*.go.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "md5.h"
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
index cfd6e59c1..2f76e6f06 100755
--- a/src/cmd/gc/mkbuiltin
+++ b/src/cmd/gc/mkbuiltin
@@ -3,29 +3,29 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# Generate builtin.c and builtin.c.boot from $* (runtime.go and unsafe.go).
+# Generate builtin.c from $* (runtime.go and unsafe.go).
# Run this after changing runtime.go and unsafe.go
# or after changing the export metadata format in the compiler.
# Either way, you need to have a working compiler binary first.
set -e
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-if [ -z "$GC" ]; then
- echo 'missing $GC - gomake failed?' 1>&2
+eval $(go tool dist env)
+if [ -z "$GOCHAR" ]; then
+ echo 'missing $GOCHAR - go tool dist failed?' 1>&2
exit 1
fi
-gomake mkbuiltin1
+GC=${GOCHAR}g
+gcc -o mkbuiltin1 mkbuiltin1.c
rm -f _builtin.c
for i in runtime unsafe
do
- $GC -A $i.go
- O=$O ./mkbuiltin1 $i >>_builtin.c
+ go tool $GC -A $i.go
+ O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c
done
-# If _builtin.c has changed vs builtin.c.boot,
+# If _builtin.c has changed vs builtin.c,
# check in the new change.
-cmp -s _builtin.c builtin.c.boot || cp _builtin.c builtin.c.boot
-
-mv _builtin.c builtin.c
+cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c
+rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
index ad83c0346..f8f61c278 100644
--- a/src/cmd/gc/mkbuiltin1.c
+++ b/src/cmd/gc/mkbuiltin1.c
@@ -2,15 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
// Compile .go file, import data from .6 file, and generate C string version.
-#include <u.h>
-#include <libc.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
void esc(char*);
+void fatal(char*, ...);
-void
+int
main(int argc, char **argv)
{
char *name;
@@ -19,7 +25,7 @@ main(int argc, char **argv)
if(argc != 2) {
fprintf(stderr, "usage: mkbuiltin1 sys\n");
- sysfatal("in file $1.6 s/PACKAGE/$1/\n");
+ fatal("in file $1.6 s/PACKAGE/$1/");
}
name = argv[1];
@@ -27,14 +33,14 @@ main(int argc, char **argv)
snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
if((fin = fopen(buf, "r")) == NULL) {
- sysfatal("open %s: %r\n", buf);
+ fatal("open %s: %s", buf, strerror(errno));
}
// look for $$ that introduces imports
while(fgets(buf, sizeof buf, fin) != NULL)
if(strstr(buf, "$$"))
goto begin;
- sysfatal("did not find beginning of imports\n");
+ fatal("did not find beginning of imports");
begin:
printf("char *%simport =\n", name);
@@ -66,11 +72,11 @@ begin:
esc(p);
printf("\\n\"\n");
}
- sysfatal("did not find end of imports\n");
+ fatal("did not find end of imports");
end:
printf("\t\"$$\\n\";\n");
- exits(0);
+ return 0;
}
void
@@ -82,3 +88,15 @@ esc(char *p)
putchar(*p);
}
}
+
+void
+fatal(char *msg, ...)
+{
+ va_list arg;
+
+ va_start(arg, msg);
+ fprintf(stderr, "fatal: ");
+ vfprintf(stderr, msg, arg);
+ fprintf(stderr, "\n");
+ exit(2);
+}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
index fb2ceec81..d3f27e815 100755
--- a/src/cmd/gc/mkopnames
+++ b/src/cmd/gc/mkopnames
@@ -14,8 +14,8 @@ echo '{'
sed -n '/OXXX/,/OEND/p' go.h |
cpp |
sed 's!//.*!!; /^#/d' |
- tr ' ' '\n' |
- tr -d ' \t,' |
+ tr ' ' '\012' |
+ tr -d ' \011,' |
grep . |
sort |
grep -v '^OEND$' |
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index 6cd4e2500..33fa90e2e 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/// uses arithmetic
@@ -70,7 +72,7 @@ void
mpsubfixfix(Mpint *a, Mpint *b)
{
mpnegfix(a);
- mpaddfixfix(a, b);
+ mpaddfixfix(a, b, 0);
mpnegfix(a);
}
@@ -88,7 +90,7 @@ mpaddcfix(Mpint *a, vlong c)
Mpint b;
mpmovecfix(&b, c);
- mpaddfixfix(a, &b);
+ mpaddfixfix(a, &b, 0);
}
void
@@ -300,7 +302,7 @@ mpatoflt(Mpflt *a, char *as)
if(c >= '0' && c <= '9') {
ex = ex*10 + (c-'0');
if(ex > 1e8) {
- yyerror("exponent out of range");
+ yyerror("constant exponent out of range: %s", as);
errorexit();
}
continue;
@@ -341,7 +343,7 @@ out:
return;
bad:
- yyerror("set ovf in mpatof");
+ yyerror("constant too large: %s", as);
mpmovecflt(a, 0.0);
}
@@ -429,7 +431,7 @@ out:
return;
bad:
- yyerror("set ovf in mpatov: %s", as);
+ yyerror("constant too large: %s", as);
mpmovecfix(a, 0);
}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index 403255005..8e52ff216 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
//
@@ -25,10 +27,10 @@ mplen(Mpint *a)
//
// left shift mpint by one
-// ignores sign and overflow
+// ignores sign
//
static void
-mplsh(Mpint *a)
+mplsh(Mpint *a, int quiet)
{
long *a1, x;
int i, c;
@@ -44,19 +46,27 @@ mplsh(Mpint *a)
}
*a1++ = x;
}
+ a->ovf = c;
+ if(a->ovf && !quiet)
+ yyerror("constant shift overflow");
}
//
// left shift mpint by Mpscale
-// ignores sign and overflow
+// ignores sign
//
static void
-mplshw(Mpint *a)
+mplshw(Mpint *a, int quiet)
{
long *a1;
int i;
a1 = &a->a[Mpprec-1];
+ if(*a1) {
+ a->ovf = 1;
+ if(!quiet)
+ yyerror("constant shift overflow");
+ }
for(i=1; i<Mpprec; i++) {
a1[0] = a1[-1];
a1--;
@@ -119,7 +129,8 @@ mpcmp(Mpint *a, Mpint *b)
int i;
if(a->ovf || b->ovf) {
- yyerror("ovf in cmp");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in cmp");
return 0;
}
@@ -165,11 +176,11 @@ mpshiftfix(Mpint *a, int s)
{
if(s >= 0) {
while(s >= Mpscale) {
- mplshw(a);
+ mplshw(a, 0);
s -= Mpscale;
}
while(s > 0) {
- mplsh(a);
+ mplsh(a, 0);
s--;
}
} else {
@@ -188,13 +199,14 @@ mpshiftfix(Mpint *a, int s)
/// implements fix arihmetic
void
-mpaddfixfix(Mpint *a, Mpint *b)
+mpaddfixfix(Mpint *a, Mpint *b, int quiet)
{
int i, c;
long x, *a1, *b1;
if(a->ovf || b->ovf) {
- yyerror("ovf in mpaddxx");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mpaddxx");
a->ovf = 1;
return;
}
@@ -216,8 +228,8 @@ mpaddfixfix(Mpint *a, Mpint *b)
*a1++ = x;
}
a->ovf = c;
- if(a->ovf)
- yyerror("set ovf in mpaddxx");
+ if(a->ovf && !quiet)
+ yyerror("constant addition overflow");
return;
@@ -264,7 +276,8 @@ mpmulfixfix(Mpint *a, Mpint *b)
Mpint s, q;
if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mpmulfixfix");
a->ovf = 1;
return;
}
@@ -288,8 +301,8 @@ mpmulfixfix(Mpint *a, Mpint *b)
x = *a1++;
for(j=0; j<Mpscale; j++) {
if(x & 1)
- mpaddfixfix(&q, &s);
- mplsh(&s);
+ mpaddfixfix(&q, &s, 1);
+ mplsh(&s, 1);
x >>= 1;
}
}
@@ -297,7 +310,7 @@ mpmulfixfix(Mpint *a, Mpint *b)
q.neg = a->neg ^ b->neg;
mpmovefixfix(a, &q);
if(a->ovf)
- yyerror("set ovf in mpmulfixfix");
+ yyerror("constant multiplication overflow");
}
void
@@ -309,7 +322,8 @@ mpmulfract(Mpint *a, Mpint *b)
Mpint s, q;
if(a->ovf || b->ovf) {
- yyerror("ovf in mpmulflt");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mpmulflt");
a->ovf = 1;
return;
}
@@ -332,7 +346,7 @@ mpmulfract(Mpint *a, Mpint *b)
for(j=0; j<Mpscale; j++) {
x <<= 1;
if(x & Mpbase)
- mpaddfixfix(&q, &s);
+ mpaddfixfix(&q, &s, 1);
mprsh(&s);
}
}
@@ -340,7 +354,7 @@ mpmulfract(Mpint *a, Mpint *b)
q.neg = a->neg ^ b->neg;
mpmovefixfix(a, &q);
if(a->ovf)
- yyerror("set ovf in mpmulflt");
+ yyerror("constant multiplication overflow");
}
void
@@ -349,8 +363,10 @@ mporfixfix(Mpint *a, Mpint *b)
int i;
long x, *a1, *b1;
+ x = 0;
if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mporfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -383,8 +399,10 @@ mpandfixfix(Mpint *a, Mpint *b)
int i;
long x, *a1, *b1;
+ x = 0;
if(a->ovf || b->ovf) {
- yyerror("ovf in mpandfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mpandfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -417,8 +435,10 @@ mpandnotfixfix(Mpint *a, Mpint *b)
int i;
long x, *a1, *b1;
+ x = 0;
if(a->ovf || b->ovf) {
- yyerror("ovf in mpandnotfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mpandnotfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -451,8 +471,10 @@ mpxorfixfix(Mpint *a, Mpint *b)
int i;
long x, *a1, *b1;
+ x = 0;
if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mporfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -485,7 +507,8 @@ mplshfixfix(Mpint *a, Mpint *b)
vlong s;
if(a->ovf || b->ovf) {
- yyerror("ovf in mporfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mporfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -506,7 +529,8 @@ mprshfixfix(Mpint *a, Mpint *b)
vlong s;
if(a->ovf || b->ovf) {
- yyerror("ovf in mprshfixfix");
+ if(nsavederrors+nerrors == 0)
+ yyerror("ovf in mprshfixfix");
mpmovecfix(a, 0);
a->ovf = 1;
return;
@@ -536,7 +560,8 @@ mpgetfix(Mpint *a)
vlong v;
if(a->ovf) {
- yyerror("constant overflow");
+ if(nsavederrors+nerrors == 0)
+ yyerror("constant overflow");
return 0;
}
@@ -589,7 +614,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
for(i=0; i<Mpprec*Mpscale; i++) {
if(mpcmp(d, r) > 0)
break;
- mplsh(d);
+ mplsh(d, 1);
}
// if it never happens
@@ -599,7 +624,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
r->ovf = 1;
n->neg = ns;
d->neg = ds;
- yyerror("set ovf in mpdivmodfixfix");
+ yyerror("constant division overflow");
return;
}
@@ -608,7 +633,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
// when done the remaining numerator
// will be the remainder
for(; i>0; i--) {
- mplsh(q);
+ mplsh(q, 1);
mprsh(d);
if(mpcmp(d, r) <= 0) {
mpaddcfix(q, 1);
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index b11a4f5f1..f8344c9b4 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -87,17 +89,17 @@ mpaddfltflt(Mpflt *a, Mpflt *b)
// a is larger, shift b right
mpmovefltflt(&c, b);
mpshiftfix(&c.val, -s);
- mpaddfixfix(&a->val, &c.val);
+ mpaddfixfix(&a->val, &c.val, 0);
goto out;
}
if(s < 0) {
// b is larger, shift a right
mpshiftfix(&a->val, s);
a->exp -= s;
- mpaddfixfix(&a->val, &b->val);
+ mpaddfixfix(&a->val, &b->val, 0);
goto out;
}
- mpaddfixfix(&a->val, &b->val);
+ mpaddfixfix(&a->val, &b->val, 0);
out:
mpnorm(a);
@@ -151,7 +153,7 @@ mpdivfltflt(Mpflt *a, Mpflt *b)
a->exp = 0;
a->val.neg = 0;
a->val.ovf = 1;
- yyerror("mpdivfltflt divide by zero");
+ yyerror("constant division by zero");
return;
}
@@ -183,7 +185,7 @@ mpgetflt(Mpflt *a)
uvlong v, vm;
double f;
- if(a->val.ovf)
+ if(a->val.ovf && nsavederrors+nerrors == 0)
yyerror("mpgetflt ovf");
s = sigfig(a);
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index f99f93bda..e45b4e0d4 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -21,7 +23,7 @@ dumpobj(void)
errorexit();
}
- Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion());
+ Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
Bprint(bout, " exports automatically generated from\n");
Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name);
dumpexport();
@@ -29,10 +31,6 @@ dumpobj(void)
outhist(bout);
- // add nil plist w AEND to catch
- // auto-generated trampolines, data
- newplist();
-
dumpglobls();
dumptypestructs();
dumpdata();
@@ -54,7 +52,7 @@ dumpglobls(void)
continue;
if(n->type == T)
- fatal("external %#N nil type\n", n);
+ fatal("external %N nil type\n", n);
if(n->class == PFUNC)
continue;
if(n->sym->pkg != localpkg)
@@ -128,10 +126,37 @@ outhist(Biobuf *b)
{
Hist *h;
char *p, ds[] = {'c', ':', '/', 0};
+ char *tofree;
+ int n;
+ static int first = 1;
+ static char *goroot, *goroot_final;
+
+ if(first) {
+ // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
+ first = 0;
+ goroot = getenv("GOROOT");
+ goroot_final = getenv("GOROOT_FINAL");
+ if(goroot == nil)
+ goroot = "";
+ if(goroot_final == nil)
+ goroot_final = goroot;
+ if(strcmp(goroot, goroot_final) == 0) {
+ goroot = nil;
+ goroot_final = nil;
+ }
+ }
+ tofree = nil;
for(h = hist; h != H; h = h->link) {
p = h->name;
if(p) {
+ if(goroot != nil) {
+ n = strlen(goroot);
+ if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
+ tofree = smprint("%s%s", goroot_final, p+n);
+ p = tofree;
+ }
+ }
if(windows) {
// if windows variable is set, then, we know already,
// pathname is started with windows drive specifier
@@ -163,9 +188,12 @@ outhist(Biobuf *b)
outzfile(b, p);
}
}
-
}
zhist(b, h->line, h->offset);
+ if(tofree) {
+ free(tofree);
+ tofree = nil;
+ }
}
}
@@ -260,7 +288,7 @@ stringsym(char *s, int len)
tmp.lit.len = len;
memmove(tmp.lit.s, s, len);
tmp.lit.s[len] = '\0';
- snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp);
+ snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
pkg = gostringpkg;
}
sym = pkglookup(namebuf, pkg);
@@ -269,8 +297,8 @@ stringsym(char *s, int len)
if(sym->flags & SymUniq)
return sym;
sym->flags |= SymUniq;
-
- data();
+ sym->def = newname(sym);
+
off = 0;
// string header
@@ -287,7 +315,6 @@ stringsym(char *s, int len)
off = duint8(sym, off, 0); // terminating NUL for runtime
off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
ggloblsym(sym, off, 1);
- text();
-
+
return sym;
}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
new file mode 100644
index 000000000..2cab5fb95
--- /dev/null
+++ b/src/cmd/gc/order.c
@@ -0,0 +1,358 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewrite tree to use separate statements to enforce
+// order of evaluation. Makes walk easier, because it
+// can (after this runs) reorder at will within an expression.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+static void orderstmt(Node*, NodeList**);
+static void orderstmtlist(NodeList*, NodeList**);
+static void orderblock(NodeList **l);
+static void orderexpr(Node**, NodeList**);
+static void orderexprlist(NodeList*, NodeList**);
+
+void
+order(Node *fn)
+{
+ orderblock(&fn->nbody);
+}
+
+static void
+orderstmtlist(NodeList *l, NodeList **out)
+{
+ for(; l; l=l->next)
+ orderstmt(l->n, out);
+}
+
+// Order the block of statements *l onto a new list,
+// and then replace *l with that list.
+static void
+orderblock(NodeList **l)
+{
+ NodeList *out;
+
+ out = nil;
+ orderstmtlist(*l, &out);
+ *l = out;
+}
+
+// Order the side effects in *np and leave them as
+// the init list of the final *np.
+static void
+orderexprinplace(Node **np)
+{
+ Node *n;
+ NodeList *out;
+
+ n = *np;
+ out = nil;
+ orderexpr(&n, &out);
+ addinit(&n, out);
+ *np = n;
+}
+
+// Like orderblock, but applied to a single statement.
+static void
+orderstmtinplace(Node **np)
+{
+ Node *n;
+ NodeList *out;
+
+ n = *np;
+ out = nil;
+ orderstmt(n, &out);
+ *np = liststmt(out);
+}
+
+// Move n's init list to *out.
+static void
+orderinit(Node *n, NodeList **out)
+{
+ orderstmtlist(n->ninit, out);
+ n->ninit = nil;
+}
+
+// Is the list l actually just f() for a multi-value function?
+static int
+ismulticall(NodeList *l)
+{
+ Node *n;
+
+ // one arg only
+ if(l == nil || l->next != nil)
+ return 0;
+ n = l->n;
+
+ // must be call
+ switch(n->op) {
+ default:
+ return 0;
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ break;
+ }
+
+ // call must return multiple values
+ return n->left->type->outtuple > 1;
+}
+
+// n is a multi-value function call. Add t1, t2, .. = n to out
+// and return the list t1, t2, ...
+static NodeList*
+copyret(Node *n, NodeList **out)
+{
+ Type *t;
+ Node *tmp, *as;
+ NodeList *l1, *l2;
+ Iter tl;
+
+ if(n->type->etype != TSTRUCT || !n->type->funarg)
+ fatal("copyret %T %d", n->type, n->left->type->outtuple);
+
+ l1 = nil;
+ l2 = nil;
+ for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
+ tmp = temp(t->type);
+ l1 = list(l1, tmp);
+ l2 = list(l2, tmp);
+ }
+
+ as = nod(OAS2, N, N);
+ as->list = l1;
+ as->rlist = list1(n);
+ typecheck(&as, Etop);
+ orderstmt(as, out);
+
+ return l2;
+}
+
+static void
+ordercallargs(NodeList **l, NodeList **out)
+{
+ if(ismulticall(*l)) {
+ // return f() where f() is multiple values.
+ *l = copyret((*l)->n, out);
+ } else {
+ orderexprlist(*l, out);
+ }
+}
+
+static void
+ordercall(Node *n, NodeList **out)
+{
+ orderexpr(&n->left, out);
+ ordercallargs(&n->list, out);
+}
+
+static void
+orderstmt(Node *n, NodeList **out)
+{
+ int lno;
+ NodeList *l;
+ Node *r;
+
+ if(n == N)
+ return;
+
+ lno = setlineno(n);
+
+ orderinit(n, out);
+
+ switch(n->op) {
+ default:
+ fatal("orderstmt %O", n->op);
+
+ case OAS2:
+ case OAS2DOTTYPE:
+ case OAS2MAPR:
+ case OAS:
+ case OASOP:
+ case OCLOSE:
+ case OCOPY:
+ case ODELETE:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ case ORECOVER:
+ case ORECV:
+ case OSEND:
+ orderexpr(&n->left, out);
+ orderexpr(&n->right, out);
+ orderexprlist(n->list, out);
+ orderexprlist(n->rlist, out);
+ *out = list(*out, n);
+ break;
+
+ case OAS2FUNC:
+ // Special: avoid copy of func call n->rlist->n.
+ orderexprlist(n->list, out);
+ ordercall(n->rlist->n, out);
+ *out = list(*out, n);
+ break;
+
+ case OAS2RECV:
+ // Special: avoid copy of receive.
+ orderexprlist(n->list, out);
+ orderexpr(&n->rlist->n->left, out); // arg to recv
+ *out = list(*out, n);
+ break;
+
+ case OBLOCK:
+ case OEMPTY:
+ // Special: does not save n onto out.
+ orderstmtlist(n->list, out);
+ break;
+
+ case OBREAK:
+ case OCONTINUE:
+ case ODCL:
+ case ODCLCONST:
+ case ODCLTYPE:
+ case OFALL:
+ case_OFALL:
+ case OGOTO:
+ case OLABEL:
+ // Special: n->left is not an expression; save as is.
+ *out = list(*out, n);
+ break;
+
+ case OCALLFUNC:
+ case OCALLINTER:
+ case OCALLMETH:
+ // Special: handle call arguments.
+ ordercall(n, out);
+ *out = list(*out, n);
+ break;
+
+ case ODEFER:
+ case OPROC:
+ // Special: order arguments to inner call but not call itself.
+ ordercall(n->left, out);
+ *out = list(*out, n);
+ break;
+
+ case OFOR:
+ orderexprinplace(&n->ntest);
+ orderstmtinplace(&n->nincr);
+ orderblock(&n->nbody);
+ *out = list(*out, n);
+ break;
+
+ case OIF:
+ orderexprinplace(&n->ntest);
+ orderblock(&n->nbody);
+ orderblock(&n->nelse);
+ *out = list(*out, n);
+ break;
+
+ case ORANGE:
+ orderexpr(&n->right, out);
+ for(l=n->list; l; l=l->next)
+ orderexprinplace(&l->n);
+ orderblock(&n->nbody);
+ *out = list(*out, n);
+ break;
+
+ case ORETURN:
+ ordercallargs(&n->list, out);
+ *out = list(*out, n);
+ break;
+
+ case OSELECT:
+ for(l=n->list; l; l=l->next) {
+ if(l->n->op != OXCASE)
+ fatal("order select case %O", l->n->op);
+ r = l->n->left;
+ if(r == nil)
+ continue;
+ switch(r->op) {
+ case OSELRECV:
+ case OSELRECV2:
+ orderexprinplace(&r->left);
+ orderexprinplace(&r->ntest);
+ orderexpr(&r->right->left, out);
+ break;
+ case OSEND:
+ orderexpr(&r->left, out);
+ orderexpr(&r->right, out);
+ break;
+ }
+ }
+ *out = list(*out, n);
+ break;
+
+ case OSWITCH:
+ orderexpr(&n->ntest, out);
+ for(l=n->list; l; l=l->next) {
+ if(l->n->op != OXCASE)
+ fatal("order switch case %O", l->n->op);
+ orderexpr(&l->n->left, &l->n->ninit);
+ }
+ *out = list(*out, n);
+ break;
+
+ case OXFALL:
+ yyerror("fallthrough statement out of place");
+ n->op = OFALL;
+ goto case_OFALL;
+ }
+
+ lineno = lno;
+}
+
+static void
+orderexprlist(NodeList *l, NodeList **out)
+{
+ for(; l; l=l->next)
+ orderexpr(&l->n, out);
+}
+
+static void
+orderexpr(Node **np, NodeList **out)
+{
+ Node *n;
+ int lno;
+
+ n = *np;
+ if(n == N)
+ return;
+
+ lno = setlineno(n);
+ orderinit(n, out);
+
+ switch(n->op) {
+ default:
+ orderexpr(&n->left, out);
+ orderexpr(&n->right, out);
+ orderexprlist(n->list, out);
+ orderexprlist(n->rlist, out);
+ break;
+
+ case OANDAND:
+ case OOROR:
+ orderexpr(&n->left, out);
+ orderexprinplace(&n->right);
+ break;
+
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ ordercall(n, out);
+ n = copyexpr(n, n->type, out);
+ break;
+
+ case ORECV:
+ n = copyexpr(n, n->type, out);
+ break;
+ }
+
+ lineno = lno;
+
+ *np = n;
+}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index abe8ea892..f2b75d61b 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
-static void compactframe(Prog* p);
+static void allocauto(Prog* p);
void
compile(Node *fn)
@@ -52,14 +54,16 @@ compile(Node *fn)
t = structnext(&save);
}
}
-
+
+ order(curfn);
+ if(nerrors != 0)
+ goto ret;
+
hasdefer = 0;
walk(curfn);
if(nerrors != 0)
goto ret;
- allocparams();
-
continpc = P;
breakpc = P;
@@ -70,6 +74,8 @@ compile(Node *fn)
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+ if(fn->dupok)
+ ptxt->TEXTFLAG = DUPOK;
afunclit(&ptxt->from);
ginit();
@@ -113,9 +119,13 @@ compile(Node *fn)
}
oldstksize = stksize;
- compactframe(ptxt);
+ allocauto(ptxt);
if(0)
- print("compactframe: %ld to %ld\n", oldstksize, stksize);
+ print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
+
+ setlineno(curfn);
+ if((int64)stksize+maxarg > (1ULL<<31))
+ yyerror("stack frame too large (>2GB)");
defframe(ptxt);
@@ -145,13 +155,13 @@ cmpstackvar(Node *a, Node *b)
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
static void
-compactframe(Prog* ptxt)
+allocauto(Prog* ptxt)
{
NodeList *ll;
Node* n;
vlong w;
- if (stksize == 0)
+ if(curfn->dcl == nil)
return;
// Mark the PAUTO's unused.
@@ -188,6 +198,7 @@ compactframe(Prog* ptxt)
if (n->class != PAUTO || n->op != ONAME)
continue;
+ dowidth(n->type);
w = n->type->width;
if(w >= MAXWIDTH || w < 0)
fatal("bad width");
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
deleted file mode 100644
index 5913e848a..000000000
--- a/src/cmd/gc/print.c
+++ /dev/null
@@ -1,480 +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.
-
-#include "go.h"
-
-enum
-{
- PFIXME = 0,
-};
-
-void
-exprlistfmt(Fmt *f, NodeList *l)
-{
- for(; l; l=l->next) {
- exprfmt(f, l->n, 0);
- if(l->next)
- fmtprint(f, ", ");
- }
-}
-
-void
-exprfmt(Fmt *f, Node *n, int prec)
-{
- int nprec;
- char *p;
-
- nprec = 0;
- if(n == nil) {
- fmtprint(f, "<nil>");
- return;
- }
-
- if(n->implicit) {
- exprfmt(f, n->left, prec);
- return;
- }
-
- switch(n->op) {
- case OAPPEND:
- case ONAME:
- case ONONAME:
- case OPACK:
- case OLITERAL:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OXDOT:
- case OARRAYBYTESTR:
- case OCAP:
- case OCLOSE:
- case OCOPY:
- case OLEN:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- case OCALL:
- case OCALLMETH:
- case OCALLINTER:
- case OCALLFUNC:
- case OCONV:
- case OCONVNOP:
- case OMAKESLICE:
- case ORUNESTR:
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- case OCONVIFACE:
- case OTPAREN:
- case OINDEX:
- case OINDEXMAP:
- case OPAREN:
- nprec = 7;
- break;
-
- case OMUL:
- case ODIV:
- case OMOD:
- case OLSH:
- case ORSH:
- case OAND:
- case OANDNOT:
- nprec = 6;
- break;
-
- case OADD:
- case OSUB:
- case OOR:
- case OXOR:
- nprec = 5;
- break;
-
- case OEQ:
- case OLT:
- case OLE:
- case OGE:
- case OGT:
- case ONE:
- nprec = 4;
- break;
-
- case OSEND:
- nprec = 3;
- break;
-
- case OANDAND:
- nprec = 2;
- break;
-
- case OOROR:
- nprec = 1;
- break;
-
- case OTYPE:
- if(n->sym != S)
- nprec = 7;
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, "(");
-
- switch(n->op) {
- default:
- bad:
- fmtprint(f, "(node %O)", n->op);
- break;
-
- case OPAREN:
- fmtprint(f, "(%#N)", n->left);
- break;
-
- case OREGISTER:
- fmtprint(f, "%R", n->val.u.reg);
- break;
-
- case OLITERAL:
- if(n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- switch(n->val.ctype) {
- default:
- goto bad;
- case CTINT:
- fmtprint(f, "%B", n->val.u.xval);
- break;
- case CTBOOL:
- if(n->val.u.bval)
- fmtprint(f, "true");
- else
- fmtprint(f, "false");
- break;
- case CTCPLX:
- fmtprint(f, "%.17g+%.17gi",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTFLT:
- fmtprint(f, "%.17g", mpgetflt(n->val.u.fval));
- break;
- case CTSTR:
- fmtprint(f, "\"%Z\"", n->val.u.sval);
- break;
- case CTNIL:
- fmtprint(f, "nil");
- break;
- }
- break;
-
- case ONAME:
- case OPACK:
- case ONONAME:
- fmtprint(f, "%S", n->sym);
- break;
-
- case OTYPE:
- if(n->type == T && n->sym != S) {
- fmtprint(f, "%S", n->sym);
- break;
- }
- fmtprint(f, "%T", n->type);
- break;
-
- case OTARRAY:
- fmtprint(f, "[]");
- exprfmt(f, n->left, PFIXME);
- break;
-
- case OTPAREN:
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OTMAP:
- fmtprint(f, "map[");
- exprfmt(f, n->left, 0);
- fmtprint(f, "] ");
- exprfmt(f, n->right, 0);
- break;
-
- case OTCHAN:
- if(n->etype == Crecv)
- fmtprint(f, "<-");
- fmtprint(f, "chan");
- if(n->etype == Csend) {
- fmtprint(f, "<- ");
- exprfmt(f, n->left, 0);
- } else {
- fmtprint(f, " ");
- if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
- fmtprint(f, "(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- } else
- exprfmt(f, n->left, 0);
- }
- break;
-
- case OTSTRUCT:
- fmtprint(f, "<struct>");
- break;
-
- case OTINTER:
- fmtprint(f, "<inter>");
- break;
-
- case OTFUNC:
- fmtprint(f, "<func>");
- break;
-
- case OAS:
- exprfmt(f, n->left, 0);
- fmtprint(f, " = ");
- exprfmt(f, n->right, 0);
- break;
-
- case OASOP:
- exprfmt(f, n->left, 0);
- fmtprint(f, " %#O= ", n->etype);
- exprfmt(f, n->right, 0);
- break;
-
- case OAS2:
- case OAS2DOTTYPE:
- case OAS2FUNC:
- case OAS2MAPR:
- case OAS2MAPW:
- case OAS2RECV:
- exprlistfmt(f, n->list);
- fmtprint(f, " = ");
- exprlistfmt(f, n->rlist);
- break;
-
- case OADD:
- case OANDAND:
- case OANDNOT:
- case ODIV:
- case OEQ:
- case OGE:
- case OGT:
- case OLE:
- case OLT:
- case OLSH:
- case OMOD:
- case OMUL:
- case ONE:
- case OOR:
- case OOROR:
- case ORSH:
- case OSEND:
- case OSUB:
- case OXOR:
- exprfmt(f, n->left, nprec);
- fmtprint(f, " %#O ", n->op);
- exprfmt(f, n->right, nprec+1);
- break;
-
- case OADDR:
- case OCOM:
- case OIND:
- case OMINUS:
- case ONOT:
- case OPLUS:
- case ORECV:
- fmtprint(f, "%#O", n->op);
- if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op)
- fmtprint(f, " ");
- exprfmt(f, n->left, 0);
- break;
-
- case OCLOSURE:
- fmtprint(f, "func literal");
- break;
-
- case OCOMPLIT:
- fmtprint(f, "composite literal");
- break;
-
- case OARRAYLIT:
- if(isslice(n->type))
- fmtprint(f, "slice literal");
- else
- fmtprint(f, "array literal");
- break;
-
- case OMAPLIT:
- fmtprint(f, "map literal");
- break;
-
- case OSTRUCTLIT:
- fmtprint(f, "struct literal");
- break;
-
- case OXDOT:
- case ODOT:
- case ODOTPTR:
- case ODOTINTER:
- case ODOTMETH:
- exprfmt(f, n->left, 7);
- if(n->right == N || n->right->sym == S)
- fmtprint(f, ".<nil>");
- else {
- // skip leading type· in method name
- p = utfrrune(n->right->sym->name, 0xb7);
- if(p)
- p+=2;
- else
- p = n->right->sym->name;
- fmtprint(f, ".%s", p);
- }
- break;
-
- case ODOTTYPE:
- case ODOTTYPE2:
- exprfmt(f, n->left, 7);
- fmtprint(f, ".(");
- if(n->right != N)
- exprfmt(f, n->right, 0);
- else
- fmtprint(f, "%T", n->type);
- fmtprint(f, ")");
- break;
-
- case OINDEX:
- case OINDEXMAP:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- exprfmt(f, n->right, 0);
- fmtprint(f, "]");
- break;
-
- case OSLICE:
- case OSLICESTR:
- case OSLICEARR:
- exprfmt(f, n->left, 7);
- fmtprint(f, "[");
- if(n->right->left != N)
- exprfmt(f, n->right->left, 0);
- fmtprint(f, ":");
- if(n->right->right != N)
- exprfmt(f, n->right->right, 0);
- fmtprint(f, "]");
- break;
-
- case OCALL:
- case OCALLFUNC:
- case OCALLINTER:
- case OCALLMETH:
- exprfmt(f, n->left, 7);
- fmtprint(f, "(");
- exprlistfmt(f, n->list);
- if(n->isddd)
- fmtprint(f, "...");
- fmtprint(f, ")");
- break;
-
- case OCOMPLEX:
- fmtprint(f, "complex(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- fmtprint(f, ")");
- break;
-
- case OREAL:
- fmtprint(f, "real(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OIMAG:
- fmtprint(f, "imag(");
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OCONV:
- case OCONVIFACE:
- case OCONVNOP:
- case OARRAYBYTESTR:
- case OSTRARRAYBYTE:
- case ORUNESTR:
- if(n->type == T || n->type->sym == S)
- fmtprint(f, "(%T)(", n->type);
- else
- fmtprint(f, "%T(", n->type);
- if(n->left == N)
- exprlistfmt(f, n->list);
- else
- exprfmt(f, n->left, 0);
- fmtprint(f, ")");
- break;
-
- case OAPPEND:
- case OCAP:
- case OCLOSE:
- case OLEN:
- case OCOPY:
- case OMAKE:
- case ONEW:
- case OPANIC:
- case OPRINT:
- case OPRINTN:
- fmtprint(f, "%#O(", n->op);
- if(n->left)
- exprfmt(f, n->left, 0);
- else
- exprlistfmt(f, n->list);
- fmtprint(f, ")");
- break;
-
- case OMAKESLICE:
- fmtprint(f, "make(%#T, ", n->type);
- exprfmt(f, n->left, 0);
- if(count(n->list) > 2) {
- fmtprint(f, ", ");
- exprfmt(f, n->right, 0);
- }
- fmtprint(f, ")");
- break;
-
- case OMAKEMAP:
- case OMAKECHAN:
- fmtprint(f, "make(%#T)", n->type);
- break;
-
- // Some statements
-
- case ODCL:
- fmtprint(f, "var %S %#T", n->left->sym, n->left->type);
- break;
-
- case ORETURN:
- fmtprint(f, "return ");
- exprlistfmt(f, n->list);
- break;
-
- case OPROC:
- fmtprint(f, "go %#N", n->left);
- break;
-
- case ODEFER:
- fmtprint(f, "defer %#N", n->left);
- break;
- }
-
- if(prec > nprec)
- fmtprint(f, ")");
-}
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index 5ce693ae3..9bcd833a7 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -6,6 +6,8 @@
* range
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
void
@@ -30,7 +32,7 @@ typecheckrange(Node *n)
switch(t->etype) {
default:
- yyerror("cannot range over %+N", n->right);
+ yyerror("cannot range over %lN", n->right);
goto out;
case TARRAY:
@@ -44,6 +46,10 @@ typecheckrange(Node *n)
break;
case TCHAN:
+ if(!(t->chan & Crecv)) {
+ yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type);
+ goto out;
+ }
t1 = t->type;
t2 = nil;
if(count(n->list) == 2)
@@ -52,7 +58,7 @@ typecheckrange(Node *n)
case TSTRING:
t1 = types[TINT];
- t2 = types[TINT];
+ t2 = runetype;
break;
}
@@ -69,12 +75,12 @@ typecheckrange(Node *n)
if(v1->defn == n)
v1->type = t1;
else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
+ yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
if(v2) {
if(v2->defn == n)
v2->type = t2;
else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
- yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
+ yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
}
out:
@@ -111,8 +117,6 @@ walkrange(Node *n)
}
v1 = n->list->n;
- hv1 = N;
-
v2 = N;
if(n->list->next)
v2 = n->list->next->n;
@@ -123,8 +127,7 @@ walkrange(Node *n)
// no need to make a potentially expensive copy.
ha = a;
} else {
- ha = nod(OXXX, N, N);
- tempname(ha, a->type);
+ ha = temp(a->type);
init = list(init, nod(OAS, ha, a));
}
@@ -133,17 +136,14 @@ walkrange(Node *n)
fatal("walkrange");
case TARRAY:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, types[TINT]);
- hn = nod(OXXX, N, N);
- tempname(hn, types[TINT]);
+ hv1 = temp(types[TINT]);
+ hn = temp(types[TINT]);
hp = nil;
init = list(init, nod(OAS, hv1, N));
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
if(v2) {
- hp = nod(OXXX, N, N);
- tempname(hp, ptrto(n->type->type));
+ hp = temp(ptrto(n->type->type));
tmp = nod(OINDEX, ha, nodintconst(0));
tmp->etype = 1; // no bounds check
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
@@ -167,9 +167,10 @@ walkrange(Node *n)
case TMAP:
th = typ(TARRAY);
th->type = ptrto(types[TUINT8]);
- th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr;
- hit = nod(OXXX, N, N);
- tempname(hit, th);
+ // see ../../pkg/runtime/hashmap.h:/hash_iter
+ // Size in words.
+ th->bound = 5 + 4*3 + 4*4/widthptr;
+ hit = temp(th);
fn = syslook("mapiterinit", 1);
argtype(fn, t->down);
@@ -200,10 +201,8 @@ walkrange(Node *n)
break;
case TCHAN:
- hv1 = nod(OXXX, N, n);
- tempname(hv1, t->type);
- hb = nod(OXXX, N, N);
- tempname(hb, types[TBOOL]);
+ hv1 = temp(t->type);
+ hb = temp(types[TBOOL]);
n->ntest = nod(ONE, hb, nodbool(0));
a = nod(OAS2RECV, N, N);
@@ -215,18 +214,15 @@ walkrange(Node *n)
break;
case TSTRING:
- ohv1 = nod(OXXX, N, N);
- tempname(ohv1, types[TINT]);
+ ohv1 = temp(types[TINT]);
- hv1 = nod(OXXX, N, N);
- tempname(hv1, types[TINT]);
+ hv1 = temp(types[TINT]);
init = list(init, nod(OAS, hv1, N));
if(v2 == N)
a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
else {
- hv2 = nod(OXXX, N, N);
- tempname(hv2, types[TINT]);
+ hv2 = temp(runetype);
a = nod(OAS2, N, N);
a->list = list(list1(hv1), hv2);
fn = syslook("stringiter2", 0);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 810787d30..07b426508 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
@@ -11,6 +13,7 @@
static NodeList* signatlist;
static Sym* dtypesym(Type*);
static Sym* weaktypesym(Type*);
+static Sym* dalgsym(Type*);
static int
sigcmp(Sig *a, Sig *b)
@@ -140,13 +143,12 @@ methods(Type *t)
Type *f, *mt, *it, *this;
Sig *a, *b;
Sym *method;
- Prog *oldlist;
- // named method type
- mt = methtype(t);
+ // method type
+ mt = methtype(t, 0);
if(mt == T)
return nil;
- expandmeth(mt->sym, mt);
+ expandmeth(mt);
// type stored in interface word
it = t;
@@ -156,12 +158,14 @@ methods(Type *t)
// make list of methods for t,
// generating code if necessary.
a = nil;
- oldlist = nil;
for(f=mt->xmethod; f; f=f->down) {
- if(f->type->etype != TFUNC)
- continue;
if(f->etype != TFIELD)
- fatal("methods: not field");
+ fatal("methods: not field %T", f);
+ if (f->type->etype != TFUNC || f->type->thistuple == 0)
+ fatal("non-method on %T method %S %T\n", mt, f->sym, f);
+ if (!getthisx(f->type)->type)
+ fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
+
method = f->sym;
if(method == nil)
continue;
@@ -195,8 +199,6 @@ methods(Type *t)
if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen;
if(!eqtype(this, it) || this->width < types[tptr]->width) {
- if(oldlist == nil)
- oldlist = pc;
// Is okay to call genwrapper here always,
// but we can generate more efficient code
// using genembedtramp if all that is necessary
@@ -212,8 +214,6 @@ methods(Type *t)
if(!(a->tsym->flags & SymSiggen)) {
a->tsym->flags |= SymSiggen;
if(!eqtype(this, t)) {
- if(oldlist == nil)
- oldlist = pc;
if(isptr[t->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f->type))
genembedtramp(t, f, a->tsym, 0);
@@ -223,16 +223,6 @@ methods(Type *t)
}
}
- // restore data output
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
return lsort(a, sigcmp);
}
@@ -245,11 +235,9 @@ imethods(Type *t)
Sig *a, *all, *last;
Type *f;
Sym *method, *isym;
- Prog *oldlist;
all = nil;
last = nil;
- oldlist = nil;
for(f=t->type; f; f=f->down) {
if(f->etype != TFIELD)
fatal("imethods: not field");
@@ -287,21 +275,9 @@ imethods(Type *t)
isym = methodsym(method, t, 0);
if(!(isym->flags & SymSiggen)) {
isym->flags |= SymSiggen;
- if(oldlist == nil)
- oldlist = pc;
genwrapper(t, f, isym, 0);
}
}
-
- if(oldlist) {
- // old list ended with AEND; change to ANOP
- // so that the trampolines that follow can be found.
- nopout(oldlist);
-
- // start new data list
- newplist();
- }
-
return all;
}
@@ -381,7 +357,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
s = sym;
if(t->sym) {
ot = dgostringptr(s, ot, t->sym->name);
- if(t != types[t->etype])
+ if(t != types[t->etype] && t != errortype)
ot = dgopkgpath(s, ot, t->sym->pkg);
else
ot = dgostringptr(s, ot, nil);
@@ -478,57 +454,20 @@ kinds[] =
[TUNSAFEPTR] = KindUnsafePointer,
};
-static char*
-structnames[] =
-{
- [TINT] = "*runtime.IntType",
- [TUINT] = "*runtime.UintType",
- [TINT8] = "*runtime.IntType",
- [TUINT8] = "*runtime.UintType",
- [TINT16] = "*runtime.IntType",
- [TUINT16] = "*runtime.UintType",
- [TINT32] = "*runtime.IntType",
- [TUINT32] = "*runtime.UintType",
- [TINT64] = "*runtime.IntType",
- [TUINT64] = "*runtime.UintType",
- [TUINTPTR] = "*runtime.UintType",
- [TCOMPLEX64] = "*runtime.ComplexType",
- [TCOMPLEX128] = "*runtime.ComplexType",
- [TFLOAT32] = "*runtime.FloatType",
- [TFLOAT64] = "*runtime.FloatType",
- [TBOOL] = "*runtime.BoolType",
- [TSTRING] = "*runtime.StringType",
- [TUNSAFEPTR] = "*runtime.UnsafePointerType",
-
- [TPTR32] = "*runtime.PtrType",
- [TPTR64] = "*runtime.PtrType",
- [TSTRUCT] = "*runtime.StructType",
- [TINTER] = "*runtime.InterfaceType",
- [TCHAN] = "*runtime.ChanType",
- [TMAP] = "*runtime.MapType",
- [TARRAY] = "*runtime.ArrayType",
- [TFUNC] = "*runtime.FuncType",
-};
-
static Sym*
typestruct(Type *t)
{
- char *name;
- int et;
-
- et = t->etype;
- if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) {
- fatal("typestruct %lT", t);
- return nil; // silence gcc
- }
-
- if(isslice(t))
- name = "*runtime.SliceType";
-
- return pkglookup(name, typepkg);
+ // We use a weak reference to the reflect type
+ // to avoid requiring package reflect in every binary.
+ // If package reflect is available, the interface{} holding
+ // a runtime type will contain a *reflect.commonType.
+ // Otherwise it will use a nil type word but still be usable
+ // by package runtime (because we always use the memory
+ // after the interface value, not the interface value itself).
+ return pkglookup("*reflect.commonType", weaktypepkg);
}
-static int
+int
haspointers(Type *t)
{
Type *t1;
@@ -578,13 +517,20 @@ haspointers(Type *t)
static int
dcommontype(Sym *s, int ot, Type *t)
{
- int i;
- Sym *sptr;
+ int i, alg, sizeofAlg;
+ Sym *sptr, *algsym;
+ static Sym *algarray;
char *p;
+ sizeofAlg = 4*widthptr;
+ if(algarray == nil)
+ algarray = pkglookup("algarray", runtimepkg);
+ alg = algtype(t);
+ algsym = S;
+ if(alg < 0)
+ algsym = dalgsym(t);
+
dowidth(t);
-
- sptr = nil;
if(t->sym != nil && !isptr[t->etype])
sptr = dtypesym(ptrto(t));
else
@@ -597,7 +543,7 @@ dcommontype(Sym *s, int ot, Type *t)
ot = dsymptr(s, ot, typestruct(t), 0);
ot = dsymptr(s, ot, s, 2*widthptr);
- // ../../pkg/runtime/type.go:/commonType
+ // ../../pkg/reflect/type.go:/^type.commonType
// actual type structure
// type commonType struct {
// size uintptr;
@@ -612,7 +558,7 @@ dcommontype(Sym *s, int ot, Type *t)
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
- ot = duint8(s, ot, algtype(t));
+ ot = duint8(s, ot, 0); // unused
ot = duint8(s, ot, t->align); // align
ot = duint8(s, ot, t->align); // fieldAlign
i = kinds[t->etype];
@@ -621,9 +567,12 @@ dcommontype(Sym *s, int ot, Type *t)
if(!haspointers(t))
i |= KindNoPointers;
ot = duint8(s, ot, i); // kind
- longsymnames = 1;
- p = smprint("%-T", t);
- longsymnames = 0;
+ if(alg >= 0)
+ ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
+ else
+ ot = dsymptr(s, ot, algsym, 0);
+ p = smprint("%-uT", t);
+ //print("dcommontype: %s\n", p);
ot = dgostringptr(s, ot, p); // string
free(p);
@@ -643,8 +592,22 @@ typesym(Type *t)
char *p;
Sym *s;
- p = smprint("%#-T", t);
+ p = smprint("%-T", t);
s = pkglookup(p, typepkg);
+ //print("typesym: %s -> %+S\n", p, s);
+ free(p);
+ return s;
+}
+
+Sym*
+typesymprefix(char *prefix, Type *t)
+{
+ char *p;
+ Sym *s;
+
+ p = smprint("%s.%-T", prefix, t);
+ s = pkglookup(p, typepkg);
+ //print("algsym: %s -> %+S\n", p, s);
free(p);
return s;
}
@@ -683,16 +646,10 @@ weaktypesym(Type *t)
{
char *p;
Sym *s;
- static Pkg *weak;
-
- if(weak == nil) {
- weak = mkpkg(strlit("weak.type"));
- weak->name = "weak.type";
- weak->prefix = "weak.type"; // not weak%2etype
- }
-
- p = smprint("%#-T", t);
- s = pkglookup(p, weak);
+
+ p = smprint("%-T", t);
+ s = pkglookup(p, weaktypepkg);
+ //print("weaktypesym: %s -> %+S\n", p, s);
free(p);
return s;
}
@@ -721,8 +678,13 @@ dtypesym(Type *t)
tbase = t->type;
dupok = tbase->sym == S;
- if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc
+ if(compiling_runtime &&
+ (tbase == types[tbase->etype] ||
+ tbase == bytetype ||
+ tbase == runetype ||
+ tbase == errortype)) { // int, float, etc
goto ok;
+ }
// named types from other files are defined only by those files
if(tbase->sym && !tbase->local)
@@ -931,9 +893,56 @@ dumptypestructs(void)
dtypesym(ptrto(types[i]));
dtypesym(ptrto(types[TSTRING]));
dtypesym(ptrto(types[TUNSAFEPTR]));
+
+ // emit type structs for error and func(error) string.
+ // The latter is the type of an auto-generated wrapper.
+ dtypesym(ptrto(errortype));
+ dtypesym(functype(nil,
+ list1(nod(ODCLFIELD, N, typenod(errortype))),
+ list1(nod(ODCLFIELD, N, typenod(types[TSTRING])))));
// add paths for runtime and main, which 6l imports implicitly.
dimportpath(runtimepkg);
dimportpath(mkpkg(strlit("main")));
}
}
+
+static Sym*
+dalgsym(Type *t)
+{
+ int ot;
+ Sym *s, *hash, *eq;
+ char buf[100];
+
+ // dalgsym is only called for a type that needs an algorithm table,
+ // which implies that the type is comparable (or else it would use ANOEQ).
+
+ s = typesymprefix(".alg", t);
+ hash = typesymprefix(".hash", t);
+ genhash(hash, t);
+ eq = typesymprefix(".eq", t);
+ geneq(eq, t);
+
+ // ../../pkg/runtime/runtime.h:/Alg
+ ot = 0;
+ ot = dsymptr(s, ot, hash, 0);
+ ot = dsymptr(s, ot, eq, 0);
+ ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0);
+ switch(t->width) {
+ default:
+ ot = dsymptr(s, ot, pkglookup("memcopy", runtimepkg), 0);
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ snprint(buf, sizeof buf, "memcopy%d", (int)t->width*8);
+ ot = dsymptr(s, ot, pkglookup(buf, runtimepkg), 0);
+ break;
+ }
+
+ ggloblsym(s, ot, 1);
+ return s;
+}
+
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 549f7abe3..15a61d9ef 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -3,14 +3,16 @@
// license that can be found in the LICENSE file.
// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
+// to update builtin.c. This is not done automatically
// to avoid depending on having a working compiler binary.
+// +build ignore
+
package PACKAGE
// emitted by compiler, not referred to by go programs
-func new(int32) *any
+func new(typ *byte) *any
func panicindex()
func panicslice()
func throwreturn()
@@ -40,18 +42,19 @@ func concatstring()
// filled in by compiler: Type*, int n, Slice, ...
func append()
func appendslice(typ *byte, x any, y []any) any
+func appendstr(typ *byte, x []byte, y string) []byte
func cmpstring(string, string) int
func slicestring(string, int, int) string
func slicestring1(string, int) string
func intstring(int64) string
func slicebytetostring([]byte) string
-func sliceinttostring([]int) string
+func slicerunetostring([]rune) string
func stringtoslicebyte(string) []byte
-func stringtosliceint(string) []int
+func stringtoslicerune(string) []rune
func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv int)
-func slicecopy(to any, fr any, wid uint32) int
+func stringiter2(string, int) (retk int, retv rune)
+func copy(to any, fr any, wid uint32) int
func slicestringcopy(to any, fr any) int
// interface conversions
@@ -79,6 +82,8 @@ func efaceeq(i1 any, i2 any) (ret bool)
func ifacethash(i1 any) (ret uint32)
func efacethash(i1 any) (ret uint32)
+func equal(typ *byte, x1, x2 any) (ret bool)
+
// *byte is really *runtime.Type
func makemap(mapType *byte, hint int64) (hmap map[any]any)
func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any)
@@ -86,6 +91,7 @@ func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)
func mapassign1(mapType *byte, hmap map[any]any, key any, val any)
func mapassign2(mapType *byte, hmap map[any]any, key any, val any, pres bool)
func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
+func mapdelete(mapType *byte, hmap map[any]any, key any)
func mapiternext(hiter *any)
func mapiter1(hiter *any) (key any)
func mapiter2(hiter *any) (key any, val any)
@@ -117,6 +123,13 @@ func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary [
func closure() // has args, but compiler fills in
+func memequal(eq *bool, size uintptr, x, y *any)
+func memequal8(eq *bool, size uintptr, x, y *any)
+func memequal16(eq *bool, size uintptr, x, y *any)
+func memequal32(eq *bool, size uintptr, x, y *any)
+func memequal64(eq *bool, size uintptr, x, y *any)
+func memequal128(eq *bool, size uintptr, x, y *any)
+
// only used on 32-bit
func int64div(int64, int64) int64
func uint64div(uint64, uint64) uint64
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 909ad3aa4..8ace1d4ee 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -6,6 +6,8 @@
* select
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
void
@@ -59,7 +61,7 @@ typecheckselect(Node *sel)
break;
case OAS2RECV:
- // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
+ // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
if(n->right->op != ORECV) {
yyerror("select assignment must have receive on right hand side");
break;
@@ -73,6 +75,7 @@ typecheckselect(Node *sel)
case ORECV:
// convert <-c into OSELRECV(N, <-c)
n = nod(OSELRECV, N, n);
+ n->typecheck = 1;
ncase->left = n;
break;
@@ -191,8 +194,7 @@ walkselect(Node *sel)
n->ntest->etype = 1; // pointer does not escape
typecheck(&n->ntest, Erv);
} else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, types[TBOOL]);
+ tmp = temp(types[TBOOL]);
a = nod(OADDR, tmp, N);
a->etype = 1; // pointer does not escape
typecheck(&a, Erv);
@@ -212,8 +214,7 @@ walkselect(Node *sel)
n->left->etype = 1; // pointer does not escape
typecheck(&n->left, Erv);
} else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, ch->type->type);
+ tmp = temp(ch->type->type);
a = nod(OADDR, tmp, N);
a->etype = 1; // pointer does not escape
typecheck(&a, Erv);
@@ -284,8 +285,7 @@ walkselect(Node *sel)
// generate sel-struct
setlineno(sel);
- var = nod(OXXX, N, N);
- tempname(var, ptrto(types[TUINT8]));
+ var = temp(ptrto(types[TUINT8]));
r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
typecheck(&r, Etop);
init = list(init, r);
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 917e2ae6d..c8796f8b7 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -6,11 +6,24 @@
* static initialization
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
+enum
+{
+ InitNotStarted = 0,
+ InitDone = 1,
+ InitPending = 2,
+};
+
+static int iszero(Node*);
+static void initplan(Node*);
static NodeList *initlist;
static void init2(Node*, NodeList**);
static void init2list(NodeList*, NodeList**);
+static int staticinit(Node*, NodeList**);
+static Node *staticname(Type*, int);
static void
init1(Node *n, NodeList **out)
@@ -31,16 +44,16 @@ init1(Node *n, NodeList **out)
case PFUNC:
break;
default:
- if(isblank(n) && n->defn != N && !n->defn->initorder) {
- n->defn->initorder = 1;
+ if(isblank(n) && n->defn != N && n->defn->initorder == InitNotStarted) {
+ n->defn->initorder = InitDone;
*out = list(*out, n->defn);
}
return;
}
- if(n->initorder == 1)
+ if(n->initorder == InitDone)
return;
- if(n->initorder == 2) {
+ if(n->initorder == InitPending) {
if(n->class == PFUNC)
return;
@@ -52,7 +65,7 @@ init1(Node *n, NodeList **out)
if(nerrors > 0)
errorexit();
- print("initialization loop:\n");
+ print("%L: initialization loop:\n", n->lineno);
for(l=initlist;; l=l->next) {
if(l->next == nil)
break;
@@ -63,7 +76,7 @@ init1(Node *n, NodeList **out)
print("\t%L %S\n", n->lineno, n->sym);
errorexit();
}
- n->initorder = 2;
+ n->initorder = InitPending;
l = malloc(sizeof *l);
l->next = initlist;
l->n = n;
@@ -84,20 +97,38 @@ init1(Node *n, NodeList **out)
case OAS:
if(n->defn->left != n)
goto bad;
+ /*
n->defn->dodata = 1;
init1(n->defn->right, out);
if(debug['j'])
print("%S\n", n->sym);
*out = list(*out, n->defn);
break;
+ */
+ if(1) {
+ init2(n->defn->right, out);
+ if(debug['j'])
+ print("%S\n", n->sym);
+ if(!staticinit(n, out)) {
+if(debug['%']) dump("nonstatic", n->defn);
+ *out = list(*out, n->defn);
+ }
+ } else if(0) {
+ n->defn->dodata = 1;
+ init1(n->defn->right, out);
+ if(debug['j'])
+ print("%S\n", n->sym);
+ *out = list(*out, n->defn);
+ }
+ break;
case OAS2FUNC:
case OAS2MAPR:
case OAS2DOTTYPE:
case OAS2RECV:
- if(n->defn->initorder)
+ if(n->defn->initorder != InitNotStarted)
break;
- n->defn->initorder = 1;
+ n->defn->initorder = InitDone;
for(l=n->defn->rlist; l; l=l->next)
init1(l->n, out);
*out = list(*out, n->defn);
@@ -109,7 +140,7 @@ init1(Node *n, NodeList **out)
if(l->n != n)
fatal("bad initlist");
free(l);
- n->initorder = 1;
+ n->initorder = InitDone;
return;
bad:
@@ -121,8 +152,12 @@ bad:
static void
init2(Node *n, NodeList **out)
{
- if(n == N || n->initorder == 1)
+ if(n == N || n->initorder == InitDone)
return;
+
+ if(n->op == ONAME && n->ninit)
+ fatal("name %S with ninit: %+N\n", n->sym, n);
+
init1(n, out);
init2(n->left, out);
init2(n->right, out);
@@ -141,7 +176,6 @@ init2list(NodeList *l, NodeList **out)
init2(l->n, out);
}
-
static void
initreorder(NodeList *l, NodeList **out)
{
@@ -165,13 +199,235 @@ NodeList*
initfix(NodeList *l)
{
NodeList *lout;
+ int lno;
lout = nil;
+ lno = lineno;
initreorder(l, &lout);
+ lineno = lno;
return lout;
}
/*
+ * compilation of top-level (static) assignments
+ * into DATA statements if at all possible.
+ */
+
+static int staticassign(Node*, Node*, NodeList**);
+
+static int
+staticinit(Node *n, NodeList **out)
+{
+ Node *l, *r;
+
+ if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS)
+ fatal("staticinit");
+
+ lineno = n->lineno;
+ l = n->defn->left;
+ r = n->defn->right;
+ return staticassign(l, r, out);
+}
+
+// like staticassign but we are copying an already
+// initialized value r.
+static int
+staticcopy(Node *l, Node *r, NodeList **out)
+{
+ int i;
+ InitEntry *e;
+ InitPlan *p;
+ Node *a, *ll, *rr, *orig, n1;
+
+ if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
+ return 0;
+ if(r->defn == N) // zeroed
+ return 1;
+ if(r->defn->op != OAS)
+ return 0;
+ orig = r;
+ r = r->defn->right;
+
+ switch(r->op) {
+ case ONAME:
+ if(staticcopy(l, r, out))
+ return 1;
+ *out = list(*out, nod(OAS, l, r));
+ return 1;
+
+ case OLITERAL:
+ if(iszero(r))
+ return 1;
+ gdata(l, r, l->type->width);
+ return 1;
+
+ case OADDR:
+ switch(r->left->op) {
+ case ONAME:
+ gdata(l, r, l->type->width);
+ return 1;
+ }
+ break;
+
+ case OPTRLIT:
+ switch(r->left->op) {
+ default:
+ //dump("not static addr", r);
+ break;
+ case OARRAYLIT:
+ case OSTRUCTLIT:
+ case OMAPLIT:
+ // copy pointer
+ gdata(l, nod(OADDR, r->nname, N), l->type->width);
+ return 1;
+ }
+ break;
+
+ case OARRAYLIT:
+ if(isslice(r->type)) {
+ // copy slice
+ a = r->nname;
+ n1 = *l;
+ n1.xoffset = l->xoffset + Array_array;
+ gdata(&n1, nod(OADDR, a, N), widthptr);
+ n1.xoffset = l->xoffset + Array_nel;
+ gdata(&n1, r->right, 4);
+ n1.xoffset = l->xoffset + Array_cap;
+ gdata(&n1, r->right, 4);
+ return 1;
+ }
+ // fall through
+ case OSTRUCTLIT:
+ p = r->initplan;
+ n1 = *l;
+ for(i=0; i<p->len; i++) {
+ e = &p->e[i];
+ n1.xoffset = l->xoffset + e->xoffset;
+ n1.type = e->expr->type;
+ if(e->expr->op == OLITERAL)
+ gdata(&n1, e->expr, n1.type->width);
+ else {
+ ll = nod(OXXX, N, N);
+ *ll = n1;
+ if(!staticassign(ll, e->expr, out)) {
+ // Requires computation, but we're
+ // copying someone else's computation.
+ rr = nod(OXXX, N, N);
+ *rr = *orig;
+ rr->type = ll->type;
+ rr->xoffset += e->xoffset;
+ *out = list(*out, nod(OAS, ll, rr));
+ }
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int
+staticassign(Node *l, Node *r, NodeList **out)
+{
+ Node *a, n1;
+ Type *ta;
+ InitPlan *p;
+ InitEntry *e;
+ int i;
+
+ switch(r->op) {
+ default:
+ //dump("not static", r);
+ break;
+
+ case ONAME:
+ if(r->class == PEXTERN && r->sym->pkg == localpkg)
+ return staticcopy(l, r, out);
+ break;
+
+ case OLITERAL:
+ if(iszero(r))
+ return 1;
+ gdata(l, r, l->type->width);
+ return 1;
+
+ case OADDR:
+ switch(r->left->op) {
+ default:
+ //dump("not static addr", r);
+ break;
+
+ case ONAME:
+ gdata(l, r, l->type->width);
+ return 1;
+ }
+
+ case OPTRLIT:
+ switch(r->left->op) {
+ default:
+ //dump("not static ptrlit", r);
+ break;
+
+ case OARRAYLIT:
+ case OMAPLIT:
+ case OSTRUCTLIT:
+ // Init pointer.
+ a = staticname(r->left->type, 1);
+ r->nname = a;
+ gdata(l, nod(OADDR, a, N), l->type->width);
+ // Init underlying literal.
+ if(!staticassign(a, r->left, out))
+ *out = list(*out, nod(OAS, a, r->left));
+ return 1;
+ }
+ break;
+
+ case OARRAYLIT:
+ initplan(r);
+ if(isslice(r->type)) {
+ // Init slice.
+ ta = typ(TARRAY);
+ ta->type = r->type->type;
+ ta->bound = mpgetfix(r->right->val.u.xval);
+ a = staticname(ta, 1);
+ r->nname = a;
+ n1 = *l;
+ n1.xoffset = l->xoffset + Array_array;
+ gdata(&n1, nod(OADDR, a, N), widthptr);
+ n1.xoffset = l->xoffset + Array_nel;
+ gdata(&n1, r->right, 4);
+ n1.xoffset = l->xoffset + Array_cap;
+ gdata(&n1, r->right, 4);
+ // Fall through to init underlying array.
+ l = a;
+ }
+ // fall through
+ case OSTRUCTLIT:
+ initplan(r);
+ p = r->initplan;
+ n1 = *l;
+ for(i=0; i<p->len; i++) {
+ e = &p->e[i];
+ n1.xoffset = l->xoffset + e->xoffset;
+ n1.type = e->expr->type;
+ if(e->expr->op == OLITERAL)
+ gdata(&n1, e->expr, n1.type->width);
+ else {
+ a = nod(OXXX, N, N);
+ *a = n1;
+ if(!staticassign(a, e->expr, out))
+ *out = list(*out, nod(OAS, a, e->expr));
+ }
+ }
+ return 1;
+
+ case OMAPLIT:
+ // TODO: Table-driven map insert.
+ break;
+ }
+ return 0;
+}
+
+/*
* from here down is the walk analysis
* of composite literals.
* most of the work is to generate
@@ -408,7 +664,6 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
dowidth(t);
if(ctxt != 0) {
-
// put everything into static array
vstat = staticname(t, ctxt);
arraylit(ctxt, 1, n, vstat, init);
@@ -452,12 +707,18 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
}
// make new auto *array (3 declare)
- vauto = nod(OXXX, N, N);
- tempname(vauto, ptrto(t));
+ vauto = temp(ptrto(t));
- // set auto to point at new heap (3 assign)
- a = nod(ONEW, N, N);
- a->list = list1(typenod(t));
+ // set auto to point at new temp or heap (3 assign)
+ if(n->esc == EscNone) {
+ a = nod(OAS, temp(t), N);
+ typecheck(&a, Etop);
+ *init = list(*init, a); // zero new temp
+ a = nod(OADDR, a->left, N);
+ } else {
+ a = nod(ONEW, N, N);
+ a->list = list1(typenod(t));
+ }
a = nod(OAS, vauto, a);
typecheck(&a, Etop);
walkexpr(&a, init);
@@ -522,6 +783,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
Node *vstat, *index, *value;
Sym *syma, *symb;
+USED(ctxt);
ctxt = 0;
// make the map var
@@ -545,7 +807,6 @@ ctxt = 0;
b++;
}
- t = T;
if(b != 0) {
// build type [count]struct { a Tindex, b Tvalue }
t = n->type;
@@ -615,8 +876,7 @@ ctxt = 0;
// for i = 0; i < len(vstat); i++ {
// map[vstat[i].a] = vstat[i].b
// }
- index = nod(OXXX, N, N);
- tempname(index, types[TINT]);
+ index = temp(types[TINT]);
a = nod(OINDEX, vstat, index);
a->etype = 1; // no bounds checking
@@ -677,6 +937,19 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
default:
fatal("anylit: not lit");
+ case OPTRLIT:
+ if(!isptr[t->etype])
+ fatal("anylit: not ptr");
+
+ a = nod(OAS, var, callnew(t->type));
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+
+ var = nod(OIND, var, N);
+ typecheck(&var, Erv | Easgn);
+ anylit(ctxt, n->left, var, init);
+ break;
+
case OSTRUCTLIT:
if(t->etype != TSTRUCT)
fatal("anylit: not struct");
@@ -917,18 +1190,15 @@ gen_as_init(Node *n)
case TPTR64:
case TFLOAT32:
case TFLOAT64:
- gused(N); // in case the data is the dest of a goto
gdata(&nam, nr, nr->type->width);
break;
case TCOMPLEX64:
case TCOMPLEX128:
- gused(N); // in case the data is the dest of a goto
gdatacomplex(&nam, nr->val.u.cval);
break;
case TSTRING:
- gused(N); // in case the data is the dest of a goto
gdatastring(&nam, nr->val.u.sval);
break;
}
@@ -969,3 +1239,152 @@ no:
return 0;
}
+static int iszero(Node*);
+static int isvaluelit(Node*);
+static InitEntry* entry(InitPlan*);
+static void addvalue(InitPlan*, vlong, Node*, Node*);
+
+static void
+initplan(Node *n)
+{
+ InitPlan *p;
+ Node *a;
+ NodeList *l;
+
+ if(n->initplan != nil)
+ return;
+ p = mal(sizeof *p);
+ n->initplan = p;
+ switch(n->op) {
+ default:
+ fatal("initplan");
+ case OARRAYLIT:
+ for(l=n->list; l; l=l->next) {
+ a = l->n;
+ if(a->op != OKEY || !smallintconst(a->left))
+ fatal("initplan arraylit");
+ addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right);
+ }
+ break;
+ case OSTRUCTLIT:
+ for(l=n->list; l; l=l->next) {
+ a = l->n;
+ if(a->op != OKEY || a->left->type == T)
+ fatal("initplan structlit");
+ addvalue(p, a->left->type->width, N, a->right);
+ }
+ break;
+ case OMAPLIT:
+ for(l=n->list; l; l=l->next) {
+ a = l->n;
+ if(a->op != OKEY)
+ fatal("initplan maplit");
+ addvalue(p, -1, a->left, a->right);
+ }
+ break;
+ }
+}
+
+static void
+addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
+{
+ int i;
+ InitPlan *q;
+ InitEntry *e;
+
+ USED(key);
+
+ // special case: zero can be dropped entirely
+ if(iszero(n)) {
+ p->zero += n->type->width;
+ return;
+ }
+
+ // special case: inline struct and array (not slice) literals
+ if(isvaluelit(n)) {
+ initplan(n);
+ q = n->initplan;
+ for(i=0; i<q->len; i++) {
+ e = entry(p);
+ *e = q->e[i];
+ e->xoffset += xoffset;
+ }
+ return;
+ }
+
+ // add to plan
+ if(n->op == OLITERAL)
+ p->lit += n->type->width;
+ else
+ p->expr += n->type->width;
+
+ e = entry(p);
+ e->xoffset = xoffset;
+ e->expr = n;
+}
+
+static int
+iszero(Node *n)
+{
+ NodeList *l;
+
+ switch(n->op) {
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ dump("unexpected literal", n);
+ fatal("iszero");
+
+ case CTNIL:
+ return 1;
+
+ case CTSTR:
+ return n->val.u.sval == nil || n->val.u.sval->len == 0;
+
+ case CTBOOL:
+ return n->val.u.bval == 0;
+
+ case CTINT:
+ case CTRUNE:
+ return mpcmpfixc(n->val.u.xval, 0) == 0;
+
+ case CTFLT:
+ return mpcmpfltc(n->val.u.fval, 0) == 0;
+
+ case CTCPLX:
+ return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0;
+ }
+ break;
+ case OARRAYLIT:
+ if(isslice(n->type))
+ break;
+ // fall through
+ case OSTRUCTLIT:
+ for(l=n->list; l; l=l->next)
+ if(!iszero(l->n->right))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+isvaluelit(Node *n)
+{
+ return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT;
+}
+
+static InitEntry*
+entry(InitPlan *p)
+{
+ if(p->len >= p->cap) {
+ if(p->cap == 0)
+ p->cap = 4;
+ else
+ p->cap *= 2;
+ p->e = realloc(p->e, p->cap*sizeof p->e[0]);
+ if(p->e == nil)
+ fatal("out of memory");
+ }
+ return &p->e[p->len++];
+}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 1a05d43d0..681c023a0 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
#include "md5.h"
#include "y.tab.h"
-#include "opnames.h"
#include "yerr.h"
-static void dodump(Node*, int);
-
typedef struct Error Error;
struct Error
{
@@ -27,7 +26,7 @@ errorexit(void)
flusherrors();
if(outfile)
remove(outfile);
- exit(1);
+ exits("error");
}
extern int yychar;
@@ -45,12 +44,10 @@ adderr(int line, char *fmt, va_list arg)
Fmt f;
Error *p;
- erroring++;
fmtstrinit(&f);
fmtprint(&f, "%L: ", line);
fmtvprint(&f, fmt, arg);
fmtprint(&f, "\n");
- erroring--;
if(nerr >= merr) {
if(merr == 0)
@@ -106,7 +103,7 @@ hcrash(void)
if(debug['h']) {
flusherrors();
if(outfile)
- unlink(outfile);
+ remove(outfile);
*(volatile int*)0 = 0;
}
}
@@ -122,7 +119,7 @@ yyerrorl(int line, char *fmt, ...)
hcrash();
nerrors++;
- if(nerrors >= 10 && !debug['e']) {
+ if(nsavederrors+nerrors >= 10 && !debug['e']) {
flusherrors();
print("%L: too many errors\n", line);
errorexit();
@@ -190,7 +187,7 @@ yyerror(char *fmt, ...)
hcrash();
nerrors++;
- if(nerrors >= 10 && !debug['e']) {
+ if(nsavederrors+nerrors >= 10 && !debug['e']) {
flusherrors();
print("%L: too many errors\n", parserline());
errorexit();
@@ -210,6 +207,16 @@ warn(char *fmt, ...)
}
void
+warnl(int line, char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ adderr(line, fmt, arg);
+ va_end(arg);
+}
+
+void
fatal(char *fmt, ...)
{
va_list arg;
@@ -393,7 +400,7 @@ importdot(Pkg *opkg, Node *pack)
}
if(n == 0) {
// can't possibly be used - there were no symbols
- yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path);
+ yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path);
}
}
@@ -483,49 +490,125 @@ nod(int op, Node *nleft, Node *nright)
n->lineno = parserline();
n->xoffset = BADWIDTH;
n->orig = n;
+ n->curfn = curfn;
return n;
}
int
+algtype1(Type *t, Type **bad)
+{
+ int a, ret;
+ Type *t1;
+
+ if(bad)
+ *bad = T;
+
+ switch(t->etype) {
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT64:
+ case TUINT64:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ case TPTR64:
+ case TCHAN:
+ case TUNSAFEPTR:
+ return AMEM;
+
+ case TFUNC:
+ case TMAP:
+ if(bad)
+ *bad = t;
+ return ANOEQ;
+
+ case TFLOAT32:
+ return AFLOAT32;
+
+ case TFLOAT64:
+ return AFLOAT64;
+
+ case TCOMPLEX64:
+ return ACPLX64;
+
+ case TCOMPLEX128:
+ return ACPLX128;
+
+ case TSTRING:
+ return ASTRING;
+
+ case TINTER:
+ if(isnilinter(t))
+ return ANILINTER;
+ return AINTER;
+
+ case TARRAY:
+ if(isslice(t)) {
+ if(bad)
+ *bad = t;
+ return ANOEQ;
+ }
+ if(t->bound == 0)
+ return AMEM;
+ a = algtype1(t->type, bad);
+ if(a == ANOEQ || a == AMEM) {
+ if(a == ANOEQ && bad)
+ *bad = t;
+ return a;
+ }
+ return -1; // needs special compare
+
+ case TSTRUCT:
+ if(t->type != T && t->type->down == T) {
+ // One-field struct is same as that one field alone.
+ return algtype1(t->type->type, bad);
+ }
+ ret = AMEM;
+ for(t1=t->type; t1!=T; t1=t1->down) {
+ if(isblanksym(t1->sym))
+ continue;
+ a = algtype1(t1->type, bad);
+ if(a == ANOEQ)
+ return ANOEQ; // not comparable
+ if(a != AMEM)
+ ret = -1; // needs special compare
+ }
+ return ret;
+ }
+
+ fatal("algtype1: unexpected type %T", t);
+ return 0;
+}
+
+int
algtype(Type *t)
{
int a;
-
- if(issimple[t->etype] || isptr[t->etype] ||
- t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
- if(t->width == 1)
- a = AMEM8;
- else if(t->width == 2)
- a = AMEM16;
- else if(t->width == 4)
- a = AMEM32;
- else if(t->width == 8)
- a = AMEM64;
- else if(t->width == 16)
- a = AMEM128;
- else
- a = AMEM; // just bytes (int, ptr, etc)
- } else if(t->etype == TSTRING)
- a = ASTRING; // string
- else if(isnilinter(t))
- a = ANILINTER; // nil interface
- else if(t->etype == TINTER)
- a = AINTER; // interface
- else if(isslice(t))
- a = ASLICE; // slice
- else {
- if(t->width == 1)
- a = ANOEQ8;
- else if(t->width == 2)
- a = ANOEQ16;
- else if(t->width == 4)
- a = ANOEQ32;
- else if(t->width == 8)
- a = ANOEQ64;
- else if(t->width == 16)
- a = ANOEQ128;
- else
- a = ANOEQ; // just bytes, but no hash/eq
+
+ a = algtype1(t, nil);
+ if(a == AMEM || a == ANOEQ) {
+ if(isslice(t))
+ return ASLICE;
+ switch(t->width) {
+ case 0:
+ return a + AMEM0 - AMEM;
+ case 1:
+ return a + AMEM8 - AMEM;
+ case 2:
+ return a + AMEM16 - AMEM;
+ case 4:
+ return a + AMEM32 - AMEM;
+ case 8:
+ return a + AMEM64 - AMEM;
+ case 16:
+ return a + AMEM128 - AMEM;
+ }
}
return a;
}
@@ -535,9 +618,16 @@ maptype(Type *key, Type *val)
{
Type *t;
-
- if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) {
- if(key->etype == TFORW) {
+ if(key != nil) {
+ switch(key->etype) {
+ default:
+ if(algtype1(key, nil) == ANOEQ)
+ yyerror("invalid map key type %T", key);
+ break;
+ case TANY:
+ // will be resolved later.
+ break;
+ case TFORW:
// map[key] used during definition of key.
// postpone check until key is fully defined.
// if there are multiple uses of map[key]
@@ -546,8 +636,8 @@ maptype(Type *key, Type *val)
// good enough.
if(key->maplineno == 0)
key->maplineno = lineno;
- } else
- yyerror("invalid map key type %T", key);
+ break;
+ }
}
t = typ(TMAP);
t->down = key;
@@ -696,6 +786,7 @@ aindex(Node *b, Type *t)
yyerror("array bound must be an integer expression");
break;
case CTINT:
+ case CTRUNE:
bound = mpgetfix(b->val.u.xval);
if(bound < 0)
yyerror("array bound must be non negative");
@@ -710,892 +801,6 @@ aindex(Node *b, Type *t)
return r;
}
-static void
-indent(int dep)
-{
- int i;
-
- for(i=0; i<dep; i++)
- print(". ");
-}
-
-static void
-dodumplist(NodeList *l, int dep)
-{
- for(; l; l=l->next)
- dodump(l->n, dep);
-}
-
-static void
-dodump(Node *n, int dep)
-{
- if(n == N)
- return;
-
- indent(dep);
- if(dep > 10) {
- print("...\n");
- return;
- }
-
- if(n->ninit != nil) {
- print("%O-init\n", n->op);
- dodumplist(n->ninit, dep+1);
- indent(dep);
- }
-
- switch(n->op) {
- default:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- break;
-
- case OTYPE:
- print("%O %S type=%T\n", n->op, n->sym, n->type);
- if(n->type == T && n->ntype) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- break;
-
- case OIF:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
- if(n->nbody != nil) {
- indent(dep);
- print("%O-then\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
- if(n->nelse != nil) {
- indent(dep);
- print("%O-else\n", n->op);
- dodumplist(n->nelse, dep+1);
- }
- break;
-
- case OSELECT:
- print("%O%J\n", n->op, n);
- dodumplist(n->nbody, dep+1);
- break;
-
- case OSWITCH:
- case OFOR:
- print("%O%J\n", n->op, n);
- dodump(n->ntest, dep+1);
-
- if(n->nbody != nil) {
- indent(dep);
- print("%O-body\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-
- if(n->nincr != N) {
- indent(dep);
- print("%O-incr\n", n->op);
- dodump(n->nincr, dep+1);
- }
- break;
-
- case OCASE:
- // the right side points to label of the body
- if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME)
- print("%O%J GOTO %N\n", n->op, n, n->right->left);
- else
- print("%O%J\n", n->op, n);
- dodump(n->left, dep+1);
- break;
-
- case OXCASE:
- print("%N\n", n);
- dodump(n->left, dep+1);
- dodump(n->right, dep+1);
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- break;
- }
-
- if(0 && n->ntype != nil) {
- indent(dep);
- print("%O-ntype\n", n->op);
- dodump(n->ntype, dep+1);
- }
- if(n->list != nil) {
- indent(dep);
- print("%O-list\n", n->op);
- dodumplist(n->list, dep+1);
- }
- if(n->rlist != nil) {
- indent(dep);
- print("%O-rlist\n", n->op);
- dodumplist(n->rlist, dep+1);
- }
- if(n->op != OIF && n->nbody != nil) {
- indent(dep);
- print("%O-nbody\n", n->op);
- dodumplist(n->nbody, dep+1);
- }
-}
-
-void
-dumplist(char *s, NodeList *l)
-{
- print("%s\n", s);
- dodumplist(l, 1);
-}
-
-void
-dump(char *s, Node *n)
-{
- print("%s [%p]\n", s, n);
- dodump(n, 1);
-}
-
-static char*
-goopnames[] =
-{
- [OADDR] = "&",
- [OADD] = "+",
- [OANDAND] = "&&",
- [OANDNOT] = "&^",
- [OAND] = "&",
- [OAPPEND] = "append",
- [OAS] = "=",
- [OAS2] = "=",
- [OBREAK] = "break",
- [OCALL] = "function call",
- [OCAP] = "cap",
- [OCASE] = "case",
- [OCLOSE] = "close",
- [OCOMPLEX] = "complex",
- [OCOM] = "^",
- [OCONTINUE] = "continue",
- [OCOPY] = "copy",
- [ODEC] = "--",
- [ODEFER] = "defer",
- [ODIV] = "/",
- [OEQ] = "==",
- [OFALL] = "fallthrough",
- [OFOR] = "for",
- [OGE] = ">=",
- [OGOTO] = "goto",
- [OGT] = ">",
- [OIF] = "if",
- [OIMAG] = "imag",
- [OINC] = "++",
- [OIND] = "*",
- [OLEN] = "len",
- [OLE] = "<=",
- [OLSH] = "<<",
- [OLT] = "<",
- [OMAKE] = "make",
- [OMINUS] = "-",
- [OMOD] = "%",
- [OMUL] = "*",
- [ONEW] = "new",
- [ONE] = "!=",
- [ONOT] = "!",
- [OOROR] = "||",
- [OOR] = "|",
- [OPANIC] = "panic",
- [OPLUS] = "+",
- [OPRINTN] = "println",
- [OPRINT] = "print",
- [ORANGE] = "range",
- [OREAL] = "real",
- [ORECV] = "<-",
- [ORETURN] = "return",
- [ORSH] = ">>",
- [OSELECT] = "select",
- [OSEND] = "<-",
- [OSUB] = "-",
- [OSWITCH] = "switch",
- [OXOR] = "^",
-};
-
-int
-Oconv(Fmt *fp)
-{
- int o;
-
- o = va_arg(fp->args, int);
- if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
- return fmtstrcpy(fp, goopnames[o]);
- if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
- return fmtprint(fp, "O-%d", o);
- return fmtstrcpy(fp, opnames[o]);
-}
-
-int
-Lconv(Fmt *fp)
-{
- struct
- {
- Hist* incl; /* start of this include file */
- int32 idel; /* delta line number to apply to include */
- Hist* line; /* start of this #line directive */
- int32 ldel; /* delta line number to apply to #line */
- } a[HISTSZ];
- int32 lno, d;
- int i, n;
- Hist *h;
-
- lno = va_arg(fp->args, int32);
-
- n = 0;
- for(h=hist; h!=H; h=h->link) {
- if(h->offset < 0)
- continue;
- if(lno < h->line)
- break;
- if(h->name) {
- if(h->offset > 0) {
- // #line directive
- if(n > 0 && n < HISTSZ) {
- a[n-1].line = h;
- a[n-1].ldel = h->line - h->offset + 1;
- }
- } else {
- // beginning of file
- if(n < HISTSZ) {
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
- }
- n++;
- }
- continue;
- }
- n--;
- if(n > 0 && n < HISTSZ) {
- d = h->line - a[n].incl->line;
- a[n-1].ldel += d;
- a[n-1].idel += d;
- }
- }
-
- if(n > HISTSZ)
- n = HISTSZ;
-
- for(i=n-1; i>=0; i--) {
- if(i != n-1) {
- if(fp->flags & ~(FmtWidth|FmtPrec))
- break;
- fmtprint(fp, " ");
- }
- if(debug['L'])
- fmtprint(fp, "%s/", pathname);
- if(a[i].line)
- fmtprint(fp, "%s:%d[%s:%d]",
- a[i].line->name, lno-a[i].ldel+1,
- a[i].incl->name, lno-a[i].idel+1);
- else
- fmtprint(fp, "%s:%d",
- a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; // now print out start of this file
- }
- if(n == 0)
- fmtprint(fp, "<epoch>");
-
- return 0;
-}
-
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[ ]*T%%g
-s%,.*%%g
-s%.+% [T&] = "&",%g
-s%^ ........*\]%&~%g
-s%~ %%g
-*/
-
-static char*
-etnames[] =
-{
- [TINT] = "INT",
- [TUINT] = "UINT",
- [TINT8] = "INT8",
- [TUINT8] = "UINT8",
- [TINT16] = "INT16",
- [TUINT16] = "UINT16",
- [TINT32] = "INT32",
- [TUINT32] = "UINT32",
- [TINT64] = "INT64",
- [TUINT64] = "UINT64",
- [TUINTPTR] = "UINTPTR",
- [TFLOAT32] = "FLOAT32",
- [TFLOAT64] = "FLOAT64",
- [TCOMPLEX64] = "COMPLEX64",
- [TCOMPLEX128] = "COMPLEX128",
- [TBOOL] = "BOOL",
- [TPTR32] = "PTR32",
- [TPTR64] = "PTR64",
- [TFUNC] = "FUNC",
- [TARRAY] = "ARRAY",
- [TSTRUCT] = "STRUCT",
- [TCHAN] = "CHAN",
- [TMAP] = "MAP",
- [TINTER] = "INTER",
- [TFORW] = "FORW",
- [TFIELD] = "FIELD",
- [TSTRING] = "STRING",
- [TANY] = "ANY",
-};
-
-int
-Econv(Fmt *fp)
-{
- int et;
-
- et = va_arg(fp->args, int);
- if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
- return fmtprint(fp, "E-%d", et);
- return fmtstrcpy(fp, etnames[et]);
-}
-
-static const char* classnames[] = {
- "Pxxx",
- "PEXTERN",
- "PAUTO",
- "PPARAM",
- "PPARAMOUT",
- "PPARAMREF",
- "PFUNC",
-};
-
-int
-Jconv(Fmt *fp)
-{
- Node *n;
- char *s;
- int c;
-
- n = va_arg(fp->args, Node*);
-
- c = fp->flags&FmtShort;
-
- if(!c && n->ullman != 0)
- fmtprint(fp, " u(%d)", n->ullman);
-
- if(!c && n->addable != 0)
- fmtprint(fp, " a(%d)", n->addable);
-
- if(!c && n->vargen != 0)
- fmtprint(fp, " g(%d)", n->vargen);
-
- if(n->lineno != 0)
- fmtprint(fp, " l(%d)", n->lineno);
-
- if(!c && n->xoffset != BADWIDTH)
- fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
-
- if(n->class != 0) {
- s = "";
- if (n->class & PHEAP) s = ",heap";
- if ((n->class & ~PHEAP) < nelem(classnames))
- fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
- else
- fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
- }
-
- if(n->colas != 0)
- fmtprint(fp, " colas(%d)", n->colas);
-
- if(n->funcdepth != 0)
- fmtprint(fp, " f(%d)", n->funcdepth);
-
- if(n->noescape != 0)
- fmtprint(fp, " ne(%d)", n->noescape);
-
- if(!c && n->typecheck != 0)
- fmtprint(fp, " tc(%d)", n->typecheck);
-
- if(!c && n->dodata != 0)
- fmtprint(fp, " dd(%d)", n->dodata);
-
- if(n->isddd != 0)
- fmtprint(fp, " isddd(%d)", n->isddd);
-
- if(n->implicit != 0)
- fmtprint(fp, " implicit(%d)", n->implicit);
-
- if(!c && n->pun != 0)
- fmtprint(fp, " pun(%d)", n->pun);
-
- if(!c && n->used != 0)
- fmtprint(fp, " used(%d)", n->used);
- return 0;
-}
-
-int
-Sconv(Fmt *fp)
-{
- Sym *s;
-
- s = va_arg(fp->args, Sym*);
- if(s == S) {
- fmtstrcpy(fp, "<S>");
- return 0;
- }
-
- if(fp->flags & FmtShort)
- goto shrt;
-
- if(exporting || (fp->flags & FmtSharp)) {
- if(packagequotes)
- fmtprint(fp, "\"%Z\"", s->pkg->path);
- else
- fmtprint(fp, "%s", s->pkg->prefix);
- fmtprint(fp, ".%s", s->name);
- return 0;
- }
-
- if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) {
- // This one is for the user. If the package name
- // was used by multiple packages, give the full
- // import path to disambiguate.
- if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) {
- fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
- return 0;
- }
- fmtprint(fp, "%s.%s", s->pkg->name, s->name);
- return 0;
- }
-
-shrt:
- fmtstrcpy(fp, s->name);
- return 0;
-}
-
-static char*
-basicnames[] =
-{
- [TINT] = "int",
- [TUINT] = "uint",
- [TINT8] = "int8",
- [TUINT8] = "uint8",
- [TINT16] = "int16",
- [TUINT16] = "uint16",
- [TINT32] = "int32",
- [TUINT32] = "uint32",
- [TINT64] = "int64",
- [TUINT64] = "uint64",
- [TUINTPTR] = "uintptr",
- [TFLOAT32] = "float32",
- [TFLOAT64] = "float64",
- [TCOMPLEX64] = "complex64",
- [TCOMPLEX128] = "complex128",
- [TBOOL] = "bool",
- [TANY] = "any",
- [TSTRING] = "string",
- [TNIL] = "nil",
- [TIDEAL] = "ideal",
- [TBLANK] = "blank",
-};
-
-int
-Tpretty(Fmt *fp, Type *t)
-{
- Type *t1;
- Sym *s;
-
- if(0 && debug['r']) {
- debug['r'] = 0;
- fmtprint(fp, "%T (orig=%T)", t, t->orig);
- debug['r'] = 1;
- return 0;
- }
-
- if(t->etype != TFIELD
- && t->sym != S
- && !(fp->flags&FmtLong)) {
- s = t->sym;
- if(t == types[t->etype] && t->etype != TUNSAFEPTR)
- return fmtprint(fp, "%s", s->name);
- if(exporting) {
- if(fp->flags & FmtShort)
- fmtprint(fp, "%hS", s);
- else
- fmtprint(fp, "%S", s);
- if(s->pkg != localpkg)
- return 0;
- if(t->vargen)
- fmtprint(fp, "·%d", t->vargen);
- return 0;
- }
- return fmtprint(fp, "%S", s);
- }
-
- if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
- if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL)
- fmtprint(fp, "ideal ");
- return fmtprint(fp, "%s", basicnames[t->etype]);
- }
-
- switch(t->etype) {
- case TPTR32:
- case TPTR64:
- if(fp->flags&FmtShort) // pass flag thru for methodsym
- return fmtprint(fp, "*%hT", t->type);
- return fmtprint(fp, "*%T", t->type);
-
- case TCHAN:
- switch(t->chan) {
- case Crecv:
- return fmtprint(fp, "<-chan %T", t->type);
- case Csend:
- return fmtprint(fp, "chan<- %T", t->type);
- }
- if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
- return fmtprint(fp, "chan (%T)", t->type);
- return fmtprint(fp, "chan %T", t->type);
-
- case TMAP:
- return fmtprint(fp, "map[%T] %T", t->down, t->type);
-
- case TFUNC:
- // t->type is method struct
- // t->type->down is result struct
- // t->type->down->down is arg struct
- if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) {
- fmtprint(fp, "method(");
- for(t1=getthisx(t)->type; t1; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- }
-
- if(!(fp->flags&FmtByte))
- fmtprint(fp, "func");
- fmtprint(fp, "(");
- for(t1=getinargx(t)->type; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD) {
- if(t1->isddd)
- fmtprint(fp, "...%T", t1->type->type);
- else
- fmtprint(fp, "%T", t1->type);
- } else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- switch(t->outtuple) {
- case 0:
- break;
- case 1:
- t1 = getoutargx(t)->type;
- if(t1 == T) {
- // failure to typecheck earlier; don't know the type
- fmtprint(fp, " ?unknown-type?");
- break;
- }
- if(t1->etype == TFIELD)
- t1 = t1->type;
- fmtprint(fp, " %T", t1);
- break;
- default:
- t1 = getoutargx(t)->type;
- fmtprint(fp, " (");
- for(; t1; t1=t1->down) {
- if(noargnames && t1->etype == TFIELD)
- fmtprint(fp, "%T", t1->type);
- else
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- fmtprint(fp, ")");
- break;
- }
- return 0;
-
- case TARRAY:
- if(t->bound >= 0)
- return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
- if(t->bound == -100)
- return fmtprint(fp, "[...]%T", t->type);
- return fmtprint(fp, "[]%T", t->type);
-
- case TINTER:
- fmtprint(fp, "interface {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " ");
- if(exportname(t1->sym->name))
- fmtprint(fp, "%hS", t1->sym);
- else
- fmtprint(fp, "%S", t1->sym);
- fmtprint(fp, "%hhT", t1->type);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TSTRUCT:
- if(t->funarg) {
- fmtprint(fp, "(");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, "%T", t1);
- if(t1->down)
- fmtprint(fp, ", ");
- }
- return fmtprint(fp, ")");
- }
- fmtprint(fp, "struct {");
- for(t1=t->type; t1!=T; t1=t1->down) {
- fmtprint(fp, " %T", t1);
- if(t1->down)
- fmtprint(fp, ";");
- }
- return fmtprint(fp, " }");
-
- case TFIELD:
- if(t->sym == S || t->embedded) {
- if(exporting)
- fmtprint(fp, "? ");
- } else
- fmtprint(fp, "%hS ", t->sym);
- if(t->isddd)
- fmtprint(fp, "...%T", t->type->type);
- else
- fmtprint(fp, "%T", t->type);
- if(t->note) {
- fmtprint(fp, " ");
- if(exporting)
- fmtprint(fp, ":");
- fmtprint(fp, "\"%Z\"", t->note);
- }
- return 0;
-
- case TFORW:
- if(exporting)
- yyerror("undefined type %S", t->sym);
- if(t->sym)
- return fmtprint(fp, "undefined %S", t->sym);
- return fmtprint(fp, "undefined");
-
- case TUNSAFEPTR:
- if(exporting)
- return fmtprint(fp, "\"unsafe\".Pointer");
- return fmtprint(fp, "unsafe.Pointer");
- }
-
- // Don't know how to handle - fall back to detailed prints.
- return -1;
-}
-
-int
-Tconv(Fmt *fp)
-{
- Type *t, *t1;
- int r, et, sharp, minus;
-
- sharp = (fp->flags & FmtSharp);
- minus = (fp->flags & FmtLeft);
- fp->flags &= ~(FmtSharp|FmtLeft);
-
- t = va_arg(fp->args, Type*);
- if(t == T)
- return fmtstrcpy(fp, "<T>");
-
- t->trecur++;
- if(t->trecur > 5) {
- fmtprint(fp, "...");
- goto out;
- }
-
- if(!debug['t']) {
- if(sharp)
- exporting++;
- if(minus)
- noargnames++;
- r = Tpretty(fp, t);
- if(sharp)
- exporting--;
- if(minus)
- noargnames--;
- if(r >= 0) {
- t->trecur--;
- return 0;
- }
- }
-
- if(sharp || exporting)
- fatal("missing %E case during export", t->etype);
-
- et = t->etype;
- fmtprint(fp, "%E ", et);
- if(t->sym != S)
- fmtprint(fp, "<%S>", t->sym);
-
- switch(et) {
- default:
- if(t->type != T)
- fmtprint(fp, " %T", t->type);
- break;
-
- case TFIELD:
- fmtprint(fp, "%T", t->type);
- break;
-
- case TFUNC:
- if(fp->flags & FmtLong)
- fmtprint(fp, "%d%d%d(%lT,%lT)%lT",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- else
- fmtprint(fp, "%d%d%d(%T,%T)%T",
- t->thistuple, t->intuple, t->outtuple,
- t->type, t->type->down->down, t->type->down);
- break;
-
- case TINTER:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TSTRUCT:
- fmtprint(fp, "{");
- if(fp->flags & FmtLong)
- for(t1=t->type; t1!=T; t1=t1->down)
- fmtprint(fp, "%lT;", t1);
- fmtprint(fp, "}");
- break;
-
- case TMAP:
- fmtprint(fp, "[%T]%T", t->down, t->type);
- break;
-
- case TARRAY:
- if(t->bound >= 0)
- fmtprint(fp, "[%d]%T", t->bound, t->type);
- else
- fmtprint(fp, "[]%T", t->type);
- break;
-
- case TPTR32:
- case TPTR64:
- fmtprint(fp, "%T", t->type);
- break;
- }
-
-out:
- t->trecur--;
- return 0;
-}
-
-int
-Nconv(Fmt *fp)
-{
- char buf1[500];
- Node *n;
-
- n = va_arg(fp->args, Node*);
- if(n == N) {
- fmtprint(fp, "<N>");
- goto out;
- }
-
- if(fp->flags & FmtSign) {
- if(n->type == T)
- fmtprint(fp, "%#N", n);
- else if(n->type->etype == TNIL)
- fmtprint(fp, "nil");
- else
- fmtprint(fp, "%#N (type %T)", n, n->type);
- goto out;
- }
-
- if(fp->flags & FmtSharp) {
- if(n->orig != N)
- n = n->orig;
- exprfmt(fp, n, 0);
- goto out;
- }
-
- switch(n->op) {
- default:
- if (fp->flags & FmtShort)
- fmtprint(fp, "%O%hJ", n->op, n);
- else
- fmtprint(fp, "%O%J", n->op, n);
- break;
-
- case ONAME:
- case ONONAME:
- if(n->sym == S) {
- if (fp->flags & FmtShort)
- fmtprint(fp, "%O%hJ", n->op, n);
- else
- fmtprint(fp, "%O%J", n->op, n);
- break;
- }
- if (fp->flags & FmtShort)
- fmtprint(fp, "%O-%S%hJ", n->op, n->sym, n);
- else
- fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
- goto ptyp;
-
- case OREGISTER:
- fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
- break;
-
- case OLITERAL:
- switch(n->val.ctype) {
- default:
- snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype);
- break;
- case CTINT:
- snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval);
- break;
- case CTFLT:
- snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval));
- break;
- case CTCPLX:
- snprint(buf1, sizeof(buf1), "(F%g+F%gi)",
- mpgetflt(&n->val.u.cval->real),
- mpgetflt(&n->val.u.cval->imag));
- break;
- case CTSTR:
- snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval);
- break;
- case CTBOOL:
- snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval);
- break;
- case CTNIL:
- snprint(buf1, sizeof(buf1), "N");
- break;
- }
- fmtprint(fp, "%O-%s%J", n->op, buf1, n);
- break;
-
- case OASOP:
- fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
- break;
-
- case OTYPE:
- fmtprint(fp, "%O %T", n->op, n->type);
- break;
- }
- if(n->sym != S)
- fmtprint(fp, " %S G%d", n->sym, n->vargen);
-
-ptyp:
- if(n->type != T)
- fmtprint(fp, " %T", n->type);
-
-out:
- return 0;
-}
-
Node*
treecopy(Node *n)
{
@@ -1636,52 +841,6 @@ treecopy(Node *n)
return m;
}
-int
-Zconv(Fmt *fp)
-{
- Rune r;
- Strlit *sp;
- char *s, *se;
- int n;
-
- sp = va_arg(fp->args, Strlit*);
- if(sp == nil)
- return fmtstrcpy(fp, "<nil>");
-
- s = sp->s;
- se = s + sp->len;
- while(s < se) {
- n = chartorune(&r, s);
- s += n;
- switch(r) {
- case Runeerror:
- if(n == 1) {
- fmtprint(fp, "\\x%02x", (uchar)*(s-1));
- break;
- }
- // fall through
- default:
- if(r < ' ') {
- fmtprint(fp, "\\x%02x", r);
- break;
- }
- fmtrune(fp, r);
- break;
- case '\t':
- fmtstrcpy(fp, "\\t");
- break;
- case '\n':
- fmtstrcpy(fp, "\\n");
- break;
- case '\"':
- case '\\':
- fmtrune(fp, '\\');
- fmtrune(fp, r);
- break;
- }
- }
- return 0;
-}
int
isnil(Node *n)
@@ -1731,11 +890,19 @@ isslice(Type *t)
int
isblank(Node *n)
{
+ if(n == N)
+ return 0;
+ return isblanksym(n->sym);
+}
+
+int
+isblanksym(Sym *s)
+{
char *p;
- if(n == N || n->sym == S)
+ if(s == S)
return 0;
- p = n->sym->name;
+ p = s->name;
if(p == nil)
return 0;
return p[0] == '_' && p[1] == '\0';
@@ -1777,7 +944,7 @@ isideal(Type *t)
* return type to hang methods off (r).
*/
Type*
-methtype(Type *t)
+methtype(Type *t, int mustname)
{
if(t == T)
return T;
@@ -1792,7 +959,7 @@ methtype(Type *t)
}
// need a type name
- if(t->sym == S)
+ if(t->sym == S && (mustname || t->etype != TSTRUCT))
return T;
// check types
@@ -1837,6 +1004,25 @@ eqnote(Strlit *a, Strlit *b)
return memcmp(a->s, b->s, a->len) == 0;
}
+typedef struct TypePairList TypePairList;
+struct TypePairList
+{
+ Type *t1;
+ Type *t2;
+ TypePairList *next;
+};
+
+static int
+onlist(TypePairList *l, Type *t1, Type *t2)
+{
+ for(; l; l=l->next)
+ if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
+ return 1;
+ return 0;
+}
+
+static int eqtype1(Type*, Type*, TypePairList*);
+
// Return 1 if t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
@@ -1846,10 +1032,40 @@ eqnote(Strlit *a, Strlit *b)
int
eqtype(Type *t1, Type *t2)
{
+ return eqtype1(t1, t2, nil);
+}
+
+static int
+eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
+{
+ TypePairList l;
+
if(t1 == t2)
return 1;
- if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
+ if(t1 == T || t2 == T || t1->etype != t2->etype)
return 0;
+ if(t1->sym || t2->sym) {
+ // Special case: we keep byte and uint8 separate
+ // for error messages. Treat them as equal.
+ switch(t1->etype) {
+ case TUINT8:
+ if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
+ return 1;
+ break;
+ case TINT:
+ case TINT32:
+ if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
+ return 1;
+ break;
+ }
+ return 0;
+ }
+
+ if(onlist(assumed_equal, t1, t2))
+ return 1;
+ l.next = assumed_equal;
+ l.t1 = t1;
+ l.t2 = t2;
switch(t1->etype) {
case TINTER:
@@ -1857,10 +1073,12 @@ eqtype(Type *t1, Type *t2)
for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
if(t1->etype != TFIELD || t2->etype != TFIELD)
fatal("struct/interface missing field: %T %T", t1, t2);
- if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
- return 0;
+ if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
+ goto no;
}
- return t1 == T && t2 == T;
+ if(t1 == T && t2 == T)
+ goto yes;
+ goto no;
case TFUNC:
// Loop over structs: receiver, in, out.
@@ -1874,26 +1092,36 @@ eqtype(Type *t1, Type *t2)
for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
if(ta->etype != TFIELD || tb->etype != TFIELD)
fatal("func struct missing field: %T %T", ta, tb);
- if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
- return 0;
+ if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
+ goto no;
}
if(ta != T || tb != T)
- return 0;
+ goto no;
}
- return t1 == T && t2 == T;
+ if(t1 == T && t2 == T)
+ goto yes;
+ goto no;
case TARRAY:
if(t1->bound != t2->bound)
- return 0;
+ goto no;
break;
case TCHAN:
if(t1->chan != t2->chan)
- return 0;
+ goto no;
break;
}
- return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
+ if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
+ goto yes;
+ goto no;
+
+yes:
+ return 1;
+
+no:
+ return 0;
}
// Are t1 and t2 equal struct types when field names are ignored?
@@ -1920,9 +1148,6 @@ eqtypenoname(Type *t1, Type *t2)
// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
// If not, return 0.
-//
-// It is the caller's responsibility to call exportassignok
-// to check for assignments to other packages' unexported fields,
int
assignop(Type *src, Type *dst, char **why)
{
@@ -1932,7 +1157,9 @@ assignop(Type *src, Type *dst, char **why)
if(why != nil)
*why = "";
- if(safemode && src != T && src->etype == TUNSAFEPTR) {
+ // TODO(rsc,lvd): This behaves poorly in the presence of inlining.
+ // https://code.google.com/p/go/issues/detail?id=2795
+ if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
yyerror("cannot use unsafe.Pointer");
errorexit();
}
@@ -1956,6 +1183,11 @@ assignop(Type *src, Type *dst, char **why)
if(dst->etype == TINTER && src->etype != TNIL) {
if(implements(src, dst, &missing, &have, &ptr))
return OCONVIFACE;
+
+ // we'll have complained about this method anyway, supress spurious messages.
+ if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
+ return OCONVIFACE;
+
if(why != nil) {
if(isptrto(src, TINTER))
*why = smprint(":\n\t%T is pointer to interface, not interface", src);
@@ -2072,29 +1304,25 @@ convertop(Type *src, Type *dst, char **why)
return OCONV;
}
- // 6. src is an integer or has type []byte or []int
+ // 6. src is an integer or has type []byte or []rune
// and dst is a string type.
if(isint[src->etype] && dst->etype == TSTRING)
return ORUNESTR;
- if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) {
- switch(src->type->etype) {
- case TUINT8:
+ if(isslice(src) && dst->etype == TSTRING) {
+ if(src->type->etype == bytetype->etype)
return OARRAYBYTESTR;
- case TINT:
+ if(src->type->etype == runetype->etype)
return OARRAYRUNESTR;
- }
}
- // 7. src is a string and dst is []byte or []int.
+ // 7. src is a string and dst is []byte or []rune.
// String to slice.
- if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
- switch(dst->type->etype) {
- case TUINT8:
+ if(src->etype == TSTRING && isslice(dst)) {
+ if(dst->type->etype == bytetype->etype)
return OSTRARRAYBYTE;
- case TINT:
+ if(dst->type->etype == runetype->etype)
return OSTRARRAYRUNE;
- }
}
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
@@ -2126,13 +1354,24 @@ assignconv(Node *n, Type *t, char *context)
if(t->etype == TBLANK)
return n;
- exportassignok(n->type, context);
+ // Convert ideal bool from comparison to plain bool
+ // if the next step is non-bool (like interface{}).
+ if(n->type == idealbool && t->etype != TBOOL) {
+ if(n->op == ONAME || n->op == OLITERAL) {
+ r = nod(OCONVNOP, n, N);
+ r->type = types[TBOOL];
+ r->typecheck = 1;
+ r->implicit = 1;
+ n = r;
+ }
+ }
+
if(eqtype(n->type, t))
return n;
op = assignop(n->type, t, &why);
if(op == 0) {
- yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
+ yyerror("cannot use %lN as type %T in %s%s", n, t, context, why);
op = OCONV;
}
@@ -2357,7 +1596,7 @@ syslook(char *name, int copy)
* compute a hash value for type t.
* if t is a method type, ignore the receiver
* so that the hash can be used in interface checks.
- * %-T (which calls Tpretty, above) already contains
+ * %T already contains
* all the necessary logic to generate a representation
* of the type that completely describes it.
* using smprint here avoids duplicating that code.
@@ -2371,15 +1610,14 @@ typehash(Type *t)
char *p;
MD5 d;
- longsymnames = 1;
if(t->thistuple) {
// hide method receiver from Tpretty
t->thistuple = 0;
- p = smprint("%-T", t);
+ p = smprint("%-uT", t);
t->thistuple = 1;
- }else
- p = smprint("%-T", t);
- longsymnames = 0;
+ } else
+ p = smprint("%-uT", t);
+ //print("typehash: %s\n", p);
md5reset(&d);
md5write(&d, (uchar*)p, strlen(p));
free(p);
@@ -2392,7 +1630,7 @@ ptrto(Type *t)
Type *t1;
if(tptr == 0)
- fatal("ptrto: nil");
+ fatal("ptrto: no tptr");
t1 = typ(tptr);
t1->type = t;
t1->width = widthptr;
@@ -2452,6 +1690,11 @@ ullmancalc(Node *n)
if(n == N)
return;
+ if(n->ninit != nil) {
+ ul = UINF;
+ goto out;
+ }
+
switch(n->op) {
case OREGISTER:
case OLITERAL:
@@ -2749,13 +1992,12 @@ safeexpr(Node *n, NodeList **init)
return cheapexpr(n, init);
}
-static Node*
+Node*
copyexpr(Node *n, Type *t, NodeList **init)
{
Node *a, *l;
- l = nod(OXXX, N, N);
- tempname(l, t);
+ l = temp(t);
a = nod(OAS, l, n);
typecheck(&a, Etop);
walkexpr(&a, init);
@@ -2806,10 +2048,12 @@ setmaxarg(Type *t)
maxarg = w;
}
-/* unicode-aware case-insensitive strcmp */
+/*
+ * unicode-aware case-insensitive strcmp
+ */
static int
-cistrcmp(char *p, char *q)
+ucistrcmp(char *p, char *q)
{
Rune rp, rq;
@@ -2851,16 +2095,16 @@ lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
c = 0;
if(u->etype == TSTRUCT || u->etype == TINTER) {
for(f=u->type; f!=T; f=f->down)
- if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) {
+ if(f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0)) {
if(save)
*save = f;
c++;
}
}
- u = methtype(t);
+ u = methtype(t, 0);
if(u != T) {
for(f=u->method; f!=T; f=f->down)
- if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) {
+ if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
if(save)
*save = f;
c++;
@@ -2869,7 +2113,7 @@ lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
return c;
}
-// search depth d --
+// search depth d for field/method s --
// return count of fields+methods
// found at search depth.
// answer is in dotlist array and
@@ -2946,8 +2190,11 @@ adddot(Node *n)
goto ret;
out:
- if(c > 1)
- yyerror("ambiguous DOT reference %T.%S", t, s);
+ if(c > 1) {
+ yyerror("ambiguous selector %N", n);
+ n->left = N;
+ return n;
+ }
// rebuild elided dots
for(c=d-1; c>=0; c--)
@@ -2992,8 +2239,6 @@ expand0(Type *t, int followptr)
if(u->etype == TINTER) {
for(f=u->type; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
if(f->sym->flags & SymUniq)
continue;
f->sym->flags |= SymUniq;
@@ -3006,11 +2251,9 @@ expand0(Type *t, int followptr)
return;
}
- u = methtype(t);
+ u = methtype(t, 0);
if(u != T) {
for(f=u->method; f!=T; f=f->down) {
- if(!exportname(f->sym->name) && f->sym->pkg != localpkg)
- continue;
if(f->sym->flags & SymUniq)
continue;
f->sym->flags |= SymUniq;
@@ -3058,14 +2301,12 @@ out:
}
void
-expandmeth(Sym *s, Type *t)
+expandmeth(Type *t)
{
Symlink *sl;
Type *f;
int c, d;
- if(s == S)
- return;
if(t == T || t->xmethod != nil)
return;
@@ -3086,8 +2327,11 @@ expandmeth(Sym *s, Type *t)
if(c == 0)
continue;
if(c == 1) {
- sl->good = 1;
- sl->field = f;
+ // addot1 may have dug out arbitrary fields, we only want methods.
+ if(f->type->etype == TFUNC && f->type->thistuple > 0) {
+ sl->good = 1;
+ sl->field = f;
+ }
}
break;
}
@@ -3128,13 +2372,12 @@ structargs(Type **tl, int mustname)
gen = 0;
for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
n = N;
- if(t->sym)
- n = newname(t->sym);
- else if(mustname) {
- // have to give it a name so we can refer to it in trampoline
+ if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) {
+ // invent a name so that we can refer to it in the trampoline
snprint(buf, sizeof buf, ".anon%d", gen++);
n = newname(lookup(buf));
- }
+ } else if(t->sym)
+ n = newname(t->sym);
a = nod(ODCLFIELD, n, typenod(t->type));
a->isddd = t->isddd;
if(n != N)
@@ -3190,8 +2433,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
in = structargs(getinarg(method->type), 1);
out = structargs(getoutarg(method->type), 0);
- fn = nod(ODCLFUNC, N, N);
- fn->nname = newname(newnam);
t = nod(OTFUNC, N, N);
l = list1(this);
if(iface && rcvr->width < types[tptr]->width) {
@@ -3208,7 +2449,12 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
}
t->list = concat(l, in);
t->rlist = out;
+
+ fn = nod(ODCLFUNC, N, N);
+ fn->nname = newname(newnam);
+ fn->nname->defn = fn;
fn->nname->ntype = t;
+ declare(fn->nname, PFUNC);
funchdr(fn);
// arg list
@@ -3262,6 +2508,448 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
funccompile(fn, 0);
}
+static Node*
+hashmem(Type *t)
+{
+ Node *tfn, *n;
+ Sym *sym;
+
+ sym = pkglookup("memhash", runtimepkg);
+
+ n = newname(sym);
+ n->class = PFUNC;
+ tfn = nod(OTFUNC, N, N);
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ typecheck(&tfn, Etype);
+ n->type = tfn->type;
+ return n;
+}
+
+static Node*
+hashfor(Type *t)
+{
+ int a;
+ Sym *sym;
+ Node *tfn, *n;
+
+ a = algtype1(t, nil);
+ switch(a) {
+ case AMEM:
+ return hashmem(t);
+ case AINTER:
+ sym = pkglookup("interhash", runtimepkg);
+ break;
+ case ANILINTER:
+ sym = pkglookup("nilinterhash", runtimepkg);
+ break;
+ case ASTRING:
+ sym = pkglookup("strhash", runtimepkg);
+ break;
+ case AFLOAT32:
+ sym = pkglookup("f32hash", runtimepkg);
+ break;
+ case AFLOAT64:
+ sym = pkglookup("f64hash", runtimepkg);
+ break;
+ case ACPLX64:
+ sym = pkglookup("c64hash", runtimepkg);
+ break;
+ case ACPLX128:
+ sym = pkglookup("c128hash", runtimepkg);
+ break;
+ default:
+ sym = typesymprefix(".hash", t);
+ break;
+ }
+
+ n = newname(sym);
+ n->class = PFUNC;
+ tfn = nod(OTFUNC, N, N);
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR]))));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ typecheck(&tfn, Etype);
+ n->type = tfn->type;
+ return n;
+}
+
+/*
+ * Generate a helper function to compute the hash of a value of type t.
+ */
+void
+genhash(Sym *sym, Type *t)
+{
+ Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn;
+ Node *hashel;
+ Type *first, *t1;
+ int old_safemode;
+ int64 size, mul;
+
+ if(debug['r'])
+ print("genhash %S %T\n", sym, t);
+
+ lineno = 1; // less confusing than end of input
+ dclcontext = PEXTERN;
+ markdcl();
+
+ // func sym(h *uintptr, s uintptr, p *T)
+ fn = nod(ODCLFUNC, N, N);
+ fn->nname = newname(sym);
+ fn->nname->class = PFUNC;
+ tfn = nod(OTFUNC, N, N);
+ fn->nname->ntype = tfn;
+
+ n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR])));
+ tfn->list = list(tfn->list, n);
+ nh = n->left;
+ n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+ tfn->list = list(tfn->list, n);
+ n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+ tfn->list = list(tfn->list, n);
+ np = n->left;
+
+ funchdr(fn);
+ typecheck(&fn->nname->ntype, Etype);
+
+ // genhash is only called for types that have equality but
+ // cannot be handled by the standard algorithms,
+ // so t must be either an array or a struct.
+ switch(t->etype) {
+ default:
+ fatal("genhash %T", t);
+ case TARRAY:
+ if(isslice(t))
+ fatal("genhash %T", t);
+ // An array of pure memory would be handled by the
+ // standard algorithm, so the element type must not be
+ // pure memory.
+ hashel = hashfor(t->type);
+ n = nod(ORANGE, N, nod(OIND, np, N));
+ ni = newname(lookup("i"));
+ ni->type = types[TINT];
+ n->list = list1(ni);
+ n->colas = 1;
+ colasdefn(n->list, n);
+ ni = n->list->n;
+
+ // *h = *h<<3 | *h>>61
+ n->nbody = list(n->nbody,
+ nod(OAS,
+ nod(OIND, nh, N),
+ nod(OOR,
+ nod(OLSH, nod(OIND, nh, N), nodintconst(3)),
+ nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3)))));
+
+ // *h *= mul
+ // Same multipliers as in runtime.memhash.
+ if(widthptr == 4)
+ mul = 3267000013LL;
+ else
+ mul = 23344194077549503LL;
+ n->nbody = list(n->nbody,
+ nod(OAS,
+ nod(OIND, nh, N),
+ nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));
+
+ // hashel(h, sizeof(p[i]), &p[i])
+ call = nod(OCALL, hashel, N);
+ call->list = list(call->list, nh);
+ call->list = list(call->list, nodintconst(t->type->width));
+ nx = nod(OINDEX, np, ni);
+ nx->etype = 1; // no bounds check
+ na = nod(OADDR, nx, N);
+ na->etype = 1; // no escape to heap
+ call->list = list(call->list, na);
+ n->nbody = list(n->nbody, call);
+
+ fn->nbody = list(fn->nbody, n);
+ break;
+
+ case TSTRUCT:
+ // Walk the struct using memhash for runs of AMEM
+ // and calling specific hash functions for the others.
+ first = T;
+ for(t1=t->type;; t1=t1->down) {
+ if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
+ if(first == T)
+ first = t1;
+ continue;
+ }
+ // Run memhash for fields up to this one.
+ while(first != T && isblanksym(first->sym))
+ first = first->down;
+ if(first != T) {
+ if(first->down == t1)
+ size = first->type->width;
+ else if(t1 == T)
+ size = t->width - first->width; // first->width is offset
+ else
+ size = t1->width - first->width; // both are offsets
+ hashel = hashmem(first->type);
+ // hashel(h, size, &p.first)
+ call = nod(OCALL, hashel, N);
+ call->list = list(call->list, nh);
+ call->list = list(call->list, nodintconst(size));
+ nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages?
+ na = nod(OADDR, nx, N);
+ na->etype = 1; // no escape to heap
+ call->list = list(call->list, na);
+ fn->nbody = list(fn->nbody, call);
+
+ first = T;
+ }
+ if(t1 == T)
+ break;
+
+ // Run hash for this field.
+ hashel = hashfor(t1->type);
+ // hashel(h, size, &p.t1)
+ call = nod(OCALL, hashel, N);
+ call->list = list(call->list, nh);
+ call->list = list(call->list, nodintconst(t1->type->width));
+ nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
+ na = nod(OADDR, nx, N);
+ na->etype = 1; // no escape to heap
+ call->list = list(call->list, na);
+ fn->nbody = list(fn->nbody, call);
+ }
+ break;
+ }
+
+ if(debug['r'])
+ dumplist("genhash body", fn->nbody);
+
+ funcbody(fn);
+ curfn = fn;
+ fn->dupok = 1;
+ typecheck(&fn, Etop);
+ typechecklist(fn->nbody, Etop);
+ curfn = nil;
+
+ // Disable safemode while compiling this code: the code we
+ // generate internally can refer to unsafe.Pointer.
+ // In this case it can happen if we need to generate an ==
+ // for a struct containing a reflect.Value, which itself has
+ // an unexported field of type unsafe.Pointer.
+ old_safemode = safemode;
+ safemode = 0;
+ funccompile(fn, 0);
+ safemode = old_safemode;
+}
+
+// Return node for
+// if p.field != q.field { *eq = false; return }
+static Node*
+eqfield(Node *p, Node *q, Node *field, Node *eq)
+{
+ Node *nif, *nx, *ny;
+
+ nx = nod(OXDOT, p, field);
+ ny = nod(OXDOT, q, field);
+ nif = nod(OIF, N, N);
+ nif->ntest = nod(ONE, nx, ny);
+ nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0)));
+ nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ return nif;
+}
+
+static Node*
+eqmemfunc(vlong size, Type *type)
+{
+ char buf[30];
+ Node *fn;
+
+ switch(size) {
+ default:
+ fn = syslook("memequal", 1);
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ snprint(buf, sizeof buf, "memequal%d", (int)size*8);
+ fn = syslook(buf, 1);
+ break;
+ }
+ argtype(fn, type);
+ argtype(fn, type);
+ return fn;
+}
+
+// Return node for
+// if memequal(size, &p.field, &q.field, eq); !*eq { return }
+static Node*
+eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq)
+{
+ Node *nif, *nx, *ny, *call;
+
+ nx = nod(OADDR, nod(OXDOT, p, field), N);
+ nx->etype = 1; // does not escape
+ ny = nod(OADDR, nod(OXDOT, q, field), N);
+ ny->etype = 1; // does not escape
+ typecheck(&nx, Erv);
+ typecheck(&ny, Erv);
+
+ call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
+ call->list = list(call->list, eq);
+ call->list = list(call->list, nodintconst(size));
+ call->list = list(call->list, nx);
+ call->list = list(call->list, ny);
+
+ nif = nod(OIF, N, N);
+ nif->ninit = list(nif->ninit, call);
+ nif->ntest = nod(ONOT, nod(OIND, eq, N), N);
+ nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ return nif;
+}
+
+/*
+ * Generate a helper function to check equality of two values of type t.
+ */
+void
+geneq(Sym *sym, Type *t)
+{
+ Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange;
+ Type *t1, *first;
+ int old_safemode;
+ int64 size;
+
+ if(debug['r'])
+ print("geneq %S %T\n", sym, t);
+
+ lineno = 1; // less confusing than end of input
+ dclcontext = PEXTERN;
+ markdcl();
+
+ // func sym(eq *bool, s uintptr, p, q *T)
+ fn = nod(ODCLFUNC, N, N);
+ fn->nname = newname(sym);
+ fn->nname->class = PFUNC;
+ tfn = nod(OTFUNC, N, N);
+ fn->nname->ntype = tfn;
+
+ n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL])));
+ tfn->list = list(tfn->list, n);
+ neq = n->left;
+ n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+ tfn->list = list(tfn->list, n);
+ n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+ tfn->list = list(tfn->list, n);
+ np = n->left;
+ n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
+ tfn->list = list(tfn->list, n);
+ nq = n->left;
+
+ funchdr(fn);
+
+ // geneq is only called for types that have equality but
+ // cannot be handled by the standard algorithms,
+ // so t must be either an array or a struct.
+ switch(t->etype) {
+ default:
+ fatal("geneq %T", t);
+ case TARRAY:
+ if(isslice(t))
+ fatal("geneq %T", t);
+ // An array of pure memory would be handled by the
+ // standard memequal, so the element type must not be
+ // pure memory. Even if we unrolled the range loop,
+ // each iteration would be a function call, so don't bother
+ // unrolling.
+ nrange = nod(ORANGE, N, nod(OIND, np, N));
+ ni = newname(lookup("i"));
+ ni->type = types[TINT];
+ nrange->list = list1(ni);
+ nrange->colas = 1;
+ colasdefn(nrange->list, nrange);
+ ni = nrange->list->n;
+
+ // if p[i] != q[i] { *eq = false; return }
+ nx = nod(OINDEX, np, ni);
+ nx->etype = 1; // no bounds check
+ ny = nod(OINDEX, nq, ni);
+ ny->etype = 1; // no bounds check
+
+ nif = nod(OIF, N, N);
+ nif->ntest = nod(ONE, nx, ny);
+ nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0)));
+ nif->nbody = list(nif->nbody, nod(ORETURN, N, N));
+ nrange->nbody = list(nrange->nbody, nif);
+ fn->nbody = list(fn->nbody, nrange);
+
+ // *eq = true;
+ fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
+ break;
+
+ case TSTRUCT:
+ // Walk the struct using memequal for runs of AMEM
+ // and calling specific equality tests for the others.
+ first = T;
+ for(t1=t->type;; t1=t1->down) {
+ if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
+ if(first == T)
+ first = t1;
+ continue;
+ }
+ // Run memequal for fields up to this one.
+ // TODO(rsc): All the calls to newname are wrong for
+ // cross-package unexported fields.
+ while(first != T && isblanksym(first->sym))
+ first = first->down;
+ if(first != T) {
+ if(first->down == t1) {
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ } else if(first->down->down == t1) {
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ first = first->down;
+ if(!isblanksym(first->sym))
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+ } else {
+ // More than two fields: use memequal.
+ if(t1 == T)
+ size = t->width - first->width; // first->width is offset
+ else
+ size = t1->width - first->width; // both are offsets
+ fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq));
+ }
+ first = T;
+ }
+ if(t1 == T)
+ break;
+
+ // Check this field, which is not just memory.
+ fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq));
+ }
+
+ // *eq = true;
+ fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1)));
+ break;
+ }
+
+ if(debug['r'])
+ dumplist("geneq body", fn->nbody);
+
+ funcbody(fn);
+ curfn = fn;
+ fn->dupok = 1;
+ typecheck(&fn, Etop);
+ typechecklist(fn->nbody, Etop);
+ curfn = nil;
+
+ // Disable safemode while compiling this code: the code we
+ // generate internally can refer to unsafe.Pointer.
+ // In this case it can happen if we need to generate an ==
+ // for a struct containing a reflect.Value, which itself has
+ // an unexported field of type unsafe.Pointer.
+ old_safemode = safemode;
+ safemode = 0;
+ funccompile(fn, 0);
+ safemode = old_safemode;
+}
+
static Type*
ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
{
@@ -3331,9 +3019,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
return 1;
}
- t = methtype(t);
+ t = methtype(t, 0);
if(t != T)
- expandmeth(t->sym, t);
+ expandmeth(t);
for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr, 0);
@@ -3410,8 +3098,13 @@ list1(Node *n)
if(n == nil)
return nil;
- if(n->op == OBLOCK && n->ninit == nil)
- return n->list;
+ if(n->op == OBLOCK && n->ninit == nil) {
+ // Flatten list and steal storage.
+ // Poison pointer to catch errant uses.
+ l = n->list;
+ n->list = (NodeList*)1;
+ return l;
+ }
l = mal(sizeof *l);
l->n = n;
l->end = l;
@@ -3453,7 +3146,7 @@ listsort(NodeList** l, int(*f)(Node*, Node*))
listsort(&l1, f);
listsort(&l2, f);
- if ((*f)(l1->n, l2->n) < 0) {
+ if((*f)(l1->n, l2->n) < 0) {
*l = l1;
} else {
*l = l2;
@@ -3469,7 +3162,7 @@ listsort(NodeList** l, int(*f)(Node*, Node*))
// l1 is last one from l1 that is < l2
le = l1->next; // le is the rest of l1, first one that is >= l2
- if (le != nil)
+ if(le != nil)
le->end = (*l)->end;
(*l)->end = l1; // cut *l at l1
@@ -3814,21 +3507,31 @@ ngotype(Node *n)
}
/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx. Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
+ * Convert raw string to the prefix that will be used in the symbol
+ * table. All control characters, space, '%' and '"', as well as
+ * non-7-bit clean bytes turn into %xx. The period needs escaping
+ * only in the last segment of the path, and it makes for happier
+ * users if we escape that as little as possible.
+ *
+ * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too.
*/
static char*
pathtoprefix(char *s)
{
static char hex[] = "0123456789abcdef";
- char *p, *r, *w;
+ char *p, *r, *w, *l;
int n;
+ // find first character past the last slash, if any.
+ l = s;
+ for(r=s; *r; r++)
+ if(*r == '/')
+ l = r+1;
+
// check for chars that need escaping
n = 0;
for(r=s; *r; r++)
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
+ if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
n++;
// quick exit
@@ -3838,7 +3541,7 @@ pathtoprefix(char *s)
// escape
p = mal((r-s)+1+2*n);
for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
+ if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
*w++ = '%';
*w++ = hex[(*r>>4)&0xF];
*w++ = hex[*r&0xF];
@@ -3854,11 +3557,9 @@ mkpkg(Strlit *path)
{
Pkg *p;
int h;
-
- if(strlen(path->s) != path->len) {
- yyerror("import path contains NUL byte");
+
+ if(isbadimport(path))
errorexit();
- }
h = stringhash(path->s) & (nelem(phash)-1);
for(p=phash[h]; p; p=p->link)
@@ -3883,3 +3584,65 @@ strlit(char *s)
t->len = strlen(s);
return t;
}
+
+void
+addinit(Node **np, NodeList *init)
+{
+ Node *n;
+
+ if(init == nil)
+ return;
+
+ n = *np;
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ // There may be multiple refs to this node;
+ // introduce OCONVNOP to hold init list.
+ n = nod(OCONVNOP, n, N);
+ n->type = n->left->type;
+ n->typecheck = 1;
+ *np = n;
+ break;
+ }
+ n->ninit = concat(init, n->ninit);
+ n->ullman = UINF;
+}
+
+int
+isbadimport(Strlit *path)
+{
+ char *s;
+ Rune r;
+
+ if(strlen(path->s) != path->len) {
+ yyerror("import path contains NUL");
+ return 1;
+ }
+
+ s = path->s;
+ while(*s) {
+ s += chartorune(&r, s);
+ if(r == Runeerror) {
+ yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
+ return 1;
+ }
+ if(r < 0x20 || r == 0x7f) {
+ yyerror("import path contains control character: \"%Z\"", path);
+ return 1;
+ }
+ if(r == '\\') {
+ yyerror("import path contains backslash; use slash: \"%Z\"", path);
+ return 1;
+ }
+ if(isspacerune(r)) {
+ yyerror("import path contains space character: \"%Z\"", path);
+ return 1;
+ }
+ if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
+ yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index c2968c44b..f1a95587f 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
enum
@@ -130,6 +132,7 @@ exprcmp(Case *c1, Case *c2)
n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
break;
case CTINT:
+ case CTRUNE:
n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
break;
case CTSTR:
@@ -378,6 +381,7 @@ mkcaselist(Node *sw, int arg)
switch(consttype(n->left)) {
case CTFLT:
case CTINT:
+ case CTRUNE:
case CTSTR:
c->type = Texprconst;
}
@@ -513,8 +517,7 @@ exprswitch(Node *sw)
exprname = N;
cas = nil;
if(arg != Strue && arg != Sfalse) {
- exprname = nod(OXXX, N, N);
- tempname(exprname, sw->ntest->type);
+ exprname = temp(sw->ntest->type);
cas = list1(nod(OAS, exprname, sw->ntest));
typechecklist(cas, Etop);
}
@@ -537,7 +540,7 @@ loop:
}
// deal with the variables one-at-a-time
- if(c0->type != Texprconst) {
+ if(!okforcmp[t->etype] || c0->type != Texprconst) {
a = exprbsw(c0, 1, arg);
cas = list(cas, a);
c0 = c0->link;
@@ -671,20 +674,17 @@ typeswitch(Node *sw)
* predeclare temporary variables
* and the boolean var
*/
- facename = nod(OXXX, N, N);
- tempname(facename, sw->ntest->right->type);
+ facename = temp(sw->ntest->right->type);
a = nod(OAS, facename, sw->ntest->right);
typecheck(&a, Etop);
cas = list(cas, a);
casebody(sw, facename);
- boolname = nod(OXXX, N, N);
- tempname(boolname, types[TBOOL]);
+ boolname = temp(types[TBOOL]);
typecheck(&boolname, Erv);
- hashname = nod(OXXX, N, N);
- tempname(hashname, types[TUINT32]);
+ hashname = temp(types[TUINT32]);
typecheck(&hashname, Erv);
t = sw->ntest->right->type;
@@ -792,7 +792,6 @@ walkswitch(Node *sw)
* cases have OGOTO into statements.
* both have inserted OBREAK statements
*/
- walkstmtlist(sw->ninit);
if(sw->ntest == N) {
sw->ntest = nodbool(1);
typecheck(&sw->ntest, Erv);
@@ -812,14 +811,16 @@ walkswitch(Node *sw)
void
typecheckswitch(Node *n)
{
- int top, lno;
- Type *t;
+ int top, lno, ptr;
+ char *nilonly;
+ Type *t, *missing, *have;
NodeList *l, *ll;
Node *ncase, *nvar;
Node *def;
lno = lineno;
typechecklist(n->ninit, Etop);
+ nilonly = nil;
if(n->ntest != N && n->ntest->op == OTYPESW) {
// type switch
@@ -827,7 +828,7 @@ typecheckswitch(Node *n)
typecheck(&n->ntest->right, Erv);
t = n->ntest->right->type;
if(t != T && t->etype != TINTER)
- yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
+ yyerror("cannot type switch on non-interface value %lN", n->ntest->right);
} else {
// value switch
top = Erv;
@@ -837,6 +838,16 @@ typecheckswitch(Node *n)
t = n->ntest->type;
} else
t = types[TBOOL];
+ if(t) {
+ if(!okforeq[t->etype] || isfixedarray(t))
+ yyerror("cannot switch on %lN", n->ntest);
+ else if(t->etype == TARRAY)
+ nilonly = "slice";
+ else if(t->etype == TFUNC)
+ nilonly = "func";
+ else if(t->etype == TMAP)
+ nilonly = "map";
+ }
}
n->type = t;
@@ -856,21 +867,37 @@ typecheckswitch(Node *n)
typecheck(&ll->n, Erv | Etype);
if(ll->n->type == T || t == T)
continue;
+ setlineno(ncase);
switch(top) {
case Erv: // expression switch
defaultlit(&ll->n, t);
if(ll->n->op == OTYPE)
yyerror("type %T is not an expression", ll->n->type);
- else if(ll->n->type != T && !eqtype(ll->n->type, t))
- yyerror("case %+N in %T switch", ll->n, t);
+ else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
+ if(n->ntest)
+ yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
+ else
+ yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
+ } else if(nilonly && !isconst(ll->n, CTNIL)) {
+ yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
+ }
break;
case Etype: // type switch
- if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
+ if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
;
- else if(ll->n->op != OTYPE && ll->n->type != T) {
- yyerror("%#N is not a type", ll->n);
+ } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||?
+ yyerror("%lN is not a type", ll->n);
// reset to original type
ll->n = n->ntest->right;
+ } else if(ll->n->type->etype != TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) {
+ if(have && !missing->broke && !have->broke)
+ yyerror("impossible type switch case: %lN cannot have dynamic type %T"
+ " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
+ n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
+ missing->sym, missing->type);
+ else if(!missing->broke)
+ yyerror("impossible type switch case: %lN cannot have dynamic type %T"
+ " (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
}
break;
}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 78cdb5bf2..e98d53857 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -10,6 +10,8 @@
* rewrites n->op to be more specific in some cases.
*/
+#include <u.h>
+#include <libc.h>
#include "go.h"
static void implicitstar(Node**);
@@ -18,10 +20,9 @@ static int twoarg(Node*);
static int lookdot(Node*, Type*, int);
static int looktypedot(Node*, Type*, int);
static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
-static Type* lookdot1(Sym *s, Type *t, Type *f, int);
+static Type* lookdot1(Node*, Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
-static void addrescapes(Node*);
static void typecheckas2(Node*);
static void typecheckas(Node*);
static void typecheckfunc(Node*);
@@ -37,12 +38,12 @@ static NodeList* typecheckdefstack;
/*
* resolve ONONAME to definition, if any.
*/
-Node*
+static Node*
resolve(Node *n)
{
Node *r;
- if(n != N && n->op == ONONAME && (r = n->sym->def) != N) {
+ if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) {
if(r->op != OIOTA)
n = r;
else if(n->iota >= 0)
@@ -78,6 +79,7 @@ static char* _typekind[] = {
[TSTRING] = "string",
[TPTR32] = "pointer",
[TPTR64] = "pointer",
+ [TUNSAFEPTR] = "unsafe.Pointer",
[TSTRUCT] = "struct",
[TINTER] = "interface",
[TCHAN] = "chan",
@@ -89,11 +91,15 @@ static char* _typekind[] = {
};
static char*
-typekind(int et)
+typekind(Type *t)
{
+ int et;
static char buf[50];
char *s;
+ if(isslice(t))
+ return "slice";
+ et = t->etype;
if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
return s;
snprint(buf, sizeof buf, "etype=%d", et);
@@ -105,17 +111,15 @@ typekind(int et)
* replaces *np with a new pointer in some cases.
* returns the final value of *np as a convenience.
*/
+static void typecheck1(Node **, int);
Node*
typecheck(Node **np, int top)
{
- int et, aop, op, ptr;
- Node *n, *l, *r;
- NodeList *args;
- int lno, ok, ntop;
- Type *t, *tp, *ft, *missing, *have;
- Sym *sym;
- Val v;
- char *why;
+ Node *n;
+ int lno;
+ Fmt fmt;
+ NodeList *l;
+ static NodeList *tcstack, *tcfree;
// cannot type check until all the source has been parsed
if(!typecheckok)
@@ -152,11 +156,92 @@ typecheck(Node **np, int top)
}
if(n->typecheck == 2) {
- yyerror("typechecking loop");
+ if(nsavederrors+nerrors == 0) {
+ fmtstrinit(&fmt);
+ for(l=tcstack; l; l=l->next)
+ fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n);
+ yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt));
+ }
lineno = lno;
return n;
}
n->typecheck = 2;
+
+ if(tcfree != nil) {
+ l = tcfree;
+ tcfree = l->next;
+ } else
+ l = mal(sizeof *l);
+ l->next = tcstack;
+ l->n = n;
+ tcstack = l;
+
+ typecheck1(&n, top);
+ *np = n;
+ n->typecheck = 1;
+
+ if(tcstack != l)
+ fatal("typecheck stack out of sync");
+ tcstack = l->next;
+ l->next = tcfree;
+ tcfree = l;
+
+ lineno = lno;
+ return n;
+}
+
+/*
+ * does n contain a call or receive operation?
+ */
+static int callrecvlist(NodeList*);
+
+static int
+callrecv(Node *n)
+{
+ if(n == nil)
+ return 0;
+
+ switch(n->op) {
+ case OCALL:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ case ORECV:
+ return 1;
+ }
+
+ return callrecv(n->left) ||
+ callrecv(n->right) ||
+ callrecv(n->ntest) ||
+ callrecv(n->nincr) ||
+ callrecvlist(n->ninit) ||
+ callrecvlist(n->nbody) ||
+ callrecvlist(n->nelse) ||
+ callrecvlist(n->list) ||
+ callrecvlist(n->rlist);
+}
+
+static int
+callrecvlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ if(callrecv(l->n))
+ return 1;
+ return 0;
+}
+
+static void
+typecheck1(Node **np, int top)
+{
+ int et, aop, op, ptr;
+ Node *n, *l, *r;
+ NodeList *args;
+ int ok, ntop;
+ Type *t, *tp, *ft, *missing, *have, *badtype;
+ Val v;
+ char *why;
+
+ n = *np;
if(n->sym) {
if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
@@ -209,6 +294,10 @@ reswitch:
}
n->used = 1;
}
+ if(!(top &Ecall) && isunsafebuiltin(n)) {
+ yyerror("%N is not an expression, must be called", n);
+ goto error;
+ }
ok |= Erv;
goto ret;
@@ -253,13 +342,14 @@ reswitch:
l = typecheck(&n->left, Erv);
switch(consttype(l)) {
case CTINT:
+ case CTRUNE:
v = l->val;
break;
case CTFLT:
v = toint(l->val);
break;
default:
- yyerror("invalid array bound %#N", l);
+ yyerror("invalid array bound %N", l);
goto error;
}
t->bound = mpgetfix(v.u.xval);
@@ -310,7 +400,7 @@ reswitch:
case OTSTRUCT:
ok |= Etype;
n->op = OTYPE;
- n->type = dostruct(n->list, TSTRUCT);
+ n->type = tostruct(n->list);
if(n->type == T)
goto error;
n->list = nil;
@@ -319,7 +409,7 @@ reswitch:
case OTINTER:
ok |= Etype;
n->op = OTYPE;
- n->type = dostruct(n->list, TINTER);
+ n->type = tointerface(n->list);
if(n->type == T)
goto error;
break;
@@ -337,8 +427,9 @@ reswitch:
*/
case OIND:
ntop = Erv | Etype;
- if(!(top & Eaddr))
+ if(!(top & Eaddr)) // The *x in &*x is not an indirect.
ntop |= Eindir;
+ ntop |= top & Ecomplit;
l = typecheck(&n->left, ntop);
if((t = l->type) == T)
goto error;
@@ -350,7 +441,7 @@ reswitch:
goto ret;
}
if(!isptr[t->etype]) {
- yyerror("invalid indirect of %+N", n->left);
+ yyerror("invalid indirect of %lN", n->left);
goto error;
}
ok |= Erv;
@@ -413,15 +504,25 @@ reswitch:
if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
// comparison is okay as long as one side is
// assignable to the other. convert so they have
- // the same type. (the only conversion that isn't
- // a no-op is concrete == interface.)
+ // the same type.
+ //
+ // the only conversion that isn't a no-op is concrete == interface.
+ // in that case, check comparability of the concrete type.
if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
+ if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
+ goto error;
+ }
l = nod(aop, l, N);
l->type = r->type;
l->typecheck = 1;
n->left = l;
t = l->type;
} else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
+ if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
+ goto error;
+ }
r = nod(aop, r, N);
r->type = l->type;
r->typecheck = 1;
@@ -432,28 +533,40 @@ reswitch:
}
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
defaultlit2(&l, &r, 1);
- yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
+ yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
}
if(!okfor[op][et]) {
- notokfor:
- yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et));
+ yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t));
+ goto error;
+ }
+ // okfor allows any array == array, map == map, func == func.
+ // restrict to slice/map/func == nil and nil == slice/map/func.
+ if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) {
+ yyerror("invalid operation: %N (%T cannot be compared)", n, l->type);
goto error;
}
- // okfor allows any array == array;
- // restrict to slice == nil and nil == slice.
- if(l->type->etype == TARRAY && !isslice(l->type))
- goto notokfor;
- if(r->type->etype == TARRAY && !isslice(r->type))
- goto notokfor;
if(isslice(l->type) && !isnil(l) && !isnil(r)) {
- yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
+ yyerror("invalid operation: %N (slice can only be compared to nil)", n);
goto error;
}
+ if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %N (map can only be compared to nil)", n);
+ goto error;
+ }
+ if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %N (func can only be compared to nil)", n);
+ goto error;
+ }
+ if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
+ yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
+ goto error;
+ }
+
t = l->type;
if(iscmp[n->op]) {
evconst(n);
- t = types[TBOOL];
+ t = idealbool;
if(n->op != OLITERAL) {
defaultlit2(&l, &r, 1);
n->left = l;
@@ -487,12 +600,12 @@ reswitch:
n->right = r;
t = r->type;
if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
+ yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
goto error;
}
t = l->type;
if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
- yyerror("invalid operation: %#N (shift of type %T)", n, t);
+ yyerror("invalid operation: %N (shift of type %T)", n, t);
goto error;
}
// no defaultlit for left
@@ -509,7 +622,7 @@ reswitch:
if((t = l->type) == T)
goto error;
if(!okfor[n->op][t->etype]) {
- yyerror("invalid operation: %#O %T", n->op, t);
+ yyerror("invalid operation: %O %T", n->op, t);
goto error;
}
n->type = t;
@@ -523,19 +636,17 @@ reswitch:
typecheck(&n->left, Erv | Eaddr);
if(n->left->type == T)
goto error;
- switch(n->left->op) {
- case OMAPLIT:
- case OSTRUCTLIT:
- case OARRAYLIT:
- break;
- default:
- checklvalue(n->left, "take the address of");
- }
+ checklvalue(n->left, "take the address of");
+ for(l=n->left; l->op == ODOT; l=l->left)
+ l->addrtaken = 1;
+ l->addrtaken = 1;
defaultlit(&n->left, T);
l = n->left;
if((t = l->type) == T)
goto error;
- if(!(top & Eindir) && !n->etype)
+ // top&Eindir means this is &x in *&x. (or the arg to built-in print)
+ // n->etype means code generator flagged it as non-escaping.
+ if(debug['N'] && !(top & Eindir) && !n->etype)
addrescapes(n->left);
n->type = ptrto(t);
goto ret;
@@ -550,40 +661,40 @@ reswitch:
case OXDOT:
n = adddot(n);
n->op = ODOT;
+ if(n->left == N)
+ goto error;
// fall through
case ODOT:
typecheck(&n->left, Erv|Etype);
defaultlit(&n->left, T);
- l = n->left;
- if((t = l->type) == T)
+ if((t = n->left->type) == T)
goto error;
if(n->right->op != ONAME) {
yyerror("rhs of . must be a name"); // impossible
goto error;
}
- sym = n->right->sym;
- if(l->op == OTYPE) {
+
+ if(n->left->op == OTYPE) {
if(!looktypedot(n, t, 0)) {
if(looktypedot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym);
+ yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym);
else
- yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym);
+ yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym);
goto error;
}
if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, sym);
+ yyerror("type %T has no method %hS", n->left->type, n->right->sym);
n->type = T;
goto error;
}
n->op = ONAME;
- n->sym = methodsym(sym, l->type, 0);
- n->type = methodfunc(n->type, l->type);
+ n->sym = n->right->sym;
+ n->type = methodfunc(n->type, n->left->type);
n->xoffset = 0;
n->class = PFUNC;
ok = Erv;
goto ret;
}
- tp = t;
if(isptr[t->etype] && t->type->etype != TINTER) {
t = t->type;
if(t == T)
@@ -593,9 +704,9 @@ reswitch:
}
if(!lookdot(n, t, 0)) {
if(lookdot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
+ yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
else
- yyerror("%#N undefined (type %T has no field or method %S)", n, tp, n->right->sym);
+ yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym);
goto error;
}
switch(n->op) {
@@ -617,7 +728,7 @@ reswitch:
if((t = l->type) == T)
goto error;
if(!isinter(t)) {
- yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t);
+ yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t);
goto error;
}
if(n->right != N) {
@@ -630,12 +741,12 @@ reswitch:
if(n->type != T && n->type->etype != TINTER)
if(!implements(n->type, t, &missing, &have, &ptr)) {
if(have)
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
- " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
+ yyerror("impossible type assertion: %lN cannot have dynamic type %T"
+ " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
l, n->type, missing->sym, have->sym, have->type,
missing->sym, missing->type);
else
- yyerror("impossible type assertion: %+N cannot have dynamic type %T"
+ yyerror("impossible type assertion: %lN cannot have dynamic type %T"
" (missing %S method)", l, n->type, missing->sym);
goto error;
}
@@ -653,13 +764,13 @@ reswitch:
goto error;
switch(t->etype) {
default:
- yyerror("invalid operation: %#N (index of type %T)", n, t);
+ yyerror("invalid operation: %N (index of type %T)", n, t);
goto error;
case TARRAY:
defaultlit(&n->right, T);
if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer array index %#N", n->right);
+ yyerror("non-integer array index %N", n->right);
n->type = t->type;
break;
@@ -675,7 +786,7 @@ reswitch:
case TSTRING:
defaultlit(&n->right, types[TUINT]);
if(n->right->type != T && !isint[n->right->type->etype])
- yyerror("non-integer string index %#N", n->right);
+ yyerror("non-integer string index %N", n->right);
n->type = types[TUINT8];
break;
}
@@ -689,11 +800,11 @@ reswitch:
if((t = l->type) == T)
goto error;
if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t);
+ yyerror("invalid operation: %N (receive from non-chan type %T)", n, t);
goto error;
}
if(!(t->chan & Crecv)) {
- yyerror("invalid operation: %#N (receive from send-only type %T)", n, t);
+ yyerror("invalid operation: %N (receive from send-only type %T)", n, t);
goto error;
}
n->type = t->type;
@@ -701,7 +812,7 @@ reswitch:
case OSEND:
if(top & Erv) {
- yyerror("send statement %#N used as value; use select for non-blocking send", n);
+ yyerror("send statement %N used as value; use select for non-blocking send", n);
goto error;
}
ok |= Etop | Erv;
@@ -712,16 +823,16 @@ reswitch:
if((t = l->type) == T)
goto error;
if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (send to non-chan type %T)", n, t);
+ yyerror("invalid operation: %N (send to non-chan type %T)", n, t);
goto error;
}
if(!(t->chan & Csend)) {
- yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
+ yyerror("invalid operation: %N (send to receive-only type %T)", n, t);
goto error;
}
defaultlit(&n->right, t->type);
r = n->right;
- if((t = r->type) == T)
+ if(r->type == T)
goto error;
r = assignconv(r, l->type->type, "send");
// TODO: more aggressive
@@ -738,14 +849,19 @@ reswitch:
defaultlit(&n->right->left, T);
defaultlit(&n->right->right, T);
if(isfixedarray(n->left->type)) {
+ if(!islvalue(n->left)) {
+ yyerror("invalid operation %N (slice of unaddressable value)", n);
+ goto error;
+ }
n->left = nod(OADDR, n->left, N);
- typecheck(&n->left, top);
+ n->left->implicit = 1;
+ typecheck(&n->left, Erv);
}
if(n->right->left != N) {
if((t = n->right->left->type) == T)
goto error;
if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->left, t);
+ yyerror("invalid slice index %N (type %T)", n->right->left, t);
goto error;
}
}
@@ -753,7 +869,7 @@ reswitch:
if((t = n->right->right->type) == T)
goto error;
if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->right, t);
+ yyerror("invalid slice index %N (type %T)", n->right->right, t);
goto error;
}
}
@@ -777,7 +893,7 @@ reswitch:
n->type = t;
goto ret;
}
- yyerror("cannot slice %#N (type %T)", l, t);
+ yyerror("cannot slice %N (type %T)", l, t);
goto error;
/*
@@ -787,7 +903,7 @@ reswitch:
l = n->left;
if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
if(n->isddd)
- yyerror("invalid use of ... with builtin %#N", l);
+ yyerror("invalid use of ... with builtin %N", l);
n = r;
goto reswitch;
}
@@ -795,7 +911,7 @@ reswitch:
l = n->left;
if(l->op == ONAME && l->etype != 0) {
if(n->isddd && l->etype != OAPPEND)
- yyerror("invalid use of ... with builtin %#N", l);
+ yyerror("invalid use of ... with builtin %N", l);
// builtin: OLEN, OCAP, etc.
n->op = l->etype;
n->left = n->right;
@@ -845,7 +961,7 @@ reswitch:
default:
n->op = OCALLFUNC;
if(t->etype != TFUNC) {
- yyerror("cannot call non-function %#N (type %T)", l, t);
+ yyerror("cannot call non-function %N (type %T)", l, t);
goto error;
}
break;
@@ -866,7 +982,7 @@ reswitch:
}
// multiple return
if(!(top & (Efnstruct | Etop))) {
- yyerror("multiple-value %#N() in single-value context", l);
+ yyerror("multiple-value %N() in single-value context", l);
goto ret;
}
n->type = getoutargx(l->type);
@@ -877,7 +993,7 @@ reswitch:
case OREAL:
case OIMAG:
ok |= Erv;
- if(onearg(n, "%#O", n->op) < 0)
+ if(onearg(n, "%O", n->op) < 0)
goto error;
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
@@ -919,12 +1035,14 @@ reswitch:
}
break;
case TARRAY:
- if(t->bound >= 0 && l->op == ONAME) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], t->bound);
- r->orig = n;
- n = r;
- }
+ if(t->bound < 0) // slice
+ break;
+ if(callrecv(l)) // has call or receive
+ break;
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], t->bound);
+ r->orig = n;
+ n = r;
break;
}
n->type = types[TINT];
@@ -943,7 +1061,7 @@ reswitch:
n->right = r;
if(l->type->etype != r->type->etype) {
badcmplx:
- yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
+ yyerror("invalid operation: %N (complex of types %T, %T)", n, l->type, r->type);
goto error;
}
switch(l->type->etype) {
@@ -967,7 +1085,7 @@ reswitch:
goto ret;
case OCLOSE:
- if(onearg(n, "%#O", n->op) < 0)
+ if(onearg(n, "%O", n->op) < 0)
goto error;
typecheck(&n->left, Erv);
defaultlit(&n->left, T);
@@ -975,12 +1093,41 @@ reswitch:
if((t = l->type) == T)
goto error;
if(t->etype != TCHAN) {
- yyerror("invalid operation: %#N (non-chan type %T)", n, t);
+ yyerror("invalid operation: %N (non-chan type %T)", n, t);
+ goto error;
+ }
+ if(!(t->chan & Csend)) {
+ yyerror("invalid operation: %N (cannot close receive-only channel)", n);
goto error;
}
ok |= Etop;
goto ret;
+ case ODELETE:
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing arguments to delete");
+ goto error;
+ }
+ if(args->next == nil) {
+ yyerror("missing second (key) argument to delete");
+ goto error;
+ }
+ if(args->next->next != nil) {
+ yyerror("too many arguments to delete");
+ goto error;
+ }
+ ok |= Etop;
+ typechecklist(args, Erv);
+ l = args->n;
+ r = args->next->n;
+ if(l->type != T && l->type->etype != TMAP) {
+ yyerror("first argument to delete must be map; have %lT", l->type);
+ goto error;
+ }
+ args->next->n = assignconv(r, l->type->down, "delete");
+ goto ret;
+
case OAPPEND:
ok |= Erv;
args = n->list;
@@ -996,6 +1143,7 @@ reswitch:
yyerror("first argument to append must be slice; have %lT", t);
goto error;
}
+
if(n->isddd) {
if(args->next == nil) {
yyerror("cannot use ... on first argument to append");
@@ -1005,6 +1153,10 @@ reswitch:
yyerror("too many arguments to append");
goto error;
}
+ if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
+ defaultlit(&args->next->n, types[TSTRING]);
+ goto ret;
+ }
args->next->n = assignconv(args->next->n, t->orig, "append");
goto ret;
}
@@ -1028,6 +1180,7 @@ reswitch:
}
n->left = args->n;
n->right = args->next->n;
+ n->list = nil;
n->type = types[TINT];
typecheck(&n->left, Erv);
typecheck(&n->right, Erv);
@@ -1035,15 +1188,15 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
-
+
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
- if (n->left->type->type == types[TUINT8])
+ if(eqtype(n->left->type->type, bytetype))
goto ret;
yyerror("arguments to copy have different element types: %lT and string", n->left->type);
goto error;
}
-
+
if(!isslice(n->left->type) || !isslice(n->right->type)) {
if(!isslice(n->left->type) && !isslice(n->right->type))
yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
@@ -1067,8 +1220,8 @@ reswitch:
if((t = n->left->type) == T || n->type == T)
goto error;
if((n->op = convertop(t, n->type, &why)) == 0) {
- yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
- op = OCONV;
+ yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
+ n->op = OCONV;
}
switch(n->op) {
case OCONVNOP:
@@ -1092,6 +1245,7 @@ reswitch:
yyerror("missing argument to make");
goto error;
}
+ n->list = nil;
l = args->n;
args = args->next;
typecheck(&l, Etype);
@@ -1205,6 +1359,13 @@ reswitch:
case OPRINTN:
ok |= Etop;
typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
+ for(args=n->list; args; args=args->next) {
+ // Special case for print: int constant is int64, not int.
+ if(isconst(args->n, CTINT))
+ defaultlit(&args->n, types[TINT64]);
+ else
+ defaultlit(&args->n, T);
+ }
goto ret;
case OPANIC:
@@ -1232,6 +1393,16 @@ reswitch:
if(n->type == T)
goto error;
goto ret;
+
+ case OITAB:
+ ok |= Erv;
+ typecheck(&n->left, Erv);
+ if((t = n->left->type) == T)
+ goto error;
+ if(t->etype != TINTER)
+ fatal("OITAB of %T", t);
+ n->type = ptrto(types[TUINTPTR]);
+ goto ret;
/*
* statements
@@ -1271,7 +1442,7 @@ reswitch:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv);
if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as for condition", n->ntest);
+ yyerror("non-bool %lN used as for condition", n->ntest);
typecheck(&n->nincr, Etop);
typechecklist(n->nbody, Etop);
goto ret;
@@ -1281,14 +1452,17 @@ reswitch:
typechecklist(n->ninit, Etop);
typecheck(&n->ntest, Erv);
if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
- yyerror("non-bool %+N used as if condition", n->ntest);
+ yyerror("non-bool %lN used as if condition", n->ntest);
typechecklist(n->nbody, Etop);
typechecklist(n->nelse, Etop);
goto ret;
case ORETURN:
ok |= Etop;
- typechecklist(n->list, Erv | Efnstruct);
+ if(count(n->list) == 1)
+ typechecklist(n->list, Erv | Efnstruct);
+ else
+ typechecklist(n->list, Erv);
if(curfn == N) {
yyerror("return outside function");
goto error;
@@ -1368,21 +1542,21 @@ ret:
goto error;
}
if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
- yyerror("%#N is not a type", n);
+ yyerror("%N is not a type", n);
goto error;
}
if((ok & Ecall) && !(top & Ecall)) {
- yyerror("method %#N is not an expression, must be called", n);
+ yyerror("method %N is not an expression, must be called", n);
goto error;
}
// TODO(rsc): simplify
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
- yyerror("%#N used as value", n);
+ yyerror("%N used as value", n);
goto error;
}
if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
if(n->diag == 0) {
- yyerror("%#N not used", n);
+ yyerror("%N not used", n);
n->diag = 1;
}
goto error;
@@ -1395,17 +1569,14 @@ ret:
goto out;
badcall1:
- yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op);
+ yyerror("invalid argument %lN for %O", n->left, n->op);
goto error;
error:
n->type = T;
out:
- lineno = lno;
- n->typecheck = 1;
*np = n;
- return n;
}
static void
@@ -1425,6 +1596,7 @@ implicitstar(Node **nn)
if(!isfixedarray(t))
return;
n = nod(OIND, n, N);
+ n->implicit = 1;
typecheck(&n, Erv);
*nn = n;
}
@@ -1441,14 +1613,14 @@ onearg(Node *n, char *f, ...)
va_start(arg, f);
p = vsmprint(f, arg);
va_end(arg);
- yyerror("missing argument to %s: %#N", p, n);
+ yyerror("missing argument to %s: %N", p, n);
return -1;
}
if(n->list->next != nil) {
va_start(arg, f);
p = vsmprint(f, arg);
va_end(arg);
- yyerror("too many arguments to %s: %#N", p, n);
+ yyerror("too many arguments to %s: %N", p, n);
n->left = n->list->n;
n->list = nil;
return -1;
@@ -1464,17 +1636,17 @@ twoarg(Node *n)
if(n->left != N)
return 0;
if(n->list == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
+ yyerror("missing argument to %O - %N", n->op, n);
return -1;
}
n->left = n->list->n;
if(n->list->next == nil) {
- yyerror("missing argument to %#O - %#N", n->op, n);
+ yyerror("missing argument to %O - %N", n->op, n);
n->list = nil;
return -1;
}
if(n->list->next->next != nil) {
- yyerror("too many arguments to %#O - %#N", n->op, n);
+ yyerror("too many arguments to %O - %N", n->op, n);
n->list = nil;
return -1;
}
@@ -1484,7 +1656,7 @@ twoarg(Node *n)
}
static Type*
-lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
+lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp)
{
Type *r;
@@ -1495,7 +1667,12 @@ lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
if(f->sym != s)
continue;
if(r != T) {
- yyerror("ambiguous DOT reference %T.%S", t, s);
+ if(errnode)
+ yyerror("ambiguous selector %N", errnode);
+ else if(isptr[t->etype])
+ yyerror("ambiguous selector (%T).%S", t, s);
+ else
+ yyerror("ambiguous selector %T.%S", t, s);
break;
}
r = f;
@@ -1512,7 +1689,7 @@ looktypedot(Node *n, Type *t, int dostrcmp)
s = n->right->sym;
if(t->etype == TINTER) {
- f1 = lookdot1(s, t, t->type, dostrcmp);
+ f1 = lookdot1(n, s, t, t->type, dostrcmp);
if(f1 == T)
return 0;
@@ -1529,12 +1706,12 @@ looktypedot(Node *n, Type *t, int dostrcmp)
if(t->sym == S && isptr[t->etype])
tt = t->type;
- f2 = methtype(tt);
+ f2 = methtype(tt, 0);
if(f2 == T)
return 0;
- expandmeth(f2->sym, f2);
- f2 = lookdot1(s, f2, f2->xmethod, dostrcmp);
+ expandmeth(f2);
+ f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp);
if(f2 == T)
return 0;
@@ -1543,7 +1720,7 @@ looktypedot(Node *n, Type *t, int dostrcmp)
&& !isptr[t->etype]
&& f2->embedded != 2
&& !isifacemethod(f2->type)) {
- yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name);
+ yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym);
return 0;
}
@@ -1554,6 +1731,14 @@ looktypedot(Node *n, Type *t, int dostrcmp)
return 1;
}
+static Type*
+derefall(Type* t)
+{
+ while(t && t->etype == tptr)
+ t = t->type;
+ return t;
+}
+
static int
lookdot(Node *n, Type *t, int dostrcmp)
{
@@ -1565,21 +1750,21 @@ lookdot(Node *n, Type *t, int dostrcmp)
dowidth(t);
f1 = T;
if(t->etype == TSTRUCT || t->etype == TINTER)
- f1 = lookdot1(s, t, t->type, dostrcmp);
+ f1 = lookdot1(n, s, t, t->type, dostrcmp);
f2 = T;
if(n->left->type == t || n->left->type->sym == S) {
- f2 = methtype(t);
+ f2 = methtype(t, 0);
if(f2 != T) {
// Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots.
- f2 = lookdot1(s, f2, f2->method, dostrcmp);
+ f2 = lookdot1(n, s, f2, f2->method, dostrcmp);
}
}
if(f1 != T) {
if(f2 != T)
- yyerror("ambiguous DOT reference %S as both field and method",
+ yyerror("%S is both field and method",
n->right->sym);
if(f1->width == BADWIDTH)
fatal("lookdot badwidth %T %p", f1, f1);
@@ -1588,6 +1773,7 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(t->etype == TINTER) {
if(isptr[n->left->type->etype]) {
n->left = nod(OIND, n->left, N); // implicitstar
+ n->left->implicit = 1;
typecheck(&n->left, Erv);
}
n->op = ODOTINTER;
@@ -1602,7 +1788,8 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on");
- addrescapes(n->left);
+ if(debug['N'])
+ addrescapes(n->left);
n->left = nod(OADDR, n->left, N);
n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
@@ -1610,14 +1797,22 @@ lookdot(Node *n, Type *t, int dostrcmp)
n->left = nod(OIND, n->left, N);
n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
+ } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) {
+ yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
+ while(tt->etype == tptr) {
+ n->left = nod(OIND, n->left, N);
+ n->left->implicit = 1;
+ typecheck(&n->left, Etype|Erv);
+ tt = tt->type;
+ }
} else {
- // method is attached to wrong type?
fatal("method mismatch: %T for %T", rcvr, tt);
}
}
n->right = methodname(n->right, n->left->type);
n->xoffset = f2->width;
n->type = f2->type;
+// print("lookdot found [%p] %T\n", f2->type, f2->type);
n->op = ODOTMETH;
return 1;
}
@@ -1656,22 +1851,20 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
for(; tn; tn=tn->down) {
- exportassignok(tn->type, desc);
if(assignop(tn->type, tl->type->type, &why) == 0) {
if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, call, why);
+ yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why);
else
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
}
}
goto out;
}
if(tn == T)
goto notenough;
- exportassignok(tn->type, desc);
if(assignop(tn->type, tl->type, &why) == 0) {
if(call != N)
- yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, call, why);
+ yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why);
else
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
}
@@ -1716,9 +1909,9 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
goto toomany;
if(isddd) {
if(call != N)
- yyerror("invalid use of ... in call to %#N", call);
+ yyerror("invalid use of ... in call to %N", call);
else
- yyerror("invalid use of ... in %#O", op);
+ yyerror("invalid use of ... in %O", op);
}
out:
@@ -1727,80 +1920,20 @@ out:
notenough:
if(call != N)
- yyerror("not enough arguments in call to %#N", call);
+ yyerror("not enough arguments in call to %N", call);
else
- yyerror("not enough arguments to %#O", op);
+ yyerror("not enough arguments to %O", op);
goto out;
toomany:
if(call != N)
- yyerror("too many arguments in call to %#N", call);
+ yyerror("too many arguments in call to %N", call);
else
- yyerror("too many arguments to %#O", op);
+ yyerror("too many arguments to %O", op);
goto out;
}
/*
- * do the export rules allow writing to this type?
- * cannot be implicitly assigning to any type with
- * an unavailable field.
- */
-int
-exportassignok(Type *t, char *desc)
-{
- Type *f;
- Sym *s;
-
- if(t == T)
- return 1;
- if(t->trecur)
- return 1;
- t->trecur = 1;
-
- switch(t->etype) {
- default:
- // most types can't contain others; they're all fine.
- break;
- case TSTRUCT:
- for(f=t->type; f; f=f->down) {
- if(f->etype != TFIELD)
- fatal("structas: not field");
- s = f->sym;
- // s == nil doesn't happen for embedded fields (they get the type symbol).
- // it only happens for fields in a ... struct.
- if(s != nil && !exportname(s->name) && s->pkg != localpkg) {
- char *prefix;
-
- prefix = "";
- if(desc != nil)
- prefix = " in ";
- else
- desc = "";
- yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc);
- goto no;
- }
- if(!exportassignok(f->type, desc))
- goto no;
- }
- break;
-
- case TARRAY:
- if(t->bound < 0) // slices are pointers; that's fine
- break;
- if(!exportassignok(t->type, desc))
- goto no;
- break;
- }
- t->trecur = 0;
- return 1;
-
-no:
- t->trecur = 0;
- return 0;
-}
-
-
-/*
* type check composite
*/
@@ -1845,6 +1978,7 @@ keydup(Node *n, Node *hash[], ulong nhash)
b = 23;
break;
case CTINT:
+ case CTRUNE:
b = mpgetfix(n->val.u.xval);
break;
case CTFLT:
@@ -1872,7 +2006,7 @@ keydup(Node *n, Node *hash[], ulong nhash)
b = cmp.val.u.bval;
if(b) {
// too lazy to print the literal
- yyerror("duplicate key in map literal");
+ yyerror("duplicate key %N in map literal", n);
return;
}
}
@@ -1953,13 +2087,52 @@ inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
return h;
}
+static int
+iscomptype(Type *t)
+{
+ switch(t->etype) {
+ case TARRAY:
+ case TSTRUCT:
+ case TMAP:
+ return 1;
+ case TPTR32:
+ case TPTR64:
+ switch(t->type->etype) {
+ case TARRAY:
+ case TSTRUCT:
+ case TMAP:
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+static void
+pushtype(Node *n, Type *t)
+{
+ if(n == N || n->op != OCOMPLIT || !iscomptype(t))
+ return;
+
+ if(n->right == N) {
+ n->right = typenod(t);
+ n->implicit = 1; // don't print
+ n->right->implicit = 1; // * is okay
+ }
+ else if(debug['s']) {
+ typecheck(&n->right, Etype);
+ if(n->right->type != T && eqtype(n->right->type, t))
+ print("%lL: redundant type: %T\n", n->lineno, t);
+ }
+}
+
static void
typecheckcomplit(Node **np)
{
int bad, i, len, nerr;
- Node *l, *n, **hash;
+ Node *l, *n, *r, **hash;
NodeList *ll;
- Type *t, *f, *pushtype;
+ Type *t, *f;
Sym *s;
int32 lno;
ulong nhash;
@@ -1974,30 +2147,28 @@ typecheckcomplit(Node **np)
yyerror("missing type in composite literal");
goto error;
}
-
+
setlineno(n->right);
l = typecheck(&n->right /* sic */, Etype|Ecomplit);
if((t = l->type) == T)
goto error;
nerr = nerrors;
-
- // can omit type on composite literal values if the outer
- // composite literal is array, slice, or map, and the
- // element type is itself a struct, array, slice, or map.
- pushtype = T;
- if(t->etype == TARRAY || t->etype == TMAP) {
- pushtype = t->type;
- if(pushtype != T) {
- switch(pushtype->etype) {
- case TSTRUCT:
- case TARRAY:
- case TMAP:
- break;
- default:
- pushtype = T;
- break;
- }
+ n->type = t;
+
+ if(isptr[t->etype]) {
+ // For better or worse, we don't allow pointers as the composite literal type,
+ // except when using the &T syntax, which sets implicit on the OIND.
+ if(!n->right->implicit) {
+ yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type);
+ goto error;
+ }
+
+ // Also, the underlying type must be a struct, map, slice, or array.
+ if(!iscomptype(t)) {
+ yyerror("invalid pointer type %T for composite literal", t);
+ goto error;
}
+ t = t->type;
}
switch(t->etype) {
@@ -2040,11 +2211,11 @@ typecheckcomplit(Node **np)
}
}
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "array element");
+ r = l->right;
+ pushtype(r, t->type);
+ typecheck(&r, Erv);
+ defaultlit(&r, t->type);
+ l->right = assignconv(r, t->type, "array element");
}
if(t->bound == -100)
t->bound = len;
@@ -2068,13 +2239,14 @@ typecheckcomplit(Node **np)
typecheck(&l->left, Erv);
defaultlit(&l->left, t->down);
l->left = assignconv(l->left, t->down, "map key");
- keydup(l->left, hash, nhash);
+ if (l->left->op != OCONV)
+ keydup(l->left, hash, nhash);
- if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
- l->right->right = typenod(pushtype);
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "map value");
+ r = l->right;
+ pushtype(r, t->type);
+ typecheck(&r, Erv);
+ defaultlit(&r, t->type);
+ l->right = assignconv(r, t->type, "map value");
}
n->op = OMAPLIT;
break;
@@ -2095,8 +2267,10 @@ typecheckcomplit(Node **np)
s = f->sym;
if(s != nil && !exportname(s->name) && s->pkg != localpkg)
yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
+ // No pushtype allowed here. Must name fields for that.
ll->n = assignconv(ll->n, f->type, "field value");
ll->n = nod(OKEY, newname(f->sym), ll->n);
+ ll->n->left->type = f;
ll->n->left->typecheck = 1;
f = f->down;
}
@@ -2117,26 +2291,31 @@ typecheckcomplit(Node **np)
}
s = l->left->sym;
if(s == S) {
- yyerror("invalid field name %#N in struct initializer", l->left);
+ yyerror("invalid field name %N in struct initializer", l->left);
typecheck(&l->right, Erv);
continue;
}
+
// Sym might have resolved to name in other top-level
// package, because of import dot. Redirect to correct sym
// before we do the lookup.
- if(s->pkg != localpkg)
+ if(s->pkg != localpkg && exportname(s->name))
s = lookup(s->name);
- l->left = newname(s);
- l->left->typecheck = 1;
- f = lookdot1(s, t, t->type, 0);
- typecheck(&l->right, Erv);
+
+ f = lookdot1(nil, s, t, t->type, 0);
if(f == nil) {
- yyerror("unknown %T field '%s' in struct literal", t, s->name);
+ yyerror("unknown %T field '%S' in struct literal", t, s);
continue;
}
+ l->left = newname(s);
+ l->left->typecheck = 1;
+ l->left->type = f;
s = f->sym;
fielddup(newname(s), hash, nhash);
- l->right = assignconv(l->right, f->type, "field value");
+ r = l->right;
+ // No pushtype allowed here. Tried and rejected.
+ typecheck(&r, Erv);
+ l->right = assignconv(r, f->type, "field value");
}
}
n->op = OSTRUCTLIT;
@@ -2144,7 +2323,14 @@ typecheckcomplit(Node **np)
}
if(nerr != nerrors)
goto error;
- n->type = t;
+
+ if(isptr[n->type->etype]) {
+ n = nod(OPTRLIT, n, N);
+ n->typecheck = 1;
+ n->type = n->left->type;
+ n->left->type = t;
+ n->left->typecheck = 1;
+ }
*np = n;
lineno = lno;
@@ -2157,82 +2343,6 @@ error:
}
/*
- * the address of n has been taken and might be used after
- * the current function returns. mark any local vars
- * as needing to move to the heap.
- */
-static void
-addrescapes(Node *n)
-{
- char buf[100];
- switch(n->op) {
- default:
- // probably a type error already.
- // dump("addrescapes", n);
- break;
-
- case ONAME:
- if(n->noescape)
- break;
- switch(n->class) {
- case PPARAMREF:
- addrescapes(n->defn);
- break;
- case PPARAM:
- case PPARAMOUT:
- // if func param, need separate temporary
- // to hold heap pointer.
- // the function type has already been checked
- // (we're in the function body)
- // so the param already has a valid xoffset.
-
- // expression to refer to stack copy
- n->stackparam = nod(OPARAM, n, N);
- n->stackparam->type = n->type;
- n->stackparam->addable = 1;
- if(n->xoffset == BADWIDTH)
- fatal("addrescapes before param assignment");
- n->stackparam->xoffset = n->xoffset;
- n->xoffset = 0;
- // fallthrough
- case PAUTO:
-
- n->class |= PHEAP;
- n->addable = 0;
- n->ullman = 2;
- n->xoffset = 0;
-
- // create stack variable to hold pointer to heap
- n->heapaddr = nod(ONAME, N, N);
- n->heapaddr->type = ptrto(n->type);
- snprint(buf, sizeof buf, "&%S", n->sym);
- n->heapaddr->sym = lookup(buf);
- n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
- n->heapaddr->ullman = 1;
- n->curfn->dcl = list(n->curfn->dcl, n->heapaddr);
-
- break;
- }
- break;
-
- case OIND:
- case ODOTPTR:
- break;
-
- case ODOT:
- case OINDEX:
- // ODOTPTR has already been introduced,
- // so these are the non-pointer ODOT and OINDEX.
- // In &x[0], if x is a slice, then x does not
- // escape--the pointer inside x does, but that
- // is always a heap pointer anyway.
- if(!isslice(n->left->type))
- addrescapes(n->left);
- break;
- }
-}
-
-/*
* lvalue etc
*/
int
@@ -2262,7 +2372,7 @@ static void
checklvalue(Node *n, char *verb)
{
if(!islvalue(n))
- yyerror("cannot %s %#N", verb, n);
+ yyerror("cannot %s %N", verb, n);
}
static void
@@ -2274,7 +2384,7 @@ checkassign(Node *n)
n->etype = 1;
return;
}
- yyerror("cannot assign to %#N", n);
+ yyerror("cannot assign to %N", n);
}
static void
@@ -2309,8 +2419,6 @@ typecheckas(Node *n)
if(n->right && n->right->type != T) {
if(n->left->type != T)
n->right = assignconv(n->right, n->left->type, "assignment");
- else if(!isblank(n->left))
- exportassignok(n->right->type, "assignment");
}
if(n->left->defn == n && n->left->ntype == N) {
defaultlit(&n->right, T);
@@ -2331,10 +2439,9 @@ checkassignto(Type *src, Node *dst)
char *why;
if(assignop(src, dst->type, &why) == 0) {
- yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why);
+ yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why);
return;
}
- exportassignok(dst->type, "multiple assignment");
}
static void
@@ -2381,10 +2488,7 @@ typecheckas2(Node *n)
if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
if(l->type == T)
goto out;
- n->op = OAS2MAPW;
- n->rlist->n = assignconv(r, l->type, "assignment");
- r = n->rlist->next->n;
- n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
+ yyerror("assignment count mismatch: %d = %d (use delete)", cl, cr);
goto out;
}
@@ -2462,12 +2566,11 @@ typecheckfunc(Node *n)
{
Type *t, *rcvr;
-//dump("nname", n->nname);
typecheck(&n->nname, Erv | Easgn);
if((t = n->nname->type) == T)
return;
n->type = t;
-
+ t->nname = n->nname;
rcvr = getthisx(t)->type;
if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
addmethod(n->shortname->sym, t, 1);
@@ -2497,7 +2600,7 @@ stringtoarraylit(Node **np)
while(p < ep)
l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
} else {
- // utf-8 []int
+ // utf-8 []rune
while(p < ep) {
p += chartorune(&r, p);
l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
@@ -2514,7 +2617,7 @@ getforwtype(Node *n)
{
Node *f1, *f2;
- for(f1=f2=n; ; n=n->ntype) {
+ for(f2=n; ; n=n->ntype) {
if((n = resolve(n)) == N || n->op != OTYPE)
return T;
@@ -2537,6 +2640,7 @@ static void
domethod(Node *n)
{
Node *nt;
+ Type *t;
nt = n->type->nname;
typecheck(&nt, Etype);
@@ -2546,6 +2650,20 @@ domethod(Node *n)
n->type->nod = N;
return;
}
+
+ // If we have
+ // type I interface {
+ // M(_ int)
+ // }
+ // then even though I.M looks like it doesn't care about the
+ // value of its argument, a specific implementation of I may
+ // care. The _ would suppress the assignment to that argument
+ // while generating a call, so remove it.
+ for(t=getinargx(nt->type)->type; t; t=t->down) {
+ if(t->sym != nil && strcmp(t->sym->name, "_") == 0)
+ t->sym = nil;
+ }
+
*n->type = *nt->type;
n->type->nod = N;
checkwidth(n->type);
@@ -2602,6 +2720,7 @@ copytype(Node *n, Type *t)
t->vargen = n->vargen;
t->siggen = 0;
t->method = nil;
+ t->xmethod = nil;
t->nod = N;
t->printed = 0;
t->deferwidth = 0;
@@ -2759,7 +2878,7 @@ typecheckdef(Node *n)
goto ret;
}
if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %+N as type %T in const initializer", e, t);
+ yyerror("cannot use %lN as type %T in const initializer", e, t);
goto ret;
}
convlit(&e, t);
@@ -2772,6 +2891,7 @@ typecheckdef(Node *n)
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
n->type = n->ntype->type;
+
if(n->type == T) {
n->diag = 1;
goto ret;
@@ -2816,6 +2936,8 @@ typecheckdef(Node *n)
}
ret:
+ if(n->op != OLITERAL && n->type != T && isideal(n->type))
+ fatal("got %T for %N", n->type, n);
if(typecheckdefstack->n != n)
fatal("typecheckdefstack mismatch");
l = typecheckdefstack;
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index d304077c8..95200ad41 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
/*
* look for
* unsafe.Sizeof
* unsafe.Offsetof
+ * unsafe.Alignof
* rewrite with a constant
*/
Node*
@@ -20,7 +23,7 @@ unsafenmagic(Node *nn)
Val val;
Node *fn;
NodeList *args;
-
+
fn = nn->left;
args = nn->list;
@@ -78,10 +81,10 @@ no:
return N;
bad:
- yyerror("invalid expression %#N", nn);
+ yyerror("invalid expression %N", nn);
v = 0;
goto ret;
-
+
yes:
if(args->next != nil)
yyerror("extra arguments for %S", s);
@@ -91,7 +94,23 @@ ret:
val.u.xval = mal(sizeof(*n->val.u.xval));
mpmovecfix(val.u.xval, v);
n = nod(OLITERAL, N, N);
+ n->orig = nn;
n->val = val;
n->type = types[TUINTPTR];
+ nn->type = types[TUINTPTR];
return n;
}
+
+int
+isunsafebuiltin(Node *n)
+{
+ if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg)
+ return 0;
+ if(strcmp(n->sym->name, "Sizeof") == 0)
+ return 1;
+ if(strcmp(n->sym->name, "Offsetof") == 0)
+ return 1;
+ if(strcmp(n->sym->name, "Alignof") == 0)
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
index db27d7425..c3c627815 100644
--- a/src/cmd/gc/unsafe.go
+++ b/src/cmd/gc/unsafe.go
@@ -6,6 +6,8 @@
// to update builtin.c.boot. This is not done automatically
// to avoid depending on having a working compiler binary.
+// +build ignore
+
package PACKAGE
type Pointer uintptr // not really; filled in by compiler
@@ -14,9 +16,3 @@ type Pointer uintptr // not really; filled in by compiler
func Offsetof(any) uintptr
func Sizeof(any) uintptr
func Alignof(any) uintptr
-
-func Typeof(i interface{}) (typ interface{})
-func Reflect(i interface{}) (typ interface{}, addr Pointer)
-func Unreflect(typ interface{}, addr Pointer) (ret interface{})
-func New(typ interface{}) Pointer
-func NewArray(typ interface{}, n int) Pointer
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 9cd4ee919..7dfd34a7a 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "go.h"
static Node* walkprint(Node*, NodeList**, int);
-static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*);
-static Node* makenewvar(Type*, NodeList**, Node**);
+static Node* mapfndel(char*, Type*);
static Node* ascompatee1(int, Node*, Node*, NodeList**);
static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
-static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**);
+static NodeList* ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**);
static Node* convas(Node*, NodeList**);
static void heapmoves(void);
static NodeList* paramstoheap(Type **argin, int out);
@@ -20,6 +21,7 @@ static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
+static void walkcompare(Node**, NodeList**);
// can this code branch reach the end
// without an unconditional RETURN
@@ -60,7 +62,6 @@ walk(Node *fn)
{
char s[50];
NodeList *l;
- Node *n;
int lno;
curfn = fn;
@@ -74,15 +75,33 @@ walk(Node *fn)
yyerror("function ends without a return statement");
lno = lineno;
+
+ // Final typecheck for any unused variables.
+ // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
+ for(l=fn->dcl; l; l=l->next)
+ if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
+ typecheck(&l->n, Erv | Easgn);
+
+ // Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
+ for(l=fn->dcl; l; l=l->next)
+ if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
+ l->n->defn->left->used++;
+
for(l=fn->dcl; l; l=l->next) {
- n = l->n;
- if(n->op != ONAME || n->class != PAUTO)
+ if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
continue;
- lineno = n->lineno;
- typecheck(&n, Erv | Easgn); // only needed for unused variables
- if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors)
- yyerror("%S declared and not used", n->sym);
- }
+ if(l->n->defn && l->n->defn->op == OTYPESW) {
+ if(l->n->defn->left->used)
+ continue;
+ lineno = l->n->defn->left->lineno;
+ yyerror("%S declared and not used", l->n->sym);
+ l->n->defn->left->used = 1; // suppress repeats
+ } else {
+ lineno = l->n->lineno;
+ yyerror("%S declared and not used", l->n->sym);
+ }
+ }
+
lineno = lno;
if(nerrors != 0)
return;
@@ -119,11 +138,12 @@ static int
paramoutheap(Node *fn)
{
NodeList *l;
-
+
for(l=fn->dcl; l; l=l->next) {
switch(l->n->class) {
+ case PPARAMOUT:
case PPARAMOUT|PHEAP:
- return 1;
+ return l->n->addrtaken;
case PAUTO:
case PAUTO|PHEAP:
// stop early - parameters are over
@@ -147,6 +167,8 @@ walkstmt(Node **np)
setlineno(n);
+ walkstmtlist(n->ninit);
+
switch(n->op) {
default:
if(n->op == ONAME)
@@ -162,7 +184,6 @@ walkstmt(Node **np)
case OAS2DOTTYPE:
case OAS2RECV:
case OAS2FUNC:
- case OAS2MAPW:
case OAS2MAPR:
case OCLOSE:
case OCOPY:
@@ -170,6 +191,7 @@ walkstmt(Node **np)
case OCALLINTER:
case OCALL:
case OCALLFUNC:
+ case ODELETE:
case OSEND:
case ORECV:
case OPRINT:
@@ -177,14 +199,12 @@ walkstmt(Node **np)
case OPANIC:
case OEMPTY:
case ORECOVER:
- if(n->typecheck == 0) {
- dump("missing typecheck:", n);
- fatal("missing typecheck");
- }
+ if(n->typecheck == 0)
+ fatal("missing typecheck: %+N", n);
init = n->ninit;
n->ninit = nil;
walkexpr(&n, &init);
- n->ninit = concat(init, n->ninit);
+ addinit(&n, init);
break;
case OBREAK:
@@ -223,20 +243,18 @@ walkstmt(Node **np)
break;
case OFOR:
- walkstmtlist(n->ninit);
if(n->ntest != N) {
walkstmtlist(n->ntest->ninit);
init = n->ntest->ninit;
n->ntest->ninit = nil;
walkexpr(&n->ntest, &init);
- n->ntest->ninit = concat(init, n->ntest->ninit);
+ addinit(&n->ntest, init);
}
walkstmt(&n->nincr);
walkstmtlist(n->nbody);
break;
case OIF:
- walkstmtlist(n->ninit);
walkexpr(&n->ntest, &n->ninit);
walkstmtlist(n->nbody);
walkstmtlist(n->nelse);
@@ -279,15 +297,18 @@ walkstmt(Node **np)
// OAS2FUNC in disguise
f = n->list->n;
if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
- fatal("expected return of call, have %#N", f);
+ fatal("expected return of call, have %N", f);
n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
break;
}
+
+ // move function calls out, to make reorder3's job easier.
+ walkexprlistsafe(n->list, &n->ninit);
ll = ascompatee(n->op, rl, n->list, &n->ninit);
n->list = reorder3(ll);
break;
}
- ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
+ ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = ll;
break;
@@ -309,6 +330,9 @@ walkstmt(Node **np)
break;
}
+ if(n->op == ONAME)
+ fatal("walkstmt ended up with name: %+N", n);
+
*np = n;
}
@@ -361,6 +385,12 @@ walkexpr(Node **np, NodeList **init)
fatal("walkexpr init == &n->ninit");
}
+ if(n->ninit != nil) {
+ walkstmtlist(n->ninit);
+ *init = concat(*init, n->ninit);
+ n->ninit = nil;
+ }
+
// annoying case - not typechecked
if(n->op == OKEY) {
walkexpr(&n->left, init);
@@ -373,19 +403,14 @@ walkexpr(Node **np, NodeList **init)
if(debug['w'] > 1)
dump("walk-before", n);
- if(n->typecheck != 1) {
- dump("missed typecheck", n);
- fatal("missed typecheck");
- }
-
- t = T;
- et = Txxx;
+ if(n->typecheck != 1)
+ fatal("missed typecheck: %+N\n", n);
switch(n->op) {
default:
dump("walk", n);
fatal("walkexpr: switch 1 unknown op %N", n);
- goto ret;
+ break;
case OTYPE:
case ONONAME:
@@ -407,10 +432,14 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
goto ret;
+ case OITAB:
+ walkexpr(&n->left, init);
+ goto ret;
+
case OLEN:
case OCAP:
walkexpr(&n->left, init);
-
+
// replace len(*[10]int) with 10.
// delayed until now to preserve side effects.
t = n->left->type;
@@ -422,7 +451,7 @@ walkexpr(Node **np, NodeList **init)
n->typecheck = 1;
}
goto ret;
-
+
case OLSH:
case ORSH:
case OAND:
@@ -430,8 +459,6 @@ walkexpr(Node **np, NodeList **init)
case OXOR:
case OSUB:
case OMUL:
- case OEQ:
- case ONE:
case OLT:
case OLE:
case OGE:
@@ -441,7 +468,14 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
-
+
+ case OEQ:
+ case ONE:
+ walkexpr(&n->left, init);
+ walkexpr(&n->right, init);
+ walkcompare(&n, init);
+ goto ret;
+
case OANDAND:
case OOROR:
walkexpr(&n->left, init);
@@ -450,7 +484,7 @@ walkexpr(Node **np, NodeList **init)
// save elsewhere and store on the eventual n->right.
ll = nil;
walkexpr(&n->right, &ll);
- n->right->ninit = concat(n->right->ninit, ll);
+ addinit(&n->right, ll);
goto ret;
case OPRINT:
@@ -482,7 +516,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -499,7 +533,7 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -509,8 +543,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init);
- lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init);
+ lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
ll = concat(ll, lr);
n->left->left = N;
ullmancalc(n->left);
@@ -554,7 +588,7 @@ walkexpr(Node **np, NodeList **init)
walkexprlistsafe(n->list, init);
walkexpr(&r, init);
l = n->list->n;
-
+
// all the really hard stuff - explicit function calls and so on -
// is gone, but map assignments remain.
// if there are map assignments here, assign via
@@ -563,8 +597,7 @@ walkexpr(Node **np, NodeList **init)
// and map index has an implicit one.
lpost = nil;
if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
+ var = temp(l->type);
n->list->n = var;
a = nod(OAS, l, var);
typecheck(&a, Etop);
@@ -572,8 +605,7 @@ walkexpr(Node **np, NodeList **init)
}
l = n->list->next->n;
if(l->op == OINDEXMAP) {
- var = nod(OXXX, N, N);
- tempname(var, l->type);
+ var = temp(l->type);
n->list->next->n = var;
a = nod(OAS, l, var);
typecheck(&a, Etop);
@@ -609,15 +641,13 @@ walkexpr(Node **np, NodeList **init)
n->op = OAS2FUNC;
goto as2func;
- case OAS2MAPW:
- // map[] = a,b - mapassign2
- // a,b = m[i];
+ case ODELETE:
*init = concat(*init, n->ninit);
n->ninit = nil;
- walkexprlistsafe(n->list, init);
l = n->list->n;
- t = l->left->type;
- n = mkcall1(mapfn("mapassign2", t), T, init, typename(t), l->left, l->right, n->rlist->n, n->rlist->next->n);
+ r = n->list->next->n;
+ t = l->type;
+ n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r);
goto ret;
case OAS2DOTTYPE:
@@ -651,7 +681,7 @@ walkexpr(Node **np, NodeList **init)
if(n->op == ODOTTYPE2)
*p++ = '2';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = list1(typename(n->type));
ll = list(ll, n->left);
@@ -682,7 +712,7 @@ walkexpr(Node **np, NodeList **init)
else
*p++ = 'I';
*p = '\0';
-
+
fn = syslook(buf, 1);
ll = nil;
if(!isinter(n->left->type))
@@ -843,6 +873,7 @@ walkexpr(Node **np, NodeList **init)
// delayed until now because "abc"[2] is not
// an ideal constant.
nodconst(n, n->type, n->left->val.u.sval->s[v]);
+ n->typecheck = 1;
}
}
goto ret;
@@ -897,7 +928,7 @@ walkexpr(Node **np, NodeList **init)
}
if(v1 >= 0 && v2 >= 0 && v1 > v2)
yyerror("inverted slice range");
-
+
if(n->op == OSLICEARR)
goto slicearray;
@@ -928,7 +959,7 @@ walkexpr(Node **np, NodeList **init)
l,
nodintconst(t->type->width));
}
- n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
+ n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret;
slicearray:
@@ -953,29 +984,22 @@ walkexpr(Node **np, NodeList **init)
nodintconst(t->type->width));
goto ret;
- case OADDR:;
- Node *nvar, *nstar;
-
- // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation.
- // initialize with
- // nvar := new(*Point);
- // *nvar = Point(1, 2);
- // and replace expression with nvar
- switch(n->left->op) {
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- nvar = makenewvar(n->type, init, &nstar);
- anylit(0, n->left, nstar, init);
- n = nvar;
- goto ret;
- }
-
+ case OADDR:
walkexpr(&n->left, init);
goto ret;
case ONEW:
- n = callnew(n->type->type);
+ if(n->esc == EscNone && n->type->type->width < (1<<16)) {
+ r = temp(n->type->type);
+ r = nod(OAS, r, N); // zero temp
+ typecheck(&r, Etop);
+ *init = list(*init, r);
+ r = nod(OADDR, r->left, N);
+ typecheck(&r, Erv);
+ n = r;
+ } else {
+ n = callnew(n->type->type);
+ }
goto ret;
case OCMPSTR:
@@ -987,6 +1011,7 @@ walkexpr(Node **np, NodeList **init)
r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
typecheck(&r, Erv);
walkexpr(&r, init);
+ r->type = n->type;
n = r;
goto ret;
}
@@ -999,6 +1024,7 @@ walkexpr(Node **np, NodeList **init)
r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0));
typecheck(&r, Erv);
walkexpr(&r, init);
+ r->type = n->type;
n = r;
goto ret;
}
@@ -1025,6 +1051,8 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&r, nil);
}
typecheck(&r, Erv);
+ if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
+ r->type = n->type;
n = r;
goto ret;
@@ -1049,10 +1077,14 @@ walkexpr(Node **np, NodeList **init)
l);
}
goto ret;
-
+
case OAPPEND:
- if(n->isddd)
- n = appendslice(n, init);
+ if(n->isddd) {
+ if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING))
+ n = mkcall("appendstr", n->type, init, typename(n->type), n->list->n, n->list->next->n);
+ else
+ n = appendslice(n, init);
+ }
else
n = append(n, init);
goto ret;
@@ -1061,7 +1093,7 @@ walkexpr(Node **np, NodeList **init)
if(n->right->type->etype == TSTRING)
fn = syslook("slicestringcopy", 1);
else
- fn = syslook("slicecopy", 1);
+ fn = syslook("copy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
n = mkcall1(fn, n->type, init,
@@ -1121,8 +1153,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OARRAYRUNESTR:
- // sliceinttostring([]int) string;
- n = mkcall("sliceinttostring", n->type, init, n->left);
+ // slicerunetostring([]rune) string;
+ n = mkcall("slicerunetostring", n->type, init, n->left);
goto ret;
case OSTRARRAYBYTE:
@@ -1131,8 +1163,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSTRARRAYRUNE:
- // stringtosliceint(string) []int
- n = mkcall("stringtosliceint", n->type, init, n->left);
+ // stringtoslicerune(string) []rune
+ n = mkcall("stringtoslicerune", n->type, init, n->left);
goto ret;
case OCMPIFACE:
@@ -1146,20 +1178,27 @@ walkexpr(Node **np, NodeList **init)
argtype(fn, n->right->type);
argtype(fn, n->left->type);
r = mkcall1(fn, n->type, init, n->left, n->right);
- if(n->etype == ONE) {
+ if(n->etype == ONE)
r = nod(ONOT, r, N);
- typecheck(&r, Erv);
- }
+
+ // check itable/type before full compare.
+ if(n->etype == OEQ)
+ r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+ else
+ r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+ typecheck(&r, Erv);
+ walkexpr(&r, nil);
+ r->type = n->type;
n = r;
goto ret;
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
- nvar = nod(OXXX, N, N);
- tempname(nvar, n->type);
- anylit(0, n, nvar, init);
- n = nvar;
+ case OPTRLIT:
+ var = temp(n->type);
+ anylit(0, n, var, init);
+ n = var;
goto ret;
case OSEND:
@@ -1173,34 +1212,20 @@ walkexpr(Node **np, NodeList **init)
fatal("missing switch %O", n->op);
ret:
+ ullmancalc(n);
+
if(debug['w'] && n != N)
dump("walk", n);
- ullmancalc(n);
lineno = lno;
*np = n;
}
static Node*
-makenewvar(Type *t, NodeList **init, Node **nstar)
-{
- Node *nvar, *nas;
-
- nvar = nod(OXXX, N, N);
- tempname(nvar, t);
- nas = nod(OAS, nvar, callnew(t->type));
- typecheck(&nas, Etop);
- walkexpr(&nas, init);
- *init = list(*init, nas);
-
- *nstar = nod(OIND, nvar, N);
- typecheck(nstar, Erv);
- return nvar;
-}
-
-static Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
+ USED(op);
+
return convas(nod(OAS, l, r), init);
}
@@ -1227,7 +1252,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
// cannot happen: caller checked that lists had same length
if(ll || lr)
- yyerror("error in shape across %O", op);
+ yyerror("error in shape across %+H %O %+H", nl, op, nr);
return nn;
}
@@ -1257,6 +1282,8 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
int ucount;
NodeList *nn, *mm;
+ USED(op);
+
/*
* check assign type list to
* a expression list. called in
@@ -1279,8 +1306,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
// deferred until all the return arguments
// have been pulled from the output arguments
if(fncall(l, r->type)) {
- tmp = nod(OXXX, N, N);
- tempname(tmp, r->type);
+ tmp = temp(r->type);
typecheck(&tmp, Erv);
a = nod(OAS, l, tmp);
a = convas(a, init);
@@ -1298,10 +1324,11 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
}
if(ll != nil || r != T)
- yyerror("assignment count mismatch: %d = %d",
+ yyerror("ascompatet: assignment count mismatch: %d = %d",
count(nl), structcount(*nr));
+
if(ucount)
- fatal("reorder2: too many function calls evaluating parameters");
+ fatal("ascompatet: too many function calls evaluating parameters");
return concat(nn, mm);
}
@@ -1309,7 +1336,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
* package all the arguments that match a ... T parameter into a []T.
*/
static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
+mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc)
{
Node *a, *n;
Type *tslice;
@@ -1318,12 +1345,18 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
tslice->type = l->type->type;
tslice->bound = -1;
- n = nod(OCOMPLIT, N, typenod(tslice));
- n->list = lr0;
- typecheck(&n, Erv);
- if(n->type == T)
- fatal("mkdotargslice: typecheck failed");
- walkexpr(&n, init);
+ if(count(lr0) == 0) {
+ n = nodnil();
+ n->type = tslice;
+ } else {
+ n = nod(OCOMPLIT, N, typenod(tslice));
+ n->list = lr0;
+ n->esc = esc;
+ typecheck(&n, Erv);
+ if(n->type == T)
+ fatal("mkdotargslice: typecheck failed");
+ walkexpr(&n, init);
+ }
a = nod(OAS, nodarg(l, fp), n);
nn = list(nn, convas(a, init));
@@ -1343,7 +1376,6 @@ dumptypes(Type **nl, char *what)
fmtstrinit(&fmt);
fmtprint(&fmt, "\t");
- l = structfirst(&savel, nl);
first = 1;
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
if(first)
@@ -1387,8 +1419,9 @@ dumpnodetypes(NodeList *l, char *what)
* func(expr-list)
*/
static NodeList*
-ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
+ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
+ int esc;
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
@@ -1401,7 +1434,7 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
if(lr)
r = lr->n;
nn = nil;
-
+
// f(g()) where g has multiple return values
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
// optimization - can do block copy
@@ -1411,13 +1444,12 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
nn = list1(convas(nod(OAS, a, r), init));
goto ret;
}
-
+
// conversions involved.
// copy into temporaries.
alist = nil;
for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
- a = nod(OXXX, N, N);
- tempname(a, l->type);
+ a = temp(l->type);
alist = list(alist, a);
}
a = nod(OAS2, N, N);
@@ -1452,7 +1484,10 @@ loop:
// normal case -- make a slice of all
// remaining arguments and pass it to
// the ddd parameter.
- nn = mkdotargslice(lr, nn, l, fp, init);
+ esc = EscUnknown;
+ if(call->right)
+ esc = call->right->esc;
+ nn = mkdotargslice(lr, nn, l, fp, init, esc);
goto ret;
}
@@ -1526,6 +1561,9 @@ walkprint(Node *nn, NodeList **init, int defer)
n = l->n;
if(n->op == OLITERAL) {
switch(n->val.ctype) {
+ case CTRUNE:
+ defaultlit(&n, runetype);
+ break;
case CTINT:
defaultlit(&n, types[TINT64]);
break;
@@ -1668,7 +1706,7 @@ callnew(Type *t)
dowidth(t);
fn = syslook("new", 1);
argtype(fn, t);
- return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
+ return mkcall1(fn, ptrto(t), nil, typename(t));
}
static Node*
@@ -1700,10 +1738,10 @@ convas(Node *n, NodeList **init)
n->left->left, n->left->right, n->right);
goto out;
}
-
+
if(eqtype(lt, rt))
goto out;
-
+
n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
@@ -1720,7 +1758,7 @@ out:
* then it is done first. otherwise must
* make temp variables
*/
-NodeList*
+static NodeList*
reorder1(NodeList *all)
{
Node *f, *a, *n;
@@ -1757,8 +1795,7 @@ reorder1(NodeList *all)
}
// make assignment of fncall to tempname
- a = nod(OXXX, N, N);
- tempname(a, n->right->type);
+ a = temp(n->right->type);
a = nod(OAS, a, n->right);
g = list(g, a);
@@ -1773,28 +1810,242 @@ reorder1(NodeList *all)
return concat(g, r);
}
+static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
+static int aliased(Node*, NodeList*, NodeList*);
+
/*
* from ascompat[ee]
* a,b = c,d
* simultaneous assignment. there cannot
* be later use of an earlier lvalue.
+ *
+ * function calls have been removed.
*/
+static NodeList*
+reorder3(NodeList *all)
+{
+ NodeList *list, *early;
+ Node *l;
+
+ // If a needed expression may be affected by an
+ // earlier assignment, make an early copy of that
+ // expression and use the copy instead.
+ early = nil;
+ for(list=all; list; list=list->next) {
+ l = list->n->left;
+
+ // Save subexpressions needed on left side.
+ // Drill through non-dereferences.
+ for(;;) {
+ if(l->op == ODOT || l->op == OPAREN) {
+ l = l->left;
+ continue;
+ }
+ if(l->op == OINDEX && isfixedarray(l->left->type)) {
+ reorder3save(&l->right, all, list, &early);
+ l = l->left;
+ continue;
+ }
+ break;
+ }
+ switch(l->op) {
+ default:
+ fatal("reorder3 unexpected lvalue %#O", l->op);
+ case ONAME:
+ break;
+ case OINDEX:
+ reorder3save(&l->left, all, list, &early);
+ reorder3save(&l->right, all, list, &early);
+ break;
+ case OIND:
+ case ODOTPTR:
+ reorder3save(&l->left, all, list, &early);
+ }
+ // Save expression on right side.
+ reorder3save(&list->n->right, all, list, &early);
+ }
+
+ return concat(early, all);
+}
+
+static int vmatch2(Node*, Node*);
+static int varexpr(Node*);
+
+/*
+ * if the evaluation of *np would be affected by the
+ * assignments in all up to but not including stop,
+ * copy into a temporary during *early and
+ * replace *np with that temp.
+ */
+static void
+reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
+{
+ Node *n, *q;
+
+ n = *np;
+ if(!aliased(n, all, stop))
+ return;
+
+ q = temp(n->type);
+ q = nod(OAS, q, n);
+ typecheck(&q, Etop);
+ *early = list(*early, q);
+ *np = q->left;
+}
+
+/*
+ * what's the outer value that a write to n affects?
+ * outer value means containing struct or array.
+ */
+static Node*
+outervalue(Node *n)
+{
+ for(;;) {
+ if(n->op == ODOT || n->op == OPAREN) {
+ n = n->left;
+ continue;
+ }
+ if(n->op == OINDEX && isfixedarray(n->left->type)) {
+ n = n->left;
+ continue;
+ }
+ break;
+ }
+ return n;
+}
+
+/*
+ * Is it possible that the computation of n might be
+ * affected by writes in as up to but not including stop?
+ */
+static int
+aliased(Node *n, NodeList *all, NodeList *stop)
+{
+ int memwrite, varwrite;
+ Node *a;
+ NodeList *l;
+
+ if(n == N)
+ return 0;
+
+ // Look for obvious aliasing: a variable being assigned
+ // during the all list and appearing in n.
+ // Also record whether there are any writes to main memory.
+ // Also record whether there are any writes to variables
+ // whose addresses have been taken.
+ memwrite = 0;
+ varwrite = 0;
+ for(l=all; l!=stop; l=l->next) {
+ a = outervalue(l->n->left);
+ if(a->op != ONAME) {
+ memwrite = 1;
+ continue;
+ }
+ switch(n->class) {
+ default:
+ varwrite = 1;
+ continue;
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ if(n->addrtaken) {
+ varwrite = 1;
+ continue;
+ }
+ if(vmatch2(a, n)) {
+ // Direct hit.
+ return 1;
+ }
+ }
+ }
+
+ // The variables being written do not appear in n.
+ // However, n might refer to computed addresses
+ // that are being written.
+
+ // If no computed addresses are affected by the writes, no aliasing.
+ if(!memwrite && !varwrite)
+ return 0;
+
+ // If n does not refer to computed addresses
+ // (that is, if n only refers to variables whose addresses
+ // have not been taken), no aliasing.
+ if(varexpr(n))
+ return 0;
+
+ // Otherwise, both the writes and n refer to computed memory addresses.
+ // Assume that they might conflict.
+ return 1;
+}
+
+/*
+ * does the evaluation of n only refer to variables
+ * whose addresses have not been taken?
+ * (and no other memory)
+ */
+static int
+varexpr(Node *n)
+{
+ if(n == N)
+ return 1;
+
+ switch(n->op) {
+ case OLITERAL:
+ return 1;
+ case ONAME:
+ switch(n->class) {
+ case PAUTO:
+ case PPARAM:
+ case PPARAMOUT:
+ if(!n->addrtaken)
+ return 1;
+ }
+ return 0;
+
+ case OADD:
+ case OSUB:
+ case OOR:
+ case OXOR:
+ case OMUL:
+ case ODIV:
+ case OMOD:
+ case OLSH:
+ case ORSH:
+ case OAND:
+ case OANDNOT:
+ case OPLUS:
+ case OMINUS:
+ case OCOM:
+ case OPAREN:
+ case OANDAND:
+ case OOROR:
+ case ODOT: // but not ODOTPTR
+ case OCONV:
+ case OCONVNOP:
+ case OCONVIFACE:
+ case ODOTTYPE:
+ return varexpr(n->left) && varexpr(n->right);
+ }
+
+ // Be conservative.
+ return 0;
+}
+
+/*
+ * is the name l mentioned in r?
+ */
static int
vmatch2(Node *l, Node *r)
{
NodeList *ll;
- /*
- * isolate all right sides
- */
if(r == N)
return 0;
switch(r->op) {
case ONAME:
// match each right given left
- if(l == r)
- return 1;
+ return l == r;
case OLITERAL:
return 0;
}
@@ -1808,6 +2059,10 @@ vmatch2(Node *l, Node *r)
return 0;
}
+/*
+ * is any name mentioned in l also mentioned in r?
+ * called by sinit.c
+ */
int
vmatch1(Node *l, Node *r)
{
@@ -1846,34 +2101,6 @@ vmatch1(Node *l, Node *r)
return 0;
}
-NodeList*
-reorder3(NodeList *all)
-{
- Node *n1, *n2, *q;
- int c1, c2;
- NodeList *l1, *l2, *r;
-
- r = nil;
- for(l1=all, c1=0; l1; l1=l1->next, c1++) {
- n1 = l1->n;
- for(l2=all, c2=0; l2; l2=l2->next, c2++) {
- n2 = l2->n;
- if(c2 > c1) {
- if(vmatch1(n1->left, n2->right)) {
- // delay assignment to n1->left
- q = nod(OXXX, N, N);
- tempname(q, n1->right->type);
- q = nod(OAS, n1->left, q);
- n1->left = q->right;
- r = list(r, q);
- break;
- }
- }
- }
- }
- return concat(all, r);
-}
-
/*
* walk through argin parameters.
* generate and return code to allocate
@@ -1940,7 +2167,7 @@ heapmoves(void)
{
NodeList *nn;
int32 lno;
-
+
lno = lineno;
lineno = curfn->lineno;
nn = paramstoheap(getthis(curfn->type), 0);
@@ -1960,7 +2187,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
NodeList *args;
if(fn->type == T || fn->type->etype != TFUNC)
- fatal("mkcall %#N %T", fn, fn->type);
+ fatal("mkcall %N %T", fn, fn->type);
args = nil;
n = fn->type->intuple;
@@ -2002,7 +2229,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...)
return r;
}
-static Node*
+Node*
conv(Node *n, Type *t)
{
if(eqtype(n->type, t))
@@ -2043,12 +2270,26 @@ mapfn(char *name, Type *t)
}
static Node*
+mapfndel(char *name, Type *t)
+{
+ Node *fn;
+
+ if(t->etype != TMAP)
+ fatal("mapfn %T", t);
+ fn = syslook(name, 1);
+ argtype(fn, t->down);
+ argtype(fn, t->type);
+ argtype(fn, t->down);
+ return fn;
+}
+
+static Node*
addstr(Node *n, NodeList **init)
{
Node *r, *cat, *typstr;
NodeList *in, *args;
int i, count;
-
+
count = 0;
for(r=n; r->op == OADDSTR; r=r->left)
count++; // r->right
@@ -2077,7 +2318,7 @@ addstr(Node *n, NodeList **init)
typecheck(&r, Erv);
walkexpr(&r, init);
r->type = n->type;
-
+
return r;
}
@@ -2085,7 +2326,7 @@ static Node*
appendslice(Node *n, NodeList **init)
{
Node *f;
-
+
f = syslook("appendslice", 1);
argtype(f, n->type);
argtype(f, n->type->type);
@@ -2099,7 +2340,7 @@ appendslice(Node *n, NodeList **init)
// s := src
// const argc = len(args) - 1
// if cap(s) - len(s) < argc {
-// s = growslice(s, argc)
+// s = growslice(s, argc)
// }
// n := len(s)
// s = s[:n+argc]
@@ -2117,6 +2358,12 @@ append(Node *n, NodeList **init)
walkexprlistsafe(n->list, init);
+ // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+ // and n are name or literal, but those may index the slice we're
+ // modifying here. Fix explicitly.
+ for(l=n->list; l; l=l->next)
+ l->n = cheapexpr(l->n, init);
+
nsrc = n->list->n;
argc = count(n->list) - 1;
if (argc < 1) {
@@ -2125,17 +2372,16 @@ append(Node *n, NodeList **init)
l = nil;
- ns = nod(OXXX, N, N); // var s
- tempname(ns, nsrc->type);
+ ns = temp(nsrc->type);
l = list(l, nod(OAS, ns, nsrc)); // s = src
- na = nodintconst(argc); // const argc
- nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
+ na = nodintconst(argc); // const argc
+ nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
- fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
- argtype(fn, ns->type->type); // 1 old []any
- argtype(fn, ns->type->type); // 2 ret []any
+ fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
+ argtype(fn, ns->type->type); // 1 old []any
+ argtype(fn, ns->type->type); // 2 ret []any
nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
typename(ns->type),
@@ -2143,18 +2389,17 @@ append(Node *n, NodeList **init)
conv(na, types[TINT64]))));
l = list(l, nx);
- nn = nod(OXXX, N, N); // var n
- tempname(nn, types[TINT]);
- l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
+ nn = temp(types[TINT]);
+ l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
- nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
+ nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
- for (a = n->list->next; a != nil; a = a->next) {
- nx = nod(OINDEX, ns, nn); // s[n] ...
- nx->etype = 1; // disable bounds check
- l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
+ for (a = n->list->next; a != nil; a = a->next) {
+ nx = nod(OINDEX, ns, nn); // s[n] ...
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
if (a->next != nil)
l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
}
@@ -2164,3 +2409,188 @@ append(Node *n, NodeList **init)
*init = concat(*init, l);
return ns;
}
+
+static Node*
+eqfor(Type *t)
+{
+ int a;
+ Node *n;
+ Node *ntype;
+ Sym *sym;
+
+ // Should only arrive here with large memory or
+ // a struct/array containing a non-memory field/element.
+ // Small memory is handled inline, and single non-memory
+ // is handled during type check (OCMPSTR etc).
+ a = algtype1(t, nil);
+ if(a != AMEM && a != -1)
+ fatal("eqfor %T", t);
+
+ if(a == AMEM) {
+ n = syslook("memequal", 1);
+ argtype(n, t);
+ argtype(n, t);
+ return n;
+ }
+
+ sym = typesymprefix(".eq", t);
+ n = newname(sym);
+ n->class = PFUNC;
+ ntype = nod(OTFUNC, N, N);
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL]))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+ typecheck(&ntype, Etype);
+ n->type = ntype->type;
+ return n;
+}
+
+static int
+countfield(Type *t)
+{
+ Type *t1;
+ int n;
+
+ n = 0;
+ for(t1=t->type; t1!=T; t1=t1->down)
+ n++;
+ return n;
+}
+
+static void
+walkcompare(Node **np, NodeList **init)
+{
+ Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr;
+ int andor, i;
+ Type *t, *t1;
+ static Node *tempbool;
+
+ n = *np;
+
+ // Must be comparison of array or struct.
+ // Otherwise back end handles it.
+ t = n->left->type;
+ switch(t->etype) {
+ default:
+ return;
+ case TARRAY:
+ if(isslice(t))
+ return;
+ break;
+ case TSTRUCT:
+ break;
+ }
+
+ if(!islvalue(n->left) || !islvalue(n->right))
+ goto hard;
+
+ l = temp(ptrto(t));
+ a = nod(OAS, l, nod(OADDR, n->left, N));
+ a->right->etype = 1; // addr does not escape
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+
+ r = temp(ptrto(t));
+ a = nod(OAS, r, nod(OADDR, n->right, N));
+ a->right->etype = 1; // addr does not escape
+ typecheck(&a, Etop);
+ *init = list(*init, a);
+
+ expr = N;
+ andor = OANDAND;
+ if(n->op == ONE)
+ andor = OOROR;
+
+ if(t->etype == TARRAY &&
+ t->bound <= 4 &&
+ issimple[t->type->etype]) {
+ // Four or fewer elements of a basic type.
+ // Unroll comparisons.
+ for(i=0; i<t->bound; i++) {
+ li = nod(OINDEX, l, nodintconst(i));
+ ri = nod(OINDEX, r, nodintconst(i));
+ a = nod(n->op, li, ri);
+ if(expr == N)
+ expr = a;
+ else
+ expr = nod(andor, expr, a);
+ }
+ if(expr == N)
+ expr = nodbool(n->op == OEQ);
+ typecheck(&expr, Erv);
+ walkexpr(&expr, init);
+ expr->type = n->type;
+ *np = expr;
+ return;
+ }
+
+ if(t->etype == TSTRUCT && countfield(t) <= 4) {
+ // Struct of four or fewer fields.
+ // Inline comparisons.
+ for(t1=t->type; t1; t1=t1->down) {
+ li = nod(OXDOT, l, newname(t1->sym));
+ ri = nod(OXDOT, r, newname(t1->sym));
+ a = nod(n->op, li, ri);
+ if(expr == N)
+ expr = a;
+ else
+ expr = nod(andor, expr, a);
+ }
+ if(expr == N)
+ expr = nodbool(n->op == OEQ);
+ typecheck(&expr, Erv);
+ walkexpr(&expr, init);
+ expr->type = n->type;
+ *np = expr;
+ return;
+ }
+
+ // Chose not to inline, but still have addresses.
+ // Call equality function directly.
+ // The equality function requires a bool pointer for
+ // storing its address, because it has to be callable
+ // from C, and C can't access an ordinary Go return value.
+ // To avoid creating many temporaries, cache one per function.
+ if(tempbool == N || tempbool->curfn != curfn)
+ tempbool = temp(types[TBOOL]);
+
+ call = nod(OCALL, eqfor(t), N);
+ a = nod(OADDR, tempbool, N);
+ a->etype = 1; // does not escape
+ call->list = list(call->list, a);
+ call->list = list(call->list, nodintconst(t->width));
+ call->list = list(call->list, l);
+ call->list = list(call->list, r);
+ typecheck(&call, Etop);
+ walkstmt(&call);
+ *init = list(*init, call);
+
+ if(n->op == OEQ)
+ r = tempbool;
+ else
+ r = nod(ONOT, tempbool, N);
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ *np = r;
+ return;
+
+hard:
+ // Cannot take address of one or both of the operands.
+ // Instead, pass directly to runtime helper function.
+ // Easier on the stack than passing the address
+ // of temporary variables, because we are better at reusing
+ // the argument space than temporary variable space.
+ fn = syslook("equal", 1);
+ l = n->left;
+ r = n->right;
+ argtype(fn, n->left->type);
+ argtype(fn, n->left->type);
+ r = mkcall1(fn, n->type, init, typename(n->left->type), l, r);
+ if(n->op == ONE) {
+ r = nod(ONOT, r, N);
+ typecheck(&r, Erv);
+ }
+ *np = r;
+ return;
+}
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
new file mode 100644
index 000000000..97bf233eb
--- /dev/null
+++ b/src/cmd/gc/y.tab.c
@@ -0,0 +1,5540 @@
+/* A Bison parser, made by GNU Bison 2.5. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.5"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Copy the first part of user declarations. */
+
+/* Line 268 of yacc.c */
+#line 20 "go.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
+#include <libc.h>
+#include "go.h"
+
+static void fixlbrace(int);
+
+
+/* Line 268 of yacc.c */
+#line 81 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 1
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LLITERAL = 258,
+ LASOP = 259,
+ LBREAK = 260,
+ LCASE = 261,
+ LCHAN = 262,
+ LCOLAS = 263,
+ LCONST = 264,
+ LCONTINUE = 265,
+ LDDD = 266,
+ LDEFAULT = 267,
+ LDEFER = 268,
+ LELSE = 269,
+ LFALL = 270,
+ LFOR = 271,
+ LFUNC = 272,
+ LGO = 273,
+ LGOTO = 274,
+ LIF = 275,
+ LIMPORT = 276,
+ LINTERFACE = 277,
+ LMAP = 278,
+ LNAME = 279,
+ LPACKAGE = 280,
+ LRANGE = 281,
+ LRETURN = 282,
+ LSELECT = 283,
+ LSTRUCT = 284,
+ LSWITCH = 285,
+ LTYPE = 286,
+ LVAR = 287,
+ LANDAND = 288,
+ LANDNOT = 289,
+ LBODY = 290,
+ LCOMM = 291,
+ LDEC = 292,
+ LEQ = 293,
+ LGE = 294,
+ LGT = 295,
+ LIGNORE = 296,
+ LINC = 297,
+ LLE = 298,
+ LLSH = 299,
+ LLT = 300,
+ LNE = 301,
+ LOROR = 302,
+ LRSH = 303,
+ NotPackage = 304,
+ NotParen = 305,
+ PreferToRightParen = 306
+ };
+#endif
+/* Tokens. */
+#define LLITERAL 258
+#define LASOP 259
+#define LBREAK 260
+#define LCASE 261
+#define LCHAN 262
+#define LCOLAS 263
+#define LCONST 264
+#define LCONTINUE 265
+#define LDDD 266
+#define LDEFAULT 267
+#define LDEFER 268
+#define LELSE 269
+#define LFALL 270
+#define LFOR 271
+#define LFUNC 272
+#define LGO 273
+#define LGOTO 274
+#define LIF 275
+#define LIMPORT 276
+#define LINTERFACE 277
+#define LMAP 278
+#define LNAME 279
+#define LPACKAGE 280
+#define LRANGE 281
+#define LRETURN 282
+#define LSELECT 283
+#define LSTRUCT 284
+#define LSWITCH 285
+#define LTYPE 286
+#define LVAR 287
+#define LANDAND 288
+#define LANDNOT 289
+#define LBODY 290
+#define LCOMM 291
+#define LDEC 292
+#define LEQ 293
+#define LGE 294
+#define LGT 295
+#define LIGNORE 296
+#define LINC 297
+#define LLE 298
+#define LLSH 299
+#define LLT 300
+#define LNE 301
+#define LOROR 302
+#define LRSH 303
+#define NotPackage 304
+#define NotParen 305
+#define PreferToRightParen 306
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 293 of yacc.c */
+#line 28 "go.y"
+
+ Node* node;
+ NodeList* list;
+ Type* type;
+ Sym* sym;
+ struct Val val;
+ int i;
+
+
+
+/* Line 293 of yacc.c */
+#line 230 "y.tab.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 343 of yacc.c */
+#line 242 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 4
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 2131
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 76
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 138
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 344
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 653
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 306
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 69, 2, 2, 64, 55, 56, 2,
+ 59, 60, 53, 49, 75, 50, 63, 54, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 66, 62,
+ 2, 65, 2, 73, 74, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 71, 2, 72, 52, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 67, 51, 68, 70, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 57, 58, 61
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 8, 9, 13, 14, 18, 19, 23,
+ 26, 32, 36, 40, 43, 45, 49, 51, 54, 57,
+ 62, 63, 65, 66, 71, 72, 74, 76, 78, 80,
+ 83, 89, 93, 96, 102, 110, 114, 117, 123, 127,
+ 129, 132, 137, 141, 146, 150, 152, 155, 157, 159,
+ 162, 164, 168, 172, 176, 179, 182, 186, 192, 198,
+ 201, 202, 207, 208, 212, 213, 216, 217, 222, 227,
+ 232, 238, 240, 242, 245, 246, 250, 252, 256, 257,
+ 258, 259, 267, 268, 271, 274, 275, 276, 284, 285,
+ 291, 293, 297, 301, 305, 309, 313, 317, 321, 325,
+ 329, 333, 337, 341, 345, 349, 353, 357, 361, 365,
+ 369, 373, 375, 378, 381, 384, 387, 390, 393, 396,
+ 399, 403, 409, 416, 418, 420, 424, 430, 436, 441,
+ 448, 450, 455, 461, 467, 475, 477, 478, 482, 484,
+ 489, 491, 495, 497, 499, 501, 503, 505, 507, 509,
+ 510, 512, 514, 516, 518, 523, 525, 527, 529, 532,
+ 534, 536, 538, 540, 542, 546, 548, 550, 552, 555,
+ 557, 559, 561, 563, 567, 569, 571, 573, 575, 577,
+ 579, 581, 583, 585, 589, 594, 599, 602, 606, 612,
+ 614, 616, 619, 623, 629, 633, 639, 643, 647, 653,
+ 662, 668, 677, 683, 684, 688, 689, 691, 695, 697,
+ 702, 705, 706, 710, 712, 716, 718, 722, 724, 728,
+ 730, 734, 736, 740, 744, 747, 752, 756, 762, 768,
+ 770, 774, 776, 779, 781, 785, 790, 792, 795, 798,
+ 800, 802, 806, 807, 810, 811, 813, 815, 817, 819,
+ 821, 823, 825, 827, 829, 830, 835, 837, 840, 843,
+ 846, 849, 852, 855, 857, 861, 863, 867, 869, 873,
+ 875, 879, 881, 885, 887, 889, 893, 897, 898, 901,
+ 902, 904, 905, 907, 908, 910, 911, 913, 914, 916,
+ 917, 919, 920, 922, 923, 925, 926, 928, 933, 938,
+ 944, 951, 956, 961, 963, 965, 967, 969, 971, 973,
+ 975, 977, 979, 983, 988, 994, 999, 1004, 1007, 1010,
+ 1015, 1019, 1023, 1029, 1033, 1038, 1042, 1048, 1050, 1051,
+ 1053, 1057, 1059, 1061, 1064, 1066, 1068, 1074, 1075, 1078,
+ 1080, 1084, 1086, 1090, 1092
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 77, 0, -1, 79, 78, 81, 162, -1, -1, 25,
+ 137, 62, -1, -1, 80, 86, 88, -1, -1, 81,
+ 82, 62, -1, 21, 83, -1, 21, 59, 84, 186,
+ 60, -1, 21, 59, 60, -1, 85, 86, 88, -1,
+ 85, 88, -1, 83, -1, 84, 62, 83, -1, 3,
+ -1, 137, 3, -1, 63, 3, -1, 25, 24, 87,
+ 62, -1, -1, 24, -1, -1, 89, 210, 64, 64,
+ -1, -1, 91, -1, 154, -1, 177, -1, 1, -1,
+ 32, 93, -1, 32, 59, 163, 186, 60, -1, 32,
+ 59, 60, -1, 92, 94, -1, 92, 59, 94, 186,
+ 60, -1, 92, 59, 94, 62, 164, 186, 60, -1,
+ 92, 59, 60, -1, 31, 97, -1, 31, 59, 165,
+ 186, 60, -1, 31, 59, 60, -1, 9, -1, 181,
+ 142, -1, 181, 142, 65, 182, -1, 181, 65, 182,
+ -1, 181, 142, 65, 182, -1, 181, 65, 182, -1,
+ 94, -1, 181, 142, -1, 181, -1, 137, -1, 96,
+ 142, -1, 123, -1, 123, 4, 123, -1, 182, 65,
+ 182, -1, 182, 8, 182, -1, 123, 42, -1, 123,
+ 37, -1, 6, 183, 66, -1, 6, 183, 65, 123,
+ 66, -1, 6, 183, 8, 123, 66, -1, 12, 66,
+ -1, -1, 67, 101, 179, 68, -1, -1, 99, 103,
+ 179, -1, -1, 104, 102, -1, -1, 35, 106, 179,
+ 68, -1, 182, 65, 26, 123, -1, 182, 8, 26,
+ 123, -1, 190, 62, 190, 62, 190, -1, 190, -1,
+ 107, -1, 108, 105, -1, -1, 16, 111, 109, -1,
+ 190, -1, 190, 62, 190, -1, -1, -1, -1, 20,
+ 114, 112, 115, 105, 116, 117, -1, -1, 14, 113,
+ -1, 14, 100, -1, -1, -1, 30, 119, 112, 120,
+ 35, 104, 68, -1, -1, 28, 122, 35, 104, 68,
+ -1, 124, -1, 123, 47, 123, -1, 123, 33, 123,
+ -1, 123, 38, 123, -1, 123, 46, 123, -1, 123,
+ 45, 123, -1, 123, 43, 123, -1, 123, 39, 123,
+ -1, 123, 40, 123, -1, 123, 49, 123, -1, 123,
+ 50, 123, -1, 123, 51, 123, -1, 123, 52, 123,
+ -1, 123, 53, 123, -1, 123, 54, 123, -1, 123,
+ 55, 123, -1, 123, 56, 123, -1, 123, 34, 123,
+ -1, 123, 44, 123, -1, 123, 48, 123, -1, 123,
+ 36, 123, -1, 130, -1, 53, 124, -1, 56, 124,
+ -1, 49, 124, -1, 50, 124, -1, 69, 124, -1,
+ 70, 124, -1, 52, 124, -1, 36, 124, -1, 130,
+ 59, 60, -1, 130, 59, 183, 187, 60, -1, 130,
+ 59, 183, 11, 187, 60, -1, 3, -1, 139, -1,
+ 130, 63, 137, -1, 130, 63, 59, 131, 60, -1,
+ 130, 63, 59, 31, 60, -1, 130, 71, 123, 72,
+ -1, 130, 71, 188, 66, 188, 72, -1, 125, -1,
+ 145, 59, 123, 60, -1, 146, 133, 127, 185, 68,
+ -1, 126, 67, 127, 185, 68, -1, 59, 131, 60,
+ 67, 127, 185, 68, -1, 161, -1, -1, 123, 66,
+ 129, -1, 123, -1, 67, 127, 185, 68, -1, 126,
+ -1, 59, 131, 60, -1, 123, -1, 143, -1, 142,
+ -1, 35, -1, 67, -1, 137, -1, 137, -1, -1,
+ 134, -1, 24, -1, 138, -1, 73, -1, 74, 3,
+ 63, 24, -1, 137, -1, 134, -1, 11, -1, 11,
+ 142, -1, 151, -1, 157, -1, 149, -1, 150, -1,
+ 148, -1, 59, 142, 60, -1, 151, -1, 157, -1,
+ 149, -1, 53, 143, -1, 157, -1, 149, -1, 150,
+ -1, 148, -1, 59, 142, 60, -1, 157, -1, 149,
+ -1, 149, -1, 151, -1, 157, -1, 149, -1, 150,
+ -1, 148, -1, 139, -1, 139, 63, 137, -1, 71,
+ 188, 72, 142, -1, 71, 11, 72, 142, -1, 7,
+ 144, -1, 7, 36, 142, -1, 23, 71, 142, 72,
+ 142, -1, 152, -1, 153, -1, 53, 142, -1, 36,
+ 7, 142, -1, 29, 133, 166, 186, 68, -1, 29,
+ 133, 68, -1, 22, 133, 167, 186, 68, -1, 22,
+ 133, 68, -1, 17, 155, 158, -1, 137, 59, 175,
+ 60, 159, -1, 59, 175, 60, 137, 59, 175, 60,
+ 159, -1, 196, 59, 191, 60, 206, -1, 59, 211,
+ 60, 137, 59, 191, 60, 206, -1, 17, 59, 175,
+ 60, 159, -1, -1, 67, 179, 68, -1, -1, 147,
+ -1, 59, 175, 60, -1, 157, -1, 160, 133, 179,
+ 68, -1, 160, 1, -1, -1, 162, 90, 62, -1,
+ 93, -1, 163, 62, 93, -1, 95, -1, 164, 62,
+ 95, -1, 97, -1, 165, 62, 97, -1, 168, -1,
+ 166, 62, 168, -1, 171, -1, 167, 62, 171, -1,
+ 180, 142, 194, -1, 170, 194, -1, 59, 170, 60,
+ 194, -1, 53, 170, 194, -1, 59, 53, 170, 60,
+ 194, -1, 53, 59, 170, 60, 194, -1, 24, -1,
+ 24, 63, 137, -1, 169, -1, 134, 172, -1, 169,
+ -1, 59, 169, 60, -1, 59, 175, 60, 159, -1,
+ 132, -1, 137, 132, -1, 137, 141, -1, 141, -1,
+ 173, -1, 174, 75, 173, -1, -1, 174, 187, -1,
+ -1, 100, -1, 91, -1, 177, -1, 1, -1, 98,
+ -1, 110, -1, 118, -1, 121, -1, 113, -1, -1,
+ 140, 66, 178, 176, -1, 15, -1, 5, 136, -1,
+ 10, 136, -1, 18, 125, -1, 13, 125, -1, 19,
+ 134, -1, 27, 189, -1, 176, -1, 179, 62, 176,
+ -1, 134, -1, 180, 75, 134, -1, 135, -1, 181,
+ 75, 135, -1, 123, -1, 182, 75, 123, -1, 131,
+ -1, 183, 75, 131, -1, 128, -1, 129, -1, 184,
+ 75, 128, -1, 184, 75, 129, -1, -1, 184, 187,
+ -1, -1, 62, -1, -1, 75, -1, -1, 123, -1,
+ -1, 182, -1, -1, 98, -1, -1, 211, -1, -1,
+ 212, -1, -1, 213, -1, -1, 3, -1, 21, 24,
+ 3, 62, -1, 32, 196, 198, 62, -1, 9, 196,
+ 65, 209, 62, -1, 9, 196, 198, 65, 209, 62,
+ -1, 31, 197, 198, 62, -1, 17, 156, 158, 62,
+ -1, 138, -1, 196, -1, 200, -1, 201, -1, 202,
+ -1, 200, -1, 202, -1, 138, -1, 24, -1, 71,
+ 72, 198, -1, 71, 3, 72, 198, -1, 23, 71,
+ 198, 72, 198, -1, 29, 67, 192, 68, -1, 22,
+ 67, 193, 68, -1, 53, 198, -1, 7, 199, -1,
+ 7, 59, 201, 60, -1, 7, 36, 198, -1, 36,
+ 7, 198, -1, 17, 59, 191, 60, 206, -1, 137,
+ 198, 194, -1, 137, 11, 198, 194, -1, 137, 198,
+ 194, -1, 137, 59, 191, 60, 206, -1, 198, -1,
+ -1, 207, -1, 59, 191, 60, -1, 198, -1, 3,
+ -1, 50, 3, -1, 137, -1, 208, -1, 59, 208,
+ 49, 208, 60, -1, -1, 210, 195, -1, 203, -1,
+ 211, 75, 203, -1, 204, -1, 212, 62, 204, -1,
+ 205, -1, 213, 62, 205, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 124, 124, 133, 140, 151, 151, 166, 167, 170,
+ 171, 172, 175, 208, 219, 220, 223, 230, 237, 246,
+ 259, 260, 267, 267, 280, 284, 285, 289, 294, 300,
+ 304, 308, 312, 318, 324, 330, 335, 339, 343, 349,
+ 355, 359, 363, 369, 373, 379, 380, 384, 390, 399,
+ 405, 409, 414, 426, 442, 447, 454, 474, 492, 501,
+ 520, 519, 531, 530, 561, 564, 571, 570, 581, 587,
+ 596, 607, 613, 616, 624, 623, 634, 640, 652, 656,
+ 661, 651, 673, 676, 680, 687, 691, 686, 709, 708,
+ 724, 725, 729, 733, 737, 741, 745, 749, 753, 757,
+ 761, 765, 769, 773, 777, 781, 785, 789, 793, 797,
+ 802, 808, 809, 813, 824, 828, 832, 836, 841, 845,
+ 855, 859, 864, 872, 876, 877, 888, 892, 896, 900,
+ 904, 905, 911, 918, 924, 931, 934, 941, 947, 948,
+ 955, 956, 974, 975, 978, 981, 985, 996, 1005, 1011,
+ 1014, 1017, 1024, 1025, 1031, 1040, 1048, 1060, 1065, 1071,
+ 1072, 1073, 1074, 1075, 1076, 1082, 1083, 1084, 1085, 1091,
+ 1092, 1093, 1094, 1095, 1101, 1102, 1105, 1108, 1109, 1110,
+ 1111, 1112, 1115, 1116, 1129, 1133, 1138, 1143, 1148, 1152,
+ 1153, 1156, 1162, 1169, 1175, 1182, 1188, 1199, 1210, 1239,
+ 1278, 1301, 1318, 1327, 1330, 1338, 1342, 1346, 1353, 1359,
+ 1364, 1376, 1379, 1387, 1388, 1394, 1395, 1401, 1405, 1411,
+ 1412, 1418, 1422, 1428, 1451, 1456, 1462, 1468, 1475, 1484,
+ 1493, 1508, 1514, 1519, 1523, 1530, 1543, 1544, 1550, 1556,
+ 1559, 1563, 1569, 1572, 1581, 1584, 1585, 1589, 1590, 1596,
+ 1597, 1598, 1599, 1600, 1602, 1601, 1616, 1621, 1625, 1629,
+ 1633, 1637, 1642, 1661, 1667, 1675, 1679, 1685, 1689, 1695,
+ 1699, 1705, 1709, 1718, 1722, 1726, 1730, 1736, 1739, 1747,
+ 1748, 1750, 1751, 1754, 1757, 1760, 1763, 1766, 1769, 1772,
+ 1775, 1778, 1781, 1784, 1787, 1790, 1793, 1799, 1803, 1807,
+ 1811, 1815, 1819, 1837, 1844, 1855, 1856, 1857, 1860, 1861,
+ 1864, 1868, 1878, 1882, 1886, 1890, 1894, 1898, 1902, 1908,
+ 1914, 1922, 1930, 1936, 1943, 1959, 1977, 1981, 1987, 1990,
+ 1993, 1997, 2007, 2011, 2026, 2034, 2035, 2045, 2046, 2049,
+ 2053, 2059, 2063, 2069, 2073
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+const char *yytname[] =
+{
+ "$end", "error", "$undefined", "LLITERAL", "LASOP", "LBREAK", "LCASE",
+ "LCHAN", "LCOLAS", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER",
+ "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT",
+ "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN",
+ "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT",
+ "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE",
+ "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'",
+ "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
+ "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
+ "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
+ "package", "loadsys", "$@1", "imports", "import", "import_stmt",
+ "import_stmt_list", "import_here", "import_package", "import_safety",
+ "import_there", "$@2", "xdcl", "common_dcl", "lconst", "vardcl",
+ "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case",
+ "compound_stmt", "$@3", "caseblock", "$@4", "caseblock_list",
+ "loop_body", "$@5", "range_stmt", "for_header", "for_body", "for_stmt",
+ "$@6", "if_header", "if_stmt", "$@7", "$@8", "$@9", "else",
+ "switch_stmt", "$@10", "$@11", "select_stmt", "$@12", "expr", "uexpr",
+ "pseudocall", "pexpr_no_paren", "start_complit", "keyval", "complitexpr",
+ "pexpr", "expr_or_type", "name_or_type", "lbrace", "new_name",
+ "dcl_name", "onew_name", "sym", "hidden_importsym", "name", "labelname",
+ "dotdotdot", "ntype", "non_expr_type", "non_recvchantype", "convtype",
+ "comptype", "fnret_type", "dotname", "othertype", "ptrtype",
+ "recvchantype", "structtype", "interfacetype", "xfndcl", "fndcl",
+ "hidden_fndcl", "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral",
+ "xdcl_list", "vardcl_list", "constdcl_list", "typedcl_list",
+ "structdcl_list", "interfacedcl_list", "structdcl", "packname", "embed",
+ "interfacedcl", "indcl", "arg_type", "arg_type_list",
+ "oarg_type_list_ocomma", "stmt", "non_dcl_stmt", "$@13", "stmt_list",
+ "new_name_list", "dcl_name_list", "expr_list", "expr_or_type_list",
+ "keyval_list", "braced_keyval_list", "osemi", "ocomma", "oexpr",
+ "oexpr_list", "osimple_stmt", "ohidden_funarg_list",
+ "ohidden_structdcl_list", "ohidden_interfacedcl_list", "oliteral",
+ "hidden_import", "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type",
+ "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan",
+ "hidden_type_func", "hidden_funarg", "hidden_structdcl",
+ "hidden_interfacedcl", "ohidden_funres", "hidden_funres",
+ "hidden_literal", "hidden_constant", "hidden_import_list",
+ "hidden_funarg_list", "hidden_structdcl_list",
+ "hidden_interfacedcl_list", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 43,
+ 45, 124, 94, 42, 47, 37, 38, 304, 305, 40,
+ 41, 306, 59, 46, 36, 61, 58, 123, 125, 33,
+ 126, 91, 93, 63, 64, 44
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 76, 77, 78, 78, 80, 79, 81, 81, 82,
+ 82, 82, 83, 83, 84, 84, 85, 85, 85, 86,
+ 87, 87, 89, 88, 90, 90, 90, 90, 90, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 92,
+ 93, 93, 93, 94, 94, 95, 95, 95, 96, 97,
+ 98, 98, 98, 98, 98, 98, 99, 99, 99, 99,
+ 101, 100, 103, 102, 104, 104, 106, 105, 107, 107,
+ 108, 108, 108, 109, 111, 110, 112, 112, 114, 115,
+ 116, 113, 117, 117, 117, 119, 120, 118, 122, 121,
+ 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 125, 125, 125, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 127, 128, 129, 129,
+ 130, 130, 131, 131, 132, 133, 133, 134, 135, 136,
+ 136, 137, 137, 137, 138, 139, 140, 141, 141, 142,
+ 142, 142, 142, 142, 142, 143, 143, 143, 143, 144,
+ 144, 144, 144, 144, 145, 145, 146, 147, 147, 147,
+ 147, 147, 148, 148, 149, 149, 149, 149, 149, 149,
+ 149, 150, 151, 152, 152, 153, 153, 154, 155, 155,
+ 156, 156, 157, 158, 158, 159, 159, 159, 160, 161,
+ 161, 162, 162, 163, 163, 164, 164, 165, 165, 166,
+ 166, 167, 167, 168, 168, 168, 168, 168, 168, 169,
+ 169, 170, 171, 171, 171, 172, 173, 173, 173, 173,
+ 174, 174, 175, 175, 176, 176, 176, 176, 176, 177,
+ 177, 177, 177, 177, 178, 177, 177, 177, 177, 177,
+ 177, 177, 177, 179, 179, 180, 180, 181, 181, 182,
+ 182, 183, 183, 184, 184, 184, 184, 185, 185, 186,
+ 186, 187, 187, 188, 188, 189, 189, 190, 190, 191,
+ 191, 192, 192, 193, 193, 194, 194, 195, 195, 195,
+ 195, 195, 195, 196, 197, 198, 198, 198, 199, 199,
+ 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
+ 200, 201, 202, 203, 203, 204, 205, 205, 206, 206,
+ 207, 207, 208, 208, 208, 209, 209, 210, 210, 211,
+ 211, 212, 212, 213, 213
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 4, 0, 3, 0, 3, 0, 3, 2,
+ 5, 3, 3, 2, 1, 3, 1, 2, 2, 4,
+ 0, 1, 0, 4, 0, 1, 1, 1, 1, 2,
+ 5, 3, 2, 5, 7, 3, 2, 5, 3, 1,
+ 2, 4, 3, 4, 3, 1, 2, 1, 1, 2,
+ 1, 3, 3, 3, 2, 2, 3, 5, 5, 2,
+ 0, 4, 0, 3, 0, 2, 0, 4, 4, 4,
+ 5, 1, 1, 2, 0, 3, 1, 3, 0, 0,
+ 0, 7, 0, 2, 2, 0, 0, 7, 0, 5,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 5, 6, 1, 1, 3, 5, 5, 4, 6,
+ 1, 4, 5, 5, 7, 1, 0, 3, 1, 4,
+ 1, 3, 1, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 4, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 3, 1, 1, 1, 2, 1,
+ 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 4, 4, 2, 3, 5, 1,
+ 1, 2, 3, 5, 3, 5, 3, 3, 5, 8,
+ 5, 8, 5, 0, 3, 0, 1, 3, 1, 4,
+ 2, 0, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 3, 2, 4, 3, 5, 5, 1,
+ 3, 1, 2, 1, 3, 4, 1, 2, 2, 1,
+ 1, 3, 0, 2, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 4, 1, 2, 2, 2,
+ 2, 2, 2, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 1, 3, 3, 0, 2, 0,
+ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0, 1, 4, 4, 5,
+ 6, 4, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 4, 5, 4, 4, 2, 2, 4,
+ 3, 3, 5, 3, 4, 3, 5, 1, 0, 1,
+ 3, 1, 1, 2, 1, 1, 5, 0, 2, 1,
+ 3, 1, 3, 1, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 5, 0, 3, 0, 1, 0, 7, 0, 22, 151,
+ 153, 0, 0, 152, 211, 20, 6, 337, 0, 4,
+ 0, 0, 0, 21, 0, 0, 0, 16, 0, 0,
+ 9, 22, 0, 8, 28, 123, 149, 0, 39, 149,
+ 0, 256, 74, 0, 0, 0, 78, 0, 0, 285,
+ 88, 0, 85, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 283, 0, 25, 0, 249, 250,
+ 253, 251, 252, 50, 90, 130, 140, 111, 156, 155,
+ 124, 0, 0, 0, 176, 189, 190, 26, 208, 0,
+ 135, 27, 0, 19, 0, 0, 0, 0, 0, 0,
+ 338, 154, 11, 14, 279, 18, 22, 13, 17, 150,
+ 257, 147, 0, 0, 0, 0, 155, 182, 186, 172,
+ 170, 171, 169, 258, 130, 0, 287, 242, 0, 203,
+ 130, 261, 287, 145, 146, 0, 0, 269, 286, 262,
+ 0, 0, 287, 0, 0, 36, 48, 0, 29, 267,
+ 148, 0, 119, 114, 115, 118, 112, 113, 0, 0,
+ 142, 0, 143, 167, 165, 166, 116, 117, 0, 284,
+ 0, 212, 0, 32, 0, 0, 0, 0, 0, 55,
+ 0, 0, 0, 54, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 136, 0,
+ 0, 283, 254, 0, 136, 210, 0, 0, 0, 0,
+ 303, 0, 0, 203, 0, 0, 304, 0, 0, 23,
+ 280, 0, 12, 242, 0, 0, 187, 163, 161, 162,
+ 159, 160, 191, 0, 0, 288, 72, 0, 75, 0,
+ 71, 157, 236, 155, 239, 144, 240, 281, 0, 242,
+ 0, 197, 79, 76, 151, 0, 196, 0, 279, 233,
+ 221, 0, 64, 0, 0, 194, 265, 279, 219, 231,
+ 295, 0, 86, 38, 217, 279, 49, 31, 213, 279,
+ 0, 0, 40, 0, 168, 141, 0, 0, 35, 279,
+ 0, 0, 51, 92, 107, 110, 93, 97, 98, 96,
+ 108, 95, 94, 91, 109, 99, 100, 101, 102, 103,
+ 104, 105, 106, 277, 120, 271, 281, 0, 125, 284,
+ 0, 0, 0, 277, 248, 60, 246, 245, 263, 247,
+ 0, 53, 52, 270, 0, 0, 0, 0, 311, 0,
+ 0, 0, 0, 0, 310, 0, 305, 306, 307, 0,
+ 339, 0, 0, 289, 0, 0, 0, 15, 10, 0,
+ 0, 0, 173, 183, 66, 73, 0, 0, 287, 158,
+ 237, 238, 282, 243, 205, 0, 0, 0, 287, 0,
+ 229, 0, 242, 232, 280, 0, 0, 0, 0, 295,
+ 0, 0, 280, 0, 296, 224, 0, 295, 0, 280,
+ 0, 280, 0, 42, 268, 0, 0, 0, 192, 163,
+ 161, 162, 160, 136, 185, 184, 280, 0, 44, 0,
+ 136, 138, 273, 274, 281, 0, 281, 282, 0, 0,
+ 0, 128, 283, 255, 131, 0, 0, 0, 209, 0,
+ 0, 318, 308, 309, 289, 293, 0, 291, 0, 317,
+ 332, 0, 0, 334, 335, 0, 0, 0, 0, 0,
+ 295, 0, 0, 302, 0, 290, 297, 301, 298, 205,
+ 164, 0, 0, 0, 0, 241, 242, 155, 206, 181,
+ 179, 180, 177, 178, 202, 205, 204, 80, 77, 230,
+ 234, 0, 222, 195, 188, 0, 0, 89, 62, 65,
+ 0, 226, 0, 295, 220, 193, 266, 223, 64, 218,
+ 37, 214, 30, 41, 0, 277, 45, 215, 279, 47,
+ 33, 43, 277, 0, 282, 278, 133, 282, 0, 272,
+ 121, 127, 126, 0, 132, 0, 264, 320, 0, 0,
+ 311, 0, 310, 0, 327, 343, 294, 0, 0, 0,
+ 341, 292, 321, 333, 0, 299, 0, 312, 0, 295,
+ 323, 0, 340, 328, 0, 69, 68, 287, 0, 242,
+ 198, 82, 205, 0, 59, 0, 295, 295, 225, 0,
+ 164, 0, 280, 0, 46, 0, 138, 137, 275, 276,
+ 122, 129, 61, 319, 328, 289, 316, 0, 0, 295,
+ 315, 0, 0, 313, 300, 324, 289, 289, 331, 200,
+ 329, 67, 70, 207, 0, 0, 81, 235, 0, 0,
+ 56, 0, 63, 228, 227, 87, 134, 216, 34, 139,
+ 322, 0, 344, 314, 325, 342, 0, 0, 0, 205,
+ 84, 83, 0, 0, 328, 336, 328, 330, 199, 58,
+ 57, 326, 201
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 6, 2, 3, 14, 21, 30, 104, 31,
+ 8, 24, 16, 17, 65, 326, 67, 148, 516, 517,
+ 144, 145, 68, 498, 327, 436, 499, 575, 387, 365,
+ 471, 236, 237, 238, 69, 126, 252, 70, 132, 377,
+ 571, 616, 71, 142, 398, 72, 140, 73, 74, 75,
+ 76, 313, 422, 423, 77, 315, 242, 135, 78, 149,
+ 110, 116, 13, 80, 81, 244, 245, 162, 118, 82,
+ 83, 478, 227, 84, 229, 230, 85, 86, 87, 129,
+ 213, 88, 251, 484, 89, 90, 22, 279, 518, 275,
+ 267, 258, 268, 269, 270, 260, 383, 246, 247, 248,
+ 328, 329, 321, 330, 271, 151, 92, 316, 424, 425,
+ 221, 373, 170, 139, 253, 464, 549, 543, 395, 100,
+ 211, 217, 608, 441, 346, 347, 348, 350, 550, 545,
+ 609, 610, 454, 455, 25, 465, 551, 546
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -551
+static const yytype_int16 yypact[] =
+{
+ -551, 46, 48, 121, -551, 58, -551, 135, -551, -551,
+ -551, 65, 72, -551, 147, 156, -551, -551, 112, -551,
+ 50, 134, 904, -551, 162, 463, 209, -551, 54, 237,
+ -551, 121, 245, -551, -551, -551, 58, 1666, -551, 58,
+ 288, -551, -551, 34, 288, 58, -551, 36, 184, 1467,
+ -551, 36, -551, 316, 462, 1467, 1467, 1467, 1467, 1467,
+ 1467, 1522, 1467, 1467, 965, 198, -551, 506, -551, -551,
+ -551, -551, -551, 796, -551, -551, 195, 1, -551, 199,
+ -551, 207, 216, 36, 221, -551, -551, -551, 226, 53,
+ -551, -551, 108, -551, 214, 110, 269, 214, 214, 233,
+ -551, -551, -551, -551, 238, -551, -551, -551, -551, -551,
+ -551, -551, 242, 1691, 1691, 1691, -551, 240, -551, -551,
+ -551, -551, -551, -551, 154, 1, 1467, 1658, 247, 246,
+ 290, -551, 1467, -551, -551, 419, 1691, 2004, 229, -551,
+ 272, 333, 1467, 258, 1691, -551, -551, 485, -551, -551,
+ -551, 656, -551, -551, -551, -551, -551, -551, 1577, 1522,
+ 2004, 255, -551, 10, -551, 51, -551, -551, 251, 2004,
+ 256, -551, 508, -551, 1632, 1467, 1467, 1467, 1467, -551,
+ 1467, 1467, 1467, -551, 1467, 1467, 1467, 1467, 1467, 1467,
+ 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, -551, 1192,
+ 552, 1467, -551, 1467, -551, -551, 1134, 1467, 1467, 1467,
+ -551, 1203, 58, 246, 260, 332, -551, 1838, 1838, -551,
+ 76, 282, -551, 1658, 344, 1691, -551, -551, -551, -551,
+ -551, -551, -551, 293, 58, -551, -551, 328, -551, 178,
+ 303, 1691, -551, 1658, -551, -551, -551, 295, 308, 1658,
+ 1134, -551, -551, 309, 271, 364, -551, 334, 337, -551,
+ -551, 330, -551, 11, 66, -551, -551, 342, -551, -551,
+ 397, 664, -551, -551, -551, 351, -551, -551, -551, 352,
+ 1467, 58, 343, 1719, -551, 349, 1691, 1691, -551, 356,
+ 1467, 357, 2004, 2075, -551, 2028, 692, 692, 692, 692,
+ -551, 692, 692, 2052, -551, 593, 593, 593, 593, -551,
+ -551, -551, -551, 1247, -551, -551, 22, 1302, -551, 1877,
+ 355, 1060, 1979, 1247, -551, -551, -551, -551, -551, -551,
+ 86, 229, 229, 2004, 1777, 367, 361, 359, -551, 366,
+ 427, 1838, 52, 29, -551, 370, -551, -551, -551, 784,
+ -551, 118, 379, 58, 396, 400, 401, -551, -551, 404,
+ 1691, 409, -551, -551, -551, -551, 1357, 1412, 1467, -551,
+ -551, -551, 1658, -551, 1744, 414, 109, 328, 1467, 58,
+ 416, 423, 1658, -551, 561, 417, 1691, 44, 364, 397,
+ 364, 428, 451, 421, -551, -551, 58, 397, 456, 58,
+ 436, 58, 438, 229, -551, 1467, 1752, 1691, -551, 24,
+ 171, 287, 338, -551, -551, -551, 58, 439, 229, 1467,
+ -551, 1907, -551, -551, 425, 435, 430, 1522, 446, 448,
+ 453, -551, 1467, -551, -551, 443, 1134, 1060, -551, 1838,
+ 479, -551, -551, -551, 58, 1805, 1838, 58, 1838, -551,
+ -551, 514, 161, -551, -551, 460, 454, 1838, 52, 1838,
+ 397, 58, 58, -551, 458, 459, -551, -551, -551, 1744,
+ -551, 1134, 1467, 1467, 467, -551, 1658, 472, -551, -551,
+ -551, -551, -551, -551, -551, 1744, -551, -551, -551, -551,
+ -551, 477, -551, -551, -551, 1522, 474, -551, -551, -551,
+ 482, -551, 500, 397, -551, -551, -551, -551, -551, -551,
+ -551, -551, -551, 229, 501, 1247, -551, -551, 505, 1632,
+ -551, 229, 1247, 1247, 1247, -551, -551, -551, 503, -551,
+ -551, -551, -551, 511, -551, 137, -551, -551, 518, 528,
+ 532, 534, 535, 530, -551, -551, 537, 533, 1838, 536,
+ -551, 538, -551, -551, 560, -551, 1838, -551, 551, 397,
+ -551, 557, -551, 1830, 151, 2004, 2004, 1467, 558, 1658,
+ -551, 605, 1744, 125, -551, 1060, 397, 397, -551, 75,
+ 360, 554, 58, 563, 357, 556, 2004, -551, -551, -551,
+ -551, -551, -551, -551, 1830, 58, -551, 1805, 1838, 397,
+ -551, 58, 161, -551, -551, -551, 58, 58, -551, -551,
+ -551, -551, -551, -551, 570, 78, -551, -551, 1467, 1467,
+ -551, 1522, 569, -551, -551, -551, -551, -551, -551, -551,
+ -551, 576, -551, -551, -551, -551, 578, 582, 584, 1744,
+ -551, -551, 1931, 1955, 1830, -551, 1830, -551, -551, -551,
+ -551, -551, -551
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -551, -551, -551, -551, -551, -551, -551, -6, -551, -551,
+ 608, -551, -11, -551, -551, 623, -551, -134, -25, 68,
+ -551, -135, -121, -551, 39, -551, -551, -551, 145, 278,
+ -551, -551, -551, -551, -551, -551, 515, 41, -551, -551,
+ -551, -551, -551, -551, -551, -551, -551, 579, 493, 45,
+ -551, -192, 138, -246, 192, -47, 415, 200, -20, 380,
+ 626, -5, 449, 346, -551, 426, 95, 509, -551, -551,
+ -551, -551, -33, 38, -31, -18, -551, -551, -551, -551,
+ -551, 43, 457, -467, -551, -551, -551, -551, -551, -551,
+ -551, -551, 280, -126, -227, 292, -551, 302, -551, -220,
+ -297, 662, -551, -248, -551, -66, 18, 194, -551, -295,
+ -228, -289, -191, -551, -119, -403, -551, -551, -305, -551,
+ -32, -551, 127, -551, 362, 250, 363, 232, 90, 98,
+ -550, -551, -426, 241, -551, 486, -551, -551
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -270
+static const yytype_int16 yytable[] =
+{
+ 12, 174, 376, 359, 119, 235, 121, 240, 274, 259,
+ 320, 235, 323, 278, 161, 32, 109, 79, 570, 109,
+ 107, 235, 103, 32, 433, 131, 554, 428, 435, 375,
+ 385, 111, 456, 426, 111, 380, 389, 391, 128, 393,
+ 111, 539, 173, 164, 630, -176, 4, 400, 146, 150,
+ 495, 402, -208, 27, 205, 450, 496, 27, 9, -172,
+ 199, 417, 150, 214, 200, 216, 218, 138, 18, -175,
+ 388, 133, 201, 5, 9, 120, 9, -176, 9, 27,
+ 122, 495, 9, -172, 501, 124, -208, 496, 133, 130,
+ 380, -172, 507, 127, 651, 222, 652, 427, 46, 163,
+ 9, 457, 451, 134, 165, 617, 174, 10, 11, 28,
+ -174, 452, 497, 29, 102, 257, 207, 29, -208, 390,
+ 134, 266, 243, 10, 11, 10, 11, 10, 11, 381,
+ 111, 10, 11, 618, 19, 525, 111, 528, 146, 29,
+ 536, 164, 150, 625, 239, 325, 7, 289, 437, 10,
+ 11, 228, 228, 228, 438, 560, 231, 231, 231, 15,
+ -260, 500, 491, 502, 450, 228, -260, 150, 20, 212,
+ 231, 437, 648, 208, 228, 26, 636, 486, 461, 231,
+ 23, 164, 228, 209, 11, 9, 366, 231, 535, 228,
+ 619, 620, 631, 462, 231, 318, 33, 163, 578, 437,
+ 621, 79, 165, 637, 638, 592, -170, 349, 226, 232,
+ 233, 451, 228, 437, 357, 32, -260, 231, 243, 611,
+ 581, 515, -260, 564, 93, 331, 332, 585, 522, 363,
+ -170, 261, 125, 101, 10, 11, 125, 163, -170, 276,
+ 105, 533, 165, 367, 243, 79, 282, 235, 108, 474,
+ 409, 141, 411, 209, 605, 136, 568, 235, 259, 488,
+ 171, 228, 198, 228, 509, -147, 231, 511, 231, 291,
+ 430, 623, 624, 202, -229, 203, 150, 587, 589, 228,
+ -175, 228, 9, 204, 231, -174, 231, 228, 11, 206,
+ 583, 35, 231, 215, 634, 37, -259, 219, 403, 164,
+ 220, 223, -259, 234, 209, 112, 249, 262, 418, 228,
+ 47, 48, 9, 250, 231, 285, 79, 51, 273, 353,
+ 361, 410, -171, 286, 228, 228, 412, 622, 287, 231,
+ 231, 10, 11, -229, 379, 354, 369, 453, 345, -229,
+ 9, 479, 358, 481, 355, 356, -171, 61, 349, 614,
+ 519, 360, -259, 362, -171, 163, 482, 254, -259, 64,
+ 165, 10, 11, 364, 257, 368, 397, 243, 374, 477,
+ 372, 378, 266, -169, 489, 143, 506, 243, 408, 111,
+ 529, 414, 415, 117, 331, 332, 263, 111, 380, 10,
+ 11, 111, 264, 382, 146, -173, 150, -169, 228, 384,
+ 394, 265, 386, 231, 392, -169, 10, 11, 405, 164,
+ 228, 150, 480, 399, 401, 231, 413, 483, 416, -173,
+ 228, 432, 419, 513, 228, 231, 444, -173, 445, 231,
+ 446, 79, 79, 447, 448, 458, 479, 521, 481, 349,
+ 541, 463, 548, 254, 228, 228, 235, 453, 612, 231,
+ 231, 482, 479, 453, 481, 408, 561, 349, 466, 117,
+ 117, 117, 467, 468, 469, 163, 79, 482, 449, 470,
+ 165, 243, 94, 117, 485, 254, 460, 164, 255, 379,
+ 95, 494, 117, 490, 96, 493, 9, 256, 503, 505,
+ 117, 508, 10, 11, 97, 98, 510, 117, 512, 520,
+ 524, 226, 514, 526, 263, 527, 530, 480, 531, 9,
+ 264, 534, 483, 532, 228, 340, 519, 553, 563, 231,
+ 117, 147, 555, 480, 10, 11, 556, 99, 483, 567,
+ 9, 569, 9, 163, 462, 10, 11, 572, 165, 479,
+ 574, 481, 576, 210, 210, 277, 210, 210, 152, 153,
+ 154, 155, 156, 157, 482, 166, 167, 228, 10, 11,
+ 577, 580, 231, 590, 243, 172, 537, 582, 288, 117,
+ 79, 117, 544, 547, 529, 552, 9, 150, 593, 10,
+ 11, 10, 11, 591, 557, 254, 559, 117, 594, 117,
+ 349, -151, 541, 595, -152, 117, 548, 453, 596, 597,
+ 601, 349, 349, 164, 600, 598, 479, 228, 481, 602,
+ 480, 317, 231, 604, 584, 483, 606, 117, 613, 615,
+ 255, 482, 626, 628, 629, 10, 11, 177, 137, 117,
+ 639, 437, 117, 117, 10, 11, 644, 185, 645, 106,
+ 160, 189, 646, 169, 647, 66, 194, 195, 196, 197,
+ 627, 152, 156, 579, 640, 487, 641, 272, 370, 163,
+ 344, 404, 588, 37, 165, 123, 344, 344, 284, 371,
+ 352, 37, 504, 112, 475, 599, 492, 480, 47, 48,
+ 9, 112, 483, 603, 91, 51, 47, 48, 9, 573,
+ 538, 635, 224, 51, 562, 632, 442, 443, 351, 558,
+ 224, 0, 0, 0, 0, 0, 117, 0, 0, 114,
+ 0, 0, 0, 0, 0, 225, 0, 114, 117, 0,
+ 117, 280, 0, 225, 544, 633, 177, 64, 117, 10,
+ 11, 281, 117, 0, 0, 64, 185, 10, 11, 396,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 0,
+ 0, 0, 117, 117, 292, 293, 294, 295, 0, 296,
+ 297, 298, 0, 299, 300, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 310, 311, 312, 0, 160, 0,
+ 319, 0, 322, 344, 0, 0, 137, 137, 333, 0,
+ 344, 334, 0, 0, 0, 459, 0, 0, 344, 0,
+ 175, 335, 0, 0, -269, 0, 336, 337, 338, 0,
+ 0, 0, 0, 339, 0, 117, 0, 0, 0, 0,
+ 340, 0, 117, 0, 0, 0, 0, 0, 0, 176,
+ 177, 117, 178, 179, 180, 181, 182, 341, 183, 184,
+ 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 0, 0, 343, 0, 0, 11, 137,
+ 0, -269, 0, 0, 0, 117, 0, 0, 0, 137,
+ 0, -269, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 344, 0,
+ 0, 0, 421, 0, 542, 344, 160, 344, 0, 0,
+ 0, 0, 421, 0, -2, 34, 344, 35, 344, 36,
+ 0, 37, 0, 38, 39, 117, 0, 40, 117, 41,
+ 42, 43, 44, 45, 46, 0, 47, 48, 9, 0,
+ 0, 49, 50, 51, 52, 53, 54, 0, 0, 0,
+ 55, 0, 0, 0, 0, 137, 137, 0, 0, 0,
+ 0, 0, 0, 56, 57, 0, 58, 59, 0, 0,
+ 60, 0, 0, 61, 0, 0, -24, 0, 35, 0,
+ 0, 0, 37, 62, 63, 64, 168, 10, 11, 0,
+ 0, 0, 112, 0, 137, 117, 0, 47, 48, 9,
+ 0, 0, 0, 0, 51, 0, 0, 344, 137, 0,
+ 0, 55, 0, 0, 0, 344, 160, 0, 0, 0,
+ 0, 169, 344, 0, 56, 57, 0, 58, 59, 0,
+ 0, 60, 0, 0, 61, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 63, 64, 0, 10, 11,
+ 0, 0, 0, 344, 0, 0, 542, 344, 0, 0,
+ 0, 565, 566, 0, 0, 0, 0, 0, 0, 0,
+ 0, 324, 0, 35, 0, 36, -244, 37, 0, 38,
+ 39, 0, -244, 40, 160, 41, 42, 112, 44, 45,
+ 46, 0, 47, 48, 9, 0, 0, 49, 50, 51,
+ 52, 53, 54, 344, 421, 344, 55, 0, 0, 0,
+ 0, 421, 586, 421, 0, 0, 0, 0, 0, 56,
+ 57, 0, 58, 59, 0, 0, 60, 0, 0, 61,
+ 0, 0, -244, 0, 0, 0, 0, 325, -244, 62,
+ 63, 64, 0, 10, 11, 324, 0, 35, 0, 36,
+ 0, 37, 0, 38, 39, 0, 0, 40, 0, 41,
+ 42, 112, 44, 45, 46, 0, 47, 48, 9, 0,
+ 0, 49, 50, 51, 52, 53, 54, 0, 0, 0,
+ 55, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 56, 57, 0, 58, 59, 0, 0,
+ 60, 0, 0, 61, 0, 35, -244, 642, 643, 37,
+ 160, 325, -244, 62, 63, 64, 0, 10, 11, 112,
+ 334, 0, 0, 0, 47, 48, 9, 0, 0, 0,
+ 335, 51, 0, 0, 0, 336, 337, 338, 158, 0,
+ 0, 0, 339, 0, 0, 0, 0, 0, 0, 340,
+ 0, 56, 57, 0, 58, 159, 0, 0, 60, 0,
+ 35, 61, 314, 0, 37, 0, 341, 0, 0, 0,
+ 0, 62, 63, 64, 112, 10, 11, 0, 342, 47,
+ 48, 9, 0, 0, 343, 0, 51, 11, 0, 0,
+ 0, 0, 0, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 56, 57, 0, 58,
+ 59, 0, 0, 60, 0, 35, 61, 0, 0, 37,
+ 0, 0, 0, 0, 420, 0, 62, 63, 64, 112,
+ 10, 11, 0, 0, 47, 48, 9, 0, 0, 0,
+ 0, 51, 0, 429, 0, 0, 0, 0, 158, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 56, 57, 0, 58, 159, 0, 0, 60, 0,
+ 35, 61, 0, 0, 37, 0, 0, 0, 0, 0,
+ 0, 62, 63, 64, 112, 10, 11, 0, 0, 47,
+ 48, 9, 0, 472, 0, 0, 51, 0, 0, 0,
+ 0, 0, 0, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 56, 57, 0, 58,
+ 59, 0, 0, 60, 0, 35, 61, 0, 0, 37,
+ 0, 0, 0, 0, 0, 0, 62, 63, 64, 112,
+ 10, 11, 0, 0, 47, 48, 9, 0, 473, 0,
+ 0, 51, 0, 0, 0, 0, 0, 0, 55, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 56, 57, 0, 58, 59, 0, 0, 60, 0,
+ 35, 61, 0, 0, 37, 0, 0, 0, 0, 0,
+ 0, 62, 63, 64, 112, 10, 11, 0, 0, 47,
+ 48, 9, 0, 0, 0, 0, 51, 0, 0, 0,
+ 0, 0, 0, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 56, 57, 0, 58,
+ 59, 0, 0, 60, 0, 35, 61, 0, 0, 37,
+ 0, 0, 0, 0, 0, 0, 62, 63, 64, 112,
+ 10, 11, 0, 0, 47, 48, 9, 0, 0, 0,
+ 0, 51, 0, 0, 0, 0, 0, 0, 158, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 56, 57, 0, 58, 159, 0, 0, 60, 0,
+ 35, 61, 0, 0, 283, 0, 0, 0, 0, 0,
+ 0, 62, 63, 64, 112, 10, 11, 0, 0, 47,
+ 48, 9, 0, 0, 0, 0, 51, 0, 0, 0,
+ 0, 0, 0, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 56, 57, 0, 58,
+ 59, 0, 0, 60, 0, 0, 61, 0, 0, 37,
+ 0, 0, 0, 0, 0, 0, 62, 63, 64, 112,
+ 10, 11, 0, 0, 47, 48, 9, 0, 0, 0,
+ 0, 51, 0, 0, 0, 37, 0, 0, 224, 241,
+ 0, 0, 0, 37, 0, 112, 0, 0, 0, 0,
+ 47, 48, 9, 112, 0, 114, 0, 51, 47, 48,
+ 9, 225, 0, 0, 224, 51, 0, 290, 37, 0,
+ 0, 0, 113, 64, 0, 10, 11, 281, 112, 0,
+ 0, 114, 0, 47, 48, 9, 0, 225, 0, 114,
+ 51, 0, 0, 0, 0, 115, 37, 224, 0, 64,
+ 0, 10, 11, 0, 0, 0, 112, 64, 0, 10,
+ 11, 47, 48, 9, 114, 0, 0, 0, 51, 0,
+ 225, 37, 0, 0, 0, 406, 0, 0, 0, 283,
+ 0, 112, 64, 0, 10, 11, 47, 48, 9, 112,
+ 0, 0, 114, 51, 47, 48, 9, 0, 407, 0,
+ 224, 51, 0, 0, 334, 0, 0, 0, 224, 0,
+ 64, 0, 10, 11, 335, 0, 0, 114, 0, 336,
+ 337, 338, 0, 476, 0, 114, 339, 0, 0, 0,
+ 0, 225, 334, 439, 0, 64, 0, 10, 11, 0,
+ 0, 0, 335, 64, 0, 10, 11, 336, 337, 540,
+ 341, 0, 0, 0, 339, 0, 440, 334, 0, 0,
+ 0, 340, 0, 0, 0, 334, 0, 335, 343, 0,
+ 0, 11, 336, 337, 338, 335, 0, 0, 341, 339,
+ 336, 337, 338, 0, 0, 0, 340, 339, 0, 0,
+ 0, 0, 0, 0, 340, 0, 343, 0, 10, 11,
+ 0, 0, 0, 341, 0, 0, 0, 0, 0, 607,
+ 0, 341, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 343, 0, 0, 11, 0, 0, 0, 0, 343,
+ 176, 177, 11, 178, 0, 180, 181, 182, 0, 0,
+ 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 0, 0, 0, 0, 0, 0,
+ 176, 177, 0, 178, 0, 180, 181, 182, 0, 431,
+ 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 176, 177, 0, 178, 0, 180,
+ 181, 182, 0, 523, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 176, 177,
+ 0, 178, 0, 180, 181, 182, 0, 649, 184, 185,
+ 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
+ 196, 197, 176, 177, 0, 178, 0, 180, 181, 182,
+ 0, 650, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 0, 176, 177, 434,
+ 178, 0, 180, 181, 182, 0, 0, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
+ 197, 176, 177, 0, 0, 0, 180, 181, 182, 0,
+ 0, 184, 185, 186, 187, 188, 189, 190, 191, 192,
+ 193, 194, 195, 196, 197, 176, 177, 0, 0, 0,
+ 180, 181, 182, 0, 0, 184, 185, 186, 187, 0,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 177,
+ 0, 0, 0, 180, 181, 182, 0, 0, 184, 185,
+ 186, 187, 0, 189, 190, 191, 192, 193, 194, 195,
+ 196, 197
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-551))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 5, 67, 250, 223, 37, 126, 37, 126, 143, 135,
+ 201, 132, 204, 147, 61, 20, 36, 22, 485, 39,
+ 31, 142, 28, 28, 321, 45, 452, 316, 323, 249,
+ 258, 36, 3, 11, 39, 24, 263, 264, 43, 267,
+ 45, 444, 67, 61, 594, 35, 0, 275, 53, 54,
+ 6, 279, 1, 3, 1, 3, 12, 3, 24, 35,
+ 59, 289, 67, 95, 63, 97, 98, 49, 3, 59,
+ 59, 35, 71, 25, 24, 37, 24, 67, 24, 3,
+ 37, 6, 24, 59, 389, 40, 35, 12, 35, 44,
+ 24, 67, 397, 59, 644, 106, 646, 75, 20, 61,
+ 24, 72, 50, 67, 61, 572, 172, 73, 74, 59,
+ 59, 59, 68, 63, 60, 135, 8, 63, 67, 53,
+ 67, 141, 127, 73, 74, 73, 74, 73, 74, 255,
+ 135, 73, 74, 8, 62, 424, 141, 426, 143, 63,
+ 437, 159, 147, 68, 126, 67, 25, 172, 62, 73,
+ 74, 113, 114, 115, 68, 460, 113, 114, 115, 24,
+ 6, 388, 382, 390, 3, 127, 12, 172, 21, 59,
+ 127, 62, 639, 65, 136, 63, 602, 68, 60, 136,
+ 24, 199, 144, 75, 74, 24, 8, 144, 436, 151,
+ 65, 66, 595, 75, 151, 200, 62, 159, 503, 62,
+ 75, 206, 159, 606, 607, 68, 35, 212, 113, 114,
+ 115, 50, 174, 62, 220, 220, 62, 174, 223, 68,
+ 515, 413, 68, 471, 62, 207, 208, 522, 420, 234,
+ 59, 136, 40, 24, 73, 74, 44, 199, 67, 144,
+ 3, 432, 199, 65, 249, 250, 151, 368, 3, 368,
+ 283, 51, 283, 75, 559, 71, 476, 378, 384, 378,
+ 62, 223, 67, 225, 399, 66, 223, 401, 225, 174,
+ 317, 576, 577, 66, 3, 59, 281, 523, 524, 241,
+ 59, 243, 24, 83, 241, 59, 243, 249, 74, 89,
+ 518, 3, 249, 24, 599, 7, 6, 64, 280, 317,
+ 62, 59, 12, 63, 75, 17, 59, 35, 290, 271,
+ 22, 23, 24, 67, 271, 60, 321, 29, 60, 59,
+ 225, 283, 35, 72, 286, 287, 283, 575, 72, 286,
+ 287, 73, 74, 62, 63, 3, 241, 342, 211, 68,
+ 24, 374, 60, 374, 217, 218, 59, 59, 353, 569,
+ 416, 7, 62, 60, 67, 317, 374, 24, 68, 71,
+ 317, 73, 74, 35, 384, 62, 271, 372, 60, 374,
+ 75, 62, 392, 35, 379, 59, 396, 382, 283, 384,
+ 427, 286, 287, 37, 366, 367, 53, 392, 24, 73,
+ 74, 396, 59, 59, 399, 35, 401, 59, 360, 62,
+ 3, 68, 72, 360, 62, 67, 73, 74, 65, 427,
+ 372, 416, 374, 62, 62, 372, 67, 374, 62, 59,
+ 382, 66, 65, 405, 386, 382, 59, 67, 67, 386,
+ 71, 436, 437, 67, 7, 65, 469, 419, 469, 444,
+ 445, 62, 447, 24, 406, 407, 567, 452, 567, 406,
+ 407, 469, 485, 458, 485, 360, 461, 462, 62, 113,
+ 114, 115, 62, 62, 60, 427, 471, 485, 341, 60,
+ 427, 476, 9, 127, 60, 24, 349, 495, 59, 63,
+ 17, 386, 136, 60, 21, 68, 24, 68, 60, 68,
+ 144, 35, 73, 74, 31, 32, 60, 151, 60, 60,
+ 75, 406, 407, 68, 53, 75, 60, 469, 60, 24,
+ 59, 68, 469, 60, 476, 36, 582, 3, 60, 476,
+ 174, 59, 62, 485, 73, 74, 72, 64, 485, 62,
+ 24, 59, 24, 495, 75, 73, 74, 60, 495, 572,
+ 66, 572, 60, 94, 95, 60, 97, 98, 55, 56,
+ 57, 58, 59, 60, 572, 62, 63, 519, 73, 74,
+ 60, 60, 519, 60, 569, 59, 439, 62, 60, 223,
+ 575, 225, 445, 446, 621, 448, 24, 582, 60, 73,
+ 74, 73, 74, 72, 457, 24, 459, 241, 60, 243,
+ 595, 59, 597, 59, 59, 249, 601, 602, 68, 62,
+ 62, 606, 607, 621, 68, 72, 639, 569, 639, 49,
+ 572, 59, 569, 62, 519, 572, 59, 271, 60, 14,
+ 59, 639, 68, 60, 68, 73, 74, 34, 49, 283,
+ 60, 62, 286, 287, 73, 74, 60, 44, 60, 31,
+ 61, 48, 60, 64, 60, 22, 53, 54, 55, 56,
+ 582, 158, 159, 508, 615, 377, 615, 142, 243, 621,
+ 211, 281, 524, 7, 621, 39, 217, 218, 159, 243,
+ 213, 7, 392, 17, 372, 548, 384, 639, 22, 23,
+ 24, 17, 639, 556, 22, 29, 22, 23, 24, 495,
+ 440, 601, 36, 29, 462, 597, 334, 334, 212, 458,
+ 36, -1, -1, -1, -1, -1, 360, -1, -1, 53,
+ -1, -1, -1, -1, -1, 59, -1, 53, 372, -1,
+ 374, 65, -1, 59, 597, 598, 34, 71, 382, 73,
+ 74, 75, 386, -1, -1, 71, 44, 73, 74, 75,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, -1,
+ -1, -1, 406, 407, 175, 176, 177, 178, -1, 180,
+ 181, 182, -1, 184, 185, 186, 187, 188, 189, 190,
+ 191, 192, 193, 194, 195, 196, 197, -1, 199, -1,
+ 201, -1, 203, 334, -1, -1, 207, 208, 209, -1,
+ 341, 7, -1, -1, -1, 11, -1, -1, 349, -1,
+ 4, 17, -1, -1, 8, -1, 22, 23, 24, -1,
+ -1, -1, -1, 29, -1, 469, -1, -1, -1, -1,
+ 36, -1, 476, -1, -1, -1, -1, -1, -1, 33,
+ 34, 485, 36, 37, 38, 39, 40, 53, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, -1, -1, 71, -1, -1, 74, 280,
+ -1, 65, -1, -1, -1, 519, -1, -1, -1, 290,
+ -1, 75, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 439, -1,
+ -1, -1, 313, -1, 445, 446, 317, 448, -1, -1,
+ -1, -1, 323, -1, 0, 1, 457, 3, 459, 5,
+ -1, 7, -1, 9, 10, 569, -1, 13, 572, 15,
+ 16, 17, 18, 19, 20, -1, 22, 23, 24, -1,
+ -1, 27, 28, 29, 30, 31, 32, -1, -1, -1,
+ 36, -1, -1, -1, -1, 366, 367, -1, -1, -1,
+ -1, -1, -1, 49, 50, -1, 52, 53, -1, -1,
+ 56, -1, -1, 59, -1, -1, 62, -1, 3, -1,
+ -1, -1, 7, 69, 70, 71, 11, 73, 74, -1,
+ -1, -1, 17, -1, 405, 639, -1, 22, 23, 24,
+ -1, -1, -1, -1, 29, -1, -1, 548, 419, -1,
+ -1, 36, -1, -1, -1, 556, 427, -1, -1, -1,
+ -1, 432, 563, -1, 49, 50, -1, 52, 53, -1,
+ -1, 56, -1, -1, 59, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 69, 70, 71, -1, 73, 74,
+ -1, -1, -1, 594, -1, -1, 597, 598, -1, -1,
+ -1, 472, 473, -1, -1, -1, -1, -1, -1, -1,
+ -1, 1, -1, 3, -1, 5, 6, 7, -1, 9,
+ 10, -1, 12, 13, 495, 15, 16, 17, 18, 19,
+ 20, -1, 22, 23, 24, -1, -1, 27, 28, 29,
+ 30, 31, 32, 644, 515, 646, 36, -1, -1, -1,
+ -1, 522, 523, 524, -1, -1, -1, -1, -1, 49,
+ 50, -1, 52, 53, -1, -1, 56, -1, -1, 59,
+ -1, -1, 62, -1, -1, -1, -1, 67, 68, 69,
+ 70, 71, -1, 73, 74, 1, -1, 3, -1, 5,
+ -1, 7, -1, 9, 10, -1, -1, 13, -1, 15,
+ 16, 17, 18, 19, 20, -1, 22, 23, 24, -1,
+ -1, 27, 28, 29, 30, 31, 32, -1, -1, -1,
+ 36, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 49, 50, -1, 52, 53, -1, -1,
+ 56, -1, -1, 59, -1, 3, 62, 618, 619, 7,
+ 621, 67, 68, 69, 70, 71, -1, 73, 74, 17,
+ 7, -1, -1, -1, 22, 23, 24, -1, -1, -1,
+ 17, 29, -1, -1, -1, 22, 23, 24, 36, -1,
+ -1, -1, 29, -1, -1, -1, -1, -1, -1, 36,
+ -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
+ 3, 59, 60, -1, 7, -1, 53, -1, -1, -1,
+ -1, 69, 70, 71, 17, 73, 74, -1, 65, 22,
+ 23, 24, -1, -1, 71, -1, 29, 74, -1, -1,
+ -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 49, 50, -1, 52,
+ 53, -1, -1, 56, -1, 3, 59, -1, -1, 7,
+ -1, -1, -1, -1, 67, -1, 69, 70, 71, 17,
+ 73, 74, -1, -1, 22, 23, 24, -1, -1, -1,
+ -1, 29, -1, 31, -1, -1, -1, -1, 36, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
+ 3, 59, -1, -1, 7, -1, -1, -1, -1, -1,
+ -1, 69, 70, 71, 17, 73, 74, -1, -1, 22,
+ 23, 24, -1, 26, -1, -1, 29, -1, -1, -1,
+ -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 49, 50, -1, 52,
+ 53, -1, -1, 56, -1, 3, 59, -1, -1, 7,
+ -1, -1, -1, -1, -1, -1, 69, 70, 71, 17,
+ 73, 74, -1, -1, 22, 23, 24, -1, 26, -1,
+ -1, 29, -1, -1, -1, -1, -1, -1, 36, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
+ 3, 59, -1, -1, 7, -1, -1, -1, -1, -1,
+ -1, 69, 70, 71, 17, 73, 74, -1, -1, 22,
+ 23, 24, -1, -1, -1, -1, 29, -1, -1, -1,
+ -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 49, 50, -1, 52,
+ 53, -1, -1, 56, -1, 3, 59, -1, -1, 7,
+ -1, -1, -1, -1, -1, -1, 69, 70, 71, 17,
+ 73, 74, -1, -1, 22, 23, 24, -1, -1, -1,
+ -1, 29, -1, -1, -1, -1, -1, -1, 36, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 49, 50, -1, 52, 53, -1, -1, 56, -1,
+ 3, 59, -1, -1, 7, -1, -1, -1, -1, -1,
+ -1, 69, 70, 71, 17, 73, 74, -1, -1, 22,
+ 23, 24, -1, -1, -1, -1, 29, -1, -1, -1,
+ -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 49, 50, -1, 52,
+ 53, -1, -1, 56, -1, -1, 59, -1, -1, 7,
+ -1, -1, -1, -1, -1, -1, 69, 70, 71, 17,
+ 73, 74, -1, -1, 22, 23, 24, -1, -1, -1,
+ -1, 29, -1, -1, -1, 7, -1, -1, 36, 11,
+ -1, -1, -1, 7, -1, 17, -1, -1, -1, -1,
+ 22, 23, 24, 17, -1, 53, -1, 29, 22, 23,
+ 24, 59, -1, -1, 36, 29, -1, 65, 7, -1,
+ -1, -1, 36, 71, -1, 73, 74, 75, 17, -1,
+ -1, 53, -1, 22, 23, 24, -1, 59, -1, 53,
+ 29, -1, -1, -1, -1, 59, 7, 36, -1, 71,
+ -1, 73, 74, -1, -1, -1, 17, 71, -1, 73,
+ 74, 22, 23, 24, 53, -1, -1, -1, 29, -1,
+ 59, 7, -1, -1, -1, 36, -1, -1, -1, 7,
+ -1, 17, 71, -1, 73, 74, 22, 23, 24, 17,
+ -1, -1, 53, 29, 22, 23, 24, -1, 59, -1,
+ 36, 29, -1, -1, 7, -1, -1, -1, 36, -1,
+ 71, -1, 73, 74, 17, -1, -1, 53, -1, 22,
+ 23, 24, -1, 59, -1, 53, 29, -1, -1, -1,
+ -1, 59, 7, 36, -1, 71, -1, 73, 74, -1,
+ -1, -1, 17, 71, -1, 73, 74, 22, 23, 24,
+ 53, -1, -1, -1, 29, -1, 59, 7, -1, -1,
+ -1, 36, -1, -1, -1, 7, -1, 17, 71, -1,
+ -1, 74, 22, 23, 24, 17, -1, -1, 53, 29,
+ 22, 23, 24, -1, -1, -1, 36, 29, -1, -1,
+ -1, -1, -1, -1, 36, -1, 71, -1, 73, 74,
+ -1, -1, -1, 53, -1, -1, -1, -1, -1, 59,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 71, -1, -1, 74, -1, -1, -1, -1, 71,
+ 33, 34, 74, 36, -1, 38, 39, 40, -1, -1,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, -1, -1, -1, -1, -1, -1,
+ 33, 34, -1, 36, -1, 38, 39, 40, -1, 72,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 33, 34, -1, 36, -1, 38,
+ 39, 40, -1, 66, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 33, 34,
+ -1, 36, -1, 38, 39, 40, -1, 66, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 33, 34, -1, 36, -1, 38, 39, 40,
+ -1, 66, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, -1, 33, 34, 60,
+ 36, -1, 38, 39, 40, -1, -1, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 33, 34, -1, -1, -1, 38, 39, 40, -1,
+ -1, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 33, 34, -1, -1, -1,
+ 38, 39, 40, -1, -1, 43, 44, 45, 46, -1,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 34,
+ -1, -1, -1, 38, 39, 40, -1, -1, 43, 44,
+ 45, 46, -1, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 77, 79, 80, 0, 25, 78, 25, 86, 24,
+ 73, 74, 137, 138, 81, 24, 88, 89, 3, 62,
+ 21, 82, 162, 24, 87, 210, 63, 3, 59, 63,
+ 83, 85, 137, 62, 1, 3, 5, 7, 9, 10,
+ 13, 15, 16, 17, 18, 19, 20, 22, 23, 27,
+ 28, 29, 30, 31, 32, 36, 49, 50, 52, 53,
+ 56, 59, 69, 70, 71, 90, 91, 92, 98, 110,
+ 113, 118, 121, 123, 124, 125, 126, 130, 134, 137,
+ 139, 140, 145, 146, 149, 152, 153, 154, 157, 160,
+ 161, 177, 182, 62, 9, 17, 21, 31, 32, 64,
+ 195, 24, 60, 83, 84, 3, 86, 88, 3, 134,
+ 136, 137, 17, 36, 53, 59, 137, 139, 144, 148,
+ 149, 150, 157, 136, 125, 130, 111, 59, 137, 155,
+ 125, 134, 114, 35, 67, 133, 71, 123, 182, 189,
+ 122, 133, 119, 59, 96, 97, 137, 59, 93, 135,
+ 137, 181, 124, 124, 124, 124, 124, 124, 36, 53,
+ 123, 131, 143, 149, 151, 157, 124, 124, 11, 123,
+ 188, 62, 59, 94, 181, 4, 33, 34, 36, 37,
+ 38, 39, 40, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 67, 59,
+ 63, 71, 66, 59, 133, 1, 133, 8, 65, 75,
+ 138, 196, 59, 156, 196, 24, 196, 197, 196, 64,
+ 62, 186, 88, 59, 36, 59, 142, 148, 149, 150,
+ 151, 157, 142, 142, 63, 98, 107, 108, 109, 182,
+ 190, 11, 132, 137, 141, 142, 173, 174, 175, 59,
+ 67, 158, 112, 190, 24, 59, 68, 134, 167, 169,
+ 171, 142, 35, 53, 59, 68, 134, 166, 168, 169,
+ 170, 180, 112, 60, 97, 165, 142, 60, 93, 163,
+ 65, 75, 142, 7, 143, 60, 72, 72, 60, 94,
+ 65, 142, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 123, 123, 127, 60, 131, 183, 59, 137, 123,
+ 188, 178, 123, 127, 1, 67, 91, 100, 176, 177,
+ 179, 182, 182, 123, 7, 17, 22, 23, 24, 29,
+ 36, 53, 65, 71, 138, 198, 200, 201, 202, 137,
+ 203, 211, 158, 59, 3, 198, 198, 83, 60, 175,
+ 7, 142, 60, 137, 35, 105, 8, 65, 62, 142,
+ 132, 141, 75, 187, 60, 175, 179, 115, 62, 63,
+ 24, 169, 59, 172, 62, 186, 72, 104, 59, 170,
+ 53, 170, 62, 186, 3, 194, 75, 142, 120, 62,
+ 186, 62, 186, 182, 135, 65, 36, 59, 142, 148,
+ 149, 150, 157, 67, 142, 142, 62, 186, 182, 65,
+ 67, 123, 128, 129, 184, 185, 11, 75, 187, 31,
+ 131, 72, 66, 176, 60, 185, 101, 62, 68, 36,
+ 59, 199, 200, 202, 59, 67, 71, 67, 7, 198,
+ 3, 50, 59, 137, 208, 209, 3, 72, 65, 11,
+ 198, 60, 75, 62, 191, 211, 62, 62, 62, 60,
+ 60, 106, 26, 26, 190, 173, 59, 137, 147, 148,
+ 149, 150, 151, 157, 159, 60, 68, 105, 190, 137,
+ 60, 175, 171, 68, 142, 6, 12, 68, 99, 102,
+ 170, 194, 170, 60, 168, 68, 134, 194, 35, 97,
+ 60, 93, 60, 182, 142, 127, 94, 95, 164, 181,
+ 60, 182, 127, 66, 75, 187, 68, 75, 187, 131,
+ 60, 60, 60, 188, 68, 179, 176, 198, 201, 191,
+ 24, 137, 138, 193, 198, 205, 213, 198, 137, 192,
+ 204, 212, 198, 3, 208, 62, 72, 198, 209, 198,
+ 194, 137, 203, 60, 179, 123, 123, 62, 175, 59,
+ 159, 116, 60, 183, 66, 103, 60, 60, 194, 104,
+ 60, 185, 62, 186, 142, 185, 123, 129, 128, 129,
+ 60, 72, 68, 60, 60, 59, 68, 62, 72, 198,
+ 68, 62, 49, 198, 62, 194, 59, 59, 198, 206,
+ 207, 68, 190, 60, 175, 14, 117, 159, 8, 65,
+ 66, 75, 179, 194, 194, 68, 68, 95, 60, 68,
+ 206, 191, 205, 198, 194, 204, 208, 191, 191, 60,
+ 100, 113, 123, 123, 60, 60, 60, 60, 159, 66,
+ 66, 206, 206
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = 0;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol. */
+int yychar, yystate;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+
+/* Line 1806 of yacc.c */
+#line 128 "go.y"
+ {
+ xtop = concat(xtop, (yyvsp[(4) - (4)].list));
+ }
+ break;
+
+ case 3:
+
+/* Line 1806 of yacc.c */
+#line 134 "go.y"
+ {
+ prevlineno = lineno;
+ yyerror("package statement must be first");
+ flusherrors();
+ mkpackage("main");
+ }
+ break;
+
+ case 4:
+
+/* Line 1806 of yacc.c */
+#line 141 "go.y"
+ {
+ mkpackage((yyvsp[(2) - (3)].sym)->name);
+ }
+ break;
+
+ case 5:
+
+/* Line 1806 of yacc.c */
+#line 151 "go.y"
+ {
+ importpkg = runtimepkg;
+
+ if(debug['A'])
+ cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
+ else
+ cannedimports("runtime.builtin", runtimeimport);
+ curio.importsafe = 1;
+ }
+ break;
+
+ case 6:
+
+/* Line 1806 of yacc.c */
+#line 162 "go.y"
+ {
+ importpkg = nil;
+ }
+ break;
+
+ case 12:
+
+/* Line 1806 of yacc.c */
+#line 176 "go.y"
+ {
+ Pkg *ipkg;
+ Sym *my;
+ Node *pack;
+
+ ipkg = importpkg;
+ my = importmyname;
+ importpkg = nil;
+ importmyname = S;
+
+ if(my == nil)
+ my = lookup(ipkg->name);
+
+ pack = nod(OPACK, N, N);
+ pack->sym = my;
+ pack->pkg = ipkg;
+ pack->lineno = (yyvsp[(1) - (3)].i);
+
+ if(my->name[0] == '.') {
+ importdot(ipkg, pack);
+ break;
+ }
+ if(my->name[0] == '_' && my->name[1] == '\0')
+ break;
+ if(my->def) {
+ lineno = (yyvsp[(1) - (3)].i);
+ redeclare(my, "as imported package name");
+ }
+ my->def = pack;
+ my->lastlineno = (yyvsp[(1) - (3)].i);
+ my->block = 1; // at top level
+ }
+ break;
+
+ case 13:
+
+/* Line 1806 of yacc.c */
+#line 209 "go.y"
+ {
+ // When an invalid import path is passed to importfile,
+ // it calls yyerror and then sets up a fake import with
+ // no package statement. This allows us to test more
+ // than one invalid import statement in a single file.
+ if(nerrors == 0)
+ fatal("phase error in import");
+ }
+ break;
+
+ case 16:
+
+/* Line 1806 of yacc.c */
+#line 224 "go.y"
+ {
+ // import with original name
+ (yyval.i) = parserline();
+ importmyname = S;
+ importfile(&(yyvsp[(1) - (1)].val), (yyval.i));
+ }
+ break;
+
+ case 17:
+
+/* Line 1806 of yacc.c */
+#line 231 "go.y"
+ {
+ // import with given name
+ (yyval.i) = parserline();
+ importmyname = (yyvsp[(1) - (2)].sym);
+ importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
+ }
+ break;
+
+ case 18:
+
+/* Line 1806 of yacc.c */
+#line 238 "go.y"
+ {
+ // import into my name space
+ (yyval.i) = parserline();
+ importmyname = lookup(".");
+ importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
+ }
+ break;
+
+ case 19:
+
+/* Line 1806 of yacc.c */
+#line 247 "go.y"
+ {
+ if(importpkg->name == nil) {
+ importpkg->name = (yyvsp[(2) - (4)].sym)->name;
+ pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++;
+ } else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0)
+ yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path);
+ importpkg->direct = 1;
+
+ if(safemode && !curio.importsafe)
+ yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
+ }
+ break;
+
+ case 21:
+
+/* Line 1806 of yacc.c */
+#line 261 "go.y"
+ {
+ if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
+ curio.importsafe = 1;
+ }
+ break;
+
+ case 22:
+
+/* Line 1806 of yacc.c */
+#line 267 "go.y"
+ {
+ defercheckwidth();
+ }
+ break;
+
+ case 23:
+
+/* Line 1806 of yacc.c */
+#line 271 "go.y"
+ {
+ resumecheckwidth();
+ unimportfile();
+ }
+ break;
+
+ case 24:
+
+/* Line 1806 of yacc.c */
+#line 280 "go.y"
+ {
+ yyerror("empty top-level declaration");
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 26:
+
+/* Line 1806 of yacc.c */
+#line 286 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 27:
+
+/* Line 1806 of yacc.c */
+#line 290 "go.y"
+ {
+ yyerror("non-declaration statement outside function body");
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 28:
+
+/* Line 1806 of yacc.c */
+#line 295 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 29:
+
+/* Line 1806 of yacc.c */
+#line 301 "go.y"
+ {
+ (yyval.list) = (yyvsp[(2) - (2)].list);
+ }
+ break;
+
+ case 30:
+
+/* Line 1806 of yacc.c */
+#line 305 "go.y"
+ {
+ (yyval.list) = (yyvsp[(3) - (5)].list);
+ }
+ break;
+
+ case 31:
+
+/* Line 1806 of yacc.c */
+#line 309 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 32:
+
+/* Line 1806 of yacc.c */
+#line 313 "go.y"
+ {
+ (yyval.list) = (yyvsp[(2) - (2)].list);
+ iota = -100000;
+ lastconst = nil;
+ }
+ break;
+
+ case 33:
+
+/* Line 1806 of yacc.c */
+#line 319 "go.y"
+ {
+ (yyval.list) = (yyvsp[(3) - (5)].list);
+ iota = -100000;
+ lastconst = nil;
+ }
+ break;
+
+ case 34:
+
+/* Line 1806 of yacc.c */
+#line 325 "go.y"
+ {
+ (yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
+ iota = -100000;
+ lastconst = nil;
+ }
+ break;
+
+ case 35:
+
+/* Line 1806 of yacc.c */
+#line 331 "go.y"
+ {
+ (yyval.list) = nil;
+ iota = -100000;
+ }
+ break;
+
+ case 36:
+
+/* Line 1806 of yacc.c */
+#line 336 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 37:
+
+/* Line 1806 of yacc.c */
+#line 340 "go.y"
+ {
+ (yyval.list) = (yyvsp[(3) - (5)].list);
+ }
+ break;
+
+ case 38:
+
+/* Line 1806 of yacc.c */
+#line 344 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 39:
+
+/* Line 1806 of yacc.c */
+#line 350 "go.y"
+ {
+ iota = 0;
+ }
+ break;
+
+ case 40:
+
+/* Line 1806 of yacc.c */
+#line 356 "go.y"
+ {
+ (yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
+ }
+ break;
+
+ case 41:
+
+/* Line 1806 of yacc.c */
+#line 360 "go.y"
+ {
+ (yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
+ }
+ break;
+
+ case 42:
+
+/* Line 1806 of yacc.c */
+#line 364 "go.y"
+ {
+ (yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 43:
+
+/* Line 1806 of yacc.c */
+#line 370 "go.y"
+ {
+ (yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
+ }
+ break;
+
+ case 44:
+
+/* Line 1806 of yacc.c */
+#line 374 "go.y"
+ {
+ (yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 46:
+
+/* Line 1806 of yacc.c */
+#line 381 "go.y"
+ {
+ (yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
+ }
+ break;
+
+ case 47:
+
+/* Line 1806 of yacc.c */
+#line 385 "go.y"
+ {
+ (yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
+ }
+ break;
+
+ case 48:
+
+/* Line 1806 of yacc.c */
+#line 391 "go.y"
+ {
+ // different from dclname because the name
+ // becomes visible right here, not at the end
+ // of the declaration.
+ (yyval.node) = typedcl0((yyvsp[(1) - (1)].sym));
+ }
+ break;
+
+ case 49:
+
+/* Line 1806 of yacc.c */
+#line 400 "go.y"
+ {
+ (yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
+ }
+ break;
+
+ case 50:
+
+/* Line 1806 of yacc.c */
+#line 406 "go.y"
+ {
+ (yyval.node) = (yyvsp[(1) - (1)].node);
+ }
+ break;
+
+ case 51:
+
+/* Line 1806 of yacc.c */
+#line 410 "go.y"
+ {
+ (yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ (yyval.node)->etype = (yyvsp[(2) - (3)].i); // rathole to pass opcode
+ }
+ break;
+
+ case 52:
+
+/* Line 1806 of yacc.c */
+#line 415 "go.y"
+ {
+ if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
+ // simple
+ (yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n);
+ break;
+ }
+ // multiple
+ (yyval.node) = nod(OAS2, N, N);
+ (yyval.node)->list = (yyvsp[(1) - (3)].list);
+ (yyval.node)->rlist = (yyvsp[(3) - (3)].list);
+ }
+ break;
+
+ case 53:
+
+/* Line 1806 of yacc.c */
+#line 427 "go.y"
+ {
+ if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
+ (yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right);
+ if((yyvsp[(3) - (3)].list)->next != nil)
+ yyerror("expr.(type) must be alone in list");
+ if((yyvsp[(1) - (3)].list)->next != nil)
+ yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1);
+ else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n))
+ yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n);
+ else
+ (yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym); // it's a colas, so must not re-use an oldname.
+ break;
+ }
+ (yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 54:
+
+/* Line 1806 of yacc.c */
+#line 443 "go.y"
+ {
+ (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
+ (yyval.node)->etype = OADD;
+ }
+ break;
+
+ case 55:
+
+/* Line 1806 of yacc.c */
+#line 448 "go.y"
+ {
+ (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
+ (yyval.node)->etype = OSUB;
+ }
+ break;
+
+ case 56:
+
+/* Line 1806 of yacc.c */
+#line 455 "go.y"
+ {
+ Node *n, *nn;
+
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ (yyval.node) = nod(OXCASE, N, N);
+ (yyval.node)->list = (yyvsp[(2) - (3)].list);
+ if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+ // type switch - declare variable
+ nn = newname(n->sym);
+ declare(nn, dclcontext);
+ (yyval.node)->nname = nn;
+
+ // keep track of the instances for reporting unused
+ nn->defn = typesw->right;
+ }
+ }
+ break;
+
+ case 57:
+
+/* Line 1806 of yacc.c */
+#line 475 "go.y"
+ {
+ Node *n;
+
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ (yyval.node) = nod(OXCASE, N, N);
+ if((yyvsp[(2) - (5)].list)->next == nil)
+ n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node));
+ else {
+ n = nod(OAS2, N, N);
+ n->list = (yyvsp[(2) - (5)].list);
+ n->rlist = list1((yyvsp[(4) - (5)].node));
+ }
+ (yyval.node)->list = list1(n);
+ }
+ break;
+
+ case 58:
+
+/* Line 1806 of yacc.c */
+#line 493 "go.y"
+ {
+ // will be converted to OCASE
+ // right will point to next case
+ // done in casebody()
+ markdcl();
+ (yyval.node) = nod(OXCASE, N, N);
+ (yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node))));
+ }
+ break;
+
+ case 59:
+
+/* Line 1806 of yacc.c */
+#line 502 "go.y"
+ {
+ Node *n, *nn;
+
+ markdcl();
+ (yyval.node) = nod(OXCASE, N, N);
+ if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+ // type switch - declare variable
+ nn = newname(n->sym);
+ declare(nn, dclcontext);
+ (yyval.node)->nname = nn;
+
+ // keep track of the instances for reporting unused
+ nn->defn = typesw->right;
+ }
+ }
+ break;
+
+ case 60:
+
+/* Line 1806 of yacc.c */
+#line 520 "go.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 61:
+
+/* Line 1806 of yacc.c */
+#line 524 "go.y"
+ {
+ (yyval.node) = liststmt((yyvsp[(3) - (4)].list));
+ popdcl();
+ }
+ break;
+
+ case 62:
+
+/* Line 1806 of yacc.c */
+#line 531 "go.y"
+ {
+ // If the last token read by the lexer was consumed
+ // as part of the case, clear it (parser has cleared yychar).
+ // If the last token read by the lexer was the lookahead
+ // leave it alone (parser has it cached in yychar).
+ // This is so that the stmt_list action doesn't look at
+ // the case tokens if the stmt_list is empty.
+ yylast = yychar;
+ }
+ break;
+
+ case 63:
+
+/* Line 1806 of yacc.c */
+#line 541 "go.y"
+ {
+ int last;
+
+ // This is the only place in the language where a statement
+ // list is not allowed to drop the final semicolon, because
+ // it's the only place where a statement list is not followed
+ // by a closing brace. Handle the error for pedantry.
+
+ // Find the final token of the statement list.
+ // yylast is lookahead; yyprev is last of stmt_list
+ last = yyprev;
+
+ if(last > 0 && last != ';' && yychar != '}')
+ yyerror("missing statement after label");
+ (yyval.node) = (yyvsp[(1) - (3)].node);
+ (yyval.node)->nbody = (yyvsp[(3) - (3)].list);
+ popdcl();
+ }
+ break;
+
+ case 64:
+
+/* Line 1806 of yacc.c */
+#line 561 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 65:
+
+/* Line 1806 of yacc.c */
+#line 565 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 66:
+
+/* Line 1806 of yacc.c */
+#line 571 "go.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 67:
+
+/* Line 1806 of yacc.c */
+#line 575 "go.y"
+ {
+ (yyval.list) = (yyvsp[(3) - (4)].list);
+ popdcl();
+ }
+ break;
+
+ case 68:
+
+/* Line 1806 of yacc.c */
+#line 582 "go.y"
+ {
+ (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
+ (yyval.node)->list = (yyvsp[(1) - (4)].list);
+ (yyval.node)->etype = 0; // := flag
+ }
+ break;
+
+ case 69:
+
+/* Line 1806 of yacc.c */
+#line 588 "go.y"
+ {
+ (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
+ (yyval.node)->list = (yyvsp[(1) - (4)].list);
+ (yyval.node)->colas = 1;
+ colasdefn((yyvsp[(1) - (4)].list), (yyval.node));
+ }
+ break;
+
+ case 70:
+
+/* Line 1806 of yacc.c */
+#line 597 "go.y"
+ {
+ // init ; test ; incr
+ if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
+ yyerror("cannot declare in the for-increment");
+ (yyval.node) = nod(OFOR, N, N);
+ if((yyvsp[(1) - (5)].node) != N)
+ (yyval.node)->ninit = list1((yyvsp[(1) - (5)].node));
+ (yyval.node)->ntest = (yyvsp[(3) - (5)].node);
+ (yyval.node)->nincr = (yyvsp[(5) - (5)].node);
+ }
+ break;
+
+ case 71:
+
+/* Line 1806 of yacc.c */
+#line 608 "go.y"
+ {
+ // normal test
+ (yyval.node) = nod(OFOR, N, N);
+ (yyval.node)->ntest = (yyvsp[(1) - (1)].node);
+ }
+ break;
+
+ case 73:
+
+/* Line 1806 of yacc.c */
+#line 617 "go.y"
+ {
+ (yyval.node) = (yyvsp[(1) - (2)].node);
+ (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
+ }
+ break;
+
+ case 74:
+
+/* Line 1806 of yacc.c */
+#line 624 "go.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 75:
+
+/* Line 1806 of yacc.c */
+#line 628 "go.y"
+ {
+ (yyval.node) = (yyvsp[(3) - (3)].node);
+ popdcl();
+ }
+ break;
+
+ case 76:
+
+/* Line 1806 of yacc.c */
+#line 635 "go.y"
+ {
+ // test
+ (yyval.node) = nod(OIF, N, N);
+ (yyval.node)->ntest = (yyvsp[(1) - (1)].node);
+ }
+ break;
+
+ case 77:
+
+/* Line 1806 of yacc.c */
+#line 641 "go.y"
+ {
+ // init ; test
+ (yyval.node) = nod(OIF, N, N);
+ if((yyvsp[(1) - (3)].node) != N)
+ (yyval.node)->ninit = list1((yyvsp[(1) - (3)].node));
+ (yyval.node)->ntest = (yyvsp[(3) - (3)].node);
+ }
+ break;
+
+ case 78:
+
+/* Line 1806 of yacc.c */
+#line 652 "go.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 79:
+
+/* Line 1806 of yacc.c */
+#line 656 "go.y"
+ {
+ if((yyvsp[(3) - (3)].node)->ntest == N)
+ yyerror("missing condition in if statement");
+ }
+ break;
+
+ case 80:
+
+/* Line 1806 of yacc.c */
+#line 661 "go.y"
+ {
+ (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
+ }
+ break;
+
+ case 81:
+
+/* Line 1806 of yacc.c */
+#line 665 "go.y"
+ {
+ popdcl();
+ (yyval.node) = (yyvsp[(3) - (7)].node);
+ if((yyvsp[(7) - (7)].node) != N)
+ (yyval.node)->nelse = list1((yyvsp[(7) - (7)].node));
+ }
+ break;
+
+ case 82:
+
+/* Line 1806 of yacc.c */
+#line 673 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 83:
+
+/* Line 1806 of yacc.c */
+#line 677 "go.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (2)].node);
+ }
+ break;
+
+ case 84:
+
+/* Line 1806 of yacc.c */
+#line 681 "go.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (2)].node);
+ }
+ break;
+
+ case 85:
+
+/* Line 1806 of yacc.c */
+#line 687 "go.y"
+ {
+ markdcl();
+ }
+ break;
+
+ case 86:
+
+/* Line 1806 of yacc.c */
+#line 691 "go.y"
+ {
+ Node *n;
+ n = (yyvsp[(3) - (3)].node)->ntest;
+ if(n != N && n->op != OTYPESW)
+ n = N;
+ typesw = nod(OXXX, typesw, n);
+ }
+ break;
+
+ case 87:
+
+/* Line 1806 of yacc.c */
+#line 699 "go.y"
+ {
+ (yyval.node) = (yyvsp[(3) - (7)].node);
+ (yyval.node)->op = OSWITCH;
+ (yyval.node)->list = (yyvsp[(6) - (7)].list);
+ typesw = typesw->left;
+ popdcl();
+ }
+ break;
+
+ case 88:
+
+/* Line 1806 of yacc.c */
+#line 709 "go.y"
+ {
+ typesw = nod(OXXX, typesw, N);
+ }
+ break;
+
+ case 89:
+
+/* Line 1806 of yacc.c */
+#line 713 "go.y"
+ {
+ (yyval.node) = nod(OSELECT, N, N);
+ (yyval.node)->lineno = typesw->lineno;
+ (yyval.node)->list = (yyvsp[(4) - (5)].list);
+ typesw = typesw->left;
+ }
+ break;
+
+ case 91:
+
+/* Line 1806 of yacc.c */
+#line 726 "go.y"
+ {
+ (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 92:
+
+/* Line 1806 of yacc.c */
+#line 730 "go.y"
+ {
+ (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 93:
+
+/* Line 1806 of yacc.c */
+#line 734 "go.y"
+ {
+ (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 94:
+
+/* Line 1806 of yacc.c */
+#line 738 "go.y"
+ {
+ (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 95:
+
+/* Line 1806 of yacc.c */
+#line 742 "go.y"
+ {
+ (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 96:
+
+/* Line 1806 of yacc.c */
+#line 746 "go.y"
+ {
+ (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 97:
+
+/* Line 1806 of yacc.c */
+#line 750 "go.y"
+ {
+ (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 98:
+
+/* Line 1806 of yacc.c */
+#line 754 "go.y"
+ {
+ (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 99:
+
+/* Line 1806 of yacc.c */
+#line 758 "go.y"
+ {
+ (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 100:
+
+/* Line 1806 of yacc.c */
+#line 762 "go.y"
+ {
+ (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 101:
+
+/* Line 1806 of yacc.c */
+#line 766 "go.y"
+ {
+ (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 102:
+
+/* Line 1806 of yacc.c */
+#line 770 "go.y"
+ {
+ (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 103:
+
+/* Line 1806 of yacc.c */
+#line 774 "go.y"
+ {
+ (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 104:
+
+/* Line 1806 of yacc.c */
+#line 778 "go.y"
+ {
+ (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 105:
+
+/* Line 1806 of yacc.c */
+#line 782 "go.y"
+ {
+ (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 106:
+
+/* Line 1806 of yacc.c */
+#line 786 "go.y"
+ {
+ (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 107:
+
+/* Line 1806 of yacc.c */
+#line 790 "go.y"
+ {
+ (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 108:
+
+/* Line 1806 of yacc.c */
+#line 794 "go.y"
+ {
+ (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 109:
+
+/* Line 1806 of yacc.c */
+#line 798 "go.y"
+ {
+ (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 110:
+
+/* Line 1806 of yacc.c */
+#line 803 "go.y"
+ {
+ (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 112:
+
+/* Line 1806 of yacc.c */
+#line 810 "go.y"
+ {
+ (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 113:
+
+/* Line 1806 of yacc.c */
+#line 814 "go.y"
+ {
+ if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
+ // Special case for &T{...}: turn into (*T){...}.
+ (yyval.node) = (yyvsp[(2) - (2)].node);
+ (yyval.node)->right = nod(OIND, (yyval.node)->right, N);
+ (yyval.node)->right->implicit = 1;
+ } else {
+ (yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N);
+ }
+ }
+ break;
+
+ case 114:
+
+/* Line 1806 of yacc.c */
+#line 825 "go.y"
+ {
+ (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 115:
+
+/* Line 1806 of yacc.c */
+#line 829 "go.y"
+ {
+ (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 116:
+
+/* Line 1806 of yacc.c */
+#line 833 "go.y"
+ {
+ (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 117:
+
+/* Line 1806 of yacc.c */
+#line 837 "go.y"
+ {
+ yyerror("the bitwise complement operator is ^");
+ (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 118:
+
+/* Line 1806 of yacc.c */
+#line 842 "go.y"
+ {
+ (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 119:
+
+/* Line 1806 of yacc.c */
+#line 846 "go.y"
+ {
+ (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 120:
+
+/* Line 1806 of yacc.c */
+#line 856 "go.y"
+ {
+ (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
+ }
+ break;
+
+ case 121:
+
+/* Line 1806 of yacc.c */
+#line 860 "go.y"
+ {
+ (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
+ (yyval.node)->list = (yyvsp[(3) - (5)].list);
+ }
+ break;
+
+ case 122:
+
+/* Line 1806 of yacc.c */
+#line 865 "go.y"
+ {
+ (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
+ (yyval.node)->list = (yyvsp[(3) - (6)].list);
+ (yyval.node)->isddd = 1;
+ }
+ break;
+
+ case 123:
+
+/* Line 1806 of yacc.c */
+#line 873 "go.y"
+ {
+ (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
+ }
+ break;
+
+ case 125:
+
+/* Line 1806 of yacc.c */
+#line 878 "go.y"
+ {
+ if((yyvsp[(1) - (3)].node)->op == OPACK) {
+ Sym *s;
+ s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
+ (yyvsp[(1) - (3)].node)->used = 1;
+ (yyval.node) = oldname(s);
+ break;
+ }
+ (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
+ }
+ break;
+
+ case 126:
+
+/* Line 1806 of yacc.c */
+#line 889 "go.y"
+ {
+ (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
+ }
+ break;
+
+ case 127:
+
+/* Line 1806 of yacc.c */
+#line 893 "go.y"
+ {
+ (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
+ }
+ break;
+
+ case 128:
+
+/* Line 1806 of yacc.c */
+#line 897 "go.y"
+ {
+ (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 129:
+
+/* Line 1806 of yacc.c */
+#line 901 "go.y"
+ {
+ (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
+ }
+ break;
+
+ case 131:
+
+/* Line 1806 of yacc.c */
+#line 906 "go.y"
+ {
+ // conversion
+ (yyval.node) = nod(OCALL, (yyvsp[(1) - (4)].node), N);
+ (yyval.node)->list = list1((yyvsp[(3) - (4)].node));
+ }
+ break;
+
+ case 132:
+
+/* Line 1806 of yacc.c */
+#line 912 "go.y"
+ {
+ (yyval.node) = (yyvsp[(3) - (5)].node);
+ (yyval.node)->right = (yyvsp[(1) - (5)].node);
+ (yyval.node)->list = (yyvsp[(4) - (5)].list);
+ fixlbrace((yyvsp[(2) - (5)].i));
+ }
+ break;
+
+ case 133:
+
+/* Line 1806 of yacc.c */
+#line 919 "go.y"
+ {
+ (yyval.node) = (yyvsp[(3) - (5)].node);
+ (yyval.node)->right = (yyvsp[(1) - (5)].node);
+ (yyval.node)->list = (yyvsp[(4) - (5)].list);
+ }
+ break;
+
+ case 134:
+
+/* Line 1806 of yacc.c */
+#line 925 "go.y"
+ {
+ yyerror("cannot parenthesize type in composite literal");
+ (yyval.node) = (yyvsp[(5) - (7)].node);
+ (yyval.node)->right = (yyvsp[(2) - (7)].node);
+ (yyval.node)->list = (yyvsp[(6) - (7)].list);
+ }
+ break;
+
+ case 136:
+
+/* Line 1806 of yacc.c */
+#line 934 "go.y"
+ {
+ // composite expression.
+ // make node early so we get the right line number.
+ (yyval.node) = nod(OCOMPLIT, N, N);
+ }
+ break;
+
+ case 137:
+
+/* Line 1806 of yacc.c */
+#line 942 "go.y"
+ {
+ (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 139:
+
+/* Line 1806 of yacc.c */
+#line 949 "go.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (4)].node);
+ (yyval.node)->list = (yyvsp[(3) - (4)].list);
+ }
+ break;
+
+ case 141:
+
+/* Line 1806 of yacc.c */
+#line 957 "go.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+
+ // Need to know on lhs of := whether there are ( ).
+ // Don't bother with the OPAREN in other cases:
+ // it's just a waste of memory and time.
+ switch((yyval.node)->op) {
+ case ONAME:
+ case ONONAME:
+ case OPACK:
+ case OTYPE:
+ case OLITERAL:
+ (yyval.node) = nod(OPAREN, (yyval.node), N);
+ }
+ }
+ break;
+
+ case 145:
+
+/* Line 1806 of yacc.c */
+#line 982 "go.y"
+ {
+ (yyval.i) = LBODY;
+ }
+ break;
+
+ case 146:
+
+/* Line 1806 of yacc.c */
+#line 986 "go.y"
+ {
+ (yyval.i) = '{';
+ }
+ break;
+
+ case 147:
+
+/* Line 1806 of yacc.c */
+#line 997 "go.y"
+ {
+ if((yyvsp[(1) - (1)].sym) == S)
+ (yyval.node) = N;
+ else
+ (yyval.node) = newname((yyvsp[(1) - (1)].sym));
+ }
+ break;
+
+ case 148:
+
+/* Line 1806 of yacc.c */
+#line 1006 "go.y"
+ {
+ (yyval.node) = dclname((yyvsp[(1) - (1)].sym));
+ }
+ break;
+
+ case 149:
+
+/* Line 1806 of yacc.c */
+#line 1011 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 151:
+
+/* Line 1806 of yacc.c */
+#line 1018 "go.y"
+ {
+ (yyval.sym) = (yyvsp[(1) - (1)].sym);
+ // during imports, unqualified non-exported identifiers are from builtinpkg
+ if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name))
+ (yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
+ }
+ break;
+
+ case 153:
+
+/* Line 1806 of yacc.c */
+#line 1026 "go.y"
+ {
+ (yyval.sym) = S;
+ }
+ break;
+
+ case 154:
+
+/* Line 1806 of yacc.c */
+#line 1032 "go.y"
+ {
+ if((yyvsp[(2) - (4)].val).u.sval->len == 0)
+ (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, importpkg);
+ else
+ (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, mkpkg((yyvsp[(2) - (4)].val).u.sval));
+ }
+ break;
+
+ case 155:
+
+/* Line 1806 of yacc.c */
+#line 1041 "go.y"
+ {
+ (yyval.node) = oldname((yyvsp[(1) - (1)].sym));
+ if((yyval.node)->pack != N)
+ (yyval.node)->pack->used = 1;
+ }
+ break;
+
+ case 157:
+
+/* Line 1806 of yacc.c */
+#line 1061 "go.y"
+ {
+ yyerror("final argument in variadic function missing type");
+ (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
+ }
+ break;
+
+ case 158:
+
+/* Line 1806 of yacc.c */
+#line 1066 "go.y"
+ {
+ (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 164:
+
+/* Line 1806 of yacc.c */
+#line 1077 "go.y"
+ {
+ (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
+ }
+ break;
+
+ case 168:
+
+/* Line 1806 of yacc.c */
+#line 1086 "go.y"
+ {
+ (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 173:
+
+/* Line 1806 of yacc.c */
+#line 1096 "go.y"
+ {
+ (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
+ }
+ break;
+
+ case 183:
+
+/* Line 1806 of yacc.c */
+#line 1117 "go.y"
+ {
+ if((yyvsp[(1) - (3)].node)->op == OPACK) {
+ Sym *s;
+ s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
+ (yyvsp[(1) - (3)].node)->used = 1;
+ (yyval.node) = oldname(s);
+ break;
+ }
+ (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
+ }
+ break;
+
+ case 184:
+
+/* Line 1806 of yacc.c */
+#line 1130 "go.y"
+ {
+ (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
+ }
+ break;
+
+ case 185:
+
+/* Line 1806 of yacc.c */
+#line 1134 "go.y"
+ {
+ // array literal of nelem
+ (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
+ }
+ break;
+
+ case 186:
+
+/* Line 1806 of yacc.c */
+#line 1139 "go.y"
+ {
+ (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
+ (yyval.node)->etype = Cboth;
+ }
+ break;
+
+ case 187:
+
+/* Line 1806 of yacc.c */
+#line 1144 "go.y"
+ {
+ (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
+ (yyval.node)->etype = Csend;
+ }
+ break;
+
+ case 188:
+
+/* Line 1806 of yacc.c */
+#line 1149 "go.y"
+ {
+ (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+ }
+ break;
+
+ case 191:
+
+/* Line 1806 of yacc.c */
+#line 1157 "go.y"
+ {
+ (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 192:
+
+/* Line 1806 of yacc.c */
+#line 1163 "go.y"
+ {
+ (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
+ (yyval.node)->etype = Crecv;
+ }
+ break;
+
+ case 193:
+
+/* Line 1806 of yacc.c */
+#line 1170 "go.y"
+ {
+ (yyval.node) = nod(OTSTRUCT, N, N);
+ (yyval.node)->list = (yyvsp[(3) - (5)].list);
+ fixlbrace((yyvsp[(2) - (5)].i));
+ }
+ break;
+
+ case 194:
+
+/* Line 1806 of yacc.c */
+#line 1176 "go.y"
+ {
+ (yyval.node) = nod(OTSTRUCT, N, N);
+ fixlbrace((yyvsp[(2) - (3)].i));
+ }
+ break;
+
+ case 195:
+
+/* Line 1806 of yacc.c */
+#line 1183 "go.y"
+ {
+ (yyval.node) = nod(OTINTER, N, N);
+ (yyval.node)->list = (yyvsp[(3) - (5)].list);
+ fixlbrace((yyvsp[(2) - (5)].i));
+ }
+ break;
+
+ case 196:
+
+/* Line 1806 of yacc.c */
+#line 1189 "go.y"
+ {
+ (yyval.node) = nod(OTINTER, N, N);
+ fixlbrace((yyvsp[(2) - (3)].i));
+ }
+ break;
+
+ case 197:
+
+/* Line 1806 of yacc.c */
+#line 1200 "go.y"
+ {
+ (yyval.node) = (yyvsp[(2) - (3)].node);
+ if((yyval.node) == N)
+ break;
+ (yyval.node)->nbody = (yyvsp[(3) - (3)].list);
+ (yyval.node)->endlineno = lineno;
+ funcbody((yyval.node));
+ }
+ break;
+
+ case 198:
+
+/* Line 1806 of yacc.c */
+#line 1211 "go.y"
+ {
+ Node *t;
+
+ (yyval.node) = N;
+ (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
+
+ if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) {
+ (yyvsp[(1) - (5)].sym) = renameinit();
+ if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
+ yyerror("func init must have no arguments and no return values");
+ }
+ if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) {
+ if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
+ yyerror("func main must have no arguments and no return values");
+ }
+
+ t = nod(OTFUNC, N, N);
+ t->list = (yyvsp[(3) - (5)].list);
+ t->rlist = (yyvsp[(5) - (5)].list);
+
+ (yyval.node) = nod(ODCLFUNC, N, N);
+ (yyval.node)->nname = newname((yyvsp[(1) - (5)].sym));
+ (yyval.node)->nname->defn = (yyval.node);
+ (yyval.node)->nname->ntype = t; // TODO: check if nname already has an ntype
+ declare((yyval.node)->nname, PFUNC);
+
+ funchdr((yyval.node));
+ }
+ break;
+
+ case 199:
+
+/* Line 1806 of yacc.c */
+#line 1240 "go.y"
+ {
+ Node *rcvr, *t;
+
+ (yyval.node) = N;
+ (yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0);
+ (yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1);
+
+ if((yyvsp[(2) - (8)].list) == nil) {
+ yyerror("method has no receiver");
+ break;
+ }
+ if((yyvsp[(2) - (8)].list)->next != nil) {
+ yyerror("method has multiple receivers");
+ break;
+ }
+ rcvr = (yyvsp[(2) - (8)].list)->n;
+ if(rcvr->op != ODCLFIELD) {
+ yyerror("bad receiver in method");
+ break;
+ }
+ if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
+ yyerror("cannot parenthesize receiver type");
+
+ t = nod(OTFUNC, rcvr, N);
+ t->list = (yyvsp[(6) - (8)].list);
+ t->rlist = (yyvsp[(8) - (8)].list);
+
+ (yyval.node) = nod(ODCLFUNC, N, N);
+ (yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym));
+ (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
+ (yyval.node)->nname->defn = (yyval.node);
+ (yyval.node)->nname->ntype = t;
+ declare((yyval.node)->nname, PFUNC);
+
+ funchdr((yyval.node));
+ }
+ break;
+
+ case 200:
+
+/* Line 1806 of yacc.c */
+#line 1279 "go.y"
+ {
+ Sym *s;
+ Type *t;
+
+ (yyval.node) = N;
+
+ s = (yyvsp[(1) - (5)].sym);
+ t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
+
+ importsym(s, ONAME);
+ if(s->def != N && s->def->op == ONAME) {
+ if(eqtype(t, s->def->type))
+ break;
+ yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
+ }
+
+ (yyval.node) = newname(s);
+ (yyval.node)->type = t;
+ declare((yyval.node), PFUNC);
+
+ funchdr((yyval.node));
+ }
+ break;
+
+ case 201:
+
+/* Line 1806 of yacc.c */
+#line 1302 "go.y"
+ {
+ (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right);
+ (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
+
+ checkwidth((yyval.node)->type);
+ addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0);
+ funchdr((yyval.node));
+
+ // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
+ // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
+ // out by typecheck's lookdot as this $$->ttype. So by providing
+ // this back link here we avoid special casing there.
+ (yyval.node)->type->nname = (yyval.node);
+ }
+ break;
+
+ case 202:
+
+/* Line 1806 of yacc.c */
+#line 1319 "go.y"
+ {
+ (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
+ (yyval.node) = nod(OTFUNC, N, N);
+ (yyval.node)->list = (yyvsp[(3) - (5)].list);
+ (yyval.node)->rlist = (yyvsp[(5) - (5)].list);
+ }
+ break;
+
+ case 203:
+
+/* Line 1806 of yacc.c */
+#line 1327 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 204:
+
+/* Line 1806 of yacc.c */
+#line 1331 "go.y"
+ {
+ (yyval.list) = (yyvsp[(2) - (3)].list);
+ if((yyval.list) == nil)
+ (yyval.list) = list1(nod(OEMPTY, N, N));
+ }
+ break;
+
+ case 205:
+
+/* Line 1806 of yacc.c */
+#line 1339 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 206:
+
+/* Line 1806 of yacc.c */
+#line 1343 "go.y"
+ {
+ (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
+ }
+ break;
+
+ case 207:
+
+/* Line 1806 of yacc.c */
+#line 1347 "go.y"
+ {
+ (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
+ (yyval.list) = (yyvsp[(2) - (3)].list);
+ }
+ break;
+
+ case 208:
+
+/* Line 1806 of yacc.c */
+#line 1354 "go.y"
+ {
+ closurehdr((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 209:
+
+/* Line 1806 of yacc.c */
+#line 1360 "go.y"
+ {
+ (yyval.node) = closurebody((yyvsp[(3) - (4)].list));
+ fixlbrace((yyvsp[(2) - (4)].i));
+ }
+ break;
+
+ case 210:
+
+/* Line 1806 of yacc.c */
+#line 1365 "go.y"
+ {
+ (yyval.node) = closurebody(nil);
+ }
+ break;
+
+ case 211:
+
+/* Line 1806 of yacc.c */
+#line 1376 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 212:
+
+/* Line 1806 of yacc.c */
+#line 1380 "go.y"
+ {
+ (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
+ if(nsyntaxerrors == 0)
+ testdclstack();
+ }
+ break;
+
+ case 214:
+
+/* Line 1806 of yacc.c */
+#line 1389 "go.y"
+ {
+ (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 216:
+
+/* Line 1806 of yacc.c */
+#line 1396 "go.y"
+ {
+ (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 217:
+
+/* Line 1806 of yacc.c */
+#line 1402 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 218:
+
+/* Line 1806 of yacc.c */
+#line 1406 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 220:
+
+/* Line 1806 of yacc.c */
+#line 1413 "go.y"
+ {
+ (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+ }
+ break;
+
+ case 221:
+
+/* Line 1806 of yacc.c */
+#line 1419 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 222:
+
+/* Line 1806 of yacc.c */
+#line 1423 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 223:
+
+/* Line 1806 of yacc.c */
+#line 1429 "go.y"
+ {
+ NodeList *l;
+
+ Node *n;
+ l = (yyvsp[(1) - (3)].list);
+ if(l != nil && l->next == nil && l->n == nil) {
+ // ? symbol, during import
+ n = (yyvsp[(2) - (3)].node);
+ if(n->op == OIND)
+ n = n->left;
+ n = embedded(n->sym);
+ n->right = (yyvsp[(2) - (3)].node);
+ n->val = (yyvsp[(3) - (3)].val);
+ (yyval.list) = list1(n);
+ break;
+ }
+
+ for(l=(yyvsp[(1) - (3)].list); l; l=l->next) {
+ l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node));
+ l->n->val = (yyvsp[(3) - (3)].val);
+ }
+ }
+ break;
+
+ case 224:
+
+/* Line 1806 of yacc.c */
+#line 1452 "go.y"
+ {
+ (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
+ (yyval.list) = list1((yyvsp[(1) - (2)].node));
+ }
+ break;
+
+ case 225:
+
+/* Line 1806 of yacc.c */
+#line 1457 "go.y"
+ {
+ (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
+ (yyval.list) = list1((yyvsp[(2) - (4)].node));
+ yyerror("cannot parenthesize embedded type");
+ }
+ break;
+
+ case 226:
+
+/* Line 1806 of yacc.c */
+#line 1463 "go.y"
+ {
+ (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
+ (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
+ (yyval.list) = list1((yyvsp[(2) - (3)].node));
+ }
+ break;
+
+ case 227:
+
+/* Line 1806 of yacc.c */
+#line 1469 "go.y"
+ {
+ (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
+ (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
+ (yyval.list) = list1((yyvsp[(3) - (5)].node));
+ yyerror("cannot parenthesize embedded type");
+ }
+ break;
+
+ case 228:
+
+/* Line 1806 of yacc.c */
+#line 1476 "go.y"
+ {
+ (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
+ (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
+ (yyval.list) = list1((yyvsp[(3) - (5)].node));
+ yyerror("cannot parenthesize embedded type");
+ }
+ break;
+
+ case 229:
+
+/* Line 1806 of yacc.c */
+#line 1485 "go.y"
+ {
+ Node *n;
+
+ (yyval.sym) = (yyvsp[(1) - (1)].sym);
+ n = oldname((yyvsp[(1) - (1)].sym));
+ if(n->pack != N)
+ n->pack->used = 1;
+ }
+ break;
+
+ case 230:
+
+/* Line 1806 of yacc.c */
+#line 1494 "go.y"
+ {
+ Pkg *pkg;
+
+ if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) {
+ yyerror("%S is not a package", (yyvsp[(1) - (3)].sym));
+ pkg = localpkg;
+ } else {
+ (yyvsp[(1) - (3)].sym)->def->used = 1;
+ pkg = (yyvsp[(1) - (3)].sym)->def->pkg;
+ }
+ (yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg);
+ }
+ break;
+
+ case 231:
+
+/* Line 1806 of yacc.c */
+#line 1509 "go.y"
+ {
+ (yyval.node) = embedded((yyvsp[(1) - (1)].sym));
+ }
+ break;
+
+ case 232:
+
+/* Line 1806 of yacc.c */
+#line 1515 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+ ifacedcl((yyval.node));
+ }
+ break;
+
+ case 233:
+
+/* Line 1806 of yacc.c */
+#line 1520 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
+ }
+ break;
+
+ case 234:
+
+/* Line 1806 of yacc.c */
+#line 1524 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
+ yyerror("cannot parenthesize embedded type");
+ }
+ break;
+
+ case 235:
+
+/* Line 1806 of yacc.c */
+#line 1531 "go.y"
+ {
+ // without func keyword
+ (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
+ (yyval.node) = nod(OTFUNC, fakethis(), N);
+ (yyval.node)->list = (yyvsp[(2) - (4)].list);
+ (yyval.node)->rlist = (yyvsp[(4) - (4)].list);
+ }
+ break;
+
+ case 237:
+
+/* Line 1806 of yacc.c */
+#line 1545 "go.y"
+ {
+ (yyval.node) = nod(ONONAME, N, N);
+ (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
+ (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 238:
+
+/* Line 1806 of yacc.c */
+#line 1551 "go.y"
+ {
+ (yyval.node) = nod(ONONAME, N, N);
+ (yyval.node)->sym = (yyvsp[(1) - (2)].sym);
+ (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
+ }
+ break;
+
+ case 240:
+
+/* Line 1806 of yacc.c */
+#line 1560 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 241:
+
+/* Line 1806 of yacc.c */
+#line 1564 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 242:
+
+/* Line 1806 of yacc.c */
+#line 1569 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 243:
+
+/* Line 1806 of yacc.c */
+#line 1573 "go.y"
+ {
+ (yyval.list) = (yyvsp[(1) - (2)].list);
+ }
+ break;
+
+ case 244:
+
+/* Line 1806 of yacc.c */
+#line 1581 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 246:
+
+/* Line 1806 of yacc.c */
+#line 1586 "go.y"
+ {
+ (yyval.node) = liststmt((yyvsp[(1) - (1)].list));
+ }
+ break;
+
+ case 248:
+
+/* Line 1806 of yacc.c */
+#line 1591 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 254:
+
+/* Line 1806 of yacc.c */
+#line 1602 "go.y"
+ {
+ (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
+ (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
+ }
+ break;
+
+ case 255:
+
+/* Line 1806 of yacc.c */
+#line 1607 "go.y"
+ {
+ NodeList *l;
+
+ (yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node);
+ l = list1((yyvsp[(1) - (4)].node));
+ if((yyvsp[(4) - (4)].node))
+ l = list(l, (yyvsp[(4) - (4)].node));
+ (yyval.node) = liststmt(l);
+ }
+ break;
+
+ case 256:
+
+/* Line 1806 of yacc.c */
+#line 1617 "go.y"
+ {
+ // will be converted to OFALL
+ (yyval.node) = nod(OXFALL, N, N);
+ }
+ break;
+
+ case 257:
+
+/* Line 1806 of yacc.c */
+#line 1622 "go.y"
+ {
+ (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 258:
+
+/* Line 1806 of yacc.c */
+#line 1626 "go.y"
+ {
+ (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 259:
+
+/* Line 1806 of yacc.c */
+#line 1630 "go.y"
+ {
+ (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 260:
+
+/* Line 1806 of yacc.c */
+#line 1634 "go.y"
+ {
+ (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
+ }
+ break;
+
+ case 261:
+
+/* Line 1806 of yacc.c */
+#line 1638 "go.y"
+ {
+ (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
+ (yyval.node)->sym = dclstack; // context, for goto restrictions
+ }
+ break;
+
+ case 262:
+
+/* Line 1806 of yacc.c */
+#line 1643 "go.y"
+ {
+ (yyval.node) = nod(ORETURN, N, N);
+ (yyval.node)->list = (yyvsp[(2) - (2)].list);
+ if((yyval.node)->list == nil && curfn != N) {
+ NodeList *l;
+
+ for(l=curfn->dcl; l; l=l->next) {
+ if(l->n->class == PPARAM)
+ continue;
+ if(l->n->class != PPARAMOUT)
+ break;
+ if(l->n->sym->def != l->n)
+ yyerror("%s is shadowed during return", l->n->sym->name);
+ }
+ }
+ }
+ break;
+
+ case 263:
+
+/* Line 1806 of yacc.c */
+#line 1662 "go.y"
+ {
+ (yyval.list) = nil;
+ if((yyvsp[(1) - (1)].node) != N)
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 264:
+
+/* Line 1806 of yacc.c */
+#line 1668 "go.y"
+ {
+ (yyval.list) = (yyvsp[(1) - (3)].list);
+ if((yyvsp[(3) - (3)].node) != N)
+ (yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 265:
+
+/* Line 1806 of yacc.c */
+#line 1676 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 266:
+
+/* Line 1806 of yacc.c */
+#line 1680 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 267:
+
+/* Line 1806 of yacc.c */
+#line 1686 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 268:
+
+/* Line 1806 of yacc.c */
+#line 1690 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 269:
+
+/* Line 1806 of yacc.c */
+#line 1696 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 270:
+
+/* Line 1806 of yacc.c */
+#line 1700 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 271:
+
+/* Line 1806 of yacc.c */
+#line 1706 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 272:
+
+/* Line 1806 of yacc.c */
+#line 1710 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 273:
+
+/* Line 1806 of yacc.c */
+#line 1719 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 274:
+
+/* Line 1806 of yacc.c */
+#line 1723 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 275:
+
+/* Line 1806 of yacc.c */
+#line 1727 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 276:
+
+/* Line 1806 of yacc.c */
+#line 1731 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 277:
+
+/* Line 1806 of yacc.c */
+#line 1736 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 278:
+
+/* Line 1806 of yacc.c */
+#line 1740 "go.y"
+ {
+ (yyval.list) = (yyvsp[(1) - (2)].list);
+ }
+ break;
+
+ case 283:
+
+/* Line 1806 of yacc.c */
+#line 1754 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 285:
+
+/* Line 1806 of yacc.c */
+#line 1760 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 287:
+
+/* Line 1806 of yacc.c */
+#line 1766 "go.y"
+ {
+ (yyval.node) = N;
+ }
+ break;
+
+ case 289:
+
+/* Line 1806 of yacc.c */
+#line 1772 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 291:
+
+/* Line 1806 of yacc.c */
+#line 1778 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 293:
+
+/* Line 1806 of yacc.c */
+#line 1784 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 295:
+
+/* Line 1806 of yacc.c */
+#line 1790 "go.y"
+ {
+ (yyval.val).ctype = CTxxx;
+ }
+ break;
+
+ case 297:
+
+/* Line 1806 of yacc.c */
+#line 1800 "go.y"
+ {
+ importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
+ }
+ break;
+
+ case 298:
+
+/* Line 1806 of yacc.c */
+#line 1804 "go.y"
+ {
+ importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
+ }
+ break;
+
+ case 299:
+
+/* Line 1806 of yacc.c */
+#line 1808 "go.y"
+ {
+ importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
+ }
+ break;
+
+ case 300:
+
+/* Line 1806 of yacc.c */
+#line 1812 "go.y"
+ {
+ importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
+ }
+ break;
+
+ case 301:
+
+/* Line 1806 of yacc.c */
+#line 1816 "go.y"
+ {
+ importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
+ }
+ break;
+
+ case 302:
+
+/* Line 1806 of yacc.c */
+#line 1820 "go.y"
+ {
+ if((yyvsp[(2) - (4)].node) == N)
+ break;
+
+ (yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list);
+
+ funcbody((yyvsp[(2) - (4)].node));
+ importlist = list(importlist, (yyvsp[(2) - (4)].node));
+
+ if(debug['E']) {
+ print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node));
+ if(debug['l'] > 2 && (yyvsp[(2) - (4)].node)->inl)
+ print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl);
+ }
+ }
+ break;
+
+ case 303:
+
+/* Line 1806 of yacc.c */
+#line 1838 "go.y"
+ {
+ (yyval.sym) = (yyvsp[(1) - (1)].sym);
+ structpkg = (yyval.sym)->pkg;
+ }
+ break;
+
+ case 304:
+
+/* Line 1806 of yacc.c */
+#line 1845 "go.y"
+ {
+ (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
+ importsym((yyvsp[(1) - (1)].sym), OTYPE);
+ }
+ break;
+
+ case 310:
+
+/* Line 1806 of yacc.c */
+#line 1865 "go.y"
+ {
+ (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
+ }
+ break;
+
+ case 311:
+
+/* Line 1806 of yacc.c */
+#line 1869 "go.y"
+ {
+ // predefined name like uint8
+ (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
+ if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) {
+ yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name);
+ (yyval.type) = T;
+ } else
+ (yyval.type) = (yyvsp[(1) - (1)].sym)->def->type;
+ }
+ break;
+
+ case 312:
+
+/* Line 1806 of yacc.c */
+#line 1879 "go.y"
+ {
+ (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
+ }
+ break;
+
+ case 313:
+
+/* Line 1806 of yacc.c */
+#line 1883 "go.y"
+ {
+ (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
+ }
+ break;
+
+ case 314:
+
+/* Line 1806 of yacc.c */
+#line 1887 "go.y"
+ {
+ (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
+ }
+ break;
+
+ case 315:
+
+/* Line 1806 of yacc.c */
+#line 1891 "go.y"
+ {
+ (yyval.type) = tostruct((yyvsp[(3) - (4)].list));
+ }
+ break;
+
+ case 316:
+
+/* Line 1806 of yacc.c */
+#line 1895 "go.y"
+ {
+ (yyval.type) = tointerface((yyvsp[(3) - (4)].list));
+ }
+ break;
+
+ case 317:
+
+/* Line 1806 of yacc.c */
+#line 1899 "go.y"
+ {
+ (yyval.type) = ptrto((yyvsp[(2) - (2)].type));
+ }
+ break;
+
+ case 318:
+
+/* Line 1806 of yacc.c */
+#line 1903 "go.y"
+ {
+ (yyval.type) = typ(TCHAN);
+ (yyval.type)->type = (yyvsp[(2) - (2)].type);
+ (yyval.type)->chan = Cboth;
+ }
+ break;
+
+ case 319:
+
+/* Line 1806 of yacc.c */
+#line 1909 "go.y"
+ {
+ (yyval.type) = typ(TCHAN);
+ (yyval.type)->type = (yyvsp[(3) - (4)].type);
+ (yyval.type)->chan = Cboth;
+ }
+ break;
+
+ case 320:
+
+/* Line 1806 of yacc.c */
+#line 1915 "go.y"
+ {
+ (yyval.type) = typ(TCHAN);
+ (yyval.type)->type = (yyvsp[(3) - (3)].type);
+ (yyval.type)->chan = Csend;
+ }
+ break;
+
+ case 321:
+
+/* Line 1806 of yacc.c */
+#line 1923 "go.y"
+ {
+ (yyval.type) = typ(TCHAN);
+ (yyval.type)->type = (yyvsp[(3) - (3)].type);
+ (yyval.type)->chan = Crecv;
+ }
+ break;
+
+ case 322:
+
+/* Line 1806 of yacc.c */
+#line 1931 "go.y"
+ {
+ (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
+ }
+ break;
+
+ case 323:
+
+/* Line 1806 of yacc.c */
+#line 1937 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
+ if((yyvsp[(1) - (3)].sym))
+ (yyval.node)->left = newname((yyvsp[(1) - (3)].sym));
+ (yyval.node)->val = (yyvsp[(3) - (3)].val);
+ }
+ break;
+
+ case 324:
+
+/* Line 1806 of yacc.c */
+#line 1944 "go.y"
+ {
+ Type *t;
+
+ t = typ(TARRAY);
+ t->bound = -1;
+ t->type = (yyvsp[(3) - (4)].type);
+
+ (yyval.node) = nod(ODCLFIELD, N, typenod(t));
+ if((yyvsp[(1) - (4)].sym))
+ (yyval.node)->left = newname((yyvsp[(1) - (4)].sym));
+ (yyval.node)->isddd = 1;
+ (yyval.node)->val = (yyvsp[(4) - (4)].val);
+ }
+ break;
+
+ case 325:
+
+/* Line 1806 of yacc.c */
+#line 1960 "go.y"
+ {
+ Sym *s;
+
+ if((yyvsp[(1) - (3)].sym) != S) {
+ (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type)));
+ (yyval.node)->val = (yyvsp[(3) - (3)].val);
+ } else {
+ s = (yyvsp[(2) - (3)].type)->sym;
+ if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype])
+ s = (yyvsp[(2) - (3)].type)->type->sym;
+ (yyval.node) = embedded(s);
+ (yyval.node)->right = typenod((yyvsp[(2) - (3)].type));
+ (yyval.node)->val = (yyvsp[(3) - (3)].val);
+ }
+ }
+ break;
+
+ case 326:
+
+/* Line 1806 of yacc.c */
+#line 1978 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
+ }
+ break;
+
+ case 327:
+
+/* Line 1806 of yacc.c */
+#line 1982 "go.y"
+ {
+ (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
+ }
+ break;
+
+ case 328:
+
+/* Line 1806 of yacc.c */
+#line 1987 "go.y"
+ {
+ (yyval.list) = nil;
+ }
+ break;
+
+ case 330:
+
+/* Line 1806 of yacc.c */
+#line 1994 "go.y"
+ {
+ (yyval.list) = (yyvsp[(2) - (3)].list);
+ }
+ break;
+
+ case 331:
+
+/* Line 1806 of yacc.c */
+#line 1998 "go.y"
+ {
+ (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
+ }
+ break;
+
+ case 332:
+
+/* Line 1806 of yacc.c */
+#line 2008 "go.y"
+ {
+ (yyval.node) = nodlit((yyvsp[(1) - (1)].val));
+ }
+ break;
+
+ case 333:
+
+/* Line 1806 of yacc.c */
+#line 2012 "go.y"
+ {
+ (yyval.node) = nodlit((yyvsp[(2) - (2)].val));
+ switch((yyval.node)->val.ctype){
+ case CTINT:
+ case CTRUNE:
+ mpnegfix((yyval.node)->val.u.xval);
+ break;
+ case CTFLT:
+ mpnegflt((yyval.node)->val.u.fval);
+ break;
+ default:
+ yyerror("bad negated constant");
+ }
+ }
+ break;
+
+ case 334:
+
+/* Line 1806 of yacc.c */
+#line 2027 "go.y"
+ {
+ (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
+ if((yyval.node)->op != OLITERAL)
+ yyerror("bad constant %S", (yyval.node)->sym);
+ }
+ break;
+
+ case 336:
+
+/* Line 1806 of yacc.c */
+#line 2036 "go.y"
+ {
+ if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
+ (yyval.node) = (yyvsp[(2) - (5)].node);
+ mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0);
+ break;
+ }
+ (yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val);
+ }
+ break;
+
+ case 339:
+
+/* Line 1806 of yacc.c */
+#line 2050 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 340:
+
+/* Line 1806 of yacc.c */
+#line 2054 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 341:
+
+/* Line 1806 of yacc.c */
+#line 2060 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 342:
+
+/* Line 1806 of yacc.c */
+#line 2064 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+ case 343:
+
+/* Line 1806 of yacc.c */
+#line 2070 "go.y"
+ {
+ (yyval.list) = list1((yyvsp[(1) - (1)].node));
+ }
+ break;
+
+ case 344:
+
+/* Line 1806 of yacc.c */
+#line 2074 "go.y"
+ {
+ (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+ }
+ break;
+
+
+
+/* Line 1806 of yacc.c */
+#line 5298 "y.tab.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+/* Line 2067 of yacc.c */
+#line 2078 "go.y"
+
+
+static void
+fixlbrace(int lbr)
+{
+ // If the opening brace was an LBODY,
+ // set up for another one now that we're done.
+ // See comment in lex.c about loophack.
+ if(lbr == LBODY)
+ loophack = 1;
+}
+
+
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
new file mode 100644
index 000000000..bc6c47d6d
--- /dev/null
+++ b/src/cmd/gc/y.tab.h
@@ -0,0 +1,171 @@
+/* A Bison parser, made by GNU Bison 2.5. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ LLITERAL = 258,
+ LASOP = 259,
+ LBREAK = 260,
+ LCASE = 261,
+ LCHAN = 262,
+ LCOLAS = 263,
+ LCONST = 264,
+ LCONTINUE = 265,
+ LDDD = 266,
+ LDEFAULT = 267,
+ LDEFER = 268,
+ LELSE = 269,
+ LFALL = 270,
+ LFOR = 271,
+ LFUNC = 272,
+ LGO = 273,
+ LGOTO = 274,
+ LIF = 275,
+ LIMPORT = 276,
+ LINTERFACE = 277,
+ LMAP = 278,
+ LNAME = 279,
+ LPACKAGE = 280,
+ LRANGE = 281,
+ LRETURN = 282,
+ LSELECT = 283,
+ LSTRUCT = 284,
+ LSWITCH = 285,
+ LTYPE = 286,
+ LVAR = 287,
+ LANDAND = 288,
+ LANDNOT = 289,
+ LBODY = 290,
+ LCOMM = 291,
+ LDEC = 292,
+ LEQ = 293,
+ LGE = 294,
+ LGT = 295,
+ LIGNORE = 296,
+ LINC = 297,
+ LLE = 298,
+ LLSH = 299,
+ LLT = 300,
+ LNE = 301,
+ LOROR = 302,
+ LRSH = 303,
+ NotPackage = 304,
+ NotParen = 305,
+ PreferToRightParen = 306
+ };
+#endif
+/* Tokens. */
+#define LLITERAL 258
+#define LASOP 259
+#define LBREAK 260
+#define LCASE 261
+#define LCHAN 262
+#define LCOLAS 263
+#define LCONST 264
+#define LCONTINUE 265
+#define LDDD 266
+#define LDEFAULT 267
+#define LDEFER 268
+#define LELSE 269
+#define LFALL 270
+#define LFOR 271
+#define LFUNC 272
+#define LGO 273
+#define LGOTO 274
+#define LIF 275
+#define LIMPORT 276
+#define LINTERFACE 277
+#define LMAP 278
+#define LNAME 279
+#define LPACKAGE 280
+#define LRANGE 281
+#define LRETURN 282
+#define LSELECT 283
+#define LSTRUCT 284
+#define LSWITCH 285
+#define LTYPE 286
+#define LVAR 287
+#define LANDAND 288
+#define LANDNOT 289
+#define LBODY 290
+#define LCOMM 291
+#define LDEC 292
+#define LEQ 293
+#define LGE 294
+#define LGT 295
+#define LIGNORE 296
+#define LINC 297
+#define LLE 298
+#define LLSH 299
+#define LLT 300
+#define LNE 301
+#define LOROR 302
+#define LRSH 303
+#define NotPackage 304
+#define NotParen 305
+#define PreferToRightParen 306
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 2068 of yacc.c */
+#line 28 "go.y"
+
+ Node* node;
+ NodeList* list;
+ Type* type;
+ Sym* sym;
+ struct Val val;
+ int i;
+
+
+
+/* Line 2068 of yacc.c */
+#line 163 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+
diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h
new file mode 100644
index 000000000..588890d0e
--- /dev/null
+++ b/src/cmd/gc/yerr.h
@@ -0,0 +1,73 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Example-based syntax error messages.
+// See bisonerrors, Makefile, go.y.
+
+static struct {
+ int yystate;
+ int yychar;
+ char *msg;
+} yymsg[] = {
+ // Each line of the form % token list
+ // is converted by bisonerrors into the yystate and yychar caused
+ // by that token list.
+
+ 221, ',',
+ "unexpected comma during import block",
+
+ 377, ';',
+ "unexpected semicolon or newline before {",
+
+ 398, ';',
+ "unexpected semicolon or newline before {",
+
+ 237, ';',
+ "unexpected semicolon or newline before {",
+
+ 474, LBODY,
+ "unexpected semicolon or newline before {",
+
+ 22, '{',
+ "unexpected semicolon or newline before {",
+
+ 144, ';',
+ "unexpected semicolon or newline in type declaration",
+
+ 37, '}',
+ "unexpected } in channel type",
+
+ 37, ')',
+ "unexpected ) in channel type",
+
+ 37, ',',
+ "unexpected comma in channel type",
+
+ 437, LELSE,
+ "unexpected semicolon or newline before else",
+
+ 257, ',',
+ "name list not allowed in interface type",
+
+ 237, LVAR,
+ "var declaration not allowed in for initializer",
+
+ 65, '{',
+ "unexpected { at end of statement",
+
+ 376, '{',
+ "unexpected { at end of statement",
+
+ 125, ';',
+ "argument to go/defer must be function call",
+
+ 425, ';',
+ "need trailing comma before newline in composite literal",
+
+ 112, LNAME,
+ "nested func not allowed",
+
+ 615, ';',
+ "else must be followed by if or statement block"
+};
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
new file mode 100644
index 000000000..32941404c
--- /dev/null
+++ b/src/cmd/go/bootstrap.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cmd_go_bootstrap
+
+// This code is compiled only into the bootstrap 'go' binary.
+// These stubs avoid importing packages with large dependency
+// trees, like the use of "net/http" in vcs.go.
+
+package main
+
+import (
+ "errors"
+ "io"
+)
+
+var errHTTP = errors.New("no http in bootstrap go command")
+
+func httpGET(url string) ([]byte, error) {
+ return nil, errHTTP
+}
+
+func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
+ return "", nil, errHTTP
+}
+
+func parseMetaGoImports(r io.Reader) (imports []metaImport) {
+ panic("unreachable")
+}
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
new file mode 100644
index 000000000..4bb83f161
--- /dev/null
+++ b/src/cmd/go/build.go
@@ -0,0 +1,1566 @@
+// 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 (
+ "bytes"
+ "container/heap"
+ "errors"
+ "fmt"
+ "go/build"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+)
+
+var cmdBuild = &Command{
+ UsageLine: "build [-o output] [build flags] [packages]",
+ Short: "compile packages and dependencies",
+ Long: `
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+If the arguments are a list of .go files, build treats them as a list
+of source files specifying a single package.
+
+When the command line specifies a single main package,
+build writes the resulting executable to output.
+Otherwise build compiles the packages but discards the results,
+serving only as a check that the packages can be built.
+
+The -o flag specifies the output file name. If not specified, the
+name is packagename.a (for a non-main package) or the base
+name of the first source file (for a main package).
+
+The build flags are shared by the build, install, run, and test commands:
+
+ -a
+ force rebuilding of packages that are already up-to-date.
+ -n
+ print the commands but do not run them.
+ -p n
+ the number of builds that can be run in parallel.
+ The default is the number of CPUs available.
+ -v
+ print the names of packages as they are compiled.
+ -work
+ print the name of the temporary work directory and
+ do not delete it when exiting.
+ -x
+ print the commands.
+
+ -compiler name
+ name of compiler to use, as in runtime.Compiler (gccgo or gc)
+ -gccgoflags 'arg list'
+ arguments to pass on each gccgo compiler/linker invocation
+ -gcflags 'arg list'
+ arguments to pass on each 5g, 6g, or 8g compiler invocation
+ -ldflags 'flag list'
+ arguments to pass on each 5l, 6l, or 8l linker invocation
+ -tags 'tag list'
+ a list of build tags to consider satisfied during the build.
+ See the documentation for the go/build package for
+ more information about build tags.
+
+For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+see 'go help gopath'.
+
+See also: go install, go get, go clean.
+ `,
+}
+
+func init() {
+ // break init cycle
+ cmdBuild.Run = runBuild
+ cmdInstall.Run = runInstall
+
+ addBuildFlags(cmdBuild)
+ addBuildFlags(cmdInstall)
+}
+
+// Flags set by multiple commands.
+var buildA bool // -a flag
+var buildN bool // -n flag
+var buildP = runtime.NumCPU() // -p flag
+var buildV bool // -v flag
+var buildX bool // -x flag
+var buildO = cmdBuild.Flag.String("o", "", "output file")
+var buildWork bool // -work flag
+var buildGcflags []string // -gcflags flag
+var buildLdflags []string // -ldflags flag
+var buildGccgoflags []string // -gccgoflags flag
+
+var buildContext = build.Default
+var buildToolchain toolchain = noToolchain{}
+
+// buildCompiler implements flag.Var.
+// It implements Set by updating both
+// buildToolchain and buildContext.Compiler.
+type buildCompiler struct{}
+
+func (c buildCompiler) Set(value string) error {
+ switch value {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgcToolchain{}
+ default:
+ return fmt.Errorf("unknown compiler %q", value)
+ }
+ buildContext.Compiler = value
+ return nil
+}
+
+func (c buildCompiler) String() string {
+ return buildContext.Compiler
+}
+
+func init() {
+ switch build.Default.Compiler {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgcToolchain{}
+ }
+}
+
+// addBuildFlags adds the flags common to the build and install commands.
+func addBuildFlags(cmd *Command) {
+ // NOTE: If you add flags here, also add them to testflag.go.
+ cmd.Flag.BoolVar(&buildA, "a", false, "")
+ cmd.Flag.BoolVar(&buildN, "n", false, "")
+ cmd.Flag.IntVar(&buildP, "p", buildP, "")
+ cmd.Flag.BoolVar(&buildV, "v", false, "")
+ cmd.Flag.BoolVar(&buildX, "x", false, "")
+ cmd.Flag.BoolVar(&buildWork, "work", false, "")
+ cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
+ cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
+ cmd.Flag.Var(buildCompiler{}, "compiler", "")
+}
+
+type stringsFlag []string
+
+func (v *stringsFlag) Set(s string) error {
+ *v = strings.Fields(s)
+ return nil
+}
+
+func (v *stringsFlag) String() string {
+ return "<stringsFlag>"
+}
+
+func runBuild(cmd *Command, args []string) {
+ var b builder
+ b.init()
+
+ pkgs := packagesForBuild(args)
+
+ if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
+ _, *buildO = path.Split(pkgs[0].ImportPath)
+ *buildO += exeSuffix
+ }
+
+ if *buildO != "" {
+ if len(pkgs) > 1 {
+ fatalf("go build: cannot use -o with multiple packages")
+ }
+ p := pkgs[0]
+ p.target = "" // must build - not up to date
+ a := b.action(modeInstall, modeBuild, p)
+ a.target = *buildO
+ b.do(a)
+ return
+ }
+
+ a := &action{}
+ for _, p := range packages(args) {
+ a.deps = append(a.deps, b.action(modeBuild, modeBuild, p))
+ }
+ b.do(a)
+}
+
+var cmdInstall = &Command{
+ UsageLine: "install [build flags] [packages]",
+ Short: "compile and install packages and dependencies",
+ Long: `
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go get, go clean.
+ `,
+}
+
+func runInstall(cmd *Command, args []string) {
+ pkgs := packagesForBuild(args)
+
+ for _, p := range pkgs {
+ if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
+ errorf("go install: no install location for %s", p.ImportPath)
+ }
+ }
+ exitIfErrors()
+
+ var b builder
+ b.init()
+ a := &action{}
+ for _, p := range pkgs {
+ a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
+ }
+ b.do(a)
+}
+
+// Global build parameters (used during package load)
+var (
+ goarch string
+ goos string
+ archChar string
+ exeSuffix string
+)
+
+func init() {
+ goarch = buildContext.GOARCH
+ goos = buildContext.GOOS
+ if goos == "windows" {
+ exeSuffix = ".exe"
+ }
+ var err error
+ archChar, err = build.ArchChar(goarch)
+ if err != nil {
+ fatalf("%s", err)
+ }
+}
+
+// A builder holds global state about a build.
+// It does not hold per-package state, because we
+// build packages in parallel, and the builder is shared.
+type builder struct {
+ work string // the temporary work directory (ends in filepath.Separator)
+ actionCache map[cacheKey]*action // a cache of already-constructed actions
+ mkdirCache map[string]bool // a cache of created directories
+ print func(args ...interface{}) (int, error)
+
+ output sync.Mutex
+ scriptDir string // current directory in printed script
+
+ exec sync.Mutex
+ readySema chan bool
+ ready actionQueue
+}
+
+// An action represents a single action in the action graph.
+type action struct {
+ p *Package // the package this action works on
+ deps []*action // actions that must happen before this one
+ triggers []*action // inverse of deps
+ cgo *action // action for cgo binary if needed
+ args []string // additional args for runProgram
+ testOutput *bytes.Buffer // test output buffer
+
+ f func(*builder, *action) error // the action itself (nil = no-op)
+ ignoreFail bool // whether to run f even if dependencies fail
+
+ // Generated files, directories.
+ link bool // target is executable, not just package
+ pkgdir string // the -I or -L argument to use when importing this package
+ objdir string // directory for intermediate objects
+ objpkg string // the intermediate package .a file created during the action
+ target string // goal of the action: the created package or executable
+
+ // Execution state.
+ pending int // number of deps yet to complete
+ priority int // relative execution priority
+ failed bool // whether the action failed
+}
+
+// cacheKey is the key for the action cache.
+type cacheKey struct {
+ mode buildMode
+ p *Package
+}
+
+// buildMode specifies the build mode:
+// are we just building things or also installing the results?
+type buildMode int
+
+const (
+ modeBuild buildMode = iota
+ modeInstall
+)
+
+var (
+ goroot = filepath.Clean(runtime.GOROOT())
+ gobin = os.Getenv("GOBIN")
+ gorootBin = filepath.Join(goroot, "bin")
+ gorootSrcPkg = filepath.Join(goroot, "src/pkg")
+ gorootPkg = filepath.Join(goroot, "pkg")
+ gorootSrc = filepath.Join(goroot, "src")
+)
+
+func (b *builder) init() {
+ var err error
+ b.print = fmt.Print
+ b.actionCache = make(map[cacheKey]*action)
+ b.mkdirCache = make(map[string]bool)
+
+ if buildN {
+ b.work = "$WORK"
+ } else {
+ b.work, err = ioutil.TempDir("", "go-build")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if buildX || buildWork {
+ fmt.Printf("WORK=%s\n", b.work)
+ }
+ if !buildWork {
+ atexit(func() { os.RemoveAll(b.work) })
+ }
+ }
+}
+
+// goFilesPackage creates a package for building a collection of Go files
+// (typically named on the command line). The target is named p.a for
+// package p or named after the first Go file for package main.
+func goFilesPackage(gofiles []string) *Package {
+ // TODO: Remove this restriction.
+ for _, f := range gofiles {
+ if !strings.HasSuffix(f, ".go") {
+ fatalf("named files must be .go files")
+ }
+ }
+
+ var stk importStack
+ ctxt := buildContext
+ ctxt.UseAllFiles = true
+
+ // Synthesize fake "directory" that only shows the named files,
+ // to make it look like this is a standard package or
+ // command directory. So that local imports resolve
+ // consistently, the files must all be in the same directory.
+ var dirent []os.FileInfo
+ var dir string
+ for _, file := range gofiles {
+ fi, err := os.Stat(file)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if fi.IsDir() {
+ fatalf("%s is a directory, should be a Go file", file)
+ }
+ dir1, _ := filepath.Split(file)
+ if dir == "" {
+ dir = dir1
+ } else if dir != dir1 {
+ fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
+ }
+ dirent = append(dirent, fi)
+ }
+ ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(cwd, dir)
+ }
+
+ bp, err := ctxt.ImportDir(dir, 0)
+ pkg := new(Package)
+ pkg.local = true
+ pkg.load(&stk, bp, err)
+ pkg.localPrefix = dirToImportPath(dir)
+ pkg.ImportPath = "command-line-arguments"
+ pkg.target = ""
+
+ if pkg.Name == "main" {
+ _, elem := filepath.Split(gofiles[0])
+ exe := elem[:len(elem)-len(".go")] + exeSuffix
+ if *buildO == "" {
+ *buildO = exe
+ }
+ if gobin != "" {
+ pkg.target = filepath.Join(gobin, exe)
+ }
+ } else {
+ if *buildO == "" {
+ *buildO = pkg.Name + ".a"
+ }
+ }
+ pkg.Target = pkg.target
+ pkg.Stale = true
+
+ computeStale(pkg)
+ return pkg
+}
+
+// action returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
+ key := cacheKey{mode, p}
+ a := b.actionCache[key]
+ if a != nil {
+ return a
+ }
+
+ a = &action{p: p, pkgdir: p.build.PkgRoot}
+ if p.pkgdir != "" { // overrides p.t
+ a.pkgdir = p.pkgdir
+ }
+
+ b.actionCache[key] = a
+
+ for _, p1 := range p.imports {
+ a.deps = append(a.deps, b.action(depMode, depMode, p1))
+ }
+
+ // If we are not doing a cross-build, then record the binary we'll
+ // generate for cgo as a dependency of the build of any package
+ // using cgo, to make sure we do not overwrite the binary while
+ // a package is using it. If this is a cross-build, then the cgo we
+ // are writing is not the cgo we need to use.
+ if goos == runtime.GOOS && goarch == runtime.GOARCH {
+ if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
+ var stk importStack
+ p1 := loadPackage("cmd/cgo", &stk)
+ if p1.Error != nil {
+ fatalf("load cmd/cgo: %v", p1.Error)
+ }
+ a.cgo = b.action(depMode, depMode, p1)
+ a.deps = append(a.deps, a.cgo)
+ }
+ }
+
+ if p.Standard {
+ switch p.ImportPath {
+ case "builtin", "unsafe":
+ // Fake packages - nothing to build.
+ return a
+ }
+ // gccgo standard library is "fake" too.
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
+ // the target name is needed for cgo.
+ a.target = p.target
+ return a
+ }
+ }
+
+ if !p.Stale && p.target != "" {
+ // p.Stale==false implies that p.target is up-to-date.
+ // Record target name for use by actions depending on this one.
+ a.target = p.target
+ return a
+ }
+
+ if p.local && p.target == "" {
+ // Imported via local path. No permanent target.
+ mode = modeBuild
+ }
+ a.objdir = filepath.Join(b.work, a.p.ImportPath, "_obj") + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(b.work, a.p)
+ a.link = p.Name == "main"
+
+ switch mode {
+ case modeInstall:
+ a.f = (*builder).install
+ a.deps = []*action{b.action(modeBuild, depMode, p)}
+ a.target = a.p.target
+ case modeBuild:
+ a.f = (*builder).build
+ a.target = a.objpkg
+ if a.link {
+ // An executable file.
+ // (This is the name of a temporary file.)
+ a.target = a.objdir + "a.out" + exeSuffix
+ }
+ }
+
+ return a
+}
+
+// actionList returns the list of actions in the dag rooted at root
+// as visited in a depth-first post-order traversal.
+func actionList(root *action) []*action {
+ seen := map[*action]bool{}
+ all := []*action{}
+ var walk func(*action)
+ walk = func(a *action) {
+ if seen[a] {
+ return
+ }
+ seen[a] = true
+ for _, a1 := range a.deps {
+ walk(a1)
+ }
+ all = append(all, a)
+ }
+ walk(root)
+ return all
+}
+
+// do runs the action graph rooted at root.
+func (b *builder) do(root *action) {
+ // Build list of all actions, assigning depth-first post-order priority.
+ // The original implementation here was a true queue
+ // (using a channel) but it had the effect of getting
+ // distracted by low-level leaf actions to the detriment
+ // of completing higher-level actions. The order of
+ // work does not matter much to overall execution time,
+ // but when running "go test std" it is nice to see each test
+ // results as soon as possible. The priorities assigned
+ // ensure that, all else being equal, the execution prefers
+ // to do what it would have done first in a simple depth-first
+ // dependency order traversal.
+ all := actionList(root)
+ for i, a := range all {
+ a.priority = i
+ }
+
+ b.readySema = make(chan bool, len(all))
+ done := make(chan bool)
+
+ // Initialize per-action execution state.
+ for _, a := range all {
+ for _, a1 := range a.deps {
+ a1.triggers = append(a1.triggers, a)
+ }
+ a.pending = len(a.deps)
+ if a.pending == 0 {
+ b.ready.push(a)
+ b.readySema <- true
+ }
+ }
+
+ // Handle runs a single action and takes care of triggering
+ // any actions that are runnable as a result.
+ handle := func(a *action) {
+ var err error
+ if a.f != nil && (!a.failed || a.ignoreFail) {
+ err = a.f(b, a)
+ }
+
+ // The actions run in parallel but all the updates to the
+ // shared work state are serialized through b.exec.
+ b.exec.Lock()
+ defer b.exec.Unlock()
+
+ if err != nil {
+ if err == errPrintedOutput {
+ setExitStatus(2)
+ } else {
+ errorf("%s", err)
+ }
+ a.failed = true
+ }
+
+ for _, a0 := range a.triggers {
+ if a.failed {
+ a0.failed = true
+ }
+ if a0.pending--; a0.pending == 0 {
+ b.ready.push(a0)
+ b.readySema <- true
+ }
+ }
+
+ if a == root {
+ close(b.readySema)
+ done <- true
+ }
+ }
+
+ // Kick off goroutines according to parallelism.
+ // If we are using the -n flag (just printing commands)
+ // drop the parallelism to 1, both to make the output
+ // deterministic and because there is no real work anyway.
+ par := buildP
+ if buildN {
+ par = 1
+ }
+ for i := 0; i < par; i++ {
+ go func() {
+ for _ = range b.readySema {
+ // Receiving a value from b.sema entitles
+ // us to take from the ready queue.
+ b.exec.Lock()
+ a := b.ready.pop()
+ b.exec.Unlock()
+ handle(a)
+ }
+ }()
+ }
+
+ <-done
+}
+
+// build is the action for building a single package or command.
+func (b *builder) build(a *action) (err error) {
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
+ }
+ }()
+ if buildN {
+ // In -n mode, print a banner between packages.
+ // The banner is five lines so that when changes to
+ // different sections of the bootstrap script have to
+ // be merged, the banners give patch something
+ // to use to find its context.
+ fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath)
+ }
+
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
+ }
+
+ // Make build directory.
+ obj := a.objdir
+ if err := b.mkdir(obj); err != nil {
+ return err
+ }
+
+ var gofiles, cfiles, sfiles, objects, cgoObjects []string
+ gofiles = append(gofiles, a.p.GoFiles...)
+ cfiles = append(cfiles, a.p.CFiles...)
+ sfiles = append(sfiles, a.p.SFiles...)
+
+ // Run cgo.
+ if len(a.p.CgoFiles) > 0 {
+ // In a package using cgo, cgo compiles the C and assembly files with gcc.
+ // There is one exception: runtime/cgo's job is to bridge the
+ // cgo and non-cgo worlds, so it necessarily has files in both.
+ // In that case gcc only gets the gcc_* files.
+ var gccfiles []string
+ if a.p.Standard && a.p.ImportPath == "runtime/cgo" {
+ filter := func(files, nongcc, gcc []string) ([]string, []string) {
+ for _, f := range files {
+ if strings.HasPrefix(f, "gcc_") {
+ gcc = append(gcc, f)
+ } else {
+ nongcc = append(nongcc, f)
+ }
+ }
+ return nongcc, gcc
+ }
+ cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles)
+ sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
+ } else {
+ gccfiles = append(cfiles, sfiles...)
+ cfiles = nil
+ sfiles = nil
+ }
+
+ cgoExe := tool("cgo")
+ if a.cgo != nil && a.cgo.target != "" {
+ cgoExe = a.cgo.target
+ }
+ outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles)
+ if err != nil {
+ return err
+ }
+ cgoObjects = append(cgoObjects, outObj...)
+ gofiles = append(gofiles, outGo...)
+ }
+
+ // Prepare Go import path list.
+ inc := b.includeArgs("-I", a.deps)
+
+ // Compile Go.
+ if len(gofiles) > 0 {
+ if out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles); err != nil {
+ return err
+ } else {
+ objects = append(objects, out)
+ }
+ }
+
+ // Copy .h files named for goos or goarch or goos_goarch
+ // to names using GOOS and GOARCH.
+ // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
+ _goos_goarch := "_" + goos + "_" + goarch + ".h"
+ _goos := "_" + goos + ".h"
+ _goarch := "_" + goarch + ".h"
+ for _, file := range a.p.HFiles {
+ switch {
+ case strings.HasSuffix(file, _goos_goarch):
+ targ := file[:len(file)-len(_goos_goarch)] + "_GOOS_GOARCH.h"
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ return err
+ }
+ case strings.HasSuffix(file, _goarch):
+ targ := file[:len(file)-len(_goarch)] + "_GOARCH.h"
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ return err
+ }
+ case strings.HasSuffix(file, _goos):
+ targ := file[:len(file)-len(_goos)] + "_GOOS.h"
+ if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0666); err != nil {
+ return err
+ }
+ }
+ }
+
+ for _, file := range cfiles {
+ out := file[:len(file)-len(".c")] + "." + archChar
+ if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
+ return err
+ }
+ objects = append(objects, out)
+ }
+
+ // Assemble .s files.
+ for _, file := range sfiles {
+ out := file[:len(file)-len(".s")] + "." + archChar
+ if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
+ return err
+ }
+ objects = append(objects, out)
+ }
+
+ // NOTE(rsc): On Windows, it is critically important that the
+ // gcc-compiled objects (cgoObjects) be listed after the ordinary
+ // objects in the archive. I do not know why this is.
+ // http://golang.org/issue/2601
+ objects = append(objects, cgoObjects...)
+
+ // Add system object files.
+ for _, syso := range a.p.SysoFiles {
+ objects = append(objects, filepath.Join(a.p.Dir, syso))
+ }
+
+ // Pack into archive in obj directory
+ if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
+ return err
+ }
+
+ // Link if needed.
+ if a.link {
+ // The compiler only cares about direct imports, but the
+ // linker needs the whole dependency tree.
+ all := actionList(a)
+ all = all[:len(all)-1] // drop a
+ if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// install is the action for installing a single package or executable.
+func (b *builder) install(a *action) (err error) {
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err)
+ }
+ }()
+ a1 := a.deps[0]
+ perm := os.FileMode(0666)
+ if a1.link {
+ perm = 0777
+ }
+
+ // make target directory
+ dir, _ := filepath.Split(a.target)
+ if dir != "" {
+ if err := b.mkdir(dir); err != nil {
+ return err
+ }
+ }
+
+ // remove object dir to keep the amount of
+ // garbage down in a large build. On an operating system
+ // with aggressive buffering, cleaning incrementally like
+ // this keeps the intermediate objects from hitting the disk.
+ if !buildWork {
+ defer os.RemoveAll(a1.objdir)
+ defer os.Remove(a1.target)
+ }
+
+ return b.copyFile(a, a.target, a1.target, perm)
+}
+
+// includeArgs returns the -I or -L directory list for access
+// to the results of the list of actions.
+func (b *builder) includeArgs(flag string, all []*action) []string {
+ inc := []string{}
+ incMap := map[string]bool{
+ b.work: true, // handled later
+ gorootPkg: true,
+ "": true, // ignore empty strings
+ }
+
+ // Look in the temporary space for results of test-specific actions.
+ // This is the $WORK/my/package/_test directory for the
+ // package being built, so there are few of these.
+ for _, a1 := range all {
+ if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
+ incMap[dir] = true
+ inc = append(inc, flag, dir)
+ }
+ }
+
+ // Also look in $WORK for any non-test packages that have
+ // been built but not installed.
+ inc = append(inc, flag, b.work)
+
+ // Finally, look in the installed package directories for each action.
+ for _, a1 := range all {
+ if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
+ incMap[dir] = true
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
+ dir = filepath.Join(dir, "gccgo")
+ } else {
+ dir = filepath.Join(dir, goos+"_"+goarch)
+ }
+ inc = append(inc, flag, dir)
+ }
+ }
+
+ return inc
+}
+
+// copyFile is like 'cp src dst'.
+func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
+ if buildN || buildX {
+ b.showcmd("", "cp %s %s", src, dst)
+ if buildN {
+ return nil
+ }
+ }
+
+ sf, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer sf.Close()
+
+ // Be careful about removing/overwriting dst.
+ // Do not remove/overwrite if dst exists and is a directory
+ // or a non-object file.
+ if fi, err := os.Stat(dst); err == nil {
+ if fi.IsDir() {
+ return fmt.Errorf("build output %q already exists and is a directory", dst)
+ }
+ if !isObject(dst) {
+ return fmt.Errorf("build output %q already exists and is not an object file", dst)
+ }
+ }
+
+ // On Windows, remove lingering ~ file from last attempt.
+ if toolIsWindows {
+ if _, err := os.Stat(dst + "~"); err == nil {
+ os.Remove(dst + "~")
+ }
+ }
+
+ os.Remove(dst)
+ df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil && toolIsWindows {
+ // Windows does not allow deletion of a binary file
+ // while it is executing. Try to move it out of the way.
+ // If the remove fails, which is likely, we'll try again the
+ // next time we do an install of this binary.
+ if err := os.Rename(dst, dst+"~"); err == nil {
+ os.Remove(dst + "~")
+ }
+ df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ }
+ if err != nil {
+ return err
+ }
+
+ _, err = io.Copy(df, sf)
+ df.Close()
+ if err != nil {
+ os.Remove(dst)
+ return fmt.Errorf("copying %s to %s: %v", src, dst, err)
+ }
+ return nil
+}
+
+var objectMagic = [][]byte{
+ {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
+ {'\x7F', 'E', 'L', 'F'}, // ELF
+ {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit
+ {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit
+ {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit
+ {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit
+ {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00}, // PE (Windows) as generated by 6l/8l
+}
+
+func isObject(s string) bool {
+ f, err := os.Open(s)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+ buf := make([]byte, 64)
+ io.ReadFull(f, buf)
+ for _, magic := range objectMagic {
+ if bytes.HasPrefix(buf, magic) {
+ return true
+ }
+ }
+ return false
+}
+
+// fmtcmd formats a command in the manner of fmt.Sprintf but also:
+//
+// If dir is non-empty and the script is not in dir right now,
+// fmtcmd inserts "cd dir\n" before the command.
+//
+// fmtcmd replaces the value of b.work with $WORK.
+// fmtcmd replaces the value of goroot with $GOROOT.
+// fmtcmd replaces the value of b.gobin with $GOBIN.
+//
+// fmtcmd replaces the name of the current directory with dot (.)
+// but only when it is at the beginning of a space-separated token.
+//
+func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string {
+ cmd := fmt.Sprintf(format, args...)
+ if dir != "" && dir != "/" {
+ cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:]
+ if b.scriptDir != dir {
+ b.scriptDir = dir
+ cmd = "cd " + dir + "\n" + cmd
+ }
+ }
+ if b.work != "" {
+ cmd = strings.Replace(cmd, b.work, "$WORK", -1)
+ }
+ return cmd
+}
+
+// showcmd prints the given command to standard output
+// for the implementation of -n or -x.
+func (b *builder) showcmd(dir string, format string, args ...interface{}) {
+ b.output.Lock()
+ defer b.output.Unlock()
+ b.print(b.fmtcmd(dir, format, args...) + "\n")
+}
+
+// showOutput prints "# desc" followed by the given output.
+// The output is expected to contain references to 'dir', usually
+// the source directory for the package that has failed to build.
+// showOutput rewrites mentions of dir with a relative path to dir
+// when the relative path is shorter. This is usually more pleasant.
+// For example, if fmt doesn't compile and we are in src/pkg/html,
+// the output is
+//
+// $ go build
+// # fmt
+// ../fmt/print.go:1090: undefined: asdf
+// $
+//
+// instead of
+//
+// $ go build
+// # fmt
+// /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf
+// $
+//
+// showOutput also replaces references to the work directory with $WORK.
+//
+func (b *builder) showOutput(dir, desc, out string) {
+ prefix := "# " + desc
+ suffix := "\n" + out
+ if reldir := shortPath(dir); reldir != dir {
+ suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1)
+ suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1)
+ }
+ suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1)
+
+ b.output.Lock()
+ defer b.output.Unlock()
+ b.print(prefix, suffix)
+}
+
+// shortPath returns an absolute or relative name for path, whatever is shorter.
+func shortPath(path string) string {
+ if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
+ return rel
+ }
+ return path
+}
+
+// relPaths returns a copy of paths with absolute paths
+// made relative to the current directory if they would be shorter.
+func relPaths(paths []string) []string {
+ var out []string
+ pwd, _ := os.Getwd()
+ for _, p := range paths {
+ rel, err := filepath.Rel(pwd, p)
+ if err == nil && len(rel) < len(p) {
+ p = rel
+ }
+ out = append(out, p)
+ }
+ return out
+}
+
+// errPrintedOutput is a special error indicating that a command failed
+// but that it generated output as well, and that output has already
+// been printed, so there's no point showing 'exit status 1' or whatever
+// the wait status was. The main executor, builder.do, knows not to
+// print this error.
+var errPrintedOutput = errors.New("already printed output - no need to show error")
+
+// run runs the command given by cmdline in the directory dir.
+// If the command fails, run prints information about the failure
+// and returns a non-nil error.
+func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {
+ out, err := b.runOut(dir, desc, cmdargs...)
+ if len(out) > 0 {
+ if out[len(out)-1] != '\n' {
+ out = append(out, '\n')
+ }
+ if desc == "" {
+ desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
+ }
+ b.showOutput(dir, desc, string(out))
+ if err != nil {
+ err = errPrintedOutput
+ }
+ }
+ return err
+}
+
+// runOut runs the command given by cmdline in the directory dir.
+// It returns the command output and any errors that occurred.
+func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byte, error) {
+ cmdline := stringList(cmdargs...)
+ if buildN || buildX {
+ b.showcmd(dir, "%s", strings.Join(cmdline, " "))
+ if buildN {
+ return nil, nil
+ }
+ }
+
+ nbusy := 0
+ for {
+ var buf bytes.Buffer
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ cmd.Dir = dir
+ // TODO: cmd.Env
+ err := cmd.Run()
+
+ // cmd.Run will fail on Unix if some other process has the binary
+ // we want to run open for writing. This can happen here because
+ // we build and install the cgo command and then run it.
+ // If another command was kicked off while we were writing the
+ // cgo binary, the child process for that command may be holding
+ // a reference to the fd, keeping us from running exec.
+ //
+ // But, you might reasonably wonder, how can this happen?
+ // The cgo fd, like all our fds, is close-on-exec, so that we need
+ // not worry about other processes inheriting the fd accidentally.
+ // The answer is that running a command is fork and exec.
+ // A child forked while the cgo fd is open inherits that fd.
+ // Until the child has called exec, it holds the fd open and the
+ // kernel will not let us run cgo. Even if the child were to close
+ // the fd explicitly, it would still be open from the time of the fork
+ // until the time of the explicit close, and the race would remain.
+ //
+ // On Unix systems, this results in ETXTBSY, which formats
+ // as "text file busy". Rather than hard-code specific error cases,
+ // we just look for that string. If this happens, sleep a little
+ // and try again. We let this happen three times, with increasing
+ // sleep lengths: 100+200+400 ms = 0.7 seconds.
+ //
+ // An alternate solution might be to split the cmd.Run into
+ // separate cmd.Start and cmd.Wait, and then use an RWLock
+ // to make sure that copyFile only executes when no cmd.Start
+ // call is in progress. However, cmd.Start (really syscall.forkExec)
+ // only guarantees that when it returns, the exec is committed to
+ // happen and succeed. It uses a close-on-exec file descriptor
+ // itself to determine this, so we know that when cmd.Start returns,
+ // at least one close-on-exec file descriptor has been closed.
+ // However, we cannot be sure that all of them have been closed,
+ // so the program might still encounter ETXTBSY even with such
+ // an RWLock. The race window would be smaller, perhaps, but not
+ // guaranteed to be gone.
+ //
+ // Sleeping when we observe the race seems to be the most reliable
+ // option we have.
+ //
+ // http://golang.org/issue/3001
+ //
+ if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
+ time.Sleep(100 * time.Millisecond << uint(nbusy))
+ nbusy++
+ continue
+ }
+
+ return buf.Bytes(), err
+ }
+ panic("unreachable")
+}
+
+// mkdir makes the named directory.
+func (b *builder) mkdir(dir string) error {
+ b.exec.Lock()
+ defer b.exec.Unlock()
+ // We can be a little aggressive about being
+ // sure directories exist. Skip repeated calls.
+ if b.mkdirCache[dir] {
+ return nil
+ }
+ b.mkdirCache[dir] = true
+
+ if buildN || buildX {
+ b.showcmd("", "mkdir -p %s", dir)
+ if buildN {
+ return nil
+ }
+ }
+
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return err
+ }
+ return nil
+}
+
+// mkAbs returns an absolute path corresponding to
+// evaluating f in the directory dir.
+// We always pass absolute paths of source files so that
+// the error messages will include the full path to a file
+// in need of attention.
+func mkAbs(dir, f string) string {
+ // Leave absolute paths alone.
+ // Also, during -n mode we use the pseudo-directory $WORK
+ // instead of creating an actual work directory that won't be used.
+ // Leave paths beginning with $WORK alone too.
+ if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
+ return f
+ }
+ return filepath.Join(dir, f)
+}
+
+type toolchain interface {
+ // gc runs the compiler in a specific directory on a set of files
+ // and returns the name of the generated output file.
+ // The compiler runs in the directory dir.
+ gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
+ // cc runs the toolchain's C compiler in a directory on a C file
+ // to produce an output file.
+ cc(b *builder, p *Package, objdir, ofile, cfile string) error
+ // asm runs the assembler in a specific directory on a specific file
+ // to generate the named output file.
+ asm(b *builder, p *Package, obj, ofile, sfile string) error
+ // pkgpath builds an appropriate path for a temporary package file.
+ pkgpath(basedir string, p *Package) string
+ // pack runs the archive packer in a specific directory to create
+ // an archive from a set of object files.
+ // typically it is run in the object directory.
+ pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
+ // ld runs the linker to create a package starting at mainpkg.
+ ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
+
+ compiler() string
+ linker() string
+}
+
+type noToolchain struct{}
+
+func noCompiler() error {
+ log.Fatalf("unknown compiler %q", buildContext.Compiler)
+ return nil
+}
+
+func (noToolchain) compiler() string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) linker() string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+ return "", noCompiler()
+}
+
+func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ return noCompiler()
+}
+
+func (noToolchain) pkgpath(basedir string, p *Package) string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+ return noCompiler()
+}
+
+// The Go toolchain.
+type gcToolchain struct{}
+
+func (gcToolchain) compiler() string {
+ return tool(archChar + "g")
+}
+
+func (gcToolchain) linker() string {
+ return tool(archChar + "l")
+}
+
+func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+ out := "_go_." + archChar
+ ofile = obj + out
+ gcargs := []string{"-p", p.ImportPath}
+ if p.Standard && p.ImportPath == "runtime" {
+ // runtime compiles with a special 6g flag to emit
+ // additional reflect type data.
+ gcargs = append(gcargs, "-+")
+ }
+
+ args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+ for _, f := range gofiles {
+ args = append(args, mkAbs(p.Dir, f))
+ }
+ return ofile, b.run(p.Dir, p.ImportPath, args)
+}
+
+func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ sfile = mkAbs(p.Dir, sfile)
+ return b.run(p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
+}
+
+func (gcToolchain) pkgpath(basedir string, p *Package) string {
+ end := filepath.FromSlash(p.ImportPath + ".a")
+ return filepath.Join(basedir, end)
+}
+
+func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ var absOfiles []string
+ for _, f := range ofiles {
+ absOfiles = append(absOfiles, mkAbs(objDir, f))
+ }
+ return b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)
+}
+
+func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ importArgs := b.includeArgs("-L", allactions)
+ return b.run(".", p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
+}
+
+func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+ inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+ cfile = mkAbs(p.Dir, cfile)
+ return b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
+ "-I", objdir, "-I", inc, "-o", ofile,
+ "-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)
+}
+
+// The Gccgo toolchain.
+type gccgcToolchain struct{}
+
+var gccgoBin, _ = exec.LookPath("gccgo")
+
+func (gccgcToolchain) compiler() string {
+ return gccgoBin
+}
+
+func (gccgcToolchain) linker() string {
+ return gccgoBin
+}
+
+func (gccgcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+ out := p.Name + ".o"
+ ofile = obj + out
+ gcargs := []string{"-g"}
+ if prefix := gccgoPrefix(p); prefix != "" {
+ gcargs = append(gcargs, "-fgo-prefix="+gccgoPrefix(p))
+ }
+ args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+ for _, f := range gofiles {
+ args = append(args, mkAbs(p.Dir, f))
+ }
+ return ofile, b.run(p.Dir, p.ImportPath, args)
+}
+
+func (gccgcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ sfile = mkAbs(p.Dir, sfile)
+ return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
+}
+
+func (gccgcToolchain) pkgpath(basedir string, p *Package) string {
+ end := filepath.FromSlash(p.ImportPath + ".a")
+ afile := filepath.Join(basedir, end)
+ // add "lib" to the final element
+ return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
+}
+
+func (gccgcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ var absOfiles []string
+ for _, f := range ofiles {
+ absOfiles = append(absOfiles, mkAbs(objDir, f))
+ }
+ return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+}
+
+func (tools gccgcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ // gccgo needs explicit linking with all package dependencies,
+ // and all LDFLAGS from cgo dependencies.
+ afiles := make(map[*Package]string)
+ ldflags := []string{}
+ cgoldflags := []string{}
+ for _, a := range allactions {
+ if a.p != nil {
+ if !a.p.Standard {
+ if afiles[a.p] == "" || a.objpkg != a.target {
+ afiles[a.p] = a.target
+ }
+ }
+ cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
+ }
+ }
+ for _, afile := range afiles {
+ ldflags = append(ldflags, afile)
+ }
+ ldflags = append(ldflags, cgoldflags...)
+ return b.run(".", p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,-)")
+}
+
+func (gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+ inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+ cfile = mkAbs(p.Dir, cfile)
+ return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
+ "-I", objdir, "-I", inc, "-o", ofile,
+ "-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
+}
+
+func gccgoPrefix(p *Package) string {
+ switch {
+ case p.build.IsCommand() && !p.forceLibrary:
+ return ""
+ case p.fake:
+ return "fake_" + p.ImportPath
+ }
+ return "go_" + p.ImportPath
+}
+
+// gcc runs the gcc C compiler to create an object from a single C file.
+func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
+ cfile = mkAbs(p.Dir, cfile)
+ return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
+}
+
+// gccld runs the gcc linker to create an executable from a set of object files
+func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
+ return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
+}
+
+// gccCmd returns a gcc command line prefix
+func (b *builder) gccCmd(objdir string) []string {
+ // NOTE: env.go's mkEnv knows that the first three
+ // strings returned are "gcc", "-I", objdir (and cuts them off).
+
+ // TODO: HOST_CC?
+ a := []string{"gcc", "-I", objdir, "-g", "-O2"}
+
+ // Definitely want -fPIC but on Windows gcc complains
+ // "-fPIC ignored for target (all code is position independent)"
+ if goos != "windows" {
+ a = append(a, "-fPIC")
+ }
+ switch archChar {
+ case "8":
+ a = append(a, "-m32")
+ case "6":
+ a = append(a, "-m64")
+ }
+ // gcc-4.5 and beyond require explicit "-pthread" flag
+ // for multithreading with pthread library.
+ if buildContext.CgoEnabled {
+ switch goos {
+ case "windows":
+ a = append(a, "-mthreads")
+ default:
+ a = append(a, "-pthread")
+ }
+ }
+
+ // On OS X, some of the compilers behave as if -fno-common
+ // is always set, and the Mach-O linker in 6l/8l assumes this.
+ // See http://golang.org/issue/3253.
+ if goos == "darwin" {
+ a = append(a, "-fno-common")
+ }
+
+ return a
+}
+
+func envList(key string) []string {
+ return strings.Fields(os.Getenv(key))
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, outObj []string, err error) {
+ if goos != toolGOOS {
+ return nil, nil, errors.New("cannot use cgo when compiling for a different operating system")
+ }
+
+ cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.CgoCFLAGS)
+ cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
+
+ if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
+ out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs)
+ if err != nil {
+ b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ return nil, nil, errPrintedOutput
+ }
+ if len(out) > 0 {
+ cgoCFLAGS = append(cgoCFLAGS, strings.Fields(string(out))...)
+ }
+ out, err = b.runOut(p.Dir, p.ImportPath, "pkg-config", "--libs", pkgs)
+ if err != nil {
+ b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ return nil, nil, errPrintedOutput
+ }
+ if len(out) > 0 {
+ cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
+ }
+ }
+
+ // Allows including _cgo_export.h from .[ch] files in the package.
+ cgoCFLAGS = append(cgoCFLAGS, "-I", obj)
+
+ // cgo
+ // TODO: CGOPKGPATH, CGO_FLAGS?
+ gofiles := []string{obj + "_cgo_gotypes.go"}
+ cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
+ for _, fn := range p.CgoFiles {
+ f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+ gofiles = append(gofiles, obj+f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := obj + "_cgo_defun.c"
+
+ cgoflags := []string{}
+ // TODO: make cgo not depend on $GOARCH?
+
+ objExt := archChar
+
+ if p.Standard && p.ImportPath == "runtime/cgo" {
+ cgoflags = append(cgoflags, "-import_runtime_cgo=false")
+ }
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
+ cgoflags = append(cgoflags, "-gccgo")
+ if prefix := gccgoPrefix(p); prefix != "" {
+ cgoflags = append(cgoflags, "-gccgoprefix="+gccgoPrefix(p))
+ }
+ objExt = "o"
+ }
+ if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
+ return nil, nil, err
+ }
+ outGo = append(outGo, gofiles...)
+
+ // cc _cgo_defun.c
+ defunObj := obj + "_cgo_defun." + objExt
+ if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+ return nil, nil, err
+ }
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ var linkobj []string
+ for _, cfile := range cfiles {
+ ofile := obj + cfile[:len(cfile)-1] + "o"
+ if err := b.gcc(p, ofile, cgoCFLAGS, obj+cfile); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ }
+ }
+ for _, file := range gccfiles {
+ ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
+ if err := b.gcc(p, ofile, cgoCFLAGS, file); err != nil {
+ return nil, nil, err
+ }
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+ dynobj := obj + "_cgo_.o"
+ if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
+ return nil, nil, err
+ }
+
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
+ // we don't use dynimport when using gccgo.
+ return outGo, outObj, nil
+ }
+
+ // cgo -dynimport
+ importC := obj + "_cgo_import.c"
+ if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC); err != nil {
+ return nil, nil, err
+ }
+
+ // cc _cgo_import.ARCH
+ importObj := obj + "_cgo_import." + objExt
+ if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
+ return nil, nil, err
+ }
+
+ // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
+ // must be processed before the gcc-generated objects.
+ // Put it first. http://golang.org/issue/2601
+ outObj = append([]string{importObj}, outObj...)
+
+ return outGo, outObj, nil
+}
+
+// An actionQueue is a priority queue of actions.
+type actionQueue []*action
+
+// Implement heap.Interface
+func (q *actionQueue) Len() int { return len(*q) }
+func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
+func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
+func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) }
+func (q *actionQueue) Pop() interface{} {
+ n := len(*q) - 1
+ x := (*q)[n]
+ *q = (*q)[:n]
+ return x
+}
+
+func (q *actionQueue) push(a *action) {
+ heap.Push(q, a)
+}
+
+func (q *actionQueue) pop() *action {
+ return heap.Pop(q).(*action)
+}
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
new file mode 100644
index 000000000..773951826
--- /dev/null
+++ b/src/cmd/go/clean.go
@@ -0,0 +1,199 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+var cmdClean = &Command{
+ UsageLine: "clean [-i] [-r] [-n] [-x] [packages]",
+ Short: "remove object files",
+ Long: `
+Clean removes object files from package source directories.
+The go command builds most objects in a temporary directory,
+so go clean is mainly concerned with object files left by other
+tools or by manual invocations of go build.
+
+Specifically, clean removes the following files from each of the
+source directories corresponding to the import paths:
+
+ _obj/ old object directory, left from Makefiles
+ _test/ old test directory, left from Makefiles
+ _testmain.go old gotest file, left from Makefiles
+ test.out old test log, left from Makefiles
+ build.out old test log, left from Makefiles
+ *.[568ao] object files, left from Makefiles
+
+ DIR(.exe) from go build
+ DIR.test(.exe) from go test -c
+ MAINFILE(.exe) from go build MAINFILE.go
+
+In the list, DIR represents the final path element of the
+directory, and MAINFILE is the base name of any Go source
+file in the directory that is not included when building
+the package.
+
+The -i flag causes clean to remove the corresponding installed
+archive or binary (what 'go install' would create).
+
+The -n flag causes clean to print the remove commands it would execute,
+but not run them.
+
+The -r flag causes clean to be applied recursively to all the
+dependencies of the packages named by the import paths.
+
+The -x flag causes clean to print remove commands as it executes them.
+
+For more about specifying packages, see 'go help packages'.
+ `,
+}
+
+var cleanI bool // clean -i flag
+var cleanN bool // clean -n flag
+var cleanR bool // clean -r flag
+var cleanX bool // clean -x flag
+
+func init() {
+ // break init cycle
+ cmdClean.Run = runClean
+
+ cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
+ cmdClean.Flag.BoolVar(&cleanN, "n", false, "")
+ cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
+ cmdClean.Flag.BoolVar(&cleanX, "x", false, "")
+}
+
+func runClean(cmd *Command, args []string) {
+ for _, pkg := range packagesAndErrors(args) {
+ clean(pkg)
+ }
+}
+
+var cleaned = map[*Package]bool{}
+
+// TODO: These are dregs left by Makefile-based builds.
+// Eventually, can stop deleting these.
+var cleanDir = map[string]bool{
+ "_test": true,
+ "_obj": true,
+}
+
+var cleanFile = map[string]bool{
+ "_testmain.go": true,
+ "test.out": true,
+ "build.out": true,
+ "a.out": true,
+}
+
+var cleanExt = map[string]bool{
+ ".5": true,
+ ".6": true,
+ ".8": true,
+ ".a": true,
+ ".o": true,
+}
+
+func clean(p *Package) {
+ if cleaned[p] {
+ return
+ }
+ if p.Dir == "" {
+ errorf("can't load package: %v", p.Error)
+ return
+ }
+ dirs, err := ioutil.ReadDir(p.Dir)
+ if err != nil {
+ errorf("go clean %s: %v", p.Dir, err)
+ return
+ }
+
+ var b builder
+ b.print = fmt.Print
+
+ packageFile := map[string]bool{}
+ if p.Name != "main" {
+ // Record which files are not in package main.
+ // The others are.
+ keep := func(list []string) {
+ for _, f := range list {
+ packageFile[f] = true
+ }
+ }
+ keep(p.GoFiles)
+ keep(p.CgoFiles)
+ keep(p.TestGoFiles)
+ keep(p.XTestGoFiles)
+ }
+
+ _, elem := filepath.Split(p.Dir)
+ allRemove := []string{
+ elem,
+ elem + ".exe",
+ elem + ".test",
+ elem + ".test.exe",
+ }
+ for _, dir := range dirs {
+ name := dir.Name()
+ if packageFile[name] {
+ continue
+ }
+ if !dir.IsDir() && strings.HasSuffix(name, ".go") {
+ base := name[:len(name)-len(".go")]
+ allRemove = append(allRemove, base, base+".exe")
+ }
+ }
+ if cleanN || cleanX {
+ b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
+ }
+
+ toRemove := map[string]bool{}
+ for _, name := range allRemove {
+ toRemove[name] = true
+ }
+ for _, dir := range dirs {
+ name := dir.Name()
+ if dir.IsDir() {
+ // TODO: Remove once Makefiles are forgotten.
+ if cleanDir[name] {
+ if cleanN || cleanX {
+ b.showcmd(p.Dir, "rm -r %s", name)
+ if cleanN {
+ continue
+ }
+ }
+ os.RemoveAll(filepath.Join(p.Dir, name))
+ }
+ continue
+ }
+
+ if cleanN {
+ continue
+ }
+
+ if cleanFile[name] || cleanExt[filepath.Ext(name)] || toRemove[name] {
+ os.Remove(filepath.Join(p.Dir, name))
+ }
+ }
+
+ if cleanI && p.target != "" {
+ if cleanN || cleanX {
+ b.showcmd("", "rm -f %s", p.target)
+ }
+ if !cleanN {
+ os.Remove(p.target)
+ }
+ }
+
+ if cleanR {
+ for _, p1 := range p.imports {
+ clean(p1)
+ }
+ }
+}
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
new file mode 100644
index 000000000..d9f930867
--- /dev/null
+++ b/src/cmd/go/discovery.go
@@ -0,0 +1,63 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package main
+
+import (
+ "encoding/xml"
+ "io"
+ "strings"
+)
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport) {
+ d := xml.NewDecoder(r)
+ d.Strict = false
+ for {
+ t, err := d.Token()
+ if err != nil {
+ return
+ }
+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+ return
+ }
+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+ return
+ }
+ e, ok := t.(xml.StartElement)
+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+ continue
+ }
+ if attrValue(e.Attr, "name") != "go-import" {
+ continue
+ }
+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+ imports = append(imports, metaImport{
+ Prefix: f[0],
+ VCS: f[1],
+ RepoRoot: f[2],
+ })
+ }
+ }
+ return
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+ for _, a := range attrs {
+ if strings.EqualFold(a.Name.Local, name) {
+ return a.Value
+ }
+ }
+ return ""
+}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
new file mode 100644
index 000000000..4bfd5236d
--- /dev/null
+++ b/src/cmd/go/doc.go
@@ -0,0 +1,769 @@
+// 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.
+
+/*
+Go is a tool for managing Go source code.
+
+Usage:
+
+ go command [arguments]
+
+The commands are:
+
+ build compile packages and dependencies
+ clean remove object files
+ doc run godoc on package sources
+ env print Go environment information
+ fix run go tool fix on packages
+ fmt run gofmt on package sources
+ get download and install packages and dependencies
+ install compile and install packages and dependencies
+ list list packages
+ run compile and run Go program
+ test test packages
+ tool run specified go tool
+ version print Go version
+ vet run go tool vet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+ gopath GOPATH environment variable
+ packages description of package lists
+ remote remote import path syntax
+ testflag description of testing flags
+ testfunc description of testing functions
+
+Use "go help [topic]" for more information about that topic.
+
+
+Compile packages and dependencies
+
+Usage:
+
+ go build [-o output] [build flags] [packages]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+If the arguments are a list of .go files, build treats them as a list
+of source files specifying a single package.
+
+When the command line specifies a single main package,
+build writes the resulting executable to output.
+Otherwise build compiles the packages but discards the results,
+serving only as a check that the packages can be built.
+
+The -o flag specifies the output file name. If not specified, the
+name is packagename.a (for a non-main package) or the base
+name of the first source file (for a main package).
+
+The build flags are shared by the build, install, run, and test commands:
+
+ -a
+ force rebuilding of packages that are already up-to-date.
+ -n
+ print the commands but do not run them.
+ -p n
+ the number of builds that can be run in parallel.
+ The default is the number of CPUs available.
+ -v
+ print the names of packages as they are compiled.
+ -work
+ print the name of the temporary work directory and
+ do not delete it when exiting.
+ -x
+ print the commands.
+
+ -compiler name
+ name of compiler to use, as in runtime.Compiler (gccgo or gc)
+ -gccgoflags 'arg list'
+ arguments to pass on each gccgo compiler/linker invocation
+ -gcflags 'arg list'
+ arguments to pass on each 5g, 6g, or 8g compiler invocation
+ -ldflags 'flag list'
+ arguments to pass on each 5l, 6l, or 8l linker invocation
+ -tags 'tag list'
+ a list of build tags to consider satisfied during the build.
+ See the documentation for the go/build package for
+ more information about build tags.
+
+For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+see 'go help gopath'.
+
+See also: go install, go get, go clean.
+
+
+Remove object files
+
+Usage:
+
+ go clean [-i] [-r] [-n] [-x] [packages]
+
+Clean removes object files from package source directories.
+The go command builds most objects in a temporary directory,
+so go clean is mainly concerned with object files left by other
+tools or by manual invocations of go build.
+
+Specifically, clean removes the following files from each of the
+source directories corresponding to the import paths:
+
+ _obj/ old object directory, left from Makefiles
+ _test/ old test directory, left from Makefiles
+ _testmain.go old gotest file, left from Makefiles
+ test.out old test log, left from Makefiles
+ build.out old test log, left from Makefiles
+ *.[568ao] object files, left from Makefiles
+
+ DIR(.exe) from go build
+ DIR.test(.exe) from go test -c
+ MAINFILE(.exe) from go build MAINFILE.go
+
+In the list, DIR represents the final path element of the
+directory, and MAINFILE is the base name of any Go source
+file in the directory that is not included when building
+the package.
+
+The -i flag causes clean to remove the corresponding installed
+archive or binary (what 'go install' would create).
+
+The -n flag causes clean to print the remove commands it would execute,
+but not run them.
+
+The -r flag causes clean to be applied recursively to all the
+dependencies of the packages named by the import paths.
+
+The -x flag causes clean to print remove commands as it executes them.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Run godoc on package sources
+
+Usage:
+
+ go doc [packages]
+
+Doc runs the godoc command on the packages named by the
+import paths.
+
+For more about godoc, see 'godoc godoc'.
+For more about specifying packages, see 'go help packages'.
+
+To run godoc with specific options, run godoc itself.
+
+See also: go fix, go fmt, go vet.
+
+
+Print Go environment information
+
+Usage:
+
+ go env [var ...]
+
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file). If one or more variable
+names is given as arguments, env prints the value of
+each named variable on its own line.
+
+
+Run go tool fix on packages
+
+Usage:
+
+ go fix [packages]
+
+Fix runs the Go fix command on the packages named by the import paths.
+
+For more about fix, see 'godoc fix'.
+For more about specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+
+
+Run gofmt on package sources
+
+Usage:
+
+ go fmt [packages]
+
+Fmt runs the command 'gofmt -l -w' on the packages named
+by the import paths. It prints the names of the files that are modified.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about specifying packages, see 'go help packages'.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go doc, go fix, go vet.
+
+
+Download and install packages and dependencies
+
+Usage:
+
+ go get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [packages]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+The -a, -n, -v, -x, and -p flags have the same meaning as in 'go build'
+and 'go install'. See 'go help build'.
+
+The -d flag instructs get to stop after downloading the packages; that is,
+it instructs get not to install the packages.
+
+The -fix flag instructs get to run the fix tool on the downloaded packages
+before resolving dependencies or building the code.
+
+The -u flag instructs get to use the network to update the named packages
+and their dependencies. By default, get uses the network to check out
+missing packages but does not use it to look for updates to existing packages.
+
+When checking out or updating a package, get looks for a branch or
+tag that matches the locally installed version of Go. If the local
+version "is release.rNN", it searches for "go.rNN". (For an
+installation using Go version "weekly.YYYY-MM-DD", it searches for a
+package version labeled "go.YYYY-MM-DD".) If the desired version
+cannot be found but others exist with labels in the correct format,
+get retrieves the most recent version before the desired label.
+Finally, if all else fails it retrieves the most recent version of
+the package.
+
+For more about specifying packages, see 'go help packages'.
+
+For more about how 'go get' finds source code to
+download, see 'go help remote'.
+
+See also: go build, go install, go clean.
+
+
+Compile and install packages and dependencies
+
+Usage:
+
+ go install [build flags] [packages]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go get, go clean.
+
+
+List packages
+
+Usage:
+
+ go list [-e] [-f format] [-json] [packages]
+
+List lists the packages named by the import paths, one per line.
+
+The default output shows the package import path:
+
+ code.google.com/p/google-api-go-client/books/v1
+ code.google.com/p/goauth2/oauth
+ code.google.com/p/sqlite
+
+The -f flag specifies an alternate format for the list,
+using the syntax of package template. The default output
+is equivalent to -f '{{.ImportPath}}'. The struct
+being passed to the template is:
+
+ type Package struct {
+ Dir string // directory containing package sources
+ ImportPath string // import path of package in dir
+ Name string // package name
+ Doc string // package documentation string
+ Target string // install path
+ Goroot bool // is this package in the Go root?
+ Standard bool // is this package part of the standard Go library?
+ Stale bool // would 'go install' do anything for this package?
+ Root string // Go root or Go path dir containing this package
+
+ // Source files
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go sources files that import "C"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso object files to add to archive
+
+ // Cgo directives
+ CgoCFLAGS []string // cgo: flags for C compiler
+ CgoLDFLAGS []string // cgo: flags for linker
+ CgoPkgConfig []string // cgo: pkg-config names
+
+ // Dependency information
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+
+ // Error information
+ Incomplete bool // this package or a dependency has an error
+ Error *PackageError // error loading package
+ DepsErrors []*PackageError // errors loading dependencies
+
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
+ }
+
+The -json flag causes the package data to be printed in JSON format
+instead of using the template format.
+
+The -e flag changes the handling of erroneous packages, those that
+cannot be found or are malformed. By default, the list command
+prints an error to standard error for each erroneous package and
+omits the packages from consideration during the usual printing.
+With the -e flag, the list command never prints errors to standard
+error and instead processes the erroneous packages with the usual
+printing. Erroneous packages will have a non-empty ImportPath and
+a non-nil Error field; other information may or may not be missing
+(zeroed).
+
+For more about specifying packages, see 'go help packages'.
+
+
+Compile and run Go program
+
+Usage:
+
+ go run [build flags] gofiles... [arguments...]
+
+Run compiles and runs the main package comprising the named Go source files.
+
+For more about build flags, see 'go help build'.
+
+See also: go build.
+
+
+Test packages
+
+Usage:
+
+ go test [-c] [-i] [build flags] [packages] [flags for test binary]
+
+'Go test' automates testing the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+ ok archive/tar 0.011s
+ FAIL archive/zip 0.022s
+ ok compress/gzip 0.033s
+ ...
+
+followed by detailed output for each failed package.
+
+'Go test' recompiles each package along with any files with names matching
+the file pattern "*_test.go". These additional files can contain test functions,
+benchmark functions, and example functions. See 'go help testfunc' for more.
+
+By default, go test needs no arguments. It compiles and tests the package
+with source in the current directory, including tests, and runs the tests.
+
+The package is built in a temporary directory so it does not interfere with the
+non-test installation.
+
+In addition to the build flags, the flags handled by 'go test' itself are:
+
+ -c Compile the test binary to pkg.test but do not run it.
+
+ -i
+ Install packages that are dependencies of the test.
+ Do not run the test.
+
+The test binary also accepts flags that control execution of the test; these
+flags are also accessible by 'go test'. See 'go help testflag' for details.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+
+
+Run specified go tool
+
+Usage:
+
+ go tool [-n] command [args...]
+
+Tool runs the go tool command identified by the arguments.
+With no arguments it prints the list of known tools.
+
+The -n flag causes tool to print the command that would be
+executed but not execute it.
+
+For more about each tool command, see 'go tool command -h'.
+
+
+Print Go version
+
+Usage:
+
+ go version
+
+Version prints the Go version, as reported by runtime.Version.
+
+
+Run go tool vet on packages
+
+Usage:
+
+ go vet [packages]
+
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet, see 'godoc vet'.
+For more about specifying packages, see 'go help packages'.
+
+To run the vet tool with specific options, run 'go tool vet'.
+
+See also: go fmt, go fix.
+
+
+GOPATH environment variable
+
+The Go path is used to resolve import statements.
+It is implemented by and documented in the go/build package.
+
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code. The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path. That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands. If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
+
+Here's an example directory layout:
+
+ GOPATH=/home/user/gocode
+
+ /home/user/gocode/
+ src/
+ foo/
+ bar/ (go code in package bar)
+ x.go
+ quux/ (go code in package main)
+ y.go
+ bin/
+ quux (installed command)
+ pkg/
+ linux_amd64/
+ foo/
+ bar.a (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+
+
+Description of package lists
+
+Many commands apply to a set of packages:
+
+ go action [packages]
+
+Usually, [packages] is a list of import paths.
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+The special import path "all" expands to all package directories
+found in all the GOPATH trees. For example, 'go list all'
+lists all the packages on the local system.
+
+The special import path "std" is like all but expands to just the
+packages in the standard Go library.
+
+An import path is a pattern if it includes one or more "..." wildcards,
+each of which can match any string, including the empty string and
+strings containing slashes. Such a pattern expands to all package
+directories found in the GOPATH trees with names matching the
+patterns. As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
+
+An import path can also name a package to be downloaded from
+a remote repository. Run 'go help remote' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you. For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'code.google.com/p/project'.
+
+As a special case, if the package list is a list of .go files from a
+single directory, the command is applied to a single synthesized
+package made up of exactly those files, ignoring any build constraints
+in those files and ignoring any other files in the directory.
+
+
+Remote import path syntax
+
+An import path (see 'go help importpath') denotes a package
+stored in the local file system. Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+ BitBucket (Mercurial)
+
+ import "bitbucket.org/user/project"
+ import "bitbucket.org/user/project/sub/directory"
+
+ GitHub (Git)
+
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
+
+ Google Code Project Hosting (Git, Mercurial, Subversion)
+
+ import "code.google.com/p/project"
+ import "code.google.com/p/project/sub/directory"
+
+ import "code.google.com/p/project.subrepository"
+ import "code.google.com/p/project.subrepository/sub/directory"
+
+ Launchpad (Bazaar)
+
+ import "launchpad.net/project"
+ import "launchpad.net/project/series"
+ import "launchpad.net/project/series/sub/directory"
+
+ import "launchpad.net/~user/project/branch"
+ import "launchpad.net/~user/project/branch/sub/directory"
+
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
+
+ repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository. The supported version control systems are:
+
+ Bazaar .bzr
+ Git .git
+ Mercurial .hg
+ Subversion .svn
+
+For example,
+
+ import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+example.org/user/foo or foo.hg, and
+
+ import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at
+example.com/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading. For example, a Git
+download tries git://, then https://, then http://.
+
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path correponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help install' for more.
+
+
+Description of testing flags
+
+The 'go test' command takes both flags that apply to 'go test' itself
+and flags that apply to the resulting test binary.
+
+The test binary, called pkg.test, where pkg is the name of the
+directory containing the package sources, has its own flags:
+
+ -test.v
+ Verbose output: log all tests as they are run.
+
+ -test.run pattern
+ Run only those tests and examples matching the regular
+ expression.
+
+ -test.bench pattern
+ Run benchmarks matching the regular expression.
+ By default, no benchmarks run.
+
+ -test.cpuprofile cpu.out
+ Write a CPU profile to the specified file before exiting.
+
+ -test.memprofile mem.out
+ Write a memory profile to the specified file when all tests
+ are complete.
+
+ -test.memprofilerate n
+ Enable more precise (and expensive) memory profiles by setting
+ runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
+ To profile all memory allocations, use -test.memprofilerate=1
+ and set the environment variable GOGC=off to disable the
+ garbage collector, provided the test can run in the available
+ memory without garbage collection.
+
+ -test.parallel n
+ Allow parallel execution of test functions that call t.Parallel.
+ The value of this flag is the maximum number of tests to run
+ simultaneously; by default, it is set to the value of GOMAXPROCS.
+
+ -test.short
+ Tell long-running tests to shorten their run time.
+ It is off by default but set during all.bash so that installing
+ the Go tree can run a sanity check but not spend time running
+ exhaustive tests.
+
+ -test.timeout t
+ If a test runs longer than t, panic.
+
+ -test.benchtime n
+ Run enough iterations of each benchmark to take n seconds.
+ The default is 1 second.
+
+ -test.cpu 1,2,4
+ Specify a list of GOMAXPROCS values for which the tests or
+ benchmarks should be executed. The default is the current value
+ of GOMAXPROCS.
+
+For convenience, each of these -test.X flags of the test binary is
+also available as the flag -X in 'go test' itself. Flags not listed
+here are passed through unaltered. For instance, the command
+
+ go test -x -v -cpuprofile=prof.out -dir=testdata -update
+
+will compile the test binary and then run it as
+
+ pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+
+
+Description of testing functions
+
+The 'go test' command expects to find test, benchmark, and example functions
+in the "*_test.go" files corresponding to the package under test.
+
+A test function is one named TestXXX (where XXX is any alphanumeric string
+not starting with a lower case letter) and should have the signature,
+
+ func TestXXX(t *testing.T) { ... }
+
+A benchmark function is one named BenchmarkXXX and should have the signature,
+
+ func BenchmarkXXX(b *testing.B) { ... }
+
+An example function is similar to a test function but, instead of using *testing.T
+to report success or failure, prints output to os.Stdout and os.Stderr.
+That output is compared against the function's "Output:" comment, which
+must be the last comment in the function body (see example below). An
+example with no such comment, or with no text after "Output:" is compiled
+but not executed.
+
+Godoc displays the body of ExampleXXX to demonstrate the use
+of the function, constant, or variable XXX. An example of a method M with
+receiver type T or *T is named ExampleT_M. There may be multiple examples
+for a given function, constant, or variable, distinguished by a trailing _xxx,
+where xxx is a suffix not beginning with an upper case letter.
+
+Here is an example of an example:
+
+ func ExamplePrintln() {
+ Println("The output of\nthis example.")
+ // Output: The output of
+ // this example.
+ }
+
+The entire test file is presented as the example when it contains a single
+example function, at least one other function, type, variable, or constant
+declaration, and no test or benchmark functions.
+
+See the documentation of the testing package for more information.
+
+
+*/
+package documentation
+
+// NOTE: cmdDoc is in fmt.go.
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
new file mode 100644
index 000000000..d5b034809
--- /dev/null
+++ b/src/cmd/go/env.go
@@ -0,0 +1,89 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+var cmdEnv = &Command{
+ Run: runEnv,
+ UsageLine: "env [var ...]",
+ Short: "print Go environment information",
+ Long: `
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file). If one or more variable
+names is given as arguments, env prints the value of
+each named variable on its own line.
+ `,
+}
+
+type envVar struct {
+ name, value string
+}
+
+func mkEnv() []envVar {
+ var b builder
+ b.init()
+
+ env := []envVar{
+ {"GOROOT", goroot},
+ {"GOBIN", gobin},
+ {"GOARCH", goarch},
+ {"GOCHAR", archChar},
+ {"GOOS", goos},
+ {"GOEXE", exeSuffix},
+ {"GOHOSTARCH", runtime.GOARCH},
+ {"GOHOSTOS", runtime.GOOS},
+ {"GOTOOLDIR", toolDir},
+ {"GOGCCFLAGS", strings.Join(b.gccCmd(".")[3:], " ")},
+ }
+
+ if buildContext.CgoEnabled {
+ env = append(env, envVar{"CGO_ENABLED", "1"})
+ } else {
+ env = append(env, envVar{"CGO_ENABLED", "0"})
+ }
+
+ return env
+}
+
+func findEnv(env []envVar, name string) string {
+ for _, e := range env {
+ if e.name == name {
+ return e.value
+ }
+ }
+ return ""
+}
+
+func runEnv(cmd *Command, args []string) {
+ env := mkEnv()
+ if len(args) > 0 {
+ for _, name := range args {
+ fmt.Printf("%s\n", findEnv(env, name))
+ }
+ return
+ }
+
+ switch runtime.GOOS {
+ default:
+ for _, e := range env {
+ fmt.Printf("%s=\"%s\"\n", e.name, e.value)
+ }
+ case "plan9":
+ for _, e := range env {
+ fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
+ }
+ case "windows":
+ for _, e := range env {
+ fmt.Printf("set %s=%s\n", e.name, e.value)
+ }
+ }
+}
diff --git a/src/cmd/go/fix.go b/src/cmd/go/fix.go
new file mode 100644
index 000000000..ef02b5739
--- /dev/null
+++ b/src/cmd/go/fix.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.
+
+package main
+
+var cmdFix = &Command{
+ Run: runFix,
+ UsageLine: "fix [packages]",
+ Short: "run go tool fix on packages",
+ Long: `
+Fix runs the Go fix command on the packages named by the import paths.
+
+For more about fix, see 'godoc fix'.
+For more about specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+ `,
+}
+
+func runFix(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ // Use pkg.gofiles instead of pkg.Dir so that
+ // the command only applies to this package,
+ // not to packages in subdirectories.
+ run(stringList(tool("fix"), relPaths(pkg.gofiles)))
+ }
+}
diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go
new file mode 100644
index 000000000..cea9b0a51
--- /dev/null
+++ b/src/cmd/go/fmt.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var cmdFmt = &Command{
+ Run: runFmt,
+ UsageLine: "fmt [packages]",
+ Short: "run gofmt on package sources",
+ Long: `
+Fmt runs the command 'gofmt -l -w' on the packages named
+by the import paths. It prints the names of the files that are modified.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about specifying packages, see 'go help packages'.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go doc, go fix, go vet.
+ `,
+}
+
+func runFmt(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ // Use pkg.gofiles instead of pkg.Dir so that
+ // the command only applies to this package,
+ // not to packages in subdirectories.
+ run(stringList("gofmt", "-l", "-w", relPaths(pkg.gofiles)))
+ }
+}
+
+var cmdDoc = &Command{
+ Run: runDoc,
+ UsageLine: "doc [packages]",
+ Short: "run godoc on package sources",
+ Long: `
+Doc runs the godoc command on the packages named by the
+import paths.
+
+For more about godoc, see 'godoc godoc'.
+For more about specifying packages, see 'go help packages'.
+
+To run godoc with specific options, run godoc itself.
+
+See also: go fix, go fmt, go vet.
+ `,
+}
+
+func runDoc(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ if pkg.ImportPath == "command-line arguments" {
+ errorf("go doc: cannot use package file list")
+ continue
+ }
+ run("godoc", pkg.Dir)
+ }
+}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
new file mode 100644
index 000000000..f70b6761d
--- /dev/null
+++ b/src/cmd/go/get.go
@@ -0,0 +1,428 @@
+// 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.
+
+// TODO: Dashboard upload
+
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+var cmdGet = &Command{
+ UsageLine: "get [-a] [-d] [-fix] [-n] [-p n] [-u] [-v] [-x] [packages]",
+ Short: "download and install packages and dependencies",
+ Long: `
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+The -a, -n, -v, -x, and -p flags have the same meaning as in 'go build'
+and 'go install'. See 'go help build'.
+
+The -d flag instructs get to stop after downloading the packages; that is,
+it instructs get not to install the packages.
+
+The -fix flag instructs get to run the fix tool on the downloaded packages
+before resolving dependencies or building the code.
+
+The -u flag instructs get to use the network to update the named packages
+and their dependencies. By default, get uses the network to check out
+missing packages but does not use it to look for updates to existing packages.
+
+When checking out or updating a package, get looks for a branch or
+tag that matches the locally installed version of Go. If the local
+version "is release.rNN", it searches for "go.rNN". (For an
+installation using Go version "weekly.YYYY-MM-DD", it searches for a
+package version labeled "go.YYYY-MM-DD".) If the desired version
+cannot be found but others exist with labels in the correct format,
+get retrieves the most recent version before the desired label.
+Finally, if all else fails it retrieves the most recent version of
+the package.
+
+For more about specifying packages, see 'go help packages'.
+
+For more about how 'go get' finds source code to
+download, see 'go help remote'.
+
+See also: go build, go install, go clean.
+ `,
+}
+
+var getD = cmdGet.Flag.Bool("d", false, "")
+var getU = cmdGet.Flag.Bool("u", false, "")
+var getFix = cmdGet.Flag.Bool("fix", false, "")
+
+func init() {
+ addBuildFlags(cmdGet)
+ cmdGet.Run = runGet // break init loop
+}
+
+func runGet(cmd *Command, args []string) {
+ // Phase 1. Download/update.
+ var stk importStack
+ for _, arg := range downloadPaths(args) {
+ download(arg, &stk)
+ }
+ exitIfErrors()
+
+ // Phase 2. Rescan packages and reevaluate args list.
+
+ // Code we downloaded and all code that depends on it
+ // needs to be evicted from the package cache so that
+ // the information will be recomputed. Instead of keeping
+ // track of the reverse dependency information, evict
+ // everything.
+ for name := range packageCache {
+ delete(packageCache, name)
+ }
+
+ args = importPaths(args)
+
+ // Phase 3. Install.
+ if *getD {
+ // Download only.
+ // Check delayed until now so that importPaths
+ // has a chance to print errors.
+ return
+ }
+
+ runInstall(cmd, args)
+}
+
+// downloadPath prepares the list of paths to pass to download.
+// It expands ... patterns that can be expanded. If there is no match
+// for a particular pattern, downloadPaths leaves it in the result list,
+// in the hope that we can figure out the repository from the
+// initial ...-free prefix.
+func downloadPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ var expand []string
+ // Use matchPackagesInFS to avoid printing
+ // warnings. They will be printed by the
+ // eventual call to importPaths instead.
+ if build.IsLocalImport(a) {
+ expand = matchPackagesInFS(a)
+ } else {
+ expand = matchPackages(a)
+ }
+ if len(expand) > 0 {
+ out = append(out, expand...)
+ continue
+ }
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// downloadCache records the import paths we have already
+// considered during the download, to avoid duplicate work when
+// there is more than one dependency sequence leading to
+// a particular package.
+var downloadCache = map[string]bool{}
+
+// downloadRootCache records the version control repository
+// root directories we have already considered during the download.
+// For example, all the packages in the code.google.com/p/codesearch repo
+// share the same root (the directory for that path), and we only need
+// to run the hg commands to consider each repository once.
+var downloadRootCache = map[string]bool{}
+
+// download runs the download half of the get command
+// for the package named by the argument.
+func download(arg string, stk *importStack) {
+ p := loadPackage(arg, stk)
+
+ // There's nothing to do if this is a package in the standard library.
+ if p.Standard {
+ return
+ }
+
+ // Only process each package once.
+ if downloadCache[arg] {
+ return
+ }
+ downloadCache[arg] = true
+
+ pkgs := []*Package{p}
+ wildcardOkay := len(*stk) == 0
+
+ // Download if the package is missing, or update if we're using -u.
+ if p.Dir == "" || *getU {
+ // The actual download.
+ stk.push(p.ImportPath)
+ err := downloadPackage(p)
+ if err != nil {
+ errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
+ stk.pop()
+ return
+ }
+
+ args := []string{arg}
+ // If the argument has a wildcard in it, re-evaluate the wildcard.
+ // We delay this until after reloadPackage so that the old entry
+ // for p has been replaced in the package cache.
+ if wildcardOkay && strings.Contains(arg, "...") {
+ if build.IsLocalImport(arg) {
+ args = matchPackagesInFS(arg)
+ } else {
+ args = matchPackages(arg)
+ }
+ }
+
+ // Clear all relevant package cache entries before
+ // doing any new loads.
+ for _, arg := range args {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ }
+
+ pkgs = pkgs[:0]
+ for _, arg := range args {
+ stk.push(arg)
+ p := loadPackage(arg, stk)
+ stk.pop()
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ continue
+ }
+ pkgs = append(pkgs, p)
+ }
+ }
+
+ // Process package, which might now be multiple packages
+ // due to wildcard expansion.
+ for _, p := range pkgs {
+ if *getFix {
+ run(stringList(tool("fix"), relPaths(p.gofiles)))
+
+ // The imports might have changed, so reload again.
+ p = reloadPackage(arg, stk)
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ return
+ }
+ }
+
+ // Process dependencies, now that we know what they are.
+ for _, dep := range p.deps {
+ download(dep.ImportPath, stk)
+ }
+ }
+}
+
+// downloadPackage runs the create or download command
+// to make the first copy of or update a copy of the given package.
+func downloadPackage(p *Package) error {
+ var (
+ vcs *vcsCmd
+ repo, rootPath string
+ err error
+ )
+ if p.build.SrcRoot != "" {
+ // Directory exists. Look for checkout along path to src.
+ vcs, rootPath, err = vcsForDir(p)
+ if err != nil {
+ return err
+ }
+ repo = "<local>" // should be unused; make distinctive
+ } else {
+ // Analyze the import path to determine the version control system,
+ // repository, and the import path for the root of the repository.
+ rr, err := repoRootForImportPath(p.ImportPath)
+ if err != nil {
+ return err
+ }
+ vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
+ }
+
+ if p.build.SrcRoot == "" {
+ // Package not found. Put in first directory of $GOPATH or else $GOROOT.
+ // Guard against people setting GOPATH=$GOROOT. We have to use
+ // $GOROOT's directory hierarchy (src/pkg, not just src) in that case.
+ if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 && list[0] != goroot {
+ p.build.SrcRoot = filepath.Join(list[0], "src")
+ p.build.PkgRoot = filepath.Join(list[0], "pkg")
+ } else {
+ p.build.SrcRoot = filepath.Join(goroot, "src", "pkg")
+ p.build.PkgRoot = filepath.Join(goroot, "pkg")
+ }
+ }
+ root := filepath.Join(p.build.SrcRoot, rootPath)
+ // If we've considered this repository already, don't do it again.
+ if downloadRootCache[root] {
+ return nil
+ }
+ downloadRootCache[root] = true
+
+ if buildV {
+ fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
+ }
+
+ // Check that this is an appropriate place for the repo to be checked out.
+ // The target directory must either not exist or have a repo checked out already.
+ meta := filepath.Join(root, "."+vcs.cmd)
+ st, err := os.Stat(meta)
+ if err == nil && !st.IsDir() {
+ return fmt.Errorf("%s exists but is not a directory", meta)
+ }
+ if err != nil {
+ // Metadata directory does not exist. Prepare to checkout new copy.
+ // Some version control tools require the target directory not to exist.
+ // We require that too, just to avoid stepping on existing work.
+ if _, err := os.Stat(root); err == nil {
+ return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
+ }
+ // Some version control tools require the parent of the target to exist.
+ parent, _ := filepath.Split(root)
+ if err := os.MkdirAll(parent, 0777); err != nil {
+ return err
+ }
+ if err = vcs.create(root, repo); err != nil {
+ return err
+ }
+ } else {
+ // Metadata directory does exist; download incremental updates.
+ if err = vcs.download(root); err != nil {
+ return err
+ }
+ }
+
+ if buildN {
+ // Do not show tag sync in -n; it's noise more than anything,
+ // and since we're not running commands, no tag will be found.
+ // But avoid printing nothing.
+ fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
+ return nil
+ }
+
+ // Select and sync to appropriate version of the repository.
+ tags, err := vcs.tags(root)
+ if err != nil {
+ return err
+ }
+ vers := runtime.Version()
+ if i := strings.Index(vers, " "); i >= 0 {
+ vers = vers[:i]
+ }
+ if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// goTag matches go release tags such as go1 and go1.2.3.
+// The numbers involved must be small (at most 4 digits),
+// have no unnecessary leading zeros, and the version cannot
+// end in .0 - it is go1, not go1.0 or go1.0.0.
+var goTag = regexp.MustCompile(
+ `^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
+)
+
+// selectTag returns the closest matching tag for a given version.
+// Closest means the latest one that is not after the current release.
+// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
+// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
+// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
+func selectTag(goVersion string, tags []string) (match string) {
+ const rPrefix = "release.r"
+ if strings.HasPrefix(goVersion, rPrefix) {
+ p := "go.r"
+ v, err := strconv.ParseFloat(goVersion[len(rPrefix):], 64)
+ if err != nil {
+ return ""
+ }
+ var matchf float64
+ for _, t := range tags {
+ if !strings.HasPrefix(t, p) {
+ continue
+ }
+ tf, err := strconv.ParseFloat(t[len(p):], 64)
+ if err != nil {
+ continue
+ }
+ if matchf < tf && tf <= v {
+ match, matchf = t, tf
+ }
+ }
+ }
+
+ const wPrefix = "weekly."
+ if strings.HasPrefix(goVersion, wPrefix) {
+ p := "go.weekly."
+ v := goVersion[len(wPrefix):]
+ for _, t := range tags {
+ if !strings.HasPrefix(t, p) {
+ continue
+ }
+ if match < t && t[len(p):] <= v {
+ match = t
+ }
+ }
+ }
+
+ if goTag.MatchString(goVersion) {
+ v := goVersion
+ for _, t := range tags {
+ if !goTag.MatchString(t) {
+ continue
+ }
+ if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
+ match = t
+ }
+ }
+ }
+
+ return match
+}
+
+// cmpGoVersion returns -1, 0, +1 reporting whether
+// x < y, x == y, or x > y.
+func cmpGoVersion(x, y string) int {
+ // Malformed strings compare less than well-formed strings.
+ if !goTag.MatchString(x) {
+ return -1
+ }
+ if !goTag.MatchString(y) {
+ return +1
+ }
+
+ // Compare numbers in sequence.
+ xx := strings.Split(x[len("go"):], ".")
+ yy := strings.Split(y[len("go"):], ".")
+
+ for i := 0; i < len(xx) && i < len(yy); i++ {
+ // The Atoi are guaranteed to succeed
+ // because the versions match goTag.
+ xi, _ := strconv.Atoi(xx[i])
+ yi, _ := strconv.Atoi(yy[i])
+ if xi < yi {
+ return -1
+ } else if xi > yi {
+ return +1
+ }
+ }
+
+ if len(xx) < len(yy) {
+ return -1
+ }
+ if len(xx) > len(yy) {
+ return +1
+ }
+ return 0
+}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
new file mode 100644
index 000000000..47ea0c711
--- /dev/null
+++ b/src/cmd/go/help.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.
+
+package main
+
+var helpPackages = &Command{
+ UsageLine: "packages",
+ Short: "description of package lists",
+ Long: `
+Many commands apply to a set of packages:
+
+ go action [packages]
+
+Usually, [packages] is a list of import paths.
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+The special import path "all" expands to all package directories
+found in all the GOPATH trees. For example, 'go list all'
+lists all the packages on the local system.
+
+The special import path "std" is like all but expands to just the
+packages in the standard Go library.
+
+An import path is a pattern if it includes one or more "..." wildcards,
+each of which can match any string, including the empty string and
+strings containing slashes. Such a pattern expands to all package
+directories found in the GOPATH trees with names matching the
+patterns. As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
+
+An import path can also name a package to be downloaded from
+a remote repository. Run 'go help remote' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you. For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'code.google.com/p/project'.
+
+As a special case, if the package list is a list of .go files from a
+single directory, the command is applied to a single synthesized
+package made up of exactly those files, ignoring any build constraints
+in those files and ignoring any other files in the directory.
+ `,
+}
+
+var helpRemote = &Command{
+ UsageLine: "remote",
+ Short: "remote import path syntax",
+ Long: `
+
+An import path (see 'go help importpath') denotes a package
+stored in the local file system. Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+ BitBucket (Mercurial)
+
+ import "bitbucket.org/user/project"
+ import "bitbucket.org/user/project/sub/directory"
+
+ GitHub (Git)
+
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
+
+ Google Code Project Hosting (Git, Mercurial, Subversion)
+
+ import "code.google.com/p/project"
+ import "code.google.com/p/project/sub/directory"
+
+ import "code.google.com/p/project.subrepository"
+ import "code.google.com/p/project.subrepository/sub/directory"
+
+ Launchpad (Bazaar)
+
+ import "launchpad.net/project"
+ import "launchpad.net/project/series"
+ import "launchpad.net/project/series/sub/directory"
+
+ import "launchpad.net/~user/project/branch"
+ import "launchpad.net/~user/project/branch/sub/directory"
+
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
+
+ repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository. The supported version control systems are:
+
+ Bazaar .bzr
+ Git .git
+ Mercurial .hg
+ Subversion .svn
+
+For example,
+
+ import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+example.org/user/foo or foo.hg, and
+
+ import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at
+example.com/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading. For example, a Git
+download tries git://, then https://, then http://.
+
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path correponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help install' for more.
+ `,
+}
+
+var helpGopath = &Command{
+ UsageLine: "gopath",
+ Short: "GOPATH environment variable",
+ Long: `
+The Go path is used to resolve import statements.
+It is implemented by and documented in the go/build package.
+
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code. The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path. That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands. If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
+
+Here's an example directory layout:
+
+ GOPATH=/home/user/gocode
+
+ /home/user/gocode/
+ src/
+ foo/
+ bar/ (go code in package bar)
+ x.go
+ quux/ (go code in package main)
+ y.go
+ bin/
+ quux (installed command)
+ pkg/
+ linux_amd64/
+ foo/
+ bar.a (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+ `,
+}
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
new file mode 100644
index 000000000..6de9a3e1e
--- /dev/null
+++ b/src/cmd/go/http.go
@@ -0,0 +1,87 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+)
+
+// httpGET returns the data from an HTTP GET request for the given URL.
+func httpGET(url string) ([]byte, error) {
+ resp, err := http.Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ return nil, fmt.Errorf("%s: %s", url, resp.Status)
+ }
+ b, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, fmt.Errorf("%s: %v", url, err)
+ }
+ return b, nil
+}
+
+// httpClient is the default HTTP client, but a variable so it can be
+// changed by tests, without modifying http.DefaultClient.
+var httpClient = http.DefaultClient
+
+// httpsOrHTTP returns the body of either the importPath's
+// https resource or, if unavailable, the http resource.
+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
+ fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
+ u, err := url.Parse(scheme + "://" + importPath)
+ if err != nil {
+ return "", nil, err
+ }
+ u.RawQuery = "go-get=1"
+ urlStr = u.String()
+ if buildV {
+ log.Printf("Fetching %s", urlStr)
+ }
+ res, err = httpClient.Get(urlStr)
+ return
+ }
+ closeBody := func(res *http.Response) {
+ if res != nil {
+ res.Body.Close()
+ }
+ }
+ urlStr, res, err := fetch("https")
+ if err != nil || res.StatusCode != 200 {
+ if buildV {
+ if err != nil {
+ log.Printf("https fetch failed.")
+ } else {
+ log.Printf("ignoring https fetch with status code %d", res.StatusCode)
+ }
+ }
+ closeBody(res)
+ urlStr, res, err = fetch("http")
+ }
+ if err != nil {
+ closeBody(res)
+ return "", nil, err
+ }
+ // Note: accepting a non-200 OK here, so people can serve a
+ // meta import in their http 404 page.
+ if buildV {
+ log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
+ }
+ return urlStr, res.Body, nil
+}
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
new file mode 100644
index 000000000..edb59aa79
--- /dev/null
+++ b/src/cmd/go/list.go
@@ -0,0 +1,168 @@
+// 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 (
+ "bufio"
+ "encoding/json"
+ "io"
+ "os"
+ "text/template"
+)
+
+var cmdList = &Command{
+ UsageLine: "list [-e] [-f format] [-json] [packages]",
+ Short: "list packages",
+ Long: `
+List lists the packages named by the import paths, one per line.
+
+The default output shows the package import path:
+
+ code.google.com/p/google-api-go-client/books/v1
+ code.google.com/p/goauth2/oauth
+ code.google.com/p/sqlite
+
+The -f flag specifies an alternate format for the list,
+using the syntax of package template. The default output
+is equivalent to -f '{{.ImportPath}}'. The struct
+being passed to the template is:
+
+ type Package struct {
+ Dir string // directory containing package sources
+ ImportPath string // import path of package in dir
+ Name string // package name
+ Doc string // package documentation string
+ Target string // install path
+ Goroot bool // is this package in the Go root?
+ Standard bool // is this package part of the standard Go library?
+ Stale bool // would 'go install' do anything for this package?
+ Root string // Go root or Go path dir containing this package
+
+ // Source files
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go sources files that import "C"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso object files to add to archive
+
+ // Cgo directives
+ CgoCFLAGS []string // cgo: flags for C compiler
+ CgoLDFLAGS []string // cgo: flags for linker
+ CgoPkgConfig []string // cgo: pkg-config names
+
+ // Dependency information
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+
+ // Error information
+ Incomplete bool // this package or a dependency has an error
+ Error *PackageError // error loading package
+ DepsErrors []*PackageError // errors loading dependencies
+
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
+ }
+
+The -json flag causes the package data to be printed in JSON format
+instead of using the template format.
+
+The -e flag changes the handling of erroneous packages, those that
+cannot be found or are malformed. By default, the list command
+prints an error to standard error for each erroneous package and
+omits the packages from consideration during the usual printing.
+With the -e flag, the list command never prints errors to standard
+error and instead processes the erroneous packages with the usual
+printing. Erroneous packages will have a non-empty ImportPath and
+a non-nil Error field; other information may or may not be missing
+(zeroed).
+
+For more about specifying packages, see 'go help packages'.
+ `,
+}
+
+func init() {
+ cmdList.Run = runList // break init cycle
+ cmdList.Flag.Var(buildCompiler{}, "compiler", "")
+}
+
+var listE = cmdList.Flag.Bool("e", false, "")
+var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
+var listJson = cmdList.Flag.Bool("json", false, "")
+var nl = []byte{'\n'}
+
+func runList(cmd *Command, args []string) {
+ out := newCountingWriter(os.Stdout)
+ defer out.w.Flush()
+
+ var do func(*Package)
+ if *listJson {
+ do = func(p *Package) {
+ b, err := json.MarshalIndent(p, "", "\t")
+ if err != nil {
+ out.Flush()
+ fatalf("%s", err)
+ }
+ out.Write(b)
+ out.Write(nl)
+ }
+ } else {
+ tmpl, err := template.New("main").Parse(*listFmt)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ do = func(p *Package) {
+ out.Reset()
+ if err := tmpl.Execute(out, p); err != nil {
+ out.Flush()
+ fatalf("%s", err)
+ }
+ if out.Count() > 0 {
+ out.w.WriteRune('\n')
+ }
+ }
+ }
+
+ load := packages
+ if *listE {
+ load = packagesAndErrors
+ }
+
+ for _, pkg := range load(args) {
+ do(pkg)
+ }
+}
+
+// CountingWriter counts its data, so we can avoid appending a newline
+// if there was no actual output.
+type CountingWriter struct {
+ w *bufio.Writer
+ count int64
+}
+
+func newCountingWriter(w io.Writer) *CountingWriter {
+ return &CountingWriter{
+ w: bufio.NewWriter(w),
+ }
+}
+
+func (cw *CountingWriter) Write(p []byte) (n int, err error) {
+ cw.count += int64(len(p))
+ return cw.w.Write(p)
+}
+
+func (cw *CountingWriter) Flush() {
+ cw.w.Flush()
+}
+
+func (cw *CountingWriter) Reset() {
+ cw.count = 0
+}
+
+func (cw *CountingWriter) Count() int64 {
+ return cw.count
+}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
new file mode 100644
index 000000000..73c2f54a7
--- /dev/null
+++ b/src/cmd/go/main.go
@@ -0,0 +1,541 @@
+// 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 (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/build"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+ "sync"
+ "text/template"
+ "unicode"
+ "unicode/utf8"
+)
+
+// A Command is an implementation of a go command
+// like go build or go fix.
+type Command struct {
+ // Run runs the command.
+ // The args are the arguments after the command name.
+ Run func(cmd *Command, args []string)
+
+ // UsageLine is the one-line usage message.
+ // The first word in the line is taken to be the command name.
+ UsageLine string
+
+ // Short is the short description shown in the 'go help' output.
+ Short string
+
+ // Long is the long message shown in the 'go help <this-command>' output.
+ Long string
+
+ // Flag is a set of flags specific to this command.
+ Flag flag.FlagSet
+
+ // CustomFlags indicates that the command will do its own
+ // flag parsing.
+ CustomFlags bool
+}
+
+// Name returns the command's name: the first word in the usage line.
+func (c *Command) Name() string {
+ name := c.UsageLine
+ i := strings.Index(name, " ")
+ if i >= 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+func (c *Command) Usage() {
+ fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
+ fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
+ os.Exit(2)
+}
+
+// Runnable reports whether the command can be run; otherwise
+// it is a documentation pseudo-command such as importpath.
+func (c *Command) Runnable() bool {
+ return c.Run != nil
+}
+
+// Commands lists the available commands and help topics.
+// The order here is the order in which they are printed by 'go help'.
+var commands = []*Command{
+ cmdBuild,
+ cmdClean,
+ cmdDoc,
+ cmdEnv,
+ cmdFix,
+ cmdFmt,
+ cmdGet,
+ cmdInstall,
+ cmdList,
+ cmdRun,
+ cmdTest,
+ cmdTool,
+ cmdVersion,
+ cmdVet,
+
+ helpGopath,
+ helpPackages,
+ helpRemote,
+ helpTestflag,
+ helpTestfunc,
+}
+
+var exitStatus = 0
+var exitMu sync.Mutex
+
+func setExitStatus(n int) {
+ exitMu.Lock()
+ if exitStatus < n {
+ exitStatus = n
+ }
+ exitMu.Unlock()
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ log.SetFlags(0)
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+
+ if args[0] == "help" {
+ help(args[1:])
+ return
+ }
+
+ // Diagnose common mistake: GOPATH==GOROOT.
+ // This setting is equivalent to not setting GOPATH at all,
+ // which is not what most people want when they do it.
+ if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
+ }
+
+ for _, cmd := range commands {
+ if cmd.Name() == args[0] && cmd.Run != nil {
+ cmd.Flag.Usage = func() { cmd.Usage() }
+ if cmd.CustomFlags {
+ args = args[1:]
+ } else {
+ cmd.Flag.Parse(args[1:])
+ args = cmd.Flag.Args()
+ }
+ cmd.Run(cmd, args)
+ exit()
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "Unknown command %#q\n\n", args[0])
+ usage()
+}
+
+var usageTemplate = `Go is a tool for managing Go source code.
+
+Usage:
+
+ go command [arguments]
+
+The commands are:
+{{range .}}{{if .Runnable}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+{{range .}}{{if not .Runnable}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "go help [topic]" for more information about that topic.
+
+`
+
+var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+`
+
+var documentationTemplate = `// 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.
+
+/*
+{{range .}}{{if .Short}}{{.Short | capitalize}}
+
+{{end}}{{if .Runnable}}Usage:
+
+ go {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+
+
+{{end}}*/
+package documentation
+
+// NOTE: cmdDoc is in fmt.go.
+`
+
+// tmpl executes the given template text on data, writing the result to w.
+func tmpl(w io.Writer, text string, data interface{}) {
+ t := template.New("top")
+ t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
+ template.Must(t.Parse(text))
+ if err := t.Execute(w, data); err != nil {
+ panic(err)
+ }
+}
+
+func capitalize(s string) string {
+ if s == "" {
+ return s
+ }
+ r, n := utf8.DecodeRuneInString(s)
+ return string(unicode.ToTitle(r)) + s[n:]
+}
+
+func printUsage(w io.Writer) {
+ tmpl(w, usageTemplate, commands)
+}
+
+func usage() {
+ printUsage(os.Stderr)
+ os.Exit(2)
+}
+
+// help implements the 'help' command.
+func help(args []string) {
+ if len(args) == 0 {
+ printUsage(os.Stdout)
+ // not exit 2: succeeded at 'go help'.
+ return
+ }
+ if len(args) != 1 {
+ fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
+ os.Exit(2) // failed at 'go help'
+ }
+
+ arg := args[0]
+
+ // 'go help documentation' generates doc.go.
+ if arg == "documentation" {
+ buf := new(bytes.Buffer)
+ printUsage(buf)
+ usage := &Command{Long: buf.String()}
+ tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
+ return
+ }
+
+ for _, cmd := range commands {
+ if cmd.Name() == arg {
+ tmpl(os.Stdout, helpTemplate, cmd)
+ // not exit 2: succeeded at 'go help cmd'.
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
+ os.Exit(2) // failed at 'go help cmd'
+}
+
+// importPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func importPathsNoDotExpansion(args []string) []string {
+ if len(args) == 0 {
+ return []string{"."}
+ }
+ var out []string
+ for _, a := range args {
+ // Arguments are supposed to be import paths, but
+ // as a courtesy to Windows developers, rewrite \ to /
+ // in command-line arguments. Handles .\... and so on.
+ if filepath.Separator == '\\' {
+ a = strings.Replace(a, `\`, `/`, -1)
+ }
+
+ // Put argument in canonical form, but preserve leading ./.
+ if strings.HasPrefix(a, "./") {
+ a = "./" + path.Clean(a)
+ if a == "./." {
+ a = "."
+ }
+ } else {
+ a = path.Clean(a)
+ }
+ if a == "all" || a == "std" {
+ out = append(out, allPackages(a)...)
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// importPaths returns the import paths to use for the given command line.
+func importPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, allPackagesInFS(a)...)
+ } else {
+ out = append(out, allPackages(a)...)
+ }
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+var atexitFuncs []func()
+
+func atexit(f func()) {
+ atexitFuncs = append(atexitFuncs, f)
+}
+
+func exit() {
+ for _, f := range atexitFuncs {
+ f()
+ }
+ os.Exit(exitStatus)
+}
+
+func fatalf(format string, args ...interface{}) {
+ errorf(format, args...)
+ exit()
+}
+
+func errorf(format string, args ...interface{}) {
+ log.Printf(format, args...)
+ setExitStatus(1)
+}
+
+var logf = log.Printf
+
+func exitIfErrors() {
+ if exitStatus != 0 {
+ exit()
+ }
+}
+
+func run(cmdargs ...interface{}) {
+ cmdline := stringList(cmdargs...)
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ errorf("%v", err)
+ }
+}
+
+func runOut(dir string, cmdargs ...interface{}) []byte {
+ cmdline := stringList(cmdargs...)
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ os.Stderr.Write(out)
+ errorf("%v", err)
+ out = nil
+ }
+ return out
+}
+
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+func matchPattern(pattern string) func(name string) bool {
+ re := regexp.QuoteMeta(pattern)
+ re = strings.Replace(re, `\.\.\.`, `.*`, -1)
+ // Special case: foo/... matches foo too.
+ if strings.HasSuffix(re, `/.*`) {
+ re = re[:len(re)-len(`/.*`)] + `(/.*)?`
+ }
+ reg := regexp.MustCompile(`^` + re + `$`)
+ return func(name string) bool {
+ return reg.MatchString(name)
+ }
+}
+
+// allPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages)
+// or a path including "...".
+func allPackages(pattern string) []string {
+ pkgs := matchPackages(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackages(pattern string) []string {
+ match := func(string) bool { return true }
+ if pattern != "all" && pattern != "std" {
+ match = matchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !buildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+ var pkgs []string
+
+ // Commands
+ cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
+ filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() || path == cmd {
+ return nil
+ }
+ name := path[len(cmd):]
+ // Commands are all in cmd/, not in subdirectories.
+ if strings.Contains(name, string(filepath.Separator)) {
+ return filepath.SkipDir
+ }
+
+ _, err = build.ImportDir(path, 0)
+ if err != nil {
+ return nil
+ }
+
+ // We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
+ name = "cmd/" + name
+ if !have[name] {
+ have[name] = true
+ if match(name) {
+ pkgs = append(pkgs, name)
+ }
+ }
+ return nil
+ })
+
+ for _, src := range buildContext.SrcDirs() {
+ if pattern == "std" && src != gorootSrcPkg {
+ continue
+ }
+ src = filepath.Clean(src) + string(filepath.Separator)
+ filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() || path == src {
+ return nil
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ name := filepath.ToSlash(path[len(src):])
+ if pattern == "std" && strings.Contains(name, ".") {
+ return filepath.SkipDir
+ }
+ if have[name] {
+ return nil
+ }
+ have[name] = true
+
+ _, err = build.ImportDir(path, 0)
+ if err != nil && strings.Contains(err.Error(), "no Go source files") {
+ return nil
+ }
+ if match(name) {
+ pkgs = append(pkgs, name)
+ }
+ return nil
+ })
+ }
+ return pkgs
+}
+
+// allPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+func allPackagesInFS(pattern string) []string {
+ pkgs := matchPackagesInFS(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackagesInFS(pattern string) []string {
+ // Find directory to begin the scan.
+ // Could be smarter but this one optimization
+ // is enough for now, since ... is usually at the
+ // end of a path.
+ i := strings.Index(pattern, "...")
+ dir, _ := path.Split(pattern[:i])
+
+ // pattern begins with ./ or ../.
+ // path.Clean will discard the ./ but not the ../.
+ // We need to preserve the ./ for pattern matching
+ // and in the returned import paths.
+ prefix := ""
+ if strings.HasPrefix(pattern, "./") {
+ prefix = "./"
+ }
+ match := matchPattern(pattern)
+
+ var pkgs []string
+ filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() || path == dir {
+ return nil
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ name := prefix + filepath.ToSlash(path)
+ if !match(name) {
+ return nil
+ }
+ if _, err = build.ImportDir(path, 0); err != nil {
+ return nil
+ }
+ pkgs = append(pkgs, name)
+ return nil
+ })
+ return pkgs
+}
+
+// stringList's arguments should be a sequence of string or []string values.
+// stringList flattens them into a single []string.
+func stringList(args ...interface{}) []string {
+ var x []string
+ for _, arg := range args {
+ switch arg := arg.(type) {
+ case []string:
+ x = append(x, arg...)
+ case string:
+ x = append(x, arg)
+ default:
+ panic("stringList: invalid argument")
+ }
+ }
+ return x
+}
diff --git a/src/cmd/go/match_test.go b/src/cmd/go/match_test.go
new file mode 100644
index 000000000..f058f235a
--- /dev/null
+++ b/src/cmd/go/match_test.go
@@ -0,0 +1,36 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "testing"
+
+var matchTests = []struct {
+ pattern string
+ path string
+ match bool
+}{
+ {"...", "foo", true},
+ {"net", "net", true},
+ {"net", "net/http", false},
+ {"net/http", "net", false},
+ {"net/http", "net/http", true},
+ {"net...", "netchan", true},
+ {"net...", "net", true},
+ {"net...", "net/http", true},
+ {"net...", "not/http", false},
+ {"net/...", "netchan", false},
+ {"net/...", "net", true},
+ {"net/...", "net/http", true},
+ {"net/...", "not/http", false},
+}
+
+func TestMatchPattern(t *testing.T) {
+ for _, tt := range matchTests {
+ match := matchPattern(tt.pattern)(tt.path)
+ if match != tt.match {
+ t.Errorf("matchPattern(%q)(%q) = %v, want %v", tt.pattern, tt.path, match, tt.match)
+ }
+ }
+}
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh
new file mode 100755
index 000000000..7768baeb6
--- /dev/null
+++ b/src/cmd/go/mkdoc.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+go help documentation > doc.go
+gofmt -w doc.go
+
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
new file mode 100644
index 000000000..30bbfad55
--- /dev/null
+++ b/src/cmd/go/pkg.go
@@ -0,0 +1,679 @@
+// 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 (
+ "bytes"
+ "errors"
+ "fmt"
+ "go/build"
+ "go/scanner"
+ "go/token"
+ "os"
+ pathpkg "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
+ "unicode"
+)
+
+// A Package describes a single package found in a directory.
+type Package struct {
+ // Note: These fields are part of the go command's public API.
+ // See list.go. It is okay to add fields, but not to change or
+ // remove existing ones. Keep in sync with list.go
+ Dir string `json:",omitempty"` // directory containing package sources
+ ImportPath string `json:",omitempty"` // import path of package in dir
+ Name string `json:",omitempty"` // package name
+ Doc string `json:",omitempty"` // package documentation string
+ Target string `json:",omitempty"` // install path
+ Goroot bool `json:",omitempty"` // is this package found in the Go root?
+ Standard bool `json:",omitempty"` // is this package part of the standard Go library?
+ Stale bool `json:",omitempty"` // would 'go install' do anything for this package?
+ Root string `json:",omitempty"` // Go root or Go path dir containing this package
+
+ // Source files
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
+ CFiles []string `json:",omitempty"` // .c source files
+ HFiles []string `json:",omitempty"` // .h source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+
+ // Cgo directives
+ CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
+ CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker
+ CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
+
+ // Dependency information
+ Imports []string `json:",omitempty"` // import paths used by this package
+ Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+
+ // Error information
+ Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
+ Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
+ DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
+
+ // Test information
+ TestGoFiles []string `json:",omitempty"` // _test.go files in package
+ TestImports []string `json:",omitempty"` // imports from TestGoFiles
+ XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
+ XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+
+ // Unexported fields are not part of the public API.
+ build *build.Package
+ pkgdir string // overrides build.PkgDir
+ imports []*Package
+ deps []*Package
+ gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ target string // installed file for this package (may be executable)
+ fake bool // synthesized package
+ forceBuild bool // this package must be rebuilt
+ forceLibrary bool // this package is a library (even if named "main")
+ local bool // imported via local path (./ or ../)
+ localPrefix string // interpret ./ and ../ imports relative to this prefix
+}
+
+func (p *Package) copyBuild(pp *build.Package) {
+ p.build = pp
+
+ p.Dir = pp.Dir
+ p.ImportPath = pp.ImportPath
+ p.Name = pp.Name
+ p.Doc = pp.Doc
+ p.Root = pp.Root
+ // TODO? Target
+ p.Goroot = pp.Goroot
+ p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
+ p.GoFiles = pp.GoFiles
+ p.CgoFiles = pp.CgoFiles
+ p.CFiles = pp.CFiles
+ p.HFiles = pp.HFiles
+ p.SFiles = pp.SFiles
+ p.SysoFiles = pp.SysoFiles
+ p.CgoCFLAGS = pp.CgoCFLAGS
+ p.CgoLDFLAGS = pp.CgoLDFLAGS
+ p.CgoPkgConfig = pp.CgoPkgConfig
+ p.Imports = pp.Imports
+ p.TestGoFiles = pp.TestGoFiles
+ p.TestImports = pp.TestImports
+ p.XTestGoFiles = pp.XTestGoFiles
+ p.XTestImports = pp.XTestImports
+}
+
+// A PackageError describes an error loading information about a package.
+type PackageError struct {
+ ImportStack []string // shortest path from package named on command line to this one
+ Pos string // position of error
+ Err string // the error itself
+}
+
+func (p *PackageError) Error() string {
+ if p.Pos != "" {
+ // Omit import stack. The full path to the file where the error
+ // is the most important thing.
+ return p.Pos + ": " + p.Err
+ }
+ return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
+}
+
+// An importStack is a stack of import paths.
+type importStack []string
+
+func (s *importStack) push(p string) {
+ *s = append(*s, p)
+}
+
+func (s *importStack) pop() {
+ *s = (*s)[0 : len(*s)-1]
+}
+
+func (s *importStack) copy() []string {
+ return append([]string{}, *s...)
+}
+
+// shorterThan returns true if sp is shorter than t.
+// We use this to record the shortest import sequence
+// that leads to a particular package.
+func (sp *importStack) shorterThan(t []string) bool {
+ s := *sp
+ if len(s) != len(t) {
+ return len(s) < len(t)
+ }
+ // If they are the same length, settle ties using string ordering.
+ for i := range s {
+ if s[i] != t[i] {
+ return s[i] < t[i]
+ }
+ }
+ return false // they are equal
+}
+
+// packageCache is a lookup cache for loadPackage,
+// so that if we look up a package multiple times
+// we return the same pointer each time.
+var packageCache = map[string]*Package{}
+
+// reloadPackage is like loadPackage but makes sure
+// not to use the package cache.
+func reloadPackage(arg string, stk *importStack) *Package {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ return loadPackage(arg, stk)
+}
+
+// dirToImportPath returns the pseudo-import path we use for a package
+// outside the Go path. It begins with _/ and then contains the full path
+// to the directory. If the package lives in c:\home\gopher\my\pkg then
+// the pseudo-import path is _/c_/home/gopher/my/pkg.
+// Using a pseudo-import path like this makes the ./ imports no longer
+// a special case, so that all the code to deal with ordinary imports works
+// automatically.
+func dirToImportPath(dir string) string {
+ return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
+}
+
+func makeImportValid(r rune) rune {
+ // Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return '_'
+ }
+ return r
+}
+
+// loadImport scans the directory named by path, which must be an import path,
+// but possibly a local import path (an absolute file system path or one beginning
+// with ./ or ../). A local relative path is interpreted relative to srcDir.
+// It returns a *Package describing the package found in that directory.
+func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
+ stk.push(path)
+ defer stk.pop()
+
+ // Determine canonical identifier for this package.
+ // For a local import the identifier is the pseudo-import path
+ // we create from the full directory to the package.
+ // Otherwise it is the usual import path.
+ importPath := path
+ isLocal := build.IsLocalImport(path)
+ if isLocal {
+ importPath = dirToImportPath(filepath.Join(srcDir, path))
+ }
+ if p := packageCache[importPath]; p != nil {
+ return reusePackage(p, stk)
+ }
+
+ p := new(Package)
+ p.local = isLocal
+ p.ImportPath = importPath
+ packageCache[importPath] = p
+
+ // Load package.
+ // Import always returns bp != nil, even if an error occurs,
+ // in order to return partial information.
+ //
+ // TODO: After Go 1, decide when to pass build.AllowBinary here.
+ // See issue 3268 for mistakes to avoid.
+ bp, err := buildContext.Import(path, srcDir, 0)
+ bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ p.load(stk, bp, err)
+ if p.Error != nil && len(importPos) > 0 {
+ pos := importPos[0]
+ pos.Filename = shortPath(pos.Filename)
+ p.Error.Pos = pos.String()
+ }
+
+ return p
+}
+
+// reusePackage reuses package p to satisfy the import at the top
+// of the import stack stk. If this use causes an import loop,
+// reusePackage updates p's error information to record the loop.
+func reusePackage(p *Package, stk *importStack) *Package {
+ // We use p.imports==nil to detect a package that
+ // is in the midst of its own loadPackage call
+ // (all the recursion below happens before p.imports gets set).
+ if p.imports == nil {
+ if p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: "import loop",
+ }
+ }
+ p.Incomplete = true
+ }
+ if p.Error != nil && stk.shorterThan(p.Error.ImportStack) {
+ p.Error.ImportStack = stk.copy()
+ }
+ return p
+}
+
+// isGoTool is the list of directories for Go programs that are installed in
+// $GOROOT/pkg/tool.
+var isGoTool = map[string]bool{
+ "cmd/api": true,
+ "cmd/cgo": true,
+ "cmd/fix": true,
+ "cmd/vet": true,
+ "cmd/yacc": true,
+ "exp/gotype": true,
+ "exp/ebnflint": true,
+}
+
+// expandScanner expands a scanner.List error into all the errors in the list.
+// The default Error method only shows the first error.
+func expandScanner(err error) error {
+ // Look for parser errors.
+ if err, ok := err.(scanner.ErrorList); ok {
+ // Prepare error with \n before each message.
+ // When printed in something like context: %v
+ // this will put the leading file positions each on
+ // its own line. It will also show all the errors
+ // instead of just the first, as err.Error does.
+ var buf bytes.Buffer
+ for _, e := range err {
+ e.Pos.Filename = shortPath(e.Pos.Filename)
+ buf.WriteString("\n")
+ buf.WriteString(e.Error())
+ }
+ return errors.New(buf.String())
+ }
+ return err
+}
+
+// load populates p using information from bp, err, which should
+// be the result of calling build.Context.Import.
+func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package {
+ p.copyBuild(bp)
+
+ // The localPrefix is the path we interpret ./ imports relative to.
+ // Synthesized main packages sometimes override this.
+ p.localPrefix = dirToImportPath(p.Dir)
+
+ if err != nil {
+ p.Incomplete = true
+ err = expandScanner(err)
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: err.Error(),
+ }
+ return p
+ }
+
+ if p.Name == "main" {
+ _, elem := filepath.Split(p.Dir)
+ full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem
+ if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH {
+ // Install cross-compiled binaries to subdirectories of bin.
+ elem = full
+ }
+ p.target = filepath.Join(p.build.BinDir, elem)
+ if p.Goroot && isGoTool[p.ImportPath] {
+ p.target = filepath.Join(gorootPkg, "tool", full)
+ }
+ if buildContext.GOOS == "windows" {
+ p.target += ".exe"
+ }
+ } else if p.local {
+ // Local import turned into absolute path.
+ // No permanent install target.
+ p.target = ""
+ } else {
+ p.target = p.build.PkgObj
+ }
+
+ importPaths := p.Imports
+ // Packages that use cgo import runtime/cgo implicitly,
+ // except runtime/cgo itself.
+ if len(p.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") {
+ importPaths = append(importPaths, "runtime/cgo")
+ }
+ // Everything depends on runtime, except runtime and unsafe.
+ if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
+ importPaths = append(importPaths, "runtime")
+ }
+
+ // Build list of full paths to all Go files in the package,
+ // for use by commands like go fmt.
+ p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles)
+ for i := range p.gofiles {
+ p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i])
+ }
+ sort.Strings(p.gofiles)
+
+ // Build list of imported packages and full dependency list.
+ imports := make([]*Package, 0, len(p.Imports))
+ deps := make(map[string]bool)
+ for i, path := range importPaths {
+ if path == "C" {
+ continue
+ }
+ p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
+ if p1.local {
+ if !p.local && p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("local import %q in non-local package", path),
+ }
+ pos := p.build.ImportPos[path]
+ if len(pos) > 0 {
+ p.Error.Pos = pos[0].String()
+ }
+ }
+ path = p1.ImportPath
+ importPaths[i] = path
+ }
+ deps[path] = true
+ imports = append(imports, p1)
+ for _, dep := range p1.Deps {
+ deps[dep] = true
+ }
+ if p1.Incomplete {
+ p.Incomplete = true
+ }
+ }
+ p.imports = imports
+
+ p.Deps = make([]string, 0, len(deps))
+ for dep := range deps {
+ p.Deps = append(p.Deps, dep)
+ }
+ sort.Strings(p.Deps)
+ for _, dep := range p.Deps {
+ p1 := packageCache[dep]
+ if p1 == nil {
+ panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
+ }
+ p.deps = append(p.deps, p1)
+ if p1.Error != nil {
+ p.DepsErrors = append(p.DepsErrors, p1.Error)
+ }
+ }
+
+ // unsafe is a fake package.
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
+ p.target = ""
+ }
+
+ p.Target = p.target
+ return p
+}
+
+// packageList returns the list of packages in the dag rooted at roots
+// as visited in a depth-first post-order traversal.
+func packageList(roots []*Package) []*Package {
+ seen := map[*Package]bool{}
+ all := []*Package{}
+ var walk func(*Package)
+ walk = func(p *Package) {
+ if seen[p] {
+ return
+ }
+ seen[p] = true
+ for _, p1 := range p.imports {
+ walk(p1)
+ }
+ all = append(all, p)
+ }
+ for _, root := range roots {
+ walk(root)
+ }
+ return all
+}
+
+// computeStale computes the Stale flag in the package dag that starts
+// at the named pkgs (command-line arguments).
+func computeStale(pkgs ...*Package) {
+ topRoot := map[string]bool{}
+ for _, p := range pkgs {
+ topRoot[p.Root] = true
+ }
+
+ for _, p := range packageList(pkgs) {
+ p.Stale = isStale(p, topRoot)
+ }
+}
+
+// isStale reports whether package p needs to be rebuilt.
+func isStale(p *Package, topRoot map[string]bool) bool {
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
+ // fake, builtin package
+ return false
+ }
+ if p.Error != nil {
+ return true
+ }
+
+ // A package without Go sources means we only found
+ // the installed .a file. Since we don't know how to rebuild
+ // it, it can't be stale, even if -a is set. This enables binary-only
+ // distributions of Go packages, although such binaries are
+ // only useful with the specific version of the toolchain that
+ // created them.
+ if len(p.gofiles) == 0 {
+ return false
+ }
+
+ if buildA || p.target == "" || p.Stale {
+ return true
+ }
+
+ // Package is stale if completely unbuilt.
+ var built time.Time
+ if fi, err := os.Stat(p.target); err == nil {
+ built = fi.ModTime()
+ }
+ if built.IsZero() {
+ return true
+ }
+
+ olderThan := func(file string) bool {
+ fi, err := os.Stat(file)
+ return err != nil || fi.ModTime().After(built)
+ }
+
+ // Package is stale if a dependency is, or if a dependency is newer.
+ for _, p1 := range p.deps {
+ if p1.Stale || p1.target != "" && olderThan(p1.target) {
+ return true
+ }
+ }
+
+ // As a courtesy to developers installing new versions of the compiler
+ // frequently, define that packages are stale if they are
+ // older than the compiler, and commands if they are older than
+ // the linker. This heuristic will not work if the binaries are back-dated,
+ // as some binary distributions may do, but it does handle a very
+ // common case. See issue 3036.
+ if olderThan(buildToolchain.compiler()) {
+ return true
+ }
+ if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
+ return true
+ }
+
+ // Have installed copy, probably built using current compilers,
+ // and built after its imported packages. The only reason now
+ // that we'd have to rebuild it is if the sources were newer than
+ // the package. If a package p is not in the same tree as any
+ // package named on the command-line, assume it is up-to-date
+ // no matter what the modification times on the source files indicate.
+ // This avoids rebuilding $GOROOT packages when people are
+ // working outside the Go root, and it effectively makes each tree
+ // listed in $GOPATH a separate compilation world.
+ // See issue 3149.
+ if p.Root != "" && !topRoot[p.Root] {
+ return false
+ }
+
+ srcs := stringList(p.GoFiles, p.CFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles)
+ for _, src := range srcs {
+ if olderThan(filepath.Join(p.Dir, src)) {
+ return true
+ }
+ }
+
+ return false
+}
+
+var cwd, _ = os.Getwd()
+
+var cmdCache = map[string]*Package{}
+
+// loadPackage is like loadImport but is used for command-line arguments,
+// not for paths found in import statements. In addition to ordinary import paths,
+// loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
+// in the Go command directory, as well as paths to those directories.
+func loadPackage(arg string, stk *importStack) *Package {
+ if build.IsLocalImport(arg) {
+ dir := arg
+ if !filepath.IsAbs(dir) {
+ if abs, err := filepath.Abs(dir); err == nil {
+ // interpret relative to current directory
+ dir = abs
+ }
+ }
+ if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") {
+ arg = sub
+ }
+ }
+ if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
+ if p := cmdCache[arg]; p != nil {
+ return p
+ }
+ stk.push(arg)
+ defer stk.pop()
+ bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
+ bp.ImportPath = arg
+ bp.Goroot = true
+ bp.BinDir = gorootBin
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
+ bp.Root = goroot
+ bp.SrcRoot = gorootSrc
+ p := new(Package)
+ cmdCache[arg] = p
+ p.load(stk, bp, err)
+ if p.Error == nil && p.Name != "main" {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir),
+ }
+ }
+ return p
+ }
+
+ // Wasn't a command; must be a package.
+ // If it is a local import path but names a standard package,
+ // we treat it as if the user specified the standard package.
+ // This lets you run go test ./ioutil in package io and be
+ // referring to io/ioutil rather than a hypothetical import of
+ // "./ioutil".
+ if build.IsLocalImport(arg) {
+ bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+ if bp.ImportPath != "" && bp.ImportPath != "." {
+ arg = bp.ImportPath
+ }
+ }
+
+ return loadImport(arg, cwd, stk, nil)
+}
+
+// packages returns the packages named by the
+// command line arguments 'args'. If a named package
+// cannot be loaded at all (for example, if the directory does not exist),
+// then packages prints an error and does not include that
+// package in the results. However, if errors occur trying
+// to load dependencies of a named package, the named
+// package is still returned, with p.Incomplete = true
+// and details in p.DepsErrors.
+func packages(args []string) []*Package {
+ var pkgs []*Package
+ for _, pkg := range packagesAndErrors(args) {
+ if pkg.Error != nil {
+ errorf("can't load package: %s", pkg.Error)
+ continue
+ }
+ pkgs = append(pkgs, pkg)
+ }
+ return pkgs
+}
+
+// packagesAndErrors is like 'packages' but returns a
+// *Package for every argument, even the ones that
+// cannot be loaded at all.
+// The packages that fail to load will have p.Error != nil.
+func packagesAndErrors(args []string) []*Package {
+ if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
+ return []*Package{goFilesPackage(args)}
+ }
+
+ args = importPaths(args)
+ var pkgs []*Package
+ var stk importStack
+ for _, arg := range args {
+ pkgs = append(pkgs, loadPackage(arg, &stk))
+ }
+
+ computeStale(pkgs...)
+
+ return pkgs
+}
+
+// packagesForBuild is like 'packages' but fails if any of
+// the packages or their dependencies have errors
+// (cannot be built).
+func packagesForBuild(args []string) []*Package {
+ pkgs := packagesAndErrors(args)
+ printed := map[*PackageError]bool{}
+ for _, pkg := range pkgs {
+ if pkg.Error != nil {
+ errorf("can't load package: %s", pkg.Error)
+ }
+ for _, err := range pkg.DepsErrors {
+ // Since these are errors in dependencies,
+ // the same error might show up multiple times,
+ // once in each package that depends on it.
+ // Only print each once.
+ if !printed[err] {
+ printed[err] = true
+ errorf("%s", err)
+ }
+ }
+ }
+ exitIfErrors()
+ return pkgs
+}
+
+// hasSubdir reports whether dir is a subdirectory of
+// (possibly multiple levels below) root.
+// If so, it sets rel to the path fragment that must be
+// appended to root to reach dir.
+func hasSubdir(root, dir string) (rel string, ok bool) {
+ if p, err := filepath.EvalSymlinks(root); err == nil {
+ root = p
+ }
+ if p, err := filepath.EvalSymlinks(dir); err == nil {
+ dir = p
+ }
+ const sep = string(filepath.Separator)
+ root = filepath.Clean(root)
+ if !strings.HasSuffix(root, sep) {
+ root += sep
+ }
+ dir = filepath.Clean(dir)
+ if !strings.HasPrefix(dir, root) {
+ return "", false
+ }
+ return filepath.ToSlash(dir[len(root):]), true
+}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
new file mode 100644
index 000000000..94cd59296
--- /dev/null
+++ b/src/cmd/go/run.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 main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+var cmdRun = &Command{
+ UsageLine: "run [build flags] gofiles... [arguments...]",
+ Short: "compile and run Go program",
+ Long: `
+Run compiles and runs the main package comprising the named Go source files.
+
+For more about build flags, see 'go help build'.
+
+See also: go build.
+ `,
+}
+
+func init() {
+ cmdRun.Run = runRun // break init loop
+
+ addBuildFlags(cmdRun)
+}
+
+func printStderr(args ...interface{}) (int, error) {
+ return fmt.Fprint(os.Stderr, args...)
+}
+
+func runRun(cmd *Command, args []string) {
+ var b builder
+ b.init()
+ b.print = printStderr
+ i := 0
+ for i < len(args) && strings.HasSuffix(args[i], ".go") {
+ i++
+ }
+ files, cmdArgs := args[:i], args[i:]
+ if len(files) == 0 {
+ fatalf("go run: no go files listed")
+ }
+ p := goFilesPackage(files)
+ if p.Error != nil {
+ fatalf("%s", p.Error)
+ }
+ if p.Name != "main" {
+ fatalf("go run: cannot run non-main package")
+ }
+ p.target = "" // must build - not up to date
+ a1 := b.action(modeBuild, modeBuild, p)
+ a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
+ b.do(a)
+}
+
+// runProgram is the action for running a binary that has already
+// been compiled. We ignore exit status.
+func (b *builder) runProgram(a *action) error {
+ if buildN || buildX {
+ b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+ if buildN {
+ return nil
+ }
+ }
+
+ runStdin(a.deps[0].target, a.args)
+ return nil
+}
+
+// runStdin is like run, but connects Stdin.
+func runStdin(cmdargs ...interface{}) {
+ cmdline := stringList(cmdargs...)
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ errorf("%v", err)
+ }
+}
diff --git a/src/cmd/go/script b/src/cmd/go/script
new file mode 100755
index 000000000..340a7e824
--- /dev/null
+++ b/src/cmd/go/script
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+x() {
+ echo '--- ' "$@"
+ "$@"
+ echo '---'
+ echo
+}
+
+x go help
+x go help build
+x go help clean
+x go help install
+x go help fix
+x go help fmt
+x go help get
+x go help list
+x go help test
+x go help version
+x go help vet
+x go help gopath
+x go help importpath
+x go help remote
diff --git a/src/cmd/go/script.txt b/src/cmd/go/script.txt
new file mode 100644
index 000000000..a67214658
--- /dev/null
+++ b/src/cmd/go/script.txt
@@ -0,0 +1,352 @@
+--- go help
+usage: go command [arguments]
+
+go manages Go source code.
+
+The commands are:
+
+ build compile and install packages and dependencies
+ clean remove intermediate objects
+ fix run gofix on packages
+ fmt run gofmt -w on packages
+ get download and install packages and dependencies
+ install install packages and dependencies
+ list list packages
+ test test packages
+ version print Go version
+ vet run govet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+ gopath GOPATH environment variable
+ importpath description of import paths
+ remote remote import path syntax
+
+Use "go help [topic]" for more information about that topic.
+
+---
+
+--- go help build
+usage: go build [-n] [-v] [importpath...]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go install, go get, go clean.
+---
+
+--- go help clean
+usage: go clean [-nuke] [importpath...]
+
+Clean removes intermediate object files generated during
+the compilation of the packages named by the import paths,
+but by default it does not remove the installed package binaries.
+
+The -nuke flag causes clean to remove the installed package binaries too.
+
+TODO: Clean does not clean dependencies of the packages.
+
+For more about import paths, see 'go help importpath'.
+---
+
+--- go help install
+usage: go install [-n] [-v] [importpath...]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go get, go clean.
+---
+
+--- go help fix
+usage: go fix [importpath...]
+
+Fix runs the gofix command on the packages named by the import paths.
+
+For more about gofix, see 'godoc gofix'.
+For more about import paths, see 'go help importpath'.
+
+To run gofix with specific options, run gofix itself.
+
+See also: go fmt, go vet.
+---
+
+--- go help fmt
+usage: go fmt [importpath...]
+
+Fmt runs the command 'gofmt -w' on the packages named by the import paths.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about import paths, see 'go help importpath'.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+---
+
+--- go help get
+usage: go get [importpath...]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+After downloading the code, 'go get' looks for a tag beginning
+with "go." that corresponds to the local Go version.
+For Go "release.r58" it looks for a tag named "go.r58".
+For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
+If the specific "go.X" tag is not found, it uses the latest earlier
+version it can find. Otherwise, it uses the default version for
+the version control system: HEAD for git, tip for Mercurial,
+and so on.
+
+TODO: Explain versions better.
+
+For more about import paths, see 'go help importpath'.
+
+For more about how 'go get' finds source code to
+download, see 'go help remote'.
+
+See also: go build, go install, go clean.
+---
+
+--- go help list
+usage: go list [-f format] [-json] [importpath...]
+
+List lists the packages named by the import paths.
+
+The default output shows the package name and file system location:
+
+ books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
+ oauth /home/you/src/goauth2.googlecode.com/hg/oauth
+ sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
+
+The -f flag specifies an alternate format for the list,
+using the syntax of package template. The default output
+is equivalent to -f '{{.Name}} {{.Dir}}' The struct
+being passed to the template is:
+
+ type Package struct {
+ Name string // package name
+ Doc string // package documentation string
+ GoFiles []string // names of Go source files in package
+ ImportPath string // import path denoting package
+ Imports []string // import paths used by this package
+ Deps []string // all (recursively) imported dependencies
+ Dir string // directory containing package sources
+ Version string // version of installed package
+ }
+
+The -json flag causes the package data to be printed in JSON format.
+
+For more about import paths, see 'go help importpath'.
+---
+
+--- go help test
+usage: go test [importpath...]
+
+Test runs gotest to test the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+ test archive/tar
+ FAIL archive/zip
+ test compress/gzip
+ ...
+
+followed by gotest output for each failed package.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go compile, go vet.
+---
+
+--- go help version
+usage: go version
+
+Version prints the Go version, as reported by runtime.Version.
+---
+
+--- go help vet
+usage: go vet [importpath...]
+
+Vet runs the govet command on the packages named by the import paths.
+
+For more about govet, see 'godoc govet'.
+For more about import paths, see 'go help importpath'.
+
+To run govet with specific options, run govet itself.
+
+See also: go fmt, go fix.
+---
+
+--- go help gopath
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code. The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path. That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands.
+
+Here's an example directory layout:
+
+ GOPATH=/home/user/gocode
+
+ /home/user/gocode/
+ src/
+ foo/
+ bar/ (go code in package bar)
+ x.go
+ quux/ (go code in package main)
+ y.go
+ bin/
+ quux (installed command)
+ pkg/
+ linux_amd64/
+ foo/
+ bar.a (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+---
+
+--- go help importpath
+Many commands apply to a set of packages named by import paths:
+
+ go action [importpath...]
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+The special import path "all" expands to all package directories
+found in all the GOPATH trees. For example, 'go list all'
+lists all the packages on the local system.
+
+An import path can also name a package to be downloaded from
+a remote repository. Run 'go help remote' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you. For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'project.googlecode.com/'.
+---
+
+--- go help remote
+An import path (see 'go help importpath') denotes a package
+stored in the local file system. Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+ BitBucket (Mercurial)
+
+ import "bitbucket.org/user/project"
+ import "bitbucket.org/user/project/sub/directory"
+
+ GitHub (Git)
+
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
+
+ Google Code Project Hosting (Git, Mercurial, Subversion)
+
+ import "project.googlecode.com/git"
+ import "project.googlecode.com/git/sub/directory"
+
+ import "project.googlecode.com/hg"
+ import "project.googlecode.com/hg/sub/directory"
+
+ import "project.googlecode.com/svn/trunk"
+ import "project.googlecode.com/svn/trunk/sub/directory"
+
+ Launchpad (Bazaar)
+
+ import "launchpad.net/project"
+ import "launchpad.net/project/series"
+ import "launchpad.net/project/series/sub/directory"
+
+ import "launchpad.net/~user/project/branch"
+ import "launchpad.net/~user/project/branch/sub/directory"
+
+For code hosted on other servers, an import path of the form
+
+ repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository. The supported version control systems are:
+
+ Bazaar .bzr
+ Git .git
+ Mercurial .hg
+ Subversion .svn
+
+For example,
+
+ import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+example.org/user/foo or foo.hg, and
+
+ import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at
+example.com/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading. For example, a Git
+download tries git://, then https://, then http://.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help install' for more.
+---
+
diff --git a/src/cmd/goinstall/tag_test.go b/src/cmd/go/tag_test.go
index a23a7ea82..556a84a8e 100644
--- a/src/cmd/goinstall/tag_test.go
+++ b/src/cmd/go/tag_test.go
@@ -18,6 +18,12 @@ var selectTagTestTags = []string{
"go.weekly.2011-10-12.1",
"go.weekly.2011-10-14",
"go.weekly.2011-11-01",
+ "go1",
+ "go1.0.1",
+ "go1.999",
+ "go1.9.2",
+ "go5",
+
// these should be ignored:
"release.r59",
"release.r59.1",
@@ -30,6 +36,14 @@ var selectTagTestTags = []string{
"go.f00",
"go!r60",
"go.1999-01-01",
+ "go.2x",
+ "go.20000000000000",
+ "go.2.",
+ "go.2.0",
+ "go2x",
+ "go20000000000000",
+ "go2.",
+ "go2.0",
}
var selectTagTests = []struct {
@@ -56,11 +70,21 @@ var selectTagTests = []struct {
{"weekly.2011-11-01", "go.weekly.2011-11-01"},
{"weekly.2014-01-01", "go.weekly.2011-11-01"},
{"weekly.3000-01-01", "go.weekly.2011-11-01"},
+ {"go1", "go1"},
+ {"go1.1", "go1.0.1"},
+ {"go1.998", "go1.9.2"},
+ {"go1.1000", "go1.999"},
+ {"go6", "go5"},
+
// faulty versions:
{"release.f00", ""},
{"weekly.1999-01-01", ""},
{"junk", ""},
{"", ""},
+ {"go2x", ""},
+ {"go200000000000", ""},
+ {"go2.", ""},
+ {"go2.0", ""},
}
func TestSelectTag(t *testing.T) {
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
new file mode 100755
index 000000000..fe186d4bb
--- /dev/null
+++ b/src/cmd/go/test.bash
@@ -0,0 +1,127 @@
+#!/bin/bash
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+set -e
+go build -o testgo
+
+ok=true
+
+unset GOPATH
+unset GOBIN
+
+# Test that error messages have file:line information
+# at beginning of line.
+for i in testdata/errmsg/*.go
+do
+ # TODO: |cat should not be necessary here but is.
+ ./testgo test $i 2>&1 | cat >err.out || true
+ if ! grep -q "^$i:" err.out; then
+ echo "$i: missing file:line in error message"
+ cat err.out
+ ok=false
+ fi
+done
+
+# Test local (./) imports.
+testlocal() {
+ local="$1"
+ ./testgo build -o hello "testdata/$local/easy.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easy.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ ./testgo build -o hello "testdata/$local/easysub/main.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easysub/main.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ ./testgo build -o hello "testdata/$local/hard.go"
+ ./hello >hello.out
+ if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
+ echo "testdata/$local/hard.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ rm -f err.out hello.out hello
+
+ # Test that go install x.go fails.
+ if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
+ echo "go install testdata/$local/easy.go succeeded"
+ ok=false
+ fi
+}
+
+# Test local imports
+testlocal local
+
+# Test local imports again, with bad characters in the directory name.
+bad='#$%:, &()*;<=>?\^{}'
+rm -rf "testdata/$bad"
+cp -R testdata/local "testdata/$bad"
+testlocal "$bad"
+rm -rf "testdata/$bad"
+
+# Test tests with relative imports.
+if ! ./testgo test ./testdata/testimport; then
+ echo "go test ./testdata/testimport failed"
+ ok=false
+fi
+
+# Test tests with relative imports in packages synthesized
+# from Go files named on the command line.
+if ! ./testgo test ./testdata/testimport/*.go; then
+ echo "go test ./testdata/testimport/*.go failed"
+ ok=false
+fi
+
+# Test that without $GOBIN set, binaries get installed
+# into the GOPATH bin directory.
+rm -rf testdata/bin
+if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
+ ok=false
+fi
+
+# And with $GOBIN set, binaries get installed to $GOBIN.
+if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+ echo "go install go-cmd-test failed"
+ ok=false
+elif ! test -x testdata/bin1/go-cmd-test; then
+ echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
+ ok=false
+fi
+
+# Without $GOBIN set, installing a program outside $GOPATH should fail
+# (there is nowhere to install it).
+if ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
+ ok=false
+fi
+
+# With $GOBIN set, should install there.
+if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go failed"
+ ok=false
+elif ! test -x testdata/bin1/helloworld; then
+ echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
+ ok=false
+fi
+
+if $ok; then
+ echo PASS
+else
+ echo FAIL
+ exit 1
+fi
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
new file mode 100644
index 000000000..870ab190f
--- /dev/null
+++ b/src/cmd/go/test.go
@@ -0,0 +1,815 @@
+// 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 (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "text/template"
+ "time"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Break init loop.
+func init() {
+ cmdTest.Run = runTest
+}
+
+var cmdTest = &Command{
+ CustomFlags: true,
+ UsageLine: "test [-c] [-i] [build flags] [packages] [flags for test binary]",
+ Short: "test packages",
+ Long: `
+'Go test' automates testing the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+ ok archive/tar 0.011s
+ FAIL archive/zip 0.022s
+ ok compress/gzip 0.033s
+ ...
+
+followed by detailed output for each failed package.
+
+'Go test' recompiles each package along with any files with names matching
+the file pattern "*_test.go". These additional files can contain test functions,
+benchmark functions, and example functions. See 'go help testfunc' for more.
+
+By default, go test needs no arguments. It compiles and tests the package
+with source in the current directory, including tests, and runs the tests.
+
+The package is built in a temporary directory so it does not interfere with the
+non-test installation.
+
+In addition to the build flags, the flags handled by 'go test' itself are:
+
+ -c Compile the test binary to pkg.test but do not run it.
+
+ -i
+ Install packages that are dependencies of the test.
+ Do not run the test.
+
+The test binary also accepts flags that control execution of the test; these
+flags are also accessible by 'go test'. See 'go help testflag' for details.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+`,
+}
+
+var helpTestflag = &Command{
+ UsageLine: "testflag",
+ Short: "description of testing flags",
+ Long: `
+The 'go test' command takes both flags that apply to 'go test' itself
+and flags that apply to the resulting test binary.
+
+The test binary, called pkg.test, where pkg is the name of the
+directory containing the package sources, has its own flags:
+
+ -test.v
+ Verbose output: log all tests as they are run.
+
+ -test.run pattern
+ Run only those tests and examples matching the regular
+ expression.
+
+ -test.bench pattern
+ Run benchmarks matching the regular expression.
+ By default, no benchmarks run.
+
+ -test.cpuprofile cpu.out
+ Write a CPU profile to the specified file before exiting.
+
+ -test.memprofile mem.out
+ Write a memory profile to the specified file when all tests
+ are complete.
+
+ -test.memprofilerate n
+ Enable more precise (and expensive) memory profiles by setting
+ runtime.MemProfileRate. See 'godoc runtime MemProfileRate'.
+ To profile all memory allocations, use -test.memprofilerate=1
+ and set the environment variable GOGC=off to disable the
+ garbage collector, provided the test can run in the available
+ memory without garbage collection.
+
+ -test.parallel n
+ Allow parallel execution of test functions that call t.Parallel.
+ The value of this flag is the maximum number of tests to run
+ simultaneously; by default, it is set to the value of GOMAXPROCS.
+
+ -test.short
+ Tell long-running tests to shorten their run time.
+ It is off by default but set during all.bash so that installing
+ the Go tree can run a sanity check but not spend time running
+ exhaustive tests.
+
+ -test.timeout t
+ If a test runs longer than t, panic.
+
+ -test.benchtime n
+ Run enough iterations of each benchmark to take n seconds.
+ The default is 1 second.
+
+ -test.cpu 1,2,4
+ Specify a list of GOMAXPROCS values for which the tests or
+ benchmarks should be executed. The default is the current value
+ of GOMAXPROCS.
+
+For convenience, each of these -test.X flags of the test binary is
+also available as the flag -X in 'go test' itself. Flags not listed
+here are passed through unaltered. For instance, the command
+
+ go test -x -v -cpuprofile=prof.out -dir=testdata -update
+
+will compile the test binary and then run it as
+
+ pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+`,
+}
+
+var helpTestfunc = &Command{
+ UsageLine: "testfunc",
+ Short: "description of testing functions",
+ Long: `
+The 'go test' command expects to find test, benchmark, and example functions
+in the "*_test.go" files corresponding to the package under test.
+
+A test function is one named TestXXX (where XXX is any alphanumeric string
+not starting with a lower case letter) and should have the signature,
+
+ func TestXXX(t *testing.T) { ... }
+
+A benchmark function is one named BenchmarkXXX and should have the signature,
+
+ func BenchmarkXXX(b *testing.B) { ... }
+
+An example function is similar to a test function but, instead of using *testing.T
+to report success or failure, prints output to os.Stdout and os.Stderr.
+That output is compared against the function's "Output:" comment, which
+must be the last comment in the function body (see example below). An
+example with no such comment, or with no text after "Output:" is compiled
+but not executed.
+
+Godoc displays the body of ExampleXXX to demonstrate the use
+of the function, constant, or variable XXX. An example of a method M with
+receiver type T or *T is named ExampleT_M. There may be multiple examples
+for a given function, constant, or variable, distinguished by a trailing _xxx,
+where xxx is a suffix not beginning with an upper case letter.
+
+Here is an example of an example:
+
+ func ExamplePrintln() {
+ Println("The output of\nthis example.")
+ // Output: The output of
+ // this example.
+ }
+
+The entire test file is presented as the example when it contains a single
+example function, at least one other function, type, variable, or constant
+declaration, and no test or benchmark functions.
+
+See the documentation of the testing package for more information.
+`,
+}
+
+var (
+ testC bool // -c flag
+ testI bool // -i flag
+ testV bool // -v flag
+ testFiles []string // -file flag(s) TODO: not respected
+ testTimeout string // -timeout flag
+ testArgs []string
+ testBench bool
+ testStreamOutput bool // show output as it is generated
+ testShowPass bool // show passing output
+
+ testKillTimeout = 10 * time.Minute
+)
+
+func runTest(cmd *Command, args []string) {
+ var pkgArgs []string
+ pkgArgs, testArgs = testFlags(args)
+
+ pkgs := packagesForBuild(pkgArgs)
+ if len(pkgs) == 0 {
+ fatalf("no packages to test")
+ }
+
+ if testC && len(pkgs) != 1 {
+ fatalf("cannot use -c flag with multiple packages")
+ }
+
+ // If a test timeout was given and is parseable, set our kill timeout
+ // to that timeout plus one minute. This is a backup alarm in case
+ // the test wedges with a goroutine spinning and its background
+ // timer does not get a chance to fire.
+ if dt, err := time.ParseDuration(testTimeout); err == nil {
+ testKillTimeout = dt + 1*time.Minute
+ }
+
+ // show passing test output (after buffering) with -v flag.
+ // must buffer because tests are running in parallel, and
+ // otherwise the output will get mixed.
+ testShowPass = testV
+
+ // stream test output (no buffering) when no package has
+ // been given on the command line (implicit current directory)
+ // or when benchmarking.
+ // Also stream if we're showing output anyway with a
+ // single package under test. In that case, streaming the
+ // output produces the same result as not streaming,
+ // just more immediately.
+ testStreamOutput = len(pkgArgs) == 0 || testBench ||
+ (len(pkgs) <= 1 && testShowPass)
+
+ var b builder
+ b.init()
+
+ if testI {
+ buildV = testV
+
+ deps := map[string]bool{
+ // Dependencies for testmain.
+ "testing": true,
+ "regexp": true,
+ }
+ for _, p := range pkgs {
+ // Dependencies for each test.
+ for _, path := range p.Imports {
+ deps[path] = true
+ }
+ for _, path := range p.TestImports {
+ deps[path] = true
+ }
+ for _, path := range p.XTestImports {
+ deps[path] = true
+ }
+ }
+
+ // translate C to runtime/cgo
+ if deps["C"] {
+ delete(deps, "C")
+ deps["runtime/cgo"] = true
+ if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
+ deps["cmd/cgo"] = true
+ }
+ }
+ // Ignore pseudo-packages.
+ delete(deps, "unsafe")
+
+ all := []string{}
+ for path := range deps {
+ all = append(all, path)
+ }
+ sort.Strings(all)
+
+ a := &action{}
+ for _, p := range packagesForBuild(all) {
+ a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
+ }
+ b.do(a)
+ if !testC {
+ return
+ }
+ b.init()
+ }
+
+ var builds, runs, prints []*action
+
+ // Prepare build + run + print actions for all packages being tested.
+ for _, p := range pkgs {
+ buildTest, runTest, printTest, err := b.test(p)
+ if err != nil {
+ str := err.Error()
+ if strings.HasPrefix(str, "\n") {
+ str = str[1:]
+ }
+ if p.ImportPath != "" {
+ errorf("# %s\n%s", p.ImportPath, str)
+ } else {
+ errorf("%s", str)
+ }
+ continue
+ }
+ builds = append(builds, buildTest)
+ runs = append(runs, runTest)
+ prints = append(prints, printTest)
+ }
+
+ // Ultimately the goal is to print the output.
+ root := &action{deps: prints}
+
+ // Force the printing of results to happen in order,
+ // one at a time.
+ for i, a := range prints {
+ if i > 0 {
+ a.deps = append(a.deps, prints[i-1])
+ }
+ }
+
+ // If we are benchmarking, force everything to
+ // happen in serial. Could instead allow all the
+ // builds to run before any benchmarks start,
+ // but try this for now.
+ if testBench {
+ for i, a := range builds {
+ if i > 0 {
+ // Make build of test i depend on
+ // completing the run of test i-1.
+ a.deps = append(a.deps, runs[i-1])
+ }
+ }
+ }
+
+ // If we are building any out-of-date packages other
+ // than those under test, warn.
+ okBuild := map[*Package]bool{}
+ for _, p := range pkgs {
+ okBuild[p] = true
+ }
+
+ warned := false
+ for _, a := range actionList(root) {
+ if a.p != nil && a.f != nil && !okBuild[a.p] && !a.p.fake && !a.p.local {
+ okBuild[a.p] = true // don't warn again
+ if !warned {
+ fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
+ warned = true
+ }
+ fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath)
+ }
+ }
+ if warned {
+ args := strings.Join(pkgArgs, " ")
+ if args != "" {
+ args = " " + args
+ }
+ fmt.Fprintf(os.Stderr, "installing these packages with 'go test -i%s' will speed future tests.\n\n", args)
+ }
+
+ b.do(root)
+}
+
+func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) {
+ if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
+ build := &action{p: p}
+ run := &action{p: p}
+ print := &action{f: (*builder).notest, p: p, deps: []*action{build}}
+ return build, run, print, nil
+ }
+
+ // Build Package structs describing:
+ // ptest - package + test files
+ // pxtest - package of external test files
+ // pmain - pkg.test binary
+ var ptest, pxtest, pmain *Package
+
+ var imports, ximports []*Package
+ var stk importStack
+ stk.push(p.ImportPath + "_test")
+ for _, path := range p.TestImports {
+ p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ imports = append(imports, p1)
+ }
+ for _, path := range p.XTestImports {
+ if path == p.ImportPath {
+ continue
+ }
+ p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
+ if p1.Error != nil {
+ return nil, nil, nil, p1.Error
+ }
+ ximports = append(ximports, p1)
+ }
+ stk.pop()
+
+ // Use last element of import path, not package name.
+ // They differ when package name is "main".
+ _, elem := path.Split(p.ImportPath)
+ testBinary := elem + ".test"
+
+ // The ptest package needs to be importable under the
+ // same import path that p has, but we cannot put it in
+ // the usual place in the temporary tree, because then
+ // other tests will see it as the real package.
+ // Instead we make a _test directory under the import path
+ // and then repeat the import path there. We tell the
+ // compiler and linker to look in that _test directory first.
+ //
+ // That is, if the package under test is unicode/utf8,
+ // then the normal place to write the package archive is
+ // $WORK/unicode/utf8.a, but we write the test package archive to
+ // $WORK/unicode/utf8/_test/unicode/utf8.a.
+ // We write the external test package archive to
+ // $WORK/unicode/utf8/_test/unicode/utf8_test.a.
+ testDir := filepath.Join(b.work, filepath.FromSlash(p.ImportPath+"/_test"))
+ ptestObj := buildToolchain.pkgpath(testDir, p)
+
+ // Create the directory for the .a files.
+ ptestDir, _ := filepath.Split(ptestObj)
+ if err := b.mkdir(ptestDir); err != nil {
+ return nil, nil, nil, err
+ }
+ if err := writeTestmain(filepath.Join(testDir, "_testmain.go"), p); err != nil {
+ return nil, nil, nil, err
+ }
+
+ // Test package.
+ if len(p.TestGoFiles) > 0 {
+ ptest = new(Package)
+ *ptest = *p
+ ptest.GoFiles = nil
+ ptest.GoFiles = append(ptest.GoFiles, p.GoFiles...)
+ ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...)
+ ptest.target = ""
+ ptest.Imports = stringList(p.Imports, p.TestImports)
+ ptest.imports = append(append([]*Package{}, p.imports...), imports...)
+ ptest.pkgdir = testDir
+ ptest.fake = true
+ ptest.forceLibrary = true
+ ptest.Stale = true
+ ptest.build = new(build.Package)
+ *ptest.build = *p.build
+ m := map[string][]token.Position{}
+ for k, v := range p.build.ImportPos {
+ m[k] = append(m[k], v...)
+ }
+ for k, v := range p.build.TestImportPos {
+ m[k] = append(m[k], v...)
+ }
+ ptest.build.ImportPos = m
+ } else {
+ ptest = p
+ }
+
+ // External test package.
+ if len(p.XTestGoFiles) > 0 {
+ pxtest = &Package{
+ Name: p.Name + "_test",
+ ImportPath: p.ImportPath + "_test",
+ localPrefix: p.localPrefix,
+ Root: p.Root,
+ Dir: p.Dir,
+ GoFiles: p.XTestGoFiles,
+ Imports: p.XTestImports,
+ build: &build.Package{
+ ImportPos: p.build.XTestImportPos,
+ },
+ imports: append(ximports, ptest),
+ pkgdir: testDir,
+ fake: true,
+ Stale: true,
+ }
+ }
+
+ // Action for building pkg.test.
+ pmain = &Package{
+ Name: "main",
+ Dir: testDir,
+ GoFiles: []string{"_testmain.go"},
+ ImportPath: "testmain",
+ Root: p.Root,
+ imports: []*Package{ptest},
+ build: &build.Package{Name: "main"},
+ fake: true,
+ Stale: true,
+ }
+ if pxtest != nil {
+ pmain.imports = append(pmain.imports, pxtest)
+ }
+
+ // The generated main also imports testing and regexp.
+ stk.push("testmain")
+ ptesting := loadImport("testing", "", &stk, nil)
+ if ptesting.Error != nil {
+ return nil, nil, nil, ptesting.Error
+ }
+ pregexp := loadImport("regexp", "", &stk, nil)
+ if pregexp.Error != nil {
+ return nil, nil, nil, pregexp.Error
+ }
+ pmain.imports = append(pmain.imports, ptesting, pregexp)
+ computeStale(pmain)
+
+ if ptest != p {
+ a := b.action(modeBuild, modeBuild, ptest)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = ptestObj
+ a.target = ptestObj
+ a.link = false
+ }
+
+ if pxtest != nil {
+ a := b.action(modeBuild, modeBuild, pxtest)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
+ a.target = a.objpkg
+ }
+
+ a := b.action(modeBuild, modeBuild, pmain)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = filepath.Join(testDir, "main.a")
+ a.target = filepath.Join(testDir, testBinary) + exeSuffix
+ pmainAction := a
+
+ if testC {
+ // -c flag: create action to copy binary to ./test.out.
+ runAction = &action{
+ f: (*builder).install,
+ deps: []*action{pmainAction},
+ p: pmain,
+ target: testBinary + exeSuffix,
+ }
+ printAction = &action{p: p, deps: []*action{runAction}} // nop
+ } else {
+ // run test
+ runAction = &action{
+ f: (*builder).runTest,
+ deps: []*action{pmainAction},
+ p: p,
+ ignoreFail: true,
+ }
+ cleanAction := &action{
+ f: (*builder).cleanTest,
+ deps: []*action{runAction},
+ p: p,
+ }
+ printAction = &action{
+ f: (*builder).printTest,
+ deps: []*action{cleanAction},
+ p: p,
+ }
+ }
+
+ return pmainAction, runAction, printAction, nil
+}
+
+// runTest is the action for running a test binary.
+func (b *builder) runTest(a *action) error {
+ args := stringList(a.deps[0].target, testArgs)
+ a.testOutput = new(bytes.Buffer)
+
+ if buildN || buildX {
+ b.showcmd("", "%s", strings.Join(args, " "))
+ if buildN {
+ return nil
+ }
+ }
+
+ if a.failed {
+ // We were unable to build the binary.
+ a.failed = false
+ fmt.Fprintf(a.testOutput, "FAIL\t%s [build failed]\n", a.p.ImportPath)
+ setExitStatus(1)
+ return nil
+ }
+
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = a.p.Dir
+ var buf bytes.Buffer
+ if testStreamOutput {
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ } else {
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ }
+
+ t0 := time.Now()
+ err := cmd.Start()
+
+ // This is a last-ditch deadline to detect and
+ // stop wedged test binaries, to keep the builders
+ // running.
+ tick := time.NewTimer(testKillTimeout)
+ if err == nil {
+ done := make(chan error)
+ go func() {
+ done <- cmd.Wait()
+ }()
+ select {
+ case err = <-done:
+ // ok
+ case <-tick.C:
+ cmd.Process.Kill()
+ err = <-done
+ fmt.Fprintf(&buf, "*** Test killed: ran too long.\n")
+ }
+ tick.Stop()
+ }
+ out := buf.Bytes()
+ t1 := time.Now()
+ t := fmt.Sprintf("%.3fs", t1.Sub(t0).Seconds())
+ if err == nil {
+ if testShowPass {
+ a.testOutput.Write(out)
+ }
+ fmt.Fprintf(a.testOutput, "ok \t%s\t%s\n", a.p.ImportPath, t)
+ return nil
+ }
+
+ setExitStatus(1)
+ if len(out) > 0 {
+ a.testOutput.Write(out)
+ // assume printing the test binary's exit status is superfluous
+ } else {
+ fmt.Fprintf(a.testOutput, "%s\n", err)
+ }
+ fmt.Fprintf(a.testOutput, "FAIL\t%s\t%s\n", a.p.ImportPath, t)
+
+ return nil
+}
+
+// cleanTest is the action for cleaning up after a test.
+func (b *builder) cleanTest(a *action) error {
+ if buildWork {
+ return nil
+ }
+ run := a.deps[0]
+ testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test"))
+ os.RemoveAll(testDir)
+ return nil
+}
+
+// printTest is the action for printing a test result.
+func (b *builder) printTest(a *action) error {
+ clean := a.deps[0]
+ run := clean.deps[0]
+ os.Stdout.Write(run.testOutput.Bytes())
+ run.testOutput = nil
+ return nil
+}
+
+// notest is the action for testing a package with no test files.
+func (b *builder) notest(a *action) error {
+ fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath)
+ return nil
+}
+
+// isTest tells whether name looks like a test (or benchmark, according to prefix).
+// It is a Test (say) if there is a character after Test that is not a lower-case letter.
+// We don't want TesticularCancer.
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+// writeTestmain writes the _testmain.go file for package p to
+// the file named out.
+func writeTestmain(out string, p *Package) error {
+ t := &testFuncs{
+ Package: p,
+ }
+ for _, file := range p.TestGoFiles {
+ if err := t.load(filepath.Join(p.Dir, file), "_test", &t.NeedTest); err != nil {
+ return err
+ }
+ }
+ for _, file := range p.XTestGoFiles {
+ if err := t.load(filepath.Join(p.Dir, file), "_xtest", &t.NeedXtest); err != nil {
+ return err
+ }
+ }
+
+ f, err := os.Create(out)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ if err := testmainTmpl.Execute(f, t); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+type testFuncs struct {
+ Tests []testFunc
+ Benchmarks []testFunc
+ Examples []testFunc
+ Package *Package
+ NeedTest bool
+ NeedXtest bool
+}
+
+type testFunc struct {
+ Package string // imported package name (_test or _xtest)
+ Name string // function name
+ Output string // output, for examples
+}
+
+var testFileSet = token.NewFileSet()
+
+func (t *testFuncs) load(filename, pkg string, seen *bool) error {
+ f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
+ if err != nil {
+ return expandScanner(err)
+ }
+ for _, d := range f.Decls {
+ n, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if n.Recv != nil {
+ continue
+ }
+ name := n.Name.String()
+ switch {
+ case isTest(name, "Test"):
+ t.Tests = append(t.Tests, testFunc{pkg, name, ""})
+ *seen = true
+ case isTest(name, "Benchmark"):
+ t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
+ *seen = true
+ }
+ }
+ for _, e := range doc.Examples(f) {
+ if e.Output == "" {
+ // Don't run examples with no output.
+ continue
+ }
+ t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
+ *seen = true
+ }
+ return nil
+}
+
+var testmainTmpl = template.Must(template.New("main").Parse(`
+package main
+
+import (
+ "regexp"
+ "testing"
+
+{{if .NeedTest}}
+ _test {{.Package.ImportPath | printf "%q"}}
+{{end}}
+{{if .NeedXtest}}
+ _xtest {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
+{{end}}
+)
+
+var tests = []testing.InternalTest{
+{{range .Tests}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var benchmarks = []testing.InternalBenchmark{
+{{range .Benchmarks}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}},
+{{end}}
+}
+
+var examples = []testing.InternalExample{
+{{range .Examples}}
+ {"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
+{{end}}
+}
+
+var matchPat string
+var matchRe *regexp.Regexp
+
+func matchString(pat, str string) (result bool, err error) {
+ if matchRe == nil || matchPat != pat {
+ matchPat = pat
+ matchRe, err = regexp.Compile(matchPat)
+ if err != nil {
+ return
+ }
+ }
+ return matchRe.MatchString(str), nil
+}
+
+func main() {
+ testing.Main(matchString, tests, benchmarks, examples)
+}
+
+`))
diff --git a/src/cmd/go/testdata/errmsg/x.go b/src/cmd/go/testdata/errmsg/x.go
new file mode 100644
index 000000000..60f5b6e98
--- /dev/null
+++ b/src/cmd/go/testdata/errmsg/x.go
@@ -0,0 +1,3 @@
+package foo
+
+import "bar"
diff --git a/src/cmd/go/testdata/errmsg/x1_test.go b/src/cmd/go/testdata/errmsg/x1_test.go
new file mode 100644
index 000000000..eb1a6798c
--- /dev/null
+++ b/src/cmd/go/testdata/errmsg/x1_test.go
@@ -0,0 +1,3 @@
+package foo_test
+
+import "bar"
diff --git a/src/cmd/go/testdata/errmsg/x_test.go b/src/cmd/go/testdata/errmsg/x_test.go
new file mode 100644
index 000000000..60f5b6e98
--- /dev/null
+++ b/src/cmd/go/testdata/errmsg/x_test.go
@@ -0,0 +1,3 @@
+package foo
+
+import "bar"
diff --git a/src/cmd/go/testdata/local/easy.go b/src/cmd/go/testdata/local/easy.go
new file mode 100644
index 000000000..4eeb517da
--- /dev/null
+++ b/src/cmd/go/testdata/local/easy.go
@@ -0,0 +1,7 @@
+package main
+
+import "./easysub"
+
+func main() {
+ easysub.Hello()
+}
diff --git a/src/cmd/go/testdata/local/easysub/easysub.go b/src/cmd/go/testdata/local/easysub/easysub.go
new file mode 100644
index 000000000..07040daee
--- /dev/null
+++ b/src/cmd/go/testdata/local/easysub/easysub.go
@@ -0,0 +1,7 @@
+package easysub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("easysub.Hello")
+}
diff --git a/src/cmd/go/testdata/local/easysub/main.go b/src/cmd/go/testdata/local/easysub/main.go
new file mode 100644
index 000000000..6c30b5236
--- /dev/null
+++ b/src/cmd/go/testdata/local/easysub/main.go
@@ -0,0 +1,9 @@
+// +build ignore
+
+package main
+
+import "."
+
+func main() {
+ easysub.Hello()
+}
diff --git a/src/cmd/go/testdata/local/hard.go b/src/cmd/go/testdata/local/hard.go
new file mode 100644
index 000000000..2ffac3fd7
--- /dev/null
+++ b/src/cmd/go/testdata/local/hard.go
@@ -0,0 +1,7 @@
+package main
+
+import "./sub"
+
+func main() {
+ sub.Hello()
+}
diff --git a/src/cmd/go/testdata/local/sub/sub.go b/src/cmd/go/testdata/local/sub/sub.go
new file mode 100644
index 000000000..d5dbf6d5f
--- /dev/null
+++ b/src/cmd/go/testdata/local/sub/sub.go
@@ -0,0 +1,12 @@
+package sub
+
+import (
+ "fmt"
+
+ subsub "./sub"
+)
+
+func Hello() {
+ fmt.Println("sub.Hello")
+ subsub.Hello()
+}
diff --git a/src/cmd/go/testdata/local/sub/sub/subsub.go b/src/cmd/go/testdata/local/sub/sub/subsub.go
new file mode 100644
index 000000000..4cc72233e
--- /dev/null
+++ b/src/cmd/go/testdata/local/sub/sub/subsub.go
@@ -0,0 +1,7 @@
+package subsub
+
+import "fmt"
+
+func Hello() {
+ fmt.Println("subsub.Hello")
+}
diff --git a/src/cmd/go/testdata/src/go-cmd-test/helloworld.go b/src/cmd/go/testdata/src/go-cmd-test/helloworld.go
new file mode 100644
index 000000000..002a5c740
--- /dev/null
+++ b/src/cmd/go/testdata/src/go-cmd-test/helloworld.go
@@ -0,0 +1,5 @@
+package main
+
+func main() {
+ println("hello world")
+}
diff --git a/src/cmd/go/testdata/testimport/p.go b/src/cmd/go/testdata/testimport/p.go
new file mode 100644
index 000000000..f94d2cd0e
--- /dev/null
+++ b/src/cmd/go/testdata/testimport/p.go
@@ -0,0 +1,3 @@
+package p
+
+func F() int { return 1 }
diff --git a/src/cmd/go/testdata/testimport/p1/p1.go b/src/cmd/go/testdata/testimport/p1/p1.go
new file mode 100644
index 000000000..fd315272e
--- /dev/null
+++ b/src/cmd/go/testdata/testimport/p1/p1.go
@@ -0,0 +1,3 @@
+package p1
+
+func F() int { return 1 }
diff --git a/src/cmd/go/testdata/testimport/p2/p2.go b/src/cmd/go/testdata/testimport/p2/p2.go
new file mode 100644
index 000000000..d4888865d
--- /dev/null
+++ b/src/cmd/go/testdata/testimport/p2/p2.go
@@ -0,0 +1,3 @@
+package p2
+
+func F() int { return 1 }
diff --git a/src/cmd/go/testdata/testimport/p_test.go b/src/cmd/go/testdata/testimport/p_test.go
new file mode 100644
index 000000000..a3fb4a9e2
--- /dev/null
+++ b/src/cmd/go/testdata/testimport/p_test.go
@@ -0,0 +1,13 @@
+package p
+
+import (
+ "./p1"
+
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ if F() != p1.F() {
+ t.Fatal(F())
+ }
+}
diff --git a/src/cmd/go/testdata/testimport/x_test.go b/src/cmd/go/testdata/testimport/x_test.go
new file mode 100644
index 000000000..b253e3fd2
--- /dev/null
+++ b/src/cmd/go/testdata/testimport/x_test.go
@@ -0,0 +1,15 @@
+package p_test
+
+import (
+ . "../testimport"
+
+ "./p2"
+
+ "testing"
+)
+
+func TestF1(t *testing.T) {
+ if F() != p2.F() {
+ t.Fatal(F())
+ }
+}
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
new file mode 100644
index 000000000..ecf5bf456
--- /dev/null
+++ b/src/cmd/go/testflag.go
@@ -0,0 +1,235 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// The flag handling part of go test is large and distracting.
+// We can't use the flag package because some of the flags from
+// our command line are for us, and some are for 6.out, and
+// some are for both.
+
+var usageMessage = `Usage of go test:
+ -c=false: compile but do not run the test binary
+ -file=file_test.go: specify file to use for tests;
+ use multiple times for multiple files
+ -p=n: build and test up to n packages in parallel
+ -x=false: print command lines as they are executed
+
+ // These flags can be passed with or without a "test." prefix: -v or -test.v.
+ -bench="": passes -test.bench to test
+ -benchtime=1: passes -test.benchtime to test
+ -cpu="": passes -test.cpu to test
+ -cpuprofile="": passes -test.cpuprofile to test
+ -memprofile="": passes -test.memprofile to test
+ -memprofilerate=0: passes -test.memprofilerate to test
+ -parallel=0: passes -test.parallel to test
+ -run="": passes -test.run to test
+ -short=false: passes -test.short to test
+ -timeout=0: passes -test.timeout to test
+ -v=false: passes -test.v to test
+`
+
+// usage prints a usage message and exits.
+func testUsage() {
+ fmt.Fprint(os.Stderr, usageMessage)
+ setExitStatus(2)
+ exit()
+}
+
+// testFlagSpec defines a flag we know about.
+type testFlagSpec struct {
+ name string
+ boolVar *bool
+ passToTest bool // pass to Test
+ multiOK bool // OK to have multiple instances
+ present bool // flag has been seen
+}
+
+// testFlagDefn is the set of flags we process.
+var testFlagDefn = []*testFlagSpec{
+ // local.
+ {name: "c", boolVar: &testC},
+ {name: "file", multiOK: true},
+ {name: "i", boolVar: &testI},
+
+ // build flags.
+ {name: "a", boolVar: &buildA},
+ {name: "n", boolVar: &buildN},
+ {name: "p"},
+ {name: "x", boolVar: &buildX},
+ {name: "work", boolVar: &buildWork},
+ {name: "gcflags"},
+ {name: "ldflags"},
+ {name: "gccgoflags"},
+ {name: "tags"},
+ {name: "compiler"},
+
+ // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
+ {name: "bench", passToTest: true},
+ {name: "benchtime", passToTest: true},
+ {name: "cpu", passToTest: true},
+ {name: "cpuprofile", passToTest: true},
+ {name: "memprofile", passToTest: true},
+ {name: "memprofilerate", passToTest: true},
+ {name: "parallel", passToTest: true},
+ {name: "run", passToTest: true},
+ {name: "short", boolVar: new(bool), passToTest: true},
+ {name: "timeout", passToTest: true},
+ {name: "v", boolVar: &testV, passToTest: true},
+}
+
+// testFlags processes the command line, grabbing -x and -c, rewriting known flags
+// to have "test" before them, and reading the command line for the 6.out.
+// Unfortunately for us, we need to do our own flag processing because go test
+// grabs some flags but otherwise its command line is just a holding place for
+// pkg.test's arguments.
+// We allow known flags both before and after the package name list,
+// to allow both
+// go test fmt -custom-flag-for-fmt-test
+// go test -x math
+func testFlags(args []string) (packageNames, passToTest []string) {
+ inPkg := false
+ for i := 0; i < len(args); i++ {
+ if !strings.HasPrefix(args[i], "-") {
+ if !inPkg && packageNames == nil {
+ // First package name we've seen.
+ inPkg = true
+ }
+ if inPkg {
+ packageNames = append(packageNames, args[i])
+ continue
+ }
+ }
+
+ if inPkg {
+ // Found an argument beginning with "-"; end of package list.
+ inPkg = false
+ }
+
+ f, value, extraWord := testFlag(args, i)
+ if f == nil {
+ // This is a flag we do not know; we must assume
+ // that any args we see after this might be flag
+ // arguments, not package names.
+ inPkg = false
+ if packageNames == nil {
+ // make non-nil: we have seen the empty package list
+ packageNames = []string{}
+ }
+ passToTest = append(passToTest, args[i])
+ continue
+ }
+ switch f.name {
+ // bool flags.
+ case "a", "c", "i", "n", "x", "v", "work":
+ setBoolFlag(f.boolVar, value)
+ case "p":
+ setIntFlag(&buildP, value)
+ case "gcflags":
+ buildGcflags = strings.Fields(value)
+ case "ldflags":
+ buildLdflags = strings.Fields(value)
+ case "gccgoflags":
+ buildGccgoflags = strings.Fields(value)
+ case "tags":
+ buildContext.BuildTags = strings.Fields(value)
+ case "compiler":
+ buildCompiler{}.Set(value)
+ case "file":
+ testFiles = append(testFiles, value)
+ case "bench":
+ // record that we saw the flag; don't care about the value
+ testBench = true
+ case "timeout":
+ testTimeout = value
+ }
+ if extraWord {
+ i++
+ }
+ if f.passToTest {
+ passToTest = append(passToTest, "-test."+f.name+"="+value)
+ }
+ }
+ return
+}
+
+// testFlag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
+func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) {
+ arg := args[i]
+ if strings.HasPrefix(arg, "--") { // reduce two minuses to one
+ arg = arg[1:]
+ }
+ switch arg {
+ case "-?", "-h", "-help":
+ usage()
+ }
+ if arg == "" || arg[0] != '-' {
+ return
+ }
+ name := arg[1:]
+ // If there's already "test.", drop it for now.
+ if strings.HasPrefix(name, "test.") {
+ name = name[5:]
+ }
+ equals := strings.Index(name, "=")
+ if equals >= 0 {
+ value = name[equals+1:]
+ name = name[:equals]
+ }
+ for _, f = range testFlagDefn {
+ if name == f.name {
+ // Booleans are special because they have modes -x, -x=true, -x=false.
+ if f.boolVar != nil {
+ if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
+ value = "true"
+ } else {
+ // verify it parses
+ setBoolFlag(new(bool), value)
+ }
+ } else { // Non-booleans must have a value.
+ extra = equals < 0
+ if extra {
+ if i+1 >= len(args) {
+ usage()
+ }
+ value = args[i+1]
+ }
+ }
+ if f.present && !f.multiOK {
+ usage()
+ }
+ f.present = true
+ return
+ }
+ }
+ f = nil
+ return
+}
+
+// setBoolFlag sets the addressed boolean to the value.
+func setBoolFlag(flag *bool, value string) {
+ x, err := strconv.ParseBool(value)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go test: illegal bool flag value %s\n", value)
+ usage()
+ }
+ *flag = x
+}
+
+// setIntFlag sets the addressed integer to the value.
+func setIntFlag(flag *int, value string) {
+ x, err := strconv.Atoi(value)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go test: illegal int flag value %s\n", value)
+ usage()
+ }
+ *flag = x
+}
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
new file mode 100644
index 000000000..cb463a2e7
--- /dev/null
+++ b/src/cmd/go/tool.go
@@ -0,0 +1,125 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+)
+
+var cmdTool = &Command{
+ Run: runTool,
+ UsageLine: "tool [-n] command [args...]",
+ Short: "run specified go tool",
+ Long: `
+Tool runs the go tool command identified by the arguments.
+With no arguments it prints the list of known tools.
+
+The -n flag causes tool to print the command that would be
+executed but not execute it.
+
+For more about each tool command, see 'go tool command -h'.
+`,
+}
+
+var (
+ toolGOOS = runtime.GOOS
+ toolGOARCH = runtime.GOARCH
+ toolIsWindows = toolGOOS == "windows"
+ toolDir = build.ToolDir
+
+ toolN bool
+)
+
+func init() {
+ cmdTool.Flag.BoolVar(&toolN, "n", false, "")
+}
+
+const toolWindowsExtension = ".exe"
+
+func tool(name string) string {
+ p := filepath.Join(toolDir, name)
+ if toolIsWindows {
+ p += toolWindowsExtension
+ }
+ return p
+}
+
+func runTool(cmd *Command, args []string) {
+ if len(args) == 0 {
+ listTools()
+ return
+ }
+ toolName := args[0]
+ // The tool name must be lower-case letters, numbers or underscores.
+ for _, c := range toolName {
+ switch {
+ case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
+ default:
+ fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
+ setExitStatus(2)
+ return
+ }
+ }
+ toolPath := tool(toolName)
+ // Give a nice message if there is no tool with that name.
+ if _, err := os.Stat(toolPath); err != nil {
+ fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
+ setExitStatus(3)
+ return
+ }
+
+ if toolN {
+ fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
+ return
+ }
+ toolCmd := &exec.Cmd{
+ Path: toolPath,
+ Args: args,
+ Stdin: os.Stdin,
+ Stdout: os.Stdout,
+ Stderr: os.Stderr,
+ }
+ err := toolCmd.Run()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
+ setExitStatus(1)
+ return
+ }
+}
+
+// listTools prints a list of the available tools in the tools directory.
+func listTools() {
+ f, err := os.Open(toolDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
+ setExitStatus(2)
+ return
+ }
+ defer f.Close()
+ names, err := f.Readdirnames(-1)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
+ setExitStatus(2)
+ return
+ }
+
+ sort.Strings(names)
+ for _, name := range names {
+ // Unify presentation by going to lower case.
+ name = strings.ToLower(name)
+ // If it's windows, don't show the .exe suffix.
+ if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
+ name = name[:len(name)-len(toolWindowsExtension)]
+ }
+ fmt.Println(name)
+ }
+}
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
new file mode 100644
index 000000000..5f63f8b56
--- /dev/null
+++ b/src/cmd/go/vcs.go
@@ -0,0 +1,674 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+// A vcsCmd describes how to use a version control system
+// like Mercurial, Git, or Subversion.
+type vcsCmd struct {
+ name string
+ cmd string // name of binary to invoke command
+
+ createCmd string // command to download a fresh copy of a repository
+ downloadCmd string // command to download updates into an existing repository
+
+ tagCmd []tagCmd // commands to list tags
+ tagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd
+ tagSyncCmd string // command to sync to specific tag
+ tagSyncDefault string // command to sync to default tag
+
+ scheme []string
+ pingCmd string
+}
+
+// A tagCmd describes a command to list available tags
+// that can be passed to tagSyncCmd.
+type tagCmd struct {
+ cmd string // command to list tags
+ pattern string // regexp to extract tags from list
+}
+
+// vcsList lists the known version control systems
+var vcsList = []*vcsCmd{
+ vcsHg,
+ vcsGit,
+ vcsSvn,
+ vcsBzr,
+}
+
+// vcsByCmd returns the version control system for the given
+// command name (hg, git, svn, bzr).
+func vcsByCmd(cmd string) *vcsCmd {
+ for _, vcs := range vcsList {
+ if vcs.cmd == cmd {
+ return vcs
+ }
+ }
+ return nil
+}
+
+// vcsHg describes how to use Mercurial.
+var vcsHg = &vcsCmd{
+ name: "Mercurial",
+ cmd: "hg",
+
+ createCmd: "clone -U {repo} {dir}",
+ downloadCmd: "pull",
+
+ // We allow both tag and branch names as 'tags'
+ // for selecting a version. This lets people have
+ // a go.release.r60 branch and a go1 branch
+ // and make changes in both, without constantly
+ // editing .hgtags.
+ tagCmd: []tagCmd{
+ {"tags", `^(\S+)`},
+ {"branches", `^(\S+)`},
+ },
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update default",
+
+ scheme: []string{"https", "http"},
+ pingCmd: "identify {scheme}://{repo}",
+}
+
+// vcsGit describes how to use Git.
+var vcsGit = &vcsCmd{
+ name: "Git",
+ cmd: "git",
+
+ createCmd: "clone {repo} {dir}",
+ downloadCmd: "fetch",
+
+ tagCmd: []tagCmd{
+ // tags/xxx matches a git tag named xxx
+ // origin/xxx matches a git branch named xxx on the default remote repository
+ {"show-ref", `(?:tags|origin)/(\S+)$`},
+ },
+ tagLookupCmd: []tagCmd{
+ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
+ },
+ tagSyncCmd: "checkout {tag}",
+ tagSyncDefault: "checkout origin/master",
+
+ scheme: []string{"git", "https", "http", "git+ssh"},
+ pingCmd: "ls-remote {scheme}://{repo}",
+}
+
+// vcsBzr describes how to use Bazaar.
+var vcsBzr = &vcsCmd{
+ name: "Bazaar",
+ cmd: "bzr",
+
+ createCmd: "branch {repo} {dir}",
+
+ // Without --overwrite bzr will not pull tags that changed.
+ // Replace by --overwrite-tags after http://pad.lv/681792 goes in.
+ downloadCmd: "pull --overwrite",
+
+ tagCmd: []tagCmd{{"tags", `^(\S+)`}},
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update -r revno:-1",
+
+ scheme: []string{"https", "http", "bzr", "bzr+ssh"},
+ pingCmd: "info {scheme}://{repo}",
+}
+
+// vcsSvn describes how to use Subversion.
+var vcsSvn = &vcsCmd{
+ name: "Subversion",
+ cmd: "svn",
+
+ createCmd: "checkout {repo} {dir}",
+ downloadCmd: "update",
+
+ // There is no tag command in subversion.
+ // The branch information is all in the path names.
+
+ scheme: []string{"https", "http", "svn", "svn+ssh"},
+ pingCmd: "info {scheme}://{repo}",
+}
+
+func (v *vcsCmd) String() string {
+ return v.name
+}
+
+// run runs the command line cmd in the given directory.
+// keyval is a list of key, value pairs. run expands
+// instances of {key} in cmd into value, but only after
+// splitting cmd into individual arguments.
+// If an error occurs, run prints the command line and the
+// command's combined stdout+stderr to standard error.
+// Otherwise run discards the command's output.
+func (v *vcsCmd) run(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, true)
+ return err
+}
+
+// runVerboseOnly is like run but only generates error output to standard error in verbose mode.
+func (v *vcsCmd) runVerboseOnly(dir string, cmd string, keyval ...string) error {
+ _, err := v.run1(dir, cmd, keyval, false)
+ return err
+}
+
+// runOutput is like run but returns the output of the command.
+func (v *vcsCmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) {
+ return v.run1(dir, cmd, keyval, true)
+}
+
+// run1 is the generalized implementation of run and runOutput.
+func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) {
+ m := make(map[string]string)
+ for i := 0; i < len(keyval); i += 2 {
+ m[keyval[i]] = keyval[i+1]
+ }
+ args := strings.Fields(cmdline)
+ for i, arg := range args {
+ args[i] = expand(m, arg)
+ }
+
+ cmd := exec.Command(v.cmd, args...)
+ cmd.Dir = dir
+ if buildX {
+ fmt.Printf("cd %s\n", dir)
+ fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
+ }
+ var buf bytes.Buffer
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ err := cmd.Run()
+ out := buf.Bytes()
+ if err != nil {
+ if verbose || buildV {
+ fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
+ os.Stderr.Write(out)
+ }
+ return nil, err
+ }
+ return out, nil
+}
+
+// ping pings to determine scheme to use.
+func (v *vcsCmd) ping(scheme, repo string) error {
+ return v.runVerboseOnly(".", v.pingCmd, "scheme", scheme, "repo", repo)
+}
+
+// create creates a new copy of repo in dir.
+// The parent of dir must exist; dir must not.
+func (v *vcsCmd) create(dir, repo string) error {
+ return v.run(".", v.createCmd, "dir", dir, "repo", repo)
+}
+
+// download downloads any new changes for the repo in dir.
+func (v *vcsCmd) download(dir string) error {
+ return v.run(dir, v.downloadCmd)
+}
+
+// tags returns the list of available tags for the repo in dir.
+func (v *vcsCmd) tags(dir string) ([]string, error) {
+ var tags []string
+ for _, tc := range v.tagCmd {
+ out, err := v.runOutput(dir, tc.cmd)
+ if err != nil {
+ return nil, err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+ for _, m := range re.FindAllStringSubmatch(string(out), -1) {
+ tags = append(tags, m[1])
+ }
+ }
+ return tags, nil
+}
+
+// tagSync syncs the repo in dir to the named tag,
+// which either is a tag returned by tags or is v.tagDefault.
+func (v *vcsCmd) tagSync(dir, tag string) error {
+ if v.tagSyncCmd == "" {
+ return nil
+ }
+ if tag != "" {
+ for _, tc := range v.tagLookupCmd {
+ out, err := v.runOutput(dir, tc.cmd, "tag", tag)
+ if err != nil {
+ return err
+ }
+ re := regexp.MustCompile(`(?m-s)` + tc.pattern)
+ m := re.FindStringSubmatch(string(out))
+ if len(m) > 1 {
+ tag = m[1]
+ break
+ }
+ }
+ }
+ if tag == "" && v.tagSyncDefault != "" {
+ return v.run(dir, v.tagSyncDefault)
+ }
+ return v.run(dir, v.tagSyncCmd, "tag", tag)
+}
+
+// A vcsPath describes how to convert an import path into a
+// version control system and repository name.
+type vcsPath struct {
+ prefix string // prefix this description applies to
+ re string // pattern for import path
+ repo string // repository to use (expand with match of re)
+ vcs string // version control system to use (expand with match of re)
+ check func(match map[string]string) error // additional checks
+ ping bool // ping for scheme to use to download repo
+
+ regexp *regexp.Regexp // cached compiled form of re
+}
+
+// vcsForDir inspects dir and its parents to determine the
+// version control system and code repository to use.
+// On return, root is the import path
+// corresponding to the root of the repository
+// (thus root is a prefix of importPath).
+func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
+ // Clean and double-check that dir is in (a subdirectory of) srcRoot.
+ dir := filepath.Clean(p.Dir)
+ srcRoot := filepath.Clean(p.build.SrcRoot)
+ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
+ return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
+ }
+
+ for len(dir) > len(srcRoot) {
+ for _, vcs := range vcsList {
+ if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
+ return vcs, dir[len(srcRoot)+1:], nil
+ }
+ }
+
+ // Move to parent.
+ ndir := filepath.Dir(dir)
+ if len(ndir) >= len(dir) {
+ // Shouldn't happen, but just in case, stop.
+ break
+ }
+ dir = ndir
+ }
+
+ return nil, "", fmt.Errorf("directory %q is not using a known version control system", dir)
+}
+
+// repoRoot represents a version control system, a repo, and a root of
+// where to put it on disk.
+type repoRoot struct {
+ vcs *vcsCmd
+
+ // repo is the repository URL, including scheme
+ repo string
+
+ // root is the import path corresponding to the root of the
+ // repository
+ root string
+}
+
+// repoRootForImportPath analyzes importPath to determine the
+// version control system, and code repository to use.
+func repoRootForImportPath(importPath string) (*repoRoot, error) {
+ rr, err := repoRootForImportPathStatic(importPath, "")
+ if err == errUnknownSite {
+ rr, err = repoRootForImportDynamic(importPath)
+
+ // repoRootForImportDynamic returns error detail
+ // that is irrelevant if the user didn't intend to use a
+ // dynamic import in the first place.
+ // Squelch it.
+ if err != nil {
+ if buildV {
+ log.Printf("import %q: %v", importPath, err)
+ }
+ err = fmt.Errorf("unrecognized import path %q", importPath)
+ }
+ }
+
+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+ // Do not allow wildcards in the repo root.
+ rr = nil
+ err = fmt.Errorf("cannot expand ... in %q", importPath)
+ }
+ return rr, err
+}
+
+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
+
+// repoRootForImportPathStatic attempts to map importPath to a
+// repoRoot using the commonly-used VCS hosting sites in vcsPaths
+// (github.com/user/dir), or from a fully-qualified importPath already
+// containing its VCS type (foo.com/repo.git/dir)
+//
+// If scheme is non-empty, that scheme is forced.
+func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
+ if strings.Contains(importPath, "://") {
+ return nil, fmt.Errorf("invalid import path %q", importPath)
+ }
+ for _, srv := range vcsPaths {
+ if !strings.HasPrefix(importPath, srv.prefix) {
+ continue
+ }
+ m := srv.regexp.FindStringSubmatch(importPath)
+ if m == nil {
+ if srv.prefix != "" {
+ return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
+ }
+ continue
+ }
+
+ // Build map of named subexpression matches for expand.
+ match := map[string]string{
+ "prefix": srv.prefix,
+ "import": importPath,
+ }
+ for i, name := range srv.regexp.SubexpNames() {
+ if name != "" && match[name] == "" {
+ match[name] = m[i]
+ }
+ }
+ if srv.vcs != "" {
+ match["vcs"] = expand(match, srv.vcs)
+ }
+ if srv.repo != "" {
+ match["repo"] = expand(match, srv.repo)
+ }
+ if srv.check != nil {
+ if err := srv.check(match); err != nil {
+ return nil, err
+ }
+ }
+ vcs := vcsByCmd(match["vcs"])
+ if vcs == nil {
+ return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
+ }
+ if srv.ping {
+ if scheme != "" {
+ match["repo"] = scheme + "://" + match["repo"]
+ } else {
+ for _, scheme := range vcs.scheme {
+ if vcs.ping(scheme, match["repo"]) == nil {
+ match["repo"] = scheme + "://" + match["repo"]
+ break
+ }
+ }
+ }
+ }
+ rr := &repoRoot{
+ vcs: vcs,
+ repo: match["repo"],
+ root: match["root"],
+ }
+ return rr, nil
+ }
+ return nil, errUnknownSite
+}
+
+// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// statically known by repoRootForImportPathStatic.
+//
+// This handles "vanity import paths" like "name.tld/pkg/foo".
+func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
+ slash := strings.Index(importPath, "/")
+ if slash < 0 {
+ return nil, fmt.Errorf("missing / in import %q", importPath)
+ }
+ urlStr, body, err := httpsOrHTTP(importPath)
+ if err != nil {
+ return nil, fmt.Errorf("http/https fetch for import %q: %v", importPath, err)
+ }
+ defer body.Close()
+ metaImport, err := matchGoImport(parseMetaGoImports(body), importPath)
+ if err != nil {
+ if err != errNoMatch {
+ return nil, fmt.Errorf("parse %s: %v", urlStr, err)
+ }
+ return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ }
+ if buildV {
+ log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+ }
+ // If the import was "uni.edu/bob/project", which said the
+ // prefix was "uni.edu" and the RepoRoot was "evilroot.com",
+ // make sure we don't trust Bob and check out evilroot.com to
+ // "uni.edu" yet (possibly overwriting/preempting another
+ // non-evil student). Instead, first verify the root and see
+ // if it matches Bob's claim.
+ if metaImport.Prefix != importPath {
+ if buildV {
+ log.Printf("get %q: verifying non-authoritative meta tag", importPath)
+ }
+ urlStr0 := urlStr
+ urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+ if err != nil {
+ return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
+ }
+ imports := parseMetaGoImports(body)
+ if len(imports) == 0 {
+ return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+ }
+ metaImport2, err := matchGoImport(imports, importPath)
+ if err != nil || metaImport != metaImport2 {
+ return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+ }
+ }
+
+ if !strings.Contains(metaImport.RepoRoot, "://") {
+ return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+ }
+ rr := &repoRoot{
+ vcs: vcsByCmd(metaImport.VCS),
+ repo: metaImport.RepoRoot,
+ root: metaImport.Prefix,
+ }
+ if rr.vcs == nil {
+ return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+ }
+ return rr, nil
+}
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+ Prefix, VCS, RepoRoot string
+}
+
+// errNoMatch is returned from matchGoImport when there's no applicable match.
+var errNoMatch = errors.New("no import match")
+
+// matchGoImport returns the metaImport from imports matching importPath.
+// An error is returned if there are multiple matches.
+// errNoMatch is returned if none match.
+func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+ match := -1
+ for i, im := range imports {
+ if !strings.HasPrefix(importPath, im.Prefix) {
+ continue
+ }
+ if match != -1 {
+ err = fmt.Errorf("multiple meta tags match import path %q", importPath)
+ return
+ }
+ match = i
+ }
+ if match == -1 {
+ err = errNoMatch
+ return
+ }
+ return imports[match], nil
+}
+
+// expand rewrites s to replace {k} with match[k] for each key k in match.
+func expand(match map[string]string, s string) string {
+ for k, v := range match {
+ s = strings.Replace(s, "{"+k+"}", v, -1)
+ }
+ return s
+}
+
+// vcsPaths lists the known vcs paths.
+var vcsPaths = []*vcsPath{
+ // Google Code - new syntax
+ {
+ prefix: "code.google.com/",
+ re: `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: googleCodeVCS,
+ },
+
+ // Google Code - old syntax
+ {
+ re: `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
+ check: oldGoogleCode,
+ },
+
+ // Github
+ {
+ prefix: "github.com/",
+ re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "git",
+ repo: "https://{root}",
+ check: noVCSSuffix,
+ },
+
+ // Bitbucket
+ {
+ prefix: "bitbucket.org/",
+ re: `^(?P<root>bitbucket\.org/(?P<bitname>[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+ repo: "https://{root}",
+ check: bitbucketVCS,
+ },
+
+ // Launchpad
+ {
+ prefix: "launchpad.net/",
+ re: `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+ vcs: "bzr",
+ repo: "https://{root}",
+ check: launchpadVCS,
+ },
+
+ // General syntax for any server.
+ {
+ re: `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
+ ping: true,
+ },
+}
+
+func init() {
+ // fill in cached regexps.
+ // Doing this eagerly discovers invalid regexp syntax
+ // without having to run a command that needs that regexp.
+ for _, srv := range vcsPaths {
+ srv.regexp = regexp.MustCompile(srv.re)
+ }
+}
+
+// noVCSSuffix checks that the repository name does not
+// end in .foo for any version control system foo.
+// The usual culprit is ".git".
+func noVCSSuffix(match map[string]string) error {
+ repo := match["repo"]
+ for _, vcs := range vcsList {
+ if strings.HasSuffix(repo, "."+vcs.cmd) {
+ return fmt.Errorf("invalid version control suffix in %s path", match["prefix"])
+ }
+ }
+ return nil
+}
+
+var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
+
+// googleCodeVCS determines the version control system for
+// a code.google.com repository, by scraping the project's
+// /source/checkout page.
+func googleCodeVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+ data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
+ if err != nil {
+ return err
+ }
+
+ if m := googleCheckout.FindSubmatch(data); m != nil {
+ if vcs := vcsByCmd(string(m[1])); vcs != nil {
+ // Subversion requires the old URLs.
+ // TODO: Test.
+ if vcs == vcsSvn {
+ if match["subrepo"] != "" {
+ return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
+ }
+ match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
+ }
+ match["vcs"] = vcs.cmd
+ return nil
+ }
+ }
+
+ return fmt.Errorf("unable to detect version control system for code.google.com/ path")
+}
+
+// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
+// It prints an error giving the equivalent new path.
+func oldGoogleCode(match map[string]string) error {
+ return fmt.Errorf("invalid Google Code import path: use %s instead",
+ expand(match, "code.google.com/p/{project}{path}"))
+}
+
+// bitbucketVCS determines the version control system for a
+// BitBucket repository, by using the BitBucket API.
+func bitbucketVCS(match map[string]string) error {
+ if err := noVCSSuffix(match); err != nil {
+ return err
+ }
+
+ var resp struct {
+ SCM string `json:"scm"`
+ }
+ url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
+ data, err := httpGET(url)
+ if err != nil {
+ return err
+ }
+ if err := json.Unmarshal(data, &resp); err != nil {
+ return fmt.Errorf("decoding %s: %v", url, err)
+ }
+
+ if vcsByCmd(resp.SCM) != nil {
+ match["vcs"] = resp.SCM
+ if resp.SCM == "git" {
+ match["repo"] += ".git"
+ }
+ return nil
+ }
+
+ return fmt.Errorf("unable to detect version control system for bitbucket.org/ path")
+}
+
+// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case,
+// "foo" could be a series name registered in Launchpad with its own branch,
+// and it could also be the name of a directory within the main project
+// branch one level up.
+func launchpadVCS(match map[string]string) error {
+ if match["project"] == "" || match["series"] == "" {
+ return nil
+ }
+ _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
+ if err != nil {
+ match["root"] = expand(match, "launchpad.net/{project}")
+ match["repo"] = expand(match, "https://{root}")
+ }
+ return nil
+}
diff --git a/src/cmd/go/version.go b/src/cmd/go/version.go
new file mode 100644
index 000000000..09e2f1633
--- /dev/null
+++ b/src/cmd/go/version.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 main
+
+import (
+ "fmt"
+ "runtime"
+)
+
+var cmdVersion = &Command{
+ Run: runVersion,
+ UsageLine: "version",
+ Short: "print Go version",
+ Long: `Version prints the Go version, as reported by runtime.Version.`,
+}
+
+func runVersion(cmd *Command, args []string) {
+ if len(args) != 0 {
+ cmd.Usage()
+ }
+
+ fmt.Printf("go version %s\n", runtime.Version())
+}
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
new file mode 100644
index 000000000..a672b9910
--- /dev/null
+++ b/src/cmd/go/vet.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.
+
+package main
+
+var cmdVet = &Command{
+ Run: runVet,
+ UsageLine: "vet [packages]",
+ Short: "run go tool vet on packages",
+ Long: `
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet, see 'godoc vet'.
+For more about specifying packages, see 'go help packages'.
+
+To run the vet tool with specific options, run 'go tool vet'.
+
+See also: go fmt, go fix.
+ `,
+}
+
+func runVet(cmd *Command, args []string) {
+ for _, pkg := range packages(args) {
+ // Use pkg.gofiles instead of pkg.Dir so that
+ // the command only applies to this package,
+ // not to packages in subdirectories.
+ run(tool("vet"), relPaths(pkg.gofiles))
+ }
+}
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
deleted file mode 100644
index 77cd26c04..000000000
--- a/src/cmd/godefs/Makefile
+++ /dev/null
@@ -1,19 +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.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=godefs
-OFILES=\
- main.$O\
- stabs.$O\
- util.$O\
-
-HFILES=a.h
-
-include ../../Make.ccmd
-
-test: $(TARG)
- ./test.sh
diff --git a/src/cmd/godefs/a.h b/src/cmd/godefs/a.h
deleted file mode 100644
index 9b4957467..000000000
--- a/src/cmd/godefs/a.h
+++ /dev/null
@@ -1,104 +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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-
-enum
-{
- Void = 1,
- Int8,
- Uint8,
- Int16,
- Uint16,
- Int32,
- Uint32,
- Int64,
- Uint64,
- Float32,
- Float64,
- Ptr,
- Struct,
- Array,
- Union,
- Typedef,
-};
-
-typedef struct Field Field;
-typedef struct Type Type;
-
-struct Type
-{
- Type *next; // next in hash table
-
- // stabs name and two-integer id
- char *name;
- int n1;
- int n2;
-
- // int kind
- int kind;
-
- // sub-type for ptr, array
- Type *type;
-
- // struct fields
- Field *f;
- int nf;
- int size;
-
- int saved; // recorded in typ array
- int warned; // warned about needing type
- int printed; // has the definition been printed yet?
-};
-
-struct Field
-{
- char *name;
- Type *type;
- int offset;
- int size;
-};
-
-// Constants
-typedef struct Const Const;
-struct Const
-{
- char *name;
- vlong value;
-};
-
-// Recorded constants and types, to be printed.
-extern Const *con;
-extern int ncon;
-extern Type **typ;
-extern int ntyp;
-extern int kindsize[];
-
-// Language output
-typedef struct Lang Lang;
-struct Lang
-{
- char *constbegin;
- char *constfmt;
- char *constend;
-
- char *typdef;
- char *typdefend;
-
- char *structbegin;
- char *unionbegin;
- char *structpadfmt;
- char *structend;
-
- int (*typefmt)(Fmt*);
-};
-
-extern Lang go, c;
-
-void* emalloc(int);
-char* estrdup(char*);
-void* erealloc(void*, int);
-void parsestabtype(char*);
diff --git a/src/cmd/godefs/doc.go b/src/cmd/godefs/doc.go
deleted file mode 100644
index 365c7cf6e..000000000
--- a/src/cmd/godefs/doc.go
+++ /dev/null
@@ -1,99 +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.
-
-/*
-
-Godefs is a bootstrapping tool for porting the Go runtime to new systems.
-It translates C type declarations into C or Go type declarations
-with the same memory layout.
-
-Usage: godefs [-g package] [-c cc] [-f cc-arg]... [defs.c ...]
-
-Godefs takes as input a host-compilable C file that includes
-standard system headers. From that input file, it generates
-a standalone (no #includes) C or Go file containing equivalent
-definitions.
-
-The input to godefs is a C input file that can be compiled by
-the host system's standard C compiler (typically gcc).
-This file is expected to define new types and enumerated constants
-whose names begin with $ (a legal identifier character in gcc).
-Godefs compile the given input file with the host compiler and
-then parses the debug info embedded in the assembly output.
-This is far easier than reading system headers on most machines.
-
-The output from godefs is either C output intended for the
-Plan 9 C compiler tool chain (6c, 8c, or 5c) or Go output.
-
-The options are:
-
- -g package
- generate Go output using the given package name.
- In the Go output, struct fields have leading xx_ prefixes
- removed and the first character capitalized (exported).
-
- -c cc
- set the name of the host system's C compiler (default "gcc")
-
- -f cc-arg
- add cc-arg to the command line when invoking the system C compiler
- (for example, -f -m64 to invoke gcc -m64).
- Repeating this option adds multiple flags to the command line.
-
-For example, if this is x.c:
-
- #include <sys/stat.h>
-
- typedef struct timespec $Timespec;
- enum {
- $S_IFMT = S_IFMT,
- $S_IFIFO = S_IFIFO,
- $S_IFCHR = S_IFCHR,
- };
-
-then "godefs x.c" generates:
-
- // godefs x.c
- // MACHINE GENERATED - DO NOT EDIT.
-
- // Constants
- enum {
- S_IFMT = 0xf000,
- S_IFIFO = 0x1000,
- S_IFCHR = 0x2000,
- };
-
- // Types
- #pragma pack on
-
- typedef struct Timespec Timespec;
- struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
- };
- #pragma pack off
-
-and "godefs -g MyPackage x.c" generates:
-
- // godefs -g MyPackage x.c
- // MACHINE GENERATED - DO NOT EDIT.
-
- package MyPackage
-
- // Constants
- const (
- S_IFMT = 0xf000;
- S_IFIFO = 0x1000;
- S_IFCHR = 0x2000;
- )
-
- // Types
-
- type Timespec struct {
- Sec int64;
- Nsec int64;
- }
-
-*/
-package documentation
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
deleted file mode 100644
index 6a8630179..000000000
--- a/src/cmd/godefs/main.c
+++ /dev/null
@@ -1,606 +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.
-
-// Godefs takes as input a host-compilable C file that includes
-// standard system headers. From that input file, it generates
-// a standalone (no #includes) C or Go file containing equivalent
-// definitions.
-//
-// The input C file is expected to define new types and enumerated
-// constants whose names begin with $ (a legal identifier character
-// in gcc). The output is the standalone definitions of those names,
-// with the $ removed.
-//
-// For example, if this is x.c:
-//
-// #include <sys/stat.h>
-//
-// typedef struct timespec $Timespec;
-// typedef struct stat $Stat;
-// enum {
-// $S_IFMT = S_IFMT,
-// $S_IFIFO = S_IFIFO,
-// $S_IFCHR = S_IFCHR,
-// };
-//
-// then "godefs x.c" generates:
-//
-// // godefs x.c
-//
-// // MACHINE GENERATED - DO NOT EDIT.
-//
-// // Constants
-// enum {
-// S_IFMT = 0xf000,
-// S_IFIFO = 0x1000,
-// S_IFCHR = 0x2000,
-// };
-//
-// // Types
-// #pragma pack on
-//
-// typedef struct Timespec Timespec;
-// struct Timespec {
-// int32 tv_sec;
-// int32 tv_nsec;
-// };
-//
-// typedef struct Stat Stat;
-// struct Stat {
-// int32 st_dev;
-// uint32 st_ino;
-// uint16 st_mode;
-// uint16 st_nlink;
-// uint32 st_uid;
-// uint32 st_gid;
-// int32 st_rdev;
-// Timespec st_atimespec;
-// Timespec st_mtimespec;
-// Timespec st_ctimespec;
-// int64 st_size;
-// int64 st_blocks;
-// int32 st_blksize;
-// uint32 st_flags;
-// uint32 st_gen;
-// int32 st_lspare;
-// int64 st_qspare[2];
-// };
-// #pragma pack off
-//
-// The -g flag to godefs causes it to generate Go output, not C.
-// In the Go output, struct fields have leading xx_ prefixes removed
-// and the first character capitalized (exported).
-//
-// Godefs works by invoking gcc to compile the given input file
-// and then parses the debug info embedded in the assembly output.
-// This is far easier than reading system headers on most machines.
-//
-// The -c flag sets the compiler (default "gcc").
-//
-// The -f flag adds a flag to pass to the compiler (e.g., -f -m64).
-
-#include "a.h"
-
-#ifdef _WIN32
-int
-spawn(char *prog, char **argv)
-{
- return _spawnvp(P_NOWAIT, prog, (const char**)argv);
-}
-#undef waitfor
-void
-waitfor(int pid)
-{
- _cwait(0, pid, 0);
-}
-#else
-int
-spawn(char *prog, char **argv)
-{
- int pid = fork();
- if(pid < 0)
- sysfatal("fork: %r");
- if(pid == 0) {
- exec(argv[0], argv);
- fprint(2, "exec gcc: %r\n");
- exit(1);
- }
- return pid;
-}
-#endif
-
-void
-usage(void)
-{
- fprint(2, "usage: godefs [-g package] [-c cc] [-f cc-arg] [defs.c ...]\n");
- exit(1);
-}
-
-int gotypefmt(Fmt*);
-int ctypefmt(Fmt*);
-int prefixlen(Type*);
-int cutprefix(char*);
-
-Lang go =
-{
- "const (\n",
- "\t%s = %#llx;\n",
- ")\n",
-
- "type",
- "\n",
-
- "type %s struct {\n",
- "type %s struct {\n",
- "\tPad_godefs_%d [%d]byte;\n",
- "}\n",
-
- gotypefmt,
-};
-
-Lang c =
-{
- "enum {\n",
- "\t%s = %#llx,\n",
- "};\n",
-
- "typedef",
- ";\n",
-
- "typedef struct %s %s;\nstruct %s {\n",
- "typedef union %s %s;\nunion %s {\n",
- "\tbyte pad_godefs_%d[%d];\n",
- "};\n",
-
- ctypefmt,
-};
-
-char *pkg;
-
-int oargc;
-char **oargv;
-Lang *lang = &c;
-
-Const *con;
-int ncon;
-
-Type **typ;
-int ntyp;
-
-void
-waitforgcc(void)
-{
- waitpid();
-}
-
-void
-main(int argc, char **argv)
-{
- int p[2], pid, i, j, n, off, npad, prefix;
- char **av, *q, *r, *tofree, *name;
- char nambuf[100];
- Biobuf *bin, *bout;
- Type *t, *tt;
- Field *f;
- int orig_output_fd;
-
- quotefmtinstall();
-
- oargc = argc;
- oargv = argv;
- av = emalloc((30+argc)*sizeof av[0]);
- atexit(waitforgcc);
-
- n = 0;
- av[n++] = "gcc";
- av[n++] = "-fdollars-in-identifiers";
- av[n++] = "-S"; // write assembly
- av[n++] = "-gstabs+"; // include stabs info
- av[n++] = "-o"; // to ...
- av[n++] = "-"; // ... stdout
- av[n++] = "-xc"; // read C
-
- ARGBEGIN{
- case 'g':
- lang = &go;
- pkg = EARGF(usage());
- break;
- case 'c':
- av[0] = EARGF(usage());
- break;
- case 'f':
- av[n++] = EARGF(usage());
- break;
- default:
- usage();
- }ARGEND
-
- if(argc == 0)
- av[n++] = "-";
- else
- av[n++] = argv[0];
- av[n] = nil;
-
- orig_output_fd = dup(1, -1);
- for(i=0; i==0 || i < argc; i++) {
- // Some versions of gcc do not accept -S with multiple files.
- // Run gcc once for each file.
- // Write assembly and stabs debugging to p[1].
- if(pipe(p) < 0)
- sysfatal("pipe: %r");
- dup(p[1], 1);
- close(p[1]);
- if (argc)
- av[n-1] = argv[i];
- pid = spawn(av[0], av);
- dup(orig_output_fd, 1);
-
- // Read assembly, pulling out .stabs lines.
- bin = Bfdopen(p[0], OREAD);
- while((q = Brdstr(bin, '\n', 1)) != nil) {
- // .stabs "float:t(0,12)=r(0,1);4;0;",128,0,0,0
- tofree = q;
- while(*q == ' ' || *q == '\t')
- q++;
- if(strncmp(q, ".stabs", 6) != 0)
- goto Continue;
- q += 6;
- while(*q == ' ' || *q == '\t')
- q++;
- if(*q++ != '\"') {
-Bad:
- sysfatal("cannot parse .stabs line:\n%s", tofree);
- }
-
- r = strchr(q, '\"');
- if(r == nil)
- goto Bad;
- *r++ = '\0';
- if(*r++ != ',')
- goto Bad;
- if(*r < '0' || *r > '9')
- goto Bad;
- if(atoi(r) != 128) // stabs kind = local symbol
- goto Continue;
-
- parsestabtype(q);
-
-Continue:
- free(tofree);
- }
- Bterm(bin);
- waitfor(pid);
- }
- close(orig_output_fd);
-
- // Write defs to standard output.
- bout = Bfdopen(1, OWRITE);
- fmtinstall('T', lang->typefmt);
-
- // Echo original command line in header.
- Bprint(bout, "//");
- for(i=0; i<oargc; i++)
- Bprint(bout, " %q", oargv[i]);
- Bprint(bout, "\n");
- Bprint(bout, "\n");
- Bprint(bout, "// MACHINE GENERATED - DO NOT EDIT.\n");
- Bprint(bout, "\n");
-
- if(pkg)
- Bprint(bout, "package %s\n\n", pkg);
-
- // Constants.
- Bprint(bout, "// Constants\n");
- if(ncon > 0) {
- Bprint(bout, lang->constbegin);
- for(i=0; i<ncon; i++) {
- // Go can handle negative constants,
- // but C enums may not be able to.
- if(lang == &go)
- Bprint(bout, lang->constfmt, con[i].name, con[i].value);
- else
- Bprint(bout, lang->constfmt, con[i].name, con[i].value & 0xFFFFFFFF);
- }
- Bprint(bout, lang->constend);
- }
- Bprint(bout, "\n");
-
- // Types
-
- // push our names down
- for(i=0; i<ntyp; i++) {
- t = typ[i];
- name = t->name;
- while(t && t->kind == Typedef)
- t = t->type;
- if(t)
- t->name = name;
- }
-
- Bprint(bout, "// Types\n");
-
- // Have to turn off structure padding in Plan 9 compiler,
- // mainly because it is more aggressive than gcc tends to be.
- if(lang == &c)
- Bprint(bout, "#pragma pack on\n");
-
- for(i=0; i<ntyp; i++) {
- Bprint(bout, "\n");
- t = typ[i];
- name = t->name;
- while(t && t->kind == Typedef) {
- if(name == nil && t->name != nil) {
- name = t->name;
- if(t->printed)
- break;
- }
- t = t->type;
- }
- if(name == nil && t->name != nil) {
- name = t->name;
- if(t->printed)
- continue;
- t->printed = 1;
- }
- if(name == nil) {
- fprint(2, "unknown name for %T", typ[i]);
- continue;
- }
- if(name[0] == '$')
- name++;
- npad = 0;
- off = 0;
- switch(t->kind) {
- case 0:
- fprint(2, "unknown type definition for %s\n", name);
- break;
- default: // numeric, array, or pointer
- case Array:
- case Ptr:
- Bprint(bout, "%s %lT%s", lang->typdef, name, t, lang->typdefend);
- break;
- case Union:
- // In Go, print union as struct with only first element,
- // padded the rest of the way.
- Bprint(bout, lang->unionbegin, name, name, name);
- goto StructBody;
- case Struct:
- Bprint(bout, lang->structbegin, name, name, name);
- StructBody:
- prefix = 0;
- if(lang == &go)
- prefix = prefixlen(t);
- for(j=0; j<t->nf; j++) {
- f = &t->f[j];
- if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
- // unknown type but <= 64 bits and bit size is a power of two.
- // could be enum - make Uint64 and then let it reduce
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- tt->kind = Uint64;
- while(tt->kind > Uint8 && kindsize[tt->kind] > f->size)
- tt->kind -= 2;
- }
- // padding
- if(t->kind == Struct || lang == &go) {
- if(f->offset%8 != 0 || f->size%8 != 0) {
- fprint(2, "ignoring bitfield %s.%s\n", t->name, f->name);
- continue;
- }
- if(f->offset < off)
- sysfatal("%s: struct fields went backward", t->name);
- if(off < f->offset) {
- Bprint(bout, lang->structpadfmt, npad++, (f->offset - off) / 8);
- off = f->offset;
- }
- off += f->size;
- }
- name = f->name;
- if(cutprefix(name))
- name += prefix;
- if(strcmp(name, "") == 0) {
- snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++);
- name = nambuf;
- }
- Bprint(bout, "\t%#lT;\n", name, f->type);
- if(t->kind == Union && lang == &go)
- break;
- }
- // final padding
- if(t->kind == Struct || lang == &go) {
- if(off/8 < t->size)
- Bprint(bout, lang->structpadfmt, npad++, t->size - off/8);
- }
- Bprint(bout, lang->structend);
- }
- }
- if(lang == &c)
- Bprint(bout, "#pragma pack off\n");
- Bterm(bout);
- exit(0);
-}
-
-char *kindnames[] = {
- "void", // actually unknown, but byte is good for pointers
- "void",
- "int8",
- "uint8",
- "int16",
- "uint16",
- "int32",
- "uint32",
- "int64",
- "uint64",
- "float32",
- "float64",
- "ptr",
- "struct",
- "array",
- "union",
- "typedef",
-};
-
-int
-ctypefmt(Fmt *f)
-{
- char *name, *s;
- Type *t;
-
- name = nil;
- if(f->flags & FmtLong) {
- name = va_arg(f->args, char*);
- if(name == nil || name[0] == '\0')
- name = "_anon_";
- }
- t = va_arg(f->args, Type*);
- while(t && t->kind == Typedef)
- t = t->type;
- switch(t->kind) {
- case Struct:
- case Union:
- // must be named
- s = t->name;
- if(s == nil) {
- fprint(2, "need name for anonymous struct\n");
- goto bad;
- }
- else if(s[0] != '$')
- fprint(2, "need name for struct %s\n", s);
- else
- s++;
- fmtprint(f, "%s", s);
- if(name)
- fmtprint(f, " %s", name);
- break;
-
- case Array:
- if(name)
- fmtprint(f, "%T %s[%d]", t->type, name, t->size);
- else
- fmtprint(f, "%T[%d]", t->type, t->size);
- break;
-
- case Ptr:
- if(name)
- fmtprint(f, "%T *%s", t->type, name);
- else
- fmtprint(f, "%T*", t->type);
- break;
-
- default:
- fmtprint(f, "%s", kindnames[t->kind]);
- if(name)
- fmtprint(f, " %s", name);
- break;
-
- bad:
- if(name)
- fmtprint(f, "byte %s[%d]", name, t->size);
- else
- fmtprint(f, "byte[%d]", t->size);
- break;
- }
-
- return 0;
-}
-
-int
-gotypefmt(Fmt *f)
-{
- char *name, *s;
- Type *t;
-
- if(f->flags & FmtLong) {
- name = va_arg(f->args, char*);
- if('a' <= name[0] && name[0] <= 'z')
- name[0] += 'A' - 'a';
- if(name[0] == '_' && (f->flags & FmtSharp))
- fmtprint(f, "X");
- fmtprint(f, "%s ", name);
- }
- t = va_arg(f->args, Type*);
- while(t && t->kind == Typedef)
- t = t->type;
-
- switch(t->kind) {
- case Struct:
- case Union:
- // must be named
- s = t->name;
- if(s == nil) {
- fprint(2, "need name for anonymous struct\n");
- fmtprint(f, "STRUCT");
- }
- else if(s[0] != '$') {
- fprint(2, "warning: missing name for struct %s\n", s);
- fmtprint(f, "[%d]byte /* %s */", t->size, s);
- } else
- fmtprint(f, "%s", s+1);
- break;
-
- case Array:
- fmtprint(f, "[%d]%T", t->size, t->type);
- break;
-
- case Ptr:
- fmtprint(f, "*%T", t->type);
- break;
-
- default:
- s = kindnames[t->kind];
- if(strcmp(s, "void") == 0)
- s = "byte";
- fmtprint(f, "%s", s);
- }
-
- return 0;
-}
-
-// Is this the kind of name we should cut a prefix from?
-// The rule is that the name cannot begin with underscore
-// and must have an underscore eventually.
-int
-cutprefix(char *name)
-{
- char *p;
-
- // special case: orig_ in register struct
- if(strncmp(name, "orig_", 5) == 0)
- return 0;
-
- for(p=name; *p; p++) {
- if(*p == '_')
- return p-name > 0;
- }
- return 0;
-}
-
-// Figure out common struct prefix len
-int
-prefixlen(Type *t)
-{
- int i;
- int len;
- char *p, *name;
- Field *f;
-
- len = 0;
- name = nil;
- for(i=0; i<t->nf; i++) {
- f = &t->f[i];
- if(!cutprefix(f->name))
- continue;
- p = strchr(f->name, '_');
- if(p == nil)
- return 0;
- if(name == nil) {
- name = f->name;
- len = p+1 - name;
- }
- else if(strncmp(f->name, name, len) != 0)
- return 0;
- }
- return len;
-}
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
deleted file mode 100644
index 2c3d431b8..000000000
--- a/src/cmd/godefs/stabs.c
+++ /dev/null
@@ -1,456 +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.
-
-// Parse stabs debug info.
-
-#include "a.h"
-
-int stabsdebug = 1;
-
-// Hash table for type lookup by number.
-Type *hash[1024];
-
-// Look up type by number pair.
-// TODO(rsc): Iant points out that n1 and n2 are always small and dense,
-// so an array of arrays would be a better representation.
-Type*
-typebynum(uint n1, uint n2)
-{
- uint h;
- Type *t;
-
- h = (n1*53+n2) % nelem(hash);
- for(t=hash[h]; t; t=t->next)
- if(t->n1 == n1 && t->n2 == n2)
- return t;
- t = emalloc(sizeof *t);
- t->next = hash[h];
- hash[h] = t;
- t->n1 = n1;
- t->n2 = n2;
- return t;
-}
-
-// Parse name and colon from *pp, leaving copy in *sp.
-static int
-parsename(char **pp, char **sp)
-{
- char *p;
- char *s;
-
- p = *pp;
- while(*p != '\0' && *p != ':')
- p++;
- if(*p == '\0') {
- fprint(2, "parsename expected colon\n");
- return -1;
- }
- s = emalloc(p - *pp + 1);
- memmove(s, *pp, p - *pp);
- *sp = s;
- *pp = p+1;
- return 0;
-}
-
-// Parse single number from *pp.
-static int
-parsenum1(char **pp, vlong *np)
-{
- char *p;
-
- p = *pp;
- if(*p != '-' && (*p < '0' || *p > '9')) {
- fprint(2, "parsenum expected minus or digit\n");
- return -1;
- }
- *np = strtoll(p, pp, 10);
- return 0;
-}
-
-// Parse type number - either single number or (n1, n2).
-static int
-parsetypenum(char **pp, vlong *n1p, vlong *n2p)
-{
- char *p;
-
- p = *pp;
- if(*p == '(') {
- p++;
- if(parsenum1(&p, n1p) < 0)
- return -1;
- if(*p++ != ',') {
- if(stabsdebug)
- fprint(2, "parsetypenum expected comma\n");
- return -1;
- }
- if(parsenum1(&p, n2p) < 0)
- return -1;
- if(*p++ != ')') {
- if(stabsdebug)
- fprint(2, "parsetypenum expected right paren\n");
- return -1;
- }
- *pp = p;
- return 0;
- }
-
- if(parsenum1(&p, n1p) < 0)
- return -1;
- *n2p = 0;
- *pp = p;
- return 0;
-}
-
-// Written to parse max/min of vlong correctly.
-static vlong
-parseoctal(char **pp)
-{
- char *p;
- vlong n;
-
- p = *pp;
- if(*p++ != '0')
- return 0;
- n = 0;
- while(*p >= '0' && *p <= '9')
- n = n << 3 | *p++ - '0';
- *pp = p;
- return n;
-}
-
-// Integer types are represented in stabs as a "range"
-// type with a lo and a hi value. The lo and hi used to
-// be lo and hi for the type, but there are now odd
-// extensions for floating point and 64-bit numbers.
-//
-// Have to keep signs separate from values because
-// Int64's lo is -0.
-typedef struct Intrange Intrange;
-struct Intrange
-{
- vlong lo;
- vlong hi;
- int kind;
-};
-
-Intrange intranges[] = {
- 0, 127, Int8, // char
- -128, 127, Int8, // signed char
- 0, 255, Uint8,
- -32768, 32767, Int16,
- 0, 65535, Uint16,
- -2147483648LL, 2147483647LL, Int32,
- 0, 4294967295LL, Uint32,
- 1LL << 63, ~(1LL << 63), Int64,
- 0, -1, Uint64,
- 4, 0, Float32,
- 8, 0, Float64,
- 16, 0, Void,
-};
-
-int kindsize[] = {
- 0,
- 0,
- 8,
- 8,
- 16,
- 16,
- 32,
- 32,
- 64,
- 64,
-};
-
-// Parse a single type definition from *pp.
-static Type*
-parsedef(char **pp, char *name)
-{
- char *p;
- Type *t, *tt;
- int i;
- vlong n1, n2, lo, hi;
- Field *f;
- Intrange *r;
-
- p = *pp;
-
- // reference to another type?
- if(isdigit(*p) || *p == '(') {
- if(parsetypenum(&p, &n1, &n2) < 0)
- return nil;
- t = typebynum(n1, n2);
- if(name && t->name == nil) {
- t->name = name;
- // save definitions of names beginning with $
- if(name[0] == '$' && !t->saved) {
- typ = erealloc(typ, (ntyp+1)*sizeof typ[0]);
- typ[ntyp] = t;
- ntyp++;
- }
- }
-
- // is there an =def suffix?
- if(*p == '=') {
- p++;
- tt = parsedef(&p, name);
- if(tt == nil)
- return nil;
-
- if(tt == t) {
- tt->kind = Void;
- } else {
- t->type = tt;
- t->kind = Typedef;
- }
-
- // assign given name, but do not record in typ.
- // assume the name came from a typedef
- // which will be recorded.
- if(name)
- tt->name = name;
- }
-
- *pp = p;
- return t;
- }
-
- // otherwise a type literal. first letter identifies kind
- t = emalloc(sizeof *t);
- switch(*p) {
- default:
- fprint(2, "unknown type char %c in %s\n", *p, p);
- *pp = "";
- return t;
-
- case '@': // type attribute
- while (*++p != ';');
- *pp = ++p;
- return parsedef(pp, nil);
-
- case '*': // pointer
- p++;
- t->kind = Ptr;
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->type = tt;
- break;
-
- case 'a': // array
- p++;
- t->kind = Array;
- // index type
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->size = tt->size;
- // element type
- tt = parsedef(&p, nil);
- if(tt == nil)
- return nil;
- t->type = tt;
- break;
-
- case 'e': // enum type - record $names in con array.
- p++;
- for(;;) {
- if(*p == '\0')
- return nil;
- if(*p == ';') {
- p++;
- break;
- }
- if(parsename(&p, &name) < 0)
- return nil;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- if(name[0] == '$') {
- con = erealloc(con, (ncon+1)*sizeof con[0]);
- name++;
- con[ncon].name = name;
- con[ncon].value = n1;
- ncon++;
- }
- if(*p != ',')
- return nil;
- p++;
- }
- break;
-
- case 'f': // function
- p++;
- if(parsedef(&p, nil) == nil)
- return nil;
- break;
-
- case 'B': // volatile
- case 'k': // const
- ++*pp;
- return parsedef(pp, nil);
-
- case 'r': // sub-range (used for integers)
- p++;
- if(parsedef(&p, nil) == nil)
- return nil;
- // usually, the return from parsedef == t, but not always.
-
- if(*p != ';' || *++p == ';') {
- if(stabsdebug)
- fprint(2, "range expected number: %s\n", p);
- return nil;
- }
- if(*p == '0')
- lo = parseoctal(&p);
- else
- lo = strtoll(p, &p, 10);
- if(*p != ';' || *++p == ';') {
- if(stabsdebug)
- fprint(2, "range expected number: %s\n", p);
- return nil;
- }
- if(*p == '0')
- hi = parseoctal(&p);
- else
- hi = strtoll(p, &p, 10);
- if(*p != ';') {
- if(stabsdebug)
- fprint(2, "range expected trailing semi: %s\n", p);
- return nil;
- }
- p++;
- t->size = hi+1; // might be array size
- for(i=0; i<nelem(intranges); i++) {
- r = &intranges[i];
- if(r->lo == lo && r->hi == hi) {
- t->kind = r->kind;
- break;
- }
- }
- break;
-
- case 's': // struct
- case 'u': // union
- t->kind = Struct;
- if(*p == 'u')
- t->kind = Union;
-
- // assign given name, but do not record in typ.
- // assume the name came from a typedef
- // which will be recorded.
- if(name)
- t->name = name;
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- t->size = n1;
- for(;;) {
- if(*p == '\0')
- return nil;
- if(*p == ';') {
- p++;
- break;
- }
- t->f = erealloc(t->f, (t->nf+1)*sizeof t->f[0]);
- f = &t->f[t->nf];
- if(parsename(&p, &f->name) < 0)
- return nil;
- f->type = parsedef(&p, nil);
- if(f->type == nil)
- return nil;
- if(*p != ',') {
- fprint(2, "expected comma after def of %s:\n%s\n", f->name, p);
- return nil;
- }
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- f->offset = n1;
- if(*p != ',') {
- fprint(2, "expected comma after offset of %s:\n%s\n", f->name, p);
- return nil;
- }
- p++;
- if(parsenum1(&p, &n1) < 0)
- return nil;
- f->size = n1;
- if(*p != ';') {
- fprint(2, "expected semi after size of %s:\n%s\n", f->name, p);
- return nil;
- }
-
- while(f->type->kind == Typedef)
- f->type = f->type->type;
-
- // rewrite
- // uint32 x : 8;
- // into
- // uint8 x;
- // hooray for bitfields.
- while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- f->type->kind -= 2;
- }
- p++;
- t->nf++;
- }
- break;
-
- case 'x':
- // reference to struct, union not yet defined.
- p++;
- switch(*p) {
- case 's':
- t->kind = Struct;
- break;
- case 'u':
- t->kind = Union;
- break;
- default:
- fprint(2, "unknown x type char x%c", *p);
- *pp = "";
- return t;
- }
- if(parsename(&p, &t->name) < 0)
- return nil;
- break;
- }
- *pp = p;
- return t;
-}
-
-
-// Parse a stab type in p, saving info in the type hash table
-// and also in the list of recorded types if appropriate.
-void
-parsestabtype(char *p)
-{
- char *p0, *name;
-
- p0 = p;
-
- // p is the quoted string output from gcc -gstabs on a .stabs line.
- // name:t(1,2)
- // name:t(1,2)=def
- if(parsename(&p, &name) < 0) {
- Bad:
- // Use fprint instead of sysfatal to avoid
- // sysfatal's internal buffer size limit.
- fprint(2, "cannot parse stabs type:\n%s\n(at %s)\n", p0, p);
- sysfatal("stabs parse");
- }
- if(*p != 't' && *p != 'T')
- goto Bad;
- p++;
-
- // parse the definition.
- if(name[0] == '\0')
- name = nil;
- if(parsedef(&p, name) == nil)
- goto Bad;
- if(*p != '\0')
- goto Bad;
-}
-
diff --git a/src/cmd/godefs/test.sh b/src/cmd/godefs/test.sh
deleted file mode 100755
index c035af8f4..000000000
--- a/src/cmd/godefs/test.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2011 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-
-TMP="testdata_tmp.go"
-TEST="testdata.c"
-GOLDEN="testdata_${GOOS}_${GOARCH}.golden"
-
-case ${GOARCH} in
-"amd64") CCARG="-f-m64";;
-"386") CCARG="-f-m32";;
-*) CCARG="";;
-esac
-
-cleanup() {
- rm ${TMP}
-}
-
-error() {
- cleanup
- echo $1
- exit 1
-}
-
-if [ ! -e ${GOLDEN} ]; then
- echo "skipping - no golden defined for this platform"
- exit
-fi
-
-./godefs -g test ${CCARG} ${TEST} > ${TMP}
-if [ $? != 0 ]; then
- error "Error: Could not run godefs for ${TEST}"
-fi
-
-diff ${TMP} ${GOLDEN}
-if [ $? != 0 ]; then
- error "FAIL: godefs for ${TEST} did not match ${GOLDEN}"
-fi
-
-cleanup
-
-echo "PASS"
diff --git a/src/cmd/godefs/testdata.c b/src/cmd/godefs/testdata.c
deleted file mode 100644
index 3f459c41b..000000000
--- a/src/cmd/godefs/testdata.c
+++ /dev/null
@@ -1,41 +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.
-
-#include <stdint.h>
-
-// Issue 432 - enum fields in struct can cause misaligned struct fields
-typedef enum {
- a
-} T1;
-
-struct T2 {
- uint8_t a;
- T1 b;
- T1 c;
- uint16_t d;
-};
-
-typedef struct T2 T2;
-typedef T2 $T2;
-
-// Issue 1162 - structs with fields named Pad[0-9]+ conflict with field
-// names used by godefs for padding
-struct T3 {
- uint8_t a;
- int Pad0;
-};
-
-typedef struct T3 $T3;
-
-// Issue 1466 - forward references to types in stabs debug info were
-// always treated as enums
-struct T4 {};
-
-struct T5 {
- struct T4 *a;
-};
-
-typedef struct T5 T5;
-typedef struct T4 $T4;
-typedef T5 $T5; \ No newline at end of file
diff --git a/src/cmd/godefs/testdata_darwin_386.golden b/src/cmd/godefs/testdata_darwin_386.golden
deleted file mode 100644
index d929238b0..000000000
--- a/src/cmd/godefs/testdata_darwin_386.golden
+++ /dev/null
@@ -1,31 +0,0 @@
-// ./godefs -g test -f-m32 testdata.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package test
-
-// Constants
-
-// Types
-
-type T2 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- B uint32;
- C uint32;
- D uint16;
- Pad_godefs_1 [2]byte;
-}
-
-type T3 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- Pad0 int32;
-}
-
-type T4 struct {
-}
-
-type T5 struct {
- A *T4;
-}
diff --git a/src/cmd/godefs/testdata_darwin_amd64.golden b/src/cmd/godefs/testdata_darwin_amd64.golden
deleted file mode 100644
index a694f4a73..000000000
--- a/src/cmd/godefs/testdata_darwin_amd64.golden
+++ /dev/null
@@ -1,31 +0,0 @@
-// ./godefs -g test -f-m64 testdata.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package test
-
-// Constants
-
-// Types
-
-type T2 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- B uint32;
- C uint32;
- D uint16;
- Pad_godefs_1 [2]byte;
-}
-
-type T3 struct {
- A uint8;
- Pad_godefs_0 [3]byte;
- Pad0 int32;
-}
-
-type T4 struct {
-}
-
-type T5 struct {
- A *T4;
-}
diff --git a/src/cmd/godefs/util.c b/src/cmd/godefs/util.c
deleted file mode 100644
index 18be00453..000000000
--- a/src/cmd/godefs/util.c
+++ /dev/null
@@ -1,36 +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.
-
-#include "a.h"
-
-void*
-emalloc(int n)
-{
- void *p;
-
- p = malloc(n);
- if(p == nil)
- sysfatal("out of memory");
- memset(p, 0, n);
- return p;
-}
-
-char*
-estrdup(char *s)
-{
- s = strdup(s);
- if(s == nil)
- sysfatal("out of memory");
- return s;
-}
-
-void*
-erealloc(void *v, int n)
-{
- v = realloc(v, n);
- if(v == nil)
- sysfatal("out of memory");
- return v;
-}
-
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
deleted file mode 100644
index f40d71703..000000000
--- a/src/cmd/godoc/Makefile
+++ /dev/null
@@ -1,24 +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.
-
-include ../../Make.inc
-
-TARG=godoc
-GOFILES=\
- codewalk.go\
- dirtrees.go\
- filesystem.go\
- format.go\
- godoc.go\
- httpzip.go\
- index.go\
- main.go\
- mapping.go\
- parser.go\
- snippet.go\
- spec.go\
- utils.go\
- zip.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/godoc/README.godoc-app b/src/cmd/godoc/README.godoc-app
new file mode 100644
index 000000000..88cfee41e
--- /dev/null
+++ b/src/cmd/godoc/README.godoc-app
@@ -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.
+
+godoc on appengine
+------------------
+
+Prerequisites
+-------------
+
+* Go appengine SDK 1.5.5 - 2011-10-11
+ http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Go
+
+* Go sources at tip under $GOROOT
+
+
+Directory structure
+-------------------
+
+* Let $APPDIR be the directory containing the app engine files.
+ (e.g., $APPDIR=$HOME/godoc-app)
+
+* $APPDIR contains the following entries (this may change depending on
+ app-engine release and version of godoc):
+
+ alt/
+ encoding/binary/
+ go/*
+ index/suffixarray/
+ app.yaml
+ godoc.zip
+ godoc/
+ index.split.*
+
+* The app.yaml file is set up per app engine documentation.
+ For instance:
+
+ application: godoc-app
+ version: 1-5-5
+ runtime: go
+ api_version: 3
+
+ handlers:
+ - url: /.*
+ script: _go_app
+
+* The godoc/ directory contains a copy of the files under $GOROOT/src/cmd/godoc
+ with modifications:
+
+ - doc.go is excluded (it belongs to pseudo-package documentation)
+ - main.go is excluded (appinit.go is taking its place)
+
+ Additional manual modifications are required to refer to the alt/ packages
+ where the app-engine library is not up-to-date with the godoc version.
+
+* The alt/ directory contains up-to-date copies of Go packages that a tip-based
+ godoc is dependent on but which do not yet exist in the current app-engine SDK.
+ At the time of this writing (10/14/2011) this is the entire go directory tree
+ (for the missing FileSet serialization code in go/token) as well as the
+ index/suffixarray package (for the missing suffix array serialization code).
+ The latest (alt/)index/suffixarray package internally requires the latest
+ version of encoding/binary, which is why it also needs to be present under
+ alt/.
+
+
+Configuring and running godoc
+-----------------------------
+
+To configure godoc, run
+
+ bash setup-godoc-app.bash
+
+to create the godoc.zip, index.split.*, and godoc/appconfig.go files
+based on $GOROOT and $APPDIR. See the script for details on usage.
+
+To run godoc locally, using the app-engine emulator, run
+
+ <path to google_appengine>/dev_appserver.py $APPDIR
+
+godoc should come up at http://localhost:8080 .
diff --git a/src/cmd/godoc/appconfig.go b/src/cmd/godoc/appconfig.go
deleted file mode 100644
index 9cbe7a443..000000000
--- a/src/cmd/godoc/appconfig.go
+++ /dev/null
@@ -1,19 +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.
-
-// This file contains configuration information used by
-// godoc when running on app engine. Adjust as needed
-// (typically when the .zip file changes).
-
-package main
-
-const (
- // zipFilename is the name of the .zip file
- // containing the file system served by godoc.
- zipFilename = "go.zip"
-
- // zipGoroot is the path of the goroot directory
- // in the .zip file.
- zipGoroot = "/home/username/go"
-)
diff --git a/src/cmd/godoc/appinit.go b/src/cmd/godoc/appinit.go
index 9b8987223..70da00110 100644
--- a/src/cmd/godoc/appinit.go
+++ b/src/cmd/godoc/appinit.go
@@ -2,58 +2,38 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// To run godoc under app engine, substitute main.go with
-// this file (appinit.go), provide a .zip file containing
-// the file system to serve, and adjust the configuration
-// parameters in appconfig.go accordingly.
-//
-// The current app engine SDK may be based on an older Go
-// release version. To correct for version skew, copy newer
-// packages into the alt directory (e.g. alt/strings) and
-// adjust the imports in the godoc source files (e.g. from
-// `import "strings"` to `import "alt/strings"`). Both old
-// and new packages may be used simultaneously as long as
-// there is no package global state that needs to be shared.
-//
-// The directory structure should look as follows:
-//
-// godoc // directory containing the app engine app
-// alt // alternative packages directory to
-// // correct for version skew
-// strings // never version of the strings package
-// ... //
-// app.yaml // app engine control file
-// go.zip // zip file containing the file system to serve
-// godoc // contains godoc sources
-// appinit.go // this file instead of godoc/main.go
-// appconfig.go // godoc for app engine configuration
-// ... //
-//
-// To run app the engine emulator locally:
-//
-// dev_appserver.py -a 0 godoc
-//
-// godoc is the top-level "goroot" directory.
-// The godoc home page is served at: <hostname>:8080 and localhost:8080.
+// +build appengine
package main
+// This file replaces main.go when running godoc under app-engine.
+// See README.godoc-app for details.
+
import (
- "alt/archive/zip"
- "http"
+ "archive/zip"
"log"
- "os"
+ "net/http"
+ "path"
)
-func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
w.WriteHeader(http.StatusNotFound)
- servePage(w, "File "+relpath, "", "", contents)
+ servePage(w, relpath, "File "+relpath, "", "", contents)
}
func init() {
log.Println("initializing godoc ...")
+ log.Printf(".zip file = %s", zipFilename)
+ log.Printf(".zip GOROOT = %s", zipGoroot)
+ log.Printf("index files = %s", indexFilenames)
+
+ // initialize flags for app engine
*goroot = path.Join("/", zipGoroot) // fsHttp paths are relative to '/'
+ *indexEnabled = true
+ *indexFiles = indexFilenames
+ *maxResults = 100 // reduce latency by limiting the number of fulltext search results
+ *indexThrottle = 0.3 // in case *indexFiles is empty (and thus the indexer is run)
// read .zip file and set up file systems
const zipfile = zipFilename
@@ -61,26 +41,24 @@ func init() {
if err != nil {
log.Fatalf("%s: %s\n", zipfile, err)
}
- fs = NewZipFS(rc)
- fsHttp = NewHttpZipFS(rc, *goroot)
+ // rc is never closed (app running forever)
+ fs.Bind("/", NewZipFS(rc, zipFilename), *goroot, bindReplace)
// initialize http handlers
- initHandlers()
readTemplates()
+ initHandlers()
registerPublicHandlers(http.DefaultServeMux)
// initialize default directory tree with corresponding timestamp.
initFSTree()
- // initialize directory trees for user-defined file systems (-path flag).
- initDirTrees()
+ // Immediately update metadata.
+ updateMetadata()
- // create search index
- // TODO(gri) Disabled for now as it takes too long. Find a solution for this.
- /*
- *indexEnabled = true
+ // initialize search index
+ if *indexEnabled {
go indexer()
- */
+ }
log.Println("godoc initialization complete")
}
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index e2643e466..f7f51d0a0 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -13,25 +13,25 @@
package main
import (
- "container/vector"
+ "encoding/xml"
+ "errors"
"fmt"
- "http"
"io"
"log"
+ "net/http"
"os"
"regexp"
"sort"
"strconv"
"strings"
- "template"
- "utf8"
- "xml"
+ "text/template"
+ "unicode/utf8"
)
// Handler for /doc/codewalk/ and below.
func codewalk(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[len("/doc/codewalk/"):]
- abspath := absolutePath(r.URL.Path[1:], *goroot)
+ abspath := r.URL.Path
r.ParseForm()
if f := r.FormValue("fileprint"); f != "" {
@@ -41,7 +41,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
// If directory exists, serve list of code walks.
dir, err := fs.Lstat(abspath)
- if err == nil && dir.IsDirectory() {
+ if err == nil && dir.IsDir() {
codewalkDir(w, r, relpath, abspath)
return
}
@@ -53,7 +53,9 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
}
// Otherwise append .xml and hope to find
- // a codewalk description.
+ // a codewalk description, but before trim
+ // the trailing /.
+ abspath = strings.TrimRight(abspath, "/")
cw, err := loadCodewalk(abspath + ".xml")
if err != nil {
log.Print(err)
@@ -67,25 +69,25 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
}
b := applyTemplate(codewalkHTML, "codewalk", cw)
- servePage(w, "Codewalk: "+cw.Title, "", "", b)
+ servePage(w, cw.Title, "Codewalk: "+cw.Title, "", "", b)
}
// A Codewalk represents a single codewalk read from an XML file.
type Codewalk struct {
- Title string `xml:"attr"`
- File []string
- Step []*Codestep
+ Title string `xml:"title,attr"`
+ File []string `xml:"file"`
+ Step []*Codestep `xml:"step"`
}
// A Codestep is a single step in a codewalk.
type Codestep struct {
// Filled in from XML
- Src string `xml:"attr"`
- Title string `xml:"attr"`
- XML string `xml:"innerxml"`
+ Src string `xml:"src,attr"`
+ Title string `xml:"title,attr"`
+ XML string `xml:",innerxml"`
// Derived from Src; not in XML.
- Err os.Error
+ Err error
File string
Lo int
LoByte int
@@ -108,18 +110,18 @@ func (st *Codestep) String() string {
}
// loadCodewalk reads a codewalk from the named XML file.
-func loadCodewalk(filename string) (*Codewalk, os.Error) {
+func loadCodewalk(filename string) (*Codewalk, error) {
f, err := fs.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
cw := new(Codewalk)
- p := xml.NewParser(f)
- p.Entity = xml.HTMLEntity
- err = p.Unmarshal(cw, nil)
+ d := xml.NewDecoder(f)
+ d.Entity = xml.HTMLEntity
+ err = d.Decode(cw)
if err != nil {
- return nil, &os.PathError{"parsing", filename, err}
+ return nil, &os.PathError{Op: "parsing", Path: filename, Err: err}
}
// Compute file list, evaluate line numbers for addresses.
@@ -130,7 +132,7 @@ func loadCodewalk(filename string) (*Codewalk, os.Error) {
i = len(st.Src)
}
filename := st.Src[0:i]
- data, err := fs.ReadFile(absolutePath(filename, *goroot))
+ data, err := ReadFile(fs, filename)
if err != nil {
st.Err = err
continue
@@ -183,22 +185,22 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
serveError(w, r, relpath, err)
return
}
- var v vector.Vector
+ var v []interface{}
for _, fi := range dir {
name := fi.Name()
- if fi.IsDirectory() {
- v.Push(&elem{name + "/", ""})
+ if fi.IsDir() {
+ v = append(v, &elem{name + "/", ""})
} else if strings.HasSuffix(name, ".xml") {
cw, err := loadCodewalk(abspath + "/" + name)
if err != nil {
continue
}
- v.Push(&elem{name[0 : len(name)-len(".xml")], cw.Title})
+ v = append(v, &elem{name[0 : len(name)-len(".xml")], cw.Title})
}
}
b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
- servePage(w, "Codewalks", "", "", b)
+ servePage(w, "", "Codewalks", "", "", b)
}
// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
@@ -208,8 +210,8 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
// of the codewalk pages. It is a separate iframe and does not get
// the usual godoc HTML wrapper.
func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
- abspath := absolutePath(f, *goroot)
- data, err := fs.ReadFile(abspath)
+ abspath := f
+ data, err := ReadFile(fs, abspath)
if err != nil {
log.Print(err)
serveError(w, r, f, err)
@@ -253,7 +255,7 @@ func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
// It returns the lo and hi byte offset of the matched region within data.
// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
// for details on the syntax.
-func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Error) {
+func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err error) {
var (
dir byte
prevc byte
@@ -265,7 +267,7 @@ func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Er
c := addr[0]
switch c {
default:
- err = os.NewError("invalid address syntax near " + string(c))
+ err = errors.New("invalid address syntax near " + string(c))
case ',':
if len(addr) == 1 {
hi = len(data)
@@ -349,7 +351,7 @@ func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err os.Er
// (or characters) after hi. Applying -n (or -#n) means to back up n lines
// (or characters) before lo.
// The return value is the new lo, hi.
-func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, os.Error) {
+func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, error) {
switch dir {
case 0:
lo = 0
@@ -425,13 +427,13 @@ func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int,
}
}
- return 0, 0, os.NewError("address out of range")
+ return 0, 0, errors.New("address out of range")
}
// addrRegexp searches for pattern in the given direction starting at lo, hi.
// The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
// Backward searches are unimplemented.
-func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os.Error) {
+func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, error) {
re, err := regexp.Compile(pattern)
if err != nil {
return 0, 0, err
@@ -439,7 +441,7 @@ func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os
if dir == '-' {
// Could implement reverse search using binary search
// through file, but that seems like overkill.
- return 0, 0, os.NewError("reverse search not implemented")
+ return 0, 0, errors.New("reverse search not implemented")
}
m := re.FindIndex(data[hi:])
if len(m) > 0 {
@@ -450,7 +452,7 @@ func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os
m = re.FindIndex(data)
}
if len(m) == 0 {
- return 0, 0, os.NewError("no match for " + pattern)
+ return 0, 0, errors.New("no match for " + pattern)
}
return m[0], m[1], nil
}
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
index aa590b363..b9b529f87 100644
--- a/src/cmd/godoc/dirtrees.go
+++ b/src/cmd/godoc/dirtrees.go
@@ -12,79 +12,49 @@ import (
"go/parser"
"go/token"
"log"
- "path/filepath"
+ "os"
+ pathpkg "path"
"strings"
- "unicode"
)
+// Conventional name for directories containing test data.
+// Excluded from directory trees.
+//
+const testdataDirName = "testdata"
+
type Directory struct {
- Depth int
- Path string // includes Name
- Name string
- Text string // package documentation, if any
- Dirs []*Directory // subdirectories
+ Depth int
+ Path string // directory path; includes Name
+ Name string // directory name
+ HasPkg bool // true if the directory contains at least one package
+ Synopsis string // package documentation, if any
+ Dirs []*Directory // subdirectories
}
-func isGoFile(fi FileInfo) bool {
+func isGoFile(fi os.FileInfo) bool {
name := fi.Name()
- return fi.IsRegular() &&
+ return !fi.IsDir() &&
len(name) > 0 && name[0] != '.' && // ignore .files
- filepath.Ext(name) == ".go"
+ pathpkg.Ext(name) == ".go"
}
-func isPkgFile(fi FileInfo) bool {
+func isPkgFile(fi os.FileInfo) bool {
return isGoFile(fi) &&
!strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
}
-func isPkgDir(fi FileInfo) bool {
+func isPkgDir(fi os.FileInfo) bool {
name := fi.Name()
- return fi.IsDirectory() && len(name) > 0 &&
+ return fi.IsDir() && len(name) > 0 &&
name[0] != '_' && name[0] != '.' // ignore _files and .files
}
-func firstSentence(s string) string {
- i := -1 // index+1 of first terminator (punctuation ending a sentence)
- j := -1 // index+1 of first terminator followed by white space
- prev := 'A'
- for k, ch := range s {
- k1 := k + 1
- if ch == '.' || ch == '!' || ch == '?' {
- if i < 0 {
- i = k1 // first terminator
- }
- if k1 < len(s) && s[k1] <= ' ' {
- if j < 0 {
- j = k1 // first terminator followed by white space
- }
- if !unicode.IsUpper(prev) {
- j = k1
- break
- }
- }
- }
- prev = ch
- }
-
- if j < 0 {
- // use the next best terminator
- j = i
- if j < 0 {
- // no terminator at all, use the entire string
- j = len(s)
- }
- }
-
- return s[0:j]
-}
-
type treeBuilder struct {
- pathFilter func(string) bool
- maxDepth int
+ maxDepth int
}
func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
- if b.pathFilter != nil && !b.pathFilter(path) {
+ if name == testdataDirName {
return nil
}
@@ -92,16 +62,14 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// return a dummy directory so that the parent directory
// doesn't get discarded just because we reached the max
// directory depth
- return &Directory{depth, path, name, "", nil}
+ return &Directory{
+ Depth: depth,
+ Path: path,
+ Name: name,
+ }
}
- list, err := fs.ReadDir(path)
- if err != nil {
- // newDirTree is called with a path that should be a package
- // directory; errors here should not happen, but if they do,
- // we want to know about them
- log.Printf("ReadDir(%s): %s", path, err)
- }
+ list, _ := fs.ReadDir(path)
// determine number of subdirectories and if there are package files
ndirs := 0
@@ -117,7 +85,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// though the directory doesn't contain any real package files - was bug)
if synopses[0] == "" {
// no "optimal" package synopsis yet; continue to collect synopses
- file, err := parser.ParseFile(fset, filepath.Join(path, d.Name()), nil,
+ file, err := parseFile(fset, pathpkg.Join(path, d.Name()),
parser.ParseComments|parser.PackageClauseOnly)
if err == nil {
hasPkgFiles = true
@@ -135,7 +103,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
i = 3 // none of the above
}
if 0 <= i && i < len(synopses) && synopses[i] == "" {
- synopses[i] = firstSentence(doc.CommentText(file.Doc))
+ synopses[i] = doc.Synopsis(file.Doc.Text())
}
}
}
@@ -151,7 +119,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
for _, d := range list {
if isPkgDir(d) {
name := d.Name()
- dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
+ dd := b.newDirTree(fset, pathpkg.Join(path, name), name, depth+1)
if dd != nil {
dirs[i] = dd
i++
@@ -175,7 +143,14 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
}
}
- return &Directory{depth, path, name, synopsis, dirs}
+ return &Directory{
+ Depth: depth,
+ Path: path,
+ Name: name,
+ HasPkg: hasPkgFiles,
+ Synopsis: synopsis,
+ Dirs: dirs,
+ }
}
// newDirectory creates a new package directory tree with at most maxDepth
@@ -188,7 +163,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// are assumed to contain package files even if their contents are not known
// (i.e., in this case the tree may contain directories w/o any package files).
//
-func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
+func newDirectory(root string, maxDepth int) *Directory {
// The root could be a symbolic link so use Stat not Lstat.
d, err := fs.Stat(root)
// If we fail here, report detailed error messages; otherwise
@@ -204,7 +179,7 @@ func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Dire
if maxDepth < 0 {
maxDepth = 1e6 // "infinity"
}
- b := treeBuilder{pathFilter, maxDepth}
+ b := treeBuilder{maxDepth}
// the file set provided is only for local parsing, no position
// information escapes and thus we don't need to save the set
return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
@@ -253,10 +228,20 @@ func (dir *Directory) lookupLocal(name string) *Directory {
return nil
}
+func splitPath(p string) []string {
+ if strings.HasPrefix(p, "/") {
+ p = p[1:]
+ }
+ if p == "" {
+ return nil
+ }
+ return strings.Split(p, "/")
+}
+
// lookup looks for the *Directory for a given path, relative to dir.
func (dir *Directory) lookup(path string) *Directory {
- d := strings.Split(dir.Path, string(filepath.Separator))
- p := strings.Split(path, string(filepath.Separator))
+ d := splitPath(dir.Path)
+ p := splitPath(path)
i := 0
for i < len(d) {
if i >= len(p) || d[i] != p[i] {
@@ -277,9 +262,10 @@ func (dir *Directory) lookup(path string) *Directory {
type DirEntry struct {
Depth int // >= 0
Height int // = DirList.MaxHeight - Depth, > 0
- Path string // includes Name, relative to DirList root
- Name string
- Synopsis string
+ Path string // directory path; includes Name, relative to DirList root
+ Name string // directory name
+ HasPkg bool // true if the directory contains at least one package
+ Synopsis string // package documentation, if any
}
type DirList struct {
@@ -328,13 +314,14 @@ func (root *Directory) listing(skipRoot bool) *DirList {
if strings.HasPrefix(d.Path, root.Path) {
path = d.Path[len(root.Path):]
}
- // remove trailing separator if any - path must be relative
- if len(path) > 0 && path[0] == filepath.Separator {
+ // remove leading separator if any - path must be relative
+ if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
p.Path = path
p.Name = d.Name
- p.Synopsis = d.Text
+ p.HasPkg = d.HasPkg
+ p.Synopsis = d.Synopsis
i++
}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 088889d2a..39ecc6e63 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -9,12 +9,15 @@ Godoc extracts and generates documentation for Go programs.
It has two modes.
Without the -http flag, it runs in command-line mode and prints plain text
-documentation to standard output and exits. If the -src flag is specified,
-godoc prints the exported interface of a package in Go source form, or the
-implementation of a specific exported language entity:
+documentation to standard output and exits. If both a library package and
+a command with the same name exists, using the prefix cmd/ will force
+documentation on the command rather than the library package. If the -src
+flag is specified, godoc prints the exported interface of a package in Go
+source form, or the implementation of a specific exported language entity:
godoc fmt # documentation for package fmt
godoc fmt Printf # documentation for fmt.Printf
+ godoc cmd/go # force documentation for the go command
godoc -src fmt # fmt package interface in Go source form
godoc -src fmt Printf # implementation of fmt.Printf
@@ -22,7 +25,7 @@ In command-line mode, the -q flag enables search queries against a godoc running
as a webserver. If no explicit server address is specified with the -server flag,
godoc first tries localhost:6060 and then http://golang.org.
- godoc -q Reader Writer
+ godoc -q Reader
godoc -q math.Sin
godoc -server=:6060 -q sin
@@ -50,6 +53,17 @@ The flags are:
-index
enable identifier and full text search index
(no search box is shown if -index is not set)
+ -index_files=""
+ glob pattern specifying index files; if not empty,
+ the index is read from these files in sorted order
+ -index_throttle=0.75
+ index throttle value; a value of 0 means no time is allocated
+ to the indexer (the indexer will never finish), a value of 1.0
+ means that index creation is running at full throttle (other
+ goroutines may get no time while the index is built)
+ -write_index=false
+ write index to a file; the file name must be specified with
+ -index_files
-maxresults=10000
maximum number of full text search results shown
(no full text index is built if maxresults <= 0)
@@ -63,23 +77,22 @@ The flags are:
HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
-server=addr
webserver address for command line searches
- -sync="command"
- if this and -sync_minutes are set, run the argument as a
- command every sync_minutes; it is intended to update the
- repository holding the source files.
- -sync_minutes=0
- sync interval in minutes; sync is disabled if <= 0
- -filter=""
- filter file containing permitted package directory paths
- -filter_minutes=0
- filter file update interval in minutes; update is disabled if <= 0
+ -templates=""
+ directory containing alternate template files; if set,
+ the directory may provide alternative template files
+ for the files in $GOROOT/lib/godoc
+ -url=path
+ print to standard output the data that would be served by
+ an HTTP request for path
-zip=""
zip file providing the file system to serve; disabled if empty
-The -path flag accepts a list of colon-separated paths; unrooted paths are relative
-to the current working directory. Each path is considered as an additional root for
-packages in order of appearance. The last (absolute) path element is the prefix for
-the package path. For instance, given the flag value:
+By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
+Additional directories may be specified via the -path flag which accepts a list
+of colon-separated paths; unrooted paths are relative to the current working
+directory. Each path is considered as an additional root for packages in order
+of appearance. The last (absolute) path element is the prefix for the package
+path. For instance, given the flag value:
path=".:/home/bar:/public"
@@ -90,29 +103,27 @@ as follows:
/home/bar/x -> bar/x
/public/x -> public/x
-Paths provided via -path may point to very large file systems that contain
-non-Go files. Creating the subtree of directories with Go packages may take
-a long amount of time. A file containing newline-separated directory paths
-may be provided with the -filter flag; if it exists, only directories
-on those paths are considered. If -filter_minutes is set, the filter_file is
-updated regularly by walking the entire directory tree.
-
When godoc runs as a web server and -index is set, a search index is maintained.
-The index is created at startup and is automatically updated every time the
--sync command terminates with exit status 0, indicating that files have changed.
-
-If the sync exit status is 1, godoc assumes that it succeeded without errors
-but that no files changed; the index is not updated in this case.
-
-In all other cases, sync is assumed to have failed and godoc backs off running
-sync exponentially (up to 1 day). As soon as sync succeeds again (exit status 0
-or 1), the normal sync rhythm is re-established.
+The index is created at startup.
The index contains both identifier and full text search information (searchable
via regular expressions). The maximum number of full text search results shown
can be set with the -maxresults flag; if set to 0, no full text results are
shown, and only an identifier index but no full text search index is created.
+The presentation mode of web pages served by godoc can be controlled with the
+"m" URL parameter; it accepts a comma-separated list of flag names as value:
+
+ all show documentation for all declarations, not just the exported ones
+ methods show all embedded methods, not just those of unexported anonymous fields
+ src show the original source code rather then the extracted documentation
+ text present the page in textual (command-line) form rather than HTML
+ flat present flat (not indented) directory listings using full paths
+
+For instance, http://golang.org/pkg/math/big/?m=all,text shows the documentation
+for all (not just the exported) declarations of package big, in textual form (as
+it would appear when using godoc from the command line: "godoc -src math/big .*").
+
By default, godoc serves files from the file system of the underlying OS.
Instead, a .zip file may be provided via the -zip flag, which contains
the file system to serve. The file paths stored in the .zip file must use
@@ -126,8 +137,8 @@ one may run godoc as follows:
godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
-
See "Godoc: documenting Go code" for how to write good comments for godoc:
-http://blog.golang.org/2011/03/godoc-documenting-go-code.html
+http://golang.org/doc/articles/godoc_documenting_go_code.html
+
*/
package documentation
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
index a68c08592..09d7b2463 100644
--- a/src/cmd/godoc/filesystem.go
+++ b/src/cmd/godoc/filesystem.go
@@ -12,58 +12,93 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/http"
"os"
+ pathpkg "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
)
-// The FileInfo interface provides access to file information.
-type FileInfo interface {
- Name() string
- Size() int64
- Mtime_ns() int64
- IsRegular() bool
- IsDirectory() bool
-}
+// fs is the file system that godoc reads from and serves.
+// It is a virtual file system that operates on slash-separated paths,
+// and its root corresponds to the Go distribution root: /src/pkg
+// holds the source tree, and so on. This means that the URLs served by
+// the godoc server are the same as the paths in the virtual file
+// system, which helps keep things simple.
+//
+// New file trees - implementations of FileSystem - can be added to
+// the virtual file system using nameSpace's Bind method.
+// The usual setup is to bind OS(runtime.GOROOT) to the root
+// of the name space and then bind any GOPATH/src directories
+// on top of /src/pkg, so that all sources are in /src/pkg.
+//
+// For more about name spaces, see the nameSpace type's
+// documentation below.
+//
+// The use of this virtual file system means that most code processing
+// paths can assume they are slash-separated and should be using
+// package path (often imported as pathpkg) to manipulate them,
+// even on Windows.
+//
+var fs = nameSpace{} // the underlying file system for godoc
+
+// Setting debugNS = true will enable debugging prints about
+// name space translations.
+const debugNS = false
// The FileSystem interface specifies the methods godoc is using
// to access the file system for which it serves documentation.
type FileSystem interface {
- Open(path string) (io.ReadCloser, os.Error)
- Lstat(path string) (FileInfo, os.Error)
- Stat(path string) (FileInfo, os.Error)
- ReadDir(path string) ([]FileInfo, os.Error)
- ReadFile(path string) ([]byte, os.Error)
-}
-
-// ----------------------------------------------------------------------------
-// OS-specific FileSystem implementation
-
-var OS FileSystem = osFS{}
-
-// osFI is the OS-specific implementation of FileInfo.
-type osFI struct {
- *os.FileInfo
+ Open(path string) (readSeekCloser, error)
+ Lstat(path string) (os.FileInfo, error)
+ Stat(path string) (os.FileInfo, error)
+ ReadDir(path string) ([]os.FileInfo, error)
+ String() string
}
-func (fi osFI) Name() string {
- return fi.FileInfo.Name
+type readSeekCloser interface {
+ io.Reader
+ io.Seeker
+ io.Closer
}
-func (fi osFI) Size() int64 {
- if fi.IsDirectory() {
- return 0
+// ReadFile reads the file named by path from fs and returns the contents.
+func ReadFile(fs FileSystem, path string) ([]byte, error) {
+ rc, err := fs.Open(path)
+ if err != nil {
+ return nil, err
}
- return fi.FileInfo.Size
+ defer rc.Close()
+ return ioutil.ReadAll(rc)
}
-func (fi osFI) Mtime_ns() int64 {
- return fi.FileInfo.Mtime_ns
+// OS returns an implementation of FileSystem reading from the
+// tree rooted at root. Recording a root is convenient everywhere
+// but necessary on Windows, because the slash-separated path
+// passed to Open has no way to specify a drive letter. Using a root
+// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
+func OS(root string) FileSystem {
+ return osFS(root)
}
-// osFS is the OS-specific implementation of FileSystem
-type osFS struct{}
+type osFS string
+
+func (root osFS) String() string { return "os(" + string(root) + ")" }
+
+func (root osFS) resolve(path string) string {
+ // Clean the path so that it cannot possibly begin with ../.
+ // If it did, the result of filepath.Join would be outside the
+ // tree rooted at root. We probably won't ever see a path
+ // with .. in it, but be safe anyway.
+ path = pathpkg.Clean("/" + path)
+
+ return filepath.Join(string(root), path)
+}
-func (osFS) Open(path string) (io.ReadCloser, os.Error) {
- f, err := os.Open(path)
+func (root osFS) Open(path string) (readSeekCloser, error) {
+ f, err := os.Open(root.resolve(path))
if err != nil {
return nil, err
}
@@ -71,34 +106,459 @@ func (osFS) Open(path string) (io.ReadCloser, os.Error) {
if err != nil {
return nil, err
}
- if fi.IsDirectory() {
+ if fi.IsDir() {
return nil, fmt.Errorf("Open: %s is a directory", path)
}
return f, nil
}
-func (osFS) Lstat(path string) (FileInfo, os.Error) {
- fi, err := os.Lstat(path)
- return osFI{fi}, err
+func (root osFS) Lstat(path string) (os.FileInfo, error) {
+ return os.Lstat(root.resolve(path))
+}
+
+func (root osFS) Stat(path string) (os.FileInfo, error) {
+ return os.Stat(root.resolve(path))
+}
+
+func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
+ return ioutil.ReadDir(root.resolve(path)) // is sorted
+}
+
+// hasPathPrefix returns true if x == y or x == y + "/" + more
+func hasPathPrefix(x, y string) bool {
+ return x == y || strings.HasPrefix(x, y) && (strings.HasSuffix(y, "/") || strings.HasPrefix(x[len(y):], "/"))
+}
+
+// A nameSpace is a file system made up of other file systems
+// mounted at specific locations in the name space.
+//
+// The representation is a map from mount point locations
+// to the list of file systems mounted at that location. A traditional
+// Unix mount table would use a single file system per mount point,
+// but we want to be able to mount multiple file systems on a single
+// mount point and have the system behave as if the union of those
+// file systems were present at the mount point.
+// For example, if the OS file system has a Go installation in
+// c:\Go and additional Go path trees in d:\Work1 and d:\Work2, then
+// this name space creates the view we want for the godoc server:
+//
+// nameSpace{
+// "/": {
+// {old: "/", fs: OS(`c:\Go`), new: "/"},
+// },
+// "/src/pkg": {
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+// },
+// }
+//
+// This is created by executing:
+//
+// ns := nameSpace{}
+// ns.Bind("/", OS(`c:\Go`), "/", bindReplace)
+// ns.Bind("/src/pkg", OS(`d:\Work1`), "/src", bindAfter)
+// ns.Bind("/src/pkg", OS(`d:\Work2`), "/src", bindAfter)
+//
+// A particular mount point entry is a triple (old, fs, new), meaning that to
+// operate on a path beginning with old, replace that prefix (old) with new
+// and then pass that path to the FileSystem implementation fs.
+//
+// Given this name space, a ReadDir of /src/pkg/code will check each prefix
+// of the path for a mount point (first /src/pkg/code, then /src/pkg, then /src,
+// then /), stopping when it finds one. For the above example, /src/pkg/code
+// will find the mount point at /src/pkg:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// ReadDir will when execute these three calls and merge the results:
+//
+// OS(`c:\Go`).ReadDir("/src/pkg/code")
+// OS(`d:\Work1').ReadDir("/src/code")
+// OS(`d:\Work2').ReadDir("/src/code")
+//
+// Note that the "/src/pkg" in "/src/pkg/code" has been replaced by
+// just "/src" in the final two calls.
+//
+// OS is itself an implementation of a file system: it implements
+// OS(`c:\Go`).ReadDir("/src/pkg/code") as ioutil.ReadDir(`c:\Go\src\pkg\code`).
+//
+// Because the new path is evaluated by fs (here OS(root)), another way
+// to read the mount table is to mentally combine fs+new, so that this table:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// reads as:
+//
+// "/src/pkg" -> c:\Go\src\pkg
+// "/src/pkg" -> d:\Work1\src
+// "/src/pkg" -> d:\Work2\src
+//
+// An invariant (a redundancy) of the name space representation is that
+// ns[mtpt][i].old is always equal to mtpt (in the example, ns["/src/pkg"]'s
+// mount table entries always have old == "/src/pkg"). The 'old' field is
+// useful to callers, because they receive just a []mountedFS and not any
+// other indication of which mount point was found.
+//
+type nameSpace map[string][]mountedFS
+
+// A mountedFS handles requests for path by replacing
+// a prefix 'old' with 'new' and then calling the fs methods.
+type mountedFS struct {
+ old string
+ fs FileSystem
+ new string
+}
+
+// translate translates path for use in m, replacing old with new.
+//
+// mountedFS{"/src/pkg", fs, "/src"}.translate("/src/pkg/code") == "/src/code".
+func (m mountedFS) translate(path string) string {
+ path = pathpkg.Clean("/" + path)
+ if !hasPathPrefix(path, m.old) {
+ panic("translate " + path + " but old=" + m.old)
+ }
+ return pathpkg.Join(m.new, path[len(m.old):])
+}
+
+func (nameSpace) String() string {
+ return "ns"
+}
+
+// Fprint writes a text representation of the name space to w.
+func (ns nameSpace) Fprint(w io.Writer) {
+ fmt.Fprint(w, "name space {\n")
+ var all []string
+ for mtpt := range ns {
+ all = append(all, mtpt)
+ }
+ sort.Strings(all)
+ for _, mtpt := range all {
+ fmt.Fprintf(w, "\t%s:\n", mtpt)
+ for _, m := range ns[mtpt] {
+ fmt.Fprintf(w, "\t\t%s %s\n", m.fs, m.new)
+ }
+ }
+ fmt.Fprint(w, "}\n")
+}
+
+// clean returns a cleaned, rooted path for evaluation.
+// It canonicalizes the path so that we can use string operations
+// to analyze it.
+func (nameSpace) clean(path string) string {
+ return pathpkg.Clean("/" + path)
+}
+
+// Bind causes references to old to redirect to the path new in newfs.
+// If mode is bindReplace, old redirections are discarded.
+// If mode is bindBefore, this redirection takes priority over existing ones,
+// but earlier ones are still consulted for paths that do not exist in newfs.
+// If mode is bindAfter, this redirection happens only after existing ones
+// have been tried and failed.
+
+const (
+ bindReplace = iota
+ bindBefore
+ bindAfter
+)
+
+func (ns nameSpace) Bind(old string, newfs FileSystem, new string, mode int) {
+ old = ns.clean(old)
+ new = ns.clean(new)
+ m := mountedFS{old, newfs, new}
+ var mtpt []mountedFS
+ switch mode {
+ case bindReplace:
+ mtpt = append(mtpt, m)
+ case bindAfter:
+ mtpt = append(mtpt, ns.resolve(old)...)
+ mtpt = append(mtpt, m)
+ case bindBefore:
+ mtpt = append(mtpt, m)
+ mtpt = append(mtpt, ns.resolve(old)...)
+ }
+
+ // Extend m.old, m.new in inherited mount point entries.
+ for i := range mtpt {
+ m := &mtpt[i]
+ if m.old != old {
+ if !hasPathPrefix(old, m.old) {
+ // This should not happen. If it does, panic so
+ // that we can see the call trace that led to it.
+ panic(fmt.Sprintf("invalid Bind: old=%q m={%q, %s, %q}", old, m.old, m.fs.String(), m.new))
+ }
+ suffix := old[len(m.old):]
+ m.old = pathpkg.Join(m.old, suffix)
+ m.new = pathpkg.Join(m.new, suffix)
+ }
+ }
+
+ ns[old] = mtpt
+}
+
+// resolve resolves a path to the list of mountedFS to use for path.
+func (ns nameSpace) resolve(path string) []mountedFS {
+ path = ns.clean(path)
+ for {
+ if m := ns[path]; m != nil {
+ if debugNS {
+ fmt.Printf("resolve %s: %v\n", path, m)
+ }
+ return m
+ }
+ if path == "/" {
+ break
+ }
+ path = pathpkg.Dir(path)
+ }
+ return nil
+}
+
+// Open implements the FileSystem Open method.
+func (ns nameSpace) Open(path string) (readSeekCloser, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ if debugNS {
+ fmt.Printf("tx %s: %v\n", path, m.translate(path))
+ }
+ r, err1 := m.fs.Open(m.translate(path))
+ if err1 == nil {
+ return r, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+// stat implements the FileSystem Stat and Lstat methods.
+func (ns nameSpace) stat(path string, f func(FileSystem, string) (os.FileInfo, error)) (os.FileInfo, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ fi, err1 := f(m.fs, m.translate(path))
+ if err1 == nil {
+ return fi, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+func (ns nameSpace) Stat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Stat)
+}
+
+func (ns nameSpace) Lstat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Lstat)
+}
+
+// dirInfo is a trivial implementation of os.FileInfo for a directory.
+type dirInfo string
+
+func (d dirInfo) Name() string { return string(d) }
+func (d dirInfo) Size() int64 { return 0 }
+func (d dirInfo) Mode() os.FileMode { return os.ModeDir | 0555 }
+func (d dirInfo) ModTime() time.Time { return startTime }
+func (d dirInfo) IsDir() bool { return true }
+func (d dirInfo) Sys() interface{} { return nil }
+
+var startTime = time.Now()
+
+// ReadDir implements the FileSystem ReadDir method. It's where most of the magic is.
+// (The rest is in resolve.)
+//
+// Logically, ReadDir must return the union of all the directories that are named
+// by path. In order to avoid misinterpreting Go packages, of all the directories
+// that contain Go source code, we only include the files from the first,
+// but we include subdirectories from all.
+//
+// ReadDir must also return directory entries needed to reach mount points.
+// If the name space looks like the example in the type nameSpace comment,
+// but c:\Go does not have a src/pkg subdirectory, we still want to be able
+// to find that subdirectory, because we've mounted d:\Work1 and d:\Work2
+// there. So if we don't see "src" in the directory listing for c:\Go, we add an
+// entry for it before returning.
+//
+func (ns nameSpace) ReadDir(path string) ([]os.FileInfo, error) {
+ path = ns.clean(path)
+
+ var (
+ haveGo = false
+ haveName = map[string]bool{}
+ all []os.FileInfo
+ err error
+ first []os.FileInfo
+ )
+
+ for _, m := range ns.resolve(path) {
+ dir, err1 := m.fs.ReadDir(m.translate(path))
+ if err1 != nil {
+ if err == nil {
+ err = err1
+ }
+ continue
+ }
+
+ if dir == nil {
+ dir = []os.FileInfo{}
+ }
+
+ if first == nil {
+ first = dir
+ }
+
+ // If we don't yet have Go files in 'all' and this directory
+ // has some, add all the files from this directory.
+ // Otherwise, only add subdirectories.
+ useFiles := false
+ if !haveGo {
+ for _, d := range dir {
+ if strings.HasSuffix(d.Name(), ".go") {
+ useFiles = true
+ haveGo = true
+ break
+ }
+ }
+ }
+
+ for _, d := range dir {
+ name := d.Name()
+ if (d.IsDir() || useFiles) && !haveName[name] {
+ haveName[name] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // We didn't find any directories containing Go files.
+ // If some directory returned successfully, use that.
+ if !haveGo {
+ for _, d := range first {
+ if !haveName[d.Name()] {
+ haveName[d.Name()] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // Built union. Add any missing directories needed to reach mount points.
+ for old := range ns {
+ if hasPathPrefix(old, path) && old != path {
+ // Find next element after path in old.
+ elem := old[len(path):]
+ if strings.HasPrefix(elem, "/") {
+ elem = elem[1:]
+ }
+ if i := strings.Index(elem, "/"); i >= 0 {
+ elem = elem[:i]
+ }
+ if !haveName[elem] {
+ haveName[elem] = true
+ all = append(all, dirInfo(elem))
+ }
+ }
+ }
+
+ if len(all) == 0 {
+ return nil, err
+ }
+
+ sort.Sort(byName(all))
+ return all, nil
}
-func (osFS) Stat(path string) (FileInfo, os.Error) {
- fi, err := os.Stat(path)
- return osFI{fi}, err
+// byName implements sort.Interface.
+type byName []os.FileInfo
+
+func (f byName) Len() int { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+
+// An httpFS implements http.FileSystem using a FileSystem.
+type httpFS struct {
+ fs FileSystem
}
-func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
- l0, err := ioutil.ReadDir(path) // l0 is sorted
+func (h *httpFS) Open(name string) (http.File, error) {
+ fi, err := h.fs.Stat(name)
if err != nil {
return nil, err
}
- l1 := make([]FileInfo, len(l0))
- for i, e := range l0 {
- l1[i] = osFI{e}
+ if fi.IsDir() {
+ return &httpDir{h.fs, name, nil}, nil
+ }
+ f, err := h.fs.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return &httpFile{h.fs, f, name}, nil
+}
+
+// httpDir implements http.File for a directory in a FileSystem.
+type httpDir struct {
+ fs FileSystem
+ name string
+ pending []os.FileInfo
+}
+
+func (h *httpDir) Close() error { return nil }
+func (h *httpDir) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpDir) Read([]byte) (int, error) {
+ return 0, fmt.Errorf("cannot Read from directory %s", h.name)
+}
+
+func (h *httpDir) Seek(offset int64, whence int) (int64, error) {
+ if offset == 0 && whence == 0 {
+ h.pending = nil
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in directory %s", h.name)
+}
+
+func (h *httpDir) Readdir(count int) ([]os.FileInfo, error) {
+ if h.pending == nil {
+ d, err := h.fs.ReadDir(h.name)
+ if err != nil {
+ return nil, err
+ }
+ if d == nil {
+ d = []os.FileInfo{} // not nil
+ }
+ h.pending = d
+ }
+
+ if len(h.pending) == 0 && count > 0 {
+ return nil, io.EOF
+ }
+ if count <= 0 || count > len(h.pending) {
+ count = len(h.pending)
}
- return l1, nil
+ d := h.pending[:count]
+ h.pending = h.pending[count:]
+ return d, nil
+}
+
+// httpFile implements http.File for a file (not directory) in a FileSystem.
+type httpFile struct {
+ fs FileSystem
+ readSeekCloser
+ name string
}
-func (osFS) ReadFile(path string) ([]byte, os.Error) {
- return ioutil.ReadFile(path)
+func (h *httpFile) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpFile) Readdir(int) ([]os.FileInfo, error) {
+ return nil, fmt.Errorf("cannot Readdir from file %s", h.name)
}
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
index 78dde4166..3b1b9a822 100644
--- a/src/cmd/godoc/format.go
+++ b/src/cmd/godoc/format.go
@@ -17,7 +17,7 @@ import (
"io"
"regexp"
"strconv"
- "template"
+ "text/template"
)
// ----------------------------------------------------------------------------
@@ -231,7 +231,7 @@ func commentSelection(src []byte) Selection {
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(src))
- s.Init(file, src, nil, scanner.ScanComments+scanner.InsertSemis)
+ s.Init(file, src, nil, scanner.ScanComments)
return func() (seg []int) {
for {
pos, tok, lit := s.Scan()
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index b8a839404..f6dc678b4 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -6,6 +6,7 @@ package main
import (
"bytes"
+ "encoding/json"
"flag"
"fmt"
"go/ast"
@@ -13,18 +14,22 @@ import (
"go/doc"
"go/printer"
"go/token"
- "http"
"io"
+ "io/ioutil"
"log"
+ "net/http"
+ "net/url"
"os"
- "path"
+ pathpkg "path"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
- "template"
+ "text/template"
"time"
+ "unicode"
+ "unicode/utf8"
)
// ----------------------------------------------------------------------------
@@ -34,9 +39,9 @@ type delayTime struct {
RWValue
}
-func (dt *delayTime) backoff(max int) {
+func (dt *delayTime) backoff(max time.Duration) {
dt.mutex.Lock()
- v := dt.value.(int) * 2
+ v := dt.value.(time.Duration) * 2
if v > max {
v = max
}
@@ -50,233 +55,68 @@ var (
// file system roots
// TODO(gri) consider the invariant that goroot always end in '/'
- 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
+ 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)")
// layout control
tabwidth = flag.Int("tabwidth", 4, "tab width")
- showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
+ showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings")
templateDir = flag.String("templates", "", "directory containing alternate template files")
// search index
indexEnabled = flag.Bool("index", false, "enable search index")
- maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
+ indexFiles = flag.String("index_files", "", "glob pattern specifying index files;"+
+ "if not empty, the index is read from these files in sorted order")
+ maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
+ indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
- // file system mapping
- fs FileSystem // the underlying file system for godoc
- fsHttp http.FileSystem // the underlying file system for http
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
- pathFilter RWValue // filter used when building fsMap directory trees
- fsModified RWValue // timestamp of last call to invalidateIndex
+ // file system information
+ fsTree RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now)
+ fsModified RWValue // timestamp of last call to invalidateIndex
+ docMetadata RWValue // mapping from paths to *Metadata
// http handlers
fileServer http.Handler // default file server
- cmdHandler httpHandler
- pkgHandler httpHandler
+ cmdHandler docServer
+ pkgHandler docServer
)
func initHandlers() {
- paths := filepath.SplitList(*pkgPath)
- for _, t := range build.Path {
- if t.Goroot {
- continue
+ // Add named directories in -path argument as
+ // subdirectories of src/pkg.
+ for _, p := range filepath.SplitList(*pkgPath) {
+ _, elem := filepath.Split(p)
+ if elem == "" {
+ log.Fatalf("invalid -path argument: %q has no final element", p)
}
- paths = append(paths, t.SrcDir())
+ fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace)
}
- fsMap.Init(paths)
- fileServer = http.FileServer(fsHttp)
- cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
- pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
+ fileServer = http.FileServer(&httpFS{fs})
+ cmdHandler = docServer{"/cmd/", "/src/cmd", false}
+ pkgHandler = docServer{"/pkg/", "/src/pkg", true}
}
func registerPublicHandlers(mux *http.ServeMux) {
mux.Handle(cmdHandler.pattern, &cmdHandler)
mux.Handle(pkgHandler.pattern, &pkgHandler)
mux.HandleFunc("/doc/codewalk/", codewalk)
+ mux.Handle("/doc/play/", fileServer)
mux.HandleFunc("/search", search)
mux.Handle("/robots.txt", fileServer)
+ mux.HandleFunc("/opensearch.xml", serveSearchDesc)
mux.HandleFunc("/", serveFile)
}
func initFSTree() {
- fsTree.set(newDirectory(filepath.Join(*goroot, *testDir), nil, -1))
- invalidateIndex()
-}
-
-// ----------------------------------------------------------------------------
-// Directory filters
-
-// isParentOf returns true if p is a parent of (or the same as) q
-// where p and q are directory paths.
-func isParentOf(p, q string) bool {
- n := len(p)
- return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
-}
-
-func setPathFilter(list []string) {
- if len(list) == 0 {
- pathFilter.set(nil)
+ dir := newDirectory(pathpkg.Join("/", *testDir), -1)
+ if dir == nil {
+ log.Println("Warning: FSTree is nil")
return
}
-
- // len(list) > 0
- pathFilter.set(func(path string) bool {
- // list is sorted in increasing order and for each path all its children are removed
- i := sort.Search(len(list), func(i int) bool { return list[i] > path })
- // Now we have list[i-1] <= path < list[i].
- // Path may be a child of list[i-1] or a parent of list[i].
- return i > 0 && isParentOf(list[i-1], path) || i < len(list) && isParentOf(path, list[i])
- })
-}
-
-func getPathFilter() func(string) bool {
- f, _ := pathFilter.get()
- if f != nil {
- return f.(func(string) bool)
- }
- return nil
-}
-
-// readDirList reads a file containing a newline-separated list
-// of directory paths and returns the list of paths.
-func readDirList(filename string) ([]string, os.Error) {
- contents, err := fs.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- // create a sorted list of valid directory names
- filter := func(path string) bool {
- d, e := fs.Lstat(path)
- if e != nil && err == nil {
- // remember first error and return it from readDirList
- // so we have at least some information if things go bad
- err = e
- }
- return e == nil && isPkgDir(d)
- }
- list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
- // for each parent path, remove all its children q
- // (requirement for binary search to work when filtering)
- i := 0
- for _, q := range list {
- if i == 0 || !isParentOf(list[i-1], q) {
- list[i] = q
- i++
- }
- }
- return list[0:i], err
-}
-
-// updateMappedDirs computes the directory tree for
-// each user-defined file system mapping. If a filter
-// is provided, it is used to filter directories.
-//
-func updateMappedDirs(filter func(string) bool) {
- if !fsMap.IsEmpty() {
- fsMap.Iterate(func(path string, value *RWValue) bool {
- value.set(newDirectory(path, filter, -1))
- return true
- })
- invalidateIndex()
- }
-}
-
-func updateFilterFile() {
- updateMappedDirs(nil) // no filter for accuracy
-
- // collect directory tree leaf node paths
- var buf bytes.Buffer
- fsMap.Iterate(func(_ string, value *RWValue) bool {
- v, _ := value.get()
- if v != nil && v.(*Directory) != nil {
- v.(*Directory).writeLeafs(&buf)
- }
- return true
- })
-
- // update filter file
- if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
- log.Printf("writeFileAtomically(%s): %s", *filter, err)
- filterDelay.backoff(24 * 60) // back off exponentially, but try at least once a day
- } else {
- filterDelay.set(*filterMin) // revert to regular filter update schedule
- }
-}
-
-func initDirTrees() {
- // setup initial path filter
- if *filter != "" {
- list, err := readDirList(*filter)
- if err != nil {
- log.Printf("readDirList(%s): %s", *filter, err)
- }
- if *verbose || len(list) == 0 {
- log.Printf("found %d directory paths in file %s", len(list), *filter)
- }
- setPathFilter(list)
- }
-
- go updateMappedDirs(getPathFilter()) // use filter for speed
-
- // start filter update goroutine, if enabled.
- if *filter != "" && *filterMin > 0 {
- filterDelay.set(*filterMin) // initial filter update delay
- go func() {
- for {
- if *verbose {
- log.Printf("start update of %s", *filter)
- }
- updateFilterFile()
- delay, _ := filterDelay.get()
- if *verbose {
- log.Printf("next filter update in %dmin", delay.(int))
- }
- time.Sleep(int64(delay.(int)) * 60e9)
- }
- }()
- }
-}
-
-// ----------------------------------------------------------------------------
-// Path mapping
-
-// Absolute paths are file system paths (backslash-separated on Windows),
-// but relative paths are always slash-separated.
-
-func absolutePath(relpath, defaultRoot string) string {
- abspath := fsMap.ToAbsolute(relpath)
- if abspath == "" {
- // no user-defined mapping found; use default mapping
- abspath = filepath.Join(defaultRoot, filepath.FromSlash(relpath))
- }
- return abspath
-}
-
-func relativeURL(abspath string) string {
- relpath := fsMap.ToRelative(abspath)
- if relpath == "" {
- // prefix must end in a path separator
- prefix := *goroot
- if len(prefix) > 0 && prefix[len(prefix)-1] != filepath.Separator {
- prefix += string(filepath.Separator)
- }
- if strings.HasPrefix(abspath, prefix) {
- // no user-defined mapping found; use default mapping
- relpath = filepath.ToSlash(abspath[len(prefix):])
- }
- }
- // Only if path is an invalid absolute path is relpath == ""
- // at this point. This should never happen since absolute paths
- // are only created via godoc for files that do exist. However,
- // it is ok to return ""; it will simply provide a link to the
- // top of the pkg or src directories.
- return relpath
+ fsTree.set(dir)
+ invalidateIndex()
}
// ----------------------------------------------------------------------------
@@ -296,7 +136,7 @@ type tconv struct {
indent int // valid if state == indenting
}
-func (p *tconv) writeIndent() (err os.Error) {
+func (p *tconv) writeIndent() (err error) {
i := p.indent
for i >= len(spaces) {
i -= len(spaces)
@@ -311,7 +151,7 @@ func (p *tconv) writeIndent() (err os.Error) {
return
}
-func (p *tconv) Write(data []byte) (n int, err os.Error) {
+func (p *tconv) Write(data []byte) (n int, err error) {
if len(data) == 0 {
return
}
@@ -368,25 +208,28 @@ func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
// with an another printer mode (which is more efficiently
// implemented in the printer than here with another layer)
mode := printer.TabIndent | printer.UseSpaces
- (&printer.Config{mode, *tabwidth}).Fprint(&tconv{output: w}, fset, x)
+ err := (&printer.Config{Mode: mode, Tabwidth: *tabwidth}).Fprint(&tconv{output: w}, fset, x)
+ if err != nil {
+ log.Print(err)
+ }
}
func filenameFunc(path string) string {
- _, localname := filepath.Split(path)
+ _, localname := pathpkg.Split(path)
return localname
}
-func fileInfoNameFunc(fi FileInfo) string {
+func fileInfoNameFunc(fi os.FileInfo) string {
name := fi.Name()
- if fi.IsDirectory() {
+ if fi.IsDir() {
name += "/"
}
return name
}
-func fileInfoTimeFunc(fi FileInfo) string {
- if t := fi.Mtime_ns(); t != 0 {
- return time.SecondsToLocalTime(t / 1e9).String()
+func fileInfoTimeFunc(fi os.FileInfo) string {
+ if t := fi.ModTime(); t.Unix() != 0 {
+ return t.Local().String()
}
return "" // don't return epoch if time is obviously not set
}
@@ -403,8 +246,8 @@ var infoKinds = [nKinds]string{
Use: "use",
}
-func infoKind_htmlFunc(kind SpotKind) string {
- return infoKinds[kind] // infoKind entries are html-escaped
+func infoKind_htmlFunc(info SpotInfo) string {
+ return infoKinds[info.Kind()] // infoKind entries are html-escaped
}
func infoLineFunc(info SpotInfo) int {
@@ -451,12 +294,118 @@ func comment_htmlFunc(comment string) string {
var buf bytes.Buffer
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
- doc.ToHTML(&buf, []byte(comment), nil) // does html-escaping
+ doc.ToHTML(&buf, comment, nil) // does html-escaping
return buf.String()
}
+// punchCardWidth is the number of columns of fixed-width
+// characters to assume when wrapping text. Very few people
+// use terminals or cards smaller than 80 characters, so 80 it is.
+// We do not try to sniff the environment or the tty to adapt to
+// the situation; instead, by using a constant we make sure that
+// godoc always produces the same output regardless of context,
+// a consistency that is lost otherwise. For example, if we sniffed
+// the environment or tty, then http://golang.org/pkg/math/?m=text
+// would depend on the width of the terminal where godoc started,
+// which is clearly bogus. More generally, the Unix tools that behave
+// differently when writing to a tty than when writing to a file have
+// a history of causing confusion (compare `ls` and `ls | cat`), and we
+// want to avoid that mistake here.
+const punchCardWidth = 80
+
+func comment_textFunc(comment, indent, preIndent string) string {
+ var buf bytes.Buffer
+ doc.ToText(&buf, comment, indent, preIndent, punchCardWidth-2*len(indent))
+ return buf.String()
+}
+
+func startsWithUppercase(s string) bool {
+ r, _ := utf8.DecodeRuneInString(s)
+ return unicode.IsUpper(r)
+}
+
+var exampleOutputRx = regexp.MustCompile(`(?i)//[[:space:]]*output:`)
+
+func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.FileSet) string {
+ var buf bytes.Buffer
+ for _, eg := range examples {
+ name := eg.Name
+
+ // strip lowercase braz in Foo_braz or Foo_Bar_braz from name
+ // while keeping uppercase Braz in Foo_Braz
+ if i := strings.LastIndex(name, "_"); i != -1 {
+ if i < len(name)-1 && !startsWithUppercase(name[i+1:]) {
+ name = name[:i]
+ }
+ }
+
+ if name != funcName {
+ continue
+ }
+
+ // print code
+ cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
+ code := node_htmlFunc(cnode, fset)
+ out := eg.Output
+
+ // additional formatting if this is a function body
+ if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
+ // remove surrounding braces
+ code = code[1 : n-1]
+ // unindent
+ code = strings.Replace(code, "\n ", "\n", -1)
+ // remove output comment
+ if loc := exampleOutputRx.FindStringIndex(code); loc != nil {
+ code = strings.TrimSpace(code[:loc[0]])
+ }
+ } else {
+ // drop output, as the output comment will appear in the code
+ out = ""
+ }
+
+ err := exampleHTML.Execute(&buf, struct {
+ Name, Doc, Code, Output string
+ }{eg.Name, eg.Doc, code, out})
+ if err != nil {
+ log.Print(err)
+ }
+ }
+ return buf.String()
+}
+
+// example_nameFunc takes an example function name and returns its display
+// name. For example, "Foo_Bar_quux" becomes "Foo.Bar (Quux)".
+func example_nameFunc(s string) string {
+ name, suffix := splitExampleName(s)
+ // replace _ with . for method names
+ name = strings.Replace(name, "_", ".", 1)
+ // use "Package" if no name provided
+ if name == "" {
+ name = "Package"
+ }
+ return name + suffix
+}
+
+// example_suffixFunc takes an example function name and returns its suffix in
+// parenthesized form. For example, "Foo_Bar_quux" becomes " (Quux)".
+func example_suffixFunc(name string) string {
+ _, suffix := splitExampleName(name)
+ return suffix
+}
+
+func splitExampleName(s string) (name, suffix string) {
+ i := strings.LastIndex(s, "_")
+ if 0 <= i && i < len(s)-1 && !startsWithUppercase(s[i+1:]) {
+ name = s[:i]
+ suffix = " (" + strings.Title(s[i+1:]) + ")"
+ return
+ }
+ name = s
+ return
+}
+
func pkgLinkFunc(path string) string {
- relpath := relativeURL(path)
+ relpath := path[1:]
// because of the irregular mapping under goroot
// we need to correct certain relative paths
if strings.HasPrefix(relpath, "src/pkg/") {
@@ -472,7 +421,7 @@ func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
if p := node.Pos(); p.IsValid() {
pos := fset.Position(p)
- relpath = relativeURL(pos.Filename)
+ relpath = pos.Filename
line = pos.Line
low = pos.Offset
}
@@ -501,6 +450,10 @@ func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
return buf.String()
}
+func srcLinkFunc(s string) string {
+ return pathpkg.Clean("/" + s)
+}
+
// fmap describes the template functions installed with all godoc templates.
// Convention: template function names ending in "_html" or "_url" produce
// HTML- or URL-escaped strings; all other function results may
@@ -523,24 +476,34 @@ var fmap = template.FuncMap{
"node": nodeFunc,
"node_html": node_htmlFunc,
"comment_html": comment_htmlFunc,
+ "comment_text": comment_textFunc,
// support for URL attributes
"pkgLink": pkgLinkFunc,
- "srcLink": relativeURL,
+ "srcLink": srcLinkFunc,
"posLink_url": posLink_urlFunc,
+
+ // formatting of Examples
+ "example_html": example_htmlFunc,
+ "example_name": example_nameFunc,
+ "example_suffix": example_suffixFunc,
}
func readTemplate(name string) *template.Template {
- path := filepath.Join(*goroot, "lib", "godoc", name)
- if *templateDir != "" {
- defaultpath := path
- path = filepath.Join(*templateDir, name)
- if _, err := fs.Stat(path); err != nil {
- log.Print("readTemplate:", err)
- path = defaultpath
- }
+ path := "lib/godoc/" + name
+
+ // use underlying file system fs to read the template file
+ // (cannot use template ParseFile functions directly)
+ data, err := ReadFile(fs, path)
+ if err != nil {
+ log.Fatal("readTemplate: ", err)
+ }
+ // be explicit with errors (for app engine use)
+ t, err := template.New(name).Funcs(fmap).Parse(string(data))
+ if err != nil {
+ log.Fatal("readTemplate: ", err)
}
- return template.Must(template.New(name).Funcs(fmap).ParseFile(path))
+ return t
}
var (
@@ -548,11 +511,13 @@ var (
codewalkdirHTML,
dirlistHTML,
errorHTML,
+ exampleHTML,
godocHTML,
packageHTML,
packageText,
searchHTML,
- searchText *template.Template
+ searchText,
+ searchDescXML *template.Template
)
func readTemplates() {
@@ -561,30 +526,35 @@ func readTemplates() {
codewalkdirHTML = readTemplate("codewalkdir.html")
dirlistHTML = readTemplate("dirlist.html")
errorHTML = readTemplate("error.html")
+ exampleHTML = readTemplate("example.html")
godocHTML = readTemplate("godoc.html")
packageHTML = readTemplate("package.html")
packageText = readTemplate("package.txt")
searchHTML = readTemplate("search.html")
searchText = readTemplate("search.txt")
+ searchDescXML = readTemplate("opensearch.xml")
}
// ----------------------------------------------------------------------------
// Generic HTML wrapper
-func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
+func servePage(w http.ResponseWriter, tabtitle, title, subtitle, query string, content []byte) {
+ if tabtitle == "" {
+ tabtitle = title
+ }
d := struct {
+ Tabtitle string
Title string
Subtitle string
- PkgRoots []string
SearchBox bool
Query string
Version string
Menu []byte
Content []byte
}{
+ tabtitle,
title,
subtitle,
- fsMap.PrefixList(),
*indexEnabled,
query,
runtime.Version(),
@@ -606,22 +576,14 @@ func serveText(w http.ResponseWriter, text []byte) {
// Files
var (
- titleRx = regexp.MustCompile(`<!-- title ([^\-]*)-->`)
- subtitleRx = regexp.MustCompile(`<!-- subtitle ([^\-]*)-->`)
- firstCommentRx = regexp.MustCompile(`<!--([^\-]*)-->`)
+ doctype = []byte("<!DOCTYPE ")
+ jsonStart = []byte("<!--{")
+ jsonEnd = []byte("}-->")
)
-func extractString(src []byte, rx *regexp.Regexp) (s string) {
- m := rx.FindSubmatch(src)
- if m != nil {
- s = strings.TrimSpace(string(m[1]))
- }
- return
-}
-
func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
// get HTML body contents
- src, err := fs.ReadFile(abspath)
+ src, err := ReadFile(fs, abspath)
if err != nil {
log.Printf("ReadFile: %s", err)
serveError(w, r, relpath, err)
@@ -630,27 +592,42 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
// if it begins with "<!DOCTYPE " assume it is standalone
// html that doesn't need the template wrapping.
- if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
+ if bytes.HasPrefix(src, doctype) {
w.Write(src)
return
}
- // if it's the language spec, add tags to EBNF productions
- if strings.HasSuffix(abspath, "go_spec.html") {
+ // if it begins with a JSON blob, read in the metadata.
+ meta, src, err := extractMetadata(src)
+ if err != nil {
+ log.Printf("decoding metadata %s: %v", relpath, err)
+ }
+
+ // evaluate as template if indicated
+ if meta.Template {
+ tmpl, err := template.New("main").Funcs(templateFuncs).Parse(string(src))
+ if err != nil {
+ log.Printf("parsing template %s: %v", relpath, err)
+ serveError(w, r, relpath, err)
+ return
+ }
var buf bytes.Buffer
- linkify(&buf, src)
+ if err := tmpl.Execute(&buf, nil); err != nil {
+ log.Printf("executing template %s: %v", relpath, err)
+ serveError(w, r, relpath, err)
+ return
+ }
src = buf.Bytes()
}
- // get title and subtitle, if any
- title := extractString(src, titleRx)
- if title == "" {
- // no title found; try first comment for backward-compatibility
- title = extractString(src, firstCommentRx)
+ // if it's the language spec, add tags to EBNF productions
+ if strings.HasSuffix(abspath, "go_spec.html") {
+ var buf bytes.Buffer
+ Linkify(&buf, src)
+ src = buf.Bytes()
}
- subtitle := extractString(src, subtitleRx)
- servePage(w, title, subtitle, "", src)
+ servePage(w, "", meta.Title, meta.Subtitle, "", src)
}
func applyTemplate(t *template.Template, name string, data interface{}) []byte {
@@ -662,7 +639,11 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
}
func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
- if canonical := path.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
+ canonical := pathpkg.Clean(r.URL.Path)
+ if !strings.HasSuffix("/", canonical) {
+ canonical += "/"
+ }
+ if r.URL.Path != canonical {
http.Redirect(w, r, canonical, http.StatusMovedPermanently)
redirected = true
}
@@ -670,7 +651,7 @@ func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
}
func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
- src, err := fs.ReadFile(abspath)
+ src, err := ReadFile(fs, abspath)
if err != nil {
log.Printf("ReadFile: %s", err)
serveError(w, r, relpath, err)
@@ -679,10 +660,10 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
var buf bytes.Buffer
buf.WriteString("<pre>")
- FormatText(&buf, src, 1, filepath.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+ FormatText(&buf, src, 1, pathpkg.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
buf.WriteString("</pre>")
- servePage(w, title+" "+relpath, "", "", buf.Bytes())
+ servePage(w, relpath, title+" "+relpath, "", "", buf.Bytes())
}
func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
@@ -692,32 +673,32 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str
list, err := fs.ReadDir(abspath)
if err != nil {
- log.Printf("ReadDir: %s", err)
serveError(w, r, relpath, err)
return
}
contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
- servePage(w, "Directory "+relpath, "", "", contents)
+ servePage(w, relpath, "Directory "+relpath, "", "", contents)
}
func serveFile(w http.ResponseWriter, r *http.Request) {
- relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
- abspath := absolutePath(relpath, *goroot)
-
- // pick off special cases and hand the rest to the standard file server
- switch r.URL.Path {
- case "/":
- serveHTMLDoc(w, r, filepath.Join(*goroot, "doc", "root.html"), "doc/root.html")
- return
+ relpath := r.URL.Path
- case "/doc/root.html":
- // hide landing page from its real name
- http.Redirect(w, r, "/", http.StatusMovedPermanently)
- return
+ // Check to see if we need to redirect or serve another file.
+ if m := metadataFor(relpath); m != nil {
+ if m.Path != relpath {
+ // Redirect to canonical path.
+ http.Redirect(w, r, m.Path, http.StatusMovedPermanently)
+ return
+ }
+ // Serve from the actual filesystem path.
+ relpath = m.filePath
}
- switch path.Ext(relpath) {
+ abspath := relpath
+ relpath = relpath[1:] // strip leading slash
+
+ switch pathpkg.Ext(relpath) {
case ".html":
if strings.HasSuffix(relpath, "/index.html") {
// We'll show index.html for the directory.
@@ -740,12 +721,12 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
return
}
- if dir != nil && dir.IsDirectory() {
+ if dir != nil && dir.IsDir() {
if redirect(w, r) {
return
}
- if index := filepath.Join(abspath, "index.html"); isTextFile(index) {
- serveHTMLDoc(w, r, index, relativeURL(index))
+ if index := pathpkg.Join(abspath, "index.html"); isTextFile(index) {
+ serveHTMLDoc(w, r, index, index)
return
}
serveDirectory(w, r, abspath, relpath)
@@ -760,6 +741,16 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
fileServer.ServeHTTP(w, r)
}
+func serveSearchDesc(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/opensearchdescription+xml")
+ data := map[string]interface{}{
+ "BaseURL": fmt.Sprintf("http://%s", r.Host),
+ }
+ if err := searchDescXML.Execute(w, &data); err != nil {
+ log.Printf("searchDescXML.Execute: %s", err)
+ }
+}
+
// ----------------------------------------------------------------------------
// Packages
@@ -769,37 +760,106 @@ const fakePkgName = "documentation"
// Fake relative package path for built-ins. Documentation for all globals
// (not just exported ones) will be shown for packages in this directory.
-const builtinPkgPath = "builtin/"
+const builtinPkgPath = "builtin"
type PageInfoMode uint
const (
- exportsOnly PageInfoMode = 1 << iota // only keep exported stuff
- genDoc // generate documentation
+ noFiltering PageInfoMode = 1 << iota // do not filter exports
+ allMethods // show all embedded methods
+ showSource // show source code, do not extract documentation
+ noHtml // show result in textual form, do not generate HTML
+ flatDir // show directory in a flat (non-indented) manner
)
+// modeNames defines names for each PageInfoMode flag.
+var modeNames = map[string]PageInfoMode{
+ "all": noFiltering,
+ "methods": allMethods,
+ "src": showSource,
+ "text": noHtml,
+ "flat": flatDir,
+}
+
+// getPageInfoMode computes the PageInfoMode flags by analyzing the request
+// URL form value "m". It is value is a comma-separated list of mode names
+// as defined by modeNames (e.g.: m=src,text).
+func getPageInfoMode(r *http.Request) PageInfoMode {
+ var mode PageInfoMode
+ for _, k := range strings.Split(r.FormValue("m"), ",") {
+ if m, found := modeNames[strings.TrimSpace(k)]; found {
+ mode |= m
+ }
+ }
+ return adjustPageInfoMode(r, mode)
+}
+
+// Specialized versions of godoc may adjust the PageInfoMode by overriding
+// this variable.
+var adjustPageInfoMode = func(_ *http.Request, mode PageInfoMode) PageInfoMode {
+ return mode
+}
+
+// remoteSearchURL returns the search URL for a given query as needed by
+// remoteSearch. If html is set, an html result is requested; otherwise
+// the result is in textual form.
+// Adjust this function as necessary if modeNames or FormValue parameters
+// change.
+func remoteSearchURL(query string, html bool) string {
+ s := "/search?m=text&q="
+ if html {
+ s = "/search?q="
+ }
+ return s + url.QueryEscape(query)
+}
+
type PageInfo struct {
- Dirname string // directory containing the package
- PList []string // list of package names found
- FSet *token.FileSet // corresponding file set
- PAst *ast.File // nil if no single AST with package exports
- PDoc *doc.PackageDoc // nil if no single package documentation
- Dirs *DirList // nil if no directory information
- DirTime int64 // directory time stamp in seconds since epoch
- IsPkg bool // false if this is not documenting a real package
- Err os.Error // directory read error or nil
+ Dirname string // directory containing the package
+ PList []string // list of package names found
+ FSet *token.FileSet // corresponding file set
+ PAst *ast.File // nil if no single AST with package exports
+ PDoc *doc.Package // nil if no single package documentation
+ Examples []*doc.Example // nil if no example code
+ Dirs *DirList // nil if no directory information
+ DirTime time.Time // directory time stamp
+ DirFlat bool // if set, show directory in a flat (non-indented) manner
+ IsPkg bool // false if this is not documenting a real package
+ Err error // I/O error or nil
}
func (info *PageInfo) IsEmpty() bool {
return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
}
-type httpHandler struct {
+type docServer struct {
pattern string // url pattern; e.g. "/pkg/"
fsRoot string // file system root to which the pattern is mapped
isPkg bool // true if this handler serves real package documentation (as opposed to command documentation)
}
+// fsReadDir implements ReadDir for the go/build package.
+func fsReadDir(dir string) ([]os.FileInfo, error) {
+ return fs.ReadDir(dir)
+}
+
+// fsOpenFile implements OpenFile for the go/build package.
+func fsOpenFile(name string) (r io.ReadCloser, err error) {
+ data, err := ReadFile(fs, name)
+ if err != nil {
+ return nil, err
+ }
+ return ioutil.NopCloser(bytes.NewReader(data)), nil
+}
+
+func inList(name string, list []string) bool {
+ for _, l := range list {
+ if name == l {
+ return true
+ }
+ }
+ return false
+}
+
// getPageInfo returns the PageInfo for a package directory abspath. If the
// parameter genAST is set, an AST containing only the package exports is
// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
@@ -808,12 +868,42 @@ type httpHandler struct {
// directories, PageInfo.Dirs is nil. If a directory read error occurred,
// PageInfo.Err is set to the respective error but the error is not logged.
//
-func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
+func (h *docServer) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
+ var pkgFiles []string
+
+ // If we're showing the default package, restrict to the ones
+ // that would be used when building the package on this
+ // system. This makes sure that if there are separate
+ // implementations for, say, Windows vs Unix, we don't
+ // jumble them all together.
+ if pkgname == "" {
+ // Note: Uses current binary's GOOS/GOARCH.
+ // To use different pair, such as if we allowed the user
+ // to choose, set ctxt.GOOS and ctxt.GOARCH before
+ // calling ctxt.ScanDir.
+ ctxt := build.Default
+ ctxt.IsAbsPath = pathpkg.IsAbs
+ ctxt.ReadDir = fsReadDir
+ ctxt.OpenFile = fsOpenFile
+ dir, err := ctxt.ImportDir(abspath, 0)
+ if err == nil {
+ pkgFiles = append(dir.GoFiles, dir.CgoFiles...)
+ }
+ }
+
// filter function to select the desired .go files
- filter := func(d FileInfo) bool {
+ filter := func(d os.FileInfo) bool {
+ // Only Go files.
+ if !isPkgFile(d) {
+ return false
+ }
// If we are looking at cmd documentation, only accept
// the special fakePkgFile containing the documentation.
- return isPkgFile(d) && (h.isPkg || d.Name() == fakePkgFile)
+ if !h.isPkg {
+ return d.Name() == fakePkgFile
+ }
+ // Also restrict file list to pkgFiles.
+ return pkgFiles == nil || inList(d.Name(), pkgFiles)
}
// get package ASTs
@@ -840,13 +930,13 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// the package with dirname, and the 3rd choice is a package
// that is not called "main" if there is exactly one such
// package. Otherwise, don't select a package.
- dirpath, dirname := filepath.Split(abspath)
+ dirpath, dirname := pathpkg.Split(abspath)
// If the dirname is "go" we might be in a sub-directory for
// .go files - use the outer directory name instead for better
// results.
if dirname == "go" {
- _, dirname = filepath.Split(filepath.Clean(dirpath))
+ _, dirname = pathpkg.Split(pathpkg.Clean(dirpath))
}
var choice3 *ast.Package
@@ -877,25 +967,54 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
}
}
plist = plist[0:i]
+ sort.Strings(plist)
+ }
+
+ // get examples from *_test.go files
+ var examples []*doc.Example
+ filter = func(d os.FileInfo) bool {
+ return isGoFile(d) && strings.HasSuffix(d.Name(), "_test.go")
+ }
+ if testpkgs, err := parseDir(fset, abspath, filter); err != nil {
+ log.Println("parsing test files:", err)
+ } else {
+ for _, testpkg := range testpkgs {
+ var files []*ast.File
+ for _, f := range testpkg.Files {
+ files = append(files, f)
+ }
+ examples = append(examples, doc.Examples(files...)...)
+ }
}
// compute package documentation
var past *ast.File
- var pdoc *doc.PackageDoc
+ var pdoc *doc.Package
if pkg != nil {
- if mode&exportsOnly != 0 {
- ast.PackageExports(pkg)
- }
- if mode&genDoc != 0 {
- pdoc = doc.NewPackageDoc(pkg, path.Clean(relpath)) // no trailing '/' in importpath
+ if mode&showSource == 0 {
+ // show extracted documentation
+ var m doc.Mode
+ if mode&noFiltering != 0 {
+ m = doc.AllDecls
+ }
+ if mode&allMethods != 0 {
+ m |= doc.AllMethods
+ }
+ pdoc = doc.New(pkg, pathpkg.Clean(relpath), m) // no trailing '/' in importpath
} else {
+ // show source code
+ // TODO(gri) Consider eliminating export filtering in this mode,
+ // or perhaps eliminating the mode altogether.
+ if mode&noFiltering == 0 {
+ ast.PackageExports(pkg)
+ }
past = ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments)
}
}
// get directory information
var dir *Directory
- var timestamp int64
+ var timestamp time.Time
if tree, ts := fsTree.get(); tree != nil && tree.(*Directory) != nil {
// directory tree is present; lookup respective directory
// (may still fail if the file system was updated and the
@@ -904,53 +1023,39 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
timestamp = ts
}
if dir == nil {
- // the path may refer to a user-specified file system mapped
- // via fsMap; lookup that mapping and corresponding RWValue
- // if any
- var v *RWValue
- fsMap.Iterate(func(path string, value *RWValue) bool {
- if isParentOf(path, abspath) {
- // mapping found
- v = value
- return false
- }
- return true
- })
- if v != nil {
- // found a RWValue associated with a user-specified file
- // system; a non-nil RWValue stores a (possibly out-of-date)
- // directory tree for that file system
- if tree, ts := v.get(); tree != nil && tree.(*Directory) != nil {
- dir = tree.(*Directory).lookup(abspath)
- timestamp = ts
- }
- }
- }
- if dir == nil {
// no directory tree present (too early after startup or
// command-line mode); compute one level for this page
// note: cannot use path filter here because in general
// it doesn't contain the fsTree path
- dir = newDirectory(abspath, nil, 1)
- timestamp = time.Seconds()
+ dir = newDirectory(abspath, 1)
+ timestamp = time.Now()
+ }
+
+ return PageInfo{
+ Dirname: abspath,
+ PList: plist,
+ FSet: fset,
+ PAst: past,
+ PDoc: pdoc,
+ Examples: examples,
+ Dirs: dir.listing(true),
+ DirTime: timestamp,
+ DirFlat: mode&flatDir != 0,
+ IsPkg: h.isPkg,
+ Err: nil,
}
-
- return PageInfo{abspath, plist, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
}
-func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if redirect(w, r) {
return
}
- relpath := r.URL.Path[len(h.pattern):]
- abspath := absolutePath(relpath, h.fsRoot)
- var mode PageInfoMode
- if relpath != builtinPkgPath {
- mode = exportsOnly
- }
- if r.FormValue("m") != "src" {
- mode |= genDoc
+ relpath := pathpkg.Clean(r.URL.Path[len(h.pattern):])
+ abspath := pathpkg.Join(h.fsRoot, relpath)
+ mode := getPageInfoMode(r)
+ if relpath == builtinPkgPath {
+ mode = noFiltering
}
info := h.getPageInfo(abspath, relpath, r.FormValue("p"), mode)
if info.Err != nil {
@@ -959,36 +1064,47 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- if r.FormValue("f") == "text" {
+ if mode&noHtml != 0 {
contents := applyTemplate(packageText, "packageText", info)
serveText(w, contents)
return
}
- var title, subtitle string
+ var tabtitle, title, subtitle string
switch {
case info.PAst != nil:
- title = "Package " + info.PAst.Name.Name
+ tabtitle = info.PAst.Name.Name
+ title = "Package " + tabtitle
case info.PDoc != nil:
- switch {
- case info.IsPkg:
- title = "Package " + info.PDoc.PackageName
- case info.PDoc.PackageName == fakePkgName:
+ if info.PDoc.Name == fakePkgName {
// assume that the directory name is the command name
- _, pkgname := path.Split(path.Clean(relpath))
- title = "Command " + pkgname
- default:
- title = "Command " + info.PDoc.PackageName
+ _, tabtitle = pathpkg.Split(relpath)
+ } else {
+ tabtitle = info.PDoc.Name
+ }
+ if info.IsPkg {
+ title = "Package " + tabtitle
+ } else {
+ title = "Command " + tabtitle
}
default:
- title = "Directory " + relativeURL(info.Dirname)
+ tabtitle = info.Dirname
+ title = "Directory " + tabtitle
if *showTimestamps {
- subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
+ subtitle = "Last update: " + info.DirTime.String()
}
}
+ // special cases for top-level package/command directories
+ switch tabtitle {
+ case "/src/pkg":
+ tabtitle = "Packages"
+ case "/src/cmd":
+ tabtitle = "Commands"
+ }
+
contents := applyTemplate(packageHTML, "packageHTML", info)
- servePage(w, title, subtitle, "", contents)
+ servePage(w, tabtitle, title, subtitle, "", contents)
}
// ----------------------------------------------------------------------------
@@ -1001,6 +1117,7 @@ type SearchResult struct {
Alert string // error or warning message
// identifier matches
+ Pak HitList // packages matching Query
Hit *LookupResult // identifier matches of Query
Alt *AltWords // alternative identifiers to look for
@@ -1018,12 +1135,12 @@ func lookup(query string) (result SearchResult) {
index := index.(*Index)
// identifier search
- var err os.Error
- result.Hit, result.Alt, err = index.Lookup(query)
+ var err error
+ result.Pak, result.Hit, result.Alt, err = index.Lookup(query)
if err != nil && *maxResults <= 0 {
// ignore the error if full text search is enabled
// since the query may be a valid regular expression
- result.Alert = "Error in query string: " + err.String()
+ result.Alert = "Error in query string: " + err.Error()
return
}
@@ -1031,7 +1148,7 @@ func lookup(query string) (result SearchResult) {
if *maxResults > 0 && query != "" {
rx, err := regexp.Compile(query)
if err != nil {
- result.Alert = "Error in query regular expression: " + err.String()
+ result.Alert = "Error in query regular expression: " + err.Error()
return
}
// If we get maxResults+1 results we know that there are more than
@@ -1048,10 +1165,8 @@ func lookup(query string) (result SearchResult) {
// is the result accurate?
if *indexEnabled {
- if _, ts := fsModified.get(); timestamp < ts {
- // The index is older than the latest file system change
- // under godoc's observation. Indexing may be in progress
- // or start shortly (see indexer()).
+ if _, ts := fsModified.get(); timestamp.Before(ts) {
+ // The index is older than the latest file system change under godoc's observation.
result.Alert = "Indexing in progress: result may be inaccurate"
}
} else {
@@ -1065,7 +1180,7 @@ func search(w http.ResponseWriter, r *http.Request) {
query := strings.TrimSpace(r.FormValue("q"))
result := lookup(query)
- if r.FormValue("f") == "text" {
+ if getPageInfoMode(r)&noHtml != 0 {
contents := applyTemplate(searchText, "searchText", result)
serveText(w, contents)
return
@@ -1079,7 +1194,133 @@ func search(w http.ResponseWriter, r *http.Request) {
}
contents := applyTemplate(searchHTML, "searchHTML", result)
- servePage(w, title, "", query, contents)
+ servePage(w, query, title, "", query, contents)
+}
+
+// ----------------------------------------------------------------------------
+// Documentation Metadata
+
+type Metadata struct {
+ Title string
+ Subtitle string
+ Template bool // execute as template
+ Path string // canonical path for this page
+ filePath string // filesystem path relative to goroot
+}
+
+// extractMetadata extracts the Metadata from a byte slice.
+// It returns the Metadata value and the remaining data.
+// If no metadata is present the original byte slice is returned.
+//
+func extractMetadata(b []byte) (meta Metadata, tail []byte, err error) {
+ tail = b
+ if !bytes.HasPrefix(b, jsonStart) {
+ return
+ }
+ end := bytes.Index(b, jsonEnd)
+ if end < 0 {
+ return
+ }
+ b = b[len(jsonStart)-1 : end+1] // drop leading <!-- and include trailing }
+ if err = json.Unmarshal(b, &meta); err != nil {
+ return
+ }
+ tail = tail[end+len(jsonEnd):]
+ return
+}
+
+// updateMetadata scans $GOROOT/doc for HTML files, reads their metadata,
+// and updates the docMetadata map.
+//
+func updateMetadata() {
+ metadata := make(map[string]*Metadata)
+ var scan func(string) // scan is recursive
+ scan = func(dir string) {
+ fis, err := fs.ReadDir(dir)
+ if err != nil {
+ log.Println("updateMetadata:", err)
+ return
+ }
+ for _, fi := range fis {
+ name := pathpkg.Join(dir, fi.Name())
+ if fi.IsDir() {
+ scan(name) // recurse
+ continue
+ }
+ if !strings.HasSuffix(name, ".html") {
+ continue
+ }
+ // Extract metadata from the file.
+ b, err := ReadFile(fs, name)
+ if err != nil {
+ log.Printf("updateMetadata %s: %v", name, err)
+ continue
+ }
+ meta, _, err := extractMetadata(b)
+ if err != nil {
+ log.Printf("updateMetadata: %s: %v", name, err)
+ continue
+ }
+ // Store relative filesystem path in Metadata.
+ meta.filePath = name
+ if meta.Path == "" {
+ // If no Path, canonical path is actual path.
+ meta.Path = meta.filePath
+ }
+ // Store under both paths.
+ metadata[meta.Path] = &meta
+ metadata[meta.filePath] = &meta
+ }
+ }
+ scan("/doc")
+ docMetadata.set(metadata)
+}
+
+// Send a value on this channel to trigger a metadata refresh.
+// It is buffered so that if a signal is not lost if sent during a refresh.
+//
+var refreshMetadataSignal = make(chan bool, 1)
+
+// refreshMetadata sends a signal to update docMetadata. If a refresh is in
+// progress the metadata will be refreshed again afterward.
+//
+func refreshMetadata() {
+ select {
+ case refreshMetadataSignal <- true:
+ default:
+ }
+}
+
+// refreshMetadataLoop runs forever, updating docMetadata when the underlying
+// file system changes. It should be launched in a goroutine by main.
+//
+func refreshMetadataLoop() {
+ for {
+ <-refreshMetadataSignal
+ updateMetadata()
+ time.Sleep(10 * time.Second) // at most once every 10 seconds
+ }
+}
+
+// metadataFor returns the *Metadata for a given relative path or nil if none
+// exists.
+//
+func metadataFor(relpath string) *Metadata {
+ if m, _ := docMetadata.get(); m != nil {
+ meta := m.(map[string]*Metadata)
+ // If metadata for this relpath exists, return it.
+ if p := meta[relpath]; p != nil {
+ return p
+ }
+ // Try with or without trailing slash.
+ if strings.HasSuffix(relpath, "/") {
+ relpath = relpath[:len(relpath)-1]
+ } else {
+ relpath = relpath + "/"
+ }
+ return meta[relpath]
+ }
+ return nil
}
// ----------------------------------------------------------------------------
@@ -1090,6 +1331,7 @@ func search(w http.ResponseWriter, r *http.Request) {
//
func invalidateIndex() {
fsModified.set(nil)
+ refreshMetadata()
}
// indexUpToDate() returns true if the search index is not older
@@ -1098,7 +1340,7 @@ func invalidateIndex() {
func indexUpToDate() bool {
_, fsTime := fsModified.get()
_, siTime := searchIndex.get()
- return fsTime <= siTime
+ return !fsTime.After(siTime)
}
// feedDirnames feeds the directory names of all directories
@@ -1116,43 +1358,77 @@ func feedDirnames(root *RWValue, c chan<- string) {
// of all the file systems under godoc's observation.
//
func fsDirnames() <-chan string {
- c := make(chan string, 256) // asynchronous for fewer context switches
+ c := make(chan string, 256) // buffered for fewer context switches
go func() {
feedDirnames(&fsTree, c)
- fsMap.Iterate(func(_ string, root *RWValue) bool {
- feedDirnames(root, c)
- return true
- })
close(c)
}()
return c
}
+func readIndex(filenames string) error {
+ matches, err := filepath.Glob(filenames)
+ if err != nil {
+ return err
+ }
+ sort.Strings(matches) // make sure files are in the right order
+ files := make([]io.Reader, 0, len(matches))
+ for _, filename := range matches {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ files = append(files, f)
+ }
+ x := new(Index)
+ if err := x.Read(io.MultiReader(files...)); err != nil {
+ return err
+ }
+ searchIndex.set(x)
+ return nil
+}
+
+func updateIndex() {
+ if *verbose {
+ log.Printf("updating index...")
+ }
+ start := time.Now()
+ index := NewIndex(fsDirnames(), *maxResults > 0, *indexThrottle)
+ stop := time.Now()
+ searchIndex.set(index)
+ if *verbose {
+ secs := stop.Sub(start).Seconds()
+ stats := index.Stats()
+ log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
+ secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
+ }
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ log.Printf("before GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
+ runtime.GC()
+ runtime.ReadMemStats(memstats)
+ log.Printf("after GC: bytes = %d footprint = %d", memstats.HeapAlloc, memstats.Sys)
+}
+
func indexer() {
+ // initialize the index from disk if possible
+ if *indexFiles != "" {
+ if err := readIndex(*indexFiles); err != nil {
+ log.Printf("error reading index: %s", err)
+ }
+ }
+
+ // repeatedly update the index when it goes out of date
for {
if !indexUpToDate() {
// index possibly out of date - make a new one
- if *verbose {
- log.Printf("updating index...")
- }
- start := time.Nanoseconds()
- index := NewIndex(fsDirnames(), *maxResults > 0)
- stop := time.Nanoseconds()
- searchIndex.set(index)
- if *verbose {
- secs := float64((stop-start)/1e6) / 1e3
- stats := index.Stats()
- log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
- secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
- }
- log.Printf("before GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
- runtime.GC()
- log.Printf("after GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ updateIndex()
}
- var delay int64 = 60 * 1e9 // by default, try every 60s
+ delay := 60 * time.Second // by default, try every 60s
if *testDir != "" {
// in test mode, try once a second for fast startup
- delay = 1 * 1e9
+ delay = 1 * time.Second
}
time.Sleep(delay)
}
diff --git a/src/cmd/godoc/httpzip.go b/src/cmd/godoc/httpzip.go
deleted file mode 100644
index cb8322ee4..000000000
--- a/src/cmd/godoc/httpzip.go
+++ /dev/null
@@ -1,181 +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.
-
-// This file provides an implementation of the http.FileSystem
-// interface based on the contents of a .zip file.
-//
-// Assumptions:
-//
-// - The file paths stored in the zip file must use a slash ('/') as path
-// separator; and they must be relative (i.e., they must not start with
-// a '/' - this is usually the case if the file was created w/o special
-// options).
-// - The zip file system treats the file paths found in the zip internally
-// like absolute paths w/o a leading '/'; i.e., the paths are considered
-// relative to the root of the file system.
-// - All path arguments to file system methods are considered relative to
-// the root specified with NewHttpZipFS (even if the paths start with a '/').
-
-// TODO(gri) Should define a commonly used FileSystem API that is the same
-// for http and godoc. Then we only need one zip-file based file
-// system implementation.
-
-package main
-
-import (
- "archive/zip"
- "fmt"
- "http"
- "io"
- "os"
- "path"
- "sort"
- "strings"
-)
-
-// We cannot import syscall on app engine.
-// TODO(gri) Once we have a truly abstract FileInfo implementation
-// this won't be needed anymore.
-const (
- S_IFDIR = 0x4000 // == syscall.S_IFDIR
- S_IFREG = 0x8000 // == syscall.S_IFREG
-)
-
-// httpZipFile is the zip-file based implementation of http.File
-type httpZipFile struct {
- path string // absolute path within zip FS without leading '/'
- info os.FileInfo
- io.ReadCloser // nil for directory
- list zipList
-}
-
-func (f *httpZipFile) Close() os.Error {
- if f.info.IsRegular() {
- return f.ReadCloser.Close()
- }
- f.list = nil
- return nil
-}
-
-func (f *httpZipFile) Stat() (*os.FileInfo, os.Error) {
- return &f.info, nil
-}
-
-func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, os.Error) {
- var list []os.FileInfo
- dirname := f.path + "/"
- prevname := ""
- for i, e := range f.list {
- if count == 0 {
- f.list = f.list[i:]
- break
- }
- if !strings.HasPrefix(e.Name, dirname) {
- f.list = nil
- break // not in the same directory anymore
- }
- name := e.Name[len(dirname):] // local name
- var mode uint32
- var size, mtime_ns int64
- if i := strings.IndexRune(name, '/'); i >= 0 {
- // We infer directories from files in subdirectories.
- // If we have x/y, return a directory entry for x.
- name = name[0:i] // keep local directory name only
- mode = S_IFDIR
- // no size or mtime_ns for directories
- } else {
- mode = S_IFREG
- size = int64(e.UncompressedSize)
- mtime_ns = e.Mtime_ns()
- }
- // If we have x/y and x/z, don't return two directory entries for x.
- // TODO(gri): It should be possible to do this more efficiently
- // by determining the (fs.list) range of local directory entries
- // (via two binary searches).
- if name != prevname {
- list = append(list, os.FileInfo{
- Name: name,
- Mode: mode,
- Size: size,
- Mtime_ns: mtime_ns,
- })
- prevname = name
- count--
- }
- }
-
- if count >= 0 && len(list) == 0 {
- return nil, os.EOF
- }
-
- return list, nil
-}
-
-func (f *httpZipFile) Seek(offset int64, whence int) (int64, os.Error) {
- return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name)
-}
-
-// httpZipFS is the zip-file based implementation of http.FileSystem
-type httpZipFS struct {
- *zip.ReadCloser
- list zipList
- root string
-}
-
-func (fs *httpZipFS) Open(name string) (http.File, os.Error) {
- // fs.root does not start with '/'.
- path := path.Join(fs.root, name) // path is clean
- index, exact := fs.list.lookup(path)
- if index < 0 || !strings.HasPrefix(path, fs.root) {
- // file not found or not under root
- return nil, fmt.Errorf("file not found: %s", name)
- }
-
- if exact {
- // exact match found - must be a file
- f := fs.list[index]
- rc, err := f.Open()
- if err != nil {
- return nil, err
- }
- return &httpZipFile{
- path,
- os.FileInfo{
- Name: name,
- Mode: S_IFREG,
- Size: int64(f.UncompressedSize),
- Mtime_ns: f.Mtime_ns(),
- },
- rc,
- nil,
- }, nil
- }
-
- // not an exact match - must be a directory
- return &httpZipFile{
- path,
- os.FileInfo{
- Name: name,
- Mode: S_IFDIR,
- // no size or mtime_ns for directories
- },
- nil,
- fs.list[index:],
- }, nil
-}
-
-func (fs *httpZipFS) Close() os.Error {
- fs.list = nil
- return fs.ReadCloser.Close()
-}
-
-// NewHttpZipFS creates a new http.FileSystem based on the contents of
-// the zip file rc restricted to the directory tree specified by root;
-// root must be an absolute path.
-func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
- list := make(zipList, len(rc.File))
- copy(list, rc.File) // sort a copy of rc.File
- sort.Sort(list)
- return &httpZipFS{rc, list, zipPath(root)}
-}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 9b4f31514..1bef79693 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -7,7 +7,7 @@
//
// Algorithm for identifier index:
// - traverse all .go files of the file tree specified by root
-// - for each word (identifier) encountered, collect all occurrences (spots)
+// - for each identifier (word) encountered, collect all occurrences (spots)
// into a list; this produces a list of spots for each word
// - reduce the lists: from a list of spots to a list of FileRuns,
// and from a list of FileRuns into a list of PakRuns
@@ -38,62 +38,80 @@
package main
import (
+ "bufio"
"bytes"
- "container/vector"
+ "encoding/gob"
+ "errors"
"go/ast"
"go/parser"
"go/token"
- "go/scanner"
"index/suffixarray"
+ "io"
"os"
- "path/filepath"
+ pathpkg "path"
"regexp"
"sort"
"strings"
+ "time"
+ "unicode"
)
// ----------------------------------------------------------------------------
+// InterfaceSlice is a helper type for sorting interface
+// slices according to some slice-specific sort criteria.
+
+type Comparer func(x, y interface{}) bool
+
+type InterfaceSlice struct {
+ slice []interface{}
+ less Comparer
+}
+
+func (p *InterfaceSlice) Len() int { return len(p.slice) }
+func (p *InterfaceSlice) Less(i, j int) bool { return p.less(p.slice[i], p.slice[j]) }
+func (p *InterfaceSlice) Swap(i, j int) { p.slice[i], p.slice[j] = p.slice[j], p.slice[i] }
+
+// ----------------------------------------------------------------------------
// RunList
-// A RunList is a vector of entries that can be sorted according to some
+// A RunList is a list of entries that can be sorted according to some
// criteria. A RunList may be compressed by grouping "runs" of entries
// which are equal (according to the sort critera) into a new RunList of
// runs. For instance, a RunList containing pairs (x, y) may be compressed
// into a RunList containing pair runs (x, {y}) where each run consists of
// a list of y's with the same x.
-type RunList struct {
- vector.Vector
- less func(x, y interface{}) bool
-}
-
-func (h *RunList) Less(i, j int) bool { return h.less(h.At(i), h.At(j)) }
+type RunList []interface{}
-func (h *RunList) sort(less func(x, y interface{}) bool) {
- h.less = less
- sort.Sort(h)
+func (h RunList) sort(less Comparer) {
+ sort.Sort(&InterfaceSlice{h, less})
}
// Compress entries which are the same according to a sort criteria
// (specified by less) into "runs".
-func (h *RunList) reduce(less func(x, y interface{}) bool, newRun func(h *RunList, i, j int) interface{}) *RunList {
+func (h RunList) reduce(less Comparer, newRun func(h RunList) interface{}) RunList {
+ if len(h) == 0 {
+ return nil
+ }
+ // len(h) > 0
+
// create runs of entries with equal values
h.sort(less)
// for each run, make a new run object and collect them in a new RunList
var hh RunList
- i := 0
- for j := 0; j < h.Len(); j++ {
- if less(h.At(i), h.At(j)) {
- hh.Push(newRun(h, i, j))
- i = j // start a new run
+ i, x := 0, h[0]
+ for j, y := range h {
+ if less(x, y) {
+ hh = append(hh, newRun(h[i:j]))
+ i, x = j, h[j] // start a new run
}
}
// add final run, if any
- if i < h.Len() {
- hh.Push(newRun(h, i, h.Len()))
+ if i < len(h) {
+ hh = append(hh, newRun(h[i:]))
}
- return &hh
+ return hh
}
// ----------------------------------------------------------------------------
@@ -164,30 +182,25 @@ func (x SpotInfo) IsIndex() bool { return x&1 != 0 }
const removeDuplicates = true
// A KindRun is a run of SpotInfos of the same kind in a given file.
-type KindRun struct {
- Kind SpotKind
- Infos []SpotInfo
-}
+// The kind (3 bits) is stored in each SpotInfo element; to find the
+// kind of a KindRun, look at any of it's elements.
+type KindRun []SpotInfo
// KindRuns are sorted by line number or index. Since the isIndex bit
// is always the same for all infos in one list we can compare lori's.
-func (f *KindRun) Len() int { return len(f.Infos) }
-func (f *KindRun) Less(i, j int) bool { return f.Infos[i].Lori() < f.Infos[j].Lori() }
-func (f *KindRun) Swap(i, j int) { f.Infos[i], f.Infos[j] = f.Infos[j], f.Infos[i] }
+func (k KindRun) Len() int { return len(k) }
+func (k KindRun) Less(i, j int) bool { return k[i].Lori() < k[j].Lori() }
+func (k KindRun) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
// FileRun contents are sorted by Kind for the reduction into KindRuns.
func lessKind(x, y interface{}) bool { return x.(SpotInfo).Kind() < y.(SpotInfo).Kind() }
-// newKindRun allocates a new KindRun from the SpotInfo run [i, j) in h.
-func newKindRun(h *RunList, i, j int) interface{} {
- kind := h.At(i).(SpotInfo).Kind()
- infos := make([]SpotInfo, j-i)
- k := 0
- for ; i < j; i++ {
- infos[k] = h.At(i).(SpotInfo)
- k++
+// newKindRun allocates a new KindRun from the SpotInfo run h.
+func newKindRun(h RunList) interface{} {
+ run := make(KindRun, len(h))
+ for i, x := range h {
+ run[i] = x.(SpotInfo)
}
- run := &KindRun{kind, infos}
// Spots were sorted by file and kind to create this run.
// Within this run, sort them by line number or index.
@@ -199,15 +212,15 @@ func newKindRun(h *RunList, i, j int) interface{} {
// bit is always the same for all infos in one
// list we can simply compare the entire info.
k := 0
- var prev SpotInfo
- for i, x := range infos {
- if x != prev || i == 0 {
- infos[k] = x
+ prev := SpotInfo(1<<32 - 1) // an unlikely value
+ for _, x := range run {
+ if x != prev {
+ run[k] = x
k++
prev = x
}
}
- run.Infos = infos[0:k]
+ run = run[0:k]
}
return run
@@ -229,8 +242,13 @@ func (p *Pak) less(q *Pak) bool {
// A File describes a Go file.
type File struct {
- Path string // complete file name
- Pak Pak // the package to which the file belongs
+ Name string // directory-local file name
+ Pak *Pak // the package to which the file belongs
+}
+
+// Path returns the file path of f.
+func (f *File) Path() string {
+ return pathpkg.Join(f.Pak.Path, f.Name)
}
// A Spot describes a single occurrence of a word.
@@ -242,30 +260,34 @@ type Spot struct {
// A FileRun is a list of KindRuns belonging to the same file.
type FileRun struct {
File *File
- Groups []*KindRun
+ Groups []KindRun
}
-// Spots are sorted by path for the reduction into FileRuns.
-func lessSpot(x, y interface{}) bool { return x.(Spot).File.Path < y.(Spot).File.Path }
+// Spots are sorted by file path for the reduction into FileRuns.
+func lessSpot(x, y interface{}) bool {
+ fx := x.(Spot).File
+ fy := y.(Spot).File
+ // same as "return fx.Path() < fy.Path()" but w/o computing the file path first
+ px := fx.Pak.Path
+ py := fy.Pak.Path
+ return px < py || px == py && fx.Name < fy.Name
+}
-// newFileRun allocates a new FileRun from the Spot run [i, j) in h.
-func newFileRun(h0 *RunList, i, j int) interface{} {
- file := h0.At(i).(Spot).File
+// newFileRun allocates a new FileRun from the Spot run h.
+func newFileRun(h RunList) interface{} {
+ file := h[0].(Spot).File
// reduce the list of Spots into a list of KindRuns
- var h1 RunList
- h1.Vector.Resize(j-i, 0)
- k := 0
- for ; i < j; i++ {
- h1.Set(k, h0.At(i).(Spot).Info)
- k++
+ h1 := make(RunList, len(h))
+ for i, x := range h {
+ h1[i] = x.(Spot).Info
}
h2 := h1.reduce(lessKind, newKindRun)
// create the FileRun
- groups := make([]*KindRun, h2.Len())
- for i := 0; i < h2.Len(); i++ {
- groups[i] = h2.At(i).(*KindRun)
+ groups := make([]KindRun, len(h2))
+ for i, x := range h2 {
+ groups[i] = x.(KindRun)
}
return &FileRun{file, groups}
}
@@ -275,28 +297,26 @@ func newFileRun(h0 *RunList, i, j int) interface{} {
// A PakRun describes a run of *FileRuns of a package.
type PakRun struct {
- Pak Pak
+ Pak *Pak
Files []*FileRun
}
// Sorting support for files within a PakRun.
func (p *PakRun) Len() int { return len(p.Files) }
-func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Path < p.Files[j].File.Path }
+func (p *PakRun) Less(i, j int) bool { return p.Files[i].File.Name < p.Files[j].File.Name }
func (p *PakRun) Swap(i, j int) { p.Files[i], p.Files[j] = p.Files[j], p.Files[i] }
// FileRuns are sorted by package for the reduction into PakRuns.
func lessFileRun(x, y interface{}) bool {
- return x.(*FileRun).File.Pak.less(&y.(*FileRun).File.Pak)
+ return x.(*FileRun).File.Pak.less(y.(*FileRun).File.Pak)
}
-// newPakRun allocates a new PakRun from the *FileRun run [i, j) in h.
-func newPakRun(h *RunList, i, j int) interface{} {
- pak := h.At(i).(*FileRun).File.Pak
- files := make([]*FileRun, j-i)
- k := 0
- for ; i < j; i++ {
- files[k] = h.At(i).(*FileRun)
- k++
+// newPakRun allocates a new PakRun from the *FileRun run h.
+func newPakRun(h RunList) interface{} {
+ pak := h[0].(*FileRun).File.Pak
+ files := make([]*FileRun, len(h))
+ for i, x := range h {
+ files[i] = x.(*FileRun)
}
run := &PakRun{pak, files}
sort.Sort(run) // files were sorted by package; sort them by file now
@@ -310,9 +330,9 @@ func newPakRun(h *RunList, i, j int) interface{} {
type HitList []*PakRun
// PakRuns are sorted by package.
-func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(&y.(*PakRun).Pak) }
+func lessPakRun(x, y interface{}) bool { return x.(*PakRun).Pak.less(y.(*PakRun).Pak) }
-func reduce(h0 *RunList) HitList {
+func reduce(h0 RunList) HitList {
// reduce a list of Spots into a list of FileRuns
h1 := h0.reduce(lessSpot, newFileRun)
// reduce a list of FileRuns into a list of PakRuns
@@ -320,28 +340,20 @@ func reduce(h0 *RunList) HitList {
// sort the list of PakRuns by package
h2.sort(lessPakRun)
// create a HitList
- h := make(HitList, h2.Len())
- for i := 0; i < h2.Len(); i++ {
- h[i] = h2.At(i).(*PakRun)
+ h := make(HitList, len(h2))
+ for i, p := range h2 {
+ h[i] = p.(*PakRun)
}
return h
}
+// filter returns a new HitList created by filtering
+// all PakRuns from h that have a matching pakname.
func (h HitList) filter(pakname string) HitList {
- // determine number of matching packages (most of the time just one)
- n := 0
- for _, p := range h {
- if p.Pak.Name == pakname {
- n++
- }
- }
- // create filtered HitList
- hh := make(HitList, n)
- i := 0
+ var hh HitList
for _, p := range h {
if p.Pak.Name == pakname {
- hh[i] = p
- i++
+ hh = append(hh, p)
}
}
return hh
@@ -365,34 +377,27 @@ type AltWords struct {
// wordPairs are sorted by their canonical spelling.
func lessWordPair(x, y interface{}) bool { return x.(*wordPair).canon < y.(*wordPair).canon }
-// newAltWords allocates a new AltWords from the *wordPair run [i, j) in h.
-func newAltWords(h *RunList, i, j int) interface{} {
- canon := h.At(i).(*wordPair).canon
- alts := make([]string, j-i)
- k := 0
- for ; i < j; i++ {
- alts[k] = h.At(i).(*wordPair).alt
- k++
+// newAltWords allocates a new AltWords from the *wordPair run h.
+func newAltWords(h RunList) interface{} {
+ canon := h[0].(*wordPair).canon
+ alts := make([]string, len(h))
+ for i, x := range h {
+ alts[i] = x.(*wordPair).alt
}
return &AltWords{canon, alts}
}
func (a *AltWords) filter(s string) *AltWords {
- if len(a.Alts) == 1 && a.Alts[0] == s {
- // there are no different alternatives
- return nil
- }
-
- // make a new AltWords with the current spelling removed
- alts := make([]string, len(a.Alts))
- i := 0
+ var alts []string
for _, w := range a.Alts {
if w != s {
- alts[i] = w
- i++
+ alts = append(alts, w)
}
}
- return &AltWords{a.Canon, alts[0:i]}
+ if len(alts) > 0 {
+ return &AltWords{a.Canon, alts}
+ }
+ return nil
}
// ----------------------------------------------------------------------------
@@ -423,17 +428,32 @@ type Statistics struct {
type Indexer struct {
fset *token.FileSet // file set for all indexed files
sources bytes.Buffer // concatenated sources
+ packages map[string]*Pak // map of canonicalized *Paks
words map[string]*IndexResult // RunLists of Spots
- snippets vector.Vector // vector of *Snippets, indexed by snippet indices
+ snippets []*Snippet // indices are stored in SpotInfos
current *token.File // last file added to file set
file *File // AST for current file
decl ast.Decl // AST for current decl
stats Statistics
}
+func (x *Indexer) lookupPackage(path, name string) *Pak {
+ // In the source directory tree, more than one package may
+ // live in the same directory. For the packages map, construct
+ // a key that includes both the directory path and the package
+ // name.
+ key := path + ":" + name
+ pak := x.packages[key]
+ if pak == nil {
+ pak = &Pak{path, name}
+ x.packages[key] = pak
+ }
+ return pak
+}
+
func (x *Indexer) addSnippet(s *Snippet) int {
- index := x.snippets.Len()
- x.snippets.Push(s)
+ index := len(x.snippets)
+ x.snippets = append(x.snippets, s)
return index
}
@@ -454,12 +474,12 @@ func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
if kind == Use || x.decl == nil {
// not a declaration or no snippet required
info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
- lists.Others.Push(Spot{x.file, info})
+ lists.Others = append(lists.Others, Spot{x.file, info})
} else {
// a declaration with snippet
index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
info := makeSpotInfo(kind, index, true)
- lists.Decls.Push(Spot{x.file, info})
+ lists.Decls = append(lists.Decls, Spot{x.file, info})
}
x.stats.Spots++
@@ -675,7 +695,7 @@ var whitelisted = map[string]bool{
// of "permitted" files for indexing. The filename must
// be the directory-local name of the file.
func isWhitelisted(filename string) bool {
- key := filepath.Ext(filename)
+ key := pathpkg.Ext(filename)
if key == "" {
// file has no extension - use entire filename
key = filename
@@ -683,12 +703,12 @@ func isWhitelisted(filename string) bool {
return whitelisted[key]
}
-func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
- if !f.IsRegular() {
+func (x *Indexer) visitFile(dirname string, f os.FileInfo, fulltextIndex bool) {
+ if f.IsDir() {
return
}
- filename := filepath.Join(dirname, f.Name())
+ filename := pathpkg.Join(dirname, f.Name())
goFile := false
switch {
@@ -713,9 +733,8 @@ func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
if fast != nil {
// we've got a Go file to index
x.current = file
- dir, _ := filepath.Split(filename)
- pak := Pak{dir, fast.Name.Name}
- x.file = &File{filename, pak}
+ pak := x.lookupPackage(dirname, fast.Name.Name)
+ x.file = &File{f.Name(), pak}
ast.Walk(x, fast)
}
@@ -747,12 +766,15 @@ func canonical(w string) string { return strings.ToLower(w) }
// NewIndex creates a new index for the .go files
// in the directories given by dirnames.
//
-func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
+func NewIndex(dirnames <-chan string, fulltextIndex bool, throttle float64) *Index {
var x Indexer
+ th := NewThrottle(throttle, 100*time.Millisecond) // run at least 0.1s at a time
// initialize Indexer
+ // (use some reasonably sized maps to start)
x.fset = token.NewFileSet()
- x.words = make(map[string]*IndexResult)
+ x.packages = make(map[string]*Pak, 256)
+ x.words = make(map[string]*IndexResult, 8192)
// index all files in the directories given by dirnames
for dirname := range dirnames {
@@ -761,9 +783,10 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
continue // ignore this directory
}
for _, f := range list {
- if !f.IsDirectory() {
+ if !f.IsDir() {
x.visitFile(dirname, f, fulltextIndex)
}
+ th.Throttle()
}
}
@@ -782,13 +805,14 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
words := make(map[string]*LookupResult)
var wlist RunList
for w, h := range x.words {
- decls := reduce(&h.Decls)
- others := reduce(&h.Others)
+ decls := reduce(h.Decls)
+ others := reduce(h.Others)
words[w] = &LookupResult{
Decls: decls,
Others: others,
}
- wlist.Push(&wordPair{canonical(w), w})
+ wlist = append(wlist, &wordPair{canonical(w), w})
+ th.Throttle()
}
x.stats.Words = len(words)
@@ -798,24 +822,92 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
// convert alist into a map of alternative spellings
alts := make(map[string]*AltWords)
- for i := 0; i < alist.Len(); i++ {
- a := alist.At(i).(*AltWords)
+ for i := 0; i < len(alist); i++ {
+ a := alist[i].(*AltWords)
alts[a.Canon] = a
}
- // convert snippet vector into a list
- snippets := make([]*Snippet, x.snippets.Len())
- for i := 0; i < x.snippets.Len(); i++ {
- snippets[i] = x.snippets.At(i).(*Snippet)
- }
-
// create text index
var suffixes *suffixarray.Index
if fulltextIndex {
suffixes = suffixarray.New(x.sources.Bytes())
}
- return &Index{x.fset, suffixes, words, alts, snippets, x.stats}
+ return &Index{x.fset, suffixes, words, alts, x.snippets, x.stats}
+}
+
+type fileIndex struct {
+ Words map[string]*LookupResult
+ Alts map[string]*AltWords
+ Snippets []*Snippet
+ Fulltext bool
+}
+
+func (x *fileIndex) Write(w io.Writer) error {
+ return gob.NewEncoder(w).Encode(x)
+}
+
+func (x *fileIndex) Read(r io.Reader) error {
+ return gob.NewDecoder(r).Decode(x)
+}
+
+// Write writes the index x to w.
+func (x *Index) Write(w io.Writer) error {
+ fulltext := false
+ if x.suffixes != nil {
+ fulltext = true
+ }
+ fx := fileIndex{
+ x.words,
+ x.alts,
+ x.snippets,
+ fulltext,
+ }
+ if err := fx.Write(w); err != nil {
+ return err
+ }
+ if fulltext {
+ encode := func(x interface{}) error {
+ return gob.NewEncoder(w).Encode(x)
+ }
+ if err := x.fset.Write(encode); err != nil {
+ return err
+ }
+ if err := x.suffixes.Write(w); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Read reads the index from r into x; x must not be nil.
+// If r does not also implement io.ByteReader, it will be wrapped in a bufio.Reader.
+func (x *Index) Read(r io.Reader) error {
+ // We use the ability to read bytes as a plausible surrogate for buffering.
+ if _, ok := r.(io.ByteReader); !ok {
+ r = bufio.NewReader(r)
+ }
+ var fx fileIndex
+ if err := fx.Read(r); err != nil {
+ return err
+ }
+ x.words = fx.Words
+ x.alts = fx.Alts
+ x.snippets = fx.Snippets
+ if fx.Fulltext {
+ x.fset = token.NewFileSet()
+ decode := func(x interface{}) error {
+ return gob.NewDecoder(r).Decode(x)
+ }
+ if err := x.fset.Read(decode); err != nil {
+ return err
+ }
+ x.suffixes = new(suffixarray.Index)
+ if err := x.suffixes.Read(r); err != nil {
+ return err
+ }
+ }
+ return nil
}
// Stats() returns index statistics.
@@ -823,7 +915,7 @@ func (x *Index) Stats() Statistics {
return x.stats
}
-func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
+func (x *Index) lookupWord(w string) (match *LookupResult, alt *AltWords) {
match = x.words[w]
alt = x.alts[canonical(w)]
// remove current spelling from alternatives
@@ -835,47 +927,56 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
return
}
+// isIdentifier reports whether s is a Go identifier.
func isIdentifier(s string) bool {
- var S scanner.Scanner
- fset := token.NewFileSet()
- S.Init(fset.AddFile("", fset.Base(), len(s)), []byte(s), nil, 0)
- if _, tok, _ := S.Scan(); tok == token.IDENT {
- _, tok, _ := S.Scan()
- return tok == token.EOF
+ for i, ch := range s {
+ if unicode.IsLetter(ch) || ch == ' ' || i > 0 && unicode.IsDigit(ch) {
+ continue
+ }
+ return false
}
- return false
+ return len(s) > 0
}
// For a given query, which is either a single identifier or a qualified
-// identifier, Lookup returns a LookupResult, and a list of alternative
-// spellings, if any. If the query syntax is wrong, an error is reported.
-func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) {
+// identifier, Lookup returns a list of packages, a LookupResult, and a
+// list of alternative spellings, if any. Any and all results may be nil.
+// If the query syntax is wrong, an error is reported.
+func (x *Index) Lookup(query string) (paks HitList, match *LookupResult, alt *AltWords, err error) {
ss := strings.Split(query, ".")
// check query syntax
for _, s := range ss {
if !isIdentifier(s) {
- err = os.NewError("all query parts must be identifiers")
+ err = errors.New("all query parts must be identifiers")
return
}
}
+ // handle simple and qualified identifiers
switch len(ss) {
case 1:
- match, alt = x.LookupWord(ss[0])
+ ident := ss[0]
+ match, alt = x.lookupWord(ident)
+ if match != nil {
+ // found a match - filter packages with same name
+ // for the list of packages called ident, if any
+ paks = match.Others.filter(ident)
+ }
case 2:
- pakname := ss[0]
- match, alt = x.LookupWord(ss[1])
+ pakname, ident := ss[0], ss[1]
+ match, alt = x.lookupWord(ident)
if match != nil {
// found a match - filter by package name
+ // (no paks - package names are not qualified)
decls := match.Decls.filter(pakname)
others := match.Others.filter(pakname)
match = &LookupResult{decls, others}
}
default:
- err = os.NewError("query is not a (qualified) identifier")
+ err = errors.New("query is not a (qualified) identifier")
}
return
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 89b12b9ac..da4fc63b5 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -7,7 +7,7 @@
// Web server tree:
//
// http://godoc/ main landing page
-// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, tutorial, etc.
+// http://godoc/doc/ serve from $GOROOT/doc - spec, mem, etc.
// http://godoc/src/ serve files from $GOROOT/src; .go gets pretty-printed
// http://godoc/cmd/ serve documentation about commands
// http://godoc/pkg/ serve documentation about packages
@@ -28,23 +28,23 @@ package main
import (
"archive/zip"
"bytes"
+ "errors"
_ "expvar" // to serve /debug/vars
"flag"
"fmt"
"go/ast"
"go/build"
- "http"
- _ "http/pprof" // to serve /debug/pprof/*
"io"
"log"
+ "net/http"
+ _ "net/http/pprof" // to serve /debug/pprof/*
+ "net/url"
"os"
- "path"
+ pathpkg "path"
"path/filepath"
"regexp"
"runtime"
"strings"
- "time"
- "url"
)
const defaultAddr = ":6060" // default webserver address
@@ -54,10 +54,8 @@ var (
// (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico)
zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty")
- // periodic sync
- syncCmd = flag.String("sync", "", "sync command; disabled if empty")
- syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
- syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
+ // file-based index
+ writeIndex = flag.Bool("write_index", false, "write index to a file; the file name must be specified with -index_files")
// network
httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
@@ -66,83 +64,16 @@ var (
// layout control
html = flag.Bool("html", false, "print HTML in command-line mode")
srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
+ urlFlag = flag.String("url", "", "print HTML for named URL")
// command-line searches
query = flag.Bool("q", false, "arguments are considered search queries")
)
-func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
w.WriteHeader(http.StatusNotFound)
- servePage(w, "File "+relpath, "", "", contents)
-}
-
-func exec(rw http.ResponseWriter, args []string) (status int) {
- r, w, err := os.Pipe()
- if err != nil {
- log.Printf("os.Pipe(): %v", err)
- return 2
- }
-
- bin := args[0]
- fds := []*os.File{nil, w, w}
- if *verbose {
- log.Printf("executing %v", args)
- }
- p, err := os.StartProcess(bin, args, &os.ProcAttr{Files: fds, Dir: *goroot})
- defer r.Close()
- w.Close()
- if err != nil {
- log.Printf("os.StartProcess(%q): %v", bin, err)
- return 2
- }
- defer p.Release()
-
- var buf bytes.Buffer
- io.Copy(&buf, r)
- wait, err := p.Wait(0)
- if err != nil {
- os.Stderr.Write(buf.Bytes())
- log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
- return 2
- }
- status = wait.ExitStatus()
- if !wait.Exited() || status > 1 {
- os.Stderr.Write(buf.Bytes())
- log.Printf("executing %v failed (exit status = %d)", args, status)
- return
- }
-
- if *verbose {
- os.Stderr.Write(buf.Bytes())
- }
- if rw != nil {
- rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- rw.Write(buf.Bytes())
- }
-
- return
-}
-
-func dosync(w http.ResponseWriter, r *http.Request) {
- args := []string{"/bin/sh", "-c", *syncCmd}
- switch exec(w, args) {
- case 0:
- // sync succeeded and some files have changed;
- // update package tree.
- // TODO(gri): The directory tree may be temporarily out-of-sync.
- // Consider keeping separate time stamps so the web-
- // page can indicate this discrepancy.
- initFSTree()
- fallthrough
- case 1:
- // sync failed because no files changed;
- // don't change the package tree
- syncDelay.set(*syncMin) // revert to regular sync schedule
- default:
- // sync failed because of an error - back off exponentially, but try at least once a day
- syncDelay.backoff(24 * 60)
- }
+ servePage(w, relpath, "File "+relpath, "", "", contents)
}
func usage() {
@@ -160,9 +91,7 @@ func loggingHandler(h http.Handler) http.Handler {
})
}
-func remoteSearch(query string) (res *http.Response, err os.Error) {
- search := "/search?f=text&q=" + url.QueryEscape(query)
-
+func remoteSearch(query string) (res *http.Response, err error) {
// list of addresses to try
var addrs []string
if *serverAddr != "" {
@@ -176,6 +105,7 @@ func remoteSearch(query string) (res *http.Response, err os.Error) {
}
// remote search
+ search := remoteSearchURL(query, *html)
for _, addr := range addrs {
url := "http://" + addr + search
res, err = http.Get(url)
@@ -185,7 +115,7 @@ func remoteSearch(query string) (res *http.Response, err os.Error) {
}
if err == nil && res.StatusCode != http.StatusOK {
- err = os.NewError(res.Status)
+ err = errors.New(res.Status)
}
return
@@ -221,8 +151,8 @@ func main() {
flag.Usage = usage
flag.Parse()
- // Check usage: either server and no args, or command line and args
- if (*httpAddr != "") != (flag.NArg() == 0) {
+ // Check usage: either server and no args, command line and args, or index creation mode
+ if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
usage()
}
@@ -236,22 +166,93 @@ func main() {
// same is true for the http handlers in initHandlers.
if *zipfile == "" {
// use file system of underlying OS
- *goroot = filepath.Clean(*goroot) // normalize path separator
- fs = OS
- fsHttp = http.Dir(*goroot)
+ fs.Bind("/", OS(*goroot), "/", bindReplace)
+ if *templateDir != "" {
+ fs.Bind("/lib/godoc", OS(*templateDir), "/", bindBefore)
+ }
} else {
// use file system specified via .zip file (path separator must be '/')
rc, err := zip.OpenReader(*zipfile)
if err != nil {
log.Fatalf("%s: %s\n", *zipfile, err)
}
- *goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/'
- fs = NewZipFS(rc)
- fsHttp = NewHttpZipFS(rc, *goroot)
+ defer rc.Close() // be nice (e.g., -writeIndex mode)
+ fs.Bind("/", NewZipFS(rc, *zipfile), *goroot, bindReplace)
+ }
+
+ // Bind $GOPATH trees into Go root.
+ for _, p := range filepath.SplitList(build.Default.GOPATH) {
+ fs.Bind("/src/pkg", OS(p), "/src", bindAfter)
}
- initHandlers()
readTemplates()
+ initHandlers()
+
+ if *writeIndex {
+ // Write search index and exit.
+ if *indexFiles == "" {
+ log.Fatal("no index file specified")
+ }
+
+ log.Println("initialize file systems")
+ *verbose = true // want to see what happens
+ initFSTree()
+
+ *indexThrottle = 1
+ updateIndex()
+
+ log.Println("writing index file", *indexFiles)
+ f, err := os.Create(*indexFiles)
+ if err != nil {
+ log.Fatal(err)
+ }
+ index, _ := searchIndex.get()
+ err = index.(*Index).Write(f)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ log.Println("done")
+ return
+ }
+
+ // Print content that would be served at the URL *urlFlag.
+ if *urlFlag != "" {
+ registerPublicHandlers(http.DefaultServeMux)
+ // Try up to 10 fetches, following redirects.
+ urlstr := *urlFlag
+ for i := 0; i < 10; i++ {
+ // Prepare request.
+ u, err := url.Parse(urlstr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ req := &http.Request{
+ URL: u,
+ }
+
+ // Invoke default HTTP handler to serve request
+ // to our buffering httpWriter.
+ w := &httpWriter{h: http.Header{}, code: 200}
+ http.DefaultServeMux.ServeHTTP(w, req)
+
+ // Return data, error, or follow redirect.
+ switch w.code {
+ case 200: // ok
+ os.Stdout.Write(w.Bytes())
+ return
+ case 301, 302, 303, 307: // redirect
+ redirect := w.h.Get("Location")
+ if redirect == "" {
+ log.Fatalf("HTTP %d without Location header", w.code)
+ }
+ urlstr = redirect
+ default:
+ log.Fatalf("HTTP error %d", w.code)
+ }
+ }
+ log.Fatalf("too many redirects")
+ }
if *httpAddr != "" {
// HTTP server mode.
@@ -270,41 +271,26 @@ func main() {
default:
log.Print("identifier search index enabled")
}
- if !fsMap.IsEmpty() {
- log.Print("user-defined mapping:")
- fsMap.Fprint(os.Stderr)
- }
+ fs.Fprint(os.Stderr)
handler = loggingHandler(handler)
}
registerPublicHandlers(http.DefaultServeMux)
- if *syncCmd != "" {
- http.Handle("/debug/sync", http.HandlerFunc(dosync))
- }
+
+ // Playground handlers are not available in local godoc.
+ http.HandleFunc("/compile", disabledHandler)
+ http.HandleFunc("/share", disabledHandler)
// Initialize default directory tree with corresponding timestamp.
// (Do it in a goroutine so that launch is quick.)
go initFSTree()
- // Initialize directory trees for user-defined file systems (-path flag).
- initDirTrees()
-
- // Start sync goroutine, if enabled.
- if *syncCmd != "" && *syncMin > 0 {
- syncDelay.set(*syncMin) // initial sync delay
- go func() {
- for {
- dosync(nil, nil)
- delay, _ := syncDelay.get()
- if *verbose {
- log.Printf("next sync in %dmin", delay.(int))
- }
- time.Sleep(int64(delay.(int)) * 60e9)
- }
- }()
- }
+ // Immediately update metadata.
+ updateMetadata()
+ // Periodically refresh metadata.
+ go refreshMetadataLoop()
- // Start indexing goroutine.
+ // Initialize search index.
if *indexEnabled {
go indexer()
}
@@ -335,52 +321,92 @@ func main() {
return
}
- // determine paths
+ // Determine paths.
+ //
+ // If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc,
+ // we need to map that path somewhere in the fs name space so that routines
+ // like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target"
+ // for this. That is, if we get passed a directory like the above, we map that
+ // directory so that getPageInfo sees it as /target.
+ const target = "/target"
+ const cmdPrefix = "cmd/"
path := flag.Arg(0)
- if len(path) > 0 && path[0] == '.' {
- // assume cwd; don't assume -goroot
+ var forceCmd bool
+ var abspath, relpath string
+ if filepath.IsAbs(path) {
+ fs.Bind(target, OS(path), "/", bindReplace)
+ abspath = target
+ } else if build.IsLocalImport(path) {
cwd, _ := os.Getwd() // ignore errors
path = filepath.Join(cwd, path)
- }
- relpath := path
- abspath := path
- if t, pkg, err := build.FindTree(path); err == nil {
- relpath = pkg
- abspath = filepath.Join(t.SrcDir(), pkg)
- } else if !filepath.IsAbs(path) {
- abspath = absolutePath(path, pkgHandler.fsRoot)
+ fs.Bind(target, OS(path), "/", bindReplace)
+ abspath = target
+ } else if strings.HasPrefix(path, cmdPrefix) {
+ path = path[len(cmdPrefix):]
+ forceCmd = true
+ } else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
+ fs.Bind(target, OS(bp.Dir), "/", bindReplace)
+ abspath = target
+ relpath = bp.ImportPath
} else {
- relpath = relativeURL(path)
+ abspath = pathpkg.Join(pkgHandler.fsRoot, path)
+ }
+ if relpath == "" {
+ relpath = abspath
}
var mode PageInfoMode
+ if relpath == builtinPkgPath {
+ // the fake built-in package contains unexported identifiers
+ mode = noFiltering
+ }
if *srcMode {
// only filter exports if we don't have explicit command-line filter arguments
- if flag.NArg() == 1 {
- mode |= exportsOnly
+ if flag.NArg() > 1 {
+ mode |= noFiltering
}
- } else {
- mode = exportsOnly | genDoc
+ mode |= showSource
}
// TODO(gri): Provide a mechanism (flag?) to select a package
// if there are multiple packages in a directory.
- info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
+ // first, try as package unless forced as command
+ var info PageInfo
+ if !forceCmd {
+ info = pkgHandler.getPageInfo(abspath, relpath, "", mode)
+ }
+
+ // second, try as command unless the path is absolute
+ // (the go command invokes godoc w/ absolute paths; don't override)
+ var cinfo PageInfo
+ if !filepath.IsAbs(path) {
+ abspath = pathpkg.Join(cmdHandler.fsRoot, path)
+ cinfo = cmdHandler.getPageInfo(abspath, relpath, "", mode)
+ }
+
+ // determine what to use
if info.IsEmpty() {
- // try again, this time assume it's a command
- if !filepath.IsAbs(path) {
- abspath = absolutePath(path, cmdHandler.fsRoot)
+ if !cinfo.IsEmpty() {
+ // only cinfo exists - switch to cinfo
+ info = cinfo
}
- cmdInfo := cmdHandler.getPageInfo(abspath, relpath, "", mode)
- // only use the cmdInfo if it actually contains a result
- // (don't hide errors reported from looking up a package)
- if !cmdInfo.IsEmpty() {
- info = cmdInfo
+ } else if !cinfo.IsEmpty() {
+ // both info and cinfo exist - use cinfo if info
+ // contains only subdirectory information
+ if info.PAst == nil && info.PDoc == nil {
+ info = cinfo
+ } else {
+ fmt.Printf("use 'godoc %s%s' for documentation on the %s command \n\n", cmdPrefix, relpath, relpath)
}
}
+
if info.Err != nil {
log.Fatalf("%v", info.Err)
}
+ if info.PDoc != nil && info.PDoc.ImportPath == target {
+ // Replace virtual /target with actual argument from command line.
+ info.PDoc.ImportPath = flag.Arg(0)
+ }
// If we have more than one argument, use the remaining arguments for filtering
if flag.NArg() > 1 {
@@ -421,3 +447,19 @@ func main() {
log.Printf("packageText.Execute: %s", err)
}
}
+
+// An httpWriter is an http.ResponseWriter writing to a bytes.Buffer.
+type httpWriter struct {
+ bytes.Buffer
+ h http.Header
+ code int
+}
+
+func (w *httpWriter) Header() http.Header { return w.h }
+func (w *httpWriter) WriteHeader(code int) { w.code = code }
+
+// disabledHandler serves a 501 "Not Implemented" response.
+func disabledHandler(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+ fmt.Fprint(w, "This functionality is not available via local godoc.")
+}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
deleted file mode 100644
index 51f23ab98..000000000
--- a/src/cmd/godoc/mapping.go
+++ /dev/null
@@ -1,200 +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.
-
-// This file implements the Mapping data structure.
-
-package main
-
-import (
- "fmt"
- "io"
- "path"
- "path/filepath"
- "sort"
- "strings"
-)
-
-// A Mapping object maps relative paths (e.g. from URLs)
-// to absolute paths (of the file system) and vice versa.
-//
-// A Mapping object consists of a list of individual mappings
-// of the form: prefix -> path which are interpreted as follows:
-// A relative path of the form prefix/tail is to be mapped to
-// the absolute path/tail, if that absolute path exists in the file
-// system. Given a Mapping object, a relative path is mapped to an
-// absolute path by trying each of the individual mappings in order,
-// until a valid mapping is found. For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the relative paths below are mapped to absolute paths as follows:
-//
-// user/foo -> /home/user/foo
-// public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
-//
-// If there is no /home/user/public/net/rpc/file2.go, the next public
-// mapping entry is used to map the relative path to:
-//
-// public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
-//
-// (assuming that file exists).
-//
-// Each individual mapping also has a RWValue associated with it that
-// may be used to store mapping-specific information. See the Iterate
-// method.
-//
-type Mapping struct {
- list []mapping
- prefixes []string // lazily computed from list
-}
-
-type mapping struct {
- prefix, path string
- value *RWValue
-}
-
-// Init initializes the Mapping from a list of paths.
-// Empty paths are ignored; relative paths are assumed to be relative to
-// the current working directory and converted to absolute paths.
-// For each path of the form:
-//
-// dirname/localname
-//
-// a mapping
-//
-// localname -> path
-//
-// is added to the Mapping object, in the order of occurrence.
-// For instance, under Unix, the argument:
-//
-// /home/user:/home/build/public
-//
-// leads to the following mapping:
-//
-// user -> /home/user
-// public -> /home/build/public
-//
-func (m *Mapping) Init(paths []string) {
- pathlist := canonicalizePaths(paths, nil)
- list := make([]mapping, len(pathlist))
-
- // create mapping list
- for i, path := range pathlist {
- _, prefix := filepath.Split(path)
- list[i] = mapping{prefix, path, new(RWValue)}
- }
-
- m.list = list
-}
-
-// IsEmpty returns true if there are no mappings specified.
-func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
-
-// PrefixList returns a list of all prefixes, with duplicates removed.
-// For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the prefix list is:
-//
-// user, public
-//
-func (m *Mapping) PrefixList() []string {
- // compute the list lazily
- if m.prefixes == nil {
- list := make([]string, len(m.list))
-
- // populate list
- for i, e := range m.list {
- list[i] = e.prefix
- }
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i := 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- m.prefixes = list[0:i]
- }
-
- return m.prefixes
-}
-
-// Fprint prints the mapping.
-func (m *Mapping) Fprint(w io.Writer) {
- for _, e := range m.list {
- fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
- }
-}
-
-func splitFirst(path string) (head, tail string) {
- i := strings.Index(path, string(filepath.Separator))
- if i > 0 {
- // 0 < i < len(path)
- return path[0:i], path[i+1:]
- }
- return "", path
-}
-
-// ToAbsolute maps a slash-separated relative path to an absolute filesystem
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToAbsolute(spath string) string {
- fpath := filepath.FromSlash(spath)
- prefix, tail := splitFirst(fpath)
- for _, e := range m.list {
- switch {
- case e.prefix == prefix:
- // use tail
- case e.prefix == "":
- tail = fpath
- default:
- continue // no match
- }
- abspath := filepath.Join(e.path, tail)
- if _, err := fs.Stat(abspath); err == nil {
- return abspath
- }
- }
-
- return "" // no match
-}
-
-// ToRelative maps an absolute filesystem path to a relative slash-separated
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToRelative(fpath string) string {
- for _, e := range m.list {
- if strings.HasPrefix(fpath, e.path) {
- spath := filepath.ToSlash(fpath)
- // /absolute/prefix/foo -> prefix/foo
- return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
- }
- }
- return "" // no match
-}
-
-// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
-// until f returns false.
-//
-func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
- for _, e := range m.list {
- if !f(e.path, e.value) {
- return
- }
- }
-}
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
index da4b3853c..c6b7c2dc8 100644
--- a/src/cmd/godoc/parser.go
+++ b/src/cmd/godoc/parser.go
@@ -14,21 +14,21 @@ import (
"go/parser"
"go/token"
"os"
- "path/filepath"
+ pathpkg "path"
)
-func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.Package, first os.Error) {
+func parseFile(fset *token.FileSet, filename string, mode parser.Mode) (*ast.File, error) {
+ src, err := ReadFile(fs, filename)
+ if err != nil {
+ return nil, err
+ }
+ return parser.ParseFile(fset, filename, src, mode)
+}
+
+func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.Package, first error) {
pkgs = make(map[string]*ast.Package)
for _, filename := range filenames {
- src, err := fs.ReadFile(filename)
- if err != nil {
- if first == nil {
- first = err
- }
- continue
- }
-
- file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
+ file, err := parseFile(fset, filename, parser.ParseComments)
if err != nil {
if first == nil {
first = err
@@ -40,7 +40,7 @@ func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.P
pkg, found := pkgs[name]
if !found {
// TODO(gri) Use NewPackage here; reconsider ParseFiles API.
- pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
+ pkg = &ast.Package{Name: name, Files: make(map[string]*ast.File)}
pkgs[name] = pkg
}
pkg.Files[filename] = file
@@ -48,7 +48,7 @@ func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.P
return
}
-func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map[string]*ast.Package, os.Error) {
+func parseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool) (map[string]*ast.Package, error) {
list, err := fs.ReadDir(path)
if err != nil {
return nil, err
@@ -58,7 +58,7 @@ func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map
i := 0
for _, d := range list {
if filter == nil || filter(d) {
- filenames[i] = filepath.Join(path, d.Name())
+ filenames[i] = pathpkg.Join(path, d.Name())
i++
}
}
diff --git a/src/cmd/godoc/setup-godoc-app.bash b/src/cmd/godoc/setup-godoc-app.bash
new file mode 100644
index 000000000..755d965d5
--- /dev/null
+++ b/src/cmd/godoc/setup-godoc-app.bash
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This script creates the .zip, index, and configuration files for running
+# godoc on app-engine.
+#
+# If an argument is provided it is assumed to be the app-engine godoc directory.
+# Without an argument, $APPDIR is used instead. If GOROOT is not set, the
+# current working directory is assumed to be $GOROOT. Various sanity checks
+# prevent accidents.
+#
+# The script creates a .zip file representing the $GOROOT file system
+# and computes the correspondig search index files. These files are then
+# copied to $APPDIR. A corresponding godoc configuration file is created
+# in $APPDIR/appconfig.go.
+
+ZIPFILE=godoc.zip
+INDEXFILE=godoc.index
+SPLITFILES=index.split.
+CONFIGFILE=godoc/appconfig.go
+
+error() {
+ echo "error: $1"
+ exit 2
+}
+
+getArgs() {
+ if [ -z $GOROOT ]; then
+ GOROOT=$(pwd)
+ echo "GOROOT not set, using cwd instead"
+ fi
+ if [ -z $APPDIR ]; then
+ if [ $# == 0 ]; then
+ error "APPDIR not set, and no argument provided"
+ fi
+ APPDIR=$1
+ echo "APPDIR not set, using argument instead"
+ fi
+
+ # safety checks
+ if [ ! -d $GOROOT ]; then
+ error "$GOROOT is not a directory"
+ fi
+ if [ ! -x $GOROOT/src/cmd/godoc/godoc ]; then
+ error "$GOROOT/src/cmd/godoc/godoc does not exist or is not executable"
+ fi
+ if [ ! -d $APPDIR ]; then
+ error "$APPDIR is not a directory"
+ fi
+ if [ ! -e $APPDIR/app.yaml ]; then
+ error "$APPDIR is not an app-engine directory; missing file app.yaml"
+ fi
+ if [ ! -d $APPDIR/godoc ]; then
+ error "$APPDIR is missing directory godoc"
+ fi
+
+ # reporting
+ echo "GOROOT = $GOROOT"
+ echo "APPDIR = $APPDIR"
+}
+
+cleanup() {
+ echo "*** cleanup $APPDIR"
+ rm $APPDIR/$ZIPFILE
+ rm $APPDIR/$INDEXFILE
+ rm $APPDIR/$SPLITFILES*
+ rm $APPDIR/$CONFIGFILE
+}
+
+makeZipfile() {
+ echo "*** make $APPDIR/$ZIPFILE"
+ zip -q -r $APPDIR/$ZIPFILE $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i \*.ico
+}
+
+makeIndexfile() {
+ echo "*** make $APPDIR/$INDEXFILE"
+ OUT=/tmp/godoc.out
+ $GOROOT/src/cmd/godoc/godoc -write_index -index_files=$APPDIR/$INDEXFILE -zip=$APPDIR/$ZIPFILE 2> $OUT
+ if [ $? != 0 ]; then
+ error "$GOROOT/src/cmd/godoc/godoc failed - see $OUT for details"
+ fi
+}
+
+splitIndexfile() {
+ echo "*** split $APPDIR/$INDEXFILE"
+ split -b8m $APPDIR/$INDEXFILE $APPDIR/$SPLITFILES
+}
+
+makeConfigfile() {
+ echo "*** make $APPDIR/$CONFIGFILE"
+ cat > $APPDIR/$CONFIGFILE <<EOF
+package main
+
+// GENERATED FILE - DO NOT MODIFY BY HAND.
+// (generated by $GOROOT/src/cmd/godoc/setup-godoc-app.bash)
+
+const (
+ // .zip filename
+ zipFilename = "$ZIPFILE"
+
+ // goroot directory in .zip file
+ zipGoroot = "$GOROOT"
+
+ // glob pattern describing search index files
+ // (if empty, the index is built at run-time)
+ indexFilenames = "$SPLITFILES*"
+)
+EOF
+}
+
+getArgs "$@"
+cleanup
+makeZipfile
+makeIndexfile
+splitIndexfile
+makeConfigfile
+
+echo "*** setup complete"
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
index 68e27d9a0..b482b7487 100755..100644
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -11,9 +11,9 @@ package main
import (
"bytes"
+ "fmt"
"go/ast"
"go/token"
- "fmt"
)
type Snippet struct {
@@ -62,7 +62,14 @@ func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
}
// only use the spec containing the id for the snippet
- dd := &ast.GenDecl{d.Doc, d.Pos(), d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
+ dd := &ast.GenDecl{
+ Doc: d.Doc,
+ TokPos: d.Pos(),
+ Tok: d.Tok,
+ Lparen: d.Lparen,
+ Specs: []ast.Spec{s},
+ Rparen: d.Rparen,
+ }
return newSnippet(fset, dd, id)
}
@@ -73,7 +80,12 @@ func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
}
// only use the function signature for the snippet
- dd := &ast.FuncDecl{d.Doc, d.Recv, d.Name, d.Type, nil}
+ dd := &ast.FuncDecl{
+ Doc: d.Doc,
+ Recv: d.Recv,
+ Name: d.Name,
+ Type: d.Type,
+ }
return newSnippet(fset, dd, id)
}
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index 3f69add86..c11f25d20 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -2,118 +2,103 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package main
+
// This file contains the mechanism to "linkify" html source
// text containing EBNF sections (as found in go_spec.html).
// The result is the input source text with the EBNF sections
// modified such that identifiers are linked to the respective
// definitions.
-package main
-
import (
"bytes"
"fmt"
- "go/scanner"
- "go/token"
"io"
+ "text/scanner"
)
type ebnfParser struct {
- out io.Writer // parser output
- src []byte // parser source
- file *token.File // for position information
+ out io.Writer // parser output
+ src []byte // parser input
scanner scanner.Scanner
- prev int // offset of previous token
- pos token.Pos // token position
- tok token.Token // one token look-ahead
- lit string // token literal
+ prev int // offset of previous token
+ pos int // offset of current token
+ tok rune // one token look-ahead
+ lit string // token literal
}
func (p *ebnfParser) flush() {
- offs := p.file.Offset(p.pos)
- p.out.Write(p.src[p.prev:offs])
- p.prev = offs
+ p.out.Write(p.src[p.prev:p.pos])
+ p.prev = p.pos
}
func (p *ebnfParser) next() {
- if p.pos.IsValid() {
- p.flush()
- }
- p.pos, p.tok, p.lit = p.scanner.Scan()
- if p.tok.IsKeyword() {
- // TODO Should keyword mapping always happen outside scanner?
- // Or should there be a flag to scanner to enable keyword mapping?
- p.tok = token.IDENT
- }
+ p.tok = p.scanner.Scan()
+ p.pos = p.scanner.Position.Offset
+ p.lit = p.scanner.TokenText()
}
-func (p *ebnfParser) Error(pos token.Position, msg string) {
- fmt.Fprintf(p.out, `<span class="alert">error: %s</span>`, msg)
+func (p *ebnfParser) printf(format string, args ...interface{}) {
+ p.flush()
+ fmt.Fprintf(p.out, format, args...)
}
-func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
- msg = "expected " + msg
- if pos == p.pos {
- // the error happened at the current position;
- // make the error message more specific
- msg += ", found '" + p.tok.String() + "'"
- if p.tok.IsLiteral() {
- msg += " " + p.lit
- }
- }
- p.Error(p.file.Position(pos), msg)
+func (p *ebnfParser) errorExpected(msg string) {
+ p.printf(`<span class="highlight">error: expected %s, found %s</span>`, msg, scanner.TokenString(p.tok))
}
-func (p *ebnfParser) expect(tok token.Token) token.Pos {
- pos := p.pos
+func (p *ebnfParser) expect(tok rune) {
if p.tok != tok {
- p.errorExpected(pos, "'"+tok.String()+"'")
+ p.errorExpected(scanner.TokenString(tok))
}
p.next() // make progress in any case
- return pos
}
func (p *ebnfParser) parseIdentifier(def bool) {
- name := p.lit
- p.expect(token.IDENT)
- if def {
- fmt.Fprintf(p.out, `<a id="%s">%s</a>`, name, name)
+ if p.tok == scanner.Ident {
+ name := p.lit
+ if def {
+ p.printf(`<a id="%s">%s</a>`, name, name)
+ } else {
+ p.printf(`<a href="#%s" class="noline">%s</a>`, name, name)
+ }
+ p.prev += len(name) // skip identifier when printing next time
+ p.next()
} else {
- fmt.Fprintf(p.out, `<a href="#%s" class="noline">%s</a>`, name, name)
+ p.expect(scanner.Ident)
}
- p.prev += len(name) // skip identifier when calling flush
}
func (p *ebnfParser) parseTerm() bool {
switch p.tok {
- case token.IDENT:
+ case scanner.Ident:
p.parseIdentifier(false)
- case token.STRING:
+ case scanner.String:
p.next()
- const ellipsis = "…" // U+2026, the horizontal ellipsis character
- if p.tok == token.ILLEGAL && p.lit == ellipsis {
+ const ellipsis = '…' // U+2026, the horizontal ellipsis character
+ if p.tok == ellipsis {
p.next()
- p.expect(token.STRING)
+ p.expect(scanner.String)
}
- case token.LPAREN:
+ case '(':
p.next()
p.parseExpression()
- p.expect(token.RPAREN)
+ p.expect(')')
- case token.LBRACK:
+ case '[':
p.next()
p.parseExpression()
- p.expect(token.RBRACK)
+ p.expect(']')
- case token.LBRACE:
+ case '{':
p.next()
p.parseExpression()
- p.expect(token.RBRACE)
+ p.expect('}')
default:
- return false
+ return false // no term found
}
return true
@@ -121,7 +106,7 @@ func (p *ebnfParser) parseTerm() bool {
func (p *ebnfParser) parseSequence() {
if !p.parseTerm() {
- p.errorExpected(p.pos, "term")
+ p.errorExpected("term")
}
for p.parseTerm() {
}
@@ -130,7 +115,7 @@ func (p *ebnfParser) parseSequence() {
func (p *ebnfParser) parseExpression() {
for {
p.parseSequence()
- if p.tok != token.OR {
+ if p.tok != '|' {
break
}
p.next()
@@ -139,23 +124,22 @@ func (p *ebnfParser) parseExpression() {
func (p *ebnfParser) parseProduction() {
p.parseIdentifier(true)
- p.expect(token.ASSIGN)
- if p.tok != token.PERIOD {
+ p.expect('=')
+ if p.tok != '.' {
p.parseExpression()
}
- p.expect(token.PERIOD)
+ p.expect('.')
}
-func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
+func (p *ebnfParser) parse(out io.Writer, src []byte) {
// initialize ebnfParser
p.out = out
p.src = src
- p.file = fset.AddFile("", fset.Base(), len(src))
- p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars)
+ p.scanner.Init(bytes.NewBuffer(src))
p.next() // initializes pos, tok, lit
// process source
- for p.tok != token.EOF {
+ for p.tok != scanner.EOF {
p.parseProduction()
}
p.flush()
@@ -167,32 +151,29 @@ var (
closeTag = []byte(`</pre>`)
)
-func linkify(out io.Writer, src []byte) {
- fset := token.NewFileSet()
+func Linkify(out io.Writer, src []byte) {
for len(src) > 0 {
- n := len(src)
-
// i: beginning of EBNF text (or end of source)
i := bytes.Index(src, openTag)
if i < 0 {
- i = n - len(openTag)
+ i = len(src) - len(openTag)
}
i += len(openTag)
// j: end of EBNF text (or end of source)
- j := bytes.Index(src[i:n], closeTag) // close marker
+ j := bytes.Index(src[i:], closeTag) // close marker
if j < 0 {
- j = n - i
+ j = len(src) - i
}
j += i
// write text before EBNF
out.Write(src[0:i])
- // parse and write EBNF
+ // process EBNF
var p ebnfParser
- p.parse(fset, out, src[i:j])
+ p.parse(out, src[i:j])
// advance
- src = src[j:n]
+ src = src[j:]
}
}
diff --git a/src/cmd/godoc/template.go b/src/cmd/godoc/template.go
new file mode 100644
index 000000000..d709baef4
--- /dev/null
+++ b/src/cmd/godoc/template.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.
+
+// Template support for writing HTML documents.
+// Documents that include Template: true in their
+// metadata are executed as input to text/template.
+//
+// This file defines functions for those templates to invoke.
+
+// The template uses the function "code" to inject program
+// source into the output by extracting code from files and
+// injecting them as HTML-escaped <pre> blocks.
+//
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+// {{code "foo.go"}}
+// One line (here the signature of main):
+// {{code "foo.go" `/^func.main/`}}
+// Block of text, determined by start and end (here the body of main):
+// {{code "foo.go" `/^func.main/` `/^}/`
+//
+// Patterns can be `/regular expression/`, a decimal number, or "$"
+// to signify the end of the file. In multi-line matches,
+// lines that end with the four characters
+// OMIT
+// are omitted from the output, making it easy to provide marker
+// lines in the input that will not appear in the output but are easy
+// to identify by pattern.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "regexp"
+ "strings"
+ "text/template"
+)
+
+// Functions in this file panic on error, but the panic is recovered
+// to an error by 'code'.
+
+var templateFuncs = template.FuncMap{
+ "code": code,
+}
+
+// contents reads and returns the content of the named file
+// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
+func contents(name string) string {
+ file, err := ReadFile(fs, name)
+ if err != nil {
+ log.Panic(err)
+ }
+ return string(file)
+}
+
+// format returns a textual representation of the arg, formatted according to its nature.
+func format(arg interface{}) string {
+ switch arg := arg.(type) {
+ case int:
+ return fmt.Sprintf("%d", arg)
+ case string:
+ if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
+ return fmt.Sprintf("%#q", arg)
+ }
+ return fmt.Sprintf("%q", arg)
+ default:
+ log.Panicf("unrecognized argument: %v type %T", arg, arg)
+ }
+ return ""
+}
+
+func code(file string, arg ...interface{}) (s string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("%v", r)
+ }
+ }()
+
+ text := contents(file)
+ var command string
+ switch len(arg) {
+ case 0:
+ // text is already whole file.
+ command = fmt.Sprintf("code %q", file)
+ case 1:
+ command = fmt.Sprintf("code %q %s", file, format(arg[0]))
+ text = oneLine(file, text, arg[0])
+ case 2:
+ command = fmt.Sprintf("code %q %s %s", file, format(arg[0]), format(arg[1]))
+ text = multipleLines(file, text, arg[0], arg[1])
+ default:
+ return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
+ }
+ // Trim spaces from output.
+ text = strings.Trim(text, "\n")
+ // Replace tabs by spaces, which work better in HTML.
+ text = strings.Replace(text, "\t", " ", -1)
+ var buf bytes.Buffer
+ // HTML-escape text and syntax-color comments like elsewhere.
+ FormatText(&buf, []byte(text), -1, true, "", nil)
+ // Include the command as a comment.
+ text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, buf.Bytes())
+ return text, nil
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, file string, max int) (ival int, sval string, isInt bool) {
+ switch n := arg.(type) {
+ case int:
+ if n <= 0 || n > max {
+ log.Panicf("%q:%d is out of range", file, n)
+ }
+ return n, "", true
+ case string:
+ return 0, n, false
+ }
+ log.Panicf("unrecognized argument %v type %T", arg, arg)
+ return
+}
+
+// oneLine returns the single line generated by a two-argument code invocation.
+func oneLine(file, text string, arg interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line, pattern, isInt := parseArg(arg, file, len(lines))
+ if isInt {
+ return lines[line-1]
+ }
+ return lines[match(file, 0, lines, pattern)-1]
+}
+
+// multipleLines returns the text generated by a three-argument code invocation.
+func multipleLines(file, text string, arg1, arg2 interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
+ line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
+ if !isInt1 {
+ line1 = match(file, 0, lines, pattern1)
+ }
+ if !isInt2 {
+ line2 = match(file, line1, lines, pattern2)
+ } else if line2 < line1 {
+ log.Panicf("lines out of order for %q: %d %d", text, line1, line2)
+ }
+ for k := line1 - 1; k < line2; k++ {
+ if strings.HasSuffix(lines[k], "OMIT\n") {
+ lines[k] = ""
+ }
+ }
+ return strings.Join(lines[line1-1:line2], "")
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) int {
+ // $ matches the end of the file.
+ if pattern == "$" {
+ if len(lines) == 0 {
+ log.Panicf("%q: empty file", file)
+ }
+ return len(lines)
+ }
+ // /regexp/ matches the line that matches the regexp.
+ if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+ re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+ if err != nil {
+ log.Panic(err)
+ }
+ for i := start; i < len(lines); i++ {
+ if re.MatchString(lines[i]) {
+ return i + 1
+ }
+ }
+ log.Panicf("%s: no match for %#q", file, pattern)
+ }
+ log.Panicf("unrecognized pattern: %q", pattern)
+ return 0
+}
diff --git a/src/cmd/godoc/throttle.go b/src/cmd/godoc/throttle.go
new file mode 100644
index 000000000..ac18b44e0
--- /dev/null
+++ b/src/cmd/godoc/throttle.go
@@ -0,0 +1,88 @@
+// 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 "time"
+
+// A Throttle permits throttling of a goroutine by
+// calling the Throttle method repeatedly.
+//
+type Throttle struct {
+ f float64 // f = (1-r)/r for 0 < r < 1
+ dt time.Duration // minimum run time slice; >= 0
+ tr time.Duration // accumulated time running
+ ts time.Duration // accumulated time stopped
+ tt time.Time // earliest throttle time (= time Throttle returned + tm)
+}
+
+// NewThrottle creates a new Throttle with a throttle value r and
+// a minimum allocated run time slice of dt:
+//
+// r == 0: "empty" throttle; the goroutine is always sleeping
+// r == 1: full throttle; the goroutine is never sleeping
+//
+// A value of r == 0.6 throttles a goroutine such that it runs
+// approx. 60% of the time, and sleeps approx. 40% of the time.
+// Values of r < 0 or r > 1 are clamped down to values between 0 and 1.
+// Values of dt < 0 are set to 0.
+//
+func NewThrottle(r float64, dt time.Duration) *Throttle {
+ var f float64
+ switch {
+ case r <= 0:
+ f = -1 // indicates always sleep
+ case r >= 1:
+ f = 0 // assume r == 1 (never sleep)
+ default:
+ // 0 < r < 1
+ f = (1 - r) / r
+ }
+ if dt < 0 {
+ dt = 0
+ }
+ return &Throttle{f: f, dt: dt, tt: time.Now().Add(dt)}
+}
+
+// Throttle calls time.Sleep such that over time the ratio tr/ts between
+// accumulated run (tr) and sleep times (ts) approximates the value 1/(1-r)
+// where r is the throttle value. Throttle returns immediately (w/o sleeping)
+// if less than tm ns have passed since the last call to Throttle.
+//
+func (p *Throttle) Throttle() {
+ if p.f < 0 {
+ select {} // always sleep
+ }
+
+ t0 := time.Now()
+ if t0.Before(p.tt) {
+ return // keep running (minimum time slice not exhausted yet)
+ }
+
+ // accumulate running time
+ p.tr += t0.Sub(p.tt) + p.dt
+
+ // compute sleep time
+ // Over time we want:
+ //
+ // tr/ts = r/(1-r)
+ //
+ // Thus:
+ //
+ // ts = tr*f with f = (1-r)/r
+ //
+ // After some incremental run time δr added to the total run time
+ // tr, the incremental sleep-time δs to get to the same ratio again
+ // after waking up from time.Sleep is:
+ if δs := time.Duration(float64(p.tr)*p.f) - p.ts; δs > 0 {
+ time.Sleep(δs)
+ }
+
+ // accumulate (actual) sleep time
+ t1 := time.Now()
+ p.ts += t1.Sub(t0)
+
+ // set earliest next throttle time
+ p.tt = t1.Add(p.dt)
+}
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 11e46aee5..7def015c8 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -7,15 +7,10 @@
package main
import (
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
+ pathpkg "path"
"sync"
"time"
- "utf8"
+ "unicode/utf8"
)
// An RWValue wraps a value and permits mutually exclusive
@@ -24,92 +19,22 @@ import (
type RWValue struct {
mutex sync.RWMutex
value interface{}
- timestamp int64 // time of last set(), in seconds since epoch
+ timestamp time.Time // time of last set()
}
func (v *RWValue) set(value interface{}) {
v.mutex.Lock()
v.value = value
- v.timestamp = time.Seconds()
+ v.timestamp = time.Now()
v.mutex.Unlock()
}
-func (v *RWValue) get() (interface{}, int64) {
+func (v *RWValue) get() (interface{}, time.Time) {
v.mutex.RLock()
defer v.mutex.RUnlock()
return v.value, v.timestamp
}
-// TODO(gri) For now, using os.Getwd() is ok here since the functionality
-// based on this code is not invoked for the appengine version,
-// but this is fragile. Determine what the right thing to do is,
-// here (possibly have some Getwd-equivalent in FileSystem).
-var cwd, _ = os.Getwd() // ignore errors
-
-// canonicalizePaths takes a list of (directory/file) paths and returns
-// the list of corresponding absolute paths in sorted (increasing) order.
-// Relative paths are assumed to be relative to the current directory,
-// empty and duplicate paths as well as paths for which filter(path) is
-// false are discarded. filter may be nil in which case it is not used.
-//
-func canonicalizePaths(list []string, filter func(path string) bool) []string {
- i := 0
- for _, path := range list {
- path = strings.TrimSpace(path)
- if len(path) == 0 {
- continue // ignore empty paths (don't assume ".")
- }
- // len(path) > 0: normalize path
- if filepath.IsAbs(path) {
- path = filepath.Clean(path)
- } else {
- path = filepath.Join(cwd, path)
- }
- // we have a non-empty absolute path
- if filter != nil && !filter(path) {
- continue
- }
- // keep the path
- list[i] = path
- i++
- }
- list = list[0:i]
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i = 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- return list[0:i]
-}
-
-// writeFileAtomically writes data to a temporary file and then
-// atomically renames that file to the file named by filename.
-//
-func writeFileAtomically(filename string, data []byte) os.Error {
- // TODO(gri) this won't work on appengine
- f, err := ioutil.TempFile(filepath.Split(filename))
- if err != nil {
- return err
- }
- n, err := f.Write(data)
- f.Close()
- if err != nil {
- return err
- }
- if n < len(data) {
- return io.ErrShortWrite
- }
- return os.Rename(f.Name(), filename)
-}
-
// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
@@ -146,7 +71,7 @@ var textExt = map[string]bool{
//
func isTextFile(filename string) bool {
// if the extension is known, use it for decision making
- if isText, found := textExt[filepath.Ext(filename)]; found {
+ if isText, found := textExt[pathpkg.Ext(filename)]; found {
return isText
}
diff --git a/src/cmd/godoc/zip.go b/src/cmd/godoc/zip.go
index 27dc142f5..620eb4f3c 100644
--- a/src/cmd/godoc/zip.go
+++ b/src/cmd/godoc/zip.go
@@ -22,11 +22,11 @@ import (
"archive/zip"
"fmt"
"io"
- "io/ioutil"
"os"
"path"
"sort"
"strings"
+ "time"
)
// zipFI is the zip-file based implementation of FileInfo
@@ -46,28 +46,41 @@ func (fi zipFI) Size() int64 {
return 0 // directory
}
-func (fi zipFI) Mtime_ns() int64 {
+func (fi zipFI) ModTime() time.Time {
if f := fi.file; f != nil {
- return f.Mtime_ns()
+ return f.ModTime()
}
- return 0 // directory has no modified time entry
+ return time.Time{} // directory has no modified time entry
}
-func (fi zipFI) IsDirectory() bool {
+func (fi zipFI) Mode() os.FileMode {
+ if fi.file == nil {
+ // Unix directories typically are executable, hence 555.
+ return os.ModeDir | 0555
+ }
+ return 0444
+}
+
+func (fi zipFI) IsDir() bool {
return fi.file == nil
}
-func (fi zipFI) IsRegular() bool {
- return fi.file != nil
+func (fi zipFI) Sys() interface{} {
+ return nil
}
// zipFS is the zip-file based implementation of FileSystem
type zipFS struct {
*zip.ReadCloser
list zipList
+ name string
+}
+
+func (fs *zipFS) String() string {
+ return "zip(" + fs.name + ")"
}
-func (fs *zipFS) Close() os.Error {
+func (fs *zipFS) Close() error {
fs.list = nil
return fs.ReadCloser.Close()
}
@@ -80,7 +93,7 @@ func zipPath(name string) string {
return name[1:] // strip leading '/'
}
-func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
+func (fs *zipFS) stat(abspath string) (int, zipFI, error) {
i, exact := fs.list.lookup(abspath)
if i < 0 {
// abspath has leading '/' stripped - print it explicitly
@@ -94,38 +107,60 @@ func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
return i, zipFI{name, file}, nil
}
-func (fs *zipFS) Open(abspath string) (io.ReadCloser, os.Error) {
+func (fs *zipFS) Open(abspath string) (readSeekCloser, error) {
_, fi, err := fs.stat(zipPath(abspath))
if err != nil {
return nil, err
}
- if fi.IsDirectory() {
+ if fi.IsDir() {
return nil, fmt.Errorf("Open: %s is a directory", abspath)
}
- return fi.file.Open()
+ r, err := fi.file.Open()
+ if err != nil {
+ return nil, err
+ }
+ return &zipSeek{fi.file, r}, nil
+}
+
+type zipSeek struct {
+ file *zip.File
+ io.ReadCloser
+}
+
+func (f *zipSeek) Seek(offset int64, whence int) (int64, error) {
+ if whence == 0 && offset == 0 {
+ r, err := f.file.Open()
+ if err != nil {
+ return 0, err
+ }
+ f.Close()
+ f.ReadCloser = r
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in %s", f.file.Name)
}
-func (fs *zipFS) Lstat(abspath string) (FileInfo, os.Error) {
+func (fs *zipFS) Lstat(abspath string) (os.FileInfo, error) {
_, fi, err := fs.stat(zipPath(abspath))
return fi, err
}
-func (fs *zipFS) Stat(abspath string) (FileInfo, os.Error) {
+func (fs *zipFS) Stat(abspath string) (os.FileInfo, error) {
_, fi, err := fs.stat(zipPath(abspath))
return fi, err
}
-func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
+func (fs *zipFS) ReadDir(abspath string) ([]os.FileInfo, error) {
path := zipPath(abspath)
i, fi, err := fs.stat(path)
if err != nil {
return nil, err
}
- if !fi.IsDirectory() {
+ if !fi.IsDir() {
return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
}
- var list []FileInfo
+ var list []os.FileInfo
dirname := path + "/"
prevname := ""
for _, e := range fs.list[i:] {
@@ -153,19 +188,11 @@ func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
return list, nil
}
-func (fs *zipFS) ReadFile(abspath string) ([]byte, os.Error) {
- rc, err := fs.Open(abspath)
- if err != nil {
- return nil, err
- }
- return ioutil.ReadAll(rc)
-}
-
-func NewZipFS(rc *zip.ReadCloser) FileSystem {
+func NewZipFS(rc *zip.ReadCloser, name string) FileSystem {
list := make(zipList, len(rc.File))
copy(list, rc.File) // sort a copy of rc.File
sort.Sort(list)
- return &zipFS{rc, list}
+ return &zipFS{rc, list, name}
}
type zipList []*zip.File
@@ -183,9 +210,10 @@ func (z zipList) lookup(name string) (index int, exact bool) {
i := sort.Search(len(z), func(i int) bool {
return name <= z[i].Name
})
- if i < 0 {
+ if i >= len(z) {
return -1, false
}
+ // 0 <= i < len(z)
if z[i].Name == name {
return i, true
}
@@ -196,9 +224,10 @@ func (z zipList) lookup(name string) (index int, exact bool) {
j := sort.Search(len(z), func(i int) bool {
return name <= z[i].Name
})
- if j < 0 {
+ if j >= len(z) {
return -1, false
}
+ // 0 <= j < len(z)
if strings.HasPrefix(z[j].Name, name) {
return i + j, false
}
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
deleted file mode 100644
index 22033d7f8..000000000
--- a/src/cmd/gofix/Makefile
+++ /dev/null
@@ -1,34 +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.
-
-include ../../Make.inc
-
-TARG=gofix
-GOFILES=\
- filepath.go\
- fix.go\
- httpfinalurl.go\
- httpfs.go\
- httpheaders.go\
- httpserver.go\
- main.go\
- netdial.go\
- oserrorstring.go\
- osopen.go\
- procattr.go\
- reflect.go\
- signal.go\
- sorthelpers.go\
- sortslice.go\
- stringssplit.go\
- typecheck.go\
- url.go\
-
-include ../../Make.cmd
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gofix/doc.go b/src/cmd/gofix/doc.go
deleted file mode 100644
index a9790e685..000000000
--- a/src/cmd/gofix/doc.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Gofix finds Go programs that use old APIs and rewrites them to use
-newer ones. After you update to a new Go release, gofix helps make
-the necessary changes to your programs.
-
-Usage:
- gofix [-r name,...] [path ...]
-
-Without an explicit path, gofix reads standard input and writes the
-result to standard output.
-
-If the named path is a file, gofix rewrites the named files in place.
-If the named path is a directory, gofix rewrites all .go files in that
-directory tree. When gofix rewrites a file, it prints a line to standard
-error giving the name of the file and the rewrite applied.
-
-If the -diff flag is set, no files are rewritten. Instead gofix prints
-the differences a rewrite would introduce.
-
-The -r flag restricts the set of rewrites considered to those in the
-named list. By default gofix considers all known rewrites. Gofix's
-rewrites are idempotent, so that it is safe to apply gofix to updated
-or partially updated code even without using the -r flag.
-
-Gofix prints the full list of fixes it can apply in its help output;
-to see them, run gofix -?.
-
-Gofix does not make backup copies of the files that it edits.
-Instead, use a version control system's ``diff'' functionality to inspect
-the changes that gofix makes before committing them.
-*/
-package documentation
diff --git a/src/cmd/gofmt/Makefile b/src/cmd/gofmt/Makefile
deleted file mode 100644
index dc5b060e6..000000000
--- a/src/cmd/gofmt/Makefile
+++ /dev/null
@@ -1,19 +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.
-
-include ../../Make.inc
-
-TARG=gofmt
-GOFILES=\
- gofmt.go\
- rewrite.go\
- simplify.go\
-
-include ../../Make.cmd
-
-test: $(TARG)
- ./test.sh
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index fca42b76b..65842a3b1 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -36,10 +36,8 @@ The flags are:
Formatting control flags:
-comments=true
Print comments; if false, all comments are elided from the output.
- -spaces
- Align with spaces instead of tabs.
- -tabindent
- Indent with tabs independent of -spaces.
+ -tabs=true
+ Indent with tabs; if false, spaces are used instead.
-tabwidth=8
Tab width in spaces.
@@ -53,6 +51,12 @@ In the pattern, single-character lowercase identifiers serve as
wildcards matching arbitrary sub-expressions; those expressions
will be substituted for the same identifiers in the replacement.
+When gofmt reads from standard input, it accepts either a full Go program
+or a program fragment. A program fragment must be a syntactically
+valid declaration list, statement list, or expression. When formatting
+such a fragment, gofmt preserves leading indentation as well as leading
+and trailing spaces, so that individual sections of a Go program can be
+formatted by piping them through gofmt.
Examples
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 975ae6ac6..0bc385b5b 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -6,7 +6,6 @@ package main
import (
"bytes"
- "exec"
"flag"
"fmt"
"go/ast"
@@ -17,6 +16,7 @@ import (
"io"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"runtime/pprof"
"strings"
@@ -26,7 +26,7 @@ var (
// main operation modes
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
- rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
+ rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
simplifyAST = flag.Bool("s", false, "simplify code")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "print all (including spurious) errors")
@@ -34,22 +34,21 @@ var (
// layout control
comments = flag.Bool("comments", true, "print comments")
tabWidth = flag.Int("tabwidth", 8, "tab width")
- tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
- useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
+ tabIndent = flag.Bool("tabs", true, "indent with tabs")
// debugging
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)
var (
- fset = token.NewFileSet()
+ fileSet = token.NewFileSet() // per process FileSet
exitCode = 0
rewrite func(*ast.File) *ast.File
- parserMode uint
- printerMode uint
+ parserMode parser.Mode
+ printerMode printer.Mode
)
-func report(err os.Error) {
+func report(err error) {
scanner.PrintError(os.Stderr, err)
exitCode = 2
}
@@ -61,7 +60,7 @@ func usage() {
}
func initParserMode() {
- parserMode = uint(0)
+ parserMode = parser.Mode(0)
if *comments {
parserMode |= parser.ParseComments
}
@@ -71,22 +70,20 @@ func initParserMode() {
}
func initPrinterMode() {
- printerMode = uint(0)
+ printerMode = printer.UseSpaces
if *tabIndent {
printerMode |= printer.TabIndent
}
- if *useSpaces {
- printerMode |= printer.UseSpaces
- }
}
-func isGoFile(f *os.FileInfo) bool {
+func isGoFile(f os.FileInfo) bool {
// ignore non-Go files
- return f.IsRegular() && !strings.HasPrefix(f.Name, ".") && strings.HasSuffix(f.Name, ".go")
+ name := f.Name()
+ return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}
// If in == nil, the source is the contents of the file with the given filename.
-func processFile(filename string, in io.Reader, out io.Writer) os.Error {
+func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
if in == nil {
f, err := os.Open(filename)
if err != nil {
@@ -101,25 +98,34 @@ func processFile(filename string, in io.Reader, out io.Writer) os.Error {
return err
}
- file, err := parser.ParseFile(fset, filename, src, parserMode)
+ file, adjust, err := parse(fileSet, filename, src, stdin)
if err != nil {
return err
}
if rewrite != nil {
- file = rewrite(file)
+ if adjust == nil {
+ file = rewrite(file)
+ } else {
+ fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
+ }
}
+ ast.SortImports(fileSet, file)
+
if *simplifyAST {
simplify(file)
}
var buf bytes.Buffer
- _, err = (&printer.Config{printerMode, *tabWidth}).Fprint(&buf, fset, file)
+ err = (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(&buf, fileSet, file)
if err != nil {
return err
}
res := buf.Bytes()
+ if adjust != nil {
+ res = adjust(src, res)
+ }
if !bytes.Equal(src, res) {
// formatting has changed
@@ -149,32 +155,18 @@ func processFile(filename string, in io.Reader, out io.Writer) os.Error {
return err
}
-type fileVisitor chan os.Error
-
-func (v fileVisitor) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-func (v fileVisitor) VisitFile(path string, f *os.FileInfo) {
- if isGoFile(f) {
- v <- nil // synchronize error handler
- if err := processFile(path, nil, os.Stdout); err != nil {
- v <- err
- }
+func visitFile(path string, f os.FileInfo, err error) error {
+ if err == nil && isGoFile(f) {
+ err = processFile(path, nil, os.Stdout, false)
+ }
+ if err != nil {
+ report(err)
}
+ return nil
}
func walkDir(path string) {
- v := make(fileVisitor)
- go func() {
- filepath.Walk(path, v, v)
- close(v)
- }()
- for err := range v {
- if err != nil {
- report(err)
- }
- }
+ filepath.Walk(path, visitFile)
}
func main() {
@@ -211,7 +203,7 @@ func gofmtMain() {
initRewrite()
if flag.NArg() == 0 {
- if err := processFile("<standard input>", os.Stdin, os.Stdout); err != nil {
+ if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
report(err)
}
return
@@ -222,17 +214,17 @@ func gofmtMain() {
switch dir, err := os.Stat(path); {
case err != nil:
report(err)
- case dir.IsRegular():
- if err := processFile(path, nil, os.Stdout); err != nil {
+ case dir.IsDir():
+ walkDir(path)
+ default:
+ if err := processFile(path, nil, os.Stdout, false); err != nil {
report(err)
}
- case dir.IsDirectory():
- walkDir(path)
}
}
}
-func diff(b1, b2 []byte) (data []byte, err os.Error) {
+func diff(b1, b2 []byte) (data []byte, err error) {
f1, err := ioutil.TempFile("", "gofmt")
if err != nil {
return
@@ -259,3 +251,111 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) {
return
}
+
+// parse parses src, which was read from filename,
+// as a Go source file or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
+ // Try as whole source file.
+ file, err := parser.ParseFile(fset, filename, src, parserMode)
+ if err == nil {
+ return file, nil, nil
+ }
+ // If the error is that the source file didn't begin with a
+ // package line and this is standard input, fall through to
+ // try as a source fragment. Stop and return on any other error.
+ if !stdin || !strings.Contains(err.Error(), "expected 'package'") {
+ return nil, nil, err
+ }
+
+ // If this is a declaration list, make it a source file
+ // by inserting a package clause.
+ // Insert using a ;, not a newline, so that the line numbers
+ // in psrc match the ones in src.
+ psrc := append([]byte("package p;"), src...)
+ file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+ if err == nil {
+ adjust := func(orig, src []byte) []byte {
+ // Remove the package clause.
+ // Gofmt has turned the ; into a \n.
+ src = src[len("package p\n"):]
+ return matchSpace(orig, src)
+ }
+ return file, adjust, nil
+ }
+ // If the error is that the source file didn't begin with a
+ // declaration, fall through to try as a statement list.
+ // Stop and return on any other error.
+ if !strings.Contains(err.Error(), "expected declaration") {
+ return nil, nil, err
+ }
+
+ // If this is a statement list, make it a source file
+ // by inserting a package clause and turning the list
+ // into a function body. This handles expressions too.
+ // Insert using a ;, not a newline, so that the line numbers
+ // in fsrc match the ones in src.
+ fsrc := append(append([]byte("package p; func _() {"), src...), '}')
+ file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+ if err == nil {
+ adjust := func(orig, src []byte) []byte {
+ // Remove the wrapping.
+ // Gofmt has turned the ; into a \n\n.
+ src = src[len("package p\n\nfunc _() {"):]
+ src = src[:len(src)-len("}\n")]
+ // Gofmt has also indented the function body one level.
+ // Remove that indent.
+ src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1)
+ return matchSpace(orig, src)
+ }
+ return file, adjust, nil
+ }
+
+ // Failed, and out of options.
+ return nil, nil, err
+}
+
+func cutSpace(b []byte) (before, middle, after []byte) {
+ i := 0
+ for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') {
+ i++
+ }
+ j := len(b)
+ for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') {
+ j--
+ }
+ if i <= j {
+ return b[:i], b[i:j], b[j:]
+ }
+ return nil, nil, b[j:]
+}
+
+// matchSpace reformats src to use the same space context as orig.
+// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
+// 2) matchSpace copies the indentation of the first non-blank line in orig
+// to every non-blank line in src.
+// 3) matchSpace copies the trailing space from orig and uses it in place
+// of src's trailing space.
+func matchSpace(orig []byte, src []byte) []byte {
+ before, _, after := cutSpace(orig)
+ i := bytes.LastIndex(before, []byte{'\n'})
+ before, indent := before[:i+1], before[i+1:]
+
+ _, src, _ = cutSpace(src)
+
+ var b bytes.Buffer
+ b.Write(before)
+ for len(src) > 0 {
+ line := src
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, src = line[:i+1], line[i+1:]
+ } else {
+ src = nil
+ }
+ if len(line) > 0 && line[0] != '\n' { // not blank
+ b.Write(indent)
+ }
+ b.Write(line)
+ }
+ b.Write(after)
+ return b.Bytes()
+}
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index 2e35ce9a4..4b2805009 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -12,13 +12,11 @@ import (
"testing"
)
-func runTest(t *testing.T, dirname, in, out, flags string) {
- in = filepath.Join(dirname, in)
- out = filepath.Join(dirname, out)
-
+func runTest(t *testing.T, in, out, flags string) {
// process flags
*simplifyAST = false
*rewriteRule = ""
+ stdin := false
for _, flag := range strings.Split(flags, " ") {
elts := strings.SplitN(flag, "=", 2)
name := elts[0]
@@ -33,6 +31,9 @@ func runTest(t *testing.T, dirname, in, out, flags string) {
*rewriteRule = value
case "-s":
*simplifyAST = true
+ case "-stdin":
+ // fake flag - pretend input is from stdin
+ stdin = true
default:
t.Errorf("unrecognized flag name: %s", name)
}
@@ -43,7 +44,7 @@ func runTest(t *testing.T, dirname, in, out, flags string) {
initRewrite()
var buf bytes.Buffer
- err := processFile(in, nil, &buf)
+ err := processFile(in, nil, &buf, stdin)
if err != nil {
t.Error(err)
return
@@ -57,23 +58,48 @@ func runTest(t *testing.T, dirname, in, out, flags string) {
if got := buf.Bytes(); bytes.Compare(got, expected) != 0 {
t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in)
+ d, err := diff(expected, got)
+ if err == nil {
+ t.Errorf("%s", d)
+ }
ioutil.WriteFile(in+".gofmt", got, 0666)
}
}
// TODO(gri) Add more test cases!
var tests = []struct {
- dirname, in, out, flags string
+ in, flags string
}{
- {".", "gofmt.go", "gofmt.go", ""},
- {".", "gofmt_test.go", "gofmt_test.go", ""},
- {"testdata", "composites.input", "composites.golden", "-s"},
- {"testdata", "rewrite1.input", "rewrite1.golden", "-r=Foo->Bar"},
- {"testdata", "rewrite2.input", "rewrite2.golden", "-r=int->bool"},
+ {"gofmt.go", ""},
+ {"gofmt_test.go", ""},
+ {"testdata/composites.input", "-s"},
+ {"testdata/old.input", ""},
+ {"testdata/rewrite1.input", "-r=Foo->Bar"},
+ {"testdata/rewrite2.input", "-r=int->bool"},
+ {"testdata/rewrite3.input", "-r=x->x"},
+ {"testdata/rewrite4.input", "-r=(x)->x"},
+ {"testdata/stdin*.input", "-stdin"},
+ {"testdata/comments.input", ""},
+ {"testdata/import.input", ""},
}
func TestRewrite(t *testing.T) {
for _, test := range tests {
- runTest(t, test.dirname, test.in, test.out, test.flags)
+ match, err := filepath.Glob(test.in)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ for _, in := range match {
+ out := in
+ if strings.HasSuffix(in, ".input") {
+ out = in[:len(in)-len(".input")] + ".golden"
+ }
+ runTest(t, in, out, test.flags)
+ if in != out {
+ // Check idempotence.
+ runTest(t, out, out, test.flags)
+ }
+ }
}
}
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
new file mode 100644
index 000000000..edbce606a
--- /dev/null
+++ b/src/cmd/gofmt/long_test.go
@@ -0,0 +1,159 @@
+// 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 test applies gofmt to all Go files under -root.
+// To test specific files provide a list of comma-separated
+// filenames via the -files flag: go test -files=gofmt.go .
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var (
+ root = flag.String("root", runtime.GOROOT(), "test root directory")
+ files = flag.String("files", "", "comma-separated list of files to test")
+ ngo = flag.Int("n", runtime.NumCPU(), "number of goroutines used")
+ verbose = flag.Bool("verbose", false, "verbose mode")
+ nfiles int // number of files processed
+)
+
+func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
+ f, _, err := parse(fset, filename, src.Bytes(), false)
+ if err != nil {
+ return err
+ }
+ ast.SortImports(fset, f)
+ src.Reset()
+ return (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(src, fset, f)
+}
+
+func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
+ // open file
+ f, err := os.Open(filename)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // read file
+ b1.Reset()
+ _, err = io.Copy(b1, f)
+ f.Close()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // exclude files w/ syntax errors (typically test cases)
+ fset := token.NewFileSet()
+ if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
+ if *verbose {
+ fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
+ }
+ return
+ }
+
+ // gofmt file
+ if err = gofmt(fset, filename, b1); err != nil {
+ t.Errorf("1st gofmt failed: %v", err)
+ return
+ }
+
+ // make a copy of the result
+ b2.Reset()
+ b2.Write(b1.Bytes())
+
+ // gofmt result again
+ if err = gofmt(fset, filename, b2); err != nil {
+ t.Errorf("2nd gofmt failed: %v", err)
+ return
+ }
+
+ // the first and 2nd result should be identical
+ if bytes.Compare(b1.Bytes(), b2.Bytes()) != 0 {
+ t.Errorf("gofmt %s not idempotent", filename)
+ }
+}
+
+func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
+ b1 := new(bytes.Buffer)
+ b2 := new(bytes.Buffer)
+ for filename := range filenames {
+ testFile(t, b1, b2, filename)
+ }
+ done <- 0
+}
+
+func genFilenames(t *testing.T, filenames chan<- string) {
+ defer close(filenames)
+
+ handleFile := func(filename string, fi os.FileInfo, err error) error {
+ if err != nil {
+ t.Error(err)
+ return nil
+ }
+ if isGoFile(fi) {
+ filenames <- filename
+ nfiles++
+ }
+ return nil
+ }
+
+ // test Go files provided via -files, if any
+ if *files != "" {
+ for _, filename := range strings.Split(*files, ",") {
+ fi, err := os.Stat(filename)
+ handleFile(filename, fi, err)
+ }
+ return // ignore files under -root
+ }
+
+ // otherwise, test all Go files under *root
+ filepath.Walk(*root, handleFile)
+}
+
+func TestAll(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ if *ngo < 1 {
+ *ngo = 1 // make sure test is run
+ }
+ if *verbose {
+ fmt.Printf("running test using %d goroutines\n", *ngo)
+ }
+
+ // generate filenames
+ filenames := make(chan string, 32)
+ go genFilenames(t, filenames)
+
+ // launch test goroutines
+ done := make(chan int)
+ for i := 0; i < *ngo; i++ {
+ go testFiles(t, filenames, done)
+ }
+
+ // wait for all test goroutines to complete
+ for i := 0; i < *ngo; i++ {
+ <-done
+ }
+
+ if *verbose {
+ fmt.Printf("processed %d files\n", nfiles)
+ }
+}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 3d74dea0f..3c7861f0d 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -13,7 +13,7 @@ import (
"reflect"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
func initRewrite() {
@@ -36,7 +36,7 @@ func initRewrite() {
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr {
- x, err := parser.ParseExpr(fset, "input", s)
+ x, err := parser.ParseExpr(s)
if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
os.Exit(2)
@@ -65,7 +65,7 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
return reflect.Value{}
}
for k := range m {
- m[k] = reflect.Value{}, false
+ delete(m, k)
}
val = apply(f, val)
if match(m, pat, val) {
@@ -85,7 +85,8 @@ func setValue(x, y reflect.Value) {
}
defer func() {
if x := recover(); x != nil {
- if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
+ if s, ok := x.(string); ok &&
+ (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
// x cannot be set to y - ignore this rewrite
return
}
@@ -158,8 +159,8 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
if m != nil && pattern.IsValid() && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) && val.IsValid() {
- // wildcards only match expressions
- if _, ok := val.Interface().(ast.Expr); ok {
+ // wildcards only match valid (non-nil) expressions.
+ if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
if old, ok := m[name]; ok {
return match(nil, old, val)
}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
index d9afc0e7b..470c00625 100644
--- a/src/cmd/gofmt/simplify.go
+++ b/src/cmd/gofmt/simplify.go
@@ -6,6 +6,7 @@ package main
import (
"go/ast"
+ "go/token"
"reflect"
)
@@ -26,10 +27,12 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
if eltType != nil {
typ := reflect.ValueOf(eltType)
- for _, x := range outer.Elts {
+ for i, x := range outer.Elts {
+ px := &outer.Elts[i]
// look at value of indexed/named elements
if t, ok := x.(*ast.KeyValueExpr); ok {
x = t.Value
+ px = &t.Value
}
simplify(x)
// if the element is a composite literal and its literal type
@@ -40,6 +43,19 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
inner.Type = nil
}
}
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := eltType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
}
// node was simplified - stop walk (there are no subnodes to simplify)
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
deleted file mode 100755
index 063a0727f..000000000
--- a/src/cmd/gofmt/test.sh
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-eval $(gomake --no-print-directory -f ../../Make.inc go-env)
-if [ -z "$O" ]; then
- echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
- exit 1
-fi
-
-CMD="./gofmt"
-TMP1=test_tmp1.go
-TMP2=test_tmp2.go
-TMP3=test_tmp3.go
-COUNT=0
-
-count() {
- #echo $1
- let COUNT=$COUNT+1
- let M=$COUNT%10
- if [ $M == 0 ]; then
- echo -n "."
- fi
-}
-
-
-error() {
- echo $1
- exit 1
-}
-
-
-# apply to one file
-apply1() {
- # the following files are skipped because they are test cases
- # for syntax errors and thus won't parse in the first place:
- case `basename "$F"` in
- func3.go | const2.go | char_lit1.go | blank1.go | ddd1.go | \
- bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \
- bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
- bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
- bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
- bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
- bug302.go | bug306.go | bug322.go | bug324.go | bug335.go | \
- bug340.go | bug349.go | bug351.go | bug358.go ) return ;;
- esac
- # the following directories are skipped because they contain test
- # cases for syntax errors and thus won't parse in the first place:
- case `dirname "$F"` in
- $GOROOT/test/syntax ) return ;;
- esac
- #echo $1 $2
- "$1" "$2"; count "$F"
-}
-
-
-# apply to local files
-applydot() {
- for F in `find . -name "*.go" | grep -v "._"`; do
- apply1 "$1" $F
- done
-}
-
-
-# apply to all .go files we can find
-apply() {
- for F in `find "$GOROOT" -name "*.go" | grep -v "._"`; do
- apply1 "$1" $F
- done
-}
-
-
-cleanup() {
- rm -f $TMP1 $TMP2 $TMP3
-}
-
-
-silent() {
- cleanup
- $CMD "$1" > /dev/null 2> $TMP1
- if [ $? != 0 ]; then
- cat $TMP1
- error "Error (silent mode test): test.sh $1"
- fi
-}
-
-
-idempotent() {
- cleanup
- $CMD "$1" > $TMP1
- if [ $? != 0 ]; then
- error "Error (step 1 of idempotency test): test.sh $1"
- fi
-
- $CMD $TMP1 > $TMP2
- if [ $? != 0 ]; then
- error "Error (step 2 of idempotency test): test.sh $1"
- fi
-
- $CMD $TMP2 > $TMP3
- if [ $? != 0 ]; then
- error "Error (step 3 of idempotency test): test.sh $1"
- fi
-
- cmp -s $TMP2 $TMP3
- if [ $? != 0 ]; then
- diff $TMP2 $TMP3
- error "Error (step 4 of idempotency test): test.sh $1"
- fi
-}
-
-
-valid() {
- cleanup
- $CMD "$1" > $TMP1
- if [ $? != 0 ]; then
- error "Error (step 1 of validity test): test.sh $1"
- fi
-
- $GC -o /dev/null $TMP1
- if [ $? != 0 ]; then
- error "Error (step 2 of validity test): test.sh $1"
- fi
-}
-
-
-runtest() {
- #echo "Testing silent mode"
- cleanup
- "$1" silent "$2"
-
- #echo "Testing idempotency"
- cleanup
- "$1" idempotent "$2"
-}
-
-
-runtests() {
- if [ $# = 0 ]; then
- runtest apply
- # verify the pretty-printed files can be compiled with $GC again
- # do it in local directory only because of the prerequisites required
- #echo "Testing validity"
- # Disabled for now due to dependency problems
- # cleanup
- # applydot valid
- else
- for F in "$@"; do
- runtest apply1 "$F"
- done
- fi
-}
-
-
-# run over all .go files
-runtests "$@"
-cleanup
-
-# done
-echo
-echo "PASSED ($COUNT tests)"
diff --git a/src/cmd/gofmt/testdata/comments.golden b/src/cmd/gofmt/testdata/comments.golden
new file mode 100644
index 000000000..ad6bcafaf
--- /dev/null
+++ b/src/cmd/gofmt/testdata/comments.golden
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/src/cmd/gofmt/testdata/comments.input b/src/cmd/gofmt/testdata/comments.input
new file mode 100644
index 000000000..ad6bcafaf
--- /dev/null
+++ b/src/cmd/gofmt/testdata/comments.input
@@ -0,0 +1,9 @@
+package main
+
+func main() {}
+
+// comment here
+
+func f() {}
+
+//line foo.go:1
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
index 1fd5847c1..b2825e732 100644
--- a/src/cmd/gofmt/testdata/composites.golden
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -102,3 +102,101 @@ var pieces4 = []Piece{
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
}
+
+var _ = [42]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ {3, 4},
+}
+
+var _ = []*[]*[]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": {3, 4},
+}
+
+var pieces4 = []*Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
index 15afd9e5c..7210dafc9 100644
--- a/src/cmd/gofmt/testdata/composites.input
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -102,3 +102,101 @@ var pieces4 = []Piece{
Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
}
+
+var _ = [42]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = [...]*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ &T{1, 2},
+ &T{3, 4},
+}
+
+var _ = []*T{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*struct {
+ x, y int
+}{
+ &struct{ x, y int }{},
+ 10: &struct{ x, y int }{1, 2},
+ 20: &struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ &T{},
+ 10: &T{1, 2},
+ 20: &T{3, 4},
+}
+
+var _ = []*[]int{
+ &[]int{},
+ &[]int{1, 2},
+ &[]int{3, 4},
+}
+
+var _ = []*[]int{
+ (&[]int{}),
+ (&[]int{1, 2}),
+ &[]int{3, 4},
+}
+
+var _ = []*[]*[]int{
+ &[]*[]int{},
+ &[]*[]int{
+ &[]int{},
+ &[]int{0, 1, 2, 3},
+ &[]int{4, 5},
+ },
+}
+
+var _ = map[string]*T{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*struct {
+ x, y int
+}{
+ "foo": &struct{ x, y int }{},
+ "bar": &struct{ x, y int }{1, 2},
+ "bal": &struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": &T{},
+ "bar": &T{1, 2},
+ "bal": &T{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": &[]int{},
+ "bar": &[]int{1, 2},
+ "bal": &[]int{3, 4},
+}
+
+var _ = map[string]*[]int{
+ "foo": (&[]int{}),
+ "bar": (&[]int{1, 2}),
+ "bal": &[]int{3, 4},
+}
+
+var pieces4 = []*Piece{
+ &Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ &Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ &Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
diff --git a/src/cmd/gofmt/testdata/import.golden b/src/cmd/gofmt/testdata/import.golden
new file mode 100644
index 000000000..e8ee44988
--- /dev/null
+++ b/src/cmd/gofmt/testdata/import.golden
@@ -0,0 +1,108 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "errors"
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+
+ "errors"
+ "fmt" // for Printf
+ "io" // for Reader
+ "log" // for Fatal
+ "math"
+)
diff --git a/src/cmd/gofmt/testdata/import.input b/src/cmd/gofmt/testdata/import.input
new file mode 100644
index 000000000..cc36c3e01
--- /dev/null
+++ b/src/cmd/gofmt/testdata/import.input
@@ -0,0 +1,108 @@
+package main
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+)
+
+import (
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ "fmt"
+ "math"
+ "log"
+ "errors"
+ "io"
+
+ "fmt"
+
+ "math"
+
+ "log"
+
+ "errors"
+
+ "io"
+)
+
+import (
+ // a block with comments
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ // for Printf
+ "fmt"
+
+ "math"
+
+ // for Fatal
+ "log"
+
+ "errors"
+
+ // for Reader
+ "io"
+)
+
+import (
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+
+ "math"
+
+ "log" // for Fatal
+
+ "errors"
+
+ "io" // for Reader
+)
+
+import (
+ "fmt" // for Printf
+
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+
+ "fmt" // for Printf
+ "math"
+ "log" // for Fatal
+ "errors"
+ "io" // for Reader
+)
diff --git a/src/cmd/gofmt/testdata/old.golden b/src/cmd/gofmt/testdata/old.golden
new file mode 100644
index 000000000..95a0b72a0
--- /dev/null
+++ b/src/cmd/gofmt/testdata/old.golden
@@ -0,0 +1,9 @@
+package P
+
+func f() {
+ if x {
+ y
+ } else {
+ z
+ }
+}
diff --git a/src/cmd/gofmt/testdata/old.input b/src/cmd/gofmt/testdata/old.input
new file mode 100644
index 000000000..e24eed215
--- /dev/null
+++ b/src/cmd/gofmt/testdata/old.input
@@ -0,0 +1,8 @@
+package P
+
+func f() {
+ if x {
+ y
+ } else
+ z
+}
diff --git a/src/cmd/gofmt/testdata/rewrite3.golden b/src/cmd/gofmt/testdata/rewrite3.golden
new file mode 100644
index 000000000..0d16d1601
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite3.golden
@@ -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
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/src/cmd/gofmt/testdata/rewrite3.input b/src/cmd/gofmt/testdata/rewrite3.input
new file mode 100644
index 000000000..0d16d1601
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite3.input
@@ -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
+
+// Field tags are *ast.BasicLit nodes that are nil when the tag is
+// absent. These nil nodes must not be mistaken for expressions,
+// the rewriter should not try to dereference them. Was issue 2410.
+type Foo struct {
+ Field int
+}
diff --git a/src/cmd/gofmt/testdata/rewrite4.golden b/src/cmd/gofmt/testdata/rewrite4.golden
new file mode 100644
index 000000000..8dfc81a07
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite4.golden
@@ -0,0 +1,74 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/src/cmd/gofmt/testdata/rewrite4.input b/src/cmd/gofmt/testdata/rewrite4.input
new file mode 100644
index 000000000..164cc0451
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite4.input
@@ -0,0 +1,74 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rewriting of parenthesized expressions (x) -> x
+// must not drop parentheses if that would lead to
+// wrong association of the operands.
+// Was issue 1847.
+
+package main
+
+// From example 1 of issue 1847.
+func _() {
+ var t = (&T{1000}).Id()
+}
+
+// From example 2 of issue 1847.
+func _() {
+ fmt.Println((*xpp).a)
+}
+
+// Some more test cases.
+func _() {
+ _ = (-x).f
+ _ = (*x).f
+ _ = (&x).f
+ _ = (!x).f
+ _ = (-x.f)
+ _ = (*x.f)
+ _ = (&x.f)
+ _ = (!x.f)
+ (-x).f()
+ (*x).f()
+ (&x).f()
+ (!x).f()
+ _ = (-x.f())
+ _ = (*x.f())
+ _ = (&x.f())
+ _ = (!x.f())
+
+ _ = ((-x)).f
+ _ = ((*x)).f
+ _ = ((&x)).f
+ _ = ((!x)).f
+ _ = ((-x.f))
+ _ = ((*x.f))
+ _ = ((&x.f))
+ _ = ((!x.f))
+ ((-x)).f()
+ ((*x)).f()
+ ((&x)).f()
+ ((!x)).f()
+ _ = ((-x.f()))
+ _ = ((*x.f()))
+ _ = ((&x.f()))
+ _ = ((!x.f()))
+
+ _ = -(x).f
+ _ = *(x).f
+ _ = &(x).f
+ _ = !(x).f
+ _ = -x.f
+ _ = *x.f
+ _ = &x.f
+ _ = !x.f
+ _ = -(x).f()
+ _ = *(x).f()
+ _ = &(x).f()
+ _ = !(x).f()
+ _ = -x.f()
+ _ = *x.f()
+ _ = &x.f()
+ _ = !x.f()
+}
diff --git a/src/cmd/gofmt/testdata/stdin1.golden b/src/cmd/gofmt/testdata/stdin1.golden
new file mode 100644
index 000000000..ff8b0b7ab
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.golden
@@ -0,0 +1,3 @@
+ if x {
+ y
+ }
diff --git a/src/cmd/gofmt/testdata/stdin1.golden.gofmt b/src/cmd/gofmt/testdata/stdin1.golden.gofmt
new file mode 100644
index 000000000..1f888877d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.golden.gofmt
@@ -0,0 +1,3 @@
+ if x {
+ y
+}
diff --git a/src/cmd/gofmt/testdata/stdin1.input b/src/cmd/gofmt/testdata/stdin1.input
new file mode 100644
index 000000000..ff8b0b7ab
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.input
@@ -0,0 +1,3 @@
+ if x {
+ y
+ }
diff --git a/src/cmd/gofmt/testdata/stdin1.input.gofmt b/src/cmd/gofmt/testdata/stdin1.input.gofmt
new file mode 100644
index 000000000..1f888877d
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin1.input.gofmt
@@ -0,0 +1,3 @@
+ if x {
+ y
+}
diff --git a/src/cmd/gofmt/testdata/stdin2.golden b/src/cmd/gofmt/testdata/stdin2.golden
new file mode 100644
index 000000000..7eb1b54fe
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.golden
@@ -0,0 +1,11 @@
+
+
+var x int
+
+func f() {
+ y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin2.golden.gofmt b/src/cmd/gofmt/testdata/stdin2.golden.gofmt
new file mode 100644
index 000000000..85e800300
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.golden.gofmt
@@ -0,0 +1,10 @@
+
+
+
+var x int
+
+func f() {
+ y := z
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin2.input b/src/cmd/gofmt/testdata/stdin2.input
new file mode 100644
index 000000000..99defd2d1
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.input
@@ -0,0 +1,11 @@
+
+
+var x int
+
+
+func f() { y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin2.input.gofmt b/src/cmd/gofmt/testdata/stdin2.input.gofmt
new file mode 100644
index 000000000..7eb1b54fe
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin2.input.gofmt
@@ -0,0 +1,11 @@
+
+
+var x int
+
+func f() {
+ y := z
+ /* this is a comment */
+ // this is a comment too
+}
+
+
diff --git a/src/cmd/gofmt/testdata/stdin3.golden b/src/cmd/gofmt/testdata/stdin3.golden
new file mode 100644
index 000000000..1bf2f5a48
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.golden
@@ -0,0 +1,6 @@
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ {
+ s += i
+ }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin3.golden.gofmt b/src/cmd/gofmt/testdata/stdin3.golden.gofmt
new file mode 100644
index 000000000..b4d1d4663
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.golden.gofmt
@@ -0,0 +1,7 @@
+
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ {
+ s += i
+ }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin3.input b/src/cmd/gofmt/testdata/stdin3.input
new file mode 100644
index 000000000..d963bd0d2
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.input
@@ -0,0 +1,4 @@
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ { s += i }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin3.input.gofmt b/src/cmd/gofmt/testdata/stdin3.input.gofmt
new file mode 100644
index 000000000..b4d1d4663
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin3.input.gofmt
@@ -0,0 +1,7 @@
+
+
+ /* note: no newline at end of file */
+ for i := 0; i < 10; i++ {
+ s += i
+ }
+ \ No newline at end of file
diff --git a/src/cmd/gofmt/testdata/stdin4.golden b/src/cmd/gofmt/testdata/stdin4.golden
new file mode 100644
index 000000000..5f7343551
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.golden
@@ -0,0 +1,3 @@
+ // comment
+
+ i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.golden.gofmt b/src/cmd/gofmt/testdata/stdin4.golden.gofmt
new file mode 100644
index 000000000..5f7343551
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.golden.gofmt
@@ -0,0 +1,3 @@
+ // comment
+
+ i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.input b/src/cmd/gofmt/testdata/stdin4.input
new file mode 100644
index 000000000..f02a54fb1
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.input
@@ -0,0 +1,3 @@
+ // comment
+
+ i := 0
diff --git a/src/cmd/gofmt/testdata/stdin4.input.gofmt b/src/cmd/gofmt/testdata/stdin4.input.gofmt
new file mode 100644
index 000000000..5f7343551
--- /dev/null
+++ b/src/cmd/gofmt/testdata/stdin4.input.gofmt
@@ -0,0 +1,3 @@
+ // comment
+
+ i := 0
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
deleted file mode 100644
index b90646973..000000000
--- a/src/cmd/goinstall/Makefile
+++ /dev/null
@@ -1,19 +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.
-
-include ../../Make.inc
-
-TARG=goinstall
-GOFILES=\
- download.go\
- main.go\
- make.go\
-
-include ../../Make.cmd
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
deleted file mode 100644
index 47c615364..000000000
--- a/src/cmd/goinstall/doc.go
+++ /dev/null
@@ -1,196 +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.
-
-/*
-Goinstall is an experiment in automatic package installation.
-It installs packages, possibly downloading them from the internet.
-It maintains a list of public Go packages at
-http://godashboard.appspot.com/package.
-
-Usage:
- goinstall [flags] importpath...
- goinstall [flags] -a
-
-Flags and default settings:
- -a=false install all previously installed packages
- -clean=false clean the package directory before installing
- -dashboard=true tally public packages on godashboard.appspot.com
- -install=true build and install the package and its dependencies
- -nuke=false remove the target object and clean before installing
- -u=false update already-downloaded packages
- -v=false verbose operation
-
-Goinstall installs each of the packages identified on the command line. It
-installs a package's prerequisites before trying to install the package
-itself. Unless -log=false is specified, goinstall logs the import path of each
-installed package to $GOROOT/goinstall.log for use by goinstall -a.
-
-If the -a flag is given, goinstall reinstalls all previously installed
-packages, reading the list from $GOROOT/goinstall.log. After updating to a
-new Go release, which deletes all package binaries, running
-
- goinstall -a
-
-will recompile and reinstall goinstalled packages.
-
-Another common idiom is to use
-
- goinstall -a -u
-
-to update, recompile, and reinstall all goinstalled packages.
-
-The source code for a package with import path foo/bar is expected
-to be in the directory $GOROOT/src/pkg/foo/bar/ or $GOPATH/src/foo/bar/.
-See "The GOPATH Environment Variable" for more about GOPATH.
-
-By default, goinstall prints output only when it encounters an error.
-The -v flag causes goinstall to print information about packages
-being considered and installed.
-
-Goinstall ignores Makefiles.
-
-
-Remote Repositories
-
-If a package import path refers to a remote repository, goinstall will
-download the code if necessary.
-
-Goinstall recognizes packages from a few common code hosting sites:
-
- BitBucket (Mercurial)
-
- import "bitbucket.org/user/project"
- import "bitbucket.org/user/project/sub/directory"
-
- GitHub (Git)
-
- import "github.com/user/project"
- import "github.com/user/project/sub/directory"
-
- Google Code Project Hosting (Git, Mercurial, Subversion)
-
- import "project.googlecode.com/git"
- import "project.googlecode.com/git/sub/directory"
-
- import "project.googlecode.com/hg"
- import "project.googlecode.com/hg/sub/directory"
-
- import "project.googlecode.com/svn/trunk"
- import "project.googlecode.com/svn/trunk/sub/directory"
-
- Launchpad (Bazaar)
-
- import "launchpad.net/project"
- import "launchpad.net/project/series"
- import "launchpad.net/project/series/sub/directory"
-
- import "launchpad.net/~user/project/branch"
- import "launchpad.net/~user/project/branch/sub/directory"
-
-If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
-already exists and contains an appropriate checkout, goinstall will not
-attempt to fetch updates. The -u flag changes this behavior,
-causing goinstall to update all remote packages encountered during
-the installation.
-
-When downloading or updating, goinstall looks for a tag with the "go." prefix
-that corresponds to the local Go version. For Go "release.r58" it looks for a
-tag named "go.r58". For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
-If the specific "go.X" tag is not found, it chooses the closest earlier version.
-If an appropriate tag is found, goinstall uses that version of the code.
-Otherwise it uses the default version selected by the version control
-system, typically HEAD for git, tip for Mercurial.
-
-After a successful download and installation of one of these import paths,
-goinstall reports the installation to godashboard.appspot.com, which
-increments a count associated with the package and the time of its most
-recent installation. This mechanism powers the package list at
-http://godashboard.appspot.com/package, allowing Go programmers to learn about
-popular packages that might be worth looking at.
-The -dashboard=false flag disables this reporting.
-
-For code hosted on other servers, goinstall recognizes the general form
-
- repository.vcs/path
-
-as denoting the given repository, with or without the .vcs suffix, using
-the named version control system, and then the path inside that repository.
-The supported version control systems are:
-
- Bazaar .bzr
- Git .git
- Mercurial .hg
- Subversion .svn
-
-For example,
-
- import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at example.org/user/foo
-or foo.hg, and
-
- import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at example.com/repo or
-repo.git.
-
-When a version control system supports multiple protocols, goinstall tries each
-in turn.
-For example, for Git it tries git://, then https://, then http://.
-
-
-The GOPATH Environment Variable
-
-GOPATH may be set to a colon-separated list of paths inside which Go code,
-package objects, and executables may be found.
-
-Set a GOPATH to use goinstall to build and install your own code and
-external libraries outside of the Go tree (and to avoid writing Makefiles).
-
-The top-level directory structure of a GOPATH is prescribed:
-
-The 'src' directory is for source code. The directory naming inside 'src'
-determines the package import path or executable name.
-
-The 'pkg' directory is for package objects. Like the Go tree, package objects
-are stored inside a directory named after the target operating system and
-processor architecture ('pkg/$GOOS_$GOARCH').
-A package whose source is located at '$GOPATH/src/foo/bar' would be imported
-as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.
-
-The 'bin' directory is for executable files.
-Goinstall installs program binaries using the name of the source folder.
-A binary whose source is at 'src/foo/qux' would be built and installed to
-'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
-you can put the bin directory in your PATH.)
-
-Here's an example directory layout:
-
- GOPATH=/home/user/gocode
-
- /home/user/gocode/
- src/foo/
- bar/ (go code in package bar)
- qux/ (go code in package main)
- bin/qux (executable file)
- pkg/linux_amd64/foo/bar.a (object file)
-
-Run 'goinstall foo/bar' to build and install the package 'foo/bar'
-(and its dependencies).
-Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
-If the directory cannot be found, goinstall will attempt to fetch the
-source from a remote repository and write it to the 'src' directory of the
-first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).
-
-Goinstall recognizes relative and absolute paths (paths beginning with / or .).
-The following commands would build our example packages:
-
- goinstall /home/user/gocode/src/foo/bar # build and install foo/bar
- cd /home/user/gocode/src/foo
- goinstall ./bar # build and install foo/bar (again)
- cd qux
- goinstall . # build and install foo/qux
-
-*/
-package documentation
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
deleted file mode 100644
index cc873150a..000000000
--- a/src/cmd/goinstall/download.go
+++ /dev/null
@@ -1,353 +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.
-
-// Download remote packages.
-
-package main
-
-import (
- "bytes"
- "exec"
- "fmt"
- "http"
- "os"
- "path/filepath"
- "regexp"
- "runtime"
- "strconv"
- "strings"
-)
-
-const dashboardURL = "http://godashboard.appspot.com/package"
-
-// maybeReportToDashboard reports path to dashboard unless
-// -dashboard=false is on command line. It ignores errors.
-func maybeReportToDashboard(path string) {
- // if -dashboard=false was on command line, do nothing
- if !*reportToDashboard {
- return
- }
-
- // otherwise lob url to dashboard
- r, _ := http.Post(dashboardURL, "application/x-www-form-urlencoded", strings.NewReader("path="+path))
- if r != nil && r.Body != nil {
- r.Body.Close()
- }
-}
-
-// a vcs represents a version control system
-// like Mercurial, Git, or Subversion.
-type vcs struct {
- name string
- cmd string
- metadir string
- checkout string
- clone string
- update string
- updateRevFlag string
- pull string
- pullForceFlag string
- tagList string
- tagListRe *regexp.Regexp
- check string
- protocols []string
- suffix string
- defaultHosts []host
-}
-
-type host struct {
- pattern *regexp.Regexp
- protocol string
- suffix string
-}
-
-var hg = vcs{
- name: "Mercurial",
- cmd: "hg",
- metadir: ".hg",
- checkout: "checkout",
- clone: "clone",
- update: "update",
- pull: "pull",
- tagList: "tags",
- tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
- check: "identify",
- protocols: []string{"https", "http"},
- suffix: ".hg",
- defaultHosts: []host{
- {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
- {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""},
- },
-}
-
-var git = vcs{
- name: "Git",
- cmd: "git",
- metadir: ".git",
- checkout: "checkout",
- clone: "clone",
- update: "pull",
- pull: "fetch",
- tagList: "tag",
- tagListRe: regexp.MustCompile("([^\n]+)\n"),
- check: "ls-remote",
- protocols: []string{"git", "https", "http"},
- suffix: ".git",
- defaultHosts: []host{
- {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/git)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
- {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
- },
-}
-
-var svn = vcs{
- name: "Subversion",
- cmd: "svn",
- metadir: ".svn",
- checkout: "checkout",
- clone: "checkout",
- update: "update",
- check: "info",
- protocols: []string{"https", "http", "svn"},
- suffix: ".svn",
- defaultHosts: []host{
- {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
- },
-}
-
-var bzr = vcs{
- name: "Bazaar",
- cmd: "bzr",
- metadir: ".bzr",
- checkout: "update",
- clone: "branch",
- update: "update",
- updateRevFlag: "-r",
- pull: "pull",
- pullForceFlag: "--overwrite",
- tagList: "tags",
- tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
- check: "info",
- protocols: []string{"https", "http", "bzr"},
- suffix: ".bzr",
- defaultHosts: []host{
- {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""},
- },
-}
-
-var vcsList = []*vcs{&git, &hg, &bzr, &svn}
-
-type vcsMatch struct {
- *vcs
- prefix, repo string
-}
-
-// findPublicRepo checks whether pkg is located at one of
-// the supported code hosting sites and, if so, returns a match.
-func findPublicRepo(pkg string) (*vcsMatch, os.Error) {
- for _, v := range vcsList {
- for _, host := range v.defaultHosts {
- if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
- if host.suffix != "" && strings.HasSuffix(hm[1], host.suffix) {
- return nil, os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
- }
- repo := host.protocol + "://" + hm[1] + host.suffix
- return &vcsMatch{v, hm[1], repo}, nil
- }
- }
- }
- return nil, nil
-}
-
-// findAnyRepo looks for a vcs suffix in pkg (.git, etc) and returns a match.
-func findAnyRepo(pkg string) (*vcsMatch, os.Error) {
- for _, v := range vcsList {
- i := strings.Index(pkg+"/", v.suffix+"/")
- if i < 0 {
- continue
- }
- if !strings.Contains(pkg[:i], "/") {
- continue // don't match vcs suffix in the host name
- }
- if m := v.find(pkg[:i]); m != nil {
- return m, nil
- }
- return nil, fmt.Errorf("couldn't find %s repository", v.name)
- }
- return nil, nil
-}
-
-func (v *vcs) find(pkg string) *vcsMatch {
- for _, proto := range v.protocols {
- for _, suffix := range []string{"", v.suffix} {
- repo := proto + "://" + pkg + suffix
- out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput()
- if err == nil {
- printf("find %s: found %s\n", pkg, repo)
- return &vcsMatch{v, pkg + v.suffix, repo}
- }
- printf("find %s: %s %s %s: %v\n%s\n", pkg, v.cmd, v.check, repo, err, out)
- }
- }
- return nil
-}
-
-// isRemote returns true if the first part of the package name looks like a
-// hostname - i.e. contains at least one '.' and the last part is at least 2
-// characters.
-func isRemote(pkg string) bool {
- parts := strings.SplitN(pkg, "/", 2)
- if len(parts) != 2 {
- return false
- }
- parts = strings.Split(parts[0], ".")
- if len(parts) < 2 || len(parts[len(parts)-1]) < 2 {
- return false
- }
- return true
-}
-
-// download checks out or updates pkg from the remote server.
-func download(pkg, srcDir string) (public bool, err os.Error) {
- if strings.Contains(pkg, "..") {
- err = os.NewError("invalid path (contains ..)")
- return
- }
- m, err := findPublicRepo(pkg)
- if err != nil {
- return
- }
- if m != nil {
- public = true
- } else {
- m, err = findAnyRepo(pkg)
- if err != nil {
- return
- }
- }
- if m == nil {
- err = os.NewError("cannot download: " + pkg)
- return
- }
- err = m.checkoutRepo(srcDir, m.prefix, m.repo)
- return
-}
-
-// updateRepo gets a list of tags in the repository and
-// checks out the tag closest to the current runtime.Version.
-// If no matching tag is found, it just updates to tip.
-func (v *vcs) updateRepo(dst string) os.Error {
- if v.tagList == "" || v.tagListRe == nil {
- // TODO(adg): fix for svn
- return run(dst, nil, v.cmd, v.update)
- }
-
- // Get tag list.
- stderr := new(bytes.Buffer)
- cmd := exec.Command(v.cmd, v.tagList)
- cmd.Dir = dst
- cmd.Stderr = stderr
- b, err := cmd.Output()
- if err != nil {
- errorf("%s %s: %s\n", v.cmd, v.tagList, stderr)
- return err
- }
- var tags []string
- for _, m := range v.tagListRe.FindAllStringSubmatch(string(b), -1) {
- tags = append(tags, m[1])
- }
-
- // Only use the tag component of runtime.Version.
- ver := strings.Split(runtime.Version(), " ")[0]
-
- // Select tag.
- if tag := selectTag(ver, tags); tag != "" {
- printf("selecting revision %q\n", tag)
- return run(dst, nil, v.cmd, v.checkout, v.updateRevFlag+tag)
- }
-
- // No matching tag found, make default selection.
- printf("selecting tip\n")
- return run(dst, nil, v.cmd, v.update)
-}
-
-// selectTag returns the closest matching tag for a given version.
-// Closest means the latest one that is not after the current release.
-// Version "release.rN" matches tags of the form "go.rN" (N being a decimal).
-// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
-func selectTag(goVersion string, tags []string) (match string) {
- const rPrefix = "release.r"
- if strings.HasPrefix(goVersion, rPrefix) {
- p := "go.r"
- v, err := strconv.Atof64(goVersion[len(rPrefix):])
- if err != nil {
- return ""
- }
- var matchf float64
- for _, t := range tags {
- if !strings.HasPrefix(t, p) {
- continue
- }
- tf, err := strconv.Atof64(t[len(p):])
- if err != nil {
- continue
- }
- if matchf < tf && tf <= v {
- match, matchf = t, tf
- }
- }
- }
- const wPrefix = "weekly."
- if strings.HasPrefix(goVersion, wPrefix) {
- p := "go.weekly."
- v := goVersion[len(wPrefix):]
- for _, t := range tags {
- if !strings.HasPrefix(t, p) {
- continue
- }
- if match < t && t[len(p):] <= v {
- match = t
- }
- }
- }
- return match
-}
-
-// checkoutRepo checks out repo into dst using vcs.
-// It tries to check out (or update, if the dst already
-// exists and -u was specified on the command line)
-// the repository at tag/branch "release". If there is no
-// such tag or branch, it falls back to the repository tip.
-func (vcs *vcs) checkoutRepo(srcDir, pkgprefix, repo string) os.Error {
- dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
- dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
- if err == nil && !dir.IsDirectory() {
- return os.NewError("not a directory: " + dst)
- }
- if err != nil {
- parent, _ := filepath.Split(dst)
- if err = os.MkdirAll(parent, 0777); err != nil {
- return err
- }
- if err = run(string(filepath.Separator), nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
- return err
- }
- return vcs.updateRepo(dst)
- }
- if *update {
- // Retrieve new revisions from the remote branch, if the VCS
- // supports this operation independently (e.g. svn doesn't)
- if vcs.pull != "" {
- if vcs.pullForceFlag != "" {
- if err = run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
- return err
- }
- } else if err = run(dst, nil, vcs.cmd, vcs.pull); err != nil {
- return err
- }
- }
- // Update to release or latest revision
- return vcs.updateRepo(dst)
- }
- return nil
-}
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
deleted file mode 100644
index acda6efbb..000000000
--- a/src/cmd/goinstall/main.go
+++ /dev/null
@@ -1,334 +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 main
-
-import (
- "bytes"
- "exec"
- "flag"
- "fmt"
- "go/build"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
- "regexp"
- "runtime"
- "strings"
-)
-
-func usage() {
- fmt.Fprint(os.Stderr, "usage: goinstall importpath...\n")
- fmt.Fprintf(os.Stderr, "\tgoinstall -a\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-const logfile = "goinstall.log"
-
-var (
- fset = token.NewFileSet()
- argv0 = os.Args[0]
- errors = false
- parents = make(map[string]string)
- visit = make(map[string]status)
- installedPkgs = make(map[string]map[string]bool)
- schemeRe = regexp.MustCompile(`^[a-z]+://`)
-
- allpkg = flag.Bool("a", false, "install all previously installed packages")
- reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
- update = flag.Bool("u", false, "update already-downloaded packages")
- doInstall = flag.Bool("install", true, "build and install")
- clean = flag.Bool("clean", false, "clean the package directory before installing")
- nuke = flag.Bool("nuke", false, "clean the package directory and target before installing")
- useMake = flag.Bool("make", true, "use make to build and install")
- verbose = flag.Bool("v", false, "verbose")
-)
-
-type status int // status for visited map
-const (
- unvisited status = iota
- visiting
- done
-)
-
-func logf(format string, args ...interface{}) {
- format = "%s: " + format
- args = append([]interface{}{argv0}, args...)
- fmt.Fprintf(os.Stderr, format, args...)
-}
-
-func printf(format string, args ...interface{}) {
- if *verbose {
- logf(format, args...)
- }
-}
-
-func errorf(format string, args ...interface{}) {
- errors = true
- logf(format, args...)
-}
-
-func terrorf(tree *build.Tree, format string, args ...interface{}) {
- if tree != nil && tree.Goroot && os.Getenv("GOPATH") == "" {
- format = strings.TrimRight(format, "\n") + " ($GOPATH not set)\n"
- }
- errorf(format, args...)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- if runtime.GOROOT() == "" {
- fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
- os.Exit(1)
- }
- readPackageList()
-
- // special case - "unsafe" is already installed
- visit["unsafe"] = done
-
- args := flag.Args()
- if *allpkg {
- if len(args) != 0 {
- usage() // -a and package list both provided
- }
- // install all packages that were ever installed
- n := 0
- for _, pkgs := range installedPkgs {
- for pkg := range pkgs {
- args = append(args, pkg)
- n++
- }
- }
- if n == 0 {
- logf("no installed packages\n")
- os.Exit(1)
- }
- }
- if len(args) == 0 {
- usage()
- }
- for _, path := range args {
- if s := schemeRe.FindString(path); s != "" {
- errorf("%q used in import path, try %q\n", s, path[len(s):])
- continue
- }
-
- install(path, "")
- }
- if errors {
- os.Exit(1)
- }
-}
-
-// printDeps prints the dependency path that leads to pkg.
-func printDeps(pkg string) {
- if pkg == "" {
- return
- }
- if visit[pkg] != done {
- printDeps(parents[pkg])
- }
- fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
-}
-
-// readPackageList reads the list of installed packages from the
-// goinstall.log files in GOROOT and the GOPATHs and initalizes
-// the installedPkgs variable.
-func readPackageList() {
- for _, t := range build.Path {
- installedPkgs[t.Path] = make(map[string]bool)
- name := filepath.Join(t.Path, logfile)
- pkglistdata, err := ioutil.ReadFile(name)
- if err != nil {
- printf("%s\n", err)
- continue
- }
- pkglist := strings.Fields(string(pkglistdata))
- for _, pkg := range pkglist {
- installedPkgs[t.Path][pkg] = true
- }
- }
-}
-
-// logPackage logs the named package as installed in the goinstall.log file
-// in the given tree if the package is not already in that file.
-func logPackage(pkg string, tree *build.Tree) (logged bool) {
- if installedPkgs[tree.Path][pkg] {
- return false
- }
- name := filepath.Join(tree.Path, logfile)
- fout, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
- if err != nil {
- terrorf(tree, "package log: %s\n", err)
- return false
- }
- fmt.Fprintf(fout, "%s\n", pkg)
- fout.Close()
- return true
-}
-
-// install installs the package named by path, which is needed by parent.
-func install(pkg, parent string) {
- // Make sure we're not already trying to install pkg.
- switch visit[pkg] {
- case done:
- return
- case visiting:
- fmt.Fprintf(os.Stderr, "%s: package dependency cycle\n", argv0)
- printDeps(parent)
- fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
- os.Exit(2)
- }
- parents[pkg] = parent
- visit[pkg] = visiting
- defer func() {
- visit[pkg] = done
- }()
-
- // Don't allow trailing '/'
- if _, f := filepath.Split(pkg); f == "" {
- errorf("%s should not have trailing '/'\n", pkg)
- return
- }
-
- // Check whether package is local or remote.
- // If remote, download or update it.
- tree, pkg, err := build.FindTree(pkg)
- // Don't build the standard library.
- if err == nil && tree.Goroot && isStandardPath(pkg) {
- if parent == "" {
- errorf("%s: can not goinstall the standard library\n", pkg)
- } else {
- printf("%s: skipping standard library\n", pkg)
- }
- return
- }
- // Download remote packages if not found or forced with -u flag.
- remote, public := isRemote(pkg), false
- if remote {
- if err == build.ErrNotFound || (err == nil && *update) {
- // Download remote package.
- printf("%s: download\n", pkg)
- public, err = download(pkg, tree.SrcDir())
- } else {
- // Test if this is a public repository
- // (for reporting to dashboard).
- m, _ := findPublicRepo(pkg)
- public = m != nil
- }
- }
- if err != nil {
- terrorf(tree, "%s: %v\n", pkg, err)
- return
- }
- dir := filepath.Join(tree.SrcDir(), pkg)
-
- // Install prerequisites.
- dirInfo, err := build.ScanDir(dir, parent == "")
- if err != nil {
- terrorf(tree, "%s: %v\n", pkg, err)
- return
- }
- if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 {
- terrorf(tree, "%s: package has no files\n", pkg)
- return
- }
- for _, p := range dirInfo.Imports {
- if p != "C" {
- install(p, pkg)
- }
- }
- if errors {
- return
- }
-
- // Install this package.
- if *useMake {
- err := domake(dir, pkg, tree, dirInfo.IsCommand())
- if err != nil {
- terrorf(tree, "%s: install: %v\n", pkg, err)
- return
- }
- } else {
- script, err := build.Build(tree, pkg, dirInfo)
- if err != nil {
- terrorf(tree, "%s: install: %v\n", pkg, err)
- return
- }
- if *nuke {
- printf("%s: nuke\n", pkg)
- script.Nuke()
- } else if *clean {
- printf("%s: clean\n", pkg)
- script.Clean()
- }
- if *doInstall {
- if script.Stale() {
- printf("%s: install\n", pkg)
- if err := script.Run(); err != nil {
- terrorf(tree, "%s: install: %v\n", pkg, err)
- return
- }
- } else {
- printf("%s: up-to-date\n", pkg)
- }
- }
- }
-
- if remote {
- // mark package as installed in goinstall.log
- logged := logPackage(pkg, tree)
-
- // report installation to the dashboard if this is the first
- // install from a public repository.
- if logged && public {
- maybeReportToDashboard(pkg)
- }
- }
-}
-
-// Is this a standard package path? strings container/vector etc.
-// Assume that if the first element has a dot, it's a domain name
-// and is not the standard package path.
-func isStandardPath(s string) bool {
- dot := strings.Index(s, ".")
- slash := strings.Index(s, "/")
- return dot < 0 || 0 < slash && slash < dot
-}
-
-// run runs the command cmd in directory dir with standard input stdin.
-// If the command fails, run prints the command and output on standard error
-// in addition to returning a non-nil os.Error.
-func run(dir string, stdin []byte, cmd ...string) os.Error {
- return genRun(dir, stdin, cmd, false)
-}
-
-// quietRun is like run but prints nothing on failure unless -v is used.
-func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
- return genRun(dir, stdin, cmd, true)
-}
-
-// genRun implements run and quietRun.
-func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
- cmd := exec.Command(arg[0], arg[1:]...)
- cmd.Stdin = bytes.NewBuffer(stdin)
- cmd.Dir = dir
- printf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
- out, err := cmd.CombinedOutput()
- if err != nil {
- if !quiet || *verbose {
- if dir != "" {
- dir = "cd " + dir + "; "
- }
- fmt.Fprintf(os.Stderr, "%s: === %s%s\n", cmd.Path, dir, strings.Join(cmd.Args, " "))
- os.Stderr.Write(out)
- fmt.Fprintf(os.Stderr, "--- %s\n", err)
- }
- return os.NewError("running " + arg[0] + ": " + err.String())
- }
- return nil
-}
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
deleted file mode 100644
index 38a70ddfd..000000000
--- a/src/cmd/goinstall/make.go
+++ /dev/null
@@ -1,175 +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.
-
-// Run "make install" to build package.
-
-package main
-
-import (
- "bytes"
- "go/build"
- "os"
- "path/filepath"
- "strings"
- "template"
-)
-
-// domake builds the package in dir.
-// domake generates a standard Makefile and passes it
-// to make on standard input.
-func domake(dir, pkg string, tree *build.Tree, isCmd bool) (err os.Error) {
- makefile, err := makeMakefile(dir, pkg, tree, isCmd)
- if err != nil {
- return err
- }
- cmd := []string{"bash", "gomake", "-f-"}
- if *nuke {
- cmd = append(cmd, "nuke")
- } else if *clean {
- cmd = append(cmd, "clean")
- }
- cmd = append(cmd, "install")
- return run(dir, makefile, cmd...)
-}
-
-// makeMakefile computes the standard Makefile for the directory dir
-// installing as package pkg. It includes all *.go files in the directory
-// except those in package main and those ending in _test.go.
-func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, os.Error) {
- if !safeName(pkg) {
- return nil, os.NewError("unsafe name: " + pkg)
- }
- targ := pkg
- targDir := tree.PkgDir()
- if isCmd {
- // use the last part of the package name for targ
- _, targ = filepath.Split(pkg)
- targDir = tree.BinDir()
- }
- dirInfo, err := build.ScanDir(dir, isCmd)
- if err != nil {
- return nil, err
- }
-
- cgoFiles := dirInfo.CgoFiles
- isCgo := make(map[string]bool, len(cgoFiles))
- for _, file := range cgoFiles {
- if !safeName(file) {
- return nil, os.NewError("bad name: " + file)
- }
- isCgo[file] = true
- }
-
- goFiles := make([]string, 0, len(dirInfo.GoFiles))
- for _, file := range dirInfo.GoFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- if !isCgo[file] {
- goFiles = append(goFiles, file)
- }
- }
-
- oFiles := make([]string, 0, len(dirInfo.CFiles)+len(dirInfo.SFiles))
- cgoOFiles := make([]string, 0, len(dirInfo.CFiles))
- for _, file := range dirInfo.CFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- // When cgo is in use, C files are compiled with gcc,
- // otherwise they're compiled with gc.
- if len(cgoFiles) > 0 {
- cgoOFiles = append(cgoOFiles, file[:len(file)-2]+".o")
- } else {
- oFiles = append(oFiles, file[:len(file)-2]+".$O")
- }
- }
-
- for _, file := range dirInfo.SFiles {
- if !safeName(file) {
- return nil, os.NewError("unsafe name: " + file)
- }
- oFiles = append(oFiles, file[:len(file)-2]+".$O")
- }
-
- var imports []string
- for _, t := range build.Path {
- imports = append(imports, t.PkgDir())
- }
-
- var buf bytes.Buffer
- md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
- if isCmd {
- md.Type = "cmd"
- }
- if err := makefileTemplate.Execute(&buf, &md); err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
-
-func safeName(s string) bool {
- if s == "" {
- return false
- }
- if strings.Contains(s, "..") {
- return false
- }
- for i := 0; i < len(s); i++ {
- if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
- return false
- }
- }
- return true
-}
-
-// makedata is the data type for the makefileTemplate.
-type makedata struct {
- Targ string // build target
- TargDir string // build target directory
- Type string // build type: "pkg" or "cmd"
- GoFiles []string // list of non-cgo .go files
- OFiles []string // list of .$O files
- CgoFiles []string // list of cgo .go files
- CgoOFiles []string // list of cgo .o files, without extension
- Imports []string // gc/ld import paths
-}
-
-var makefileTemplate = template.Must(template.New("Makefile").Parse(`
-include $(GOROOT)/src/Make.inc
-
-TARG={{.Targ}}
-TARGDIR={{.TargDir}}
-
-{{with .GoFiles}}
-GOFILES=\
-{{range .}} {{.}}\
-{{end}}
-
-{{end}}
-{{with .OFiles}}
-OFILES=\
-{{range .}} {{.}}\
-{{end}}
-
-{{end}}
-{{with .CgoFiles}}
-CGOFILES=\
-{{range .}} {{.}}\
-{{end}}
-
-{{end}}
-{{with .CgoOFiles}}
-CGO_OFILES=\
-{{range .}} {{.}}\
-{{end}}
-
-{{end}}
-GCIMPORTS={{range .Imports}}-I "{{.}}" {{end}}
-LDIMPORTS={{range .Imports}}-L "{{.}}" {{end}}
-
-include $(GOROOT)/src/Make.{{.Type}}
-`))
diff --git a/src/cmd/gomake/doc.go b/src/cmd/gomake/doc.go
deleted file mode 100644
index 2f35fd9dd..000000000
--- a/src/cmd/gomake/doc.go
+++ /dev/null
@@ -1,36 +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.
-
-/*
-The gomake command runs GNU make with an appropriate environment
-for using the conventional Go makefiles. If $GOROOT is already
-set in the environment, running gomake is exactly the same
-as running make (or, on BSD systems, running gmake).
-
-Usage: gomake [ target ... ]
-
-Common targets are:
-
- all (default)
- build the package or command, but do not install it.
-
- install
- build and install the package or command
-
- test
- run the tests (packages only)
-
- bench
- run benchmarks (packages only)
-
- clean
- remove object files from the current directory
-
- nuke
- make clean and remove the installed package or command
-
-See http://golang.org/doc/code.html for information about
-writing makefiles.
-*/
-package documentation
diff --git a/src/cmd/gopack/Makefile b/src/cmd/gopack/Makefile
deleted file mode 100644
index 91a8ac2df..000000000
--- a/src/cmd/gopack/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=gopack
-OFILES=\
- ar.$O\
-
-include ../../Make.ccmd
diff --git a/src/cmd/gotest/Makefile b/src/cmd/gotest/Makefile
deleted file mode 100644
index 5c1154537..000000000
--- a/src/cmd/gotest/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=gotest
-GOFILES=\
- flag.go\
- gotest.go\
-
-include ../../Make.cmd
diff --git a/src/cmd/gotest/doc.go b/src/cmd/gotest/doc.go
deleted file mode 100644
index 5be06f817..000000000
--- a/src/cmd/gotest/doc.go
+++ /dev/null
@@ -1,113 +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.
-
-/*
-
-Gotest is an automated testing tool for Go packages.
-
-Normally a Go package is compiled without its test files. Gotest is a
-tool that recompiles the package whose source is in the current
-directory, along with any files whose names match the pattern
-"[^.]*_test.go". Functions in the test source named TestXXX (where
-XXX is any alphanumeric string not starting with a lower case letter)
-will be run when the binary is executed. Gotest requires that the
-package have a standard package Makefile, one that includes
-go/src/Make.pkg.
-
-The test functions are run in the order they appear in the source.
-They should have the signature,
-
- func TestXXX(t *testing.T) { ... }
-
-Benchmark functions can be written as well; they will be run only when
-the -test.bench flag is provided. Benchmarks should have the
-signature,
-
- func BenchmarkXXX(b *testing.B) { ... }
-
-See the documentation of the testing package for more information.
-
-By default, gotest needs no arguments. It compiles all the .go files
-in the directory, including tests, and runs the tests. If file names
-are given (with flag -file=test.go, one per extra test source file),
-only those test files are added to the package. (The non-test files
-are always compiled.)
-
-The package is built in a special subdirectory so it does not
-interfere with the non-test installation.
-
-Usage:
- gotest [-file a.go -file b.go ...] [-c] [-x] [args for test binary]
-
-The flags specific to gotest are:
- -c Compile the test binary but do not run it.
- -file a.go Use only the tests in the source file a.go.
- Multiple -file flags may be provided.
- -x Print each subcommand gotest executes.
-
-Everything else on the command line is passed to the test binary.
-
-The resulting test binary, called (for amd64) 6.out, has several flags.
-
-Usage:
- 6.out [-test.v] [-test.run pattern] [-test.bench pattern] \
- [-test.cpuprofile=cpu.out] \
- [-test.memprofile=mem.out] [-test.memprofilerate=1] \
- [-test.timeout=10] [-test.short] \
- [-test.benchtime=3] [-test.cpu=1,2,3,4]
-
-The -test.v flag causes the tests to be logged as they run. The
--test.run flag causes only those tests whose names match the regular
-expression pattern to be run. By default all tests are run silently.
-
-If all specified tests pass, 6.out prints the word PASS and exits with
-a 0 exit code. If any tests fail, it prints error details, the word
-FAIL, and exits with a non-zero code. The -test.bench flag is
-analogous to the -test.run flag, but applies to benchmarks. No
-benchmarks run by default.
-
-The -test.cpuprofile flag causes the testing software to write a CPU
-profile to the specified file before exiting.
-
-The -test.memprofile flag causes the testing software to write a
-memory profile to the specified file when all tests are complete. The
--test.memprofilerate flag enables more precise (and expensive)
-profiles by setting runtime.MemProfileRate; run
- godoc runtime MemProfileRate
-for details. The defaults are no memory profile and the standard
-setting of MemProfileRate. The memory profile records a sampling of
-the memory in use at the end of the test. To profile all memory
-allocations, use -test.memprofilerate=1 to sample every byte and set
-the environment variable GOGC=off to disable the garbage collector,
-provided the test can run in the available memory without garbage
-collection.
-
-Use -test.run or -test.bench to limit profiling to a particular test
-or benchmark.
-
-The -test.short flag tells long-running tests to shorten their run
-time. It is off by default but set by all.bash so installations of
-the Go tree can do a sanity check but not spend time running
-exhaustive tests.
-
-The -test.timeout flag sets a timeout for the test in seconds. If the
-test runs for longer than that, it will panic, dumping a stack trace
-of all existing goroutines.
-
-The -test.benchtime flag specifies the number of seconds to run each benchmark.
-The default is one second.
-
-The -test.cpu flag specifies a list of GOMAXPROCS values for which
-the tests or benchmarks are executed. The default is the current
-value of GOMAXPROCS.
-
-For convenience, each of these -test.X flags of the test binary is
-also available as the flag -X in gotest itself. Flags not listed here
-are unaffected. For instance, the command
- gotest -x -v -cpuprofile=prof.out -dir=testdata -update -file x_test.go
-will compile the test binary using x_test.go and then run it as
- 6.out -test.v -test.cpuprofile=prof.out -dir=testdata -update
-
-*/
-package documentation
diff --git a/src/cmd/gotest/flag.go b/src/cmd/gotest/flag.go
deleted file mode 100644
index c3a28f9a3..000000000
--- a/src/cmd/gotest/flag.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "fmt"
- "os"
- "strconv"
- "strings"
-)
-
-// The flag handling part of gotest is large and distracting.
-// We can't use the flag package because some of the flags from
-// our command line are for us, and some are for 6.out, and
-// some are for both.
-
-var usageMessage = `Usage of %s:
- -c=false: compile but do not run the test binary
- -file=file:
- -x=false: print command lines as they are executed
-
- // These flags can be passed with or without a "test." prefix: -v or -test.v.
- -bench="": passes -test.bench to test
- -benchtime=1: passes -test.benchtime to test
- -cpu="": passes -test.cpu to test
- -cpuprofile="": passes -test.cpuprofile to test
- -memprofile="": passes -test.memprofile to test
- -memprofilerate=0: passes -test.memprofilerate to test
- -run="": passes -test.run to test
- -short=false: passes -test.short to test
- -timeout=0: passes -test.timeout to test
- -v=false: passes -test.v to test
-`
-
-// usage prints a usage message and exits.
-func usage() {
- fmt.Fprintf(os.Stdout, usageMessage, os.Args[0])
- os.Exit(2)
-}
-
-// flagSpec defines a flag we know about.
-type flagSpec struct {
- name string
- isBool bool
- passToTest bool // pass to Test
- multiOK bool // OK to have multiple instances
- present bool // flag has been seen
-}
-
-// flagDefn is the set of flags we process.
-var flagDefn = []*flagSpec{
- // gotest-local.
- &flagSpec{name: "c", isBool: true},
- &flagSpec{name: "file", multiOK: true},
- &flagSpec{name: "x", isBool: true},
-
- // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
- &flagSpec{name: "bench", passToTest: true},
- &flagSpec{name: "benchtime", passToTest: true},
- &flagSpec{name: "cpu", passToTest: true},
- &flagSpec{name: "cpuprofile", passToTest: true},
- &flagSpec{name: "memprofile", passToTest: true},
- &flagSpec{name: "memprofilerate", passToTest: true},
- &flagSpec{name: "run", passToTest: true},
- &flagSpec{name: "short", isBool: true, passToTest: true},
- &flagSpec{name: "timeout", passToTest: true},
- &flagSpec{name: "v", isBool: true, passToTest: true},
-}
-
-// flags processes the command line, grabbing -x and -c, rewriting known flags
-// to have "test" before them, and reading the command line for the 6.out.
-// Unfortunately for us, we need to do our own flag processing because gotest
-// grabs some flags but otherwise its command line is just a holding place for
-// 6.out's arguments.
-func flags() {
- for i := 1; i < len(os.Args); i++ {
- arg := os.Args[i]
- f, value, extraWord := flag(i)
- if f == nil {
- args = append(args, arg)
- continue
- }
- switch f.name {
- case "c":
- setBoolFlag(&cFlag, value)
- case "x":
- setBoolFlag(&xFlag, value)
- case "file":
- fileNames = append(fileNames, value)
- }
- if extraWord {
- i++
- }
- if f.passToTest {
- args = append(args, "-test."+f.name+"="+value)
- }
- }
-}
-
-// flag sees if argument i is a known flag and returns its definition, value, and whether it consumed an extra word.
-func flag(i int) (f *flagSpec, value string, extra bool) {
- arg := os.Args[i]
- if strings.HasPrefix(arg, "--") { // reduce two minuses to one
- arg = arg[1:]
- }
- if arg == "" || arg[0] != '-' {
- return
- }
- name := arg[1:]
- // If there's already "test.", drop it for now.
- if strings.HasPrefix(name, "test.") {
- name = name[5:]
- }
- equals := strings.Index(name, "=")
- if equals >= 0 {
- value = name[equals+1:]
- name = name[:equals]
- }
- for _, f = range flagDefn {
- if name == f.name {
- // Booleans are special because they have modes -x, -x=true, -x=false.
- if f.isBool {
- if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
- value = "true"
- } else {
- // verify it parses
- setBoolFlag(new(bool), value)
- }
- } else { // Non-booleans must have a value.
- extra = equals < 0
- if extra {
- if i+1 >= len(os.Args) {
- usage()
- }
- value = os.Args[i+1]
- }
- }
- if f.present && !f.multiOK {
- usage()
- }
- f.present = true
- return
- }
- }
- f = nil
- return
-}
-
-// setBoolFlag sets the addressed boolean to the value.
-func setBoolFlag(flag *bool, value string) {
- x, err := strconv.Atob(value)
- if err != nil {
- fmt.Fprintf(os.Stderr, "gotest: illegal bool flag value %s\n", value)
- usage()
- }
- *flag = x
-}
diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go
deleted file mode 100644
index 4cb3da23c..000000000
--- a/src/cmd/gotest/gotest.go
+++ /dev/null
@@ -1,435 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bufio"
- "exec"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "time"
- "unicode"
- "utf8"
-)
-
-// Environment for commands.
-var (
- XGC []string // 6g -I _test -o _xtest_.6
- GC []string // 6g -I _test _testmain.go
- GL []string // 6l -L _test _testmain.6
- GOARCH string
- GOROOT string
- GORUN string
- O string
- args []string // arguments passed to gotest; also passed to the binary
- fileNames []string
- env = os.Environ()
-)
-
-// These strings are created by getTestNames.
-var (
- insideFileNames []string // list of *.go files inside the package.
- outsideFileNames []string // list of *.go files outside the package (in package foo_test).
-)
-
-var (
- files []*File
- importPath string
-)
-
-// Flags for our own purposes. We do our own flag processing.
-var (
- cFlag bool
- xFlag bool
-)
-
-// elapsed returns the number of seconds since gotest started.
-func elapsed() float64 {
- return float64(time.Nanoseconds()-start) / 1e9
-}
-
-var start = time.Nanoseconds()
-
-// File represents a file that contains tests.
-type File struct {
- name string
- pkg string
- file *os.File
- astFile *ast.File
- tests []string // The names of the TestXXXs.
- benchmarks []string // The names of the BenchmarkXXXs.
-}
-
-func main() {
- flags()
- needMakefile()
- setEnvironment()
- getTestFileNames()
- parseFiles()
- getTestNames()
- run("gomake", "testpackage-clean")
- run("gomake", "testpackage", fmt.Sprintf("GOTESTFILES=%s", strings.Join(insideFileNames, " ")))
- if len(outsideFileNames) > 0 {
- run(append(XGC, outsideFileNames...)...)
- }
- importPath = runWithStdout("gomake", "-s", "importpath")
- writeTestmainGo()
- run(GC...)
- run(GL...)
- if !cFlag {
- runTestWithArgs("./" + O + ".out")
- }
- if xFlag {
- fmt.Printf("gotest %.2fs: done\n", elapsed())
- }
-}
-
-// needMakefile tests that we have a Makefile in this directory.
-func needMakefile() {
- if _, err := os.Stat("Makefile"); err != nil {
- Fatalf("please create a Makefile for gotest; see http://golang.org/doc/code.html for details")
- }
-}
-
-// Fatalf formats its arguments, prints the message with a final newline, and exits.
-func Fatalf(s string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "gotest: "+s+"\n", args...)
- os.Exit(2)
-}
-
-// theChar is the map from architecture to object character.
-var theChar = map[string]string{
- "arm": "5",
- "amd64": "6",
- "386": "8",
-}
-
-// addEnv adds a name=value pair to the environment passed to subcommands.
-// If the item is already in the environment, addEnv replaces the value.
-func addEnv(name, value string) {
- for i := 0; i < len(env); i++ {
- if strings.HasPrefix(env[i], name+"=") {
- env[i] = name + "=" + value
- return
- }
- }
- env = append(env, name+"="+value)
-}
-
-// setEnvironment assembles the configuration for gotest and its subcommands.
-func setEnvironment() {
- // Basic environment.
- GOROOT = runtime.GOROOT()
- addEnv("GOROOT", GOROOT)
- GOARCH = os.Getenv("GOARCH")
- if GOARCH == "" {
- GOARCH = runtime.GOARCH
- }
- addEnv("GOARCH", GOARCH)
- O = theChar[GOARCH]
- if O == "" {
- Fatalf("unknown architecture %s", GOARCH)
- }
-
- // Commands and their flags.
- gc := os.Getenv("GC")
- if gc == "" {
- gc = O + "g"
- }
- XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
- GC = []string{gc, "-I", "_test", "_testmain.go"}
- gl := os.Getenv("GL")
- if gl == "" {
- gl = O + "l"
- }
- GL = []string{gl, "-L", "_test", "_testmain." + O}
-
- // Silence make on Linux
- addEnv("MAKEFLAGS", "")
- addEnv("MAKELEVEL", "")
-}
-
-// getTestFileNames gets the set of files we're looking at.
-// If gotest has no arguments, it scans for file names matching "[^.]*_test.go".
-func getTestFileNames() {
- names := fileNames
- if len(names) == 0 {
- var err os.Error
- names, err = filepath.Glob("[^.]*_test.go")
- if err != nil {
- Fatalf("Glob pattern error: %s", err)
- }
- if len(names) == 0 {
- Fatalf(`no test files found: no match for "[^.]*_test.go"`)
- }
- }
- for _, n := range names {
- fd, err := os.Open(n)
- if err != nil {
- Fatalf("%s: %s", n, err)
- }
- f := &File{name: n, file: fd}
- files = append(files, f)
- }
-}
-
-// parseFiles parses the files and remembers the packages we find.
-func parseFiles() {
- fileSet := token.NewFileSet()
- for _, f := range files {
- // Report declaration errors so we can abort if the files are incorrect Go.
- file, err := parser.ParseFile(fileSet, f.name, nil, parser.DeclarationErrors)
- if err != nil {
- Fatalf("parse error: %s", err)
- }
- f.astFile = file
- f.pkg = file.Name.String()
- if f.pkg == "" {
- Fatalf("cannot happen: no package name in %s", f.name)
- }
- }
-}
-
-// getTestNames extracts the names of tests and benchmarks. They are all
-// top-level functions that are not methods.
-func getTestNames() {
- for _, f := range files {
- for _, d := range f.astFile.Decls {
- n, ok := d.(*ast.FuncDecl)
- if !ok {
- continue
- }
- if n.Recv != nil { // a method, not a function.
- continue
- }
- name := n.Name.String()
- if isTest(name, "Test") {
- f.tests = append(f.tests, name)
- } else if isTest(name, "Benchmark") {
- f.benchmarks = append(f.benchmarks, name)
- }
- // TODO: worth checking the signature? Probably not.
- }
- if strings.HasSuffix(f.pkg, "_test") {
- outsideFileNames = append(outsideFileNames, f.name)
- } else {
- insideFileNames = append(insideFileNames, f.name)
- }
- }
-}
-
-// isTest tells whether name looks like a test (or benchmark, according to prefix).
-// It is a Test (say) if there is a character after Test that is not a lower-case letter.
-// We don't want TesticularCancer.
-func isTest(name, prefix string) bool {
- if !strings.HasPrefix(name, prefix) {
- return false
- }
- if len(name) == len(prefix) { // "Test" is ok
- return true
- }
- rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
- return !unicode.IsLower(rune)
-}
-
-func run(args ...string) {
- doRun(args, false)
-}
-
-// runWithStdout is like run, but returns the text of standard output with the last newline dropped.
-func runWithStdout(argv ...string) string {
- s := doRun(argv, true)
- if strings.HasSuffix(s, "\r\n") {
- s = s[:len(s)-2]
- } else if strings.HasSuffix(s, "\n") {
- s = s[:len(s)-1]
- }
- if len(s) == 0 {
- Fatalf("no output from command %s", strings.Join(argv, " "))
- }
- return s
-}
-
-// runTestWithArgs appends gotest's runs the provided binary with the args passed on the command line.
-func runTestWithArgs(binary string) {
- doRun(append([]string{binary}, args...), false)
-}
-
-// doRun is the general command runner. The flag says whether we want to
-// retrieve standard output.
-func doRun(argv []string, returnStdout bool) string {
- if xFlag {
- fmt.Printf("gotest %.2fs: %s\n", elapsed(), strings.Join(argv, " "))
- t := -time.Nanoseconds()
- defer func() {
- t += time.Nanoseconds()
- fmt.Printf(" [+%.2fs]\n", float64(t)/1e9)
- }()
- }
- command := argv[0]
- if runtime.GOOS == "windows" && command == "gomake" {
- // gomake is a shell script and it cannot be executed directly on Windows.
- cmd := ""
- for i, v := range argv {
- if i > 0 {
- cmd += " "
- }
- cmd += `"` + v + `"`
- }
- command = "bash"
- argv = []string{"bash", "-c", cmd}
- }
- var err os.Error
- argv[0], err = exec.LookPath(argv[0])
- if err != nil {
- Fatalf("can't find %s: %s", command, err)
- }
- procAttr := &os.ProcAttr{
- Env: env,
- Files: []*os.File{
- os.Stdin,
- os.Stdout,
- os.Stderr,
- },
- }
- var r, w *os.File
- if returnStdout {
- r, w, err = os.Pipe()
- if err != nil {
- Fatalf("can't create pipe: %s", err)
- }
- procAttr.Files[1] = w
- }
- proc, err := os.StartProcess(argv[0], argv, procAttr)
- if err != nil {
- Fatalf("%s failed to start: %s", command, err)
- }
- if returnStdout {
- defer r.Close()
- w.Close()
- }
- waitMsg, err := proc.Wait(0)
- if err != nil || waitMsg == nil {
- Fatalf("%s failed: %s", command, err)
- }
- if !waitMsg.Exited() || waitMsg.ExitStatus() != 0 {
- Fatalf("%q failed: %s", strings.Join(argv, " "), waitMsg)
- }
- if returnStdout {
- b, err := ioutil.ReadAll(r)
- if err != nil {
- Fatalf("can't read output from command: %s", err)
- }
- return string(b)
- }
- return ""
-}
-
-// writeTestmainGo generates the test program to be compiled, "./_testmain.go".
-func writeTestmainGo() {
- f, err := os.Create("_testmain.go")
- if err != nil {
- Fatalf("can't create _testmain.go: %s", err)
- }
- defer f.Close()
- b := bufio.NewWriter(f)
- defer b.Flush()
-
- // Package and imports.
- fmt.Fprint(b, "package main\n\n")
- // Are there tests from a package other than the one we're testing?
- // We can't just use file names because some of the things we compiled
- // contain no tests.
- outsideTests := false
- insideTests := false
- for _, f := range files {
- //println(f.name, f.pkg)
- if len(f.tests) == 0 && len(f.benchmarks) == 0 {
- continue
- }
- if strings.HasSuffix(f.pkg, "_test") {
- outsideTests = true
- } else {
- insideTests = true
- }
- }
- if insideTests {
- switch importPath {
- case "testing":
- case "main":
- // Import path main is reserved, so import with
- // explicit reference to ./_test/main instead.
- // Also, the file we are writing defines a function named main,
- // so rename this import to __main__ to avoid name conflict.
- fmt.Fprintf(b, "import __main__ %q\n", "./_test/main")
- default:
- fmt.Fprintf(b, "import %q\n", importPath)
- }
- }
- if outsideTests {
- fmt.Fprintf(b, "import %q\n", "./_xtest_")
- }
- fmt.Fprintf(b, "import %q\n", "testing")
- fmt.Fprintf(b, "import __os__ %q\n", "os") // rename in case tested package is called os
- fmt.Fprintf(b, "import __regexp__ %q\n", "regexp") // rename in case tested package is called regexp
- fmt.Fprintln(b) // for gofmt
-
- // Tests.
- fmt.Fprintln(b, "var tests = []testing.InternalTest{")
- for _, f := range files {
- for _, t := range f.tests {
- fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, t, notMain(f.pkg), t)
- }
- }
- fmt.Fprintln(b, "}")
- fmt.Fprintln(b)
-
- // Benchmarks.
- fmt.Fprintf(b, "var benchmarks = []testing.InternalBenchmark{")
- for _, f := range files {
- for _, bm := range f.benchmarks {
- fmt.Fprintf(b, "\t{\"%s.%s\", %s.%s},\n", f.pkg, bm, notMain(f.pkg), bm)
- }
- }
- fmt.Fprintln(b, "}")
-
- // Body.
- fmt.Fprintln(b, testBody)
-}
-
-// notMain returns the package, renaming as appropriate if it's "main".
-func notMain(pkg string) string {
- if pkg == "main" {
- return "__main__"
- }
- return pkg
-}
-
-// testBody is just copied to the output. It's the code that runs the tests.
-var testBody = `
-var matchPat string
-var matchRe *__regexp__.Regexp
-
-func matchString(pat, str string) (result bool, err __os__.Error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = __regexp__.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
-func main() {
- testing.Main(matchString, tests, benchmarks)
-}`
diff --git a/src/cmd/gotry/Makefile b/src/cmd/gotry/Makefile
deleted file mode 100644
index 6a32bbf2d..000000000
--- a/src/cmd/gotry/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=install
-
-clean:
- @true
-
-install: install-gotry
-
-install-%: %
- ! test -f "$(GOBIN)"/$* || chmod u+w "$(GOBIN)"/$*
- sed 's`@@GOROOT@@`$(GOROOT_FINAL)`' $* >"$(GOBIN)"/$*
- chmod +x "$(GOBIN)"/$*
-
diff --git a/src/cmd/gotry/gotry b/src/cmd/gotry/gotry
deleted file mode 100755
index 3cc7a9864..000000000
--- a/src/cmd/gotry/gotry
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Using all the non-test *.go files in the named directory, write
-# out a file /tmp/$USER.try.go to evaluate the expressions on the
-# command line, perhaps to discover a function or method that
-# gives the desired results. See usage message.
-# Compile the program and run it.
-
-# Makes egrep,grep work better in general if we put them
-# in ordinary C mode instead of what the current language is.
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
-
-export GOROOT=${GOROOT:-"@@GOROOT@@"}
-eval $(gomake -j1 --no-print-directory -f "$GOROOT"/src/Make.inc go-env)
-if [ -z "$O" ]; then
- echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
- exit 2
-fi
-
-# Allow overrides
-GC="${_GC:-$GC} -I _test"
-GL="${GL:-$LD} -L _test"
-AS="$AS"
-CC="$CC"
-LD="$LD"
-export GC GL O AS CC LD
-
-# Macros for tab and quotes for easier readability.
-T=' '
-BQ='`'
-SQ="'"
-DQ='"'
-SD="$SQ$DQ"
-DS="$DQ$SQ"
-
-usage="usage: gotry [packagedirectory] expression ...
-Given one expression, gotry attempts to evaluate that expression.
-Given multiple expressions, gotry treats them as a list of arguments
-and result values and attempts to find a function in the package
-that, given the first few expressions as arguments, evaluates to
-the remaining expressions as results. If the first expression has
-methods, it will also search for applicable methods.
-
-If there are multiple expressions, a package directory must be
-specified. If there is a package argument, the expressions are
-evaluated in an environment that includes
- import . ${DQ}packagedirectory${DQ}
-
-Examples:
- gotry 3+4
- # evaluates to 7
- gotry strings ${SD}abc${DS} ${SD}c${DS} 7-5
- # finds strings.Index etc.
- gotry regexp ${SQ}MustCompile(${DQ}^[0-9]+${DQ})${SQ} ${SD}12345${DS} true
- # finds Regexp.MatchString
-
-"
-
-function fail() {
- echo 2>&1 "$@"
- exit 2
-}
-
-case $# in
- 0)
- fail "$usage"
- ;;
- *)
- case "$1" in
- -*help|-*'?'|'?')
- fail "$usage"
- esac
- if test -d "$GOROOT/src/pkg/$1"
- then
- pkg=$(basename $1)
- dir=$GOROOT/src/pkg/$1
- importdir=$1
- shift
- case "$pkg" in
- os|syscall)
- fail "gotry: cannot try packages os or syscall; they are too dangerous"
- esac
- fi
- ;;
-esac
-
-spaces='[ ][ ]*'
-
-function getFunctions() {
- if [ "$pkg" = "" ]
- then
- return
- fi
- for file in $dir/*.go
- do
- case $file in
- *_test*)
- continue
- esac
- grep "func$spaces[A-Z]" $file | # TODO: should be Unicode upper case
- sed "s/func$spaces//;s/(.*//"
- done | sort -u
-}
-
-# Generate list of public functions.
-functions=$(getFunctions)
-
-# Write file to compile
-file="/tmp/$USER.try"
-rm -f "file.go"
-(
-cat <<'!'
-package main
-
-import (
- "os"
- "try"
-!
-
-if [ "$pkg" != "" ]
-then
- echo "$T" . '"'$importdir'"'
-fi
-
-cat <<!
-)
-func main() {
- try.Main("$pkg", firstArg, functions, args)
-}
-var functions = map[string] interface{}{
-!
-
-for i in $functions
-do
- echo "$T"'"'$i'": '$i','
-done
-echo "}"
-
-echo 'var args = []interface{}{'
-
-if [ $# = 1 ]
-then
- echo "${T}toSlice($1)",
-else
-for i
- do
- echo "$T$i",
- done
-fi
-echo "}"
-
-cat <<!
-var firstArg = $BQ$1$BQ
-var _ os.Error
-func toSlice(a ...interface{}) []interface{} { return a }
-!
-
-)>"$file.go"
-
-$GC -o "$file.$O" "$file.go" &&
-$GL -o "$file" "$file.$O" &&
-"$file" "_$@"
-rm -f "$file" "$file.go" "$file.$O"
diff --git a/src/cmd/gotype/Makefile b/src/cmd/gotype/Makefile
deleted file mode 100644
index 18171945d..000000000
--- a/src/cmd/gotype/Makefile
+++ /dev/null
@@ -1,17 +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.
-
-include ../../Make.inc
-
-TARG=gotype
-GOFILES=\
- gotype.go\
-
-include ../../Make.cmd
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/gotype/doc.go b/src/cmd/gotype/doc.go
deleted file mode 100644
index 1aa0faa75..000000000
--- a/src/cmd/gotype/doc.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-The gotype command does syntactic and semantic analysis of Go files
-and packages similar to the analysis performed by the front-end of
-a Go compiler. Errors are reported if the analysis fails; otherwise
-gotype is quiet (unless -v is set).
-
-Without a list of paths, gotype processes the standard input, which must
-be the source of a single package file.
-
-Given a list of file names, each file must be a source file belonging to
-the same package unless the package name is explicitly specified with the
--p flag.
-
-Given a directory name, gotype collects all .go files in the directory
-and processes them as if they were provided as an explicit list of file
-names. Each directory is processed independently. Files starting with .
-or not ending in .go are ignored.
-
-Usage:
- gotype [flags] [path ...]
-
-The flags are:
- -e
- Print all (including spurious) errors.
- -p pkgName
- Process only those files in package pkgName.
- -r
- Recursively process subdirectories.
- -v
- Verbose mode.
-
-Debugging flags:
- -ast
- Print AST (disables concurrent parsing).
- -trace
- Print parse trace (disables concurrent parsing).
-
-
-Examples
-
-To check the files file.go, old.saved, and .ignored:
-
- gotype file.go old.saved .ignored
-
-To check all .go files belonging to package main in the current directory
-and recursively in all subdirectories:
-
- gotype -p main -r .
-
-To verify the output of a pipe:
-
- echo "package foo" | gotype
-
-*/
-package documentation
-
-// BUG(gri): At the moment, only single-file scope analysis is performed.
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
deleted file mode 100644
index e5e9417ff..000000000
--- a/src/cmd/gotype/gotype.go
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/scanner"
- "go/token"
- "go/types"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-)
-
-var (
- // main operation modes
- pkgName = flag.String("p", "", "process only those files in package pkgName")
- recursive = flag.Bool("r", false, "recursively process subdirectories")
- verbose = flag.Bool("v", false, "verbose mode")
- allErrors = flag.Bool("e", false, "print all (including spurious) errors")
-
- // debugging support
- printTrace = flag.Bool("trace", false, "print parse trace")
- printAST = flag.Bool("ast", false, "print AST")
-)
-
-var exitCode = 0
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func report(err os.Error) {
- scanner.PrintError(os.Stderr, err)
- exitCode = 2
-}
-
-// parse returns the AST for the Go source src.
-// The filename is for error reporting only.
-// The result is nil if there were errors or if
-// the file does not belong to the -p package.
-func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
- if *verbose {
- fmt.Println(filename)
- }
-
- // ignore files with different package name
- if *pkgName != "" {
- file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
- if err != nil {
- report(err)
- return nil
- }
- if file.Name.Name != *pkgName {
- if *verbose {
- fmt.Printf("\tignored (package %s)\n", file.Name.Name)
- }
- return nil
- }
- }
-
- // parse entire file
- mode := parser.DeclarationErrors
- if *allErrors {
- mode |= parser.SpuriousErrors
- }
- if *printTrace {
- mode |= parser.Trace
- }
- file, err := parser.ParseFile(fset, filename, src, mode)
- if err != nil {
- report(err)
- return nil
- }
- if *printAST {
- ast.Print(fset, file)
- }
-
- return file
-}
-
-func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
- files = make(map[string]*ast.File)
- src, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- report(err)
- return
- }
- const filename = "<standard input>"
- if file := parse(fset, filename, src); file != nil {
- files[filename] = file
- }
- return
-}
-
-func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
- files = make(map[string]*ast.File)
- for _, filename := range filenames {
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- report(err)
- continue
- }
- if file := parse(fset, filename, src); file != nil {
- if files[filename] != nil {
- report(os.NewError(fmt.Sprintf("%q: duplicate file", filename)))
- continue
- }
- files[filename] = file
- }
- }
- return
-}
-
-func isGoFilename(filename string) bool {
- // ignore non-Go files
- return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
-}
-
-func processDirectory(dirname string) {
- f, err := os.Open(dirname)
- if err != nil {
- report(err)
- return
- }
- filenames, err := f.Readdirnames(-1)
- f.Close()
- if err != nil {
- report(err)
- // continue since filenames may not be empty
- }
- for i, filename := range filenames {
- filenames[i] = filepath.Join(dirname, filename)
- }
- processFiles(filenames, false)
-}
-
-func processFiles(filenames []string, allFiles bool) {
- i := 0
- for _, filename := range filenames {
- switch info, err := os.Stat(filename); {
- case err != nil:
- report(err)
- case info.IsRegular():
- if allFiles || isGoFilename(info.Name) {
- filenames[i] = filename
- i++
- }
- case info.IsDirectory():
- if allFiles || *recursive {
- processDirectory(filename)
- }
- }
- }
- fset := token.NewFileSet()
- processPackage(fset, parseFiles(fset, filenames[0:i]))
-}
-
-func processPackage(fset *token.FileSet, files map[string]*ast.File) {
- // make a package (resolve all identifiers)
- pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
- if err != nil {
- report(err)
- return
- }
- _, err = types.Check(fset, pkg)
- if err != nil {
- report(err)
- }
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if flag.NArg() == 0 {
- fset := token.NewFileSet()
- processPackage(fset, parseStdin(fset))
- } else {
- processFiles(flag.Args(), true)
- }
-
- os.Exit(exitCode)
-}
diff --git a/src/cmd/gotype/gotype_test.go b/src/cmd/gotype/gotype_test.go
deleted file mode 100644
index ad0bc8903..000000000
--- a/src/cmd/gotype/gotype_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "path/filepath"
- "runtime"
- "testing"
-)
-
-func runTest(t *testing.T, path, pkg string) {
- exitCode = 0
- *pkgName = pkg
- *recursive = false
-
- if pkg == "" {
- processFiles([]string{path}, true)
- } else {
- processDirectory(path)
- }
-
- if exitCode != 0 {
- t.Errorf("processing %s failed: exitCode = %d", path, exitCode)
- }
-}
-
-var tests = []struct {
- path string
- pkg string
-}{
- // individual files
- {"testdata/test1.go", ""},
-
- // directories
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/ast"), "ast"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/doc"), "doc"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/token"), "scanner"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/scanner"), "scanner"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/parser"), "parser"},
- {filepath.Join(runtime.GOROOT(), "src/pkg/go/types"), "types"},
-}
-
-func Test(t *testing.T) {
- for _, test := range tests {
- runTest(t, test.path, test.pkg)
- }
-}
diff --git a/src/cmd/gotype/testdata/test1.go b/src/cmd/gotype/testdata/test1.go
deleted file mode 100644
index 0bd46568d..000000000
--- a/src/cmd/gotype/testdata/test1.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package p
-
-func _() {
- // the scope of a local type declaration starts immediately after the type name
- type T struct{ _ *T }
-}
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
deleted file mode 100644
index f565b78f5..000000000
--- a/src/cmd/govet/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=govet
-GOFILES=\
- govet.go\
-
-include ../../Make.cmd
-
-test testshort: $(TARG)
- ../../../test/errchk $(TARG) -printfuncs='Warn:1,Warnf:1' govet.go
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
deleted file mode 100644
index ac0f427cc..000000000
--- a/src/cmd/goyacc/Makefile
+++ /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.
-
-include ../../Make.inc
-
-TARG=goyacc
-GOFILES=\
- goyacc.go\
-
-include ../../Make.cmd
-
-units: goyacc units.y
- ./goyacc -p units_ units.y
- $(GC) y.go
- $(LD) -o units y.$O
-
diff --git a/src/cmd/hgpatch/doc.go b/src/cmd/hgpatch/doc.go
deleted file mode 100644
index 1e0f1da38..000000000
--- a/src/cmd/hgpatch/doc.go
+++ /dev/null
@@ -1,18 +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.
-
-/*
-
-Hgpatch applies a patch to the local Mercurial repository.
-The patch should have been been generated by
-a version control system like CVS, Git, Mercurial, or Subversion.
-If successful, hgpatch writes a list of affected files to standard output.
-
-Hgpatch is meant to be used by the Mercurial codereview extension.
-
-Usage:
- hgpatch [patchfile]
-
-*/
-package documentation
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
deleted file mode 100644
index 9e338abcb..000000000
--- a/src/cmd/hgpatch/main.go
+++ /dev/null
@@ -1,358 +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 (
- "bytes"
- "container/vector"
- "exec"
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "patch"
- "path/filepath"
- "sort"
- "strings"
-)
-
-var checkSync = flag.Bool("checksync", true, "check whether repository is out of sync")
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: hgpatch [options] [patchfile]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- args := flag.Args()
- var data []byte
- var err os.Error
- switch len(args) {
- case 0:
- data, err = ioutil.ReadAll(os.Stdin)
- case 1:
- data, err = ioutil.ReadFile(args[0])
- default:
- usage()
- }
- chk(err)
-
- pset, err := patch.Parse(data)
- chk(err)
-
- // Change to hg root directory, because
- // patch paths are relative to root.
- root, err := hgRoot()
- chk(err)
- chk(os.Chdir(root))
-
- // Make sure there are no pending changes on the server.
- if *checkSync && hgIncoming() {
- fmt.Fprintf(os.Stderr, "incoming changes waiting; run hg sync first\n")
- os.Exit(2)
- }
-
- // Make sure we won't be editing files with local pending changes.
- dirtylist, err := hgModified()
- chk(err)
- dirty := make(map[string]bool)
- for _, f := range dirtylist {
- dirty[f] = true
- }
- conflict := make(map[string]bool)
- for _, f := range pset.File {
- if f.Verb == patch.Delete || f.Verb == patch.Rename {
- if dirty[f.Src] {
- conflict[f.Src] = true
- }
- }
- if f.Verb != patch.Delete {
- if dirty[f.Dst] {
- conflict[f.Dst] = true
- }
- }
- }
- if len(conflict) > 0 {
- fmt.Fprintf(os.Stderr, "cannot apply patch to locally modified files:\n")
- for name := range conflict {
- fmt.Fprintf(os.Stderr, "\t%s\n", name)
- }
- os.Exit(2)
- }
-
- // Apply changes in memory.
- op, err := pset.Apply(ioutil.ReadFile)
- chk(err)
-
- // Write changes to disk copy: order of commands matters.
- // Accumulate undo log as we go, in case there is an error.
- // Also accumulate list of modified files to print at end.
- changed := make(map[string]int)
-
- // Copy, Rename create the destination file, so they
- // must happen before we write the data out.
- // A single patch may have a Copy and a Rename
- // with the same source, so we have to run all the
- // Copy in one pass, then all the Rename.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Copy {
- makeParent(o.Dst)
- chk(hgCopy(o.Dst, o.Src))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Rename {
- makeParent(o.Dst)
- chk(hgRename(o.Dst, o.Src))
- undoRevert(o.Dst)
- undoRevert(o.Src)
- changed[o.Src] = 1
- changed[o.Dst] = 1
- }
- }
-
- // Run Delete before writing to files in case one of the
- // deleted paths is becoming a directory.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Delete {
- chk(hgRemove(o.Src))
- undoRevert(o.Src)
- changed[o.Src] = 1
- }
- }
-
- // Write files.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Delete {
- continue
- }
- if o.Verb == patch.Add {
- makeParent(o.Dst)
- changed[o.Dst] = 1
- }
- if o.Data != nil {
- chk(ioutil.WriteFile(o.Dst, o.Data, 0644))
- if o.Verb == patch.Add {
- undoRm(o.Dst)
- } else {
- undoRevert(o.Dst)
- }
- changed[o.Dst] = 1
- }
- if o.Mode != 0 {
- chk(os.Chmod(o.Dst, uint32(o.Mode&0755)))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
-
- // hg add looks at the destination file, so it must happen
- // after we write the data out.
- for i := range op {
- o := &op[i]
- if o.Verb == patch.Add {
- chk(hgAdd(o.Dst))
- undoRevert(o.Dst)
- changed[o.Dst] = 1
- }
- }
-
- // Finished editing files. Write the list of changed files to stdout.
- list := make([]string, len(changed))
- i := 0
- for f := range changed {
- list[i] = f
- i++
- }
- sort.Strings(list)
- for _, f := range list {
- fmt.Printf("%s\n", f)
- }
-}
-
-// make parent directory for name, if necessary
-func makeParent(name string) {
- parent, _ := filepath.Split(name)
- chk(mkdirAll(parent, 0755))
-}
-
-// Copy of os.MkdirAll but adds to undo log after
-// creating a directory.
-func mkdirAll(path string, perm uint32) os.Error {
- dir, err := os.Lstat(path)
- if err == nil {
- if dir.IsDirectory() {
- return nil
- }
- return &os.PathError{"mkdir", path, os.ENOTDIR}
- }
-
- i := len(path)
- for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
- i--
- }
-
- j := i
- for j > 0 && path[j-1] != '/' { // Scan backward over element.
- j--
- }
-
- if j > 0 {
- err = mkdirAll(path[0:j-1], perm)
- if err != nil {
- return err
- }
- }
-
- err = os.Mkdir(path, perm)
- if err != nil {
- // Handle arguments like "foo/." by
- // double-checking that directory doesn't exist.
- dir, err1 := os.Lstat(path)
- if err1 == nil && dir.IsDirectory() {
- return nil
- }
- return err
- }
- undoRm(path)
- return nil
-}
-
-// If err != nil, process the undo log and exit.
-func chk(err os.Error) {
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- runUndo()
- os.Exit(2)
- }
-}
-
-// Undo log
-type undo func() os.Error
-
-var undoLog vector.Vector // vector of undo
-
-func undoRevert(name string) { undoLog.Push(undo(func() os.Error { return hgRevert(name) })) }
-
-func undoRm(name string) { undoLog.Push(undo(func() os.Error { return os.Remove(name) })) }
-
-func runUndo() {
- for i := undoLog.Len() - 1; i >= 0; i-- {
- if err := undoLog.At(i).(undo)(); err != nil {
- fmt.Fprintf(os.Stderr, "%s\n", err)
- }
- }
-}
-
-// hgRoot returns the root directory of the repository.
-func hgRoot() (string, os.Error) {
- out, err := run([]string{"hg", "root"}, nil)
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(out), nil
-}
-
-// hgIncoming returns true if hg sync will pull in changes.
-func hgIncoming() bool {
- // hg -q incoming exits 0 when there is nothing incoming, 1 otherwise.
- _, err := run([]string{"hg", "-q", "incoming"}, nil)
- return err == nil
-}
-
-// hgModified returns a list of the modified files in the
-// repository.
-func hgModified() ([]string, os.Error) {
- out, err := run([]string{"hg", "status", "-n"}, nil)
- if err != nil {
- return nil, err
- }
- return strings.Split(strings.TrimSpace(out), "\n"), nil
-}
-
-// hgAdd adds name to the repository.
-func hgAdd(name string) os.Error {
- _, err := run([]string{"hg", "add", name}, nil)
- return err
-}
-
-// hgRemove removes name from the repository.
-func hgRemove(name string) os.Error {
- _, err := run([]string{"hg", "rm", name}, nil)
- return err
-}
-
-// hgRevert reverts name.
-func hgRevert(name string) os.Error {
- _, err := run([]string{"hg", "revert", name}, nil)
- return err
-}
-
-// hgCopy copies src to dst in the repository.
-// Note that the argument order matches io.Copy, not "hg cp".
-func hgCopy(dst, src string) os.Error {
- _, err := run([]string{"hg", "cp", src, dst}, nil)
- return err
-}
-
-// hgRename renames src to dst in the repository.
-// Note that the argument order matches io.Copy, not "hg mv".
-func hgRename(dst, src string) os.Error {
- _, err := run([]string{"hg", "mv", src, dst}, nil)
- return err
-}
-
-func dup(a []string) []string {
- b := make([]string, len(a))
- copy(b, a)
- return b
-}
-
-var lookPathCache = make(map[string]string)
-
-// run runs the command argv, resolving argv[0] if necessary by searching $PATH.
-// It provides input on standard input to the command.
-func run(argv []string, input []byte) (out string, err os.Error) {
- if len(argv) < 1 {
- return "", &runError{dup(argv), os.EINVAL}
- }
-
- prog, ok := lookPathCache[argv[0]]
- if !ok {
- prog, err = exec.LookPath(argv[0])
- if err != nil {
- return "", &runError{dup(argv), err}
- }
- lookPathCache[argv[0]] = prog
- }
-
- cmd := exec.Command(prog, argv[1:]...)
- if len(input) > 0 {
- cmd.Stdin = bytes.NewBuffer(input)
- }
- bs, err := cmd.CombinedOutput()
- if err != nil {
- return "", &runError{dup(argv), err}
- }
- return string(bs), nil
-}
-
-// A runError represents an error that occurred while running a command.
-type runError struct {
- cmd []string
- err os.Error
-}
-
-func (e *runError) String() string { return strings.Join(e.cmd, " ") + ": " + e.err.String() }
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index e7269169e..786c10b64 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -182,7 +182,11 @@ relocsym(Sym *s)
o = symaddr(r->sym) + r->add;
break;
case D_PCREL:
- o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz);
+ // r->sym can be null when CALL $(constant) is transformed from absoulte PC to relative PC call.
+ o = 0;
+ if(r->sym)
+ o += symaddr(r->sym);
+ o += r->add - (s->value + r->off + r->siz);
break;
case D_SIZE:
o = r->sym->size + r->add;
@@ -410,13 +414,13 @@ savedata(Sym *s, Prog *p, char *pn)
}
static void
-blk(Sym *allsym, int32 addr, int32 size)
+blk(Sym *start, int32 addr, int32 size)
{
Sym *sym;
int32 eaddr;
uchar *p, *ep;
- for(sym = allsym; sym != nil; sym = sym->next)
+ for(sym = start; sym != nil; sym = sym->next)
if(!(sym->type&SSUB) && sym->value >= addr)
break;
@@ -585,6 +589,25 @@ strnput(char *s, int n)
}
}
+void
+addstrdata(char *name, char *value)
+{
+ Sym *s, *sp;
+ char *p;
+
+ p = smprint("%s.str", name);
+ sp = lookup(p, 0);
+ free(p);
+ addstring(sp, value);
+
+ s = lookup(name, 0);
+ s->dupok = 1;
+ addaddr(s, sp);
+ adduint32(s, strlen(value));
+ if(PtrSize == 8)
+ adduint32(s, 0); // round struct to pointer width
+}
+
vlong
addstring(Sym *s, char *str)
{
@@ -592,7 +615,7 @@ addstring(Sym *s, char *str)
int32 r;
if(s->type == 0)
- s->type = SDATA;
+ s->type = SNOPTRDATA;
s->reachable = 1;
r = s->size;
n = strlen(str)+1;
@@ -756,10 +779,25 @@ addsize(Sym *s, Sym *t)
}
void
+dosymtype(void)
+{
+ Sym *s;
+
+ for(s = allsym; s != nil; s = s->allsym) {
+ if(s->np > 0) {
+ if(s->type == SBSS)
+ s->type = SDATA;
+ if(s->type == SNOPTRBSS)
+ s->type = SNOPTRDATA;
+ }
+ }
+}
+
+void
dodata(void)
{
int32 t, datsize;
- Section *sect;
+ Section *sect, *noptr;
Sym *s, *last, **l;
if(debug['v'])
@@ -783,13 +821,12 @@ dodata(void)
}
for(s = datap; s != nil; s = s->next) {
- if(s->np > 0 && s->type == SBSS)
- s->type = SDATA;
if(s->np > s->size)
diag("%s: initialize bounds (%lld < %d)",
s->name, (vlong)s->size, s->np);
}
-
+
+
/*
* now that we have the datap list, but before we start
* to assign addresses, record all the necessary
@@ -820,6 +857,8 @@ dodata(void)
datsize = 0;
s = datap;
for(; s != nil && s->type < SSYMTAB; s = s->next) {
+ if(s->align != 0)
+ datsize = rnd(datsize, s->align);
s->type = SRODATA;
s->value = datsize;
datsize += rnd(s->size, PtrSize);
@@ -851,6 +890,8 @@ dodata(void)
/* read-only ELF sections */
for(; s != nil && s->type < SELFSECT; s = s->next) {
sect = addsection(&segtext, s->name, 04);
+ if(s->align != 0)
+ datsize = rnd(datsize, s->align);
sect->vaddr = datsize;
s->type = SRODATA;
s->value = datsize;
@@ -860,30 +901,43 @@ dodata(void)
/* writable ELF sections */
datsize = 0;
- for(; s != nil && s->type < SDATA; s = s->next) {
+ for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
sect = addsection(&segdata, s->name, 06);
+ if(s->align != 0)
+ datsize = rnd(datsize, s->align);
sect->vaddr = datsize;
s->type = SDATA;
s->value = datsize;
datsize += rnd(s->size, PtrSize);
sect->len = datsize - sect->vaddr;
}
-
- /* data */
- sect = addsection(&segdata, ".data", 06);
+
+ /* pointer-free data, then data */
+ sect = addsection(&segdata, ".noptrdata", 06);
sect->vaddr = datsize;
- for(; s != nil && s->type < SBSS; s = s->next) {
+ noptr = sect;
+ for(; ; s = s->next) {
+ if((s == nil || s->type >= SDATA) && sect == noptr) {
+ // finish noptrdata, start data
+ datsize = rnd(datsize, 8);
+ sect->len = datsize - sect->vaddr;
+ sect = addsection(&segdata, ".data", 06);
+ sect->vaddr = datsize;
+ }
+ if(s == nil || s->type >= SBSS) {
+ // finish data
+ sect->len = datsize - sect->vaddr;
+ break;
+ }
s->type = SDATA;
t = s->size;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
if(t >= PtrSize)
t = rnd(t, PtrSize);
else if(t > 2)
t = rnd(t, 4);
- if(t & 1) {
+ if(s->align != 0)
+ datsize = rnd(datsize, s->align);
+ else if(t & 1) {
;
} else if(t & 2)
datsize = rnd(datsize, 2);
@@ -894,13 +948,25 @@ dodata(void)
s->value = datsize;
datsize += t;
}
- sect->len = datsize - sect->vaddr;
- /* bss */
+ /* bss, then pointer-free bss */
+ noptr = nil;
sect = addsection(&segdata, ".bss", 06);
sect->vaddr = datsize;
- for(; s != nil; s = s->next) {
- if(s->type != SBSS) {
+ for(; ; s = s->next) {
+ if((s == nil || s->type >= SNOPTRBSS) && noptr == nil) {
+ // finish bss, start noptrbss
+ datsize = rnd(datsize, 8);
+ sect->len = datsize - sect->vaddr;
+ sect = addsection(&segdata, ".noptrbss", 06);
+ sect->vaddr = datsize;
+ noptr = sect;
+ }
+ if(s == nil) {
+ sect->len = datsize - sect->vaddr;
+ break;
+ }
+ if(s->type > SNOPTRBSS) {
cursym = s;
diag("unexpected symbol type %d", s->type);
}
@@ -909,7 +975,9 @@ dodata(void)
t = rnd(t, PtrSize);
else if(t > 2)
t = rnd(t, 4);
- if(t & 1) {
+ if(s->align != 0)
+ datsize = rnd(datsize, s->align);
+ else if(t & 1) {
;
} else if(t & 2)
datsize = rnd(datsize, 2);
@@ -920,7 +988,6 @@ dodata(void)
s->value = datsize;
datsize += t;
}
- sect->len = datsize - sect->vaddr;
}
// assign addresses to text
@@ -943,6 +1010,8 @@ textaddress(void)
for(sym = textp; sym != nil; sym = sym->next) {
if(sym->type & SSUB)
continue;
+ if(sym->align != 0)
+ va = rnd(va, sym->align);
sym->value = 0;
for(sub = sym; sub != S; sub = sub->sub) {
sub->value += va;
@@ -954,6 +1023,11 @@ textaddress(void)
}
va += sym->size;
}
+
+ // Align end of code so that rodata starts aligned.
+ // 128 bytes is likely overkill but definitely cheap.
+ va = rnd(va, 128);
+
sect->len = va - sect->vaddr;
}
@@ -961,7 +1035,7 @@ textaddress(void)
void
address(void)
{
- Section *s, *text, *data, *rodata, *symtab, *pclntab;
+ Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Sym *sym, *sub;
uvlong va;
@@ -987,6 +1061,9 @@ address(void)
if(HEADTYPE == Hplan9x32)
segdata.fileoff = segtext.fileoff + segtext.filelen;
data = nil;
+ noptr = nil;
+ bss = nil;
+ noptrbss = nil;
for(s=segdata.sect; s != nil; s=s->next) {
s->vaddr = va;
va += s->len;
@@ -994,8 +1071,14 @@ address(void)
segdata.len = va - segdata.vaddr;
if(strcmp(s->name, ".data") == 0)
data = s;
+ if(strcmp(s->name, ".noptrdata") == 0)
+ noptr = s;
+ if(strcmp(s->name, ".bss") == 0)
+ bss = s;
+ if(strcmp(s->name, ".noptrbss") == 0)
+ noptrbss = s;
}
- segdata.filelen -= data->next->len; // deduct .bss
+ segdata.filelen -= bss->len + noptrbss->len; // deduct .bss
text = segtext.sect;
rodata = text->next;
@@ -1004,7 +1087,7 @@ address(void)
for(sym = datap; sym != nil; sym = sym->next) {
cursym = sym;
- if(sym->type < SDATA)
+ if(sym->type < SNOPTRDATA)
sym->value += rodata->vaddr;
else
sym->value += segdata.sect->vaddr;
@@ -1020,7 +1103,13 @@ address(void)
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
xdefine("pclntab", SRODATA, pclntab->vaddr);
xdefine("epclntab", SRODATA, pclntab->vaddr + pclntab->len);
- xdefine("data", SBSS, data->vaddr);
- xdefine("edata", SBSS, data->vaddr + data->len);
+ xdefine("noptrdata", SNOPTRDATA, noptr->vaddr);
+ xdefine("enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
+ xdefine("bss", SBSS, bss->vaddr);
+ xdefine("ebss", SBSS, bss->vaddr + bss->len);
+ xdefine("data", SDATA, data->vaddr);
+ xdefine("edata", SDATA, data->vaddr + data->len);
+ xdefine("noptrbss", SNOPTRBSS, noptrbss->vaddr);
+ xdefine("enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
xdefine("end", SBSS, segdata.vaddr + segdata.len);
}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
index 972e2a32c..e99e50466 100644
--- a/src/cmd/ld/doc.go
+++ b/src/cmd/ld/doc.go
@@ -4,8 +4,57 @@
/*
-This directory contains the portable section of the Plan 9 C linkers.
-See ../6l, ../8l, and ../5l for more information.
+Ld is the portable code for a modified version of the Plan 9 linker. The original is documented at
+ http://plan9.bell-labs.com/magic/man2html/1/2l
+
+It reads object files (.5, .6, or .8 files) and writes a binary named for the
+architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
+will be appended).
+
+Major changes include:
+ - support for ELF, Mach-O and PE binary files
+ - support for segmented stacks (this feature is implemented here, not in the compilers).
+
+Original options are listed on the manual page linked above.
+
+Usage:
+ go tool 6l [flags] mainObj
+Substitute 6l with 8l or 5l as appropriate.
+
+Options new in this version:
+
+ -d
+ Elide the dynamic linking header. With this option, the binary
+ is statically linked and does not refer to a dynamic linker. Without this option
+ (the default), the binary's contents are identical but it is loaded with a dynamic
+ linker. This flag cannot be used when $GOOS is windows.
+ -Hdarwin (only in 6l/8l)
+ Write Apple Mach-O binaries (default when $GOOS is darwin)
+ -Hlinux
+ Write Linux ELF binaries (default when $GOOS is linux)
+ -Hfreebsd (only in 6l/8l)
+ Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+ -Hnetbsd (only in 6l/8l)
+ Write NetBSD ELF binaries (default when $GOOS is netbsd)
+ -Hopenbsd (only in 6l/8l)
+ Write OpenBSD ELF binaries (default when $GOOS is openbsd)
+ -Hwindows (only in 6l/8l)
+ Write Windows PE32+ Console binaries (default when $GOOS is windows)
+ -Hwindowsgui (only in 6l/8l)
+ Write Windows PE32+ GUI binaries
+ -I interpreter
+ Set the ELF dynamic linker to use.
+ -L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
+ The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
+ -r dir1:dir2:...
+ Set the dynamic linker search path when using ELF.
+ -V
+ Print the linker version.
+ -X symbol value
+ Set the value of an otherwise uninitialized string variable.
+ The symbol name should be of the form importpath.name,
+ as displayed in the symbol table printed by "go tool nm".
*/
package documentation
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 373cf5523..57e5a4283 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -775,7 +775,7 @@ enum {
KindNoPointers = 1<<7,
// size of Type interface header + CommonType structure.
- CommonSize = 2*PtrSize+ 4*PtrSize + 8,
+ CommonSize = 2*PtrSize+ 5*PtrSize + 8,
};
static Reloc*
@@ -1439,7 +1439,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
if (strncmp(s, "go.string.", 10) == 0)
return;
- if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0) {
+ if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0 && strncmp(s, "type..", 6) != 0) {
defgotype(sym);
return;
}
@@ -1601,7 +1601,7 @@ finddebugruntimepath(void)
char *c;
for (i = 1; i < histfilesize; i++) {
- if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) {
+ if ((c = strstr(histfile[i], "runtime/zruntime_defs")) != nil) {
l = c - histfile[i];
memmove(gdbscript, histfile[i], l);
memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1);
@@ -2317,7 +2317,7 @@ dwarfemitdebugsections(void)
// Needed by the prettyprinter code for interface inspection.
defgotype(lookup_or_diag("type.runtime.commonType"));
- defgotype(lookup_or_diag("type.runtime.InterfaceType"));
+ defgotype(lookup_or_diag("type.runtime.interfaceType"));
defgotype(lookup_or_diag("type.runtime.itab"));
genasmsym(defdwsymb);
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index f9f9ef6b2..de9e6b854 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -77,6 +77,19 @@ elf64phdr(ElfPhdr *e)
void
elf32phdr(ElfPhdr *e)
{
+ int frag;
+
+ if(e->type == PT_LOAD) {
+ // Correct ELF loaders will do this implicitly,
+ // but buggy ELF loaders like the one in some
+ // versions of QEMU won't.
+ frag = e->vaddr&(e->align-1);
+ e->off -= frag;
+ e->vaddr -= frag;
+ e->paddr -= frag;
+ e->filesz += frag;
+ e->memsz += frag;
+ }
LPUT(e->type);
LPUT(e->off);
LPUT(e->vaddr);
@@ -305,29 +318,77 @@ elfwritedynentsymsize(Sym *s, int tag, Sym *t)
}
int
-elfwriteinterp(void)
+elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p)
{
int n;
- if(interp == nil)
- return 0;
-
+ interp = p;
n = strlen(interp)+1;
- cseek(ELFRESERVE-n);
- cwrite(interp, n);
+ sh->addr = startva + resoff - n;
+ sh->off = resoff - n;
+ sh->size = n;
+
return n;
}
-void
-elfinterp(ElfShdr *sh, uint64 startva, char *p)
+int
+elfwriteinterp(vlong stridx)
+{
+ ElfShdr *sh = nil;
+ int i;
+
+ for(i = 0; i < hdr.shnum; i++)
+ if(shdr[i]->name == stridx)
+ sh = shdr[i];
+ if(sh == nil || interp == nil)
+ return 0;
+
+ cseek(sh->off);
+ cwrite(interp, sh->size);
+ return sh->size;
+}
+
+// Defined in NetBSD's sys/exec_elf.h
+#define ELF_NOTE_TYPE_NETBSD_TAG 1
+#define ELF_NOTE_NETBSD_NAMESZ 7
+#define ELF_NOTE_NETBSD_DESCSZ 4
+#define ELF_NOTE_NETBSD_NAME "NetBSD\0\0"
+#define ELF_NOTE_NETBSD_VERSION 599000000 /* NetBSD 5.99 */
+
+int
+elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
{
int n;
- interp = p;
- n = strlen(interp)+1;
- sh->addr = startva + ELFRESERVE - n;
- sh->off = ELFRESERVE - n;
+ n = sizeof(Elf_Note) + ELF_NOTE_NETBSD_NAMESZ + ELF_NOTE_NETBSD_DESCSZ + 1;
+ n += resoff % 4;
+ sh->addr = startva + resoff - n;
+ sh->off = resoff - n;
sh->size = n;
+
+ return n;
+}
+
+int
+elfwritenetbsdsig(vlong stridx) {
+ ElfShdr *sh = nil;
+ int i;
+
+ for(i = 0; i < hdr.shnum; i++)
+ if(shdr[i]->name == stridx)
+ sh = shdr[i];
+ if(sh == nil)
+ return 0;
+
+ // Write Elf_Note header followed by NetBSD string.
+ cseek(sh->off);
+ LPUT(ELF_NOTE_NETBSD_NAMESZ);
+ LPUT(ELF_NOTE_NETBSD_DESCSZ);
+ LPUT(ELF_NOTE_TYPE_NETBSD_TAG);
+ cwrite(ELF_NOTE_NETBSD_NAME, 8);
+ LPUT(ELF_NOTE_NETBSD_VERSION);
+
+ return sh->size;
}
extern int nelfsym;
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index c63df2241..690ade975 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -968,8 +968,10 @@ extern int numelfphdr;
extern int numelfshdr;
extern int iself;
extern int elfverneed;
-int elfwriteinterp(void);
-void elfinterp(ElfShdr*, uint64, char*);
+int elfinterp(ElfShdr*, uint64, uint64, char*);
+int elfwriteinterp(vlong);
+int elfnetbsdsig(ElfShdr*, uint64, uint64);
+int elfwritenetbsdsig(vlong);
void elfdynhash(void);
ElfPhdr* elfphload(Segment*);
ElfShdr* elfshbits(Section*);
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index fd7278a7b..3271be1f5 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -235,7 +235,7 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
x = ilookup(name);
if(x->prefix == nil) {
x->prefix = prefix;
- x->def = def;
+ x->def = strdup(def);
x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
@@ -248,7 +248,10 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
nerrors++;
}
+ free(name);
+ free(def);
}
+ free(file);
}
// replace all "". with pkg.
@@ -264,7 +267,7 @@ expandpkg(char *t0, char *pkg)
n++;
if(n == 0)
- return t0;
+ return strdup(t0);
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
@@ -479,6 +482,7 @@ loaddynimport(char *file, char *pkg, char *p, int n)
if(q)
*q++ = '\0';
s = lookup(name, 0);
+ free(name);
if(s->type == 0 || s->type == SXREF) {
s->dynimplib = lib;
s->dynimpname = def;
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 924687867..bd4f3e7d8 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -538,6 +538,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->np = sect->size;
}
s->size = sect->size;
+ s->align = sect->align;
if(s->type == STEXT) {
if(etextp)
etextp->next = s;
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 680557075..feb8620bd 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -282,8 +282,10 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
diag("%s: unknown relocation type %d;", pn, type);
case IMAGE_REL_I386_REL32:
case IMAGE_REL_AMD64_REL32:
+ case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
+ case IMAGE_REL_AMD64_ADDR32NB:
rp->type = D_PCREL;
- rp->add = 0;
+ rp->add = le32(rsect->base+rp->off);
break;
case IMAGE_REL_I386_DIR32NB:
case IMAGE_REL_I386_DIR32:
@@ -291,10 +293,6 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
// load addend from image
rp->add = le32(rsect->base+rp->off);
break;
- case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
- rp->type = D_PCREL;
- rp->add += 4;
- break;
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
rp->siz = 8;
rp->type = D_ADDR;
@@ -408,13 +406,15 @@ readsym(PeObj *obj, int i, PeSym **y)
sym = &obj->pesym[i];
*y = sym;
- name = sym->name;
- if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
+ if(sym->name[0] == '.') // .section
name = obj->sect[sym->sectnum-1].sym->name;
- if(strncmp(sym->name, "__imp__", 7) == 0)
- name = &sym->name[7]; // __imp__Name => Name
- else if(sym->name[0] == '_')
- name = &sym->name[1]; // _Name => Name
+ else {
+ name = sym->name;
+ if(strncmp(name, "__imp_", 6) == 0)
+ name = &name[6]; // __imp_Name => Name
+ if(thechar == '8' && name[0] == '_')
+ name = &name[1]; // _Name => Name
+ }
// remove last @XXX
p = strchr(name, '@');
if(p)
@@ -443,8 +443,8 @@ readsym(PeObj *obj, int i, PeSym **y)
if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
s->type = SXREF;
- if(strncmp(sym->name, "__imp__", 7) == 0)
- s->got = -2; // flag for __imp__
+ if(strncmp(sym->name, "__imp_", 6) == 0)
+ s->got = -2; // flag for __imp_
sym->sym = s;
return 0;
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 5d1e6d61b..4a100cac3 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -39,20 +39,32 @@ int iconv(Fmt*);
char symname[] = SYMDEF;
char pkgname[] = "__.PKGDEF";
-char* libdir[16];
+char** libdir;
int nlibdir = 0;
+static int maxlibdir = 0;
static int cout = -1;
char* goroot;
char* goarch;
char* goos;
+char* theline;
void
Lflag(char *arg)
{
- if(nlibdir >= nelem(libdir)-1) {
- print("too many -L's: %d\n", nlibdir);
- usage();
+ char **p;
+
+ if(nlibdir >= maxlibdir) {
+ if (maxlibdir == 0)
+ maxlibdir = 8;
+ else
+ maxlibdir *= 2;
+ p = realloc(libdir, maxlibdir * sizeof(*p));
+ if (p == nil) {
+ print("too many -L's: %d\n", nlibdir);
+ usage();
+ }
+ libdir = p;
}
libdir[nlibdir++] = arg;
}
@@ -68,9 +80,14 @@ libinit(void)
print("goarch is not known: %s\n", goarch);
// add goroot to the end of the libdir list.
- libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch);
+ Lflag(smprint("%s/pkg/%s_%s", goroot, goos, goarch));
+ // Unix doesn't like it when we write to a running (or, sometimes,
+ // recently run) binary, so remove the output file before writing it.
+ // On Windows 7, remove() can force the following create() to fail.
+#ifndef _WIN32
remove(outfile);
+#endif
cout = create(outfile, 1, 0775);
if(cout < 0) {
diag("cannot create %s", outfile);
@@ -109,7 +126,7 @@ addlib(char *src, char *obj)
sprint(name, "");
i = 1;
} else
- if(isalpha(histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
+ if(isalpha((uchar)histfrog[0]->name[1]) && histfrog[0]->name[2] == ':') {
strcpy(name, histfrog[0]->name+1);
i = 1;
} else
@@ -268,6 +285,7 @@ loadlib(void)
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
+ iscgo |= strcmp(library[i].pkg, "runtime/cgo") == 0;
objfile(library[i].file, library[i].pkg);
}
@@ -295,19 +313,27 @@ nextar(Biobuf *bp, int off, struct ar_hdr *a)
{
int r;
int32 arsize;
+ char *buf;
if (off&01)
off++;
Bseek(bp, off, 0);
- r = Bread(bp, a, SAR_HDR);
+ buf = Brdline(bp, '\n');
+ r = Blinelen(bp);
+ if(buf == nil) {
+ if(r == 0)
+ return 0;
+ return -1;
+ }
if(r != SAR_HDR)
- return 0;
- if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag)))
+ return -1;
+ memmove(a, buf, SAR_HDR);
+ if(strncmp(a->fmag, ARFMAG, sizeof a->fmag))
return -1;
arsize = strtol(a->size, 0, 0);
if (arsize&1)
arsize++;
- return arsize + SAR_HDR;
+ return arsize + r;
}
void
@@ -336,6 +362,7 @@ objfile(char *file, char *pkg)
Bseek(f, 0L, 0);
ldobj(f, pkg, l, file, FileObj);
Bterm(f);
+ free(pkg);
return;
}
@@ -397,6 +424,7 @@ objfile(char *file, char *pkg)
out:
Bterm(f);
+ free(pkg);
}
void
@@ -424,14 +452,17 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
ldelf(f, pkg, len, pn);
+ free(pn);
return;
}
if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
ldmacho(f, pkg, len, pn);
+ free(pn);
return;
}
if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
ldpe(f, pkg, len, pn);
+ free(pn);
return;
}
@@ -457,14 +488,36 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
return;
}
diag("%s: not an object file", pn);
+ free(pn);
return;
}
- t = smprint("%s %s %s", getgoos(), thestring, getgoversion());
- if(strcmp(line+10, t) != 0 && !debug['f']) {
+
+ // First, check that the basic goos, string, and version match.
+ t = smprint("%s %s %s ", goos, thestring, getgoversion());
+ line[n] = ' ';
+ if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
+ line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, t);
free(t);
+ free(pn);
return;
}
+
+ // Second, check that longer lines match each other exactly,
+ // so that the Go compiler and write additional information
+ // that must be the same from run to run.
+ line[n] = '\0';
+ if(n-10 > strlen(t)) {
+ if(theline == nil)
+ theline = strdup(line+10);
+ else if(strcmp(theline, line+10) != 0) {
+ line[n] = '\0';
+ diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
+ free(t);
+ free(pn);
+ return;
+ }
+ }
free(t);
line[n] = '\n';
@@ -487,10 +540,12 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
Bseek(f, import1, 0);
ldobj1(f, pkg, eof - Boffset(f), pn);
+ free(pn);
return;
eof:
diag("truncated object file: %s", pn);
+ free(pn);
}
static Sym*
@@ -870,18 +925,26 @@ unmal(void *v, uint32 n)
* Convert raw string to the prefix that will be used in the symbol table.
* Invalid bytes turn into %xx. Right now the only bytes that need
* escaping are %, ., and ", but we escape all control characters too.
+ *
+ * Must be same as ../gc/subr.c:/^pathtoprefix.
*/
static char*
pathtoprefix(char *s)
{
static char hex[] = "0123456789abcdef";
- char *p, *r, *w;
+ char *p, *r, *w, *l;
int n;
+ // find first character past the last slash, if any.
+ l = s;
+ for(r=s; *r; r++)
+ if(*r == '/')
+ l = r+1;
+
// check for chars that need escaping
n = 0;
for(r=s; *r; r++)
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"')
+ if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
n++;
// quick exit
@@ -891,7 +954,7 @@ pathtoprefix(char *s)
// escape
p = mal((r-s)+1+2*n);
for(r=s, w=p; *r; r++) {
- if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') {
+ if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
*w++ = '%';
*w++ = hex[(*r>>4)&0xF];
*w++ = hex[*r&0xF];
@@ -1332,7 +1395,7 @@ Yconv(Fmt *fp)
fmtprint(fp, "<nil>");
} else {
fmtstrinit(&fmt);
- fmtprint(&fmt, "%s @0x%08x [%d]", s->name, s->value, s->size);
+ fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size);
for (i = 0; i < s->size; i++) {
if (!(i%8)) fmtprint(&fmt, "\n\t0x%04x ", i);
fmtprint(&fmt, "%02x ", s->p[i]);
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index d13eea31e..02dac6e1c 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -43,11 +43,13 @@ enum
SPCLNTAB,
SELFROSECT,
SELFSECT,
+ SNOPTRDATA,
SDATA,
SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT,
SWINDOWS,
SBSS,
+ SNOPTRBSS,
SXREF,
SMACHODYNSTR,
@@ -101,7 +103,7 @@ struct Section
};
extern char symname[];
-extern char *libdir[];
+extern char **libdir;
extern int nlibdir;
EXTERN char* INITENTRY;
@@ -125,10 +127,12 @@ EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
EXTERN int havedynamic;
+EXTERN int iscgo;
EXTERN Segment segtext;
EXTERN Segment segdata;
EXTERN Segment segsym;
+EXTERN Segment segdwarf;
void addlib(char *src, char *obj);
void addlibpath(char *srcref, char *objref, char *file, char *pkg);
@@ -177,6 +181,7 @@ void reloc(void);
void relocsym(Sym*);
void savedata(Sym*, Prog*, char*);
void symgrow(Sym*, int32);
+void addstrdata(char*, char*);
vlong addstring(Sym*, char*);
vlong adduint32(Sym*, uint32);
vlong adduint64(Sym*, uint64);
@@ -191,6 +196,7 @@ void asmelfsym(void);
void asmplan9sym(void);
void strnput(char*, int);
void dodata(void);
+void dosymtype(void);
void address(void);
void textaddress(void);
void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 70133d665..6781c25a4 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -413,9 +413,9 @@ asmbmacho(void)
// must match domacholink below
s1 = lookup(".dynsym", 0);
- s2 = lookup(".dynstr", 0);
- s3 = lookup(".linkedit.plt", 0);
- s4 = lookup(".linkedit.got", 0);
+ s2 = lookup(".linkedit.plt", 0);
+ s3 = lookup(".linkedit.got", 0);
+ s4 = lookup(".dynstr", 0);
ms = newMachoSeg("__LINKEDIT", 0);
ms->vaddr = va+v+rnd(segdata.len, INITRND);
@@ -428,8 +428,8 @@ asmbmacho(void)
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
- ml->data[2] = linkoff + s1->size; /* stroff */
- ml->data[3] = s2->size; /* strsize */
+ ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */
+ ml->data[3] = s4->size; /* strsize */
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
ml->data[0] = 0; /* ilocalsym */
@@ -444,8 +444,8 @@ asmbmacho(void)
ml->data[9] = 0; /* nmodtab */
ml->data[10] = 0; /* extrefsymoff */
ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */
- ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */
+ ml->data[12] = linkoff + s1->size; /* indirectsymoff */
+ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
ml->data[14] = 0; /* extreloff */
ml->data[15] = 0; /* nextrel */
ml->data[16] = 0; /* locreloff */
@@ -495,17 +495,34 @@ domacholink(void)
// write data that will be linkedit section
s1 = lookup(".dynsym", 0);
relocsym(s1);
- s2 = lookup(".dynstr", 0);
- s3 = lookup(".linkedit.plt", 0);
- s4 = lookup(".linkedit.got", 0);
-
- while(s2->size%4)
- adduint8(s2, 0);
+ s2 = lookup(".linkedit.plt", 0);
+ s3 = lookup(".linkedit.got", 0);
+ s4 = lookup(".dynstr", 0);
+
+ // Force the linkedit section to end on a 16-byte
+ // boundary. This allows pure (non-cgo) Go binaries
+ // to be code signed correctly.
+ //
+ // Apple's codesign_allocate (a helper utility for
+ // the codesign utility) can do this fine itself if
+ // it is run on a dynamic Mach-O binary. However,
+ // when it is run on a pure (non-cgo) Go binary, where
+ // the linkedit section is mostly empty, it fails to
+ // account for the extra padding that it itself adds
+ // when adding the LC_CODE_SIGNATURE load command
+ // (which must be aligned on a 16-byte boundary).
+ //
+ // By forcing the linkedit section to end on a 16-byte
+ // boundary, codesign_allocate will not need to apply
+ // any alignment padding itself, working around the
+ // issue.
+ while(s4->size%16)
+ adduint8(s4, 0);
size = s1->size + s2->size + s3->size + s4->size;
if(size > 0) {
- linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND);
cseek(linkoff);
cwrite(s1->p, s1->size);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 334c9959f..1d70b4808 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -32,6 +32,11 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+// Note: currently only up to 8 chars plus \0.
+static char *symlabels[] = {
+ "symtab", "esymtab", "pclntab", "epclntab"
+};
+
static Sym *rsrcsym;
static char symnames[256];
@@ -44,6 +49,7 @@ static int pe64;
static int nsect;
static int nextsectoff;
static int nextfileoff;
+static int textsect;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
@@ -449,20 +455,29 @@ addsymtable(void)
{
IMAGE_SECTION_HEADER *h;
int i, size;
+ Sym *s;
- if(nextsymoff == 0)
- return;
-
- size = nextsymoff + 4 + 18;
+ fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
+ size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
h = addpesection(".symtab", size, size);
h->Characteristics = IMAGE_SCN_MEM_READ|
IMAGE_SCN_MEM_DISCARDABLE;
chksectoff(h, cpos());
fh.PointerToSymbolTable = cpos();
- fh.NumberOfSymbols = 1;
- strnput("", 18); // one empty symbol
- // put symbol string table
- lputl(size);
+
+ // put COFF symbol table
+ for (i=0; i<fh.NumberOfSymbols; i++) {
+ s = rlookup(symlabels[i], 0);
+ strnput(s->name, 8);
+ lputl(datoff(s->value));
+ wputl(textsect);
+ wputl(0x0308); // "array of structs"
+ cput(2); // storage class: external
+ cput(0); // no aux entries
+ }
+
+ // put COFF string table
+ lputl(nextsymoff + 4);
for (i=0; i<nextsymoff; i++)
cput(symnames[i]);
strnput("", h->SizeOfRawData - size);
@@ -510,6 +525,48 @@ addpersrc(void)
dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
}
+static void
+addexcept(IMAGE_SECTION_HEADER *text)
+{
+ IMAGE_SECTION_HEADER *pdata, *xdata;
+ vlong startoff;
+ uvlong n;
+ Sym *sym;
+
+ if(thechar != '6')
+ return;
+
+ // write unwind info
+ sym = lookup("runtime.sigtramp", 0);
+ startoff = cpos();
+ lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0
+ lputl(sym->value - PEBASE);
+ lputl(0);
+
+ n = cpos() - startoff;
+ xdata = addpesection(".xdata", n, n);
+ xdata->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_CNT_INITIALIZED_DATA;
+ chksectoff(xdata, startoff);
+ strnput("", xdata->SizeOfRawData - n);
+
+ // write a function table entry for the whole text segment
+ startoff = cpos();
+ lputl(text->VirtualAddress);
+ lputl(text->VirtualAddress + text->VirtualSize);
+ lputl(xdata->VirtualAddress);
+
+ n = cpos() - startoff;
+ pdata = addpesection(".pdata", n, n);
+ pdata->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_CNT_INITIALIZED_DATA;
+ chksectoff(pdata, startoff);
+ strnput("", pdata->SizeOfRawData - n);
+
+ dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = pdata->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = pdata->VirtualSize;
+}
+
void
asmbpe(void)
{
@@ -532,6 +589,7 @@ asmbpe(void)
IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
chksectseg(t, &segtext);
+ textsect = nsect;
d = addpesection(".data", segdata.len, segdata.filelen);
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
@@ -546,7 +604,8 @@ asmbpe(void)
addexports();
addsymtable();
addpersrc();
-
+ addexcept(t);
+
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
@@ -561,7 +620,7 @@ asmbpe(void)
set(Magic, 0x10b); // PE32
oh.BaseOfData = d->VirtualAddress;
}
- set(MajorLinkerVersion, 1);
+ set(MajorLinkerVersion, 3);
set(MinorLinkerVersion, 0);
set(SizeOfCode, t->SizeOfRawData);
set(SizeOfInitializedData, d->SizeOfRawData);
@@ -583,8 +642,29 @@ asmbpe(void)
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
else
set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
- set(SizeOfStackReserve, 0x0040000);
- set(SizeOfStackCommit, 0x00001000);
+
+ // Disable stack growth as we don't want Windows to
+ // fiddle with the thread stack limits, which we set
+ // ourselves to circumvent the stack checks in the
+ // Windows exception dispatcher.
+ // Commit size must be strictly less than reserve
+ // size otherwise reserve will be rounded up to a
+ // larger size, as verified with VMMap.
+
+ // Go code would be OK with 64k stacks, but we need larger stacks for cgo.
+ // That default stack reserve size affects only the main thread,
+ // for other threads we specify stack size in runtime explicitly
+ // (runtime knows whether cgo is enabled or not).
+ // If you change stack reserve sizes here,
+ // change them in runtime/cgo/windows_386/amd64.c as well.
+ if(!iscgo) {
+ set(SizeOfStackReserve, 0x00010000);
+ set(SizeOfStackCommit, 0x0000ffff);
+ } else {
+ set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
+ // account for 2 guard pages
+ set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
+ }
set(SizeOfHeapReserve, 0x00100000);
set(SizeOfHeapCommit, 0x00001000);
set(NumberOfRvaAndSizes, 16);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 60e146b35..129b13ea0 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -34,10 +34,7 @@
#include "../ld/lib.h"
#include "../ld/elf.h"
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-int elftextsh;
+static int maxelfstr;
int
putelfstr(char *s)
@@ -327,14 +324,22 @@ symtab(void)
{
Sym *s;
+ dosymtype();
+
// Define these so that they'll get put into the symbol table.
// data.c:/^address will provide the actual values.
xdefine("text", STEXT, 0);
xdefine("etext", STEXT, 0);
xdefine("rodata", SRODATA, 0);
xdefine("erodata", SRODATA, 0);
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, 0);
+ xdefine("noptrdata", SNOPTRDATA, 0);
+ xdefine("enoptrdata", SNOPTRDATA, 0);
+ xdefine("data", SDATA, 0);
+ xdefine("edata", SDATA, 0);
+ xdefine("bss", SBSS, 0);
+ xdefine("ebss", SBSS, 0);
+ xdefine("noptrbss", SNOPTRBSS, 0);
+ xdefine("enoptrbss", SNOPTRBSS, 0);
xdefine("end", SBSS, 0);
xdefine("epclntab", SRODATA, 0);
xdefine("esymtab", SRODATA, 0);
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
index 81bc348de..3f528d751 100644
--- a/src/cmd/nm/Makefile
+++ b/src/cmd/nm/Makefile
@@ -1,15 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is nm because the source is portable and general.
-# We call the binary 6nm to avoid confusion with the host nm.
-
-TARG=6nm
-OFILES=\
- nm.$O\
-
-include ../../Make.ccmd
+include ../../Make.dist
diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go
index 2a37dd835..c84369a5f 100644
--- a/src/cmd/nm/doc.go
+++ b/src/cmd/nm/doc.go
@@ -14,8 +14,8 @@ Plan 9 C compiler.
This implementation adds the flag -S, which prints each symbol's size
in decimal after its address.
-For reasons of disambiguation it is installed as 6nm although it also serves
-as an 8nm and a 5nm.
+Usage:
+ go tool nm [-aghnsTu] file
*/
package documentation
diff --git a/src/cmd/objdump/main.c b/src/cmd/objdump/main.c
new file mode 100644
index 000000000..b684be7fb
--- /dev/null
+++ b/src/cmd/objdump/main.c
@@ -0,0 +1,68 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * objdump simulation - only enough to make pprof work on Macs
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+void
+usage(void)
+{
+ fprint(2, "usage: objdump binary start stop\n");
+ fprint(2, "Disassembles binary from PC start up to stop.\n");
+ exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, n;
+ uvlong pc, start, stop;
+ Fhdr fhdr;
+ Biobuf bout;
+ char buf[1024];
+ Map *text;
+
+ ARGBEGIN{
+ default:
+ usage();
+ }ARGEND
+
+ if(argc != 3)
+ usage();
+ start = strtoull(argv[1], 0, 16);
+ stop = strtoull(argv[2], 0, 16);
+
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("open %s: %r", argv[0]);
+ if(crackhdr(fd, &fhdr) <= 0)
+ sysfatal("crackhdr: %r");
+ machbytype(fhdr.type);
+ if(syminit(fd, &fhdr) <= 0)
+ sysfatal("syminit: %r");
+ text = loadmap(nil, fd, &fhdr);
+ if(text == nil)
+ sysfatal("loadmap: %r");
+
+ Binit(&bout, 1, OWRITE);
+ for(pc=start; pc<stop; ) {
+ if(fileline(buf, sizeof buf, pc))
+ Bprint(&bout, "%s\n", buf);
+ buf[0] = '\0';
+ machdata->das(text, pc, 0, buf, sizeof buf);
+ Bprint(&bout, " %llx: %s\n", pc, buf);
+ n = machdata->instsize(text, pc);
+ if(n <= 0)
+ break;
+ pc += n;
+ }
+ Bflush(&bout);
+ exits(0);
+}
diff --git a/src/cmd/pack/Makefile b/src/cmd/pack/Makefile
new file mode 100644
index 000000000..3f528d751
--- /dev/null
+++ b/src/cmd/pack/Makefile
@@ -0,0 +1,5 @@
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.dist
diff --git a/src/cmd/gopack/ar.c b/src/cmd/pack/ar.c
index 0b5e608c7..7e07fbc89 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/pack/ar.c
@@ -37,7 +37,6 @@
#define rcmd your_rcmd
#include <u.h>
-#include <time.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
@@ -228,12 +227,12 @@ main(int argc, char *argv[])
case 'S': Sflag = 1; break;
case 'P': Pflag = 1; break;
default:
- fprint(2, "gopack: bad option `%c'\n", *cp);
+ fprint(2, "pack: bad option `%c'\n", *cp);
exits("error");
}
}
if (aflag && bflag) {
- fprint(2, "gopack: only one of 'a' and 'b' can be specified\n");
+ fprint(2, "pack: only one of 'a' and 'b' can be specified\n");
usage();
}
if(aflag || bflag) {
@@ -245,7 +244,7 @@ main(int argc, char *argv[])
}
if(Pflag) {
if(argc < 4) {
- fprint(2, "gopack: P flag requires prefix argument\n");
+ fprint(2, "pack: P flag requires prefix argument\n");
usage();
}
prefix = argv[2];
@@ -254,7 +253,7 @@ main(int argc, char *argv[])
}
if(comfun == 0) {
if(uflag == 0) {
- fprint(2, "gopack: one of [%s] must be specified\n", man);
+ fprint(2, "pack: one of [%s] must be specified\n", man);
usage();
}
setcom(rcmd);
@@ -268,7 +267,7 @@ main(int argc, char *argv[])
cp = 0;
while (argc--) {
if (*argv) {
- fprint(2, "gopack: %s not found\n", *argv);
+ fprint(2, "pack: %s not found\n", *argv);
cp = "error";
}
argv++;
@@ -285,7 +284,7 @@ setcom(void (*fun)(char *, int, char**))
{
if(comfun != 0) {
- fprint(2, "gopack: only one of [%s] allowed\n", man);
+ fprint(2, "pack: only one of [%s] allowed\n", man);
usage();
}
comfun = fun;
@@ -346,7 +345,7 @@ rcmd(char *arname, int count, char **files)
bfile = Bopen(file, OREAD);
if (!bfile) {
if (count != 0) {
- fprint(2, "gopack: cannot open %s\n", file);
+ fprint(2, "pack: cannot open %s\n", file);
errors++;
}
scanobj(&bar, ap, bp->size);
@@ -355,7 +354,7 @@ rcmd(char *arname, int count, char **files)
}
d = dirfstat(Bfildes(bfile));
if(d == nil)
- fprint(2, "gopack: cannot stat %s: %r\n", file);
+ fprint(2, "pack: cannot stat %s: %r\n", file);
if (uflag && (d==nil || d->mtime <= bp->date)) {
scanobj(&bar, ap, bp->size);
arcopy(&bar, ap, bp);
@@ -380,7 +379,7 @@ rcmd(char *arname, int count, char **files)
files[i] = 0;
bfile = Bopen(file, OREAD);
if (!bfile) {
- fprint(2, "gopack: cannot open %s\n", file);
+ fprint(2, "pack: cannot open %s\n", file);
errors++;
} else {
mesg('a', file);
@@ -448,7 +447,7 @@ xcmd(char *arname, int count, char **files)
mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
f = create(file, OWRITE, mode);
if(f < 0) {
- fprint(2, "gopack: %s cannot create\n", file);
+ fprint(2, "pack: %s cannot create\n", file);
skip(&bar, bp->size);
} else {
mesg('x', file);
@@ -542,7 +541,7 @@ mcmd(char *arname, int count, char **files)
}
close(fd);
if (poname[0] && aend == 0)
- fprint(2, "gopack: %s not found - files moved to end.\n", poname);
+ fprint(2, "pack: %s not found - files moved to end.\n", poname);
install(arname, astart, amiddle, aend, 0);
}
void
@@ -575,13 +574,13 @@ qcmd(char *arname, int count, char **files)
Biobuf *bfile;
if(aflag || bflag) {
- fprint(2, "gopack: abi not allowed with q\n");
+ fprint(2, "pack: abi not allowed with q\n");
exits("error");
}
fd = openar(arname, ORDWR, 1);
if (fd < 0) {
if(!cflag)
- fprint(2, "gopack: creating %s\n", arname);
+ fprint(2, "pack: creating %s\n", arname);
fd = arcreate(arname);
}
Binit(&bar, fd, OREAD);
@@ -595,7 +594,7 @@ qcmd(char *arname, int count, char **files)
files[i] = 0;
bfile = Bopen(file, OREAD);
if(!bfile) {
- fprint(2, "gopack: cannot open %s\n", file);
+ fprint(2, "pack: cannot open %s\n", file);
errors++;
} else {
mesg('q', file);
@@ -612,12 +611,49 @@ qcmd(char *arname, int count, char **files)
}
/*
+ * does the object header line p match the last one we saw?
+ * update *lastp if it gets more specific.
+ */
+int
+matchhdr(char *p, char **lastp)
+{
+ int n;
+ char *last;
+
+ // no information?
+ last = *lastp;
+ if(last == nil) {
+ *lastp = strdup(p);
+ return 1;
+ }
+
+ // identical match?
+ if(strcmp(last, p) == 0)
+ return 1;
+
+ // last has extra fields
+ n = strlen(p);
+ if(n < strlen(last) && last[n] == ' ')
+ return 1;
+
+ // p has extra fields - save in last
+ n = strlen(last);
+ if(n < strlen(p) && p[n] == ' ') {
+ free(last);
+ *lastp = strdup(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
* extract the symbol references from an object file
*/
void
scanobj(Biobuf *b, Arfile *ap, long size)
{
- int obj;
+ int obj, goobject;
vlong offset, offset1;
Dir *d;
static int lastobj = -1;
@@ -644,13 +680,13 @@ scanobj(Biobuf *b, Arfile *ap, long size)
}
if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */
- fprint(2, "gopack: non-object file %s\n", file);
+ fprint(2, "pack: non-object file %s\n", file);
errors++;
allobj = 0;
}
d = dirfstat(Bfildes(b));
if (d != nil && d->length == 0) {
- fprint(2, "gopack: zero length file %s\n", file);
+ fprint(2, "pack: zero length file %s\n", file);
errors++;
}
free(d);
@@ -658,33 +694,48 @@ scanobj(Biobuf *b, Arfile *ap, long size)
return;
}
+ goobject = 1;
offset1 = Boffset(b);
Bseek(b, offset, 0);
p = Brdstr(b, '\n', 1);
+
+ // After the go object header comes the Go metadata,
+ // followed by ! on a line by itself. If this is not a Go object,
+ // the ! comes immediately. Catch that so we can avoid
+ // the call to scanpkg below, since scanpkg assumes that the
+ // Go metadata is present.
+ if(Bgetc(b) == '!')
+ goobject = 0;
+
Bseek(b, offset1, 0);
if(p == nil || strncmp(p, "go object ", 10) != 0) {
- fprint(2, "gopack: malformed object file %s\n", file);
+ fprint(2, "pack: malformed object file %s\n", file);
errors++;
Bseek(b, offset, 0);
free(p);
return;
}
- if ((lastobj >= 0 && obj != lastobj) || (objhdr != nil && strcmp(p, objhdr) != 0)) {
- fprint(2, "gopack: inconsistent object file %s\n", file);
+ if (!matchhdr(p, &objhdr)) {
+ fprint(2, "pack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr);
errors++;
allobj = 0;
free(p);
return;
}
+ free(p);
+
+ // Old check. Should be impossible since objhdrs match, but keep the check anyway.
+ if (lastobj >= 0 && obj != lastobj) {
+ fprint(2, "pack: inconsistent object file %s\n", file);
+ errors++;
+ allobj = 0;
+ return;
+ }
lastobj = obj;
- if(objhdr == nil)
- objhdr = p;
- else
- free(p);
if (!readar(b, obj, offset+size, 0)) {
- fprint(2, "gopack: invalid symbol reference in file %s\n", file);
+ fprint(2, "pack: invalid symbol reference in file %s\n", file);
errors++;
allobj = 0;
Bseek(b, offset, 0);
@@ -692,7 +743,7 @@ scanobj(Biobuf *b, Arfile *ap, long size)
}
Bseek(b, offset, 0);
objtraverse(objsym, ap);
- if (gflag) {
+ if (gflag && goobject) {
scanpkg(b, size);
Bseek(b, offset, 0);
}
@@ -774,7 +825,7 @@ scanpkg(Biobuf *b, long size)
continue;
goto foundstart;
}
- // fprint(2, "gopack: warning: no package import section in %s\n", file);
+ // fprint(2, "pack: warning: no package import section in %s\n", file);
if(b != &bar || !pkgdefsafe)
safe = 0; // non-Go file (C or assembly)
return;
@@ -786,7 +837,6 @@ foundstart:
goto bad;
/* how big is it? */
- pkg = nil;
first = 1;
start = end = 0;
for (n=0; n<size; n+=Blinelen(b)) {
@@ -825,7 +875,7 @@ foundstart:
free(line);
}
bad:
- fprint(2, "gopack: bad package import section in %s\n", file);
+ fprint(2, "pack: bad package import section in %s\n", file);
errors++;
return;
@@ -835,7 +885,7 @@ foundend:
if (end == 0)
goto bad;
if(importblock != nil) {
- fprint(2, "gopack: multiple Go object files\n");
+ fprint(2, "pack: multiple Go object files\n");
errors++;
return;
}
@@ -843,7 +893,7 @@ foundend:
data = armalloc(end - start + 1);
Bseek(b, start, 0);
if (Bread(b, data, pkgsize) != pkgsize) {
- fprint(2, "gopack: error reading package import section in %s\n", file);
+ fprint(2, "pack: error reading package import section in %s\n", file);
errors++;
return;
}
@@ -943,11 +993,11 @@ openar(char *arname, int mode, int errok)
fd = open(arname, mode);
if(fd >= 0){
if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
- fprint(2, "gopack: %s not in archive format\n", arname);
+ fprint(2, "pack: %s not in archive format\n", arname);
exits("error");
}
}else if(!errok){
- fprint(2, "gopack: cannot open %s: %r\n", arname);
+ fprint(2, "pack: cannot open %s: %r\n", arname);
exits("error");
}
return fd;
@@ -963,7 +1013,7 @@ arcreate(char *arname)
fd = create(arname, OWRITE, 0664);
if(fd < 0){
- fprint(2, "gopack: cannot create %s: %r\n", arname);
+ fprint(2, "pack: cannot create %s: %r\n", arname);
exits("error");
}
if(write(fd, ARMAG, SARMAG) != SARMAG)
@@ -977,28 +1027,28 @@ arcreate(char *arname)
void
wrerr(void)
{
- perror("gopack: write error");
+ perror("pack: write error");
exits("error");
}
void
rderr(void)
{
- perror("gopack: read error");
+ perror("pack: read error");
exits("error");
}
void
phaseerr(int offset)
{
- fprint(2, "gopack: phase error at offset %d\n", offset);
+ fprint(2, "pack: phase error at offset %d\n", offset);
exits("error");
}
void
usage(void)
{
- fprint(2, "usage: gopack [%s][%s][P prefix] archive files ...\n", opt, man);
+ fprint(2, "usage: pack [%s][%s][P prefix] archive files ...\n", opt, man);
exits("error");
}
@@ -1042,7 +1092,7 @@ armove(Biobuf *b, Arfile *ap, Armember *bp)
d = dirfstat(Bfildes(b));
if (d == nil) {
- fprint(2, "gopack: cannot stat %s\n", file);
+ fprint(2, "pack: cannot stat %s\n", file);
return;
}
@@ -1050,7 +1100,7 @@ armove(Biobuf *b, Arfile *ap, Armember *bp)
for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */
cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
*cp = ' ';
- sprint(bp->hdr.date, "%-12ld", 0); // was d->mtime but removed for idempotent builds
+ sprint(bp->hdr.date, "%-12ld", 0L); // was d->mtime but removed for idempotent builds
sprint(bp->hdr.uid, "%-6d", 0);
sprint(bp->hdr.gid, "%-6d", 0);
sprint(bp->hdr.mode, "%-8lo", d->mode);
@@ -1143,7 +1193,7 @@ install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createf
rfork(RFNOTEG);
if(createflag)
- fprint(2, "gopack: creating %s\n", arname);
+ fprint(2, "pack: creating %s\n", arname);
fd = arcreate(arname);
if(allobj)
@@ -1184,7 +1234,7 @@ rl(int fd)
len = symdefsize;
if(len&01)
len++;
- sprint(a.date, "%-12ld", 0); // time(0)
+ sprint(a.date, "%-12ld", 0L); // time(0)
sprint(a.uid, "%-6d", 0);
sprint(a.gid, "%-6d", 0);
sprint(a.mode, "%-8lo", 0644L);
@@ -1221,7 +1271,7 @@ rl(int fd)
if (gflag) {
len = pkgdefsize;
- sprint(a.date, "%-12ld", 0); // time(0)
+ sprint(a.date, "%-12ld", 0L); // time(0)
sprint(a.uid, "%-6d", 0);
sprint(a.gid, "%-6d", 0);
sprint(a.mode, "%-8lo", 0644L);
@@ -1332,11 +1382,14 @@ mesg(int c, char *file)
void
trim(char *s, char *buf, int n)
{
- char *p;
+ char *p, *q;
for(;;) {
p = strrchr(s, '/');
- if (!p) { /* no slash in name */
+ q = strrchr(s, '\\');
+ if (q > p)
+ p = q;
+ if (!p) { /* no (back)slash in name */
strncpy(buf, s, n);
return;
}
@@ -1344,7 +1397,7 @@ trim(char *s, char *buf, int n)
strncpy(buf, p+1, n);
return;
}
- *p = 0; /* strip trailing slash */
+ *p = 0; /* strip trailing (back)slash */
}
}
@@ -1368,15 +1421,12 @@ void
longt(Armember *bp)
{
char *cp;
- time_t date;
pmode(strtoul(bp->hdr.mode, 0, 8));
Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
Bprint(&bout, "%7ld", bp->size);
- date = bp->date;
- cp = ctime(&date);
- /* using unix ctime, not plan 9 time, so cp+20 for year, not cp+24 */
- Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+20);
+ cp = ctime(bp->date);
+ Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
}
int m1[] = { 1, ROWN, 'r', '-' };
@@ -1532,6 +1582,8 @@ arwrite(int fd, Armember *bp)
int
page(Arfile *ap)
{
+ USED(ap);
+
sysfatal("page");
return 1;
}
@@ -1544,7 +1596,6 @@ page(Arfile *ap)
int
getspace(void)
{
-fprint(2, "IN GETSPACE\n");
if (astart && astart->head && page(astart))
return 1;
if (amiddle && amiddle->head && page(amiddle))
@@ -1589,7 +1640,7 @@ armalloc(int n)
return cp;
}
} while (getspace());
- fprint(2, "gopack: out of memory\n");
+ fprint(2, "pack: out of memory\n");
exits("malloc");
return 0;
}
diff --git a/src/cmd/gopack/doc.go b/src/cmd/pack/doc.go
index 1551a275f..8b17f3ca2 100644
--- a/src/cmd/gopack/doc.go
+++ b/src/cmd/pack/doc.go
@@ -4,7 +4,7 @@
/*
-Gopack is a variant of the Plan 9 ar tool. The original is documented at
+Pack is a variant of the Plan 9 ar tool. The original is documented at
http://plan9.bell-labs.com/magic/man2html/1/ar
@@ -12,14 +12,15 @@ It adds a special Go-specific section __.PKGDEF that collects all the
Go type information from the files in the archive; that section is
used by the compiler when importing the package during compilation.
-Usage: gopack [uvnbailogS][mrxtdpq][P prefix] archive files ...
+Usage:
+ go tool pack [uvnbailogS][mrxtdpq][P prefix] archive files ...
-The new option 'g' causes gopack to maintain the __.PKGDEF section
+The new option 'g' causes pack to maintain the __.PKGDEF section
as files are added to the archive.
-The new option 'S' forces gopack to mark the archive as safe.
+The new option 'S' forces pack to mark the archive as safe.
-The new option 'P' causes gopack to remove the given prefix
+The new option 'P' causes pack to remove the given prefix
from file names in the line number information in object files
that are already stored in or added to the archive.
*/
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
deleted file mode 100644
index 8a1a2f308..000000000
--- a/src/cmd/prof/Makefile
+++ /dev/null
@@ -1,38 +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.
-
-include ../../Make.inc
-O:=$(HOST_O)
-
-# The directory is prof because the source is portable and general.
-# We call the binary 6prof to avoid confusion and because this binary
-# is linked only with amd64 and x86 support.
-
-TARG=6prof
-OFILES=\
- main.$O\
-
-NOINSTALL=1
-include ../../Make.ccmd
-
-ifeq ($(GOOS),windows)
-NAME=windows
-else
-NAME=$(shell uname | tr A-Z a-z)
-endif
-
-install: install-$(NAME) install-pprof
-install-linux: install-default
-install-freebsd: install-default
-install-windows: install-default
-
-# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
-install-darwin: $(TARG)
- @true
-
-install-default: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-install-pprof: gopprof
- cp gopprof "$(GOBIN)"/gopprof
diff --git a/src/cmd/prof/doc.go b/src/cmd/prof/doc.go
deleted file mode 100644
index 1f2209f04..000000000
--- a/src/cmd/prof/doc.go
+++ /dev/null
@@ -1,48 +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.
-
-/*
-
-Prof is a rudimentary real-time profiler.
-
-Given a command to run or the process id (pid) of a command already
-running, it samples the program's state at regular intervals and reports
-on its behavior. With no options, it prints a histogram of the locations
-in the code that were sampled during execution.
-
-Since it is a real-time profiler, unlike a traditional profiler it samples
-the program's state even when it is not running, such as when it is
-asleep or waiting for I/O. Each thread contributes equally to the
-statistics.
-
-
-Usage: prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
-
-The output modes (default -h) are:
-
- -P file.prof:
- Write the profile information to file.prof, in the format used by pprof.
- At the moment, this only works on Linux amd64 binaries and requires that the
- binary be written using 6l -e to produce ELF debug info.
- See http://code.google.com/p/google-perftools for details.
- -h: histograms
- How many times a sample occurred at each location.
- -f: dynamic functions
- At each sample period, print the name of the executing function.
- -l: dynamic file and line numbers
- At each sample period, print the file and line number of the executing instruction.
- -r: dynamic registers
- At each sample period, print the register contents.
- -s: dynamic function stack traces
- At each sample period, print the symbolic stack trace.
-
-Flag -t sets the maximum real time to sample, in seconds, and -d
-sets the sampling interval in milliseconds. The default is to sample
-every 100ms until the program completes.
-
-For reasons of disambiguation it is installed as 6prof although it also serves
-as an 8prof and a 5prof.
-
-*/
-package documentation
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
deleted file mode 100755
index be5f84e9e..000000000
--- a/src/cmd/prof/gopprof
+++ /dev/null
@@ -1,4975 +0,0 @@
-#! /usr/bin/env perl
-
-# This is a copy of http://google-perftools.googlecode.com/svn/trunk/src/pprof
-# with local modifications to handle generation of SVG images and
-# the Go-style pprof paths. These modifications will probably filter
-# back into the official source before long.
-# It's convenient to have a copy here because we need just the one
-# Perl script, not all the C++ libraries that surround it.
-
-# Copyright (c) 1998-2007, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# ---
-# Program for printing the profile generated by common/profiler.cc,
-# or by the heap profiler (common/debugallocation.cc)
-#
-# The profile contains a sequence of entries of the form:
-# <count> <stack trace>
-# This program parses the profile, and generates user-readable
-# output.
-#
-# Examples:
-#
-# % tools/pprof "program" "profile"
-# Enters "interactive" mode
-#
-# % tools/pprof --text "program" "profile"
-# Generates one line per procedure
-#
-# % tools/pprof --gv "program" "profile"
-# Generates annotated call-graph and displays via "gv"
-#
-# % tools/pprof --gv --focus=Mutex "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-#
-# % tools/pprof --gv --focus=Mutex --ignore=string "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-# and does not match "string"
-#
-# % tools/pprof --list=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --list=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each line.
-#
-# % tools/pprof --disasm=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --disasm=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each PC value.
-#
-# TODO: Use color to indicate files?
-
-use strict;
-use warnings;
-use Getopt::Long;
-
-my $PPROF_VERSION = "1.5";
-
-# These are the object tools we use which can come from a
-# user-specified location using --tools, from the PPROF_TOOLS
-# environment variable, or from the environment.
-my %obj_tool_map = (
- "objdump" => "objdump",
- "nm" => "nm",
- "addr2line" => "addr2line",
- "c++filt" => "c++filt",
- ## ConfigureObjTools may add architecture-specific entries:
- #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
- #"addr2line_pdb" => "addr2line-pdb", # ditto
- #"otool" => "otool", # equivalent of objdump on OS X
-);
-my $DOT = "dot"; # leave non-absolute, since it may be in /usr/local
-my $GV = "gv";
-my $KCACHEGRIND = "kcachegrind";
-my $PS2PDF = "ps2pdf";
-# These are used for dynamic profiles
-my $CURL = "curl";
-
-# These are the web pages that servers need to support for dynamic profiles
-my $HEAP_PAGE = "/pprof/heap";
-my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
-my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
- # ?seconds=#&event=x&period=n
-my $GROWTH_PAGE = "/pprof/growth";
-my $CONTENTION_PAGE = "/pprof/contention";
-my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
-my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
-my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
-my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
-
-# default binary name
-my $UNKNOWN_BINARY = "(unknown)";
-
-# There is a pervasive dependency on the length (in hex characters,
-# i.e., nibbles) of an address, distinguishing between 32-bit and
-# 64-bit profiles. To err on the safe size, default to 64-bit here:
-my $address_length = 16;
-
-# A list of paths to search for shared object files
-my @prefix_list = ();
-
-# Special routine name that should not have any symbols.
-# Used as separator to parse "addr2line -i" output.
-my $sep_symbol = '_fini';
-my $sep_address = undef;
-
-##### Argument parsing #####
-
-sub usage_string {
- return <<EOF;
-Usage:
-pprof [options] <program> <profiles>
- <profiles> is a space separated list of profile names.
-pprof [options] <symbolized-profiles>
- <symbolized-profiles> is a list of profile files where each file contains
- the necessary symbol mappings as well as profile data (likely generated
- with --raw).
-pprof [options] <profile>
- <profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE
-
- Each name can be:
- /path/to/profile - a path to a profile file
- host:port[/<service>] - a location of a service to get profile from
-
- The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
- $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
- or /pprof/filteredprofile.
- For instance:
- pprof http://myserver.com:80$HEAP_PAGE
- If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
-pprof --symbols <program>
- Maps addresses to symbol names. In this mode, stdin should be a
- list of library mappings, in the same format as is found in the heap-
- and cpu-profile files (this loosely matches that of /proc/self/maps
- on linux), followed by a list of hex addresses to map, one per line.
-
- For more help with querying remote servers, including how to add the
- necessary server-side support code, see this filename (or one like it):
-
- /usr/doc/google-perftools-$PPROF_VERSION/pprof_remote_servers.html
-
-Options:
- --cum Sort by cumulative data
- --base=<base> Subtract <base> from <profile> before display
- --interactive Run in interactive mode (interactive "help" gives help) [default]
- --seconds=<n> Length of time for dynamic profiles [default=30 secs]
- --add_lib=<file> Read additional symbols and line info from the given library
- --lib_prefix=<dir> Comma separated list of library path prefixes
-
-Reporting Granularity:
- --addresses Report at address level
- --lines Report at source line level
- --functions Report at function level [default]
- --files Report at source file level
-
-Output type:
- --text Generate text report
- --callgrind Generate callgrind format to stdout
- --gv Generate Postscript and display
- --web Generate SVG and display
- --list=<regexp> Generate source listing of matching routines
- --disasm=<regexp> Generate disassembly of matching routines
- --symbols Print demangled symbol names found at given addresses
- --dot Generate DOT file to stdout
- --ps Generate Postcript to stdout
- --pdf Generate PDF to stdout
- --svg Generate SVG to stdout
- --gif Generate GIF to stdout
- --raw Generate symbolized pprof data (useful with remote fetch)
-
-Heap-Profile Options:
- --inuse_space Display in-use (mega)bytes [default]
- --inuse_objects Display in-use objects
- --alloc_space Display allocated (mega)bytes
- --alloc_objects Display allocated objects
- --show_bytes Display space in bytes
- --drop_negative Ignore negative differences
-
-Contention-profile options:
- --total_delay Display total delay at each region [default]
- --contentions Display number of delays at each region
- --mean_delay Display mean delay at each region
-
-Call-graph Options:
- --nodecount=<n> Show at most so many nodes [default=80]
- --nodefraction=<f> Hide nodes below <f>*total [default=.005]
- --edgefraction=<f> Hide edges below <f>*total [default=.001]
- --focus=<regexp> Focus on nodes matching <regexp>
- --ignore=<regexp> Ignore nodes matching <regexp>
- --scale=<n> Set GV scaling [default=0]
- --heapcheck Make nodes with non-0 object counts
- (i.e. direct leak generators) more visible
-
-Miscellaneous:
- --tools=<prefix> Prefix for object tool pathnames
- --test Run unit tests
- --help This message
- --version Version information
-
-Environment Variables:
- PPROF_TMPDIR Profiles directory. Defaults to \$HOME/pprof
- PPROF_TOOLS Prefix for object tools pathnames
-
-Examples:
-
-pprof /bin/ls ls.prof
- Enters "interactive" mode
-pprof --text /bin/ls ls.prof
- Outputs one line per procedure
-pprof --web /bin/ls ls.prof
- Displays annotated call-graph in web browser
-pprof --gv /bin/ls ls.prof
- Displays annotated call-graph via 'gv'
-pprof --gv --focus=Mutex /bin/ls ls.prof
- Restricts to code paths including a .*Mutex.* entry
-pprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
- Code paths including Mutex but not string
-pprof --list=getdir /bin/ls ls.prof
- (Per-line) annotated source listing for getdir()
-pprof --disasm=getdir /bin/ls ls.prof
- (Per-PC) annotated disassembly for getdir()
-
-pprof http://localhost:1234/
- Enters "interactive" mode
-pprof --text localhost:1234
- Outputs one line per procedure for localhost:1234
-pprof --raw localhost:1234 > ./local.raw
-pprof --text ./local.raw
- Fetches a remote profile for later analysis and then
- analyzes it in text mode.
-EOF
-}
-
-sub version_string {
- return <<EOF
-pprof (part of google-perftools $PPROF_VERSION)
-
-Copyright 1998-2007 Google Inc.
-
-This is BSD licensed software; see the source for copying conditions
-and license information.
-There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE.
-EOF
-}
-
-sub usage {
- my $msg = shift;
- print STDERR "$msg\n\n";
- print STDERR usage_string();
- print STDERR "\nFATAL ERROR: $msg\n"; # just as a reminder
- exit(1);
-}
-
-sub Init() {
- # Setup tmp-file name and handler to clean it up.
- # We do this in the very beginning so that we can use
- # error() and cleanup() function anytime here after.
- $main::tmpfile_sym = "/tmp/pprof$$.sym";
- $main::tmpfile_ps = "/tmp/pprof$$";
- $main::next_tmpfile = 0;
- $SIG{'INT'} = \&sighandler;
-
- # Cache from filename/linenumber to source code
- $main::source_cache = ();
-
- $main::opt_help = 0;
- $main::opt_version = 0;
-
- $main::opt_cum = 0;
- $main::opt_base = '';
- $main::opt_addresses = 0;
- $main::opt_lines = 0;
- $main::opt_functions = 0;
- $main::opt_files = 0;
- $main::opt_lib_prefix = "";
-
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_list = "";
- $main::opt_disasm = "";
- $main::opt_symbols = 0;
- $main::opt_gv = 0;
- $main::opt_web = 0;
- $main::opt_dot = 0;
- $main::opt_ps = 0;
- $main::opt_pdf = 0;
- $main::opt_gif = 0;
- $main::opt_svg = 0;
- $main::opt_raw = 0;
-
- $main::opt_nodecount = 80;
- $main::opt_nodefraction = 0.005;
- $main::opt_edgefraction = 0.001;
- $main::opt_focus = '';
- $main::opt_ignore = '';
- $main::opt_scale = 0;
- $main::opt_heapcheck = 0;
- $main::opt_seconds = 30;
- $main::opt_lib = "";
-
- $main::opt_inuse_space = 0;
- $main::opt_inuse_objects = 0;
- $main::opt_alloc_space = 0;
- $main::opt_alloc_objects = 0;
- $main::opt_show_bytes = 0;
- $main::opt_drop_negative = 0;
- $main::opt_interactive = 0;
-
- $main::opt_total_delay = 0;
- $main::opt_contentions = 0;
- $main::opt_mean_delay = 0;
-
- $main::opt_tools = "";
- $main::opt_debug = 0;
- $main::opt_test = 0;
-
- # These are undocumented flags used only by unittests.
- $main::opt_test_stride = 0;
-
- # Are we using $SYMBOL_PAGE?
- $main::use_symbol_page = 0;
-
- # Files returned by TempName.
- %main::tempnames = ();
-
- # Type of profile we are dealing with
- # Supported types:
- # cpu
- # heap
- # growth
- # contention
- $main::profile_type = ''; # Empty type means "unknown"
-
- GetOptions("help!" => \$main::opt_help,
- "version!" => \$main::opt_version,
- "cum!" => \$main::opt_cum,
- "base=s" => \$main::opt_base,
- "seconds=i" => \$main::opt_seconds,
- "add_lib=s" => \$main::opt_lib,
- "lib_prefix=s" => \$main::opt_lib_prefix,
- "functions!" => \$main::opt_functions,
- "lines!" => \$main::opt_lines,
- "addresses!" => \$main::opt_addresses,
- "files!" => \$main::opt_files,
- "text!" => \$main::opt_text,
- "callgrind!" => \$main::opt_callgrind,
- "list=s" => \$main::opt_list,
- "disasm=s" => \$main::opt_disasm,
- "symbols!" => \$main::opt_symbols,
- "gv!" => \$main::opt_gv,
- "web!" => \$main::opt_web,
- "dot!" => \$main::opt_dot,
- "ps!" => \$main::opt_ps,
- "pdf!" => \$main::opt_pdf,
- "svg!" => \$main::opt_svg,
- "gif!" => \$main::opt_gif,
- "raw!" => \$main::opt_raw,
- "interactive!" => \$main::opt_interactive,
- "nodecount=i" => \$main::opt_nodecount,
- "nodefraction=f" => \$main::opt_nodefraction,
- "edgefraction=f" => \$main::opt_edgefraction,
- "focus=s" => \$main::opt_focus,
- "ignore=s" => \$main::opt_ignore,
- "scale=i" => \$main::opt_scale,
- "heapcheck" => \$main::opt_heapcheck,
- "inuse_space!" => \$main::opt_inuse_space,
- "inuse_objects!" => \$main::opt_inuse_objects,
- "alloc_space!" => \$main::opt_alloc_space,
- "alloc_objects!" => \$main::opt_alloc_objects,
- "show_bytes!" => \$main::opt_show_bytes,
- "drop_negative!" => \$main::opt_drop_negative,
- "total_delay!" => \$main::opt_total_delay,
- "contentions!" => \$main::opt_contentions,
- "mean_delay!" => \$main::opt_mean_delay,
- "tools=s" => \$main::opt_tools,
- "test!" => \$main::opt_test,
- "debug!" => \$main::opt_debug,
- # Undocumented flags used only by unittests:
- "test_stride=i" => \$main::opt_test_stride,
- ) || usage("Invalid option(s)");
-
- # Deal with the standard --help and --version
- if ($main::opt_help) {
- print usage_string();
- exit(0);
- }
-
- if ($main::opt_version) {
- print version_string();
- exit(0);
- }
-
- # Disassembly/listing/symbols mode requires address-level info
- if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
- $main::opt_functions = 0;
- $main::opt_lines = 0;
- $main::opt_addresses = 1;
- $main::opt_files = 0;
- }
-
- # Check heap-profiling flags
- if ($main::opt_inuse_space +
- $main::opt_inuse_objects +
- $main::opt_alloc_space +
- $main::opt_alloc_objects > 1) {
- usage("Specify at most on of --inuse/--alloc options");
- }
-
- # Check output granularities
- my $grains =
- $main::opt_functions +
- $main::opt_lines +
- $main::opt_addresses +
- $main::opt_files +
- 0;
- if ($grains > 1) {
- usage("Only specify one output granularity option");
- }
- if ($grains == 0) {
- $main::opt_functions = 1;
- }
-
- # Check output modes
- my $modes =
- $main::opt_text +
- $main::opt_callgrind +
- ($main::opt_list eq '' ? 0 : 1) +
- ($main::opt_disasm eq '' ? 0 : 1) +
- ($main::opt_symbols == 0 ? 0 : 1) +
- $main::opt_gv +
- $main::opt_web +
- $main::opt_dot +
- $main::opt_ps +
- $main::opt_pdf +
- $main::opt_svg +
- $main::opt_gif +
- $main::opt_raw +
- $main::opt_interactive +
- 0;
- if ($modes > 1) {
- usage("Only specify one output mode");
- }
- if ($modes == 0) {
- if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode
- $main::opt_interactive = 1;
- } else {
- $main::opt_text = 1;
- }
- }
-
- if ($main::opt_test) {
- RunUnitTests();
- # Should not return
- exit(1);
- }
-
- # Binary name and profile arguments list
- $main::prog = "";
- @main::pfile_args = ();
-
- # Remote profiling without a binary (using $SYMBOL_PAGE instead)
- if (IsProfileURL($ARGV[0])) {
- $main::use_symbol_page = 1;
- } elsif (IsSymbolizedProfileFile($ARGV[0])) {
- $main::use_symbolized_profile = 1;
- $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file
- }
-
- if ($main::use_symbol_page || $main::use_symbolized_profile) {
- # We don't need a binary!
- my %disabled = ('--lines' => $main::opt_lines,
- '--disasm' => $main::opt_disasm);
- for my $option (keys %disabled) {
- usage("$option cannot be used without a binary") if $disabled{$option};
- }
- # Set $main::prog later...
- scalar(@ARGV) || usage("Did not specify profile file");
- } elsif ($main::opt_symbols) {
- # --symbols needs a binary-name (to run nm on, etc) but not profiles
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- } else {
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- scalar(@ARGV) || usage("Did not specify profile file");
- }
-
- # Parse profile file/location arguments
- foreach my $farg (@ARGV) {
- if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
- my $machine = $1;
- my $num_machines = $2;
- my $path = $3;
- for (my $i = 0; $i < $num_machines; $i++) {
- unshift(@main::pfile_args, "$i.$machine$path");
- }
- } else {
- unshift(@main::pfile_args, $farg);
- }
- }
-
- if ($main::use_symbol_page) {
- unless (IsProfileURL($main::pfile_args[0])) {
- error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
- }
- CheckSymbolPage();
- $main::prog = FetchProgramName();
- } elsif (!$main::use_symbolized_profile) { # may not need objtools!
- ConfigureObjTools($main::prog)
- }
-
- # Break the opt_lib_prefix into the prefix_list array
- @prefix_list = split (',', $main::opt_lib_prefix);
-
- # Remove trailing / from the prefixes, in the list to prevent
- # searching things like /my/path//lib/mylib.so
- foreach (@prefix_list) {
- s|/+$||;
- }
-}
-
-sub Main() {
- Init();
- $main::collected_profile = undef;
- @main::profile_files = ();
- $main::op_time = time();
-
- # Printing symbols is special and requires a lot less info that most.
- if ($main::opt_symbols) {
- PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin
- return;
- }
-
- # Fetch all profile data
- FetchDynamicProfiles();
-
- # this will hold symbols that we read from the profile files
- my $symbol_map = {};
-
- # Read one profile, pick the last item on the list
- my $data = ReadProfile($main::prog, pop(@main::profile_files));
- my $profile = $data->{profile};
- my $pcs = $data->{pcs};
- my $libs = $data->{libs}; # Info about main program and shared libraries
- $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
-
- # Add additional profiles, if available.
- if (scalar(@main::profile_files) > 0) {
- foreach my $pname (@main::profile_files) {
- my $data2 = ReadProfile($main::prog, $pname);
- $profile = AddProfile($profile, $data2->{profile});
- $pcs = AddPcs($pcs, $data2->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
- }
- }
-
- # Subtract base from profile, if specified
- if ($main::opt_base ne '') {
- my $base = ReadProfile($main::prog, $main::opt_base);
- $profile = SubtractProfile($profile, $base->{profile});
- $pcs = AddPcs($pcs, $base->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
- }
-
- # Get total data in profile
- my $total = TotalProfile($profile);
-
- # Collect symbols
- my $symbols;
- if ($main::use_symbolized_profile) {
- $symbols = FetchSymbols($pcs, $symbol_map);
- } elsif ($main::use_symbol_page) {
- $symbols = FetchSymbols($pcs);
- } else {
- $symbols = ExtractSymbols($libs, $pcs);
- }
-
- # Remove uniniteresting stack items
- $profile = RemoveUninterestingFrames($symbols, $profile);
-
- # Focus?
- if ($main::opt_focus ne '') {
- $profile = FocusProfile($symbols, $profile, $main::opt_focus);
- }
-
- # Ignore?
- if ($main::opt_ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
- }
-
- my $calls = ExtractCalls($symbols, $profile);
-
- # Reduce profiles to required output granularity, and also clean
- # each stack trace so a given entry exists at most once.
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- # Print
- if (!$main::opt_interactive) {
- if ($main::opt_disasm) {
- PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
- } elsif ($main::opt_list) {
- PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
- } elsif ($main::opt_text) {
- # Make sure the output is empty when have nothing to report
- # (only matters when --heapcheck is given but we must be
- # compatible with old branches that did not pass --heapcheck always):
- if ($total != 0) {
- printf("Total: %s %s\n", Unparse($total), Units());
- }
- PrintText($symbols, $flat, $cumulative, $total, -1);
- } elsif ($main::opt_raw) {
- PrintSymbolizedProfile($symbols, $profile, $main::prog);
- } elsif ($main::opt_callgrind) {
- PrintCallgrind($calls);
- } else {
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), "");
- } elsif ($main::opt_web) {
- my $tmp = TempName($main::next_tmpfile, "svg");
- RunWeb($tmp);
- # The command we run might hand the file name off
- # to an already running browser instance and then exit.
- # Normally, we'd remove $tmp on exit (right now),
- # but fork a child to remove $tmp a little later, so that the
- # browser has time to load it first.
- delete $main::tempnames{$tmp};
- if (fork() == 0) {
- sleep 5;
- unlink($tmp);
- exit(0);
- }
- }
- } else {
- exit(1);
- }
- }
- } else {
- InteractiveMode($profile, $symbols, $libs, $total);
- }
-
- cleanup();
- exit(0);
-}
-
-##### Entry Point #####
-
-Main();
-
-# Temporary code to detect if we're running on a Goobuntu system.
-# These systems don't have the right stuff installed for the special
-# Readline libraries to work, so as a temporary workaround, we default
-# to using the normal stdio code, rather than the fancier readline-based
-# code
-sub ReadlineMightFail {
- if (-e '/lib/libtermcap.so.2') {
- return 0; # libtermcap exists, so readline should be okay
- } else {
- return 1;
- }
-}
-
-sub RunGV {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- if (!system("$GV --version >/dev/null 2>&1")) {
- # Options using double dash are supported by this gv version.
- # Also, turn on noantialias to better handle bug in gv for
- # postscript files with large dimensions.
- # TODO: Maybe we should not pass the --noantialias flag
- # if the gv version is known to work properly without the flag.
- system("$GV --scale=$main::opt_scale --noantialias " . $fname . $bg);
- } else {
- # Old gv version - only supports options that use single dash.
- print STDERR "$GV -scale $main::opt_scale\n";
- system("$GV -scale $main::opt_scale " . $fname . $bg);
- }
-}
-
-sub RunWeb {
- my $fname = shift;
- print STDERR "Loading web page file:///$fname\n";
-
- if (`uname` =~ /Darwin/) {
- # OS X: open will use standard preference for SVG files.
- system("/usr/bin/open", $fname);
- return;
- }
-
- # Some kind of Unix; try generic symlinks, then specific browsers.
- # (Stop once we find one.)
- # Works best if the browser is already running.
- my @alt = (
- "/etc/alternatives/gnome-www-browser",
- "/etc/alternatives/x-www-browser",
- "google-chrome",
- "firefox",
- );
- foreach my $b (@alt) {
- if (-f $b) {
- if (system($b, $fname) == 0) {
- return;
- }
- }
- }
-
- print STDERR "Could not load web browser.\n";
-}
-
-sub RunKcachegrind {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- print STDERR "Starting '$KCACHEGRIND " . $fname . $bg . "'\n";
- system("$KCACHEGRIND " . $fname . $bg);
-}
-
-
-##### Interactive helper routines #####
-
-sub InteractiveMode {
- $| = 1; # Make output unbuffered for interactive mode
- my ($orig_profile, $symbols, $libs, $total) = @_;
-
- print STDERR "Welcome to pprof! For help, type 'help'.\n";
-
- # Use ReadLine if it's installed and input comes from a console.
- if ( -t STDIN &&
- !ReadlineMightFail() &&
- defined(eval {require Term::ReadLine}) ) {
- my $term = new Term::ReadLine 'pprof';
- while ( defined ($_ = $term->readline('(pprof) '))) {
- $term->addhistory($_) if /\S/;
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
- }
- } else { # don't have readline
- while (1) {
- print STDERR "(pprof) ";
- $_ = <STDIN>;
- last if ! defined $_ ;
- s/\r//g; # turn windows-looking lines into unix-looking lines
-
- # Save some flags that might be reset by InteractiveCommand()
- my $save_opt_lines = $main::opt_lines;
-
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
-
- # Restore flags
- $main::opt_lines = $save_opt_lines;
- }
- }
-}
-
-# Takes two args: orig profile, and command to run.
-# Returns 1 if we should keep going, or 0 if we were asked to quit
-sub InteractiveCommand {
- my($orig_profile, $symbols, $libs, $total, $command) = @_;
- $_ = $command; # just to make future m//'s easier
- if (!defined($_)) {
- print STDERR "\n";
- return 0;
- }
- if (m/^\s*quit/) {
- return 0;
- }
- if (m/^\s*help/) {
- InteractiveHelpMessage();
- return 1;
- }
- # Clear all the mode options -- mode is controlled by "$command"
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_disasm = 0;
- $main::opt_list = 0;
- $main::opt_gv = 0;
- $main::opt_cum = 0;
-
- if (m/^\s*(text|top)(\d*)\s*(.*)/) {
- $main::opt_text = 1;
-
- my $line_limit = ($2 ne "") ? int($2) : 10;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($3);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintText($symbols, $flat, $cumulative, $total, $line_limit);
- return 1;
- }
- if (m/^\s*callgrind\s*([^ \n]*)/) {
- $main::opt_callgrind = 1;
-
- # Get derived profiles
- my $calls = ExtractCalls($symbols, $orig_profile);
- my $filename = $1;
- if ( $1 eq '' ) {
- $filename = TempName($main::next_tmpfile, "callgrind");
- }
- PrintCallgrind($calls, $filename);
- if ( $1 eq '' ) {
- RunKcachegrind($filename, " & ");
- $main::next_tmpfile++;
- }
-
- return 1;
- }
- if (m/^\s*(web)?list\s*(.+)/) {
- my $html = (defined($1) && ($1 eq "web"));
- $main::opt_list = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($2);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
- return 1;
- }
- if (m/^\s*disasm\s*(.+)/) {
- $main::opt_disasm = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintDisassembly($libs, $flat, $cumulative, $routine, $total);
- return 1;
- }
- if (m/^\s*(gv|web)\s*(.*)/) {
- $main::opt_gv = 0;
- $main::opt_web = 0;
- if ($1 eq "gv") {
- $main::opt_gv = 1;
- } elsif ($1 eq "web") {
- $main::opt_web = 1;
- }
-
- my $focus;
- my $ignore;
- ($focus, $ignore) = ParseInteractiveArgs($2);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), " &");
- } elsif ($main::opt_web) {
- RunWeb(TempName($main::next_tmpfile, "svg"));
- }
- $main::next_tmpfile++;
- }
- return 1;
- }
- if (m/^\s*$/) {
- return 1;
- }
- print STDERR "Unknown command: try 'help'.\n";
- return 1;
-}
-
-
-sub ProcessProfile {
- my $total_count = shift;
- my $orig_profile = shift;
- my $symbols = shift;
- my $focus = shift;
- my $ignore = shift;
-
- # Process current profile to account for various settings
- my $profile = $orig_profile;
- printf("Total: %s %s\n", Unparse($total_count), Units());
- if ($focus ne '') {
- $profile = FocusProfile($symbols, $profile, $focus);
- my $focus_count = TotalProfile($profile);
- printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
- $focus,
- Unparse($focus_count), Units(),
- Unparse($total_count), ($focus_count*100.0) / $total_count);
- }
- if ($ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $ignore);
- my $ignore_count = TotalProfile($profile);
- printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
- $ignore,
- Unparse($ignore_count), Units(),
- Unparse($total_count),
- ($ignore_count*100.0) / $total_count);
- }
-
- return $profile;
-}
-
-sub InteractiveHelpMessage {
- print STDERR <<ENDOFHELP;
-Interactive pprof mode
-
-Commands:
- gv
- gv [focus] [-ignore1] [-ignore2]
- Show graphical hierarchical display of current profile. Without
- any arguments, shows all samples in the profile. With the optional
- "focus" argument, restricts the samples shown to just those where
- the "focus" regular expression matches a routine name on the stack
- trace.
-
- web
- web [focus] [-ignore1] [-ignore2]
- Like GV, but displays profile in your web browser instead of using
- Ghostview. Works best if your web browser is already running.
- To change the browser that gets used:
- On Linux, set the /etc/alternatives/gnome-www-browser symlink.
- On OS X, change the Finder association for SVG files.
-
- list [routine_regexp] [-ignore1] [-ignore2]
- Show source listing of routines whose names match "routine_regexp"
-
- weblist [routine_regexp] [-ignore1] [-ignore2]
- Displays a source listing of routines whose names match "routine_regexp"
- in a web browser. You can click on source lines to view the
- corresponding disassembly.
-
- top [--cum] [-ignore1] [-ignore2]
- top20 [--cum] [-ignore1] [-ignore2]
- top37 [--cum] [-ignore1] [-ignore2]
- Show top lines ordered by flat profile count, or cumulative count
- if --cum is specified. If a number is present after 'top', the
- top K routines will be shown (defaults to showing the top 10)
-
- disasm [routine_regexp] [-ignore1] [-ignore2]
- Show disassembly of routines whose names match "routine_regexp",
- annotated with sample counts.
-
- callgrind
- callgrind [filename]
- Generates callgrind file. If no filename is given, kcachegrind is called.
-
- help - This listing
- quit or ^D - End pprof
-
-For commands that accept optional -ignore tags, samples where any routine in
-the stack trace matches the regular expression in any of the -ignore
-parameters will be ignored.
-
-Further pprof details are available at this location (or one similar):
-
- /usr/doc/google-perftools-$PPROF_VERSION/cpu_profiler.html
- /usr/doc/google-perftools-$PPROF_VERSION/heap_profiler.html
-
-ENDOFHELP
-}
-sub ParseInteractiveArgs {
- my $args = shift;
- my $focus = "";
- my $ignore = "";
- my @x = split(/ +/, $args);
- foreach $a (@x) {
- if ($a =~ m/^(--|-)lines$/) {
- $main::opt_lines = 1;
- } elsif ($a =~ m/^(--|-)cum$/) {
- $main::opt_cum = 1;
- } elsif ($a =~ m/^-(.*)/) {
- $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
- } else {
- $focus .= (($focus ne "") ? "|" : "" ) . $a;
- }
- }
- if ($ignore ne "") {
- print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
- }
- return ($focus, $ignore);
-}
-
-##### Output code #####
-
-sub TempName {
- my $fnum = shift;
- my $ext = shift;
- my $file = "$main::tmpfile_ps.$fnum.$ext";
- $main::tempnames{$file} = 1;
- return $file;
-}
-
-# Print profile data in packed binary format (64-bit) to standard out
-sub PrintProfileData {
- my $profile = shift;
-
- # print header (64-bit style)
- # (zero) (header-size) (version) (sample-period) (zero)
- print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
-
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- my $depth = $#addrs + 1;
- # int(foo / 2**32) is the only reliable way to get rid of bottom
- # 32 bits on both 32- and 64-bit systems.
- print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
- print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
-
- foreach my $full_addr (@addrs) {
- my $addr = $full_addr;
- $addr =~ s/0x0*//; # strip off leading 0x, zeroes
- if (length($addr) > 16) {
- print STDERR "Invalid address in profile: $full_addr\n";
- next;
- }
- my $low_addr = substr($addr, -8); # get last 8 hex chars
- my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars
- print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
- }
- }
- }
-}
-
-# Print symbols and profile data
-sub PrintSymbolizedProfile {
- my $symbols = shift;
- my $profile = shift;
- my $prog = shift;
-
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
-
- print '--- ', $symbol_marker, "\n";
- if (defined($prog)) {
- print 'binary=', $prog, "\n";
- }
- while (my ($pc, $name) = each(%{$symbols})) {
- my $sep = ' ';
- print '0x', $pc;
- # We have a list of function names, which include the inlined
- # calls. They are separated (and terminated) by --, which is
- # illegal in function names.
- for (my $j = 2; $j <= $#{$name}; $j += 3) {
- print $sep, $name->[$j];
- $sep = '--';
- }
- print "\n";
- }
- print '---', "\n";
-
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $profile_marker = $&;
- print '--- ', $profile_marker, "\n";
- if (defined($main::collected_profile)) {
- # if used with remote fetch, simply dump the collected profile to output.
- open(SRC, "<$main::collected_profile");
- while (<SRC>) {
- print $_;
- }
- close(SRC);
- } else {
- # dump a cpu-format profile to standard out
- PrintProfileData($profile);
- }
-}
-
-# Print text output
-sub PrintText {
- my $symbols = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $total = shift;
- my $line_limit = shift;
-
- # Which profile to sort by?
- my $s = $main::opt_cum ? $cumulative : $flat;
-
- my $running_sum = 0;
- my $lines = 0;
- foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
- keys(%{$cumulative})) {
- my $f = GetEntry($flat, $k);
- my $c = GetEntry($cumulative, $k);
- $running_sum += $f;
-
- my $sym = $k;
- if (exists($symbols->{$k})) {
- $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
- if ($main::opt_addresses) {
- $sym = $k . " " . $sym;
- }
- }
-
- if ($f != 0 || $c != 0) {
- printf("%8s %6s %6s %8s %6s %s\n",
- Unparse($f),
- Percent($f, $total),
- Percent($running_sum, $total),
- Unparse($c),
- Percent($c, $total),
- $sym);
- }
- $lines++;
- last if ($line_limit >= 0 && $lines >= $line_limit);
- }
-}
-
-# Print the call graph in a way that's suiteable for callgrind.
-sub PrintCallgrind {
- my $calls = shift;
- my $filename;
- if ($main::opt_interactive) {
- $filename = shift;
- print STDERR "Writing callgrind file to '$filename'.\n"
- } else {
- $filename = "&STDOUT";
- }
- open(CG, ">".$filename );
- printf CG ("events: Hits\n\n");
- foreach my $call ( map { $_->[0] }
- sort { $a->[1] cmp $b ->[1] ||
- $a->[2] <=> $b->[2] }
- map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- [$_, $1, $2] }
- keys %$calls ) {
- my $count = int($calls->{$call});
- $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- my ( $caller_file, $caller_line, $caller_function,
- $callee_file, $callee_line, $callee_function ) =
- ( $1, $2, $3, $5, $6, $7 );
-
- printf CG ("fl=$caller_file\nfn=$caller_function\n");
- if (defined $6) {
- printf CG ("cfl=$callee_file\n");
- printf CG ("cfn=$callee_function\n");
- printf CG ("calls=$count $callee_line\n");
- }
- printf CG ("$caller_line $count\n\n");
- }
-}
-
-# Print disassembly for all all routines that match $main::opt_disasm
-sub PrintDisassembly {
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $disasm_opts = shift;
- my $total = shift;
-
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- # See if there are any samples in this routine
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- PrintDisassembledFunction($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr, $total);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-}
-
-# Return reference to array of tuples of the form:
-# [start_address, filename, linenumber, instruction, limit_address]
-# E.g.,
-# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
-sub Disassemble {
- my $prog = shift;
- my $offset = shift;
- my $start_addr = shift;
- my $end_addr = shift;
-
- my $objdump = $obj_tool_map{"objdump"};
- my $cmd = sprintf("$objdump -C -d -l --no-show-raw-insn " .
- "--start-address=0x$start_addr " .
- "--stop-address=0x$end_addr $prog");
- open(OBJDUMP, "$cmd |") || error("$objdump: $!\n");
- my @result = ();
- my $filename = "";
- my $linenumber = -1;
- my $last = ["", "", "", ""];
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- chop;
- if (m|\s*([^:\s]+):(\d+)\s*$|) {
- # Location line of the form:
- # <filename>:<linenumber>
- $filename = $1;
- $linenumber = $2;
- } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
- # Disassembly line -- zero-extend address to full length
- my $addr = HexExtend($1);
- my $k = AddressAdd($addr, $offset);
- $last->[4] = $k; # Store ending address for previous instruction
- $last = [$k, $filename, $linenumber, $2, $end_addr];
- push(@result, $last);
- }
- }
- close(OBJDUMP);
- return @result;
-}
-
-# The input file should contain lines of the form /proc/maps-like
-# output (same format as expected from the profiles) or that looks
-# like hex addresses (like "0xDEADBEEF"). We will parse all
-# /proc/maps output, and for all the hex addresses, we will output
-# "short" symbol names, one per line, in the same order as the input.
-sub PrintSymbols {
- my $maps_and_symbols_file = shift;
-
- # ParseLibraries expects pcs to be in a set. Fine by us...
- my @pclist = (); # pcs in sorted order
- my $pcs = {};
- my $map = "";
- foreach my $line (<$maps_and_symbols_file>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
- push(@pclist, HexExtend($1));
- $pcs->{$pclist[-1]} = 1;
- } else {
- $map .= $line;
- }
- }
-
- my $libs = ParseLibraries($main::prog, $map, $pcs);
- my $symbols = ExtractSymbols($libs, $pcs);
-
- foreach my $pc (@pclist) {
- # ->[0] is the shortname, ->[2] is the full name
- print(($symbols->{$pc}->[0] || "??") . "\n");
- }
-}
-
-
-# For sorting functions by name
-sub ByName {
- return ShortFunctionName($a) cmp ShortFunctionName($b);
-}
-
-# Print source-listing for all all routines that match $main::opt_list
-sub PrintListing {
- my $total = shift;
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $list_opts = shift;
- my $html = shift;
-
- my $output = \*STDOUT;
- my $fname = "";
-
-
- if ($html) {
- # Arrange to write the output to a temporary file
- $fname = TempName($main::next_tmpfile, "html");
- $main::next_tmpfile++;
- if (!open(TEMP, ">$fname")) {
- print STDERR "$fname: $!\n";
- return;
- }
- $output = \*TEMP;
- print $output HtmlListingHeader();
- printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
- $main::prog, Unparse($total), Units());
- }
-
- my $listed = 0;
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- # Print if there are any samples in this routine
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- $listed += PrintSource(
- $lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr,
- $html,
- $output);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-
- if ($html) {
- if ($listed > 0) {
- print $output HtmlListingFooter();
- close($output);
- RunWeb($fname);
- } else {
- close($output);
- unlink($fname);
- }
- }
-}
-
-sub HtmlListingHeader {
- return <<'EOF';
-<DOCTYPE html>
-<html>
-<head>
-<title>Pprof listing</title>
-<style type="text/css">
-body {
- font-family: sans-serif;
-}
-h1 {
- font-size: 1.5em;
- margin-bottom: 4px;
-}
-.legend {
- font-size: 1.25em;
-}
-.line {
- color: #aaaaaa;
-}
-.livesrc {
- color: #0000ff;
- cursor: pointer;
-}
-.livesrc:hover {
- background-color: #cccccc;
-}
-.asm {
- color: #888888;
- display: none;
-}
-</style>
-<script type="text/javascript">
-function pprof_toggle_asm(e) {
- var target;
- if (!e) e = window.event;
- if (e.target) target = e.target;
- else if (e.srcElement) target = e.srcElement;
-
- if (target && target.className == "livesrc") {
- var asm = target.nextSibling;
- if (asm && asm.className == "asm") {
- asm.style.display = (asm.style.display == "block" ? "none" : "block");
- e.preventDefault();
- return false;
- }
- }
-}
-</script>
-</head>
-<body>
-EOF
-}
-
-sub HtmlListingFooter {
- return <<'EOF';
-</body>
-</html>
-EOF
-}
-
-sub HtmlEscape {
- my $text = shift;
- $text =~ s/&/&amp;/g;
- $text =~ s/</&lt;/g;
- $text =~ s/>/&gt;/g;
- return $text;
-}
-
-# Returns the indentation of the line, if it has any non-whitespace
-# characters. Otherwise, returns -1.
-sub Indentation {
- my $line = shift;
- if (m/^(\s*)\S/) {
- return length($1);
- } else {
- return -1;
- }
-}
-
-# Print source-listing for one routine
-sub PrintSource {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $html = shift;
- my $output = shift;
-
- # Disassemble all instructions (just to get line numbers)
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
-
- # Hack 1: assume that the first source file encountered in the
- # disassembly contains the routine
- my $filename = undef;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[2] >= 0) {
- $filename = $instructions[$i]->[1];
- last;
- }
- }
- if (!defined($filename)) {
- print STDERR "no filename found in $routine\n";
- return 0;
- }
-
- # Hack 2: assume that the largest line number from $filename is the
- # end of the procedure. This is typically safe since if P1 contains
- # an inlined call to P2, then P2 usually occurs earlier in the
- # source file. If this does not work, we might have to compute a
- # density profile or just print all regions we find.
- my $lastline = 0;
- for (my $i = 0; $i <= $#instructions; $i++) {
- my $f = $instructions[$i]->[1];
- my $l = $instructions[$i]->[2];
- if (($f eq $filename) && ($l > $lastline)) {
- $lastline = $l;
- }
- }
-
- # Hack 3: assume the first source location from "filename" is the start of
- # the source code.
- my $firstline = 1;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[1] eq $filename) {
- $firstline = $instructions[$i]->[2];
- last;
- }
- }
-
- # Hack 4: Extend last line forward until its indentation is less than
- # the indentation we saw on $firstline
- my $oldlastline = $lastline;
- {
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- my $first_indentation = -1;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- my $indent = Indentation($_);
- if ($l >= $firstline) {
- if ($first_indentation < 0 && $indent >= 0) {
- $first_indentation = $indent;
- last if ($first_indentation == 0);
- }
- }
- if ($l >= $lastline && $indent >= 0) {
- if ($indent >= $first_indentation) {
- $lastline = $l+1;
- } else {
- last;
- }
- }
- }
- close(FILE);
- }
-
- # Assign all samples to the range $firstline,$lastline,
- # Hack 4: If an instruction does not occur in the range, its samples
- # are moved to the next instruction that occurs in the range.
- my $samples1 = {}; # Map from line number to flat count
- my $samples2 = {}; # Map from line number to cumulative count
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
- my %disasm = (); # Map from line number to disassembly
- my $running_disasm = ""; # Unassigned disassembly
- my $skip_marker = "---\n";
- if ($html) {
- $skip_marker = "";
- for (my $l = $firstline; $l <= $lastline; $l++) {
- $disasm{$l} = "";
- }
- }
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
-
- if ($html) {
- $running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
- HtmlPrintNumber($c1),
- HtmlPrintNumber($c2),
- $e->[0],
- CleanDisassembly($e->[3]));
- }
-
- $running1 += $c1;
- $running2 += $c2;
- $total1 += $c1;
- $total2 += $c2;
- my $file = $e->[1];
- my $line = $e->[2];
- if (($file eq $filename) &&
- ($line >= $firstline) &&
- ($line <= $lastline)) {
- # Assign all accumulated samples to this line
- AddEntry($samples1, $line, $running1);
- AddEntry($samples2, $line, $running2);
- $running1 = 0;
- $running2 = 0;
- if ($html) {
- $disasm{$line} .= $running_disasm;
- $running_disasm = '';
- }
- }
- }
-
- # Assign any leftover samples to $lastline
- AddEntry($samples1, $lastline, $running1);
- AddEntry($samples2, $lastline, $running2);
-
- if ($html) {
- printf $output (
- "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
- "Total:%6s %6s (flat / cumulative %s)\n",
- HtmlEscape(ShortFunctionName($routine)),
- HtmlEscape($filename),
- Unparse($total1),
- Unparse($total2),
- Units());
- } else {
- printf $output (
- "ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- $filename,
- Unparse($total1),
- Unparse($total2),
- Units());
- }
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- if ($l >= $firstline - 5 &&
- (($l <= $oldlastline + 5) || ($l <= $lastline))) {
- chop;
- my $text = $_;
- if ($l == $firstline) { print $output $skip_marker; }
- my $n1 = GetEntry($samples1, $l);
- my $n2 = GetEntry($samples2, $l);
- if ($html) {
- my $dis = $disasm{$l};
- if (!defined($dis) || $n1 + $n2 == 0) {
- # No samples/disassembly for this source line
- printf $output (
- "<span class=\"line\">%5d</span> " .
- "<span class=\"deadsrc\">%6s %6s %s</span>\n",
- $l,
- HtmlPrintNumber($n1),
- HtmlPrintNumber($n2),
- HtmlEscape($text));
- } else {
- printf $output (
- "<span class=\"line\">%5d</span> " .
- "<span class=\"livesrc\">%6s %6s %s</span>" .
- "<span class=\"asm\">%s</span>\n",
- $l,
- HtmlPrintNumber($n1),
- HtmlPrintNumber($n2),
- HtmlEscape($text),
- HtmlEscape($dis));
- }
- } else {
- printf $output(
- "%6s %6s %4d: %s\n",
- UnparseAlt($n1),
- UnparseAlt($n2),
- $l,
- $text);
- }
- if ($l == $lastline) { print $output $skip_marker; }
- };
- }
- close(FILE);
- if ($html) {
- print $output "</pre>\n";
- }
- return 1;
-}
-
-# Return the source line for the specified file/linenumber.
-# Returns undef if not found.
-sub SourceLine {
- my $file = shift;
- my $line = shift;
-
- # Look in cache
- if (!defined($main::source_cache{$file})) {
- if (100 < scalar keys(%main::source_cache)) {
- # Clear the cache when it gets too big
- $main::source_cache = ();
- }
-
- # Read all lines from the file
- if (!open(FILE, "<$file")) {
- print STDERR "$file: $!\n";
- $main::source_cache{$file} = []; # Cache the negative result
- return undef;
- }
- my $lines = [];
- push(@{$lines}, ""); # So we can use 1-based line numbers as indices
- while (<FILE>) {
- push(@{$lines}, $_);
- }
- close(FILE);
-
- # Save the lines in the cache
- $main::source_cache{$file} = $lines;
- }
-
- my $lines = $main::source_cache{$file};
- if (($line < 0) || ($line > $#{$lines})) {
- return undef;
- } else {
- return $lines->[$line];
- }
-}
-
-# Print disassembly for one routine with interspersed source if available
-sub PrintDisassembledFunction {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $total = shift;
-
- # Disassemble all instructions
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
-
- # Make array of counts per instruction
- my @flat_count = ();
- my @cum_count = ();
- my $flat_total = 0;
- my $cum_total = 0;
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
- push(@flat_count, $c1);
- push(@cum_count, $c2);
- $flat_total += $c1;
- $cum_total += $c2;
- }
-
- # Print header with total counts
- printf("ROUTINE ====================== %s\n" .
- "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
- ShortFunctionName($routine),
- Unparse($flat_total),
- Unparse($cum_total),
- Units(),
- ($cum_total * 100.0) / $total);
-
- # Process instructions in order
- my $current_file = "";
- for (my $i = 0; $i <= $#instructions; ) {
- my $e = $instructions[$i];
-
- # Print the new file name whenever we switch files
- if ($e->[1] ne $current_file) {
- $current_file = $e->[1];
- my $fname = $current_file;
- $fname =~ s|^\./||; # Trim leading "./"
-
- # Shorten long file names
- if (length($fname) >= 58) {
- $fname = "..." . substr($fname, -55);
- }
- printf("-------------------- %s\n", $fname);
- }
-
- # TODO: Compute range of lines to print together to deal with
- # small reorderings.
- my $first_line = $e->[2];
- my $last_line = $first_line;
- my %flat_sum = ();
- my %cum_sum = ();
- for (my $l = $first_line; $l <= $last_line; $l++) {
- $flat_sum{$l} = 0;
- $cum_sum{$l} = 0;
- }
-
- # Find run of instructions for this range of source lines
- my $first_inst = $i;
- while (($i <= $#instructions) &&
- ($instructions[$i]->[2] >= $first_line) &&
- ($instructions[$i]->[2] <= $last_line)) {
- $e = $instructions[$i];
- $flat_sum{$e->[2]} += $flat_count[$i];
- $cum_sum{$e->[2]} += $cum_count[$i];
- $i++;
- }
- my $last_inst = $i - 1;
-
- # Print source lines
- for (my $l = $first_line; $l <= $last_line; $l++) {
- my $line = SourceLine($current_file, $l);
- if (!defined($line)) {
- $line = "?\n";
- next;
- } else {
- $line =~ s/^\s+//;
- }
- printf("%6s %6s %5d: %s",
- UnparseAlt($flat_sum{$l}),
- UnparseAlt($cum_sum{$l}),
- $l,
- $line);
- }
-
- # Print disassembly
- for (my $x = $first_inst; $x <= $last_inst; $x++) {
- my $e = $instructions[$x];
- my $address = $e->[0];
- $address = AddressSub($address, $offset); # Make relative to section
- $address =~ s/^0x//;
- $address =~ s/^0*//;
-
- printf("%6s %6s %8s: %6s\n",
- UnparseAlt($flat_count[$x]),
- UnparseAlt($cum_count[$x]),
- $address,
- CleanDisassembly($e->[3]));
- }
- }
-}
-
-# Print DOT graph
-sub PrintDot {
- my $prog = shift;
- my $symbols = shift;
- my $raw = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $overall_total = shift;
-
- # Get total
- my $local_total = TotalProfile($flat);
- my $nodelimit = int($main::opt_nodefraction * $local_total);
- my $edgelimit = int($main::opt_edgefraction * $local_total);
- my $nodecount = $main::opt_nodecount;
-
- # Find nodes to include
- my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
- abs(GetEntry($cumulative, $a))
- || $a cmp $b }
- keys(%{$cumulative}));
- my $last = $nodecount - 1;
- if ($last > $#list) {
- $last = $#list;
- }
- while (($last >= 0) &&
- (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
- $last--;
- }
- if ($last < 0) {
- print STDERR "No nodes to print\n";
- cleanup();
- return 0;
- }
-
- if ($nodelimit > 0 || $edgelimit > 0) {
- printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
- Unparse($nodelimit), Units(),
- Unparse($edgelimit), Units());
- }
-
- # Open DOT output file
- my $output;
- if ($main::opt_gv) {
- $output = "| $DOT -Tps2 >" . TempName($main::next_tmpfile, "ps");
- } elsif ($main::opt_ps) {
- $output = "| $DOT -Tps2";
- } elsif ($main::opt_pdf) {
- $output = "| $DOT -Tps2 | $PS2PDF - -";
- } elsif ($main::opt_web || $main::opt_svg) {
- # We need to post-process the SVG, so write to a temporary file always.
- $output = "| $DOT -Tsvg >" . TempName($main::next_tmpfile, "svg");
- } elsif ($main::opt_gif) {
- $output = "| $DOT -Tgif";
- } else {
- $output = ">&STDOUT";
- }
- open(DOT, $output) || error("$output: $!\n");
-
- # Title
- printf DOT ("digraph \"%s; %s %s\" {\n",
- $prog,
- Unparse($overall_total),
- Units());
- if ($main::opt_pdf) {
- # The output is more printable if we set the page size for dot.
- printf DOT ("size=\"8,11\"\n");
- }
- printf DOT ("node [width=0.375,height=0.25];\n");
-
- # Print legend
- printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
- "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
- $prog,
- sprintf("Total %s: %s", Units(), Unparse($overall_total)),
- sprintf("Focusing on: %s", Unparse($local_total)),
- sprintf("Dropped nodes with <= %s abs(%s)",
- Unparse($nodelimit), Units()),
- sprintf("Dropped edges with <= %s %s",
- Unparse($edgelimit), Units())
- );
-
- # Print nodes
- my %node = ();
- my $nextnode = 1;
- foreach my $a (@list[0..$last]) {
- # Pick font size
- my $f = GetEntry($flat, $a);
- my $c = GetEntry($cumulative, $a);
-
- my $fs = 8;
- if ($local_total > 0) {
- $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
- }
-
- $node{$a} = $nextnode++;
- my $sym = $a;
- $sym =~ s/\s+/\\n/g;
- $sym =~ s/::/\\n/g;
-
- # Extra cumulative info to print for non-leaves
- my $extra = "";
- if ($f != $c) {
- $extra = sprintf("\\rof %s (%s)",
- Unparse($c),
- Percent($c, $overall_total));
- }
- my $style = "";
- if ($main::opt_heapcheck) {
- if ($f > 0) {
- # make leak-causing nodes more visible (add a background)
- $style = ",style=filled,fillcolor=gray"
- } elsif ($f < 0) {
- # make anti-leak-causing nodes (which almost never occur)
- # stand out as well (triple border)
- $style = ",peripheries=3"
- }
- }
-
- printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
- "\",shape=box,fontsize=%.1f%s];\n",
- $node{$a},
- $sym,
- Unparse($f),
- Percent($f, $overall_total),
- $extra,
- $fs,
- $style,
- );
- }
-
- # Get edges and counts per edge
- my %edge = ();
- my $n;
- foreach my $k (keys(%{$raw})) {
- # TODO: omit low %age edges
- $n = $raw->{$k};
- my @translated = TranslateStack($symbols, $k);
- for (my $i = 1; $i <= $#translated; $i++) {
- my $src = $translated[$i];
- my $dst = $translated[$i-1];
- #next if ($src eq $dst); # Avoid self-edges?
- if (exists($node{$src}) && exists($node{$dst})) {
- my $edge_label = "$src\001$dst";
- if (!exists($edge{$edge_label})) {
- $edge{$edge_label} = 0;
- }
- $edge{$edge_label} += $n;
- }
- }
- }
-
- # Print edges
- foreach my $e (keys(%edge)) {
- my @x = split(/\001/, $e);
- $n = $edge{$e};
-
- if (abs($n) > $edgelimit) {
- # Compute line width based on edge count
- my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
- if ($fraction > 1) { $fraction = 1; }
- my $w = $fraction * 2;
- if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
- # SVG output treats line widths < 1 poorly.
- $w = 1;
- }
-
- # Dot sometimes segfaults if given edge weights that are too large, so
- # we cap the weights at a large value
- my $edgeweight = abs($n) ** 0.7;
- if ($edgeweight > 100000) { $edgeweight = 100000; }
- $edgeweight = int($edgeweight);
-
- my $style = sprintf("setlinewidth(%f)", $w);
- if ($x[1] =~ m/\(inline\)/) {
- $style .= ",dashed";
- }
-
- # Use a slightly squashed function of the edge count as the weight
- printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
- $node{$x[0]},
- $node{$x[1]},
- Unparse($n),
- $edgeweight,
- $style);
- }
- }
-
- print DOT ("}\n");
- close(DOT);
-
- if ($main::opt_web || $main::opt_svg) {
- # Rewrite SVG to be more usable inside web browser.
- RewriteSvg(TempName($main::next_tmpfile, "svg"));
- }
-
- return 1;
-}
-
-sub RewriteSvg {
- my $svgfile = shift;
-
- open(SVG, $svgfile) || die "open temp svg: $!";
- my @svg = <SVG>;
- close(SVG);
- unlink $svgfile;
- my $svg = join('', @svg);
-
- # Dot's SVG output is
- #
- # <svg width="___" height="___"
- # viewBox="___" xmlns=...>
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </svg>
- #
- # Change it to
- #
- # <svg width="100%" height="100%"
- # xmlns=...>
- # $svg_javascript
- # <g id="viewport" transform="translate(0,0)">
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </g>
- # </svg>
-
- # Fix width, height; drop viewBox.
- $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/;
-
- # Insert script, viewport <g> above first <g>
- my $svg_javascript = SvgJavascript();
- my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n";
- $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/;
-
- # Insert final </g> above </svg>.
- $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/;
- $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/;
-
- if ($main::opt_svg) {
- # --svg: write to standard output.
- print $svg;
- } else {
- # Write back to temporary file.
- open(SVG, ">$svgfile") || die "open $svgfile: $!";
- print SVG $svg;
- close(SVG);
- }
-}
-
-sub SvgJavascript {
- return <<'EOF';
-<script type="text/ecmascript"><![CDATA[
-// SVGPan
-// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
-// Local modification: if(true || ...) below to force panning, never moving.
-// Local modification: add clamping to fix bug in handleMouseWheel.
-
-/**
- * SVGPan library 1.2
- * ====================
- *
- * Given an unique existing element with id "viewport", including the
- * the library into any SVG adds the following capabilities:
- *
- * - Mouse panning
- * - Mouse zooming (using the wheel)
- * - Object dargging
- *
- * Known issues:
- *
- * - Zooming (while panning) on Safari has still some issues
- *
- * Releases:
- *
- * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
- * Fixed a bug with browser mouse handler interaction
- *
- * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui
- * Updated the zoom code to support the mouse wheel on Safari/Chrome
- *
- * 1.0, Andrea Leofreddi
- * First release
- *
- * This code is licensed under the following BSD license:
- *
- * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this list of
- * conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice, this list
- * of conditions and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of Andrea Leofreddi.
- */
-
-var root = document.documentElement;
-
-var state = 'none', stateTarget, stateOrigin, stateTf;
-
-setupHandlers(root);
-
-/**
- * Register handlers
- */
-function setupHandlers(root){
- setAttributes(root, {
- "onmouseup" : "add(evt)",
- "onmousedown" : "handleMouseDown(evt)",
- "onmousemove" : "handleMouseMove(evt)",
- "onmouseup" : "handleMouseUp(evt)",
- //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
- });
-
- if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
- window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
- else
- window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
-
- var g = svgDoc.getElementById("svg");
- g.width = "100%";
- g.height = "100%";
-}
-
-/**
- * Instance an SVGPoint object with given event coordinates.
- */
-function getEventPoint(evt) {
- var p = root.createSVGPoint();
-
- p.x = evt.clientX;
- p.y = evt.clientY;
-
- return p;
-}
-
-/**
- * Sets the current transform matrix of an element.
- */
-function setCTM(element, matrix) {
- var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
-
- element.setAttribute("transform", s);
-}
-
-/**
- * Dumps a matrix to a string (useful for debug).
- */
-function dumpMatrix(matrix) {
- var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
-
- return s;
-}
-
-/**
- * Sets attributes of an element.
- */
-function setAttributes(element, attributes){
- for (i in attributes)
- element.setAttributeNS(null, i, attributes[i]);
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseWheel(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var delta;
-
- if(evt.wheelDelta)
- delta = evt.wheelDelta / 3600; // Chrome/Safari
- else
- delta = evt.detail / -90; // Mozilla
-
- var z = 1 + delta; // Zoom factor: 0.9/1.1
-
- // Clamp to reasonable values.
- // The 0.1 check is important because
- // a very large scroll can turn into a
- // negative z, which rotates the image 180 degrees.
- if(z < 0.1)
- z = 0.1;
- if(z > 10.0)
- z = 10.0;
-
- var g = svgDoc.getElementById("viewport");
-
- var p = getEventPoint(evt);
-
- p = p.matrixTransform(g.getCTM().inverse());
-
- // Compute new scale matrix in current mouse position
- var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
-
- setCTM(g, g.getCTM().multiply(k));
-
- stateTf = stateTf.multiply(k.inverse());
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseMove(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(state == 'pan') {
- // Pan mode
- var p = getEventPoint(evt).matrixTransform(stateTf);
-
- setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
- } else if(state == 'move') {
- // Move mode
- var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
-
- setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
-
- stateOrigin = p;
- }
-}
-
-/**
- * Handle click event.
- */
-function handleMouseDown(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(true || evt.target.tagName == "svg") {
- // Pan mode
- state = 'pan';
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- } else {
- // Move mode
- state = 'move';
-
- stateTarget = evt.target;
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- }
-}
-
-/**
- * Handle mouse button release event.
- */
-function handleMouseUp(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- if(state == 'pan' || state == 'move') {
- // Quit pan mode
- state = '';
- }
-}
-
-]]></script>
-EOF
-}
-
-# Translate a stack of addresses into a stack of symbols
-sub TranslateStack {
- my $symbols = shift;
- my $k = shift;
-
- my @addrs = split(/\n/, $k);
- my @result = ();
- for (my $i = 0; $i <= $#addrs; $i++) {
- my $a = $addrs[$i];
-
- # Skip large addresses since they sometimes show up as fake entries on RH9
- if (length($a) > 8 && $a gt "7fffffffffffffff") {
- next;
- }
-
- if ($main::opt_disasm || $main::opt_list) {
- # We want just the address for the key
- push(@result, $a);
- next;
- }
-
- my $symlist = $symbols->{$a};
- if (!defined($symlist)) {
- $symlist = [$a, "", $a];
- }
-
- # We can have a sequence of symbols for a particular entry
- # (more than one symbol in the case of inlining). Callers
- # come before callees in symlist, so walk backwards since
- # the translated stack should contain callees before callers.
- for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
- my $func = $symlist->[$j-2];
- my $fileline = $symlist->[$j-1];
- my $fullfunc = $symlist->[$j];
- if ($j > 2) {
- $func = "$func (inline)";
- }
- if ($main::opt_addresses) {
- push(@result, "$a $func $fileline");
- } elsif ($main::opt_lines) {
- if ($func eq '??' && $fileline eq '??:0') {
- push(@result, "$a");
- } else {
- push(@result, "$func $fileline");
- }
- } elsif ($main::opt_functions) {
- if ($func eq '??') {
- push(@result, "$a");
- } else {
- push(@result, $func);
- }
- } elsif ($main::opt_files) {
- if ($fileline eq '??:0' || $fileline eq '') {
- push(@result, "$a");
- } else {
- my $f = $fileline;
- $f =~ s/:\d+$//;
- push(@result, $f);
- }
- } else {
- push(@result, $a);
- last; # Do not print inlined info
- }
- }
- }
-
- # print join(",", @addrs), " => ", join(",", @result), "\n";
- return @result;
-}
-
-# Generate percent string for a number and a total
-sub Percent {
- my $num = shift;
- my $tot = shift;
- if ($tot != 0) {
- return sprintf("%.1f%%", $num * 100.0 / $tot);
- } else {
- return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
- }
-}
-
-# Generate pretty-printed form of number
-sub Unparse {
- my $num = shift;
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return sprintf("%d", $num);
- } else {
- if ($main::opt_show_bytes) {
- return sprintf("%d", $num);
- } else {
- return sprintf("%.1f", $num / 1048576.0);
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds
- } else {
- return sprintf("%d", $num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to "."
-sub UnparseAlt {
- my $num = shift;
- if ($num == 0) {
- return ".";
- } else {
- return Unparse($num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to ""
-sub HtmlPrintNumber {
- my $num = shift;
- if ($num == 0) {
- return "";
- } else {
- return Unparse($num);
- }
-}
-
-# Return output units
-sub Units {
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return "objects";
- } else {
- if ($main::opt_show_bytes) {
- return "B";
- } else {
- return "MB";
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return "seconds";
- } else {
- return "samples";
- }
-}
-
-##### Profile manipulation code #####
-
-# Generate flattened profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a]
-sub FlatProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- AddEntry($result, $addrs[0], $count);
- }
- }
- return $result;
-}
-
-# Generate cumulative profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a], [b], [c], [d]
-sub CumulativeProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- AddEntry($result, $a, $count);
- }
- }
- return $result;
-}
-
-# If the second-youngest PC on the stack is always the same, returns
-# that pc. Otherwise, returns undef.
-sub IsSecondPcAlwaysTheSame {
- my $profile = shift;
-
- my $second_pc = undef;
- foreach my $k (keys(%{$profile})) {
- my @addrs = split(/\n/, $k);
- if ($#addrs < 1) {
- return undef;
- }
- if (not defined $second_pc) {
- $second_pc = $addrs[1];
- } else {
- if ($second_pc ne $addrs[1]) {
- return undef;
- }
- }
- }
- return $second_pc;
-}
-
-sub ExtractSymbolLocation {
- my $symbols = shift;
- my $address = shift;
- # 'addr2line' outputs "??:0" for unknown locations; we do the
- # same to be consistent.
- my $location = "??:0:unknown";
- if (exists $symbols->{$address}) {
- my $file = $symbols->{$address}->[1];
- if ($file eq "?") {
- $file = "??:0"
- }
- $location = $file . ":" . $symbols->{$address}->[0];
- }
- return $location;
-}
-
-# Extracts a graph of calls.
-sub ExtractCalls {
- my $symbols = shift;
- my $profile = shift;
-
- my $calls = {};
- while( my ($stack_trace, $count) = each %$profile ) {
- my @address = split(/\n/, $stack_trace);
- my $destination = ExtractSymbolLocation($symbols, $address[0]);
- AddEntry($calls, $destination, $count);
- for (my $i = 1; $i <= $#address; $i++) {
- my $source = ExtractSymbolLocation($symbols, $address[$i]);
- my $call = "$source -> $destination";
- AddEntry($calls, $call, $count);
- $destination = $source;
- }
- }
-
- return $calls;
-}
-
-sub RemoveUninterestingFrames {
- my $symbols = shift;
- my $profile = shift;
-
- # List of function names to skip
- my %skip = ();
- my $skip_regexp = 'NOMATCH';
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- foreach my $name ('calloc',
- 'cfree',
- 'malloc',
- 'free',
- 'memalign',
- 'posix_memalign',
- 'pvalloc',
- 'valloc',
- 'realloc',
- 'tc_calloc',
- 'tc_cfree',
- 'tc_malloc',
- 'tc_free',
- 'tc_memalign',
- 'tc_posix_memalign',
- 'tc_pvalloc',
- 'tc_valloc',
- 'tc_realloc',
- 'tc_new',
- 'tc_delete',
- 'tc_newarray',
- 'tc_deletearray',
- 'tc_new_nothrow',
- 'tc_newarray_nothrow',
- 'do_malloc',
- '::do_malloc', # new name -- got moved to an unnamed ns
- '::do_malloc_or_cpp_alloc',
- 'DoSampledAllocation',
- 'simple_alloc::allocate',
- '__malloc_alloc_template::allocate',
- '__builtin_delete',
- '__builtin_new',
- '__builtin_vec_delete',
- '__builtin_vec_new',
- 'operator new',
- 'operator new[]',
- # Go
- 'catstring',
- 'copyin',
- 'gostring',
- 'gostringsize',
- 'growslice1',
- 'appendslice1',
- 'hash_init',
- 'hash_subtable_new',
- 'hash_conv',
- 'hash_grow',
- 'hash_insert_internal',
- 'hash_insert',
- 'mapassign',
- 'runtime.mapassign',
- 'runtime.appendslice',
- 'runtime.mapassign1',
- 'makechan',
- 'makemap',
- 'mal',
- 'runtime.new',
- 'makeslice1',
- 'runtime.gostringsize',
- 'runtime.malloc',
- 'unsafe.New',
- 'runtime.mallocgc',
- 'runtime.catstring',
- 'runtime.growslice',
- 'runtime.ifaceT2E',
- 'runtime.ifaceT2I',
- 'runtime.makechan',
- 'runtime.makechan_c',
- 'runtime.makemap',
- 'runtime.makemap_c',
- 'runtime.makeslice',
- 'runtime.mal',
- 'runtime.slicebytetostring',
- 'runtime.sliceinttostring',
- 'runtime.stringtoslicebyte',
- 'runtime.stringtosliceint',
- # These mark the beginning/end of our custom sections
- '__start_google_malloc',
- '__stop_google_malloc',
- '__start_malloc_hook',
- '__stop_malloc_hook') {
- $skip{$name} = 1;
- $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
- }
- # TODO: Remove TCMalloc once everything has been
- # moved into the tcmalloc:: namespace and we have flushed
- # old code out of the system.
- $skip_regexp = "TCMalloc|^tcmalloc::";
- } elsif ($main::profile_type eq 'contention') {
- foreach my $vname ('Mutex::Unlock', 'Mutex::UnlockSlow') {
- $skip{$vname} = 1;
- }
- } elsif ($main::profile_type eq 'cpu') {
- # Drop signal handlers used for CPU profile collection
- # TODO(dpeng): this should not be necessary; it's taken
- # care of by the general 2nd-pc mechanism below.
- foreach my $name ('ProfileData::Add', # historical
- 'ProfileData::prof_handler', # historical
- 'CpuProfiler::prof_handler',
- '__FRAME_END__',
- '__pthread_sighandler',
- '__restore') {
- $skip{$name} = 1;
- }
- } else {
- # Nothing skipped for unknown types
- }
-
- # Go doesn't have the problem that this heuristic tries to fix. Disable.
- if (0 && $main::profile_type eq 'cpu') {
- # If all the second-youngest program counters are the same,
- # this STRONGLY suggests that it is an artifact of measurement,
- # i.e., stack frames pushed by the CPU profiler signal handler.
- # Hence, we delete them.
- # (The topmost PC is read from the signal structure, not from
- # the stack, so it does not get involved.)
- while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) {
- my $result = {};
- my $func = '';
- if (exists($symbols->{$second_pc})) {
- $second_pc = $symbols->{$second_pc}->[0];
- }
- print STDERR "Removing $second_pc from all stack traces.\n";
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- splice @addrs, 1, 1;
- my $reduced_path = join("\n", @addrs);
- AddEntry($result, $reduced_path, $count);
- }
- $profile = $result;
- }
- }
-
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my @path = ();
- foreach my $a (@addrs) {
- if (exists($symbols->{$a})) {
- my $func = $symbols->{$a}->[0];
- if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
- next;
- }
- }
- push(@path, $a);
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- return $result;
-}
-
-# Reduce profile to granularity given by user
-sub ReduceProfile {
- my $symbols = shift;
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @translated = TranslateStack($symbols, $k);
- my @path = ();
- my %seen = ();
- $seen{''} = 1; # So that empty keys are skipped
- foreach my $e (@translated) {
- # To avoid double-counting due to recursion, skip a stack-trace
- # entry if it has already been seen
- if (!$seen{$e}) {
- $seen{$e} = 1;
- push(@path, $e);
- }
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- return $result;
-}
-
-# Does the specified symbol array match the regexp?
-sub SymbolMatches {
- my $sym = shift;
- my $re = shift;
- if (defined($sym)) {
- for (my $i = 0; $i < $#{$sym}; $i += 3) {
- if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-# Focus only on paths involving specified regexps
-sub FocusProfile {
- my $symbols = shift;
- my $profile = shift;
- my $focus = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
- AddEntry($result, $k, $count);
- last;
- }
- }
- }
- return $result;
-}
-
-# Focus only on paths not involving specified regexps
-sub IgnoreProfile {
- my $symbols = shift;
- my $profile = shift;
- my $ignore = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my $matched = 0;
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
- $matched = 1;
- last;
- }
- }
- if (!$matched) {
- AddEntry($result, $k, $count);
- }
- }
- return $result;
-}
-
-# Get total count in profile
-sub TotalProfile {
- my $profile = shift;
- my $result = 0;
- foreach my $k (keys(%{$profile})) {
- $result += $profile->{$k};
- }
- return $result;
-}
-
-# Add A to B
-sub AddProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k};
- AddEntry($R, $k, $v);
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- my $v = $B->{$k};
- AddEntry($R, $k, $v);
- }
- return $R;
-}
-
-# Merges symbol maps
-sub MergeSymbols {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- $R->{$k} = $A->{$k};
- }
- if (defined($B)) {
- foreach my $k (keys(%{$B})) {
- $R->{$k} = $B->{$k};
- }
- }
- return $R;
-}
-
-
-# Add A to B
-sub AddPcs {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- $R->{$k} = 1
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- $R->{$k} = 1
- }
- return $R;
-}
-
-# Subtract B from A
-sub SubtractProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k} - GetEntry($B, $k);
- if ($v < 0 && $main::opt_drop_negative) {
- $v = 0;
- }
- AddEntry($R, $k, $v);
- }
- if (!$main::opt_drop_negative) {
- # Take care of when subtracted profile has more entries
- foreach my $k (keys(%{$B})) {
- if (!exists($A->{$k})) {
- AddEntry($R, $k, 0 - $B->{$k});
- }
- }
- }
- return $R;
-}
-
-# Get entry from profile; zero if not present
-sub GetEntry {
- my $profile = shift;
- my $k = shift;
- if (exists($profile->{$k})) {
- return $profile->{$k};
- } else {
- return 0;
- }
-}
-
-# Add entry to specified profile
-sub AddEntry {
- my $profile = shift;
- my $k = shift;
- my $n = shift;
- if (!exists($profile->{$k})) {
- $profile->{$k} = 0;
- }
- $profile->{$k} += $n;
-}
-
-# Add a stack of entries to specified profile, and add them to the $pcs
-# list.
-sub AddEntries {
- my $profile = shift;
- my $pcs = shift;
- my $stack = shift;
- my $count = shift;
- my @k = ();
-
- foreach my $e (split(/\s+/, $stack)) {
- my $pc = HexExtend($e);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
- AddEntry($profile, (join "\n", @k), $count);
-}
-
-sub IsSymbolizedProfileFile {
- my $file_name = shift;
-
- if (!(-e $file_name) || !(-r $file_name)) {
- return 0;
- }
-
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- # Check if the file contains a symbol-section marker.
- open(TFILE, "<$file_name");
- my @lines = <TFILE>;
- my $result = grep(/^--- *$symbol_marker/, @lines);
- close(TFILE);
- return $result > 0;
-}
-
-##### Code to profile a server dynamically #####
-
-sub CheckSymbolPage {
- my $url = SymbolPageURL();
-print STDERR "Read $url\n";
- open(SYMBOL, "$CURL -s '$url' |");
- my $line = <SYMBOL>;
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(SYMBOL);
- unless (defined($line)) {
- error("$url doesn't exist\n");
- }
-
- if ($line =~ /^num_symbols:\s+(\d+)$/) {
- if ($1 == 0) {
- error("Stripped binary. No symbols available.\n");
- }
- } else {
- error("Failed to get the number of symbols from $url\n");
- }
-}
-
-sub IsProfileURL {
- my $profile_name = shift;
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- return defined($host) and defined($port) and defined($path);
-}
-
-sub ParseProfileURL {
- my $profile_name = shift;
- if (defined($profile_name) &&
- $profile_name =~ m,^(http://|)([^/:]+):(\d+)(|\@\d+)(|/|(.*?)($PROFILE_PAGE|$PMUPROFILE_PAGE|$HEAP_PAGE|$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|$FILTEREDPROFILE_PAGE))$,o) {
- # $7 is $PROFILE_PAGE/$HEAP_PAGE/etc. $5 is *everything* after
- # the hostname, as long as that everything is the empty string,
- # a slash, or something ending in $PROFILE_PAGE/$HEAP_PAGE/etc.
- # So "$7 || $5" is $PROFILE_PAGE/etc if there, or else it's "/" or "".
- return ($2, $3, $6, $7 || $5);
- }
- return ();
-}
-
-# We fetch symbols from the first profile argument.
-sub SymbolPageURL {
- my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
- return "http://$host:$port$prefix$SYMBOL_PAGE";
-}
-
-sub FetchProgramName() {
- my ($host, $port, $prefix, $path) = ParseProfileURL($main::pfile_args[0]);
- my $url = "http://$host:$port$prefix$PROGRAM_NAME_PAGE";
- my $command_line = "$CURL -s '$url'";
- open(CMDLINE, "$command_line |") or error($command_line);
- my $cmdline = <CMDLINE>;
- $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(CMDLINE);
- error("Failed to get program name from $url\n") unless defined($cmdline);
- $cmdline =~ s/\x00.+//; # Remove argv[1] and latters.
- $cmdline =~ s!\n!!g; # Remove LFs.
- return $cmdline;
-}
-
-# Gee, curl's -L (--location) option isn't reliable at least
-# with its 7.12.3 version. Curl will forget to post data if
-# there is a redirection. This function is a workaround for
-# curl. Redirection happens on borg hosts.
-sub ResolveRedirectionForCurl {
- my $url = shift;
- my $command_line = "$CURL -s --head '$url'";
- open(CMDLINE, "$command_line |") or error($command_line);
- while (<CMDLINE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^Location: (.*)/) {
- $url = $1;
- }
- }
- close(CMDLINE);
- return $url;
-}
-
-# Reads a symbol map from the file handle name given as $1, returning
-# the resulting symbol map. Also processes variables relating to symbols.
-# Currently, the only variable processed is 'binary=<value>' which updates
-# $main::prog to have the correct program name.
-sub ReadSymbols {
- my $in = shift;
- my $map = shift;
- while (<$in>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Removes all the leading zeroes from the symbols, see comment below.
- if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
- $map->{$1} = $2;
- } elsif (m/^---/) {
- last;
- } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1, $2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "binary") {
- if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) {
- printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n",
- $main::prog, $value);
- }
- $main::prog = $value;
- } else {
- printf STDERR ("Ignoring unknown variable in symbols list: " .
- "'%s' = '%s'\n", $variable, $value);
- }
- }
- }
- return $map;
-}
-
-# Fetches and processes symbols to prepare them for use in the profile output
-# code. If the optional 'symbol_map' arg is not given, fetches symbols from
-# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols
-# are assumed to have already been fetched into 'symbol_map' and are simply
-# extracted and processed.
-sub FetchSymbols {
- my $pcset = shift;
- my $symbol_map = shift;
-
- my %seen = ();
- my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
-
- if (!defined($symbol_map)) {
- $symbol_map = {};
- my @toask = @pcs;
- while (@toask > 0) {
- my $n = @toask;
- # NOTE(rsc): Limiting the number of PCs requested per round
- # used to be necessary, but I think it was a bug in
- # debug/pprof/symbol's implementation. Leaving here
- # in case I am wrong.
- # if ($n > 49) { $n = 49; }
- my @thisround = @toask[0..$n];
- @toask = @toask[($n+1)..(@toask-1)];
- my $post_data = join("+", sort((map {"0x" . "$_"} @thisround)));
- open(POSTFILE, ">$main::tmpfile_sym");
- print POSTFILE $post_data;
- close(POSTFILE);
-
- my $url = SymbolPageURL();
- $url = ResolveRedirectionForCurl($url);
- my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
- # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
- my $cppfilt = $obj_tool_map{"c++filt"};
- open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
- ReadSymbols(*SYMBOL{IO}, $symbol_map);
- close(SYMBOL);
- }
- }
-
- my $symbols = {};
- foreach my $pc (@pcs) {
- my $fullname;
- # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
- # Then /symbol reads the long symbols in as uint64, and outputs
- # the result with a "0x%08llx" format which get rid of the zeroes.
- # By removing all the leading zeroes in both $pc and the symbols from
- # /symbol, the symbols match and are retrievable from the map.
- my $shortpc = $pc;
- $shortpc =~ s/^0*//;
- # Each line may have a list of names, which includes the function
- # and also other functions it has inlined. They are separated
- # (in PrintSymbolizedFile), by --, which is illegal in function names.
- my $fullnames;
- if (defined($symbol_map->{$shortpc})) {
- $fullnames = $symbol_map->{$shortpc};
- } else {
- $fullnames = "0x" . $pc; # Just use addresses
- }
- my $sym = [];
- $symbols->{$pc} = $sym;
- foreach my $fullname (split("--", $fullnames)) {
- my $name = ShortFunctionName($fullname);
- push(@{$sym}, $name, "?", $fullname);
- }
- }
- return $symbols;
-}
-
-sub BaseName {
- my $file_name = shift;
- $file_name =~ s!^.*/!!; # Remove directory name
- return $file_name;
-}
-
-sub MakeProfileBaseName {
- my ($binary_name, $profile_name) = @_;
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- my $binary_shortname = BaseName($binary_name);
- return sprintf("%s.%s.%s-port%s",
- $binary_shortname, $main::op_time, $host, $port);
-}
-
-sub FetchDynamicProfile {
- my $binary_name = shift;
- my $profile_name = shift;
- my $fetch_name_only = shift;
- my $encourage_patience = shift;
-
- if (!IsProfileURL($profile_name)) {
- return $profile_name;
- } else {
- my ($host, $port, $prefix, $path) = ParseProfileURL($profile_name);
- if ($path eq "" || $path eq "/") {
- # Missing type specifier defaults to cpu-profile
- $path = $PROFILE_PAGE;
- }
-
- my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
-
- my $url;
- my $curl_timeout;
- if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)) {
- if ($path =~ m/$PROFILE_PAGE/) {
- $url = sprintf("http://$host:$port$prefix$path?seconds=%d",
- $main::opt_seconds);
- } else {
- if ($profile_name =~ m/[?]/) {
- $profile_name .= "&"
- } else {
- $profile_name .= "?"
- }
- $url = sprintf("http://$profile_name" . "seconds=%d",
- $main::opt_seconds);
- }
- $curl_timeout = sprintf("--max-time %d",
- int($main::opt_seconds * 1.01 + 60));
- } else {
- # For non-CPU profiles, we add a type-extension to
- # the target profile file name.
- my $suffix = $path;
- $suffix =~ s,/,.,g;
- $profile_file .= "$suffix";
- $url = "http://$host:$port$prefix$path";
- $curl_timeout = "";
- }
-
- my $profile_dir = $ENV{"PPROF_TMPDIR"} || ($ENV{HOME} . "/pprof");
- if (!(-d $profile_dir)) {
- mkdir($profile_dir)
- || die("Unable to create profile directory $profile_dir: $!\n");
- }
- my $tmp_profile = "$profile_dir/.tmp.$profile_file";
- my $real_profile = "$profile_dir/$profile_file";
-
- if ($fetch_name_only > 0) {
- return $real_profile;
- }
-
- my $cmd = "$CURL $curl_timeout -s -o $tmp_profile '$url'";
- if (($path =~ m/$PROFILE_PAGE/) || ($path =~ m/$PMUPROFILE_PAGE/)){
- print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
- if ($encourage_patience) {
- print STDERR "Be patient...\n";
- }
- } else {
- print STDERR "Fetching $path profile from $host:$port to\n ${real_profile}\n";
- }
-
- (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
- (system("mv $tmp_profile $real_profile") == 0) || error("Unable to rename profile\n");
- print STDERR "Wrote profile to $real_profile\n";
- $main::collected_profile = $real_profile;
- return $main::collected_profile;
- }
-}
-
-# Collect profiles in parallel
-sub FetchDynamicProfiles {
- my $items = scalar(@main::pfile_args);
- my $levels = log($items) / log(2);
-
- if ($items == 1) {
- $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1);
- } else {
- # math rounding issues
- if ((2 ** $levels) < $items) {
- $levels++;
- }
- my $count = scalar(@main::pfile_args);
- for (my $i = 0; $i < $count; $i++) {
- $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0);
- }
- print STDERR "Fetching $count profiles, Be patient...\n";
- FetchDynamicProfilesRecurse($levels, 0, 0);
- $main::collected_profile = join(" \\\n ", @main::profile_files);
- }
-}
-
-# Recursively fork a process to get enough processes
-# collecting profiles
-sub FetchDynamicProfilesRecurse {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if (my $pid = fork()) {
- $position = 0 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- wait;
- } else {
- $position = 1 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- exit(0);
- }
-}
-
-# Collect a single profile
-sub TryCollectProfile {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if ($level >= ($maxlevel - 1)) {
- if ($position < scalar(@main::pfile_args)) {
- FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0);
- }
- } else {
- FetchDynamicProfilesRecurse($maxlevel, $level+1, $position);
- }
-}
-
-##### Parsing code #####
-
-# Provide a small streaming-read module to handle very large
-# cpu-profile files. Stream in chunks along a sliding window.
-# Provides an interface to get one 'slot', correctly handling
-# endian-ness differences. A slot is one 32-bit or 64-bit word
-# (depending on the input profile). We tell endianness and bit-size
-# for the profile by looking at the first 8 bytes: in cpu profiles,
-# the second slot is always 3 (we'll accept anything that's not 0).
-BEGIN {
- package CpuProfileStream;
-
- sub new {
- my ($class, $file, $fname) = @_;
- my $self = { file => $file,
- base => 0,
- stride => 512 * 1024, # must be a multiple of bitsize/8
- slots => [],
- unpack_code => "", # N for big-endian, V for little
- };
- bless $self, $class;
- # Let unittests adjust the stride
- if ($main::opt_test_stride > 0) {
- $self->{stride} = $main::opt_test_stride;
- }
- # Read the first two slots to figure out bitsize and endianness.
- my $slots = $self->{slots};
- my $str;
- read($self->{file}, $str, 8);
- # Set the global $address_length based on what we see here.
- # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
- $address_length = ($str eq (chr(0)x8)) ? 16 : 8;
- if ($address_length == 8) {
- if (substr($str, 6, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 4, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**16\n");
- }
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # If we're a 64-bit profile, make sure we're a 64-bit-capable
- # perl. Otherwise, each slot will be represented as a float
- # instead of an int64, losing precision and making all the
- # 64-bit addresses right. We *could* try to handle this with
- # software emulation of 64-bit ints, but that's added complexity
- # for no clear benefit (yet). We use 'Q' to test for 64-bit-ness;
- # perl docs say it's only available on 64-bit perl systems.
- my $has_q = 0;
- eval { $has_q = pack("Q", "1") ? 1 : 1; };
- if (!$has_q) {
- ::error("$fname: need a 64-bit perl to process this 64-bit profile.\n");
- }
- read($self->{file}, $str, 8);
- if (substr($str, 4, 4) eq chr(0)x4) {
- # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 0, 4) eq chr(0)x4) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**32\n");
- }
- my @pair = unpack($self->{unpack_code} . "*", $str);
- # Since we know one of the pair is 0, it's fine to just add them.
- @$slots = (0, $pair[0] + $pair[1]);
- }
- return $self;
- }
-
- # Load more data when we access slots->get(X) which is not yet in memory.
- sub overflow {
- my ($self) = @_;
- my $slots = $self->{slots};
- $self->{base} += $#$slots + 1; # skip over data we're replacing
- my $str;
- read($self->{file}, $str, $self->{stride});
- if ($address_length == 8) { # the 32-bit case
- # This is the easy case: unpack provides 32-bit unpacking primitives.
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # We need to unpack 32 bits at a time and combine.
- my @b32_values = unpack($self->{unpack_code} . "*", $str);
- my @b64_values = ();
- for (my $i = 0; $i < $#b32_values; $i += 2) {
- # TODO(csilvers): if this is a 32-bit perl, the math below
- # could end up in a too-large int, which perl will promote
- # to a double, losing necessary precision. Deal with that.
- if ($self->{unpack_code} eq 'V') { # little-endian
- push(@b64_values, $b32_values[$i] + $b32_values[$i+1] * (2**32));
- } else {
- push(@b64_values, $b32_values[$i] * (2**32) + $b32_values[$i+1]);
- }
- }
- @$slots = @b64_values;
- }
- }
-
- # Access the i-th long in the file (logically), or -1 at EOF.
- sub get {
- my ($self, $idx) = @_;
- my $slots = $self->{slots};
- while ($#$slots >= 0) {
- if ($idx < $self->{base}) {
- # The only time we expect a reference to $slots[$i - something]
- # after referencing $slots[$i] is reading the very first header.
- # Since $stride > |header|, that shouldn't cause any lookback
- # errors. And everything after the header is sequential.
- print STDERR "Unexpected look-back reading CPU profile";
- return -1; # shrug, don't know what better to return
- } elsif ($idx > $self->{base} + $#$slots) {
- $self->overflow();
- } else {
- return $slots->[$idx - $self->{base}];
- }
- }
- # If we get here, $slots is [], which means we've reached EOF
- return -1; # unique since slots is supposed to hold unsigned numbers
- }
-}
-
-# Parse profile generated by common/profiler.cc and return a reference
-# to a map:
-# $result->{version} Version number of profile file
-# $result->{period} Sampling period (in microseconds)
-# $result->{profile} Profile object
-# $result->{map} Memory map info from profile
-# $result->{pcs} Hash of all PC values seen, key is hex address
-sub ReadProfile {
- my $prog = shift;
- my $fname = shift;
-
- if (IsSymbolizedProfileFile($fname) && !$main::use_symbolized_profile) {
- # we have both a binary and symbolized profiles, abort
- usage("Symbolized profile '$fname' cannot be used with a binary arg. " .
- "Try again without passing '$prog'.");
- }
-
- $main::profile_type = '';
-
- $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $contention_marker = $&;
- $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $growth_marker = $&;
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $profile_marker = $&;
-
- # Look at first line to see if it is a heap or a CPU profile.
- # CPU profile may start with no header at all, and just binary data
- # (starting with \0\0\0\0) -- in that case, don't try to read the
- # whole firstline, since it may be gigabytes(!) of data.
- open(PROFILE, "<$fname") || error("$fname: $!\n");
- binmode PROFILE; # New perls do UTF-8 processing
- my $firstchar = "";
- my $header = "";
- read(PROFILE, $firstchar, 1);
- seek(PROFILE, -1, 1); # unread the firstchar
- if ($firstchar ne "\0") {
- $header = <PROFILE>;
- if (!defined($header)) {
- error("Profile is empty.\n");
- }
- $header =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- }
-
- my $symbols;
- if ($header =~ m/^--- *$symbol_marker/o) {
- # read the symbol section of the symbolized profile file
- $symbols = ReadSymbols(*PROFILE{IO});
-
- # read the next line to get the header for the remaining profile
- $header = "";
- read(PROFILE, $firstchar, 1);
- seek(PROFILE, -1, 1); # unread the firstchar
- if ($firstchar ne "\0") {
- $header = <PROFILE>;
- $header =~ s/\r//g;
- }
- }
-
- my $result;
-
- if ($header =~ m/^heap profile:.*$growth_marker/o) {
- $main::profile_type = 'growth';
- $result = ReadHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^heap profile:/) {
- $main::profile_type = 'heap';
- $result = ReadHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^--- *$contention_marker/o) {
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, $fname);
- } elsif ($header =~ m/^--- *Stacks:/) {
- print STDERR
- "Old format contention profile: mistakenly reports " .
- "condition variable signals as lock contentions.\n";
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, $fname);
- } elsif ($header =~ m/^--- *$profile_marker/) {
- # the binary cpu profile data starts immediately after this line
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname);
- } else {
- if (defined($symbols)) {
- # a symbolized profile contains a format we don't recognize, bail out
- error("$fname: Cannot recognize profile section after symbols.\n");
- }
- # no ascii header present -- must be a CPU profile
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname);
- }
-
- # if we got symbols along with the profile, return those as well
- if (defined($symbols)) {
- $result->{symbols} = $symbols;
- }
-
- return $result;
-}
-
-# Subtract one from caller pc so we map back to call instr.
-# However, don't do this if we're reading a symbolized profile
-# file, in which case the subtract-one was done when the file
-# was written.
-#
-# We apply the same logic to all readers, though ReadCPUProfile uses an
-# independent implementation.
-sub FixCallerAddresses {
- my $stack = shift;
- if ($main::use_symbolized_profile) {
- return $stack;
- } else {
- $stack =~ /(\s)/;
- my $delimiter = $1;
- my @addrs = split(' ', $stack);
- my @fixedaddrs;
- $#fixedaddrs = $#addrs;
- if ($#addrs >= 0) {
- $fixedaddrs[0] = $addrs[0];
- }
- for (my $i = 1; $i <= $#addrs; $i++) {
- $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1");
- }
- return join $delimiter, @fixedaddrs;
- }
-}
-
-# CPU profile reader
-sub ReadCPUProfile {
- my $prog = shift;
- my $fname = shift;
- my $version;
- my $period;
- my $i;
- my $profile = {};
- my $pcs = {};
-
- # Parse string into array of slots.
- my $slots = CpuProfileStream->new(*PROFILE, $fname);
-
- # Read header. The current header version is a 5-element structure
- # containing:
- # 0: header count (always 0)
- # 1: header "words" (after this one: 3)
- # 2: format version (0)
- # 3: sampling period (usec)
- # 4: unused padding (always 0)
- if ($slots->get(0) != 0 ) {
- error("$fname: not a profile file, or old format profile file\n");
- }
- $i = 2 + $slots->get(1);
- $version = $slots->get(2);
- $period = $slots->get(3);
- # Do some sanity checking on these header values.
- if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) {
- error("$fname: not a profile file, or corrupted profile file\n");
- }
-
- # Parse profile
- while ($slots->get($i) != -1) {
- my $n = $slots->get($i++);
- my $d = $slots->get($i++);
- if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth?
- my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8));
- print STDERR "At index $i (address $addr):\n";
- error("$fname: stack trace depth >= 2**32\n");
- }
- if ($slots->get($i) == 0) {
- # End of profile data marker
- $i += $d;
- last;
- }
-
- # Make key out of the stack entries
- my @k = ();
- for (my $j = 0; $j < $d; $j++) {
- my $pc = $slots->get($i+$j);
- # Subtract one from caller pc so we map back to call instr.
- # However, don't do this if we're reading a symbolized profile
- # file, in which case the subtract-one was done when the file
- # was written.
- if ($j > 0 && !$main::use_symbolized_profile) {
- $pc--;
- }
- $pc = sprintf("%0*x", $address_length, $pc);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
-
- AddEntry($profile, (join "\n", @k), $n);
- $i += $d;
- }
-
- # Parse map
- my $map = '';
- seek(PROFILE, $i * 4, 0);
- read(PROFILE, $map, (stat PROFILE)[7]);
- close(PROFILE);
-
- my $r = {};
- $r->{version} = $version;
- $r->{period} = $period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
-
- return $r;
-}
-
-sub ReadHeapProfile {
- my $prog = shift;
- my $fname = shift;
- my $header = shift;
-
- my $index = 1;
- if ($main::opt_inuse_space) {
- $index = 1;
- } elsif ($main::opt_inuse_objects) {
- $index = 0;
- } elsif ($main::opt_alloc_space) {
- $index = 3;
- } elsif ($main::opt_alloc_objects) {
- $index = 2;
- }
-
- # Find the type of this profile. The header line looks like:
- # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
- # There are two pairs <count: size>, the first inuse objects/space, and the
- # second allocated objects/space. This is followed optionally by a profile
- # type, and if that is present, optionally by a sampling frequency.
- # For remote heap profiles (v1):
- # The interpretation of the sampling frequency is that the profiler, for
- # each sample, calculates a uniformly distributed random integer less than
- # the given value, and records the next sample after that many bytes have
- # been allocated. Therefore, the expected sample interval is half of the
- # given frequency. By default, if not specified, the expected sample
- # interval is 128KB. Only remote-heap-page profiles are adjusted for
- # sample size.
- # For remote heap profiles (v2):
- # The sampling frequency is the rate of a Poisson process. This means that
- # the probability of sampling an allocation of size X with sampling rate Y
- # is 1 - exp(-X/Y)
- # For version 2, a typical header line might look like this:
- # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
- # the trailing number (524288) is the sampling rate. (Version 1 showed
- # double the 'rate' here)
- my $sampling_algorithm = 0;
- my $sample_adjustment = 0;
- chomp($header);
- my $type = "unknown";
- if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
- if (defined($6) && ($6 ne '')) {
- $type = $6;
- my $sample_period = $8;
- # $type is "heapprofile" for profiles generated by the
- # heap-profiler, and either "heap" or "heap_v2" for profiles
- # generated by sampling directly within tcmalloc. It can also
- # be "growth" for heap-growth profiles. The first is typically
- # found for profiles generated locally, and the others for
- # remote profiles.
- if (($type eq "heapprofile") || ($type !~ /heap/) ) {
- # No need to adjust for the sampling rate with heap-profiler-derived data
- $sampling_algorithm = 0;
- } elsif ($type =~ /_v2/) {
- $sampling_algorithm = 2; # version 2 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period);
- }
- } else {
- $sampling_algorithm = 1; # version 1 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period)/2;
- }
- }
- } else {
- # We detect whether or not this is a remote-heap profile by checking
- # that the total-allocated stats ($n2,$s2) are exactly the
- # same as the in-use stats ($n1,$s1). It is remotely conceivable
- # that a non-remote-heap profile may pass this check, but it is hard
- # to imagine how that could happen.
- # In this case it's so old it's guaranteed to be remote-heap version 1.
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
- if (($n1 == $n2) && ($s1 == $s2)) {
- # This is likely to be a remote-heap based sample profile
- $sampling_algorithm = 1;
- }
- }
- }
-
- if ($sampling_algorithm > 0) {
- # For remote-heap generated profiles, adjust the counts and sizes to
- # account for the sample rate (we sample once every 128KB by default).
- if ($sample_adjustment == 0) {
- # Turn on profile adjustment.
- $sample_adjustment = 128*1024;
- print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
- } else {
- printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
- $sample_adjustment);
- }
- if ($sampling_algorithm > 1) {
- # We don't bother printing anything for the original version (version 1)
- printf STDERR "Heap version $sampling_algorithm\n";
- }
- }
-
- my $profile = {};
- my $pcs = {};
- my $map = "";
-
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^MAPPED_LIBRARIES:/) {
- # Read the /proc/self/maps data
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $map .= $_;
- }
- last;
- }
-
- if (/^--- Memory map:/) {
- # Read /proc/self/maps data as formatted by DumpAddressMap()
- my $buildvar = "";
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Parse "build=<dir>" specification if supplied
- if (m/^\s*build=(.*)\n/) {
- $buildvar = $1;
- }
-
- # Expand "$build" variable if available
- $_ =~ s/\$build\b/$buildvar/g;
-
- $map .= $_;
- }
- last;
- }
-
- # Read entry of the form:
- # <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an
- s/^\s*//;
- s/\s*$//;
- if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) {
- my $stack = $5;
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
-
- if ($sample_adjustment) {
- if ($sampling_algorithm == 2) {
- # Remote-heap version 2
- # The sampling frequency is the rate of a Poisson process.
- # This means that the probability of sampling an allocation of
- # size X with sampling rate Y is 1 - exp(-X/Y)
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- my $scale_factor;
- $scale_factor = 1/(1 - exp(-$ratio));
- $n1 *= $scale_factor;
- $s1 *= $scale_factor;
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- $scale_factor = 1/(1 - exp(-$ratio));
- $n2 *= $scale_factor;
- $s2 *= $scale_factor;
- } else {
- # Remote-heap version 1
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- if ($ratio < 1) {
- $n1 /= $ratio;
- $s1 /= $ratio;
- }
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- if ($ratio < 1) {
- $n2 /= $ratio;
- $s2 /= $ratio;
- }
- }
- }
-
- my @counts = ($n1, $s1, $n2, $s2);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
- }
- }
-
- my $r = {};
- $r->{version} = "heap";
- $r->{period} = 1;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-sub ReadSynchProfile {
- my ($prog, $fname, $header) = @_;
-
- my $map = '';
- my $profile = {};
- my $pcs = {};
- my $sampling_period = 1;
- my $cyclespernanosec = 2.8; # Default assumption for old binaries
- my $seen_clockrate = 0;
- my $line;
-
- my $index = 0;
- if ($main::opt_total_delay) {
- $index = 0;
- } elsif ($main::opt_contentions) {
- $index = 1;
- } elsif ($main::opt_mean_delay) {
- $index = 2;
- }
-
- while ( $line = <PROFILE> ) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $count, $stack) = ($1, $2, $3);
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
- $count *= $sampling_period;
-
- my @values = ($cycles, $count, $cycles / $count);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]);
-
- } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ ||
- $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $stack) = ($1, $2);
- if ($cycles !~ /^\d+$/) {
- next;
- }
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
-
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles);
-
- } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1,$2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "cycles/second") {
- $cyclespernanosec = $value / 1e9;
- $seen_clockrate = 1;
- } elsif ($variable eq "sampling period") {
- $sampling_period = $value;
- } elsif ($variable eq "ms since reset") {
- # Currently nothing is done with this value in pprof
- # So we just silently ignore it for now
- } elsif ($variable eq "discarded samples") {
- # Currently nothing is done with this value in pprof
- # So we just silently ignore it for now
- } else {
- printf STDERR ("Ignoring unnknown variable in /contention output: " .
- "'%s' = '%s'\n",$variable,$value);
- }
- } else {
- # Memory map entry
- $map .= $line;
- }
- }
- close PROFILE;
-
- if (!$seen_clockrate) {
- printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
- $cyclespernanosec);
- }
-
- my $r = {};
- $r->{version} = 0;
- $r->{period} = $sampling_period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-# Given a hex value in the form "0x1abcd" return "0001abcd" or
-# "000000000001abcd", depending on the current address length.
-# There's probably a more idiomatic (or faster) way to do this...
-sub HexExtend {
- my $addr = shift;
-
- $addr =~ s/^0x//;
-
- if (length $addr > $address_length) {
- printf STDERR "Warning: address $addr is longer than address length $address_length\n";
- }
-
- return substr("000000000000000".$addr, -$address_length);
-}
-
-##### Symbol extraction #####
-
-# Aggressively search the lib_prefix values for the given library
-# If all else fails, just return the name of the library unmodified.
-# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so"
-# it will search the following locations in this order, until it finds a file:
-# /my/path/lib/dir/mylib.so
-# /other/path/lib/dir/mylib.so
-# /my/path/dir/mylib.so
-# /other/path/dir/mylib.so
-# /my/path/mylib.so
-# /other/path/mylib.so
-# /lib/dir/mylib.so (returned as last resort)
-sub FindLibrary {
- my $file = shift;
- my $suffix = $file;
-
- # Search for the library as described above
- do {
- foreach my $prefix (@prefix_list) {
- my $fullpath = $prefix . $suffix;
- if (-e $fullpath) {
- return $fullpath;
- }
- }
- } while ($suffix =~ s|^/[^/]+/|/|);
- return $file;
-}
-
-# Return path to library with debugging symbols.
-# For libc libraries, the copy in /usr/lib/debug contains debugging symbols
-sub DebuggingLibrary {
- my $file = shift;
- if ($file =~ m|^/| && -f "/usr/lib/debug$file") {
- return "/usr/lib/debug$file";
- }
- return undef;
-}
-
-# Parse text section header of a library using objdump
-sub ParseTextSectionHeaderFromObjdump {
- my $lib = shift;
-
- my $size = undef;
- my $vma;
- my $file_offset;
- # Get objdump output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $objdump = $obj_tool_map{"objdump"};
- open(OBJDUMP, "$objdump -h $lib |")
- || error("$objdump $lib: $!\n");
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Idx Name Size VMA LMA File off Algn
- # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4
- # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
- # offset may still be 8. But AddressSub below will still handle that.
- my @x = split;
- if (($#x >= 6) && ($x[1] eq '.text')) {
- $size = $x[2];
- $vma = $x[3];
- $file_offset = $x[5];
- last;
- }
- }
- close(OBJDUMP);
-
- if (!defined($size)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-# Parse text section header of a library using otool (on OS X)
-sub ParseTextSectionHeaderFromOtool {
- my $lib = shift;
-
- my $size = undef;
- my $vma = undef;
- my $file_offset = undef;
- # Get otool output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $otool = $obj_tool_map{"otool"};
- open(OTOOL, "$otool -l $lib |")
- || error("$otool $lib: $!\n");
- my $cmd = "";
- my $sectname = "";
- my $segname = "";
- foreach my $line (<OTOOL>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- # Load command <#>
- # cmd LC_SEGMENT
- # [...]
- # Section
- # sectname __text
- # segname __TEXT
- # addr 0x000009f8
- # size 0x00018b9e
- # offset 2552
- # align 2^2 (4)
- # We will need to strip off the leading 0x from the hex addresses,
- # and convert the offset into hex.
- if ($line =~ /Load command/) {
- $cmd = "";
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /Section/) {
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /cmd (\w+)/) {
- $cmd = $1;
- } elsif ($line =~ /sectname (\w+)/) {
- $sectname = $1;
- } elsif ($line =~ /segname (\w+)/) {
- $segname = $1;
- } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
- $sectname eq "__text" &&
- $segname eq "__TEXT")) {
- next;
- } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
- $vma = $1;
- } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
- $size = $1;
- } elsif ($line =~ /\boffset ([0-9]+)/) {
- $file_offset = sprintf("%016x", $1);
- }
- if (defined($vma) && defined($size) && defined($file_offset)) {
- last;
- }
- }
- close(OTOOL);
-
- if (!defined($vma) || !defined($size) || !defined($file_offset)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-sub ParseTextSectionHeader {
- # obj_tool_map("otool") is only defined if we're in a Mach-O environment
- if (defined($obj_tool_map{"otool"})) {
- my $r = ParseTextSectionHeaderFromOtool(@_);
- if (defined($r)){
- return $r;
- }
- }
- # If otool doesn't work, or we don't have it, fall back to objdump
- return ParseTextSectionHeaderFromObjdump(@_);
-}
-
-# Split /proc/pid/maps dump into a list of libraries
-sub ParseLibraries {
- return if $main::use_symbol_page; # We don't need libraries info.
- my $prog = shift;
- my $map = shift;
- my $pcs = shift;
-
- my $result = [];
- my $h = "[a-f0-9]+";
- my $zero_offset = HexExtend("0");
-
- my $buildvar = "";
- foreach my $l (split("\n", $map)) {
- if ($l =~ m/^\s*build=(.*)$/) {
- $buildvar = $1;
- }
-
- my $start;
- my $finish;
- my $offset;
- my $lib;
- if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) {
- # Full line from /proc/self/maps. Example:
- # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = HexExtend($3);
- $lib = $4;
- $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
- } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
- # Cooked line from DumpAddressMap. Example:
- # 40000000-40015000: /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = $zero_offset;
- $lib = $3;
- } else {
- next;
- }
-
- # Expand "$build" variable if available
- $lib =~ s/\$build\b/$buildvar/g;
-
- $lib = FindLibrary($lib);
-
- # Check for pre-relocated libraries, which use pre-relocated symbol tables
- # and thus require adjusting the offset that we'll use to translate
- # VM addresses into symbol table addresses.
- # Only do this if we're not going to fetch the symbol table from a
- # debugging copy of the library.
- if (!DebuggingLibrary($lib)) {
- my $text = ParseTextSectionHeader($lib);
- if (defined($text)) {
- my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
- $offset = AddressAdd($offset, $vma_offset);
- }
- }
-
- push(@{$result}, [$lib, $start, $finish, $offset]);
- }
-
- # Append special entry for additional library (not relocated)
- if ($main::opt_lib ne "") {
- my $text = ParseTextSectionHeader($main::opt_lib);
- if (defined($text)) {
- my $start = $text->{vma};
- my $finish = AddressAdd($start, $text->{size});
-
- push(@{$result}, [$main::opt_lib, $start, $finish, $start]);
- }
- }
-
- # Append special entry for the main program. This covers
- # 0..max_pc_value_seen, so that we assume pc values not found in one
- # of the library ranges will be treated as coming from the main
- # program binary.
- my $min_pc = HexExtend("0");
- my $max_pc = $min_pc; # find the maximal PC value in any sample
- foreach my $pc (keys(%{$pcs})) {
- if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); }
- }
- push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]);
-
- return $result;
-}
-
-# Add two hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressAdd {
- my $addr1 = shift;
- my $addr2 = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
-
- if ($main::opt_debug and $main::opt_test) {
- print STDERR "AddressAdd $addr1 + $addr2 = ";
- }
-
- my $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- my $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2);
- my $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- my $r = sprintf("%07x", $sum);
-
- $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2) + $c;
- $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- $r = sprintf("%07x", $sum) . $r;
-
- $sum = hex($addr1) + hex($addr2) + $c;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-
-# Subtract two hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressSub {
- my $addr1 = shift;
- my $addr2 = shift;
- my $diff;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $diff);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize borrow handling.
- # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
-
- my $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- my $a2 = hex(substr($addr2,-7));
- $addr2 = substr($addr2,0,-7);
- my $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- my $r = sprintf("%07x", $diff);
-
- $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- $a2 = hex(substr($addr2,-7)) + $b;
- $addr2 = substr($addr2,0,-7);
- $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- $r = sprintf("%07x", $diff) . $r;
-
- $a1 = hex($addr1);
- $a2 = hex($addr2) + $b;
- if ($a2 > $a1) { $a1 += 0x100; }
- $diff = $a1 - $a2;
- $r = sprintf("%02x", $diff) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-# Increment a hex addresses of length $address_length.
-# Run pprof --test for unit test if this is changed.
-sub AddressInc {
- my $addr = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr)+1) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
- # We are always doing this to step through the addresses in a function,
- # and will almost never overflow the first chunk, so we check for this
- # case and exit early.
-
- # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; }
-
- my $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- my $r = sprintf("%07x", $sum);
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "0000000";
- }
-
- $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- $r = sprintf("%07x", $sum) . $r;
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "00000000000000";
- }
-
- $sum = hex($addr) + 1;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return $r;
- }
-}
-
-# Extract symbols for all PC values found in profile
-sub ExtractSymbols {
- my $libs = shift;
- my $pcset = shift;
-
- my $symbols = {};
-
- # Map each PC value to the containing library
- my %seen = ();
- foreach my $lib (@{$libs}) {
- my $libname = $lib->[0];
- my $start = $lib->[1];
- my $finish = $lib->[2];
- my $offset = $lib->[3];
-
- # Get list of pcs that belong in this library.
- my $contained = [];
- foreach my $pc (keys(%{$pcset})) {
- if (!$seen{$pc} && ($pc ge $start) && ($pc le $finish)) {
- $seen{$pc} = 1;
- push(@{$contained}, $pc);
- }
- }
- # Map to symbols
- MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
- }
-
- return $symbols;
-}
-
-# Map list of PC values to symbols for a given image
-sub MapToSymbols {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- my $debug = 0;
-
- # Ignore empty binaries
- if ($#{$pclist} < 0) { return; }
-
- # Figure out the addr2line command to use
- my $addr2line = $obj_tool_map{"addr2line"};
- my $cmd = "$addr2line -f -C -e $image";
- if (exists $obj_tool_map{"addr2line_pdb"}) {
- $addr2line = $obj_tool_map{"addr2line_pdb"};
- $cmd = "$addr2line --demangle -f -C -e $image";
- }
-
- # If "addr2line" isn't installed on the system at all, just use
- # nm to get what info we can (function names, but not line numbers).
- if (system("$addr2line --help >/dev/null 2>&1") != 0) {
- MapSymbolsWithNM($image, $offset, $pclist, $symbols);
- return;
- }
-
- # "addr2line -i" can produce a variable number of lines per input
- # address, with no separator that allows us to tell when data for
- # the next address starts. So we find the address for a special
- # symbol (_fini) and interleave this address between all real
- # addresses passed to addr2line. The name of this special symbol
- # can then be used as a separator.
- $sep_address = undef; # May be filled in by MapSymbolsWithNM()
- my $nm_symbols = {};
- MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
- # TODO(csilvers): only add '-i' if addr2line supports it.
- if (defined($sep_address)) {
- # Only add " -i" to addr2line if the binary supports it.
- # addr2line --help returns 0, but not if it sees an unknown flag first.
- if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
- $cmd .= " -i";
- } else {
- $sep_address = undef; # no need for sep_address if we don't support -i
- }
- }
-
- # Make file with all PC values with intervening 'sep_address' so
- # that we can reliably detect the end of inlined function list
- open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
- if ($debug) { print("---- $image ---\n"); }
- for (my $i = 0; $i <= $#{$pclist}; $i++) {
- # addr2line always reads hex addresses, and does not need '0x' prefix.
- if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
- printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
- if (defined($sep_address)) {
- printf ADDRESSES ("%s\n", $sep_address);
- }
- }
- close(ADDRESSES);
- if ($debug) {
- print("----\n");
- system("cat $main::tmpfile_sym");
- print("----\n");
- system("$cmd <$main::tmpfile_sym");
- print("----\n");
- }
-
- open(SYMBOLS, "$cmd <$main::tmpfile_sym |") || error("$cmd: $!\n");
- my $count = 0; # Index in pclist
- while (<SYMBOLS>) {
- # Read fullfunction and filelineinfo from next pair of lines
- s/\r?\n$//g;
- my $fullfunction = $_;
- $_ = <SYMBOLS>;
- s/\r?\n$//g;
- my $filelinenum = $_;
-
- if (defined($sep_address) && $fullfunction eq $sep_symbol) {
- # Terminating marker for data for this address
- $count++;
- next;
- }
-
- $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
-
- my $pcstr = $pclist->[$count];
- my $function = ShortFunctionName($fullfunction);
- if ($fullfunction eq '??') {
- # See if nm found a symbol
- my $nms = $nm_symbols->{$pcstr};
- if (defined($nms)) {
- $function = $nms->[0];
- $fullfunction = $nms->[2];
- }
- }
-
- # Prepend to accumulated symbols for pcstr
- # (so that caller comes before callee)
- my $sym = $symbols->{$pcstr};
- if (!defined($sym)) {
- $sym = [];
- $symbols->{$pcstr} = $sym;
- }
- unshift(@{$sym}, $function, $filelinenum, $fullfunction);
- if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
- if (!defined($sep_address)) {
- # Inlining is off, se this entry ends immediately
- $count++;
- }
- }
- close(SYMBOLS);
-}
-
-# Use nm to map the list of referenced PCs to symbols. Return true iff we
-# are able to read procedure information via nm.
-sub MapSymbolsWithNM {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- # Get nm output sorted by increasing address
- my $symbol_table = GetProcedureBoundaries($image, ".");
- if (!%{$symbol_table}) {
- return 0;
- }
- # Start addresses are already the right length (8 or 16 hex digits).
- my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
- keys(%{$symbol_table});
-
- if ($#names < 0) {
- # No symbols: just use addresses
- foreach my $pc (@{$pclist}) {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- return 0;
- }
-
- # Sort addresses so we can do a join against nm output
- my $index = 0;
- my $fullname = $names[0];
- my $name = ShortFunctionName($fullname);
- foreach my $pc (sort { $a cmp $b } @{$pclist}) {
- # Adjust for mapped offset
- my $mpc = AddressSub($pc, $offset);
- while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
- $index++;
- $fullname = $names[$index];
- $name = ShortFunctionName($fullname);
- }
- if ($mpc lt $symbol_table->{$fullname}->[1]) {
- $symbols->{$pc} = [$name, "?", $fullname];
- } else {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- }
- return 1;
-}
-
-sub ShortFunctionName {
- my $function = shift;
- while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
- while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments
- $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type
- return $function;
-}
-
-# Trim overly long symbols found in disassembler output
-sub CleanDisassembly {
- my $d = shift;
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
- return $d;
-}
-
-##### Miscellaneous #####
-
-# Find the right versions of the above object tools to use. The
-# argument is the program file being analyzed, and should be an ELF
-# 32-bit or ELF 64-bit executable file. The location of the tools
-# is determined by considering the following options in this order:
-# 1) --tools option, if set
-# 2) PPROF_TOOLS environment variable, if set
-# 3) the environment
-sub ConfigureObjTools {
- my $prog_file = shift;
-
- # Check for the existence of $prog_file because /usr/bin/file does not
- # predictably return error status in prod.
- (-e $prog_file) || error("$prog_file does not exist.\n");
-
- # Follow symlinks (at least for systems where "file" supports that)
- my $file_type = `/usr/bin/file -L $prog_file 2>/dev/null || /usr/bin/file $prog_file`;
- if ($file_type =~ /64-bit/) {
- # Change $address_length to 16 if the program file is ELF 64-bit.
- # We can't detect this from many (most?) heap or lock contention
- # profiles, since the actual addresses referenced are generally in low
- # memory even for 64-bit programs.
- $address_length = 16;
- }
-
- if ($file_type =~ /MS Windows/) {
- # For windows, we provide a version of nm and addr2line as part of
- # the opensource release, which is capable of parsing
- # Windows-style PDB executables. It should live in the path, or
- # in the same directory as pprof.
- $obj_tool_map{"nm_pdb"} = "nm-pdb";
- $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
- }
-
- if ($file_type =~ /Mach-O/) {
- # OS X uses otool to examine Mach-O files, rather than objdump.
- $obj_tool_map{"otool"} = "otool";
- $obj_tool_map{"addr2line"} = "false"; # no addr2line
- $obj_tool_map{"objdump"} = "false"; # no objdump
- }
-
- # Go fill in %obj_tool_map with the pathnames to use:
- foreach my $tool (keys %obj_tool_map) {
- $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool});
- }
-}
-
-# Returns the path of a caller-specified object tool. If --tools or
-# PPROF_TOOLS are specified, then returns the full path to the tool
-# with that prefix. Otherwise, returns the path unmodified (which
-# means we will look for it on PATH).
-sub ConfigureTool {
- my $tool = shift;
- my $path;
-
- if ($main::opt_tools ne "") {
- # Use a prefix specified by the --tools option...
- $path = $main::opt_tools . $tool;
- if (!-x $path) {
- error("No '$tool' found with prefix specified by --tools $main::opt_tools\n");
- }
- } elsif (exists $ENV{"PPROF_TOOLS"} &&
- $ENV{"PPROF_TOOLS"} ne "") {
- #... or specified with the PPROF_TOOLS environment variable...
- $path = $ENV{"PPROF_TOOLS"} . $tool;
- if (!-x $path) {
- error("No '$tool' found with prefix specified by PPROF_TOOLS=$ENV{PPROF_TOOLS}\n");
- }
- } else {
- # ... otherwise use the version that exists in the same directory as
- # pprof. If there's nothing there, use $PATH.
- $0 =~ m,[^/]*$,; # this is everything after the last slash
- my $dirname = $`; # this is everything up to and including the last slash
- if (-x "$dirname$tool") {
- $path = "$dirname$tool";
- } else {
- $path = $tool;
- }
- }
- if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; }
- return $path;
-}
-
-sub cleanup {
- unlink($main::tmpfile_sym);
- unlink(keys %main::tempnames);
-
- # We leave any collected profiles in $HOME/pprof in case the user wants
- # to look at them later. We print a message informing them of this.
- if ((scalar(@main::profile_files) > 0) &&
- defined($main::collected_profile)) {
- if (scalar(@main::profile_files) == 1) {
- print STDERR "Dynamically gathered profile is in $main::collected_profile\n";
- }
- print STDERR "If you want to investigate this profile further, you can do:\n";
- print STDERR "\n";
- print STDERR " pprof \\\n";
- print STDERR " $main::prog \\\n";
- print STDERR " $main::collected_profile\n";
- print STDERR "\n";
- }
-}
-
-sub sighandler {
- cleanup();
- exit(1);
-}
-
-sub error {
- my $msg = shift;
- print STDERR $msg;
- cleanup();
- exit(1);
-}
-
-
-# Run $nm_command and get all the resulting procedure boundaries whose
-# names match "$regexp" and returns them in a hashtable mapping from
-# procedure name to a two-element vector of [start address, end address]
-sub GetProcedureBoundariesViaNm {
- my $nm_command = shift;
- my $regexp = shift;
-
- my $symbol_table = {};
- open(NM, "$nm_command |") || error("$nm_command: $!\n");
- my $last_start = "0";
- my $routine = "";
- while (<NM>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (m/^\s*([0-9a-f]+) (.) (..*)/) {
- my $start_val = $1;
- my $type = $2;
- my $this_routine = $3;
-
- # It's possible for two symbols to share the same address, if
- # one is a zero-length variable (like __start_google_malloc) or
- # one symbol is a weak alias to another (like __libc_malloc).
- # In such cases, we want to ignore all values except for the
- # actual symbol, which in nm-speak has type "T". The logic
- # below does this, though it's a bit tricky: what happens when
- # we have a series of lines with the same address, is the first
- # one gets queued up to be processed. However, it won't
- # *actually* be processed until later, when we read a line with
- # a different address. That means that as long as we're reading
- # lines with the same address, we have a chance to replace that
- # item in the queue, which we do whenever we see a 'T' entry --
- # that is, a line with type 'T'. If we never see a 'T' entry,
- # we'll just go ahead and process the first entry (which never
- # got touched in the queue), and ignore the others.
- if ($start_val eq $last_start && $type =~ /t/i) {
- # We are the 'T' symbol at this address, replace previous symbol.
- $routine = $this_routine;
- next;
- } elsif ($start_val eq $last_start) {
- # We're not the 'T' symbol at this address, so ignore us.
- next;
- }
-
- if ($this_routine eq $sep_symbol) {
- $sep_address = HexExtend($start_val);
- }
-
- # Tag this routine with the starting address in case the image
- # has multiple occurrences of this routine. We use a syntax
- # that resembles template paramters that are automatically
- # stripped out by ShortFunctionName()
- $this_routine .= "<$start_val>";
-
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($start_val)];
- }
- $last_start = $start_val;
- $routine = $this_routine;
- } elsif (m/^Loaded image name: (.+)/) {
- # The win32 nm workalike emits information about the binary it is using.
- if ($main::opt_debug) { print STDERR "Using Image $1\n"; }
- } elsif (m/^PDB file name: (.+)/) {
- # The win32 nm workalike emits information about the pdb it is using.
- if ($main::opt_debug) { print STDERR "Using PDB $1\n"; }
- }
- }
- close(NM);
- # Handle the last line in the nm output. Unfortunately, we don't know
- # how big this last symbol is, because we don't know how big the file
- # is. For now, we just give it a size of 0.
- # TODO(csilvers): do better here.
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($last_start)];
- }
- return $symbol_table;
-}
-
-# Gets the procedure boundaries for all routines in "$image" whose names
-# match "$regexp" and returns them in a hashtable mapping from procedure
-# name to a two-element vector of [start address, end address].
-# Will return an empty map if nm is not installed or not working properly.
-sub GetProcedureBoundaries {
- my $image = shift;
- my $regexp = shift;
-
- # For libc libraries, the copy in /usr/lib/debug contains debugging symbols
- my $debugging = DebuggingLibrary($image);
- if ($debugging) {
- $image = $debugging;
- }
-
- my $nm = $obj_tool_map{"nm"};
- my $cppfilt = $obj_tool_map{"c++filt"};
-
- # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm
- # binary doesn't support --demangle. In addition, for OS X we need
- # to use the -f flag to get 'flat' nm output (otherwise we don't sort
- # properly and get incorrect results). Unfortunately, GNU nm uses -f
- # in an incompatible way. So first we test whether our nm supports
- # --demangle and -f.
- my $demangle_flag = "";
- my $cppfilt_flag = "";
- if (system("$nm --demangle $image >/dev/null 2>&1") == 0) {
- # In this mode, we do "nm --demangle <foo>"
- $demangle_flag = "--demangle";
- $cppfilt_flag = "";
- } elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) {
- # In this mode, we do "nm <foo> | c++filt"
- $cppfilt_flag = " | $cppfilt";
- };
- my $flatten_flag = "";
- if (system("$nm -f $image >/dev/null 2>&1") == 0) {
- $flatten_flag = "-f";
- }
-
- # Finally, in the case $imagie isn't a debug library, we try again with
- # -D to at least get *exported* symbols. If we can't use --demangle,
- # we use c++filt instead, if it exists on this system.
- my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
- "$nm -D -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
- # 6nm is for Go binaries
- "6nm $image 2>/dev/null | sort");
-
- # If the executable is an MS Windows PDB-format executable, we'll
- # have set up obj_tool_map("nm_pdb"). In this case, we actually
- # want to use both unix nm and windows-specific nm_pdb, since
- # PDB-format executables can apparently include dwarf .o files.
- if (exists $obj_tool_map{"nm_pdb"}) {
- my $nm_pdb = $obj_tool_map{"nm_pdb"};
- push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null");
- }
-
- foreach my $nm_command (@nm_commands) {
- my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
- return $symbol_table if (%{$symbol_table});
- }
- my $symbol_table = {};
- return $symbol_table;
-}
-
-
-# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
-# To make them more readable, we add underscores at interesting places.
-# This routine removes the underscores, producing the canonical representation
-# used by pprof to represent addresses, particularly in the tested routines.
-sub CanonicalHex {
- my $arg = shift;
- return join '', (split '_',$arg);
-}
-
-
-# Unit test for AddressAdd:
-sub AddressAddUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd ($row->[0], $row->[1]);
- if ($sum ne $row->[2]) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- my $expected = join '', (split '_',$row->[2]);
- if ($sum ne CanonicalHex($row->[2])) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressSub:
-sub AddressSubUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub ($row->[0], $row->[1]);
- if ($sum ne $row->[3]) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- if ($sum ne CanonicalHex($row->[3])) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressInc:
-sub AddressIncUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc ($row->[0]);
- if ($sum ne $row->[4]) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc (CanonicalHex($row->[0]));
- if ($sum ne CanonicalHex($row->[4])) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Driver for unit tests.
-# Currently just the address add/subtract/increment routines for 64-bit.
-sub RunUnitTests {
- my $error_count = 0;
-
- # This is a list of tuples [a, b, a+b, a-b, a+1]
- my $unit_test_data_8 = [
- [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)],
- [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)],
- [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)],
- [qw(00000001 ffffffff 00000000 00000002 00000002)],
- [qw(00000001 fffffff0 fffffff1 00000011 00000002)],
- ];
- my $unit_test_data_16 = [
- # The implementation handles data in 7-nibble chunks, so those are the
- # interesting boundaries.
- [qw(aaaaaaaa 50505050
- 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)],
- [qw(50505050 aaaaaaaa
- 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)],
- [qw(ffffffff aaaaaaaa
- 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)],
- [qw(00000001 ffffffff
- 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)],
- [qw(00000001 fffffff0
- 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)],
-
- [qw(00_a00000a_aaaaaaa 50505050
- 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)],
- [qw(0f_fff0005_0505050 aaaaaaaa
- 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)],
- [qw(00_000000f_fffffff 01_800000a_aaaaaaa
- 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)],
- [qw(00_0000000_0000001 ff_fffffff_fffffff
- 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)],
- [qw(00_0000000_0000001 ff_fffffff_ffffff0
- ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)],
- ];
-
- $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
- if ($error_count > 0) {
- print STDERR $error_count, " errors: FAILED\n";
- } else {
- print STDERR "PASS\n";
- }
- exit ($error_count);
-}
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
deleted file mode 100644
index f36759cd3..000000000
--- a/src/cmd/prof/main.c
+++ /dev/null
@@ -1,895 +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.
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-
-#define Ureg Ureg_amd64
- #include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg_x86
- #include <ureg_x86.h>
-#undef Ureg
-#include <mach.h>
-
-char* file = "6.out";
-static Fhdr fhdr;
-int have_syms;
-int fd;
-struct Ureg_amd64 ureg_amd64;
-struct Ureg_x86 ureg_x86;
-int total_sec = 0;
-int delta_msec = 100;
-int nsample;
-int nsamplethread;
-
-// pprof data, stored as sequences of N followed by N PC values.
-// See http://code.google.com/p/google-perftools .
-uvlong *ppdata; // traces
-Biobuf* pproffd; // file descriptor to write trace info
-long ppstart; // start position of current trace
-long nppdata; // length of data
-long ppalloc; // size of allocated data
-char ppmapdata[10*1024]; // the map information for the output file
-
-// output formats
-int pprof; // print pprof output to named file
-int functions; // print functions
-int histograms; // print histograms
-int linenums; // print file and line numbers rather than function names
-int registers; // print registers
-int stacks; // print stack traces
-
-int pid; // main process pid
-
-int nthread; // number of threads
-int thread[32]; // thread pids
-Map *map[32]; // thread maps
-
-void
-Usage(void)
-{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
- fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
- fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
- fprint(2, "\t\t-h: histograms\n");
- fprint(2, "\t\t-f: dynamic functions\n");
- fprint(2, "\t\t-l: dynamic file and line numbers\n");
- fprint(2, "\t\t-r: dynamic registers\n");
- fprint(2, "\t\t-s: dynamic function stack traces\n");
- fprint(2, "\t\t-hs: include stack info in histograms\n");
- exit(2);
-}
-
-typedef struct PC PC;
-struct PC {
- uvlong pc;
- uvlong callerpc;
- unsigned int count;
- PC* next;
-};
-
-enum {
- Ncounters = 256
-};
-
-PC *counters[Ncounters];
-
-// Set up by setarch() to make most of the code architecture-independent.
-typedef struct Arch Arch;
-struct Arch {
- char* name;
- void (*regprint)(void);
- int (*getregs)(Map*);
- int (*getPC)(Map*);
- int (*getSP)(Map*);
- uvlong (*uregPC)(void);
- uvlong (*uregSP)(void);
- void (*ppword)(uvlong w);
-};
-
-void
-amd64_regprint(void)
-{
- fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
- fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
- fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
- fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
- fprint(2, "si\t0x%llux\n", ureg_amd64.si);
- fprint(2, "di\t0x%llux\n", ureg_amd64.di);
- fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
- fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
- fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
- fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
- fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
- fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
- fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
- fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
- fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
- fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
- fprint(2, "es\t0x%llux\n", ureg_amd64.es);
- fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
- fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
- fprint(2, "type\t0x%llux\n", ureg_amd64.type);
- fprint(2, "error\t0x%llux\n", ureg_amd64.error);
- fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
- fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
- fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
- fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
- fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
-}
-
-int
-amd64_getregs(Map *map)
-{
- int i;
- union {
- uvlong regs[1];
- struct Ureg_amd64 ureg;
- } u;
-
- for(i = 0; i < sizeof ureg_amd64; i+=8) {
- if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
- return -1;
- }
- ureg_amd64 = u.ureg;
- return 0;
-}
-
-int
-amd64_getPC(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
- ureg_amd64.ip = x;
- return r;
-}
-
-int
-amd64_getSP(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
- ureg_amd64.sp = x;
- return r;
-}
-
-uvlong
-amd64_uregPC(void)
-{
- return ureg_amd64.ip;
-}
-
-uvlong
-amd64_uregSP(void) {
- return ureg_amd64.sp;
-}
-
-void
-amd64_ppword(uvlong w)
-{
- uchar buf[8];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- buf[4] = w >> 32;
- buf[5] = w >> 40;
- buf[6] = w >> 48;
- buf[7] = w >> 56;
- Bwrite(pproffd, buf, 8);
-}
-
-void
-x86_regprint(void)
-{
- fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
- fprint(2, "si\t0x%ux\n", ureg_x86.si);
- fprint(2, "di\t0x%ux\n", ureg_x86.di);
- fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
- fprint(2, "es\t0x%ux\n", ureg_x86.es);
- fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
-}
-
-int
-x86_getregs(Map *map)
-{
- int i;
-
- for(i = 0; i < sizeof ureg_x86; i+=4) {
- if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
- return -1;
- }
- return 0;
-}
-
-int
-x86_getPC(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
-}
-
-int
-x86_getSP(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
-}
-
-uvlong
-x86_uregPC(void)
-{
- return (uvlong)ureg_x86.pc;
-}
-
-uvlong
-x86_uregSP(void)
-{
- return (uvlong)ureg_x86.sp;
-}
-
-void
-x86_ppword(uvlong w)
-{
- uchar buf[4];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- Bwrite(pproffd, buf, 4);
-}
-
-Arch archtab[] = {
- {
- "amd64",
- amd64_regprint,
- amd64_getregs,
- amd64_getPC,
- amd64_getSP,
- amd64_uregPC,
- amd64_uregSP,
- amd64_ppword,
- },
- {
- "386",
- x86_regprint,
- x86_getregs,
- x86_getPC,
- x86_getSP,
- x86_uregPC,
- x86_uregSP,
- x86_ppword,
- },
- {
- nil
- }
-};
-
-Arch *arch;
-
-int
-setarch(void)
-{
- int i;
-
- if(mach != nil) {
- for(i = 0; archtab[i].name != nil; i++) {
- if (strcmp(mach->name, archtab[i].name) == 0) {
- arch = &archtab[i];
- return 0;
- }
- }
- }
- return -1;
-}
-
-int
-getthreads(void)
-{
- int i, j, curn, found;
- Map *curmap[nelem(map)];
- int curthread[nelem(map)];
- static int complained = 0;
-
- curn = procthreadpids(pid, curthread, nelem(curthread));
- if(curn <= 0)
- return curn;
-
- if(curn > nelem(map)) {
- if(complained == 0) {
- fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
- complained = 1;
- }
- curn = nelem(map);
- }
- if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
- return curn; // no changes
-
- // Number of threads has changed (might be the init case).
- // A bit expensive but rare enough not to bother being clever.
- for(i = 0; i < curn; i++) {
- found = 0;
- for(j = 0; j < nthread; j++) {
- if(curthread[i] == thread[j]) {
- found = 1;
- curmap[i] = map[j];
- map[j] = nil;
- break;
- }
- }
- if(found)
- continue;
-
- // map new thread
- curmap[i] = attachproc(curthread[i], &fhdr);
- if(curmap[i] == nil) {
- fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
- return -1;
- }
- }
-
- for(j = 0; j < nthread; j++)
- if(map[j] != nil)
- detachproc(map[j]);
-
- nthread = curn;
- memmove(thread, curthread, nthread*sizeof thread[0]);
- memmove(map, curmap, sizeof map);
- return nthread;
-}
-
-int
-sample(Map *map)
-{
- static int n;
-
- n++;
- if(registers) {
- if(arch->getregs(map) < 0)
- goto bad;
- } else {
- // we need only two registers
- if(arch->getPC(map) < 0)
- goto bad;
- if(arch->getSP(map) < 0)
- goto bad;
- }
- return 1;
-bad:
- if(n == 1)
- fprint(2, "prof: can't read registers: %r\n");
- return 0;
-}
-
-void
-addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
-{
- int h;
- PC *x;
-
- h = (pc + callerpc*101) % Ncounters;
- for(x = counters[h]; x != NULL; x = x->next) {
- if(x->pc == pc && x->callerpc == callerpc) {
- x->count++;
- return;
- }
- }
- x = malloc(sizeof(PC));
- x->pc = pc;
- x->callerpc = callerpc;
- x->count = 1;
- x->next = counters[h];
- counters[h] = x;
-}
-
-void
-addppword(uvlong pc)
-{
- if(pc == 0) {
- return;
- }
- if(nppdata == ppalloc) {
- ppalloc = (1000+nppdata)*2;
- ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
- if(ppdata == nil) {
- fprint(2, "prof: realloc failed: %r\n");
- exit(2);
- }
- }
- ppdata[nppdata++] = pc;
-}
-
-void
-startpptrace()
-{
- ppstart = nppdata;
- addppword(~0);
-}
-
-void
-endpptrace()
-{
- ppdata[ppstart] = nppdata-ppstart-1;
-}
-
-uvlong nextpc;
-
-void
-xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
-{
- char buf[1024];
- if(sym == nil){
- fprint(2, "syms\n");
- return;
- }
- if(histograms)
- addtohistogram(nextpc, pc, sp);
- if(!histograms || stacks > 1 || pprof) {
- if(nextpc == 0)
- nextpc = sym->value;
- if(stacks){
- fprint(2, "%s(", sym->name);
- fprint(2, ")");
- if(nextpc != sym->value)
- fprint(2, "+%#llux ", nextpc - sym->value);
- if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
- fprint(2, " %s", buf);
- }
- fprint(2, "\n");
- }
- if (pprof) {
- addppword(nextpc);
- }
- }
- nextpc = pc;
-}
-
-void
-stacktracepcsp(Map *map, uvlong pc, uvlong sp)
-{
- nextpc = pc;
- if(pprof){
- startpptrace();
- }
- if(machdata->ctrace==nil)
- fprint(2, "no machdata->ctrace\n");
- else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
- fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
- else {
- addtohistogram(nextpc, 0, sp);
- if(stacks)
- fprint(2, "\n");
- }
- if(pprof){
- endpptrace();
- }
-}
-
-void
-printpc(Map *map, uvlong pc, uvlong sp)
-{
- char buf[1024];
- if(registers)
- arch->regprint();
- if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
- fprint(2, "%s\n", buf);
- if(have_syms > 0 && functions) {
- symoff(buf, sizeof(buf), pc, CANY);
- fprint(2, "%s\n", buf);
- }
- if(stacks || pprof){
- stacktracepcsp(map, pc, sp);
- }
- else if(histograms){
- addtohistogram(pc, 0, sp);
- }
-}
-
-void
-ppmaps(void)
-{
- int fd, n;
- char tmp[100];
- Seg *seg;
-
- // If it's Linux, the info is in /proc/$pid/maps
- snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
- fd = open(tmp, 0);
- if(fd >= 0) {
- n = read(fd, ppmapdata, sizeof ppmapdata - 1);
- close(fd);
- if(n < 0) {
- fprint(2, "prof: can't read %s: %r\n", tmp);
- exit(2);
- }
- ppmapdata[n] = 0;
- return;
- }
-
- // It's probably a mac. Synthesize an entry for the text file.
- // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
- for(n = 0; n < 3; n++){
- seg = &map[0]->seg[n];
- if(seg->b == 0) {
- continue;
- }
- snprint(ppmapdata, sizeof ppmapdata,
- "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
- seg->b, seg->e, seg->f, "/home/r/6.out"
- );
- return;
- }
- fprint(2, "prof: no text segment in maps for %s\n", file);
- exit(2);
-}
-
-void
-samples(void)
-{
- int i, pid, msec;
- struct timespec req;
- int getmaps;
-
- req.tv_sec = delta_msec/1000;
- req.tv_nsec = 1000000*(delta_msec % 1000);
- getmaps = 0;
- if(pprof)
- getmaps= 1;
- for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
- nsample++;
- nsamplethread += nthread;
- for(i = 0; i < nthread; i++) {
- pid = thread[i];
- if(ctlproc(pid, "stop") < 0)
- return;
- if(!sample(map[i])) {
- ctlproc(pid, "start");
- return;
- }
- printpc(map[i], arch->uregPC(), arch->uregSP());
- ctlproc(pid, "start");
- }
- nanosleep(&req, NULL);
- getthreads();
- if(nthread == 0)
- break;
- if(getmaps) {
- getmaps = 0;
- ppmaps();
- }
- }
-}
-
-typedef struct Func Func;
-struct Func
-{
- Func *next;
- Symbol s;
- uint onstack;
- uint leaf;
-};
-
-Func *func[257];
-int nfunc;
-
-Func*
-findfunc(uvlong pc)
-{
- Func *f;
- uint h;
- Symbol s;
-
- if(pc == 0)
- return nil;
-
- if(!findsym(pc, CTEXT, &s))
- return nil;
-
- h = s.value % nelem(func);
- for(f = func[h]; f != NULL; f = f->next)
- if(f->s.value == s.value)
- return f;
-
- f = malloc(sizeof *f);
- memset(f, 0, sizeof *f);
- f->s = s;
- f->next = func[h];
- func[h] = f;
- nfunc++;
- return f;
-}
-
-int
-compareleaf(const void *va, const void *vb)
-{
- Func *a, *b;
-
- a = *(Func**)va;
- b = *(Func**)vb;
- if(a->leaf != b->leaf)
- return b->leaf - a->leaf;
- if(a->onstack != b->onstack)
- return b->onstack - a->onstack;
- return strcmp(a->s.name, b->s.name);
-}
-
-void
-dumphistogram()
-{
- int i, h, n;
- PC *x;
- Func *f, **ff;
-
- if(!histograms)
- return;
-
- // assign counts to functions.
- for(h = 0; h < Ncounters; h++) {
- for(x = counters[h]; x != NULL; x = x->next) {
- f = findfunc(x->pc);
- if(f) {
- f->onstack += x->count;
- f->leaf += x->count;
- }
- f = findfunc(x->callerpc);
- if(f)
- f->leaf -= x->count;
- }
- }
-
- // build array
- ff = malloc(nfunc*sizeof ff[0]);
- n = 0;
- for(h = 0; h < nelem(func); h++)
- for(f = func[h]; f != NULL; f = f->next)
- ff[n++] = f;
-
- // sort by leaf counts
- qsort(ff, nfunc, sizeof ff[0], compareleaf);
-
- // print.
- fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
- for(i = 0; i < nfunc; i++) {
- f = ff[i];
- fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
- if(stacks)
- fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
- fprint(2, "%s\n", f->s.name);
- }
-}
-
-typedef struct Trace Trace;
-struct Trace {
- int count;
- int npc;
- uvlong *pc;
- Trace *next;
-};
-
-void
-dumppprof()
-{
- uvlong i, n, *p, *e;
- int ntrace;
- Trace *trace, *tp, *up, *prev;
-
- if(!pprof)
- return;
- e = ppdata + nppdata;
- // Create list of traces. First, count the traces
- ntrace = 0;
- for(p = ppdata; p < e;) {
- n = *p++;
- p += n;
- if(n == 0)
- continue;
- ntrace++;
- }
- if(ntrace <= 0)
- return;
- // Allocate and link the traces together.
- trace = malloc(ntrace * sizeof(Trace));
- tp = trace;
- for(p = ppdata; p < e;) {
- n = *p++;
- if(n == 0)
- continue;
- tp->count = 1;
- tp->npc = n;
- tp->pc = p;
- tp->next = tp+1;
- tp++;
- p += n;
- }
- trace[ntrace-1].next = nil;
- // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
- // the list collapses fast.
- for(tp = trace; tp != nil; tp = tp->next) {
- prev = tp;
- for(up = tp->next; up != nil; up = up->next) {
- if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
- tp->count++;
- prev->next = up->next;
- } else {
- prev = up;
- }
- }
- }
- // Write file.
- // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
- // 1) Header
- arch->ppword(0); // must be zero
- arch->ppword(3); // 3 words follow in header
- arch->ppword(0); // must be zero
- arch->ppword(delta_msec * 1000); // sampling period in microseconds
- arch->ppword(0); // must be zero (padding)
- // 2) One record for each trace.
- for(tp = trace; tp != nil; tp = tp->next) {
- arch->ppword(tp->count);
- arch->ppword(tp->npc);
- for(i = 0; i < tp->npc; i++) {
- arch->ppword(tp->pc[i]);
- }
- }
- // 3) Binary trailer
- arch->ppword(0); // must be zero
- arch->ppword(1); // must be one
- arch->ppword(0); // must be zero
- // 4) Mapped objects.
- Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
- // 5) That's it.
- Bterm(pproffd);
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0){
- fprint(2, "prof: child process could not hang\n");
- exits(0);
- }
- execv(argv[0], argv);
- fprint(2, "prof: could not exec %s: %r\n", argv[0]);
- exits(0);
- }
-
- if(pid == -1) {
- fprint(2, "prof: could not fork\n");
- exit(1);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
- fprint(2, "prof: could not attach to child process: %r\n");
- exit(1);
- }
- return pid;
-}
-
-void
-detach(void)
-{
- int i;
-
- for(i = 0; i < nthread; i++)
- detachproc(map[i]);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- char *ppfile;
-
- ARGBEGIN{
- case 'P':
- pprof =1;
- ppfile = EARGF(Usage());
- pproffd = Bopen(ppfile, OWRITE);
- if(pproffd == nil) {
- fprint(2, "prof: cannot open %s: %r\n", ppfile);
- exit(2);
- }
- break;
- case 'd':
- delta_msec = atoi(EARGF(Usage()));
- break;
- case 't':
- total_sec = atoi(EARGF(Usage()));
- break;
- case 'p':
- pid = atoi(EARGF(Usage()));
- break;
- case 'f':
- functions = 1;
- break;
- case 'h':
- histograms = 1;
- break;
- case 'l':
- linenums = 1;
- break;
- case 'r':
- registers = 1;
- break;
- case 's':
- stacks++;
- break;
- default:
- Usage();
- }ARGEND
- if(pid <= 0 && argc == 0)
- Usage();
- if(functions+linenums+registers+stacks+pprof == 0)
- histograms = 1;
- if(!machbyname("amd64")) {
- fprint(2, "prof: no amd64 support\n", pid);
- exit(1);
- }
- if(argc > 0)
- file = argv[0];
- else if(pid) {
- file = proctextfile(pid);
- if (file == NULL) {
- fprint(2, "prof: can't find file for pid %d: %r\n", pid);
- fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
- exit(1);
- }
- }
- fd = open(file, 0);
- if(fd < 0) {
- fprint(2, "prof: can't open %s: %r\n", file);
- exit(1);
- }
- if(crackhdr(fd, &fhdr)) {
- have_syms = syminit(fd, &fhdr);
- if(!have_syms) {
- fprint(2, "prof: no symbols for %s: %r\n", file);
- }
- } else {
- fprint(2, "prof: crack header for %s: %r\n", file);
- exit(1);
- }
- if(pid <= 0)
- pid = startprocess(argv);
- attachproc(pid, &fhdr); // initializes thread list
- if(setarch() < 0) {
- detach();
- fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
- exit(1);
- }
- if(getthreads() <= 0) {
- detach();
- fprint(2, "prof: can't find threads for pid %d\n", pid);
- exit(1);
- }
- for(i = 0; i < nthread; i++)
- ctlproc(thread[i], "start");
- samples();
- detach();
- dumphistogram();
- dumppprof();
- exit(0);
-}
diff --git a/src/pkg/http/pprof/Makefile b/src/cmd/vet/Makefile
index 5858a0efa..2a35d1ae3 100644
--- a/src/pkg/http/pprof/Makefile
+++ b/src/cmd/vet/Makefile
@@ -2,10 +2,6 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.inc
-
-TARG=http/pprof
-GOFILES=\
- pprof.go\
-
-include ../../../Make.pkg
+test testshort:
+ go build
+ ../../../test/errchk ./vet -printfuncs='Warn:1,Warnf:1' print.go
diff --git a/src/cmd/govet/doc.go b/src/cmd/vet/doc.go
index 5a2489fca..620964aaf 100644
--- a/src/cmd/govet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -4,22 +4,46 @@
/*
-Govet does simple checking of Go source code.
+Vet examines Go source code and reports suspicious constructs, such as Printf
+calls whose arguments do not align with the format string. Vet uses heuristics
+that do not guarantee all reports are genuine problems, but it can find errors
+not caught by the compilers.
-It checks for simple errors in calls to functions named
+Available checks:
+
+1. Printf family
+
+Suspicious calls to functions in the Printf family, including any functions
+with these names:
Print Printf Println
Fprint Fprintf Fprintln
Sprint Sprintf Sprintln
Error Errorf
Fatal Fatalf
+ Panic Panicf Panicln
If the function name ends with an 'f', the function is assumed to take
-a format descriptor string in the manner of fmt.Printf. If not, govet
+a format descriptor string in the manner of fmt.Printf. If not, vet
complains about arguments that look like format descriptor strings.
+It also checks for errors such as using a Writer as the first argument of
+Printf.
+
+2. Methods
+
+Non-standard signatures for methods with familiar names, including:
+ Format GobEncode GobDecode MarshalJSON MarshalXML
+ Peek ReadByte ReadFrom ReadRune Scan Seek
+ UnmarshalJSON UnreadByte UnreadRune WriteByte
+ WriteTo
+
+3. Struct tags
+
+Struct tags that do not follow the format understood by reflect.StructTag.Get.
+
Usage:
- govet [flag] [file.go ...]
- govet [flag] [directory ...] # Scan all .go files under directory, recursively
+ go tool vet [flag] [file.go ...]
+ go tool vet [flag] [directory ...] # Scan all .go files under directory, recursively
The flags are:
-v
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
new file mode 100644
index 000000000..625133315
--- /dev/null
+++ b/src/cmd/vet/main.go
@@ -0,0 +1,239 @@
+// 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.
+
+// Vet is a simple checker for static errors in Go source code.
+// See doc.go for more information.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+var verbose = flag.Bool("v", false, "verbose")
+var exitCode = 0
+
+// setExit sets the value for os.Exit when it is called, later. It
+// remembers the highest value.
+func setExit(err int) {
+ if err > exitCode {
+ exitCode = err
+ }
+}
+
+// Usage is a replacement usage function for the flags package.
+func Usage() {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The parse tree walkers are all methods of this type.
+type File struct {
+ fset *token.FileSet
+ file *ast.File
+ b bytes.Buffer // for use by methods
+}
+
+func main() {
+ flag.Usage = Usage
+ flag.Parse()
+
+ if *printfuncs != "" {
+ for _, name := range strings.Split(*printfuncs, ",") {
+ if len(name) == 0 {
+ flag.Usage()
+ }
+ skip := 0
+ if colon := strings.LastIndex(name, ":"); colon > 0 {
+ var err error
+ skip, err = strconv.Atoi(name[colon+1:])
+ if err != nil {
+ errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
+ }
+ name = name[:colon]
+ }
+ name = strings.ToLower(name)
+ if name[len(name)-1] == 'f' {
+ printfList[name] = skip
+ } else {
+ printList[name] = skip
+ }
+ }
+ }
+
+ if flag.NArg() == 0 {
+ doFile("stdin", os.Stdin)
+ } else {
+ for _, name := range flag.Args() {
+ // Is it a directory?
+ if fi, err := os.Stat(name); err == nil && fi.IsDir() {
+ walkDir(name)
+ } else {
+ doFile(name, nil)
+ }
+ }
+ }
+ os.Exit(exitCode)
+}
+
+// doFile analyzes one file. If the reader is nil, the source code is read from the
+// named file.
+func doFile(name string, reader io.Reader) {
+ fs := token.NewFileSet()
+ parsedFile, err := parser.ParseFile(fs, name, reader, 0)
+ if err != nil {
+ errorf("%s: %s", name, err)
+ return
+ }
+ file := &File{fset: fs, file: parsedFile}
+ file.walkFile(name, parsedFile)
+}
+
+func visit(path string, f os.FileInfo, err error) error {
+ if err != nil {
+ errorf("walk error: %s", err)
+ return nil
+ }
+ if !f.IsDir() && strings.HasSuffix(path, ".go") {
+ doFile(path, nil)
+ }
+ return nil
+}
+
+// walkDir recursively walks the tree looking for .go files.
+func walkDir(root string) {
+ filepath.Walk(root, visit)
+}
+
+// error formats the error to standard error, adding program
+// identification and a newline
+func errorf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
+ setExit(2)
+}
+
+// Println is fmt.Println guarded by -v.
+func Println(args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Println(args...)
+}
+
+// Printf is fmt.Printf guarded by -v.
+func Printf(format string, args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Printf(format+"\n", args...)
+}
+
+// Bad reports an error and sets the exit code..
+func (f *File) Bad(pos token.Pos, args ...interface{}) {
+ f.Warn(pos, args...)
+ setExit(1)
+}
+
+// Badf reports a formatted error and sets the exit code.
+func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
+ f.Warnf(pos, format, args...)
+ setExit(1)
+}
+
+// Warn reports an error but does not set the exit code.
+func (f *File) Warn(pos token.Pos, args ...interface{}) {
+ loc := f.fset.Position(pos).String() + ": "
+ fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
+}
+
+// Warnf reports a formatted error but does not set the exit code.
+func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
+ loc := f.fset.Position(pos).String() + ": "
+ fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
+}
+
+// walkFile walks the file's tree.
+func (f *File) walkFile(name string, file *ast.File) {
+ Println("Checking file", name)
+ ast.Walk(f, file)
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CallExpr:
+ f.walkCallExpr(n)
+ case *ast.CompositeLit:
+ f.walkCompositeLit(n)
+ case *ast.Field:
+ f.walkFieldTag(n)
+ case *ast.FuncDecl:
+ f.walkMethodDecl(n)
+ case *ast.InterfaceType:
+ f.walkInterfaceType(n)
+ }
+ return f
+}
+
+// walkCall walks a call expression.
+func (f *File) walkCall(call *ast.CallExpr, name string) {
+ f.checkFmtPrintfCall(call, name)
+}
+
+// walkCompositeLit walks a composite literal.
+func (f *File) walkCompositeLit(c *ast.CompositeLit) {
+ f.checkUntaggedLiteral(c)
+}
+
+// walkFieldTag walks a struct field tag.
+func (f *File) walkFieldTag(field *ast.Field) {
+ if field.Tag == nil {
+ return
+ }
+ f.checkCanonicalFieldTag(field)
+}
+
+// walkMethodDecl walks the method's signature.
+func (f *File) walkMethod(id *ast.Ident, t *ast.FuncType) {
+ f.checkCanonicalMethod(id, t)
+}
+
+// walkMethodDecl walks the method signature in the declaration.
+func (f *File) walkMethodDecl(d *ast.FuncDecl) {
+ if d.Recv == nil {
+ // not a method
+ return
+ }
+ f.walkMethod(d.Name, d.Type)
+}
+
+// walkInterfaceType walks the method signatures of an interface.
+func (f *File) walkInterfaceType(t *ast.InterfaceType) {
+ for _, field := range t.Methods.List {
+ for _, id := range field.Names {
+ f.walkMethod(id, field.Type.(*ast.FuncType))
+ }
+ }
+}
+
+// walkCallExpr walks a call expression.
+func (f *File) walkCallExpr(call *ast.CallExpr) {
+ switch x := call.Fun.(type) {
+ case *ast.Ident:
+ f.walkCall(call, x.Name)
+ case *ast.SelectorExpr:
+ f.walkCall(call, x.Sel.Name)
+ }
+}
diff --git a/src/cmd/vet/method.go b/src/cmd/vet/method.go
new file mode 100644
index 000000000..41cb40ff9
--- /dev/null
+++ b/src/cmd/vet/method.go
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the code to check canonical methods.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "strings"
+)
+
+type MethodSig struct {
+ args []string
+ results []string
+}
+
+// canonicalMethods lists the input and output types for Go methods
+// that are checked using dynamic interface checks. Because the
+// checks are dynamic, such methods would not cause a compile error
+// if they have the wrong signature: instead the dynamic check would
+// fail, sometimes mysteriously. If a method is found with a name listed
+// here but not the input/output types listed here, vet complains.
+//
+// A few of the canonical methods have very common names.
+// For example, a type might implement a Scan method that
+// has nothing to do with fmt.Scanner, but we still want to check
+// the methods that are intended to implement fmt.Scanner.
+// To do that, the arguments that have a = prefix are treated as
+// signals that the canonical meaning is intended: if a Scan
+// method doesn't have a fmt.ScanState as its first argument,
+// we let it go. But if it does have a fmt.ScanState, then the
+// rest has to match.
+var canonicalMethods = map[string]MethodSig{
+ // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
+ "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter
+ "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder
+ "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder
+ "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler
+ "MarshalXML": {[]string{}, []string{"[]byte", "error"}}, // xml.Marshaler
+ "Peek": {[]string{"=int"}, []string{"[]byte", "error"}}, // image.reader (matching bufio.Reader)
+ "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader
+ "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom
+ "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader
+ "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner
+ "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker
+ "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler
+ "UnreadByte": {[]string{}, []string{"error"}},
+ "UnreadRune": {[]string{}, []string{"error"}},
+ "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer)
+ "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
+}
+
+func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
+ // Expected input/output.
+ expect, ok := canonicalMethods[id.Name]
+ if !ok {
+ return
+ }
+
+ // Actual input/output
+ args := typeFlatten(t.Params.List)
+ var results []ast.Expr
+ if t.Results != nil {
+ results = typeFlatten(t.Results.List)
+ }
+
+ // Do the =s (if any) all match?
+ if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
+ return
+ }
+
+ // Everything must match.
+ if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
+ expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
+ if len(expect.results) == 1 {
+ expectFmt += " " + argjoin(expect.results)
+ } else if len(expect.results) > 1 {
+ expectFmt += " (" + argjoin(expect.results) + ")"
+ }
+
+ f.b.Reset()
+ if err := printer.Fprint(&f.b, f.fset, t); err != nil {
+ fmt.Fprintf(&f.b, "<%s>", err)
+ }
+ actual := f.b.String()
+ if strings.HasPrefix(actual, "func(") {
+ actual = actual[4:]
+ }
+ actual = id.Name + actual
+
+ f.Warnf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
+ }
+}
+
+func argjoin(x []string) string {
+ y := make([]string, len(x))
+ for i, s := range x {
+ if s[0] == '=' {
+ s = s[1:]
+ }
+ y[i] = s
+ }
+ return strings.Join(y, ", ")
+}
+
+// Turn parameter list into slice of types
+// (in the ast, types are Exprs).
+// Have to handle f(int, bool) and f(x, y, z int)
+// so not a simple 1-to-1 conversion.
+func typeFlatten(l []*ast.Field) []ast.Expr {
+ var t []ast.Expr
+ for _, f := range l {
+ if len(f.Names) == 0 {
+ t = append(t, f.Type)
+ continue
+ }
+ for _ = range f.Names {
+ t = append(t, f.Type)
+ }
+ }
+ return t
+}
+
+// Does each type in expect with the given prefix match the corresponding type in actual?
+func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool {
+ for i, x := range expect {
+ if !strings.HasPrefix(x, prefix) {
+ continue
+ }
+ if i >= len(actual) {
+ return false
+ }
+ if !f.matchParamType(x, actual[i]) {
+ return false
+ }
+ }
+ if prefix == "" && len(actual) > len(expect) {
+ return false
+ }
+ return true
+}
+
+// Does this one type match?
+func (f *File) matchParamType(expect string, actual ast.Expr) bool {
+ if strings.HasPrefix(expect, "=") {
+ expect = expect[1:]
+ }
+ // Strip package name if we're in that package.
+ if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
+ expect = expect[n+1:]
+ }
+
+ // Overkill but easy.
+ f.b.Reset()
+ printer.Fprint(&f.b, f.fset, actual)
+ return f.b.String() == expect
+}
diff --git a/src/cmd/govet/govet.go b/src/cmd/vet/print.go
index 98d3d5c17..ee9a33c70 100644
--- a/src/cmd/govet/govet.go
+++ b/src/cmd/vet/print.go
@@ -2,229 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Govet is a simple checker for static errors in Go source code.
-// See doc.go for more information.
+// This file contains the printf-checker.
+
package main
import (
"flag"
"fmt"
- "io"
"go/ast"
- "go/parser"
"go/token"
- "os"
- "path/filepath"
- "reflect"
- "strconv"
"strings"
- "utf8"
+ "unicode/utf8"
)
-var verbose = flag.Bool("v", false, "verbose")
var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
-var exitCode = 0
-
-// setExit sets the value for os.Exit when it is called, later. It
-// remembers the highest value.
-func setExit(err int) {
- if err > exitCode {
- exitCode = err
- }
-}
-
-// Usage is a replacement usage function for the flags package.
-func Usage() {
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-// File is a wrapper for the state of a file used in the parser.
-// The parse tree walkers are all methods of this type.
-type File struct {
- file *token.File
-}
-
-func main() {
- flag.Usage = Usage
- flag.Parse()
-
- if *printfuncs != "" {
- for _, name := range strings.Split(*printfuncs, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
- skip := 0
- if colon := strings.LastIndex(name, ":"); colon > 0 {
- var err os.Error
- skip, err = strconv.Atoi(name[colon+1:])
- if err != nil {
- errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
- }
- name = name[:colon]
- }
- name = strings.ToLower(name)
- if name[len(name)-1] == 'f' {
- printfList[name] = skip
- } else {
- printList[name] = skip
- }
- }
- }
-
- if flag.NArg() == 0 {
- doFile("stdin", os.Stdin)
- } else {
- for _, name := range flag.Args() {
- // Is it a directory?
- if fi, err := os.Stat(name); err == nil && fi.IsDirectory() {
- walkDir(name)
- } else {
- doFile(name, nil)
- }
- }
- }
- os.Exit(exitCode)
-}
-
-// doFile analyzes one file. If the reader is nil, the source code is read from the
-// named file.
-func doFile(name string, reader io.Reader) {
- fs := token.NewFileSet()
- parsedFile, err := parser.ParseFile(fs, name, reader, 0)
- if err != nil {
- errorf("%s: %s", name, err)
- return
- }
- file := &File{fs.File(parsedFile.Pos())}
- file.checkFile(name, parsedFile)
-}
-
-// Visitor for filepath.Walk - trivial. Just calls doFile on each file.
-// TODO: if govet becomes richer, might want to process
-// a directory (package) at a time.
-type V struct{}
-
-func (v V) VisitDir(path string, f *os.FileInfo) bool {
- return true
-}
-
-func (v V) VisitFile(path string, f *os.FileInfo) {
- if strings.HasSuffix(path, ".go") {
- doFile(path, nil)
- }
-}
-
-// walkDir recursively walks the tree looking for .go files.
-func walkDir(root string) {
- errors := make(chan os.Error)
- done := make(chan bool)
- go func() {
- for e := range errors {
- errorf("walk error: %s", e)
- }
- done <- true
- }()
- filepath.Walk(root, V{}, errors)
- close(errors)
- <-done
-}
-
-// error formats the error to standard error, adding program
-// identification and a newline
-func errorf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
- setExit(2)
-}
-
-// Println is fmt.Println guarded by -v.
-func Println(args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Println(args...)
-}
-
-// Printf is fmt.Printf guarded by -v.
-func Printf(format string, args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Printf(format+"\n", args...)
-}
-
-// Bad reports an error and sets the exit code..
-func (f *File) Bad(pos token.Pos, args ...interface{}) {
- f.Warn(pos, args...)
- setExit(1)
-}
-
-// Badf reports a formatted error and sets the exit code.
-func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
- f.Warnf(pos, format, args...)
- setExit(1)
-}
-
-// Warn reports an error but does not set the exit code.
-func (f *File) Warn(pos token.Pos, args ...interface{}) {
- loc := f.file.Position(pos).String() + ": "
- fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
-}
-
-// Warnf reports a formatted error but does not set the exit code.
-func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
- loc := f.file.Position(pos).String() + ": "
- fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
-}
-
-// checkFile checks all the top-level declarations in a file.
-func (f *File) checkFile(name string, file *ast.File) {
- Println("Checking file", name)
- ast.Walk(f, file)
-}
-
-// Visit implements the ast.Visitor interface.
-func (f *File) Visit(node ast.Node) ast.Visitor {
- switch n := node.(type) {
- case *ast.CallExpr:
- f.checkCallExpr(n)
- case *ast.Field:
- f.checkFieldTag(n)
- }
- return f
-}
-
-// checkField checks a struct field tag.
-func (f *File) checkFieldTag(field *ast.Field) {
- if field.Tag == nil {
- return
- }
-
- tag, err := strconv.Unquote(field.Tag.Value)
- if err != nil {
- f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
- return
- }
-
- // Check tag for validity by appending
- // new key:value to end and checking that
- // the tag parsing code can find it.
- if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
- f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
- return
- }
-}
-
-// checkCallExpr checks a call expression.
-func (f *File) checkCallExpr(call *ast.CallExpr) {
- switch x := call.Fun.(type) {
- case *ast.Ident:
- f.checkCall(call, x.Name)
- case *ast.SelectorExpr:
- f.checkCall(call, x.Sel.Name)
- }
-}
// printfList records the formatted-print functions. The value is the location
// of the format parameter. Names are lower-cased so the lookup is
@@ -251,7 +42,7 @@ var printList = map[string]int{
}
// checkCall triggers the print-specific checks if the call invokes a print function.
-func (f *File) checkCall(call *ast.CallExpr, Name string) {
+func (f *File) checkFmtPrintfCall(call *ast.CallExpr, Name string) {
name := strings.ToLower(Name)
if skip, ok := printfList[name]; ok {
f.checkPrintf(call, Name, skip)
@@ -276,7 +67,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
if !ok {
// Too hard to check.
if *verbose {
- f.Warn(call.Pos(), "can't check args for call to", name)
+ f.Warn(call.Pos(), "can't check non-literal format in call to", name)
}
return
}
@@ -294,7 +85,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
for i, w := 0, 0; i < len(lit.Value); i += w {
w = 1
if lit.Value[i] == '%' {
- nbytes, nargs := parsePrintfVerb(lit.Value[i:])
+ nbytes, nargs := f.parsePrintfVerb(call, lit.Value[i:])
w = nbytes
numArgs += nargs
}
@@ -308,8 +99,9 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
// parsePrintfVerb returns the number of bytes and number of arguments
// consumed by the Printf directive that begins s, including its percent sign
// and verb.
-func parsePrintfVerb(s string) (nbytes, nargs int) {
+func (f *File) parsePrintfVerb(call *ast.CallExpr, s string) (nbytes, nargs int) {
// There's guaranteed a percent sign.
+ flags := make([]byte, 0, 5)
nbytes = 1
end := len(s)
// There may be flags.
@@ -317,6 +109,7 @@ FlagLoop:
for nbytes < end {
switch s[nbytes] {
case '#', '0', '+', '-', ' ':
+ flags = append(flags, s[nbytes])
nbytes++
default:
break FlagLoop
@@ -336,6 +129,7 @@ FlagLoop:
getNum()
// If there's a period, there may be a precision.
if nbytes < end && s[nbytes] == '.' {
+ flags = append(flags, '.') // Treat precision as a flag.
nbytes++
getNum()
}
@@ -344,16 +138,87 @@ FlagLoop:
nbytes += w
if c != '%' {
nargs++
+ f.checkPrintfVerb(call, c, flags)
}
return
}
+type printVerb struct {
+ verb rune
+ flags string // known flags are all ASCII
+}
+
+// Common flag sets for printf verbs.
+const (
+ numFlag = " -+.0"
+ sharpNumFlag = " -+.0#"
+ allFlags = " -+.0#"
+)
+
+// printVerbs identifies which flags are known to printf for each verb.
+// TODO: A type that implements Formatter may do what it wants, and vet
+// will complain incorrectly.
+var printVerbs = []printVerb{
+ // '-' is a width modifier, always valid.
+ // '.' is a precision for float, max width for strings.
+ // '+' is required sign for numbers, Go format for %v.
+ // '#' is alternate format for several verbs.
+ // ' ' is spacer for numbers
+ {'b', numFlag},
+ {'c', "-"},
+ {'d', numFlag},
+ {'e', numFlag},
+ {'E', numFlag},
+ {'f', numFlag},
+ {'F', numFlag},
+ {'g', numFlag},
+ {'G', numFlag},
+ {'o', sharpNumFlag},
+ {'p', "-#"},
+ {'q', "-+#."},
+ {'s', "-."},
+ {'t', "-"},
+ {'T', "-"},
+ {'U', "-#"},
+ {'v', allFlags},
+ {'x', sharpNumFlag},
+ {'X', sharpNumFlag},
+}
+
+const printfVerbs = "bcdeEfFgGopqstTvxUX"
+
+func (f *File) checkPrintfVerb(call *ast.CallExpr, verb rune, flags []byte) {
+ // Linear scan is fast enough for a small list.
+ for _, v := range printVerbs {
+ if v.verb == verb {
+ for _, flag := range flags {
+ if !strings.ContainsRune(v.flags, rune(flag)) {
+ f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", verb, flag)
+ }
+ }
+ return
+ }
+ }
+ f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
+}
+
// checkPrint checks a call to an unformatted print routine such as Println.
// The skip argument records how many arguments to ignore; that is,
// call.Args[skip] is the first argument to be printed.
func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
isLn := strings.HasSuffix(name, "ln")
+ isF := strings.HasPrefix(name, "F")
args := call.Args
+ // check for Println(os.Stderr, ...)
+ if skip == 0 && !isF && len(args) > 0 {
+ if sel, ok := args[0].(*ast.SelectorExpr); ok {
+ if x, ok := sel.X.(*ast.Ident); ok {
+ if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
+ f.Warnf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
+ }
+ }
+ }
+ }
if len(args) <= skip {
if *verbose && !isLn {
f.Badf(call.Pos(), "no args in %s call", name)
@@ -392,12 +257,21 @@ func BadFunctionUsedInTests() {
f := new(File)
f.Warn(0, "%s", "hello", 3) // ERROR "possible formatting directive in Warn call"
f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args in Warnf call"
+ f.Warnf(0, "%r", "hello") // ERROR "unrecognized printf verb"
+ f.Warnf(0, "%#s", "hello") // ERROR "unrecognized printf flag"
}
type BadTypeUsedInTests struct {
X int "hello" // ERROR "struct field tag"
}
+func (t *BadTypeUsedInTests) Scan(x fmt.ScanState, c byte) { // ERROR "method Scan[(]x fmt.ScanState, c byte[)] should have signature Scan[(]fmt.ScanState, rune[)] error"
+}
+
+type BadInterfaceUsedInTests interface {
+ ReadByte() byte // ERROR "method ReadByte[(][)] byte should have signature ReadByte[(][)] [(]byte, error[)]"
+}
+
// printf is used by the test.
func printf(format string, args ...interface{}) {
panic("don't call - testing only")
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
new file mode 100644
index 000000000..ea2a9d863
--- /dev/null
+++ b/src/cmd/vet/structtag.go
@@ -0,0 +1,34 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the test for canonical struct tags.
+
+package main
+
+import (
+ "go/ast"
+ "reflect"
+ "strconv"
+)
+
+// checkField checks a struct field tag.
+func (f *File) checkCanonicalFieldTag(field *ast.Field) {
+ if field.Tag == nil {
+ return
+ }
+
+ tag, err := strconv.Unquote(field.Tag.Value)
+ if err != nil {
+ f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+ return
+ }
+
+ // Check tag for validity by appending
+ // new key:value to end and checking that
+ // the tag parsing code can find it.
+ if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
+ f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
+ return
+ }
+}
diff --git a/src/cmd/vet/taglit.go b/src/cmd/vet/taglit.go
new file mode 100644
index 000000000..c3c4f3234
--- /dev/null
+++ b/src/cmd/vet/taglit.go
@@ -0,0 +1,121 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the test for untagged struct literals.
+
+package main
+
+import (
+ "go/ast"
+ "strings"
+)
+
+// checkUntaggedLiteral checks if a composite literal is an struct literal with
+// untagged fields.
+func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
+ // Check if the CompositeLit contains an untagged field.
+ allKeyValue := true
+ for _, e := range c.Elts {
+ if _, ok := e.(*ast.KeyValueExpr); !ok {
+ allKeyValue = false
+ break
+ }
+ }
+ if allKeyValue {
+ return
+ }
+
+ // Check that the CompositeLit's type has the form pkg.Typ.
+ s, ok := c.Type.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ pkg, ok := s.X.(*ast.Ident)
+ if !ok {
+ return
+ }
+
+ // Convert the package name to an import path, and compare to a whitelist.
+ path := pkgPath(f, pkg.Name)
+ if path == "" {
+ f.Warnf(c.Pos(), "unresolvable package for %s.%s literal", pkg.Name, s.Sel.Name)
+ return
+ }
+ typ := path + "." + s.Sel.Name
+ if untaggedLiteralWhitelist[typ] {
+ return
+ }
+
+ f.Warnf(c.Pos(), "%s struct literal uses untagged fields", typ)
+}
+
+// pkgPath returns the import path "image/png" for the package name "png".
+//
+// This is based purely on syntax and convention, and not on the imported
+// package's contents. It will be incorrect if a package name differs from the
+// leaf element of the import path, or if the package was a dot import.
+func pkgPath(f *File, pkgName string) (path string) {
+ for _, x := range f.file.Imports {
+ s := strings.Trim(x.Path.Value, `"`)
+ if x.Name != nil {
+ // Catch `import pkgName "foo/bar"`.
+ if x.Name.Name == pkgName {
+ return s
+ }
+ } else {
+ // Catch `import "pkgName"` or `import "foo/bar/pkgName"`.
+ if s == pkgName || strings.HasSuffix(s, "/"+pkgName) {
+ return s
+ }
+ }
+ }
+ return ""
+}
+
+var untaggedLiteralWhitelist = map[string]bool{
+ /*
+ These types are actually slices. Syntactically, we cannot tell
+ whether the Typ in pkg.Typ{1, 2, 3} is a slice or a struct, so we
+ whitelist all the standard package library's exported slice types.
+
+ find $GOROOT/src/pkg -type f | grep -v _test.go | xargs grep '^type.*\[\]' | \
+ grep -v ' map\[' | sed 's,/[^/]*go.type,,' | sed 's,.*src/pkg/,,' | \
+ sed 's, ,.,' | sed 's, .*,,' | grep -v '\.[a-z]' | \
+ sort | awk '{ print "\"" $0 "\": true," }'
+ */
+ "crypto/x509/pkix.RDNSequence": true,
+ "crypto/x509/pkix.RelativeDistinguishedNameSET": true,
+ "database/sql.RawBytes": true,
+ "debug/macho.LoadBytes": true,
+ "encoding/asn1.ObjectIdentifier": true,
+ "encoding/asn1.RawContent": true,
+ "encoding/json.RawMessage": true,
+ "encoding/xml.CharData": true,
+ "encoding/xml.Comment": true,
+ "encoding/xml.Directive": true,
+ "exp/norm.Decomposition": true,
+ "exp/types.ObjList": true,
+ "go/scanner.ErrorList": true,
+ "image/color.Palette": true,
+ "net.HardwareAddr": true,
+ "net.IP": true,
+ "net.IPMask": true,
+ "sort.Float64Slice": true,
+ "sort.IntSlice": true,
+ "sort.StringSlice": true,
+ "unicode.SpecialCase": true,
+
+ // These image and image/color struct types are frozen. We will never add fields to them.
+ "image/color.Alpha16": true,
+ "image/color.Alpha": true,
+ "image/color.Gray16": true,
+ "image/color.Gray": true,
+ "image/color.NRGBA64": true,
+ "image/color.NRGBA": true,
+ "image/color.RGBA64": true,
+ "image/color.RGBA": true,
+ "image/color.YCbCr": true,
+ "image.Point": true,
+ "image.Rectangle": true,
+}
diff --git a/src/cmd/hgpatch/Makefile b/src/cmd/yacc/Makefile
index 1ef98d7f9..56e954289 100644
--- a/src/cmd/hgpatch/Makefile
+++ b/src/cmd/yacc/Makefile
@@ -2,10 +2,9 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
+units: yacc.go units.y
+ go run yacc.go -p units_ units.y
+ go build -o units y.go
-TARG=hgpatch
-GOFILES=\
- main.go\
-
-include ../../Make.cmd
+clean:
+ rm -f y.go y.output units
diff --git a/src/cmd/goyacc/doc.go b/src/cmd/yacc/doc.go
index 5dd6abe69..4a2c2a314 100644
--- a/src/cmd/goyacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -4,16 +4,21 @@
/*
-Goyacc is a version of yacc for Go.
+Yacc is a version of yacc for Go.
It is written in Go and generates parsers written in Go.
+Usage:
+
+ go tool yacc args...
+
It is largely transliterated from the Inferno version written in Limbo
which in turn was largely transliterated from the Plan 9 version
written in C and documented at
http://plan9.bell-labs.com/magic/man2html/1/yacc
-Yacc adepts will have no trouble adapting to this form of the tool.
+Adepts of the original yacc will have no trouble adapting to this
+form of the tool.
The file units.y in this directory is a yacc grammar for a version of
the Unix tool units, also written in Go and largely transliterated
@@ -37,9 +42,9 @@ which holds the yyLexer passed to Parse.
Multiple grammars compiled into a single program should be placed in
distinct packages. If that is impossible, the "-p prefix" flag to
-goyacc sets the prefix, by default yy, that begins the names of
+yacc sets the prefix, by default yy, that begins the names of
symbols, including types, the parser, and the lexer, generated and
-referenced by goyacc's generated code. Setting it to distinct values
+referenced by yacc's generated code. Setting it to distinct values
allows multiple grammars to be placed in a single package.
*/
diff --git a/src/cmd/goyacc/units.txt b/src/cmd/yacc/units.txt
index ddb2bc294..ddb2bc294 100644
--- a/src/cmd/goyacc/units.txt
+++ b/src/cmd/yacc/units.txt
diff --git a/src/cmd/goyacc/units.y b/src/cmd/yacc/units.y
index d9ef663d9..7258e3e59 100644
--- a/src/cmd/goyacc/units.y
+++ b/src/cmd/yacc/units.y
@@ -7,17 +7,16 @@
// See http://plan9.bell-labs.com/plan9/license.html
// Generate parser with prefix "units_":
-// goyacc -p "units_"
+// go tool yacc -p "units_"
%{
// units.y
-// example of a goyacc program
+// example of a Go yacc program
// usage is
-// goyacc units.y (produces y.go)
-// 6g y.go
-// 6l y.6
-// ./6.out $GOROOT/src/cmd/goyacc/units
+// go tool yacc -p "units_" units.y (produces y.go)
+// go build -o units y.go
+// ./units $GOROOT/src/cmd/yacc/units.txt
// you have: c
// you want: furlongs/fortnight
// * 1.8026178e+12
@@ -33,7 +32,7 @@ import (
"os"
"math"
"strconv"
- "utf8"
+ "unicode/utf8"
)
const (
@@ -58,21 +57,19 @@ var lineno int // current input line number
var linep int // index to next rune in unput
var nerrors int // error count
var one Node // constant one
-var peekrune int // backup runt from input
+var peekrune rune // backup runt from input
var retnode1 Node
var retnode2 Node
var retnode Node
var sym string
var vflag bool
-
%}
-%union
-{
- node Node
- vvar *Var
- numb int
- vval float64
+%union {
+ node Node
+ vvar *Var
+ numb int
+ vval float64
}
%type <node> prog expr expr0 expr1 expr2 expr3 expr4
@@ -85,7 +82,6 @@ prog:
':' VAR expr
{
var f int
-
f = int($2.node.dim[0])
$2.node = $3
$2.node.dim[0] = 1
@@ -98,26 +94,23 @@ prog:
| ':' VAR '#'
{
var f, i int
-
- for i=1; i<Ndim; i++ {
+ for i = 1; i < Ndim; i++ {
if fund[i] == nil {
break
}
}
if i >= Ndim {
Error("too many dimensions")
- i = Ndim-1
+ i = Ndim - 1
}
fund[i] = $2
-
f = int($2.node.dim[0])
$2.node = one
$2.node.dim[0] = 1
$2.node.dim[i] = 1
if f != 0 {
Errorf("redefinition of %v", $2.name)
- } else
- if vflag {
+ } else if vflag {
fmt.Printf("%v\t#\n", $2.name)
}
}
@@ -171,8 +164,7 @@ expr2:
| expr2 '^' expr1
{
var i int
-
- for i=1; i<Ndim; i++ {
+ for i = 1; i < Ndim; i++ {
if $3.dim[i] != 0 {
Error("exponent has units")
$$ = $1
@@ -219,7 +211,8 @@ expr0:
type UnitsLex int
func (UnitsLex) Lex(yylval *units_SymType) int {
- var c, i int
+ var c rune
+ var i int
c = peekrune
peekrune = ' '
@@ -249,7 +242,7 @@ loop:
yylval.numb = 3
return SUP
}
- return c
+ return int(c)
alpha:
sym = ""
@@ -274,7 +267,7 @@ numb:
}
}
peekrune = c
- f, err := strconv.Atof64(sym)
+ f, err := strconv.ParseFloat(sym, 64)
if err != nil {
fmt.Printf("error converting %v\n", sym)
f = 0
@@ -294,9 +287,14 @@ func main() {
flag.Parse()
- file = os.Getenv("GOROOT") + "/src/cmd/goyacc/units.txt"
+ if dir := os.Getenv("GOROOT"); dir != "" {
+ file = dir + "/src/cmd/yacc/units.txt"
+ }
if flag.NArg() > 0 {
file = flag.Arg(0)
+ } else if file == "" {
+ fmt.Fprintf(os.Stderr, "can not find data file units.txt; provide it as argument or set $GOROOT\n")
+ os.Exit(1)
}
f, err := os.Open(file)
@@ -369,7 +367,7 @@ func main() {
* all characters that have some
* meaning. rest are usable as names
*/
-func ralpha(c int) bool {
+func ralpha(c rune) bool {
switch c {
case 0, '+', '-', '*', '/', '[', ']', '(', ')',
'^', ':', '?', ' ', '\t', '.', '|', '#',
@@ -382,7 +380,7 @@ func ralpha(c int) bool {
/*
* number forming character
*/
-func rdigit(c int) bool {
+func rdigit(c rune) bool {
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'.', 'e', '+', '-':
@@ -584,8 +582,9 @@ func readline() bool {
return false
}
-func getrune() int {
- var c, n int
+func getrune() rune {
+ var c rune
+ var n int
if linep >= len(line) {
return 0
@@ -690,7 +689,6 @@ func pname() float64 {
return 0
}
-
// careful multiplication
// exponents (log) are checked before multiply
func fmul(a, b float64) float64 {
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/yacc/yacc.go
index 481540188..e94228152 100644
--- a/src/cmd/goyacc/goyacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -45,12 +45,12 @@ package main
//
import (
+ "bufio"
+ "bytes"
"flag"
"fmt"
- "bufio"
"os"
"strings"
- "bytes"
)
// the following are adjustable
@@ -506,19 +506,20 @@ outer:
// non-literals
c := tokset[i].name[0]
if c != ' ' && c != '$' {
- fmt.Fprintf(ftable, "const\t%v\t= %v\n", tokset[i].name, tokset[i].value)
+ fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
}
}
// put out names of token names
- fmt.Fprintf(ftable, "var\t%sToknames\t =[]string {\n", prefix)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "var %sToknames = []string{\n", prefix)
for i := TOKSTART; i <= ntokens; i++ {
fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
}
fmt.Fprintf(ftable, "}\n")
// put out names of state names
- fmt.Fprintf(ftable, "var\t%sStatenames\t =[]string {\n", prefix)
+ fmt.Fprintf(ftable, "var %sStatenames = []string{", prefix)
// for i:=TOKSTART; i<=ntokens; i++ {
// fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
// }
@@ -544,7 +545,7 @@ outer:
// put into prdptr array in the format
// target
// followed by id's of terminals and non-terminals
- // followd by -nprod
+ // followed by -nprod
for t != MARK && t != ENDFILE {
mem := 0
@@ -595,7 +596,7 @@ outer:
break
}
levprd[nprod] |= ACTFLAG
- fmt.Fprintf(fcode, "\ncase %v:", nprod)
+ fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
cpyact(curprod, mem)
// action within rule...
@@ -652,8 +653,8 @@ outer:
if tempty != nontrst[curprod[0]-NTBASE].value {
errorf("default action causes potential type clash")
}
- fmt.Fprintf(fcode, "\ncase %v:", nprod)
- fmt.Fprintf(fcode, "\n\t%sVAL.%v = %sS[%spt-0].%v;",
+ fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+ fmt.Fprintf(fcode, "\n\t\t%sVAL.%v = %sS[%spt-0].%v",
prefix, typeset[tempty], prefix, prefix, typeset[tempty])
}
moreprod()
@@ -671,9 +672,10 @@ outer:
fmt.Fprintf(fcode, "\n\t}")
- fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
- fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
- fmt.Fprintf(ftable, "const %sMaxDepth = %v\n", prefix, stacksize)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
+ fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
+ fmt.Fprintf(ftable, "const %sMaxDepth = %v\n", prefix, stacksize)
//
// copy any postfix code
@@ -811,7 +813,8 @@ func defin(nt int, s string) int {
var peekline = 0
func gettok() int {
- var i, match, c int
+ var i int
+ var match, c rune
tokname = ""
for {
@@ -917,25 +920,25 @@ func gettok() int {
getword(c)
// find a reserved word
- for c = 0; c < len(resrv); c++ {
- if tokname == resrv[c].name {
+ for i := range resrv {
+ if tokname == resrv[i].name {
if tokflag {
fmt.Printf(">>> %%%v %v %v\n", tokname,
- resrv[c].value-PRIVATE, lineno)
+ resrv[i].value-PRIVATE, lineno)
}
- return resrv[c].value
+ return resrv[i].value
}
}
errorf("invalid escape, or illegal reserved word: %v", tokname)
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- numbval = c - '0'
+ numbval = int(c - '0')
for {
c = getrune(finput)
if !isdigit(c) {
break
}
- numbval = numbval*10 + c - '0'
+ numbval = numbval*10 + int(c-'0')
}
ungetrune(finput, c)
if tokflag {
@@ -951,7 +954,7 @@ func gettok() int {
if tokflag {
fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
}
- return c
+ return int(c)
}
// look ahead to distinguish IDENTIFIER from IDENTCOLON
@@ -980,7 +983,7 @@ func gettok() int {
return IDENTIFIER
}
-func getword(c int) {
+func getword(c rune) {
tokname = ""
for isword(c) || isdigit(c) || c == '_' || c == '.' || c == '$' {
tokname += string(c)
@@ -1039,7 +1042,7 @@ func cpyunion() {
if !lflag {
fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
}
- fmt.Fprintf(ftable, "type\t%sSymType\tstruct", prefix)
+ fmt.Fprintf(ftable, "type %sSymType struct", prefix)
level := 0
@@ -1055,7 +1058,7 @@ out:
lineno++
case '{':
if level == 0 {
- fmt.Fprintf(ftable, "\n\tyys\tint;")
+ fmt.Fprintf(ftable, "\n\tyys int")
}
level++
case '}':
@@ -1065,7 +1068,7 @@ out:
}
}
}
- fmt.Fprintf(ftable, "\n")
+ fmt.Fprintf(ftable, "\n\n")
}
//
@@ -1105,7 +1108,7 @@ func cpycode() {
// skipcom is called after reading a '/'
//
func skipcom() int {
- var c int
+ var c rune
c = getrune(finput)
if c == '/' {
@@ -1163,7 +1166,7 @@ func dumpprod(curprod []int, max int) {
func cpyact(curprod []int, max int) {
if !lflag {
- fmt.Fprintf(fcode, "\n//line %v:%v\n", infile, lineno)
+ fmt.Fprintf(fcode, "\n\t\t//line %v:%v\n\t\t", infile, lineno)
}
lno := lineno
@@ -1177,14 +1180,13 @@ loop:
switch c {
case ';':
if brac == 0 {
- ftable.WriteRune(c)
+ fcode.WriteRune(c)
return
}
case '{':
if brac == 0 {
}
- ftable.WriteRune('\t')
brac++
case '$':
@@ -1220,7 +1222,7 @@ loop:
j := 0
if isdigit(c) {
for isdigit(c) {
- j = j*10 + c - '0'
+ j = j*10 + int(c-'0')
c = getrune(finput)
}
ungetrune(finput, c)
@@ -1345,7 +1347,9 @@ loop:
errorf("action does not terminate")
case '\n':
+ fmt.Fprint(fcode, "\n\t")
lineno++
+ continue loop
}
fcode.WriteRune(c)
@@ -2072,7 +2076,7 @@ func output() {
var c, u, v int
fmt.Fprintf(ftable, "\n//line yacctab:1\n")
- fmt.Fprintf(ftable, "var\t%sExca = []int {\n", prefix)
+ fmt.Fprintf(ftable, "var %sExca = []int{\n", prefix)
noset := mkset()
@@ -2145,10 +2149,12 @@ func output() {
}
fmt.Fprintf(ftable, "}\n")
- fmt.Fprintf(ftable, "const\t%sNprod\t= %v\n", prefix, nprod)
- fmt.Fprintf(ftable, "const\t%sPrivate\t= %v\n", prefix, PRIVATE)
- fmt.Fprintf(ftable, "var\t%sTokenNames []string\n", prefix)
- fmt.Fprintf(ftable, "var\t%sStates []string\n", prefix)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sNprod = %v\n", prefix, nprod)
+ fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix)
+ fmt.Fprintf(ftable, "var %sStates []string\n", prefix)
}
//
@@ -2264,7 +2270,7 @@ func wract(i int) {
continue
}
if flag == 0 {
- fmt.Fprintf(ftable, "-1, %v,\n", i)
+ fmt.Fprintf(ftable, "\t-1, %v,\n", i)
}
flag++
fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
@@ -2723,7 +2729,8 @@ nextn:
// write out the optimized parser
//
func aoutput() {
- fmt.Fprintf(ftable, "const\t%sLast\t= %v\n", prefix, maxa+1)
+ ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "const %sLast = %v\n\n", prefix, maxa+1)
arout("Act", amem, maxa+1)
arout("Pact", indgo, nstate)
arout("Pgo", pgo, nnonter+1)
@@ -2805,7 +2812,7 @@ func others() {
arout("Tok2", temp1, c+1)
// table 3 has everything else
- fmt.Fprintf(ftable, "var\t%sTok3\t= []int {\n", prefix)
+ fmt.Fprintf(ftable, "var %sTok3 = []int{\n\t", prefix)
c = 0
for i = 1; i <= ntokens; i++ {
j = tokset[i].value
@@ -2816,19 +2823,25 @@ func others() {
continue
}
- fmt.Fprintf(ftable, "%4d,%4d,", j, i)
+ if c%5 != 0 {
+ ftable.WriteRune(' ')
+ }
+ fmt.Fprintf(ftable, "%d, %d,", j, i)
c++
if c%5 == 0 {
- ftable.WriteRune('\n')
+ fmt.Fprint(ftable, "\n\t")
}
}
- fmt.Fprintf(ftable, "%4d,\n };\n", 0)
+ if c%5 != 0 {
+ ftable.WriteRune(' ')
+ }
+ fmt.Fprintf(ftable, "%d,\n}\n", 0)
// copy parser text
- c = getrune(finput)
- for c != EOF {
- ftable.WriteRune(c)
- c = getrune(finput)
+ ch := getrune(finput)
+ for ch != EOF {
+ ftable.WriteRune(ch)
+ ch = getrune(finput)
}
// copy yaccpar
@@ -2842,15 +2855,16 @@ func others() {
func arout(s string, v []int, n int) {
s = prefix + s
- fmt.Fprintf(ftable, "var\t%v\t= []int {\n", s)
+ fmt.Fprintf(ftable, "var %v = []int{\n", s)
for i := 0; i < n; i++ {
if i%10 == 0 {
- ftable.WriteRune('\n')
+ fmt.Fprintf(ftable, "\n\t")
+ } else {
+ ftable.WriteRune(' ')
}
- fmt.Fprintf(ftable, "%4d", v[i])
- ftable.WriteRune(',')
+ fmt.Fprintf(ftable, "%d,", v[i])
}
- fmt.Fprintf(ftable, "\n};\n")
+ fmt.Fprintf(ftable, "\n}\n")
}
//
@@ -2919,7 +2933,7 @@ func chcopy(q string) string {
}
func usage() {
- fmt.Fprintf(stderr, "usage: goyacc [-o output] [-v parsetable] input\n")
+ fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n")
exit(1)
}
@@ -2963,11 +2977,11 @@ func prlook(p Lkset) {
//
// utility routines
//
-var peekrune int
+var peekrune rune
-func isdigit(c int) bool { return c >= '0' && c <= '9' }
+func isdigit(c rune) bool { return c >= '0' && c <= '9' }
-func isword(c int) bool {
+func isword(c rune) bool {
return c >= 0xa0 || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
}
@@ -2997,8 +3011,8 @@ func putrune(f *bufio.Writer, c int) {
}
}
-func getrune(f *bufio.Reader) int {
- var r int
+func getrune(f *bufio.Reader) rune {
+ var r rune
if peekrune != 0 {
if peekrune == EOF {
@@ -3020,7 +3034,7 @@ func getrune(f *bufio.Reader) int {
return c
}
-func ungetrune(f *bufio.Reader, c int) {
+func ungetrune(f *bufio.Reader, c rune) {
if f != finput {
panic("ungetc - not finput")
}
@@ -3257,10 +3271,9 @@ $$default:
}
}
- /* the current p has no shift onn "error", pop stack */
+ /* the current p has no shift on "error", pop stack */
if $$Debug >= 2 {
- fmt.Printf("error recovery pops state %d, uncovers %d\n",
- $$S[$$p].yys, $$S[$$p-1].yys)
+ fmt.Printf("error recovery pops state %d\n", $$S[$$p].yys)
}
$$p--
}
@@ -3286,7 +3299,7 @@ $$default:
$$nt := $$n
$$pt := $$p
- _ = $$pt // guard against "declared and not used"
+ _ = $$pt // guard against "declared and not used"
$$p -= $$R2[$$n]
$$VAL = $$S[$$p+1]
diff --git a/src/env.bash b/src/env.bash
deleted file mode 100644
index de446bf47..000000000
--- a/src/env.bash
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# If set to a Windows-style path convert to an MSYS-Unix
-# one using the built-in shell commands.
-if [[ "$GOROOT" == *:* ]]; then
- GOROOT=$(cd "$GOROOT"; pwd)
-fi
-
-if [[ "$GOBIN" == *:* ]]; then
- GOBIN=$(cd "$GOBIN"; pwd)
-fi
-
-export GOROOT=${GOROOT:-$(cd ..; pwd)}
-
-if ! test -f "$GOROOT"/include/u.h
-then
- echo '$GOROOT is not set correctly or not exported: '$GOROOT 1>&2
- exit 1
-fi
-
-# Double-check that we're in $GOROOT, for people with multiple Go trees.
-# Various aspects of the build cd into $GOROOT-rooted paths,
-# making it easy to jump to a different tree and get confused.
-DIR1=$(cd ..; pwd)
-DIR2=$(cd "$GOROOT"; pwd)
-if [ "$DIR1" != "$DIR2" ]; then
- echo 'Suspicious $GOROOT '"$GOROOT"': does not match current directory.' 1>&2
- exit 1
-fi
-
-export GOBIN=${GOBIN:-"$GOROOT/bin"}
-if [ ! -d "$GOBIN" -a "$GOBIN" != "$GOROOT/bin" ]; then
- echo '$GOBIN is not a directory or does not exist' 1>&2
- echo 'create it or set $GOBIN differently' 1>&2
- exit 1
-fi
-
-export OLDPATH=$PATH
-export PATH="$GOBIN":$PATH
-
-MAKE=make
-if ! make --version 2>/dev/null | grep 'GNU Make' >/dev/null; then
- MAKE=gmake
-fi
-
-PROGS="
- ar
- awk
- bash
- bison
- chmod
- cp
- cut
- echo
- egrep
- gcc
- grep
- ls
- mkdir
- mv
- pwd
- rm
- sed
- sort
- tee
- touch
- tr
- true
- uname
- uniq
-"
-
-for i in $PROGS; do
- if ! which $i >/dev/null 2>&1; then
- echo "Cannot find '$i' on search path." 1>&2
- echo "See http://golang.org/doc/install.html#ctools" 1>&2
- exit 1
- fi
-done
-
-if bison --version 2>&1 | grep 'bison++' >/dev/null 2>&1; then
- echo "Your system's 'bison' is bison++."
- echo "Go needs the original bison instead." 1>&2
- echo "See http://golang.org/doc/install.html#ctools" 1>&2
- exit 1
-fi
-
-# Issue 2020: some users configure bash to default to
-# set -o noclobber
-# which makes >x fail if x already exists. Restore sanity.
-set +o noclobber
-
-# Tried to use . <($MAKE ...) here, but it cannot set environment
-# variables in the version of bash that ships with OS X. Amazing.
-eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GOHOSTARCH|GOHOSTOS|GO_ENV')
-
-# Shell doesn't tell us whether make succeeded,
-# so Make.inc generates a fake variable name.
-if [ "$MAKE_GO_ENV_WORKED" != 1 ]; then
- echo 'Did not find Go environment variables.' 1>&2
- exit 1
-fi
-unset MAKE_GO_ENV_WORKED
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
index 28c97c9b4..62aba5dca 100644
--- a/src/lib9/Makefile
+++ b/src/lib9/Makefile
@@ -1,121 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../Make.inc
-O:=$(HOST_O)
-
-LIB=lib9.a
-
-NUM=\
- charstod.$O\
- pow10.$O\
-
-# Could add fmt/errfmt, but we want to pick it up from ./errstr.c instead.
-FMTOFILES=\
- dofmt.$O\
- fltfmt.$O\
- fmt.$O\
- fmtfd.$O\
- fmtfdflush.$O\
- fmtlocale.$O\
- fmtlock2.$O\
- fmtnull.$O\
- fmtprint.$O\
- fmtquote.$O\
- fmtrune.$O\
- fmtstr.$O\
- fmtvprint.$O\
- fprint.$O\
- nan64.$O\
- print.$O\
- seprint.$O\
- smprint.$O\
- snprint.$O\
- sprint.$O\
- strtod.$O\
- vfprint.$O\
- vseprint.$O\
- vsmprint.$O\
- vsnprint.$O\
- $(NUM)\
-
-UTFOFILES=\
- rune.$O\
- utfecpy.$O\
- utflen.$O\
- utfnlen.$O\
- utfrrune.$O\
- utfrune.$O\
- utfutf.$O\
- runetype.$O\
-
-LIB9OFILES=\
- _p9dir.$O\
- _exits.$O\
- argv0.$O\
- atoi.$O\
- cleanname.$O\
- create.$O\
- dirfstat.$O\
- dirfwstat.$O\
- dirstat.$O\
- dirwstat.$O\
- dup.$O\
- errstr.$O\
- exec.$O\
- execl.$O\
- exitcode.$O\
- exits.$O\
- getenv.$O\
- getfields.$O\
- getwd.$O\
- goos.$O\
- main.$O\
- nan.$O\
- nulldir.$O\
- open.$O\
- readn.$O\
- seek.$O\
- strecpy.$O\
- sysfatal.$O\
- time.$O\
- tokenize.$O\
-
-ifeq ($(GOHOSTOS),windows)
-LIB9OFILES+=\
- win32.$O\
-
-else
-LIB9OFILES+=\
- await.$O\
- getuser.$O\
- jmp.$O\
- notify.$O\
- rfork.$O\
-
-endif
-
-OFILES=\
- $(LIB9OFILES)\
- $(FMTOFILES)\
- $(UTFOFILES)\
-
-HFILES=\
- $(QUOTED_GOROOT)/include/u.h\
- $(QUOTED_GOROOT)/include/libc.h\
-
-include ../Make.clib
-
-GOROOT_FINAL?=$(GOROOT)
-
-%.$O: fmt/%.c
- $(HOST_CC) -c $(HOST_CFLAGS) -DPLAN9PORT -Ifmt $<
-
-%.$O: utf/%.c
- $(HOST_CC) -c $(HOST_CFLAGS) $<
-
-goos.$O: goos.c
- GOVERSION=`../version.bash` && \
- $(HOST_CC) -c $(HOST_CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT_FINAL)"' -DGOVERSION='"'"$$GOVERSION"'"' $<
-
+include ../Make.dist
diff --git a/src/lib9/await.c b/src/lib9/await.c
index 90be598a1..0f00a94bd 100644
--- a/src/lib9/await.c
+++ b/src/lib9/await.c
@@ -1,3 +1,5 @@
+// +build !windows
+
/*
Plan 9 from User Space src/lib9/await.c
http://code.swtch.com/plan9port/src/tip/src/lib9/await.c
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
new file mode 100644
index 000000000..1bc29fbf9
--- /dev/null
+++ b/src/lib9/ctime.c
@@ -0,0 +1,28 @@
+// 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.
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+
+char*
+p9ctime(long t)
+{
+ static char buf[100];
+ time_t tt;
+ struct tm *tm;
+
+ tt = t;
+ tm = localtime(&tt);
+ snprint(buf, sizeof buf, "%3.3s %3.3s %02d %02d:%02d:%02d %3.3s %d\n",
+ "SunMonTueWedThuFriSat"+(tm->tm_wday*3),
+ "JanFebMarAprMayJunJulAugSepOctNovDec"+(tm->tm_mon*3),
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ "XXX", // tm_zone is unavailable on windows, and no one cares
+ tm->tm_year + 1900);
+ return buf;
+}
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
index 234492acf..a952b2da2 100644
--- a/src/lib9/exitcode.c
+++ b/src/lib9/exitcode.c
@@ -29,6 +29,7 @@ THE SOFTWARE.
int
exitcode(char *s)
{
+ USED(s);
return 1;
}
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
deleted file mode 100644
index 66c9600f0..000000000
--- a/src/lib9/fmt/errfmt.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- * Copyright (c) 2002-2006 by Lucent Technologies.
- * Portions Copyright (c) 2004 Google Inc.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-__errfmt(Fmt *f)
-{
- char *s;
-
- s = strerror(errno);
- return fmtstrcpy(f, s);
-}
diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
index 8a29e6faf..6848ab4eb 100644
--- a/src/lib9/fmt/fmtprint.c
+++ b/src/lib9/fmt/fmtprint.c
@@ -21,31 +21,19 @@
#include "fmtdef.h"
/*
- * format a string into the output buffer
- * designed for formats which themselves call fmt,
- * but ignore any width flags
+ * Format a string into the output buffer.
+ * Designed for formats which themselves call fmt.
+ * Flags, precision and width are preserved.
*/
int
fmtprint(Fmt *f, char *fmt, ...)
{
- va_list va;
int n;
+ va_list va;
- f->flags = 0;
- f->width = 0;
- f->prec = 0;
- VA_COPY(va, f->args);
- VA_END(f->args);
- va_start(f->args, fmt);
- n = dofmt(f, fmt);
- va_end(f->args);
- f->flags = 0;
- f->width = 0;
- f->prec = 0;
- VA_COPY(f->args,va);
- VA_END(va);
- if(n >= 0)
- return 0;
+ va_start(va, fmt);
+ n = fmtvprint(f, fmt, va);
+ va_end(va);
return n;
}
diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
index 6acd37a51..f18d27bba 100644
--- a/src/lib9/fmt/fmtvprint.c
+++ b/src/lib9/fmt/fmtvprint.c
@@ -22,31 +22,31 @@
/*
- * format a string into the output buffer
- * designed for formats which themselves call fmt,
- * but ignore any width flags
+ * Format a string into the output buffer.
+ * Designed for formats which themselves call fmt.
+ * Flags, precision and width are preserved.
*/
int
fmtvprint(Fmt *f, char *fmt, va_list args)
{
va_list va;
- int n;
+ int n, w, p;
+ unsigned long fl;
- f->flags = 0;
- f->width = 0;
- f->prec = 0;
- VA_COPY(va,f->args);
+ w = f->width;
+ p = f->prec;
+ fl = f->flags;
+ VA_COPY(va, f->args);
VA_END(f->args);
- VA_COPY(f->args,args);
+ VA_COPY(f->args, args);
n = dofmt(f, fmt);
- f->flags = 0;
- f->width = 0;
- f->prec = 0;
VA_END(f->args);
- VA_COPY(f->args,va);
+ VA_COPY(f->args, va);
VA_END(va);
+ f->width = w;
+ f->prec = p;
+ f->flags = fl;
if(n >= 0)
return 0;
return n;
}
-
diff --git a/src/lib9/fork.c b/src/lib9/fork.c
deleted file mode 100644
index 0dd79dfb8..000000000
--- a/src/lib9/fork.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-Plan 9 from User Space src/lib9/fork.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/fork.c
-
-Copyright 2001-2007 Russ Cox. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-#include <u.h>
-#include <signal.h>
-#include <libc.h>
-#include "9proc.h"
-#undef fork
-
-int
-p9fork(void)
-{
- int pid;
- sigset_t all, old;
-
- sigfillset(&all);
- sigprocmask(SIG_SETMASK, &all, &old);
- pid = fork();
- if(pid == 0){
- _clearuproc();
- _p9uproc(0);
- }
- sigprocmask(SIG_SETMASK, &old, nil);
- return pid;
-}
diff --git a/src/lib9/getuser.c b/src/lib9/getuser.c
index f70b35c87..d611f4467 100644
--- a/src/lib9/getuser.c
+++ b/src/lib9/getuser.c
@@ -1,3 +1,5 @@
+// +build !windows
+
/*
Plan 9 from User Space src/lib9/getuser.c
http://code.swtch.com/plan9port/src/tip/src/lib9/getuser.c
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
index a606fb07b..c44e040d2 100644
--- a/src/lib9/jmp.c
+++ b/src/lib9/jmp.c
@@ -1,3 +1,5 @@
+// +build !windows
+
/*
Plan 9 from User Space src/lib9/jmp.c
http://code.swtch.com/plan9port/src/tip/src/lib9/jmp.c
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
index 84999b887..c424aed54 100644
--- a/src/lib9/notify.c
+++ b/src/lib9/notify.c
@@ -1,3 +1,5 @@
+// +build !windows
+
/*
Plan 9 from User Space src/lib9/notify.c
http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
index c9d632189..5a6eaeb94 100644
--- a/src/lib9/rfork.c
+++ b/src/lib9/rfork.c
@@ -1,3 +1,5 @@
+// +build !windows
+
/*
Plan 9 from User Space src/lib9/rfork.c
http://code.swtch.com/plan9port/src/tip/src/lib9/rfork.c
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
index c3b9ec5d0..bbb2da6a9 100644
--- a/src/lib9/utf/Makefile
+++ b/src/lib9/utf/Makefile
@@ -4,21 +4,17 @@
# The library is built by the Makefile in the parent directory.
# This Makefile only builds mkrunetype.
-
-include ../../Make.inc
-O:=$(HOST_O)
+# GOROOT, GOOS, and GOARCH must be set explicitly.
TARG=mkrunetype
-OFILES=\
- mkrunetype.$O\
-
-include ../../Make.ccmd
-
UnicodeData-%.txt:
curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@
mv _$@ $@
+mkrunetype: mkrunetype.c
+ cc -I../../../include -o mkrunetype -L$(GOROOT)/pkg/obj/$(GOOS)_$(GOARCH)/ mkrunetype.c -l9
+
runetypebody-%.c: mkrunetype UnicodeData-%.txt
mkrunetype -p UnicodeData-$*.txt >_$@
mv _$@ $@
@@ -30,3 +26,5 @@ UNICODE_VERSION=6.0.0
test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
+clean:
+ rm -f UnicodeData.txt mkrunetype \ No newline at end of file
diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c
index 06d52b572..01eb6b6ec 100644
--- a/src/lib9/utf/mkrunetype.c
+++ b/src/lib9/utf/mkrunetype.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
/*
* make is(upper|lower|title|space|alpha)rune and
* to(upper|lower|title)rune from a UnicodeData.txt file.
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
index 27867430b..51729fb01 100644
--- a/src/lib9/utf/runetype.c
+++ b/src/lib9/utf/runetype.c
@@ -35,4 +35,4 @@ rbsearch(Rune c, Rune *t, int n, int ne)
return 0;
}
-#include "runetypebody-6.0.0.c"
+#include "runetypebody-6.0.0.h"
diff --git a/src/lib9/utf/runetypebody-5.0.0.c b/src/lib9/utf/runetypebody-5.0.0.c
deleted file mode 100644
index 67a645d60..000000000
--- a/src/lib9/utf/runetypebody-5.0.0.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-/* generated automatically by mkrunetype.c from UnicodeData-5.0.0.txt */
-
-static Rune __isspacer[] = {
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x180e, 0x180e,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
- 0xfeff, 0xfeff,
-};
-
-int
-isspacerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- return 0;
-}
-
-static Rune __isdigitr[] = {
- 0x0030, 0x0039,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0be6, 0x0bef,
- 0x0c66, 0x0c6f,
- 0x0ce6, 0x0cef,
- 0x0d66, 0x0d6f,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f29,
- 0x1040, 0x1049,
- 0x17e0, 0x17e9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19d9,
- 0x1b50, 0x1b59,
- 0xff10, 0xff19,
- 0x104a0, 0x104a9,
- 0x1d7ce, 0x1d7ff,
-};
-
-int
-isdigitrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- return 0;
-}
-
-static Rune __isalphar[] = {
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x037a, 0x037d,
- 0x0388, 0x038a,
- 0x038e, 0x03a1,
- 0x03a3, 0x03ce,
- 0x03d0, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x0513,
- 0x0531, 0x0556,
- 0x0561, 0x0587,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f2,
- 0x0621, 0x063a,
- 0x0640, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x0712, 0x072f,
- 0x074d, 0x076d,
- 0x0780, 0x07a5,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x0904, 0x0939,
- 0x0958, 0x0961,
- 0x097b, 0x097f,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b6, 0x09b9,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0ae0, 0x0ae1,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c60, 0x0c61,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0ce0, 0x0ce1,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d60, 0x0d61,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e87, 0x0e88,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ec0, 0x0ec4,
- 0x0edc, 0x0edd,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6a,
- 0x0f88, 0x0f8b,
- 0x1000, 0x1021,
- 0x1023, 0x1027,
- 0x1029, 0x102a,
- 0x1050, 0x1055,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fa,
- 0x1100, 0x1159,
- 0x115f, 0x11a2,
- 0x11a8, 0x11f9,
- 0x1200, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x125a, 0x125d,
- 0x1260, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12d6,
- 0x12d8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135a,
- 0x1380, 0x138f,
- 0x13a0, 0x13f4,
- 0x1401, 0x166c,
- 0x166f, 0x1676,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x1700, 0x170c,
- 0x170e, 0x1711,
- 0x1720, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x1820, 0x1877,
- 0x1880, 0x18a8,
- 0x1900, 0x191c,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19a9,
- 0x19c1, 0x19c7,
- 0x1a00, 0x1a16,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4b,
- 0x1d00, 0x1dbf,
- 0x1e00, 0x1e9b,
- 0x1ea0, 0x1ef9,
- 0x1f00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fbc,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fcc,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fe0, 0x1fec,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffc,
- 0x2090, 0x2094,
- 0x210a, 0x2113,
- 0x2119, 0x211d,
- 0x212a, 0x212d,
- 0x212f, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x2183, 0x2184,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2c6c,
- 0x2c74, 0x2c77,
- 0x2c80, 0x2ce4,
- 0x2d00, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x3005, 0x3006,
- 0x3031, 0x3035,
- 0x303b, 0x303c,
- 0x3041, 0x3096,
- 0x309d, 0x309f,
- 0x30a1, 0x30fa,
- 0x30fc, 0x30ff,
- 0x3105, 0x312c,
- 0x3131, 0x318e,
- 0x31a0, 0x31b7,
- 0x31f0, 0x31ff,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fbb,
- 0xa000, 0xa48c,
- 0xa717, 0xa71a,
- 0xa800, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xac00, 0xd7a3,
- 0xf900, 0xfa2d,
- 0xfa30, 0xfa6a,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1f, 0xfb28,
- 0xfb2a, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0xff66, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10300, 0x1031e,
- 0x10330, 0x10340,
- 0x10342, 0x10349,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 0x10400, 0x1049d,
- 0x10800, 0x10805,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x10900, 0x10915,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x12000, 0x1236e,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a5,
- 0x1d6a8, 0x1d6c0,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6fa,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d734,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d76e,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d7a8,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7cb,
- 0x20000, 0x2a6d6,
- 0x2f800, 0x2fa1d,
-};
-
-static Rune __isalphas[] = {
- 0x00aa,
- 0x00b5,
- 0x00ba,
- 0x02ee,
- 0x0386,
- 0x038c,
- 0x0559,
- 0x06d5,
- 0x06ff,
- 0x0710,
- 0x07b1,
- 0x07fa,
- 0x093d,
- 0x0950,
- 0x09b2,
- 0x09bd,
- 0x09ce,
- 0x0a5e,
- 0x0abd,
- 0x0ad0,
- 0x0b3d,
- 0x0b71,
- 0x0b83,
- 0x0b9c,
- 0x0cbd,
- 0x0cde,
- 0x0dbd,
- 0x0e84,
- 0x0e8a,
- 0x0e8d,
- 0x0ea5,
- 0x0ea7,
- 0x0ebd,
- 0x0ec6,
- 0x0f00,
- 0x10fc,
- 0x1258,
- 0x12c0,
- 0x17d7,
- 0x17dc,
- 0x1f59,
- 0x1f5b,
- 0x1f5d,
- 0x1fbe,
- 0x2071,
- 0x207f,
- 0x2102,
- 0x2107,
- 0x2115,
- 0x2124,
- 0x2126,
- 0x2128,
- 0x214e,
- 0x2d6f,
- 0xfb1d,
- 0xfb3e,
- 0x10808,
- 0x1083c,
- 0x1083f,
- 0x10a00,
- 0x1d4a2,
- 0x1d4bb,
- 0x1d546,
-};
-
-int
-isalpharune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __isupperr[] = {
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0178, 0x0179,
- 0x0181, 0x0182,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a6, 0x01a7,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b7, 0x01b8,
- 0x01f6, 0x01f8,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0243, 0x0246,
- 0x0388, 0x038a,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03d2, 0x03d4,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x04c0, 0x04c1,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x1f08, 0x1f0f,
- 0x1f18, 0x1f1d,
- 0x1f28, 0x1f2f,
- 0x1f38, 0x1f3f,
- 0x1f48, 0x1f4d,
- 0x1f68, 0x1f6f,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fb8, 0x1fbc,
- 0x1fc8, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffc,
- 0x210b, 0x210d,
- 0x2110, 0x2112,
- 0x2119, 0x211d,
- 0x212a, 0x212d,
- 0x2130, 0x2133,
- 0x213e, 0x213f,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x2c00, 0x2c2e,
- 0x2c62, 0x2c64,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x1d400, 0x1d419,
- 0x1d434, 0x1d44d,
- 0x1d468, 0x1d481,
- 0x1d49e, 0x1d49f,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b5,
- 0x1d4d0, 0x1d4e9,
- 0x1d504, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d538, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d54a, 0x1d550,
- 0x1d56c, 0x1d585,
- 0x1d5a0, 0x1d5b9,
- 0x1d5d4, 0x1d5ed,
- 0x1d608, 0x1d621,
- 0x1d63c, 0x1d655,
- 0x1d670, 0x1d689,
- 0x1d6a8, 0x1d6c0,
- 0x1d6e2, 0x1d6fa,
- 0x1d71c, 0x1d734,
- 0x1d756, 0x1d76e,
- 0x1d790, 0x1d7a8,
-};
-
-static Rune __isupperp[] = {
- 0x0100, 0x0136,
- 0x0139, 0x0147,
- 0x014a, 0x0176,
- 0x017b, 0x017d,
- 0x01a2, 0x01a4,
- 0x01cd, 0x01db,
- 0x01de, 0x01ee,
- 0x01fa, 0x0232,
- 0x0248, 0x024e,
- 0x03d8, 0x03ee,
- 0x0460, 0x0480,
- 0x048a, 0x04be,
- 0x04c3, 0x04cd,
- 0x04d0, 0x0512,
- 0x1e00, 0x1e94,
- 0x1ea0, 0x1ef8,
- 0x1f59, 0x1f5f,
- 0x2124, 0x2128,
- 0x2c67, 0x2c6b,
- 0x2c80, 0x2ce2,
-};
-
-static Rune __isuppers[] = {
- 0x0184,
- 0x01a9,
- 0x01ac,
- 0x01b5,
- 0x01bc,
- 0x01c4,
- 0x01c7,
- 0x01ca,
- 0x01f1,
- 0x01f4,
- 0x0241,
- 0x0386,
- 0x038c,
- 0x03f4,
- 0x03f7,
- 0x2102,
- 0x2107,
- 0x2115,
- 0x2145,
- 0x2183,
- 0x2c60,
- 0x2c75,
- 0x1d49c,
- 0x1d4a2,
- 0x1d546,
- 0x1d7ca,
-};
-
-int
-isupperrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __islowerr[] = {
- 0x0061, 0x007a,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0137, 0x0138,
- 0x0148, 0x0149,
- 0x017e, 0x0180,
- 0x018c, 0x018d,
- 0x0199, 0x019b,
- 0x01aa, 0x01ab,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01dc, 0x01dd,
- 0x01ef, 0x01f0,
- 0x0233, 0x0239,
- 0x023f, 0x0240,
- 0x024f, 0x0293,
- 0x0295, 0x02af,
- 0x037b, 0x037d,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03ef, 0x03f3,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x04ce, 0x04cf,
- 0x0561, 0x0587,
- 0x1d00, 0x1d2b,
- 0x1d62, 0x1d77,
- 0x1d79, 0x1d9a,
- 0x1e95, 0x1e9b,
- 0x1f00, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x210e, 0x210f,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x2170, 0x217f,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5e,
- 0x2c65, 0x2c66,
- 0x2c76, 0x2c77,
- 0x2ce3, 0x2ce4,
- 0x2d00, 0x2d25,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
-};
-
-static Rune __islowerp[] = {
- 0x0101, 0x0135,
- 0x013a, 0x0146,
- 0x014b, 0x0177,
- 0x017a, 0x017c,
- 0x0183, 0x0185,
- 0x01a1, 0x01a5,
- 0x01b4, 0x01b6,
- 0x01cc, 0x01da,
- 0x01df, 0x01ed,
- 0x01f3, 0x01f5,
- 0x01f9, 0x0231,
- 0x0247, 0x024d,
- 0x03d9, 0x03ed,
- 0x0461, 0x0481,
- 0x048b, 0x04bf,
- 0x04c2, 0x04cc,
- 0x04d1, 0x0513,
- 0x1e01, 0x1e93,
- 0x1ea1, 0x1ef9,
- 0x2c68, 0x2c6c,
- 0x2c81, 0x2ce1,
-};
-
-static Rune __islowers[] = {
- 0x00aa,
- 0x00b5,
- 0x00ba,
- 0x0188,
- 0x0192,
- 0x0195,
- 0x019e,
- 0x01a8,
- 0x01ad,
- 0x01b0,
- 0x01c6,
- 0x01c9,
- 0x023c,
- 0x0242,
- 0x0390,
- 0x03f5,
- 0x03f8,
- 0x1fbe,
- 0x2071,
- 0x207f,
- 0x210a,
- 0x2113,
- 0x212f,
- 0x2134,
- 0x2139,
- 0x214e,
- 0x2184,
- 0x2c61,
- 0x2c74,
- 0x1d4bb,
- 0x1d7cb,
-};
-
-int
-islowerrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __islowers, nelem(__islowers), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __istitler[] = {
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0178, 0x0179,
- 0x0181, 0x0182,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a6, 0x01a7,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b7, 0x01b8,
- 0x01f6, 0x01f8,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0243, 0x0246,
- 0x0388, 0x038a,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x04c0, 0x04c1,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x1f08, 0x1f0f,
- 0x1f18, 0x1f1d,
- 0x1f28, 0x1f2f,
- 0x1f38, 0x1f3f,
- 0x1f48, 0x1f4d,
- 0x1f68, 0x1f6f,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fb8, 0x1fbc,
- 0x1fc8, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffc,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x2c00, 0x2c2e,
- 0x2c62, 0x2c64,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
-};
-
-static Rune __istitlep[] = {
- 0x0100, 0x012e,
- 0x0132, 0x0136,
- 0x0139, 0x0147,
- 0x014a, 0x0176,
- 0x017b, 0x017d,
- 0x01a2, 0x01a4,
- 0x01cb, 0x01db,
- 0x01de, 0x01ee,
- 0x01f2, 0x01f4,
- 0x01fa, 0x0232,
- 0x0248, 0x024e,
- 0x03d8, 0x03ee,
- 0x0460, 0x0480,
- 0x048a, 0x04be,
- 0x04c3, 0x04cd,
- 0x04d0, 0x0512,
- 0x1e00, 0x1e94,
- 0x1ea0, 0x1ef8,
- 0x1f59, 0x1f5f,
- 0x2c67, 0x2c6b,
- 0x2c80, 0x2ce2,
-};
-
-static Rune __istitles[] = {
- 0x0184,
- 0x01a9,
- 0x01ac,
- 0x01b5,
- 0x01bc,
- 0x01c5,
- 0x01c8,
- 0x0241,
- 0x0386,
- 0x038c,
- 0x03f7,
- 0x2132,
- 0x2183,
- 0x2c60,
- 0x2c75,
-};
-
-int
-istitlerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __istitles, nelem(__istitles), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __toupperr[] = {
- 0x0061, 0x007a, 1048544,
- 0x00e0, 0x00f6, 1048544,
- 0x00f8, 0x00fe, 1048544,
- 0x0256, 0x0257, 1048371,
- 0x028a, 0x028b, 1048359,
- 0x037b, 0x037d, 1048706,
- 0x03ad, 0x03af, 1048539,
- 0x03b1, 0x03c1, 1048544,
- 0x03c3, 0x03cb, 1048544,
- 0x03cd, 0x03ce, 1048513,
- 0x0430, 0x044f, 1048544,
- 0x0450, 0x045f, 1048496,
- 0x0561, 0x0586, 1048528,
- 0x1f00, 0x1f07, 1048584,
- 0x1f10, 0x1f15, 1048584,
- 0x1f20, 0x1f27, 1048584,
- 0x1f30, 0x1f37, 1048584,
- 0x1f40, 0x1f45, 1048584,
- 0x1f60, 0x1f67, 1048584,
- 0x1f70, 0x1f71, 1048650,
- 0x1f72, 0x1f75, 1048662,
- 0x1f76, 0x1f77, 1048676,
- 0x1f78, 0x1f79, 1048704,
- 0x1f7a, 0x1f7b, 1048688,
- 0x1f7c, 0x1f7d, 1048702,
- 0x1f80, 0x1f87, 1048584,
- 0x1f90, 0x1f97, 1048584,
- 0x1fa0, 0x1fa7, 1048584,
- 0x1fb0, 0x1fb1, 1048584,
- 0x1fd0, 0x1fd1, 1048584,
- 0x1fe0, 0x1fe1, 1048584,
- 0x2170, 0x217f, 1048560,
- 0x24d0, 0x24e9, 1048550,
- 0x2c30, 0x2c5e, 1048528,
- 0x2d00, 0x2d25, 1041312,
- 0xff41, 0xff5a, 1048544,
- 0x10428, 0x1044f, 1048536,
-};
-
-static Rune __toupperp[] = {
- 0x0101, 0x012f, 1048575,
- 0x0133, 0x0137, 1048575,
- 0x013a, 0x0148, 1048575,
- 0x014b, 0x0177, 1048575,
- 0x017a, 0x017e, 1048575,
- 0x0183, 0x0185, 1048575,
- 0x01a1, 0x01a5, 1048575,
- 0x01b4, 0x01b6, 1048575,
- 0x01ce, 0x01dc, 1048575,
- 0x01df, 0x01ef, 1048575,
- 0x01f9, 0x021f, 1048575,
- 0x0223, 0x0233, 1048575,
- 0x0247, 0x024f, 1048575,
- 0x03d9, 0x03ef, 1048575,
- 0x0461, 0x0481, 1048575,
- 0x048b, 0x04bf, 1048575,
- 0x04c2, 0x04ce, 1048575,
- 0x04d1, 0x0513, 1048575,
- 0x1e01, 0x1e95, 1048575,
- 0x1ea1, 0x1ef9, 1048575,
- 0x1f51, 0x1f57, 1048584,
- 0x2c68, 0x2c6c, 1048575,
- 0x2c81, 0x2ce3, 1048575,
-};
-
-static Rune __touppers[] = {
- 0x00b5, 1049319,
- 0x00ff, 1048697,
- 0x0131, 1048344,
- 0x017f, 1048276,
- 0x0180, 1048771,
- 0x0188, 1048575,
- 0x018c, 1048575,
- 0x0192, 1048575,
- 0x0195, 1048673,
- 0x0199, 1048575,
- 0x019a, 1048739,
- 0x019e, 1048706,
- 0x01a8, 1048575,
- 0x01ad, 1048575,
- 0x01b0, 1048575,
- 0x01b9, 1048575,
- 0x01bd, 1048575,
- 0x01bf, 1048632,
- 0x01c5, 1048575,
- 0x01c6, 1048574,
- 0x01c8, 1048575,
- 0x01c9, 1048574,
- 0x01cb, 1048575,
- 0x01cc, 1048574,
- 0x01dd, 1048497,
- 0x01f2, 1048575,
- 0x01f3, 1048574,
- 0x01f5, 1048575,
- 0x023c, 1048575,
- 0x0242, 1048575,
- 0x0253, 1048366,
- 0x0254, 1048370,
- 0x0259, 1048374,
- 0x025b, 1048373,
- 0x0260, 1048371,
- 0x0263, 1048369,
- 0x0268, 1048367,
- 0x0269, 1048365,
- 0x026b, 1059319,
- 0x026f, 1048365,
- 0x0272, 1048363,
- 0x0275, 1048362,
- 0x027d, 1059303,
- 0x0280, 1048358,
- 0x0283, 1048358,
- 0x0288, 1048358,
- 0x0289, 1048507,
- 0x028c, 1048505,
- 0x0292, 1048357,
- 0x0345, 1048660,
- 0x03ac, 1048538,
- 0x03c2, 1048545,
- 0x03cc, 1048512,
- 0x03d0, 1048514,
- 0x03d1, 1048519,
- 0x03d5, 1048529,
- 0x03d6, 1048522,
- 0x03f0, 1048490,
- 0x03f1, 1048496,
- 0x03f2, 1048583,
- 0x03f5, 1048480,
- 0x03f8, 1048575,
- 0x03fb, 1048575,
- 0x04cf, 1048561,
- 0x1d7d, 1052390,
- 0x1e9b, 1048517,
- 0x1fb3, 1048585,
- 0x1fbe, 1041371,
- 0x1fc3, 1048585,
- 0x1fe5, 1048583,
- 0x1ff3, 1048585,
- 0x214e, 1048548,
- 0x2184, 1048575,
- 0x2c61, 1048575,
- 0x2c65, 1037781,
- 0x2c66, 1037784,
- 0x2c76, 1048575,
-};
-
-Rune
-toupperrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
-static Rune __tolowerr[] = {
- 0x0041, 0x005a, 1048608,
- 0x00c0, 0x00d6, 1048608,
- 0x00d8, 0x00de, 1048608,
- 0x0189, 0x018a, 1048781,
- 0x01b1, 0x01b2, 1048793,
- 0x0388, 0x038a, 1048613,
- 0x038e, 0x038f, 1048639,
- 0x0391, 0x03a1, 1048608,
- 0x03a3, 0x03ab, 1048608,
- 0x03fd, 0x03ff, 1048446,
- 0x0400, 0x040f, 1048656,
- 0x0410, 0x042f, 1048608,
- 0x0531, 0x0556, 1048624,
- 0x10a0, 0x10c5, 1055840,
- 0x1f08, 0x1f0f, 1048568,
- 0x1f18, 0x1f1d, 1048568,
- 0x1f28, 0x1f2f, 1048568,
- 0x1f38, 0x1f3f, 1048568,
- 0x1f48, 0x1f4d, 1048568,
- 0x1f68, 0x1f6f, 1048568,
- 0x1f88, 0x1f8f, 1048568,
- 0x1f98, 0x1f9f, 1048568,
- 0x1fa8, 0x1faf, 1048568,
- 0x1fb8, 0x1fb9, 1048568,
- 0x1fba, 0x1fbb, 1048502,
- 0x1fc8, 0x1fcb, 1048490,
- 0x1fd8, 0x1fd9, 1048568,
- 0x1fda, 0x1fdb, 1048476,
- 0x1fe8, 0x1fe9, 1048568,
- 0x1fea, 0x1feb, 1048464,
- 0x1ff8, 0x1ff9, 1048448,
- 0x1ffa, 0x1ffb, 1048450,
- 0x2160, 0x216f, 1048592,
- 0x24b6, 0x24cf, 1048602,
- 0x2c00, 0x2c2e, 1048624,
- 0xff21, 0xff3a, 1048608,
- 0x10400, 0x10427, 1048616,
-};
-
-static Rune __tolowerp[] = {
- 0x0100, 0x012e, 1048577,
- 0x0132, 0x0136, 1048577,
- 0x0139, 0x0147, 1048577,
- 0x014a, 0x0176, 1048577,
- 0x017b, 0x017d, 1048577,
- 0x01a2, 0x01a4, 1048577,
- 0x01b3, 0x01b5, 1048577,
- 0x01cd, 0x01db, 1048577,
- 0x01de, 0x01ee, 1048577,
- 0x01f8, 0x021e, 1048577,
- 0x0222, 0x0232, 1048577,
- 0x0248, 0x024e, 1048577,
- 0x03d8, 0x03ee, 1048577,
- 0x0460, 0x0480, 1048577,
- 0x048a, 0x04be, 1048577,
- 0x04c3, 0x04cd, 1048577,
- 0x04d0, 0x0512, 1048577,
- 0x1e00, 0x1e94, 1048577,
- 0x1ea0, 0x1ef8, 1048577,
- 0x1f59, 0x1f5f, 1048568,
- 0x2c67, 0x2c6b, 1048577,
- 0x2c80, 0x2ce2, 1048577,
-};
-
-static Rune __tolowers[] = {
- 0x0130, 1048377,
- 0x0178, 1048455,
- 0x0179, 1048577,
- 0x0181, 1048786,
- 0x0182, 1048577,
- 0x0184, 1048577,
- 0x0186, 1048782,
- 0x0187, 1048577,
- 0x018b, 1048577,
- 0x018e, 1048655,
- 0x018f, 1048778,
- 0x0190, 1048779,
- 0x0191, 1048577,
- 0x0193, 1048781,
- 0x0194, 1048783,
- 0x0196, 1048787,
- 0x0197, 1048785,
- 0x0198, 1048577,
- 0x019c, 1048787,
- 0x019d, 1048789,
- 0x019f, 1048790,
- 0x01a0, 1048577,
- 0x01a6, 1048794,
- 0x01a7, 1048577,
- 0x01a9, 1048794,
- 0x01ac, 1048577,
- 0x01ae, 1048794,
- 0x01af, 1048577,
- 0x01b7, 1048795,
- 0x01b8, 1048577,
- 0x01bc, 1048577,
- 0x01c4, 1048578,
- 0x01c5, 1048577,
- 0x01c7, 1048578,
- 0x01c8, 1048577,
- 0x01ca, 1048578,
- 0x01cb, 1048577,
- 0x01f1, 1048578,
- 0x01f2, 1048577,
- 0x01f4, 1048577,
- 0x01f6, 1048479,
- 0x01f7, 1048520,
- 0x0220, 1048446,
- 0x023a, 1059371,
- 0x023b, 1048577,
- 0x023d, 1048413,
- 0x023e, 1059368,
- 0x0241, 1048577,
- 0x0243, 1048381,
- 0x0244, 1048645,
- 0x0245, 1048647,
- 0x0246, 1048577,
- 0x0386, 1048614,
- 0x038c, 1048640,
- 0x03f4, 1048516,
- 0x03f7, 1048577,
- 0x03f9, 1048569,
- 0x03fa, 1048577,
- 0x04c0, 1048591,
- 0x04c1, 1048577,
- 0x1fbc, 1048567,
- 0x1fcc, 1048567,
- 0x1fec, 1048569,
- 0x1ffc, 1048567,
- 0x2126, 1041059,
- 0x212a, 1040193,
- 0x212b, 1040314,
- 0x2132, 1048604,
- 0x2183, 1048577,
- 0x2c60, 1048577,
- 0x2c62, 1037833,
- 0x2c63, 1044762,
- 0x2c64, 1037849,
- 0x2c75, 1048577,
-};
-
-Rune
-tolowerrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
-static Rune __totitler[] = {
- 0x0061, 0x007a, 1048544,
- 0x00e0, 0x00f6, 1048544,
- 0x00f8, 0x00fe, 1048544,
- 0x0256, 0x0257, 1048371,
- 0x028a, 0x028b, 1048359,
- 0x037b, 0x037d, 1048706,
- 0x03ad, 0x03af, 1048539,
- 0x03b1, 0x03c1, 1048544,
- 0x03c3, 0x03cb, 1048544,
- 0x03cd, 0x03ce, 1048513,
- 0x0430, 0x044f, 1048544,
- 0x0450, 0x045f, 1048496,
- 0x0561, 0x0586, 1048528,
- 0x1f00, 0x1f07, 1048584,
- 0x1f10, 0x1f15, 1048584,
- 0x1f20, 0x1f27, 1048584,
- 0x1f30, 0x1f37, 1048584,
- 0x1f40, 0x1f45, 1048584,
- 0x1f60, 0x1f67, 1048584,
- 0x1f70, 0x1f71, 1048650,
- 0x1f72, 0x1f75, 1048662,
- 0x1f76, 0x1f77, 1048676,
- 0x1f78, 0x1f79, 1048704,
- 0x1f7a, 0x1f7b, 1048688,
- 0x1f7c, 0x1f7d, 1048702,
- 0x1f80, 0x1f87, 1048584,
- 0x1f90, 0x1f97, 1048584,
- 0x1fa0, 0x1fa7, 1048584,
- 0x1fb0, 0x1fb1, 1048584,
- 0x1fd0, 0x1fd1, 1048584,
- 0x1fe0, 0x1fe1, 1048584,
- 0x2170, 0x217f, 1048560,
- 0x24d0, 0x24e9, 1048550,
- 0x2c30, 0x2c5e, 1048528,
- 0x2d00, 0x2d25, 1041312,
- 0xff41, 0xff5a, 1048544,
- 0x10428, 0x1044f, 1048536,
-};
-
-static Rune __totitlep[] = {
- 0x0101, 0x012f, 1048575,
- 0x0133, 0x0137, 1048575,
- 0x013a, 0x0148, 1048575,
- 0x014b, 0x0177, 1048575,
- 0x017a, 0x017e, 1048575,
- 0x0183, 0x0185, 1048575,
- 0x01a1, 0x01a5, 1048575,
- 0x01b4, 0x01b6, 1048575,
- 0x01cc, 0x01dc, 1048575,
- 0x01df, 0x01ef, 1048575,
- 0x01f3, 0x01f5, 1048575,
- 0x01f9, 0x021f, 1048575,
- 0x0223, 0x0233, 1048575,
- 0x0247, 0x024f, 1048575,
- 0x03d9, 0x03ef, 1048575,
- 0x0461, 0x0481, 1048575,
- 0x048b, 0x04bf, 1048575,
- 0x04c2, 0x04ce, 1048575,
- 0x04d1, 0x0513, 1048575,
- 0x1e01, 0x1e95, 1048575,
- 0x1ea1, 0x1ef9, 1048575,
- 0x1f51, 0x1f57, 1048584,
- 0x2c68, 0x2c6c, 1048575,
- 0x2c81, 0x2ce3, 1048575,
-};
-
-static Rune __totitles[] = {
- 0x00b5, 1049319,
- 0x00ff, 1048697,
- 0x0131, 1048344,
- 0x017f, 1048276,
- 0x0180, 1048771,
- 0x0188, 1048575,
- 0x018c, 1048575,
- 0x0192, 1048575,
- 0x0195, 1048673,
- 0x0199, 1048575,
- 0x019a, 1048739,
- 0x019e, 1048706,
- 0x01a8, 1048575,
- 0x01ad, 1048575,
- 0x01b0, 1048575,
- 0x01b9, 1048575,
- 0x01bd, 1048575,
- 0x01bf, 1048632,
- 0x01c4, 1048577,
- 0x01c6, 1048575,
- 0x01c7, 1048577,
- 0x01c9, 1048575,
- 0x01ca, 1048577,
- 0x01dd, 1048497,
- 0x01f1, 1048577,
- 0x023c, 1048575,
- 0x0242, 1048575,
- 0x0253, 1048366,
- 0x0254, 1048370,
- 0x0259, 1048374,
- 0x025b, 1048373,
- 0x0260, 1048371,
- 0x0263, 1048369,
- 0x0268, 1048367,
- 0x0269, 1048365,
- 0x026b, 1059319,
- 0x026f, 1048365,
- 0x0272, 1048363,
- 0x0275, 1048362,
- 0x027d, 1059303,
- 0x0280, 1048358,
- 0x0283, 1048358,
- 0x0288, 1048358,
- 0x0289, 1048507,
- 0x028c, 1048505,
- 0x0292, 1048357,
- 0x0345, 1048660,
- 0x03ac, 1048538,
- 0x03c2, 1048545,
- 0x03cc, 1048512,
- 0x03d0, 1048514,
- 0x03d1, 1048519,
- 0x03d5, 1048529,
- 0x03d6, 1048522,
- 0x03f0, 1048490,
- 0x03f1, 1048496,
- 0x03f2, 1048583,
- 0x03f5, 1048480,
- 0x03f8, 1048575,
- 0x03fb, 1048575,
- 0x04cf, 1048561,
- 0x1d7d, 1052390,
- 0x1e9b, 1048517,
- 0x1fb3, 1048585,
- 0x1fbe, 1041371,
- 0x1fc3, 1048585,
- 0x1fe5, 1048583,
- 0x1ff3, 1048585,
- 0x214e, 1048548,
- 0x2184, 1048575,
- 0x2c61, 1048575,
- 0x2c65, 1037781,
- 0x2c66, 1037784,
- 0x2c76, 1048575,
-};
-
-Rune
-totitlerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
diff --git a/src/lib9/utf/runetypebody-5.2.0.c b/src/lib9/utf/runetypebody-5.2.0.c
deleted file mode 100644
index 4ff66b9d9..000000000
--- a/src/lib9/utf/runetypebody-5.2.0.c
+++ /dev/null
@@ -1,1541 +0,0 @@
-/* generated automatically by mkrunetype.c from UnicodeData-5.2.0.txt */
-
-static Rune __isspacer[] = {
- 0x0009, 0x000d,
- 0x0020, 0x0020,
- 0x0085, 0x0085,
- 0x00a0, 0x00a0,
- 0x1680, 0x1680,
- 0x180e, 0x180e,
- 0x2000, 0x200a,
- 0x2028, 0x2029,
- 0x202f, 0x202f,
- 0x205f, 0x205f,
- 0x3000, 0x3000,
- 0xfeff, 0xfeff,
-};
-
-int
-isspacerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- return 0;
-}
-
-static Rune __isdigitr[] = {
- 0x0030, 0x0039,
- 0x0660, 0x0669,
- 0x06f0, 0x06f9,
- 0x07c0, 0x07c9,
- 0x0966, 0x096f,
- 0x09e6, 0x09ef,
- 0x0a66, 0x0a6f,
- 0x0ae6, 0x0aef,
- 0x0b66, 0x0b6f,
- 0x0be6, 0x0bef,
- 0x0c66, 0x0c6f,
- 0x0ce6, 0x0cef,
- 0x0d66, 0x0d6f,
- 0x0e50, 0x0e59,
- 0x0ed0, 0x0ed9,
- 0x0f20, 0x0f29,
- 0x1040, 0x1049,
- 0x1090, 0x1099,
- 0x17e0, 0x17e9,
- 0x1810, 0x1819,
- 0x1946, 0x194f,
- 0x19d0, 0x19da,
- 0x1a80, 0x1a89,
- 0x1a90, 0x1a99,
- 0x1b50, 0x1b59,
- 0x1bb0, 0x1bb9,
- 0x1c40, 0x1c49,
- 0x1c50, 0x1c59,
- 0xa620, 0xa629,
- 0xa8d0, 0xa8d9,
- 0xa900, 0xa909,
- 0xa9d0, 0xa9d9,
- 0xaa50, 0xaa59,
- 0xabf0, 0xabf9,
- 0xff10, 0xff19,
- 0x104a0, 0x104a9,
- 0x1d7ce, 0x1d7ff,
-};
-
-int
-isdigitrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- return 0;
-}
-
-static Rune __isalphar[] = {
- 0x0041, 0x005a,
- 0x0061, 0x007a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00f6,
- 0x00f8, 0x02c1,
- 0x02c6, 0x02d1,
- 0x02e0, 0x02e4,
- 0x0370, 0x0374,
- 0x0376, 0x0377,
- 0x037a, 0x037d,
- 0x0388, 0x038a,
- 0x038e, 0x03a1,
- 0x03a3, 0x03f5,
- 0x03f7, 0x0481,
- 0x048a, 0x0525,
- 0x0531, 0x0556,
- 0x0561, 0x0587,
- 0x05d0, 0x05ea,
- 0x05f0, 0x05f2,
- 0x0621, 0x064a,
- 0x066e, 0x066f,
- 0x0671, 0x06d3,
- 0x06e5, 0x06e6,
- 0x06ee, 0x06ef,
- 0x06fa, 0x06fc,
- 0x0712, 0x072f,
- 0x074d, 0x07a5,
- 0x07ca, 0x07ea,
- 0x07f4, 0x07f5,
- 0x0800, 0x0815,
- 0x0904, 0x0939,
- 0x0958, 0x0961,
- 0x0971, 0x0972,
- 0x0979, 0x097f,
- 0x0985, 0x098c,
- 0x098f, 0x0990,
- 0x0993, 0x09a8,
- 0x09aa, 0x09b0,
- 0x09b6, 0x09b9,
- 0x09dc, 0x09dd,
- 0x09df, 0x09e1,
- 0x09f0, 0x09f1,
- 0x0a05, 0x0a0a,
- 0x0a0f, 0x0a10,
- 0x0a13, 0x0a28,
- 0x0a2a, 0x0a30,
- 0x0a32, 0x0a33,
- 0x0a35, 0x0a36,
- 0x0a38, 0x0a39,
- 0x0a59, 0x0a5c,
- 0x0a72, 0x0a74,
- 0x0a85, 0x0a8d,
- 0x0a8f, 0x0a91,
- 0x0a93, 0x0aa8,
- 0x0aaa, 0x0ab0,
- 0x0ab2, 0x0ab3,
- 0x0ab5, 0x0ab9,
- 0x0ae0, 0x0ae1,
- 0x0b05, 0x0b0c,
- 0x0b0f, 0x0b10,
- 0x0b13, 0x0b28,
- 0x0b2a, 0x0b30,
- 0x0b32, 0x0b33,
- 0x0b35, 0x0b39,
- 0x0b5c, 0x0b5d,
- 0x0b5f, 0x0b61,
- 0x0b85, 0x0b8a,
- 0x0b8e, 0x0b90,
- 0x0b92, 0x0b95,
- 0x0b99, 0x0b9a,
- 0x0b9e, 0x0b9f,
- 0x0ba3, 0x0ba4,
- 0x0ba8, 0x0baa,
- 0x0bae, 0x0bb9,
- 0x0c05, 0x0c0c,
- 0x0c0e, 0x0c10,
- 0x0c12, 0x0c28,
- 0x0c2a, 0x0c33,
- 0x0c35, 0x0c39,
- 0x0c58, 0x0c59,
- 0x0c60, 0x0c61,
- 0x0c85, 0x0c8c,
- 0x0c8e, 0x0c90,
- 0x0c92, 0x0ca8,
- 0x0caa, 0x0cb3,
- 0x0cb5, 0x0cb9,
- 0x0ce0, 0x0ce1,
- 0x0d05, 0x0d0c,
- 0x0d0e, 0x0d10,
- 0x0d12, 0x0d28,
- 0x0d2a, 0x0d39,
- 0x0d60, 0x0d61,
- 0x0d7a, 0x0d7f,
- 0x0d85, 0x0d96,
- 0x0d9a, 0x0db1,
- 0x0db3, 0x0dbb,
- 0x0dc0, 0x0dc6,
- 0x0e01, 0x0e30,
- 0x0e32, 0x0e33,
- 0x0e40, 0x0e46,
- 0x0e81, 0x0e82,
- 0x0e87, 0x0e88,
- 0x0e94, 0x0e97,
- 0x0e99, 0x0e9f,
- 0x0ea1, 0x0ea3,
- 0x0eaa, 0x0eab,
- 0x0ead, 0x0eb0,
- 0x0eb2, 0x0eb3,
- 0x0ec0, 0x0ec4,
- 0x0edc, 0x0edd,
- 0x0f40, 0x0f47,
- 0x0f49, 0x0f6c,
- 0x0f88, 0x0f8b,
- 0x1000, 0x102a,
- 0x1050, 0x1055,
- 0x105a, 0x105d,
- 0x1065, 0x1066,
- 0x106e, 0x1070,
- 0x1075, 0x1081,
- 0x10a0, 0x10c5,
- 0x10d0, 0x10fa,
- 0x1100, 0x1248,
- 0x124a, 0x124d,
- 0x1250, 0x1256,
- 0x125a, 0x125d,
- 0x1260, 0x1288,
- 0x128a, 0x128d,
- 0x1290, 0x12b0,
- 0x12b2, 0x12b5,
- 0x12b8, 0x12be,
- 0x12c2, 0x12c5,
- 0x12c8, 0x12d6,
- 0x12d8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135a,
- 0x1380, 0x138f,
- 0x13a0, 0x13f4,
- 0x1401, 0x166c,
- 0x166f, 0x167f,
- 0x1681, 0x169a,
- 0x16a0, 0x16ea,
- 0x1700, 0x170c,
- 0x170e, 0x1711,
- 0x1720, 0x1731,
- 0x1740, 0x1751,
- 0x1760, 0x176c,
- 0x176e, 0x1770,
- 0x1780, 0x17b3,
- 0x1820, 0x1877,
- 0x1880, 0x18a8,
- 0x18b0, 0x18f5,
- 0x1900, 0x191c,
- 0x1950, 0x196d,
- 0x1970, 0x1974,
- 0x1980, 0x19ab,
- 0x19c1, 0x19c7,
- 0x1a00, 0x1a16,
- 0x1a20, 0x1a54,
- 0x1b05, 0x1b33,
- 0x1b45, 0x1b4b,
- 0x1b83, 0x1ba0,
- 0x1bae, 0x1baf,
- 0x1c00, 0x1c23,
- 0x1c4d, 0x1c4f,
- 0x1c5a, 0x1c7d,
- 0x1ce9, 0x1cec,
- 0x1cee, 0x1cf1,
- 0x1d00, 0x1dbf,
- 0x1e00, 0x1f15,
- 0x1f18, 0x1f1d,
- 0x1f20, 0x1f45,
- 0x1f48, 0x1f4d,
- 0x1f50, 0x1f57,
- 0x1f5f, 0x1f7d,
- 0x1f80, 0x1fb4,
- 0x1fb6, 0x1fbc,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fcc,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fdb,
- 0x1fe0, 0x1fec,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ffc,
- 0x2090, 0x2094,
- 0x210a, 0x2113,
- 0x2119, 0x211d,
- 0x212a, 0x212d,
- 0x212f, 0x2139,
- 0x213c, 0x213f,
- 0x2145, 0x2149,
- 0x2183, 0x2184,
- 0x2c00, 0x2c2e,
- 0x2c30, 0x2c5e,
- 0x2c60, 0x2ce4,
- 0x2ceb, 0x2cee,
- 0x2d00, 0x2d25,
- 0x2d30, 0x2d65,
- 0x2d80, 0x2d96,
- 0x2da0, 0x2da6,
- 0x2da8, 0x2dae,
- 0x2db0, 0x2db6,
- 0x2db8, 0x2dbe,
- 0x2dc0, 0x2dc6,
- 0x2dc8, 0x2dce,
- 0x2dd0, 0x2dd6,
- 0x2dd8, 0x2dde,
- 0x3005, 0x3006,
- 0x3031, 0x3035,
- 0x303b, 0x303c,
- 0x3041, 0x3096,
- 0x309d, 0x309f,
- 0x30a1, 0x30fa,
- 0x30fc, 0x30ff,
- 0x3105, 0x312d,
- 0x3131, 0x318e,
- 0x31a0, 0x31b7,
- 0x31f0, 0x31ff,
- 0x3400, 0x4db5,
- 0x4e00, 0x9fcb,
- 0xa000, 0xa48c,
- 0xa4d0, 0xa4fd,
- 0xa500, 0xa60c,
- 0xa610, 0xa61f,
- 0xa62a, 0xa62b,
- 0xa640, 0xa65f,
- 0xa662, 0xa66e,
- 0xa67f, 0xa697,
- 0xa6a0, 0xa6e5,
- 0xa717, 0xa71f,
- 0xa722, 0xa788,
- 0xa78b, 0xa78c,
- 0xa7fb, 0xa801,
- 0xa803, 0xa805,
- 0xa807, 0xa80a,
- 0xa80c, 0xa822,
- 0xa840, 0xa873,
- 0xa882, 0xa8b3,
- 0xa8f2, 0xa8f7,
- 0xa90a, 0xa925,
- 0xa930, 0xa946,
- 0xa960, 0xa97c,
- 0xa984, 0xa9b2,
- 0xaa00, 0xaa28,
- 0xaa40, 0xaa42,
- 0xaa44, 0xaa4b,
- 0xaa60, 0xaa76,
- 0xaa80, 0xaaaf,
- 0xaab5, 0xaab6,
- 0xaab9, 0xaabd,
- 0xaadb, 0xaadd,
- 0xabc0, 0xabe2,
- 0xac00, 0xd7a3,
- 0xd7b0, 0xd7c6,
- 0xd7cb, 0xd7fb,
- 0xf900, 0xfa2d,
- 0xfa30, 0xfa6d,
- 0xfa70, 0xfad9,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xfb1f, 0xfb28,
- 0xfb2a, 0xfb36,
- 0xfb38, 0xfb3c,
- 0xfb40, 0xfb41,
- 0xfb43, 0xfb44,
- 0xfb46, 0xfbb1,
- 0xfbd3, 0xfd3d,
- 0xfd50, 0xfd8f,
- 0xfd92, 0xfdc7,
- 0xfdf0, 0xfdfb,
- 0xfe70, 0xfe74,
- 0xfe76, 0xfefc,
- 0xff21, 0xff3a,
- 0xff41, 0xff5a,
- 0xff66, 0xffbe,
- 0xffc2, 0xffc7,
- 0xffca, 0xffcf,
- 0xffd2, 0xffd7,
- 0xffda, 0xffdc,
- 0x10000, 0x1000b,
- 0x1000d, 0x10026,
- 0x10028, 0x1003a,
- 0x1003c, 0x1003d,
- 0x1003f, 0x1004d,
- 0x10050, 0x1005d,
- 0x10080, 0x100fa,
- 0x10280, 0x1029c,
- 0x102a0, 0x102d0,
- 0x10300, 0x1031e,
- 0x10330, 0x10340,
- 0x10342, 0x10349,
- 0x10380, 0x1039d,
- 0x103a0, 0x103c3,
- 0x103c8, 0x103cf,
- 0x10400, 0x1049d,
- 0x10800, 0x10805,
- 0x1080a, 0x10835,
- 0x10837, 0x10838,
- 0x1083f, 0x10855,
- 0x10900, 0x10915,
- 0x10920, 0x10939,
- 0x10a10, 0x10a13,
- 0x10a15, 0x10a17,
- 0x10a19, 0x10a33,
- 0x10a60, 0x10a7c,
- 0x10b00, 0x10b35,
- 0x10b40, 0x10b55,
- 0x10b60, 0x10b72,
- 0x10c00, 0x10c48,
- 0x11083, 0x110af,
- 0x12000, 0x1236e,
- 0x13000, 0x1342e,
- 0x1d400, 0x1d454,
- 0x1d456, 0x1d49c,
- 0x1d49e, 0x1d49f,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b9,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d51e, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d54a, 0x1d550,
- 0x1d552, 0x1d6a5,
- 0x1d6a8, 0x1d6c0,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6fa,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d734,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d76e,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d7a8,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7cb,
- 0x20000, 0x2a6d6,
- 0x2a700, 0x2b734,
- 0x2f800, 0x2fa1d,
-};
-
-static Rune __isalphas[] = {
- 0x00aa,
- 0x00b5,
- 0x00ba,
- 0x02ec,
- 0x02ee,
- 0x0386,
- 0x038c,
- 0x0559,
- 0x06d5,
- 0x06ff,
- 0x0710,
- 0x07b1,
- 0x07fa,
- 0x081a,
- 0x0824,
- 0x0828,
- 0x093d,
- 0x0950,
- 0x09b2,
- 0x09bd,
- 0x09ce,
- 0x0a5e,
- 0x0abd,
- 0x0ad0,
- 0x0b3d,
- 0x0b71,
- 0x0b83,
- 0x0b9c,
- 0x0bd0,
- 0x0c3d,
- 0x0cbd,
- 0x0cde,
- 0x0d3d,
- 0x0dbd,
- 0x0e84,
- 0x0e8a,
- 0x0e8d,
- 0x0ea5,
- 0x0ea7,
- 0x0ebd,
- 0x0ec6,
- 0x0f00,
- 0x103f,
- 0x1061,
- 0x108e,
- 0x10fc,
- 0x1258,
- 0x12c0,
- 0x17d7,
- 0x17dc,
- 0x18aa,
- 0x1aa7,
- 0x1f59,
- 0x1f5b,
- 0x1f5d,
- 0x1fbe,
- 0x2071,
- 0x207f,
- 0x2102,
- 0x2107,
- 0x2115,
- 0x2124,
- 0x2126,
- 0x2128,
- 0x214e,
- 0x2d6f,
- 0x2e2f,
- 0xa8fb,
- 0xa9cf,
- 0xaa7a,
- 0xaab1,
- 0xaac0,
- 0xaac2,
- 0xfb1d,
- 0xfb3e,
- 0x10808,
- 0x1083c,
- 0x10a00,
- 0x1d4a2,
- 0x1d4bb,
- 0x1d546,
-};
-
-int
-isalpharune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __isupperr[] = {
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0178, 0x0179,
- 0x0181, 0x0182,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a6, 0x01a7,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b7, 0x01b8,
- 0x01f6, 0x01f8,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0243, 0x0246,
- 0x0388, 0x038a,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03d2, 0x03d4,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x04c0, 0x04c1,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x1f08, 0x1f0f,
- 0x1f18, 0x1f1d,
- 0x1f28, 0x1f2f,
- 0x1f38, 0x1f3f,
- 0x1f48, 0x1f4d,
- 0x1f68, 0x1f6f,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fb8, 0x1fbc,
- 0x1fc8, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffc,
- 0x210b, 0x210d,
- 0x2110, 0x2112,
- 0x2119, 0x211d,
- 0x212a, 0x212d,
- 0x2130, 0x2133,
- 0x213e, 0x213f,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x2c00, 0x2c2e,
- 0x2c62, 0x2c64,
- 0x2c6d, 0x2c70,
- 0x2c7e, 0x2c80,
- 0xa77d, 0xa77e,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
- 0x1d400, 0x1d419,
- 0x1d434, 0x1d44d,
- 0x1d468, 0x1d481,
- 0x1d49e, 0x1d49f,
- 0x1d4a5, 0x1d4a6,
- 0x1d4a9, 0x1d4ac,
- 0x1d4ae, 0x1d4b5,
- 0x1d4d0, 0x1d4e9,
- 0x1d504, 0x1d505,
- 0x1d507, 0x1d50a,
- 0x1d50d, 0x1d514,
- 0x1d516, 0x1d51c,
- 0x1d538, 0x1d539,
- 0x1d53b, 0x1d53e,
- 0x1d540, 0x1d544,
- 0x1d54a, 0x1d550,
- 0x1d56c, 0x1d585,
- 0x1d5a0, 0x1d5b9,
- 0x1d5d4, 0x1d5ed,
- 0x1d608, 0x1d621,
- 0x1d63c, 0x1d655,
- 0x1d670, 0x1d689,
- 0x1d6a8, 0x1d6c0,
- 0x1d6e2, 0x1d6fa,
- 0x1d71c, 0x1d734,
- 0x1d756, 0x1d76e,
- 0x1d790, 0x1d7a8,
-};
-
-static Rune __isupperp[] = {
- 0x0100, 0x0136,
- 0x0139, 0x0147,
- 0x014a, 0x0176,
- 0x017b, 0x017d,
- 0x01a2, 0x01a4,
- 0x01cd, 0x01db,
- 0x01de, 0x01ee,
- 0x01fa, 0x0232,
- 0x0248, 0x024e,
- 0x0370, 0x0372,
- 0x03d8, 0x03ee,
- 0x0460, 0x0480,
- 0x048a, 0x04be,
- 0x04c3, 0x04cd,
- 0x04d0, 0x0524,
- 0x1e00, 0x1e94,
- 0x1e9e, 0x1efe,
- 0x1f59, 0x1f5f,
- 0x2124, 0x2128,
- 0x2c67, 0x2c6b,
- 0x2c82, 0x2ce2,
- 0x2ceb, 0x2ced,
- 0xa640, 0xa65e,
- 0xa662, 0xa66c,
- 0xa680, 0xa696,
- 0xa722, 0xa72e,
- 0xa732, 0xa76e,
- 0xa779, 0xa77b,
- 0xa780, 0xa786,
-};
-
-static Rune __isuppers[] = {
- 0x0184,
- 0x01a9,
- 0x01ac,
- 0x01b5,
- 0x01bc,
- 0x01c4,
- 0x01c7,
- 0x01ca,
- 0x01f1,
- 0x01f4,
- 0x0241,
- 0x0376,
- 0x0386,
- 0x038c,
- 0x03cf,
- 0x03f4,
- 0x03f7,
- 0x2102,
- 0x2107,
- 0x2115,
- 0x2145,
- 0x2183,
- 0x2c60,
- 0x2c72,
- 0x2c75,
- 0xa78b,
- 0x1d49c,
- 0x1d4a2,
- 0x1d546,
- 0x1d7ca,
-};
-
-int
-isupperrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __islowerr[] = {
- 0x0061, 0x007a,
- 0x00df, 0x00f6,
- 0x00f8, 0x00ff,
- 0x0137, 0x0138,
- 0x0148, 0x0149,
- 0x017e, 0x0180,
- 0x018c, 0x018d,
- 0x0199, 0x019b,
- 0x01aa, 0x01ab,
- 0x01b9, 0x01ba,
- 0x01bd, 0x01bf,
- 0x01dc, 0x01dd,
- 0x01ef, 0x01f0,
- 0x0233, 0x0239,
- 0x023f, 0x0240,
- 0x024f, 0x0293,
- 0x0295, 0x02af,
- 0x037b, 0x037d,
- 0x03ac, 0x03ce,
- 0x03d0, 0x03d1,
- 0x03d5, 0x03d7,
- 0x03ef, 0x03f3,
- 0x03fb, 0x03fc,
- 0x0430, 0x045f,
- 0x04ce, 0x04cf,
- 0x0561, 0x0587,
- 0x1d00, 0x1d2b,
- 0x1d62, 0x1d77,
- 0x1d79, 0x1d9a,
- 0x1e95, 0x1e9d,
- 0x1eff, 0x1f07,
- 0x1f10, 0x1f15,
- 0x1f20, 0x1f27,
- 0x1f30, 0x1f37,
- 0x1f40, 0x1f45,
- 0x1f50, 0x1f57,
- 0x1f60, 0x1f67,
- 0x1f70, 0x1f7d,
- 0x1f80, 0x1f87,
- 0x1f90, 0x1f97,
- 0x1fa0, 0x1fa7,
- 0x1fb0, 0x1fb4,
- 0x1fb6, 0x1fb7,
- 0x1fc2, 0x1fc4,
- 0x1fc6, 0x1fc7,
- 0x1fd0, 0x1fd3,
- 0x1fd6, 0x1fd7,
- 0x1fe0, 0x1fe7,
- 0x1ff2, 0x1ff4,
- 0x1ff6, 0x1ff7,
- 0x210e, 0x210f,
- 0x213c, 0x213d,
- 0x2146, 0x2149,
- 0x2170, 0x217f,
- 0x24d0, 0x24e9,
- 0x2c30, 0x2c5e,
- 0x2c65, 0x2c66,
- 0x2c73, 0x2c74,
- 0x2c76, 0x2c7c,
- 0x2ce3, 0x2ce4,
- 0x2d00, 0x2d25,
- 0xa72f, 0xa731,
- 0xa771, 0xa778,
- 0xfb00, 0xfb06,
- 0xfb13, 0xfb17,
- 0xff41, 0xff5a,
- 0x10428, 0x1044f,
- 0x1d41a, 0x1d433,
- 0x1d44e, 0x1d454,
- 0x1d456, 0x1d467,
- 0x1d482, 0x1d49b,
- 0x1d4b6, 0x1d4b9,
- 0x1d4bd, 0x1d4c3,
- 0x1d4c5, 0x1d4cf,
- 0x1d4ea, 0x1d503,
- 0x1d51e, 0x1d537,
- 0x1d552, 0x1d56b,
- 0x1d586, 0x1d59f,
- 0x1d5ba, 0x1d5d3,
- 0x1d5ee, 0x1d607,
- 0x1d622, 0x1d63b,
- 0x1d656, 0x1d66f,
- 0x1d68a, 0x1d6a5,
- 0x1d6c2, 0x1d6da,
- 0x1d6dc, 0x1d6e1,
- 0x1d6fc, 0x1d714,
- 0x1d716, 0x1d71b,
- 0x1d736, 0x1d74e,
- 0x1d750, 0x1d755,
- 0x1d770, 0x1d788,
- 0x1d78a, 0x1d78f,
- 0x1d7aa, 0x1d7c2,
- 0x1d7c4, 0x1d7c9,
-};
-
-static Rune __islowerp[] = {
- 0x0101, 0x0135,
- 0x013a, 0x0146,
- 0x014b, 0x0177,
- 0x017a, 0x017c,
- 0x0183, 0x0185,
- 0x01a1, 0x01a5,
- 0x01b4, 0x01b6,
- 0x01cc, 0x01da,
- 0x01df, 0x01ed,
- 0x01f3, 0x01f5,
- 0x01f9, 0x0231,
- 0x0247, 0x024d,
- 0x0371, 0x0373,
- 0x03d9, 0x03ed,
- 0x0461, 0x0481,
- 0x048b, 0x04bf,
- 0x04c2, 0x04cc,
- 0x04d1, 0x0525,
- 0x1e01, 0x1e93,
- 0x1e9f, 0x1efd,
- 0x2c68, 0x2c6c,
- 0x2c81, 0x2ce1,
- 0x2cec, 0x2cee,
- 0xa641, 0xa65f,
- 0xa663, 0xa66d,
- 0xa681, 0xa697,
- 0xa723, 0xa72d,
- 0xa733, 0xa76f,
- 0xa77a, 0xa77c,
- 0xa77f, 0xa787,
-};
-
-static Rune __islowers[] = {
- 0x00aa,
- 0x00b5,
- 0x00ba,
- 0x0188,
- 0x0192,
- 0x0195,
- 0x019e,
- 0x01a8,
- 0x01ad,
- 0x01b0,
- 0x01c6,
- 0x01c9,
- 0x023c,
- 0x0242,
- 0x0377,
- 0x0390,
- 0x03f5,
- 0x03f8,
- 0x1fbe,
- 0x210a,
- 0x2113,
- 0x212f,
- 0x2134,
- 0x2139,
- 0x214e,
- 0x2184,
- 0x2c61,
- 0x2c71,
- 0xa78c,
- 0x1d4bb,
- 0x1d7cb,
-};
-
-int
-islowerrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __islowers, nelem(__islowers), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __istitler[] = {
- 0x0041, 0x005a,
- 0x00c0, 0x00d6,
- 0x00d8, 0x00de,
- 0x0178, 0x0179,
- 0x0181, 0x0182,
- 0x0186, 0x0187,
- 0x0189, 0x018b,
- 0x018e, 0x0191,
- 0x0193, 0x0194,
- 0x0196, 0x0198,
- 0x019c, 0x019d,
- 0x019f, 0x01a0,
- 0x01a6, 0x01a7,
- 0x01ae, 0x01af,
- 0x01b1, 0x01b3,
- 0x01b7, 0x01b8,
- 0x01f6, 0x01f8,
- 0x023a, 0x023b,
- 0x023d, 0x023e,
- 0x0243, 0x0246,
- 0x0388, 0x038a,
- 0x038e, 0x038f,
- 0x0391, 0x03a1,
- 0x03a3, 0x03ab,
- 0x03f9, 0x03fa,
- 0x03fd, 0x042f,
- 0x04c0, 0x04c1,
- 0x0531, 0x0556,
- 0x10a0, 0x10c5,
- 0x1f08, 0x1f0f,
- 0x1f18, 0x1f1d,
- 0x1f28, 0x1f2f,
- 0x1f38, 0x1f3f,
- 0x1f48, 0x1f4d,
- 0x1f68, 0x1f6f,
- 0x1f88, 0x1f8f,
- 0x1f98, 0x1f9f,
- 0x1fa8, 0x1faf,
- 0x1fb8, 0x1fbc,
- 0x1fc8, 0x1fcc,
- 0x1fd8, 0x1fdb,
- 0x1fe8, 0x1fec,
- 0x1ff8, 0x1ffc,
- 0x2160, 0x216f,
- 0x24b6, 0x24cf,
- 0x2c00, 0x2c2e,
- 0x2c62, 0x2c64,
- 0x2c6d, 0x2c70,
- 0x2c7e, 0x2c80,
- 0xa77d, 0xa77e,
- 0xff21, 0xff3a,
- 0x10400, 0x10427,
-};
-
-static Rune __istitlep[] = {
- 0x0100, 0x012e,
- 0x0132, 0x0136,
- 0x0139, 0x0147,
- 0x014a, 0x0176,
- 0x017b, 0x017d,
- 0x01a2, 0x01a4,
- 0x01cb, 0x01db,
- 0x01de, 0x01ee,
- 0x01f2, 0x01f4,
- 0x01fa, 0x0232,
- 0x0248, 0x024e,
- 0x0370, 0x0372,
- 0x03d8, 0x03ee,
- 0x0460, 0x0480,
- 0x048a, 0x04be,
- 0x04c3, 0x04cd,
- 0x04d0, 0x0524,
- 0x1e00, 0x1e94,
- 0x1ea0, 0x1efe,
- 0x1f59, 0x1f5f,
- 0x2c67, 0x2c6b,
- 0x2c82, 0x2ce2,
- 0x2ceb, 0x2ced,
- 0xa640, 0xa65e,
- 0xa662, 0xa66c,
- 0xa680, 0xa696,
- 0xa722, 0xa72e,
- 0xa732, 0xa76e,
- 0xa779, 0xa77b,
- 0xa780, 0xa786,
-};
-
-static Rune __istitles[] = {
- 0x0184,
- 0x01a9,
- 0x01ac,
- 0x01b5,
- 0x01bc,
- 0x01c5,
- 0x01c8,
- 0x0241,
- 0x0376,
- 0x0386,
- 0x038c,
- 0x03cf,
- 0x03f7,
- 0x2132,
- 0x2183,
- 0x2c60,
- 0x2c72,
- 0x2c75,
- 0xa78b,
-};
-
-int
-istitlerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
- if(p && c >= p[0] && c <= p[1])
- return 1;
- p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return 1;
- p = rbsearch(c, __istitles, nelem(__istitles), 1);
- if(p && c == p[0])
- return 1;
- return 0;
-}
-
-static Rune __toupperr[] = {
- 0x0061, 0x007a, 1048544,
- 0x00e0, 0x00f6, 1048544,
- 0x00f8, 0x00fe, 1048544,
- 0x023f, 0x0240, 1059391,
- 0x0256, 0x0257, 1048371,
- 0x028a, 0x028b, 1048359,
- 0x037b, 0x037d, 1048706,
- 0x03ad, 0x03af, 1048539,
- 0x03b1, 0x03c1, 1048544,
- 0x03c3, 0x03cb, 1048544,
- 0x03cd, 0x03ce, 1048513,
- 0x0430, 0x044f, 1048544,
- 0x0450, 0x045f, 1048496,
- 0x0561, 0x0586, 1048528,
- 0x1f00, 0x1f07, 1048584,
- 0x1f10, 0x1f15, 1048584,
- 0x1f20, 0x1f27, 1048584,
- 0x1f30, 0x1f37, 1048584,
- 0x1f40, 0x1f45, 1048584,
- 0x1f60, 0x1f67, 1048584,
- 0x1f70, 0x1f71, 1048650,
- 0x1f72, 0x1f75, 1048662,
- 0x1f76, 0x1f77, 1048676,
- 0x1f78, 0x1f79, 1048704,
- 0x1f7a, 0x1f7b, 1048688,
- 0x1f7c, 0x1f7d, 1048702,
- 0x1f80, 0x1f87, 1048584,
- 0x1f90, 0x1f97, 1048584,
- 0x1fa0, 0x1fa7, 1048584,
- 0x1fb0, 0x1fb1, 1048584,
- 0x1fd0, 0x1fd1, 1048584,
- 0x1fe0, 0x1fe1, 1048584,
- 0x2170, 0x217f, 1048560,
- 0x24d0, 0x24e9, 1048550,
- 0x2c30, 0x2c5e, 1048528,
- 0x2d00, 0x2d25, 1041312,
- 0xff41, 0xff5a, 1048544,
- 0x10428, 0x1044f, 1048536,
-};
-
-static Rune __toupperp[] = {
- 0x0101, 0x012f, 1048575,
- 0x0133, 0x0137, 1048575,
- 0x013a, 0x0148, 1048575,
- 0x014b, 0x0177, 1048575,
- 0x017a, 0x017e, 1048575,
- 0x0183, 0x0185, 1048575,
- 0x01a1, 0x01a5, 1048575,
- 0x01b4, 0x01b6, 1048575,
- 0x01ce, 0x01dc, 1048575,
- 0x01df, 0x01ef, 1048575,
- 0x01f9, 0x021f, 1048575,
- 0x0223, 0x0233, 1048575,
- 0x0247, 0x024f, 1048575,
- 0x0371, 0x0373, 1048575,
- 0x03d9, 0x03ef, 1048575,
- 0x0461, 0x0481, 1048575,
- 0x048b, 0x04bf, 1048575,
- 0x04c2, 0x04ce, 1048575,
- 0x04d1, 0x0525, 1048575,
- 0x1e01, 0x1e95, 1048575,
- 0x1ea1, 0x1eff, 1048575,
- 0x1f51, 0x1f57, 1048584,
- 0x2c68, 0x2c6c, 1048575,
- 0x2c81, 0x2ce3, 1048575,
- 0x2cec, 0x2cee, 1048575,
- 0xa641, 0xa65f, 1048575,
- 0xa663, 0xa66d, 1048575,
- 0xa681, 0xa697, 1048575,
- 0xa723, 0xa72f, 1048575,
- 0xa733, 0xa76f, 1048575,
- 0xa77a, 0xa77c, 1048575,
- 0xa77f, 0xa787, 1048575,
-};
-
-static Rune __touppers[] = {
- 0x00b5, 1049319,
- 0x00ff, 1048697,
- 0x0131, 1048344,
- 0x017f, 1048276,
- 0x0180, 1048771,
- 0x0188, 1048575,
- 0x018c, 1048575,
- 0x0192, 1048575,
- 0x0195, 1048673,
- 0x0199, 1048575,
- 0x019a, 1048739,
- 0x019e, 1048706,
- 0x01a8, 1048575,
- 0x01ad, 1048575,
- 0x01b0, 1048575,
- 0x01b9, 1048575,
- 0x01bd, 1048575,
- 0x01bf, 1048632,
- 0x01c5, 1048575,
- 0x01c6, 1048574,
- 0x01c8, 1048575,
- 0x01c9, 1048574,
- 0x01cb, 1048575,
- 0x01cc, 1048574,
- 0x01dd, 1048497,
- 0x01f2, 1048575,
- 0x01f3, 1048574,
- 0x01f5, 1048575,
- 0x023c, 1048575,
- 0x0242, 1048575,
- 0x0250, 1059359,
- 0x0251, 1059356,
- 0x0252, 1059358,
- 0x0253, 1048366,
- 0x0254, 1048370,
- 0x0259, 1048374,
- 0x025b, 1048373,
- 0x0260, 1048371,
- 0x0263, 1048369,
- 0x0268, 1048367,
- 0x0269, 1048365,
- 0x026b, 1059319,
- 0x026f, 1048365,
- 0x0271, 1059325,
- 0x0272, 1048363,
- 0x0275, 1048362,
- 0x027d, 1059303,
- 0x0280, 1048358,
- 0x0283, 1048358,
- 0x0288, 1048358,
- 0x0289, 1048507,
- 0x028c, 1048505,
- 0x0292, 1048357,
- 0x0345, 1048660,
- 0x0377, 1048575,
- 0x03ac, 1048538,
- 0x03c2, 1048545,
- 0x03cc, 1048512,
- 0x03d0, 1048514,
- 0x03d1, 1048519,
- 0x03d5, 1048529,
- 0x03d6, 1048522,
- 0x03d7, 1048568,
- 0x03f0, 1048490,
- 0x03f1, 1048496,
- 0x03f2, 1048583,
- 0x03f5, 1048480,
- 0x03f8, 1048575,
- 0x03fb, 1048575,
- 0x04cf, 1048561,
- 0x1d79, 1083908,
- 0x1d7d, 1052390,
- 0x1e9b, 1048517,
- 0x1fb3, 1048585,
- 0x1fbe, 1041371,
- 0x1fc3, 1048585,
- 0x1fe5, 1048583,
- 0x1ff3, 1048585,
- 0x214e, 1048548,
- 0x2184, 1048575,
- 0x2c61, 1048575,
- 0x2c65, 1037781,
- 0x2c66, 1037784,
- 0x2c73, 1048575,
- 0x2c76, 1048575,
- 0xa78c, 1048575,
-};
-
-Rune
-toupperrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
-static Rune __tolowerr[] = {
- 0x0041, 0x005a, 1048608,
- 0x00c0, 0x00d6, 1048608,
- 0x00d8, 0x00de, 1048608,
- 0x0189, 0x018a, 1048781,
- 0x01b1, 0x01b2, 1048793,
- 0x0388, 0x038a, 1048613,
- 0x038e, 0x038f, 1048639,
- 0x0391, 0x03a1, 1048608,
- 0x03a3, 0x03ab, 1048608,
- 0x03fd, 0x03ff, 1048446,
- 0x0400, 0x040f, 1048656,
- 0x0410, 0x042f, 1048608,
- 0x0531, 0x0556, 1048624,
- 0x10a0, 0x10c5, 1055840,
- 0x1f08, 0x1f0f, 1048568,
- 0x1f18, 0x1f1d, 1048568,
- 0x1f28, 0x1f2f, 1048568,
- 0x1f38, 0x1f3f, 1048568,
- 0x1f48, 0x1f4d, 1048568,
- 0x1f68, 0x1f6f, 1048568,
- 0x1f88, 0x1f8f, 1048568,
- 0x1f98, 0x1f9f, 1048568,
- 0x1fa8, 0x1faf, 1048568,
- 0x1fb8, 0x1fb9, 1048568,
- 0x1fba, 0x1fbb, 1048502,
- 0x1fc8, 0x1fcb, 1048490,
- 0x1fd8, 0x1fd9, 1048568,
- 0x1fda, 0x1fdb, 1048476,
- 0x1fe8, 0x1fe9, 1048568,
- 0x1fea, 0x1feb, 1048464,
- 0x1ff8, 0x1ff9, 1048448,
- 0x1ffa, 0x1ffb, 1048450,
- 0x2160, 0x216f, 1048592,
- 0x24b6, 0x24cf, 1048602,
- 0x2c00, 0x2c2e, 1048624,
- 0x2c7e, 0x2c7f, 1037761,
- 0xff21, 0xff3a, 1048608,
- 0x10400, 0x10427, 1048616,
-};
-
-static Rune __tolowerp[] = {
- 0x0100, 0x012e, 1048577,
- 0x0132, 0x0136, 1048577,
- 0x0139, 0x0147, 1048577,
- 0x014a, 0x0176, 1048577,
- 0x017b, 0x017d, 1048577,
- 0x01a2, 0x01a4, 1048577,
- 0x01b3, 0x01b5, 1048577,
- 0x01cd, 0x01db, 1048577,
- 0x01de, 0x01ee, 1048577,
- 0x01f8, 0x021e, 1048577,
- 0x0222, 0x0232, 1048577,
- 0x0248, 0x024e, 1048577,
- 0x0370, 0x0372, 1048577,
- 0x03d8, 0x03ee, 1048577,
- 0x0460, 0x0480, 1048577,
- 0x048a, 0x04be, 1048577,
- 0x04c3, 0x04cd, 1048577,
- 0x04d0, 0x0524, 1048577,
- 0x1e00, 0x1e94, 1048577,
- 0x1ea0, 0x1efe, 1048577,
- 0x1f59, 0x1f5f, 1048568,
- 0x2c67, 0x2c6b, 1048577,
- 0x2c80, 0x2ce2, 1048577,
- 0x2ceb, 0x2ced, 1048577,
- 0xa640, 0xa65e, 1048577,
- 0xa662, 0xa66c, 1048577,
- 0xa680, 0xa696, 1048577,
- 0xa722, 0xa72e, 1048577,
- 0xa732, 0xa76e, 1048577,
- 0xa779, 0xa77b, 1048577,
- 0xa780, 0xa786, 1048577,
-};
-
-static Rune __tolowers[] = {
- 0x0130, 1048377,
- 0x0178, 1048455,
- 0x0179, 1048577,
- 0x0181, 1048786,
- 0x0182, 1048577,
- 0x0184, 1048577,
- 0x0186, 1048782,
- 0x0187, 1048577,
- 0x018b, 1048577,
- 0x018e, 1048655,
- 0x018f, 1048778,
- 0x0190, 1048779,
- 0x0191, 1048577,
- 0x0193, 1048781,
- 0x0194, 1048783,
- 0x0196, 1048787,
- 0x0197, 1048785,
- 0x0198, 1048577,
- 0x019c, 1048787,
- 0x019d, 1048789,
- 0x019f, 1048790,
- 0x01a0, 1048577,
- 0x01a6, 1048794,
- 0x01a7, 1048577,
- 0x01a9, 1048794,
- 0x01ac, 1048577,
- 0x01ae, 1048794,
- 0x01af, 1048577,
- 0x01b7, 1048795,
- 0x01b8, 1048577,
- 0x01bc, 1048577,
- 0x01c4, 1048578,
- 0x01c5, 1048577,
- 0x01c7, 1048578,
- 0x01c8, 1048577,
- 0x01ca, 1048578,
- 0x01cb, 1048577,
- 0x01f1, 1048578,
- 0x01f2, 1048577,
- 0x01f4, 1048577,
- 0x01f6, 1048479,
- 0x01f7, 1048520,
- 0x0220, 1048446,
- 0x023a, 1059371,
- 0x023b, 1048577,
- 0x023d, 1048413,
- 0x023e, 1059368,
- 0x0241, 1048577,
- 0x0243, 1048381,
- 0x0244, 1048645,
- 0x0245, 1048647,
- 0x0246, 1048577,
- 0x0376, 1048577,
- 0x0386, 1048614,
- 0x038c, 1048640,
- 0x03cf, 1048584,
- 0x03f4, 1048516,
- 0x03f7, 1048577,
- 0x03f9, 1048569,
- 0x03fa, 1048577,
- 0x04c0, 1048591,
- 0x04c1, 1048577,
- 0x1e9e, 1040961,
- 0x1fbc, 1048567,
- 0x1fcc, 1048567,
- 0x1fec, 1048569,
- 0x1ffc, 1048567,
- 0x2126, 1041059,
- 0x212a, 1040193,
- 0x212b, 1040314,
- 0x2132, 1048604,
- 0x2183, 1048577,
- 0x2c60, 1048577,
- 0x2c62, 1037833,
- 0x2c63, 1044762,
- 0x2c64, 1037849,
- 0x2c6d, 1037796,
- 0x2c6e, 1037827,
- 0x2c6f, 1037793,
- 0x2c70, 1037794,
- 0x2c72, 1048577,
- 0x2c75, 1048577,
- 0xa77d, 1013244,
- 0xa77e, 1048577,
- 0xa78b, 1048577,
-};
-
-Rune
-tolowerrune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
-static Rune __totitler[] = {
- 0x0061, 0x007a, 1048544,
- 0x00e0, 0x00f6, 1048544,
- 0x00f8, 0x00fe, 1048544,
- 0x023f, 0x0240, 1059391,
- 0x0256, 0x0257, 1048371,
- 0x028a, 0x028b, 1048359,
- 0x037b, 0x037d, 1048706,
- 0x03ad, 0x03af, 1048539,
- 0x03b1, 0x03c1, 1048544,
- 0x03c3, 0x03cb, 1048544,
- 0x03cd, 0x03ce, 1048513,
- 0x0430, 0x044f, 1048544,
- 0x0450, 0x045f, 1048496,
- 0x0561, 0x0586, 1048528,
- 0x1f00, 0x1f07, 1048584,
- 0x1f10, 0x1f15, 1048584,
- 0x1f20, 0x1f27, 1048584,
- 0x1f30, 0x1f37, 1048584,
- 0x1f40, 0x1f45, 1048584,
- 0x1f60, 0x1f67, 1048584,
- 0x1f70, 0x1f71, 1048650,
- 0x1f72, 0x1f75, 1048662,
- 0x1f76, 0x1f77, 1048676,
- 0x1f78, 0x1f79, 1048704,
- 0x1f7a, 0x1f7b, 1048688,
- 0x1f7c, 0x1f7d, 1048702,
- 0x1f80, 0x1f87, 1048584,
- 0x1f90, 0x1f97, 1048584,
- 0x1fa0, 0x1fa7, 1048584,
- 0x1fb0, 0x1fb1, 1048584,
- 0x1fd0, 0x1fd1, 1048584,
- 0x1fe0, 0x1fe1, 1048584,
- 0x2170, 0x217f, 1048560,
- 0x24d0, 0x24e9, 1048550,
- 0x2c30, 0x2c5e, 1048528,
- 0x2d00, 0x2d25, 1041312,
- 0xff41, 0xff5a, 1048544,
- 0x10428, 0x1044f, 1048536,
-};
-
-static Rune __totitlep[] = {
- 0x0101, 0x012f, 1048575,
- 0x0133, 0x0137, 1048575,
- 0x013a, 0x0148, 1048575,
- 0x014b, 0x0177, 1048575,
- 0x017a, 0x017e, 1048575,
- 0x0183, 0x0185, 1048575,
- 0x01a1, 0x01a5, 1048575,
- 0x01b4, 0x01b6, 1048575,
- 0x01cc, 0x01dc, 1048575,
- 0x01df, 0x01ef, 1048575,
- 0x01f3, 0x01f5, 1048575,
- 0x01f9, 0x021f, 1048575,
- 0x0223, 0x0233, 1048575,
- 0x0247, 0x024f, 1048575,
- 0x0371, 0x0373, 1048575,
- 0x03d9, 0x03ef, 1048575,
- 0x0461, 0x0481, 1048575,
- 0x048b, 0x04bf, 1048575,
- 0x04c2, 0x04ce, 1048575,
- 0x04d1, 0x0525, 1048575,
- 0x1e01, 0x1e95, 1048575,
- 0x1ea1, 0x1eff, 1048575,
- 0x1f51, 0x1f57, 1048584,
- 0x2c68, 0x2c6c, 1048575,
- 0x2c81, 0x2ce3, 1048575,
- 0x2cec, 0x2cee, 1048575,
- 0xa641, 0xa65f, 1048575,
- 0xa663, 0xa66d, 1048575,
- 0xa681, 0xa697, 1048575,
- 0xa723, 0xa72f, 1048575,
- 0xa733, 0xa76f, 1048575,
- 0xa77a, 0xa77c, 1048575,
- 0xa77f, 0xa787, 1048575,
-};
-
-static Rune __totitles[] = {
- 0x00b5, 1049319,
- 0x00ff, 1048697,
- 0x0131, 1048344,
- 0x017f, 1048276,
- 0x0180, 1048771,
- 0x0188, 1048575,
- 0x018c, 1048575,
- 0x0192, 1048575,
- 0x0195, 1048673,
- 0x0199, 1048575,
- 0x019a, 1048739,
- 0x019e, 1048706,
- 0x01a8, 1048575,
- 0x01ad, 1048575,
- 0x01b0, 1048575,
- 0x01b9, 1048575,
- 0x01bd, 1048575,
- 0x01bf, 1048632,
- 0x01c4, 1048577,
- 0x01c6, 1048575,
- 0x01c7, 1048577,
- 0x01c9, 1048575,
- 0x01ca, 1048577,
- 0x01dd, 1048497,
- 0x01f1, 1048577,
- 0x023c, 1048575,
- 0x0242, 1048575,
- 0x0250, 1059359,
- 0x0251, 1059356,
- 0x0252, 1059358,
- 0x0253, 1048366,
- 0x0254, 1048370,
- 0x0259, 1048374,
- 0x025b, 1048373,
- 0x0260, 1048371,
- 0x0263, 1048369,
- 0x0268, 1048367,
- 0x0269, 1048365,
- 0x026b, 1059319,
- 0x026f, 1048365,
- 0x0271, 1059325,
- 0x0272, 1048363,
- 0x0275, 1048362,
- 0x027d, 1059303,
- 0x0280, 1048358,
- 0x0283, 1048358,
- 0x0288, 1048358,
- 0x0289, 1048507,
- 0x028c, 1048505,
- 0x0292, 1048357,
- 0x0345, 1048660,
- 0x0377, 1048575,
- 0x03ac, 1048538,
- 0x03c2, 1048545,
- 0x03cc, 1048512,
- 0x03d0, 1048514,
- 0x03d1, 1048519,
- 0x03d5, 1048529,
- 0x03d6, 1048522,
- 0x03d7, 1048568,
- 0x03f0, 1048490,
- 0x03f1, 1048496,
- 0x03f2, 1048583,
- 0x03f5, 1048480,
- 0x03f8, 1048575,
- 0x03fb, 1048575,
- 0x04cf, 1048561,
- 0x1d79, 1083908,
- 0x1d7d, 1052390,
- 0x1e9b, 1048517,
- 0x1fb3, 1048585,
- 0x1fbe, 1041371,
- 0x1fc3, 1048585,
- 0x1fe5, 1048583,
- 0x1ff3, 1048585,
- 0x214e, 1048548,
- 0x2184, 1048575,
- 0x2c61, 1048575,
- 0x2c65, 1037781,
- 0x2c66, 1037784,
- 0x2c73, 1048575,
- 0x2c76, 1048575,
- 0xa78c, 1048575,
-};
-
-Rune
-totitlerune(Rune c)
-{
- Rune *p;
-
- p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
- if(p && c >= p[0] && c <= p[1])
- return c + p[2] - 1048576;
- p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
- if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
- return c + p[2] - 1048576;
- p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
- if(p && c == p[0])
- return c + p[1] - 1048576;
- return c;
-}
-
diff --git a/src/lib9/utf/runetypebody-6.0.0.c b/src/lib9/utf/runetypebody-6.0.0.h
index 47c0faf73..47c0faf73 100644
--- a/src/lib9/utf/runetypebody-6.0.0.c
+++ b/src/lib9/utf/runetypebody-6.0.0.h
diff --git a/src/lib9/win32.c b/src/lib9/windows.c
index 90753bb8d..90753bb8d 100644
--- a/src/lib9/win32.c
+++ b/src/lib9/windows.c
diff --git a/src/libbio/Makefile b/src/libbio/Makefile
index 4340b0eae..62aba5dca 100644
--- a/src/libbio/Makefile
+++ b/src/libbio/Makefile
@@ -1,51 +1,5 @@
-# Derived from http://code.google.com/p/inferno-os/source/browse/libbio/mkfile
-#
-# Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-# Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-# Portions Copyright © 2009 The Go Authors. All rights reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
-include ../Make.inc
-O:=$(HOST_O)
-
-LIB=libbio.a
-
-OFILES=\
- bbuffered.$O\
- bfildes.$O\
- bflush.$O\
- bgetc.$O\
- bgetrune.$O\
- bgetd.$O\
- binit.$O\
- boffset.$O\
- bprint.$O\
- bputc.$O\
- bputrune.$O\
- brdline.$O\
- brdstr.$O\
- bread.$O\
- bseek.$O\
- bwrite.$O\
-
-HFILES=\
- ../../include/bio.h
-
-include ../Make.clib
+include ../Make.dist
diff --git a/src/libmach/5db.c b/src/libmach/5db.c
index aea391edf..ae71dd90d 100644
--- a/src/libmach/5db.c
+++ b/src/libmach/5db.c
@@ -307,7 +307,7 @@ gsymoff(char *buf, int n, long v, int space)
if (!delta)
return snprint(buf, n, "%s", s.name);
if (s.type != 't' && s.type != 'T')
- return snprint(buf, n, "%s+%lux", s.name, v-s.value);
+ return snprint(buf, n, "%s+%llux", s.name, v-s.value);
else
return snprint(buf, n, "#%lux", v);
}
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
index 5b3de69a5..ce1b4ddd7 100644
--- a/src/libmach/8db.c
+++ b/src/libmach/8db.c
@@ -1,11 +1,11 @@
// Inferno libmach/8db.c
// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8db.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc.
-// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-// Portions Copyright © 1997-1999 Vita Nuova Limited.
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+// Copyright © 1994-1999 Lucent Technologies Inc.
+// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+// Portions Copyright © 1997-1999 Vita Nuova Limited.
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -125,7 +125,7 @@ i386excep(Map *map, Rgetter rget)
if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
return "breakpoint";
}
- snprint(buf, sizeof(buf), "exception %ld", c);
+ snprint(buf, sizeof(buf), "exception %d", c);
return buf;
} else
return excname[c];
@@ -688,6 +688,7 @@ static Optable optab0F[256]=
[0x74] = { RM,0, "PCMPEQB %m,%M" },
[0x75] = { RM,0, "PCMPEQW %m,%M" },
[0x76] = { RM,0, "PCMPEQL %m,%M" },
+[0x77] = { 0,0, "EMMS" },
[0x7E] = { RM,0, "MOV%S %M,%e" },
[0x7F] = { RM,0, "MOVQ %M,%m" },
[0xAE] = { RMOP,0, optab0FAE },
@@ -1971,7 +1972,7 @@ plocal(Instr *ip)
offset = ip->disp;
if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
- bprint(ip, "%lux(SP)", offset);
+ bprint(ip, "%ux(SP)", offset);
return;
}
@@ -1987,7 +1988,7 @@ plocal(Instr *ip)
bprint(ip, "%s+", s.name);
else
offset = ip->disp;
- bprint(ip, "%lux%s", offset, reg);
+ bprint(ip, "%ux%s", offset, reg);
}
static int
@@ -2061,7 +2062,7 @@ immediate(Instr *ip, vlong val)
w = -w;
if (issymref(ip, &s, w, val)) {
if (w)
- bprint(ip, "%s+%#lux(SB)", s.name, w);
+ bprint(ip, "%s+%#ux(SB)", s.name, w);
else
bprint(ip, "%s(SB)", s.name);
return;
@@ -2087,24 +2088,29 @@ immediate(Instr *ip, vlong val)
static void
pea(Instr *ip)
{
+ int base;
+
+ base = ip->base;
+ if(base >= 0 && (ip->rex & REXB))
+ base += 8;
+
if (ip->mod == 3) {
if (ip->osize == 'B')
bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
- else if(ip->rex & REXB)
- bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
else
- bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
+ bprint(ip, "%s%s", ANAME(ip), reg[base]);
return;
}
+
if (ip->segment)
bprint(ip, ip->segment);
- if (ip->asize == 'E' && ip->base == SP)
+ if (ip->asize == 'E' && base == SP)
plocal(ip);
else {
if (ip->base < 0)
immediate(ip, ip->disp);
else {
- bprint(ip, "%lux", ip->disp);
+ bprint(ip, "%ux", ip->disp);
if(ip->rip)
bprint(ip, "(RIP)");
bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
@@ -2197,7 +2203,7 @@ prinstr(Instr *ip, char *fmt)
bprint(ip, "CBW");
break;
case 'd':
- bprint(ip,"%ux:%lux",ip->seg,ip->disp);
+ bprint(ip,"%ux:%ux", ip->seg, ip->disp);
break;
case 'm':
if (ip->mod == 3 && ip->osize != 'B') {
diff --git a/src/libmach/Makefile b/src/libmach/Makefile
index 2a53749c8..62aba5dca 100644
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -1,64 +1,5 @@
-# Derived from Inferno libmach/mkfile
-# http://code.google.com/p/inferno-os/source/browse/utils/libmach/mkfile
-#
-# Copyright © 1994-1999 Lucent Technologies Inc.
-# Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
-# Portions Copyright © 1997-1999 Vita Nuova Limited.
-# Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
-# Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
-# Portions Copyright © 2009 The Go Authors. All rights reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
-include ../Make.inc
-O:=$(HOST_O)
-
-LIB=libmach.a
-OFILES=\
- executable.$O\
- fakeobj.$O\
- map.$O\
- obj.$O\
- swap.$O\
- sym.$O\
- access.$O\
- machdata.$O\
- setmach.$O\
- 5.$O\
- 6.$O\
- 8.$O\
- 5db.$O\
- 8db.$O\
- 5obj.$O\
- 6obj.$O\
- 8obj.$O\
-
-ifneq ($(GOHOSTOS),windows)
-OFILES+=\
- $(shell uname | tr A-Z a-z).$O\
-
-else
-OFILES+=\
- windows.$O\
-
-endif
-
-HFILES=../../include/mach.h elf.h macho.h obj.h
-
-include ../Make.clib
+include ../Make.dist
diff --git a/src/libmach/executable.c b/src/libmach/executable.c
index e90334438..3db3e7da4 100644
--- a/src/libmach/executable.c
+++ b/src/libmach/executable.c
@@ -66,6 +66,7 @@ static int adotout(int, Fhdr*, ExecHdr*);
static int elfdotout(int, Fhdr*, ExecHdr*);
static int machdotout(int, Fhdr*, ExecHdr*);
static int armdotout(int, Fhdr*, ExecHdr*);
+static int pedotout(int, Fhdr*, ExecHdr*);
static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
static void setdata(Fhdr*, uvlong, int32, vlong, int32);
static void settext(Fhdr*, uvlong, uvlong, int32, vlong);
@@ -312,6 +313,15 @@ ExecTable exectab[] =
sizeof(Exec),
beswal,
common },
+ { 0x4d5a9000, /* see dosstub[] in pe.c */
+ "windows PE executable",
+ nil,
+ FWINPE,
+ 0,
+ &mi386,
+ sizeof(Exec), /* TODO */
+ nil,
+ pedotout },
{ 0 },
};
@@ -502,6 +512,8 @@ commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
int32 pgsize;
uvlong entry;
+ USED(unused);
+
hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
if(!(hp->e.exechdr.magic & HDR_MAGIC))
return 0;
@@ -542,6 +554,10 @@ commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
static int
mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
{
+ USED(fd);
+ USED(fp);
+ USED(hp);
+
abort();
#ifdef unused
USED(fd);
@@ -573,6 +589,10 @@ abort();
static int
mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
{
+ USED(fd);
+ USED(fp);
+ USED(hp);
+
abort();
#ifdef unused
USED(fd);
@@ -604,6 +624,10 @@ abort();
static int
sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
{
+ USED(fd);
+ USED(fp);
+ USED(hp);
+
abort();
#ifdef unused
USED(fd);
@@ -624,6 +648,10 @@ abort();
static int
nextboot(int fd, Fhdr *fp, ExecHdr *hp)
{
+ USED(fd);
+ USED(fp);
+ USED(hp);
+
abort();
#ifdef unused
USED(fd);
@@ -645,12 +673,11 @@ abort();
static int
elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
{
-
uvlong (*swav)(uvlong);
uint32 (*swal)(uint32);
ushort (*swab)(ushort);
Ehdr64 *ep;
- Phdr64 *ph;
+ Phdr64 *ph, *pph;
Shdr64 *sh;
int i, it, id, is, phsz, shsz;
@@ -770,7 +797,8 @@ elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
}
settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
- setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
+ pph = ph + id;
+ setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
if(is != -1)
setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
else if(sh != 0){
@@ -784,7 +812,7 @@ elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
buf = malloc(sh[ep->shstrndx].size);
if (buf == 0)
goto done;
- memset(buf, 0, sizeof buf);
+ memset(buf, 0, sh[ep->shstrndx].size);
seek(fd, sh[ep->shstrndx].offset, 0);
i = read(fd, buf, sh[ep->shstrndx].size);
USED(i); // shut up ubuntu gcc
@@ -962,7 +990,7 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
buf = malloc(sh[ep->shstrndx].size);
if (buf == 0)
goto done;
- memset(buf, 0, sizeof buf);
+ memset(buf, 0, sh[ep->shstrndx].size);
seek(fd, sh[ep->shstrndx].offset, 0);
i = read(fd, buf, sh[ep->shstrndx].size);
USED(i); // shut up ubuntu gcc
@@ -1022,7 +1050,6 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp)
mp->sizeofcmds = swal(mp->sizeofcmds);
mp->flags = swal(mp->flags);
mp->reserved = swal(mp->reserved);
- hdrsize = 0;
switch(mp->magic) {
case 0xFEEDFACE: // 32-bit mach
@@ -1077,7 +1104,9 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp)
datava = 0;
symtab = 0;
pclntab = 0;
- textsize = datasize = bsssize = 0;
+ textsize = 0;
+ datasize = 0;
+ bsssize = 0;
for (i = 0; i < mp->ncmds; i++) {
MachCmd *c;
@@ -1232,6 +1261,165 @@ armdotout(int fd, Fhdr *fp, ExecHdr *hp)
return 1;
}
+/*
+ * Structures needed to parse PE image.
+ */
+typedef struct {
+ uint16 Machine;
+ uint16 NumberOfSections;
+ uint32 TimeDateStamp;
+ uint32 PointerToSymbolTable;
+ uint32 NumberOfSymbols;
+ uint16 SizeOfOptionalHeader;
+ uint16 Characteristics;
+} IMAGE_FILE_HEADER;
+
+typedef struct {
+ uint8 Name[8];
+ uint32 VirtualSize;
+ uint32 VirtualAddress;
+ uint32 SizeOfRawData;
+ uint32 PointerToRawData;
+ uint32 PointerToRelocations;
+ uint32 PointerToLineNumbers;
+ uint16 NumberOfRelocations;
+ uint16 NumberOfLineNumbers;
+ uint32 Characteristics;
+} IMAGE_SECTION_HEADER;
+
+typedef struct {
+ uint32 VirtualAddress;
+ uint32 Size;
+} IMAGE_DATA_DIRECTORY;
+
+typedef struct {
+ uint16 Magic;
+ uint8 MajorLinkerVersion;
+ uint8 MinorLinkerVersion;
+ uint32 SizeOfCode;
+ uint32 SizeOfInitializedData;
+ uint32 SizeOfUninitializedData;
+ uint32 AddressOfEntryPoint;
+ uint32 BaseOfCode;
+ uint32 BaseOfData;
+ uint32 ImageBase;
+ uint32 SectionAlignment;
+ uint32 FileAlignment;
+ uint16 MajorOperatingSystemVersion;
+ uint16 MinorOperatingSystemVersion;
+ uint16 MajorImageVersion;
+ uint16 MinorImageVersion;
+ uint16 MajorSubsystemVersion;
+ uint16 MinorSubsystemVersion;
+ uint32 Win32VersionValue;
+ uint32 SizeOfImage;
+ uint32 SizeOfHeaders;
+ uint32 CheckSum;
+ uint16 Subsystem;
+ uint16 DllCharacteristics;
+ uint32 SizeOfStackReserve;
+ uint32 SizeOfStackCommit;
+ uint32 SizeOfHeapReserve;
+ uint32 SizeOfHeapCommit;
+ uint32 LoaderFlags;
+ uint32 NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} IMAGE_OPTIONAL_HEADER;
+
+static int
+match8(void *buf, char *cmp)
+{
+ return strncmp((char*)buf, cmp, 8) == 0;
+}
+
+/* TODO(czaplinski): 64b windows? */
+/*
+ * Read from Windows PE/COFF .exe file image.
+ */
+static int
+pedotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+ uint32 start, magic;
+ uint32 symtab, esymtab;
+ IMAGE_FILE_HEADER fh;
+ IMAGE_SECTION_HEADER sh;
+ IMAGE_OPTIONAL_HEADER oh;
+ uint8 sym[18];
+ uint32 *valp;
+ int i;
+
+ USED(hp);
+ seek(fd, 0x3c, 0);
+ if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
+ werrstr("crippled PE MSDOS header");
+ return 0;
+ }
+ start = leswal(start);
+
+ seek(fd, start, 0);
+ if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
+ werrstr("no PE magic number found");
+ return 0;
+ }
+ if (beswal(magic) != 0x50450000) { /* "PE\0\0" */
+ werrstr("incorrect PE magic number");
+ return 0;
+ }
+
+ if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
+ werrstr("crippled PE File Header");
+ return 0;
+ }
+ if (fh.PointerToSymbolTable == 0) {
+ werrstr("zero pointer to COFF symbol table");
+ return 0;
+ }
+
+ if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
+ werrstr("crippled PE Optional Header");
+ return 0;
+ }
+
+ seek(fd, start+sizeof(magic)+sizeof(fh)+leswab(fh.SizeOfOptionalHeader), 0);
+ fp->txtaddr = 0;
+ fp->dataddr = 0;
+ for (i=0; i<leswab(fh.NumberOfSections); i++) {
+ if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
+ werrstr("could not read Section Header %d", i+1);
+ return 0;
+ }
+ if (match8(sh.Name, ".text"))
+ settext(fp, leswal(sh.VirtualAddress), leswal(oh.AddressOfEntryPoint), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
+ if (match8(sh.Name, ".data"))
+ setdata(fp, leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
+ }
+ if (fp->txtaddr==0 || fp->dataddr==0) {
+ werrstr("no .text or .data");
+ return 0;
+ }
+
+ seek(fd, leswal(fh.PointerToSymbolTable), 0);
+ symtab = esymtab = 0;
+ for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
+ if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
+ werrstr("crippled COFF symbol %d", i);
+ return 0;
+ }
+ valp = (uint32 *)&sym[8];
+ if (match8(sym, "symtab"))
+ symtab = leswal(*valp);
+ if (match8(sym, "esymtab"))
+ esymtab = leswal(*valp);
+ }
+ if (symtab==0 || esymtab==0) {
+ werrstr("no symtab or esymtab in COFF symbol table");
+ return 0;
+ }
+ setsym(fp, symtab, esymtab-symtab, 0, 0, 0, 0);
+
+ return 1;
+}
+
static void
settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
{
@@ -1267,7 +1455,6 @@ setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong l
fp->lnpcsz = lnpcsz;
}
-
static uvlong
_round(uvlong a, uint32 b)
{
diff --git a/src/libmach/fakeobj.c b/src/libmach/fakeobj.c
index ea7ef012c..a4a897cfe 100644
--- a/src/libmach/fakeobj.c
+++ b/src/libmach/fakeobj.c
@@ -13,17 +13,17 @@
#include <mach.h>
#include "obj.h"
-int _is2(char* x) { return 0; }
-int _is7(char* x) { return 0; }
-int _is9(char* x) { return 0; }
-int _isk(char* x) { return 0; }
-int _isq(char* x) { return 0; }
-int _isv(char* x) { return 0; }
-int _isu(char* x) { return 0; }
-int _read2(Biobuf* b, Prog* p) { return 0; }
-int _read7(Biobuf* b, Prog* p) { return 0; }
-int _read9(Biobuf* b, Prog* p) { return 0; }
-int _readk(Biobuf* b, Prog* p) { return 0; }
-int _readq(Biobuf* b, Prog* p) { return 0; }
-int _readv(Biobuf* b, Prog* p) { return 0; }
-int _readu(Biobuf* b, Prog* p) { return 0; }
+int _is2(char* x) { USED(x); return 0; }
+int _is7(char* x) { USED(x); return 0; }
+int _is9(char* x) { USED(x); return 0; }
+int _isk(char* x) { USED(x); return 0; }
+int _isq(char* x) { USED(x); return 0; }
+int _isv(char* x) { USED(x); return 0; }
+int _isu(char* x) { USED(x); return 0; }
+int _read2(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _read7(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _read9(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _readk(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _readq(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _readv(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+int _readu(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
index 6ce18957f..2c143266a 100644
--- a/src/libmach/linux.c
+++ b/src/libmach/linux.c
@@ -807,6 +807,8 @@ ptraceerr:
static int
ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
{
+ USED(seg);
+
return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
isr, map->pid, addr, v, n);
}
@@ -937,6 +939,8 @@ ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
{
int laddr;
uvlong u;
+
+ USED(seg);
if((laddr = go2linux(addr)) < 0){
if(isr){
diff --git a/src/libmach/machdata.c b/src/libmach/machdata.c
index 425a92179..66c19f953 100644
--- a/src/libmach/machdata.c
+++ b/src/libmach/machdata.c
@@ -113,7 +113,7 @@ symoff(char *buf, int n, uvlong v, int space)
if (s.type != 't' && s.type != 'T' && delta >= 4096)
return snprint(buf, n, "%llux", v);
else if (delta)
- return snprint(buf, n, "%s+%#lux", s.name, delta);
+ return snprint(buf, n, "%s+%#ux", s.name, delta);
else
return snprint(buf, n, "%s", s.name);
}
@@ -139,7 +139,7 @@ fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
case 'X':
if (get4(map, rp->roffs, &r) < 0)
return -1;
- snprint(buf, n, "%lux", r);
+ snprint(buf, n, "%ux", r);
break;
case 'F': /* first reg of double reg pair */
if (modif == 'F')
@@ -219,12 +219,12 @@ ieeedftos(char *buf, int n, uint32 h, uint32 l)
return snprint(buf, n, "0.");
exp = (h>>20) & ((1L<<11)-1L);
if(exp == 0)
- return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
+ return snprint(buf, n, "DeN(%.8ux%.8ux)", h, l);
if(exp == ((1L<<11)-1L)){
if(l==0 && (h&((1L<<20)-1L)) == 0)
return snprint(buf, n, "Inf");
else
- return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
+ return snprint(buf, n, "NaN(%.8ux%.8ux)", h&((1<<20)-1), l);
}
exp -= (1L<<10) - 2L;
fr = l & ((1L<<16)-1L);
@@ -256,7 +256,7 @@ ieeesftos(char *buf, int n, uint32 h)
return snprint(buf, n, "0.");
exp = (h>>23) & ((1L<<8)-1L);
if(exp == 0)
- return snprint(buf, n, "DeN(%.8lux)", h);
+ return snprint(buf, n, "DeN(%.8ux)", h);
if(exp == ((1L<<8)-1L)){
if((h&((1L<<23)-1L)) == 0)
return snprint(buf, n, "Inf");
diff --git a/src/libmach/map.c b/src/libmach/map.c
index ebfe03702..cd5ef0985 100644
--- a/src/libmach/map.c
+++ b/src/libmach/map.c
@@ -137,6 +137,8 @@ int
fdrw(Map *map, Seg *s, uvlong addr, void *v, uint n, int isread)
{
int tot, m;
+
+ USED(map);
for(tot=0; tot<n; tot+=m){
if(isread)
diff --git a/src/libmach/netbsd.c b/src/libmach/netbsd.c
new file mode 100644
index 000000000..03e08d9e8
--- /dev/null
+++ b/src/libmach/netbsd.c
@@ -0,0 +1,46 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+ sysfatal("ctlproc unimplemented in NetBSD");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ sysfatal("proctextfile unimplemented in NetBSD");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ sysfatal("procstatus unimplemented in NetBSD");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ sysfatal("attachproc unimplemented in NetBSD");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ sysfatal("detachproc unimplemented in NetBSD");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ sysfatal("procthreadpids unimplemented in NetBSD");
+ return -1;
+}
diff --git a/src/libmach/plan9.c b/src/libmach/plan9.c
new file mode 100644
index 000000000..59e2649d0
--- /dev/null
+++ b/src/libmach/plan9.c
@@ -0,0 +1,72 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+ USED(pid);
+ USED(msg);
+
+ sysfatal("ctlproc unimplemented on Plan 9");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ USED(pid);
+
+ sysfatal("proctextfile unimplemented on Plan 9");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ USED(pid);
+
+ sysfatal("procstatus unimplemented on Plan 9");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ USED(pid);
+ USED(fp);
+
+ sysfatal("attachproc unimplemented on Plan 9");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ USED(m);
+
+ sysfatal("detachproc unimplemented on Plan 9");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ USED(pid);
+ USED(p);
+ USED(np);
+
+ sysfatal("procthreadpids unimplemented on Plan 9");
+ return -1;
+}
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ USED(rqtp);
+ USED(rmtp);
+
+ sysfatal("nanosleep unimplemented on Plan 9");
+ return -1;
+}
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
index 5e4fdd867..1512d7a4f 100644
--- a/src/libmach/sym.c
+++ b/src/libmach/sym.c
@@ -124,7 +124,7 @@ syminit(int fd, Fhdr *fp)
/* minimum symbol record size = 4+1+2 bytes */
symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
if(symbols == 0) {
- werrstr("can't malloc %ld bytes", fp->symsz);
+ werrstr("can't malloc %d bytes", fp->symsz);
return -1;
}
Binit(&b, fd, OREAD);
@@ -203,11 +203,11 @@ syminit(int fd, Fhdr *fp)
}
}
if (debug)
- print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fmaxi);
+ print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmaxi);
if (fp->sppcsz) { /* pc-sp offset table */
spoff = (uchar *)malloc(fp->sppcsz);
if(spoff == 0) {
- werrstr("can't malloc %ld bytes", fp->sppcsz);
+ werrstr("can't malloc %d bytes", fp->sppcsz);
return -1;
}
Bseek(&b, fp->sppcoff, 0);
@@ -220,7 +220,7 @@ syminit(int fd, Fhdr *fp)
if (fp->lnpcsz) { /* pc-line number table */
pcline = (uchar *)malloc(fp->lnpcsz);
if(pcline == 0) {
- werrstr("can't malloc %ld bytes", fp->lnpcsz);
+ werrstr("can't malloc %d bytes", fp->lnpcsz);
return -1;
}
Bseek(&b, fp->lnpcoff, 0);
@@ -280,12 +280,12 @@ decodename(Biobuf *bp, Sym *p)
n = Bseek(bp, 0, 1)-o;
p->name = malloc(n);
if(p->name == 0) {
- werrstr("can't malloc %ld bytes", n);
+ werrstr("can't malloc %d bytes", n);
return -1;
}
Bseek(bp, -n, 1);
if(Bread(bp, p->name, n) != n) {
- werrstr("can't read %ld bytes of symbol name", n);
+ werrstr("can't read %d bytes of symbol name", n);
return -1;
}
} else {
@@ -297,7 +297,7 @@ decodename(Biobuf *bp, Sym *p)
n = Blinelen(bp);
p->name = malloc(n);
if(p->name == 0) {
- werrstr("can't malloc %ld bytes", n);
+ werrstr("can't malloc %d bytes", n);
return -1;
}
strcpy(p->name, cp);
@@ -913,7 +913,7 @@ file2pc(char *file, int32 line)
break;
free(name);
if(i >= nfiles) {
- werrstr("line %ld in file %s not found", line, file);
+ werrstr("line %d in file %s not found", line, file);
return ~0;
}
start = fp->addr; /* first text addr this file */
@@ -926,10 +926,10 @@ file2pc(char *file, int32 line)
* run the state machine to locate the pc closest to that value.
*/
if(debug)
- print("find pc for %ld - between: %llux and %llux\n", line, start, end);
+ print("find pc for %d - between: %llux and %llux\n", line, start, end);
pc = line2addr(line, start, end);
if(pc == ~0) {
- werrstr("line %ld not in file %s", line, file);
+ werrstr("line %d not in file %s", line, file);
return ~0;
}
return pc;
@@ -1146,7 +1146,7 @@ fline(char *str, int n, int32 line, Hist *base, Hist **ret)
else {
k = fileelem(fnames, (uchar*)start->name, str, n);
if(k+8 < n)
- sprint(str+k, ":%ld", line);
+ sprint(str+k, ":%d", line);
}
/**********Remove comments for complete back-trace of include sequence
* if(start != base) {
@@ -1404,7 +1404,7 @@ printhist(char *msg, Hist *hp, int count)
while(hp->name) {
if(count && ++i > count)
break;
- print("%s Line: %lx (%ld) Offset: %lx (%ld) Name: ", msg,
+ print("%s Line: %x (%d) Offset: %x (%d) Name: ", msg,
hp->line, hp->line, hp->offset, hp->offset);
for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
if (cp != (uchar *)hp->name+1)
diff --git a/src/make.bash b/src/make.bash
index 84b9908f4..b2de37b72 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -3,14 +3,48 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+# Environment variables that control make.bash:
+#
+# GOROOT_FINAL: The expected final Go root, baked into binaries.
+# The default is the location of the Go tree during the build.
+#
+# GOHOSTARCH: The architecture for host tools (compilers and
+# binaries). Binaries of this type must be executable on the current
+# system, so the only common reason to set this is to set
+# GOHOSTARCH=386 on an amd64 machine.
+#
+# GOARCH: The target architecture for installed packages and tools.
+#
+# GOOS: The target operating system for installed packages and tools.
+#
+# GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+# building the packages and commands.
+#
+# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+# building the commands.
+#
+# CGO_ENABLED: Controls cgo usage during the build. Set it to 1
+# to include all cgo related files, .c and .go file with "cgo"
+# build directive, in the build. Set it to 0 to ignore them.
+
set -e
-if [ ! -f env.bash ]; then
+if [ ! -f run.bash ]; then
echo 'make.bash must be run from $GOROOT/src' 1>&2
exit 1
fi
-. ./env.bash
-if ld --version 2>&1 | grep 'gold.*2\.20' >/dev/null; then
+# Test for Windows.
+case "$(uname)" in
+*MINGW* | *WIN32* | *CYGWIN*)
+ echo 'ERROR: Do not use make.bash to build on Windows.'
+ echo 'Use make.bat instead.'
+ echo
+ exit 1
+ ;;
+esac
+
+# Test for bad ld.
+if ld --version 2>&1 | grep 'gold.* 2\.20' >/dev/null; then
echo 'ERROR: Your system has gold 2.20 installed.'
echo 'This version is shipped by Ubuntu even though'
echo 'it is known not to work on Ubuntu.'
@@ -21,90 +55,83 @@ if ld --version 2>&1 | grep 'gold.*2\.20' >/dev/null; then
exit 1
fi
-# Create target directories
-if [ "$GOBIN" = "$GOROOT/bin" ]; then
- mkdir -p "$GOROOT/bin"
-fi
-mkdir -p "$GOROOT/pkg"
-
-GOROOT_FINAL=${GOROOT_FINAL:-$GOROOT}
-
-MAKEFLAGS=${MAKEFLAGS:-"-j4"}
-export MAKEFLAGS
-unset CDPATH # in case user has it set
-
-rm -f "$GOBIN"/quietgcc
-CC=${CC:-gcc}
-export CC
-sed -e "s|@CC@|$CC|" < "$GOROOT"/src/quietgcc.bash > "$GOBIN"/quietgcc
-chmod +x "$GOBIN"/quietgcc
-
-rm -f "$GOBIN"/gomake
-(
- echo '#!/bin/sh'
- echo 'export GOROOT=${GOROOT:-'$GOROOT_FINAL'}'
- echo 'exec '$MAKE' "$@"'
-) >"$GOBIN"/gomake
-chmod +x "$GOBIN"/gomake
-
-# TODO(brainman): delete this after 01/01/2012.
-rm -f "$GOBIN"/gotest # remove old bash version of gotest on Windows
-
-if [ -d /selinux -a -f /selinux/booleans/allow_execstack -a -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
- if ! cat /selinux/booleans/allow_execstack | grep -c '^1 1$' >> /dev/null ; then
- echo "WARNING: the default SELinux policy on, at least, Fedora 12 breaks "
- echo "Go. You can enable the features that Go needs via the following "
- echo "command (as root):"
- echo " # setsebool -P allow_execstack 1"
- echo
- echo "Note that this affects your system globally! "
- echo
- echo "The build will continue in five seconds in case we "
- echo "misdiagnosed the issue..."
-
- sleep 5
+# Test for bad SELinux.
+# On Fedora 16 the selinux filesystem is mounted at /sys/fs/selinux,
+# so loop through the possible selinux mount points.
+for se_mount in /selinux /sys/fs/selinux
+do
+ if [ -d $se_mount -a -f $se_mount/booleans/allow_execstack -a -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
+ if ! cat $se_mount/booleans/allow_execstack | grep -c '^1 1$' >> /dev/null ; then
+ echo "WARNING: the default SELinux policy on, at least, Fedora 12 breaks "
+ echo "Go. You can enable the features that Go needs via the following "
+ echo "command (as root):"
+ echo " # setsebool -P allow_execstack 1"
+ echo
+ echo "Note that this affects your system globally! "
+ echo
+ echo "The build will continue in five seconds in case we "
+ echo "misdiagnosed the issue..."
+
+ sleep 5
+ fi
fi
-fi
+done
-(
- cd "$GOROOT"/src/pkg;
- bash deps.bash # do this here so clean.bash will work in the pkg directory
-)
-bash "$GOROOT"/src/clean.bash
+# Clean old generated file that will cause problems in the build.
+rm -f ./pkg/runtime/runtime_defs.go
-# pkg builds libcgo and the Go programs in cmd.
-for i in lib9 libbio libmach cmd pkg
-do
- echo; echo; echo %%%% making $i %%%%; echo
- gomake -C $i install
-done
+# Finally! Run the build.
-# Print post-install messages.
-# Implemented as a function so that all.bash can repeat the output
-# after run.bash finishes running all the tests.
-installed() {
- eval $(gomake --no-print-directory -f Make.inc go-env)
- echo
- echo ---
- echo Installed Go for $GOOS/$GOARCH in "$GOROOT".
- echo Installed commands in "$GOBIN".
- case "$OLDPATH" in
- "$GOBIN:"* | *":$GOBIN" | *":$GOBIN:"*)
- ;;
- *)
- echo '***' "You need to add $GOBIN to your "'$PATH.' '***'
- esac
- echo The compiler is $GC.
- if [ "$(uname)" = "Darwin" ]; then
- echo
- echo On OS X the debuggers must be installed setgrp procmod.
- echo Read and run ./sudo.bash to install the debuggers.
- fi
- if [ "$GOROOT_FINAL" != "$GOROOT" ]; then
- echo
- echo The binaries expect "$GOROOT" to be copied or moved to "$GOROOT_FINAL".
+echo '# Building C bootstrap tool.'
+echo cmd/dist
+export GOROOT="$(cd .. && pwd)"
+GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
+DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'
+
+mflag=""
+case "$GOHOSTARCH" in
+386) mflag=-m32;;
+amd64) mflag=-m64;;
+esac
+gcc $mflag -O2 -Wall -Werror -ggdb -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
+
+eval $(./cmd/dist/dist env -p)
+echo
+
+if [ "$1" = "--dist-tool" ]; then
+ # Stop after building dist tool.
+ mkdir -p "$GOTOOLDIR"
+ if [ "$2" != "" ]; then
+ cp cmd/dist/dist "$2"
fi
-}
+ mv cmd/dist/dist "$GOTOOLDIR"/dist
+ exit 0
+fi
+
+echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
+buildall="-a"
+if [ "$1" = "--no-clean" ]; then
+ buildall=""
+fi
+./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap
+# Delay move of dist tool to now, because bootstrap may clear tool directory.
+mv cmd/dist/dist "$GOTOOLDIR"/dist
+"$GOTOOLDIR"/go_bootstrap clean -i std
+echo
+
+if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
+ echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
+ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+ "$GOTOOLDIR"/go_bootstrap install -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+ echo
+fi
+
+echo "# Building packages and commands for $GOOS/$GOARCH."
+"$GOTOOLDIR"/go_bootstrap install -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+echo
-(installed) # run in sub-shell to avoid polluting environment
+rm -f "$GOTOOLDIR"/go_bootstrap
+if [ "$1" != "--no-banner" ]; then
+ "$GOTOOLDIR"/dist banner
+fi
diff --git a/src/make.bat b/src/make.bat
new file mode 100644
index 000000000..ec39392dd
--- /dev/null
+++ b/src/make.bat
@@ -0,0 +1,111 @@
+:: Copyright 2012 The Go Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style
+:: license that can be found in the LICENSE file.
+
+:: Environment variables that control make.bat:
+::
+:: GOROOT_FINAL: The expected final Go root, baked into binaries.
+:: The default is the location of the Go tree during the build.
+::
+:: GOHOSTARCH: The architecture for host tools (compilers and
+:: binaries). Binaries of this type must be executable on the current
+:: system, so the only common reason to set this is to set
+:: GOHOSTARCH=386 on an amd64 machine.
+::
+:: GOARCH: The target architecture for installed packages and tools.
+::
+:: GOOS: The target operating system for installed packages and tools.
+::
+:: GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+:: building the packages and commands.
+::
+:: GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+:: building the commands.
+::
+:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
+:: to include all cgo related files, .c and .go file with "cgo"
+:: build directive, in the build. Set it to 0 to ignore them.
+
+@echo off
+
+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+setlocal
+:nolocal
+
+set GOBUILDFAIL=0
+
+if exist make.bat goto ok
+echo Must run make.bat from Go src directory.
+goto fail
+:ok
+
+:: Clean old generated file that will cause problems in the build.
+del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
+
+:: Grab default GOROOT_FINAL and set GOROOT for build.
+:: The expression %VAR:\=\\% means to take %VAR%
+:: and apply the substitution \ = \\, escaping the
+:: backslashes. Then we wrap that in quotes to create
+:: a C string.
+cd ..
+set GOROOT=%CD%
+cd src
+if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL=%GOROOT%
+set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
+
+echo # Building C bootstrap tool.
+echo cmd/dist
+if not exist ..\bin\tool mkdir ..\bin\tool
+:: Windows has no glob expansion, so spell out cmd/dist/*.c.
+gcc -O2 -Wall -Werror -o cmd/dist/dist.exe -Icmd/dist %DEFGOROOT% cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildruntime.c cmd/dist/goc2c.c cmd/dist/main.c cmd/dist/windows.c
+if errorlevel 1 goto fail
+.\cmd\dist\dist env -wp >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
+echo # Building compilers and Go bootstrap tool.
+set buildall=-a
+if x%1==x--no-clean set buildall=
+.\cmd\dist\dist bootstrap %buildall% -v
+if errorlevel 1 goto fail
+:: Delay move of dist tool to now, because bootstrap cleared tool directory.
+move .\cmd\dist\dist.exe "%GOTOOLDIR%\dist.exe"
+"%GOTOOLDIR%\go_bootstrap" clean -i std
+echo.
+
+if not %GOHOSTARCH% == %GOARCH% goto localbuild
+if not %GOHOSTOS% == %GOOS% goto localbuild
+goto mainbuild
+
+:localbuild
+echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%
+setlocal
+set GOOS=%GOHOSTOS%
+set GOARCH=%GOHOSTARCH%
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std
+endlocal
+if errorlevel 1 goto fail
+echo.
+
+:mainbuild
+echo # Building packages and commands.
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std
+if errorlevel 1 goto fail
+del "%GOTOOLDIR%\go_bootstrap.exe"
+echo.
+
+if x%1==x--no-banner goto nobanner
+"%GOTOOLDIR%\dist" banner
+:nobanner
+
+goto end
+
+:fail
+set GOBUILDFAIL=1
+
+:end
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
deleted file mode 100644
index 44d7f4367..000000000
--- a/src/pkg/Makefile
+++ /dev/null
@@ -1,311 +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.
-
-# After editing the DIRS= list or adding imports to any Go files
-# in any of those directories, run:
-#
-# ./deps.bash
-#
-# to rebuild the dependency information in Make.deps.
-
-include ../Make.inc
-
-all: install
-
-DIRS=\
- archive/tar\
- archive/zip\
- asn1\
- big\
- bufio\
- bytes\
- cmath\
- compress/bzip2\
- compress/flate\
- compress/gzip\
- compress/lzw \
- compress/zlib\
- container/heap\
- container/list\
- container/ring\
- container/vector\
- crypto\
- crypto/aes\
- crypto/blowfish\
- crypto/cast5\
- crypto/cipher\
- crypto/des\
- crypto/dsa\
- crypto/ecdsa\
- crypto/elliptic\
- crypto/hmac\
- crypto/md4\
- crypto/md5\
- crypto/ocsp\
- crypto/openpgp\
- crypto/openpgp/armor\
- crypto/openpgp/elgamal\
- crypto/openpgp/error\
- crypto/openpgp/packet\
- crypto/openpgp/s2k\
- crypto/rand\
- crypto/rc4\
- crypto/ripemd160\
- crypto/rsa\
- crypto/sha1\
- crypto/sha256\
- crypto/sha512\
- crypto/subtle\
- crypto/tls\
- crypto/twofish\
- crypto/x509\
- crypto/x509/pkix\
- crypto/xtea\
- csv\
- debug/dwarf\
- debug/macho\
- debug/elf\
- debug/gosym\
- debug/pe\
- ebnf\
- encoding/ascii85\
- encoding/base32\
- encoding/base64\
- encoding/binary\
- encoding/git85\
- encoding/hex\
- encoding/pem\
- exec\
- exp/gui\
- exp/gui/x11\
- exp/norm\
- exp/regexp/syntax\
- exp/template/html\
- expvar\
- flag\
- fmt\
- go/ast\
- go/build\
- go/doc\
- go/parser\
- go/printer\
- go/scanner\
- go/token\
- go/typechecker\
- go/types\
- gob\
- hash\
- hash/adler32\
- hash/crc32\
- hash/crc64\
- hash/fnv\
- html\
- http\
- http/cgi\
- http/fcgi\
- http/pprof\
- http/httptest\
- http/spdy\
- image\
- image/bmp\
- image/draw\
- image/gif\
- image/jpeg\
- image/png\
- image/tiff\
- image/ycbcr\
- index/suffixarray\
- io\
- io/ioutil\
- json\
- log\
- mail\
- math\
- mime\
- mime/multipart\
- net\
- net/dict\
- net/textproto\
- netchan\
- old/template\
- os\
- os/signal\
- os/user\
- patch\
- path\
- path/filepath\
- rand\
- reflect\
- regexp\
- rpc\
- rpc/jsonrpc\
- runtime\
- runtime/cgo\
- runtime/debug\
- runtime/pprof\
- scanner\
- smtp\
- sort\
- strconv\
- strings\
- sync\
- sync/atomic\
- syscall\
- syslog\
- tabwriter\
- template\
- template/parse\
- testing\
- testing/iotest\
- testing/quick\
- testing/script\
- time\
- try\
- unicode\
- url\
- utf16\
- utf8\
- websocket\
- xml\
- ../cmd/cgo\
- ../cmd/ebnflint\
- ../cmd/godoc\
- ../cmd/gofix\
- ../cmd/gofmt\
- ../cmd/goinstall\
- ../cmd/gotest\
- ../cmd/gotype\
- ../cmd/govet\
- ../cmd/goyacc\
- ../cmd/hgpatch\
-
-ifeq ($(GOOS),linux)
-DIRS+=\
- os/inotify\
-
-endif
-
-ifeq ($(GOOS),plan9)
-NOPLAN9BUILD=\
- crypto/tls\
- exp/gui/x11\
- expvar\
- http\
- http/cgi\
- http/fcgi\
- http/httptest\
- http/pprof\
- http/spdy\
- mail\
- mime/multipart\
- net\
- net/dict\
- net/textproto\
- netchan\
- os/signal\
- rpc\
- rpc/jsonrpc\
- smtp\
- syslog\
- websocket\
- ../cmd/godoc\
- ../cmd/goinstall\
-
-DIRS:=$(filter-out $(NOPLAN9BUILD),$(DIRS))
-endif
-
-NOTEST+=\
- crypto\
- crypto/openpgp/error\
- crypto/x509/pkix\
- exp/gui\
- exp/gui/x11\
- go/ast\
- go/doc\
- go/token\
- hash\
- http/pprof\
- http/httptest\
- image/bmp\
- image/gif\
- net/dict\
- rand\
- runtime/cgo\
- syscall\
- testing\
- testing/iotest\
- try\
- ../cmd/cgo\
- ../cmd/ebnflint\
- ../cmd/godoc\
- ../cmd/gotest\
- ../cmd/goyacc\
- ../cmd/hgpatch\
-
-NOBENCH+=\
- container/vector\
-
-# Disable tests that windows cannot run yet.
-ifeq ($(GOOS),windows)
-NOTEST+=os/signal # no signals
-NOTEST+=syslog # no network
-NOTEST+=time # no syscall.Kill, syscall.SIGCHLD for sleep tests
-endif
-
-TEST=\
- $(filter-out $(NOTEST),$(DIRS))
-
-BENCH=\
- $(filter-out $(NOBENCH),$(TEST))
-
-clean.dirs: $(addsuffix .clean, $(DIRS))
-install.dirs: $(addsuffix .install, $(DIRS))
-nuke.dirs: $(addsuffix .nuke, $(DIRS))
-test.dirs: $(addsuffix .test, $(TEST))
-testshort.dirs: $(addsuffix .testshort, $(TEST))
-bench.dirs: $(addsuffix .bench, $(BENCH))
-
-%.clean:
- +$(MAKE) -C $* clean
-
-%.install:
- +@echo install $*
- +@$(MAKE) -C $* install.clean >$*/build.out 2>&1 || (echo INSTALL FAIL $*; cat $*/build.out; exit 1)
-
-%.nuke:
- +$(MAKE) -C $* nuke
-
-%.test:
- +@echo test $*
- +@$(MAKE) -C $* test.clean >$*/test.out 2>&1 || (echo TEST FAIL $*; cat $*/test.out; exit 1)
-
-%.testshort:
- +@echo test $*
- +@$(MAKE) -C $* testshort.clean >$*/test.out 2>&1 || (echo TEST FAIL $*; cat $*/test.out; exit 1)
-
-%.bench:
- +$(MAKE) -C $* bench
-
-clean: clean.dirs
-
-install: install.dirs
-
-test: test.dirs
-
-testshort: testshort.dirs
-
-bench: bench.dirs ../../test/garbage.bench
-
-nuke: nuke.dirs
- rm -rf "$(GOROOT)"/pkg/*
-
-deps:
- ./deps.bash
-
-echo-dirs:
- @echo $(DIRS)
-
--include Make.deps
-
-runtime/cgo.install: ../cmd/cgo.install
diff --git a/src/pkg/archive/tar/Makefile b/src/pkg/archive/tar/Makefile
deleted file mode 100644
index 8897e883e..000000000
--- a/src/pkg/archive/tar/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=archive/tar
-GOFILES=\
- common.go\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
index 528858765..fc7a40923 100644
--- a/src/pkg/archive/tar/common.go
+++ b/src/pkg/archive/tar/common.go
@@ -11,40 +11,42 @@
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
package tar
+import "time"
+
const (
blockSize = 512
// Types
- TypeReg = '0'
- TypeRegA = '\x00'
- TypeLink = '1'
- TypeSymlink = '2'
- TypeChar = '3'
- TypeBlock = '4'
- TypeDir = '5'
- TypeFifo = '6'
- TypeCont = '7'
- TypeXHeader = 'x'
- TypeXGlobalHeader = 'g'
+ TypeReg = '0' // regular file
+ TypeRegA = '\x00' // regular file
+ TypeLink = '1' // hard link
+ TypeSymlink = '2' // symbolic link
+ TypeChar = '3' // character device node
+ TypeBlock = '4' // block device node
+ TypeDir = '5' // directory
+ TypeFifo = '6' // fifo node
+ TypeCont = '7' // reserved
+ TypeXHeader = 'x' // extended header
+ TypeXGlobalHeader = 'g' // global extended header
)
// A Header represents a single header in a tar archive.
// Some fields may not be populated.
type Header struct {
- Name string
- Mode int64
- Uid int
- Gid int
- Size int64
- Mtime int64
- Typeflag byte
- Linkname string
- Uname string
- Gname string
- Devmajor int64
- Devminor int64
- Atime int64
- Ctime int64
+ Name string // name of header file entry
+ Mode int64 // permission and mode bits
+ Uid int // user id of owner
+ Gid int // group id of owner
+ Size int64 // length in bytes
+ ModTime time.Time // modified time
+ Typeflag byte // type of header entry
+ Linkname string // target name of link
+ Uname string // user name of owner
+ Gname string // group name of owner
+ Devmajor int64 // major number of character or block device
+ Devminor int64 // minor number of character or block device
+ AccessTime time.Time // access time
+ ChangeTime time.Time // status change time
}
var zeroBlock = make([]byte, blockSize)
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index 45d95c3df..1b40af812 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -9,14 +9,16 @@ package tar
import (
"bytes"
+ "errors"
"io"
"io/ioutil"
"os"
"strconv"
+ "time"
)
var (
- HeaderError = os.NewError("invalid tar header")
+ ErrHeader = errors.New("archive/tar: invalid tar header")
)
// A Reader provides sequential access to the contents of a tar archive.
@@ -28,7 +30,7 @@ var (
// tr := tar.NewReader(r)
// for {
// hdr, err := tr.Next()
-// if err == os.EOF {
+// if err == io.EOF {
// // end of tar archive
// break
// }
@@ -39,7 +41,7 @@ var (
// }
type Reader struct {
r io.Reader
- err os.Error
+ err error
nb int64 // number of unread bytes for current file entry
pad int64 // amount of padding (ignored) after current file entry
}
@@ -48,7 +50,7 @@ type Reader struct {
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
// Next advances to the next entry in the tar archive.
-func (tr *Reader) Next() (*Header, os.Error) {
+func (tr *Reader) Next() (*Header, error) {
var hdr *Header
if tr.err == nil {
tr.skipUnread()
@@ -78,7 +80,7 @@ func (tr *Reader) octal(b []byte) int64 {
for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
b = b[0 : len(b)-1]
}
- x, err := strconv.Btoui64(cString(b), 8)
+ x, err := strconv.ParseUint(cString(b), 8, 64)
if err != nil {
tr.err = err
}
@@ -94,7 +96,7 @@ func (tr *Reader) skipUnread() {
return
}
}
- _, tr.err = io.Copyn(ioutil.Discard, tr.r, nr)
+ _, tr.err = io.CopyN(ioutil.Discard, tr.r, nr)
}
func (tr *Reader) verifyChecksum(header []byte) bool {
@@ -119,15 +121,15 @@ func (tr *Reader) readHeader() *Header {
return nil
}
if bytes.Equal(header, zeroBlock[0:blockSize]) {
- tr.err = os.EOF
+ tr.err = io.EOF
} else {
- tr.err = HeaderError // zero block and then non-zero block
+ tr.err = ErrHeader // zero block and then non-zero block
}
return nil
}
if !tr.verifyChecksum(header) {
- tr.err = HeaderError
+ tr.err = ErrHeader
return nil
}
@@ -140,7 +142,7 @@ func (tr *Reader) readHeader() *Header {
hdr.Uid = int(tr.octal(s.next(8)))
hdr.Gid = int(tr.octal(s.next(8)))
hdr.Size = tr.octal(s.next(12))
- hdr.Mtime = tr.octal(s.next(12))
+ hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
s.next(8) // chksum
hdr.Typeflag = s.next(1)[0]
hdr.Linkname = cString(s.next(100))
@@ -177,8 +179,8 @@ func (tr *Reader) readHeader() *Header {
prefix = cString(s.next(155))
case "star":
prefix = cString(s.next(131))
- hdr.Atime = tr.octal(s.next(12))
- hdr.Ctime = tr.octal(s.next(12))
+ hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
+ hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name
@@ -186,7 +188,7 @@ func (tr *Reader) readHeader() *Header {
}
if tr.err != nil {
- tr.err = HeaderError
+ tr.err = ErrHeader
return nil
}
@@ -199,12 +201,12 @@ func (tr *Reader) readHeader() *Header {
}
// Read reads from the current entry in the tar archive.
-// It returns 0, os.EOF when it reaches the end of that entry,
+// It returns 0, io.EOF when it reaches the end of that entry,
// until Next is called to advance to the next entry.
-func (tr *Reader) Read(b []byte) (n int, err os.Error) {
+func (tr *Reader) Read(b []byte) (n int, err error) {
if tr.nb == 0 {
// file consumed
- return 0, os.EOF
+ return 0, io.EOF
}
if int64(len(b)) > tr.nb {
@@ -213,7 +215,7 @@ func (tr *Reader) Read(b []byte) (n int, err os.Error) {
n, err = tr.r.Read(b)
tr.nb -= int64(n)
- if err == os.EOF && tr.nb > 0 {
+ if err == io.EOF && tr.nb > 0 {
err = io.ErrUnexpectedEOF
}
tr.err = err
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index f473c900f..0a8646c39 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -10,8 +10,8 @@ import (
"fmt"
"io"
"os"
- "reflect"
"testing"
+ "time"
)
type untarTest struct {
@@ -23,24 +23,24 @@ type untarTest struct {
var gnuTarTest = &untarTest{
file: "testdata/gnu.tar",
headers: []*Header{
- &Header{
+ {
Name: "small.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1244428340,
+ ModTime: time.Unix(1244428340, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
- &Header{
+ {
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1244436044,
+ ModTime: time.Unix(1244436044, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
@@ -54,56 +54,56 @@ var gnuTarTest = &untarTest{
var untarTests = []*untarTest{
gnuTarTest,
- &untarTest{
+ {
file: "testdata/star.tar",
headers: []*Header{
- &Header{
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- Mtime: 1244592783,
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- Atime: 1244592783,
- Ctime: 1244592783,
+ {
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
},
- &Header{
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- Mtime: 1244592783,
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- Atime: 1244592783,
- Ctime: 1244592783,
+ {
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
},
},
},
- &untarTest{
+ {
file: "testdata/v7.tar",
headers: []*Header{
- &Header{
+ {
Name: "small.txt",
Mode: 0444,
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1244593104,
+ ModTime: time.Unix(1244593104, 0),
Typeflag: '\x00',
},
- &Header{
+ {
Name: "small2.txt",
Mode: 0444,
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1244593104,
+ ModTime: time.Unix(1244593104, 0),
Typeflag: '\x00',
},
},
@@ -126,13 +126,13 @@ testLoop:
f.Close()
continue testLoop
}
- if !reflect.DeepEqual(hdr, header) {
+ if *hdr != *header {
t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
i, j, *hdr, *header)
}
}
hdr, err := tr.Next()
- if err == os.EOF {
+ if err == io.EOF {
break
}
if hdr != nil || err != nil {
@@ -195,12 +195,12 @@ func TestIncrementalRead(t *testing.T) {
// loop over all files
for ; ; nread++ {
hdr, err := tr.Next()
- if hdr == nil || err == os.EOF {
+ if hdr == nil || err == io.EOF {
break
}
// check the header
- if !reflect.DeepEqual(hdr, headers[nread]) {
+ if *hdr != *headers[nread] {
t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
*hdr, headers[nread])
}
@@ -211,7 +211,7 @@ func TestIncrementalRead(t *testing.T) {
rdbuf := make([]uint8, 8)
for {
nr, err := tr.Read(rdbuf)
- if err == os.EOF {
+ if err == io.EOF {
break
}
if err != nil {
@@ -221,7 +221,7 @@ func TestIncrementalRead(t *testing.T) {
h.Write(rdbuf[0:nr])
}
// verify checksum
- have := fmt.Sprintf("%x", h.Sum())
+ have := fmt.Sprintf("%x", h.Sum(nil))
want := cksums[nread]
if want != have {
t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
@@ -240,31 +240,20 @@ func TestNonSeekable(t *testing.T) {
}
defer f.Close()
- // pipe the data in
- r, w, err := os.Pipe()
- if err != nil {
- t.Fatalf("Unexpected error %s", err)
+ type readerOnly struct {
+ io.Reader
}
- go func() {
- rdbuf := make([]uint8, 1<<16)
- for {
- nr, err := f.Read(rdbuf)
- w.Write(rdbuf[0:nr])
- if err == os.EOF {
- break
- }
- }
- w.Close()
- }()
-
- tr := NewReader(r)
+ tr := NewReader(readerOnly{f})
nread := 0
for ; ; nread++ {
- hdr, err := tr.Next()
- if hdr == nil || err == os.EOF {
+ _, err := tr.Next()
+ if err == io.EOF {
break
}
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
}
if nread != len(test.headers) {
diff --git a/src/pkg/archive/tar/testdata/writer.tar b/src/pkg/archive/tar/testdata/writer.tar
index 0358f91b9..e6d816ad0 100644
--- a/src/pkg/archive/tar/testdata/writer.tar
+++ b/src/pkg/archive/tar/testdata/writer.tar
Binary files differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index 8673bad31..b2b7a58a1 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -5,18 +5,19 @@
package tar
// TODO(dsymonds):
-// - catch more errors (no first header, write after close, etc.)
+// - catch more errors (no first header, etc.)
import (
+ "errors"
+ "fmt"
"io"
- "os"
"strconv"
)
var (
- ErrWriteTooLong = os.NewError("write too long")
- ErrFieldTooLong = os.NewError("header field too long")
- ErrWriteAfterClose = os.NewError("write after close")
+ ErrWriteTooLong = errors.New("archive/tar: write too long")
+ ErrFieldTooLong = errors.New("archive/tar: header field too long")
+ ErrWriteAfterClose = errors.New("archive/tar: write after close")
)
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
@@ -36,7 +37,7 @@ var (
// tw.Close()
type Writer struct {
w io.Writer
- err os.Error
+ err error
nb int64 // number of unwritten bytes for current file entry
pad int64 // amount of padding to write after current file entry
closed bool
@@ -47,7 +48,12 @@ type Writer struct {
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
// Flush finishes writing the current file (optional).
-func (tw *Writer) Flush() os.Error {
+func (tw *Writer) Flush() error {
+ if tw.nb > 0 {
+ tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
+ return tw.err
+ }
+
n := tw.nb + tw.pad
for n > 0 && tw.err == nil {
nr := n
@@ -79,7 +85,7 @@ func (tw *Writer) cString(b []byte, s string) {
// Encode x as an octal ASCII string and write it into b with leading zeros.
func (tw *Writer) octal(b []byte, x int64) {
- s := strconv.Itob64(x, 8)
+ s := strconv.FormatInt(x, 8)
// leading zeros, but leave room for a NUL.
for len(s)+1 < len(b) {
s = "0" + s
@@ -90,7 +96,7 @@ func (tw *Writer) octal(b []byte, x int64) {
// Write x into b, either as octal or as binary (GNUtar/star extension).
func (tw *Writer) numeric(b []byte, x int64) {
// Try octal first.
- s := strconv.Itob64(x, 8)
+ s := strconv.FormatInt(x, 8)
if len(s) < len(b) {
tw.octal(b, x)
return
@@ -107,7 +113,7 @@ func (tw *Writer) numeric(b []byte, x int64) {
// WriteHeader writes hdr and prepares to accept the file's contents.
// WriteHeader calls Flush if it is not the first header.
// Calling after a Close will return ErrWriteAfterClose.
-func (tw *Writer) WriteHeader(hdr *Header) os.Error {
+func (tw *Writer) WriteHeader(hdr *Header) error {
if tw.closed {
return ErrWriteAfterClose
}
@@ -127,19 +133,19 @@ func (tw *Writer) WriteHeader(hdr *Header) os.Error {
// TODO(dsymonds): handle names longer than 100 chars
copy(s.next(100), []byte(hdr.Name))
- tw.octal(s.next(8), hdr.Mode) // 100:108
- tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
- tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
- tw.numeric(s.next(12), hdr.Size) // 124:136
- tw.numeric(s.next(12), hdr.Mtime) // 136:148
- s.next(8) // chksum (148:156)
- s.next(1)[0] = hdr.Typeflag // 156:157
- s.next(100) // linkname (157:257)
- copy(s.next(8), []byte("ustar\x0000")) // 257:265
- tw.cString(s.next(32), hdr.Uname) // 265:297
- tw.cString(s.next(32), hdr.Gname) // 297:329
- tw.numeric(s.next(8), hdr.Devmajor) // 329:337
- tw.numeric(s.next(8), hdr.Devminor) // 337:345
+ tw.octal(s.next(8), hdr.Mode) // 100:108
+ tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
+ tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
+ tw.numeric(s.next(12), hdr.Size) // 124:136
+ tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148
+ s.next(8) // chksum (148:156)
+ s.next(1)[0] = hdr.Typeflag // 156:157
+ tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
+ copy(s.next(8), []byte("ustar\x0000")) // 257:265
+ tw.cString(s.next(32), hdr.Uname) // 265:297
+ tw.cString(s.next(32), hdr.Gname) // 297:329
+ tw.numeric(s.next(8), hdr.Devmajor) // 329:337
+ tw.numeric(s.next(8), hdr.Devminor) // 337:345
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
@@ -165,7 +171,7 @@ func (tw *Writer) WriteHeader(hdr *Header) os.Error {
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.
-func (tw *Writer) Write(b []byte) (n int, err os.Error) {
+func (tw *Writer) Write(b []byte) (n int, err error) {
if tw.closed {
err = ErrWriteTooLong
return
@@ -187,12 +193,15 @@ func (tw *Writer) Write(b []byte) (n int, err os.Error) {
// Close closes the tar archive, flushing any unwritten
// data to the underlying writer.
-func (tw *Writer) Close() os.Error {
+func (tw *Writer) Close() error {
if tw.err != nil || tw.closed {
return tw.err
}
tw.Flush()
tw.closed = true
+ if tw.err != nil {
+ return tw.err
+ }
// trailer: two zero blocks
for i := 0; i < 2; i++ {
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 838cb7e1f..a214e57b9 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/archive/tar/writer_test.go
@@ -9,8 +9,10 @@ import (
"fmt"
"io"
"io/ioutil"
+ "strings"
"testing"
"testing/iotest"
+ "time"
)
type writerTestEntry struct {
@@ -24,58 +26,78 @@ type writerTest struct {
}
var writerTests = []*writerTest{
- &writerTest{
+ // The writer test file was produced with this command:
+ // tar (GNU tar) 1.26
+ // ln -s small.txt link.txt
+ // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
+ {
file: "testdata/writer.tar",
entries: []*writerTestEntry{
- &writerTestEntry{
+ {
header: &Header{
Name: "small.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 5,
- Mtime: 1246508266,
+ ModTime: time.Unix(1246508266, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
contents: "Kilts",
},
- &writerTestEntry{
+ {
header: &Header{
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 11,
- Mtime: 1245217492,
+ ModTime: time.Unix(1245217492, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
contents: "Google.com\n",
},
+ {
+ header: &Header{
+ Name: "link.txt",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 0,
+ ModTime: time.Unix(1314603082, 0),
+ Typeflag: '2',
+ Linkname: "small.txt",
+ Uname: "strings",
+ Gname: "strings",
+ },
+ // no contents
+ },
},
},
// The truncated test file was produced using these commands:
// dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
// tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
- &writerTest{
+ {
file: "testdata/writer-big.tar",
entries: []*writerTestEntry{
- &writerTestEntry{
+ {
header: &Header{
Name: "tmp/16gig.txt",
Mode: 0640,
Uid: 73025,
Gid: 5000,
Size: 16 << 30,
- Mtime: 1254699560,
+ ModTime: time.Unix(1254699560, 0),
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
},
- // no contents
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
},
},
},
@@ -130,7 +152,9 @@ testLoop:
buf := new(bytes.Buffer)
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+ big := false
for j, entry := range test.entries {
+ big = big || entry.header.Size > 1<<10
if err := tw.WriteHeader(entry.header); err != nil {
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
continue testLoop
@@ -140,7 +164,8 @@ testLoop:
continue testLoop
}
}
- if err := tw.Close(); err != nil {
+ // Only interested in Close failures for the small tests.
+ if err := tw.Close(); err != nil && !big {
t.Errorf("test %d: Failed closing archive: %v", i, err)
continue testLoop
}
diff --git a/src/pkg/archive/zip/Makefile b/src/pkg/archive/zip/Makefile
deleted file mode 100644
index 9071690f0..000000000
--- a/src/pkg/archive/zip/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=archive/zip
-GOFILES=\
- reader.go\
- struct.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/archive/zip/example_test.go b/src/pkg/archive/zip/example_test.go
new file mode 100644
index 000000000..c2ed9e79c
--- /dev/null
+++ b/src/pkg/archive/zip/example_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip_test
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleWriter() {
+ // Create a buffer to write our archive to.
+ buf := new(bytes.Buffer)
+
+ // Create a new zip archive.
+ w := zip.NewWriter(buf)
+
+ // Add some files to the archive.
+ var files = []struct {
+ Name, Body string
+ }{
+ {"readme.txt", "This archive contains some text files."},
+ {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
+ {"todo.txt", "Get animal handling licence.\nWrite more examples."},
+ }
+ for _, file := range files {
+ f, err := w.Create(file.Name)
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, err = f.Write([]byte(file.Body))
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ // Make sure to check the error on Close.
+ err := w.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleReader() {
+ // Open a zip archive for reading.
+ r, err := zip.OpenReader("testdata/readme.zip")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer r.Close()
+
+ // Iterate through the files in the archive,
+ // printing some of their contents.
+ for _, f := range r.File {
+ fmt.Printf("Contents of %s:\n", f.Name)
+ rc, err := f.Open()
+ if err != nil {
+ log.Fatal(err)
+ }
+ _, err = io.CopyN(os.Stdout, rc, 68)
+ if err != nil {
+ log.Fatal(err)
+ }
+ rc.Close()
+ fmt.Println()
+ }
+ // Output:
+ // Contents of README:
+ // This is the source code repository for the Go programming language.
+}
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index f92f9297a..ddd507538 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -7,18 +7,19 @@ package zip
import (
"bufio"
"compress/flate"
+ "encoding/binary"
+ "errors"
"hash"
"hash/crc32"
- "encoding/binary"
"io"
"io/ioutil"
"os"
)
var (
- FormatError = os.NewError("zip: not a valid zip file")
- UnsupportedMethod = os.NewError("zip: unsupported compression algorithm")
- ChecksumError = os.NewError("zip: checksum error")
+ ErrFormat = errors.New("zip: not a valid zip file")
+ ErrAlgorithm = errors.New("zip: unsupported compression algorithm")
+ ErrChecksum = errors.New("zip: checksum error")
)
type Reader struct {
@@ -44,7 +45,7 @@ func (f *File) hasDataDescriptor() bool {
}
// OpenReader will open the Zip file specified by name and return a ReadCloser.
-func OpenReader(name string) (*ReadCloser, os.Error) {
+func OpenReader(name string) (*ReadCloser, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
@@ -55,16 +56,17 @@ func OpenReader(name string) (*ReadCloser, os.Error) {
return nil, err
}
r := new(ReadCloser)
- if err := r.init(f, fi.Size); err != nil {
+ if err := r.init(f, fi.Size()); err != nil {
f.Close()
return nil, err
}
+ r.f = f
return r, nil
}
// NewReader returns a new Reader reading from r, which is assumed to
// have the given size in bytes.
-func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
zr := new(Reader)
if err := zr.init(r, size); err != nil {
return nil, err
@@ -72,7 +74,7 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
return zr, nil
}
-func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
+func (z *Reader) init(r io.ReaderAt, size int64) error {
end, err := readDirectoryEnd(r, size)
if err != nil {
return err
@@ -88,12 +90,12 @@ func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
// 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
+ // a bad one, and then only report a ErrFormat 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 {
+ if err == ErrFormat || err == io.ErrUnexpectedEOF {
break
}
if err != nil {
@@ -110,22 +112,18 @@ func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
}
// Close closes the Zip file, rendering it unusable for I/O.
-func (rc *ReadCloser) Close() os.Error {
+func (rc *ReadCloser) Close() error {
return rc.f.Close()
}
// 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) {
+// Multiple files may be read concurrently.
+func (f *File) Open() (rc io.ReadCloser, err error) {
bodyOffset, err := f.findBodyOffset()
if err != nil {
return
}
size := int64(f.CompressedSize)
- 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, f.headerOffset+bodyOffset, size)
switch f.Method {
case Store: // (no compression)
@@ -133,11 +131,14 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
case Deflate:
rc = flate.NewReader(r)
default:
- err = UnsupportedMethod
+ err = ErrAlgorithm
+ return
}
- if rc != nil {
- rc = &checksumReader{rc, crc32.NewIEEE(), f, r}
+ var desr io.Reader
+ if f.hasDataDescriptor() {
+ desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
}
+ rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
return
}
@@ -145,101 +146,86 @@ type checksumReader struct {
rc io.ReadCloser
hash hash.Hash32
f *File
- zipr io.Reader // for reading the data descriptor
+ desr io.Reader // if non-nil, where to read the data descriptor
+ err error // sticky error
}
-func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
+func (r *checksumReader) Read(b []byte) (n int, err error) {
+ if r.err != nil {
+ return 0, r.err
+ }
n, err = r.rc.Read(b)
r.hash.Write(b[:n])
- if err != os.EOF {
+ if err == nil {
return
}
- if r.f.hasDataDescriptor() {
- if err = readDataDescriptor(r.zipr, r.f); err != nil {
- return
+ if err == io.EOF {
+ if r.desr != nil {
+ if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
+ err = err1
+ } else if r.hash.Sum32() != r.f.CRC32 {
+ err = ErrChecksum
+ }
+ } else {
+ // If there's not a data descriptor, we still compare
+ // the CRC32 of what we've read against the file header
+ // or TOC's CRC32, if it seems like it was set.
+ if r.f.CRC32 != 0 && r.hash.Sum32() != r.f.CRC32 {
+ err = ErrChecksum
+ }
}
}
- if r.hash.Sum32() != r.f.CRC32 {
- err = ChecksumError
- }
+ r.err = err
return
}
-func (r *checksumReader) Close() os.Error { return r.rc.Close() }
-
-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
- }
- 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 (r *checksumReader) Close() error { return r.rc.Close() }
// 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) {
+func (f *File) findBodyOffset() (int64, error) {
r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
- var b [fileHeaderLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
+ var buf [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
return 0, err
}
- c := binary.LittleEndian
- if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
- return 0, FormatError
+ b := readBuf(buf[:])
+ if sig := b.uint32(); sig != fileHeaderSignature {
+ return 0, ErrFormat
}
- filenameLen := int(c.Uint16(b[26:28]))
- extraLen := int(c.Uint16(b[28:30]))
+ b = b[22:] // skip over most of the header
+ filenameLen := int(b.uint16())
+ extraLen := int(b.uint16())
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 {
+// and ErrFormat if it doesn't find a valid header signature.
+func readDirectoryHeader(f *File, r io.Reader) error {
+ var buf [directoryHeaderLen]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
return err
}
- c := binary.LittleEndian
- if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
- return FormatError
+ b := readBuf(buf[:])
+ if sig := b.uint32(); sig != directoryHeaderSignature {
+ return ErrFormat
}
- 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]))
+ f.CreatorVersion = b.uint16()
+ f.ReaderVersion = b.uint16()
+ f.Flags = b.uint16()
+ f.Method = b.uint16()
+ f.ModifiedTime = b.uint16()
+ f.ModifiedDate = b.uint16()
+ f.CRC32 = b.uint32()
+ f.CompressedSize = b.uint32()
+ f.UncompressedSize = b.uint32()
+ filenameLen := int(b.uint16())
+ extraLen := int(b.uint16())
+ commentLen := int(b.uint16())
+ b = b[4:] // skipped start disk number and internal attributes (2x uint16)
+ f.ExternalAttrs = b.uint32()
+ f.headerOffset = int64(b.uint32())
d := make([]byte, filenameLen+extraLen+commentLen)
if _, err := io.ReadFull(r, d); err != nil {
return err
@@ -250,49 +236,75 @@ func readDirectoryHeader(f *File, r io.Reader) os.Error {
return nil
}
-func readDataDescriptor(r io.Reader, f *File) os.Error {
- var b [dataDescriptorLen]byte
- if _, err := io.ReadFull(r, b[:]); err != nil {
+func readDataDescriptor(r io.Reader, f *File) error {
+ var buf [dataDescriptorLen]byte
+
+ // The spec says: "Although not originally assigned a
+ // signature, the value 0x08074b50 has commonly been adopted
+ // as a signature value for the data descriptor record.
+ // Implementers should be aware that ZIP files may be
+ // encountered with or without this signature marking data
+ // descriptors and should account for either case when reading
+ // ZIP files to ensure compatibility."
+ //
+ // dataDescriptorLen includes the size of the signature but
+ // first read just those 4 bytes to see if it exists.
+ if _, err := io.ReadFull(r, buf[:4]); err != nil {
+ return err
+ }
+ off := 0
+ maybeSig := readBuf(buf[:4])
+ if maybeSig.uint32() != dataDescriptorSignature {
+ // No data descriptor signature. Keep these four
+ // bytes.
+ off += 4
+ }
+ if _, err := io.ReadFull(r, buf[off:12]); 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])
+ b := readBuf(buf[:12])
+ f.CRC32 = b.uint32()
+ f.CompressedSize = b.uint32()
+ f.UncompressedSize = b.uint32()
return nil
}
-func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err os.Error) {
+func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
// look for directoryEndSignature in the last 1k, then in the last 65k
- var b []byte
+ var buf []byte
for i, bLen := range []int64{1024, 65 * 1024} {
if bLen > size {
bLen = size
}
- b = make([]byte, int(bLen))
- if _, err := r.ReadAt(b, size-bLen); err != nil && err != os.EOF {
+ buf = make([]byte, int(bLen))
+ if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
return nil, err
}
- if p := findSignatureInBlock(b); p >= 0 {
- b = b[p:]
+ if p := findSignatureInBlock(buf); p >= 0 {
+ buf = buf[p:]
break
}
if i == 1 || bLen == size {
- return nil, FormatError
+ return nil, ErrFormat
}
}
// read header into struct
- 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)])
+ b := readBuf(buf[4:]) // skip signature
+ d := &directoryEnd{
+ diskNbr: b.uint16(),
+ dirDiskNbr: b.uint16(),
+ dirRecordsThisDisk: b.uint16(),
+ directoryRecords: b.uint16(),
+ directorySize: b.uint32(),
+ directoryOffset: b.uint32(),
+ commentLen: b.uint16(),
+ }
+ l := int(d.commentLen)
+ if l > len(b) {
+ return nil, errors.New("zip: invalid comment length")
+ }
+ d.comment = string(b[:l])
return d, nil
}
@@ -309,3 +321,17 @@ func findSignatureInBlock(b []byte) int {
}
return -1
}
+
+type readBuf []byte
+
+func (b *readBuf) uint16() uint16 {
+ v := binary.LittleEndian.Uint16(*b)
+ *b = (*b)[2:]
+ return v
+}
+
+func (b *readBuf) uint32() uint32 {
+ v := binary.LittleEndian.Uint32(*b)
+ *b = (*b)[4:]
+ return v
+}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index fd5fed2af..5f1d1b28a 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -7,25 +7,31 @@ package zip
import (
"bytes"
"encoding/binary"
+ "encoding/hex"
"io"
"io/ioutil"
"os"
+ "path/filepath"
+ "regexp"
"testing"
"time"
)
type ZipTest struct {
Name string
+ Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
Comment string
File []ZipTestFile
- Error os.Error // the error that Opening this file should return
+ Error error // the error that Opening this file should return
}
type ZipTestFile struct {
- Name string
- Content []byte // if blank, will attempt to compare against File
- File string // name of file to compare to (relative to testdata/)
- Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
+ Name string
+ Content []byte // if blank, will attempt to compare against File
+ ContentErr error
+ File string // name of file to compare to (relative to testdata/)
+ Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
+ Mode os.FileMode
}
// Caution: The Mtime values found for the test files should correspond to
@@ -47,26 +53,45 @@ var tests = []ZipTest{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
Mtime: "09-05-10 12:12:02",
+ Mode: 0644,
},
{
Name: "gophercolor16x16.png",
File: "gophercolor16x16.png",
Mtime: "09-05-10 15:52:58",
+ Mode: 0644,
+ },
+ },
+ },
+ {
+ Name: "r.zip",
+ Source: returnRecursiveZip,
+ File: []ZipTestFile{
+ {
+ Name: "r/r.zip",
+ Content: rZipBytes(),
+ Mtime: "03-04-10 00:24:16",
+ Mode: 0666,
},
},
},
{
- Name: "r.zip",
+ Name: "symlink.zip",
File: []ZipTestFile{
{
- Name: "r/r.zip",
- File: "r.zip",
- Mtime: "03-04-10 00:24:16",
+ Name: "symlink",
+ Content: []byte("../target"),
+ Mode: 0777 | os.ModeSymlink,
},
},
},
- {Name: "readme.zip"},
- {Name: "readme.notzip", Error: FormatError},
+ {
+ Name: "readme.zip",
+ },
+ {
+ Name: "readme.notzip",
+ Error: ErrFormat,
+ },
{
Name: "dd.zip",
File: []ZipTestFile{
@@ -74,9 +99,136 @@ var tests = []ZipTest{
Name: "filename",
Content: []byte("This is a test textfile.\n"),
Mtime: "02-02-11 13:06:20",
+ Mode: 0666,
},
},
},
+ {
+ // created in windows XP file manager.
+ Name: "winxp.zip",
+ File: crossPlatform,
+ },
+ {
+ // created by Zip 3.0 under Linux
+ Name: "unix.zip",
+ File: crossPlatform,
+ },
+ {
+ // created by Go, before we wrote the "optional" data
+ // descriptor signatures (which are required by OS X)
+ Name: "go-no-datadesc-sig.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
+ {
+ // created by Go, after we wrote the "optional" data
+ // descriptor signatures (which are required by OS X)
+ Name: "go-with-datadesc-sig.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mode: 0666,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mode: 0666,
+ },
+ },
+ },
+ {
+ Name: "Bad-CRC32-in-data-descriptor",
+ Source: returnCorruptCRC32Zip,
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mode: 0666,
+ ContentErr: ErrChecksum,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mode: 0666,
+ },
+ },
+ },
+ // Tests that we verify (and accept valid) crc32s on files
+ // with crc32s in their file header (not in data descriptors)
+ {
+ Name: "crc32-not-streamed.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
+ // Tests that we verify (and reject invalid) crc32s on files
+ // with crc32s in their file header (not in data descriptors)
+ {
+ Name: "crc32-not-streamed.zip",
+ Source: returnCorruptNotStreamedZip,
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ ContentErr: ErrChecksum,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
+}
+
+var crossPlatform = []ZipTestFile{
+ {
+ Name: "hello",
+ Content: []byte("world \r\n"),
+ Mode: 0666,
+ },
+ {
+ Name: "dir/bar",
+ Content: []byte("foo \r\n"),
+ Mode: 0666,
+ },
+ {
+ Name: "dir/empty/",
+ Content: []byte{},
+ Mode: os.ModeDir | 0777,
+ },
+ {
+ Name: "readonly",
+ Content: []byte("important \r\n"),
+ Mode: 0444,
+ },
}
func TestReader(t *testing.T) {
@@ -86,17 +238,27 @@ func TestReader(t *testing.T) {
}
func readTestZip(t *testing.T, zt ZipTest) {
- z, err := OpenReader("testdata/" + zt.Name)
+ var z *Reader
+ var err error
+ if zt.Source != nil {
+ rat, size := zt.Source()
+ z, err = NewReader(rat, size)
+ } else {
+ var rc *ReadCloser
+ rc, err = OpenReader(filepath.Join("testdata", zt.Name))
+ if err == nil {
+ z = &rc.Reader
+ }
+ }
if err != zt.Error {
t.Errorf("error=%v, want %v", err, zt.Error)
return
}
// bail if file is not zip
- if err == FormatError {
+ if err == ErrFormat {
return
}
- defer z.Close()
// bail here if no Files expected to be tested
// (there may actually be files in the zip, but we don't care)
@@ -108,12 +270,12 @@ func readTestZip(t *testing.T, zt ZipTest) {
t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
}
if len(z.File) != len(zt.File) {
- t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+ t.Fatalf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
}
// test read of each file
for i, ft := range zt.File {
- readTestFile(t, ft, z.File[i])
+ readTestFile(t, zt, ft, z.File[i])
}
// test simultaneous reads
@@ -121,46 +283,35 @@ func readTestZip(t *testing.T, zt ZipTest) {
done := make(chan bool)
for i := 0; i < 5; i++ {
for j, ft := range zt.File {
- go func() {
- readTestFile(t, ft, z.File[j])
+ go func(j int, ft ZipTestFile) {
+ readTestFile(t, zt, ft, z.File[j])
done <- true
- }()
+ }(j, ft)
n++
}
}
for ; n > 0; n-- {
<-done
}
+}
+
+func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
+ if f.Name != ft.Name {
+ t.Errorf("%s: name=%q, want %q", zt.Name, f.Name, ft.Name)
+ }
- // test invalid checksum
- if !z.File[0].hasDataDescriptor() { // skip test when crc32 in dd
- z.File[0].CRC32++ // invalidate
- r, err := z.File[0].Open()
+ if ft.Mtime != "" {
+ mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
if err != nil {
t.Error(err)
return
}
- var b bytes.Buffer
- _, err = io.Copy(&b, r)
- if err != ChecksumError {
- t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+ if ft := f.ModTime(); !ft.Equal(mtime) {
+ t.Errorf("%s: %s: mtime=%s, want %s", zt.Name, f.Name, ft, mtime)
}
}
-}
-
-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)
- }
+ testFileMode(t, zt.Name, f, ft.Mode)
size0 := f.UncompressedSize
@@ -176,14 +327,16 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
_, err = io.Copy(&b, r)
+ if err != ft.ContentErr {
+ t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
+ }
if err != nil {
- t.Error(err)
return
}
r.Close()
var c []byte
- if len(ft.Content) != 0 {
+ if ft.Content != nil {
c = ft.Content
} else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
t.Error(err)
@@ -203,14 +356,23 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
}
+func testFileMode(t *testing.T, zipName string, f *File, want os.FileMode) {
+ mode := f.Mode()
+ if want == 0 {
+ t.Errorf("%s: %s mode: got %v, want none", zipName, f.Name, mode)
+ } else if mode != want {
+ t.Errorf("%s: %s mode: want %v, got %v", zipName, f.Name, want, mode)
+ }
+}
+
func TestInvalidFiles(t *testing.T) {
const size = 1024 * 70 // 70kb
b := make([]byte, size)
// zeroes
- _, err := NewReader(sliceReaderAt(b), size)
- if err != FormatError {
- t.Errorf("zeroes: error=%v, want %v", err, FormatError)
+ _, err := NewReader(bytes.NewReader(b), size)
+ if err != ErrFormat {
+ t.Errorf("zeroes: error=%v, want %v", err, ErrFormat)
}
// repeated directoryEndSignatures
@@ -219,15 +381,86 @@ func TestInvalidFiles(t *testing.T) {
for i := 0; i < size-4; i += 4 {
copy(b[i:i+4], sig)
}
- _, err = NewReader(sliceReaderAt(b), size)
- if err != FormatError {
- t.Errorf("sigs: error=%v, want %v", err, FormatError)
+ _, err = NewReader(bytes.NewReader(b), size)
+ if err != ErrFormat {
+ t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
}
}
-type sliceReaderAt []byte
+func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
+ data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
+ if err != nil {
+ panic("Error reading " + fileName + ": " + err.Error())
+ }
+ corrupter(data)
+ return bytes.NewReader(data), int64(len(data))
+}
+
+func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) {
+ return messWith("go-with-datadesc-sig.zip", func(b []byte) {
+ // Corrupt one of the CRC32s in the data descriptor:
+ b[0x2d]++
+ })
+}
+
+func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) {
+ return messWith("crc32-not-streamed.zip", func(b []byte) {
+ // Corrupt foo.txt's final crc32 byte, in both
+ // the file header and TOC. (0x7e -> 0x7f)
+ b[0x11]++
+ b[0x9d]++
+
+ // TODO(bradfitz): add a new test that only corrupts
+ // one of these values, and verify that that's also an
+ // error. Currently, the reader code doesn't verify the
+ // fileheader and TOC's crc32 match if they're both
+ // non-zero and only the second line above, the TOC,
+ // is what matters.
+ })
+}
+
+// rZipBytes returns the bytes of a recursive zip file, without
+// putting it on disk and triggering certain virus scanners.
+func rZipBytes() []byte {
+ s := `
+0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4
+0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f
+0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00
+0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00
+0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00
+0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00
+0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8
+0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f
+0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e
+0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb
+00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff
+00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42
+00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14
+00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21
+00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb
+00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff
+0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a
+0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3
+0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06
+0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00
+0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf
+0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06
+0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01
+0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89
+0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00
+0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a
+00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00
+00001b0 00 00 6d 01 00 00 00 00`
+ s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
+ s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
-func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
- copy(b, r[int(off):int(off)+len(b)])
- return len(b), nil
+func returnRecursiveZip() (r io.ReaderAt, size int64) {
+ b := rZipBytes()
+ return bytes.NewReader(b), int64(len(b))
}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 1d6e70f10..55f3dcfb8 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -11,8 +11,11 @@ This package does not support ZIP64 or disk spanning.
*/
package zip
-import "os"
-import "time"
+import (
+ "errors"
+ "os"
+ "time"
+)
// Compression methods.
const (
@@ -24,10 +27,18 @@ const (
fileHeaderSignature = 0x04034b50
directoryHeaderSignature = 0x02014b50
directoryEndSignature = 0x06054b50
- fileHeaderLen = 30 // + filename + extra
- directoryHeaderLen = 46 // + filename + extra + comment
- directoryEndLen = 22 // + comment
- dataDescriptorLen = 12
+ dataDescriptorSignature = 0x08074b50 // de-facto standard; required by OS X Finder
+ fileHeaderLen = 30 // + filename + extra
+ directoryHeaderLen = 46 // + filename + extra + comment
+ directoryEndLen = 22 // + comment
+ dataDescriptorLen = 16 // four uint32: descriptor signature, crc32, compressed size, size
+
+ // Constants for the first byte in CreatorVersion
+ creatorFAT = 0
+ creatorUnix = 3
+ creatorNTFS = 11
+ creatorVFAT = 14
+ creatorMacOSX = 19
)
type FileHeader struct {
@@ -42,9 +53,43 @@ type FileHeader struct {
CompressedSize uint32
UncompressedSize uint32
Extra []byte
+ ExternalAttrs uint32 // Meaning depends on CreatorVersion
Comment string
}
+// FileInfo returns an os.FileInfo for the FileHeader.
+func (h *FileHeader) FileInfo() os.FileInfo {
+ return headerFileInfo{h}
+}
+
+// headerFileInfo implements os.FileInfo.
+type headerFileInfo struct {
+ fh *FileHeader
+}
+
+func (fi headerFileInfo) Name() string { return fi.fh.Name }
+func (fi headerFileInfo) Size() int64 { return int64(fi.fh.UncompressedSize) }
+func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
+func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
+func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
+func (fi headerFileInfo) Sys() interface{} { return fi.fh }
+
+// FileInfoHeader creates a partially-populated FileHeader from an
+// os.FileInfo.
+func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
+ size := fi.Size()
+ if size > (1<<32 - 1) {
+ return nil, errors.New("zip: file over 4GB")
+ }
+ fh := &FileHeader{
+ Name: fi.Name(),
+ UncompressedSize: uint32(size),
+ }
+ fh.SetModTime(fi.ModTime())
+ fh.SetMode(fi.Mode())
+ return fh, nil
+}
+
type directoryEnd struct {
diskNbr uint16 // unused
dirDiskNbr uint16 // unused
@@ -56,36 +101,165 @@ type directoryEnd struct {
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{
+ return time.Date(
// date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
- Year: int64(dosDate>>9 + 1980),
- Month: int(dosDate >> 5 & 0xf),
- Day: int(dosDate & 0x1f),
+ int(dosDate>>9+1980),
+ time.Month(dosDate>>5&0xf),
+ int(dosDate&0x1f),
// time bits 0-4: second/2; 5-10: minute; 11-15: hour
- Hour: int(dosTime >> 11),
- Minute: int(dosTime >> 5 & 0x3f),
- Second: int(dosTime & 0x1f * 2),
- }
+ int(dosTime>>11),
+ int(dosTime>>5&0x3f),
+ int(dosTime&0x1f*2),
+ 0, // nanoseconds
+
+ time.UTC,
+ )
}
-// Mtime_ns returns the modified time in ns since epoch.
+// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
// The resolution is 2s.
-func (h *FileHeader) Mtime_ns() int64 {
- t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
- return t.Seconds() * 1e9
+// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
+func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
+ t = t.In(time.UTC)
+ fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
+ fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
+ return
+}
+
+// ModTime returns the modification time.
+// The resolution is 2s.
+func (h *FileHeader) ModTime() time.Time {
+ return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
+}
+
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// The resolution is 2s.
+func (h *FileHeader) SetModTime(t time.Time) {
+ h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
+}
+
+const (
+ // Unix constants. The specification doesn't mention them,
+ // but these seem to be the values agreed on by tools.
+ s_IFMT = 0xf000
+ s_IFSOCK = 0xc000
+ s_IFLNK = 0xa000
+ s_IFREG = 0x8000
+ s_IFBLK = 0x6000
+ s_IFDIR = 0x4000
+ s_IFCHR = 0x2000
+ s_IFIFO = 0x1000
+ s_ISUID = 0x800
+ s_ISGID = 0x400
+ s_ISVTX = 0x200
+
+ msdosDir = 0x10
+ msdosReadOnly = 0x01
+)
+
+// Mode returns the permission and mode bits for the FileHeader.
+func (h *FileHeader) Mode() (mode os.FileMode) {
+ switch h.CreatorVersion >> 8 {
+ case creatorUnix, creatorMacOSX:
+ mode = unixModeToFileMode(h.ExternalAttrs >> 16)
+ case creatorNTFS, creatorVFAT, creatorFAT:
+ mode = msdosModeToFileMode(h.ExternalAttrs)
+ }
+ if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
+ mode |= os.ModeDir
+ }
+ return mode
+}
+
+// SetMode changes the permission and mode bits for the FileHeader.
+func (h *FileHeader) SetMode(mode os.FileMode) {
+ h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
+ h.ExternalAttrs = fileModeToUnixMode(mode) << 16
+
+ // set MSDOS attributes too, as the original zip does.
+ if mode&os.ModeDir != 0 {
+ h.ExternalAttrs |= msdosDir
+ }
+ if mode&0200 == 0 {
+ h.ExternalAttrs |= msdosReadOnly
+ }
+}
+
+func msdosModeToFileMode(m uint32) (mode os.FileMode) {
+ if m&msdosDir != 0 {
+ mode = os.ModeDir | 0777
+ } else {
+ mode = 0666
+ }
+ if m&msdosReadOnly != 0 {
+ mode &^= 0222
+ }
+ return mode
+}
+
+func fileModeToUnixMode(mode os.FileMode) uint32 {
+ var m uint32
+ switch mode & os.ModeType {
+ default:
+ m = s_IFREG
+ case os.ModeDir:
+ m = s_IFDIR
+ case os.ModeSymlink:
+ m = s_IFLNK
+ case os.ModeNamedPipe:
+ m = s_IFIFO
+ case os.ModeSocket:
+ m = s_IFSOCK
+ case os.ModeDevice:
+ if mode&os.ModeCharDevice != 0 {
+ m = s_IFCHR
+ } else {
+ m = s_IFBLK
+ }
+ }
+ if mode&os.ModeSetuid != 0 {
+ m |= s_ISUID
+ }
+ if mode&os.ModeSetgid != 0 {
+ m |= s_ISGID
+ }
+ if mode&os.ModeSticky != 0 {
+ m |= s_ISVTX
+ }
+ return m | uint32(mode&0777)
+}
+
+func unixModeToFileMode(m uint32) os.FileMode {
+ mode := os.FileMode(m & 0777)
+ switch m & s_IFMT {
+ case s_IFBLK:
+ mode |= os.ModeDevice
+ case s_IFCHR:
+ mode |= os.ModeDevice | os.ModeCharDevice
+ case s_IFDIR:
+ mode |= os.ModeDir
+ case s_IFIFO:
+ mode |= os.ModeNamedPipe
+ case s_IFLNK:
+ mode |= os.ModeSymlink
+ case s_IFREG:
+ // nothing to do
+ case s_IFSOCK:
+ mode |= os.ModeSocket
+ }
+ if m&s_ISGID != 0 {
+ mode |= os.ModeSetgid
+ }
+ if m&s_ISUID != 0 {
+ mode |= os.ModeSetuid
+ }
+ if m&s_ISVTX != 0 {
+ mode |= os.ModeSticky
+ }
+ return mode
}
diff --git a/src/pkg/archive/zip/testdata/crc32-not-streamed.zip b/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
new file mode 100644
index 000000000..f268d8873
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
new file mode 100644
index 000000000..c3d593f44
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
new file mode 100644
index 000000000..bcfe121bb
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/r.zip b/src/pkg/archive/zip/testdata/r.zip
deleted file mode 100644
index ea0fa2ffc..000000000
--- a/src/pkg/archive/zip/testdata/r.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/symlink.zip b/src/pkg/archive/zip/testdata/symlink.zip
new file mode 100644
index 000000000..af846938c
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/symlink.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/unix.zip b/src/pkg/archive/zip/testdata/unix.zip
new file mode 100644
index 000000000..ce1a981b2
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/unix.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/winxp.zip b/src/pkg/archive/zip/testdata/winxp.zip
new file mode 100644
index 000000000..3919322f0
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/winxp.zip
Binary files differ
diff --git a/src/pkg/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
index 2065b06da..45eb6bd73 100644
--- a/src/pkg/archive/zip/writer.go
+++ b/src/pkg/archive/zip/writer.go
@@ -8,10 +8,10 @@ import (
"bufio"
"compress/flate"
"encoding/binary"
+ "errors"
"hash"
"hash/crc32"
"io"
- "os"
)
// TODO(adg): support zip file comments
@@ -19,7 +19,7 @@ import (
// Writer implements a zip file writer.
type Writer struct {
- *countWriter
+ cw *countWriter
dir []*header
last *fileWriter
closed bool
@@ -32,69 +32,81 @@ type header struct {
// NewWriter returns a new Writer writing a zip file to w.
func NewWriter(w io.Writer) *Writer {
- return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}}
+ return &Writer{cw: &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) {
+func (w *Writer) Close() error {
if w.last != nil && !w.last.closed {
- if err = w.last.close(); err != nil {
- return
+ if err := w.last.close(); err != nil {
+ return err
}
w.last = nil
}
if w.closed {
- return os.NewError("zip: writer closed twice")
+ return errors.New("zip: writer closed twice")
}
w.closed = true
- defer recoverError(&err)
-
// write central directory
- start := w.count
+ start := w.cw.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))
+ var buf [directoryHeaderLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(directoryHeaderSignature))
+ b.uint16(h.CreatorVersion)
+ b.uint16(h.ReaderVersion)
+ b.uint16(h.Flags)
+ b.uint16(h.Method)
+ b.uint16(h.ModifiedTime)
+ b.uint16(h.ModifiedDate)
+ b.uint32(h.CRC32)
+ b.uint32(h.CompressedSize)
+ b.uint32(h.UncompressedSize)
+ b.uint16(uint16(len(h.Name)))
+ b.uint16(uint16(len(h.Extra)))
+ b.uint16(uint16(len(h.Comment)))
+ b = b[4:] // skip disk number start and internal file attr (2x uint16)
+ b.uint32(h.ExternalAttrs)
+ b.uint32(h.offset)
+ if _, err := w.cw.Write(buf[:]); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w.cw, h.Name); err != nil {
+ return err
+ }
+ if _, err := w.cw.Write(h.Extra); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w.cw, h.Comment); err != nil {
+ return err
+ }
}
- end := w.count
+ end := w.cw.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
+ var buf [directoryEndLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(directoryEndSignature))
+ b = b[4:] // skip over disk number and first disk number (2x uint16)
+ b.uint16(uint16(len(w.dir))) // number of entries this disk
+ b.uint16(uint16(len(w.dir))) // number of entries total
+ b.uint32(uint32(end - start)) // size of directory
+ b.uint32(uint32(start)) // start of directory
+ // skipped size of comment (always zero)
+ if _, err := w.cw.Write(buf[:]); err != nil {
+ return err
+ }
- return w.w.(*bufio.Writer).Flush()
+ return w.cw.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) {
+func (w *Writer) Create(name string) (io.Writer, error) {
header := &FileHeader{
Name: name,
Method: Deflate,
@@ -107,7 +119,7 @@ func (w *Writer) Create(name string) (io.Writer, os.Error) {
// 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) {
+func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
if w.last != nil && !w.last.closed {
if err := w.last.close(); err != nil {
return nil, err
@@ -115,32 +127,36 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
}
fh.Flags |= 0x8 // we will write a data descriptor
- fh.CreatorVersion = 0x14
+ fh.CreatorVersion = fh.CreatorVersion&0xff00 | 0x14
fh.ReaderVersion = 0x14
fw := &fileWriter{
- zipw: w,
- compCount: &countWriter{w: w},
+ zipw: w.cw,
+ compCount: &countWriter{w: w.cw},
crc32: crc32.NewIEEE(),
}
switch fh.Method {
case Store:
fw.comp = nopCloser{fw.compCount}
case Deflate:
- fw.comp = flate.NewWriter(fw.compCount, 5)
+ var err error
+ fw.comp, err = flate.NewWriter(fw.compCount, 5)
+ if err != nil {
+ return nil, err
+ }
default:
- return nil, UnsupportedMethod
+ return nil, ErrAlgorithm
}
fw.rawCount = &countWriter{w: fw.comp}
h := &header{
FileHeader: fh,
- offset: uint32(w.count),
+ offset: uint32(w.cw.count),
}
w.dir = append(w.dir, h)
fw.header = h
- if err := writeHeader(w, fh); err != nil {
+ if err := writeHeader(w.cw, fh); err != nil {
return nil, err
}
@@ -148,22 +164,28 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
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
+func writeHeader(w io.Writer, h *FileHeader) error {
+ var buf [fileHeaderLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(uint32(fileHeaderSignature))
+ b.uint16(h.ReaderVersion)
+ b.uint16(h.Flags)
+ b.uint16(h.Method)
+ b.uint16(h.ModifiedTime)
+ b.uint16(h.ModifiedDate)
+ b.uint32(h.CRC32)
+ b.uint32(h.CompressedSize)
+ b.uint32(h.UncompressedSize)
+ b.uint16(uint16(len(h.Name)))
+ b.uint16(uint16(len(h.Extra)))
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+ if _, err := io.WriteString(w, h.Name); err != nil {
+ return err
+ }
+ _, err := w.Write(h.Extra)
+ return err
}
type fileWriter struct {
@@ -176,21 +198,21 @@ type fileWriter struct {
closed bool
}
-func (w *fileWriter) Write(p []byte) (int, os.Error) {
+func (w *fileWriter) Write(p []byte) (int, error) {
if w.closed {
- return 0, os.NewError("zip: write to closed file")
+ return 0, errors.New("zip: write to closed file")
}
w.crc32.Write(p)
return w.rawCount.Write(p)
}
-func (w *fileWriter) close() (err os.Error) {
+func (w *fileWriter) close() error {
if w.closed {
- return os.NewError("zip: file closed twice")
+ return errors.New("zip: file closed twice")
}
w.closed = true
- if err = w.comp.Close(); err != nil {
- return
+ if err := w.comp.Close(); err != nil {
+ return err
}
// update FileHeader
@@ -200,12 +222,14 @@ func (w *fileWriter) close() (err os.Error) {
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
+ var buf [dataDescriptorLen]byte
+ b := writeBuf(buf[:])
+ b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X
+ b.uint32(fh.CRC32)
+ b.uint32(fh.CompressedSize)
+ b.uint32(fh.UncompressedSize)
+ _, err := w.zipw.Write(buf[:])
+ return err
}
type countWriter struct {
@@ -213,7 +237,7 @@ type countWriter struct {
count int64
}
-func (w *countWriter) Write(p []byte) (int, os.Error) {
+func (w *countWriter) Write(p []byte) (int, error) {
n, err := w.w.Write(p)
w.count += int64(n)
return n, err
@@ -223,22 +247,18 @@ type nopCloser struct {
io.Writer
}
-func (w nopCloser) Close() os.Error {
+func (w nopCloser) Close() error {
return nil
}
-func write(w io.Writer, data interface{}) {
- if err := binary.Write(w, binary.LittleEndian, data); err != nil {
- panic(err)
- }
+type writeBuf []byte
+
+func (b *writeBuf) uint16(v uint16) {
+ binary.LittleEndian.PutUint16(*b, v)
+ *b = (*b)[2:]
}
-func writeBytes(w io.Writer, b []byte) {
- n, err := w.Write(b)
- if err != nil {
- panic(err)
- }
- if n != len(b) {
- panic(io.ErrShortWrite)
- }
+func (b *writeBuf) uint32(v uint32) {
+ binary.LittleEndian.PutUint32(*b, v)
+ *b = (*b)[4:]
}
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
index eb2a80c3f..8b1c4dfd2 100644
--- a/src/pkg/archive/zip/writer_test.go
+++ b/src/pkg/archive/zip/writer_test.go
@@ -7,54 +7,108 @@ package zip
import (
"bytes"
"io/ioutil"
- "rand"
+ "math/rand"
+ "os"
"testing"
)
// TODO(adg): a more sophisticated test suite
-const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls."
+type WriteTest struct {
+ Name string
+ Data []byte
+ Method uint16
+ Mode os.FileMode
+}
+
+var writeTests = []WriteTest{
+ {
+ Name: "foo",
+ Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
+ Method: Store,
+ Mode: 0666,
+ },
+ {
+ Name: "bar",
+ Data: nil, // large data set in the test
+ Method: Deflate,
+ Mode: 0644,
+ },
+ {
+ Name: "setuid",
+ Data: []byte("setuid file"),
+ Method: Deflate,
+ Mode: 0755 | os.ModeSetuid,
+ },
+ {
+ Name: "setgid",
+ Data: []byte("setgid file"),
+ Method: Deflate,
+ Mode: 0755 | os.ModeSetgid,
+ },
+ {
+ Name: "symlink",
+ Data: []byte("../link/target"),
+ Method: Deflate,
+ Mode: 0755 | os.ModeSymlink,
+ },
+}
func TestWriter(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
largeData[i] = byte(rand.Int())
}
+ writeTests[1].Data = largeData
+ defer func() {
+ writeTests[1].Data = nil
+ }()
// write a zip file
buf := new(bytes.Buffer)
w := NewWriter(buf)
- testCreate(t, w, "foo", []byte(testString), Store)
- testCreate(t, w, "bar", largeData, Deflate)
+
+ for _, wt := range writeTests {
+ testCreate(t, w, &wt)
+ }
+
if err := w.Close(); err != nil {
t.Fatal(err)
}
// read it back
- r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len()))
+ r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil {
t.Fatal(err)
}
- testReadFile(t, r.File[0], []byte(testString))
- testReadFile(t, r.File[1], largeData)
+ for i, wt := range writeTests {
+ testReadFile(t, r.File[i], &wt)
+ }
}
-func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) {
+func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
header := &FileHeader{
- Name: name,
- Method: method,
+ Name: wt.Name,
+ Method: wt.Method,
+ }
+ if wt.Mode != 0 {
+ header.SetMode(wt.Mode)
}
f, err := w.CreateHeader(header)
if err != nil {
t.Fatal(err)
}
- _, err = f.Write(data)
+ _, err = f.Write(wt.Data)
if err != nil {
t.Fatal(err)
}
}
-func testReadFile(t *testing.T, f *File, data []byte) {
+func testReadFile(t *testing.T, f *File, wt *WriteTest) {
+ if f.Name != wt.Name {
+ t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
+ }
+ testFileMode(t, wt.Name, f, wt.Mode)
rc, err := f.Open()
if err != nil {
t.Fatal("opening:", err)
@@ -67,7 +121,7 @@ func testReadFile(t *testing.T, f *File, data []byte) {
if err != nil {
t.Fatal("closing:", err)
}
- if !bytes.Equal(b, data) {
- t.Errorf("File contents %q, want %q", b, data)
+ if !bytes.Equal(b, wt.Data) {
+ t.Errorf("File contents %q, want %q", b, wt.Data)
}
}
diff --git a/src/pkg/archive/zip/zip_test.go b/src/pkg/archive/zip/zip_test.go
index 0f71fdfac..d6490c4cb 100644
--- a/src/pkg/archive/zip/zip_test.go
+++ b/src/pkg/archive/zip/zip_test.go
@@ -9,20 +9,12 @@ package zip
import (
"bytes"
"fmt"
- "os"
+ "reflect"
+ "strings"
"testing"
+ "time"
)
-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")
@@ -40,8 +32,8 @@ func TestOver65kFiles(t *testing.T) {
if err := w.Close(); err != nil {
t.Fatalf("Writer.Close: %v", err)
}
- rat := stringReaderAt(buf.String())
- zr, err := NewReader(rat, int64(len(rat)))
+ s := buf.String()
+ zr, err := NewReader(strings.NewReader(s), int64(len(s)))
if err != nil {
t.Fatalf("NewReader: %v", err)
}
@@ -55,3 +47,35 @@ func TestOver65kFiles(t *testing.T) {
}
}
}
+
+func TestModTime(t *testing.T) {
+ var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC)
+ fh := new(FileHeader)
+ fh.SetModTime(testTime)
+ outTime := fh.ModTime()
+ if !outTime.Equal(testTime) {
+ t.Errorf("times don't match: got %s, want %s", outTime, testTime)
+ }
+}
+
+func TestFileHeaderRoundTrip(t *testing.T) {
+ fh := &FileHeader{
+ Name: "foo.txt",
+ UncompressedSize: 987654321,
+ ModifiedTime: 1234,
+ ModifiedDate: 5678,
+ }
+ fi := fh.FileInfo()
+ fh2, err := FileInfoHeader(fi)
+
+ // Ignore these fields:
+ fh2.CreatorVersion = 0
+ fh2.ExternalAttrs = 0
+
+ if !reflect.DeepEqual(fh, fh2) {
+ t.Errorf("mismatch\n input=%#v\noutput=%#v\nerr=%v", fh, fh2, err)
+ }
+ if sysfh, ok := fi.Sys().(*FileHeader); !ok && sysfh != fh {
+ t.Errorf("Sys didn't return original *FileHeader")
+ }
+}
diff --git a/src/pkg/asn1/Makefile b/src/pkg/asn1/Makefile
deleted file mode 100644
index 6b7770e82..000000000
--- a/src/pkg/asn1/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=asn1
-GOFILES=\
- asn1.go\
- common.go\
- marshal.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/big/Makefile b/src/pkg/big/Makefile
deleted file mode 100644
index 3d4b56d78..000000000
--- a/src/pkg/big/Makefile
+++ /dev/null
@@ -1,18 +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.
-
-include ../../Make.inc
-
-TARG=big
-GOFILES=\
- arith.go\
- arith_decl.go\
- int.go\
- nat.go\
- rat.go\
-
-OFILES=\
- arith_$(GOARCH).$O\
-
-include ../../Make.pkg
diff --git a/src/pkg/bufio/Makefile b/src/pkg/bufio/Makefile
deleted file mode 100644
index 85430e8e8..000000000
--- a/src/pkg/bufio/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=bufio
-GOFILES=\
- bufio.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index 727ebfdbb..b44d0e7d1 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -9,38 +9,22 @@ package bufio
import (
"bytes"
+ "errors"
"io"
- "os"
- "strconv"
- "utf8"
+ "unicode/utf8"
)
const (
defaultBufSize = 4096
)
-// Errors introduced by this package.
-type Error struct {
- 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"}
- ErrBufferFull os.Error = &Error{"bufio: buffer full"}
- ErrNegativeCount os.Error = &Error{"bufio: negative count"}
- errInternal os.Error = &Error{"bufio: internal error"}
+ ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
+ ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
+ ErrBufferFull = errors.New("bufio: buffer full")
+ ErrNegativeCount = errors.New("bufio: negative count")
)
-// BufSizeError is the error representing an invalid buffer size.
-type BufSizeError int
-
-func (b BufSizeError) String() string {
- return "bufio: bad buffer size " + strconv.Itoa(int(b))
-}
-
// Buffered input.
// Reader implements buffering for an io.Reader object.
@@ -48,40 +32,36 @@ type Reader struct {
buf []byte
rd io.Reader
r, w int
- err os.Error
+ err error
lastByte int
lastRuneSize int
}
-// NewReaderSize creates a new Reader whose buffer has the specified size,
-// which must be greater than zero. If the argument io.Reader is already a
-// Reader with large enough size, it returns the underlying Reader.
-// It returns the Reader and any error.
-func NewReaderSize(rd io.Reader, size int) (*Reader, os.Error) {
- if size <= 0 {
- return nil, BufSizeError(size)
- }
+const minReadBufferSize = 16
+
+// NewReaderSize returns a new Reader whose buffer has at least the specified
+// size. If the argument io.Reader is already a Reader with large enough
+// size, it returns the underlying Reader.
+func NewReaderSize(rd io.Reader, size int) *Reader {
// Is it already a Reader?
b, ok := rd.(*Reader)
if ok && len(b.buf) >= size {
- return b, nil
+ return b
+ }
+ if size < minReadBufferSize {
+ size = minReadBufferSize
+ }
+ return &Reader{
+ buf: make([]byte, size),
+ rd: rd,
+ lastByte: -1,
+ lastRuneSize: -1,
}
- b = new(Reader)
- b.buf = make([]byte, size)
- b.rd = rd
- b.lastByte = -1
- b.lastRuneSize = -1
- return b, nil
}
// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) *Reader {
- b, err := NewReaderSize(rd, defaultBufSize)
- if err != nil {
- // cannot happen - defaultBufSize is a valid size
- panic(err)
- }
- return b
+ return NewReaderSize(rd, defaultBufSize)
}
// fill reads a new chunk into the buffer.
@@ -101,7 +81,7 @@ func (b *Reader) fill() {
}
}
-func (b *Reader) readErr() os.Error {
+func (b *Reader) readErr() error {
err := b.err
b.err = nil
return err
@@ -111,7 +91,7 @@ func (b *Reader) readErr() os.Error {
// being valid at the next read call. If Peek returns fewer than n bytes, it
// also returns an error explaining why the read is short. The error is
// ErrBufferFull if n is larger than b's buffer size.
-func (b *Reader) Peek(n int) ([]byte, os.Error) {
+func (b *Reader) Peek(n int) ([]byte, error) {
if n < 0 {
return nil, ErrNegativeCount
}
@@ -125,9 +105,12 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
if m > n {
m = n
}
- err := b.readErr()
- if m < n && err == nil {
- err = ErrBufferFull
+ var err error
+ if m < n {
+ err = b.readErr()
+ if err == nil {
+ err = ErrBufferFull
+ }
}
return b.buf[b.r : b.r+m], err
}
@@ -136,8 +119,8 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
// It returns the number of bytes read into p.
// It calls Read at most once on the underlying Reader,
// hence n may be less than len(p).
-// At EOF, the count will be zero and err will be os.EOF.
-func (b *Reader) Read(p []byte) (n int, err os.Error) {
+// At EOF, the count will be zero and err will be io.EOF.
+func (b *Reader) Read(p []byte) (n int, err error) {
n = len(p)
if n == 0 {
return 0, b.readErr()
@@ -174,7 +157,7 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) {
// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
-func (b *Reader) ReadByte() (c byte, err os.Error) {
+func (b *Reader) ReadByte() (c byte, err error) {
b.lastRuneSize = -1
for b.w == b.r {
if b.err != nil {
@@ -189,7 +172,7 @@ func (b *Reader) ReadByte() (c byte, err os.Error) {
}
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
-func (b *Reader) UnreadByte() os.Error {
+func (b *Reader) UnreadByte() error {
b.lastRuneSize = -1
if b.r == b.w && b.lastByte >= 0 {
b.w = 1
@@ -207,8 +190,9 @@ func (b *Reader) UnreadByte() os.Error {
}
// ReadRune reads a single UTF-8 encoded Unicode character and returns the
-// rune and its size in bytes.
-func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
+// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte
+// and returns unicode.ReplacementChar (U+FFFD) with a size of 1.
+func (b *Reader) ReadRune() (r rune, size int, err error) {
for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
b.fill()
}
@@ -216,21 +200,21 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
if b.r == b.w {
return 0, 0, b.readErr()
}
- rune, size = int(b.buf[b.r]), 1
- if rune >= 0x80 {
- rune, size = utf8.DecodeRune(b.buf[b.r:b.w])
+ r, size = rune(b.buf[b.r]), 1
+ if r >= 0x80 {
+ r, size = utf8.DecodeRune(b.buf[b.r:b.w])
}
b.r += size
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = size
- return rune, size, nil
+ return r, size, nil
}
// UnreadRune unreads the last rune. If the most recent read operation on
// the buffer was not a ReadRune, UnreadRune returns an error. (In this
// regard it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
-func (b *Reader) UnreadRune() os.Error {
+func (b *Reader) UnreadRune() error {
if b.lastRuneSize < 0 || b.r == 0 {
return ErrInvalidUnreadRune
}
@@ -247,13 +231,13 @@ func (b *Reader) Buffered() int { return b.w - b.r }
// returning a slice pointing at the bytes in the buffer.
// The bytes stop being valid at the next read call.
// If ReadSlice encounters an error before finding a delimiter,
-// it returns all the data in the buffer and the error itself (often os.EOF).
+// it returns all the data in the buffer and the error itself (often io.EOF).
// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
// Because the data returned from ReadSlice will be overwritten
// by the next I/O operation, most clients should use
// ReadBytes or ReadString instead.
// ReadSlice returns err != nil if and only if line does not end in delim.
-func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
+func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
// Look in buffer.
if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
line1 := b.buf[b.r : b.r+i+1]
@@ -295,22 +279,37 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
// of the line. The returned buffer is only valid until the next call to
// ReadLine. ReadLine either returns a non-nil line or it returns an error,
// never both.
-func (b *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
+func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == ErrBufferFull {
+ // Handle the case where "\r\n" straddles the buffer.
+ if len(line) > 0 && line[len(line)-1] == '\r' {
+ // Put the '\r' back on buf and drop it from line.
+ // Let the next call to ReadLine check for "\r\n".
+ if b.r == 0 {
+ // should be unreachable
+ panic("bufio: tried to rewind past start of buffer")
+ }
+ b.r--
+ line = line[:len(line)-1]
+ }
return line, true, nil
}
if len(line) == 0 {
+ if err != nil {
+ line = nil
+ }
return
}
err = nil
if line[len(line)-1] == '\n' {
- line = line[:len(line)-1]
- }
- if len(line) > 0 && line[len(line)-1] == '\r' {
- line = line[:len(line)-1]
+ drop := 1
+ if len(line) > 1 && line[len(line)-2] == '\r' {
+ drop = 2
+ }
+ line = line[:len(line)-drop]
}
return
}
@@ -318,10 +317,10 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
-// it returns the data read before the error and the error itself (often os.EOF).
+// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
-func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
+func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// Use ReadSlice to look for array,
// accumulating full buffers.
var frag []byte
@@ -329,7 +328,7 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
err = nil
for {
- var e os.Error
+ var e error
frag, e = b.ReadSlice(delim)
if e == nil { // got final fragment
break
@@ -365,10 +364,10 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
-// it returns the data read before the error and the error itself (often os.EOF).
+// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end in
// delim.
-func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
+func (b *Reader) ReadString(delim byte) (line string, err error) {
bytes, e := b.ReadBytes(delim)
return string(bytes), e
}
@@ -376,44 +375,40 @@ func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
// buffered output
// Writer implements buffering for an io.Writer object.
+// If an error occurs writing to a Writer, no more data will be
+// accepted and all subsequent writes will return the error.
type Writer struct {
- err os.Error
+ err error
buf []byte
n int
wr io.Writer
}
-// NewWriterSize creates a new Writer whose buffer has the specified size,
-// which must be greater than zero. If the argument io.Writer is already a
-// Writer with large enough size, it returns the underlying Writer.
-// It returns the Writer and any error.
-func NewWriterSize(wr io.Writer, size int) (*Writer, os.Error) {
- if size <= 0 {
- return nil, BufSizeError(size)
- }
+// NewWriterSize returns a new Writer whose buffer has at least the specified
+// size. If the argument io.Writer is already a Writer with large enough
+// size, it returns the underlying Writer.
+func NewWriterSize(wr io.Writer, size int) *Writer {
// Is it already a Writer?
b, ok := wr.(*Writer)
if ok && len(b.buf) >= size {
- return b, nil
+ return b
+ }
+ if size <= 0 {
+ size = defaultBufSize
}
b = new(Writer)
b.buf = make([]byte, size)
b.wr = wr
- return b, nil
+ return b
}
// NewWriter returns a new Writer whose buffer has the default size.
func NewWriter(wr io.Writer) *Writer {
- b, err := NewWriterSize(wr, defaultBufSize)
- if err != nil {
- // cannot happen - defaultBufSize is valid size
- panic(err)
- }
- return b
+ return NewWriterSize(wr, defaultBufSize)
}
// Flush writes any buffered data to the underlying io.Writer.
-func (b *Writer) Flush() os.Error {
+func (b *Writer) Flush() error {
if b.err != nil {
return b.err
}
@@ -446,7 +441,7 @@ func (b *Writer) Buffered() int { return b.n }
// It returns the number of bytes written.
// If nn < len(p), it also returns an error explaining
// why the write is short.
-func (b *Writer) Write(p []byte) (nn int, err os.Error) {
+func (b *Writer) Write(p []byte) (nn int, err error) {
for len(p) > b.Available() && b.err == nil {
var n int
if b.Buffered() == 0 {
@@ -471,7 +466,7 @@ func (b *Writer) Write(p []byte) (nn int, err os.Error) {
}
// WriteByte writes a single byte.
-func (b *Writer) WriteByte(c byte) os.Error {
+func (b *Writer) WriteByte(c byte) error {
if b.err != nil {
return b.err
}
@@ -485,9 +480,9 @@ func (b *Writer) WriteByte(c byte) os.Error {
// WriteRune writes a single Unicode code point, returning
// the number of bytes written and any error.
-func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
- if rune < utf8.RuneSelf {
- err = b.WriteByte(byte(rune))
+func (b *Writer) WriteRune(r rune) (size int, err error) {
+ if r < utf8.RuneSelf {
+ err = b.WriteByte(byte(r))
if err != nil {
return 0, err
}
@@ -504,10 +499,10 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
n = b.Available()
if n < utf8.UTFMax {
// Can only happen if buffer is silly small.
- return b.WriteString(string(rune))
+ return b.WriteString(string(r))
}
}
- size = utf8.EncodeRune(b.buf[b.n:], rune)
+ size = utf8.EncodeRune(b.buf[b.n:], r)
b.n += size
return size, nil
}
@@ -516,7 +511,7 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
// It returns the number of bytes written.
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
-func (b *Writer) WriteString(s string) (int, os.Error) {
+func (b *Writer) WriteString(s string) (int, error) {
nn := 0
for len(s) > b.Available() && b.err == nil {
n := copy(b.buf[b.n:], s)
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 82c73d36a..a43cbd23a 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -10,11 +10,10 @@ import (
"fmt"
"io"
"io/ioutil"
- "os"
"strings"
"testing"
"testing/iotest"
- "utf8"
+ "unicode/utf8"
)
// Reads from a reader and rot13s the result.
@@ -28,7 +27,7 @@ func newRot13Reader(r io.Reader) *rot13Reader {
return r13
}
-func (r13 *rot13Reader) Read(p []byte) (int, os.Error) {
+func (r13 *rot13Reader) Read(p []byte) (int, error) {
n, e := r13.r.Read(p)
if e != nil {
return n, e
@@ -50,14 +49,14 @@ func readBytes(buf *Reader) string {
nb := 0
for {
c, e := buf.ReadByte()
- if e == os.EOF {
+ if e == io.EOF {
break
}
if e == nil {
b[nb] = c
nb++
} else if e != iotest.ErrTimeout {
- panic("Data: " + e.String())
+ panic("Data: " + e.Error())
}
}
return string(b[0:nb])
@@ -95,11 +94,11 @@ func readLines(b *Reader) string {
s := ""
for {
s1, e := b.ReadString('\n')
- if e == os.EOF {
+ if e == io.EOF {
break
}
if e != nil && e != iotest.ErrTimeout {
- panic("GetLines: " + e.String())
+ panic("GetLines: " + e.Error())
}
s += s1
}
@@ -113,7 +112,7 @@ func reads(buf *Reader, m int) string {
for {
n, e := buf.Read(b[nb : nb+m])
nb += n
- if e == os.EOF {
+ if e == io.EOF {
break
}
}
@@ -136,9 +135,10 @@ var bufreaders = []bufReader{
{"lines", readLines},
}
+const minReadBufferSize = 16
+
var bufsizes = []int{
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
- 23, 32, 46, 64, 93, 128, 1024, 4096,
+ minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
}
func TestReader(t *testing.T) {
@@ -161,7 +161,7 @@ func TestReader(t *testing.T) {
bufreader := bufreaders[j]
bufsize := bufsizes[k]
read := readmaker.fn(bytes.NewBufferString(text))
- buf, _ := NewReaderSize(read, bufsize)
+ buf := NewReaderSize(read, bufsize)
s := bufreader.fn(buf)
if s != text {
t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
@@ -179,13 +179,13 @@ type StringReader struct {
step int
}
-func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+func (r *StringReader) Read(p []byte) (n int, err error) {
if r.step < len(r.data) {
s := r.data[r.step]
n = copy(p, s)
r.step++
} else {
- err = os.EOF
+ err = io.EOF
}
return
}
@@ -195,14 +195,14 @@ func readRuneSegments(t *testing.T, segments []string) {
want := strings.Join(segments, "")
r := NewReader(&StringReader{data: segments})
for {
- rune, _, err := r.ReadRune()
+ r, _, err := r.ReadRune()
if err != nil {
- if err != os.EOF {
+ if err != io.EOF {
return
}
break
}
- got += string(rune)
+ got += string(r)
}
if got != want {
t.Errorf("segments=%v got=%s want=%s", segments, got, want)
@@ -233,24 +233,24 @@ func TestUnreadRune(t *testing.T) {
r := NewReader(&StringReader{data: segments})
// Normal execution.
for {
- rune, _, err := r.ReadRune()
+ r1, _, err := r.ReadRune()
if err != nil {
- if err != os.EOF {
+ if err != io.EOF {
t.Error("unexpected EOF")
}
break
}
- got += string(rune)
+ got += string(r1)
// Put it back and read it again
if err = r.UnreadRune(); err != nil {
t.Error("unexpected error on UnreadRune:", err)
}
- rune1, _, err := r.ReadRune()
+ r2, _, err := r.ReadRune()
if err != nil {
t.Error("unexpected error reading after unreading:", err)
}
- if rune != rune1 {
- t.Errorf("incorrect rune after unread: got %c wanted %c", rune1, rune)
+ if r1 != r2 {
+ t.Errorf("incorrect rune after unread: got %c wanted %c", r1, r2)
}
}
if got != data {
@@ -328,7 +328,7 @@ func TestUnreadRuneAtEOF(t *testing.T) {
_, _, err := r.ReadRune()
if err == nil {
t.Error("expected error at EOF")
- } else if err != os.EOF {
+ } else if err != io.EOF {
t.Error("expected EOF; got", err)
}
}
@@ -339,25 +339,25 @@ func TestReadWriteRune(t *testing.T) {
w := NewWriter(byteBuf)
// Write the runes out using WriteRune
buf := make([]byte, utf8.UTFMax)
- for rune := 0; rune < NRune; rune++ {
- size := utf8.EncodeRune(buf, rune)
- nbytes, err := w.WriteRune(rune)
+ for r := rune(0); r < NRune; r++ {
+ size := utf8.EncodeRune(buf, r)
+ nbytes, err := w.WriteRune(r)
if err != nil {
- t.Fatalf("WriteRune(0x%x) error: %s", rune, err)
+ t.Fatalf("WriteRune(0x%x) error: %s", r, err)
}
if nbytes != size {
- t.Fatalf("WriteRune(0x%x) expected %d, got %d", rune, size, nbytes)
+ t.Fatalf("WriteRune(0x%x) expected %d, got %d", r, size, nbytes)
}
}
w.Flush()
r := NewReader(byteBuf)
// Read them back with ReadRune
- for rune := 0; rune < NRune; rune++ {
- size := utf8.EncodeRune(buf, rune)
+ for r1 := rune(0); r1 < NRune; r1++ {
+ size := utf8.EncodeRune(buf, r1)
nr, nbytes, err := r.ReadRune()
- if nr != rune || nbytes != size || err != nil {
- t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
+ if nr != r1 || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r1, nr, nbytes, r1, size, err)
}
}
}
@@ -379,18 +379,14 @@ func TestWriter(t *testing.T) {
// and that the data is correct.
w.Reset()
- buf, e := NewWriterSize(w, bs)
+ buf := NewWriterSize(w, bs)
context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs)
- if e != nil {
- t.Errorf("%s: NewWriterSize %d: %v", context, bs, e)
- continue
- }
n, e1 := buf.Write(data[0:nwrite])
if e1 != nil || n != nwrite {
t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1)
continue
}
- if e = buf.Flush(); e != nil {
+ if e := buf.Flush(); e != nil {
t.Errorf("%s: buf.Flush = %v", context, e)
}
@@ -413,11 +409,11 @@ func TestWriter(t *testing.T) {
type errorWriterTest struct {
n, m int
- err os.Error
- expect os.Error
+ err error
+ expect error
}
-func (w errorWriterTest) Write(p []byte) (int, os.Error) {
+func (w errorWriterTest) Write(p []byte) (int, error) {
return len(p) * w.n / w.m, w.err
}
@@ -425,9 +421,9 @@ var errorWriterTests = []errorWriterTest{
{0, 1, nil, io.ErrShortWrite},
{1, 2, nil, io.ErrShortWrite},
{1, 1, nil, nil},
- {0, 1, os.EPIPE, os.EPIPE},
- {1, 2, os.EPIPE, os.EPIPE},
- {1, 1, os.EPIPE, os.EPIPE},
+ {0, 1, io.ErrClosedPipe, io.ErrClosedPipe},
+ {1, 2, io.ErrClosedPipe, io.ErrClosedPipe},
+ {1, 1, io.ErrClosedPipe, io.ErrClosedPipe},
}
func TestWriteErrors(t *testing.T) {
@@ -447,23 +443,14 @@ func TestWriteErrors(t *testing.T) {
func TestNewReaderSizeIdempotent(t *testing.T) {
const BufSize = 1000
- b, err := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
- if err != nil {
- t.Error("NewReaderSize create fail", err)
- }
+ b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
// Does it recognize itself?
- b1, err2 := NewReaderSize(b, BufSize)
- if err2 != nil {
- t.Error("NewReaderSize #2 create fail", err2)
- }
+ b1 := NewReaderSize(b, BufSize)
if b1 != b {
t.Error("NewReaderSize did not detect underlying Reader")
}
// Does it wrap if existing buffer is too small?
- b2, err3 := NewReaderSize(b, 2*BufSize)
- if err3 != nil {
- t.Error("NewReaderSize #3 create fail", err3)
- }
+ b2 := NewReaderSize(b, 2*BufSize)
if b2 == b {
t.Error("NewReaderSize did not enlarge buffer")
}
@@ -471,23 +458,14 @@ func TestNewReaderSizeIdempotent(t *testing.T) {
func TestNewWriterSizeIdempotent(t *testing.T) {
const BufSize = 1000
- b, err := NewWriterSize(new(bytes.Buffer), BufSize)
- if err != nil {
- t.Error("NewWriterSize create fail", err)
- }
+ b := NewWriterSize(new(bytes.Buffer), BufSize)
// Does it recognize itself?
- b1, err2 := NewWriterSize(b, BufSize)
- if err2 != nil {
- t.Error("NewWriterSize #2 create fail", err2)
- }
+ b1 := NewWriterSize(b, BufSize)
if b1 != b {
t.Error("NewWriterSize did not detect underlying Writer")
}
// Does it wrap if existing buffer is too small?
- b2, err3 := NewWriterSize(b, 2*BufSize)
- if err3 != nil {
- t.Error("NewWriterSize #3 create fail", err3)
- }
+ b2 := NewWriterSize(b, 2*BufSize)
if b2 == b {
t.Error("NewWriterSize did not enlarge buffer")
}
@@ -496,10 +474,7 @@ func TestNewWriterSizeIdempotent(t *testing.T) {
func TestWriteString(t *testing.T) {
const BufSize = 8
buf := new(bytes.Buffer)
- b, err := NewWriterSize(buf, BufSize)
- if err != nil {
- t.Error("NewWriterSize create fail", err)
- }
+ b := NewWriterSize(buf, BufSize)
b.WriteString("0") // easy
b.WriteString("123456") // still easy
b.WriteString("7890") // easy after flush
@@ -515,27 +490,29 @@ func TestWriteString(t *testing.T) {
}
func TestBufferFull(t *testing.T) {
- buf, _ := NewReaderSize(strings.NewReader("hello, world"), 5)
- line, err := buf.ReadSlice(',')
- if string(line) != "hello" || err != ErrBufferFull {
+ const longString = "And now, hello, world! It is the time for all good men to come to the aid of their party"
+ buf := NewReaderSize(strings.NewReader(longString), minReadBufferSize)
+ line, err := buf.ReadSlice('!')
+ if string(line) != "And now, hello, " || err != ErrBufferFull {
t.Errorf("first ReadSlice(,) = %q, %v", line, err)
}
- line, err = buf.ReadSlice(',')
- if string(line) != "," || err != nil {
+ line, err = buf.ReadSlice('!')
+ if string(line) != "world!" || err != nil {
t.Errorf("second ReadSlice(,) = %q, %v", line, err)
}
}
func TestPeek(t *testing.T) {
p := make([]byte, 10)
- buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+ // string is 16 (minReadBufferSize) long.
+ buf := NewReaderSize(strings.NewReader("abcdefghijklmnop"), minReadBufferSize)
if s, err := buf.Peek(1); string(s) != "a" || err != nil {
t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
}
if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
}
- if _, err := buf.Peek(5); err != ErrBufferFull {
+ if _, err := buf.Peek(32); err != ErrBufferFull {
t.Fatalf("want ErrBufFull got %v", err)
}
if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
@@ -553,15 +530,36 @@ func TestPeek(t *testing.T) {
if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
}
- if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
- t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+ if _, err := buf.Read(p[0:]); string(p[0:]) != "ghijklmnop" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghijklmnop", string(p[0:minReadBufferSize]), err)
}
if s, err := buf.Peek(0); string(s) != "" || err != nil {
t.Fatalf("want %q got %q, err=%v", "", string(s), err)
}
- if _, err := buf.Peek(1); err != os.EOF {
+ if _, err := buf.Peek(1); err != io.EOF {
t.Fatalf("want EOF got %v", err)
}
+
+ // Test for issue 3022, not exposing a reader's error on a successful Peek.
+ buf = NewReaderSize(dataAndEOFReader("abcd"), 32)
+ if s, err := buf.Peek(2); string(s) != "ab" || err != nil {
+ t.Errorf(`Peek(2) on "abcd", EOF = %q, %v; want "ab", nil`, string(s), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+ t.Errorf(`Peek(4) on "abcd", EOF = %q, %v; want "abcd", nil`, string(s), err)
+ }
+ if n, err := buf.Read(p[0:5]); string(p[0:n]) != "abcd" || err != nil {
+ t.Fatalf("Read after peek = %q, %v; want abcd, EOF", p[0:n], err)
+ }
+ if n, err := buf.Read(p[0:1]); string(p[0:n]) != "" || err != io.EOF {
+ t.Fatalf(`second Read after peek = %q, %v; want "", EOF`, p[0:n], err)
+ }
+}
+
+type dataAndEOFReader string
+
+func (r dataAndEOFReader) Read(p []byte) (int, error) {
+ return copy(p, r), io.EOF
}
func TestPeekThenUnreadRune(t *testing.T) {
@@ -583,7 +581,7 @@ type testReader struct {
stride int
}
-func (t *testReader) Read(buf []byte) (n int, err os.Error) {
+func (t *testReader) Read(buf []byte) (n int, err error) {
n = t.stride
if n > len(t.data) {
n = len(t.data)
@@ -594,7 +592,7 @@ func (t *testReader) Read(buf []byte) (n int, err os.Error) {
copy(buf, t.data)
t.data = t.data[n:]
if len(t.data) == 0 {
- err = os.EOF
+ err = io.EOF
}
return
}
@@ -604,7 +602,7 @@ func testReadLine(t *testing.T, input []byte) {
for stride := 1; stride < 2; stride++ {
done := 0
reader := testReader{input, stride}
- l, _ := NewReaderSize(&reader, len(input)+1)
+ l := NewReaderSize(&reader, len(input)+1)
for {
line, isPrefix, err := l.ReadLine()
if len(line) > 0 && err != nil {
@@ -614,7 +612,7 @@ func testReadLine(t *testing.T, input []byte) {
t.Errorf("ReadLine returned prefix")
}
if err != nil {
- if err != os.EOF {
+ if err != io.EOF {
t.Fatalf("Got unknown error: %s", err)
}
break
@@ -636,19 +634,25 @@ func TestReadLine(t *testing.T) {
}
func TestLineTooLong(t *testing.T) {
- buf := bytes.NewBuffer([]byte("aaabbbcc\n"))
- l, _ := NewReaderSize(buf, 3)
+ data := make([]byte, 0)
+ for i := 0; i < minReadBufferSize*5/2; i++ {
+ data = append(data, '0'+byte(i%10))
+ }
+ buf := bytes.NewBuffer(data)
+ l := NewReaderSize(buf, minReadBufferSize)
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)
+ if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
+ t.Errorf("bad result for first line: got %q want %q %v", line, data[:minReadBufferSize], err)
}
+ data = data[len(line):]
line, isPrefix, err = l.ReadLine()
- if !isPrefix || !bytes.Equal(line, []byte("bbb")) || err != nil {
- t.Errorf("bad result for second line: %x", line)
+ if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
+ t.Errorf("bad result for second line: got %q want %q %v", line, data[:minReadBufferSize], err)
}
+ data = data[len(line):]
line, isPrefix, err = l.ReadLine()
- if isPrefix || !bytes.Equal(line, []byte("cc")) || err != nil {
- t.Errorf("bad result for third line: %x", line)
+ if isPrefix || !bytes.Equal(line, data[:minReadBufferSize/2]) || err != nil {
+ t.Errorf("bad result for third line: got %q want %q %v", line, data[:minReadBufferSize/2], err)
}
line, isPrefix, err = l.ReadLine()
if isPrefix || err == nil {
@@ -657,12 +661,12 @@ func TestLineTooLong(t *testing.T) {
}
func TestReadAfterLines(t *testing.T) {
- line1 := "line1"
- restData := "line2\nline 3\n"
+ line1 := "this is line1"
+ restData := "this is line2\nthis is line 3\n"
inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
outbuf := new(bytes.Buffer)
maxLineLength := len(line1) + len(restData)/2
- l, _ := NewReaderSize(inbuf, maxLineLength)
+ l := NewReaderSize(inbuf, maxLineLength)
line, isPrefix, err := l.ReadLine()
if isPrefix || err != nil || string(line) != line1 {
t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line))
@@ -677,15 +681,15 @@ func TestReadAfterLines(t *testing.T) {
}
func TestReadEmptyBuffer(t *testing.T) {
- l, _ := NewReaderSize(bytes.NewBuffer(nil), 10)
+ l := NewReaderSize(new(bytes.Buffer), minReadBufferSize)
line, isPrefix, err := l.ReadLine()
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
}
}
func TestLinesAfterRead(t *testing.T) {
- l, _ := NewReaderSize(bytes.NewBuffer([]byte("foo")), 10)
+ l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
_, err := ioutil.ReadAll(l)
if err != nil {
t.Error(err)
@@ -693,7 +697,68 @@ func TestLinesAfterRead(t *testing.T) {
}
line, isPrefix, err := l.ReadLine()
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
}
}
+
+func TestReadLineNonNilLineOrError(t *testing.T) {
+ r := NewReader(strings.NewReader("line 1\n"))
+ for i := 0; i < 2; i++ {
+ l, _, err := r.ReadLine()
+ if l != nil && err != nil {
+ t.Fatalf("on line %d/2; ReadLine=%#v, %v; want non-nil line or Error, but not both",
+ i+1, l, err)
+ }
+ }
+}
+
+type readLineResult struct {
+ line []byte
+ isPrefix bool
+ err error
+}
+
+var readLineNewlinesTests = []struct {
+ input string
+ expect []readLineResult
+}{
+ {"012345678901234\r\n012345678901234\r\n", []readLineResult{
+ {[]byte("012345678901234"), true, nil},
+ {nil, false, nil},
+ {[]byte("012345678901234"), true, nil},
+ {nil, false, nil},
+ {nil, false, io.EOF},
+ }},
+ {"0123456789012345\r012345678901234\r", []readLineResult{
+ {[]byte("0123456789012345"), true, nil},
+ {[]byte("\r012345678901234"), true, nil},
+ {[]byte("\r"), false, nil},
+ {nil, false, io.EOF},
+ }},
+}
+
+func TestReadLineNewlines(t *testing.T) {
+ for _, e := range readLineNewlinesTests {
+ testReadLineNewlines(t, e.input, e.expect)
+ }
+}
+
+func testReadLineNewlines(t *testing.T, input string, expect []readLineResult) {
+ b := NewReaderSize(strings.NewReader(input), minReadBufferSize)
+ for i, e := range expect {
+ line, isPrefix, err := b.ReadLine()
+ if bytes.Compare(line, e.line) != 0 {
+ t.Errorf("%q call %d, line == %q, want %q", input, i, line, e.line)
+ return
+ }
+ if isPrefix != e.isPrefix {
+ t.Errorf("%q call %d, isPrefix == %v, want %v", input, i, isPrefix, e.isPrefix)
+ return
+ }
+ if err != e.err {
+ t.Errorf("%q call %d, err == %v, want %v", input, i, err, e.err)
+ return
+ }
+ }
+}
diff --git a/src/pkg/builtin/builtin.go b/src/pkg/builtin/builtin.go
index 07acce4f7..e81616ca4 100644
--- a/src/pkg/builtin/builtin.go
+++ b/src/pkg/builtin/builtin.go
@@ -3,29 +3,110 @@
// 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
+ Package builtin provides documentation for Go's predeclared identifiers.
+ The items documented here are not actually in package builtin
but their descriptions here allow godoc to present documentation
- for the language's special functions.
+ for the language's special identifiers.
*/
package builtin
+// bool is the set of boolean values, true and false.
+type bool bool
+
+// uint8 is the set of all unsigned 8-bit integers.
+// Range: 0 through 255.
+type uint8 uint8
+
+// uint16 is the set of all unsigned 16-bit integers.
+// Range: 0 through 65535.
+type uint16 uint16
+
+// uint32 is the set of all unsigned 32-bit integers.
+// Range: 0 through 4294967295.
+type uint32 uint32
+
+// uint64 is the set of all unsigned 64-bit integers.
+// Range: 0 through 18446744073709551615.
+type uint64 uint64
+
+// int8 is the set of all signed 8-bit integers.
+// Range: -128 through 127.
+type int8 int8
+
+// int16 is the set of all signed 16-bit integers.
+// Range: -32768 through 32767.
+type int16 int16
+
+// int32 is the set of all signed 32-bit integers.
+// Range: -2147483648 through 2147483647.
+type int32 int32
+
+// int64 is the set of all signed 64-bit integers.
+// Range: -9223372036854775808 through 9223372036854775807.
+type int64 int64
+
+// float32 is the set of all IEEE-754 32-bit floating-point numbers.
+type float32 float32
+
+// float64 is the set of all IEEE-754 64-bit floating-point numbers.
+type float64 float64
+
+// complex64 is the set of all complex numbers with float32 real and
+// imaginary parts.
+type complex64 complex64
+
+// complex128 is the set of all complex numbers with float64 real and
+// imaginary parts.
+type complex128 complex128
+
+// string is the set of all strings of 8-bit bytes, conventionally but not
+// necessarily representing UTF-8-encoded text. A string may be empty, but
+// not nil. Values of string type are immutable.
+type string string
+
+// int is a signed integer type that is at least 32 bits in size. It is a
+// distinct type, however, and not an alias for, say, int32.
+type int int
+
+// uint is an unsigned integer type that is at least 32 bits in size. It is a
+// distinct type, however, and not an alias for, say, uint32.
+type uint uint
+
+// uintptr is an integer type that is large enough to hold the bit pattern of
+// any pointer.
+type uintptr uintptr
+
+// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
+// used, by convention, to distinguish byte values from 8-bit unsigned
+// integer values.
+type byte byte
+
+// rune is an alias for int and is equivalent to int in all ways. It is
+// used, by convention, to distinguish character values from integer values.
+// In a future version of Go, it will change to an alias of int32.
+type rune rune
+
// 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
+// Type1 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 Type1 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
+type FloatType float32
// ComplexType is here for the purposes of documentation only. It is a
// stand-in for either complex type: complex64 or complex128.
-type ComplexType int
+type ComplexType complex64
// 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
@@ -43,6 +124,11 @@ func append(slice []Type, elems ...Type) []Type
// len(src) and len(dst).
func copy(dst, src []Type) int
+// The delete built-in function deletes the element with the specified key
+// (m[key]) from the map. If there is no such element, delete is a no-op.
+// If m is nil, delete panics.
+func delete(m map[Type]Type1, key Type)
+
// 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).
@@ -95,7 +181,7 @@ func complex(r, i FloatType) ComplexType
// 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
+// The imag 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
@@ -133,3 +219,9 @@ func panic(v interface{})
// nil. Thus the return value from recover reports whether the goroutine is
// panicking.
func recover() interface{}
+
+// The error built-in interface type is the conventional interface for
+// representing an error condition, with the nil value representing no error.
+type error interface {
+ Error() string
+}
diff --git a/src/pkg/bytes/Makefile b/src/pkg/bytes/Makefile
deleted file mode 100644
index 03395c7a4..000000000
--- a/src/pkg/bytes/Makefile
+++ /dev/null
@@ -1,16 +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.
-
-include ../../Make.inc
-
-TARG=bytes
-GOFILES=\
- buffer.go\
- bytes.go\
- bytes_decl.go\
-
-OFILES=\
- asm_$(GOARCH).$O\
-
-include ../../Make.pkg
diff --git a/src/pkg/bytes/asm_386.s b/src/pkg/bytes/asm_386.s
index f3391740b..e7833de0c 100644
--- a/src/pkg/bytes/asm_386.s
+++ b/src/pkg/bytes/asm_386.s
@@ -15,3 +15,19 @@ TEXT ·IndexByte(SB),7,$0
SUBL $1, DI
MOVL DI, ret+16(FP)
RET
+
+TEXT ·Equal(SB),7,$0
+ MOVL len+4(FP), BX
+ MOVL len1+16(FP), CX
+ MOVL $0, AX
+ CMPL BX, CX
+ JNE eqret
+ MOVL p+0(FP), SI
+ MOVL q+12(FP), DI
+ CLD
+ REP; CMPSB
+ JNE eqret
+ MOVL $1, AX
+eqret:
+ MOVB AX, ret+24(FP)
+ RET
diff --git a/src/pkg/bytes/asm_amd64.s b/src/pkg/bytes/asm_amd64.s
index c6793cbdc..5caea5c52 100644
--- a/src/pkg/bytes/asm_amd64.s
+++ b/src/pkg/bytes/asm_amd64.s
@@ -90,3 +90,19 @@ success:
MOVL DI, ret+24(FP)
RET
+TEXT ·Equal(SB),7,$0
+ MOVL len+8(FP), BX
+ MOVL len1+24(FP), CX
+ MOVL $0, AX
+ CMPL BX, CX
+ JNE eqret
+ MOVQ p+0(FP), SI
+ MOVQ q+16(FP), DI
+ CLD
+ REP; CMPSB
+ MOVL $1, DX
+ CMOVLEQ DX, AX
+eqret:
+ MOVB AX, ret+32(FP)
+ RET
+
diff --git a/src/pkg/bytes/asm_arm.s b/src/pkg/bytes/asm_arm.s
index f32fca136..4ed0c1580 100644
--- a/src/pkg/bytes/asm_arm.s
+++ b/src/pkg/bytes/asm_arm.s
@@ -6,3 +6,6 @@
TEXT ·IndexByte(SB),7,$0
B ·indexBytePortable(SB)
+// no memcmp implementation on arm yet
+TEXT ·Equal(SB),7,$0
+ B ·equalPortable(SB)
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 5de86105d..afdf22055 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -7,9 +7,9 @@ package bytes
// Simple byte buffer for marshaling data.
import (
+ "errors"
"io"
- "os"
- "utf8"
+ "unicode/utf8"
)
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
@@ -33,6 +33,9 @@ const (
opRead // Any other read operation.
)
+// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
+var ErrTooLarge = errors.New("bytes.Buffer: too large")
+
// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
@@ -54,10 +57,13 @@ func (b *Buffer) String() string {
func (b *Buffer) Len() int { return len(b.buf) - b.off }
// Truncate discards all but the first n unread bytes from the buffer.
-// It is an error to call b.Truncate(n) with n > b.Len().
+// It panics if n is negative or greater than the length of the buffer.
func (b *Buffer) Truncate(n int) {
b.lastRead = opInvalid
- if n == 0 {
+ switch {
+ case n < 0 || n > b.Len():
+ panic("bytes.Buffer: truncation out of range")
+ case n == 0:
// Reuse buffer space.
b.off = 0
}
@@ -68,8 +74,9 @@ func (b *Buffer) Truncate(n int) {
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }
-// Grow buffer to guarantee space for n more bytes.
-// Return index where bytes should be written.
+// grow grows the buffer to guarantee space for n more bytes.
+// It returns the index where bytes should be written.
+// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int {
m := b.Len()
// If buffer is empty, reset to recover space.
@@ -82,7 +89,7 @@ func (b *Buffer) grow(n int) int {
buf = b.bootstrap[0:]
} else {
// not enough space anywhere
- buf = make([]byte, 2*cap(b.buf)+n)
+ buf = makeSlice(2*cap(b.buf) + n)
copy(buf, b.buf[b.off:])
}
b.buf = buf
@@ -94,16 +101,19 @@ func (b *Buffer) grow(n int) int {
// Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil.
-func (b *Buffer) Write(p []byte) (n int, err os.Error) {
+// If the buffer becomes too large, Write will panic with
+// ErrTooLarge.
+func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
- copy(b.buf[m:], p)
- return len(p), nil
+ return copy(b.buf[m:], p), nil
}
// WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil.
-func (b *Buffer) WriteString(s string) (n int, err os.Error) {
+// If the buffer becomes too large, WriteString will panic with
+// ErrTooLarge.
+func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
return copy(b.buf[m:], s), nil
@@ -117,33 +127,33 @@ const MinRead = 512
// ReadFrom reads data from r until EOF and appends it to the buffer.
// The return value n is the number of bytes read.
-// Any error except os.EOF encountered during the read
+// Any error except io.EOF encountered during the read
// is also returned.
-func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+// If the buffer becomes too large, ReadFrom will panic with
+// ErrTooLarge.
+func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
if b.off >= len(b.buf) {
b.Truncate(0)
}
for {
- if cap(b.buf)-len(b.buf) < MinRead {
- var newBuf []byte
- // can we get space without allocation?
- if b.off+cap(b.buf)-len(b.buf) >= MinRead {
- // reuse beginning of buffer
- newBuf = b.buf[0 : len(b.buf)-b.off]
- } else {
- // not enough space at end; put space on end
- newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+ if free := cap(b.buf) - len(b.buf); free < MinRead {
+ // not enough space at end
+ newBuf := b.buf
+ if b.off+free < MinRead {
+ // not enough space using beginning of buffer;
+ // double buffer capacity
+ newBuf = makeSlice(2*cap(b.buf) + MinRead)
}
copy(newBuf, b.buf[b.off:])
- b.buf = newBuf
+ b.buf = newBuf[:len(b.buf)-b.off]
b.off = 0
}
m, e := r.Read(b.buf[len(b.buf):cap(b.buf)])
b.buf = b.buf[0 : len(b.buf)+m]
n += int64(m)
- if e == os.EOF {
+ if e == io.EOF {
break
}
if e != nil {
@@ -153,21 +163,40 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
return n, nil // err is EOF, so return nil explicitly
}
+// makeSlice allocates a slice of size n. If the allocation fails, it panics
+// with ErrTooLarge.
+func makeSlice(n int) []byte {
+ // If the make fails, give a known error.
+ defer func() {
+ if recover() != nil {
+ panic(ErrTooLarge)
+ }
+ }()
+ return make([]byte, n)
+}
+
// WriteTo writes data to w until the buffer is drained or an error
// occurs. The return value n is the number of bytes written; it always
// fits into an int, but it is int64 to match the io.WriterTo interface.
// Any error encountered during the write is also returned.
-func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
b.lastRead = opInvalid
if b.off < len(b.buf) {
+ nBytes := b.Len()
m, e := w.Write(b.buf[b.off:])
+ if m > nBytes {
+ panic("bytes.Buffer.WriteTo: invalid Write count")
+ }
b.off += m
n = int64(m)
if e != nil {
return n, e
}
- // otherwise all bytes were written, by definition of
+ // all bytes should have been written, by definition of
// Write method in io.Writer
+ if m != nBytes {
+ return n, io.ErrShortWrite
+ }
}
// Buffer is now empty; reset.
b.Truncate(0)
@@ -177,7 +206,9 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
-func (b *Buffer) WriteByte(c byte) os.Error {
+// If the buffer becomes too large, WriteByte will panic with
+// ErrTooLarge.
+func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
m := b.grow(1)
b.buf[m] = c
@@ -188,7 +219,9 @@ func (b *Buffer) WriteByte(c byte) os.Error {
// code point r to the buffer, returning its length and
// an error, which is always nil but is included
// to match bufio.Writer's WriteRune.
-func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
+// If the buffer becomes too large, WriteRune will panic with
+// ErrTooLarge.
+func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf {
b.WriteByte(byte(r))
return 1, nil
@@ -200,14 +233,17 @@ func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained. The return value n is the number of bytes read. If the
-// buffer has no data to return, err is os.EOF even if len(p) is zero;
+// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
-func (b *Buffer) Read(p []byte) (n int, err os.Error) {
+func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
- return 0, os.EOF
+ if len(p) == 0 {
+ return
+ }
+ return 0, io.EOF
}
n = copy(p, b.buf[b.off:])
b.off += n
@@ -236,13 +272,13 @@ func (b *Buffer) Next(n int) []byte {
}
// ReadByte reads and returns the next byte from the buffer.
-// If no byte is available, it returns error os.EOF.
-func (b *Buffer) ReadByte() (c byte, err os.Error) {
+// If no byte is available, it returns error io.EOF.
+func (b *Buffer) ReadByte() (c byte, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
- return 0, os.EOF
+ return 0, io.EOF
}
c = b.buf[b.off]
b.off++
@@ -252,21 +288,21 @@ func (b *Buffer) ReadByte() (c byte, err os.Error) {
// 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 no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
-func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
+func (b *Buffer) ReadRune() (r rune, size int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
- return 0, 0, os.EOF
+ return 0, 0, io.EOF
}
b.lastRead = opReadRune
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
- return int(c), 1, nil
+ return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.buf[b.off:])
b.off += n
@@ -278,9 +314,9 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
// not a ReadRune, UnreadRune returns an error. (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
-func (b *Buffer) UnreadRune() os.Error {
+func (b *Buffer) UnreadRune() error {
if b.lastRead != opReadRune {
- return os.NewError("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
+ return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
b.lastRead = opInvalid
if b.off > 0 {
@@ -293,9 +329,9 @@ func (b *Buffer) UnreadRune() os.Error {
// UnreadByte unreads the last byte returned by the most recent
// read operation. If write has happened since the last read, UnreadByte
// returns an error.
-func (b *Buffer) UnreadByte() os.Error {
+func (b *Buffer) UnreadByte() error {
if b.lastRead != opReadRune && b.lastRead != opRead {
- return os.NewError("bytes.Buffer: UnreadByte: previous operation was not a read")
+ return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
}
b.lastRead = opInvalid
if b.off > 0 {
@@ -307,15 +343,15 @@ func (b *Buffer) UnreadByte() os.Error {
// ReadBytes reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
-// it returns the data read before the error and the error itself (often os.EOF).
+// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
-func (b *Buffer) ReadBytes(delim byte) (line []byte, err os.Error) {
+func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
i := IndexByte(b.buf[b.off:], delim)
size := i + 1
if i < 0 {
size = len(b.buf) - b.off
- err = os.EOF
+ err = io.EOF
}
line = make([]byte, size)
copy(line, b.buf[b.off:])
@@ -326,23 +362,29 @@ func (b *Buffer) ReadBytes(delim byte) (line []byte, err os.Error) {
// ReadString reads until the first occurrence of delim in the input,
// returning a string containing the data up to and including the delimiter.
// If ReadString encounters an error before finding a delimiter,
-// it returns the data read before the error and the error itself (often os.EOF).
+// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end
// in delim.
-func (b *Buffer) ReadString(delim byte) (line string, err os.Error) {
+func (b *Buffer) ReadString(delim byte) (line string, err error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err
}
// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents. It is intended to prepare a Buffer to read existing data. It
-// can also be used to size the internal buffer for writing. To do that,
+// can also be used to size the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
+//
+// In most cases, new(Buffer) (or just declaring a Buffer variable) is
+// sufficient to initialize a Buffer.
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
// NewBufferString creates and initializes a new Buffer using string s as its
-// initial contents. It is intended to prepare a buffer to read an existing
+// initial contents. It is intended to prepare a buffer to read an existing
// string.
+//
+// In most cases, new(Buffer) (or just declaring a Buffer variable) is
+// sufficient to initialize a Buffer.
func NewBufferString(s string) *Buffer {
return &Buffer{buf: []byte(s)}
}
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
index 06d2a65c6..d0af11f10 100644
--- a/src/pkg/bytes/buffer_test.go
+++ b/src/pkg/bytes/buffer_test.go
@@ -6,17 +6,16 @@ package bytes_test
import (
. "bytes"
- "os"
- "rand"
+ "io"
+ "math/rand"
"testing"
- "utf8"
+ "unicode/utf8"
)
const N = 10000 // make this bigger for a larger (and slower) test
var data string // test data for write tests
var bytes []byte // test data; same as data but as a slice.
-
func init() {
bytes = make([]byte, N)
for i := 0; i < N; i++ {
@@ -264,7 +263,7 @@ func TestRuneIO(t *testing.T) {
b := make([]byte, utf8.UTFMax*NRune)
var buf Buffer
n := 0
- for r := 0; r < NRune; r++ {
+ for r := rune(0); r < NRune; r++ {
size := utf8.EncodeRune(b[n:], r)
nbytes, err := buf.WriteRune(r)
if err != nil {
@@ -284,7 +283,7 @@ func TestRuneIO(t *testing.T) {
p := make([]byte, utf8.UTFMax)
// Read it back with ReadRune
- for r := 0; r < NRune; r++ {
+ for r := rune(0); r < NRune; r++ {
size := utf8.EncodeRune(p, r)
nr, nbytes, err := buf.ReadRune()
if nr != r || nbytes != size || err != nil {
@@ -295,7 +294,7 @@ func TestRuneIO(t *testing.T) {
// Check that UnreadRune works
buf.Reset()
buf.Write(b)
- for r := 0; r < NRune; r++ {
+ for r := rune(0); r < NRune; r++ {
r1, size, _ := buf.ReadRune()
if err := buf.UnreadRune(); err != nil {
t.Fatalf("UnreadRune(%U) got error %q", r, err)
@@ -344,21 +343,21 @@ var readBytesTests = []struct {
buffer string
delim byte
expected []string
- err os.Error
+ err error
}{
- {"", 0, []string{""}, os.EOF},
+ {"", 0, []string{""}, io.EOF},
{"a\x00", 0, []string{"a\x00"}, nil},
{"abbbaaaba", 'b', []string{"ab", "b", "b", "aaab"}, nil},
{"hello\x01world", 1, []string{"hello\x01"}, nil},
- {"foo\nbar", 0, []string{"foo\nbar"}, os.EOF},
+ {"foo\nbar", 0, []string{"foo\nbar"}, io.EOF},
{"alpha\nbeta\ngamma\n", '\n', []string{"alpha\n", "beta\n", "gamma\n"}, nil},
- {"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, os.EOF},
+ {"alpha\nbeta\ngamma", '\n', []string{"alpha\n", "beta\n", "gamma"}, io.EOF},
}
func TestReadBytes(t *testing.T) {
for _, test := range readBytesTests {
buf := NewBufferString(test.buffer)
- var err os.Error
+ var err error
for _, expected := range test.expected {
var bytes []byte
bytes, err = buf.ReadBytes(test.delim)
@@ -374,3 +373,16 @@ func TestReadBytes(t *testing.T) {
}
}
}
+
+// Was a bug: used to give EOF reading empty slice at EOF.
+func TestReadEmptyAtEOF(t *testing.T) {
+ b := new(Buffer)
+ slice := make([]byte, 0)
+ n, err := b.Read(slice)
+ if err != nil {
+ t.Errorf("read error: %v", err)
+ }
+ if n != 0 {
+ t.Errorf("wrong count; got %d want 0", n)
+ }
+}
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 5119fce94..7d1426fb4 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -8,11 +8,12 @@ package bytes
import (
"unicode"
- "utf8"
+ "unicode/utf8"
)
// Compare returns an integer comparing the two byte arrays lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b
+// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int {
m := len(a)
if m > len(b) {
@@ -37,7 +38,10 @@ func Compare(a, b []byte) int {
}
// Equal returns a boolean reporting whether a == b.
-func Equal(a, b []byte) bool {
+// A nil argument is equivalent to an empty slice.
+func Equal(a, b []byte) bool
+
+func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
}
@@ -74,18 +78,38 @@ func explode(s []byte, n int) [][]byte {
// Count counts the number of non-overlapping instances of sep in s.
func Count(s, sep []byte) int {
- if len(sep) == 0 {
+ n := len(sep)
+ if n == 0 {
return utf8.RuneCount(s) + 1
}
+ if n > len(s) {
+ return 0
+ }
+ count := 0
c := sep[0]
- n := 0
- for i := 0; i+len(sep) <= len(s); i++ {
- if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
- n++
- i += len(sep) - 1
+ i := 0
+ t := s[:len(s)-n+1]
+ for i < len(t) {
+ if t[i] != c {
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ break
+ }
+ i += o
+ }
+ if n == 1 || Equal(s[i:i+n], sep) {
+ count++
+ i += n
+ continue
}
+ i++
}
- return n
+ return count
+}
+
+// Contains returns whether subslice is within b.
+func Contains(b, subslice []byte) bool {
+ return Index(b, subslice) != -1
}
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
@@ -94,11 +118,27 @@ func Index(s, sep []byte) int {
if n == 0 {
return 0
}
+ if n > len(s) {
+ return -1
+ }
c := sep[0]
- for i := 0; i+n <= len(s); i++ {
- if s[i] == c && (n == 1 || Equal(s[i:i+n], sep)) {
+ if n == 1 {
+ return IndexByte(s, c)
+ }
+ i := 0
+ t := s[:len(s)-n+1]
+ for i < len(t) {
+ if t[i] != c {
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ break
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
return i
}
+ i++
}
return -1
}
@@ -130,10 +170,10 @@ func LastIndex(s, sep []byte) int {
// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index of the first occurrence in s of the given rune.
// It returns -1 if rune is not present in s.
-func IndexRune(s []byte, rune int) int {
+func IndexRune(s []byte, r rune) int {
for i := 0; i < len(s); {
- r, size := utf8.DecodeRune(s[i:])
- if r == rune {
+ r1, size := utf8.DecodeRune(s[i:])
+ if r == r1 {
return i
}
i += size
@@ -147,16 +187,17 @@ func IndexRune(s []byte, rune int) int {
// point in common.
func IndexAny(s []byte, chars string) int {
if len(chars) > 0 {
- var rune, width int
+ var r rune
+ var width int
for i := 0; i < len(s); i += width {
- rune = int(s[i])
- if rune < utf8.RuneSelf {
+ r = rune(s[i])
+ if r < utf8.RuneSelf {
width = 1
} else {
- rune, width = utf8.DecodeRune(s[i:])
+ r, width = utf8.DecodeRune(s[i:])
}
- for _, r := range chars {
- if rune == r {
+ for _, ch := range chars {
+ if r == ch {
return i
}
}
@@ -172,10 +213,10 @@ func IndexAny(s []byte, chars string) int {
func LastIndexAny(s []byte, chars string) int {
if len(chars) > 0 {
for i := len(s); i > 0; {
- rune, size := utf8.DecodeLastRune(s[0:i])
+ r, size := utf8.DecodeLastRune(s[0:i])
i -= size
- for _, m := range chars {
- if rune == m {
+ for _, ch := range chars {
+ if r == ch {
return i
}
}
@@ -256,13 +297,13 @@ func Fields(s []byte) [][]byte {
// It splits the array s at each run of code points c satisfying f(c) and
// returns a slice of subarrays of s. If no code points in s satisfy f(c), an
// empty slice is returned.
-func FieldsFunc(s []byte, f func(int) bool) [][]byte {
+func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
n := 0
inField := false
for i := 0; i < len(s); {
- rune, size := utf8.DecodeRune(s[i:])
+ r, size := utf8.DecodeRune(s[i:])
wasInField := inField
- inField = !f(rune)
+ inField = !f(r)
if inField && !wasInField {
n++
}
@@ -273,13 +314,13 @@ func FieldsFunc(s []byte, f func(int) bool) [][]byte {
na := 0
fieldStart := -1
for i := 0; i <= len(s) && na < n; {
- rune, size := utf8.DecodeRune(s[i:])
- if fieldStart < 0 && size > 0 && !f(rune) {
+ r, size := utf8.DecodeRune(s[i:])
+ if fieldStart < 0 && size > 0 && !f(r) {
fieldStart = i
i += size
continue
}
- if fieldStart >= 0 && (size == 0 || f(rune)) {
+ if fieldStart >= 0 && (size == 0 || f(r)) {
a[na] = s[fieldStart:i]
na++
fieldStart = -1
@@ -329,7 +370,7 @@ func HasSuffix(s, suffix []byte) bool {
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement. The characters in s and the
// output are interpreted as UTF-8-encoded Unicode code points.
-func Map(mapping func(rune int) int, s []byte) []byte {
+func Map(mapping func(r rune) rune, s []byte) []byte {
// In the worst case, the array can grow when mapped, making
// things unpleasant. But it's so rare we barge in assuming it's
// fine. It could also shrink but that falls out naturally.
@@ -338,20 +379,20 @@ func Map(mapping func(rune int) int, s []byte) []byte {
b := make([]byte, maxbytes)
for i := 0; i < len(s); {
wid := 1
- rune := int(s[i])
- if rune >= utf8.RuneSelf {
- rune, wid = utf8.DecodeRune(s[i:])
+ r := rune(s[i])
+ if r >= utf8.RuneSelf {
+ r, wid = utf8.DecodeRune(s[i:])
}
- rune = mapping(rune)
- if rune >= 0 {
- if nbytes+utf8.RuneLen(rune) > maxbytes {
+ r = mapping(r)
+ if r >= 0 {
+ if nbytes+utf8.RuneLen(r) > maxbytes {
// Grow the buffer.
maxbytes = maxbytes*2 + utf8.UTFMax
nb := make([]byte, maxbytes)
copy(nb, b[0:nbytes])
b = nb
}
- nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r)
}
i += wid
}
@@ -383,44 +424,44 @@ func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the byte array s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r int) int { return _case.ToUpper(r) }, s)
+ return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the byte array s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r int) int { return _case.ToLower(r) }, s)
+ return Map(func(r rune) rune { return _case.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the byte array s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r int) int { return _case.ToTitle(r) }, s)
+ return Map(func(r rune) rune { 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 {
+func isSeparator(r rune) bool {
// ASCII alphanumerics and underscore are not separators
- if rune <= 0x7F {
+ if r <= 0x7F {
switch {
- case '0' <= rune && rune <= '9':
+ case '0' <= r && r <= '9':
return false
- case 'a' <= rune && rune <= 'z':
+ case 'a' <= r && r <= 'z':
return false
- case 'A' <= rune && rune <= 'Z':
+ case 'A' <= r && r <= 'Z':
return false
- case rune == '_':
+ case r == '_':
return false
}
return true
}
// Letters and digits are not separators
- if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ if unicode.IsLetter(r) || unicode.IsDigit(r) {
return false
}
// Otherwise, all we can do for now is treat spaces as separators.
- return unicode.IsSpace(rune)
+ return unicode.IsSpace(r)
}
// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
@@ -433,7 +474,7 @@ func Title(s []byte) []byte {
// the closure once per rune.
prev := ' '
return Map(
- func(r int) int {
+ func(r rune) rune {
if isSeparator(prev) {
prev = r
return unicode.ToTitle(r)
@@ -446,7 +487,7 @@ func Title(s []byte) []byte {
// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded
// Unicode code points c that satisfy f(c).
-func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
+func TrimLeftFunc(s []byte, f func(r rune) bool) []byte {
i := indexFunc(s, f, false)
if i == -1 {
return nil
@@ -456,7 +497,7 @@ func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8
// encoded Unicode code points c that satisfy f(c).
-func TrimRightFunc(s []byte, f func(r int) bool) []byte {
+func TrimRightFunc(s []byte, f func(r rune) bool) []byte {
i := lastIndexFunc(s, f, false)
if i >= 0 && s[i] >= utf8.RuneSelf {
_, wid := utf8.DecodeRune(s[i:])
@@ -469,36 +510,36 @@ func TrimRightFunc(s []byte, f func(r int) bool) []byte {
// TrimFunc returns a subslice of s by slicing off all leading and trailing
// UTF-8-encoded Unicode code points c that satisfy f(c).
-func TrimFunc(s []byte, f func(r int) bool) []byte {
+func TrimFunc(s []byte, f func(r rune) bool) []byte {
return TrimRightFunc(TrimLeftFunc(s, f), f)
}
// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index in s of the first Unicode
// code point satisfying f(c), or -1 if none do.
-func IndexFunc(s []byte, f func(r int) bool) int {
+func IndexFunc(s []byte, f func(r rune) bool) int {
return indexFunc(s, f, true)
}
// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index in s of the last Unicode
// code point satisfying f(c), or -1 if none do.
-func LastIndexFunc(s []byte, f func(r int) bool) int {
+func LastIndexFunc(s []byte, f func(r rune) bool) int {
return lastIndexFunc(s, f, true)
}
// indexFunc is the same as IndexFunc except that if
// truth==false, the sense of the predicate function is
// inverted.
-func indexFunc(s []byte, f func(r int) bool, truth bool) int {
+func indexFunc(s []byte, f func(r rune) bool, truth bool) int {
start := 0
for start < len(s) {
wid := 1
- rune := int(s[start])
- if rune >= utf8.RuneSelf {
- rune, wid = utf8.DecodeRune(s[start:])
+ r := rune(s[start])
+ if r >= utf8.RuneSelf {
+ r, wid = utf8.DecodeRune(s[start:])
}
- if f(rune) == truth {
+ if f(r) == truth {
return start
}
start += wid
@@ -509,21 +550,21 @@ func indexFunc(s []byte, f func(r int) bool, truth bool) int {
// lastIndexFunc is the same as LastIndexFunc except that if
// truth==false, the sense of the predicate function is
// inverted.
-func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int {
+func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
for i := len(s); i > 0; {
- rune, size := utf8.DecodeLastRune(s[0:i])
+ r, size := utf8.DecodeLastRune(s[0:i])
i -= size
- if f(rune) == truth {
+ if f(r) == truth {
return i
}
}
return -1
}
-func makeCutsetFunc(cutset string) func(rune int) bool {
- return func(rune int) bool {
+func makeCutsetFunc(cutset string) func(r rune) bool {
+ return func(r rune) bool {
for _, c := range cutset {
- if c == rune {
+ if c == r {
return true
}
}
@@ -556,8 +597,8 @@ func TrimSpace(s []byte) []byte {
}
// Runes returns a slice of runes (Unicode code points) equivalent to s.
-func Runes(s []byte) []int {
- t := make([]int, utf8.RuneCount(s))
+func Runes(s []byte) []rune {
+ t := make([]rune, utf8.RuneCount(s))
i := 0
for len(s) > 0 {
r, l := utf8.DecodeRune(s)
@@ -572,13 +613,18 @@ func Runes(s []byte) []int {
// non-overlapping instances of old replaced by new.
// If n < 0, there is no limit on the number of replacements.
func Replace(s, old, new []byte, n int) []byte {
- if n == 0 {
- return s // avoid allocation
- }
- // Compute number of replacements.
- if m := Count(s, old); m == 0 {
- return s // avoid allocation
- } else if n <= 0 || m < n {
+ m := 0
+ if n != 0 {
+ // Compute number of replacements.
+ m = Count(s, old)
+ }
+ if m == 0 {
+ // Nothing to do. Just copy.
+ t := make([]byte, len(s))
+ copy(t, s)
+ return t
+ }
+ if n < 0 || m < n {
n = m
}
@@ -603,3 +649,58 @@ func Replace(s, old, new []byte, n int) []byte {
w += copy(t[w:], s[start:])
return t[0:w]
}
+
+// EqualFold reports whether s and t, interpreted as UTF-8 strings,
+// are equal under Unicode case-folding.
+func EqualFold(s, t []byte) bool {
+ for len(s) != 0 && len(t) != 0 {
+ // Extract first rune from each.
+ var sr, tr rune
+ if s[0] < utf8.RuneSelf {
+ sr, s = rune(s[0]), s[1:]
+ } else {
+ r, size := utf8.DecodeRune(s)
+ sr, s = r, s[size:]
+ }
+ if t[0] < utf8.RuneSelf {
+ tr, t = rune(t[0]), t[1:]
+ } else {
+ r, size := utf8.DecodeRune(t)
+ tr, t = r, t[size:]
+ }
+
+ // If they match, keep going; if not, return false.
+
+ // Easy case.
+ if tr == sr {
+ continue
+ }
+
+ // Make sr < tr to simplify what follows.
+ if tr < sr {
+ tr, sr = sr, tr
+ }
+ // Fast check for ASCII.
+ if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' {
+ // ASCII, and sr is upper case. tr must be lower case.
+ if tr == sr+'a'-'A' {
+ continue
+ }
+ return false
+ }
+
+ // General case. SimpleFold(x) returns the next equivalent rune > x
+ // or wraps around to smaller values.
+ r := unicode.SimpleFold(sr)
+ for r != sr && r < tr {
+ r = unicode.SimpleFold(r)
+ }
+ if r == tr {
+ continue
+ }
+ return false
+ }
+
+ // One string is empty. Are both?
+ return len(s) == len(t)
+}
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index 9444358a8..000f23517 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -9,7 +9,7 @@ import (
"reflect"
"testing"
"unicode"
- "utf8"
+ "unicode/utf8"
)
func eq(a, b []string) bool {
@@ -46,31 +46,42 @@ type BinOpTest struct {
i int
}
-var comparetests = []BinOpTest{
- {"", "", 0},
- {"a", "", 1},
- {"", "a", -1},
- {"abc", "abc", 0},
- {"ab", "abc", -1},
- {"abc", "ab", 1},
- {"x", "ab", 1},
- {"ab", "x", -1},
- {"x", "a", 1},
- {"b", "x", -1},
+var compareTests = []struct {
+ a, b []byte
+ i int
+}{
+ {[]byte(""), []byte(""), 0},
+ {[]byte("a"), []byte(""), 1},
+ {[]byte(""), []byte("a"), -1},
+ {[]byte("abc"), []byte("abc"), 0},
+ {[]byte("ab"), []byte("abc"), -1},
+ {[]byte("abc"), []byte("ab"), 1},
+ {[]byte("x"), []byte("ab"), 1},
+ {[]byte("ab"), []byte("x"), -1},
+ {[]byte("x"), []byte("a"), 1},
+ {[]byte("b"), []byte("x"), -1},
+ // nil tests
+ {nil, nil, 0},
+ {[]byte(""), nil, 0},
+ {nil, []byte(""), 0},
+ {[]byte("a"), nil, 1},
+ {nil, []byte("a"), -1},
}
func TestCompare(t *testing.T) {
- for _, tt := range comparetests {
- a := []byte(tt.a)
- b := []byte(tt.b)
- cmp := Compare(a, b)
- eql := Equal(a, b)
+ for _, tt := range compareTests {
+ cmp := Compare(tt.a, tt.b)
if cmp != tt.i {
t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
}
+ eql := Equal(tt.a, tt.b)
if eql != (tt.i == 0) {
t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql)
}
+ eql = EqualPortable(tt.a, tt.b)
+ if eql != (tt.i == 0) {
+ t.Errorf(`EqualPortable(%q, %q) = %v`, tt.a, tt.b, eql)
+ }
}
}
@@ -264,41 +275,147 @@ func TestIndexRune(t *testing.T) {
}
}
-func BenchmarkIndexByte4K(b *testing.B) { bmIndex(b, IndexByte, 4<<10) }
+var bmbuf []byte
+
+func BenchmarkIndexByte32(b *testing.B) { bmIndexByte(b, IndexByte, 32) }
+func BenchmarkIndexByte4K(b *testing.B) { bmIndexByte(b, IndexByte, 4<<10) }
+func BenchmarkIndexByte4M(b *testing.B) { bmIndexByte(b, IndexByte, 4<<20) }
+func BenchmarkIndexByte64M(b *testing.B) { bmIndexByte(b, IndexByte, 64<<20) }
+func BenchmarkIndexBytePortable32(b *testing.B) { bmIndexByte(b, IndexBytePortable, 32) }
+func BenchmarkIndexBytePortable4K(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<10) }
+func BenchmarkIndexBytePortable4M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<20) }
+func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) }
+
+func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
+}
+
+func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) }
+func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) }
+func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) }
+func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) }
+func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) }
+func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) }
+func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) }
+func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) }
-func BenchmarkIndexByte4M(b *testing.B) { bmIndex(b, IndexByte, 4<<20) }
+func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
+ if len(bmbuf) < 2*n {
+ bmbuf = make([]byte, 2*n)
+ }
+ b.SetBytes(int64(n))
+ buf1 := bmbuf[0:n]
+ buf2 := bmbuf[n : 2*n]
+ buf1[n-1] = 'x'
+ buf2[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ eq := equal(buf1, buf2)
+ if !eq {
+ b.Fatal("bad equal")
+ }
+ }
+ buf1[n-1] = '\x00'
+ buf2[n-1] = '\x00'
+}
-func BenchmarkIndexByte64M(b *testing.B) { bmIndex(b, IndexByte, 64<<20) }
+func BenchmarkIndex32(b *testing.B) { bmIndex(b, Index, 32) }
+func BenchmarkIndex4K(b *testing.B) { bmIndex(b, Index, 4<<10) }
+func BenchmarkIndex4M(b *testing.B) { bmIndex(b, Index, 4<<20) }
+func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) }
-func BenchmarkIndexBytePortable4K(b *testing.B) {
- bmIndex(b, IndexBytePortable, 4<<10)
+func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, buf[n-7:])
+ if j != n-7 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
}
-func BenchmarkIndexBytePortable4M(b *testing.B) {
- bmIndex(b, IndexBytePortable, 4<<20)
+func BenchmarkIndexEasy32(b *testing.B) { bmIndexEasy(b, Index, 32) }
+func BenchmarkIndexEasy4K(b *testing.B) { bmIndexEasy(b, Index, 4<<10) }
+func BenchmarkIndexEasy4M(b *testing.B) { bmIndexEasy(b, Index, 4<<20) }
+func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) }
+
+func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ buf[n-7] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, buf[n-7:])
+ if j != n-7 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ buf[n-7] = '\x00'
}
-func BenchmarkIndexBytePortable64M(b *testing.B) {
- bmIndex(b, IndexBytePortable, 64<<20)
+func BenchmarkCount32(b *testing.B) { bmCount(b, Count, 32) }
+func BenchmarkCount4K(b *testing.B) { bmCount(b, Count, 4<<10) }
+func BenchmarkCount4M(b *testing.B) { bmCount(b, Count, 4<<20) }
+func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) }
+
+func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
+ if len(bmbuf) < n {
+ bmbuf = make([]byte, n)
+ }
+ b.SetBytes(int64(n))
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := count(buf, buf[n-7:])
+ if j != 1 {
+ b.Fatal("bad count", j)
+ }
+ }
+ buf[n-1] = '\x00'
}
-var bmbuf []byte
+func BenchmarkCountEasy32(b *testing.B) { bmCountEasy(b, Count, 32) }
+func BenchmarkCountEasy4K(b *testing.B) { bmCountEasy(b, Count, 4<<10) }
+func BenchmarkCountEasy4M(b *testing.B) { bmCountEasy(b, Count, 4<<20) }
+func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) }
-func bmIndex(b *testing.B, index func([]byte, byte) int, n int) {
+func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
if len(bmbuf) < n {
bmbuf = make([]byte, n)
}
b.SetBytes(int64(n))
buf := bmbuf[0:n]
buf[n-1] = 'x'
+ buf[n-7] = 'x'
for i := 0; i < b.N; i++ {
- j := index(buf, 'x')
- if j != n-1 {
- println("bad index", j)
- panic("bad index")
+ j := count(buf, buf[n-7:])
+ if j != 1 {
+ b.Fatal("bad count", j)
}
}
- buf[n-1] = '0'
+ buf[n-1] = '\x00'
+ buf[n-7] = '\x00'
}
type ExplodeTest struct {
@@ -444,7 +561,7 @@ func TestFields(t *testing.T) {
}
func TestFieldsFunc(t *testing.T) {
- pred := func(c int) bool { return c == 'X' }
+ pred := func(c rune) bool { return c == 'X' }
var fieldsFuncTests = []FieldsTest{
{"", []string{}},
{"XX", []string{}},
@@ -514,24 +631,24 @@ func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCa
}
}
-func tenRunes(rune int) string {
- r := make([]int, 10)
- for i := range r {
- r[i] = rune
+func tenRunes(r rune) string {
+ runes := make([]rune, 10)
+ for i := range runes {
+ runes[i] = r
}
- return string(r)
+ return string(runes)
}
// User-defined self-inverse mapping function
-func rot13(rune int) int {
- step := 13
- if rune >= 'a' && rune <= 'z' {
- return ((rune - 'a' + step) % 26) + 'a'
+func rot13(r rune) rune {
+ const step = 13
+ if r >= 'a' && r <= 'z' {
+ return ((r - 'a' + step) % 26) + 'a'
}
- if rune >= 'A' && rune <= 'Z' {
- return ((rune - 'A' + step) % 26) + 'A'
+ if r >= 'A' && r <= 'Z' {
+ return ((r - 'A' + step) % 26) + 'A'
}
- return rune
+ return r
}
func TestMap(t *testing.T) {
@@ -539,7 +656,7 @@ func TestMap(t *testing.T) {
a := tenRunes('a')
// 1. Grow. This triggers two reallocations in Map.
- maxRune := func(rune int) int { return unicode.MaxRune }
+ maxRune := func(r rune) rune { return unicode.MaxRune }
m := Map(maxRune, []byte(a))
expect := tenRunes(unicode.MaxRune)
if string(m) != expect {
@@ -547,7 +664,7 @@ func TestMap(t *testing.T) {
}
// 2. Shrink
- minRune := func(rune int) int { return 'a' }
+ minRune := func(r rune) rune { return 'a' }
m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
expect = a
if string(m) != expect {
@@ -569,9 +686,9 @@ func TestMap(t *testing.T) {
}
// 5. Drop
- dropNotLatin := func(rune int) int {
- if unicode.Is(unicode.Latin, rune) {
- return rune
+ dropNotLatin := func(r rune) rune {
+ if unicode.Is(unicode.Latin, r) {
+ return r
}
return -1
}
@@ -615,7 +732,7 @@ func TestRepeat(t *testing.T) {
}
}
-func runesEqual(a, b []int) bool {
+func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
}
@@ -629,18 +746,18 @@ func runesEqual(a, b []int) bool {
type RunesTest struct {
in string
- out []int
+ out []rune
lossy bool
}
var RunesTests = []RunesTest{
- {"", []int{}, false},
- {" ", []int{32}, false},
- {"ABC", []int{65, 66, 67}, false},
- {"abc", []int{97, 98, 99}, false},
- {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
- {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
- {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+ {"", []rune{}, false},
+ {" ", []rune{32}, false},
+ {"ABC", []rune{65, 66, 67}, false},
+ {"abc", []rune{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false},
+ {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true},
}
func TestRunes(t *testing.T) {
@@ -662,48 +779,49 @@ func TestRunes(t *testing.T) {
}
type TrimTest struct {
- f func([]byte, string) []byte
+ f string
in, cutset, out string
}
var trimTests = []TrimTest{
- {Trim, "abba", "a", "bb"},
- {Trim, "abba", "ab", ""},
- {TrimLeft, "abba", "ab", ""},
- {TrimRight, "abba", "ab", ""},
- {TrimLeft, "abba", "a", "bba"},
- {TrimRight, "abba", "a", "abb"},
- {Trim, "<tag>", "<>", "tag"},
- {Trim, "* listitem", " *", "listitem"},
- {Trim, `"quote"`, `"`, "quote"},
- {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "abba", "a", "bb"},
+ {"Trim", "abba", "ab", ""},
+ {"TrimLeft", "abba", "ab", ""},
+ {"TrimRight", "abba", "ab", ""},
+ {"TrimLeft", "abba", "a", "bba"},
+ {"TrimRight", "abba", "a", "abb"},
+ {"Trim", "<tag>", "<>", "tag"},
+ {"Trim", "* listitem", " *", "listitem"},
+ {"Trim", `"quote"`, `"`, "quote"},
+ {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
//empty string tests
- {Trim, "abba", "", "abba"},
- {Trim, "", "123", ""},
- {Trim, "", "", ""},
- {TrimLeft, "abba", "", "abba"},
- {TrimLeft, "", "123", ""},
- {TrimLeft, "", "", ""},
- {TrimRight, "abba", "", "abba"},
- {TrimRight, "", "123", ""},
- {TrimRight, "", "", ""},
- {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+ {"Trim", "abba", "", "abba"},
+ {"Trim", "", "123", ""},
+ {"Trim", "", "", ""},
+ {"TrimLeft", "abba", "", "abba"},
+ {"TrimLeft", "", "123", ""},
+ {"TrimLeft", "", "", ""},
+ {"TrimRight", "abba", "", "abba"},
+ {"TrimRight", "", "123", ""},
+ {"TrimRight", "", "", ""},
+ {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
- actual := string(tc.f([]byte(tc.in), tc.cutset))
- var name string
- switch tc.f {
- case Trim:
- name = "Trim"
- case TrimLeft:
- name = "TrimLeft"
- case TrimRight:
- name = "TrimRight"
+ name := tc.f
+ var f func([]byte, string) []byte
+ switch name {
+ case "Trim":
+ f = Trim
+ case "TrimLeft":
+ f = TrimLeft
+ case "TrimRight":
+ f = TrimRight
default:
- t.Error("Undefined trim function")
+ t.Errorf("Undefined trim function %s", name)
}
+ actual := string(f([]byte(tc.in), tc.cutset))
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
}
@@ -711,7 +829,7 @@ func TestTrim(t *testing.T) {
}
type predicate struct {
- f func(r int) bool
+ f func(r rune) bool
name string
}
@@ -719,7 +837,7 @@ var isSpace = predicate{unicode.IsSpace, "IsSpace"}
var isDigit = predicate{unicode.IsDigit, "IsDigit"}
var isUpper = predicate{unicode.IsUpper, "IsUpper"}
var isValidRune = predicate{
- func(r int) bool {
+ func(r rune) bool {
return r != utf8.RuneError
},
"IsValidRune",
@@ -732,7 +850,7 @@ type TrimFuncTest struct {
func not(p predicate) predicate {
return predicate{
- func(r int) bool {
+ func(r rune) bool {
return !p.f(r)
},
"not " + p.name,
@@ -829,9 +947,15 @@ var ReplaceTests = []ReplaceTest{
func TestReplace(t *testing.T) {
for _, tt := range ReplaceTests {
- if s := string(Replace([]byte(tt.in), []byte(tt.old), []byte(tt.new), tt.n)); s != tt.out {
+ in := append([]byte(tt.in), "<spare>"...)
+ in = in[:len(tt.in)]
+ out := Replace(in, []byte(tt.old), []byte(tt.new), tt.n)
+ if s := string(out); s != tt.out {
t.Errorf("Replace(%q, %q, %q, %d) = %q, want %q", tt.in, tt.old, tt.new, tt.n, s, tt.out)
}
+ if cap(in) == cap(out) && &in[:1][0] == &out[:1][0] {
+ t.Errorf("Replace(%q, %q, %q, %d) didn't copy", tt.in, tt.old, tt.new, tt.n)
+ }
}
}
@@ -856,3 +980,31 @@ func TestTitle(t *testing.T) {
}
}
}
+
+var EqualFoldTests = []struct {
+ s, t string
+ out bool
+}{
+ {"abc", "abc", true},
+ {"ABcd", "ABcd", true},
+ {"123abc", "123ABC", true},
+ {"αβδ", "ΑΒΔ", true},
+ {"abc", "xyz", false},
+ {"abc", "XYZ", false},
+ {"abcdefghijk", "abcdefghijX", false},
+ {"abcdefghijk", "abcdefghij\u212A", true},
+ {"abcdefghijK", "abcdefghij\u212A", true},
+ {"abcdefghijkz", "abcdefghij\u212Ay", false},
+ {"abcdefghijKz", "abcdefghij\u212Ay", false},
+}
+
+func TestEqualFold(t *testing.T) {
+ for _, tt := range EqualFoldTests {
+ if out := EqualFold([]byte(tt.s), []byte(tt.t)); out != tt.out {
+ t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out)
+ }
+ if out := EqualFold([]byte(tt.t), []byte(tt.s)); out != tt.out {
+ t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/bytes/example_test.go b/src/pkg/bytes/example_test.go
new file mode 100644
index 000000000..6fe8cd5a9
--- /dev/null
+++ b/src/pkg/bytes/example_test.go
@@ -0,0 +1,28 @@
+// 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 bytes_test
+
+import (
+ . "bytes"
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+func ExampleBuffer() {
+ var b Buffer // A Buffer needs no initialization.
+ b.Write([]byte("Hello "))
+ b.Write([]byte("world!"))
+ b.WriteTo(os.Stdout)
+ // Output: Hello world!
+}
+
+func ExampleBuffer_reader() {
+ // A Buffer can turn a string or a []byte into an io.Reader.
+ buf := NewBufferString("R29waGVycyBydWxlIQ==")
+ dec := base64.NewDecoder(base64.StdEncoding, buf)
+ io.Copy(os.Stdout, dec)
+ // Output: Gophers rule!
+}
diff --git a/src/pkg/bytes/export_test.go b/src/pkg/bytes/export_test.go
index b65428d9c..f61523e60 100644
--- a/src/pkg/bytes/export_test.go
+++ b/src/pkg/bytes/export_test.go
@@ -6,3 +6,4 @@ package bytes
// Export func for testing
var IndexBytePortable = indexBytePortable
+var EqualPortable = equalPortable
diff --git a/src/pkg/bytes/reader.go b/src/pkg/bytes/reader.go
new file mode 100644
index 000000000..a062e54ba
--- /dev/null
+++ b/src/pkg/bytes/reader.go
@@ -0,0 +1,125 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+import (
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+// A Reader implements the io.Reader, io.ReaderAt, io.Seeker,
+// io.ByteScanner, and io.RuneScanner interfaces by reading from
+// a byte slice.
+// Unlike a Buffer, a Reader is read-only and supports seeking.
+type Reader struct {
+ s []byte
+ 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
+// slice.
+func (r *Reader) Len() int {
+ if r.i >= len(r.s) {
+ return 0
+ }
+ return len(r.s) - r.i
+}
+
+func (r *Reader) Read(b []byte) (n int, err error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
+ if r.i >= len(r.s) {
+ return 0, io.EOF
+ }
+ n = copy(b, r.s[r.i:])
+ r.i += n
+ r.prevRune = -1
+ return
+}
+
+func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ if off < 0 {
+ return 0, errors.New("bytes: invalid offset")
+ }
+ if off >= int64(len(r.s)) {
+ return 0, io.EOF
+ }
+ n = copy(b, r.s[int(off):])
+ if n < len(b) {
+ err = io.EOF
+ }
+ return
+}
+
+func (r *Reader) ReadByte() (b byte, err error) {
+ if r.i >= len(r.s) {
+ return 0, io.EOF
+ }
+ b = r.s[r.i]
+ r.i++
+ r.prevRune = -1
+ return
+}
+
+func (r *Reader) UnreadByte() error {
+ if r.i <= 0 {
+ return errors.New("bytes.Reader: at beginning of slice")
+ }
+ r.i--
+ r.prevRune = -1
+ return nil
+}
+
+func (r *Reader) ReadRune() (ch rune, size int, err error) {
+ if r.i >= len(r.s) {
+ return 0, 0, io.EOF
+ }
+ r.prevRune = r.i
+ if c := r.s[r.i]; c < utf8.RuneSelf {
+ r.i++
+ return rune(c), 1, nil
+ }
+ ch, size = utf8.DecodeRune(r.s[r.i:])
+ r.i += size
+ return
+}
+
+func (r *Reader) UnreadRune() error {
+ if r.prevRune < 0 {
+ return errors.New("bytes.Reader: previous operation was not ReadRune")
+ }
+ r.i = r.prevRune
+ r.prevRune = -1
+ return nil
+}
+
+// Seek implements the io.Seeker interface.
+func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ var abs int64
+ switch whence {
+ case 0:
+ abs = offset
+ case 1:
+ abs = int64(r.i) + offset
+ case 2:
+ abs = int64(len(r.s)) + offset
+ default:
+ return 0, errors.New("bytes: invalid whence")
+ }
+ if abs < 0 {
+ return 0, errors.New("bytes: negative position")
+ }
+ if abs >= 1<<31 {
+ return 0, errors.New("bytes: position out of range")
+ }
+ r.i = int(abs)
+ return abs, nil
+}
+
+// NewReader returns a new Reader reading from b.
+func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
diff --git a/src/pkg/bytes/reader_test.go b/src/pkg/bytes/reader_test.go
new file mode 100644
index 000000000..2e4b1f26e
--- /dev/null
+++ b/src/pkg/bytes/reader_test.go
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes_test
+
+import (
+ . "bytes"
+ "fmt"
+ "io"
+ "os"
+ "testing"
+)
+
+func TestReader(t *testing.T) {
+ r := NewReader([]byte("0123456789"))
+ tests := []struct {
+ off int64
+ seek int
+ n int
+ want string
+ wantpos int64
+ seekerr string
+ }{
+ {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
+ {seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"},
+ {seek: os.SEEK_SET, off: 1<<31 - 1},
+ {seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"},
+ {seek: os.SEEK_SET, n: 5, want: "01234"},
+ {seek: os.SEEK_CUR, n: 5, want: "56789"},
+ {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+ }
+
+ for i, tt := range tests {
+ pos, err := r.Seek(tt.off, tt.seek)
+ if err == nil && tt.seekerr != "" {
+ t.Errorf("%d. want seek error %q", i, tt.seekerr)
+ continue
+ }
+ if err != nil && err.Error() != tt.seekerr {
+ t.Errorf("%d. seek error = %q; want %q", i, err.Error(), tt.seekerr)
+ continue
+ }
+ if tt.wantpos != 0 && tt.wantpos != pos {
+ t.Errorf("%d. pos = %d, want %d", i, pos, tt.wantpos)
+ }
+ buf := make([]byte, tt.n)
+ n, err := r.Read(buf)
+ if err != nil {
+ t.Errorf("%d. read = %v", i, err)
+ continue
+ }
+ got := string(buf[:n])
+ if got != tt.want {
+ t.Errorf("%d. got %q; want %q", i, got, tt.want)
+ }
+ }
+}
+
+func TestReaderAt(t *testing.T) {
+ r := NewReader([]byte("0123456789"))
+ tests := []struct {
+ off int64
+ n int
+ want string
+ wanterr interface{}
+ }{
+ {0, 10, "0123456789", nil},
+ {1, 10, "123456789", io.EOF},
+ {1, 9, "123456789", nil},
+ {11, 10, "", io.EOF},
+ {0, 0, "", nil},
+ {-1, 0, "", "bytes: invalid offset"},
+ }
+ for i, tt := range tests {
+ b := make([]byte, tt.n)
+ rn, err := r.ReadAt(b, tt.off)
+ got := string(b[:rn])
+ if got != tt.want {
+ t.Errorf("%d. got %q; want %q", i, got, tt.want)
+ }
+ if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr)
+ }
+ }
+}
diff --git a/src/pkg/cmath/Makefile b/src/pkg/cmath/Makefile
deleted file mode 100644
index 486caace4..000000000
--- a/src/pkg/cmath/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=cmath
-
-GOFILES=\
- abs.go\
- asin.go\
- conj.go\
- exp.go\
- isinf.go\
- isnan.go\
- log.go\
- phase.go\
- polar.go\
- pow.go\
- rect.go\
- sin.go\
- sqrt.go\
- tan.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/compress/bzip2/Makefile b/src/pkg/compress/bzip2/Makefile
deleted file mode 100644
index a4bceef16..000000000
--- a/src/pkg/compress/bzip2/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../../Make.inc
-
-TARG=compress/bzip2
-GOFILES=\
- bit_reader.go\
- bzip2.go\
- huffman.go\
- move_to_front.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/compress/bzip2/bit_reader.go b/src/pkg/compress/bzip2/bit_reader.go
index 50f0ec836..b35c69a1c 100644
--- a/src/pkg/compress/bzip2/bit_reader.go
+++ b/src/pkg/compress/bzip2/bit_reader.go
@@ -7,25 +7,24 @@ package bzip2
import (
"bufio"
"io"
- "os"
)
// bitReader wraps an io.Reader and provides the ability to read values,
-// bit-by-bit, from it. Its Read* methods don't return the usual os.Error
+// bit-by-bit, from it. Its Read* methods don't return the usual error
// because the error handling was verbose. Instead, any error is kept and can
// be checked afterwards.
type bitReader struct {
r byteReader
n uint64
bits uint
- err os.Error
+ err error
}
-// bitReader needs to read bytes from an io.Reader. We attempt to cast the
+// bitReader needs to read bytes from an io.Reader. We attempt to convert the
// given io.Reader to this interface and, if it doesn't already fit, we wrap in
// a bufio.Reader.
type byteReader interface {
- ReadByte() (byte, os.Error)
+ ReadByte() (byte, error)
}
func newBitReader(r io.Reader) bitReader {
@@ -38,11 +37,11 @@ func newBitReader(r io.Reader) bitReader {
// ReadBits64 reads the given number of bits and returns them in the
// least-significant part of a uint64. In the event of an error, it returns 0
-// and the error can be obtained by calling Error().
+// and the error can be obtained by calling Err().
func (br *bitReader) ReadBits64(bits uint) (n uint64) {
for bits > br.bits {
b, err := br.r.ReadByte()
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
if err != nil {
@@ -83,6 +82,6 @@ func (br *bitReader) ReadBit() bool {
return n != 0
}
-func (br *bitReader) Error() os.Error {
+func (br *bitReader) Err() error {
return br.err
}
diff --git a/src/pkg/compress/bzip2/bzip2.go b/src/pkg/compress/bzip2/bzip2.go
index 8b4572306..3dc8c6206 100644
--- a/src/pkg/compress/bzip2/bzip2.go
+++ b/src/pkg/compress/bzip2/bzip2.go
@@ -5,10 +5,7 @@
// Package bzip2 implements bzip2 decompression.
package bzip2
-import (
- "io"
- "os"
-)
+import "io"
// There's no RFC for bzip2. I used the Wikipedia page for reference and a lot
// of guessing: http://en.wikipedia.org/wiki/Bzip2
@@ -19,7 +16,7 @@ import (
// syntactically invalid.
type StructuralError string
-func (s StructuralError) String() string {
+func (s StructuralError) Error() string {
return "bzip2 data invalid: " + string(s)
}
@@ -53,7 +50,7 @@ const bzip2BlockMagic = 0x314159265359
const bzip2FinalMagic = 0x177245385090
// setup parses the bzip2 header.
-func (bz2 *reader) setup() os.Error {
+func (bz2 *reader) setup() error {
br := &bz2.br
magic := br.ReadBits(16)
@@ -76,14 +73,14 @@ func (bz2 *reader) setup() os.Error {
return nil
}
-func (bz2 *reader) Read(buf []byte) (n int, err os.Error) {
+func (bz2 *reader) Read(buf []byte) (n int, err error) {
if bz2.eof {
- return 0, os.EOF
+ return 0, io.EOF
}
if !bz2.setupDone {
err = bz2.setup()
- brErr := bz2.br.Error()
+ brErr := bz2.br.Err()
if brErr != nil {
err = brErr
}
@@ -94,14 +91,14 @@ func (bz2 *reader) Read(buf []byte) (n int, err os.Error) {
}
n, err = bz2.read(buf)
- brErr := bz2.br.Error()
+ brErr := bz2.br.Err()
if brErr != nil {
err = brErr
}
return
}
-func (bz2 *reader) read(buf []byte) (n int, err os.Error) {
+func (bz2 *reader) read(buf []byte) (n int, err error) {
// bzip2 is a block based compressor, except that it has a run-length
// preprocessing step. The block based nature means that we can
// preallocate fixed-size buffers and reuse them. However, the RLE
@@ -162,7 +159,7 @@ func (bz2 *reader) read(buf []byte) (n int, err os.Error) {
if magic == bzip2FinalMagic {
br.ReadBits64(32) // ignored CRC
bz2.eof = true
- return 0, os.EOF
+ return 0, io.EOF
} else if magic != bzip2BlockMagic {
return 0, StructuralError("bad magic value found")
}
@@ -176,7 +173,7 @@ func (bz2 *reader) read(buf []byte) (n int, err os.Error) {
}
// readBlock reads a bzip2 block. The magic number should already have been consumed.
-func (bz2 *reader) readBlock() (err os.Error) {
+func (bz2 *reader) readBlock() (err error) {
br := &bz2.br
br.ReadBits64(32) // skip checksum. TODO: check it if we can figure out what it is.
randomized := br.ReadBits(1)
diff --git a/src/pkg/compress/bzip2/bzip2_test.go b/src/pkg/compress/bzip2/bzip2_test.go
index 156eea83f..7b227ac9f 100644
--- a/src/pkg/compress/bzip2/bzip2_test.go
+++ b/src/pkg/compress/bzip2/bzip2_test.go
@@ -9,7 +9,6 @@ import (
"encoding/hex"
"io"
"io/ioutil"
- "os"
"testing"
)
@@ -46,7 +45,7 @@ func readerFromHex(s string) io.Reader {
return bytes.NewBuffer(data)
}
-func decompressHex(s string) (out []byte, err os.Error) {
+func decompressHex(s string) (out []byte, err error) {
r := NewReader(readerFromHex(s))
return ioutil.ReadAll(r)
}
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
index dc05739c7..078c1cb89 100644
--- a/src/pkg/compress/bzip2/huffman.go
+++ b/src/pkg/compress/bzip2/huffman.go
@@ -4,10 +4,7 @@
package bzip2
-import (
- "os"
- "sort"
-)
+import "sort"
// A huffmanTree is a binary tree which is navigated, bit-by-bit to reach a
// symbol.
@@ -63,7 +60,7 @@ func (t huffmanTree) Decode(br *bitReader) (v uint16) {
// newHuffmanTree builds a Huffman tree from a slice containing the code
// lengths of each symbol. The maximum code length is 32 bits.
-func newHuffmanTree(lengths []uint8) (huffmanTree, os.Error) {
+func newHuffmanTree(lengths []uint8) (huffmanTree, error) {
// There are many possible trees that assign the same code length to
// each symbol (consider reflecting a tree down the middle, for
// example). Since the code length assignments determine the
@@ -176,7 +173,7 @@ func (n huffmanCodes) Swap(i, j int) {
// buildHuffmanNode takes a slice of sorted huffmanCodes and builds a node in
// the Huffman tree at the given level. It returns the index of the newly
// constructed node.
-func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIndex uint16, err os.Error) {
+func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIndex uint16, err error) {
test := uint32(1) << (31 - level)
// We have to search the list of codes to find the divide between the left and right sides.
diff --git a/src/pkg/compress/flate/Makefile b/src/pkg/compress/flate/Makefile
deleted file mode 100644
index 197828a92..000000000
--- a/src/pkg/compress/flate/Makefile
+++ /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.
-
-include ../../../Make.inc
-
-TARG=compress/flate
-GOFILES=\
- deflate.go\
- huffman_bit_writer.go\
- huffman_code.go\
- inflate.go\
- reverse_bits.go\
- token.go\
- util.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/compress/flate/deflate.go b/src/pkg/compress/flate/deflate.go
index b1cee0b2f..20408409c 100644
--- a/src/pkg/compress/flate/deflate.go
+++ b/src/pkg/compress/flate/deflate.go
@@ -5,9 +5,9 @@
package flate
import (
+ "fmt"
"io"
"math"
- "os"
)
const (
@@ -28,10 +28,12 @@ const (
// stop things from getting too large.
maxFlateBlockTokens = 1 << 14
maxStoreBlockSize = 65535
- hashBits = 15
+ hashBits = 17
hashSize = 1 << hashBits
hashMask = (1 << hashBits) - 1
hashShift = (hashBits + minMatchLength - 1) / minMatchLength
+
+ skipNever = math.MaxInt32
)
type compressionLevel struct {
@@ -46,12 +48,12 @@ var levels = []compressionLevel{
{3, 0, 32, 32, 6},
// Levels 4-9 use increasingly more lazy matching
// and increasingly stringent conditions for "good enough".
- {4, 4, 16, 16, math.MaxInt32},
- {8, 16, 32, 32, math.MaxInt32},
- {8, 16, 128, 128, math.MaxInt32},
- {8, 32, 128, 256, math.MaxInt32},
- {32, 128, 258, 1024, math.MaxInt32},
- {32, 258, 258, 4096, math.MaxInt32},
+ {4, 4, 16, 16, skipNever},
+ {8, 16, 32, 32, skipNever},
+ {8, 16, 128, 128, skipNever},
+ {8, 32, 128, 256, skipNever},
+ {32, 128, 258, 1024, skipNever},
+ {32, 258, 258, 4096, skipNever},
}
type compressor struct {
@@ -69,9 +71,10 @@ type compressor struct {
// If hashHead[hashValue] is within the current window, then
// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
// with the same hash value.
- chainHead int
- hashHead []int
- hashPrev []int
+ chainHead int
+ hashHead []int
+ hashPrev []int
+ hashOffset int
// input window: unprocessed data is window[index:windowEnd]
index int
@@ -80,16 +83,15 @@ type compressor struct {
blockStart int // window index where current tokens start
byteAvailable bool // if true, still need to process window[index-1].
- // queued output tokens: tokens[:ti]
+ // queued output tokens
tokens []token
- ti int
// deflate state
length int
offset int
hash int
maxInsertIndex int
- err os.Error
+ err error
}
func (d *compressor) fillDeflate(b []byte) int {
@@ -103,27 +105,14 @@ func (d *compressor) fillDeflate(b []byte) int {
} else {
d.blockStart = math.MaxInt32
}
- for i, h := range d.hashHead {
- v := h - windowSize
- if v < -1 {
- v = -1
- }
- d.hashHead[i] = v
- }
- for i, h := range d.hashPrev {
- v := -h - windowSize
- if v < -1 {
- v = -1
- }
- d.hashPrev[i] = v
- }
+ d.hashOffset += windowSize
}
n := copy(d.window[d.windowEnd:], b)
d.windowEnd += n
return n
}
-func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
+func (d *compressor) writeBlock(tokens []token, index int, eof bool) error {
if index > 0 || eof {
var window []byte
if d.blockStart <= index {
@@ -187,14 +176,14 @@ 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&windowMask]; i < minIndex || i < 0 {
+ if i = d.hashPrev[i&windowMask] - d.hashOffset; i < minIndex || i < 0 {
break
}
}
return
}
-func (d *compressor) writeStoredBlock(buf []byte) os.Error {
+func (d *compressor) writeStoredBlock(buf []byte) error {
if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
return d.w.err
}
@@ -206,13 +195,12 @@ func (d *compressor) initDeflate() {
d.hashHead = make([]int, hashSize)
d.hashPrev = make([]int, windowSize)
d.window = make([]byte, 2*windowSize)
- fillInts(d.hashHead, -1)
- d.tokens = make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1)
+ d.hashOffset = 1
+ d.tokens = make([]token, 0, maxFlateBlockTokens+1)
d.length = minMatchLength - 1
d.offset = 0
d.byteAvailable = false
d.index = 0
- d.ti = 0
d.hash = 0
d.chainHead = -1
}
@@ -244,15 +232,14 @@ Loop:
// Flush current output block if any.
if d.byteAvailable {
// There is still one pending token that needs to be flushed
- d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1]))
- d.ti++
+ d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1])))
d.byteAvailable = false
}
- if d.ti > 0 {
- if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.err != nil {
+ if len(d.tokens) > 0 {
+ if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
return
}
- d.ti = 0
+ d.tokens = d.tokens[:0]
}
break Loop
}
@@ -262,7 +249,7 @@ Loop:
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
+ d.hashHead[d.hash] = d.index + d.hashOffset
}
prevLength := d.length
prevOffset := d.offset
@@ -273,34 +260,33 @@ Loop:
minIndex = 0
}
- 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 {
+ if d.chainHead-d.hashOffset >= minIndex &&
+ (d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 ||
+ d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) {
+ if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok {
d.length = newLength
d.offset = newOffset
}
}
- if d.fastSkipHashing != 0 && d.length >= minMatchLength ||
- d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.length <= prevLength {
+ if d.fastSkipHashing != skipNever && d.length >= minMatchLength ||
+ d.fastSkipHashing == skipNever && 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 d.fastSkipHashing != 0 {
- d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize))
+ if d.fastSkipHashing != skipNever {
+ d.tokens = append(d.tokens, matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)))
} else {
- d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
+ d.tokens = append(d.tokens, matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)))
}
- 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 d.length <= d.fastSkipHashing {
var newIndex int
- if d.fastSkipHashing != 0 {
+ if d.fastSkipHashing != skipNever {
newIndex = d.index + d.length
} else {
- newIndex = prevLength - 1
+ newIndex = d.index + prevLength - 1
}
for d.index++; d.index < newIndex; d.index++ {
if d.index < d.maxInsertIndex {
@@ -309,10 +295,10 @@ Loop:
// Our chain should point to the previous value.
d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
// Set the head of the hash chain to us.
- d.hashHead[d.hash] = d.index
+ d.hashHead[d.hash] = d.index + d.hashOffset
}
}
- if d.fastSkipHashing == 0 {
+ if d.fastSkipHashing == skipNever {
d.byteAvailable = false
d.length = minMatchLength - 1
}
@@ -320,32 +306,33 @@ Loop:
// For matches this long, we don't bother inserting each individual
// item into the table.
d.index += d.length
- d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
+ if d.index < d.maxInsertIndex {
+ d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
+ }
}
- if d.ti == maxFlateBlockTokens {
+ if len(d.tokens) == maxFlateBlockTokens {
// The block includes the current character
if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
return
}
- d.ti = 0
+ d.tokens = d.tokens[:0]
}
} else {
- if d.fastSkipHashing != 0 || d.byteAvailable {
+ if d.fastSkipHashing != skipNever || d.byteAvailable {
i := d.index - 1
- if d.fastSkipHashing != 0 {
+ if d.fastSkipHashing != skipNever {
i = d.index
}
- d.tokens[d.ti] = literalToken(uint32(d.window[i]))
- d.ti++
- if d.ti == maxFlateBlockTokens {
+ d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
+ if len(d.tokens) == maxFlateBlockTokens {
if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
return
}
- d.ti = 0
+ d.tokens = d.tokens[:0]
}
}
d.index++
- if d.fastSkipHashing == 0 {
+ if d.fastSkipHashing == skipNever {
d.byteAvailable = true
}
}
@@ -365,7 +352,7 @@ func (d *compressor) store() {
d.windowEnd = 0
}
-func (d *compressor) write(b []byte) (n int, err os.Error) {
+func (d *compressor) write(b []byte) (n int, err error) {
n = len(b)
b = b[d.fill(d, b):]
for len(b) > 0 {
@@ -375,7 +362,7 @@ func (d *compressor) write(b []byte) (n int, err os.Error) {
return n, d.err
}
-func (d *compressor) syncFlush() os.Error {
+func (d *compressor) syncFlush() error {
d.sync = true
d.step(d)
if d.err == nil {
@@ -387,7 +374,7 @@ func (d *compressor) syncFlush() os.Error {
return d.err
}
-func (d *compressor) init(w io.Writer, level int) (err os.Error) {
+func (d *compressor) init(w io.Writer, level int) (err error) {
d.w = newHuffmanBitWriter(w)
switch {
@@ -404,12 +391,12 @@ func (d *compressor) init(w io.Writer, level int) (err os.Error) {
d.fill = (*compressor).fillDeflate
d.step = (*compressor).deflate
default:
- return WrongValueError{"level", 0, 9, int32(level)}
+ return fmt.Errorf("flate: invalid compression level %d: want value in range [-1, 9]", level)
}
return nil
}
-func (d *compressor) close() os.Error {
+func (d *compressor) close() error {
d.sync = true
d.step(d)
if d.err != nil {
@@ -422,17 +409,22 @@ func (d *compressor) close() os.Error {
return d.w.err
}
-// NewWriter returns a new Writer compressing
-// data at the given level. Following zlib, levels
-// range from 1 (BestSpeed) to 9 (BestCompression);
-// higher levels typically run slower but compress more.
-// Level 0 (NoCompression) does not attempt any
-// compression; it only adds the necessary DEFLATE framing.
-func NewWriter(w io.Writer, level int) *Writer {
+// NewWriter returns a new Writer compressing data at the given level.
+// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
+// higher levels typically run slower but compress more. Level 0
+// (NoCompression) does not attempt any compression; it only adds the
+// necessary DEFLATE framing. Level -1 (DefaultCompression) uses the default
+// compression level.
+//
+// If level is in the range [-1, 9] then the error returned will be nil.
+// Otherwise the error returned will be non-nil.
+func NewWriter(w io.Writer, level int) (*Writer, error) {
const logWindowSize = logMaxOffsetSize
var dw Writer
- dw.d.init(w, level)
- return &dw
+ if err := dw.d.init(w, level); err != nil {
+ return nil, err
+ }
+ return &dw, nil
}
// NewWriterDict is like NewWriter but initializes the new
@@ -441,13 +433,16 @@ func NewWriter(w io.Writer, level int) *Writer {
// any compressed output. The compressed data written to w
// can only be decompressed by a Reader initialized with the
// same dictionary.
-func NewWriterDict(w io.Writer, level int, dict []byte) *Writer {
+func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
dw := &dictWriter{w, false}
- zw := NewWriter(dw, level)
+ zw, err := NewWriter(dw, level)
+ if err != nil {
+ return nil, err
+ }
zw.Write(dict)
zw.Flush()
dw.enabled = true
- return zw
+ return zw, err
}
type dictWriter struct {
@@ -455,7 +450,7 @@ type dictWriter struct {
enabled bool
}
-func (w *dictWriter) Write(b []byte) (n int, err os.Error) {
+func (w *dictWriter) Write(b []byte) (n int, err error) {
if w.enabled {
return w.w.Write(b)
}
@@ -470,7 +465,7 @@ type Writer struct {
// 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) {
+func (w *Writer) Write(data []byte) (n int, err error) {
return w.d.write(data)
}
@@ -481,13 +476,13 @@ func (w *Writer) Write(data []byte) (n int, err os.Error) {
// If the underlying writer returns an error, Flush returns that error.
//
// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
-func (w *Writer) Flush() os.Error {
+func (w *Writer) Flush() error {
// For more about flushing:
// http://www.bolet.org/~pornin/deflate-flush.html
return w.d.syncFlush()
}
// Close flushes and closes the writer.
-func (w *Writer) Close() os.Error {
+func (w *Writer) Close() error {
return w.d.close()
}
diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go
index 930823685..543c59505 100644
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "os"
"sync"
"testing"
)
@@ -31,44 +30,44 @@ type reverseBitsTest struct {
}
var deflateTests = []*deflateTest{
- &deflateTest{[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
-
- &deflateTest{[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
+ {[]byte{}, 0, []byte{1, 0, 0, 255, 255}},
+ {[]byte{0x11}, -1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ {[]byte{0x11}, DefaultCompression, []byte{18, 4, 4, 0, 0, 255, 255}},
+ {[]byte{0x11}, 4, []byte{18, 4, 4, 0, 0, 255, 255}},
+
+ {[]byte{0x11}, 0, []byte{0, 1, 0, 254, 255, 17, 1, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x12}, 0, []byte{0, 2, 0, 253, 255, 17, 18, 1, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
[]byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
},
- &deflateTest{[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
- &deflateTest{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
- &deflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+ {[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
+ {[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+ {[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
+ {[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+ {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
}
var deflateInflateTests = []*deflateInflateTest{
- &deflateInflateTest{[]byte{}},
- &deflateInflateTest{[]byte{0x11}},
- &deflateInflateTest{[]byte{0x11, 0x12}},
- &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
- &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
- &deflateInflateTest{largeDataChunk()},
+ {[]byte{}},
+ {[]byte{0x11}},
+ {[]byte{0x11, 0x12}},
+ {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ {[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}},
+ {largeDataChunk()},
}
var reverseBitsTests = []*reverseBitsTest{
- &reverseBitsTest{1, 1, 1},
- &reverseBitsTest{1, 2, 2},
- &reverseBitsTest{1, 3, 4},
- &reverseBitsTest{1, 4, 8},
- &reverseBitsTest{1, 5, 16},
- &reverseBitsTest{17, 5, 17},
- &reverseBitsTest{257, 9, 257},
- &reverseBitsTest{29, 5, 23},
+ {1, 1, 1},
+ {1, 2, 2},
+ {1, 3, 4},
+ {1, 4, 8},
+ {1, 5, 16},
+ {17, 5, 17},
+ {257, 9, 257},
+ {29, 5, 23},
}
func largeDataChunk() []byte {
@@ -82,7 +81,11 @@ func largeDataChunk() []byte {
func TestDeflate(t *testing.T) {
for _, h := range deflateTests {
var buf bytes.Buffer
- w := NewWriter(&buf, h.level)
+ w, err := NewWriter(&buf, h.level)
+ if err != nil {
+ t.Errorf("NewWriter: %v", err)
+ continue
+ }
w.Write(h.in)
w.Close()
if !bytes.Equal(buf.Bytes(), h.out) {
@@ -102,7 +105,7 @@ func newSyncBuffer() *syncBuffer {
return &syncBuffer{ready: make(chan bool, 1)}
}
-func (b *syncBuffer) Read(p []byte) (n int, err os.Error) {
+func (b *syncBuffer) Read(p []byte) (n int, err error) {
for {
b.mu.RLock()
n, err = b.buf.Read(p)
@@ -122,7 +125,7 @@ func (b *syncBuffer) signal() {
}
}
-func (b *syncBuffer) Write(p []byte) (n int, err os.Error) {
+func (b *syncBuffer) Write(p []byte) (n int, err error) {
n, err = b.buf.Write(p)
b.signal()
return
@@ -137,7 +140,7 @@ func (b *syncBuffer) ReadMode() {
b.signal()
}
-func (b *syncBuffer) Close() os.Error {
+func (b *syncBuffer) Close() error {
b.closed = true
b.signal()
return nil
@@ -152,7 +155,11 @@ func testSync(t *testing.T, level int, input []byte, name string) {
buf := newSyncBuffer()
buf1 := new(bytes.Buffer)
buf.WriteMode()
- w := NewWriter(io.MultiWriter(buf, buf1), level)
+ w, err := NewWriter(io.MultiWriter(buf, buf1), level)
+ if err != nil {
+ t.Errorf("NewWriter: %v", err)
+ return
+ }
r := NewReader(buf)
// Write half the input and read back.
@@ -204,7 +211,7 @@ func testSync(t *testing.T, level int, input []byte, name string) {
}
buf.ReadMode()
out := make([]byte, 10)
- if n, err := r.Read(out); n > 0 || err != os.EOF {
+ if n, err := r.Read(out); n > 0 || err != io.EOF {
t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
}
if buf.buf.Len() != 0 {
@@ -214,7 +221,7 @@ func testSync(t *testing.T, level int, input []byte, name string) {
// stream should work for ordinary reader too
r = NewReader(buf1)
- out, err := ioutil.ReadAll(r)
+ out, err = ioutil.ReadAll(r)
if err != nil {
t.Errorf("testSync: read: %s", err)
return
@@ -225,35 +232,42 @@ 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)
+func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) {
+ var buffer bytes.Buffer
+ w, err := NewWriter(&buffer, level)
+ if err != nil {
+ t.Errorf("NewWriter: %v", err)
+ return
+ }
w.Write(input)
w.Close()
- r := NewReader(buffer)
+ if limit > 0 && buffer.Len() > limit {
+ t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
+ return
+ }
+ r := NewReader(&buffer)
out, err := ioutil.ReadAll(r)
if err != nil {
t.Errorf("read: %s", err)
- return err
+ return
}
r.Close()
if !bytes.Equal(input, out) {
t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
+ return
}
-
testSync(t, level, input, name)
- return nil
}
-func testToFrom(t *testing.T, input []byte, name string) {
+func testToFromWithLimit(t *testing.T, input []byte, name string, limit [10]int) {
for i := 0; i < 10; i++ {
- testToFromWithLevel(t, i, input, name)
+ testToFromWithLevelAndLimit(t, i, input, name, limit[i])
}
}
func TestDeflateInflate(t *testing.T) {
for i, h := range deflateInflateTests {
- testToFrom(t, h.in, fmt.Sprintf("#%d", i))
+ testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [10]int{})
}
}
@@ -266,12 +280,36 @@ func TestReverseBits(t *testing.T) {
}
}
+type deflateInflateStringTest struct {
+ filename string
+ label string
+ limit [10]int
+}
+
+var deflateInflateStringTests = []deflateInflateStringTest{
+ {
+ "../testdata/e.txt",
+ "2.718281828...",
+ [...]int{10013, 5065, 5096, 5115, 5093, 5079, 5079, 5079, 5079, 5079},
+ },
+ {
+ "../testdata/Mark.Twain-Tom.Sawyer.txt",
+ "Mark.Twain-Tom.Sawyer",
+ [...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295},
+ },
+}
+
func TestDeflateInflateString(t *testing.T) {
- gold, err := ioutil.ReadFile("../testdata/e.txt")
- if err != nil {
- t.Error(err)
+ for _, test := range deflateInflateStringTests {
+ gold, err := ioutil.ReadFile(test.filename)
+ if err != nil {
+ t.Error(err)
+ }
+ testToFromWithLimit(t, gold, test.label, test.limit)
+ if testing.Short() {
+ break
+ }
}
- testToFromWithLevel(t, 1, gold, "2.718281828...")
}
func TestReaderDict(t *testing.T) {
@@ -280,7 +318,10 @@ func TestReaderDict(t *testing.T) {
text = "hello again world"
)
var b bytes.Buffer
- w := NewWriter(&b, 5)
+ w, err := NewWriter(&b, 5)
+ if err != nil {
+ t.Fatalf("NewWriter: %v", err)
+ }
w.Write([]byte(dict))
w.Flush()
b.Reset()
@@ -303,7 +344,10 @@ func TestWriterDict(t *testing.T) {
text = "hello again world"
)
var b bytes.Buffer
- w := NewWriter(&b, 5)
+ w, err := NewWriter(&b, 5)
+ if err != nil {
+ t.Fatalf("NewWriter: %v", err)
+ }
w.Write([]byte(dict))
w.Flush()
b.Reset()
@@ -311,7 +355,7 @@ func TestWriterDict(t *testing.T) {
w.Close()
var b1 bytes.Buffer
- w = NewWriterDict(&b1, 5, []byte(dict))
+ w, _ = NewWriterDict(&b1, 5, []byte(dict))
w.Write([]byte(text))
w.Close()
@@ -319,3 +363,22 @@ func TestWriterDict(t *testing.T) {
t.Fatalf("writer wrote %q want %q", b1.Bytes(), b.Bytes())
}
}
+
+// See http://code.google.com/p/go/issues/detail?id=2508
+func TestRegression2508(t *testing.T) {
+ if testing.Short() {
+ t.Logf("test disabled with -short")
+ return
+ }
+ w, err := NewWriter(ioutil.Discard, 1)
+ if err != nil {
+ t.Fatalf("NewWriter: %v", err)
+ }
+ buf := make([]byte, 1024)
+ for i := 0; i < 131072; i++ {
+ if _, err := w.Write(buf); err != nil {
+ t.Fatalf("writer failed: %v", err)
+ }
+ }
+ w.Close()
+}
diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go
index bfd3b8381..94efc90ac 100644
--- a/src/pkg/compress/flate/flate_test.go
+++ b/src/pkg/compress/flate/flate_test.go
@@ -52,7 +52,7 @@ type InitDecoderTest struct {
var initDecoderTests = []*InitDecoderTest{
// Example from Connell 1973,
- &InitDecoderTest{
+ {
[]int{3, 5, 2, 4, 3, 5, 5, 4, 4, 3, 4, 5},
huffmanDecoder{
2, 5,
@@ -68,7 +68,7 @@ var initDecoderTests = []*InitDecoderTest{
},
// Example from RFC 1951 section 3.2.2
- &InitDecoderTest{
+ {
[]int{2, 1, 3, 3},
huffmanDecoder{
1, 3,
@@ -80,7 +80,7 @@ var initDecoderTests = []*InitDecoderTest{
},
// Second example from RFC 1951 section 3.2.2
- &InitDecoderTest{
+ {
[]int{3, 3, 3, 3, 3, 2, 4, 4},
huffmanDecoder{
2, 4,
@@ -92,21 +92,21 @@ var initDecoderTests = []*InitDecoderTest{
},
// Static Huffman codes (RFC 1951 section 3.2.6)
- &InitDecoderTest{
+ {
fixedHuffmanBits[0:],
fixedHuffmanDecoder,
true,
},
// Illegal input.
- &InitDecoderTest{
+ {
[]int{},
huffmanDecoder{},
false,
},
// Illegal input.
- &InitDecoderTest{
+ {
[]int{0, 0, 0, 0, 0, 0, 0},
huffmanDecoder{},
false,
diff --git a/src/pkg/compress/flate/huffman_bit_writer.go b/src/pkg/compress/flate/huffman_bit_writer.go
index 3981df5cb..25e1da336 100644
--- a/src/pkg/compress/flate/huffman_bit_writer.go
+++ b/src/pkg/compress/flate/huffman_bit_writer.go
@@ -7,8 +7,6 @@ package flate
import (
"io"
"math"
- "os"
- "strconv"
)
const (
@@ -83,14 +81,7 @@ type huffmanBitWriter struct {
literalEncoding *huffmanEncoder
offsetEncoding *huffmanEncoder
codegenEncoding *huffmanEncoder
- err os.Error
-}
-
-type WrongValueError struct {
- name string
- from int32
- to int32
- value int32
+ err error
}
func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
@@ -106,11 +97,6 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
}
}
-func (err WrongValueError) String() string {
- return "huffmanBitWriter: " + err.name + " should belong to [" + strconv.Itoa64(int64(err.from)) + ";" +
- strconv.Itoa64(int64(err.to)) + "] but actual value is " + strconv.Itoa64(int64(err.value))
-}
-
func (w *huffmanBitWriter) flushBits() {
if w.err != nil {
w.nbits = 0
@@ -194,15 +180,17 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
// numLiterals The number of literals in literalEncoding
// numOffsets The number of offsets in offsetEncoding
func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
- fillInt32s(w.codegenFreq, 0)
+ for i := range w.codegenFreq {
+ w.codegenFreq[i] = 0
+ }
// Note that we are using codegen both as a temporary variable for holding
// a copy of the frequencies, and as the place where we put the result.
// This is fine because the output is always shorter than the input used
// so far.
codegen := w.codegen // cache
// Copy the concatenated code sizes to codegen. Put a marker at the end.
- copyUint8s(codegen[0:numLiterals], w.literalEncoding.codeBits)
- copyUint8s(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+ copy(codegen[0:numLiterals], w.literalEncoding.codeBits)
+ copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
codegen[numLiterals+numOffsets] = badCode
size := codegen[0]
@@ -223,7 +211,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
w.codegenFreq[size]++
count--
for count >= 3 {
- n := min(count, 6)
+ n := 6
+ if n > count {
+ n = count
+ }
codegen[outIndex] = 16
outIndex++
codegen[outIndex] = uint8(n - 3)
@@ -233,7 +224,10 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
}
} else {
for count >= 11 {
- n := min(count, 138)
+ n := 138
+ if n > count {
+ n = count
+ }
codegen[outIndex] = 18
outIndex++
codegen[outIndex] = uint8(n - 11)
@@ -352,8 +346,12 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
if w.err != nil {
return
}
- fillInt32s(w.literalFreq, 0)
- fillInt32s(w.offsetFreq, 0)
+ for i := range w.literalFreq {
+ w.literalFreq[i] = 0
+ }
+ for i := range w.offsetFreq {
+ w.offsetFreq[i] = 0
+ }
n := len(tokens)
tokens = tokens[0 : n+1]
diff --git a/src/pkg/compress/flate/huffman_code.go b/src/pkg/compress/flate/huffman_code.go
index 7ed603a4f..009cce626 100644
--- a/src/pkg/compress/flate/huffman_code.go
+++ b/src/pkg/compress/flate/huffman_code.go
@@ -121,61 +121,6 @@ func (h *huffmanEncoder) bitLength(freq []int32) int64 {
return total
}
-// Generate elements in the chain using an iterative algorithm.
-func (h *huffmanEncoder) generateChains(top *levelInfo, list []literalNode) {
- n := len(list)
- list = list[0 : n+1]
- list[n] = maxNode()
-
- l := top
- for {
- if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
- // We've run out of both leafs and pairs.
- // End all calculations for this level.
- // To m sure we never come back to this level or any lower level,
- // set nextPairFreq impossibly large.
- l.lastChain = nil
- l.needed = 0
- l = l.up
- l.nextPairFreq = math.MaxInt32
- continue
- }
-
- prevFreq := l.lastChain.freq
- if l.nextCharFreq < l.nextPairFreq {
- // The next item on this row is a leaf node.
- n := l.lastChain.leafCount + 1
- l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
- l.nextCharFreq = list[n].freq
- } else {
- // The next item on this row is a pair from the previous row.
- // nextPairFreq isn't valid until we generate two
- // more values in the level below
- l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
- l.down.needed = 2
- }
-
- if l.needed--; l.needed == 0 {
- // We've done everything we need to do for this level.
- // Continue calculating one level up. Fill in nextPairFreq
- // of that level with the sum of the two nodes we've just calculated on
- // this level.
- up := l.up
- if up == nil {
- // All done!
- return
- }
- up.nextPairFreq = prevFreq + l.lastChain.freq
- l = up
- } else {
- // If we stole from below, move down temporarily to replenish it.
- for l.down.needed > 0 {
- l = l.down
- }
- }
- }
-}
-
// Return the number of literals assigned to each bit size in the Huffman encoding
//
// This method is only called when list.length >= 3
@@ -195,7 +140,9 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
// The tree can't have greater depth than n - 1, no matter what. This
// saves a little bit of work in some small cases
- maxBits = minInt32(maxBits, n-1)
+ if maxBits > n-1 {
+ maxBits = n - 1
+ }
// Create information about each of the levels.
// A bogus "Level 0" whose sole purpose is so that
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index 3845f1204..3f2042bfe 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -10,7 +10,6 @@ package flate
import (
"bufio"
"io"
- "os"
"strconv"
)
@@ -25,33 +24,33 @@ const (
// A CorruptInputError reports the presence of corrupt input at a given offset.
type CorruptInputError int64
-func (e CorruptInputError) String() string {
- return "flate: corrupt input before offset " + strconv.Itoa64(int64(e))
+func (e CorruptInputError) Error() string {
+ return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10)
}
// An InternalError reports an error in the flate code itself.
type InternalError string
-func (e InternalError) String() string { return "flate: internal error: " + string(e) }
+func (e InternalError) Error() string { return "flate: internal error: " + string(e) }
// A ReadError reports an error encountered while reading input.
type ReadError struct {
- Offset int64 // byte offset where error occurred
- Error os.Error // error returned by underlying Read
+ Offset int64 // byte offset where error occurred
+ Err error // error returned by underlying Read
}
-func (e *ReadError) String() string {
- return "flate: read error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+func (e *ReadError) Error() string {
+ return "flate: read error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
}
// A WriteError reports an error encountered while writing output.
type WriteError struct {
- Offset int64 // byte offset where error occurred
- Error os.Error // error returned by underlying Write
+ Offset int64 // byte offset where error occurred
+ Err error // error returned by underlying Write
}
-func (e *WriteError) String() string {
- return "flate: write error at offset " + strconv.Itoa64(e.Offset) + ": " + e.Error.String()
+func (e *WriteError) Error() string {
+ return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
}
// Huffman decoder is based on
@@ -190,7 +189,7 @@ var fixedHuffmanDecoder = huffmanDecoder{
// the NewReader will introduce its own buffering.
type Reader interface {
io.Reader
- ReadByte() (c byte, err os.Error)
+ ReadByte() (c byte, err error)
}
// Decompress state.
@@ -224,7 +223,7 @@ type decompressor struct {
// and decompression state.
step func(*decompressor)
final bool
- err os.Error
+ err error
toRead []byte
hl, hd *huffmanDecoder
copyLen int
@@ -237,7 +236,7 @@ func (f *decompressor) nextBlock() {
f.flush((*decompressor).nextBlock)
return
}
- f.err = os.EOF
+ f.err = io.EOF
return
}
for f.nb < 1+2 {
@@ -272,7 +271,7 @@ func (f *decompressor) nextBlock() {
}
}
-func (f *decompressor) Read(b []byte) (int, os.Error) {
+func (f *decompressor) Read(b []byte) (int, error) {
for {
if len(f.toRead) > 0 {
n := copy(b, f.toRead)
@@ -287,8 +286,8 @@ func (f *decompressor) Read(b []byte) (int, os.Error) {
panic("unreachable")
}
-func (f *decompressor) Close() os.Error {
- if f.err == os.EOF {
+func (f *decompressor) Close() error {
+ if f.err == io.EOF {
return nil
}
return f.err
@@ -299,7 +298,7 @@ func (f *decompressor) Close() os.Error {
var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
-func (f *decompressor) readHuffman() os.Error {
+func (f *decompressor) readHuffman() error {
// HLIT[5], HDIST[5], HCLEN[4].
for f.nb < 5+5+4 {
if err := f.moreBits(); err != nil {
@@ -625,10 +624,10 @@ func (f *decompressor) setDict(dict []byte) {
f.hw = f.hp
}
-func (f *decompressor) moreBits() os.Error {
+func (f *decompressor) moreBits() error {
c, err := f.r.ReadByte()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
@@ -640,7 +639,7 @@ func (f *decompressor) moreBits() os.Error {
}
// Read the next Huffman-encoded symbol from f according to h.
-func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
+func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
for n := uint(h.min); n <= uint(h.max); n++ {
lim := h.limit[n]
if lim == -1 {
diff --git a/src/pkg/compress/flate/util.go b/src/pkg/compress/flate/util.go
deleted file mode 100644
index aca5c78b2..000000000
--- a/src/pkg/compress/flate/util.go
+++ /dev/null
@@ -1,72 +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 flate
-
-func min(left int, right int) int {
- if left < right {
- return left
- }
- return right
-}
-
-func minInt32(left int32, right int32) int32 {
- if left < right {
- return left
- }
- return right
-}
-
-func max(left int, right int) int {
- if left > right {
- return left
- }
- return right
-}
-
-func fillInts(a []int, value int) {
- for i := range a {
- a[i] = value
- }
-}
-
-func fillInt32s(a []int32, value int32) {
- for i := range a {
- a[i] = value
- }
-}
-
-func fillBytes(a []byte, value byte) {
- for i := range a {
- a[i] = value
- }
-}
-
-func fillInt8s(a []int8, value int8) {
- for i := range a {
- a[i] = value
- }
-}
-
-func fillUint8s(a []uint8, value uint8) {
- for i := range a {
- a[i] = value
- }
-}
-
-func copyInt8s(dst []int8, src []int8) int {
- cnt := min(len(dst), len(src))
- for i := 0; i < cnt; i++ {
- dst[i] = src[i]
- }
- return cnt
-}
-
-func copyUint8s(dst []uint8, src []uint8) int {
- cnt := min(len(dst), len(src))
- for i := 0; i < cnt; i++ {
- dst[i] = src[i]
- }
- return cnt
-}
diff --git a/src/pkg/compress/gzip/Makefile b/src/pkg/compress/gzip/Makefile
deleted file mode 100644
index b671fc72c..000000000
--- a/src/pkg/compress/gzip/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=compress/gzip
-GOFILES=\
- gunzip.go\
- gzip.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index 6ac9293d7..33736f635 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -9,15 +9,13 @@ package gzip
import (
"bufio"
"compress/flate"
+ "errors"
"hash"
"hash/crc32"
"io"
- "os"
+ "time"
)
-// BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of
-// the 0x00-0x7f range to ISO 8859-1 (Latin-1).
-
const (
gzipID1 = 0x1f
gzipID2 = 0x8b
@@ -36,34 +34,38 @@ func makeReader(r io.Reader) flate.Reader {
return bufio.NewReader(r)
}
-var HeaderError = os.NewError("invalid gzip header")
-var ChecksumError = os.NewError("gzip checksum error")
+var (
+ // ErrChecksum is returned when reading GZIP data that has an invalid checksum.
+ ErrChecksum = errors.New("gzip: invalid checksum")
+ // ErrHeader is returned when reading GZIP data that has an invalid header.
+ ErrHeader = errors.New("gzip: invalid header")
+)
// 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.
+// That header is exposed as the fields of the Writer and Reader structs.
type Header struct {
- Comment string // comment
- Extra []byte // "extra data"
- Mtime uint32 // modification time (seconds since January 1, 1970)
- Name string // file name
- OS byte // operating system type
+ Comment string // comment
+ Extra []byte // "extra data"
+ ModTime time.Time // modification time
+ Name string // file name
+ OS byte // operating system type
}
-// An Decompressor is an io.Reader that can be read to retrieve
+// A Reader is an io.Reader that can be read to retrieve
// uncompressed data from a gzip-format compressed file.
//
// In general, a gzip file can be a concatenation of gzip files,
-// each with its own header. Reads from the Decompressor
+// each with its own header. Reads from the Reader
// return the concatenation of the uncompressed data of each.
-// Only the first header is recorded in the Decompressor fields.
+// Only the first header is recorded in the Reader fields.
//
// Gzip files store a length and checksum of the uncompressed data.
-// The Decompressor will return a ChecksumError when Read
+// The Reader will return a ErrChecksum when Read
// reaches the end of the uncompressed data if it does not
// have the expected length or checksum. Clients should treat data
-// returned by Read as tentative until they receive the successful
-// (zero length, nil error) Read marking the end of the data.
-type Decompressor struct {
+// returned by Read as tentative until they receive the io.EOF
+// marking the end of the data.
+type Reader struct {
Header
r flate.Reader
decompressor io.ReadCloser
@@ -71,18 +73,17 @@ type Decompressor struct {
size uint32
flg byte
buf [512]byte
- err os.Error
+ err error
}
-// NewReader creates a new Decompressor reading the given reader.
+// NewReader creates a new Reader reading the given reader.
// The implementation buffers input and may read more data than necessary from r.
-// It is the caller's responsibility to call Close on the Decompressor when done.
-func NewReader(r io.Reader) (*Decompressor, os.Error) {
- z := new(Decompressor)
+// It is the caller's responsibility to call Close on the Reader when done.
+func NewReader(r io.Reader) (*Reader, error) {
+ z := new(Reader)
z.r = makeReader(r)
z.digest = crc32.NewIEEE()
if err := z.readHeader(true); err != nil {
- z.err = err
return nil, err
}
return z, nil
@@ -93,26 +94,36 @@ func get4(p []byte) uint32 {
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
}
-func (z *Decompressor) readString() (string, os.Error) {
- var err os.Error
+func (z *Reader) readString() (string, error) {
+ var err error
+ needconv := false
for i := 0; ; i++ {
if i >= len(z.buf) {
- return "", HeaderError
+ return "", ErrHeader
}
z.buf[i], err = z.r.ReadByte()
if err != nil {
return "", err
}
+ if z.buf[i] > 0x7f {
+ needconv = true
+ }
if z.buf[i] == 0 {
// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
- // TODO(nigeltao): Convert from ISO 8859-1 (Latin-1) to UTF-8.
+ if needconv {
+ s := make([]rune, 0, i)
+ for _, v := range z.buf[0:i] {
+ s = append(s, rune(v))
+ }
+ return string(s), nil
+ }
return string(z.buf[0:i]), nil
}
}
panic("not reached")
}
-func (z *Decompressor) read2() (uint32, os.Error) {
+func (z *Reader) read2() (uint32, error) {
_, err := io.ReadFull(z.r, z.buf[0:2])
if err != nil {
return 0, err
@@ -120,17 +131,17 @@ func (z *Decompressor) read2() (uint32, os.Error) {
return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
}
-func (z *Decompressor) readHeader(save bool) os.Error {
+func (z *Reader) readHeader(save bool) error {
_, err := io.ReadFull(z.r, z.buf[0:10])
if err != nil {
return err
}
if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
- return HeaderError
+ return ErrHeader
}
z.flg = z.buf[3]
if save {
- z.Mtime = get4(z.buf[4:8])
+ z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0)
// z.buf[8] is xfl, ignored
z.OS = z.buf[9]
}
@@ -177,7 +188,7 @@ func (z *Decompressor) readHeader(save bool) os.Error {
}
sum := z.digest.Sum32() & 0xFFFF
if n != sum {
- return HeaderError
+ return ErrHeader
}
}
@@ -186,7 +197,7 @@ func (z *Decompressor) readHeader(save bool) os.Error {
return nil
}
-func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
+func (z *Reader) Read(p []byte) (n int, err error) {
if z.err != nil {
return 0, z.err
}
@@ -197,7 +208,7 @@ func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
n, err = z.decompressor.Read(p)
z.digest.Write(p[0:n])
z.size += uint32(n)
- if n != 0 || err != os.EOF {
+ if n != 0 || err != io.EOF {
z.err = err
return
}
@@ -210,7 +221,7 @@ func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
sum := z.digest.Sum32()
if sum != crc32 || isize != z.size {
- z.err = ChecksumError
+ z.err = ErrChecksum
return 0, z.err
}
@@ -226,5 +237,5 @@ func (z *Decompressor) Read(p []byte) (n int, err os.Error) {
return z.Read(p)
}
-// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
-func (z *Decompressor) Close() os.Error { return z.decompressor.Close() }
+// Close closes the Reader. It does not close the underlying io.Reader.
+func (z *Reader) Close() error { return z.decompressor.Close() }
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
index 1c08c7374..a1333580d 100644
--- a/src/pkg/compress/gzip/gunzip_test.go
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -7,7 +7,6 @@ package gzip
import (
"bytes"
"io"
- "os"
"testing"
)
@@ -16,7 +15,7 @@ type gunzipTest struct {
desc string
raw string
gzip []byte
- err os.Error
+ err error
}
var gunzipTests = []gunzipTest{
@@ -233,7 +232,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0x0c, 0x00,
0x00, 0x00, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', '!', '!',
},
- HeaderError,
+ ErrHeader,
},
{ // has 1 non-empty fixed huffman block not enough header
"hello.txt",
@@ -261,7 +260,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00,
0x00, 0x00,
},
- ChecksumError,
+ ErrChecksum,
},
{ // has 1 non-empty fixed huffman block but corrupt size
"hello.txt",
@@ -275,7 +274,7 @@ var gunzipTests = []gunzipTest{
0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, 0xff, 0x00,
0x00, 0x00,
},
- ChecksumError,
+ ErrChecksum,
},
}
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
index 8860d10af..3035dfffc 100644
--- a/src/pkg/compress/gzip/gzip.go
+++ b/src/pkg/compress/gzip/gzip.go
@@ -6,10 +6,11 @@ package gzip
import (
"compress/flate"
+ "errors"
+ "fmt"
"hash"
"hash/crc32"
"io"
- "os"
)
// These constants are copied from the flate package, so that code that imports
@@ -21,9 +22,9 @@ const (
DefaultCompression = flate.DefaultCompression
)
-// A Compressor is an io.WriteCloser that satisfies writes by compressing data written
+// A Writer is an io.WriteCloser that satisfies writes by compressing data written
// to its wrapped io.Writer.
-type Compressor struct {
+type Writer struct {
Header
w io.Writer
level int
@@ -32,28 +33,43 @@ type Compressor struct {
size uint32
closed bool
buf [10]byte
- err os.Error
+ err error
}
-// NewWriter calls NewWriterLevel with the default compression level.
-func NewWriter(w io.Writer) (*Compressor, os.Error) {
- return NewWriterLevel(w, DefaultCompression)
+// NewWriter creates a new Writer that satisfies writes by compressing data
+// written to w.
+//
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// Writes may be buffered and not flushed until Close.
+//
+// Callers that wish to set the fields in Writer.Header must do so before
+// the first call to Write or Close. The Comment and Name header fields are
+// UTF-8 strings in Go, but the underlying format requires NUL-terminated ISO
+// 8859-1 (Latin-1). NUL or non-Latin-1 runes in those strings will lead to an
+// error on Write.
+func NewWriter(w io.Writer) *Writer {
+ z, _ := NewWriterLevel(w, DefaultCompression)
+ return z
}
-// NewWriterLevel creates a new Compressor writing to the given writer.
-// Writes may be buffered and not flushed until Close.
-// Callers that wish to set the fields in Compressor.Header must
-// do so before the first call to Write or Close.
-// It is the caller's responsibility to call Close on the WriteCloser when done.
-// level is the compression level, which can be DefaultCompression, NoCompression,
-// or any integer value between BestSpeed and BestCompression (inclusive).
-func NewWriterLevel(w io.Writer, level int) (*Compressor, os.Error) {
- z := new(Compressor)
- z.OS = 255 // unknown
- z.w = w
- z.level = level
- z.digest = crc32.NewIEEE()
- return z, nil
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+//
+// The compression level can be DefaultCompression, NoCompression, or any
+// integer value between BestSpeed and BestCompression inclusive. The error
+// returned will be nil if the level is valid.
+func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
+ if level < DefaultCompression || level > BestCompression {
+ return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
+ }
+ return &Writer{
+ Header: Header{
+ OS: 255, // unknown
+ },
+ w: w,
+ level: level,
+ digest: crc32.NewIEEE(),
+ }, nil
}
// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
@@ -70,9 +86,9 @@ func put4(p []byte, v uint32) {
}
// writeBytes writes a length-prefixed byte slice to z.w.
-func (z *Compressor) writeBytes(b []byte) os.Error {
+func (z *Writer) writeBytes(b []byte) error {
if len(b) > 0xffff {
- return os.NewError("gzip.Write: Extra data is too large")
+ return errors.New("gzip.Write: Extra data is too large")
}
put2(z.buf[0:2], uint16(len(b)))
_, err := z.w.Write(z.buf[0:2])
@@ -83,16 +99,28 @@ func (z *Compressor) writeBytes(b []byte) os.Error {
return err
}
-// writeString writes a string (in ISO 8859-1 (Latin-1) format) to z.w.
-func (z *Compressor) writeString(s string) os.Error {
- // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
- // TODO(nigeltao): Convert from UTF-8 to ISO 8859-1 (Latin-1).
+// writeString writes a UTF-8 string s in GZIP's format to z.w.
+// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
+func (z *Writer) writeString(s string) (err error) {
+ // GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII.
+ needconv := false
for _, v := range s {
- if v == 0 || v > 0x7f {
- return os.NewError("gzip.Write: non-ASCII header string")
+ if v == 0 || v > 0xff {
+ return errors.New("gzip.Write: non-Latin-1 header string")
+ }
+ if v > 0x7f {
+ needconv = true
+ }
+ }
+ if needconv {
+ b := make([]byte, 0, len(s))
+ for _, v := range s {
+ b = append(b, byte(v))
}
+ _, err = z.w.Write(b)
+ } else {
+ _, err = io.WriteString(z.w, s)
}
- _, err := io.WriteString(z.w, s)
if err != nil {
return err
}
@@ -102,7 +130,9 @@ func (z *Compressor) writeString(s string) os.Error {
return err
}
-func (z *Compressor) Write(p []byte) (int, os.Error) {
+// Write writes a compressed form of p to the underlying io.Writer. The
+// compressed bytes are not necessarily flushed until the Writer is closed.
+func (z *Writer) Write(p []byte) (int, error) {
if z.err != nil {
return 0, z.err
}
@@ -122,7 +152,7 @@ func (z *Compressor) Write(p []byte) (int, os.Error) {
if z.Comment != "" {
z.buf[3] |= 0x10
}
- put4(z.buf[4:8], z.Mtime)
+ put4(z.buf[4:8], uint32(z.ModTime.Unix()))
if z.level == BestCompression {
z.buf[8] = 2
} else if z.level == BestSpeed {
@@ -153,7 +183,7 @@ func (z *Compressor) Write(p []byte) (int, os.Error) {
return n, z.err
}
}
- z.compressor = flate.NewWriter(z.w, z.level)
+ z.compressor, _ = flate.NewWriter(z.w, z.level)
}
z.size += uint32(len(p))
z.digest.Write(p)
@@ -161,8 +191,8 @@ func (z *Compressor) Write(p []byte) (int, os.Error) {
return n, z.err
}
-// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
-func (z *Compressor) Close() os.Error {
+// Close closes the Writer. It does not close the underlying io.Writer.
+func (z *Writer) Close() error {
if z.err != nil {
return z.err
}
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
index 121e627e6..6f7b59364 100644
--- a/src/pkg/compress/gzip/gzip_test.go
+++ b/src/pkg/compress/gzip/gzip_test.go
@@ -5,80 +5,155 @@
package gzip
import (
- "io"
+ "bufio"
+ "bytes"
"io/ioutil"
"testing"
+ "time"
)
-// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
-// 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()
- go func() {
- defer pipew.Close()
- compressor, err := NewWriter(pipew)
- if err != nil {
- t.Fatalf("%v", err)
- }
- defer compressor.Close()
- dfunc(compressor)
- }()
- decompressor, err := NewReader(piper)
+// TestEmpty tests that an empty payload still forms a valid GZIP stream.
+func TestEmpty(t *testing.T) {
+ buf := new(bytes.Buffer)
+
+ if err := NewWriter(buf).Close(); err != nil {
+ t.Fatalf("Writer.Close: %v", err)
+ }
+
+ r, err := NewReader(buf)
if err != nil {
- t.Fatalf("%v", err)
+ t.Fatalf("NewReader: %v", err)
+ }
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Fatalf("ReadAll: %v", err)
+ }
+ if len(b) != 0 {
+ t.Fatalf("got %d bytes, want 0", len(b))
+ }
+ if err := r.Close(); err != nil {
+ t.Fatalf("Reader.Close: %v", err)
}
- defer decompressor.Close()
- cfunc(decompressor)
}
-// Tests that an empty payload still forms a valid GZIP stream.
-func TestEmpty(t *testing.T) {
- pipe(t,
- func(compressor *Compressor) {},
- func(decompressor *Decompressor) {
- b, err := ioutil.ReadAll(decompressor)
- if err != nil {
- t.Fatalf("%v", err)
- }
- if len(b) != 0 {
- t.Fatalf("did not read an empty slice")
- }
- })
+// TestRoundTrip tests that gzipping and then gunzipping is the identity
+// function.
+func TestRoundTrip(t *testing.T) {
+ buf := new(bytes.Buffer)
+
+ w := NewWriter(buf)
+ w.Comment = "comment"
+ w.Extra = []byte("extra")
+ w.ModTime = time.Unix(1e8, 0)
+ w.Name = "name"
+ if _, err := w.Write([]byte("payload")); err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close: %v", err)
+ }
+
+ r, err := NewReader(buf)
+ if err != nil {
+ t.Fatalf("NewReader: %v", err)
+ }
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Fatalf("ReadAll: %v", err)
+ }
+ if string(b) != "payload" {
+ t.Fatalf("payload is %q, want %q", string(b), "payload")
+ }
+ if r.Comment != "comment" {
+ t.Fatalf("comment is %q, want %q", r.Comment, "comment")
+ }
+ if string(r.Extra) != "extra" {
+ t.Fatalf("extra is %q, want %q", r.Extra, "extra")
+ }
+ if r.ModTime.Unix() != 1e8 {
+ t.Fatalf("mtime is %d, want %d", r.ModTime.Unix(), uint32(1e8))
+ }
+ if r.Name != "name" {
+ t.Fatalf("name is %q, want %q", r.Name, "name")
+ }
+ if err := r.Close(); err != nil {
+ t.Fatalf("Reader.Close: %v", err)
+ }
}
-// Tests that gzipping and then gunzipping is the identity function.
-func TestWriter(t *testing.T) {
- pipe(t,
- func(compressor *Compressor) {
- compressor.Comment = "comment"
- compressor.Extra = []byte("extra")
- compressor.Mtime = 1e8
- compressor.Name = "name"
- _, err := compressor.Write([]byte("payload"))
- if err != nil {
- t.Fatalf("%v", err)
- }
- },
- func(decompressor *Decompressor) {
- b, err := ioutil.ReadAll(decompressor)
- if err != nil {
- t.Fatalf("%v", err)
- }
- if string(b) != "payload" {
- t.Fatalf("payload is %q, want %q", string(b), "payload")
- }
- if decompressor.Comment != "comment" {
- t.Fatalf("comment is %q, want %q", decompressor.Comment, "comment")
- }
- if string(decompressor.Extra) != "extra" {
- t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra")
- }
- if decompressor.Mtime != 1e8 {
- t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8))
- }
- if decompressor.Name != "name" {
- t.Fatalf("name is %q, want %q", decompressor.Name, "name")
- }
- })
+// TestLatin1 tests the internal functions for converting to and from Latin-1.
+func TestLatin1(t *testing.T) {
+ latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
+ utf8 := "Äußerung"
+ z := Reader{r: bufio.NewReader(bytes.NewBuffer(latin1))}
+ s, err := z.readString()
+ if err != nil {
+ t.Fatalf("readString: %v", err)
+ }
+ if s != utf8 {
+ t.Fatalf("read latin-1: got %q, want %q", s, utf8)
+ }
+
+ buf := bytes.NewBuffer(make([]byte, 0, len(latin1)))
+ c := Writer{w: buf}
+ if err = c.writeString(utf8); err != nil {
+ t.Fatalf("writeString: %v", err)
+ }
+ s = buf.String()
+ if s != string(latin1) {
+ t.Fatalf("write utf-8: got %q, want %q", s, string(latin1))
+ }
+}
+
+// TestLatin1RoundTrip tests that metadata that is representable in Latin-1
+// survives a round trip.
+func TestLatin1RoundTrip(t *testing.T) {
+ testCases := []struct {
+ name string
+ ok bool
+ }{
+ {"", true},
+ {"ASCII is OK", true},
+ {"unless it contains a NUL\x00", false},
+ {"no matter where \x00 occurs", false},
+ {"\x00\x00\x00", false},
+ {"Látin-1 also passes (U+00E1)", true},
+ {"but LĀtin Extended-A (U+0100) does not", false},
+ {"neither does 日本語", false},
+ {"invalid UTF-8 also \xffails", false},
+ {"\x00 as does Látin-1 with NUL", false},
+ }
+ for _, tc := range testCases {
+ buf := new(bytes.Buffer)
+
+ w := NewWriter(buf)
+ w.Name = tc.name
+ err := w.Close()
+ if (err == nil) != tc.ok {
+ t.Errorf("Writer.Close: name = %q, err = %v", tc.name, err)
+ continue
+ }
+ if !tc.ok {
+ continue
+ }
+
+ r, err := NewReader(buf)
+ if err != nil {
+ t.Errorf("NewReader: %v", err)
+ continue
+ }
+ _, err = ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("ReadAll: %v", err)
+ continue
+ }
+ if r.Name != tc.name {
+ t.Errorf("name is %q, want %q", r.Name, tc.name)
+ continue
+ }
+ if err := r.Close(); err != nil {
+ t.Errorf("Reader.Close: %v", err)
+ continue
+ }
+ }
}
diff --git a/src/pkg/compress/lzw/Makefile b/src/pkg/compress/lzw/Makefile
deleted file mode 100644
index 28f5e6abc..000000000
--- a/src/pkg/compress/lzw/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=compress/lzw
-GOFILES=\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index 21231c8e5..0ed742c89 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -16,9 +16,9 @@ package lzw
import (
"bufio"
+ "errors"
"fmt"
"io"
- "os"
)
// Order specifies the bit ordering in an LZW data stream.
@@ -45,9 +45,9 @@ type decoder struct {
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
+ read func(*decoder) (uint16, error) // readLSB or readMSB
+ litWidth int // width in bits of literal codes
+ err error
// The first 1<<litWidth codes are literal codes.
// The next two codes mean clear and EOF.
@@ -78,7 +78,7 @@ type decoder struct {
}
// readLSB returns the next code for "Least Significant Bits first" data.
-func (d *decoder) readLSB() (uint16, os.Error) {
+func (d *decoder) readLSB() (uint16, error) {
for d.nBits < d.width {
x, err := d.r.ReadByte()
if err != nil {
@@ -94,7 +94,7 @@ func (d *decoder) readLSB() (uint16, os.Error) {
}
// readMSB returns the next code for "Most Significant Bits first" data.
-func (d *decoder) readMSB() (uint16, os.Error) {
+func (d *decoder) readMSB() (uint16, error) {
for d.nBits < d.width {
x, err := d.r.ReadByte()
if err != nil {
@@ -109,7 +109,7 @@ func (d *decoder) readMSB() (uint16, os.Error) {
return code, nil
}
-func (d *decoder) Read(b []byte) (int, os.Error) {
+func (d *decoder) Read(b []byte) (int, error) {
for {
if len(d.toRead) > 0 {
n := copy(b, d.toRead)
@@ -132,7 +132,7 @@ func (d *decoder) decode() {
for {
code, err := d.read(d)
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
d.err = err
@@ -156,7 +156,7 @@ func (d *decoder) decode() {
continue
case code == d.eof:
d.flush()
- d.err = os.EOF
+ d.err = io.EOF
return
case code <= d.hi:
c, i := code, len(d.output)-1
@@ -186,7 +186,7 @@ func (d *decoder) decode() {
d.prefix[d.hi] = d.last
}
default:
- d.err = os.NewError("lzw: invalid code")
+ d.err = errors.New("lzw: invalid code")
return
}
d.last, d.hi = code, d.hi+1
@@ -211,8 +211,10 @@ func (d *decoder) flush() {
d.o = 0
}
-func (d *decoder) Close() os.Error {
- d.err = os.EINVAL // in case any Reads come along
+var errClosed = errors.New("compress/lzw: reader/writer is closed")
+
+func (d *decoder) Close() error {
+ d.err = errClosed // in case any Reads come along
return nil
}
@@ -230,7 +232,7 @@ func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
case MSB:
d.read = (*decoder).readMSB
default:
- d.err = os.NewError("lzw: unknown order")
+ d.err = errors.New("lzw: unknown order")
return d
}
if litWidth < 2 || 8 < litWidth {
diff --git a/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
index f8042b0d1..e5be12f54 100644
--- a/src/pkg/compress/lzw/reader_test.go
+++ b/src/pkg/compress/lzw/reader_test.go
@@ -8,7 +8,6 @@ import (
"bytes"
"io"
"io/ioutil"
- "os"
"runtime"
"strconv"
"strings"
@@ -19,7 +18,7 @@ type lzwTest struct {
desc string
raw string
compressed string
- err os.Error
+ err error
}
var lzwTests = []lzwTest{
@@ -82,7 +81,7 @@ var lzwTests = []lzwTest{
}
func TestReader(t *testing.T) {
- b := bytes.NewBuffer(nil)
+ var b bytes.Buffer
for _, tt := range lzwTests {
d := strings.Split(tt.desc, ";")
var order Order
@@ -98,7 +97,7 @@ func TestReader(t *testing.T) {
rc := NewReader(strings.NewReader(tt.compressed), order, litWidth)
defer rc.Close()
b.Reset()
- n, err := io.Copy(b, rc)
+ n, err := io.Copy(&b, rc)
if err != nil {
if err != tt.err {
t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
@@ -117,7 +116,7 @@ func benchmarkDecoder(b *testing.B, n int) {
b.SetBytes(int64(n))
buf0, _ := ioutil.ReadFile("../testdata/e.txt")
buf0 = buf0[:10000]
- compressed := bytes.NewBuffer(nil)
+ compressed := new(bytes.Buffer)
w := NewWriter(compressed, LSB, 8)
for i := 0; i < n; i += len(buf0) {
io.Copy(w, bytes.NewBuffer(buf0))
diff --git a/src/pkg/compress/lzw/writer.go b/src/pkg/compress/lzw/writer.go
index 87143b7aa..488ba6428 100644
--- a/src/pkg/compress/lzw/writer.go
+++ b/src/pkg/compress/lzw/writer.go
@@ -6,27 +6,27 @@ package lzw
import (
"bufio"
+ "errors"
"fmt"
"io"
- "os"
)
// A writer is a buffered, flushable writer.
type writer interface {
- WriteByte(byte) os.Error
- Flush() os.Error
+ WriteByte(byte) error
+ Flush() error
}
// An errWriteCloser is an io.WriteCloser that always returns a given error.
type errWriteCloser struct {
- err os.Error
+ err error
}
-func (e *errWriteCloser) Write([]byte) (int, os.Error) {
+func (e *errWriteCloser) Write([]byte) (int, error) {
return 0, e.err
}
-func (e *errWriteCloser) Close() os.Error {
+func (e *errWriteCloser) Close() error {
return e.err
}
@@ -48,9 +48,10 @@ const (
type encoder struct {
// w is the writer that compressed bytes are written to.
w writer
- // write, bits, nBits and width are the state for converting a code stream
- // into a byte stream.
- write func(*encoder, uint32) os.Error
+ // order, write, bits, nBits and width are the state for
+ // converting a code stream into a byte stream.
+ order Order
+ write func(*encoder, uint32) error
bits uint32
nBits uint
width uint
@@ -63,8 +64,8 @@ type encoder struct {
// call. It is equal to invalidCode if there was no such call.
savedCode uint32
// err is the first error encountered during writing. Closing the encoder
- // will make any future Write calls return os.EINVAL.
- err os.Error
+ // will make any future Write calls return errClosed
+ err error
// table is the hash table from 20-bit keys to 12-bit values. Each table
// entry contains key<<12|val and collisions resolve by linear probing.
// The keys consist of a 12-bit code prefix and an 8-bit byte suffix.
@@ -73,7 +74,7 @@ type encoder struct {
}
// writeLSB writes the code c for "Least Significant Bits first" data.
-func (e *encoder) writeLSB(c uint32) os.Error {
+func (e *encoder) writeLSB(c uint32) error {
e.bits |= c << e.nBits
e.nBits += e.width
for e.nBits >= 8 {
@@ -87,7 +88,7 @@ func (e *encoder) writeLSB(c uint32) os.Error {
}
// writeMSB writes the code c for "Most Significant Bits first" data.
-func (e *encoder) writeMSB(c uint32) os.Error {
+func (e *encoder) writeMSB(c uint32) error {
e.bits |= c << (32 - e.width - e.nBits)
e.nBits += e.width
for e.nBits >= 8 {
@@ -102,12 +103,12 @@ func (e *encoder) writeMSB(c uint32) os.Error {
// errOutOfCodes is an internal error that means that the encoder has run out
// of unused codes and a clear code needs to be sent next.
-var errOutOfCodes = os.NewError("lzw: out of codes")
+var errOutOfCodes = errors.New("lzw: out of codes")
// incHi increments e.hi and checks for both overflow and running out of
// unused codes. In the latter case, incHi sends a clear code, resets the
// encoder state and returns errOutOfCodes.
-func (e *encoder) incHi() os.Error {
+func (e *encoder) incHi() error {
e.hi++
if e.hi == e.overflow {
e.width++
@@ -130,7 +131,7 @@ func (e *encoder) incHi() os.Error {
}
// Write writes a compressed representation of p to e's underlying writer.
-func (e *encoder) Write(p []byte) (int, os.Error) {
+func (e *encoder) Write(p []byte) (int, error) {
if e.err != nil {
return 0, e.err
}
@@ -188,15 +189,15 @@ loop:
// Close closes the encoder, flushing any pending output. It does not close or
// flush e's underlying writer.
-func (e *encoder) Close() os.Error {
+func (e *encoder) Close() error {
if e.err != nil {
- if e.err == os.EINVAL {
+ if e.err == errClosed {
return nil
}
return e.err
}
- // Make any future calls to Write return os.EINVAL.
- e.err = os.EINVAL
+ // Make any future calls to Write return errClosed.
+ e.err = errClosed
// Write the savedCode if valid.
if e.savedCode != invalidCode {
if err := e.write(e, e.savedCode); err != nil {
@@ -213,7 +214,7 @@ func (e *encoder) Close() os.Error {
}
// Write the final bits.
if e.nBits > 0 {
- if e.write == (*encoder).writeMSB {
+ if e.order == MSB {
e.bits >>= 24
}
if err := e.w.WriteByte(uint8(e.bits)); err != nil {
@@ -230,14 +231,14 @@ func (e *encoder) Close() os.Error {
// The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8.
func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
- var write func(*encoder, uint32) os.Error
+ var write func(*encoder, uint32) error
switch order {
case LSB:
write = (*encoder).writeLSB
case MSB:
write = (*encoder).writeMSB
default:
- return &errWriteCloser{os.NewError("lzw: unknown order")}
+ return &errWriteCloser{errors.New("lzw: unknown order")}
}
if litWidth < 2 || 8 < litWidth {
return &errWriteCloser{fmt.Errorf("lzw: litWidth %d out of range", litWidth)}
@@ -249,6 +250,7 @@ func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
lw := uint(litWidth)
return &encoder{
w: bw,
+ order: order,
write: write,
width: 1 + lw,
litWidth: lw,
diff --git a/src/pkg/compress/lzw/writer_test.go b/src/pkg/compress/lzw/writer_test.go
index 4c5e522f9..d249a09b2 100644
--- a/src/pkg/compress/lzw/writer_test.go
+++ b/src/pkg/compress/lzw/writer_test.go
@@ -45,20 +45,16 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
var b [4096]byte
for {
n, err0 := raw.Read(b[:])
- if err0 != nil && err0 != os.EOF {
+ if err0 != nil && err0 != io.EOF {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0)
return
}
_, err1 := lzww.Write(b[: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 (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
return
}
- if err0 == os.EOF {
+ if err0 == io.EOF {
break
}
}
diff --git a/src/pkg/compress/testdata/Mark.Twain-Tom.Sawyer.txt b/src/pkg/compress/testdata/Mark.Twain-Tom.Sawyer.txt
new file mode 100644
index 000000000..8d0ff4e65
--- /dev/null
+++ b/src/pkg/compress/testdata/Mark.Twain-Tom.Sawyer.txt
@@ -0,0 +1,8858 @@
+The Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete
+by Mark Twain (Samuel Clemens)
+
+This eBook is for the use of anyone anywhere at no cost and with
+almost no restrictions whatsoever. You may copy it, give it away or
+re-use it under the terms of the Project Gutenberg License included
+with this eBook or online at www.gutenberg.net
+
+
+Title: The Adventures of Tom Sawyer, Complete
+
+Author: Mark Twain (Samuel Clemens)
+
+Release Date: August 20, 2006 [EBook #74]
+[Last updated: May 3, 2011]
+
+Language: English
+
+
+*** START OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***
+
+
+
+
+Produced by David Widger. The previous edition was updated by Jose
+Menendez.
+
+
+
+
+
+ THE ADVENTURES OF TOM SAWYER
+ BY
+ MARK TWAIN
+ (Samuel Langhorne Clemens)
+
+
+
+
+ P R E F A C E
+
+MOST of the adventures recorded in this book really occurred; one or
+two were experiences of my own, the rest those of boys who were
+schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
+not from an individual--he is a combination of the characteristics of
+three boys whom I knew, and therefore belongs to the composite order of
+architecture.
+
+The odd superstitions touched upon were all prevalent among children
+and slaves in the West at the period of this story--that is to say,
+thirty or forty years ago.
+
+Although my book is intended mainly for the entertainment of boys and
+girls, I hope it will not be shunned by men and women on that account,
+for part of my plan has been to try to pleasantly remind adults of what
+they once were themselves, and of how they felt and thought and talked,
+and what queer enterprises they sometimes engaged in.
+
+ THE AUTHOR.
+
+HARTFORD, 1876.
+
+
+
+ T O M S A W Y E R
+
+
+
+CHAPTER I
+
+"TOM!"
+
+No answer.
+
+"TOM!"
+
+No answer.
+
+"What's gone with that boy, I wonder? You TOM!"
+
+No answer.
+
+The old lady pulled her spectacles down and looked over them about the
+room; then she put them up and looked out under them. She seldom or
+never looked THROUGH them for so small a thing as a boy; they were her
+state pair, the pride of her heart, and were built for "style," not
+service--she could have seen through a pair of stove-lids just as well.
+She looked perplexed for a moment, and then said, not fiercely, but
+still loud enough for the furniture to hear:
+
+"Well, I lay if I get hold of you I'll--"
+
+She did not finish, for by this time she was bending down and punching
+under the bed with the broom, and so she needed breath to punctuate the
+punches with. She resurrected nothing but the cat.
+
+"I never did see the beat of that boy!"
+
+She went to the open door and stood in it and looked out among the
+tomato vines and "jimpson" weeds that constituted the garden. No Tom.
+So she lifted up her voice at an angle calculated for distance and
+shouted:
+
+"Y-o-u-u TOM!"
+
+There was a slight noise behind her and she turned just in time to
+seize a small boy by the slack of his roundabout and arrest his flight.
+
+"There! I might 'a' thought of that closet. What you been doing in
+there?"
+
+"Nothing."
+
+"Nothing! Look at your hands. And look at your mouth. What IS that
+truck?"
+
+"I don't know, aunt."
+
+"Well, I know. It's jam--that's what it is. Forty times I've said if
+you didn't let that jam alone I'd skin you. Hand me that switch."
+
+The switch hovered in the air--the peril was desperate--
+
+"My! Look behind you, aunt!"
+
+The old lady whirled round, and snatched her skirts out of danger. The
+lad fled on the instant, scrambled up the high board-fence, and
+disappeared over it.
+
+His aunt Polly stood surprised a moment, and then broke into a gentle
+laugh.
+
+"Hang the boy, can't I never learn anything? Ain't he played me tricks
+enough like that for me to be looking out for him by this time? But old
+fools is the biggest fools there is. Can't learn an old dog new tricks,
+as the saying is. But my goodness, he never plays them alike, two days,
+and how is a body to know what's coming? He 'pears to know just how
+long he can torment me before I get my dander up, and he knows if he
+can make out to put me off for a minute or make me laugh, it's all down
+again and I can't hit him a lick. I ain't doing my duty by that boy,
+and that's the Lord's truth, goodness knows. Spare the rod and spile
+the child, as the Good Book says. I'm a laying up sin and suffering for
+us both, I know. He's full of the Old Scratch, but laws-a-me! he's my
+own dead sister's boy, poor thing, and I ain't got the heart to lash
+him, somehow. Every time I let him off, my conscience does hurt me so,
+and every time I hit him my old heart most breaks. Well-a-well, man
+that is born of woman is of few days and full of trouble, as the
+Scripture says, and I reckon it's so. He'll play hookey this evening, *
+and [* Southwestern for "afternoon"] I'll just be obleeged to make him
+work, to-morrow, to punish him. It's mighty hard to make him work
+Saturdays, when all the boys is having holiday, but he hates work more
+than he hates anything else, and I've GOT to do some of my duty by him,
+or I'll be the ruination of the child."
+
+Tom did play hookey, and he had a very good time. He got back home
+barely in season to help Jim, the small colored boy, saw next-day's
+wood and split the kindlings before supper--at least he was there in
+time to tell his adventures to Jim while Jim did three-fourths of the
+work. Tom's younger brother (or rather half-brother) Sid was already
+through with his part of the work (picking up chips), for he was a
+quiet boy, and had no adventurous, troublesome ways.
+
+While Tom was eating his supper, and stealing sugar as opportunity
+offered, Aunt Polly asked him questions that were full of guile, and
+very deep--for she wanted to trap him into damaging revealments. Like
+many other simple-hearted souls, it was her pet vanity to believe she
+was endowed with a talent for dark and mysterious diplomacy, and she
+loved to contemplate her most transparent devices as marvels of low
+cunning. Said she:
+
+"Tom, it was middling warm in school, warn't it?"
+
+"Yes'm."
+
+"Powerful warm, warn't it?"
+
+"Yes'm."
+
+"Didn't you want to go in a-swimming, Tom?"
+
+A bit of a scare shot through Tom--a touch of uncomfortable suspicion.
+He searched Aunt Polly's face, but it told him nothing. So he said:
+
+"No'm--well, not very much."
+
+The old lady reached out her hand and felt Tom's shirt, and said:
+
+"But you ain't too warm now, though." And it flattered her to reflect
+that she had discovered that the shirt was dry without anybody knowing
+that that was what she had in her mind. But in spite of her, Tom knew
+where the wind lay, now. So he forestalled what might be the next move:
+
+"Some of us pumped on our heads--mine's damp yet. See?"
+
+Aunt Polly was vexed to think she had overlooked that bit of
+circumstantial evidence, and missed a trick. Then she had a new
+inspiration:
+
+"Tom, you didn't have to undo your shirt collar where I sewed it, to
+pump on your head, did you? Unbutton your jacket!"
+
+The trouble vanished out of Tom's face. He opened his jacket. His
+shirt collar was securely sewed.
+
+"Bother! Well, go 'long with you. I'd made sure you'd played hookey
+and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a
+singed cat, as the saying is--better'n you look. THIS time."
+
+She was half sorry her sagacity had miscarried, and half glad that Tom
+had stumbled into obedient conduct for once.
+
+But Sidney said:
+
+"Well, now, if I didn't think you sewed his collar with white thread,
+but it's black."
+
+"Why, I did sew it with white! Tom!"
+
+But Tom did not wait for the rest. As he went out at the door he said:
+
+"Siddy, I'll lick you for that."
+
+In a safe place Tom examined two large needles which were thrust into
+the lapels of his jacket, and had thread bound about them--one needle
+carried white thread and the other black. He said:
+
+"She'd never noticed if it hadn't been for Sid. Confound it! sometimes
+she sews it with white, and sometimes she sews it with black. I wish to
+geeminy she'd stick to one or t'other--I can't keep the run of 'em. But
+I bet you I'll lam Sid for that. I'll learn him!"
+
+He was not the Model Boy of the village. He knew the model boy very
+well though--and loathed him.
+
+Within two minutes, or even less, he had forgotten all his troubles.
+Not because his troubles were one whit less heavy and bitter to him
+than a man's are to a man, but because a new and powerful interest bore
+them down and drove them out of his mind for the time--just as men's
+misfortunes are forgotten in the excitement of new enterprises. This
+new interest was a valued novelty in whistling, which he had just
+acquired from a negro, and he was suffering to practise it undisturbed.
+It consisted in a peculiar bird-like turn, a sort of liquid warble,
+produced by touching the tongue to the roof of the mouth at short
+intervals in the midst of the music--the reader probably remembers how
+to do it, if he has ever been a boy. Diligence and attention soon gave
+him the knack of it, and he strode down the street with his mouth full
+of harmony and his soul full of gratitude. He felt much as an
+astronomer feels who has discovered a new planet--no doubt, as far as
+strong, deep, unalloyed pleasure is concerned, the advantage was with
+the boy, not the astronomer.
+
+The summer evenings were long. It was not dark, yet. Presently Tom
+checked his whistle. A stranger was before him--a boy a shade larger
+than himself. A new-comer of any age or either sex was an impressive
+curiosity in the poor little shabby village of St. Petersburg. This boy
+was well dressed, too--well dressed on a week-day. This was simply
+astounding. His cap was a dainty thing, his close-buttoned blue cloth
+roundabout was new and natty, and so were his pantaloons. He had shoes
+on--and it was only Friday. He even wore a necktie, a bright bit of
+ribbon. He had a citified air about him that ate into Tom's vitals. The
+more Tom stared at the splendid marvel, the higher he turned up his
+nose at his finery and the shabbier and shabbier his own outfit seemed
+to him to grow. Neither boy spoke. If one moved, the other moved--but
+only sidewise, in a circle; they kept face to face and eye to eye all
+the time. Finally Tom said:
+
+"I can lick you!"
+
+"I'd like to see you try it."
+
+"Well, I can do it."
+
+"No you can't, either."
+
+"Yes I can."
+
+"No you can't."
+
+"I can."
+
+"You can't."
+
+"Can!"
+
+"Can't!"
+
+An uncomfortable pause. Then Tom said:
+
+"What's your name?"
+
+"'Tisn't any of your business, maybe."
+
+"Well I 'low I'll MAKE it my business."
+
+"Well why don't you?"
+
+"If you say much, I will."
+
+"Much--much--MUCH. There now."
+
+"Oh, you think you're mighty smart, DON'T you? I could lick you with
+one hand tied behind me, if I wanted to."
+
+"Well why don't you DO it? You SAY you can do it."
+
+"Well I WILL, if you fool with me."
+
+"Oh yes--I've seen whole families in the same fix."
+
+"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!"
+
+"You can lump that hat if you don't like it. I dare you to knock it
+off--and anybody that'll take a dare will suck eggs."
+
+"You're a liar!"
+
+"You're another."
+
+"You're a fighting liar and dasn't take it up."
+
+"Aw--take a walk!"
+
+"Say--if you give me much more of your sass I'll take and bounce a
+rock off'n your head."
+
+"Oh, of COURSE you will."
+
+"Well I WILL."
+
+"Well why don't you DO it then? What do you keep SAYING you will for?
+Why don't you DO it? It's because you're afraid."
+
+"I AIN'T afraid."
+
+"You are."
+
+"I ain't."
+
+"You are."
+
+Another pause, and more eying and sidling around each other. Presently
+they were shoulder to shoulder. Tom said:
+
+"Get away from here!"
+
+"Go away yourself!"
+
+"I won't."
+
+"I won't either."
+
+So they stood, each with a foot placed at an angle as a brace, and
+both shoving with might and main, and glowering at each other with
+hate. But neither could get an advantage. After struggling till both
+were hot and flushed, each relaxed his strain with watchful caution,
+and Tom said:
+
+"You're a coward and a pup. I'll tell my big brother on you, and he
+can thrash you with his little finger, and I'll make him do it, too."
+
+"What do I care for your big brother? I've got a brother that's bigger
+than he is--and what's more, he can throw him over that fence, too."
+[Both brothers were imaginary.]
+
+"That's a lie."
+
+"YOUR saying so don't make it so."
+
+Tom drew a line in the dust with his big toe, and said:
+
+"I dare you to step over that, and I'll lick you till you can't stand
+up. Anybody that'll take a dare will steal sheep."
+
+The new boy stepped over promptly, and said:
+
+"Now you said you'd do it, now let's see you do it."
+
+"Don't you crowd me now; you better look out."
+
+"Well, you SAID you'd do it--why don't you do it?"
+
+"By jingo! for two cents I WILL do it."
+
+The new boy took two broad coppers out of his pocket and held them out
+with derision. Tom struck them to the ground. In an instant both boys
+were rolling and tumbling in the dirt, gripped together like cats; and
+for the space of a minute they tugged and tore at each other's hair and
+clothes, punched and scratched each other's nose, and covered
+themselves with dust and glory. Presently the confusion took form, and
+through the fog of battle Tom appeared, seated astride the new boy, and
+pounding him with his fists. "Holler 'nuff!" said he.
+
+The boy only struggled to free himself. He was crying--mainly from rage.
+
+"Holler 'nuff!"--and the pounding went on.
+
+At last the stranger got out a smothered "'Nuff!" and Tom let him up
+and said:
+
+"Now that'll learn you. Better look out who you're fooling with next
+time."
+
+The new boy went off brushing the dust from his clothes, sobbing,
+snuffling, and occasionally looking back and shaking his head and
+threatening what he would do to Tom the "next time he caught him out."
+To which Tom responded with jeers, and started off in high feather, and
+as soon as his back was turned the new boy snatched up a stone, threw
+it and hit him between the shoulders and then turned tail and ran like
+an antelope. Tom chased the traitor home, and thus found out where he
+lived. He then held a position at the gate for some time, daring the
+enemy to come outside, but the enemy only made faces at him through the
+window and declined. At last the enemy's mother appeared, and called
+Tom a bad, vicious, vulgar child, and ordered him away. So he went
+away; but he said he "'lowed" to "lay" for that boy.
+
+He got home pretty late that night, and when he climbed cautiously in
+at the window, he uncovered an ambuscade, in the person of his aunt;
+and when she saw the state his clothes were in her resolution to turn
+his Saturday holiday into captivity at hard labor became adamantine in
+its firmness.
+
+
+
+CHAPTER II
+
+SATURDAY morning was come, and all the summer world was bright and
+fresh, and brimming with life. There was a song in every heart; and if
+the heart was young the music issued at the lips. There was cheer in
+every face and a spring in every step. The locust-trees were in bloom
+and the fragrance of the blossoms filled the air. Cardiff Hill, beyond
+the village and above it, was green with vegetation and it lay just far
+enough away to seem a Delectable Land, dreamy, reposeful, and inviting.
+
+Tom appeared on the sidewalk with a bucket of whitewash and a
+long-handled brush. He surveyed the fence, and all gladness left him and
+a deep melancholy settled down upon his spirit. Thirty yards of board
+fence nine feet high. Life to him seemed hollow, and existence but a
+burden. Sighing, he dipped his brush and passed it along the topmost
+plank; repeated the operation; did it again; compared the insignificant
+whitewashed streak with the far-reaching continent of unwhitewashed
+fence, and sat down on a tree-box discouraged. Jim came skipping out at
+the gate with a tin pail, and singing Buffalo Gals. Bringing water from
+the town pump had always been hateful work in Tom's eyes, before, but
+now it did not strike him so. He remembered that there was company at
+the pump. White, mulatto, and negro boys and girls were always there
+waiting their turns, resting, trading playthings, quarrelling,
+fighting, skylarking. And he remembered that although the pump was only
+a hundred and fifty yards off, Jim never got back with a bucket of
+water under an hour--and even then somebody generally had to go after
+him. Tom said:
+
+"Say, Jim, I'll fetch the water if you'll whitewash some."
+
+Jim shook his head and said:
+
+"Can't, Mars Tom. Ole missis, she tole me I got to go an' git dis
+water an' not stop foolin' roun' wid anybody. She say she spec' Mars
+Tom gwine to ax me to whitewash, an' so she tole me go 'long an' 'tend
+to my own business--she 'lowed SHE'D 'tend to de whitewashin'."
+
+"Oh, never you mind what she said, Jim. That's the way she always
+talks. Gimme the bucket--I won't be gone only a a minute. SHE won't
+ever know."
+
+"Oh, I dasn't, Mars Tom. Ole missis she'd take an' tar de head off'n
+me. 'Deed she would."
+
+"SHE! She never licks anybody--whacks 'em over the head with her
+thimble--and who cares for that, I'd like to know. She talks awful, but
+talk don't hurt--anyways it don't if she don't cry. Jim, I'll give you
+a marvel. I'll give you a white alley!"
+
+Jim began to waver.
+
+"White alley, Jim! And it's a bully taw."
+
+"My! Dat's a mighty gay marvel, I tell you! But Mars Tom I's powerful
+'fraid ole missis--"
+
+"And besides, if you will I'll show you my sore toe."
+
+Jim was only human--this attraction was too much for him. He put down
+his pail, took the white alley, and bent over the toe with absorbing
+interest while the bandage was being unwound. In another moment he was
+flying down the street with his pail and a tingling rear, Tom was
+whitewashing with vigor, and Aunt Polly was retiring from the field
+with a slipper in her hand and triumph in her eye.
+
+But Tom's energy did not last. He began to think of the fun he had
+planned for this day, and his sorrows multiplied. Soon the free boys
+would come tripping along on all sorts of delicious expeditions, and
+they would make a world of fun of him for having to work--the very
+thought of it burnt him like fire. He got out his worldly wealth and
+examined it--bits of toys, marbles, and trash; enough to buy an
+exchange of WORK, maybe, but not half enough to buy so much as half an
+hour of pure freedom. So he returned his straitened means to his
+pocket, and gave up the idea of trying to buy the boys. At this dark
+and hopeless moment an inspiration burst upon him! Nothing less than a
+great, magnificent inspiration.
+
+He took up his brush and went tranquilly to work. Ben Rogers hove in
+sight presently--the very boy, of all boys, whose ridicule he had been
+dreading. Ben's gait was the hop-skip-and-jump--proof enough that his
+heart was light and his anticipations high. He was eating an apple, and
+giving a long, melodious whoop, at intervals, followed by a deep-toned
+ding-dong-dong, ding-dong-dong, for he was personating a steamboat. As
+he drew near, he slackened speed, took the middle of the street, leaned
+far over to starboard and rounded to ponderously and with laborious
+pomp and circumstance--for he was personating the Big Missouri, and
+considered himself to be drawing nine feet of water. He was boat and
+captain and engine-bells combined, so he had to imagine himself
+standing on his own hurricane-deck giving the orders and executing them:
+
+"Stop her, sir! Ting-a-ling-ling!" The headway ran almost out, and he
+drew up slowly toward the sidewalk.
+
+"Ship up to back! Ting-a-ling-ling!" His arms straightened and
+stiffened down his sides.
+
+"Set her back on the stabboard! Ting-a-ling-ling! Chow! ch-chow-wow!
+Chow!" His right hand, meantime, describing stately circles--for it was
+representing a forty-foot wheel.
+
+"Let her go back on the labboard! Ting-a-lingling! Chow-ch-chow-chow!"
+The left hand began to describe circles.
+
+"Stop the stabboard! Ting-a-ling-ling! Stop the labboard! Come ahead
+on the stabboard! Stop her! Let your outside turn over slow!
+Ting-a-ling-ling! Chow-ow-ow! Get out that head-line! LIVELY now!
+Come--out with your spring-line--what're you about there! Take a turn
+round that stump with the bight of it! Stand by that stage, now--let her
+go! Done with the engines, sir! Ting-a-ling-ling! SH'T! S'H'T! SH'T!"
+(trying the gauge-cocks).
+
+Tom went on whitewashing--paid no attention to the steamboat. Ben
+stared a moment and then said: "Hi-YI! YOU'RE up a stump, ain't you!"
+
+No answer. Tom surveyed his last touch with the eye of an artist, then
+he gave his brush another gentle sweep and surveyed the result, as
+before. Ben ranged up alongside of him. Tom's mouth watered for the
+apple, but he stuck to his work. Ben said:
+
+"Hello, old chap, you got to work, hey?"
+
+Tom wheeled suddenly and said:
+
+"Why, it's you, Ben! I warn't noticing."
+
+"Say--I'm going in a-swimming, I am. Don't you wish you could? But of
+course you'd druther WORK--wouldn't you? Course you would!"
+
+Tom contemplated the boy a bit, and said:
+
+"What do you call work?"
+
+"Why, ain't THAT work?"
+
+Tom resumed his whitewashing, and answered carelessly:
+
+"Well, maybe it is, and maybe it ain't. All I know, is, it suits Tom
+Sawyer."
+
+"Oh come, now, you don't mean to let on that you LIKE it?"
+
+The brush continued to move.
+
+"Like it? Well, I don't see why I oughtn't to like it. Does a boy get
+a chance to whitewash a fence every day?"
+
+That put the thing in a new light. Ben stopped nibbling his apple. Tom
+swept his brush daintily back and forth--stepped back to note the
+effect--added a touch here and there--criticised the effect again--Ben
+watching every move and getting more and more interested, more and more
+absorbed. Presently he said:
+
+"Say, Tom, let ME whitewash a little."
+
+Tom considered, was about to consent; but he altered his mind:
+
+"No--no--I reckon it wouldn't hardly do, Ben. You see, Aunt Polly's
+awful particular about this fence--right here on the street, you know
+--but if it was the back fence I wouldn't mind and SHE wouldn't. Yes,
+she's awful particular about this fence; it's got to be done very
+careful; I reckon there ain't one boy in a thousand, maybe two
+thousand, that can do it the way it's got to be done."
+
+"No--is that so? Oh come, now--lemme just try. Only just a little--I'd
+let YOU, if you was me, Tom."
+
+"Ben, I'd like to, honest injun; but Aunt Polly--well, Jim wanted to
+do it, but she wouldn't let him; Sid wanted to do it, and she wouldn't
+let Sid. Now don't you see how I'm fixed? If you was to tackle this
+fence and anything was to happen to it--"
+
+"Oh, shucks, I'll be just as careful. Now lemme try. Say--I'll give
+you the core of my apple."
+
+"Well, here--No, Ben, now don't. I'm afeard--"
+
+"I'll give you ALL of it!"
+
+Tom gave up the brush with reluctance in his face, but alacrity in his
+heart. And while the late steamer Big Missouri worked and sweated in
+the sun, the retired artist sat on a barrel in the shade close by,
+dangled his legs, munched his apple, and planned the slaughter of more
+innocents. There was no lack of material; boys happened along every
+little while; they came to jeer, but remained to whitewash. By the time
+Ben was fagged out, Tom had traded the next chance to Billy Fisher for
+a kite, in good repair; and when he played out, Johnny Miller bought in
+for a dead rat and a string to swing it with--and so on, and so on,
+hour after hour. And when the middle of the afternoon came, from being
+a poor poverty-stricken boy in the morning, Tom was literally rolling
+in wealth. He had besides the things before mentioned, twelve marbles,
+part of a jews-harp, a piece of blue bottle-glass to look through, a
+spool cannon, a key that wouldn't unlock anything, a fragment of chalk,
+a glass stopper of a decanter, a tin soldier, a couple of tadpoles, six
+fire-crackers, a kitten with only one eye, a brass doorknob, a
+dog-collar--but no dog--the handle of a knife, four pieces of
+orange-peel, and a dilapidated old window sash.
+
+He had had a nice, good, idle time all the while--plenty of company
+--and the fence had three coats of whitewash on it! If he hadn't run out
+of whitewash he would have bankrupted every boy in the village.
+
+Tom said to himself that it was not such a hollow world, after all. He
+had discovered a great law of human action, without knowing it--namely,
+that in order to make a man or a boy covet a thing, it is only
+necessary to make the thing difficult to attain. If he had been a great
+and wise philosopher, like the writer of this book, he would now have
+comprehended that Work consists of whatever a body is OBLIGED to do,
+and that Play consists of whatever a body is not obliged to do. And
+this would help him to understand why constructing artificial flowers
+or performing on a tread-mill is work, while rolling ten-pins or
+climbing Mont Blanc is only amusement. There are wealthy gentlemen in
+England who drive four-horse passenger-coaches twenty or thirty miles
+on a daily line, in the summer, because the privilege costs them
+considerable money; but if they were offered wages for the service,
+that would turn it into work and then they would resign.
+
+The boy mused awhile over the substantial change which had taken place
+in his worldly circumstances, and then wended toward headquarters to
+report.
+
+
+
+CHAPTER III
+
+TOM presented himself before Aunt Polly, who was sitting by an open
+window in a pleasant rearward apartment, which was bedroom,
+breakfast-room, dining-room, and library, combined. The balmy summer
+air, the restful quiet, the odor of the flowers, and the drowsing murmur
+of the bees had had their effect, and she was nodding over her knitting
+--for she had no company but the cat, and it was asleep in her lap. Her
+spectacles were propped up on her gray head for safety. She had thought
+that of course Tom had deserted long ago, and she wondered at seeing him
+place himself in her power again in this intrepid way. He said: "Mayn't
+I go and play now, aunt?"
+
+"What, a'ready? How much have you done?"
+
+"It's all done, aunt."
+
+"Tom, don't lie to me--I can't bear it."
+
+"I ain't, aunt; it IS all done."
+
+Aunt Polly placed small trust in such evidence. She went out to see
+for herself; and she would have been content to find twenty per cent.
+of Tom's statement true. When she found the entire fence whitewashed,
+and not only whitewashed but elaborately coated and recoated, and even
+a streak added to the ground, her astonishment was almost unspeakable.
+She said:
+
+"Well, I never! There's no getting round it, you can work when you're
+a mind to, Tom." And then she diluted the compliment by adding, "But
+it's powerful seldom you're a mind to, I'm bound to say. Well, go 'long
+and play; but mind you get back some time in a week, or I'll tan you."
+
+She was so overcome by the splendor of his achievement that she took
+him into the closet and selected a choice apple and delivered it to
+him, along with an improving lecture upon the added value and flavor a
+treat took to itself when it came without sin through virtuous effort.
+And while she closed with a happy Scriptural flourish, he "hooked" a
+doughnut.
+
+Then he skipped out, and saw Sid just starting up the outside stairway
+that led to the back rooms on the second floor. Clods were handy and
+the air was full of them in a twinkling. They raged around Sid like a
+hail-storm; and before Aunt Polly could collect her surprised faculties
+and sally to the rescue, six or seven clods had taken personal effect,
+and Tom was over the fence and gone. There was a gate, but as a general
+thing he was too crowded for time to make use of it. His soul was at
+peace, now that he had settled with Sid for calling attention to his
+black thread and getting him into trouble.
+
+Tom skirted the block, and came round into a muddy alley that led by
+the back of his aunt's cow-stable. He presently got safely beyond the
+reach of capture and punishment, and hastened toward the public square
+of the village, where two "military" companies of boys had met for
+conflict, according to previous appointment. Tom was General of one of
+these armies, Joe Harper (a bosom friend) General of the other. These
+two great commanders did not condescend to fight in person--that being
+better suited to the still smaller fry--but sat together on an eminence
+and conducted the field operations by orders delivered through
+aides-de-camp. Tom's army won a great victory, after a long and
+hard-fought battle. Then the dead were counted, prisoners exchanged,
+the terms of the next disagreement agreed upon, and the day for the
+necessary battle appointed; after which the armies fell into line and
+marched away, and Tom turned homeward alone.
+
+As he was passing by the house where Jeff Thatcher lived, he saw a new
+girl in the garden--a lovely little blue-eyed creature with yellow hair
+plaited into two long-tails, white summer frock and embroidered
+pantalettes. The fresh-crowned hero fell without firing a shot. A
+certain Amy Lawrence vanished out of his heart and left not even a
+memory of herself behind. He had thought he loved her to distraction;
+he had regarded his passion as adoration; and behold it was only a poor
+little evanescent partiality. He had been months winning her; she had
+confessed hardly a week ago; he had been the happiest and the proudest
+boy in the world only seven short days, and here in one instant of time
+she had gone out of his heart like a casual stranger whose visit is
+done.
+
+He worshipped this new angel with furtive eye, till he saw that she
+had discovered him; then he pretended he did not know she was present,
+and began to "show off" in all sorts of absurd boyish ways, in order to
+win her admiration. He kept up this grotesque foolishness for some
+time; but by-and-by, while he was in the midst of some dangerous
+gymnastic performances, he glanced aside and saw that the little girl
+was wending her way toward the house. Tom came up to the fence and
+leaned on it, grieving, and hoping she would tarry yet awhile longer.
+She halted a moment on the steps and then moved toward the door. Tom
+heaved a great sigh as she put her foot on the threshold. But his face
+lit up, right away, for she tossed a pansy over the fence a moment
+before she disappeared.
+
+The boy ran around and stopped within a foot or two of the flower, and
+then shaded his eyes with his hand and began to look down street as if
+he had discovered something of interest going on in that direction.
+Presently he picked up a straw and began trying to balance it on his
+nose, with his head tilted far back; and as he moved from side to side,
+in his efforts, he edged nearer and nearer toward the pansy; finally
+his bare foot rested upon it, his pliant toes closed upon it, and he
+hopped away with the treasure and disappeared round the corner. But
+only for a minute--only while he could button the flower inside his
+jacket, next his heart--or next his stomach, possibly, for he was not
+much posted in anatomy, and not hypercritical, anyway.
+
+He returned, now, and hung about the fence till nightfall, "showing
+off," as before; but the girl never exhibited herself again, though Tom
+comforted himself a little with the hope that she had been near some
+window, meantime, and been aware of his attentions. Finally he strode
+home reluctantly, with his poor head full of visions.
+
+All through supper his spirits were so high that his aunt wondered
+"what had got into the child." He took a good scolding about clodding
+Sid, and did not seem to mind it in the least. He tried to steal sugar
+under his aunt's very nose, and got his knuckles rapped for it. He said:
+
+"Aunt, you don't whack Sid when he takes it."
+
+"Well, Sid don't torment a body the way you do. You'd be always into
+that sugar if I warn't watching you."
+
+Presently she stepped into the kitchen, and Sid, happy in his
+immunity, reached for the sugar-bowl--a sort of glorying over Tom which
+was wellnigh unbearable. But Sid's fingers slipped and the bowl dropped
+and broke. Tom was in ecstasies. In such ecstasies that he even
+controlled his tongue and was silent. He said to himself that he would
+not speak a word, even when his aunt came in, but would sit perfectly
+still till she asked who did the mischief; and then he would tell, and
+there would be nothing so good in the world as to see that pet model
+"catch it." He was so brimful of exultation that he could hardly hold
+himself when the old lady came back and stood above the wreck
+discharging lightnings of wrath from over her spectacles. He said to
+himself, "Now it's coming!" And the next instant he was sprawling on
+the floor! The potent palm was uplifted to strike again when Tom cried
+out:
+
+"Hold on, now, what 'er you belting ME for?--Sid broke it!"
+
+Aunt Polly paused, perplexed, and Tom looked for healing pity. But
+when she got her tongue again, she only said:
+
+"Umf! Well, you didn't get a lick amiss, I reckon. You been into some
+other audacious mischief when I wasn't around, like enough."
+
+Then her conscience reproached her, and she yearned to say something
+kind and loving; but she judged that this would be construed into a
+confession that she had been in the wrong, and discipline forbade that.
+So she kept silence, and went about her affairs with a troubled heart.
+Tom sulked in a corner and exalted his woes. He knew that in her heart
+his aunt was on her knees to him, and he was morosely gratified by the
+consciousness of it. He would hang out no signals, he would take notice
+of none. He knew that a yearning glance fell upon him, now and then,
+through a film of tears, but he refused recognition of it. He pictured
+himself lying sick unto death and his aunt bending over him beseeching
+one little forgiving word, but he would turn his face to the wall, and
+die with that word unsaid. Ah, how would she feel then? And he pictured
+himself brought home from the river, dead, with his curls all wet, and
+his sore heart at rest. How she would throw herself upon him, and how
+her tears would fall like rain, and her lips pray God to give her back
+her boy and she would never, never abuse him any more! But he would lie
+there cold and white and make no sign--a poor little sufferer, whose
+griefs were at an end. He so worked upon his feelings with the pathos
+of these dreams, that he had to keep swallowing, he was so like to
+choke; and his eyes swam in a blur of water, which overflowed when he
+winked, and ran down and trickled from the end of his nose. And such a
+luxury to him was this petting of his sorrows, that he could not bear
+to have any worldly cheeriness or any grating delight intrude upon it;
+it was too sacred for such contact; and so, presently, when his cousin
+Mary danced in, all alive with the joy of seeing home again after an
+age-long visit of one week to the country, he got up and moved in
+clouds and darkness out at one door as she brought song and sunshine in
+at the other.
+
+He wandered far from the accustomed haunts of boys, and sought
+desolate places that were in harmony with his spirit. A log raft in the
+river invited him, and he seated himself on its outer edge and
+contemplated the dreary vastness of the stream, wishing, the while,
+that he could only be drowned, all at once and unconsciously, without
+undergoing the uncomfortable routine devised by nature. Then he thought
+of his flower. He got it out, rumpled and wilted, and it mightily
+increased his dismal felicity. He wondered if she would pity him if she
+knew? Would she cry, and wish that she had a right to put her arms
+around his neck and comfort him? Or would she turn coldly away like all
+the hollow world? This picture brought such an agony of pleasurable
+suffering that he worked it over and over again in his mind and set it
+up in new and varied lights, till he wore it threadbare. At last he
+rose up sighing and departed in the darkness.
+
+About half-past nine or ten o'clock he came along the deserted street
+to where the Adored Unknown lived; he paused a moment; no sound fell
+upon his listening ear; a candle was casting a dull glow upon the
+curtain of a second-story window. Was the sacred presence there? He
+climbed the fence, threaded his stealthy way through the plants, till
+he stood under that window; he looked up at it long, and with emotion;
+then he laid him down on the ground under it, disposing himself upon
+his back, with his hands clasped upon his breast and holding his poor
+wilted flower. And thus he would die--out in the cold world, with no
+shelter over his homeless head, no friendly hand to wipe the
+death-damps from his brow, no loving face to bend pityingly over him
+when the great agony came. And thus SHE would see him when she looked
+out upon the glad morning, and oh! would she drop one little tear upon
+his poor, lifeless form, would she heave one little sigh to see a bright
+young life so rudely blighted, so untimely cut down?
+
+The window went up, a maid-servant's discordant voice profaned the
+holy calm, and a deluge of water drenched the prone martyr's remains!
+
+The strangling hero sprang up with a relieving snort. There was a whiz
+as of a missile in the air, mingled with the murmur of a curse, a sound
+as of shivering glass followed, and a small, vague form went over the
+fence and shot away in the gloom.
+
+Not long after, as Tom, all undressed for bed, was surveying his
+drenched garments by the light of a tallow dip, Sid woke up; but if he
+had any dim idea of making any "references to allusions," he thought
+better of it and held his peace, for there was danger in Tom's eye.
+
+Tom turned in without the added vexation of prayers, and Sid made
+mental note of the omission.
+
+
+
+CHAPTER IV
+
+THE sun rose upon a tranquil world, and beamed down upon the peaceful
+village like a benediction. Breakfast over, Aunt Polly had family
+worship: it began with a prayer built from the ground up of solid
+courses of Scriptural quotations, welded together with a thin mortar of
+originality; and from the summit of this she delivered a grim chapter
+of the Mosaic Law, as from Sinai.
+
+Then Tom girded up his loins, so to speak, and went to work to "get
+his verses." Sid had learned his lesson days before. Tom bent all his
+energies to the memorizing of five verses, and he chose part of the
+Sermon on the Mount, because he could find no verses that were shorter.
+At the end of half an hour Tom had a vague general idea of his lesson,
+but no more, for his mind was traversing the whole field of human
+thought, and his hands were busy with distracting recreations. Mary
+took his book to hear him recite, and he tried to find his way through
+the fog:
+
+"Blessed are the--a--a--"
+
+"Poor"--
+
+"Yes--poor; blessed are the poor--a--a--"
+
+"In spirit--"
+
+"In spirit; blessed are the poor in spirit, for they--they--"
+
+"THEIRS--"
+
+"For THEIRS. Blessed are the poor in spirit, for theirs is the kingdom
+of heaven. Blessed are they that mourn, for they--they--"
+
+"Sh--"
+
+"For they--a--"
+
+"S, H, A--"
+
+"For they S, H--Oh, I don't know what it is!"
+
+"SHALL!"
+
+"Oh, SHALL! for they shall--for they shall--a--a--shall mourn--a--a--
+blessed are they that shall--they that--a--they that shall mourn, for
+they shall--a--shall WHAT? Why don't you tell me, Mary?--what do you
+want to be so mean for?"
+
+"Oh, Tom, you poor thick-headed thing, I'm not teasing you. I wouldn't
+do that. You must go and learn it again. Don't you be discouraged, Tom,
+you'll manage it--and if you do, I'll give you something ever so nice.
+There, now, that's a good boy."
+
+"All right! What is it, Mary, tell me what it is."
+
+"Never you mind, Tom. You know if I say it's nice, it is nice."
+
+"You bet you that's so, Mary. All right, I'll tackle it again."
+
+And he did "tackle it again"--and under the double pressure of
+curiosity and prospective gain he did it with such spirit that he
+accomplished a shining success. Mary gave him a brand-new "Barlow"
+knife worth twelve and a half cents; and the convulsion of delight that
+swept his system shook him to his foundations. True, the knife would
+not cut anything, but it was a "sure-enough" Barlow, and there was
+inconceivable grandeur in that--though where the Western boys ever got
+the idea that such a weapon could possibly be counterfeited to its
+injury is an imposing mystery and will always remain so, perhaps. Tom
+contrived to scarify the cupboard with it, and was arranging to begin
+on the bureau, when he was called off to dress for Sunday-school.
+
+Mary gave him a tin basin of water and a piece of soap, and he went
+outside the door and set the basin on a little bench there; then he
+dipped the soap in the water and laid it down; turned up his sleeves;
+poured out the water on the ground, gently, and then entered the
+kitchen and began to wipe his face diligently on the towel behind the
+door. But Mary removed the towel and said:
+
+"Now ain't you ashamed, Tom. You mustn't be so bad. Water won't hurt
+you."
+
+Tom was a trifle disconcerted. The basin was refilled, and this time
+he stood over it a little while, gathering resolution; took in a big
+breath and began. When he entered the kitchen presently, with both eyes
+shut and groping for the towel with his hands, an honorable testimony
+of suds and water was dripping from his face. But when he emerged from
+the towel, he was not yet satisfactory, for the clean territory stopped
+short at his chin and his jaws, like a mask; below and beyond this line
+there was a dark expanse of unirrigated soil that spread downward in
+front and backward around his neck. Mary took him in hand, and when she
+was done with him he was a man and a brother, without distinction of
+color, and his saturated hair was neatly brushed, and its short curls
+wrought into a dainty and symmetrical general effect. [He privately
+smoothed out the curls, with labor and difficulty, and plastered his
+hair close down to his head; for he held curls to be effeminate, and
+his own filled his life with bitterness.] Then Mary got out a suit of
+his clothing that had been used only on Sundays during two years--they
+were simply called his "other clothes"--and so by that we know the
+size of his wardrobe. The girl "put him to rights" after he had dressed
+himself; she buttoned his neat roundabout up to his chin, turned his
+vast shirt collar down over his shoulders, brushed him off and crowned
+him with his speckled straw hat. He now looked exceedingly improved and
+uncomfortable. He was fully as uncomfortable as he looked; for there
+was a restraint about whole clothes and cleanliness that galled him. He
+hoped that Mary would forget his shoes, but the hope was blighted; she
+coated them thoroughly with tallow, as was the custom, and brought them
+out. He lost his temper and said he was always being made to do
+everything he didn't want to do. But Mary said, persuasively:
+
+"Please, Tom--that's a good boy."
+
+So he got into the shoes snarling. Mary was soon ready, and the three
+children set out for Sunday-school--a place that Tom hated with his
+whole heart; but Sid and Mary were fond of it.
+
+Sabbath-school hours were from nine to half-past ten; and then church
+service. Two of the children always remained for the sermon
+voluntarily, and the other always remained too--for stronger reasons.
+The church's high-backed, uncushioned pews would seat about three
+hundred persons; the edifice was but a small, plain affair, with a sort
+of pine board tree-box on top of it for a steeple. At the door Tom
+dropped back a step and accosted a Sunday-dressed comrade:
+
+"Say, Billy, got a yaller ticket?"
+
+"Yes."
+
+"What'll you take for her?"
+
+"What'll you give?"
+
+"Piece of lickrish and a fish-hook."
+
+"Less see 'em."
+
+Tom exhibited. They were satisfactory, and the property changed hands.
+Then Tom traded a couple of white alleys for three red tickets, and
+some small trifle or other for a couple of blue ones. He waylaid other
+boys as they came, and went on buying tickets of various colors ten or
+fifteen minutes longer. He entered the church, now, with a swarm of
+clean and noisy boys and girls, proceeded to his seat and started a
+quarrel with the first boy that came handy. The teacher, a grave,
+elderly man, interfered; then turned his back a moment and Tom pulled a
+boy's hair in the next bench, and was absorbed in his book when the boy
+turned around; stuck a pin in another boy, presently, in order to hear
+him say "Ouch!" and got a new reprimand from his teacher. Tom's whole
+class were of a pattern--restless, noisy, and troublesome. When they
+came to recite their lessons, not one of them knew his verses
+perfectly, but had to be prompted all along. However, they worried
+through, and each got his reward--in small blue tickets, each with a
+passage of Scripture on it; each blue ticket was pay for two verses of
+the recitation. Ten blue tickets equalled a red one, and could be
+exchanged for it; ten red tickets equalled a yellow one; for ten yellow
+tickets the superintendent gave a very plainly bound Bible (worth forty
+cents in those easy times) to the pupil. How many of my readers would
+have the industry and application to memorize two thousand verses, even
+for a Dore Bible? And yet Mary had acquired two Bibles in this way--it
+was the patient work of two years--and a boy of German parentage had
+won four or five. He once recited three thousand verses without
+stopping; but the strain upon his mental faculties was too great, and
+he was little better than an idiot from that day forth--a grievous
+misfortune for the school, for on great occasions, before company, the
+superintendent (as Tom expressed it) had always made this boy come out
+and "spread himself." Only the older pupils managed to keep their
+tickets and stick to their tedious work long enough to get a Bible, and
+so the delivery of one of these prizes was a rare and noteworthy
+circumstance; the successful pupil was so great and conspicuous for
+that day that on the spot every scholar's heart was fired with a fresh
+ambition that often lasted a couple of weeks. It is possible that Tom's
+mental stomach had never really hungered for one of those prizes, but
+unquestionably his entire being had for many a day longed for the glory
+and the eclat that came with it.
+
+In due course the superintendent stood up in front of the pulpit, with
+a closed hymn-book in his hand and his forefinger inserted between its
+leaves, and commanded attention. When a Sunday-school superintendent
+makes his customary little speech, a hymn-book in the hand is as
+necessary as is the inevitable sheet of music in the hand of a singer
+who stands forward on the platform and sings a solo at a concert
+--though why, is a mystery: for neither the hymn-book nor the sheet of
+music is ever referred to by the sufferer. This superintendent was a
+slim creature of thirty-five, with a sandy goatee and short sandy hair;
+he wore a stiff standing-collar whose upper edge almost reached his
+ears and whose sharp points curved forward abreast the corners of his
+mouth--a fence that compelled a straight lookout ahead, and a turning
+of the whole body when a side view was required; his chin was propped
+on a spreading cravat which was as broad and as long as a bank-note,
+and had fringed ends; his boot toes were turned sharply up, in the
+fashion of the day, like sleigh-runners--an effect patiently and
+laboriously produced by the young men by sitting with their toes
+pressed against a wall for hours together. Mr. Walters was very earnest
+of mien, and very sincere and honest at heart; and he held sacred
+things and places in such reverence, and so separated them from worldly
+matters, that unconsciously to himself his Sunday-school voice had
+acquired a peculiar intonation which was wholly absent on week-days. He
+began after this fashion:
+
+"Now, children, I want you all to sit up just as straight and pretty
+as you can and give me all your attention for a minute or two. There
+--that is it. That is the way good little boys and girls should do. I see
+one little girl who is looking out of the window--I am afraid she
+thinks I am out there somewhere--perhaps up in one of the trees making
+a speech to the little birds. [Applausive titter.] I want to tell you
+how good it makes me feel to see so many bright, clean little faces
+assembled in a place like this, learning to do right and be good." And
+so forth and so on. It is not necessary to set down the rest of the
+oration. It was of a pattern which does not vary, and so it is familiar
+to us all.
+
+The latter third of the speech was marred by the resumption of fights
+and other recreations among certain of the bad boys, and by fidgetings
+and whisperings that extended far and wide, washing even to the bases
+of isolated and incorruptible rocks like Sid and Mary. But now every
+sound ceased suddenly, with the subsidence of Mr. Walters' voice, and
+the conclusion of the speech was received with a burst of silent
+gratitude.
+
+A good part of the whispering had been occasioned by an event which
+was more or less rare--the entrance of visitors: lawyer Thatcher,
+accompanied by a very feeble and aged man; a fine, portly, middle-aged
+gentleman with iron-gray hair; and a dignified lady who was doubtless
+the latter's wife. The lady was leading a child. Tom had been restless
+and full of chafings and repinings; conscience-smitten, too--he could
+not meet Amy Lawrence's eye, he could not brook her loving gaze. But
+when he saw this small new-comer his soul was all ablaze with bliss in
+a moment. The next moment he was "showing off" with all his might
+--cuffing boys, pulling hair, making faces--in a word, using every art
+that seemed likely to fascinate a girl and win her applause. His
+exaltation had but one alloy--the memory of his humiliation in this
+angel's garden--and that record in sand was fast washing out, under
+the waves of happiness that were sweeping over it now.
+
+The visitors were given the highest seat of honor, and as soon as Mr.
+Walters' speech was finished, he introduced them to the school. The
+middle-aged man turned out to be a prodigious personage--no less a one
+than the county judge--altogether the most august creation these
+children had ever looked upon--and they wondered what kind of material
+he was made of--and they half wanted to hear him roar, and were half
+afraid he might, too. He was from Constantinople, twelve miles away--so
+he had travelled, and seen the world--these very eyes had looked upon
+the county court-house--which was said to have a tin roof. The awe
+which these reflections inspired was attested by the impressive silence
+and the ranks of staring eyes. This was the great Judge Thatcher,
+brother of their own lawyer. Jeff Thatcher immediately went forward, to
+be familiar with the great man and be envied by the school. It would
+have been music to his soul to hear the whisperings:
+
+"Look at him, Jim! He's a going up there. Say--look! he's a going to
+shake hands with him--he IS shaking hands with him! By jings, don't you
+wish you was Jeff?"
+
+Mr. Walters fell to "showing off," with all sorts of official
+bustlings and activities, giving orders, delivering judgments,
+discharging directions here, there, everywhere that he could find a
+target. The librarian "showed off"--running hither and thither with his
+arms full of books and making a deal of the splutter and fuss that
+insect authority delights in. The young lady teachers "showed off"
+--bending sweetly over pupils that were lately being boxed, lifting
+pretty warning fingers at bad little boys and patting good ones
+lovingly. The young gentlemen teachers "showed off" with small
+scoldings and other little displays of authority and fine attention to
+discipline--and most of the teachers, of both sexes, found business up
+at the library, by the pulpit; and it was business that frequently had
+to be done over again two or three times (with much seeming vexation).
+The little girls "showed off" in various ways, and the little boys
+"showed off" with such diligence that the air was thick with paper wads
+and the murmur of scufflings. And above it all the great man sat and
+beamed a majestic judicial smile upon all the house, and warmed himself
+in the sun of his own grandeur--for he was "showing off," too.
+
+There was only one thing wanting to make Mr. Walters' ecstasy
+complete, and that was a chance to deliver a Bible-prize and exhibit a
+prodigy. Several pupils had a few yellow tickets, but none had enough
+--he had been around among the star pupils inquiring. He would have given
+worlds, now, to have that German lad back again with a sound mind.
+
+And now at this moment, when hope was dead, Tom Sawyer came forward
+with nine yellow tickets, nine red tickets, and ten blue ones, and
+demanded a Bible. This was a thunderbolt out of a clear sky. Walters
+was not expecting an application from this source for the next ten
+years. But there was no getting around it--here were the certified
+checks, and they were good for their face. Tom was therefore elevated
+to a place with the Judge and the other elect, and the great news was
+announced from headquarters. It was the most stunning surprise of the
+decade, and so profound was the sensation that it lifted the new hero
+up to the judicial one's altitude, and the school had two marvels to
+gaze upon in place of one. The boys were all eaten up with envy--but
+those that suffered the bitterest pangs were those who perceived too
+late that they themselves had contributed to this hated splendor by
+trading tickets to Tom for the wealth he had amassed in selling
+whitewashing privileges. These despised themselves, as being the dupes
+of a wily fraud, a guileful snake in the grass.
+
+The prize was delivered to Tom with as much effusion as the
+superintendent could pump up under the circumstances; but it lacked
+somewhat of the true gush, for the poor fellow's instinct taught him
+that there was a mystery here that could not well bear the light,
+perhaps; it was simply preposterous that this boy had warehoused two
+thousand sheaves of Scriptural wisdom on his premises--a dozen would
+strain his capacity, without a doubt.
+
+Amy Lawrence was proud and glad, and she tried to make Tom see it in
+her face--but he wouldn't look. She wondered; then she was just a grain
+troubled; next a dim suspicion came and went--came again; she watched;
+a furtive glance told her worlds--and then her heart broke, and she was
+jealous, and angry, and the tears came and she hated everybody. Tom
+most of all (she thought).
+
+Tom was introduced to the Judge; but his tongue was tied, his breath
+would hardly come, his heart quaked--partly because of the awful
+greatness of the man, but mainly because he was her parent. He would
+have liked to fall down and worship him, if it were in the dark. The
+Judge put his hand on Tom's head and called him a fine little man, and
+asked him what his name was. The boy stammered, gasped, and got it out:
+
+"Tom."
+
+"Oh, no, not Tom--it is--"
+
+"Thomas."
+
+"Ah, that's it. I thought there was more to it, maybe. That's very
+well. But you've another one I daresay, and you'll tell it to me, won't
+you?"
+
+"Tell the gentleman your other name, Thomas," said Walters, "and say
+sir. You mustn't forget your manners."
+
+"Thomas Sawyer--sir."
+
+"That's it! That's a good boy. Fine boy. Fine, manly little fellow.
+Two thousand verses is a great many--very, very great many. And you
+never can be sorry for the trouble you took to learn them; for
+knowledge is worth more than anything there is in the world; it's what
+makes great men and good men; you'll be a great man and a good man
+yourself, some day, Thomas, and then you'll look back and say, It's all
+owing to the precious Sunday-school privileges of my boyhood--it's all
+owing to my dear teachers that taught me to learn--it's all owing to
+the good superintendent, who encouraged me, and watched over me, and
+gave me a beautiful Bible--a splendid elegant Bible--to keep and have
+it all for my own, always--it's all owing to right bringing up! That is
+what you will say, Thomas--and you wouldn't take any money for those
+two thousand verses--no indeed you wouldn't. And now you wouldn't mind
+telling me and this lady some of the things you've learned--no, I know
+you wouldn't--for we are proud of little boys that learn. Now, no
+doubt you know the names of all the twelve disciples. Won't you tell us
+the names of the first two that were appointed?"
+
+Tom was tugging at a button-hole and looking sheepish. He blushed,
+now, and his eyes fell. Mr. Walters' heart sank within him. He said to
+himself, it is not possible that the boy can answer the simplest
+question--why DID the Judge ask him? Yet he felt obliged to speak up
+and say:
+
+"Answer the gentleman, Thomas--don't be afraid."
+
+Tom still hung fire.
+
+"Now I know you'll tell me," said the lady. "The names of the first
+two disciples were--"
+
+"DAVID AND GOLIAH!"
+
+Let us draw the curtain of charity over the rest of the scene.
+
+
+
+CHAPTER V
+
+ABOUT half-past ten the cracked bell of the small church began to
+ring, and presently the people began to gather for the morning sermon.
+The Sunday-school children distributed themselves about the house and
+occupied pews with their parents, so as to be under supervision. Aunt
+Polly came, and Tom and Sid and Mary sat with her--Tom being placed
+next the aisle, in order that he might be as far away from the open
+window and the seductive outside summer scenes as possible. The crowd
+filed up the aisles: the aged and needy postmaster, who had seen better
+days; the mayor and his wife--for they had a mayor there, among other
+unnecessaries; the justice of the peace; the widow Douglass, fair,
+smart, and forty, a generous, good-hearted soul and well-to-do, her
+hill mansion the only palace in the town, and the most hospitable and
+much the most lavish in the matter of festivities that St. Petersburg
+could boast; the bent and venerable Major and Mrs. Ward; lawyer
+Riverson, the new notable from a distance; next the belle of the
+village, followed by a troop of lawn-clad and ribbon-decked young
+heart-breakers; then all the young clerks in town in a body--for they
+had stood in the vestibule sucking their cane-heads, a circling wall of
+oiled and simpering admirers, till the last girl had run their gantlet;
+and last of all came the Model Boy, Willie Mufferson, taking as heedful
+care of his mother as if she were cut glass. He always brought his
+mother to church, and was the pride of all the matrons. The boys all
+hated him, he was so good. And besides, he had been "thrown up to them"
+so much. His white handkerchief was hanging out of his pocket behind, as
+usual on Sundays--accidentally. Tom had no handkerchief, and he looked
+upon boys who had as snobs.
+
+The congregation being fully assembled, now, the bell rang once more,
+to warn laggards and stragglers, and then a solemn hush fell upon the
+church which was only broken by the tittering and whispering of the
+choir in the gallery. The choir always tittered and whispered all
+through service. There was once a church choir that was not ill-bred,
+but I have forgotten where it was, now. It was a great many years ago,
+and I can scarcely remember anything about it, but I think it was in
+some foreign country.
+
+The minister gave out the hymn, and read it through with a relish, in
+a peculiar style which was much admired in that part of the country.
+His voice began on a medium key and climbed steadily up till it reached
+a certain point, where it bore with strong emphasis upon the topmost
+word and then plunged down as if from a spring-board:
+
+ Shall I be car-ri-ed toe the skies, on flow'ry BEDS of ease,
+
+ Whilst others fight to win the prize, and sail thro' BLOODY seas?
+
+He was regarded as a wonderful reader. At church "sociables" he was
+always called upon to read poetry; and when he was through, the ladies
+would lift up their hands and let them fall helplessly in their laps,
+and "wall" their eyes, and shake their heads, as much as to say, "Words
+cannot express it; it is too beautiful, TOO beautiful for this mortal
+earth."
+
+After the hymn had been sung, the Rev. Mr. Sprague turned himself into
+a bulletin-board, and read off "notices" of meetings and societies and
+things till it seemed that the list would stretch out to the crack of
+doom--a queer custom which is still kept up in America, even in cities,
+away here in this age of abundant newspapers. Often, the less there is
+to justify a traditional custom, the harder it is to get rid of it.
+
+And now the minister prayed. A good, generous prayer it was, and went
+into details: it pleaded for the church, and the little children of the
+church; for the other churches of the village; for the village itself;
+for the county; for the State; for the State officers; for the United
+States; for the churches of the United States; for Congress; for the
+President; for the officers of the Government; for poor sailors, tossed
+by stormy seas; for the oppressed millions groaning under the heel of
+European monarchies and Oriental despotisms; for such as have the light
+and the good tidings, and yet have not eyes to see nor ears to hear
+withal; for the heathen in the far islands of the sea; and closed with
+a supplication that the words he was about to speak might find grace
+and favor, and be as seed sown in fertile ground, yielding in time a
+grateful harvest of good. Amen.
+
+There was a rustling of dresses, and the standing congregation sat
+down. The boy whose history this book relates did not enjoy the prayer,
+he only endured it--if he even did that much. He was restive all
+through it; he kept tally of the details of the prayer, unconsciously
+--for he was not listening, but he knew the ground of old, and the
+clergyman's regular route over it--and when a little trifle of new
+matter was interlarded, his ear detected it and his whole nature
+resented it; he considered additions unfair, and scoundrelly. In the
+midst of the prayer a fly had lit on the back of the pew in front of
+him and tortured his spirit by calmly rubbing its hands together,
+embracing its head with its arms, and polishing it so vigorously that
+it seemed to almost part company with the body, and the slender thread
+of a neck was exposed to view; scraping its wings with its hind legs
+and smoothing them to its body as if they had been coat-tails; going
+through its whole toilet as tranquilly as if it knew it was perfectly
+safe. As indeed it was; for as sorely as Tom's hands itched to grab for
+it they did not dare--he believed his soul would be instantly destroyed
+if he did such a thing while the prayer was going on. But with the
+closing sentence his hand began to curve and steal forward; and the
+instant the "Amen" was out the fly was a prisoner of war. His aunt
+detected the act and made him let it go.
+
+The minister gave out his text and droned along monotonously through
+an argument that was so prosy that many a head by and by began to nod
+--and yet it was an argument that dealt in limitless fire and brimstone
+and thinned the predestined elect down to a company so small as to be
+hardly worth the saving. Tom counted the pages of the sermon; after
+church he always knew how many pages there had been, but he seldom knew
+anything else about the discourse. However, this time he was really
+interested for a little while. The minister made a grand and moving
+picture of the assembling together of the world's hosts at the
+millennium when the lion and the lamb should lie down together and a
+little child should lead them. But the pathos, the lesson, the moral of
+the great spectacle were lost upon the boy; he only thought of the
+conspicuousness of the principal character before the on-looking
+nations; his face lit with the thought, and he said to himself that he
+wished he could be that child, if it was a tame lion.
+
+Now he lapsed into suffering again, as the dry argument was resumed.
+Presently he bethought him of a treasure he had and got it out. It was
+a large black beetle with formidable jaws--a "pinchbug," he called it.
+It was in a percussion-cap box. The first thing the beetle did was to
+take him by the finger. A natural fillip followed, the beetle went
+floundering into the aisle and lit on its back, and the hurt finger
+went into the boy's mouth. The beetle lay there working its helpless
+legs, unable to turn over. Tom eyed it, and longed for it; but it was
+safe out of his reach. Other people uninterested in the sermon found
+relief in the beetle, and they eyed it too. Presently a vagrant poodle
+dog came idling along, sad at heart, lazy with the summer softness and
+the quiet, weary of captivity, sighing for change. He spied the beetle;
+the drooping tail lifted and wagged. He surveyed the prize; walked
+around it; smelt at it from a safe distance; walked around it again;
+grew bolder, and took a closer smell; then lifted his lip and made a
+gingerly snatch at it, just missing it; made another, and another;
+began to enjoy the diversion; subsided to his stomach with the beetle
+between his paws, and continued his experiments; grew weary at last,
+and then indifferent and absent-minded. His head nodded, and little by
+little his chin descended and touched the enemy, who seized it. There
+was a sharp yelp, a flirt of the poodle's head, and the beetle fell a
+couple of yards away, and lit on its back once more. The neighboring
+spectators shook with a gentle inward joy, several faces went behind
+fans and handkerchiefs, and Tom was entirely happy. The dog looked
+foolish, and probably felt so; but there was resentment in his heart,
+too, and a craving for revenge. So he went to the beetle and began a
+wary attack on it again; jumping at it from every point of a circle,
+lighting with his fore-paws within an inch of the creature, making even
+closer snatches at it with his teeth, and jerking his head till his
+ears flapped again. But he grew tired once more, after a while; tried
+to amuse himself with a fly but found no relief; followed an ant
+around, with his nose close to the floor, and quickly wearied of that;
+yawned, sighed, forgot the beetle entirely, and sat down on it. Then
+there was a wild yelp of agony and the poodle went sailing up the
+aisle; the yelps continued, and so did the dog; he crossed the house in
+front of the altar; he flew down the other aisle; he crossed before the
+doors; he clamored up the home-stretch; his anguish grew with his
+progress, till presently he was but a woolly comet moving in its orbit
+with the gleam and the speed of light. At last the frantic sufferer
+sheered from its course, and sprang into its master's lap; he flung it
+out of the window, and the voice of distress quickly thinned away and
+died in the distance.
+
+By this time the whole church was red-faced and suffocating with
+suppressed laughter, and the sermon had come to a dead standstill. The
+discourse was resumed presently, but it went lame and halting, all
+possibility of impressiveness being at an end; for even the gravest
+sentiments were constantly being received with a smothered burst of
+unholy mirth, under cover of some remote pew-back, as if the poor
+parson had said a rarely facetious thing. It was a genuine relief to
+the whole congregation when the ordeal was over and the benediction
+pronounced.
+
+Tom Sawyer went home quite cheerful, thinking to himself that there
+was some satisfaction about divine service when there was a bit of
+variety in it. He had but one marring thought; he was willing that the
+dog should play with his pinchbug, but he did not think it was upright
+in him to carry it off.
+
+
+
+CHAPTER VI
+
+MONDAY morning found Tom Sawyer miserable. Monday morning always found
+him so--because it began another week's slow suffering in school. He
+generally began that day with wishing he had had no intervening
+holiday, it made the going into captivity and fetters again so much
+more odious.
+
+Tom lay thinking. Presently it occurred to him that he wished he was
+sick; then he could stay home from school. Here was a vague
+possibility. He canvassed his system. No ailment was found, and he
+investigated again. This time he thought he could detect colicky
+symptoms, and he began to encourage them with considerable hope. But
+they soon grew feeble, and presently died wholly away. He reflected
+further. Suddenly he discovered something. One of his upper front teeth
+was loose. This was lucky; he was about to begin to groan, as a
+"starter," as he called it, when it occurred to him that if he came
+into court with that argument, his aunt would pull it out, and that
+would hurt. So he thought he would hold the tooth in reserve for the
+present, and seek further. Nothing offered for some little time, and
+then he remembered hearing the doctor tell about a certain thing that
+laid up a patient for two or three weeks and threatened to make him
+lose a finger. So the boy eagerly drew his sore toe from under the
+sheet and held it up for inspection. But now he did not know the
+necessary symptoms. However, it seemed well worth while to chance it,
+so he fell to groaning with considerable spirit.
+
+But Sid slept on unconscious.
+
+Tom groaned louder, and fancied that he began to feel pain in the toe.
+
+No result from Sid.
+
+Tom was panting with his exertions by this time. He took a rest and
+then swelled himself up and fetched a succession of admirable groans.
+
+Sid snored on.
+
+Tom was aggravated. He said, "Sid, Sid!" and shook him. This course
+worked well, and Tom began to groan again. Sid yawned, stretched, then
+brought himself up on his elbow with a snort, and began to stare at
+Tom. Tom went on groaning. Sid said:
+
+"Tom! Say, Tom!" [No response.] "Here, Tom! TOM! What is the matter,
+Tom?" And he shook him and looked in his face anxiously.
+
+Tom moaned out:
+
+"Oh, don't, Sid. Don't joggle me."
+
+"Why, what's the matter, Tom? I must call auntie."
+
+"No--never mind. It'll be over by and by, maybe. Don't call anybody."
+
+"But I must! DON'T groan so, Tom, it's awful. How long you been this
+way?"
+
+"Hours. Ouch! Oh, don't stir so, Sid, you'll kill me."
+
+"Tom, why didn't you wake me sooner? Oh, Tom, DON'T! It makes my
+flesh crawl to hear you. Tom, what is the matter?"
+
+"I forgive you everything, Sid. [Groan.] Everything you've ever done
+to me. When I'm gone--"
+
+"Oh, Tom, you ain't dying, are you? Don't, Tom--oh, don't. Maybe--"
+
+"I forgive everybody, Sid. [Groan.] Tell 'em so, Sid. And Sid, you
+give my window-sash and my cat with one eye to that new girl that's
+come to town, and tell her--"
+
+But Sid had snatched his clothes and gone. Tom was suffering in
+reality, now, so handsomely was his imagination working, and so his
+groans had gathered quite a genuine tone.
+
+Sid flew down-stairs and said:
+
+"Oh, Aunt Polly, come! Tom's dying!"
+
+"Dying!"
+
+"Yes'm. Don't wait--come quick!"
+
+"Rubbage! I don't believe it!"
+
+But she fled up-stairs, nevertheless, with Sid and Mary at her heels.
+And her face grew white, too, and her lip trembled. When she reached
+the bedside she gasped out:
+
+"You, Tom! Tom, what's the matter with you?"
+
+"Oh, auntie, I'm--"
+
+"What's the matter with you--what is the matter with you, child?"
+
+"Oh, auntie, my sore toe's mortified!"
+
+The old lady sank down into a chair and laughed a little, then cried a
+little, then did both together. This restored her and she said:
+
+"Tom, what a turn you did give me. Now you shut up that nonsense and
+climb out of this."
+
+The groans ceased and the pain vanished from the toe. The boy felt a
+little foolish, and he said:
+
+"Aunt Polly, it SEEMED mortified, and it hurt so I never minded my
+tooth at all."
+
+"Your tooth, indeed! What's the matter with your tooth?"
+
+"One of them's loose, and it aches perfectly awful."
+
+"There, there, now, don't begin that groaning again. Open your mouth.
+Well--your tooth IS loose, but you're not going to die about that.
+Mary, get me a silk thread, and a chunk of fire out of the kitchen."
+
+Tom said:
+
+"Oh, please, auntie, don't pull it out. It don't hurt any more. I wish
+I may never stir if it does. Please don't, auntie. I don't want to stay
+home from school."
+
+"Oh, you don't, don't you? So all this row was because you thought
+you'd get to stay home from school and go a-fishing? Tom, Tom, I love
+you so, and you seem to try every way you can to break my old heart
+with your outrageousness." By this time the dental instruments were
+ready. The old lady made one end of the silk thread fast to Tom's tooth
+with a loop and tied the other to the bedpost. Then she seized the
+chunk of fire and suddenly thrust it almost into the boy's face. The
+tooth hung dangling by the bedpost, now.
+
+But all trials bring their compensations. As Tom wended to school
+after breakfast, he was the envy of every boy he met because the gap in
+his upper row of teeth enabled him to expectorate in a new and
+admirable way. He gathered quite a following of lads interested in the
+exhibition; and one that had cut his finger and had been a centre of
+fascination and homage up to this time, now found himself suddenly
+without an adherent, and shorn of his glory. His heart was heavy, and
+he said with a disdain which he did not feel that it wasn't anything to
+spit like Tom Sawyer; but another boy said, "Sour grapes!" and he
+wandered away a dismantled hero.
+
+Shortly Tom came upon the juvenile pariah of the village, Huckleberry
+Finn, son of the town drunkard. Huckleberry was cordially hated and
+dreaded by all the mothers of the town, because he was idle and lawless
+and vulgar and bad--and because all their children admired him so, and
+delighted in his forbidden society, and wished they dared to be like
+him. Tom was like the rest of the respectable boys, in that he envied
+Huckleberry his gaudy outcast condition, and was under strict orders
+not to play with him. So he played with him every time he got a chance.
+Huckleberry was always dressed in the cast-off clothes of full-grown
+men, and they were in perennial bloom and fluttering with rags. His hat
+was a vast ruin with a wide crescent lopped out of its brim; his coat,
+when he wore one, hung nearly to his heels and had the rearward buttons
+far down the back; but one suspender supported his trousers; the seat
+of the trousers bagged low and contained nothing, the fringed legs
+dragged in the dirt when not rolled up.
+
+Huckleberry came and went, at his own free will. He slept on doorsteps
+in fine weather and in empty hogsheads in wet; he did not have to go to
+school or to church, or call any being master or obey anybody; he could
+go fishing or swimming when and where he chose, and stay as long as it
+suited him; nobody forbade him to fight; he could sit up as late as he
+pleased; he was always the first boy that went barefoot in the spring
+and the last to resume leather in the fall; he never had to wash, nor
+put on clean clothes; he could swear wonderfully. In a word, everything
+that goes to make life precious that boy had. So thought every
+harassed, hampered, respectable boy in St. Petersburg.
+
+Tom hailed the romantic outcast:
+
+"Hello, Huckleberry!"
+
+"Hello yourself, and see how you like it."
+
+"What's that you got?"
+
+"Dead cat."
+
+"Lemme see him, Huck. My, he's pretty stiff. Where'd you get him?"
+
+"Bought him off'n a boy."
+
+"What did you give?"
+
+"I give a blue ticket and a bladder that I got at the slaughter-house."
+
+"Where'd you get the blue ticket?"
+
+"Bought it off'n Ben Rogers two weeks ago for a hoop-stick."
+
+"Say--what is dead cats good for, Huck?"
+
+"Good for? Cure warts with."
+
+"No! Is that so? I know something that's better."
+
+"I bet you don't. What is it?"
+
+"Why, spunk-water."
+
+"Spunk-water! I wouldn't give a dern for spunk-water."
+
+"You wouldn't, wouldn't you? D'you ever try it?"
+
+"No, I hain't. But Bob Tanner did."
+
+"Who told you so!"
+
+"Why, he told Jeff Thatcher, and Jeff told Johnny Baker, and Johnny
+told Jim Hollis, and Jim told Ben Rogers, and Ben told a nigger, and
+the nigger told me. There now!"
+
+"Well, what of it? They'll all lie. Leastways all but the nigger. I
+don't know HIM. But I never see a nigger that WOULDN'T lie. Shucks! Now
+you tell me how Bob Tanner done it, Huck."
+
+"Why, he took and dipped his hand in a rotten stump where the
+rain-water was."
+
+"In the daytime?"
+
+"Certainly."
+
+"With his face to the stump?"
+
+"Yes. Least I reckon so."
+
+"Did he say anything?"
+
+"I don't reckon he did. I don't know."
+
+"Aha! Talk about trying to cure warts with spunk-water such a blame
+fool way as that! Why, that ain't a-going to do any good. You got to go
+all by yourself, to the middle of the woods, where you know there's a
+spunk-water stump, and just as it's midnight you back up against the
+stump and jam your hand in and say:
+
+ 'Barley-corn, barley-corn, injun-meal shorts,
+ Spunk-water, spunk-water, swaller these warts,'
+
+and then walk away quick, eleven steps, with your eyes shut, and then
+turn around three times and walk home without speaking to anybody.
+Because if you speak the charm's busted."
+
+"Well, that sounds like a good way; but that ain't the way Bob Tanner
+done."
+
+"No, sir, you can bet he didn't, becuz he's the wartiest boy in this
+town; and he wouldn't have a wart on him if he'd knowed how to work
+spunk-water. I've took off thousands of warts off of my hands that way,
+Huck. I play with frogs so much that I've always got considerable many
+warts. Sometimes I take 'em off with a bean."
+
+"Yes, bean's good. I've done that."
+
+"Have you? What's your way?"
+
+"You take and split the bean, and cut the wart so as to get some
+blood, and then you put the blood on one piece of the bean and take and
+dig a hole and bury it 'bout midnight at the crossroads in the dark of
+the moon, and then you burn up the rest of the bean. You see that piece
+that's got the blood on it will keep drawing and drawing, trying to
+fetch the other piece to it, and so that helps the blood to draw the
+wart, and pretty soon off she comes."
+
+"Yes, that's it, Huck--that's it; though when you're burying it if you
+say 'Down bean; off wart; come no more to bother me!' it's better.
+That's the way Joe Harper does, and he's been nearly to Coonville and
+most everywheres. But say--how do you cure 'em with dead cats?"
+
+"Why, you take your cat and go and get in the graveyard 'long about
+midnight when somebody that was wicked has been buried; and when it's
+midnight a devil will come, or maybe two or three, but you can't see
+'em, you can only hear something like the wind, or maybe hear 'em talk;
+and when they're taking that feller away, you heave your cat after 'em
+and say, 'Devil follow corpse, cat follow devil, warts follow cat, I'm
+done with ye!' That'll fetch ANY wart."
+
+"Sounds right. D'you ever try it, Huck?"
+
+"No, but old Mother Hopkins told me."
+
+"Well, I reckon it's so, then. Becuz they say she's a witch."
+
+"Say! Why, Tom, I KNOW she is. She witched pap. Pap says so his own
+self. He come along one day, and he see she was a-witching him, so he
+took up a rock, and if she hadn't dodged, he'd a got her. Well, that
+very night he rolled off'n a shed wher' he was a layin drunk, and broke
+his arm."
+
+"Why, that's awful. How did he know she was a-witching him?"
+
+"Lord, pap can tell, easy. Pap says when they keep looking at you
+right stiddy, they're a-witching you. Specially if they mumble. Becuz
+when they mumble they're saying the Lord's Prayer backards."
+
+"Say, Hucky, when you going to try the cat?"
+
+"To-night. I reckon they'll come after old Hoss Williams to-night."
+
+"But they buried him Saturday. Didn't they get him Saturday night?"
+
+"Why, how you talk! How could their charms work till midnight?--and
+THEN it's Sunday. Devils don't slosh around much of a Sunday, I don't
+reckon."
+
+"I never thought of that. That's so. Lemme go with you?"
+
+"Of course--if you ain't afeard."
+
+"Afeard! 'Tain't likely. Will you meow?"
+
+"Yes--and you meow back, if you get a chance. Last time, you kep' me
+a-meowing around till old Hays went to throwing rocks at me and says
+'Dern that cat!' and so I hove a brick through his window--but don't
+you tell."
+
+"I won't. I couldn't meow that night, becuz auntie was watching me,
+but I'll meow this time. Say--what's that?"
+
+"Nothing but a tick."
+
+"Where'd you get him?"
+
+"Out in the woods."
+
+"What'll you take for him?"
+
+"I don't know. I don't want to sell him."
+
+"All right. It's a mighty small tick, anyway."
+
+"Oh, anybody can run a tick down that don't belong to them. I'm
+satisfied with it. It's a good enough tick for me."
+
+"Sho, there's ticks a plenty. I could have a thousand of 'em if I
+wanted to."
+
+"Well, why don't you? Becuz you know mighty well you can't. This is a
+pretty early tick, I reckon. It's the first one I've seen this year."
+
+"Say, Huck--I'll give you my tooth for him."
+
+"Less see it."
+
+Tom got out a bit of paper and carefully unrolled it. Huckleberry
+viewed it wistfully. The temptation was very strong. At last he said:
+
+"Is it genuwyne?"
+
+Tom lifted his lip and showed the vacancy.
+
+"Well, all right," said Huckleberry, "it's a trade."
+
+Tom enclosed the tick in the percussion-cap box that had lately been
+the pinchbug's prison, and the boys separated, each feeling wealthier
+than before.
+
+When Tom reached the little isolated frame schoolhouse, he strode in
+briskly, with the manner of one who had come with all honest speed.
+He hung his hat on a peg and flung himself into his seat with
+business-like alacrity. The master, throned on high in his great
+splint-bottom arm-chair, was dozing, lulled by the drowsy hum of study.
+The interruption roused him.
+
+"Thomas Sawyer!"
+
+Tom knew that when his name was pronounced in full, it meant trouble.
+
+"Sir!"
+
+"Come up here. Now, sir, why are you late again, as usual?"
+
+Tom was about to take refuge in a lie, when he saw two long tails of
+yellow hair hanging down a back that he recognized by the electric
+sympathy of love; and by that form was THE ONLY VACANT PLACE on the
+girls' side of the schoolhouse. He instantly said:
+
+"I STOPPED TO TALK WITH HUCKLEBERRY FINN!"
+
+The master's pulse stood still, and he stared helplessly. The buzz of
+study ceased. The pupils wondered if this foolhardy boy had lost his
+mind. The master said:
+
+"You--you did what?"
+
+"Stopped to talk with Huckleberry Finn."
+
+There was no mistaking the words.
+
+"Thomas Sawyer, this is the most astounding confession I have ever
+listened to. No mere ferule will answer for this offence. Take off your
+jacket."
+
+The master's arm performed until it was tired and the stock of
+switches notably diminished. Then the order followed:
+
+"Now, sir, go and sit with the girls! And let this be a warning to you."
+
+The titter that rippled around the room appeared to abash the boy, but
+in reality that result was caused rather more by his worshipful awe of
+his unknown idol and the dread pleasure that lay in his high good
+fortune. He sat down upon the end of the pine bench and the girl
+hitched herself away from him with a toss of her head. Nudges and winks
+and whispers traversed the room, but Tom sat still, with his arms upon
+the long, low desk before him, and seemed to study his book.
+
+By and by attention ceased from him, and the accustomed school murmur
+rose upon the dull air once more. Presently the boy began to steal
+furtive glances at the girl. She observed it, "made a mouth" at him and
+gave him the back of her head for the space of a minute. When she
+cautiously faced around again, a peach lay before her. She thrust it
+away. Tom gently put it back. She thrust it away again, but with less
+animosity. Tom patiently returned it to its place. Then she let it
+remain. Tom scrawled on his slate, "Please take it--I got more." The
+girl glanced at the words, but made no sign. Now the boy began to draw
+something on the slate, hiding his work with his left hand. For a time
+the girl refused to notice; but her human curiosity presently began to
+manifest itself by hardly perceptible signs. The boy worked on,
+apparently unconscious. The girl made a sort of noncommittal attempt to
+see, but the boy did not betray that he was aware of it. At last she
+gave in and hesitatingly whispered:
+
+"Let me see it."
+
+Tom partly uncovered a dismal caricature of a house with two gable
+ends to it and a corkscrew of smoke issuing from the chimney. Then the
+girl's interest began to fasten itself upon the work and she forgot
+everything else. When it was finished, she gazed a moment, then
+whispered:
+
+"It's nice--make a man."
+
+The artist erected a man in the front yard, that resembled a derrick.
+He could have stepped over the house; but the girl was not
+hypercritical; she was satisfied with the monster, and whispered:
+
+"It's a beautiful man--now make me coming along."
+
+Tom drew an hour-glass with a full moon and straw limbs to it and
+armed the spreading fingers with a portentous fan. The girl said:
+
+"It's ever so nice--I wish I could draw."
+
+"It's easy," whispered Tom, "I'll learn you."
+
+"Oh, will you? When?"
+
+"At noon. Do you go home to dinner?"
+
+"I'll stay if you will."
+
+"Good--that's a whack. What's your name?"
+
+"Becky Thatcher. What's yours? Oh, I know. It's Thomas Sawyer."
+
+"That's the name they lick me by. I'm Tom when I'm good. You call me
+Tom, will you?"
+
+"Yes."
+
+Now Tom began to scrawl something on the slate, hiding the words from
+the girl. But she was not backward this time. She begged to see. Tom
+said:
+
+"Oh, it ain't anything."
+
+"Yes it is."
+
+"No it ain't. You don't want to see."
+
+"Yes I do, indeed I do. Please let me."
+
+"You'll tell."
+
+"No I won't--deed and deed and double deed won't."
+
+"You won't tell anybody at all? Ever, as long as you live?"
+
+"No, I won't ever tell ANYbody. Now let me."
+
+"Oh, YOU don't want to see!"
+
+"Now that you treat me so, I WILL see." And she put her small hand
+upon his and a little scuffle ensued, Tom pretending to resist in
+earnest but letting his hand slip by degrees till these words were
+revealed: "I LOVE YOU."
+
+"Oh, you bad thing!" And she hit his hand a smart rap, but reddened
+and looked pleased, nevertheless.
+
+Just at this juncture the boy felt a slow, fateful grip closing on his
+ear, and a steady lifting impulse. In that wise he was borne across the
+house and deposited in his own seat, under a peppering fire of giggles
+from the whole school. Then the master stood over him during a few
+awful moments, and finally moved away to his throne without saying a
+word. But although Tom's ear tingled, his heart was jubilant.
+
+As the school quieted down Tom made an honest effort to study, but the
+turmoil within him was too great. In turn he took his place in the
+reading class and made a botch of it; then in the geography class and
+turned lakes into mountains, mountains into rivers, and rivers into
+continents, till chaos was come again; then in the spelling class, and
+got "turned down," by a succession of mere baby words, till he brought
+up at the foot and yielded up the pewter medal which he had worn with
+ostentation for months.
+
+
+
+CHAPTER VII
+
+THE harder Tom tried to fasten his mind on his book, the more his
+ideas wandered. So at last, with a sigh and a yawn, he gave it up. It
+seemed to him that the noon recess would never come. The air was
+utterly dead. There was not a breath stirring. It was the sleepiest of
+sleepy days. The drowsing murmur of the five and twenty studying
+scholars soothed the soul like the spell that is in the murmur of bees.
+Away off in the flaming sunshine, Cardiff Hill lifted its soft green
+sides through a shimmering veil of heat, tinted with the purple of
+distance; a few birds floated on lazy wing high in the air; no other
+living thing was visible but some cows, and they were asleep. Tom's
+heart ached to be free, or else to have something of interest to do to
+pass the dreary time. His hand wandered into his pocket and his face
+lit up with a glow of gratitude that was prayer, though he did not know
+it. Then furtively the percussion-cap box came out. He released the
+tick and put him on the long flat desk. The creature probably glowed
+with a gratitude that amounted to prayer, too, at this moment, but it
+was premature: for when he started thankfully to travel off, Tom turned
+him aside with a pin and made him take a new direction.
+
+Tom's bosom friend sat next him, suffering just as Tom had been, and
+now he was deeply and gratefully interested in this entertainment in an
+instant. This bosom friend was Joe Harper. The two boys were sworn
+friends all the week, and embattled enemies on Saturdays. Joe took a
+pin out of his lapel and began to assist in exercising the prisoner.
+The sport grew in interest momently. Soon Tom said that they were
+interfering with each other, and neither getting the fullest benefit of
+the tick. So he put Joe's slate on the desk and drew a line down the
+middle of it from top to bottom.
+
+"Now," said he, "as long as he is on your side you can stir him up and
+I'll let him alone; but if you let him get away and get on my side,
+you're to leave him alone as long as I can keep him from crossing over."
+
+"All right, go ahead; start him up."
+
+The tick escaped from Tom, presently, and crossed the equator. Joe
+harassed him awhile, and then he got away and crossed back again. This
+change of base occurred often. While one boy was worrying the tick with
+absorbing interest, the other would look on with interest as strong,
+the two heads bowed together over the slate, and the two souls dead to
+all things else. At last luck seemed to settle and abide with Joe. The
+tick tried this, that, and the other course, and got as excited and as
+anxious as the boys themselves, but time and again just as he would
+have victory in his very grasp, so to speak, and Tom's fingers would be
+twitching to begin, Joe's pin would deftly head him off, and keep
+possession. At last Tom could stand it no longer. The temptation was
+too strong. So he reached out and lent a hand with his pin. Joe was
+angry in a moment. Said he:
+
+"Tom, you let him alone."
+
+"I only just want to stir him up a little, Joe."
+
+"No, sir, it ain't fair; you just let him alone."
+
+"Blame it, I ain't going to stir him much."
+
+"Let him alone, I tell you."
+
+"I won't!"
+
+"You shall--he's on my side of the line."
+
+"Look here, Joe Harper, whose is that tick?"
+
+"I don't care whose tick he is--he's on my side of the line, and you
+sha'n't touch him."
+
+"Well, I'll just bet I will, though. He's my tick and I'll do what I
+blame please with him, or die!"
+
+A tremendous whack came down on Tom's shoulders, and its duplicate on
+Joe's; and for the space of two minutes the dust continued to fly from
+the two jackets and the whole school to enjoy it. The boys had been too
+absorbed to notice the hush that had stolen upon the school awhile
+before when the master came tiptoeing down the room and stood over
+them. He had contemplated a good part of the performance before he
+contributed his bit of variety to it.
+
+When school broke up at noon, Tom flew to Becky Thatcher, and
+whispered in her ear:
+
+"Put on your bonnet and let on you're going home; and when you get to
+the corner, give the rest of 'em the slip, and turn down through the
+lane and come back. I'll go the other way and come it over 'em the same
+way."
+
+So the one went off with one group of scholars, and the other with
+another. In a little while the two met at the bottom of the lane, and
+when they reached the school they had it all to themselves. Then they
+sat together, with a slate before them, and Tom gave Becky the pencil
+and held her hand in his, guiding it, and so created another surprising
+house. When the interest in art began to wane, the two fell to talking.
+Tom was swimming in bliss. He said:
+
+"Do you love rats?"
+
+"No! I hate them!"
+
+"Well, I do, too--LIVE ones. But I mean dead ones, to swing round your
+head with a string."
+
+"No, I don't care for rats much, anyway. What I like is chewing-gum."
+
+"Oh, I should say so! I wish I had some now."
+
+"Do you? I've got some. I'll let you chew it awhile, but you must give
+it back to me."
+
+That was agreeable, so they chewed it turn about, and dangled their
+legs against the bench in excess of contentment.
+
+"Was you ever at a circus?" said Tom.
+
+"Yes, and my pa's going to take me again some time, if I'm good."
+
+"I been to the circus three or four times--lots of times. Church ain't
+shucks to a circus. There's things going on at a circus all the time.
+I'm going to be a clown in a circus when I grow up."
+
+"Oh, are you! That will be nice. They're so lovely, all spotted up."
+
+"Yes, that's so. And they get slathers of money--most a dollar a day,
+Ben Rogers says. Say, Becky, was you ever engaged?"
+
+"What's that?"
+
+"Why, engaged to be married."
+
+"No."
+
+"Would you like to?"
+
+"I reckon so. I don't know. What is it like?"
+
+"Like? Why it ain't like anything. You only just tell a boy you won't
+ever have anybody but him, ever ever ever, and then you kiss and that's
+all. Anybody can do it."
+
+"Kiss? What do you kiss for?"
+
+"Why, that, you know, is to--well, they always do that."
+
+"Everybody?"
+
+"Why, yes, everybody that's in love with each other. Do you remember
+what I wrote on the slate?"
+
+"Ye--yes."
+
+"What was it?"
+
+"I sha'n't tell you."
+
+"Shall I tell YOU?"
+
+"Ye--yes--but some other time."
+
+"No, now."
+
+"No, not now--to-morrow."
+
+"Oh, no, NOW. Please, Becky--I'll whisper it, I'll whisper it ever so
+easy."
+
+Becky hesitating, Tom took silence for consent, and passed his arm
+about her waist and whispered the tale ever so softly, with his mouth
+close to her ear. And then he added:
+
+"Now you whisper it to me--just the same."
+
+She resisted, for a while, and then said:
+
+"You turn your face away so you can't see, and then I will. But you
+mustn't ever tell anybody--WILL you, Tom? Now you won't, WILL you?"
+
+"No, indeed, indeed I won't. Now, Becky."
+
+He turned his face away. She bent timidly around till her breath
+stirred his curls and whispered, "I--love--you!"
+
+Then she sprang away and ran around and around the desks and benches,
+with Tom after her, and took refuge in a corner at last, with her
+little white apron to her face. Tom clasped her about her neck and
+pleaded:
+
+"Now, Becky, it's all done--all over but the kiss. Don't you be afraid
+of that--it ain't anything at all. Please, Becky." And he tugged at her
+apron and the hands.
+
+By and by she gave up, and let her hands drop; her face, all glowing
+with the struggle, came up and submitted. Tom kissed the red lips and
+said:
+
+"Now it's all done, Becky. And always after this, you know, you ain't
+ever to love anybody but me, and you ain't ever to marry anybody but
+me, ever never and forever. Will you?"
+
+"No, I'll never love anybody but you, Tom, and I'll never marry
+anybody but you--and you ain't to ever marry anybody but me, either."
+
+"Certainly. Of course. That's PART of it. And always coming to school
+or when we're going home, you're to walk with me, when there ain't
+anybody looking--and you choose me and I choose you at parties, because
+that's the way you do when you're engaged."
+
+"It's so nice. I never heard of it before."
+
+"Oh, it's ever so gay! Why, me and Amy Lawrence--"
+
+The big eyes told Tom his blunder and he stopped, confused.
+
+"Oh, Tom! Then I ain't the first you've ever been engaged to!"
+
+The child began to cry. Tom said:
+
+"Oh, don't cry, Becky, I don't care for her any more."
+
+"Yes, you do, Tom--you know you do."
+
+Tom tried to put his arm about her neck, but she pushed him away and
+turned her face to the wall, and went on crying. Tom tried again, with
+soothing words in his mouth, and was repulsed again. Then his pride was
+up, and he strode away and went outside. He stood about, restless and
+uneasy, for a while, glancing at the door, every now and then, hoping
+she would repent and come to find him. But she did not. Then he began
+to feel badly and fear that he was in the wrong. It was a hard struggle
+with him to make new advances, now, but he nerved himself to it and
+entered. She was still standing back there in the corner, sobbing, with
+her face to the wall. Tom's heart smote him. He went to her and stood a
+moment, not knowing exactly how to proceed. Then he said hesitatingly:
+
+"Becky, I--I don't care for anybody but you."
+
+No reply--but sobs.
+
+"Becky"--pleadingly. "Becky, won't you say something?"
+
+More sobs.
+
+Tom got out his chiefest jewel, a brass knob from the top of an
+andiron, and passed it around her so that she could see it, and said:
+
+"Please, Becky, won't you take it?"
+
+She struck it to the floor. Then Tom marched out of the house and over
+the hills and far away, to return to school no more that day. Presently
+Becky began to suspect. She ran to the door; he was not in sight; she
+flew around to the play-yard; he was not there. Then she called:
+
+"Tom! Come back, Tom!"
+
+She listened intently, but there was no answer. She had no companions
+but silence and loneliness. So she sat down to cry again and upbraid
+herself; and by this time the scholars began to gather again, and she
+had to hide her griefs and still her broken heart and take up the cross
+of a long, dreary, aching afternoon, with none among the strangers
+about her to exchange sorrows with.
+
+
+
+CHAPTER VIII
+
+TOM dodged hither and thither through lanes until he was well out of
+the track of returning scholars, and then fell into a moody jog. He
+crossed a small "branch" two or three times, because of a prevailing
+juvenile superstition that to cross water baffled pursuit. Half an hour
+later he was disappearing behind the Douglas mansion on the summit of
+Cardiff Hill, and the schoolhouse was hardly distinguishable away off
+in the valley behind him. He entered a dense wood, picked his pathless
+way to the centre of it, and sat down on a mossy spot under a spreading
+oak. There was not even a zephyr stirring; the dead noonday heat had
+even stilled the songs of the birds; nature lay in a trance that was
+broken by no sound but the occasional far-off hammering of a
+woodpecker, and this seemed to render the pervading silence and sense
+of loneliness the more profound. The boy's soul was steeped in
+melancholy; his feelings were in happy accord with his surroundings. He
+sat long with his elbows on his knees and his chin in his hands,
+meditating. It seemed to him that life was but a trouble, at best, and
+he more than half envied Jimmy Hodges, so lately released; it must be
+very peaceful, he thought, to lie and slumber and dream forever and
+ever, with the wind whispering through the trees and caressing the
+grass and the flowers over the grave, and nothing to bother and grieve
+about, ever any more. If he only had a clean Sunday-school record he
+could be willing to go, and be done with it all. Now as to this girl.
+What had he done? Nothing. He had meant the best in the world, and been
+treated like a dog--like a very dog. She would be sorry some day--maybe
+when it was too late. Ah, if he could only die TEMPORARILY!
+
+But the elastic heart of youth cannot be compressed into one
+constrained shape long at a time. Tom presently began to drift
+insensibly back into the concerns of this life again. What if he turned
+his back, now, and disappeared mysteriously? What if he went away--ever
+so far away, into unknown countries beyond the seas--and never came
+back any more! How would she feel then! The idea of being a clown
+recurred to him now, only to fill him with disgust. For frivolity and
+jokes and spotted tights were an offense, when they intruded themselves
+upon a spirit that was exalted into the vague august realm of the
+romantic. No, he would be a soldier, and return after long years, all
+war-worn and illustrious. No--better still, he would join the Indians,
+and hunt buffaloes and go on the warpath in the mountain ranges and the
+trackless great plains of the Far West, and away in the future come
+back a great chief, bristling with feathers, hideous with paint, and
+prance into Sunday-school, some drowsy summer morning, with a
+bloodcurdling war-whoop, and sear the eyeballs of all his companions
+with unappeasable envy. But no, there was something gaudier even than
+this. He would be a pirate! That was it! NOW his future lay plain
+before him, and glowing with unimaginable splendor. How his name would
+fill the world, and make people shudder! How gloriously he would go
+plowing the dancing seas, in his long, low, black-hulled racer, the
+Spirit of the Storm, with his grisly flag flying at the fore! And at
+the zenith of his fame, how he would suddenly appear at the old village
+and stalk into church, brown and weather-beaten, in his black velvet
+doublet and trunks, his great jack-boots, his crimson sash, his belt
+bristling with horse-pistols, his crime-rusted cutlass at his side, his
+slouch hat with waving plumes, his black flag unfurled, with the skull
+and crossbones on it, and hear with swelling ecstasy the whisperings,
+"It's Tom Sawyer the Pirate!--the Black Avenger of the Spanish Main!"
+
+Yes, it was settled; his career was determined. He would run away from
+home and enter upon it. He would start the very next morning. Therefore
+he must now begin to get ready. He would collect his resources
+together. He went to a rotten log near at hand and began to dig under
+one end of it with his Barlow knife. He soon struck wood that sounded
+hollow. He put his hand there and uttered this incantation impressively:
+
+"What hasn't come here, come! What's here, stay here!"
+
+Then he scraped away the dirt, and exposed a pine shingle. He took it
+up and disclosed a shapely little treasure-house whose bottom and sides
+were of shingles. In it lay a marble. Tom's astonishment was boundless!
+He scratched his head with a perplexed air, and said:
+
+"Well, that beats anything!"
+
+Then he tossed the marble away pettishly, and stood cogitating. The
+truth was, that a superstition of his had failed, here, which he and
+all his comrades had always looked upon as infallible. If you buried a
+marble with certain necessary incantations, and left it alone a
+fortnight, and then opened the place with the incantation he had just
+used, you would find that all the marbles you had ever lost had
+gathered themselves together there, meantime, no matter how widely they
+had been separated. But now, this thing had actually and unquestionably
+failed. Tom's whole structure of faith was shaken to its foundations.
+He had many a time heard of this thing succeeding but never of its
+failing before. It did not occur to him that he had tried it several
+times before, himself, but could never find the hiding-places
+afterward. He puzzled over the matter some time, and finally decided
+that some witch had interfered and broken the charm. He thought he
+would satisfy himself on that point; so he searched around till he
+found a small sandy spot with a little funnel-shaped depression in it.
+He laid himself down and put his mouth close to this depression and
+called--
+
+"Doodle-bug, doodle-bug, tell me what I want to know! Doodle-bug,
+doodle-bug, tell me what I want to know!"
+
+The sand began to work, and presently a small black bug appeared for a
+second and then darted under again in a fright.
+
+"He dasn't tell! So it WAS a witch that done it. I just knowed it."
+
+He well knew the futility of trying to contend against witches, so he
+gave up discouraged. But it occurred to him that he might as well have
+the marble he had just thrown away, and therefore he went and made a
+patient search for it. But he could not find it. Now he went back to
+his treasure-house and carefully placed himself just as he had been
+standing when he tossed the marble away; then he took another marble
+from his pocket and tossed it in the same way, saying:
+
+"Brother, go find your brother!"
+
+He watched where it stopped, and went there and looked. But it must
+have fallen short or gone too far; so he tried twice more. The last
+repetition was successful. The two marbles lay within a foot of each
+other.
+
+Just here the blast of a toy tin trumpet came faintly down the green
+aisles of the forest. Tom flung off his jacket and trousers, turned a
+suspender into a belt, raked away some brush behind the rotten log,
+disclosing a rude bow and arrow, a lath sword and a tin trumpet, and in
+a moment had seized these things and bounded away, barelegged, with
+fluttering shirt. He presently halted under a great elm, blew an
+answering blast, and then began to tiptoe and look warily out, this way
+and that. He said cautiously--to an imaginary company:
+
+"Hold, my merry men! Keep hid till I blow."
+
+Now appeared Joe Harper, as airily clad and elaborately armed as Tom.
+Tom called:
+
+"Hold! Who comes here into Sherwood Forest without my pass?"
+
+"Guy of Guisborne wants no man's pass. Who art thou that--that--"
+
+"Dares to hold such language," said Tom, prompting--for they talked
+"by the book," from memory.
+
+"Who art thou that dares to hold such language?"
+
+"I, indeed! I am Robin Hood, as thy caitiff carcase soon shall know."
+
+"Then art thou indeed that famous outlaw? Right gladly will I dispute
+with thee the passes of the merry wood. Have at thee!"
+
+They took their lath swords, dumped their other traps on the ground,
+struck a fencing attitude, foot to foot, and began a grave, careful
+combat, "two up and two down." Presently Tom said:
+
+"Now, if you've got the hang, go it lively!"
+
+So they "went it lively," panting and perspiring with the work. By and
+by Tom shouted:
+
+"Fall! fall! Why don't you fall?"
+
+"I sha'n't! Why don't you fall yourself? You're getting the worst of
+it."
+
+"Why, that ain't anything. I can't fall; that ain't the way it is in
+the book. The book says, 'Then with one back-handed stroke he slew poor
+Guy of Guisborne.' You're to turn around and let me hit you in the
+back."
+
+There was no getting around the authorities, so Joe turned, received
+the whack and fell.
+
+"Now," said Joe, getting up, "you got to let me kill YOU. That's fair."
+
+"Why, I can't do that, it ain't in the book."
+
+"Well, it's blamed mean--that's all."
+
+"Well, say, Joe, you can be Friar Tuck or Much the miller's son, and
+lam me with a quarter-staff; or I'll be the Sheriff of Nottingham and
+you be Robin Hood a little while and kill me."
+
+This was satisfactory, and so these adventures were carried out. Then
+Tom became Robin Hood again, and was allowed by the treacherous nun to
+bleed his strength away through his neglected wound. And at last Joe,
+representing a whole tribe of weeping outlaws, dragged him sadly forth,
+gave his bow into his feeble hands, and Tom said, "Where this arrow
+falls, there bury poor Robin Hood under the greenwood tree." Then he
+shot the arrow and fell back and would have died, but he lit on a
+nettle and sprang up too gaily for a corpse.
+
+The boys dressed themselves, hid their accoutrements, and went off
+grieving that there were no outlaws any more, and wondering what modern
+civilization could claim to have done to compensate for their loss.
+They said they would rather be outlaws a year in Sherwood Forest than
+President of the United States forever.
+
+
+
+CHAPTER IX
+
+AT half-past nine, that night, Tom and Sid were sent to bed, as usual.
+They said their prayers, and Sid was soon asleep. Tom lay awake and
+waited, in restless impatience. When it seemed to him that it must be
+nearly daylight, he heard the clock strike ten! This was despair. He
+would have tossed and fidgeted, as his nerves demanded, but he was
+afraid he might wake Sid. So he lay still, and stared up into the dark.
+Everything was dismally still. By and by, out of the stillness, little,
+scarcely perceptible noises began to emphasize themselves. The ticking
+of the clock began to bring itself into notice. Old beams began to
+crack mysteriously. The stairs creaked faintly. Evidently spirits were
+abroad. A measured, muffled snore issued from Aunt Polly's chamber. And
+now the tiresome chirping of a cricket that no human ingenuity could
+locate, began. Next the ghastly ticking of a deathwatch in the wall at
+the bed's head made Tom shudder--it meant that somebody's days were
+numbered. Then the howl of a far-off dog rose on the night air, and was
+answered by a fainter howl from a remoter distance. Tom was in an
+agony. At last he was satisfied that time had ceased and eternity
+begun; he began to doze, in spite of himself; the clock chimed eleven,
+but he did not hear it. And then there came, mingling with his
+half-formed dreams, a most melancholy caterwauling. The raising of a
+neighboring window disturbed him. A cry of "Scat! you devil!" and the
+crash of an empty bottle against the back of his aunt's woodshed
+brought him wide awake, and a single minute later he was dressed and
+out of the window and creeping along the roof of the "ell" on all
+fours. He "meow'd" with caution once or twice, as he went; then jumped
+to the roof of the woodshed and thence to the ground. Huckleberry Finn
+was there, with his dead cat. The boys moved off and disappeared in the
+gloom. At the end of half an hour they were wading through the tall
+grass of the graveyard.
+
+It was a graveyard of the old-fashioned Western kind. It was on a
+hill, about a mile and a half from the village. It had a crazy board
+fence around it, which leaned inward in places, and outward the rest of
+the time, but stood upright nowhere. Grass and weeds grew rank over the
+whole cemetery. All the old graves were sunken in, there was not a
+tombstone on the place; round-topped, worm-eaten boards staggered over
+the graves, leaning for support and finding none. "Sacred to the memory
+of" So-and-So had been painted on them once, but it could no longer
+have been read, on the most of them, now, even if there had been light.
+
+A faint wind moaned through the trees, and Tom feared it might be the
+spirits of the dead, complaining at being disturbed. The boys talked
+little, and only under their breath, for the time and the place and the
+pervading solemnity and silence oppressed their spirits. They found the
+sharp new heap they were seeking, and ensconced themselves within the
+protection of three great elms that grew in a bunch within a few feet
+of the grave.
+
+Then they waited in silence for what seemed a long time. The hooting
+of a distant owl was all the sound that troubled the dead stillness.
+Tom's reflections grew oppressive. He must force some talk. So he said
+in a whisper:
+
+"Hucky, do you believe the dead people like it for us to be here?"
+
+Huckleberry whispered:
+
+"I wisht I knowed. It's awful solemn like, AIN'T it?"
+
+"I bet it is."
+
+There was a considerable pause, while the boys canvassed this matter
+inwardly. Then Tom whispered:
+
+"Say, Hucky--do you reckon Hoss Williams hears us talking?"
+
+"O' course he does. Least his sperrit does."
+
+Tom, after a pause:
+
+"I wish I'd said Mister Williams. But I never meant any harm.
+Everybody calls him Hoss."
+
+"A body can't be too partic'lar how they talk 'bout these-yer dead
+people, Tom."
+
+This was a damper, and conversation died again.
+
+Presently Tom seized his comrade's arm and said:
+
+"Sh!"
+
+"What is it, Tom?" And the two clung together with beating hearts.
+
+"Sh! There 'tis again! Didn't you hear it?"
+
+"I--"
+
+"There! Now you hear it."
+
+"Lord, Tom, they're coming! They're coming, sure. What'll we do?"
+
+"I dono. Think they'll see us?"
+
+"Oh, Tom, they can see in the dark, same as cats. I wisht I hadn't
+come."
+
+"Oh, don't be afeard. I don't believe they'll bother us. We ain't
+doing any harm. If we keep perfectly still, maybe they won't notice us
+at all."
+
+"I'll try to, Tom, but, Lord, I'm all of a shiver."
+
+"Listen!"
+
+The boys bent their heads together and scarcely breathed. A muffled
+sound of voices floated up from the far end of the graveyard.
+
+"Look! See there!" whispered Tom. "What is it?"
+
+"It's devil-fire. Oh, Tom, this is awful."
+
+Some vague figures approached through the gloom, swinging an
+old-fashioned tin lantern that freckled the ground with innumerable
+little spangles of light. Presently Huckleberry whispered with a
+shudder:
+
+"It's the devils sure enough. Three of 'em! Lordy, Tom, we're goners!
+Can you pray?"
+
+"I'll try, but don't you be afeard. They ain't going to hurt us. 'Now
+I lay me down to sleep, I--'"
+
+"Sh!"
+
+"What is it, Huck?"
+
+"They're HUMANS! One of 'em is, anyway. One of 'em's old Muff Potter's
+voice."
+
+"No--'tain't so, is it?"
+
+"I bet I know it. Don't you stir nor budge. He ain't sharp enough to
+notice us. Drunk, the same as usual, likely--blamed old rip!"
+
+"All right, I'll keep still. Now they're stuck. Can't find it. Here
+they come again. Now they're hot. Cold again. Hot again. Red hot!
+They're p'inted right, this time. Say, Huck, I know another o' them
+voices; it's Injun Joe."
+
+"That's so--that murderin' half-breed! I'd druther they was devils a
+dern sight. What kin they be up to?"
+
+The whisper died wholly out, now, for the three men had reached the
+grave and stood within a few feet of the boys' hiding-place.
+
+"Here it is," said the third voice; and the owner of it held the
+lantern up and revealed the face of young Doctor Robinson.
+
+Potter and Injun Joe were carrying a handbarrow with a rope and a
+couple of shovels on it. They cast down their load and began to open
+the grave. The doctor put the lantern at the head of the grave and came
+and sat down with his back against one of the elm trees. He was so
+close the boys could have touched him.
+
+"Hurry, men!" he said, in a low voice; "the moon might come out at any
+moment."
+
+They growled a response and went on digging. For some time there was
+no noise but the grating sound of the spades discharging their freight
+of mould and gravel. It was very monotonous. Finally a spade struck
+upon the coffin with a dull woody accent, and within another minute or
+two the men had hoisted it out on the ground. They pried off the lid
+with their shovels, got out the body and dumped it rudely on the
+ground. The moon drifted from behind the clouds and exposed the pallid
+face. The barrow was got ready and the corpse placed on it, covered
+with a blanket, and bound to its place with the rope. Potter took out a
+large spring-knife and cut off the dangling end of the rope and then
+said:
+
+"Now the cussed thing's ready, Sawbones, and you'll just out with
+another five, or here she stays."
+
+"That's the talk!" said Injun Joe.
+
+"Look here, what does this mean?" said the doctor. "You required your
+pay in advance, and I've paid you."
+
+"Yes, and you done more than that," said Injun Joe, approaching the
+doctor, who was now standing. "Five years ago you drove me away from
+your father's kitchen one night, when I come to ask for something to
+eat, and you said I warn't there for any good; and when I swore I'd get
+even with you if it took a hundred years, your father had me jailed for
+a vagrant. Did you think I'd forget? The Injun blood ain't in me for
+nothing. And now I've GOT you, and you got to SETTLE, you know!"
+
+He was threatening the doctor, with his fist in his face, by this
+time. The doctor struck out suddenly and stretched the ruffian on the
+ground. Potter dropped his knife, and exclaimed:
+
+"Here, now, don't you hit my pard!" and the next moment he had
+grappled with the doctor and the two were struggling with might and
+main, trampling the grass and tearing the ground with their heels.
+Injun Joe sprang to his feet, his eyes flaming with passion, snatched
+up Potter's knife, and went creeping, catlike and stooping, round and
+round about the combatants, seeking an opportunity. All at once the
+doctor flung himself free, seized the heavy headboard of Williams'
+grave and felled Potter to the earth with it--and in the same instant
+the half-breed saw his chance and drove the knife to the hilt in the
+young man's breast. He reeled and fell partly upon Potter, flooding him
+with his blood, and in the same moment the clouds blotted out the
+dreadful spectacle and the two frightened boys went speeding away in
+the dark.
+
+Presently, when the moon emerged again, Injun Joe was standing over
+the two forms, contemplating them. The doctor murmured inarticulately,
+gave a long gasp or two and was still. The half-breed muttered:
+
+"THAT score is settled--damn you."
+
+Then he robbed the body. After which he put the fatal knife in
+Potter's open right hand, and sat down on the dismantled coffin. Three
+--four--five minutes passed, and then Potter began to stir and moan. His
+hand closed upon the knife; he raised it, glanced at it, and let it
+fall, with a shudder. Then he sat up, pushing the body from him, and
+gazed at it, and then around him, confusedly. His eyes met Joe's.
+
+"Lord, how is this, Joe?" he said.
+
+"It's a dirty business," said Joe, without moving.
+
+"What did you do it for?"
+
+"I! I never done it!"
+
+"Look here! That kind of talk won't wash."
+
+Potter trembled and grew white.
+
+"I thought I'd got sober. I'd no business to drink to-night. But it's
+in my head yet--worse'n when we started here. I'm all in a muddle;
+can't recollect anything of it, hardly. Tell me, Joe--HONEST, now, old
+feller--did I do it? Joe, I never meant to--'pon my soul and honor, I
+never meant to, Joe. Tell me how it was, Joe. Oh, it's awful--and him
+so young and promising."
+
+"Why, you two was scuffling, and he fetched you one with the headboard
+and you fell flat; and then up you come, all reeling and staggering
+like, and snatched the knife and jammed it into him, just as he fetched
+you another awful clip--and here you've laid, as dead as a wedge til
+now."
+
+"Oh, I didn't know what I was a-doing. I wish I may die this minute if
+I did. It was all on account of the whiskey and the excitement, I
+reckon. I never used a weepon in my life before, Joe. I've fought, but
+never with weepons. They'll all say that. Joe, don't tell! Say you
+won't tell, Joe--that's a good feller. I always liked you, Joe, and
+stood up for you, too. Don't you remember? You WON'T tell, WILL you,
+Joe?" And the poor creature dropped on his knees before the stolid
+murderer, and clasped his appealing hands.
+
+"No, you've always been fair and square with me, Muff Potter, and I
+won't go back on you. There, now, that's as fair as a man can say."
+
+"Oh, Joe, you're an angel. I'll bless you for this the longest day I
+live." And Potter began to cry.
+
+"Come, now, that's enough of that. This ain't any time for blubbering.
+You be off yonder way and I'll go this. Move, now, and don't leave any
+tracks behind you."
+
+Potter started on a trot that quickly increased to a run. The
+half-breed stood looking after him. He muttered:
+
+"If he's as much stunned with the lick and fuddled with the rum as he
+had the look of being, he won't think of the knife till he's gone so
+far he'll be afraid to come back after it to such a place by himself
+--chicken-heart!"
+
+Two or three minutes later the murdered man, the blanketed corpse, the
+lidless coffin, and the open grave were under no inspection but the
+moon's. The stillness was complete again, too.
+
+
+
+CHAPTER X
+
+THE two boys flew on and on, toward the village, speechless with
+horror. They glanced backward over their shoulders from time to time,
+apprehensively, as if they feared they might be followed. Every stump
+that started up in their path seemed a man and an enemy, and made them
+catch their breath; and as they sped by some outlying cottages that lay
+near the village, the barking of the aroused watch-dogs seemed to give
+wings to their feet.
+
+"If we can only get to the old tannery before we break down!"
+whispered Tom, in short catches between breaths. "I can't stand it much
+longer."
+
+Huckleberry's hard pantings were his only reply, and the boys fixed
+their eyes on the goal of their hopes and bent to their work to win it.
+They gained steadily on it, and at last, breast to breast, they burst
+through the open door and fell grateful and exhausted in the sheltering
+shadows beyond. By and by their pulses slowed down, and Tom whispered:
+
+"Huckleberry, what do you reckon'll come of this?"
+
+"If Doctor Robinson dies, I reckon hanging'll come of it."
+
+"Do you though?"
+
+"Why, I KNOW it, Tom."
+
+Tom thought a while, then he said:
+
+"Who'll tell? We?"
+
+"What are you talking about? S'pose something happened and Injun Joe
+DIDN'T hang? Why, he'd kill us some time or other, just as dead sure as
+we're a laying here."
+
+"That's just what I was thinking to myself, Huck."
+
+"If anybody tells, let Muff Potter do it, if he's fool enough. He's
+generally drunk enough."
+
+Tom said nothing--went on thinking. Presently he whispered:
+
+"Huck, Muff Potter don't know it. How can he tell?"
+
+"What's the reason he don't know it?"
+
+"Because he'd just got that whack when Injun Joe done it. D'you reckon
+he could see anything? D'you reckon he knowed anything?"
+
+"By hokey, that's so, Tom!"
+
+"And besides, look-a-here--maybe that whack done for HIM!"
+
+"No, 'taint likely, Tom. He had liquor in him; I could see that; and
+besides, he always has. Well, when pap's full, you might take and belt
+him over the head with a church and you couldn't phase him. He says so,
+his own self. So it's the same with Muff Potter, of course. But if a
+man was dead sober, I reckon maybe that whack might fetch him; I dono."
+
+After another reflective silence, Tom said:
+
+"Hucky, you sure you can keep mum?"
+
+"Tom, we GOT to keep mum. You know that. That Injun devil wouldn't
+make any more of drownding us than a couple of cats, if we was to
+squeak 'bout this and they didn't hang him. Now, look-a-here, Tom, less
+take and swear to one another--that's what we got to do--swear to keep
+mum."
+
+"I'm agreed. It's the best thing. Would you just hold hands and swear
+that we--"
+
+"Oh no, that wouldn't do for this. That's good enough for little
+rubbishy common things--specially with gals, cuz THEY go back on you
+anyway, and blab if they get in a huff--but there orter be writing
+'bout a big thing like this. And blood."
+
+Tom's whole being applauded this idea. It was deep, and dark, and
+awful; the hour, the circumstances, the surroundings, were in keeping
+with it. He picked up a clean pine shingle that lay in the moonlight,
+took a little fragment of "red keel" out of his pocket, got the moon on
+his work, and painfully scrawled these lines, emphasizing each slow
+down-stroke by clamping his tongue between his teeth, and letting up
+the pressure on the up-strokes. [See next page.]
+
+ "Huck Finn and
+ Tom Sawyer swears
+ they will keep mum
+ about This and They
+ wish They may Drop
+ down dead in Their
+ Tracks if They ever
+ Tell and Rot."
+
+Huckleberry was filled with admiration of Tom's facility in writing,
+and the sublimity of his language. He at once took a pin from his lapel
+and was going to prick his flesh, but Tom said:
+
+"Hold on! Don't do that. A pin's brass. It might have verdigrease on
+it."
+
+"What's verdigrease?"
+
+"It's p'ison. That's what it is. You just swaller some of it once
+--you'll see."
+
+So Tom unwound the thread from one of his needles, and each boy
+pricked the ball of his thumb and squeezed out a drop of blood. In
+time, after many squeezes, Tom managed to sign his initials, using the
+ball of his little finger for a pen. Then he showed Huckleberry how to
+make an H and an F, and the oath was complete. They buried the shingle
+close to the wall, with some dismal ceremonies and incantations, and
+the fetters that bound their tongues were considered to be locked and
+the key thrown away.
+
+A figure crept stealthily through a break in the other end of the
+ruined building, now, but they did not notice it.
+
+"Tom," whispered Huckleberry, "does this keep us from EVER telling
+--ALWAYS?"
+
+"Of course it does. It don't make any difference WHAT happens, we got
+to keep mum. We'd drop down dead--don't YOU know that?"
+
+"Yes, I reckon that's so."
+
+They continued to whisper for some little time. Presently a dog set up
+a long, lugubrious howl just outside--within ten feet of them. The boys
+clasped each other suddenly, in an agony of fright.
+
+"Which of us does he mean?" gasped Huckleberry.
+
+"I dono--peep through the crack. Quick!"
+
+"No, YOU, Tom!"
+
+"I can't--I can't DO it, Huck!"
+
+"Please, Tom. There 'tis again!"
+
+"Oh, lordy, I'm thankful!" whispered Tom. "I know his voice. It's Bull
+Harbison." *
+
+[* If Mr. Harbison owned a slave named Bull, Tom would have spoken of
+him as "Harbison's Bull," but a son or a dog of that name was "Bull
+Harbison."]
+
+"Oh, that's good--I tell you, Tom, I was most scared to death; I'd a
+bet anything it was a STRAY dog."
+
+The dog howled again. The boys' hearts sank once more.
+
+"Oh, my! that ain't no Bull Harbison!" whispered Huckleberry. "DO, Tom!"
+
+Tom, quaking with fear, yielded, and put his eye to the crack. His
+whisper was hardly audible when he said:
+
+"Oh, Huck, IT S A STRAY DOG!"
+
+"Quick, Tom, quick! Who does he mean?"
+
+"Huck, he must mean us both--we're right together."
+
+"Oh, Tom, I reckon we're goners. I reckon there ain't no mistake 'bout
+where I'LL go to. I been so wicked."
+
+"Dad fetch it! This comes of playing hookey and doing everything a
+feller's told NOT to do. I might a been good, like Sid, if I'd a tried
+--but no, I wouldn't, of course. But if ever I get off this time, I lay
+I'll just WALLER in Sunday-schools!" And Tom began to snuffle a little.
+
+"YOU bad!" and Huckleberry began to snuffle too. "Consound it, Tom
+Sawyer, you're just old pie, 'longside o' what I am. Oh, LORDY, lordy,
+lordy, I wisht I only had half your chance."
+
+Tom choked off and whispered:
+
+"Look, Hucky, look! He's got his BACK to us!"
+
+Hucky looked, with joy in his heart.
+
+"Well, he has, by jingoes! Did he before?"
+
+"Yes, he did. But I, like a fool, never thought. Oh, this is bully,
+you know. NOW who can he mean?"
+
+The howling stopped. Tom pricked up his ears.
+
+"Sh! What's that?" he whispered.
+
+"Sounds like--like hogs grunting. No--it's somebody snoring, Tom."
+
+"That IS it! Where 'bouts is it, Huck?"
+
+"I bleeve it's down at 'tother end. Sounds so, anyway. Pap used to
+sleep there, sometimes, 'long with the hogs, but laws bless you, he
+just lifts things when HE snores. Besides, I reckon he ain't ever
+coming back to this town any more."
+
+The spirit of adventure rose in the boys' souls once more.
+
+"Hucky, do you das't to go if I lead?"
+
+"I don't like to, much. Tom, s'pose it's Injun Joe!"
+
+Tom quailed. But presently the temptation rose up strong again and the
+boys agreed to try, with the understanding that they would take to
+their heels if the snoring stopped. So they went tiptoeing stealthily
+down, the one behind the other. When they had got to within five steps
+of the snorer, Tom stepped on a stick, and it broke with a sharp snap.
+The man moaned, writhed a little, and his face came into the moonlight.
+It was Muff Potter. The boys' hearts had stood still, and their hopes
+too, when the man moved, but their fears passed away now. They tiptoed
+out, through the broken weather-boarding, and stopped at a little
+distance to exchange a parting word. That long, lugubrious howl rose on
+the night air again! They turned and saw the strange dog standing
+within a few feet of where Potter was lying, and FACING Potter, with
+his nose pointing heavenward.
+
+"Oh, geeminy, it's HIM!" exclaimed both boys, in a breath.
+
+"Say, Tom--they say a stray dog come howling around Johnny Miller's
+house, 'bout midnight, as much as two weeks ago; and a whippoorwill
+come in and lit on the banisters and sung, the very same evening; and
+there ain't anybody dead there yet."
+
+"Well, I know that. And suppose there ain't. Didn't Gracie Miller fall
+in the kitchen fire and burn herself terrible the very next Saturday?"
+
+"Yes, but she ain't DEAD. And what's more, she's getting better, too."
+
+"All right, you wait and see. She's a goner, just as dead sure as Muff
+Potter's a goner. That's what the niggers say, and they know all about
+these kind of things, Huck."
+
+Then they separated, cogitating. When Tom crept in at his bedroom
+window the night was almost spent. He undressed with excessive caution,
+and fell asleep congratulating himself that nobody knew of his
+escapade. He was not aware that the gently-snoring Sid was awake, and
+had been so for an hour.
+
+When Tom awoke, Sid was dressed and gone. There was a late look in the
+light, a late sense in the atmosphere. He was startled. Why had he not
+been called--persecuted till he was up, as usual? The thought filled
+him with bodings. Within five minutes he was dressed and down-stairs,
+feeling sore and drowsy. The family were still at table, but they had
+finished breakfast. There was no voice of rebuke; but there were
+averted eyes; there was a silence and an air of solemnity that struck a
+chill to the culprit's heart. He sat down and tried to seem gay, but it
+was up-hill work; it roused no smile, no response, and he lapsed into
+silence and let his heart sink down to the depths.
+
+After breakfast his aunt took him aside, and Tom almost brightened in
+the hope that he was going to be flogged; but it was not so. His aunt
+wept over him and asked him how he could go and break her old heart so;
+and finally told him to go on, and ruin himself and bring her gray
+hairs with sorrow to the grave, for it was no use for her to try any
+more. This was worse than a thousand whippings, and Tom's heart was
+sorer now than his body. He cried, he pleaded for forgiveness, promised
+to reform over and over again, and then received his dismissal, feeling
+that he had won but an imperfect forgiveness and established but a
+feeble confidence.
+
+He left the presence too miserable to even feel revengeful toward Sid;
+and so the latter's prompt retreat through the back gate was
+unnecessary. He moped to school gloomy and sad, and took his flogging,
+along with Joe Harper, for playing hookey the day before, with the air
+of one whose heart was busy with heavier woes and wholly dead to
+trifles. Then he betook himself to his seat, rested his elbows on his
+desk and his jaws in his hands, and stared at the wall with the stony
+stare of suffering that has reached the limit and can no further go.
+His elbow was pressing against some hard substance. After a long time
+he slowly and sadly changed his position, and took up this object with
+a sigh. It was in a paper. He unrolled it. A long, lingering, colossal
+sigh followed, and his heart broke. It was his brass andiron knob!
+
+This final feather broke the camel's back.
+
+
+
+CHAPTER XI
+
+CLOSE upon the hour of noon the whole village was suddenly electrified
+with the ghastly news. No need of the as yet undreamed-of telegraph;
+the tale flew from man to man, from group to group, from house to
+house, with little less than telegraphic speed. Of course the
+schoolmaster gave holiday for that afternoon; the town would have
+thought strangely of him if he had not.
+
+A gory knife had been found close to the murdered man, and it had been
+recognized by somebody as belonging to Muff Potter--so the story ran.
+And it was said that a belated citizen had come upon Potter washing
+himself in the "branch" about one or two o'clock in the morning, and
+that Potter had at once sneaked off--suspicious circumstances,
+especially the washing which was not a habit with Potter. It was also
+said that the town had been ransacked for this "murderer" (the public
+are not slow in the matter of sifting evidence and arriving at a
+verdict), but that he could not be found. Horsemen had departed down
+all the roads in every direction, and the Sheriff "was confident" that
+he would be captured before night.
+
+All the town was drifting toward the graveyard. Tom's heartbreak
+vanished and he joined the procession, not because he would not a
+thousand times rather go anywhere else, but because an awful,
+unaccountable fascination drew him on. Arrived at the dreadful place,
+he wormed his small body through the crowd and saw the dismal
+spectacle. It seemed to him an age since he was there before. Somebody
+pinched his arm. He turned, and his eyes met Huckleberry's. Then both
+looked elsewhere at once, and wondered if anybody had noticed anything
+in their mutual glance. But everybody was talking, and intent upon the
+grisly spectacle before them.
+
+"Poor fellow!" "Poor young fellow!" "This ought to be a lesson to
+grave robbers!" "Muff Potter'll hang for this if they catch him!" This
+was the drift of remark; and the minister said, "It was a judgment; His
+hand is here."
+
+Now Tom shivered from head to heel; for his eye fell upon the stolid
+face of Injun Joe. At this moment the crowd began to sway and struggle,
+and voices shouted, "It's him! it's him! he's coming himself!"
+
+"Who? Who?" from twenty voices.
+
+"Muff Potter!"
+
+"Hallo, he's stopped!--Look out, he's turning! Don't let him get away!"
+
+People in the branches of the trees over Tom's head said he wasn't
+trying to get away--he only looked doubtful and perplexed.
+
+"Infernal impudence!" said a bystander; "wanted to come and take a
+quiet look at his work, I reckon--didn't expect any company."
+
+The crowd fell apart, now, and the Sheriff came through,
+ostentatiously leading Potter by the arm. The poor fellow's face was
+haggard, and his eyes showed the fear that was upon him. When he stood
+before the murdered man, he shook as with a palsy, and he put his face
+in his hands and burst into tears.
+
+"I didn't do it, friends," he sobbed; "'pon my word and honor I never
+done it."
+
+"Who's accused you?" shouted a voice.
+
+This shot seemed to carry home. Potter lifted his face and looked
+around him with a pathetic hopelessness in his eyes. He saw Injun Joe,
+and exclaimed:
+
+"Oh, Injun Joe, you promised me you'd never--"
+
+"Is that your knife?" and it was thrust before him by the Sheriff.
+
+Potter would have fallen if they had not caught him and eased him to
+the ground. Then he said:
+
+"Something told me 't if I didn't come back and get--" He shuddered;
+then waved his nerveless hand with a vanquished gesture and said, "Tell
+'em, Joe, tell 'em--it ain't any use any more."
+
+Then Huckleberry and Tom stood dumb and staring, and heard the
+stony-hearted liar reel off his serene statement, they expecting every
+moment that the clear sky would deliver God's lightnings upon his head,
+and wondering to see how long the stroke was delayed. And when he had
+finished and still stood alive and whole, their wavering impulse to
+break their oath and save the poor betrayed prisoner's life faded and
+vanished away, for plainly this miscreant had sold himself to Satan and
+it would be fatal to meddle with the property of such a power as that.
+
+"Why didn't you leave? What did you want to come here for?" somebody
+said.
+
+"I couldn't help it--I couldn't help it," Potter moaned. "I wanted to
+run away, but I couldn't seem to come anywhere but here." And he fell
+to sobbing again.
+
+Injun Joe repeated his statement, just as calmly, a few minutes
+afterward on the inquest, under oath; and the boys, seeing that the
+lightnings were still withheld, were confirmed in their belief that Joe
+had sold himself to the devil. He was now become, to them, the most
+balefully interesting object they had ever looked upon, and they could
+not take their fascinated eyes from his face.
+
+They inwardly resolved to watch him nights, when opportunity should
+offer, in the hope of getting a glimpse of his dread master.
+
+Injun Joe helped to raise the body of the murdered man and put it in a
+wagon for removal; and it was whispered through the shuddering crowd
+that the wound bled a little! The boys thought that this happy
+circumstance would turn suspicion in the right direction; but they were
+disappointed, for more than one villager remarked:
+
+"It was within three feet of Muff Potter when it done it."
+
+Tom's fearful secret and gnawing conscience disturbed his sleep for as
+much as a week after this; and at breakfast one morning Sid said:
+
+"Tom, you pitch around and talk in your sleep so much that you keep me
+awake half the time."
+
+Tom blanched and dropped his eyes.
+
+"It's a bad sign," said Aunt Polly, gravely. "What you got on your
+mind, Tom?"
+
+"Nothing. Nothing 't I know of." But the boy's hand shook so that he
+spilled his coffee.
+
+"And you do talk such stuff," Sid said. "Last night you said, 'It's
+blood, it's blood, that's what it is!' You said that over and over. And
+you said, 'Don't torment me so--I'll tell!' Tell WHAT? What is it
+you'll tell?"
+
+Everything was swimming before Tom. There is no telling what might
+have happened, now, but luckily the concern passed out of Aunt Polly's
+face and she came to Tom's relief without knowing it. She said:
+
+"Sho! It's that dreadful murder. I dream about it most every night
+myself. Sometimes I dream it's me that done it."
+
+Mary said she had been affected much the same way. Sid seemed
+satisfied. Tom got out of the presence as quick as he plausibly could,
+and after that he complained of toothache for a week, and tied up his
+jaws every night. He never knew that Sid lay nightly watching, and
+frequently slipped the bandage free and then leaned on his elbow
+listening a good while at a time, and afterward slipped the bandage
+back to its place again. Tom's distress of mind wore off gradually and
+the toothache grew irksome and was discarded. If Sid really managed to
+make anything out of Tom's disjointed mutterings, he kept it to himself.
+
+It seemed to Tom that his schoolmates never would get done holding
+inquests on dead cats, and thus keeping his trouble present to his
+mind. Sid noticed that Tom never was coroner at one of these inquiries,
+though it had been his habit to take the lead in all new enterprises;
+he noticed, too, that Tom never acted as a witness--and that was
+strange; and Sid did not overlook the fact that Tom even showed a
+marked aversion to these inquests, and always avoided them when he
+could. Sid marvelled, but said nothing. However, even inquests went out
+of vogue at last, and ceased to torture Tom's conscience.
+
+Every day or two, during this time of sorrow, Tom watched his
+opportunity and went to the little grated jail-window and smuggled such
+small comforts through to the "murderer" as he could get hold of. The
+jail was a trifling little brick den that stood in a marsh at the edge
+of the village, and no guards were afforded for it; indeed, it was
+seldom occupied. These offerings greatly helped to ease Tom's
+conscience.
+
+The villagers had a strong desire to tar-and-feather Injun Joe and
+ride him on a rail, for body-snatching, but so formidable was his
+character that nobody could be found who was willing to take the lead
+in the matter, so it was dropped. He had been careful to begin both of
+his inquest-statements with the fight, without confessing the
+grave-robbery that preceded it; therefore it was deemed wisest not
+to try the case in the courts at present.
+
+
+
+CHAPTER XII
+
+ONE of the reasons why Tom's mind had drifted away from its secret
+troubles was, that it had found a new and weighty matter to interest
+itself about. Becky Thatcher had stopped coming to school. Tom had
+struggled with his pride a few days, and tried to "whistle her down the
+wind," but failed. He began to find himself hanging around her father's
+house, nights, and feeling very miserable. She was ill. What if she
+should die! There was distraction in the thought. He no longer took an
+interest in war, nor even in piracy. The charm of life was gone; there
+was nothing but dreariness left. He put his hoop away, and his bat;
+there was no joy in them any more. His aunt was concerned. She began to
+try all manner of remedies on him. She was one of those people who are
+infatuated with patent medicines and all new-fangled methods of
+producing health or mending it. She was an inveterate experimenter in
+these things. When something fresh in this line came out she was in a
+fever, right away, to try it; not on herself, for she was never ailing,
+but on anybody else that came handy. She was a subscriber for all the
+"Health" periodicals and phrenological frauds; and the solemn ignorance
+they were inflated with was breath to her nostrils. All the "rot" they
+contained about ventilation, and how to go to bed, and how to get up,
+and what to eat, and what to drink, and how much exercise to take, and
+what frame of mind to keep one's self in, and what sort of clothing to
+wear, was all gospel to her, and she never observed that her
+health-journals of the current month customarily upset everything they
+had recommended the month before. She was as simple-hearted and honest
+as the day was long, and so she was an easy victim. She gathered
+together her quack periodicals and her quack medicines, and thus armed
+with death, went about on her pale horse, metaphorically speaking, with
+"hell following after." But she never suspected that she was not an
+angel of healing and the balm of Gilead in disguise, to the suffering
+neighbors.
+
+The water treatment was new, now, and Tom's low condition was a
+windfall to her. She had him out at daylight every morning, stood him
+up in the woodshed and drowned him with a deluge of cold water; then
+she scrubbed him down with a towel like a file, and so brought him to;
+then she rolled him up in a wet sheet and put him away under blankets
+till she sweated his soul clean and "the yellow stains of it came
+through his pores"--as Tom said.
+
+Yet notwithstanding all this, the boy grew more and more melancholy
+and pale and dejected. She added hot baths, sitz baths, shower baths,
+and plunges. The boy remained as dismal as a hearse. She began to
+assist the water with a slim oatmeal diet and blister-plasters. She
+calculated his capacity as she would a jug's, and filled him up every
+day with quack cure-alls.
+
+Tom had become indifferent to persecution by this time. This phase
+filled the old lady's heart with consternation. This indifference must
+be broken up at any cost. Now she heard of Pain-killer for the first
+time. She ordered a lot at once. She tasted it and was filled with
+gratitude. It was simply fire in a liquid form. She dropped the water
+treatment and everything else, and pinned her faith to Pain-killer. She
+gave Tom a teaspoonful and watched with the deepest anxiety for the
+result. Her troubles were instantly at rest, her soul at peace again;
+for the "indifference" was broken up. The boy could not have shown a
+wilder, heartier interest, if she had built a fire under him.
+
+Tom felt that it was time to wake up; this sort of life might be
+romantic enough, in his blighted condition, but it was getting to have
+too little sentiment and too much distracting variety about it. So he
+thought over various plans for relief, and finally hit pon that of
+professing to be fond of Pain-killer. He asked for it so often that he
+became a nuisance, and his aunt ended by telling him to help himself
+and quit bothering her. If it had been Sid, she would have had no
+misgivings to alloy her delight; but since it was Tom, she watched the
+bottle clandestinely. She found that the medicine did really diminish,
+but it did not occur to her that the boy was mending the health of a
+crack in the sitting-room floor with it.
+
+One day Tom was in the act of dosing the crack when his aunt's yellow
+cat came along, purring, eying the teaspoon avariciously, and begging
+for a taste. Tom said:
+
+"Don't ask for it unless you want it, Peter."
+
+But Peter signified that he did want it.
+
+"You better make sure."
+
+Peter was sure.
+
+"Now you've asked for it, and I'll give it to you, because there ain't
+anything mean about me; but if you find you don't like it, you mustn't
+blame anybody but your own self."
+
+Peter was agreeable. So Tom pried his mouth open and poured down the
+Pain-killer. Peter sprang a couple of yards in the air, and then
+delivered a war-whoop and set off round and round the room, banging
+against furniture, upsetting flower-pots, and making general havoc.
+Next he rose on his hind feet and pranced around, in a frenzy of
+enjoyment, with his head over his shoulder and his voice proclaiming
+his unappeasable happiness. Then he went tearing around the house again
+spreading chaos and destruction in his path. Aunt Polly entered in time
+to see him throw a few double summersets, deliver a final mighty
+hurrah, and sail through the open window, carrying the rest of the
+flower-pots with him. The old lady stood petrified with astonishment,
+peering over her glasses; Tom lay on the floor expiring with laughter.
+
+"Tom, what on earth ails that cat?"
+
+"I don't know, aunt," gasped the boy.
+
+"Why, I never see anything like it. What did make him act so?"
+
+"Deed I don't know, Aunt Polly; cats always act so when they're having
+a good time."
+
+"They do, do they?" There was something in the tone that made Tom
+apprehensive.
+
+"Yes'm. That is, I believe they do."
+
+"You DO?"
+
+"Yes'm."
+
+The old lady was bending down, Tom watching, with interest emphasized
+by anxiety. Too late he divined her "drift." The handle of the telltale
+teaspoon was visible under the bed-valance. Aunt Polly took it, held it
+up. Tom winced, and dropped his eyes. Aunt Polly raised him by the
+usual handle--his ear--and cracked his head soundly with her thimble.
+
+"Now, sir, what did you want to treat that poor dumb beast so, for?"
+
+"I done it out of pity for him--because he hadn't any aunt."
+
+"Hadn't any aunt!--you numskull. What has that got to do with it?"
+
+"Heaps. Because if he'd had one she'd a burnt him out herself! She'd a
+roasted his bowels out of him 'thout any more feeling than if he was a
+human!"
+
+Aunt Polly felt a sudden pang of remorse. This was putting the thing
+in a new light; what was cruelty to a cat MIGHT be cruelty to a boy,
+too. She began to soften; she felt sorry. Her eyes watered a little,
+and she put her hand on Tom's head and said gently:
+
+"I was meaning for the best, Tom. And, Tom, it DID do you good."
+
+Tom looked up in her face with just a perceptible twinkle peeping
+through his gravity.
+
+"I know you was meaning for the best, aunty, and so was I with Peter.
+It done HIM good, too. I never see him get around so since--"
+
+"Oh, go 'long with you, Tom, before you aggravate me again. And you
+try and see if you can't be a good boy, for once, and you needn't take
+any more medicine."
+
+Tom reached school ahead of time. It was noticed that this strange
+thing had been occurring every day latterly. And now, as usual of late,
+he hung about the gate of the schoolyard instead of playing with his
+comrades. He was sick, he said, and he looked it. He tried to seem to
+be looking everywhere but whither he really was looking--down the road.
+Presently Jeff Thatcher hove in sight, and Tom's face lighted; he gazed
+a moment, and then turned sorrowfully away. When Jeff arrived, Tom
+accosted him; and "led up" warily to opportunities for remark about
+Becky, but the giddy lad never could see the bait. Tom watched and
+watched, hoping whenever a frisking frock came in sight, and hating the
+owner of it as soon as he saw she was not the right one. At last frocks
+ceased to appear, and he dropped hopelessly into the dumps; he entered
+the empty schoolhouse and sat down to suffer. Then one more frock
+passed in at the gate, and Tom's heart gave a great bound. The next
+instant he was out, and "going on" like an Indian; yelling, laughing,
+chasing boys, jumping over the fence at risk of life and limb, throwing
+handsprings, standing on his head--doing all the heroic things he could
+conceive of, and keeping a furtive eye out, all the while, to see if
+Becky Thatcher was noticing. But she seemed to be unconscious of it
+all; she never looked. Could it be possible that she was not aware that
+he was there? He carried his exploits to her immediate vicinity; came
+war-whooping around, snatched a boy's cap, hurled it to the roof of the
+schoolhouse, broke through a group of boys, tumbling them in every
+direction, and fell sprawling, himself, under Becky's nose, almost
+upsetting her--and she turned, with her nose in the air, and he heard
+her say: "Mf! some people think they're mighty smart--always showing
+off!"
+
+Tom's cheeks burned. He gathered himself up and sneaked off, crushed
+and crestfallen.
+
+
+
+CHAPTER XIII
+
+TOM'S mind was made up now. He was gloomy and desperate. He was a
+forsaken, friendless boy, he said; nobody loved him; when they found
+out what they had driven him to, perhaps they would be sorry; he had
+tried to do right and get along, but they would not let him; since
+nothing would do them but to be rid of him, let it be so; and let them
+blame HIM for the consequences--why shouldn't they? What right had the
+friendless to complain? Yes, they had forced him to it at last: he
+would lead a life of crime. There was no choice.
+
+By this time he was far down Meadow Lane, and the bell for school to
+"take up" tinkled faintly upon his ear. He sobbed, now, to think he
+should never, never hear that old familiar sound any more--it was very
+hard, but it was forced on him; since he was driven out into the cold
+world, he must submit--but he forgave them. Then the sobs came thick
+and fast.
+
+Just at this point he met his soul's sworn comrade, Joe Harper
+--hard-eyed, and with evidently a great and dismal purpose in his heart.
+Plainly here were "two souls with but a single thought." Tom, wiping
+his eyes with his sleeve, began to blubber out something about a
+resolution to escape from hard usage and lack of sympathy at home by
+roaming abroad into the great world never to return; and ended by
+hoping that Joe would not forget him.
+
+But it transpired that this was a request which Joe had just been
+going to make of Tom, and had come to hunt him up for that purpose. His
+mother had whipped him for drinking some cream which he had never
+tasted and knew nothing about; it was plain that she was tired of him
+and wished him to go; if she felt that way, there was nothing for him
+to do but succumb; he hoped she would be happy, and never regret having
+driven her poor boy out into the unfeeling world to suffer and die.
+
+As the two boys walked sorrowing along, they made a new compact to
+stand by each other and be brothers and never separate till death
+relieved them of their troubles. Then they began to lay their plans.
+Joe was for being a hermit, and living on crusts in a remote cave, and
+dying, some time, of cold and want and grief; but after listening to
+Tom, he conceded that there were some conspicuous advantages about a
+life of crime, and so he consented to be a pirate.
+
+Three miles below St. Petersburg, at a point where the Mississippi
+River was a trifle over a mile wide, there was a long, narrow, wooded
+island, with a shallow bar at the head of it, and this offered well as
+a rendezvous. It was not inhabited; it lay far over toward the further
+shore, abreast a dense and almost wholly unpeopled forest. So Jackson's
+Island was chosen. Who were to be the subjects of their piracies was a
+matter that did not occur to them. Then they hunted up Huckleberry
+Finn, and he joined them promptly, for all careers were one to him; he
+was indifferent. They presently separated to meet at a lonely spot on
+the river-bank two miles above the village at the favorite hour--which
+was midnight. There was a small log raft there which they meant to
+capture. Each would bring hooks and lines, and such provision as he
+could steal in the most dark and mysterious way--as became outlaws. And
+before the afternoon was done, they had all managed to enjoy the sweet
+glory of spreading the fact that pretty soon the town would "hear
+something." All who got this vague hint were cautioned to "be mum and
+wait."
+
+About midnight Tom arrived with a boiled ham and a few trifles,
+and stopped in a dense undergrowth on a small bluff overlooking the
+meeting-place. It was starlight, and very still. The mighty river lay
+like an ocean at rest. Tom listened a moment, but no sound disturbed the
+quiet. Then he gave a low, distinct whistle. It was answered from under
+the bluff. Tom whistled twice more; these signals were answered in the
+same way. Then a guarded voice said:
+
+"Who goes there?"
+
+"Tom Sawyer, the Black Avenger of the Spanish Main. Name your names."
+
+"Huck Finn the Red-Handed, and Joe Harper the Terror of the Seas." Tom
+had furnished these titles, from his favorite literature.
+
+"'Tis well. Give the countersign."
+
+Two hoarse whispers delivered the same awful word simultaneously to
+the brooding night:
+
+"BLOOD!"
+
+Then Tom tumbled his ham over the bluff and let himself down after it,
+tearing both skin and clothes to some extent in the effort. There was
+an easy, comfortable path along the shore under the bluff, but it
+lacked the advantages of difficulty and danger so valued by a pirate.
+
+The Terror of the Seas had brought a side of bacon, and had about worn
+himself out with getting it there. Finn the Red-Handed had stolen a
+skillet and a quantity of half-cured leaf tobacco, and had also brought
+a few corn-cobs to make pipes with. But none of the pirates smoked or
+"chewed" but himself. The Black Avenger of the Spanish Main said it
+would never do to start without some fire. That was a wise thought;
+matches were hardly known there in that day. They saw a fire
+smouldering upon a great raft a hundred yards above, and they went
+stealthily thither and helped themselves to a chunk. They made an
+imposing adventure of it, saying, "Hist!" every now and then, and
+suddenly halting with finger on lip; moving with hands on imaginary
+dagger-hilts; and giving orders in dismal whispers that if "the foe"
+stirred, to "let him have it to the hilt," because "dead men tell no
+tales." They knew well enough that the raftsmen were all down at the
+village laying in stores or having a spree, but still that was no
+excuse for their conducting this thing in an unpiratical way.
+
+They shoved off, presently, Tom in command, Huck at the after oar and
+Joe at the forward. Tom stood amidships, gloomy-browed, and with folded
+arms, and gave his orders in a low, stern whisper:
+
+"Luff, and bring her to the wind!"
+
+"Aye-aye, sir!"
+
+"Steady, steady-y-y-y!"
+
+"Steady it is, sir!"
+
+"Let her go off a point!"
+
+"Point it is, sir!"
+
+As the boys steadily and monotonously drove the raft toward mid-stream
+it was no doubt understood that these orders were given only for
+"style," and were not intended to mean anything in particular.
+
+"What sail's she carrying?"
+
+"Courses, tops'ls, and flying-jib, sir."
+
+"Send the r'yals up! Lay out aloft, there, half a dozen of ye
+--foretopmaststuns'l! Lively, now!"
+
+"Aye-aye, sir!"
+
+"Shake out that maintogalans'l! Sheets and braces! NOW my hearties!"
+
+"Aye-aye, sir!"
+
+"Hellum-a-lee--hard a port! Stand by to meet her when she comes! Port,
+port! NOW, men! With a will! Stead-y-y-y!"
+
+"Steady it is, sir!"
+
+The raft drew beyond the middle of the river; the boys pointed her
+head right, and then lay on their oars. The river was not high, so
+there was not more than a two or three mile current. Hardly a word was
+said during the next three-quarters of an hour. Now the raft was
+passing before the distant town. Two or three glimmering lights showed
+where it lay, peacefully sleeping, beyond the vague vast sweep of
+star-gemmed water, unconscious of the tremendous event that was happening.
+The Black Avenger stood still with folded arms, "looking his last" upon
+the scene of his former joys and his later sufferings, and wishing
+"she" could see him now, abroad on the wild sea, facing peril and death
+with dauntless heart, going to his doom with a grim smile on his lips.
+It was but a small strain on his imagination to remove Jackson's Island
+beyond eyeshot of the village, and so he "looked his last" with a
+broken and satisfied heart. The other pirates were looking their last,
+too; and they all looked so long that they came near letting the
+current drift them out of the range of the island. But they discovered
+the danger in time, and made shift to avert it. About two o'clock in
+the morning the raft grounded on the bar two hundred yards above the
+head of the island, and they waded back and forth until they had landed
+their freight. Part of the little raft's belongings consisted of an old
+sail, and this they spread over a nook in the bushes for a tent to
+shelter their provisions; but they themselves would sleep in the open
+air in good weather, as became outlaws.
+
+They built a fire against the side of a great log twenty or thirty
+steps within the sombre depths of the forest, and then cooked some
+bacon in the frying-pan for supper, and used up half of the corn "pone"
+stock they had brought. It seemed glorious sport to be feasting in that
+wild, free way in the virgin forest of an unexplored and uninhabited
+island, far from the haunts of men, and they said they never would
+return to civilization. The climbing fire lit up their faces and threw
+its ruddy glare upon the pillared tree-trunks of their forest temple,
+and upon the varnished foliage and festooning vines.
+
+When the last crisp slice of bacon was gone, and the last allowance of
+corn pone devoured, the boys stretched themselves out on the grass,
+filled with contentment. They could have found a cooler place, but they
+would not deny themselves such a romantic feature as the roasting
+camp-fire.
+
+"AIN'T it gay?" said Joe.
+
+"It's NUTS!" said Tom. "What would the boys say if they could see us?"
+
+"Say? Well, they'd just die to be here--hey, Hucky!"
+
+"I reckon so," said Huckleberry; "anyways, I'm suited. I don't want
+nothing better'n this. I don't ever get enough to eat, gen'ally--and
+here they can't come and pick at a feller and bullyrag him so."
+
+"It's just the life for me," said Tom. "You don't have to get up,
+mornings, and you don't have to go to school, and wash, and all that
+blame foolishness. You see a pirate don't have to do ANYTHING, Joe,
+when he's ashore, but a hermit HE has to be praying considerable, and
+then he don't have any fun, anyway, all by himself that way."
+
+"Oh yes, that's so," said Joe, "but I hadn't thought much about it,
+you know. I'd a good deal rather be a pirate, now that I've tried it."
+
+"You see," said Tom, "people don't go much on hermits, nowadays, like
+they used to in old times, but a pirate's always respected. And a
+hermit's got to sleep on the hardest place he can find, and put
+sackcloth and ashes on his head, and stand out in the rain, and--"
+
+"What does he put sackcloth and ashes on his head for?" inquired Huck.
+
+"I dono. But they've GOT to do it. Hermits always do. You'd have to do
+that if you was a hermit."
+
+"Dern'd if I would," said Huck.
+
+"Well, what would you do?"
+
+"I dono. But I wouldn't do that."
+
+"Why, Huck, you'd HAVE to. How'd you get around it?"
+
+"Why, I just wouldn't stand it. I'd run away."
+
+"Run away! Well, you WOULD be a nice old slouch of a hermit. You'd be
+a disgrace."
+
+The Red-Handed made no response, being better employed. He had
+finished gouging out a cob, and now he fitted a weed stem to it, loaded
+it with tobacco, and was pressing a coal to the charge and blowing a
+cloud of fragrant smoke--he was in the full bloom of luxurious
+contentment. The other pirates envied him this majestic vice, and
+secretly resolved to acquire it shortly. Presently Huck said:
+
+"What does pirates have to do?"
+
+Tom said:
+
+"Oh, they have just a bully time--take ships and burn them, and get
+the money and bury it in awful places in their island where there's
+ghosts and things to watch it, and kill everybody in the ships--make
+'em walk a plank."
+
+"And they carry the women to the island," said Joe; "they don't kill
+the women."
+
+"No," assented Tom, "they don't kill the women--they're too noble. And
+the women's always beautiful, too.
+
+"And don't they wear the bulliest clothes! Oh no! All gold and silver
+and di'monds," said Joe, with enthusiasm.
+
+"Who?" said Huck.
+
+"Why, the pirates."
+
+Huck scanned his own clothing forlornly.
+
+"I reckon I ain't dressed fitten for a pirate," said he, with a
+regretful pathos in his voice; "but I ain't got none but these."
+
+But the other boys told him the fine clothes would come fast enough,
+after they should have begun their adventures. They made him understand
+that his poor rags would do to begin with, though it was customary for
+wealthy pirates to start with a proper wardrobe.
+
+Gradually their talk died out and drowsiness began to steal upon the
+eyelids of the little waifs. The pipe dropped from the fingers of the
+Red-Handed, and he slept the sleep of the conscience-free and the
+weary. The Terror of the Seas and the Black Avenger of the Spanish Main
+had more difficulty in getting to sleep. They said their prayers
+inwardly, and lying down, since there was nobody there with authority
+to make them kneel and recite aloud; in truth, they had a mind not to
+say them at all, but they were afraid to proceed to such lengths as
+that, lest they might call down a sudden and special thunderbolt from
+heaven. Then at once they reached and hovered upon the imminent verge
+of sleep--but an intruder came, now, that would not "down." It was
+conscience. They began to feel a vague fear that they had been doing
+wrong to run away; and next they thought of the stolen meat, and then
+the real torture came. They tried to argue it away by reminding
+conscience that they had purloined sweetmeats and apples scores of
+times; but conscience was not to be appeased by such thin
+plausibilities; it seemed to them, in the end, that there was no
+getting around the stubborn fact that taking sweetmeats was only
+"hooking," while taking bacon and hams and such valuables was plain
+simple stealing--and there was a command against that in the Bible. So
+they inwardly resolved that so long as they remained in the business,
+their piracies should not again be sullied with the crime of stealing.
+Then conscience granted a truce, and these curiously inconsistent
+pirates fell peacefully to sleep.
+
+
+
+CHAPTER XIV
+
+WHEN Tom awoke in the morning, he wondered where he was. He sat up and
+rubbed his eyes and looked around. Then he comprehended. It was the
+cool gray dawn, and there was a delicious sense of repose and peace in
+the deep pervading calm and silence of the woods. Not a leaf stirred;
+not a sound obtruded upon great Nature's meditation. Beaded dewdrops
+stood upon the leaves and grasses. A white layer of ashes covered the
+fire, and a thin blue breath of smoke rose straight into the air. Joe
+and Huck still slept.
+
+Now, far away in the woods a bird called; another answered; presently
+the hammering of a woodpecker was heard. Gradually the cool dim gray of
+the morning whitened, and as gradually sounds multiplied and life
+manifested itself. The marvel of Nature shaking off sleep and going to
+work unfolded itself to the musing boy. A little green worm came
+crawling over a dewy leaf, lifting two-thirds of his body into the air
+from time to time and "sniffing around," then proceeding again--for he
+was measuring, Tom said; and when the worm approached him, of its own
+accord, he sat as still as a stone, with his hopes rising and falling,
+by turns, as the creature still came toward him or seemed inclined to
+go elsewhere; and when at last it considered a painful moment with its
+curved body in the air and then came decisively down upon Tom's leg and
+began a journey over him, his whole heart was glad--for that meant that
+he was going to have a new suit of clothes--without the shadow of a
+doubt a gaudy piratical uniform. Now a procession of ants appeared,
+from nowhere in particular, and went about their labors; one struggled
+manfully by with a dead spider five times as big as itself in its arms,
+and lugged it straight up a tree-trunk. A brown spotted lady-bug
+climbed the dizzy height of a grass blade, and Tom bent down close to
+it and said, "Lady-bug, lady-bug, fly away home, your house is on fire,
+your children's alone," and she took wing and went off to see about it
+--which did not surprise the boy, for he knew of old that this insect was
+credulous about conflagrations, and he had practised upon its
+simplicity more than once. A tumblebug came next, heaving sturdily at
+its ball, and Tom touched the creature, to see it shut its legs against
+its body and pretend to be dead. The birds were fairly rioting by this
+time. A catbird, the Northern mocker, lit in a tree over Tom's head,
+and trilled out her imitations of her neighbors in a rapture of
+enjoyment; then a shrill jay swept down, a flash of blue flame, and
+stopped on a twig almost within the boy's reach, cocked his head to one
+side and eyed the strangers with a consuming curiosity; a gray squirrel
+and a big fellow of the "fox" kind came skurrying along, sitting up at
+intervals to inspect and chatter at the boys, for the wild things had
+probably never seen a human being before and scarcely knew whether to
+be afraid or not. All Nature was wide awake and stirring, now; long
+lances of sunlight pierced down through the dense foliage far and near,
+and a few butterflies came fluttering upon the scene.
+
+Tom stirred up the other pirates and they all clattered away with a
+shout, and in a minute or two were stripped and chasing after and
+tumbling over each other in the shallow limpid water of the white
+sandbar. They felt no longing for the little village sleeping in the
+distance beyond the majestic waste of water. A vagrant current or a
+slight rise in the river had carried off their raft, but this only
+gratified them, since its going was something like burning the bridge
+between them and civilization.
+
+They came back to camp wonderfully refreshed, glad-hearted, and
+ravenous; and they soon had the camp-fire blazing up again. Huck found
+a spring of clear cold water close by, and the boys made cups of broad
+oak or hickory leaves, and felt that water, sweetened with such a
+wildwood charm as that, would be a good enough substitute for coffee.
+While Joe was slicing bacon for breakfast, Tom and Huck asked him to
+hold on a minute; they stepped to a promising nook in the river-bank
+and threw in their lines; almost immediately they had reward. Joe had
+not had time to get impatient before they were back again with some
+handsome bass, a couple of sun-perch and a small catfish--provisions
+enough for quite a family. They fried the fish with the bacon, and were
+astonished; for no fish had ever seemed so delicious before. They did
+not know that the quicker a fresh-water fish is on the fire after he is
+caught the better he is; and they reflected little upon what a sauce
+open-air sleeping, open-air exercise, bathing, and a large ingredient
+of hunger make, too.
+
+They lay around in the shade, after breakfast, while Huck had a smoke,
+and then went off through the woods on an exploring expedition. They
+tramped gayly along, over decaying logs, through tangled underbrush,
+among solemn monarchs of the forest, hung from their crowns to the
+ground with a drooping regalia of grape-vines. Now and then they came
+upon snug nooks carpeted with grass and jeweled with flowers.
+
+They found plenty of things to be delighted with, but nothing to be
+astonished at. They discovered that the island was about three miles
+long and a quarter of a mile wide, and that the shore it lay closest to
+was only separated from it by a narrow channel hardly two hundred yards
+wide. They took a swim about every hour, so it was close upon the
+middle of the afternoon when they got back to camp. They were too
+hungry to stop to fish, but they fared sumptuously upon cold ham, and
+then threw themselves down in the shade to talk. But the talk soon
+began to drag, and then died. The stillness, the solemnity that brooded
+in the woods, and the sense of loneliness, began to tell upon the
+spirits of the boys. They fell to thinking. A sort of undefined longing
+crept upon them. This took dim shape, presently--it was budding
+homesickness. Even Finn the Red-Handed was dreaming of his doorsteps
+and empty hogsheads. But they were all ashamed of their weakness, and
+none was brave enough to speak his thought.
+
+For some time, now, the boys had been dully conscious of a peculiar
+sound in the distance, just as one sometimes is of the ticking of a
+clock which he takes no distinct note of. But now this mysterious sound
+became more pronounced, and forced a recognition. The boys started,
+glanced at each other, and then each assumed a listening attitude.
+There was a long silence, profound and unbroken; then a deep, sullen
+boom came floating down out of the distance.
+
+"What is it!" exclaimed Joe, under his breath.
+
+"I wonder," said Tom in a whisper.
+
+"'Tain't thunder," said Huckleberry, in an awed tone, "becuz thunder--"
+
+"Hark!" said Tom. "Listen--don't talk."
+
+They waited a time that seemed an age, and then the same muffled boom
+troubled the solemn hush.
+
+"Let's go and see."
+
+They sprang to their feet and hurried to the shore toward the town.
+They parted the bushes on the bank and peered out over the water. The
+little steam ferryboat was about a mile below the village, drifting
+with the current. Her broad deck seemed crowded with people. There were
+a great many skiffs rowing about or floating with the stream in the
+neighborhood of the ferryboat, but the boys could not determine what
+the men in them were doing. Presently a great jet of white smoke burst
+from the ferryboat's side, and as it expanded and rose in a lazy cloud,
+that same dull throb of sound was borne to the listeners again.
+
+"I know now!" exclaimed Tom; "somebody's drownded!"
+
+"That's it!" said Huck; "they done that last summer, when Bill Turner
+got drownded; they shoot a cannon over the water, and that makes him
+come up to the top. Yes, and they take loaves of bread and put
+quicksilver in 'em and set 'em afloat, and wherever there's anybody
+that's drownded, they'll float right there and stop."
+
+"Yes, I've heard about that," said Joe. "I wonder what makes the bread
+do that."
+
+"Oh, it ain't the bread, so much," said Tom; "I reckon it's mostly
+what they SAY over it before they start it out."
+
+"But they don't say anything over it," said Huck. "I've seen 'em and
+they don't."
+
+"Well, that's funny," said Tom. "But maybe they say it to themselves.
+Of COURSE they do. Anybody might know that."
+
+The other boys agreed that there was reason in what Tom said, because
+an ignorant lump of bread, uninstructed by an incantation, could not be
+expected to act very intelligently when set upon an errand of such
+gravity.
+
+"By jings, I wish I was over there, now," said Joe.
+
+"I do too" said Huck "I'd give heaps to know who it is."
+
+The boys still listened and watched. Presently a revealing thought
+flashed through Tom's mind, and he exclaimed:
+
+"Boys, I know who's drownded--it's us!"
+
+They felt like heroes in an instant. Here was a gorgeous triumph; they
+were missed; they were mourned; hearts were breaking on their account;
+tears were being shed; accusing memories of unkindness to these poor
+lost lads were rising up, and unavailing regrets and remorse were being
+indulged; and best of all, the departed were the talk of the whole
+town, and the envy of all the boys, as far as this dazzling notoriety
+was concerned. This was fine. It was worth while to be a pirate, after
+all.
+
+As twilight drew on, the ferryboat went back to her accustomed
+business and the skiffs disappeared. The pirates returned to camp. They
+were jubilant with vanity over their new grandeur and the illustrious
+trouble they were making. They caught fish, cooked supper and ate it,
+and then fell to guessing at what the village was thinking and saying
+about them; and the pictures they drew of the public distress on their
+account were gratifying to look upon--from their point of view. But
+when the shadows of night closed them in, they gradually ceased to
+talk, and sat gazing into the fire, with their minds evidently
+wandering elsewhere. The excitement was gone, now, and Tom and Joe
+could not keep back thoughts of certain persons at home who were not
+enjoying this fine frolic as much as they were. Misgivings came; they
+grew troubled and unhappy; a sigh or two escaped, unawares. By and by
+Joe timidly ventured upon a roundabout "feeler" as to how the others
+might look upon a return to civilization--not right now, but--
+
+Tom withered him with derision! Huck, being uncommitted as yet, joined
+in with Tom, and the waverer quickly "explained," and was glad to get
+out of the scrape with as little taint of chicken-hearted homesickness
+clinging to his garments as he could. Mutiny was effectually laid to
+rest for the moment.
+
+As the night deepened, Huck began to nod, and presently to snore. Joe
+followed next. Tom lay upon his elbow motionless, for some time,
+watching the two intently. At last he got up cautiously, on his knees,
+and went searching among the grass and the flickering reflections flung
+by the camp-fire. He picked up and inspected several large
+semi-cylinders of the thin white bark of a sycamore, and finally chose
+two which seemed to suit him. Then he knelt by the fire and painfully
+wrote something upon each of these with his "red keel"; one he rolled up
+and put in his jacket pocket, and the other he put in Joe's hat and
+removed it to a little distance from the owner. And he also put into the
+hat certain schoolboy treasures of almost inestimable value--among them
+a lump of chalk, an India-rubber ball, three fishhooks, and one of that
+kind of marbles known as a "sure 'nough crystal." Then he tiptoed his
+way cautiously among the trees till he felt that he was out of hearing,
+and straightway broke into a keen run in the direction of the sandbar.
+
+
+
+CHAPTER XV
+
+A FEW minutes later Tom was in the shoal water of the bar, wading
+toward the Illinois shore. Before the depth reached his middle he was
+half-way over; the current would permit no more wading, now, so he
+struck out confidently to swim the remaining hundred yards. He swam
+quartering upstream, but still was swept downward rather faster than he
+had expected. However, he reached the shore finally, and drifted along
+till he found a low place and drew himself out. He put his hand on his
+jacket pocket, found his piece of bark safe, and then struck through
+the woods, following the shore, with streaming garments. Shortly before
+ten o'clock he came out into an open place opposite the village, and
+saw the ferryboat lying in the shadow of the trees and the high bank.
+Everything was quiet under the blinking stars. He crept down the bank,
+watching with all his eyes, slipped into the water, swam three or four
+strokes and climbed into the skiff that did "yawl" duty at the boat's
+stern. He laid himself down under the thwarts and waited, panting.
+
+Presently the cracked bell tapped and a voice gave the order to "cast
+off." A minute or two later the skiff's head was standing high up,
+against the boat's swell, and the voyage was begun. Tom felt happy in
+his success, for he knew it was the boat's last trip for the night. At
+the end of a long twelve or fifteen minutes the wheels stopped, and Tom
+slipped overboard and swam ashore in the dusk, landing fifty yards
+downstream, out of danger of possible stragglers.
+
+He flew along unfrequented alleys, and shortly found himself at his
+aunt's back fence. He climbed over, approached the "ell," and looked in
+at the sitting-room window, for a light was burning there. There sat
+Aunt Polly, Sid, Mary, and Joe Harper's mother, grouped together,
+talking. They were by the bed, and the bed was between them and the
+door. Tom went to the door and began to softly lift the latch; then he
+pressed gently and the door yielded a crack; he continued pushing
+cautiously, and quaking every time it creaked, till he judged he might
+squeeze through on his knees; so he put his head through and began,
+warily.
+
+"What makes the candle blow so?" said Aunt Polly. Tom hurried up.
+"Why, that door's open, I believe. Why, of course it is. No end of
+strange things now. Go 'long and shut it, Sid."
+
+Tom disappeared under the bed just in time. He lay and "breathed"
+himself for a time, and then crept to where he could almost touch his
+aunt's foot.
+
+"But as I was saying," said Aunt Polly, "he warn't BAD, so to say
+--only mischEEvous. Only just giddy, and harum-scarum, you know. He
+warn't any more responsible than a colt. HE never meant any harm, and
+he was the best-hearted boy that ever was"--and she began to cry.
+
+"It was just so with my Joe--always full of his devilment, and up to
+every kind of mischief, but he was just as unselfish and kind as he
+could be--and laws bless me, to think I went and whipped him for taking
+that cream, never once recollecting that I throwed it out myself
+because it was sour, and I never to see him again in this world, never,
+never, never, poor abused boy!" And Mrs. Harper sobbed as if her heart
+would break.
+
+"I hope Tom's better off where he is," said Sid, "but if he'd been
+better in some ways--"
+
+"SID!" Tom felt the glare of the old lady's eye, though he could not
+see it. "Not a word against my Tom, now that he's gone! God'll take
+care of HIM--never you trouble YOURself, sir! Oh, Mrs. Harper, I don't
+know how to give him up! I don't know how to give him up! He was such a
+comfort to me, although he tormented my old heart out of me, 'most."
+
+"The Lord giveth and the Lord hath taken away--Blessed be the name of
+the Lord! But it's so hard--Oh, it's so hard! Only last Saturday my
+Joe busted a firecracker right under my nose and I knocked him
+sprawling. Little did I know then, how soon--Oh, if it was to do over
+again I'd hug him and bless him for it."
+
+"Yes, yes, yes, I know just how you feel, Mrs. Harper, I know just
+exactly how you feel. No longer ago than yesterday noon, my Tom took
+and filled the cat full of Pain-killer, and I did think the cretur
+would tear the house down. And God forgive me, I cracked Tom's head
+with my thimble, poor boy, poor dead boy. But he's out of all his
+troubles now. And the last words I ever heard him say was to reproach--"
+
+But this memory was too much for the old lady, and she broke entirely
+down. Tom was snuffling, now, himself--and more in pity of himself than
+anybody else. He could hear Mary crying, and putting in a kindly word
+for him from time to time. He began to have a nobler opinion of himself
+than ever before. Still, he was sufficiently touched by his aunt's
+grief to long to rush out from under the bed and overwhelm her with
+joy--and the theatrical gorgeousness of the thing appealed strongly to
+his nature, too, but he resisted and lay still.
+
+He went on listening, and gathered by odds and ends that it was
+conjectured at first that the boys had got drowned while taking a swim;
+then the small raft had been missed; next, certain boys said the
+missing lads had promised that the village should "hear something"
+soon; the wise-heads had "put this and that together" and decided that
+the lads had gone off on that raft and would turn up at the next town
+below, presently; but toward noon the raft had been found, lodged
+against the Missouri shore some five or six miles below the village
+--and then hope perished; they must be drowned, else hunger would have
+driven them home by nightfall if not sooner. It was believed that the
+search for the bodies had been a fruitless effort merely because the
+drowning must have occurred in mid-channel, since the boys, being good
+swimmers, would otherwise have escaped to shore. This was Wednesday
+night. If the bodies continued missing until Sunday, all hope would be
+given over, and the funerals would be preached on that morning. Tom
+shuddered.
+
+Mrs. Harper gave a sobbing good-night and turned to go. Then with a
+mutual impulse the two bereaved women flung themselves into each
+other's arms and had a good, consoling cry, and then parted. Aunt Polly
+was tender far beyond her wont, in her good-night to Sid and Mary. Sid
+snuffled a bit and Mary went off crying with all her heart.
+
+Aunt Polly knelt down and prayed for Tom so touchingly, so
+appealingly, and with such measureless love in her words and her old
+trembling voice, that he was weltering in tears again, long before she
+was through.
+
+He had to keep still long after she went to bed, for she kept making
+broken-hearted ejaculations from time to time, tossing unrestfully, and
+turning over. But at last she was still, only moaning a little in her
+sleep. Now the boy stole out, rose gradually by the bedside, shaded the
+candle-light with his hand, and stood regarding her. His heart was full
+of pity for her. He took out his sycamore scroll and placed it by the
+candle. But something occurred to him, and he lingered considering. His
+face lighted with a happy solution of his thought; he put the bark
+hastily in his pocket. Then he bent over and kissed the faded lips, and
+straightway made his stealthy exit, latching the door behind him.
+
+He threaded his way back to the ferry landing, found nobody at large
+there, and walked boldly on board the boat, for he knew she was
+tenantless except that there was a watchman, who always turned in and
+slept like a graven image. He untied the skiff at the stern, slipped
+into it, and was soon rowing cautiously upstream. When he had pulled a
+mile above the village, he started quartering across and bent himself
+stoutly to his work. He hit the landing on the other side neatly, for
+this was a familiar bit of work to him. He was moved to capture the
+skiff, arguing that it might be considered a ship and therefore
+legitimate prey for a pirate, but he knew a thorough search would be
+made for it and that might end in revelations. So he stepped ashore and
+entered the woods.
+
+He sat down and took a long rest, torturing himself meanwhile to keep
+awake, and then started warily down the home-stretch. The night was far
+spent. It was broad daylight before he found himself fairly abreast the
+island bar. He rested again until the sun was well up and gilding the
+great river with its splendor, and then he plunged into the stream. A
+little later he paused, dripping, upon the threshold of the camp, and
+heard Joe say:
+
+"No, Tom's true-blue, Huck, and he'll come back. He won't desert. He
+knows that would be a disgrace to a pirate, and Tom's too proud for
+that sort of thing. He's up to something or other. Now I wonder what?"
+
+"Well, the things is ours, anyway, ain't they?"
+
+"Pretty near, but not yet, Huck. The writing says they are if he ain't
+back here to breakfast."
+
+"Which he is!" exclaimed Tom, with fine dramatic effect, stepping
+grandly into camp.
+
+A sumptuous breakfast of bacon and fish was shortly provided, and as
+the boys set to work upon it, Tom recounted (and adorned) his
+adventures. They were a vain and boastful company of heroes when the
+tale was done. Then Tom hid himself away in a shady nook to sleep till
+noon, and the other pirates got ready to fish and explore.
+
+
+
+CHAPTER XVI
+
+AFTER dinner all the gang turned out to hunt for turtle eggs on the
+bar. They went about poking sticks into the sand, and when they found a
+soft place they went down on their knees and dug with their hands.
+Sometimes they would take fifty or sixty eggs out of one hole. They
+were perfectly round white things a trifle smaller than an English
+walnut. They had a famous fried-egg feast that night, and another on
+Friday morning.
+
+After breakfast they went whooping and prancing out on the bar, and
+chased each other round and round, shedding clothes as they went, until
+they were naked, and then continued the frolic far away up the shoal
+water of the bar, against the stiff current, which latter tripped their
+legs from under them from time to time and greatly increased the fun.
+And now and then they stooped in a group and splashed water in each
+other's faces with their palms, gradually approaching each other, with
+averted faces to avoid the strangling sprays, and finally gripping and
+struggling till the best man ducked his neighbor, and then they all
+went under in a tangle of white legs and arms and came up blowing,
+sputtering, laughing, and gasping for breath at one and the same time.
+
+When they were well exhausted, they would run out and sprawl on the
+dry, hot sand, and lie there and cover themselves up with it, and by
+and by break for the water again and go through the original
+performance once more. Finally it occurred to them that their naked
+skin represented flesh-colored "tights" very fairly; so they drew a
+ring in the sand and had a circus--with three clowns in it, for none
+would yield this proudest post to his neighbor.
+
+Next they got their marbles and played "knucks" and "ring-taw" and
+"keeps" till that amusement grew stale. Then Joe and Huck had another
+swim, but Tom would not venture, because he found that in kicking off
+his trousers he had kicked his string of rattlesnake rattles off his
+ankle, and he wondered how he had escaped cramp so long without the
+protection of this mysterious charm. He did not venture again until he
+had found it, and by that time the other boys were tired and ready to
+rest. They gradually wandered apart, dropped into the "dumps," and fell
+to gazing longingly across the wide river to where the village lay
+drowsing in the sun. Tom found himself writing "BECKY" in the sand with
+his big toe; he scratched it out, and was angry with himself for his
+weakness. But he wrote it again, nevertheless; he could not help it. He
+erased it once more and then took himself out of temptation by driving
+the other boys together and joining them.
+
+But Joe's spirits had gone down almost beyond resurrection. He was so
+homesick that he could hardly endure the misery of it. The tears lay
+very near the surface. Huck was melancholy, too. Tom was downhearted,
+but tried hard not to show it. He had a secret which he was not ready
+to tell, yet, but if this mutinous depression was not broken up soon,
+he would have to bring it out. He said, with a great show of
+cheerfulness:
+
+"I bet there's been pirates on this island before, boys. We'll explore
+it again. They've hid treasures here somewhere. How'd you feel to light
+on a rotten chest full of gold and silver--hey?"
+
+But it roused only faint enthusiasm, which faded out, with no reply.
+Tom tried one or two other seductions; but they failed, too. It was
+discouraging work. Joe sat poking up the sand with a stick and looking
+very gloomy. Finally he said:
+
+"Oh, boys, let's give it up. I want to go home. It's so lonesome."
+
+"Oh no, Joe, you'll feel better by and by," said Tom. "Just think of
+the fishing that's here."
+
+"I don't care for fishing. I want to go home."
+
+"But, Joe, there ain't such another swimming-place anywhere."
+
+"Swimming's no good. I don't seem to care for it, somehow, when there
+ain't anybody to say I sha'n't go in. I mean to go home."
+
+"Oh, shucks! Baby! You want to see your mother, I reckon."
+
+"Yes, I DO want to see my mother--and you would, too, if you had one.
+I ain't any more baby than you are." And Joe snuffled a little.
+
+"Well, we'll let the cry-baby go home to his mother, won't we, Huck?
+Poor thing--does it want to see its mother? And so it shall. You like
+it here, don't you, Huck? We'll stay, won't we?"
+
+Huck said, "Y-e-s"--without any heart in it.
+
+"I'll never speak to you again as long as I live," said Joe, rising.
+"There now!" And he moved moodily away and began to dress himself.
+
+"Who cares!" said Tom. "Nobody wants you to. Go 'long home and get
+laughed at. Oh, you're a nice pirate. Huck and me ain't cry-babies.
+We'll stay, won't we, Huck? Let him go if he wants to. I reckon we can
+get along without him, per'aps."
+
+But Tom was uneasy, nevertheless, and was alarmed to see Joe go
+sullenly on with his dressing. And then it was discomforting to see
+Huck eying Joe's preparations so wistfully, and keeping up such an
+ominous silence. Presently, without a parting word, Joe began to wade
+off toward the Illinois shore. Tom's heart began to sink. He glanced at
+Huck. Huck could not bear the look, and dropped his eyes. Then he said:
+
+"I want to go, too, Tom. It was getting so lonesome anyway, and now
+it'll be worse. Let's us go, too, Tom."
+
+"I won't! You can all go, if you want to. I mean to stay."
+
+"Tom, I better go."
+
+"Well, go 'long--who's hendering you."
+
+Huck began to pick up his scattered clothes. He said:
+
+"Tom, I wisht you'd come, too. Now you think it over. We'll wait for
+you when we get to shore."
+
+"Well, you'll wait a blame long time, that's all."
+
+Huck started sorrowfully away, and Tom stood looking after him, with a
+strong desire tugging at his heart to yield his pride and go along too.
+He hoped the boys would stop, but they still waded slowly on. It
+suddenly dawned on Tom that it was become very lonely and still. He
+made one final struggle with his pride, and then darted after his
+comrades, yelling:
+
+"Wait! Wait! I want to tell you something!"
+
+They presently stopped and turned around. When he got to where they
+were, he began unfolding his secret, and they listened moodily till at
+last they saw the "point" he was driving at, and then they set up a
+war-whoop of applause and said it was "splendid!" and said if he had
+told them at first, they wouldn't have started away. He made a plausible
+excuse; but his real reason had been the fear that not even the secret
+would keep them with him any very great length of time, and so he had
+meant to hold it in reserve as a last seduction.
+
+The lads came gayly back and went at their sports again with a will,
+chattering all the time about Tom's stupendous plan and admiring the
+genius of it. After a dainty egg and fish dinner, Tom said he wanted to
+learn to smoke, now. Joe caught at the idea and said he would like to
+try, too. So Huck made pipes and filled them. These novices had never
+smoked anything before but cigars made of grape-vine, and they "bit"
+the tongue, and were not considered manly anyway.
+
+Now they stretched themselves out on their elbows and began to puff,
+charily, and with slender confidence. The smoke had an unpleasant
+taste, and they gagged a little, but Tom said:
+
+"Why, it's just as easy! If I'd a knowed this was all, I'd a learnt
+long ago."
+
+"So would I," said Joe. "It's just nothing."
+
+"Why, many a time I've looked at people smoking, and thought well I
+wish I could do that; but I never thought I could," said Tom.
+
+"That's just the way with me, hain't it, Huck? You've heard me talk
+just that way--haven't you, Huck? I'll leave it to Huck if I haven't."
+
+"Yes--heaps of times," said Huck.
+
+"Well, I have too," said Tom; "oh, hundreds of times. Once down by the
+slaughter-house. Don't you remember, Huck? Bob Tanner was there, and
+Johnny Miller, and Jeff Thatcher, when I said it. Don't you remember,
+Huck, 'bout me saying that?"
+
+"Yes, that's so," said Huck. "That was the day after I lost a white
+alley. No, 'twas the day before."
+
+"There--I told you so," said Tom. "Huck recollects it."
+
+"I bleeve I could smoke this pipe all day," said Joe. "I don't feel
+sick."
+
+"Neither do I," said Tom. "I could smoke it all day. But I bet you
+Jeff Thatcher couldn't."
+
+"Jeff Thatcher! Why, he'd keel over just with two draws. Just let him
+try it once. HE'D see!"
+
+"I bet he would. And Johnny Miller--I wish could see Johnny Miller
+tackle it once."
+
+"Oh, don't I!" said Joe. "Why, I bet you Johnny Miller couldn't any
+more do this than nothing. Just one little snifter would fetch HIM."
+
+"'Deed it would, Joe. Say--I wish the boys could see us now."
+
+"So do I."
+
+"Say--boys, don't say anything about it, and some time when they're
+around, I'll come up to you and say, 'Joe, got a pipe? I want a smoke.'
+And you'll say, kind of careless like, as if it warn't anything, you'll
+say, 'Yes, I got my OLD pipe, and another one, but my tobacker ain't
+very good.' And I'll say, 'Oh, that's all right, if it's STRONG
+enough.' And then you'll out with the pipes, and we'll light up just as
+ca'm, and then just see 'em look!"
+
+"By jings, that'll be gay, Tom! I wish it was NOW!"
+
+"So do I! And when we tell 'em we learned when we was off pirating,
+won't they wish they'd been along?"
+
+"Oh, I reckon not! I'll just BET they will!"
+
+So the talk ran on. But presently it began to flag a trifle, and grow
+disjointed. The silences widened; the expectoration marvellously
+increased. Every pore inside the boys' cheeks became a spouting
+fountain; they could scarcely bail out the cellars under their tongues
+fast enough to prevent an inundation; little overflowings down their
+throats occurred in spite of all they could do, and sudden retchings
+followed every time. Both boys were looking very pale and miserable,
+now. Joe's pipe dropped from his nerveless fingers. Tom's followed.
+Both fountains were going furiously and both pumps bailing with might
+and main. Joe said feebly:
+
+"I've lost my knife. I reckon I better go and find it."
+
+Tom said, with quivering lips and halting utterance:
+
+"I'll help you. You go over that way and I'll hunt around by the
+spring. No, you needn't come, Huck--we can find it."
+
+So Huck sat down again, and waited an hour. Then he found it lonesome,
+and went to find his comrades. They were wide apart in the woods, both
+very pale, both fast asleep. But something informed him that if they
+had had any trouble they had got rid of it.
+
+They were not talkative at supper that night. They had a humble look,
+and when Huck prepared his pipe after the meal and was going to prepare
+theirs, they said no, they were not feeling very well--something they
+ate at dinner had disagreed with them.
+
+About midnight Joe awoke, and called the boys. There was a brooding
+oppressiveness in the air that seemed to bode something. The boys
+huddled themselves together and sought the friendly companionship of
+the fire, though the dull dead heat of the breathless atmosphere was
+stifling. They sat still, intent and waiting. The solemn hush
+continued. Beyond the light of the fire everything was swallowed up in
+the blackness of darkness. Presently there came a quivering glow that
+vaguely revealed the foliage for a moment and then vanished. By and by
+another came, a little stronger. Then another. Then a faint moan came
+sighing through the branches of the forest and the boys felt a fleeting
+breath upon their cheeks, and shuddered with the fancy that the Spirit
+of the Night had gone by. There was a pause. Now a weird flash turned
+night into day and showed every little grass-blade, separate and
+distinct, that grew about their feet. And it showed three white,
+startled faces, too. A deep peal of thunder went rolling and tumbling
+down the heavens and lost itself in sullen rumblings in the distance. A
+sweep of chilly air passed by, rustling all the leaves and snowing the
+flaky ashes broadcast about the fire. Another fierce glare lit up the
+forest and an instant crash followed that seemed to rend the tree-tops
+right over the boys' heads. They clung together in terror, in the thick
+gloom that followed. A few big rain-drops fell pattering upon the
+leaves.
+
+"Quick! boys, go for the tent!" exclaimed Tom.
+
+They sprang away, stumbling over roots and among vines in the dark, no
+two plunging in the same direction. A furious blast roared through the
+trees, making everything sing as it went. One blinding flash after
+another came, and peal on peal of deafening thunder. And now a
+drenching rain poured down and the rising hurricane drove it in sheets
+along the ground. The boys cried out to each other, but the roaring
+wind and the booming thunder-blasts drowned their voices utterly.
+However, one by one they straggled in at last and took shelter under
+the tent, cold, scared, and streaming with water; but to have company
+in misery seemed something to be grateful for. They could not talk, the
+old sail flapped so furiously, even if the other noises would have
+allowed them. The tempest rose higher and higher, and presently the
+sail tore loose from its fastenings and went winging away on the blast.
+The boys seized each others' hands and fled, with many tumblings and
+bruises, to the shelter of a great oak that stood upon the river-bank.
+Now the battle was at its highest. Under the ceaseless conflagration of
+lightning that flamed in the skies, everything below stood out in
+clean-cut and shadowless distinctness: the bending trees, the billowy
+river, white with foam, the driving spray of spume-flakes, the dim
+outlines of the high bluffs on the other side, glimpsed through the
+drifting cloud-rack and the slanting veil of rain. Every little while
+some giant tree yielded the fight and fell crashing through the younger
+growth; and the unflagging thunder-peals came now in ear-splitting
+explosive bursts, keen and sharp, and unspeakably appalling. The storm
+culminated in one matchless effort that seemed likely to tear the island
+to pieces, burn it up, drown it to the tree-tops, blow it away, and
+deafen every creature in it, all at one and the same moment. It was a
+wild night for homeless young heads to be out in.
+
+But at last the battle was done, and the forces retired with weaker
+and weaker threatenings and grumblings, and peace resumed her sway. The
+boys went back to camp, a good deal awed; but they found there was
+still something to be thankful for, because the great sycamore, the
+shelter of their beds, was a ruin, now, blasted by the lightnings, and
+they were not under it when the catastrophe happened.
+
+Everything in camp was drenched, the camp-fire as well; for they were
+but heedless lads, like their generation, and had made no provision
+against rain. Here was matter for dismay, for they were soaked through
+and chilled. They were eloquent in their distress; but they presently
+discovered that the fire had eaten so far up under the great log it had
+been built against (where it curved upward and separated itself from
+the ground), that a handbreadth or so of it had escaped wetting; so
+they patiently wrought until, with shreds and bark gathered from the
+under sides of sheltered logs, they coaxed the fire to burn again. Then
+they piled on great dead boughs till they had a roaring furnace, and
+were glad-hearted once more. They dried their boiled ham and had a
+feast, and after that they sat by the fire and expanded and glorified
+their midnight adventure until morning, for there was not a dry spot to
+sleep on, anywhere around.
+
+As the sun began to steal in upon the boys, drowsiness came over them,
+and they went out on the sandbar and lay down to sleep. They got
+scorched out by and by, and drearily set about getting breakfast. After
+the meal they felt rusty, and stiff-jointed, and a little homesick once
+more. Tom saw the signs, and fell to cheering up the pirates as well as
+he could. But they cared nothing for marbles, or circus, or swimming,
+or anything. He reminded them of the imposing secret, and raised a ray
+of cheer. While it lasted, he got them interested in a new device. This
+was to knock off being pirates, for a while, and be Indians for a
+change. They were attracted by this idea; so it was not long before
+they were stripped, and striped from head to heel with black mud, like
+so many zebras--all of them chiefs, of course--and then they went
+tearing through the woods to attack an English settlement.
+
+By and by they separated into three hostile tribes, and darted upon
+each other from ambush with dreadful war-whoops, and killed and scalped
+each other by thousands. It was a gory day. Consequently it was an
+extremely satisfactory one.
+
+They assembled in camp toward supper-time, hungry and happy; but now a
+difficulty arose--hostile Indians could not break the bread of
+hospitality together without first making peace, and this was a simple
+impossibility without smoking a pipe of peace. There was no other
+process that ever they had heard of. Two of the savages almost wished
+they had remained pirates. However, there was no other way; so with
+such show of cheerfulness as they could muster they called for the pipe
+and took their whiff as it passed, in due form.
+
+And behold, they were glad they had gone into savagery, for they had
+gained something; they found that they could now smoke a little without
+having to go and hunt for a lost knife; they did not get sick enough to
+be seriously uncomfortable. They were not likely to fool away this high
+promise for lack of effort. No, they practised cautiously, after
+supper, with right fair success, and so they spent a jubilant evening.
+They were prouder and happier in their new acquirement than they would
+have been in the scalping and skinning of the Six Nations. We will
+leave them to smoke and chatter and brag, since we have no further use
+for them at present.
+
+
+
+CHAPTER XVII
+
+BUT there was no hilarity in the little town that same tranquil
+Saturday afternoon. The Harpers, and Aunt Polly's family, were being
+put into mourning, with great grief and many tears. An unusual quiet
+possessed the village, although it was ordinarily quiet enough, in all
+conscience. The villagers conducted their concerns with an absent air,
+and talked little; but they sighed often. The Saturday holiday seemed a
+burden to the children. They had no heart in their sports, and
+gradually gave them up.
+
+In the afternoon Becky Thatcher found herself moping about the
+deserted schoolhouse yard, and feeling very melancholy. But she found
+nothing there to comfort her. She soliloquized:
+
+"Oh, if I only had a brass andiron-knob again! But I haven't got
+anything now to remember him by." And she choked back a little sob.
+
+Presently she stopped, and said to herself:
+
+"It was right here. Oh, if it was to do over again, I wouldn't say
+that--I wouldn't say it for the whole world. But he's gone now; I'll
+never, never, never see him any more."
+
+This thought broke her down, and she wandered away, with tears rolling
+down her cheeks. Then quite a group of boys and girls--playmates of
+Tom's and Joe's--came by, and stood looking over the paling fence and
+talking in reverent tones of how Tom did so-and-so the last time they
+saw him, and how Joe said this and that small trifle (pregnant with
+awful prophecy, as they could easily see now!)--and each speaker
+pointed out the exact spot where the lost lads stood at the time, and
+then added something like "and I was a-standing just so--just as I am
+now, and as if you was him--I was as close as that--and he smiled, just
+this way--and then something seemed to go all over me, like--awful, you
+know--and I never thought what it meant, of course, but I can see now!"
+
+Then there was a dispute about who saw the dead boys last in life, and
+many claimed that dismal distinction, and offered evidences, more or
+less tampered with by the witness; and when it was ultimately decided
+who DID see the departed last, and exchanged the last words with them,
+the lucky parties took upon themselves a sort of sacred importance, and
+were gaped at and envied by all the rest. One poor chap, who had no
+other grandeur to offer, said with tolerably manifest pride in the
+remembrance:
+
+"Well, Tom Sawyer he licked me once."
+
+But that bid for glory was a failure. Most of the boys could say that,
+and so that cheapened the distinction too much. The group loitered
+away, still recalling memories of the lost heroes, in awed voices.
+
+When the Sunday-school hour was finished, the next morning, the bell
+began to toll, instead of ringing in the usual way. It was a very still
+Sabbath, and the mournful sound seemed in keeping with the musing hush
+that lay upon nature. The villagers began to gather, loitering a moment
+in the vestibule to converse in whispers about the sad event. But there
+was no whispering in the house; only the funereal rustling of dresses
+as the women gathered to their seats disturbed the silence there. None
+could remember when the little church had been so full before. There
+was finally a waiting pause, an expectant dumbness, and then Aunt Polly
+entered, followed by Sid and Mary, and they by the Harper family, all
+in deep black, and the whole congregation, the old minister as well,
+rose reverently and stood until the mourners were seated in the front
+pew. There was another communing silence, broken at intervals by
+muffled sobs, and then the minister spread his hands abroad and prayed.
+A moving hymn was sung, and the text followed: "I am the Resurrection
+and the Life."
+
+As the service proceeded, the clergyman drew such pictures of the
+graces, the winning ways, and the rare promise of the lost lads that
+every soul there, thinking he recognized these pictures, felt a pang in
+remembering that he had persistently blinded himself to them always
+before, and had as persistently seen only faults and flaws in the poor
+boys. The minister related many a touching incident in the lives of the
+departed, too, which illustrated their sweet, generous natures, and the
+people could easily see, now, how noble and beautiful those episodes
+were, and remembered with grief that at the time they occurred they had
+seemed rank rascalities, well deserving of the cowhide. The
+congregation became more and more moved, as the pathetic tale went on,
+till at last the whole company broke down and joined the weeping
+mourners in a chorus of anguished sobs, the preacher himself giving way
+to his feelings, and crying in the pulpit.
+
+There was a rustle in the gallery, which nobody noticed; a moment
+later the church door creaked; the minister raised his streaming eyes
+above his handkerchief, and stood transfixed! First one and then
+another pair of eyes followed the minister's, and then almost with one
+impulse the congregation rose and stared while the three dead boys came
+marching up the aisle, Tom in the lead, Joe next, and Huck, a ruin of
+drooping rags, sneaking sheepishly in the rear! They had been hid in
+the unused gallery listening to their own funeral sermon!
+
+Aunt Polly, Mary, and the Harpers threw themselves upon their restored
+ones, smothered them with kisses and poured out thanksgivings, while
+poor Huck stood abashed and uncomfortable, not knowing exactly what to
+do or where to hide from so many unwelcoming eyes. He wavered, and
+started to slink away, but Tom seized him and said:
+
+"Aunt Polly, it ain't fair. Somebody's got to be glad to see Huck."
+
+"And so they shall. I'm glad to see him, poor motherless thing!" And
+the loving attentions Aunt Polly lavished upon him were the one thing
+capable of making him more uncomfortable than he was before.
+
+Suddenly the minister shouted at the top of his voice: "Praise God
+from whom all blessings flow--SING!--and put your hearts in it!"
+
+And they did. Old Hundred swelled up with a triumphant burst, and
+while it shook the rafters Tom Sawyer the Pirate looked around upon the
+envying juveniles about him and confessed in his heart that this was
+the proudest moment of his life.
+
+As the "sold" congregation trooped out they said they would almost be
+willing to be made ridiculous again to hear Old Hundred sung like that
+once more.
+
+Tom got more cuffs and kisses that day--according to Aunt Polly's
+varying moods--than he had earned before in a year; and he hardly knew
+which expressed the most gratefulness to God and affection for himself.
+
+
+
+CHAPTER XVIII
+
+THAT was Tom's great secret--the scheme to return home with his
+brother pirates and attend their own funerals. They had paddled over to
+the Missouri shore on a log, at dusk on Saturday, landing five or six
+miles below the village; they had slept in the woods at the edge of the
+town till nearly daylight, and had then crept through back lanes and
+alleys and finished their sleep in the gallery of the church among a
+chaos of invalided benches.
+
+At breakfast, Monday morning, Aunt Polly and Mary were very loving to
+Tom, and very attentive to his wants. There was an unusual amount of
+talk. In the course of it Aunt Polly said:
+
+"Well, I don't say it wasn't a fine joke, Tom, to keep everybody
+suffering 'most a week so you boys had a good time, but it is a pity
+you could be so hard-hearted as to let me suffer so. If you could come
+over on a log to go to your funeral, you could have come over and give
+me a hint some way that you warn't dead, but only run off."
+
+"Yes, you could have done that, Tom," said Mary; "and I believe you
+would if you had thought of it."
+
+"Would you, Tom?" said Aunt Polly, her face lighting wistfully. "Say,
+now, would you, if you'd thought of it?"
+
+"I--well, I don't know. 'Twould 'a' spoiled everything."
+
+"Tom, I hoped you loved me that much," said Aunt Polly, with a grieved
+tone that discomforted the boy. "It would have been something if you'd
+cared enough to THINK of it, even if you didn't DO it."
+
+"Now, auntie, that ain't any harm," pleaded Mary; "it's only Tom's
+giddy way--he is always in such a rush that he never thinks of
+anything."
+
+"More's the pity. Sid would have thought. And Sid would have come and
+DONE it, too. Tom, you'll look back, some day, when it's too late, and
+wish you'd cared a little more for me when it would have cost you so
+little."
+
+"Now, auntie, you know I do care for you," said Tom.
+
+"I'd know it better if you acted more like it."
+
+"I wish now I'd thought," said Tom, with a repentant tone; "but I
+dreamt about you, anyway. That's something, ain't it?"
+
+"It ain't much--a cat does that much--but it's better than nothing.
+What did you dream?"
+
+"Why, Wednesday night I dreamt that you was sitting over there by the
+bed, and Sid was sitting by the woodbox, and Mary next to him."
+
+"Well, so we did. So we always do. I'm glad your dreams could take
+even that much trouble about us."
+
+"And I dreamt that Joe Harper's mother was here."
+
+"Why, she was here! Did you dream any more?"
+
+"Oh, lots. But it's so dim, now."
+
+"Well, try to recollect--can't you?"
+
+"Somehow it seems to me that the wind--the wind blowed the--the--"
+
+"Try harder, Tom! The wind did blow something. Come!"
+
+Tom pressed his fingers on his forehead an anxious minute, and then
+said:
+
+"I've got it now! I've got it now! It blowed the candle!"
+
+"Mercy on us! Go on, Tom--go on!"
+
+"And it seems to me that you said, 'Why, I believe that that door--'"
+
+"Go ON, Tom!"
+
+"Just let me study a moment--just a moment. Oh, yes--you said you
+believed the door was open."
+
+"As I'm sitting here, I did! Didn't I, Mary! Go on!"
+
+"And then--and then--well I won't be certain, but it seems like as if
+you made Sid go and--and--"
+
+"Well? Well? What did I make him do, Tom? What did I make him do?"
+
+"You made him--you--Oh, you made him shut it."
+
+"Well, for the land's sake! I never heard the beat of that in all my
+days! Don't tell ME there ain't anything in dreams, any more. Sereny
+Harper shall know of this before I'm an hour older. I'd like to see her
+get around THIS with her rubbage 'bout superstition. Go on, Tom!"
+
+"Oh, it's all getting just as bright as day, now. Next you said I
+warn't BAD, only mischeevous and harum-scarum, and not any more
+responsible than--than--I think it was a colt, or something."
+
+"And so it was! Well, goodness gracious! Go on, Tom!"
+
+"And then you began to cry."
+
+"So I did. So I did. Not the first time, neither. And then--"
+
+"Then Mrs. Harper she began to cry, and said Joe was just the same,
+and she wished she hadn't whipped him for taking cream when she'd
+throwed it out her own self--"
+
+"Tom! The sperrit was upon you! You was a prophesying--that's what you
+was doing! Land alive, go on, Tom!"
+
+"Then Sid he said--he said--"
+
+"I don't think I said anything," said Sid.
+
+"Yes you did, Sid," said Mary.
+
+"Shut your heads and let Tom go on! What did he say, Tom?"
+
+"He said--I THINK he said he hoped I was better off where I was gone
+to, but if I'd been better sometimes--"
+
+"THERE, d'you hear that! It was his very words!"
+
+"And you shut him up sharp."
+
+"I lay I did! There must 'a' been an angel there. There WAS an angel
+there, somewheres!"
+
+"And Mrs. Harper told about Joe scaring her with a firecracker, and
+you told about Peter and the Painkiller--"
+
+"Just as true as I live!"
+
+"And then there was a whole lot of talk 'bout dragging the river for
+us, and 'bout having the funeral Sunday, and then you and old Miss
+Harper hugged and cried, and she went."
+
+"It happened just so! It happened just so, as sure as I'm a-sitting in
+these very tracks. Tom, you couldn't told it more like if you'd 'a'
+seen it! And then what? Go on, Tom!"
+
+"Then I thought you prayed for me--and I could see you and hear every
+word you said. And you went to bed, and I was so sorry that I took and
+wrote on a piece of sycamore bark, 'We ain't dead--we are only off
+being pirates,' and put it on the table by the candle; and then you
+looked so good, laying there asleep, that I thought I went and leaned
+over and kissed you on the lips."
+
+"Did you, Tom, DID you! I just forgive you everything for that!" And
+she seized the boy in a crushing embrace that made him feel like the
+guiltiest of villains.
+
+"It was very kind, even though it was only a--dream," Sid soliloquized
+just audibly.
+
+"Shut up, Sid! A body does just the same in a dream as he'd do if he
+was awake. Here's a big Milum apple I've been saving for you, Tom, if
+you was ever found again--now go 'long to school. I'm thankful to the
+good God and Father of us all I've got you back, that's long-suffering
+and merciful to them that believe on Him and keep His word, though
+goodness knows I'm unworthy of it, but if only the worthy ones got His
+blessings and had His hand to help them over the rough places, there's
+few enough would smile here or ever enter into His rest when the long
+night comes. Go 'long Sid, Mary, Tom--take yourselves off--you've
+hendered me long enough."
+
+The children left for school, and the old lady to call on Mrs. Harper
+and vanquish her realism with Tom's marvellous dream. Sid had better
+judgment than to utter the thought that was in his mind as he left the
+house. It was this: "Pretty thin--as long a dream as that, without any
+mistakes in it!"
+
+What a hero Tom was become, now! He did not go skipping and prancing,
+but moved with a dignified swagger as became a pirate who felt that the
+public eye was on him. And indeed it was; he tried not to seem to see
+the looks or hear the remarks as he passed along, but they were food
+and drink to him. Smaller boys than himself flocked at his heels, as
+proud to be seen with him, and tolerated by him, as if he had been the
+drummer at the head of a procession or the elephant leading a menagerie
+into town. Boys of his own size pretended not to know he had been away
+at all; but they were consuming with envy, nevertheless. They would
+have given anything to have that swarthy suntanned skin of his, and his
+glittering notoriety; and Tom would not have parted with either for a
+circus.
+
+At school the children made so much of him and of Joe, and delivered
+such eloquent admiration from their eyes, that the two heroes were not
+long in becoming insufferably "stuck-up." They began to tell their
+adventures to hungry listeners--but they only began; it was not a thing
+likely to have an end, with imaginations like theirs to furnish
+material. And finally, when they got out their pipes and went serenely
+puffing around, the very summit of glory was reached.
+
+Tom decided that he could be independent of Becky Thatcher now. Glory
+was sufficient. He would live for glory. Now that he was distinguished,
+maybe she would be wanting to "make up." Well, let her--she should see
+that he could be as indifferent as some other people. Presently she
+arrived. Tom pretended not to see her. He moved away and joined a group
+of boys and girls and began to talk. Soon he observed that she was
+tripping gayly back and forth with flushed face and dancing eyes,
+pretending to be busy chasing schoolmates, and screaming with laughter
+when she made a capture; but he noticed that she always made her
+captures in his vicinity, and that she seemed to cast a conscious eye
+in his direction at such times, too. It gratified all the vicious
+vanity that was in him; and so, instead of winning him, it only "set
+him up" the more and made him the more diligent to avoid betraying that
+he knew she was about. Presently she gave over skylarking, and moved
+irresolutely about, sighing once or twice and glancing furtively and
+wistfully toward Tom. Then she observed that now Tom was talking more
+particularly to Amy Lawrence than to any one else. She felt a sharp
+pang and grew disturbed and uneasy at once. She tried to go away, but
+her feet were treacherous, and carried her to the group instead. She
+said to a girl almost at Tom's elbow--with sham vivacity:
+
+"Why, Mary Austin! you bad girl, why didn't you come to Sunday-school?"
+
+"I did come--didn't you see me?"
+
+"Why, no! Did you? Where did you sit?"
+
+"I was in Miss Peters' class, where I always go. I saw YOU."
+
+"Did you? Why, it's funny I didn't see you. I wanted to tell you about
+the picnic."
+
+"Oh, that's jolly. Who's going to give it?"
+
+"My ma's going to let me have one."
+
+"Oh, goody; I hope she'll let ME come."
+
+"Well, she will. The picnic's for me. She'll let anybody come that I
+want, and I want you."
+
+"That's ever so nice. When is it going to be?"
+
+"By and by. Maybe about vacation."
+
+"Oh, won't it be fun! You going to have all the girls and boys?"
+
+"Yes, every one that's friends to me--or wants to be"; and she glanced
+ever so furtively at Tom, but he talked right along to Amy Lawrence
+about the terrible storm on the island, and how the lightning tore the
+great sycamore tree "all to flinders" while he was "standing within
+three feet of it."
+
+"Oh, may I come?" said Grace Miller.
+
+"Yes."
+
+"And me?" said Sally Rogers.
+
+"Yes."
+
+"And me, too?" said Susy Harper. "And Joe?"
+
+"Yes."
+
+And so on, with clapping of joyful hands till all the group had begged
+for invitations but Tom and Amy. Then Tom turned coolly away, still
+talking, and took Amy with him. Becky's lips trembled and the tears
+came to her eyes; she hid these signs with a forced gayety and went on
+chattering, but the life had gone out of the picnic, now, and out of
+everything else; she got away as soon as she could and hid herself and
+had what her sex call "a good cry." Then she sat moody, with wounded
+pride, till the bell rang. She roused up, now, with a vindictive cast
+in her eye, and gave her plaited tails a shake and said she knew what
+SHE'D do.
+
+At recess Tom continued his flirtation with Amy with jubilant
+self-satisfaction. And he kept drifting about to find Becky and lacerate
+her with the performance. At last he spied her, but there was a sudden
+falling of his mercury. She was sitting cosily on a little bench behind
+the schoolhouse looking at a picture-book with Alfred Temple--and so
+absorbed were they, and their heads so close together over the book,
+that they did not seem to be conscious of anything in the world besides.
+Jealousy ran red-hot through Tom's veins. He began to hate himself for
+throwing away the chance Becky had offered for a reconciliation. He
+called himself a fool, and all the hard names he could think of. He
+wanted to cry with vexation. Amy chatted happily along, as they walked,
+for her heart was singing, but Tom's tongue had lost its function. He
+did not hear what Amy was saying, and whenever she paused expectantly he
+could only stammer an awkward assent, which was as often misplaced as
+otherwise. He kept drifting to the rear of the schoolhouse, again and
+again, to sear his eyeballs with the hateful spectacle there. He could
+not help it. And it maddened him to see, as he thought he saw, that
+Becky Thatcher never once suspected that he was even in the land of the
+living. But she did see, nevertheless; and she knew she was winning her
+fight, too, and was glad to see him suffer as she had suffered.
+
+Amy's happy prattle became intolerable. Tom hinted at things he had to
+attend to; things that must be done; and time was fleeting. But in
+vain--the girl chirped on. Tom thought, "Oh, hang her, ain't I ever
+going to get rid of her?" At last he must be attending to those
+things--and she said artlessly that she would be "around" when school
+let out. And he hastened away, hating her for it.
+
+"Any other boy!" Tom thought, grating his teeth. "Any boy in the whole
+town but that Saint Louis smarty that thinks he dresses so fine and is
+aristocracy! Oh, all right, I licked you the first day you ever saw
+this town, mister, and I'll lick you again! You just wait till I catch
+you out! I'll just take and--"
+
+And he went through the motions of thrashing an imaginary boy
+--pummelling the air, and kicking and gouging. "Oh, you do, do you? You
+holler 'nough, do you? Now, then, let that learn you!" And so the
+imaginary flogging was finished to his satisfaction.
+
+Tom fled home at noon. His conscience could not endure any more of
+Amy's grateful happiness, and his jealousy could bear no more of the
+other distress. Becky resumed her picture inspections with Alfred, but
+as the minutes dragged along and no Tom came to suffer, her triumph
+began to cloud and she lost interest; gravity and absent-mindedness
+followed, and then melancholy; two or three times she pricked up her
+ear at a footstep, but it was a false hope; no Tom came. At last she
+grew entirely miserable and wished she hadn't carried it so far. When
+poor Alfred, seeing that he was losing her, he did not know how, kept
+exclaiming: "Oh, here's a jolly one! look at this!" she lost patience
+at last, and said, "Oh, don't bother me! I don't care for them!" and
+burst into tears, and got up and walked away.
+
+Alfred dropped alongside and was going to try to comfort her, but she
+said:
+
+"Go away and leave me alone, can't you! I hate you!"
+
+So the boy halted, wondering what he could have done--for she had said
+she would look at pictures all through the nooning--and she walked on,
+crying. Then Alfred went musing into the deserted schoolhouse. He was
+humiliated and angry. He easily guessed his way to the truth--the girl
+had simply made a convenience of him to vent her spite upon Tom Sawyer.
+He was far from hating Tom the less when this thought occurred to him.
+He wished there was some way to get that boy into trouble without much
+risk to himself. Tom's spelling-book fell under his eye. Here was his
+opportunity. He gratefully opened to the lesson for the afternoon and
+poured ink upon the page.
+
+Becky, glancing in at a window behind him at the moment, saw the act,
+and moved on, without discovering herself. She started homeward, now,
+intending to find Tom and tell him; Tom would be thankful and their
+troubles would be healed. Before she was half way home, however, she
+had changed her mind. The thought of Tom's treatment of her when she
+was talking about her picnic came scorching back and filled her with
+shame. She resolved to let him get whipped on the damaged
+spelling-book's account, and to hate him forever, into the bargain.
+
+
+
+CHAPTER XIX
+
+TOM arrived at home in a dreary mood, and the first thing his aunt
+said to him showed him that he had brought his sorrows to an
+unpromising market:
+
+"Tom, I've a notion to skin you alive!"
+
+"Auntie, what have I done?"
+
+"Well, you've done enough. Here I go over to Sereny Harper, like an
+old softy, expecting I'm going to make her believe all that rubbage
+about that dream, when lo and behold you she'd found out from Joe that
+you was over here and heard all the talk we had that night. Tom, I
+don't know what is to become of a boy that will act like that. It makes
+me feel so bad to think you could let me go to Sereny Harper and make
+such a fool of myself and never say a word."
+
+This was a new aspect of the thing. His smartness of the morning had
+seemed to Tom a good joke before, and very ingenious. It merely looked
+mean and shabby now. He hung his head and could not think of anything
+to say for a moment. Then he said:
+
+"Auntie, I wish I hadn't done it--but I didn't think."
+
+"Oh, child, you never think. You never think of anything but your own
+selfishness. You could think to come all the way over here from
+Jackson's Island in the night to laugh at our troubles, and you could
+think to fool me with a lie about a dream; but you couldn't ever think
+to pity us and save us from sorrow."
+
+"Auntie, I know now it was mean, but I didn't mean to be mean. I
+didn't, honest. And besides, I didn't come over here to laugh at you
+that night."
+
+"What did you come for, then?"
+
+"It was to tell you not to be uneasy about us, because we hadn't got
+drownded."
+
+"Tom, Tom, I would be the thankfullest soul in this world if I could
+believe you ever had as good a thought as that, but you know you never
+did--and I know it, Tom."
+
+"Indeed and 'deed I did, auntie--I wish I may never stir if I didn't."
+
+"Oh, Tom, don't lie--don't do it. It only makes things a hundred times
+worse."
+
+"It ain't a lie, auntie; it's the truth. I wanted to keep you from
+grieving--that was all that made me come."
+
+"I'd give the whole world to believe that--it would cover up a power
+of sins, Tom. I'd 'most be glad you'd run off and acted so bad. But it
+ain't reasonable; because, why didn't you tell me, child?"
+
+"Why, you see, when you got to talking about the funeral, I just got
+all full of the idea of our coming and hiding in the church, and I
+couldn't somehow bear to spoil it. So I just put the bark back in my
+pocket and kept mum."
+
+"What bark?"
+
+"The bark I had wrote on to tell you we'd gone pirating. I wish, now,
+you'd waked up when I kissed you--I do, honest."
+
+The hard lines in his aunt's face relaxed and a sudden tenderness
+dawned in her eyes.
+
+"DID you kiss me, Tom?"
+
+"Why, yes, I did."
+
+"Are you sure you did, Tom?"
+
+"Why, yes, I did, auntie--certain sure."
+
+"What did you kiss me for, Tom?"
+
+"Because I loved you so, and you laid there moaning and I was so sorry."
+
+The words sounded like truth. The old lady could not hide a tremor in
+her voice when she said:
+
+"Kiss me again, Tom!--and be off with you to school, now, and don't
+bother me any more."
+
+The moment he was gone, she ran to a closet and got out the ruin of a
+jacket which Tom had gone pirating in. Then she stopped, with it in her
+hand, and said to herself:
+
+"No, I don't dare. Poor boy, I reckon he's lied about it--but it's a
+blessed, blessed lie, there's such a comfort come from it. I hope the
+Lord--I KNOW the Lord will forgive him, because it was such
+goodheartedness in him to tell it. But I don't want to find out it's a
+lie. I won't look."
+
+She put the jacket away, and stood by musing a minute. Twice she put
+out her hand to take the garment again, and twice she refrained. Once
+more she ventured, and this time she fortified herself with the
+thought: "It's a good lie--it's a good lie--I won't let it grieve me."
+So she sought the jacket pocket. A moment later she was reading Tom's
+piece of bark through flowing tears and saying: "I could forgive the
+boy, now, if he'd committed a million sins!"
+
+
+
+CHAPTER XX
+
+THERE was something about Aunt Polly's manner, when she kissed Tom,
+that swept away his low spirits and made him lighthearted and happy
+again. He started to school and had the luck of coming upon Becky
+Thatcher at the head of Meadow Lane. His mood always determined his
+manner. Without a moment's hesitation he ran to her and said:
+
+"I acted mighty mean to-day, Becky, and I'm so sorry. I won't ever,
+ever do that way again, as long as ever I live--please make up, won't
+you?"
+
+The girl stopped and looked him scornfully in the face:
+
+"I'll thank you to keep yourself TO yourself, Mr. Thomas Sawyer. I'll
+never speak to you again."
+
+She tossed her head and passed on. Tom was so stunned that he had not
+even presence of mind enough to say "Who cares, Miss Smarty?" until the
+right time to say it had gone by. So he said nothing. But he was in a
+fine rage, nevertheless. He moped into the schoolyard wishing she were
+a boy, and imagining how he would trounce her if she were. He presently
+encountered her and delivered a stinging remark as he passed. She
+hurled one in return, and the angry breach was complete. It seemed to
+Becky, in her hot resentment, that she could hardly wait for school to
+"take in," she was so impatient to see Tom flogged for the injured
+spelling-book. If she had had any lingering notion of exposing Alfred
+Temple, Tom's offensive fling had driven it entirely away.
+
+Poor girl, she did not know how fast she was nearing trouble herself.
+The master, Mr. Dobbins, had reached middle age with an unsatisfied
+ambition. The darling of his desires was, to be a doctor, but poverty
+had decreed that he should be nothing higher than a village
+schoolmaster. Every day he took a mysterious book out of his desk and
+absorbed himself in it at times when no classes were reciting. He kept
+that book under lock and key. There was not an urchin in school but was
+perishing to have a glimpse of it, but the chance never came. Every boy
+and girl had a theory about the nature of that book; but no two
+theories were alike, and there was no way of getting at the facts in
+the case. Now, as Becky was passing by the desk, which stood near the
+door, she noticed that the key was in the lock! It was a precious
+moment. She glanced around; found herself alone, and the next instant
+she had the book in her hands. The title-page--Professor Somebody's
+ANATOMY--carried no information to her mind; so she began to turn the
+leaves. She came at once upon a handsomely engraved and colored
+frontispiece--a human figure, stark naked. At that moment a shadow fell
+on the page and Tom Sawyer stepped in at the door and caught a glimpse
+of the picture. Becky snatched at the book to close it, and had the
+hard luck to tear the pictured page half down the middle. She thrust
+the volume into the desk, turned the key, and burst out crying with
+shame and vexation.
+
+"Tom Sawyer, you are just as mean as you can be, to sneak up on a
+person and look at what they're looking at."
+
+"How could I know you was looking at anything?"
+
+"You ought to be ashamed of yourself, Tom Sawyer; you know you're
+going to tell on me, and oh, what shall I do, what shall I do! I'll be
+whipped, and I never was whipped in school."
+
+Then she stamped her little foot and said:
+
+"BE so mean if you want to! I know something that's going to happen.
+You just wait and you'll see! Hateful, hateful, hateful!"--and she
+flung out of the house with a new explosion of crying.
+
+Tom stood still, rather flustered by this onslaught. Presently he said
+to himself:
+
+"What a curious kind of a fool a girl is! Never been licked in school!
+Shucks! What's a licking! That's just like a girl--they're so
+thin-skinned and chicken-hearted. Well, of course I ain't going to tell
+old Dobbins on this little fool, because there's other ways of getting
+even on her, that ain't so mean; but what of it? Old Dobbins will ask
+who it was tore his book. Nobody'll answer. Then he'll do just the way
+he always does--ask first one and then t'other, and when he comes to the
+right girl he'll know it, without any telling. Girls' faces always tell
+on them. They ain't got any backbone. She'll get licked. Well, it's a
+kind of a tight place for Becky Thatcher, because there ain't any way
+out of it." Tom conned the thing a moment longer, and then added: "All
+right, though; she'd like to see me in just such a fix--let her sweat it
+out!"
+
+Tom joined the mob of skylarking scholars outside. In a few moments
+the master arrived and school "took in." Tom did not feel a strong
+interest in his studies. Every time he stole a glance at the girls'
+side of the room Becky's face troubled him. Considering all things, he
+did not want to pity her, and yet it was all he could do to help it. He
+could get up no exultation that was really worthy the name. Presently
+the spelling-book discovery was made, and Tom's mind was entirely full
+of his own matters for a while after that. Becky roused up from her
+lethargy of distress and showed good interest in the proceedings. She
+did not expect that Tom could get out of his trouble by denying that he
+spilt the ink on the book himself; and she was right. The denial only
+seemed to make the thing worse for Tom. Becky supposed she would be
+glad of that, and she tried to believe she was glad of it, but she
+found she was not certain. When the worst came to the worst, she had an
+impulse to get up and tell on Alfred Temple, but she made an effort and
+forced herself to keep still--because, said she to herself, "he'll tell
+about me tearing the picture sure. I wouldn't say a word, not to save
+his life!"
+
+Tom took his whipping and went back to his seat not at all
+broken-hearted, for he thought it was possible that he had unknowingly
+upset the ink on the spelling-book himself, in some skylarking bout--he
+had denied it for form's sake and because it was custom, and had stuck
+to the denial from principle.
+
+A whole hour drifted by, the master sat nodding in his throne, the air
+was drowsy with the hum of study. By and by, Mr. Dobbins straightened
+himself up, yawned, then unlocked his desk, and reached for his book,
+but seemed undecided whether to take it out or leave it. Most of the
+pupils glanced up languidly, but there were two among them that watched
+his movements with intent eyes. Mr. Dobbins fingered his book absently
+for a while, then took it out and settled himself in his chair to read!
+Tom shot a glance at Becky. He had seen a hunted and helpless rabbit
+look as she did, with a gun levelled at its head. Instantly he forgot
+his quarrel with her. Quick--something must be done! done in a flash,
+too! But the very imminence of the emergency paralyzed his invention.
+Good!--he had an inspiration! He would run and snatch the book, spring
+through the door and fly. But his resolution shook for one little
+instant, and the chance was lost--the master opened the volume. If Tom
+only had the wasted opportunity back again! Too late. There was no help
+for Becky now, he said. The next moment the master faced the school.
+Every eye sank under his gaze. There was that in it which smote even
+the innocent with fear. There was silence while one might count ten
+--the master was gathering his wrath. Then he spoke: "Who tore this book?"
+
+There was not a sound. One could have heard a pin drop. The stillness
+continued; the master searched face after face for signs of guilt.
+
+"Benjamin Rogers, did you tear this book?"
+
+A denial. Another pause.
+
+"Joseph Harper, did you?"
+
+Another denial. Tom's uneasiness grew more and more intense under the
+slow torture of these proceedings. The master scanned the ranks of
+boys--considered a while, then turned to the girls:
+
+"Amy Lawrence?"
+
+A shake of the head.
+
+"Gracie Miller?"
+
+The same sign.
+
+"Susan Harper, did you do this?"
+
+Another negative. The next girl was Becky Thatcher. Tom was trembling
+from head to foot with excitement and a sense of the hopelessness of
+the situation.
+
+"Rebecca Thatcher" [Tom glanced at her face--it was white with terror]
+--"did you tear--no, look me in the face" [her hands rose in appeal]
+--"did you tear this book?"
+
+A thought shot like lightning through Tom's brain. He sprang to his
+feet and shouted--"I done it!"
+
+The school stared in perplexity at this incredible folly. Tom stood a
+moment, to gather his dismembered faculties; and when he stepped
+forward to go to his punishment the surprise, the gratitude, the
+adoration that shone upon him out of poor Becky's eyes seemed pay
+enough for a hundred floggings. Inspired by the splendor of his own
+act, he took without an outcry the most merciless flaying that even Mr.
+Dobbins had ever administered; and also received with indifference the
+added cruelty of a command to remain two hours after school should be
+dismissed--for he knew who would wait for him outside till his
+captivity was done, and not count the tedious time as loss, either.
+
+Tom went to bed that night planning vengeance against Alfred Temple;
+for with shame and repentance Becky had told him all, not forgetting
+her own treachery; but even the longing for vengeance had to give way,
+soon, to pleasanter musings, and he fell asleep at last with Becky's
+latest words lingering dreamily in his ear--
+
+"Tom, how COULD you be so noble!"
+
+
+
+CHAPTER XXI
+
+VACATION was approaching. The schoolmaster, always severe, grew
+severer and more exacting than ever, for he wanted the school to make a
+good showing on "Examination" day. His rod and his ferule were seldom
+idle now--at least among the smaller pupils. Only the biggest boys, and
+young ladies of eighteen and twenty, escaped lashing. Mr. Dobbins'
+lashings were very vigorous ones, too; for although he carried, under
+his wig, a perfectly bald and shiny head, he had only reached middle
+age, and there was no sign of feebleness in his muscle. As the great
+day approached, all the tyranny that was in him came to the surface; he
+seemed to take a vindictive pleasure in punishing the least
+shortcomings. The consequence was, that the smaller boys spent their
+days in terror and suffering and their nights in plotting revenge. They
+threw away no opportunity to do the master a mischief. But he kept
+ahead all the time. The retribution that followed every vengeful
+success was so sweeping and majestic that the boys always retired from
+the field badly worsted. At last they conspired together and hit upon a
+plan that promised a dazzling victory. They swore in the sign-painter's
+boy, told him the scheme, and asked his help. He had his own reasons
+for being delighted, for the master boarded in his father's family and
+had given the boy ample cause to hate him. The master's wife would go
+on a visit to the country in a few days, and there would be nothing to
+interfere with the plan; the master always prepared himself for great
+occasions by getting pretty well fuddled, and the sign-painter's boy
+said that when the dominie had reached the proper condition on
+Examination Evening he would "manage the thing" while he napped in his
+chair; then he would have him awakened at the right time and hurried
+away to school.
+
+In the fulness of time the interesting occasion arrived. At eight in
+the evening the schoolhouse was brilliantly lighted, and adorned with
+wreaths and festoons of foliage and flowers. The master sat throned in
+his great chair upon a raised platform, with his blackboard behind him.
+He was looking tolerably mellow. Three rows of benches on each side and
+six rows in front of him were occupied by the dignitaries of the town
+and by the parents of the pupils. To his left, back of the rows of
+citizens, was a spacious temporary platform upon which were seated the
+scholars who were to take part in the exercises of the evening; rows of
+small boys, washed and dressed to an intolerable state of discomfort;
+rows of gawky big boys; snowbanks of girls and young ladies clad in
+lawn and muslin and conspicuously conscious of their bare arms, their
+grandmothers' ancient trinkets, their bits of pink and blue ribbon and
+the flowers in their hair. All the rest of the house was filled with
+non-participating scholars.
+
+The exercises began. A very little boy stood up and sheepishly
+recited, "You'd scarce expect one of my age to speak in public on the
+stage," etc.--accompanying himself with the painfully exact and
+spasmodic gestures which a machine might have used--supposing the
+machine to be a trifle out of order. But he got through safely, though
+cruelly scared, and got a fine round of applause when he made his
+manufactured bow and retired.
+
+A little shamefaced girl lisped, "Mary had a little lamb," etc.,
+performed a compassion-inspiring curtsy, got her meed of applause, and
+sat down flushed and happy.
+
+Tom Sawyer stepped forward with conceited confidence and soared into
+the unquenchable and indestructible "Give me liberty or give me death"
+speech, with fine fury and frantic gesticulation, and broke down in the
+middle of it. A ghastly stage-fright seized him, his legs quaked under
+him and he was like to choke. True, he had the manifest sympathy of the
+house but he had the house's silence, too, which was even worse than
+its sympathy. The master frowned, and this completed the disaster. Tom
+struggled awhile and then retired, utterly defeated. There was a weak
+attempt at applause, but it died early.
+
+"The Boy Stood on the Burning Deck" followed; also "The Assyrian Came
+Down," and other declamatory gems. Then there were reading exercises,
+and a spelling fight. The meagre Latin class recited with honor. The
+prime feature of the evening was in order, now--original "compositions"
+by the young ladies. Each in her turn stepped forward to the edge of
+the platform, cleared her throat, held up her manuscript (tied with
+dainty ribbon), and proceeded to read, with labored attention to
+"expression" and punctuation. The themes were the same that had been
+illuminated upon similar occasions by their mothers before them, their
+grandmothers, and doubtless all their ancestors in the female line
+clear back to the Crusades. "Friendship" was one; "Memories of Other
+Days"; "Religion in History"; "Dream Land"; "The Advantages of
+Culture"; "Forms of Political Government Compared and Contrasted";
+"Melancholy"; "Filial Love"; "Heart Longings," etc., etc.
+
+A prevalent feature in these compositions was a nursed and petted
+melancholy; another was a wasteful and opulent gush of "fine language";
+another was a tendency to lug in by the ears particularly prized words
+and phrases until they were worn entirely out; and a peculiarity that
+conspicuously marked and marred them was the inveterate and intolerable
+sermon that wagged its crippled tail at the end of each and every one
+of them. No matter what the subject might be, a brain-racking effort
+was made to squirm it into some aspect or other that the moral and
+religious mind could contemplate with edification. The glaring
+insincerity of these sermons was not sufficient to compass the
+banishment of the fashion from the schools, and it is not sufficient
+to-day; it never will be sufficient while the world stands, perhaps.
+There is no school in all our land where the young ladies do not feel
+obliged to close their compositions with a sermon; and you will find
+that the sermon of the most frivolous and the least religious girl in
+the school is always the longest and the most relentlessly pious. But
+enough of this. Homely truth is unpalatable.
+
+Let us return to the "Examination." The first composition that was
+read was one entitled "Is this, then, Life?" Perhaps the reader can
+endure an extract from it:
+
+ "In the common walks of life, with what delightful
+ emotions does the youthful mind look forward to some
+ anticipated scene of festivity! Imagination is busy
+ sketching rose-tinted pictures of joy. In fancy, the
+ voluptuous votary of fashion sees herself amid the
+ festive throng, 'the observed of all observers.' Her
+ graceful form, arrayed in snowy robes, is whirling
+ through the mazes of the joyous dance; her eye is
+ brightest, her step is lightest in the gay assembly.
+
+ "In such delicious fancies time quickly glides by,
+ and the welcome hour arrives for her entrance into
+ the Elysian world, of which she has had such bright
+ dreams. How fairy-like does everything appear to
+ her enchanted vision! Each new scene is more charming
+ than the last. But after a while she finds that
+ beneath this goodly exterior, all is vanity, the
+ flattery which once charmed her soul, now grates
+ harshly upon her ear; the ball-room has lost its
+ charms; and with wasted health and imbittered heart,
+ she turns away with the conviction that earthly
+ pleasures cannot satisfy the longings of the soul!"
+
+And so forth and so on. There was a buzz of gratification from time to
+time during the reading, accompanied by whispered ejaculations of "How
+sweet!" "How eloquent!" "So true!" etc., and after the thing had closed
+with a peculiarly afflicting sermon the applause was enthusiastic.
+
+Then arose a slim, melancholy girl, whose face had the "interesting"
+paleness that comes of pills and indigestion, and read a "poem." Two
+stanzas of it will do:
+
+ "A MISSOURI MAIDEN'S FAREWELL TO ALABAMA
+
+ "Alabama, good-bye! I love thee well!
+ But yet for a while do I leave thee now!
+ Sad, yes, sad thoughts of thee my heart doth swell,
+ And burning recollections throng my brow!
+ For I have wandered through thy flowery woods;
+ Have roamed and read near Tallapoosa's stream;
+ Have listened to Tallassee's warring floods,
+ And wooed on Coosa's side Aurora's beam.
+
+ "Yet shame I not to bear an o'er-full heart,
+ Nor blush to turn behind my tearful eyes;
+ 'Tis from no stranger land I now must part,
+ 'Tis to no strangers left I yield these sighs.
+ Welcome and home were mine within this State,
+ Whose vales I leave--whose spires fade fast from me
+ And cold must be mine eyes, and heart, and tete,
+ When, dear Alabama! they turn cold on thee!"
+
+There were very few there who knew what "tete" meant, but the poem was
+very satisfactory, nevertheless.
+
+Next appeared a dark-complexioned, black-eyed, black-haired young
+lady, who paused an impressive moment, assumed a tragic expression, and
+began to read in a measured, solemn tone:
+
+ "A VISION
+
+ "Dark and tempestuous was night. Around the
+ throne on high not a single star quivered; but
+ the deep intonations of the heavy thunder
+ constantly vibrated upon the ear; whilst the
+ terrific lightning revelled in angry mood
+ through the cloudy chambers of heaven, seeming
+ to scorn the power exerted over its terror by
+ the illustrious Franklin! Even the boisterous
+ winds unanimously came forth from their mystic
+ homes, and blustered about as if to enhance by
+ their aid the wildness of the scene.
+
+ "At such a time, so dark, so dreary, for human
+ sympathy my very spirit sighed; but instead thereof,
+
+ "'My dearest friend, my counsellor, my comforter
+ and guide--My joy in grief, my second bliss
+ in joy,' came to my side. She moved like one of
+ those bright beings pictured in the sunny walks
+ of fancy's Eden by the romantic and young, a
+ queen of beauty unadorned save by her own
+ transcendent loveliness. So soft was her step, it
+ failed to make even a sound, and but for the
+ magical thrill imparted by her genial touch, as
+ other unobtrusive beauties, she would have glided
+ away un-perceived--unsought. A strange sadness
+ rested upon her features, like icy tears upon
+ the robe of December, as she pointed to the
+ contending elements without, and bade me contemplate
+ the two beings presented."
+
+This nightmare occupied some ten pages of manuscript and wound up with
+a sermon so destructive of all hope to non-Presbyterians that it took
+the first prize. This composition was considered to be the very finest
+effort of the evening. The mayor of the village, in delivering the
+prize to the author of it, made a warm speech in which he said that it
+was by far the most "eloquent" thing he had ever listened to, and that
+Daniel Webster himself might well be proud of it.
+
+It may be remarked, in passing, that the number of compositions in
+which the word "beauteous" was over-fondled, and human experience
+referred to as "life's page," was up to the usual average.
+
+Now the master, mellow almost to the verge of geniality, put his chair
+aside, turned his back to the audience, and began to draw a map of
+America on the blackboard, to exercise the geography class upon. But he
+made a sad business of it with his unsteady hand, and a smothered
+titter rippled over the house. He knew what the matter was, and set
+himself to right it. He sponged out lines and remade them; but he only
+distorted them more than ever, and the tittering was more pronounced.
+He threw his entire attention upon his work, now, as if determined not
+to be put down by the mirth. He felt that all eyes were fastened upon
+him; he imagined he was succeeding, and yet the tittering continued; it
+even manifestly increased. And well it might. There was a garret above,
+pierced with a scuttle over his head; and down through this scuttle
+came a cat, suspended around the haunches by a string; she had a rag
+tied about her head and jaws to keep her from mewing; as she slowly
+descended she curved upward and clawed at the string, she swung
+downward and clawed at the intangible air. The tittering rose higher
+and higher--the cat was within six inches of the absorbed teacher's
+head--down, down, a little lower, and she grabbed his wig with her
+desperate claws, clung to it, and was snatched up into the garret in an
+instant with her trophy still in her possession! And how the light did
+blaze abroad from the master's bald pate--for the sign-painter's boy
+had GILDED it!
+
+That broke up the meeting. The boys were avenged. Vacation had come.
+
+ NOTE:--The pretended "compositions" quoted in
+ this chapter are taken without alteration from a
+ volume entitled "Prose and Poetry, by a Western
+ Lady"--but they are exactly and precisely after
+ the schoolgirl pattern, and hence are much
+ happier than any mere imitations could be.
+
+
+
+CHAPTER XXII
+
+TOM joined the new order of Cadets of Temperance, being attracted by
+the showy character of their "regalia." He promised to abstain from
+smoking, chewing, and profanity as long as he remained a member. Now he
+found out a new thing--namely, that to promise not to do a thing is the
+surest way in the world to make a body want to go and do that very
+thing. Tom soon found himself tormented with a desire to drink and
+swear; the desire grew to be so intense that nothing but the hope of a
+chance to display himself in his red sash kept him from withdrawing
+from the order. Fourth of July was coming; but he soon gave that up
+--gave it up before he had worn his shackles over forty-eight hours--and
+fixed his hopes upon old Judge Frazer, justice of the peace, who was
+apparently on his deathbed and would have a big public funeral, since
+he was so high an official. During three days Tom was deeply concerned
+about the Judge's condition and hungry for news of it. Sometimes his
+hopes ran high--so high that he would venture to get out his regalia
+and practise before the looking-glass. But the Judge had a most
+discouraging way of fluctuating. At last he was pronounced upon the
+mend--and then convalescent. Tom was disgusted; and felt a sense of
+injury, too. He handed in his resignation at once--and that night the
+Judge suffered a relapse and died. Tom resolved that he would never
+trust a man like that again.
+
+The funeral was a fine thing. The Cadets paraded in a style calculated
+to kill the late member with envy. Tom was a free boy again, however
+--there was something in that. He could drink and swear, now--but found
+to his surprise that he did not want to. The simple fact that he could,
+took the desire away, and the charm of it.
+
+Tom presently wondered to find that his coveted vacation was beginning
+to hang a little heavily on his hands.
+
+He attempted a diary--but nothing happened during three days, and so
+he abandoned it.
+
+The first of all the negro minstrel shows came to town, and made a
+sensation. Tom and Joe Harper got up a band of performers and were
+happy for two days.
+
+Even the Glorious Fourth was in some sense a failure, for it rained
+hard, there was no procession in consequence, and the greatest man in
+the world (as Tom supposed), Mr. Benton, an actual United States
+Senator, proved an overwhelming disappointment--for he was not
+twenty-five feet high, nor even anywhere in the neighborhood of it.
+
+A circus came. The boys played circus for three days afterward in
+tents made of rag carpeting--admission, three pins for boys, two for
+girls--and then circusing was abandoned.
+
+A phrenologist and a mesmerizer came--and went again and left the
+village duller and drearier than ever.
+
+There were some boys-and-girls' parties, but they were so few and so
+delightful that they only made the aching voids between ache the harder.
+
+Becky Thatcher was gone to her Constantinople home to stay with her
+parents during vacation--so there was no bright side to life anywhere.
+
+The dreadful secret of the murder was a chronic misery. It was a very
+cancer for permanency and pain.
+
+Then came the measles.
+
+During two long weeks Tom lay a prisoner, dead to the world and its
+happenings. He was very ill, he was interested in nothing. When he got
+upon his feet at last and moved feebly down-town, a melancholy change
+had come over everything and every creature. There had been a
+"revival," and everybody had "got religion," not only the adults, but
+even the boys and girls. Tom went about, hoping against hope for the
+sight of one blessed sinful face, but disappointment crossed him
+everywhere. He found Joe Harper studying a Testament, and turned sadly
+away from the depressing spectacle. He sought Ben Rogers, and found him
+visiting the poor with a basket of tracts. He hunted up Jim Hollis, who
+called his attention to the precious blessing of his late measles as a
+warning. Every boy he encountered added another ton to his depression;
+and when, in desperation, he flew for refuge at last to the bosom of
+Huckleberry Finn and was received with a Scriptural quotation, his
+heart broke and he crept home and to bed realizing that he alone of all
+the town was lost, forever and forever.
+
+And that night there came on a terrific storm, with driving rain,
+awful claps of thunder and blinding sheets of lightning. He covered his
+head with the bedclothes and waited in a horror of suspense for his
+doom; for he had not the shadow of a doubt that all this hubbub was
+about him. He believed he had taxed the forbearance of the powers above
+to the extremity of endurance and that this was the result. It might
+have seemed to him a waste of pomp and ammunition to kill a bug with a
+battery of artillery, but there seemed nothing incongruous about the
+getting up such an expensive thunderstorm as this to knock the turf
+from under an insect like himself.
+
+By and by the tempest spent itself and died without accomplishing its
+object. The boy's first impulse was to be grateful, and reform. His
+second was to wait--for there might not be any more storms.
+
+The next day the doctors were back; Tom had relapsed. The three weeks
+he spent on his back this time seemed an entire age. When he got abroad
+at last he was hardly grateful that he had been spared, remembering how
+lonely was his estate, how companionless and forlorn he was. He drifted
+listlessly down the street and found Jim Hollis acting as judge in a
+juvenile court that was trying a cat for murder, in the presence of her
+victim, a bird. He found Joe Harper and Huck Finn up an alley eating a
+stolen melon. Poor lads! they--like Tom--had suffered a relapse.
+
+
+
+CHAPTER XXIII
+
+AT last the sleepy atmosphere was stirred--and vigorously: the murder
+trial came on in the court. It became the absorbing topic of village
+talk immediately. Tom could not get away from it. Every reference to
+the murder sent a shudder to his heart, for his troubled conscience and
+fears almost persuaded him that these remarks were put forth in his
+hearing as "feelers"; he did not see how he could be suspected of
+knowing anything about the murder, but still he could not be
+comfortable in the midst of this gossip. It kept him in a cold shiver
+all the time. He took Huck to a lonely place to have a talk with him.
+It would be some relief to unseal his tongue for a little while; to
+divide his burden of distress with another sufferer. Moreover, he
+wanted to assure himself that Huck had remained discreet.
+
+"Huck, have you ever told anybody about--that?"
+
+"'Bout what?"
+
+"You know what."
+
+"Oh--'course I haven't."
+
+"Never a word?"
+
+"Never a solitary word, so help me. What makes you ask?"
+
+"Well, I was afeard."
+
+"Why, Tom Sawyer, we wouldn't be alive two days if that got found out.
+YOU know that."
+
+Tom felt more comfortable. After a pause:
+
+"Huck, they couldn't anybody get you to tell, could they?"
+
+"Get me to tell? Why, if I wanted that half-breed devil to drownd me
+they could get me to tell. They ain't no different way."
+
+"Well, that's all right, then. I reckon we're safe as long as we keep
+mum. But let's swear again, anyway. It's more surer."
+
+"I'm agreed."
+
+So they swore again with dread solemnities.
+
+"What is the talk around, Huck? I've heard a power of it."
+
+"Talk? Well, it's just Muff Potter, Muff Potter, Muff Potter all the
+time. It keeps me in a sweat, constant, so's I want to hide som'ers."
+
+"That's just the same way they go on round me. I reckon he's a goner.
+Don't you feel sorry for him, sometimes?"
+
+"Most always--most always. He ain't no account; but then he hain't
+ever done anything to hurt anybody. Just fishes a little, to get money
+to get drunk on--and loafs around considerable; but lord, we all do
+that--leastways most of us--preachers and such like. But he's kind of
+good--he give me half a fish, once, when there warn't enough for two;
+and lots of times he's kind of stood by me when I was out of luck."
+
+"Well, he's mended kites for me, Huck, and knitted hooks on to my
+line. I wish we could get him out of there."
+
+"My! we couldn't get him out, Tom. And besides, 'twouldn't do any
+good; they'd ketch him again."
+
+"Yes--so they would. But I hate to hear 'em abuse him so like the
+dickens when he never done--that."
+
+"I do too, Tom. Lord, I hear 'em say he's the bloodiest looking
+villain in this country, and they wonder he wasn't ever hung before."
+
+"Yes, they talk like that, all the time. I've heard 'em say that if he
+was to get free they'd lynch him."
+
+"And they'd do it, too."
+
+The boys had a long talk, but it brought them little comfort. As the
+twilight drew on, they found themselves hanging about the neighborhood
+of the little isolated jail, perhaps with an undefined hope that
+something would happen that might clear away their difficulties. But
+nothing happened; there seemed to be no angels or fairies interested in
+this luckless captive.
+
+The boys did as they had often done before--went to the cell grating
+and gave Potter some tobacco and matches. He was on the ground floor
+and there were no guards.
+
+His gratitude for their gifts had always smote their consciences
+before--it cut deeper than ever, this time. They felt cowardly and
+treacherous to the last degree when Potter said:
+
+"You've been mighty good to me, boys--better'n anybody else in this
+town. And I don't forget it, I don't. Often I says to myself, says I,
+'I used to mend all the boys' kites and things, and show 'em where the
+good fishin' places was, and befriend 'em what I could, and now they've
+all forgot old Muff when he's in trouble; but Tom don't, and Huck
+don't--THEY don't forget him, says I, 'and I don't forget them.' Well,
+boys, I done an awful thing--drunk and crazy at the time--that's the
+only way I account for it--and now I got to swing for it, and it's
+right. Right, and BEST, too, I reckon--hope so, anyway. Well, we won't
+talk about that. I don't want to make YOU feel bad; you've befriended
+me. But what I want to say, is, don't YOU ever get drunk--then you won't
+ever get here. Stand a litter furder west--so--that's it; it's a prime
+comfort to see faces that's friendly when a body's in such a muck of
+trouble, and there don't none come here but yourn. Good friendly
+faces--good friendly faces. Git up on one another's backs and let me
+touch 'em. That's it. Shake hands--yourn'll come through the bars, but
+mine's too big. Little hands, and weak--but they've helped Muff Potter
+a power, and they'd help him more if they could."
+
+Tom went home miserable, and his dreams that night were full of
+horrors. The next day and the day after, he hung about the court-room,
+drawn by an almost irresistible impulse to go in, but forcing himself
+to stay out. Huck was having the same experience. They studiously
+avoided each other. Each wandered away, from time to time, but the same
+dismal fascination always brought them back presently. Tom kept his
+ears open when idlers sauntered out of the court-room, but invariably
+heard distressing news--the toils were closing more and more
+relentlessly around poor Potter. At the end of the second day the
+village talk was to the effect that Injun Joe's evidence stood firm and
+unshaken, and that there was not the slightest question as to what the
+jury's verdict would be.
+
+Tom was out late, that night, and came to bed through the window. He
+was in a tremendous state of excitement. It was hours before he got to
+sleep. All the village flocked to the court-house the next morning, for
+this was to be the great day. Both sexes were about equally represented
+in the packed audience. After a long wait the jury filed in and took
+their places; shortly afterward, Potter, pale and haggard, timid and
+hopeless, was brought in, with chains upon him, and seated where all
+the curious eyes could stare at him; no less conspicuous was Injun Joe,
+stolid as ever. There was another pause, and then the judge arrived and
+the sheriff proclaimed the opening of the court. The usual whisperings
+among the lawyers and gathering together of papers followed. These
+details and accompanying delays worked up an atmosphere of preparation
+that was as impressive as it was fascinating.
+
+Now a witness was called who testified that he found Muff Potter
+washing in the brook, at an early hour of the morning that the murder
+was discovered, and that he immediately sneaked away. After some
+further questioning, counsel for the prosecution said:
+
+"Take the witness."
+
+The prisoner raised his eyes for a moment, but dropped them again when
+his own counsel said:
+
+"I have no questions to ask him."
+
+The next witness proved the finding of the knife near the corpse.
+Counsel for the prosecution said:
+
+"Take the witness."
+
+"I have no questions to ask him," Potter's lawyer replied.
+
+A third witness swore he had often seen the knife in Potter's
+possession.
+
+"Take the witness."
+
+Counsel for Potter declined to question him. The faces of the audience
+began to betray annoyance. Did this attorney mean to throw away his
+client's life without an effort?
+
+Several witnesses deposed concerning Potter's guilty behavior when
+brought to the scene of the murder. They were allowed to leave the
+stand without being cross-questioned.
+
+Every detail of the damaging circumstances that occurred in the
+graveyard upon that morning which all present remembered so well was
+brought out by credible witnesses, but none of them were cross-examined
+by Potter's lawyer. The perplexity and dissatisfaction of the house
+expressed itself in murmurs and provoked a reproof from the bench.
+Counsel for the prosecution now said:
+
+"By the oaths of citizens whose simple word is above suspicion, we
+have fastened this awful crime, beyond all possibility of question,
+upon the unhappy prisoner at the bar. We rest our case here."
+
+A groan escaped from poor Potter, and he put his face in his hands and
+rocked his body softly to and fro, while a painful silence reigned in
+the court-room. Many men were moved, and many women's compassion
+testified itself in tears. Counsel for the defence rose and said:
+
+"Your honor, in our remarks at the opening of this trial, we
+foreshadowed our purpose to prove that our client did this fearful deed
+while under the influence of a blind and irresponsible delirium
+produced by drink. We have changed our mind. We shall not offer that
+plea." [Then to the clerk:] "Call Thomas Sawyer!"
+
+A puzzled amazement awoke in every face in the house, not even
+excepting Potter's. Every eye fastened itself with wondering interest
+upon Tom as he rose and took his place upon the stand. The boy looked
+wild enough, for he was badly scared. The oath was administered.
+
+"Thomas Sawyer, where were you on the seventeenth of June, about the
+hour of midnight?"
+
+Tom glanced at Injun Joe's iron face and his tongue failed him. The
+audience listened breathless, but the words refused to come. After a
+few moments, however, the boy got a little of his strength back, and
+managed to put enough of it into his voice to make part of the house
+hear:
+
+"In the graveyard!"
+
+"A little bit louder, please. Don't be afraid. You were--"
+
+"In the graveyard."
+
+A contemptuous smile flitted across Injun Joe's face.
+
+"Were you anywhere near Horse Williams' grave?"
+
+"Yes, sir."
+
+"Speak up--just a trifle louder. How near were you?"
+
+"Near as I am to you."
+
+"Were you hidden, or not?"
+
+"I was hid."
+
+"Where?"
+
+"Behind the elms that's on the edge of the grave."
+
+Injun Joe gave a barely perceptible start.
+
+"Any one with you?"
+
+"Yes, sir. I went there with--"
+
+"Wait--wait a moment. Never mind mentioning your companion's name. We
+will produce him at the proper time. Did you carry anything there with
+you."
+
+Tom hesitated and looked confused.
+
+"Speak out, my boy--don't be diffident. The truth is always
+respectable. What did you take there?"
+
+"Only a--a--dead cat."
+
+There was a ripple of mirth, which the court checked.
+
+"We will produce the skeleton of that cat. Now, my boy, tell us
+everything that occurred--tell it in your own way--don't skip anything,
+and don't be afraid."
+
+Tom began--hesitatingly at first, but as he warmed to his subject his
+words flowed more and more easily; in a little while every sound ceased
+but his own voice; every eye fixed itself upon him; with parted lips
+and bated breath the audience hung upon his words, taking no note of
+time, rapt in the ghastly fascinations of the tale. The strain upon
+pent emotion reached its climax when the boy said:
+
+"--and as the doctor fetched the board around and Muff Potter fell,
+Injun Joe jumped with the knife and--"
+
+Crash! Quick as lightning the half-breed sprang for a window, tore his
+way through all opposers, and was gone!
+
+
+
+CHAPTER XXIV
+
+TOM was a glittering hero once more--the pet of the old, the envy of
+the young. His name even went into immortal print, for the village
+paper magnified him. There were some that believed he would be
+President, yet, if he escaped hanging.
+
+As usual, the fickle, unreasoning world took Muff Potter to its bosom
+and fondled him as lavishly as it had abused him before. But that sort
+of conduct is to the world's credit; therefore it is not well to find
+fault with it.
+
+Tom's days were days of splendor and exultation to him, but his nights
+were seasons of horror. Injun Joe infested all his dreams, and always
+with doom in his eye. Hardly any temptation could persuade the boy to
+stir abroad after nightfall. Poor Huck was in the same state of
+wretchedness and terror, for Tom had told the whole story to the lawyer
+the night before the great day of the trial, and Huck was sore afraid
+that his share in the business might leak out, yet, notwithstanding
+Injun Joe's flight had saved him the suffering of testifying in court.
+The poor fellow had got the attorney to promise secrecy, but what of
+that? Since Tom's harassed conscience had managed to drive him to the
+lawyer's house by night and wring a dread tale from lips that had been
+sealed with the dismalest and most formidable of oaths, Huck's
+confidence in the human race was well-nigh obliterated.
+
+Daily Muff Potter's gratitude made Tom glad he had spoken; but nightly
+he wished he had sealed up his tongue.
+
+Half the time Tom was afraid Injun Joe would never be captured; the
+other half he was afraid he would be. He felt sure he never could draw
+a safe breath again until that man was dead and he had seen the corpse.
+
+Rewards had been offered, the country had been scoured, but no Injun
+Joe was found. One of those omniscient and awe-inspiring marvels, a
+detective, came up from St. Louis, moused around, shook his head,
+looked wise, and made that sort of astounding success which members of
+that craft usually achieve. That is to say, he "found a clew." But you
+can't hang a "clew" for murder, and so after that detective had got
+through and gone home, Tom felt just as insecure as he was before.
+
+The slow days drifted on, and each left behind it a slightly lightened
+weight of apprehension.
+
+
+
+CHAPTER XXV
+
+THERE comes a time in every rightly-constructed boy's life when he has
+a raging desire to go somewhere and dig for hidden treasure. This
+desire suddenly came upon Tom one day. He sallied out to find Joe
+Harper, but failed of success. Next he sought Ben Rogers; he had gone
+fishing. Presently he stumbled upon Huck Finn the Red-Handed. Huck
+would answer. Tom took him to a private place and opened the matter to
+him confidentially. Huck was willing. Huck was always willing to take a
+hand in any enterprise that offered entertainment and required no
+capital, for he had a troublesome superabundance of that sort of time
+which is not money. "Where'll we dig?" said Huck.
+
+"Oh, most anywhere."
+
+"Why, is it hid all around?"
+
+"No, indeed it ain't. It's hid in mighty particular places, Huck
+--sometimes on islands, sometimes in rotten chests under the end of a
+limb of an old dead tree, just where the shadow falls at midnight; but
+mostly under the floor in ha'nted houses."
+
+"Who hides it?"
+
+"Why, robbers, of course--who'd you reckon? Sunday-school
+sup'rintendents?"
+
+"I don't know. If 'twas mine I wouldn't hide it; I'd spend it and have
+a good time."
+
+"So would I. But robbers don't do that way. They always hide it and
+leave it there."
+
+"Don't they come after it any more?"
+
+"No, they think they will, but they generally forget the marks, or
+else they die. Anyway, it lays there a long time and gets rusty; and by
+and by somebody finds an old yellow paper that tells how to find the
+marks--a paper that's got to be ciphered over about a week because it's
+mostly signs and hy'roglyphics."
+
+"Hyro--which?"
+
+"Hy'roglyphics--pictures and things, you know, that don't seem to mean
+anything."
+
+"Have you got one of them papers, Tom?"
+
+"No."
+
+"Well then, how you going to find the marks?"
+
+"I don't want any marks. They always bury it under a ha'nted house or
+on an island, or under a dead tree that's got one limb sticking out.
+Well, we've tried Jackson's Island a little, and we can try it again
+some time; and there's the old ha'nted house up the Still-House branch,
+and there's lots of dead-limb trees--dead loads of 'em."
+
+"Is it under all of them?"
+
+"How you talk! No!"
+
+"Then how you going to know which one to go for?"
+
+"Go for all of 'em!"
+
+"Why, Tom, it'll take all summer."
+
+"Well, what of that? Suppose you find a brass pot with a hundred
+dollars in it, all rusty and gray, or rotten chest full of di'monds.
+How's that?"
+
+Huck's eyes glowed.
+
+"That's bully. Plenty bully enough for me. Just you gimme the hundred
+dollars and I don't want no di'monds."
+
+"All right. But I bet you I ain't going to throw off on di'monds. Some
+of 'em's worth twenty dollars apiece--there ain't any, hardly, but's
+worth six bits or a dollar."
+
+"No! Is that so?"
+
+"Cert'nly--anybody'll tell you so. Hain't you ever seen one, Huck?"
+
+"Not as I remember."
+
+"Oh, kings have slathers of them."
+
+"Well, I don' know no kings, Tom."
+
+"I reckon you don't. But if you was to go to Europe you'd see a raft
+of 'em hopping around."
+
+"Do they hop?"
+
+"Hop?--your granny! No!"
+
+"Well, what did you say they did, for?"
+
+"Shucks, I only meant you'd SEE 'em--not hopping, of course--what do
+they want to hop for?--but I mean you'd just see 'em--scattered around,
+you know, in a kind of a general way. Like that old humpbacked Richard."
+
+"Richard? What's his other name?"
+
+"He didn't have any other name. Kings don't have any but a given name."
+
+"No?"
+
+"But they don't."
+
+"Well, if they like it, Tom, all right; but I don't want to be a king
+and have only just a given name, like a nigger. But say--where you
+going to dig first?"
+
+"Well, I don't know. S'pose we tackle that old dead-limb tree on the
+hill t'other side of Still-House branch?"
+
+"I'm agreed."
+
+So they got a crippled pick and a shovel, and set out on their
+three-mile tramp. They arrived hot and panting, and threw themselves
+down in the shade of a neighboring elm to rest and have a smoke.
+
+"I like this," said Tom.
+
+"So do I."
+
+"Say, Huck, if we find a treasure here, what you going to do with your
+share?"
+
+"Well, I'll have pie and a glass of soda every day, and I'll go to
+every circus that comes along. I bet I'll have a gay time."
+
+"Well, ain't you going to save any of it?"
+
+"Save it? What for?"
+
+"Why, so as to have something to live on, by and by."
+
+"Oh, that ain't any use. Pap would come back to thish-yer town some
+day and get his claws on it if I didn't hurry up, and I tell you he'd
+clean it out pretty quick. What you going to do with yourn, Tom?"
+
+"I'm going to buy a new drum, and a sure-'nough sword, and a red
+necktie and a bull pup, and get married."
+
+"Married!"
+
+"That's it."
+
+"Tom, you--why, you ain't in your right mind."
+
+"Wait--you'll see."
+
+"Well, that's the foolishest thing you could do. Look at pap and my
+mother. Fight! Why, they used to fight all the time. I remember, mighty
+well."
+
+"That ain't anything. The girl I'm going to marry won't fight."
+
+"Tom, I reckon they're all alike. They'll all comb a body. Now you
+better think 'bout this awhile. I tell you you better. What's the name
+of the gal?"
+
+"It ain't a gal at all--it's a girl."
+
+"It's all the same, I reckon; some says gal, some says girl--both's
+right, like enough. Anyway, what's her name, Tom?"
+
+"I'll tell you some time--not now."
+
+"All right--that'll do. Only if you get married I'll be more lonesomer
+than ever."
+
+"No you won't. You'll come and live with me. Now stir out of this and
+we'll go to digging."
+
+They worked and sweated for half an hour. No result. They toiled
+another half-hour. Still no result. Huck said:
+
+"Do they always bury it as deep as this?"
+
+"Sometimes--not always. Not generally. I reckon we haven't got the
+right place."
+
+So they chose a new spot and began again. The labor dragged a little,
+but still they made progress. They pegged away in silence for some
+time. Finally Huck leaned on his shovel, swabbed the beaded drops from
+his brow with his sleeve, and said:
+
+"Where you going to dig next, after we get this one?"
+
+"I reckon maybe we'll tackle the old tree that's over yonder on
+Cardiff Hill back of the widow's."
+
+"I reckon that'll be a good one. But won't the widow take it away from
+us, Tom? It's on her land."
+
+"SHE take it away! Maybe she'd like to try it once. Whoever finds one
+of these hid treasures, it belongs to him. It don't make any difference
+whose land it's on."
+
+That was satisfactory. The work went on. By and by Huck said:
+
+"Blame it, we must be in the wrong place again. What do you think?"
+
+"It is mighty curious, Huck. I don't understand it. Sometimes witches
+interfere. I reckon maybe that's what's the trouble now."
+
+"Shucks! Witches ain't got no power in the daytime."
+
+"Well, that's so. I didn't think of that. Oh, I know what the matter
+is! What a blamed lot of fools we are! You got to find out where the
+shadow of the limb falls at midnight, and that's where you dig!"
+
+"Then consound it, we've fooled away all this work for nothing. Now
+hang it all, we got to come back in the night. It's an awful long way.
+Can you get out?"
+
+"I bet I will. We've got to do it to-night, too, because if somebody
+sees these holes they'll know in a minute what's here and they'll go
+for it."
+
+"Well, I'll come around and maow to-night."
+
+"All right. Let's hide the tools in the bushes."
+
+The boys were there that night, about the appointed time. They sat in
+the shadow waiting. It was a lonely place, and an hour made solemn by
+old traditions. Spirits whispered in the rustling leaves, ghosts lurked
+in the murky nooks, the deep baying of a hound floated up out of the
+distance, an owl answered with his sepulchral note. The boys were
+subdued by these solemnities, and talked little. By and by they judged
+that twelve had come; they marked where the shadow fell, and began to
+dig. Their hopes commenced to rise. Their interest grew stronger, and
+their industry kept pace with it. The hole deepened and still deepened,
+but every time their hearts jumped to hear the pick strike upon
+something, they only suffered a new disappointment. It was only a stone
+or a chunk. At last Tom said:
+
+"It ain't any use, Huck, we're wrong again."
+
+"Well, but we CAN'T be wrong. We spotted the shadder to a dot."
+
+"I know it, but then there's another thing."
+
+"What's that?".
+
+"Why, we only guessed at the time. Like enough it was too late or too
+early."
+
+Huck dropped his shovel.
+
+"That's it," said he. "That's the very trouble. We got to give this
+one up. We can't ever tell the right time, and besides this kind of
+thing's too awful, here this time of night with witches and ghosts
+a-fluttering around so. I feel as if something's behind me all the time;
+and I'm afeard to turn around, becuz maybe there's others in front
+a-waiting for a chance. I been creeping all over, ever since I got here."
+
+"Well, I've been pretty much so, too, Huck. They most always put in a
+dead man when they bury a treasure under a tree, to look out for it."
+
+"Lordy!"
+
+"Yes, they do. I've always heard that."
+
+"Tom, I don't like to fool around much where there's dead people. A
+body's bound to get into trouble with 'em, sure."
+
+"I don't like to stir 'em up, either. S'pose this one here was to
+stick his skull out and say something!"
+
+"Don't Tom! It's awful."
+
+"Well, it just is. Huck, I don't feel comfortable a bit."
+
+"Say, Tom, let's give this place up, and try somewheres else."
+
+"All right, I reckon we better."
+
+"What'll it be?"
+
+Tom considered awhile; and then said:
+
+"The ha'nted house. That's it!"
+
+"Blame it, I don't like ha'nted houses, Tom. Why, they're a dern sight
+worse'n dead people. Dead people might talk, maybe, but they don't come
+sliding around in a shroud, when you ain't noticing, and peep over your
+shoulder all of a sudden and grit their teeth, the way a ghost does. I
+couldn't stand such a thing as that, Tom--nobody could."
+
+"Yes, but, Huck, ghosts don't travel around only at night. They won't
+hender us from digging there in the daytime."
+
+"Well, that's so. But you know mighty well people don't go about that
+ha'nted house in the day nor the night."
+
+"Well, that's mostly because they don't like to go where a man's been
+murdered, anyway--but nothing's ever been seen around that house except
+in the night--just some blue lights slipping by the windows--no regular
+ghosts."
+
+"Well, where you see one of them blue lights flickering around, Tom,
+you can bet there's a ghost mighty close behind it. It stands to
+reason. Becuz you know that they don't anybody but ghosts use 'em."
+
+"Yes, that's so. But anyway they don't come around in the daytime, so
+what's the use of our being afeard?"
+
+"Well, all right. We'll tackle the ha'nted house if you say so--but I
+reckon it's taking chances."
+
+They had started down the hill by this time. There in the middle of
+the moonlit valley below them stood the "ha'nted" house, utterly
+isolated, its fences gone long ago, rank weeds smothering the very
+doorsteps, the chimney crumbled to ruin, the window-sashes vacant, a
+corner of the roof caved in. The boys gazed awhile, half expecting to
+see a blue light flit past a window; then talking in a low tone, as
+befitted the time and the circumstances, they struck far off to the
+right, to give the haunted house a wide berth, and took their way
+homeward through the woods that adorned the rearward side of Cardiff
+Hill.
+
+
+
+CHAPTER XXVI
+
+ABOUT noon the next day the boys arrived at the dead tree; they had
+come for their tools. Tom was impatient to go to the haunted house;
+Huck was measurably so, also--but suddenly said:
+
+"Lookyhere, Tom, do you know what day it is?"
+
+Tom mentally ran over the days of the week, and then quickly lifted
+his eyes with a startled look in them--
+
+"My! I never once thought of it, Huck!"
+
+"Well, I didn't neither, but all at once it popped onto me that it was
+Friday."
+
+"Blame it, a body can't be too careful, Huck. We might 'a' got into an
+awful scrape, tackling such a thing on a Friday."
+
+"MIGHT! Better say we WOULD! There's some lucky days, maybe, but
+Friday ain't."
+
+"Any fool knows that. I don't reckon YOU was the first that found it
+out, Huck."
+
+"Well, I never said I was, did I? And Friday ain't all, neither. I had
+a rotten bad dream last night--dreampt about rats."
+
+"No! Sure sign of trouble. Did they fight?"
+
+"No."
+
+"Well, that's good, Huck. When they don't fight it's only a sign that
+there's trouble around, you know. All we got to do is to look mighty
+sharp and keep out of it. We'll drop this thing for to-day, and play.
+Do you know Robin Hood, Huck?"
+
+"No. Who's Robin Hood?"
+
+"Why, he was one of the greatest men that was ever in England--and the
+best. He was a robber."
+
+"Cracky, I wisht I was. Who did he rob?"
+
+"Only sheriffs and bishops and rich people and kings, and such like.
+But he never bothered the poor. He loved 'em. He always divided up with
+'em perfectly square."
+
+"Well, he must 'a' been a brick."
+
+"I bet you he was, Huck. Oh, he was the noblest man that ever was.
+They ain't any such men now, I can tell you. He could lick any man in
+England, with one hand tied behind him; and he could take his yew bow
+and plug a ten-cent piece every time, a mile and a half."
+
+"What's a YEW bow?"
+
+"I don't know. It's some kind of a bow, of course. And if he hit that
+dime only on the edge he would set down and cry--and curse. But we'll
+play Robin Hood--it's nobby fun. I'll learn you."
+
+"I'm agreed."
+
+So they played Robin Hood all the afternoon, now and then casting a
+yearning eye down upon the haunted house and passing a remark about the
+morrow's prospects and possibilities there. As the sun began to sink
+into the west they took their way homeward athwart the long shadows of
+the trees and soon were buried from sight in the forests of Cardiff
+Hill.
+
+On Saturday, shortly after noon, the boys were at the dead tree again.
+They had a smoke and a chat in the shade, and then dug a little in
+their last hole, not with great hope, but merely because Tom said there
+were so many cases where people had given up a treasure after getting
+down within six inches of it, and then somebody else had come along and
+turned it up with a single thrust of a shovel. The thing failed this
+time, however, so the boys shouldered their tools and went away feeling
+that they had not trifled with fortune, but had fulfilled all the
+requirements that belong to the business of treasure-hunting.
+
+When they reached the haunted house there was something so weird and
+grisly about the dead silence that reigned there under the baking sun,
+and something so depressing about the loneliness and desolation of the
+place, that they were afraid, for a moment, to venture in. Then they
+crept to the door and took a trembling peep. They saw a weed-grown,
+floorless room, unplastered, an ancient fireplace, vacant windows, a
+ruinous staircase; and here, there, and everywhere hung ragged and
+abandoned cobwebs. They presently entered, softly, with quickened
+pulses, talking in whispers, ears alert to catch the slightest sound,
+and muscles tense and ready for instant retreat.
+
+In a little while familiarity modified their fears and they gave the
+place a critical and interested examination, rather admiring their own
+boldness, and wondering at it, too. Next they wanted to look up-stairs.
+This was something like cutting off retreat, but they got to daring
+each other, and of course there could be but one result--they threw
+their tools into a corner and made the ascent. Up there were the same
+signs of decay. In one corner they found a closet that promised
+mystery, but the promise was a fraud--there was nothing in it. Their
+courage was up now and well in hand. They were about to go down and
+begin work when--
+
+"Sh!" said Tom.
+
+"What is it?" whispered Huck, blanching with fright.
+
+"Sh!... There!... Hear it?"
+
+"Yes!... Oh, my! Let's run!"
+
+"Keep still! Don't you budge! They're coming right toward the door."
+
+The boys stretched themselves upon the floor with their eyes to
+knot-holes in the planking, and lay waiting, in a misery of fear.
+
+"They've stopped.... No--coming.... Here they are. Don't whisper
+another word, Huck. My goodness, I wish I was out of this!"
+
+Two men entered. Each boy said to himself: "There's the old deaf and
+dumb Spaniard that's been about town once or twice lately--never saw
+t'other man before."
+
+"T'other" was a ragged, unkempt creature, with nothing very pleasant
+in his face. The Spaniard was wrapped in a serape; he had bushy white
+whiskers; long white hair flowed from under his sombrero, and he wore
+green goggles. When they came in, "t'other" was talking in a low voice;
+they sat down on the ground, facing the door, with their backs to the
+wall, and the speaker continued his remarks. His manner became less
+guarded and his words more distinct as he proceeded:
+
+"No," said he, "I've thought it all over, and I don't like it. It's
+dangerous."
+
+"Dangerous!" grunted the "deaf and dumb" Spaniard--to the vast
+surprise of the boys. "Milksop!"
+
+This voice made the boys gasp and quake. It was Injun Joe's! There was
+silence for some time. Then Joe said:
+
+"What's any more dangerous than that job up yonder--but nothing's come
+of it."
+
+"That's different. Away up the river so, and not another house about.
+'Twon't ever be known that we tried, anyway, long as we didn't succeed."
+
+"Well, what's more dangerous than coming here in the daytime!--anybody
+would suspicion us that saw us."
+
+"I know that. But there warn't any other place as handy after that
+fool of a job. I want to quit this shanty. I wanted to yesterday, only
+it warn't any use trying to stir out of here, with those infernal boys
+playing over there on the hill right in full view."
+
+"Those infernal boys" quaked again under the inspiration of this
+remark, and thought how lucky it was that they had remembered it was
+Friday and concluded to wait a day. They wished in their hearts they
+had waited a year.
+
+The two men got out some food and made a luncheon. After a long and
+thoughtful silence, Injun Joe said:
+
+"Look here, lad--you go back up the river where you belong. Wait there
+till you hear from me. I'll take the chances on dropping into this town
+just once more, for a look. We'll do that 'dangerous' job after I've
+spied around a little and think things look well for it. Then for
+Texas! We'll leg it together!"
+
+This was satisfactory. Both men presently fell to yawning, and Injun
+Joe said:
+
+"I'm dead for sleep! It's your turn to watch."
+
+He curled down in the weeds and soon began to snore. His comrade
+stirred him once or twice and he became quiet. Presently the watcher
+began to nod; his head drooped lower and lower, both men began to snore
+now.
+
+The boys drew a long, grateful breath. Tom whispered:
+
+"Now's our chance--come!"
+
+Huck said:
+
+"I can't--I'd die if they was to wake."
+
+Tom urged--Huck held back. At last Tom rose slowly and softly, and
+started alone. But the first step he made wrung such a hideous creak
+from the crazy floor that he sank down almost dead with fright. He
+never made a second attempt. The boys lay there counting the dragging
+moments till it seemed to them that time must be done and eternity
+growing gray; and then they were grateful to note that at last the sun
+was setting.
+
+Now one snore ceased. Injun Joe sat up, stared around--smiled grimly
+upon his comrade, whose head was drooping upon his knees--stirred him
+up with his foot and said:
+
+"Here! YOU'RE a watchman, ain't you! All right, though--nothing's
+happened."
+
+"My! have I been asleep?"
+
+"Oh, partly, partly. Nearly time for us to be moving, pard. What'll we
+do with what little swag we've got left?"
+
+"I don't know--leave it here as we've always done, I reckon. No use to
+take it away till we start south. Six hundred and fifty in silver's
+something to carry."
+
+"Well--all right--it won't matter to come here once more."
+
+"No--but I'd say come in the night as we used to do--it's better."
+
+"Yes: but look here; it may be a good while before I get the right
+chance at that job; accidents might happen; 'tain't in such a very good
+place; we'll just regularly bury it--and bury it deep."
+
+"Good idea," said the comrade, who walked across the room, knelt down,
+raised one of the rearward hearth-stones and took out a bag that
+jingled pleasantly. He subtracted from it twenty or thirty dollars for
+himself and as much for Injun Joe, and passed the bag to the latter,
+who was on his knees in the corner, now, digging with his bowie-knife.
+
+The boys forgot all their fears, all their miseries in an instant.
+With gloating eyes they watched every movement. Luck!--the splendor of
+it was beyond all imagination! Six hundred dollars was money enough to
+make half a dozen boys rich! Here was treasure-hunting under the
+happiest auspices--there would not be any bothersome uncertainty as to
+where to dig. They nudged each other every moment--eloquent nudges and
+easily understood, for they simply meant--"Oh, but ain't you glad NOW
+we're here!"
+
+Joe's knife struck upon something.
+
+"Hello!" said he.
+
+"What is it?" said his comrade.
+
+"Half-rotten plank--no, it's a box, I believe. Here--bear a hand and
+we'll see what it's here for. Never mind, I've broke a hole."
+
+He reached his hand in and drew it out--
+
+"Man, it's money!"
+
+The two men examined the handful of coins. They were gold. The boys
+above were as excited as themselves, and as delighted.
+
+Joe's comrade said:
+
+"We'll make quick work of this. There's an old rusty pick over amongst
+the weeds in the corner the other side of the fireplace--I saw it a
+minute ago."
+
+He ran and brought the boys' pick and shovel. Injun Joe took the pick,
+looked it over critically, shook his head, muttered something to
+himself, and then began to use it. The box was soon unearthed. It was
+not very large; it was iron bound and had been very strong before the
+slow years had injured it. The men contemplated the treasure awhile in
+blissful silence.
+
+"Pard, there's thousands of dollars here," said Injun Joe.
+
+"'Twas always said that Murrel's gang used to be around here one
+summer," the stranger observed.
+
+"I know it," said Injun Joe; "and this looks like it, I should say."
+
+"Now you won't need to do that job."
+
+The half-breed frowned. Said he:
+
+"You don't know me. Least you don't know all about that thing. 'Tain't
+robbery altogether--it's REVENGE!" and a wicked light flamed in his
+eyes. "I'll need your help in it. When it's finished--then Texas. Go
+home to your Nance and your kids, and stand by till you hear from me."
+
+"Well--if you say so; what'll we do with this--bury it again?"
+
+"Yes. [Ravishing delight overhead.] NO! by the great Sachem, no!
+[Profound distress overhead.] I'd nearly forgot. That pick had fresh
+earth on it! [The boys were sick with terror in a moment.] What
+business has a pick and a shovel here? What business with fresh earth
+on them? Who brought them here--and where are they gone? Have you heard
+anybody?--seen anybody? What! bury it again and leave them to come and
+see the ground disturbed? Not exactly--not exactly. We'll take it to my
+den."
+
+"Why, of course! Might have thought of that before. You mean Number
+One?"
+
+"No--Number Two--under the cross. The other place is bad--too common."
+
+"All right. It's nearly dark enough to start."
+
+Injun Joe got up and went about from window to window cautiously
+peeping out. Presently he said:
+
+"Who could have brought those tools here? Do you reckon they can be
+up-stairs?"
+
+The boys' breath forsook them. Injun Joe put his hand on his knife,
+halted a moment, undecided, and then turned toward the stairway. The
+boys thought of the closet, but their strength was gone. The steps came
+creaking up the stairs--the intolerable distress of the situation woke
+the stricken resolution of the lads--they were about to spring for the
+closet, when there was a crash of rotten timbers and Injun Joe landed
+on the ground amid the debris of the ruined stairway. He gathered
+himself up cursing, and his comrade said:
+
+"Now what's the use of all that? If it's anybody, and they're up
+there, let them STAY there--who cares? If they want to jump down, now,
+and get into trouble, who objects? It will be dark in fifteen minutes
+--and then let them follow us if they want to. I'm willing. In my
+opinion, whoever hove those things in here caught a sight of us and
+took us for ghosts or devils or something. I'll bet they're running
+yet."
+
+Joe grumbled awhile; then he agreed with his friend that what daylight
+was left ought to be economized in getting things ready for leaving.
+Shortly afterward they slipped out of the house in the deepening
+twilight, and moved toward the river with their precious box.
+
+Tom and Huck rose up, weak but vastly relieved, and stared after them
+through the chinks between the logs of the house. Follow? Not they.
+They were content to reach ground again without broken necks, and take
+the townward track over the hill. They did not talk much. They were too
+much absorbed in hating themselves--hating the ill luck that made them
+take the spade and the pick there. But for that, Injun Joe never would
+have suspected. He would have hidden the silver with the gold to wait
+there till his "revenge" was satisfied, and then he would have had the
+misfortune to find that money turn up missing. Bitter, bitter luck that
+the tools were ever brought there!
+
+They resolved to keep a lookout for that Spaniard when he should come
+to town spying out for chances to do his revengeful job, and follow him
+to "Number Two," wherever that might be. Then a ghastly thought
+occurred to Tom.
+
+"Revenge? What if he means US, Huck!"
+
+"Oh, don't!" said Huck, nearly fainting.
+
+They talked it all over, and as they entered town they agreed to
+believe that he might possibly mean somebody else--at least that he
+might at least mean nobody but Tom, since only Tom had testified.
+
+Very, very small comfort it was to Tom to be alone in danger! Company
+would be a palpable improvement, he thought.
+
+
+
+CHAPTER XXVII
+
+THE adventure of the day mightily tormented Tom's dreams that night.
+Four times he had his hands on that rich treasure and four times it
+wasted to nothingness in his fingers as sleep forsook him and
+wakefulness brought back the hard reality of his misfortune. As he lay
+in the early morning recalling the incidents of his great adventure, he
+noticed that they seemed curiously subdued and far away--somewhat as if
+they had happened in another world, or in a time long gone by. Then it
+occurred to him that the great adventure itself must be a dream! There
+was one very strong argument in favor of this idea--namely, that the
+quantity of coin he had seen was too vast to be real. He had never seen
+as much as fifty dollars in one mass before, and he was like all boys
+of his age and station in life, in that he imagined that all references
+to "hundreds" and "thousands" were mere fanciful forms of speech, and
+that no such sums really existed in the world. He never had supposed
+for a moment that so large a sum as a hundred dollars was to be found
+in actual money in any one's possession. If his notions of hidden
+treasure had been analyzed, they would have been found to consist of a
+handful of real dimes and a bushel of vague, splendid, ungraspable
+dollars.
+
+But the incidents of his adventure grew sensibly sharper and clearer
+under the attrition of thinking them over, and so he presently found
+himself leaning to the impression that the thing might not have been a
+dream, after all. This uncertainty must be swept away. He would snatch
+a hurried breakfast and go and find Huck. Huck was sitting on the
+gunwale of a flatboat, listlessly dangling his feet in the water and
+looking very melancholy. Tom concluded to let Huck lead up to the
+subject. If he did not do it, then the adventure would be proved to
+have been only a dream.
+
+"Hello, Huck!"
+
+"Hello, yourself."
+
+Silence, for a minute.
+
+"Tom, if we'd 'a' left the blame tools at the dead tree, we'd 'a' got
+the money. Oh, ain't it awful!"
+
+"'Tain't a dream, then, 'tain't a dream! Somehow I most wish it was.
+Dog'd if I don't, Huck."
+
+"What ain't a dream?"
+
+"Oh, that thing yesterday. I been half thinking it was."
+
+"Dream! If them stairs hadn't broke down you'd 'a' seen how much dream
+it was! I've had dreams enough all night--with that patch-eyed Spanish
+devil going for me all through 'em--rot him!"
+
+"No, not rot him. FIND him! Track the money!"
+
+"Tom, we'll never find him. A feller don't have only one chance for
+such a pile--and that one's lost. I'd feel mighty shaky if I was to see
+him, anyway."
+
+"Well, so'd I; but I'd like to see him, anyway--and track him out--to
+his Number Two."
+
+"Number Two--yes, that's it. I been thinking 'bout that. But I can't
+make nothing out of it. What do you reckon it is?"
+
+"I dono. It's too deep. Say, Huck--maybe it's the number of a house!"
+
+"Goody!... No, Tom, that ain't it. If it is, it ain't in this
+one-horse town. They ain't no numbers here."
+
+"Well, that's so. Lemme think a minute. Here--it's the number of a
+room--in a tavern, you know!"
+
+"Oh, that's the trick! They ain't only two taverns. We can find out
+quick."
+
+"You stay here, Huck, till I come."
+
+Tom was off at once. He did not care to have Huck's company in public
+places. He was gone half an hour. He found that in the best tavern, No.
+2 had long been occupied by a young lawyer, and was still so occupied.
+In the less ostentatious house, No. 2 was a mystery. The
+tavern-keeper's young son said it was kept locked all the time, and he
+never saw anybody go into it or come out of it except at night; he did
+not know any particular reason for this state of things; had had some
+little curiosity, but it was rather feeble; had made the most of the
+mystery by entertaining himself with the idea that that room was
+"ha'nted"; had noticed that there was a light in there the night before.
+
+"That's what I've found out, Huck. I reckon that's the very No. 2
+we're after."
+
+"I reckon it is, Tom. Now what you going to do?"
+
+"Lemme think."
+
+Tom thought a long time. Then he said:
+
+"I'll tell you. The back door of that No. 2 is the door that comes out
+into that little close alley between the tavern and the old rattle trap
+of a brick store. Now you get hold of all the door-keys you can find,
+and I'll nip all of auntie's, and the first dark night we'll go there
+and try 'em. And mind you, keep a lookout for Injun Joe, because he
+said he was going to drop into town and spy around once more for a
+chance to get his revenge. If you see him, you just follow him; and if
+he don't go to that No. 2, that ain't the place."
+
+"Lordy, I don't want to foller him by myself!"
+
+"Why, it'll be night, sure. He mightn't ever see you--and if he did,
+maybe he'd never think anything."
+
+"Well, if it's pretty dark I reckon I'll track him. I dono--I dono.
+I'll try."
+
+"You bet I'll follow him, if it's dark, Huck. Why, he might 'a' found
+out he couldn't get his revenge, and be going right after that money."
+
+"It's so, Tom, it's so. I'll foller him; I will, by jingoes!"
+
+"Now you're TALKING! Don't you ever weaken, Huck, and I won't."
+
+
+
+CHAPTER XXVIII
+
+THAT night Tom and Huck were ready for their adventure. They hung
+about the neighborhood of the tavern until after nine, one watching the
+alley at a distance and the other the tavern door. Nobody entered the
+alley or left it; nobody resembling the Spaniard entered or left the
+tavern door. The night promised to be a fair one; so Tom went home with
+the understanding that if a considerable degree of darkness came on,
+Huck was to come and "maow," whereupon he would slip out and try the
+keys. But the night remained clear, and Huck closed his watch and
+retired to bed in an empty sugar hogshead about twelve.
+
+Tuesday the boys had the same ill luck. Also Wednesday. But Thursday
+night promised better. Tom slipped out in good season with his aunt's
+old tin lantern, and a large towel to blindfold it with. He hid the
+lantern in Huck's sugar hogshead and the watch began. An hour before
+midnight the tavern closed up and its lights (the only ones
+thereabouts) were put out. No Spaniard had been seen. Nobody had
+entered or left the alley. Everything was auspicious. The blackness of
+darkness reigned, the perfect stillness was interrupted only by
+occasional mutterings of distant thunder.
+
+Tom got his lantern, lit it in the hogshead, wrapped it closely in the
+towel, and the two adventurers crept in the gloom toward the tavern.
+Huck stood sentry and Tom felt his way into the alley. Then there was a
+season of waiting anxiety that weighed upon Huck's spirits like a
+mountain. He began to wish he could see a flash from the lantern--it
+would frighten him, but it would at least tell him that Tom was alive
+yet. It seemed hours since Tom had disappeared. Surely he must have
+fainted; maybe he was dead; maybe his heart had burst under terror and
+excitement. In his uneasiness Huck found himself drawing closer and
+closer to the alley; fearing all sorts of dreadful things, and
+momentarily expecting some catastrophe to happen that would take away
+his breath. There was not much to take away, for he seemed only able to
+inhale it by thimblefuls, and his heart would soon wear itself out, the
+way it was beating. Suddenly there was a flash of light and Tom came
+tearing by him: "Run!" said he; "run, for your life!"
+
+He needn't have repeated it; once was enough; Huck was making thirty
+or forty miles an hour before the repetition was uttered. The boys
+never stopped till they reached the shed of a deserted slaughter-house
+at the lower end of the village. Just as they got within its shelter
+the storm burst and the rain poured down. As soon as Tom got his breath
+he said:
+
+"Huck, it was awful! I tried two of the keys, just as soft as I could;
+but they seemed to make such a power of racket that I couldn't hardly
+get my breath I was so scared. They wouldn't turn in the lock, either.
+Well, without noticing what I was doing, I took hold of the knob, and
+open comes the door! It warn't locked! I hopped in, and shook off the
+towel, and, GREAT CAESAR'S GHOST!"
+
+"What!--what'd you see, Tom?"
+
+"Huck, I most stepped onto Injun Joe's hand!"
+
+"No!"
+
+"Yes! He was lying there, sound asleep on the floor, with his old
+patch on his eye and his arms spread out."
+
+"Lordy, what did you do? Did he wake up?"
+
+"No, never budged. Drunk, I reckon. I just grabbed that towel and
+started!"
+
+"I'd never 'a' thought of the towel, I bet!"
+
+"Well, I would. My aunt would make me mighty sick if I lost it."
+
+"Say, Tom, did you see that box?"
+
+"Huck, I didn't wait to look around. I didn't see the box, I didn't
+see the cross. I didn't see anything but a bottle and a tin cup on the
+floor by Injun Joe; yes, I saw two barrels and lots more bottles in the
+room. Don't you see, now, what's the matter with that ha'nted room?"
+
+"How?"
+
+"Why, it's ha'nted with whiskey! Maybe ALL the Temperance Taverns have
+got a ha'nted room, hey, Huck?"
+
+"Well, I reckon maybe that's so. Who'd 'a' thought such a thing? But
+say, Tom, now's a mighty good time to get that box, if Injun Joe's
+drunk."
+
+"It is, that! You try it!"
+
+Huck shuddered.
+
+"Well, no--I reckon not."
+
+"And I reckon not, Huck. Only one bottle alongside of Injun Joe ain't
+enough. If there'd been three, he'd be drunk enough and I'd do it."
+
+There was a long pause for reflection, and then Tom said:
+
+"Lookyhere, Huck, less not try that thing any more till we know Injun
+Joe's not in there. It's too scary. Now, if we watch every night, we'll
+be dead sure to see him go out, some time or other, and then we'll
+snatch that box quicker'n lightning."
+
+"Well, I'm agreed. I'll watch the whole night long, and I'll do it
+every night, too, if you'll do the other part of the job."
+
+"All right, I will. All you got to do is to trot up Hooper Street a
+block and maow--and if I'm asleep, you throw some gravel at the window
+and that'll fetch me."
+
+"Agreed, and good as wheat!"
+
+"Now, Huck, the storm's over, and I'll go home. It'll begin to be
+daylight in a couple of hours. You go back and watch that long, will
+you?"
+
+"I said I would, Tom, and I will. I'll ha'nt that tavern every night
+for a year! I'll sleep all day and I'll stand watch all night."
+
+"That's all right. Now, where you going to sleep?"
+
+"In Ben Rogers' hayloft. He lets me, and so does his pap's nigger man,
+Uncle Jake. I tote water for Uncle Jake whenever he wants me to, and
+any time I ask him he gives me a little something to eat if he can
+spare it. That's a mighty good nigger, Tom. He likes me, becuz I don't
+ever act as if I was above him. Sometime I've set right down and eat
+WITH him. But you needn't tell that. A body's got to do things when
+he's awful hungry he wouldn't want to do as a steady thing."
+
+"Well, if I don't want you in the daytime, I'll let you sleep. I won't
+come bothering around. Any time you see something's up, in the night,
+just skip right around and maow."
+
+
+
+CHAPTER XXIX
+
+THE first thing Tom heard on Friday morning was a glad piece of news
+--Judge Thatcher's family had come back to town the night before. Both
+Injun Joe and the treasure sunk into secondary importance for a moment,
+and Becky took the chief place in the boy's interest. He saw her and
+they had an exhausting good time playing "hi-spy" and "gully-keeper"
+with a crowd of their school-mates. The day was completed and crowned
+in a peculiarly satisfactory way: Becky teased her mother to appoint
+the next day for the long-promised and long-delayed picnic, and she
+consented. The child's delight was boundless; and Tom's not more
+moderate. The invitations were sent out before sunset, and straightway
+the young folks of the village were thrown into a fever of preparation
+and pleasurable anticipation. Tom's excitement enabled him to keep
+awake until a pretty late hour, and he had good hopes of hearing Huck's
+"maow," and of having his treasure to astonish Becky and the picnickers
+with, next day; but he was disappointed. No signal came that night.
+
+Morning came, eventually, and by ten or eleven o'clock a giddy and
+rollicking company were gathered at Judge Thatcher's, and everything
+was ready for a start. It was not the custom for elderly people to mar
+the picnics with their presence. The children were considered safe
+enough under the wings of a few young ladies of eighteen and a few
+young gentlemen of twenty-three or thereabouts. The old steam ferryboat
+was chartered for the occasion; presently the gay throng filed up the
+main street laden with provision-baskets. Sid was sick and had to miss
+the fun; Mary remained at home to entertain him. The last thing Mrs.
+Thatcher said to Becky, was:
+
+"You'll not get back till late. Perhaps you'd better stay all night
+with some of the girls that live near the ferry-landing, child."
+
+"Then I'll stay with Susy Harper, mamma."
+
+"Very well. And mind and behave yourself and don't be any trouble."
+
+Presently, as they tripped along, Tom said to Becky:
+
+"Say--I'll tell you what we'll do. 'Stead of going to Joe Harper's
+we'll climb right up the hill and stop at the Widow Douglas'. She'll
+have ice-cream! She has it most every day--dead loads of it. And she'll
+be awful glad to have us."
+
+"Oh, that will be fun!"
+
+Then Becky reflected a moment and said:
+
+"But what will mamma say?"
+
+"How'll she ever know?"
+
+The girl turned the idea over in her mind, and said reluctantly:
+
+"I reckon it's wrong--but--"
+
+"But shucks! Your mother won't know, and so what's the harm? All she
+wants is that you'll be safe; and I bet you she'd 'a' said go there if
+she'd 'a' thought of it. I know she would!"
+
+The Widow Douglas' splendid hospitality was a tempting bait. It and
+Tom's persuasions presently carried the day. So it was decided to say
+nothing anybody about the night's programme. Presently it occurred to
+Tom that maybe Huck might come this very night and give the signal. The
+thought took a deal of the spirit out of his anticipations. Still he
+could not bear to give up the fun at Widow Douglas'. And why should he
+give it up, he reasoned--the signal did not come the night before, so
+why should it be any more likely to come to-night? The sure fun of the
+evening outweighed the uncertain treasure; and, boy-like, he determined
+to yield to the stronger inclination and not allow himself to think of
+the box of money another time that day.
+
+Three miles below town the ferryboat stopped at the mouth of a woody
+hollow and tied up. The crowd swarmed ashore and soon the forest
+distances and craggy heights echoed far and near with shoutings and
+laughter. All the different ways of getting hot and tired were gone
+through with, and by-and-by the rovers straggled back to camp fortified
+with responsible appetites, and then the destruction of the good things
+began. After the feast there was a refreshing season of rest and chat
+in the shade of spreading oaks. By-and-by somebody shouted:
+
+"Who's ready for the cave?"
+
+Everybody was. Bundles of candles were procured, and straightway there
+was a general scamper up the hill. The mouth of the cave was up the
+hillside--an opening shaped like a letter A. Its massive oaken door
+stood unbarred. Within was a small chamber, chilly as an ice-house, and
+walled by Nature with solid limestone that was dewy with a cold sweat.
+It was romantic and mysterious to stand here in the deep gloom and look
+out upon the green valley shining in the sun. But the impressiveness of
+the situation quickly wore off, and the romping began again. The moment
+a candle was lighted there was a general rush upon the owner of it; a
+struggle and a gallant defence followed, but the candle was soon
+knocked down or blown out, and then there was a glad clamor of laughter
+and a new chase. But all things have an end. By-and-by the procession
+went filing down the steep descent of the main avenue, the flickering
+rank of lights dimly revealing the lofty walls of rock almost to their
+point of junction sixty feet overhead. This main avenue was not more
+than eight or ten feet wide. Every few steps other lofty and still
+narrower crevices branched from it on either hand--for McDougal's cave
+was but a vast labyrinth of crooked aisles that ran into each other and
+out again and led nowhere. It was said that one might wander days and
+nights together through its intricate tangle of rifts and chasms, and
+never find the end of the cave; and that he might go down, and down,
+and still down, into the earth, and it was just the same--labyrinth
+under labyrinth, and no end to any of them. No man "knew" the cave.
+That was an impossible thing. Most of the young men knew a portion of
+it, and it was not customary to venture much beyond this known portion.
+Tom Sawyer knew as much of the cave as any one.
+
+The procession moved along the main avenue some three-quarters of a
+mile, and then groups and couples began to slip aside into branch
+avenues, fly along the dismal corridors, and take each other by
+surprise at points where the corridors joined again. Parties were able
+to elude each other for the space of half an hour without going beyond
+the "known" ground.
+
+By-and-by, one group after another came straggling back to the mouth
+of the cave, panting, hilarious, smeared from head to foot with tallow
+drippings, daubed with clay, and entirely delighted with the success of
+the day. Then they were astonished to find that they had been taking no
+note of time and that night was about at hand. The clanging bell had
+been calling for half an hour. However, this sort of close to the day's
+adventures was romantic and therefore satisfactory. When the ferryboat
+with her wild freight pushed into the stream, nobody cared sixpence for
+the wasted time but the captain of the craft.
+
+Huck was already upon his watch when the ferryboat's lights went
+glinting past the wharf. He heard no noise on board, for the young
+people were as subdued and still as people usually are who are nearly
+tired to death. He wondered what boat it was, and why she did not stop
+at the wharf--and then he dropped her out of his mind and put his
+attention upon his business. The night was growing cloudy and dark. Ten
+o'clock came, and the noise of vehicles ceased, scattered lights began
+to wink out, all straggling foot-passengers disappeared, the village
+betook itself to its slumbers and left the small watcher alone with the
+silence and the ghosts. Eleven o'clock came, and the tavern lights were
+put out; darkness everywhere, now. Huck waited what seemed a weary long
+time, but nothing happened. His faith was weakening. Was there any use?
+Was there really any use? Why not give it up and turn in?
+
+A noise fell upon his ear. He was all attention in an instant. The
+alley door closed softly. He sprang to the corner of the brick store.
+The next moment two men brushed by him, and one seemed to have
+something under his arm. It must be that box! So they were going to
+remove the treasure. Why call Tom now? It would be absurd--the men
+would get away with the box and never be found again. No, he would
+stick to their wake and follow them; he would trust to the darkness for
+security from discovery. So communing with himself, Huck stepped out
+and glided along behind the men, cat-like, with bare feet, allowing
+them to keep just far enough ahead not to be invisible.
+
+They moved up the river street three blocks, then turned to the left
+up a cross-street. They went straight ahead, then, until they came to
+the path that led up Cardiff Hill; this they took. They passed by the
+old Welshman's house, half-way up the hill, without hesitating, and
+still climbed upward. Good, thought Huck, they will bury it in the old
+quarry. But they never stopped at the quarry. They passed on, up the
+summit. They plunged into the narrow path between the tall sumach
+bushes, and were at once hidden in the gloom. Huck closed up and
+shortened his distance, now, for they would never be able to see him.
+He trotted along awhile; then slackened his pace, fearing he was
+gaining too fast; moved on a piece, then stopped altogether; listened;
+no sound; none, save that he seemed to hear the beating of his own
+heart. The hooting of an owl came over the hill--ominous sound! But no
+footsteps. Heavens, was everything lost! He was about to spring with
+winged feet, when a man cleared his throat not four feet from him!
+Huck's heart shot into his throat, but he swallowed it again; and then
+he stood there shaking as if a dozen agues had taken charge of him at
+once, and so weak that he thought he must surely fall to the ground. He
+knew where he was. He knew he was within five steps of the stile
+leading into Widow Douglas' grounds. Very well, he thought, let them
+bury it there; it won't be hard to find.
+
+Now there was a voice--a very low voice--Injun Joe's:
+
+"Damn her, maybe she's got company--there's lights, late as it is."
+
+"I can't see any."
+
+This was that stranger's voice--the stranger of the haunted house. A
+deadly chill went to Huck's heart--this, then, was the "revenge" job!
+His thought was, to fly. Then he remembered that the Widow Douglas had
+been kind to him more than once, and maybe these men were going to
+murder her. He wished he dared venture to warn her; but he knew he
+didn't dare--they might come and catch him. He thought all this and
+more in the moment that elapsed between the stranger's remark and Injun
+Joe's next--which was--
+
+"Because the bush is in your way. Now--this way--now you see, don't
+you?"
+
+"Yes. Well, there IS company there, I reckon. Better give it up."
+
+"Give it up, and I just leaving this country forever! Give it up and
+maybe never have another chance. I tell you again, as I've told you
+before, I don't care for her swag--you may have it. But her husband was
+rough on me--many times he was rough on me--and mainly he was the
+justice of the peace that jugged me for a vagrant. And that ain't all.
+It ain't a millionth part of it! He had me HORSEWHIPPED!--horsewhipped
+in front of the jail, like a nigger!--with all the town looking on!
+HORSEWHIPPED!--do you understand? He took advantage of me and died. But
+I'll take it out of HER."
+
+"Oh, don't kill her! Don't do that!"
+
+"Kill? Who said anything about killing? I would kill HIM if he was
+here; but not her. When you want to get revenge on a woman you don't
+kill her--bosh! you go for her looks. You slit her nostrils--you notch
+her ears like a sow!"
+
+"By God, that's--"
+
+"Keep your opinion to yourself! It will be safest for you. I'll tie
+her to the bed. If she bleeds to death, is that my fault? I'll not cry,
+if she does. My friend, you'll help me in this thing--for MY sake
+--that's why you're here--I mightn't be able alone. If you flinch, I'll
+kill you. Do you understand that? And if I have to kill you, I'll kill
+her--and then I reckon nobody'll ever know much about who done this
+business."
+
+"Well, if it's got to be done, let's get at it. The quicker the
+better--I'm all in a shiver."
+
+"Do it NOW? And company there? Look here--I'll get suspicious of you,
+first thing you know. No--we'll wait till the lights are out--there's
+no hurry."
+
+Huck felt that a silence was going to ensue--a thing still more awful
+than any amount of murderous talk; so he held his breath and stepped
+gingerly back; planted his foot carefully and firmly, after balancing,
+one-legged, in a precarious way and almost toppling over, first on one
+side and then on the other. He took another step back, with the same
+elaboration and the same risks; then another and another, and--a twig
+snapped under his foot! His breath stopped and he listened. There was
+no sound--the stillness was perfect. His gratitude was measureless. Now
+he turned in his tracks, between the walls of sumach bushes--turned
+himself as carefully as if he were a ship--and then stepped quickly but
+cautiously along. When he emerged at the quarry he felt secure, and so
+he picked up his nimble heels and flew. Down, down he sped, till he
+reached the Welshman's. He banged at the door, and presently the heads
+of the old man and his two stalwart sons were thrust from windows.
+
+"What's the row there? Who's banging? What do you want?"
+
+"Let me in--quick! I'll tell everything."
+
+"Why, who are you?"
+
+"Huckleberry Finn--quick, let me in!"
+
+"Huckleberry Finn, indeed! It ain't a name to open many doors, I
+judge! But let him in, lads, and let's see what's the trouble."
+
+"Please don't ever tell I told you," were Huck's first words when he
+got in. "Please don't--I'd be killed, sure--but the widow's been good
+friends to me sometimes, and I want to tell--I WILL tell if you'll
+promise you won't ever say it was me."
+
+"By George, he HAS got something to tell, or he wouldn't act so!"
+exclaimed the old man; "out with it and nobody here'll ever tell, lad."
+
+Three minutes later the old man and his sons, well armed, were up the
+hill, and just entering the sumach path on tiptoe, their weapons in
+their hands. Huck accompanied them no further. He hid behind a great
+bowlder and fell to listening. There was a lagging, anxious silence,
+and then all of a sudden there was an explosion of firearms and a cry.
+
+Huck waited for no particulars. He sprang away and sped down the hill
+as fast as his legs could carry him.
+
+
+
+CHAPTER XXX
+
+AS the earliest suspicion of dawn appeared on Sunday morning, Huck
+came groping up the hill and rapped gently at the old Welshman's door.
+The inmates were asleep, but it was a sleep that was set on a
+hair-trigger, on account of the exciting episode of the night. A call
+came from a window:
+
+"Who's there!"
+
+Huck's scared voice answered in a low tone:
+
+"Please let me in! It's only Huck Finn!"
+
+"It's a name that can open this door night or day, lad!--and welcome!"
+
+These were strange words to the vagabond boy's ears, and the
+pleasantest he had ever heard. He could not recollect that the closing
+word had ever been applied in his case before. The door was quickly
+unlocked, and he entered. Huck was given a seat and the old man and his
+brace of tall sons speedily dressed themselves.
+
+"Now, my boy, I hope you're good and hungry, because breakfast will be
+ready as soon as the sun's up, and we'll have a piping hot one, too
+--make yourself easy about that! I and the boys hoped you'd turn up and
+stop here last night."
+
+"I was awful scared," said Huck, "and I run. I took out when the
+pistols went off, and I didn't stop for three mile. I've come now becuz
+I wanted to know about it, you know; and I come before daylight becuz I
+didn't want to run across them devils, even if they was dead."
+
+"Well, poor chap, you do look as if you'd had a hard night of it--but
+there's a bed here for you when you've had your breakfast. No, they
+ain't dead, lad--we are sorry enough for that. You see we knew right
+where to put our hands on them, by your description; so we crept along
+on tiptoe till we got within fifteen feet of them--dark as a cellar
+that sumach path was--and just then I found I was going to sneeze. It
+was the meanest kind of luck! I tried to keep it back, but no use
+--'twas bound to come, and it did come! I was in the lead with my pistol
+raised, and when the sneeze started those scoundrels a-rustling to get
+out of the path, I sung out, 'Fire boys!' and blazed away at the place
+where the rustling was. So did the boys. But they were off in a jiffy,
+those villains, and we after them, down through the woods. I judge we
+never touched them. They fired a shot apiece as they started, but their
+bullets whizzed by and didn't do us any harm. As soon as we lost the
+sound of their feet we quit chasing, and went down and stirred up the
+constables. They got a posse together, and went off to guard the river
+bank, and as soon as it is light the sheriff and a gang are going to
+beat up the woods. My boys will be with them presently. I wish we had
+some sort of description of those rascals--'twould help a good deal.
+But you couldn't see what they were like, in the dark, lad, I suppose?"
+
+"Oh yes; I saw them down-town and follered them."
+
+"Splendid! Describe them--describe them, my boy!"
+
+"One's the old deaf and dumb Spaniard that's ben around here once or
+twice, and t'other's a mean-looking, ragged--"
+
+"That's enough, lad, we know the men! Happened on them in the woods
+back of the widow's one day, and they slunk away. Off with you, boys,
+and tell the sheriff--get your breakfast to-morrow morning!"
+
+The Welshman's sons departed at once. As they were leaving the room
+Huck sprang up and exclaimed:
+
+"Oh, please don't tell ANYbody it was me that blowed on them! Oh,
+please!"
+
+"All right if you say it, Huck, but you ought to have the credit of
+what you did."
+
+"Oh no, no! Please don't tell!"
+
+When the young men were gone, the old Welshman said:
+
+"They won't tell--and I won't. But why don't you want it known?"
+
+Huck would not explain, further than to say that he already knew too
+much about one of those men and would not have the man know that he
+knew anything against him for the whole world--he would be killed for
+knowing it, sure.
+
+The old man promised secrecy once more, and said:
+
+"How did you come to follow these fellows, lad? Were they looking
+suspicious?"
+
+Huck was silent while he framed a duly cautious reply. Then he said:
+
+"Well, you see, I'm a kind of a hard lot,--least everybody says so,
+and I don't see nothing agin it--and sometimes I can't sleep much, on
+account of thinking about it and sort of trying to strike out a new way
+of doing. That was the way of it last night. I couldn't sleep, and so I
+come along up-street 'bout midnight, a-turning it all over, and when I
+got to that old shackly brick store by the Temperance Tavern, I backed
+up agin the wall to have another think. Well, just then along comes
+these two chaps slipping along close by me, with something under their
+arm, and I reckoned they'd stole it. One was a-smoking, and t'other one
+wanted a light; so they stopped right before me and the cigars lit up
+their faces and I see that the big one was the deaf and dumb Spaniard,
+by his white whiskers and the patch on his eye, and t'other one was a
+rusty, ragged-looking devil."
+
+"Could you see the rags by the light of the cigars?"
+
+This staggered Huck for a moment. Then he said:
+
+"Well, I don't know--but somehow it seems as if I did."
+
+"Then they went on, and you--"
+
+"Follered 'em--yes. That was it. I wanted to see what was up--they
+sneaked along so. I dogged 'em to the widder's stile, and stood in the
+dark and heard the ragged one beg for the widder, and the Spaniard
+swear he'd spile her looks just as I told you and your two--"
+
+"What! The DEAF AND DUMB man said all that!"
+
+Huck had made another terrible mistake! He was trying his best to keep
+the old man from getting the faintest hint of who the Spaniard might
+be, and yet his tongue seemed determined to get him into trouble in
+spite of all he could do. He made several efforts to creep out of his
+scrape, but the old man's eye was upon him and he made blunder after
+blunder. Presently the Welshman said:
+
+"My boy, don't be afraid of me. I wouldn't hurt a hair of your head
+for all the world. No--I'd protect you--I'd protect you. This Spaniard
+is not deaf and dumb; you've let that slip without intending it; you
+can't cover that up now. You know something about that Spaniard that
+you want to keep dark. Now trust me--tell me what it is, and trust me
+--I won't betray you."
+
+Huck looked into the old man's honest eyes a moment, then bent over
+and whispered in his ear:
+
+"'Tain't a Spaniard--it's Injun Joe!"
+
+The Welshman almost jumped out of his chair. In a moment he said:
+
+"It's all plain enough, now. When you talked about notching ears and
+slitting noses I judged that that was your own embellishment, because
+white men don't take that sort of revenge. But an Injun! That's a
+different matter altogether."
+
+During breakfast the talk went on, and in the course of it the old man
+said that the last thing which he and his sons had done, before going
+to bed, was to get a lantern and examine the stile and its vicinity for
+marks of blood. They found none, but captured a bulky bundle of--
+
+"Of WHAT?"
+
+If the words had been lightning they could not have leaped with a more
+stunning suddenness from Huck's blanched lips. His eyes were staring
+wide, now, and his breath suspended--waiting for the answer. The
+Welshman started--stared in return--three seconds--five seconds--ten
+--then replied:
+
+"Of burglar's tools. Why, what's the MATTER with you?"
+
+Huck sank back, panting gently, but deeply, unutterably grateful. The
+Welshman eyed him gravely, curiously--and presently said:
+
+"Yes, burglar's tools. That appears to relieve you a good deal. But
+what did give you that turn? What were YOU expecting we'd found?"
+
+Huck was in a close place--the inquiring eye was upon him--he would
+have given anything for material for a plausible answer--nothing
+suggested itself--the inquiring eye was boring deeper and deeper--a
+senseless reply offered--there was no time to weigh it, so at a venture
+he uttered it--feebly:
+
+"Sunday-school books, maybe."
+
+Poor Huck was too distressed to smile, but the old man laughed loud
+and joyously, shook up the details of his anatomy from head to foot,
+and ended by saying that such a laugh was money in a-man's pocket,
+because it cut down the doctor's bill like everything. Then he added:
+
+"Poor old chap, you're white and jaded--you ain't well a bit--no
+wonder you're a little flighty and off your balance. But you'll come
+out of it. Rest and sleep will fetch you out all right, I hope."
+
+Huck was irritated to think he had been such a goose and betrayed such
+a suspicious excitement, for he had dropped the idea that the parcel
+brought from the tavern was the treasure, as soon as he had heard the
+talk at the widow's stile. He had only thought it was not the treasure,
+however--he had not known that it wasn't--and so the suggestion of a
+captured bundle was too much for his self-possession. But on the whole
+he felt glad the little episode had happened, for now he knew beyond
+all question that that bundle was not THE bundle, and so his mind was
+at rest and exceedingly comfortable. In fact, everything seemed to be
+drifting just in the right direction, now; the treasure must be still
+in No. 2, the men would be captured and jailed that day, and he and Tom
+could seize the gold that night without any trouble or any fear of
+interruption.
+
+Just as breakfast was completed there was a knock at the door. Huck
+jumped for a hiding-place, for he had no mind to be connected even
+remotely with the late event. The Welshman admitted several ladies and
+gentlemen, among them the Widow Douglas, and noticed that groups of
+citizens were climbing up the hill--to stare at the stile. So the news
+had spread. The Welshman had to tell the story of the night to the
+visitors. The widow's gratitude for her preservation was outspoken.
+
+"Don't say a word about it, madam. There's another that you're more
+beholden to than you are to me and my boys, maybe, but he don't allow
+me to tell his name. We wouldn't have been there but for him."
+
+Of course this excited a curiosity so vast that it almost belittled
+the main matter--but the Welshman allowed it to eat into the vitals of
+his visitors, and through them be transmitted to the whole town, for he
+refused to part with his secret. When all else had been learned, the
+widow said:
+
+"I went to sleep reading in bed and slept straight through all that
+noise. Why didn't you come and wake me?"
+
+"We judged it warn't worth while. Those fellows warn't likely to come
+again--they hadn't any tools left to work with, and what was the use of
+waking you up and scaring you to death? My three negro men stood guard
+at your house all the rest of the night. They've just come back."
+
+More visitors came, and the story had to be told and retold for a
+couple of hours more.
+
+There was no Sabbath-school during day-school vacation, but everybody
+was early at church. The stirring event was well canvassed. News came
+that not a sign of the two villains had been yet discovered. When the
+sermon was finished, Judge Thatcher's wife dropped alongside of Mrs.
+Harper as she moved down the aisle with the crowd and said:
+
+"Is my Becky going to sleep all day? I just expected she would be
+tired to death."
+
+"Your Becky?"
+
+"Yes," with a startled look--"didn't she stay with you last night?"
+
+"Why, no."
+
+Mrs. Thatcher turned pale, and sank into a pew, just as Aunt Polly,
+talking briskly with a friend, passed by. Aunt Polly said:
+
+"Good-morning, Mrs. Thatcher. Good-morning, Mrs. Harper. I've got a
+boy that's turned up missing. I reckon my Tom stayed at your house last
+night--one of you. And now he's afraid to come to church. I've got to
+settle with him."
+
+Mrs. Thatcher shook her head feebly and turned paler than ever.
+
+"He didn't stay with us," said Mrs. Harper, beginning to look uneasy.
+A marked anxiety came into Aunt Polly's face.
+
+"Joe Harper, have you seen my Tom this morning?"
+
+"No'm."
+
+"When did you see him last?"
+
+Joe tried to remember, but was not sure he could say. The people had
+stopped moving out of church. Whispers passed along, and a boding
+uneasiness took possession of every countenance. Children were
+anxiously questioned, and young teachers. They all said they had not
+noticed whether Tom and Becky were on board the ferryboat on the
+homeward trip; it was dark; no one thought of inquiring if any one was
+missing. One young man finally blurted out his fear that they were
+still in the cave! Mrs. Thatcher swooned away. Aunt Polly fell to
+crying and wringing her hands.
+
+The alarm swept from lip to lip, from group to group, from street to
+street, and within five minutes the bells were wildly clanging and the
+whole town was up! The Cardiff Hill episode sank into instant
+insignificance, the burglars were forgotten, horses were saddled,
+skiffs were manned, the ferryboat ordered out, and before the horror
+was half an hour old, two hundred men were pouring down highroad and
+river toward the cave.
+
+All the long afternoon the village seemed empty and dead. Many women
+visited Aunt Polly and Mrs. Thatcher and tried to comfort them. They
+cried with them, too, and that was still better than words. All the
+tedious night the town waited for news; but when the morning dawned at
+last, all the word that came was, "Send more candles--and send food."
+Mrs. Thatcher was almost crazed; and Aunt Polly, also. Judge Thatcher
+sent messages of hope and encouragement from the cave, but they
+conveyed no real cheer.
+
+The old Welshman came home toward daylight, spattered with
+candle-grease, smeared with clay, and almost worn out. He found Huck
+still in the bed that had been provided for him, and delirious with
+fever. The physicians were all at the cave, so the Widow Douglas came
+and took charge of the patient. She said she would do her best by him,
+because, whether he was good, bad, or indifferent, he was the Lord's,
+and nothing that was the Lord's was a thing to be neglected. The
+Welshman said Huck had good spots in him, and the widow said:
+
+"You can depend on it. That's the Lord's mark. He don't leave it off.
+He never does. Puts it somewhere on every creature that comes from his
+hands."
+
+Early in the forenoon parties of jaded men began to straggle into the
+village, but the strongest of the citizens continued searching. All the
+news that could be gained was that remotenesses of the cavern were
+being ransacked that had never been visited before; that every corner
+and crevice was going to be thoroughly searched; that wherever one
+wandered through the maze of passages, lights were to be seen flitting
+hither and thither in the distance, and shoutings and pistol-shots sent
+their hollow reverberations to the ear down the sombre aisles. In one
+place, far from the section usually traversed by tourists, the names
+"BECKY & TOM" had been found traced upon the rocky wall with
+candle-smoke, and near at hand a grease-soiled bit of ribbon. Mrs.
+Thatcher recognized the ribbon and cried over it. She said it was the
+last relic she should ever have of her child; and that no other memorial
+of her could ever be so precious, because this one parted latest from
+the living body before the awful death came. Some said that now and
+then, in the cave, a far-away speck of light would glimmer, and then a
+glorious shout would burst forth and a score of men go trooping down the
+echoing aisle--and then a sickening disappointment always followed; the
+children were not there; it was only a searcher's light.
+
+Three dreadful days and nights dragged their tedious hours along, and
+the village sank into a hopeless stupor. No one had heart for anything.
+The accidental discovery, just made, that the proprietor of the
+Temperance Tavern kept liquor on his premises, scarcely fluttered the
+public pulse, tremendous as the fact was. In a lucid interval, Huck
+feebly led up to the subject of taverns, and finally asked--dimly
+dreading the worst--if anything had been discovered at the Temperance
+Tavern since he had been ill.
+
+"Yes," said the widow.
+
+Huck started up in bed, wild-eyed:
+
+"What? What was it?"
+
+"Liquor!--and the place has been shut up. Lie down, child--what a turn
+you did give me!"
+
+"Only tell me just one thing--only just one--please! Was it Tom Sawyer
+that found it?"
+
+The widow burst into tears. "Hush, hush, child, hush! I've told you
+before, you must NOT talk. You are very, very sick!"
+
+Then nothing but liquor had been found; there would have been a great
+powwow if it had been the gold. So the treasure was gone forever--gone
+forever! But what could she be crying about? Curious that she should
+cry.
+
+These thoughts worked their dim way through Huck's mind, and under the
+weariness they gave him he fell asleep. The widow said to herself:
+
+"There--he's asleep, poor wreck. Tom Sawyer find it! Pity but somebody
+could find Tom Sawyer! Ah, there ain't many left, now, that's got hope
+enough, or strength enough, either, to go on searching."
+
+
+
+CHAPTER XXXI
+
+NOW to return to Tom and Becky's share in the picnic. They tripped
+along the murky aisles with the rest of the company, visiting the
+familiar wonders of the cave--wonders dubbed with rather
+over-descriptive names, such as "The Drawing-Room," "The Cathedral,"
+"Aladdin's Palace," and so on. Presently the hide-and-seek frolicking
+began, and Tom and Becky engaged in it with zeal until the exertion
+began to grow a trifle wearisome; then they wandered down a sinuous
+avenue holding their candles aloft and reading the tangled web-work of
+names, dates, post-office addresses, and mottoes with which the rocky
+walls had been frescoed (in candle-smoke). Still drifting along and
+talking, they scarcely noticed that they were now in a part of the cave
+whose walls were not frescoed. They smoked their own names under an
+overhanging shelf and moved on. Presently they came to a place where a
+little stream of water, trickling over a ledge and carrying a limestone
+sediment with it, had, in the slow-dragging ages, formed a laced and
+ruffled Niagara in gleaming and imperishable stone. Tom squeezed his
+small body behind it in order to illuminate it for Becky's
+gratification. He found that it curtained a sort of steep natural
+stairway which was enclosed between narrow walls, and at once the
+ambition to be a discoverer seized him. Becky responded to his call,
+and they made a smoke-mark for future guidance, and started upon their
+quest. They wound this way and that, far down into the secret depths of
+the cave, made another mark, and branched off in search of novelties to
+tell the upper world about. In one place they found a spacious cavern,
+from whose ceiling depended a multitude of shining stalactites of the
+length and circumference of a man's leg; they walked all about it,
+wondering and admiring, and presently left it by one of the numerous
+passages that opened into it. This shortly brought them to a bewitching
+spring, whose basin was incrusted with a frostwork of glittering
+crystals; it was in the midst of a cavern whose walls were supported by
+many fantastic pillars which had been formed by the joining of great
+stalactites and stalagmites together, the result of the ceaseless
+water-drip of centuries. Under the roof vast knots of bats had packed
+themselves together, thousands in a bunch; the lights disturbed the
+creatures and they came flocking down by hundreds, squeaking and
+darting furiously at the candles. Tom knew their ways and the danger of
+this sort of conduct. He seized Becky's hand and hurried her into the
+first corridor that offered; and none too soon, for a bat struck
+Becky's light out with its wing while she was passing out of the
+cavern. The bats chased the children a good distance; but the fugitives
+plunged into every new passage that offered, and at last got rid of the
+perilous things. Tom found a subterranean lake, shortly, which
+stretched its dim length away until its shape was lost in the shadows.
+He wanted to explore its borders, but concluded that it would be best
+to sit down and rest awhile, first. Now, for the first time, the deep
+stillness of the place laid a clammy hand upon the spirits of the
+children. Becky said:
+
+"Why, I didn't notice, but it seems ever so long since I heard any of
+the others."
+
+"Come to think, Becky, we are away down below them--and I don't know
+how far away north, or south, or east, or whichever it is. We couldn't
+hear them here."
+
+Becky grew apprehensive.
+
+"I wonder how long we've been down here, Tom? We better start back."
+
+"Yes, I reckon we better. P'raps we better."
+
+"Can you find the way, Tom? It's all a mixed-up crookedness to me."
+
+"I reckon I could find it--but then the bats. If they put our candles
+out it will be an awful fix. Let's try some other way, so as not to go
+through there."
+
+"Well. But I hope we won't get lost. It would be so awful!" and the
+girl shuddered at the thought of the dreadful possibilities.
+
+They started through a corridor, and traversed it in silence a long
+way, glancing at each new opening, to see if there was anything
+familiar about the look of it; but they were all strange. Every time
+Tom made an examination, Becky would watch his face for an encouraging
+sign, and he would say cheerily:
+
+"Oh, it's all right. This ain't the one, but we'll come to it right
+away!"
+
+But he felt less and less hopeful with each failure, and presently
+began to turn off into diverging avenues at sheer random, in desperate
+hope of finding the one that was wanted. He still said it was "all
+right," but there was such a leaden dread at his heart that the words
+had lost their ring and sounded just as if he had said, "All is lost!"
+Becky clung to his side in an anguish of fear, and tried hard to keep
+back the tears, but they would come. At last she said:
+
+"Oh, Tom, never mind the bats, let's go back that way! We seem to get
+worse and worse off all the time."
+
+"Listen!" said he.
+
+Profound silence; silence so deep that even their breathings were
+conspicuous in the hush. Tom shouted. The call went echoing down the
+empty aisles and died out in the distance in a faint sound that
+resembled a ripple of mocking laughter.
+
+"Oh, don't do it again, Tom, it is too horrid," said Becky.
+
+"It is horrid, but I better, Becky; they might hear us, you know," and
+he shouted again.
+
+The "might" was even a chillier horror than the ghostly laughter, it
+so confessed a perishing hope. The children stood still and listened;
+but there was no result. Tom turned upon the back track at once, and
+hurried his steps. It was but a little while before a certain
+indecision in his manner revealed another fearful fact to Becky--he
+could not find his way back!
+
+"Oh, Tom, you didn't make any marks!"
+
+"Becky, I was such a fool! Such a fool! I never thought we might want
+to come back! No--I can't find the way. It's all mixed up."
+
+"Tom, Tom, we're lost! we're lost! We never can get out of this awful
+place! Oh, why DID we ever leave the others!"
+
+She sank to the ground and burst into such a frenzy of crying that Tom
+was appalled with the idea that she might die, or lose her reason. He
+sat down by her and put his arms around her; she buried her face in his
+bosom, she clung to him, she poured out her terrors, her unavailing
+regrets, and the far echoes turned them all to jeering laughter. Tom
+begged her to pluck up hope again, and she said she could not. He fell
+to blaming and abusing himself for getting her into this miserable
+situation; this had a better effect. She said she would try to hope
+again, she would get up and follow wherever he might lead if only he
+would not talk like that any more. For he was no more to blame than
+she, she said.
+
+So they moved on again--aimlessly--simply at random--all they could do
+was to move, keep moving. For a little while, hope made a show of
+reviving--not with any reason to back it, but only because it is its
+nature to revive when the spring has not been taken out of it by age
+and familiarity with failure.
+
+By-and-by Tom took Becky's candle and blew it out. This economy meant
+so much! Words were not needed. Becky understood, and her hope died
+again. She knew that Tom had a whole candle and three or four pieces in
+his pockets--yet he must economize.
+
+By-and-by, fatigue began to assert its claims; the children tried to
+pay attention, for it was dreadful to think of sitting down when time
+was grown to be so precious, moving, in some direction, in any
+direction, was at least progress and might bear fruit; but to sit down
+was to invite death and shorten its pursuit.
+
+At last Becky's frail limbs refused to carry her farther. She sat
+down. Tom rested with her, and they talked of home, and the friends
+there, and the comfortable beds and, above all, the light! Becky cried,
+and Tom tried to think of some way of comforting her, but all his
+encouragements were grown threadbare with use, and sounded like
+sarcasms. Fatigue bore so heavily upon Becky that she drowsed off to
+sleep. Tom was grateful. He sat looking into her drawn face and saw it
+grow smooth and natural under the influence of pleasant dreams; and
+by-and-by a smile dawned and rested there. The peaceful face reflected
+somewhat of peace and healing into his own spirit, and his thoughts
+wandered away to bygone times and dreamy memories. While he was deep in
+his musings, Becky woke up with a breezy little laugh--but it was
+stricken dead upon her lips, and a groan followed it.
+
+"Oh, how COULD I sleep! I wish I never, never had waked! No! No, I
+don't, Tom! Don't look so! I won't say it again."
+
+"I'm glad you've slept, Becky; you'll feel rested, now, and we'll find
+the way out."
+
+"We can try, Tom; but I've seen such a beautiful country in my dream.
+I reckon we are going there."
+
+"Maybe not, maybe not. Cheer up, Becky, and let's go on trying."
+
+They rose up and wandered along, hand in hand and hopeless. They tried
+to estimate how long they had been in the cave, but all they knew was
+that it seemed days and weeks, and yet it was plain that this could not
+be, for their candles were not gone yet. A long time after this--they
+could not tell how long--Tom said they must go softly and listen for
+dripping water--they must find a spring. They found one presently, and
+Tom said it was time to rest again. Both were cruelly tired, yet Becky
+said she thought she could go a little farther. She was surprised to
+hear Tom dissent. She could not understand it. They sat down, and Tom
+fastened his candle to the wall in front of them with some clay.
+Thought was soon busy; nothing was said for some time. Then Becky broke
+the silence:
+
+"Tom, I am so hungry!"
+
+Tom took something out of his pocket.
+
+"Do you remember this?" said he.
+
+Becky almost smiled.
+
+"It's our wedding-cake, Tom."
+
+"Yes--I wish it was as big as a barrel, for it's all we've got."
+
+"I saved it from the picnic for us to dream on, Tom, the way grown-up
+people do with wedding-cake--but it'll be our--"
+
+She dropped the sentence where it was. Tom divided the cake and Becky
+ate with good appetite, while Tom nibbled at his moiety. There was
+abundance of cold water to finish the feast with. By-and-by Becky
+suggested that they move on again. Tom was silent a moment. Then he
+said:
+
+"Becky, can you bear it if I tell you something?"
+
+Becky's face paled, but she thought she could.
+
+"Well, then, Becky, we must stay here, where there's water to drink.
+That little piece is our last candle!"
+
+Becky gave loose to tears and wailings. Tom did what he could to
+comfort her, but with little effect. At length Becky said:
+
+"Tom!"
+
+"Well, Becky?"
+
+"They'll miss us and hunt for us!"
+
+"Yes, they will! Certainly they will!"
+
+"Maybe they're hunting for us now, Tom."
+
+"Why, I reckon maybe they are. I hope they are."
+
+"When would they miss us, Tom?"
+
+"When they get back to the boat, I reckon."
+
+"Tom, it might be dark then--would they notice we hadn't come?"
+
+"I don't know. But anyway, your mother would miss you as soon as they
+got home."
+
+A frightened look in Becky's face brought Tom to his senses and he saw
+that he had made a blunder. Becky was not to have gone home that night!
+The children became silent and thoughtful. In a moment a new burst of
+grief from Becky showed Tom that the thing in his mind had struck hers
+also--that the Sabbath morning might be half spent before Mrs. Thatcher
+discovered that Becky was not at Mrs. Harper's.
+
+The children fastened their eyes upon their bit of candle and watched
+it melt slowly and pitilessly away; saw the half inch of wick stand
+alone at last; saw the feeble flame rise and fall, climb the thin
+column of smoke, linger at its top a moment, and then--the horror of
+utter darkness reigned!
+
+How long afterward it was that Becky came to a slow consciousness that
+she was crying in Tom's arms, neither could tell. All that they knew
+was, that after what seemed a mighty stretch of time, both awoke out of
+a dead stupor of sleep and resumed their miseries once more. Tom said
+it might be Sunday, now--maybe Monday. He tried to get Becky to talk,
+but her sorrows were too oppressive, all her hopes were gone. Tom said
+that they must have been missed long ago, and no doubt the search was
+going on. He would shout and maybe some one would come. He tried it;
+but in the darkness the distant echoes sounded so hideously that he
+tried it no more.
+
+The hours wasted away, and hunger came to torment the captives again.
+A portion of Tom's half of the cake was left; they divided and ate it.
+But they seemed hungrier than before. The poor morsel of food only
+whetted desire.
+
+By-and-by Tom said:
+
+"SH! Did you hear that?"
+
+Both held their breath and listened. There was a sound like the
+faintest, far-off shout. Instantly Tom answered it, and leading Becky
+by the hand, started groping down the corridor in its direction.
+Presently he listened again; again the sound was heard, and apparently
+a little nearer.
+
+"It's them!" said Tom; "they're coming! Come along, Becky--we're all
+right now!"
+
+The joy of the prisoners was almost overwhelming. Their speed was
+slow, however, because pitfalls were somewhat common, and had to be
+guarded against. They shortly came to one and had to stop. It might be
+three feet deep, it might be a hundred--there was no passing it at any
+rate. Tom got down on his breast and reached as far down as he could.
+No bottom. They must stay there and wait until the searchers came. They
+listened; evidently the distant shoutings were growing more distant! a
+moment or two more and they had gone altogether. The heart-sinking
+misery of it! Tom whooped until he was hoarse, but it was of no use. He
+talked hopefully to Becky; but an age of anxious waiting passed and no
+sounds came again.
+
+The children groped their way back to the spring. The weary time
+dragged on; they slept again, and awoke famished and woe-stricken. Tom
+believed it must be Tuesday by this time.
+
+Now an idea struck him. There were some side passages near at hand. It
+would be better to explore some of these than bear the weight of the
+heavy time in idleness. He took a kite-line from his pocket, tied it to
+a projection, and he and Becky started, Tom in the lead, unwinding the
+line as he groped along. At the end of twenty steps the corridor ended
+in a "jumping-off place." Tom got down on his knees and felt below, and
+then as far around the corner as he could reach with his hands
+conveniently; he made an effort to stretch yet a little farther to the
+right, and at that moment, not twenty yards away, a human hand, holding
+a candle, appeared from behind a rock! Tom lifted up a glorious shout,
+and instantly that hand was followed by the body it belonged to--Injun
+Joe's! Tom was paralyzed; he could not move. He was vastly gratified
+the next moment, to see the "Spaniard" take to his heels and get
+himself out of sight. Tom wondered that Joe had not recognized his
+voice and come over and killed him for testifying in court. But the
+echoes must have disguised the voice. Without doubt, that was it, he
+reasoned. Tom's fright weakened every muscle in his body. He said to
+himself that if he had strength enough to get back to the spring he
+would stay there, and nothing should tempt him to run the risk of
+meeting Injun Joe again. He was careful to keep from Becky what it was
+he had seen. He told her he had only shouted "for luck."
+
+But hunger and wretchedness rise superior to fears in the long run.
+Another tedious wait at the spring and another long sleep brought
+changes. The children awoke tortured with a raging hunger. Tom believed
+that it must be Wednesday or Thursday or even Friday or Saturday, now,
+and that the search had been given over. He proposed to explore another
+passage. He felt willing to risk Injun Joe and all other terrors. But
+Becky was very weak. She had sunk into a dreary apathy and would not be
+roused. She said she would wait, now, where she was, and die--it would
+not be long. She told Tom to go with the kite-line and explore if he
+chose; but she implored him to come back every little while and speak
+to her; and she made him promise that when the awful time came, he
+would stay by her and hold her hand until all was over.
+
+Tom kissed her, with a choking sensation in his throat, and made a
+show of being confident of finding the searchers or an escape from the
+cave; then he took the kite-line in his hand and went groping down one
+of the passages on his hands and knees, distressed with hunger and sick
+with bodings of coming doom.
+
+
+
+CHAPTER XXXII
+
+TUESDAY afternoon came, and waned to the twilight. The village of St.
+Petersburg still mourned. The lost children had not been found. Public
+prayers had been offered up for them, and many and many a private
+prayer that had the petitioner's whole heart in it; but still no good
+news came from the cave. The majority of the searchers had given up the
+quest and gone back to their daily avocations, saying that it was plain
+the children could never be found. Mrs. Thatcher was very ill, and a
+great part of the time delirious. People said it was heartbreaking to
+hear her call her child, and raise her head and listen a whole minute
+at a time, then lay it wearily down again with a moan. Aunt Polly had
+drooped into a settled melancholy, and her gray hair had grown almost
+white. The village went to its rest on Tuesday night, sad and forlorn.
+
+Away in the middle of the night a wild peal burst from the village
+bells, and in a moment the streets were swarming with frantic half-clad
+people, who shouted, "Turn out! turn out! they're found! they're
+found!" Tin pans and horns were added to the din, the population massed
+itself and moved toward the river, met the children coming in an open
+carriage drawn by shouting citizens, thronged around it, joined its
+homeward march, and swept magnificently up the main street roaring
+huzzah after huzzah!
+
+The village was illuminated; nobody went to bed again; it was the
+greatest night the little town had ever seen. During the first half-hour
+a procession of villagers filed through Judge Thatcher's house, seized
+the saved ones and kissed them, squeezed Mrs. Thatcher's hand, tried to
+speak but couldn't--and drifted out raining tears all over the place.
+
+Aunt Polly's happiness was complete, and Mrs. Thatcher's nearly so. It
+would be complete, however, as soon as the messenger dispatched with
+the great news to the cave should get the word to her husband. Tom lay
+upon a sofa with an eager auditory about him and told the history of
+the wonderful adventure, putting in many striking additions to adorn it
+withal; and closed with a description of how he left Becky and went on
+an exploring expedition; how he followed two avenues as far as his
+kite-line would reach; how he followed a third to the fullest stretch of
+the kite-line, and was about to turn back when he glimpsed a far-off
+speck that looked like daylight; dropped the line and groped toward it,
+pushed his head and shoulders through a small hole, and saw the broad
+Mississippi rolling by! And if it had only happened to be night he would
+not have seen that speck of daylight and would not have explored that
+passage any more! He told how he went back for Becky and broke the good
+news and she told him not to fret her with such stuff, for she was
+tired, and knew she was going to die, and wanted to. He described how he
+labored with her and convinced her; and how she almost died for joy when
+she had groped to where she actually saw the blue speck of daylight; how
+he pushed his way out at the hole and then helped her out; how they sat
+there and cried for gladness; how some men came along in a skiff and Tom
+hailed them and told them their situation and their famished condition;
+how the men didn't believe the wild tale at first, "because," said they,
+"you are five miles down the river below the valley the cave is in"
+--then took them aboard, rowed to a house, gave them supper, made them
+rest till two or three hours after dark and then brought them home.
+
+Before day-dawn, Judge Thatcher and the handful of searchers with him
+were tracked out, in the cave, by the twine clews they had strung
+behind them, and informed of the great news.
+
+Three days and nights of toil and hunger in the cave were not to be
+shaken off at once, as Tom and Becky soon discovered. They were
+bedridden all of Wednesday and Thursday, and seemed to grow more and
+more tired and worn, all the time. Tom got about, a little, on
+Thursday, was down-town Friday, and nearly as whole as ever Saturday;
+but Becky did not leave her room until Sunday, and then she looked as
+if she had passed through a wasting illness.
+
+Tom learned of Huck's sickness and went to see him on Friday, but
+could not be admitted to the bedroom; neither could he on Saturday or
+Sunday. He was admitted daily after that, but was warned to keep still
+about his adventure and introduce no exciting topic. The Widow Douglas
+stayed by to see that he obeyed. At home Tom learned of the Cardiff
+Hill event; also that the "ragged man's" body had eventually been found
+in the river near the ferry-landing; he had been drowned while trying
+to escape, perhaps.
+
+About a fortnight after Tom's rescue from the cave, he started off to
+visit Huck, who had grown plenty strong enough, now, to hear exciting
+talk, and Tom had some that would interest him, he thought. Judge
+Thatcher's house was on Tom's way, and he stopped to see Becky. The
+Judge and some friends set Tom to talking, and some one asked him
+ironically if he wouldn't like to go to the cave again. Tom said he
+thought he wouldn't mind it. The Judge said:
+
+"Well, there are others just like you, Tom, I've not the least doubt.
+But we have taken care of that. Nobody will get lost in that cave any
+more."
+
+"Why?"
+
+"Because I had its big door sheathed with boiler iron two weeks ago,
+and triple-locked--and I've got the keys."
+
+Tom turned as white as a sheet.
+
+"What's the matter, boy! Here, run, somebody! Fetch a glass of water!"
+
+The water was brought and thrown into Tom's face.
+
+"Ah, now you're all right. What was the matter with you, Tom?"
+
+"Oh, Judge, Injun Joe's in the cave!"
+
+
+
+CHAPTER XXXIII
+
+WITHIN a few minutes the news had spread, and a dozen skiff-loads of
+men were on their way to McDougal's cave, and the ferryboat, well
+filled with passengers, soon followed. Tom Sawyer was in the skiff that
+bore Judge Thatcher.
+
+When the cave door was unlocked, a sorrowful sight presented itself in
+the dim twilight of the place. Injun Joe lay stretched upon the ground,
+dead, with his face close to the crack of the door, as if his longing
+eyes had been fixed, to the latest moment, upon the light and the cheer
+of the free world outside. Tom was touched, for he knew by his own
+experience how this wretch had suffered. His pity was moved, but
+nevertheless he felt an abounding sense of relief and security, now,
+which revealed to him in a degree which he had not fully appreciated
+before how vast a weight of dread had been lying upon him since the day
+he lifted his voice against this bloody-minded outcast.
+
+Injun Joe's bowie-knife lay close by, its blade broken in two. The
+great foundation-beam of the door had been chipped and hacked through,
+with tedious labor; useless labor, too, it was, for the native rock
+formed a sill outside it, and upon that stubborn material the knife had
+wrought no effect; the only damage done was to the knife itself. But if
+there had been no stony obstruction there the labor would have been
+useless still, for if the beam had been wholly cut away Injun Joe could
+not have squeezed his body under the door, and he knew it. So he had
+only hacked that place in order to be doing something--in order to pass
+the weary time--in order to employ his tortured faculties. Ordinarily
+one could find half a dozen bits of candle stuck around in the crevices
+of this vestibule, left there by tourists; but there were none now. The
+prisoner had searched them out and eaten them. He had also contrived to
+catch a few bats, and these, also, he had eaten, leaving only their
+claws. The poor unfortunate had starved to death. In one place, near at
+hand, a stalagmite had been slowly growing up from the ground for ages,
+builded by the water-drip from a stalactite overhead. The captive had
+broken off the stalagmite, and upon the stump had placed a stone,
+wherein he had scooped a shallow hollow to catch the precious drop
+that fell once in every three minutes with the dreary regularity of a
+clock-tick--a dessertspoonful once in four and twenty hours. That drop
+was falling when the Pyramids were new; when Troy fell; when the
+foundations of Rome were laid; when Christ was crucified; when the
+Conqueror created the British empire; when Columbus sailed; when the
+massacre at Lexington was "news." It is falling now; it will still be
+falling when all these things shall have sunk down the afternoon of
+history, and the twilight of tradition, and been swallowed up in the
+thick night of oblivion. Has everything a purpose and a mission? Did
+this drop fall patiently during five thousand years to be ready for
+this flitting human insect's need? and has it another important object
+to accomplish ten thousand years to come? No matter. It is many and
+many a year since the hapless half-breed scooped out the stone to catch
+the priceless drops, but to this day the tourist stares longest at that
+pathetic stone and that slow-dropping water when he comes to see the
+wonders of McDougal's cave. Injun Joe's cup stands first in the list of
+the cavern's marvels; even "Aladdin's Palace" cannot rival it.
+
+Injun Joe was buried near the mouth of the cave; and people flocked
+there in boats and wagons from the towns and from all the farms and
+hamlets for seven miles around; they brought their children, and all
+sorts of provisions, and confessed that they had had almost as
+satisfactory a time at the funeral as they could have had at the
+hanging.
+
+This funeral stopped the further growth of one thing--the petition to
+the governor for Injun Joe's pardon. The petition had been largely
+signed; many tearful and eloquent meetings had been held, and a
+committee of sappy women been appointed to go in deep mourning and wail
+around the governor, and implore him to be a merciful ass and trample
+his duty under foot. Injun Joe was believed to have killed five
+citizens of the village, but what of that? If he had been Satan himself
+there would have been plenty of weaklings ready to scribble their names
+to a pardon-petition, and drip a tear on it from their permanently
+impaired and leaky water-works.
+
+The morning after the funeral Tom took Huck to a private place to have
+an important talk. Huck had learned all about Tom's adventure from the
+Welshman and the Widow Douglas, by this time, but Tom said he reckoned
+there was one thing they had not told him; that thing was what he
+wanted to talk about now. Huck's face saddened. He said:
+
+"I know what it is. You got into No. 2 and never found anything but
+whiskey. Nobody told me it was you; but I just knowed it must 'a' ben
+you, soon as I heard 'bout that whiskey business; and I knowed you
+hadn't got the money becuz you'd 'a' got at me some way or other and
+told me even if you was mum to everybody else. Tom, something's always
+told me we'd never get holt of that swag."
+
+"Why, Huck, I never told on that tavern-keeper. YOU know his tavern
+was all right the Saturday I went to the picnic. Don't you remember you
+was to watch there that night?"
+
+"Oh yes! Why, it seems 'bout a year ago. It was that very night that I
+follered Injun Joe to the widder's."
+
+"YOU followed him?"
+
+"Yes--but you keep mum. I reckon Injun Joe's left friends behind him,
+and I don't want 'em souring on me and doing me mean tricks. If it
+hadn't ben for me he'd be down in Texas now, all right."
+
+Then Huck told his entire adventure in confidence to Tom, who had only
+heard of the Welshman's part of it before.
+
+"Well," said Huck, presently, coming back to the main question,
+"whoever nipped the whiskey in No. 2, nipped the money, too, I reckon
+--anyways it's a goner for us, Tom."
+
+"Huck, that money wasn't ever in No. 2!"
+
+"What!" Huck searched his comrade's face keenly. "Tom, have you got on
+the track of that money again?"
+
+"Huck, it's in the cave!"
+
+Huck's eyes blazed.
+
+"Say it again, Tom."
+
+"The money's in the cave!"
+
+"Tom--honest injun, now--is it fun, or earnest?"
+
+"Earnest, Huck--just as earnest as ever I was in my life. Will you go
+in there with me and help get it out?"
+
+"I bet I will! I will if it's where we can blaze our way to it and not
+get lost."
+
+"Huck, we can do that without the least little bit of trouble in the
+world."
+
+"Good as wheat! What makes you think the money's--"
+
+"Huck, you just wait till we get in there. If we don't find it I'll
+agree to give you my drum and every thing I've got in the world. I
+will, by jings."
+
+"All right--it's a whiz. When do you say?"
+
+"Right now, if you say it. Are you strong enough?"
+
+"Is it far in the cave? I ben on my pins a little, three or four days,
+now, but I can't walk more'n a mile, Tom--least I don't think I could."
+
+"It's about five mile into there the way anybody but me would go,
+Huck, but there's a mighty short cut that they don't anybody but me
+know about. Huck, I'll take you right to it in a skiff. I'll float the
+skiff down there, and I'll pull it back again all by myself. You
+needn't ever turn your hand over."
+
+"Less start right off, Tom."
+
+"All right. We want some bread and meat, and our pipes, and a little
+bag or two, and two or three kite-strings, and some of these
+new-fangled things they call lucifer matches. I tell you, many's
+the time I wished I had some when I was in there before."
+
+A trifle after noon the boys borrowed a small skiff from a citizen who
+was absent, and got under way at once. When they were several miles
+below "Cave Hollow," Tom said:
+
+"Now you see this bluff here looks all alike all the way down from the
+cave hollow--no houses, no wood-yards, bushes all alike. But do you see
+that white place up yonder where there's been a landslide? Well, that's
+one of my marks. We'll get ashore, now."
+
+They landed.
+
+"Now, Huck, where we're a-standing you could touch that hole I got out
+of with a fishing-pole. See if you can find it."
+
+Huck searched all the place about, and found nothing. Tom proudly
+marched into a thick clump of sumach bushes and said:
+
+"Here you are! Look at it, Huck; it's the snuggest hole in this
+country. You just keep mum about it. All along I've been wanting to be
+a robber, but I knew I'd got to have a thing like this, and where to
+run across it was the bother. We've got it now, and we'll keep it
+quiet, only we'll let Joe Harper and Ben Rogers in--because of course
+there's got to be a Gang, or else there wouldn't be any style about it.
+Tom Sawyer's Gang--it sounds splendid, don't it, Huck?"
+
+"Well, it just does, Tom. And who'll we rob?"
+
+"Oh, most anybody. Waylay people--that's mostly the way."
+
+"And kill them?"
+
+"No, not always. Hive them in the cave till they raise a ransom."
+
+"What's a ransom?"
+
+"Money. You make them raise all they can, off'n their friends; and
+after you've kept them a year, if it ain't raised then you kill them.
+That's the general way. Only you don't kill the women. You shut up the
+women, but you don't kill them. They're always beautiful and rich, and
+awfully scared. You take their watches and things, but you always take
+your hat off and talk polite. They ain't anybody as polite as robbers
+--you'll see that in any book. Well, the women get to loving you, and
+after they've been in the cave a week or two weeks they stop crying and
+after that you couldn't get them to leave. If you drove them out they'd
+turn right around and come back. It's so in all the books."
+
+"Why, it's real bully, Tom. I believe it's better'n to be a pirate."
+
+"Yes, it's better in some ways, because it's close to home and
+circuses and all that."
+
+By this time everything was ready and the boys entered the hole, Tom
+in the lead. They toiled their way to the farther end of the tunnel,
+then made their spliced kite-strings fast and moved on. A few steps
+brought them to the spring, and Tom felt a shudder quiver all through
+him. He showed Huck the fragment of candle-wick perched on a lump of
+clay against the wall, and described how he and Becky had watched the
+flame struggle and expire.
+
+The boys began to quiet down to whispers, now, for the stillness and
+gloom of the place oppressed their spirits. They went on, and presently
+entered and followed Tom's other corridor until they reached the
+"jumping-off place." The candles revealed the fact that it was not
+really a precipice, but only a steep clay hill twenty or thirty feet
+high. Tom whispered:
+
+"Now I'll show you something, Huck."
+
+He held his candle aloft and said:
+
+"Look as far around the corner as you can. Do you see that? There--on
+the big rock over yonder--done with candle-smoke."
+
+"Tom, it's a CROSS!"
+
+"NOW where's your Number Two? 'UNDER THE CROSS,' hey? Right yonder's
+where I saw Injun Joe poke up his candle, Huck!"
+
+Huck stared at the mystic sign awhile, and then said with a shaky voice:
+
+"Tom, less git out of here!"
+
+"What! and leave the treasure?"
+
+"Yes--leave it. Injun Joe's ghost is round about there, certain."
+
+"No it ain't, Huck, no it ain't. It would ha'nt the place where he
+died--away out at the mouth of the cave--five mile from here."
+
+"No, Tom, it wouldn't. It would hang round the money. I know the ways
+of ghosts, and so do you."
+
+Tom began to fear that Huck was right. Misgivings gathered in his
+mind. But presently an idea occurred to him--
+
+"Lookyhere, Huck, what fools we're making of ourselves! Injun Joe's
+ghost ain't a going to come around where there's a cross!"
+
+The point was well taken. It had its effect.
+
+"Tom, I didn't think of that. But that's so. It's luck for us, that
+cross is. I reckon we'll climb down there and have a hunt for that box."
+
+Tom went first, cutting rude steps in the clay hill as he descended.
+Huck followed. Four avenues opened out of the small cavern which the
+great rock stood in. The boys examined three of them with no result.
+They found a small recess in the one nearest the base of the rock, with
+a pallet of blankets spread down in it; also an old suspender, some
+bacon rind, and the well-gnawed bones of two or three fowls. But there
+was no money-box. The lads searched and researched this place, but in
+vain. Tom said:
+
+"He said UNDER the cross. Well, this comes nearest to being under the
+cross. It can't be under the rock itself, because that sets solid on
+the ground."
+
+They searched everywhere once more, and then sat down discouraged.
+Huck could suggest nothing. By-and-by Tom said:
+
+"Lookyhere, Huck, there's footprints and some candle-grease on the
+clay about one side of this rock, but not on the other sides. Now,
+what's that for? I bet you the money IS under the rock. I'm going to
+dig in the clay."
+
+"That ain't no bad notion, Tom!" said Huck with animation.
+
+Tom's "real Barlow" was out at once, and he had not dug four inches
+before he struck wood.
+
+"Hey, Huck!--you hear that?"
+
+Huck began to dig and scratch now. Some boards were soon uncovered and
+removed. They had concealed a natural chasm which led under the rock.
+Tom got into this and held his candle as far under the rock as he
+could, but said he could not see to the end of the rift. He proposed to
+explore. He stooped and passed under; the narrow way descended
+gradually. He followed its winding course, first to the right, then to
+the left, Huck at his heels. Tom turned a short curve, by-and-by, and
+exclaimed:
+
+"My goodness, Huck, lookyhere!"
+
+It was the treasure-box, sure enough, occupying a snug little cavern,
+along with an empty powder-keg, a couple of guns in leather cases, two
+or three pairs of old moccasins, a leather belt, and some other rubbish
+well soaked with the water-drip.
+
+"Got it at last!" said Huck, ploughing among the tarnished coins with
+his hand. "My, but we're rich, Tom!"
+
+"Huck, I always reckoned we'd get it. It's just too good to believe,
+but we HAVE got it, sure! Say--let's not fool around here. Let's snake
+it out. Lemme see if I can lift the box."
+
+It weighed about fifty pounds. Tom could lift it, after an awkward
+fashion, but could not carry it conveniently.
+
+"I thought so," he said; "THEY carried it like it was heavy, that day
+at the ha'nted house. I noticed that. I reckon I was right to think of
+fetching the little bags along."
+
+The money was soon in the bags and the boys took it up to the cross
+rock.
+
+"Now less fetch the guns and things," said Huck.
+
+"No, Huck--leave them there. They're just the tricks to have when we
+go to robbing. We'll keep them there all the time, and we'll hold our
+orgies there, too. It's an awful snug place for orgies."
+
+"What orgies?"
+
+"I dono. But robbers always have orgies, and of course we've got to
+have them, too. Come along, Huck, we've been in here a long time. It's
+getting late, I reckon. I'm hungry, too. We'll eat and smoke when we
+get to the skiff."
+
+They presently emerged into the clump of sumach bushes, looked warily
+out, found the coast clear, and were soon lunching and smoking in the
+skiff. As the sun dipped toward the horizon they pushed out and got
+under way. Tom skimmed up the shore through the long twilight, chatting
+cheerily with Huck, and landed shortly after dark.
+
+"Now, Huck," said Tom, "we'll hide the money in the loft of the
+widow's woodshed, and I'll come up in the morning and we'll count it
+and divide, and then we'll hunt up a place out in the woods for it
+where it will be safe. Just you lay quiet here and watch the stuff till
+I run and hook Benny Taylor's little wagon; I won't be gone a minute."
+
+He disappeared, and presently returned with the wagon, put the two
+small sacks into it, threw some old rags on top of them, and started
+off, dragging his cargo behind him. When the boys reached the
+Welshman's house, they stopped to rest. Just as they were about to move
+on, the Welshman stepped out and said:
+
+"Hallo, who's that?"
+
+"Huck and Tom Sawyer."
+
+"Good! Come along with me, boys, you are keeping everybody waiting.
+Here--hurry up, trot ahead--I'll haul the wagon for you. Why, it's not
+as light as it might be. Got bricks in it?--or old metal?"
+
+"Old metal," said Tom.
+
+"I judged so; the boys in this town will take more trouble and fool
+away more time hunting up six bits' worth of old iron to sell to the
+foundry than they would to make twice the money at regular work. But
+that's human nature--hurry along, hurry along!"
+
+The boys wanted to know what the hurry was about.
+
+"Never mind; you'll see, when we get to the Widow Douglas'."
+
+Huck said with some apprehension--for he was long used to being
+falsely accused:
+
+"Mr. Jones, we haven't been doing nothing."
+
+The Welshman laughed.
+
+"Well, I don't know, Huck, my boy. I don't know about that. Ain't you
+and the widow good friends?"
+
+"Yes. Well, she's ben good friends to me, anyway."
+
+"All right, then. What do you want to be afraid for?"
+
+This question was not entirely answered in Huck's slow mind before he
+found himself pushed, along with Tom, into Mrs. Douglas' drawing-room.
+Mr. Jones left the wagon near the door and followed.
+
+The place was grandly lighted, and everybody that was of any
+consequence in the village was there. The Thatchers were there, the
+Harpers, the Rogerses, Aunt Polly, Sid, Mary, the minister, the editor,
+and a great many more, and all dressed in their best. The widow
+received the boys as heartily as any one could well receive two such
+looking beings. They were covered with clay and candle-grease. Aunt
+Polly blushed crimson with humiliation, and frowned and shook her head
+at Tom. Nobody suffered half as much as the two boys did, however. Mr.
+Jones said:
+
+"Tom wasn't at home, yet, so I gave him up; but I stumbled on him and
+Huck right at my door, and so I just brought them along in a hurry."
+
+"And you did just right," said the widow. "Come with me, boys."
+
+She took them to a bedchamber and said:
+
+"Now wash and dress yourselves. Here are two new suits of clothes
+--shirts, socks, everything complete. They're Huck's--no, no thanks,
+Huck--Mr. Jones bought one and I the other. But they'll fit both of you.
+Get into them. We'll wait--come down when you are slicked up enough."
+
+Then she left.
+
+
+
+CHAPTER XXXIV
+
+HUCK said: "Tom, we can slope, if we can find a rope. The window ain't
+high from the ground."
+
+"Shucks! what do you want to slope for?"
+
+"Well, I ain't used to that kind of a crowd. I can't stand it. I ain't
+going down there, Tom."
+
+"Oh, bother! It ain't anything. I don't mind it a bit. I'll take care
+of you."
+
+Sid appeared.
+
+"Tom," said he, "auntie has been waiting for you all the afternoon.
+Mary got your Sunday clothes ready, and everybody's been fretting about
+you. Say--ain't this grease and clay, on your clothes?"
+
+"Now, Mr. Siddy, you jist 'tend to your own business. What's all this
+blow-out about, anyway?"
+
+"It's one of the widow's parties that she's always having. This time
+it's for the Welshman and his sons, on account of that scrape they
+helped her out of the other night. And say--I can tell you something,
+if you want to know."
+
+"Well, what?"
+
+"Why, old Mr. Jones is going to try to spring something on the people
+here to-night, but I overheard him tell auntie to-day about it, as a
+secret, but I reckon it's not much of a secret now. Everybody knows
+--the widow, too, for all she tries to let on she don't. Mr. Jones was
+bound Huck should be here--couldn't get along with his grand secret
+without Huck, you know!"
+
+"Secret about what, Sid?"
+
+"About Huck tracking the robbers to the widow's. I reckon Mr. Jones
+was going to make a grand time over his surprise, but I bet you it will
+drop pretty flat."
+
+Sid chuckled in a very contented and satisfied way.
+
+"Sid, was it you that told?"
+
+"Oh, never mind who it was. SOMEBODY told--that's enough."
+
+"Sid, there's only one person in this town mean enough to do that, and
+that's you. If you had been in Huck's place you'd 'a' sneaked down the
+hill and never told anybody on the robbers. You can't do any but mean
+things, and you can't bear to see anybody praised for doing good ones.
+There--no thanks, as the widow says"--and Tom cuffed Sid's ears and
+helped him to the door with several kicks. "Now go and tell auntie if
+you dare--and to-morrow you'll catch it!"
+
+Some minutes later the widow's guests were at the supper-table, and a
+dozen children were propped up at little side-tables in the same room,
+after the fashion of that country and that day. At the proper time Mr.
+Jones made his little speech, in which he thanked the widow for the
+honor she was doing himself and his sons, but said that there was
+another person whose modesty--
+
+And so forth and so on. He sprung his secret about Huck's share in the
+adventure in the finest dramatic manner he was master of, but the
+surprise it occasioned was largely counterfeit and not as clamorous and
+effusive as it might have been under happier circumstances. However,
+the widow made a pretty fair show of astonishment, and heaped so many
+compliments and so much gratitude upon Huck that he almost forgot the
+nearly intolerable discomfort of his new clothes in the entirely
+intolerable discomfort of being set up as a target for everybody's gaze
+and everybody's laudations.
+
+The widow said she meant to give Huck a home under her roof and have
+him educated; and that when she could spare the money she would start
+him in business in a modest way. Tom's chance was come. He said:
+
+"Huck don't need it. Huck's rich."
+
+Nothing but a heavy strain upon the good manners of the company kept
+back the due and proper complimentary laugh at this pleasant joke. But
+the silence was a little awkward. Tom broke it:
+
+"Huck's got money. Maybe you don't believe it, but he's got lots of
+it. Oh, you needn't smile--I reckon I can show you. You just wait a
+minute."
+
+Tom ran out of doors. The company looked at each other with a
+perplexed interest--and inquiringly at Huck, who was tongue-tied.
+
+"Sid, what ails Tom?" said Aunt Polly. "He--well, there ain't ever any
+making of that boy out. I never--"
+
+Tom entered, struggling with the weight of his sacks, and Aunt Polly
+did not finish her sentence. Tom poured the mass of yellow coin upon
+the table and said:
+
+"There--what did I tell you? Half of it's Huck's and half of it's mine!"
+
+The spectacle took the general breath away. All gazed, nobody spoke
+for a moment. Then there was a unanimous call for an explanation. Tom
+said he could furnish it, and he did. The tale was long, but brimful of
+interest. There was scarcely an interruption from any one to break the
+charm of its flow. When he had finished, Mr. Jones said:
+
+"I thought I had fixed up a little surprise for this occasion, but it
+don't amount to anything now. This one makes it sing mighty small, I'm
+willing to allow."
+
+The money was counted. The sum amounted to a little over twelve
+thousand dollars. It was more than any one present had ever seen at one
+time before, though several persons were there who were worth
+considerably more than that in property.
+
+
+
+CHAPTER XXXV
+
+THE reader may rest satisfied that Tom's and Huck's windfall made a
+mighty stir in the poor little village of St. Petersburg. So vast a
+sum, all in actual cash, seemed next to incredible. It was talked
+about, gloated over, glorified, until the reason of many of the
+citizens tottered under the strain of the unhealthy excitement. Every
+"haunted" house in St. Petersburg and the neighboring villages was
+dissected, plank by plank, and its foundations dug up and ransacked for
+hidden treasure--and not by boys, but men--pretty grave, unromantic
+men, too, some of them. Wherever Tom and Huck appeared they were
+courted, admired, stared at. The boys were not able to remember that
+their remarks had possessed weight before; but now their sayings were
+treasured and repeated; everything they did seemed somehow to be
+regarded as remarkable; they had evidently lost the power of doing and
+saying commonplace things; moreover, their past history was raked up
+and discovered to bear marks of conspicuous originality. The village
+paper published biographical sketches of the boys.
+
+The Widow Douglas put Huck's money out at six per cent., and Judge
+Thatcher did the same with Tom's at Aunt Polly's request. Each lad had
+an income, now, that was simply prodigious--a dollar for every week-day
+in the year and half of the Sundays. It was just what the minister got
+--no, it was what he was promised--he generally couldn't collect it. A
+dollar and a quarter a week would board, lodge, and school a boy in
+those old simple days--and clothe him and wash him, too, for that
+matter.
+
+Judge Thatcher had conceived a great opinion of Tom. He said that no
+commonplace boy would ever have got his daughter out of the cave. When
+Becky told her father, in strict confidence, how Tom had taken her
+whipping at school, the Judge was visibly moved; and when she pleaded
+grace for the mighty lie which Tom had told in order to shift that
+whipping from her shoulders to his own, the Judge said with a fine
+outburst that it was a noble, a generous, a magnanimous lie--a lie that
+was worthy to hold up its head and march down through history breast to
+breast with George Washington's lauded Truth about the hatchet! Becky
+thought her father had never looked so tall and so superb as when he
+walked the floor and stamped his foot and said that. She went straight
+off and told Tom about it.
+
+Judge Thatcher hoped to see Tom a great lawyer or a great soldier some
+day. He said he meant to look to it that Tom should be admitted to the
+National Military Academy and afterward trained in the best law school
+in the country, in order that he might be ready for either career or
+both.
+
+Huck Finn's wealth and the fact that he was now under the Widow
+Douglas' protection introduced him into society--no, dragged him into
+it, hurled him into it--and his sufferings were almost more than he
+could bear. The widow's servants kept him clean and neat, combed and
+brushed, and they bedded him nightly in unsympathetic sheets that had
+not one little spot or stain which he could press to his heart and know
+for a friend. He had to eat with a knife and fork; he had to use
+napkin, cup, and plate; he had to learn his book, he had to go to
+church; he had to talk so properly that speech was become insipid in
+his mouth; whithersoever he turned, the bars and shackles of
+civilization shut him in and bound him hand and foot.
+
+He bravely bore his miseries three weeks, and then one day turned up
+missing. For forty-eight hours the widow hunted for him everywhere in
+great distress. The public were profoundly concerned; they searched
+high and low, they dragged the river for his body. Early the third
+morning Tom Sawyer wisely went poking among some old empty hogsheads
+down behind the abandoned slaughter-house, and in one of them he found
+the refugee. Huck had slept there; he had just breakfasted upon some
+stolen odds and ends of food, and was lying off, now, in comfort, with
+his pipe. He was unkempt, uncombed, and clad in the same old ruin of
+rags that had made him picturesque in the days when he was free and
+happy. Tom routed him out, told him the trouble he had been causing,
+and urged him to go home. Huck's face lost its tranquil content, and
+took a melancholy cast. He said:
+
+"Don't talk about it, Tom. I've tried it, and it don't work; it don't
+work, Tom. It ain't for me; I ain't used to it. The widder's good to
+me, and friendly; but I can't stand them ways. She makes me get up just
+at the same time every morning; she makes me wash, they comb me all to
+thunder; she won't let me sleep in the woodshed; I got to wear them
+blamed clothes that just smothers me, Tom; they don't seem to any air
+git through 'em, somehow; and they're so rotten nice that I can't set
+down, nor lay down, nor roll around anywher's; I hain't slid on a
+cellar-door for--well, it 'pears to be years; I got to go to church and
+sweat and sweat--I hate them ornery sermons! I can't ketch a fly in
+there, I can't chaw. I got to wear shoes all Sunday. The widder eats by
+a bell; she goes to bed by a bell; she gits up by a bell--everything's
+so awful reg'lar a body can't stand it."
+
+"Well, everybody does that way, Huck."
+
+"Tom, it don't make no difference. I ain't everybody, and I can't
+STAND it. It's awful to be tied up so. And grub comes too easy--I don't
+take no interest in vittles, that way. I got to ask to go a-fishing; I
+got to ask to go in a-swimming--dern'd if I hain't got to ask to do
+everything. Well, I'd got to talk so nice it wasn't no comfort--I'd got
+to go up in the attic and rip out awhile, every day, to git a taste in
+my mouth, or I'd a died, Tom. The widder wouldn't let me smoke; she
+wouldn't let me yell, she wouldn't let me gape, nor stretch, nor
+scratch, before folks--" [Then with a spasm of special irritation and
+injury]--"And dad fetch it, she prayed all the time! I never see such a
+woman! I HAD to shove, Tom--I just had to. And besides, that school's
+going to open, and I'd a had to go to it--well, I wouldn't stand THAT,
+Tom. Looky here, Tom, being rich ain't what it's cracked up to be. It's
+just worry and worry, and sweat and sweat, and a-wishing you was dead
+all the time. Now these clothes suits me, and this bar'l suits me, and
+I ain't ever going to shake 'em any more. Tom, I wouldn't ever got into
+all this trouble if it hadn't 'a' ben for that money; now you just take
+my sheer of it along with your'n, and gimme a ten-center sometimes--not
+many times, becuz I don't give a dern for a thing 'thout it's tollable
+hard to git--and you go and beg off for me with the widder."
+
+"Oh, Huck, you know I can't do that. 'Tain't fair; and besides if
+you'll try this thing just a while longer you'll come to like it."
+
+"Like it! Yes--the way I'd like a hot stove if I was to set on it long
+enough. No, Tom, I won't be rich, and I won't live in them cussed
+smothery houses. I like the woods, and the river, and hogsheads, and
+I'll stick to 'em, too. Blame it all! just as we'd got guns, and a
+cave, and all just fixed to rob, here this dern foolishness has got to
+come up and spile it all!"
+
+Tom saw his opportunity--
+
+"Lookyhere, Huck, being rich ain't going to keep me back from turning
+robber."
+
+"No! Oh, good-licks; are you in real dead-wood earnest, Tom?"
+
+"Just as dead earnest as I'm sitting here. But Huck, we can't let you
+into the gang if you ain't respectable, you know."
+
+Huck's joy was quenched.
+
+"Can't let me in, Tom? Didn't you let me go for a pirate?"
+
+"Yes, but that's different. A robber is more high-toned than what a
+pirate is--as a general thing. In most countries they're awful high up
+in the nobility--dukes and such."
+
+"Now, Tom, hain't you always ben friendly to me? You wouldn't shet me
+out, would you, Tom? You wouldn't do that, now, WOULD you, Tom?"
+
+"Huck, I wouldn't want to, and I DON'T want to--but what would people
+say? Why, they'd say, 'Mph! Tom Sawyer's Gang! pretty low characters in
+it!' They'd mean you, Huck. You wouldn't like that, and I wouldn't."
+
+Huck was silent for some time, engaged in a mental struggle. Finally
+he said:
+
+"Well, I'll go back to the widder for a month and tackle it and see if
+I can come to stand it, if you'll let me b'long to the gang, Tom."
+
+"All right, Huck, it's a whiz! Come along, old chap, and I'll ask the
+widow to let up on you a little, Huck."
+
+"Will you, Tom--now will you? That's good. If she'll let up on some of
+the roughest things, I'll smoke private and cuss private, and crowd
+through or bust. When you going to start the gang and turn robbers?"
+
+"Oh, right off. We'll get the boys together and have the initiation
+to-night, maybe."
+
+"Have the which?"
+
+"Have the initiation."
+
+"What's that?"
+
+"It's to swear to stand by one another, and never tell the gang's
+secrets, even if you're chopped all to flinders, and kill anybody and
+all his family that hurts one of the gang."
+
+"That's gay--that's mighty gay, Tom, I tell you."
+
+"Well, I bet it is. And all that swearing's got to be done at
+midnight, in the lonesomest, awfulest place you can find--a ha'nted
+house is the best, but they're all ripped up now."
+
+"Well, midnight's good, anyway, Tom."
+
+"Yes, so it is. And you've got to swear on a coffin, and sign it with
+blood."
+
+"Now, that's something LIKE! Why, it's a million times bullier than
+pirating. I'll stick to the widder till I rot, Tom; and if I git to be
+a reg'lar ripper of a robber, and everybody talking 'bout it, I reckon
+she'll be proud she snaked me in out of the wet."
+
+
+
+CONCLUSION
+
+SO endeth this chronicle. It being strictly a history of a BOY, it
+must stop here; the story could not go much further without becoming
+the history of a MAN. When one writes a novel about grown people, he
+knows exactly where to stop--that is, with a marriage; but when he
+writes of juveniles, he must stop where he best can.
+
+Most of the characters that perform in this book still live, and are
+prosperous and happy. Some day it may seem worth while to take up the
+story of the younger ones again and see what sort of men and women they
+turned out to be; therefore it will be wisest not to reveal any of that
+part of their lives at present.
+
+
+
+
+
+End of the Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete
+by Mark Twain (Samuel Clemens)
+
+*** END OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***
+
+***** This file should be named 74.txt or 74.zip *****
+This and all associated files of various formats will be found in:
+ http://www.gutenberg.net/7/74/
+
+Produced by David Widger. The previous edition was update by Jose
+Menendez.
+
+
+Updated editions will replace the previous one--the old editions
+will be renamed.
+
+Creating the works from public domain print editions means that no
+one owns a United States copyright in these works, so the Foundation
+(and you!) can copy and distribute it in the United States without
+permission and without paying copyright royalties. Special rules,
+set forth in the General Terms of Use part of this license, apply to
+copying and distributing Project Gutenberg-tm electronic works to
+protect the PROJECT GUTENBERG-tm concept and trademark. Project
+Gutenberg is a registered trademark, and may not be used if you
+charge for the eBooks, unless you receive specific permission. If you
+do not charge anything for copies of this eBook, complying with the
+rules is very easy. You may use this eBook for nearly any purpose
+such as creation of derivative works, reports, performances and
+research. They may be modified and printed and given away--you may do
+practically ANYTHING with public domain eBooks. Redistribution is
+subject to the trademark license, especially commercial
+redistribution.
+
+
+
+*** START: FULL LICENSE ***
+
+THE FULL PROJECT GUTENBERG LICENSE
+PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
+
+To protect the Project Gutenberg-tm mission of promoting the free
+distribution of electronic works, by using or distributing this work
+(or any other work associated in any way with the phrase "Project
+Gutenberg"), you agree to comply with all the terms of the Full Project
+Gutenberg-tm License (available with this file or online at
+http://gutenberg.net/license).
+
+
+Section 1. General Terms of Use and Redistributing Project Gutenberg-tm
+electronic works
+
+1.A. By reading or using any part of this Project Gutenberg-tm
+electronic work, you indicate that you have read, understand, agree to
+and accept all the terms of this license and intellectual property
+(trademark/copyright) agreement. If you do not agree to abide by all
+the terms of this agreement, you must cease using and return or destroy
+all copies of Project Gutenberg-tm electronic works in your possession.
+If you paid a fee for obtaining a copy of or access to a Project
+Gutenberg-tm electronic work and you do not agree to be bound by the
+terms of this agreement, you may obtain a refund from the person or
+entity to whom you paid the fee as set forth in paragraph 1.E.8.
+
+1.B. "Project Gutenberg" is a registered trademark. It may only be
+used on or associated in any way with an electronic work by people who
+agree to be bound by the terms of this agreement. There are a few
+things that you can do with most Project Gutenberg-tm electronic works
+even without complying with the full terms of this agreement. See
+paragraph 1.C below. There are a lot of things you can do with Project
+Gutenberg-tm electronic works if you follow the terms of this agreement
+and help preserve free future access to Project Gutenberg-tm electronic
+works. See paragraph 1.E below.
+
+1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation"
+or PGLAF), owns a compilation copyright in the collection of Project
+Gutenberg-tm electronic works. Nearly all the individual works in the
+collection are in the public domain in the United States. If an
+individual work is in the public domain in the United States and you are
+located in the United States, we do not claim a right to prevent you from
+copying, distributing, performing, displaying or creating derivative
+works based on the work as long as all references to Project Gutenberg
+are removed. Of course, we hope that you will support the Project
+Gutenberg-tm mission of promoting free access to electronic works by
+freely sharing Project Gutenberg-tm works in compliance with the terms of
+this agreement for keeping the Project Gutenberg-tm name associated with
+the work. You can easily comply with the terms of this agreement by
+keeping this work in the same format with its attached full Project
+Gutenberg-tm License when you share it without charge with others.
+
+1.D. The copyright laws of the place where you are located also govern
+what you can do with this work. Copyright laws in most countries are in
+a constant state of change. If you are outside the United States, check
+the laws of your country in addition to the terms of this agreement
+before downloading, copying, displaying, performing, distributing or
+creating derivative works based on this work or any other Project
+Gutenberg-tm work. The Foundation makes no representations concerning
+the copyright status of any work in any country outside the United
+States.
+
+1.E. Unless you have removed all references to Project Gutenberg:
+
+1.E.1. The following sentence, with active links to, or other immediate
+access to, the full Project Gutenberg-tm License must appear prominently
+whenever any copy of a Project Gutenberg-tm work (any work on which the
+phrase "Project Gutenberg" appears, or with which the phrase "Project
+Gutenberg" is associated) is accessed, displayed, performed, viewed,
+copied or distributed:
+
+This eBook is for the use of anyone anywhere at no cost and with
+almost no restrictions whatsoever. You may copy it, give it away or
+re-use it under the terms of the Project Gutenberg License included
+with this eBook or online at www.gutenberg.net
+
+1.E.2. If an individual Project Gutenberg-tm electronic work is derived
+from the public domain (does not contain a notice indicating that it is
+posted with permission of the copyright holder), the work can be copied
+and distributed to anyone in the United States without paying any fees
+or charges. If you are redistributing or providing access to a work
+with the phrase "Project Gutenberg" associated with or appearing on the
+work, you must comply either with the requirements of paragraphs 1.E.1
+through 1.E.7 or obtain permission for the use of the work and the
+Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or
+1.E.9.
+
+1.E.3. If an individual Project Gutenberg-tm electronic work is posted
+with the permission of the copyright holder, your use and distribution
+must comply with both paragraphs 1.E.1 through 1.E.7 and any additional
+terms imposed by the copyright holder. Additional terms will be linked
+to the Project Gutenberg-tm License for all works posted with the
+permission of the copyright holder found at the beginning of this work.
+
+1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm
+License terms from this work, or any files containing a part of this
+work or any other work associated with Project Gutenberg-tm.
+
+1.E.5. Do not copy, display, perform, distribute or redistribute this
+electronic work, or any part of this electronic work, without
+prominently displaying the sentence set forth in paragraph 1.E.1 with
+active links or immediate access to the full terms of the Project
+Gutenberg-tm License.
+
+1.E.6. You may convert to and distribute this work in any binary,
+compressed, marked up, nonproprietary or proprietary form, including any
+word processing or hypertext form. However, if you provide access to or
+distribute copies of a Project Gutenberg-tm work in a format other than
+"Plain Vanilla ASCII" or other format used in the official version
+posted on the official Project Gutenberg-tm web site (www.gutenberg.net),
+you must, at no additional cost, fee or expense to the user, provide a
+copy, a means of exporting a copy, or a means of obtaining a copy upon
+request, of the work in its original "Plain Vanilla ASCII" or other
+form. Any alternate format must include the full Project Gutenberg-tm
+License as specified in paragraph 1.E.1.
+
+1.E.7. Do not charge a fee for access to, viewing, displaying,
+performing, copying or distributing any Project Gutenberg-tm works
+unless you comply with paragraph 1.E.8 or 1.E.9.
+
+1.E.8. You may charge a reasonable fee for copies of or providing
+access to or distributing Project Gutenberg-tm electronic works provided
+that
+
+- You pay a royalty fee of 20% of the gross profits you derive from
+ the use of Project Gutenberg-tm works calculated using the method
+ you already use to calculate your applicable taxes. The fee is
+ owed to the owner of the Project Gutenberg-tm trademark, but he
+ has agreed to donate royalties under this paragraph to the
+ Project Gutenberg Literary Archive Foundation. Royalty payments
+ must be paid within 60 days following each date on which you
+ prepare (or are legally required to prepare) your periodic tax
+ returns. Royalty payments should be clearly marked as such and
+ sent to the Project Gutenberg Literary Archive Foundation at the
+ address specified in Section 4, "Information about donations to
+ the Project Gutenberg Literary Archive Foundation."
+
+- You provide a full refund of any money paid by a user who notifies
+ you in writing (or by e-mail) within 30 days of receipt that s/he
+ does not agree to the terms of the full Project Gutenberg-tm
+ License. You must require such a user to return or
+ destroy all copies of the works possessed in a physical medium
+ and discontinue all use of and all access to other copies of
+ Project Gutenberg-tm works.
+
+- You provide, in accordance with paragraph 1.F.3, a full refund of any
+ money paid for a work or a replacement copy, if a defect in the
+ electronic work is discovered and reported to you within 90 days
+ of receipt of the work.
+
+- You comply with all other terms of this agreement for free
+ distribution of Project Gutenberg-tm works.
+
+1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm
+electronic work or group of works on different terms than are set
+forth in this agreement, you must obtain permission in writing from
+both the Project Gutenberg Literary Archive Foundation and Michael
+Hart, the owner of the Project Gutenberg-tm trademark. Contact the
+Foundation as set forth in Section 3 below.
+
+1.F.
+
+1.F.1. Project Gutenberg volunteers and employees expend considerable
+effort to identify, do copyright research on, transcribe and proofread
+public domain works in creating the Project Gutenberg-tm
+collection. Despite these efforts, Project Gutenberg-tm electronic
+works, and the medium on which they may be stored, may contain
+"Defects," such as, but not limited to, incomplete, inaccurate or
+corrupt data, transcription errors, a copyright or other intellectual
+property infringement, a defective or damaged disk or other medium, a
+computer virus, or computer codes that damage or cannot be read by
+your equipment.
+
+1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right
+of Replacement or Refund" described in paragraph 1.F.3, the Project
+Gutenberg Literary Archive Foundation, the owner of the Project
+Gutenberg-tm trademark, and any other party distributing a Project
+Gutenberg-tm electronic work under this agreement, disclaim all
+liability to you for damages, costs and expenses, including legal
+fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT
+LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE
+PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE
+TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE
+LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
+INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a
+defect in this electronic work within 90 days of receiving it, you can
+receive a refund of the money (if any) you paid for it by sending a
+written explanation to the person you received the work from. If you
+received the work on a physical medium, you must return the medium with
+your written explanation. The person or entity that provided you with
+the defective work may elect to provide a replacement copy in lieu of a
+refund. If you received the work electronically, the person or entity
+providing it to you may choose to give you a second opportunity to
+receive the work electronically in lieu of a refund. If the second copy
+is also defective, you may demand a refund in writing without further
+opportunities to fix the problem.
+
+1.F.4. Except for the limited right of replacement or refund set forth
+in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER
+WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE.
+
+1.F.5. Some states do not allow disclaimers of certain implied
+warranties or the exclusion or limitation of certain types of damages.
+If any disclaimer or limitation set forth in this agreement violates the
+law of the state applicable to this agreement, the agreement shall be
+interpreted to make the maximum disclaimer or limitation permitted by
+the applicable state law. The invalidity or unenforceability of any
+provision of this agreement shall not void the remaining provisions.
+
+1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the
+trademark owner, any agent or employee of the Foundation, anyone
+providing copies of Project Gutenberg-tm electronic works in accordance
+with this agreement, and any volunteers associated with the production,
+promotion and distribution of Project Gutenberg-tm electronic works,
+harmless from all liability, costs and expenses, including legal fees,
+that arise directly or indirectly from any of the following which you do
+or cause to occur: (a) distribution of this or any Project Gutenberg-tm
+work, (b) alteration, modification, or additions or deletions to any
+Project Gutenberg-tm work, and (c) any Defect you cause.
+
+
+Section 2. Information about the Mission of Project Gutenberg-tm
+
+Project Gutenberg-tm is synonymous with the free distribution of
+electronic works in formats readable by the widest variety of computers
+including obsolete, old, middle-aged and new computers. It exists
+because of the efforts of hundreds of volunteers and donations from
+people in all walks of life.
+
+Volunteers and financial support to provide volunteers with the
+assistance they need, is critical to reaching Project Gutenberg-tm's
+goals and ensuring that the Project Gutenberg-tm collection will
+remain freely available for generations to come. In 2001, the Project
+Gutenberg Literary Archive Foundation was created to provide a secure
+and permanent future for Project Gutenberg-tm and future generations.
+To learn more about the Project Gutenberg Literary Archive Foundation
+and how your efforts and donations can help, see Sections 3 and 4
+and the Foundation web page at http://www.pglaf.org.
+
+
+Section 3. Information about the Project Gutenberg Literary Archive
+Foundation
+
+The Project Gutenberg Literary Archive Foundation is a non profit
+501(c)(3) educational corporation organized under the laws of the
+state of Mississippi and granted tax exempt status by the Internal
+Revenue Service. The Foundation's EIN or federal tax identification
+number is 64-6221541. Its 501(c)(3) letter is posted at
+http://pglaf.org/fundraising. Contributions to the Project Gutenberg
+Literary Archive Foundation are tax deductible to the full extent
+permitted by U.S. federal laws and your state's laws.
+
+The Foundation's principal office is located at 4557 Melan Dr. S.
+Fairbanks, AK, 99712., but its volunteers and employees are scattered
+throughout numerous locations. Its business office is located at
+809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email
+business@pglaf.org. Email contact links and up to date contact
+information can be found at the Foundation's web site and official
+page at http://pglaf.org
+
+For additional contact information:
+ Dr. Gregory B. Newby
+ Chief Executive and Director
+ gbnewby@pglaf.org
+
+
+Section 4. Information about Donations to the Project Gutenberg
+Literary Archive Foundation
+
+Project Gutenberg-tm depends upon and cannot survive without wide
+spread public support and donations to carry out its mission of
+increasing the number of public domain and licensed works that can be
+freely distributed in machine readable form accessible by the widest
+array of equipment including outdated equipment. Many small donations
+($1 to $5,000) are particularly important to maintaining tax exempt
+status with the IRS.
+
+The Foundation is committed to complying with the laws regulating
+charities and charitable donations in all 50 states of the United
+States. Compliance requirements are not uniform and it takes a
+considerable effort, much paperwork and many fees to meet and keep up
+with these requirements. We do not solicit donations in locations
+where we have not received written confirmation of compliance. To
+SEND DONATIONS or determine the status of compliance for any
+particular state visit http://pglaf.org
+
+While we cannot and do not solicit contributions from states where we
+have not met the solicitation requirements, we know of no prohibition
+against accepting unsolicited donations from donors in such states who
+approach us with offers to donate.
+
+International donations are gratefully accepted, but we cannot make
+any statements concerning tax treatment of donations received from
+outside the United States. U.S. laws alone swamp our small staff.
+
+Please check the Project Gutenberg Web pages for current donation
+methods and addresses. Donations are accepted in a number of other
+ways including including checks, online payments and credit card
+donations. To donate, please visit: http://pglaf.org/donate
+
+
+Section 5. General Information About Project Gutenberg-tm electronic
+works.
+
+Professor Michael S. Hart is the originator of the Project Gutenberg-tm
+concept of a library of electronic works that could be freely shared
+with anyone. For thirty years, he produced and distributed Project
+Gutenberg-tm eBooks with only a loose network of volunteer support.
+
+
+Project Gutenberg-tm eBooks are often created from several printed
+editions, all of which are confirmed as Public Domain in the U.S.
+unless a copyright notice is included. Thus, we do not necessarily
+keep eBooks in compliance with any particular paper edition.
+
+
+Most people start at our Web site which has the main PG search facility:
+
+ http://www.gutenberg.net
+
+This Web site includes information about Project Gutenberg-tm,
+including how to make donations to the Project Gutenberg Literary
+Archive Foundation, how to help produce our new eBooks, and how to
+subscribe to our email newsletter to hear about new eBooks.
diff --git a/src/pkg/compress/zlib/Makefile b/src/pkg/compress/zlib/Makefile
deleted file mode 100644
index 791072d34..000000000
--- a/src/pkg/compress/zlib/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=compress/zlib
-GOFILES=\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
index 78dabdf4d..f38ef5a88 100644
--- a/src/pkg/compress/zlib/reader.go
+++ b/src/pkg/compress/zlib/reader.go
@@ -26,36 +26,41 @@ package zlib
import (
"bufio"
"compress/flate"
+ "errors"
"hash"
"hash/adler32"
"io"
- "os"
)
const zlibDeflate = 8
-var ChecksumError = os.NewError("zlib checksum error")
-var HeaderError = os.NewError("invalid zlib header")
-var DictionaryError = os.NewError("invalid zlib dictionary")
+var (
+ // ErrChecksum is returned when reading ZLIB data that has an invalid checksum.
+ ErrChecksum = errors.New("zlib: invalid checksum")
+ // ErrDictionary is returned when reading ZLIB data that has an invalid dictionary.
+ ErrDictionary = errors.New("zlib: invalid dictionary")
+ // ErrHeader is returned when reading ZLIB data that has an invalid header.
+ ErrHeader = errors.New("zlib: invalid header")
+)
type reader struct {
r flate.Reader
decompressor io.ReadCloser
digest hash.Hash32
- err os.Error
+ err error
scratch [4]byte
}
// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
// The implementation buffers input and may read more data than necessary from r.
// It is the caller's responsibility to call Close on the ReadCloser when done.
-func NewReader(r io.Reader) (io.ReadCloser, os.Error) {
+func NewReader(r io.Reader) (io.ReadCloser, error) {
return NewReaderDict(r, nil)
}
// NewReaderDict is like NewReader but uses a preset dictionary.
// NewReaderDict ignores the dictionary if the compressed data does not refer to it.
-func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, os.Error) {
+func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
z := new(reader)
if fr, ok := r.(flate.Reader); ok {
z.r = fr
@@ -68,7 +73,7 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, os.Error) {
}
h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
- return nil, HeaderError
+ return nil, ErrHeader
}
if z.scratch[1]&0x20 != 0 {
_, err = io.ReadFull(z.r, z.scratch[0:4])
@@ -77,7 +82,7 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, os.Error) {
}
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != adler32.Checksum(dict) {
- return nil, DictionaryError
+ return nil, ErrDictionary
}
z.decompressor = flate.NewReaderDict(z.r, dict)
} else {
@@ -87,7 +92,7 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, os.Error) {
return z, nil
}
-func (z *reader) Read(p []byte) (n int, err os.Error) {
+func (z *reader) Read(p []byte) (n int, err error) {
if z.err != nil {
return 0, z.err
}
@@ -97,7 +102,7 @@ func (z *reader) Read(p []byte) (n int, err os.Error) {
n, err = z.decompressor.Read(p)
z.digest.Write(p[0:n])
- if n != 0 || err != os.EOF {
+ if n != 0 || err != io.EOF {
z.err = err
return
}
@@ -110,14 +115,14 @@ func (z *reader) Read(p []byte) (n int, err os.Error) {
// ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
if checksum != z.digest.Sum32() {
- z.err = ChecksumError
+ z.err = ErrChecksum
return 0, z.err
}
return
}
// Calling Close does not close the wrapped io.Reader originally passed to NewReader.
-func (z *reader) Close() os.Error {
+func (z *reader) Close() error {
if z.err != nil {
return z.err
}
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
index 195db446c..3b02a0868 100644
--- a/src/pkg/compress/zlib/reader_test.go
+++ b/src/pkg/compress/zlib/reader_test.go
@@ -7,7 +7,6 @@ package zlib
import (
"bytes"
"io"
- "os"
"testing"
)
@@ -16,7 +15,7 @@ type zlibTest struct {
raw string
compressed []byte
dict []byte
- err os.Error
+ err error
}
// Compare-to-golden test data was generated by the ZLIB example program at
@@ -46,14 +45,14 @@ var zlibTests = []zlibTest{
"",
[]byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
nil,
- HeaderError,
+ ErrHeader,
},
{
"bad checksum",
"",
[]byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
nil,
- ChecksumError,
+ ErrChecksum,
},
{
"not enough data",
@@ -96,7 +95,7 @@ var zlibTests = []zlibTest{
[]byte{
0x48, 0x65, 0x6c, 0x6c,
},
- DictionaryError,
+ ErrDictionary,
},
}
diff --git a/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go
index 8f86e9c4c..cd8dea460 100644
--- a/src/pkg/compress/zlib/writer.go
+++ b/src/pkg/compress/zlib/writer.go
@@ -6,10 +6,10 @@ package zlib
import (
"compress/flate"
+ "fmt"
"hash"
"hash/adler32"
"io"
- "os"
)
// These constants are copied from the flate package, so that code that imports
@@ -24,30 +24,55 @@ const (
// 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 io.Writer
- compressor *flate.Writer
- digest hash.Hash32
- err os.Error
- scratch [4]byte
+ w io.Writer
+ level int
+ dict []byte
+ compressor *flate.Writer
+ digest hash.Hash32
+ err error
+ scratch [4]byte
+ wroteHeader bool
}
-// NewWriter calls NewWriterLevel with the default compression level.
-func NewWriter(w io.Writer) (*Writer, os.Error) {
- return NewWriterLevel(w, DefaultCompression)
+// NewWriter creates a new Writer that satisfies writes by compressing data
+// written to w.
+//
+// It is the caller's responsibility to call Close on the WriteCloser when done.
+// Writes may be buffered and not flushed until Close.
+func NewWriter(w io.Writer) *Writer {
+ z, _ := NewWriterLevelDict(w, DefaultCompression, nil)
+ return z
}
-// NewWriterLevel calls NewWriterDict with no dictionary.
-func NewWriterLevel(w io.Writer, level int) (*Writer, os.Error) {
- return NewWriterDict(w, level, nil)
+// NewWriterLevel is like NewWriter but specifies the compression level instead
+// of assuming DefaultCompression.
+//
+// The compression level can be DefaultCompression, NoCompression, or any
+// integer value between BestSpeed and BestCompression inclusive. The error
+// returned will be nil if the level is valid.
+func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
+ return NewWriterLevelDict(w, level, nil)
}
-// NewWriterDict creates a new io.WriteCloser that satisfies writes by compressing data written to w.
-// It is the caller's responsibility to call Close on the WriteCloser when done.
-// level is the compression level, which can be DefaultCompression, NoCompression,
-// or any integer value between BestSpeed and BestCompression (inclusive).
-// dict is the preset dictionary to compress with, or nil to use no dictionary.
-func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
- z := new(Writer)
+// NewWriterLevelDict is like NewWriterLevel but specifies a dictionary to
+// compress with.
+//
+// The dictionary may be nil. If not, its contents should not be modified until
+// the Writer is closed.
+func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
+ if level < DefaultCompression || level > BestCompression {
+ return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
+ }
+ return &Writer{
+ w: w,
+ level: level,
+ dict: dict,
+ }, nil
+}
+
+// writeHeader writes the ZLIB header.
+func (z *Writer) writeHeader() (err error) {
+ z.wroteHeader = true
// ZLIB has a two-byte header (as documented in RFC 1950).
// The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
// The next four bits is the CM (compression method), which is 8 for deflate.
@@ -56,7 +81,7 @@ func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
// 0=fastest, 1=fast, 2=default, 3=best.
// The next bit, FDICT, is set if a dictionary is given.
// The final five FCHECK bits form a mod-31 checksum.
- switch level {
+ switch z.level {
case 0, 1:
z.scratch[1] = 0 << 6
case 2, 3, 4, 5:
@@ -66,35 +91,41 @@ func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
case 7, 8, 9:
z.scratch[1] = 3 << 6
default:
- return nil, os.NewError("level out of range")
+ panic("unreachable")
}
- if dict != nil {
+ if z.dict != nil {
z.scratch[1] |= 1 << 5
}
z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31)
- _, err := w.Write(z.scratch[0:2])
- if err != nil {
- return nil, err
+ if _, err = z.w.Write(z.scratch[0:2]); err != nil {
+ return err
}
- if dict != nil {
+ if z.dict != nil {
// The next four bytes are the Adler-32 checksum of the dictionary.
- checksum := adler32.Checksum(dict)
+ checksum := adler32.Checksum(z.dict)
z.scratch[0] = uint8(checksum >> 24)
z.scratch[1] = uint8(checksum >> 16)
z.scratch[2] = uint8(checksum >> 8)
z.scratch[3] = uint8(checksum >> 0)
- _, err = w.Write(z.scratch[0:4])
- if err != nil {
- return nil, err
+ if _, err = z.w.Write(z.scratch[0:4]); err != nil {
+ return err
}
}
- z.w = w
- z.compressor = flate.NewWriterDict(w, level, dict)
+ z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict)
+ if err != nil {
+ return err
+ }
z.digest = adler32.New()
- return z, nil
+ return nil
}
-func (z *Writer) Write(p []byte) (n int, err os.Error) {
+// Write writes a compressed form of p to the underlying io.Writer. The
+// compressed bytes are not necessarily flushed until the Writer is closed or
+// explicitly flushed.
+func (z *Writer) Write(p []byte) (n int, err error) {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
if z.err != nil {
return 0, z.err
}
@@ -110,8 +141,11 @@ func (z *Writer) Write(p []byte) (n int, err os.Error) {
return
}
-// Flush flushes the underlying compressor.
-func (z *Writer) Flush() os.Error {
+// Flush flushes the Writer to its underlying io.Writer.
+func (z *Writer) Flush() error {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
if z.err != nil {
return z.err
}
@@ -120,7 +154,10 @@ func (z *Writer) Flush() os.Error {
}
// Calling Close does not close the wrapped io.Writer originally passed to NewWriter.
-func (z *Writer) Close() os.Error {
+func (z *Writer) Close() error {
+ if !z.wroteHeader {
+ z.err = z.writeHeader()
+ }
if z.err != nil {
return z.err
}
diff --git a/src/pkg/compress/zlib/writer_test.go b/src/pkg/compress/zlib/writer_test.go
index 32f05ab68..aee1a5c2f 100644
--- a/src/pkg/compress/zlib/writer_test.go
+++ b/src/pkg/compress/zlib/writer_test.go
@@ -52,17 +52,13 @@ func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) {
defer piper.Close()
go func() {
defer pipew.Close()
- zlibw, err := NewWriterDict(pipew, level, dict)
+ zlibw, err := NewWriterLevelDict(pipew, level, dict)
if err != nil {
t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
return
}
defer zlibw.Close()
_, 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
@@ -128,10 +124,10 @@ func TestWriterDict(t *testing.T) {
func TestWriterDictIsUsed(t *testing.T) {
var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
- buf := bytes.NewBuffer(nil)
- compressor, err := NewWriterDict(buf, BestCompression, input)
+ var buf bytes.Buffer
+ compressor, err := NewWriterLevelDict(&buf, BestCompression, input)
if err != nil {
- t.Errorf("error in NewWriterDict: %s", err)
+ t.Errorf("error in NewWriterLevelDict: %s", err)
return
}
compressor.Write(input)
diff --git a/src/pkg/container/heap/Makefile b/src/pkg/container/heap/Makefile
deleted file mode 100644
index 4291d1122..000000000
--- a/src/pkg/container/heap/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=container/heap
-GOFILES=\
- heap.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/container/heap/example_test.go b/src/pkg/container/heap/example_test.go
new file mode 100644
index 000000000..2050bc835
--- /dev/null
+++ b/src/pkg/container/heap/example_test.go
@@ -0,0 +1,105 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This example demonstrates a priority queue built using the heap interface.
+package heap_test
+
+import (
+ "container/heap"
+ "fmt"
+)
+
+// An Item is something we manage in a priority queue.
+type Item struct {
+ value string // The value of the item; arbitrary.
+ priority int // The priority of the item in the queue.
+ // The index is needed by changePriority and is maintained by the heap.Interface methods.
+ index int // The index of the item in the heap.
+}
+
+// A PriorityQueue implements heap.Interface and holds Items.
+type PriorityQueue []*Item
+
+func (pq PriorityQueue) Len() int { return len(pq) }
+
+func (pq PriorityQueue) Less(i, j int) bool {
+ // We want Pop to give us the highest, not lowest, priority so we use greater than here.
+ return pq[i].priority > pq[j].priority
+}
+
+func (pq PriorityQueue) Swap(i, j int) {
+ pq[i], pq[j] = pq[j], pq[i]
+ pq[i].index = i
+ pq[j].index = j
+}
+
+func (pq *PriorityQueue) Push(x interface{}) {
+ // Push and Pop use pointer receivers because they modify the slice's length,
+ // not just its contents.
+ // To simplify indexing expressions in these methods, we save a copy of the
+ // slice object. We could instead write (*pq)[i].
+ a := *pq
+ n := len(a)
+ a = a[0 : n+1]
+ item := x.(*Item)
+ item.index = n
+ a[n] = item
+ *pq = a
+}
+
+func (pq *PriorityQueue) Pop() interface{} {
+ a := *pq
+ n := len(a)
+ item := a[n-1]
+ item.index = -1 // for safety
+ *pq = a[0 : n-1]
+ return item
+}
+
+// update is not used by the example but shows how to take the top item from
+// the queue, update its priority and value, and put it back.
+func (pq *PriorityQueue) update(value string, priority int) {
+ item := heap.Pop(pq).(*Item)
+ item.value = value
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// changePriority is not used by the example but shows how to change the
+// priority of an arbitrary item.
+func (pq *PriorityQueue) changePriority(item *Item, priority int) {
+ heap.Remove(pq, item.index)
+ item.priority = priority
+ heap.Push(pq, item)
+}
+
+// This example pushes 10 items into a PriorityQueue and takes them out in
+// order of priority.
+func Example() {
+ const nItem = 10
+ // Random priorities for the items (a permutation of 0..9, times 11)).
+ priorities := [nItem]int{
+ 77, 22, 44, 55, 11, 88, 33, 99, 00, 66,
+ }
+ values := [nItem]string{
+ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
+ }
+ // Create a priority queue and put some items in it.
+ pq := make(PriorityQueue, 0, nItem)
+ for i := 0; i < cap(pq); i++ {
+ item := &Item{
+ value: values[i],
+ priority: priorities[i],
+ }
+ heap.Push(&pq, item)
+ }
+ // Take the items out; should arrive in decreasing priority order.
+ // For example, the highest priority (99) is the seventh item, so output starts with 99:"seven".
+ for i := 0; i < nItem; i++ {
+ item := heap.Pop(&pq).(*Item)
+ fmt.Printf("%.2d:%s ", item.priority, item.value)
+ }
+ // Output:
+ // 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
+}
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 2dfe5b43c..67018e6ba 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/container/heap/heap.go
@@ -3,7 +3,14 @@
// license that can be found in the LICENSE file.
// Package heap provides heap operations for any type that implements
-// heap.Interface.
+// heap.Interface. A heap is a tree with the property that each node is the
+// highest-valued node in its subtree.
+//
+// A heap is a common way to implement a priority queue. To build a priority
+// queue, implement the Heap interface with the (negative) priority as the
+// ordering for the Less method, so Push adds items while Pop removes the
+// highest-priority item from the queue. The Examples include such an
+// implementation; the file example_test.go has the complete source.
//
package heap
@@ -11,14 +18,17 @@ import "sort"
// Any type that implements heap.Interface may be used as a
// min-heap with the following invariants (established after
-// Init has been called):
+// Init has been called or if the data is empty or sorted):
//
// !h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
//
+// Note that Push and Pop in this interface are for package heap's
+// implementation to call. To add and remove things from the heap,
+// use heap.Push and heap.Pop.
type Interface interface {
sort.Interface
- Push(x interface{})
- Pop() interface{}
+ Push(x interface{}) // add x as element Len()
+ Pop() interface{} // remove and return element Len() - 1.
}
// A heap must be initialized before any of the heap operations
diff --git a/src/pkg/container/heap/heap_test.go b/src/pkg/container/heap/heap_test.go
index c5c1f76e1..cb31ef6d3 100644
--- a/src/pkg/container/heap/heap_test.go
+++ b/src/pkg/container/heap/heap_test.go
@@ -5,33 +5,47 @@
package heap_test
import (
- "testing"
- "container/vector"
. "container/heap"
+ "testing"
)
-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
+type myHeap []int
+
+func (h *myHeap) Less(i, j int) bool {
+ return (*h)[i] < (*h)[j]
+}
+
+func (h *myHeap) Swap(i, j int) {
+ (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
}
-func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) }
+func (h *myHeap) Len() int {
+ return len(*h)
+}
+
+func (h *myHeap) Pop() (v interface{}) {
+ *h, v = (*h)[:h.Len()-1], (*h)[h.Len()-1]
+ return
+}
+
+func (h *myHeap) Push(v interface{}) {
+ *h = append(*h, v.(int))
+}
-func (h *myHeap) verify(t *testing.T, i int) {
+func (h myHeap) verify(t *testing.T, i int) {
n := h.Len()
j1 := 2*i + 1
j2 := 2*i + 2
if j1 < n {
if h.Less(j1, i) {
- t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j1))
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j1])
return
}
h.verify(t, j1)
}
if j2 < n {
if h.Less(j2, i) {
- t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h.At(i), j1, h.At(j2))
+ t.Errorf("heap invariant invalidated [%d] = %d > [%d] = %d", i, h[i], j1, h[j2])
return
}
h.verify(t, j2)
diff --git a/src/pkg/container/list/Makefile b/src/pkg/container/list/Makefile
deleted file mode 100644
index 7fcd5f99a..000000000
--- a/src/pkg/container/list/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=container/list
-GOFILES=\
- list.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/container/ring/Makefile b/src/pkg/container/ring/Makefile
deleted file mode 100644
index fb0900774..000000000
--- a/src/pkg/container/ring/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=container/ring
-GOFILES=\
- ring.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/container/vector/Makefile b/src/pkg/container/vector/Makefile
deleted file mode 100644
index f6b50156f..000000000
--- a/src/pkg/container/vector/Makefile
+++ /dev/null
@@ -1,69 +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.
-
-include ../../../Make.inc
-
-TARG=container/vector
-GOFILES=\
- defs.go\
- intvector.go\
- stringvector.go\
- vector.go\
-
-include ../../../Make.pkg
-
-generate: vector.go vector_test.go
- < vector.go cat\
- | gofmt -r='Vector -> IntVector'\
- | gofmt -r='interface{} -> int'\
- > intvector.go\
-
- < vector.go cat\
- | gofmt -r='Vector -> StringVector'\
- | gofmt -r='interface{} -> string'\
- > stringvector.go\
-
- < vector_test.go cat\
- | gofmt -r='Vector -> IntVector'\
- | gofmt -r='zero -> intzero'\
- | gofmt -r='elem2Value -> elem2IntValue'\
- | gofmt -r='intf2Value -> intf2IntValue'\
- | gofmt -r='int2Value -> int2IntValue'\
- | gofmt -r='TestZeroLen -> TestIntZeroLen'\
- | gofmt -r='TestResize -> TestIntResize'\
- | gofmt -r='TestResize2 -> TestIntResize2'\
- | gofmt -r='checkZero -> checkIntZero'\
- | gofmt -r='TestTrailingElements -> TestIntTrailingElements'\
- | gofmt -r='TestAccess -> TestIntAccess'\
- | gofmt -r='TestInsertDeleteClear -> TestIntInsertDeleteClear'\
- | gofmt -r='verify_slice -> verify_sliceInt'\
- | gofmt -r='verify_pattern -> verify_patternInt'\
- | gofmt -r='make_vector -> make_vectorInt'\
- | gofmt -r='TestInsertVector -> TestIntInsertVector'\
- | gofmt -r='TestDo -> TestIntDo'\
- | gofmt -r='TestVectorCopy -> TestIntVectorCopy'\
- | gofmt -r='interface{} -> int'\
- > intvector_test.go\
-
- < vector_test.go cat\
- | gofmt -r='Vector -> StringVector'\
- | gofmt -r='zero -> strzero'\
- | gofmt -r='int2Value -> int2StrValue'\
- | gofmt -r='intf2Value -> intf2StrValue'\
- | gofmt -r='elem2Value -> elem2StrValue'\
- | gofmt -r='TestZeroLen -> TestStrZeroLen'\
- | gofmt -r='TestResize -> TestStrResize'\
- | gofmt -r='TestResize2 -> TestStrResize2'\
- | gofmt -r='checkZero -> checkStrZero'\
- | gofmt -r='TestTrailingElements -> TestStrTrailingElements'\
- | gofmt -r='TestAccess -> TestStrAccess'\
- | gofmt -r='TestInsertDeleteClear -> TestStrInsertDeleteClear'\
- | gofmt -r='verify_slice -> verify_sliceStr'\
- | gofmt -r='verify_pattern -> verify_patternStr'\
- | gofmt -r='make_vector -> make_vectorStr'\
- | gofmt -r='TestInsertVector -> TestStrInsertVector'\
- | gofmt -r='TestDo -> TestStrDo'\
- | gofmt -r='TestVectorCopy -> TestStrVectorCopy'\
- | gofmt -r='interface{} -> string'\
- > stringvector_test.go
diff --git a/src/pkg/container/vector/defs.go b/src/pkg/container/vector/defs.go
deleted file mode 100644
index 6d6b2ac81..000000000
--- a/src/pkg/container/vector/defs.go
+++ /dev/null
@@ -1,43 +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 vector implements containers for managing sequences of elements.
-// Vectors grow and shrink dynamically as necessary.
-package vector
-
-// Vector is a container for numbered sequences of elements of type interface{}.
-// A vector's length and capacity adjusts automatically as necessary.
-// The zero value for Vector is an empty vector ready to use.
-type Vector []interface{}
-
-// IntVector is a container for numbered sequences of elements of type int.
-// A vector's length and capacity adjusts automatically as necessary.
-// The zero value for IntVector is an empty vector ready to use.
-type IntVector []int
-
-// StringVector is a container for numbered sequences of elements of type string.
-// A vector's length and capacity adjusts automatically as necessary.
-// The zero value for StringVector is an empty vector ready to use.
-type StringVector []string
-
-// Initial underlying array size
-const initialSize = 8
-
-// Partial sort.Interface support
-
-// LessInterface provides partial support of the sort.Interface.
-type LessInterface interface {
- Less(y interface{}) bool
-}
-
-// Less returns a boolean denoting whether the i'th element is less than the j'th element.
-func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) }
-
-// sort.Interface support
-
-// Less returns a boolean denoting whether the i'th element is less than the j'th element.
-func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
-
-// Less returns a boolean denoting whether the i'th element is less than the j'th element.
-func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] }
diff --git a/src/pkg/container/vector/intvector.go b/src/pkg/container/vector/intvector.go
deleted file mode 100644
index aa88cfeb3..000000000
--- a/src/pkg/container/vector/intvector.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.
-
-// CAUTION: If this file is not vector.go, it was generated
-// automatically from vector.go - DO NOT EDIT in that case!
-
-package vector
-
-func (p *IntVector) realloc(length, capacity int) (b []int) {
- if capacity < initialSize {
- capacity = initialSize
- }
- if capacity < length {
- capacity = length
- }
- b = make(IntVector, length, capacity)
- copy(b, *p)
- *p = b
- return
-}
-
-// Insert n elements at position i.
-func (p *IntVector) Expand(i, n int) {
- a := *p
-
- // make sure we have enough space
- len0 := len(a)
- len1 := len0 + n
- if len1 <= cap(a) {
- // enough space - just expand
- a = a[0:len1]
- } else {
- // not enough space - double capacity
- capb := cap(a) * 2
- if capb < len1 {
- // still not enough - use required length
- capb = len1
- }
- // capb >= len1
- a = p.realloc(len1, capb)
- }
-
- // make a hole
- for j := len0 - 1; j >= i; j-- {
- a[j+n] = a[j]
- }
-
- *p = a
-}
-
-// Insert n elements at the end of a vector.
-func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) }
-
-// Resize changes the length and capacity of a vector.
-// If the new length is shorter than the current length, Resize discards
-// trailing elements. If the new length is longer than the current length,
-// Resize adds the respective zero values for the additional elements. The capacity
-// parameter is ignored unless the new length or capacity is longer than the current
-// capacity. The resized vector's capacity may be larger than the requested capacity.
-func (p *IntVector) Resize(length, capacity int) *IntVector {
- a := *p
-
- if length > cap(a) || capacity > cap(a) {
- // not enough space or larger capacity requested explicitly
- a = p.realloc(length, capacity)
- } else if length < len(a) {
- // clear trailing elements
- for i := range a[length:] {
- var zero int
- a[length+i] = zero
- }
- }
-
- *p = a[0:length]
- return p
-}
-
-// Len returns the number of elements in the vector.
-// Same as len(*p).
-func (p *IntVector) Len() int { return len(*p) }
-
-// Cap returns the capacity of the vector; that is, the
-// maximum length the vector can grow without resizing.
-// Same as cap(*p).
-func (p *IntVector) Cap() int { return cap(*p) }
-
-// At returns the i'th element of the vector.
-func (p *IntVector) At(i int) int { return (*p)[i] }
-
-// Set sets the i'th element of the vector to value x.
-func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
-
-// Last returns the element in the vector of highest index.
-func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
-
-// Copy makes a copy of the vector and returns it.
-func (p *IntVector) Copy() IntVector {
- arr := make(IntVector, len(*p))
- copy(arr, *p)
- return arr
-}
-
-// Insert inserts into the vector an element of value x before
-// the current element at index i.
-func (p *IntVector) Insert(i int, x int) {
- p.Expand(i, 1)
- (*p)[i] = x
-}
-
-// Delete deletes the i'th element of the vector. The gap is closed so the old
-// element at index i+1 has index i afterwards.
-func (p *IntVector) Delete(i int) {
- a := *p
- n := len(a)
-
- copy(a[i:n-1], a[i+1:n])
- var zero int
- a[n-1] = zero // support GC, zero out entry
- *p = a[0 : n-1]
-}
-
-// InsertVector inserts into the vector the contents of the vector
-// x such that the 0th element of x appears at index i after insertion.
-func (p *IntVector) InsertVector(i int, x *IntVector) {
- b := *x
-
- p.Expand(i, len(b))
- copy((*p)[i:i+len(b)], b)
-}
-
-// Cut deletes elements i through j-1, inclusive.
-func (p *IntVector) Cut(i, j int) {
- a := *p
- n := len(a)
- m := n - (j - i)
-
- copy(a[i:m], a[j:n])
- for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
- var zero int
- a[k] = zero // support GC, zero out entries
- }
-
- *p = a[0:m]
-}
-
-// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
-// The elements are copied. The original vector is unchanged.
-func (p *IntVector) Slice(i, j int) *IntVector {
- var s IntVector
- s.realloc(j-i, 0) // will fail in Init() if j < i
- copy(s, (*p)[i:j])
- return &s
-}
-
-// Convenience wrappers
-
-// Push appends x to the end of the vector.
-func (p *IntVector) Push(x int) { p.Insert(len(*p), x) }
-
-// Pop deletes the last element of the vector.
-func (p *IntVector) Pop() int {
- a := *p
-
- i := len(a) - 1
- x := a[i]
- var zero int
- a[i] = zero // support GC, zero out entry
- *p = a[0:i]
- return x
-}
-
-// AppendVector appends the entire vector x to the end of this vector.
-func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) }
-
-// Swap exchanges the elements at indexes i and j.
-func (p *IntVector) Swap(i, j int) {
- a := *p
- a[i], a[j] = a[j], a[i]
-}
-
-// Do calls function f for each element of the vector, in order.
-// The behavior of Do is undefined if f changes *p.
-func (p *IntVector) Do(f func(elem int)) {
- for _, e := range *p {
- f(e)
- }
-}
diff --git a/src/pkg/container/vector/intvector_test.go b/src/pkg/container/vector/intvector_test.go
deleted file mode 100644
index b825af912..000000000
--- a/src/pkg/container/vector/intvector_test.go
+++ /dev/null
@@ -1,331 +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.
-
-// CAUTION: If this file is not vector_test.go, it was generated
-// automatically from vector_test.go - DO NOT EDIT in that case!
-
-package vector
-
-import "testing"
-
-func TestIntZeroLen(t *testing.T) {
- a := new(IntVector)
- if a.Len() != 0 {
- t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
- }
- if len(*a) != 0 {
- t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
- }
- var b IntVector
- if b.Len() != 0 {
- t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
- }
- if len(b) != 0 {
- t.Errorf("%T: B4) expected 0, got %d", b, len(b))
- }
-}
-
-func TestIntResize(t *testing.T) {
- var a IntVector
- checkSize(t, &a, 0, 0)
- checkSize(t, a.Resize(0, 5), 0, 5)
- checkSize(t, a.Resize(1, 0), 1, 5)
- checkSize(t, a.Resize(10, 0), 10, 10)
- checkSize(t, a.Resize(5, 0), 5, 10)
- checkSize(t, a.Resize(3, 8), 3, 10)
- checkSize(t, a.Resize(0, 100), 0, 100)
- checkSize(t, a.Resize(11, 100), 11, 100)
-}
-
-func TestIntResize2(t *testing.T) {
- var a IntVector
- checkSize(t, &a, 0, 0)
- a.Push(int2IntValue(1))
- a.Push(int2IntValue(2))
- a.Push(int2IntValue(3))
- a.Push(int2IntValue(4))
- checkSize(t, &a, 4, 4)
- checkSize(t, a.Resize(10, 0), 10, 10)
- for i := 4; i < a.Len(); i++ {
- if a.At(i) != intzero {
- t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, intzero, a.At(i))
- }
- }
- for i := 4; i < len(a); i++ {
- if a[i] != intzero {
- t.Errorf("%T: expected a[%d] == %v; found %v", a, i, intzero, a[i])
- }
- }
-}
-
-func checkIntZero(t *testing.T, a *IntVector, i int) {
- for j := 0; j < i; j++ {
- if a.At(j) == intzero {
- t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
- }
- if (*a)[j] == intzero {
- t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
- }
- }
- for ; i < a.Len(); i++ {
- if a.At(i) != intzero {
- t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, intzero, a.At(i))
- }
- if (*a)[i] != intzero {
- t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, intzero, (*a)[i])
- }
- }
-}
-
-func TestIntTrailingElements(t *testing.T) {
- var a IntVector
- for i := 0; i < 10; i++ {
- a.Push(int2IntValue(i + 1))
- }
- checkIntZero(t, &a, 10)
- checkSize(t, &a, 10, 16)
- checkSize(t, a.Resize(5, 0), 5, 16)
- checkSize(t, a.Resize(10, 0), 10, 16)
- checkIntZero(t, &a, 5)
-}
-
-func TestIntAccess(t *testing.T) {
- const n = 100
- var a IntVector
- a.Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2IntValue(val(i)))
- }
- for i := 0; i < n; i++ {
- if elem2IntValue(a.At(i)) != int2IntValue(val(i)) {
- t.Error(i)
- }
- }
- var b IntVector
- b.Resize(n, 0)
- for i := 0; i < n; i++ {
- b[i] = int2IntValue(val(i))
- }
- for i := 0; i < n; i++ {
- if elem2IntValue(b[i]) != int2IntValue(val(i)) {
- t.Error(i)
- }
- }
-}
-
-func TestIntInsertDeleteClear(t *testing.T) {
- const n = 100
- var a IntVector
-
- for i := 0; i < n; i++ {
- if a.Len() != i {
- t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
- }
- a.Insert(0, int2IntValue(val(i)))
- if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
- t.Errorf("%T: B", a)
- }
- }
- for i := n - 1; i >= 0; i-- {
- if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
- t.Errorf("%T: C", a)
- }
- if elem2IntValue(a.At(0)) != int2IntValue(val(i)) {
- t.Errorf("%T: D", a)
- }
- if elem2IntValue(a[0]) != int2IntValue(val(i)) {
- t.Errorf("%T: D2", a)
- }
- a.Delete(0)
- if a.Len() != i {
- t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
- }
- }
-
- if a.Len() != 0 {
- t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
- }
- for i := 0; i < n; i++ {
- a.Push(int2IntValue(val(i)))
- if a.Len() != i+1 {
- t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
- }
- if len(a) != i+1 {
- t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
- }
- if elem2IntValue(a.Last()) != int2IntValue(val(i)) {
- t.Errorf("%T: H", a)
- }
- }
- a.Resize(0, 0)
- if a.Len() != 0 {
- t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
- }
-
- const m = 5
- for j := 0; j < m; j++ {
- a.Push(int2IntValue(j))
- for i := 0; i < n; i++ {
- x := val(i)
- a.Push(int2IntValue(x))
- if elem2IntValue(a.Pop()) != int2IntValue(x) {
- t.Errorf("%T: J", a)
- }
- if a.Len() != j+1 {
- t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
- }
- if len(a) != j+1 {
- t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
- }
- }
- }
- if a.Len() != m {
- t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
- }
- if len(a) != m {
- t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
- }
-}
-
-func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
- for k := i; k < j; k++ {
- if elem2IntValue(x.At(k)) != int2IntValue(elt) {
- t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
- }
- }
-
- s := x.Slice(i, j)
- for k, n := 0, j-i; k < n; k++ {
- if elem2IntValue(s.At(k)) != int2IntValue(elt) {
- t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
- }
- }
-}
-
-func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
- n := a + b + c
- if x.Len() != n {
- t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
- }
- if len(*x) != n {
- t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
- }
- verify_sliceInt(t, x, 0, 0, a)
- verify_sliceInt(t, x, 1, a, a+b)
- verify_sliceInt(t, x, 0, a+b, n)
-}
-
-func make_vectorInt(elt, len int) *IntVector {
- x := new(IntVector).Resize(len, 0)
- for i := 0; i < len; i++ {
- x.Set(i, int2IntValue(elt))
- }
- return x
-}
-
-func TestIntInsertVector(t *testing.T) {
- // 1
- a := make_vectorInt(0, 0)
- b := make_vectorInt(1, 10)
- a.InsertVector(0, b)
- verify_patternInt(t, a, 0, 10, 0)
- // 2
- a = make_vectorInt(0, 10)
- b = make_vectorInt(1, 0)
- a.InsertVector(5, b)
- verify_patternInt(t, a, 5, 0, 5)
- // 3
- a = make_vectorInt(0, 10)
- b = make_vectorInt(1, 3)
- a.InsertVector(3, b)
- verify_patternInt(t, a, 3, 3, 7)
- // 4
- a = make_vectorInt(0, 10)
- b = make_vectorInt(1, 1000)
- a.InsertVector(8, b)
- verify_patternInt(t, a, 8, 1000, 2)
-}
-
-func TestIntDo(t *testing.T) {
- const n = 25
- const salt = 17
- a := new(IntVector).Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2IntValue(salt*i))
- }
- count := 0
- a.Do(func(e int) {
- i := intf2IntValue(e)
- if i != int2IntValue(count*salt) {
- t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(a), "should visit", n, "values; did visit", count)
- }
-
- b := new(IntVector).Resize(n, 0)
- for i := 0; i < n; i++ {
- (*b)[i] = int2IntValue(salt * i)
- }
- count = 0
- b.Do(func(e int) {
- i := intf2IntValue(e)
- if i != int2IntValue(count*salt) {
- t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(b), "b) should visit", n, "values; did visit", count)
- }
-
- var c IntVector
- c.Resize(n, 0)
- for i := 0; i < n; i++ {
- c[i] = int2IntValue(salt * i)
- }
- count = 0
- c.Do(func(e int) {
- i := intf2IntValue(e)
- if i != int2IntValue(count*salt) {
- t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(c), "c) should visit", n, "values; did visit", count)
- }
-
-}
-
-func TestIntVectorCopy(t *testing.T) {
- // verify Copy() returns a copy, not simply a slice of the original vector
- const Len = 10
- var src IntVector
- for i := 0; i < Len; i++ {
- src.Push(int2IntValue(i * i))
- }
- dest := src.Copy()
- for i := 0; i < Len; i++ {
- src[i] = int2IntValue(-1)
- v := elem2IntValue(dest[i])
- if v != int2IntValue(i*i) {
- t.Error(tname(src), "expected", i*i, "got", v)
- }
- }
-}
diff --git a/src/pkg/container/vector/nogen_test.go b/src/pkg/container/vector/nogen_test.go
deleted file mode 100644
index 7b6a25952..000000000
--- a/src/pkg/container/vector/nogen_test.go
+++ /dev/null
@@ -1,67 +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 vector
-
-import (
- "fmt"
- "sort"
- "testing"
-)
-
-var (
- zero interface{}
- intzero int
- strzero string
-)
-
-func int2Value(x int) int { return x }
-func int2IntValue(x int) int { return x }
-func int2StrValue(x int) string { return string(x) }
-
-func elem2Value(x interface{}) int { return x.(int) }
-func elem2IntValue(x int) int { return x }
-func elem2StrValue(x string) string { return x }
-
-func intf2Value(x interface{}) int { return x.(int) }
-func intf2IntValue(x interface{}) int { return x.(int) }
-func intf2StrValue(x interface{}) string { return x.(string) }
-
-type VectorInterface interface {
- Len() int
- Cap() int
-}
-
-func checkSize(t *testing.T, v VectorInterface, len, cap int) {
- if v.Len() != len {
- t.Errorf("%T expected len = %d; found %d", v, len, v.Len())
- }
- if v.Cap() < cap {
- t.Errorf("%T expected cap >= %d; found %d", v, cap, v.Cap())
- }
-}
-
-func val(i int) int { return i*991 - 1234 }
-
-func TestSorting(t *testing.T) {
- const n = 100
-
- a := new(IntVector).Resize(n, 0)
- for i := n - 1; i >= 0; i-- {
- a.Set(i, n-1-i)
- }
- if sort.IsSorted(a) {
- t.Error("int vector not sorted")
- }
-
- b := new(StringVector).Resize(n, 0)
- for i := n - 1; i >= 0; i-- {
- b.Set(i, fmt.Sprint(n-1-i))
- }
- if sort.IsSorted(b) {
- t.Error("string vector not sorted")
- }
-}
-
-func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) }
diff --git a/src/pkg/container/vector/numbers_test.go b/src/pkg/container/vector/numbers_test.go
deleted file mode 100644
index abe01a8fb..000000000
--- a/src/pkg/container/vector/numbers_test.go
+++ /dev/null
@@ -1,123 +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 vector
-
-import (
- "fmt"
- "runtime"
- "strings"
- "testing"
-)
-
-const memTestN = 1000000
-
-func s(n uint64) string {
- str := fmt.Sprintf("%d", n)
- lens := len(str)
- a := make([]string, (lens+2)/3)
- start := lens
- for i := range a {
- start -= 3
- if start < 0 {
- start = 0
- }
- a[len(a)-i-1] = str[start:lens]
- lens -= 3
- }
- return strings.Join(a, " ")
-}
-
-func TestVectorNums(t *testing.T) {
- if testing.Short() {
- return
- }
- var v Vector
- c := int(0)
- runtime.GC()
- m0 := runtime.MemStats
- v.Resize(memTestN, memTestN)
- for i := 0; i < memTestN; i++ {
- v.Set(i, c)
- }
- runtime.GC()
- m := runtime.MemStats
- v.Resize(0, 0)
- runtime.GC()
- n := m.Alloc - m0.Alloc
- t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
-}
-
-func TestIntVectorNums(t *testing.T) {
- if testing.Short() {
- return
- }
- var v IntVector
- c := int(0)
- runtime.GC()
- m0 := runtime.MemStats
- v.Resize(memTestN, memTestN)
- for i := 0; i < memTestN; i++ {
- v.Set(i, c)
- }
- runtime.GC()
- m := runtime.MemStats
- v.Resize(0, 0)
- runtime.GC()
- n := m.Alloc - m0.Alloc
- t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
-}
-
-func TestStringVectorNums(t *testing.T) {
- if testing.Short() {
- return
- }
- var v StringVector
- c := ""
- runtime.GC()
- m0 := runtime.MemStats
- v.Resize(memTestN, memTestN)
- for i := 0; i < memTestN; i++ {
- v.Set(i, c)
- }
- runtime.GC()
- m := runtime.MemStats
- v.Resize(0, 0)
- runtime.GC()
- n := m.Alloc - m0.Alloc
- t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
-}
-
-func BenchmarkVectorNums(b *testing.B) {
- c := int(0)
- var v Vector
- b.StopTimer()
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- v.Push(c)
- }
-}
-
-func BenchmarkIntVectorNums(b *testing.B) {
- c := int(0)
- var v IntVector
- b.StopTimer()
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- v.Push(c)
- }
-}
-
-func BenchmarkStringVectorNums(b *testing.B) {
- c := ""
- var v StringVector
- b.StopTimer()
- runtime.GC()
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- v.Push(c)
- }
-}
diff --git a/src/pkg/container/vector/stringvector.go b/src/pkg/container/vector/stringvector.go
deleted file mode 100644
index dc81f06b7..000000000
--- a/src/pkg/container/vector/stringvector.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.
-
-// CAUTION: If this file is not vector.go, it was generated
-// automatically from vector.go - DO NOT EDIT in that case!
-
-package vector
-
-func (p *StringVector) realloc(length, capacity int) (b []string) {
- if capacity < initialSize {
- capacity = initialSize
- }
- if capacity < length {
- capacity = length
- }
- b = make(StringVector, length, capacity)
- copy(b, *p)
- *p = b
- return
-}
-
-// Insert n elements at position i.
-func (p *StringVector) Expand(i, n int) {
- a := *p
-
- // make sure we have enough space
- len0 := len(a)
- len1 := len0 + n
- if len1 <= cap(a) {
- // enough space - just expand
- a = a[0:len1]
- } else {
- // not enough space - double capacity
- capb := cap(a) * 2
- if capb < len1 {
- // still not enough - use required length
- capb = len1
- }
- // capb >= len1
- a = p.realloc(len1, capb)
- }
-
- // make a hole
- for j := len0 - 1; j >= i; j-- {
- a[j+n] = a[j]
- }
-
- *p = a
-}
-
-// Insert n elements at the end of a vector.
-func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) }
-
-// Resize changes the length and capacity of a vector.
-// If the new length is shorter than the current length, Resize discards
-// trailing elements. If the new length is longer than the current length,
-// Resize adds the respective zero values for the additional elements. The capacity
-// parameter is ignored unless the new length or capacity is longer than the current
-// capacity. The resized vector's capacity may be larger than the requested capacity.
-func (p *StringVector) Resize(length, capacity int) *StringVector {
- a := *p
-
- if length > cap(a) || capacity > cap(a) {
- // not enough space or larger capacity requested explicitly
- a = p.realloc(length, capacity)
- } else if length < len(a) {
- // clear trailing elements
- for i := range a[length:] {
- var zero string
- a[length+i] = zero
- }
- }
-
- *p = a[0:length]
- return p
-}
-
-// Len returns the number of elements in the vector.
-// Same as len(*p).
-func (p *StringVector) Len() int { return len(*p) }
-
-// Cap returns the capacity of the vector; that is, the
-// maximum length the vector can grow without resizing.
-// Same as cap(*p).
-func (p *StringVector) Cap() int { return cap(*p) }
-
-// At returns the i'th element of the vector.
-func (p *StringVector) At(i int) string { return (*p)[i] }
-
-// Set sets the i'th element of the vector to value x.
-func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
-
-// Last returns the element in the vector of highest index.
-func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
-
-// Copy makes a copy of the vector and returns it.
-func (p *StringVector) Copy() StringVector {
- arr := make(StringVector, len(*p))
- copy(arr, *p)
- return arr
-}
-
-// Insert inserts into the vector an element of value x before
-// the current element at index i.
-func (p *StringVector) Insert(i int, x string) {
- p.Expand(i, 1)
- (*p)[i] = x
-}
-
-// Delete deletes the i'th element of the vector. The gap is closed so the old
-// element at index i+1 has index i afterwards.
-func (p *StringVector) Delete(i int) {
- a := *p
- n := len(a)
-
- copy(a[i:n-1], a[i+1:n])
- var zero string
- a[n-1] = zero // support GC, zero out entry
- *p = a[0 : n-1]
-}
-
-// InsertVector inserts into the vector the contents of the vector
-// x such that the 0th element of x appears at index i after insertion.
-func (p *StringVector) InsertVector(i int, x *StringVector) {
- b := *x
-
- p.Expand(i, len(b))
- copy((*p)[i:i+len(b)], b)
-}
-
-// Cut deletes elements i through j-1, inclusive.
-func (p *StringVector) Cut(i, j int) {
- a := *p
- n := len(a)
- m := n - (j - i)
-
- copy(a[i:m], a[j:n])
- for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
- var zero string
- a[k] = zero // support GC, zero out entries
- }
-
- *p = a[0:m]
-}
-
-// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
-// The elements are copied. The original vector is unchanged.
-func (p *StringVector) Slice(i, j int) *StringVector {
- var s StringVector
- s.realloc(j-i, 0) // will fail in Init() if j < i
- copy(s, (*p)[i:j])
- return &s
-}
-
-// Convenience wrappers
-
-// Push appends x to the end of the vector.
-func (p *StringVector) Push(x string) { p.Insert(len(*p), x) }
-
-// Pop deletes the last element of the vector.
-func (p *StringVector) Pop() string {
- a := *p
-
- i := len(a) - 1
- x := a[i]
- var zero string
- a[i] = zero // support GC, zero out entry
- *p = a[0:i]
- return x
-}
-
-// AppendVector appends the entire vector x to the end of this vector.
-func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) }
-
-// Swap exchanges the elements at indexes i and j.
-func (p *StringVector) Swap(i, j int) {
- a := *p
- a[i], a[j] = a[j], a[i]
-}
-
-// Do calls function f for each element of the vector, in order.
-// The behavior of Do is undefined if f changes *p.
-func (p *StringVector) Do(f func(elem string)) {
- for _, e := range *p {
- f(e)
- }
-}
diff --git a/src/pkg/container/vector/stringvector_test.go b/src/pkg/container/vector/stringvector_test.go
deleted file mode 100644
index c75676f78..000000000
--- a/src/pkg/container/vector/stringvector_test.go
+++ /dev/null
@@ -1,331 +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.
-
-// CAUTION: If this file is not vector_test.go, it was generated
-// automatically from vector_test.go - DO NOT EDIT in that case!
-
-package vector
-
-import "testing"
-
-func TestStrZeroLen(t *testing.T) {
- a := new(StringVector)
- if a.Len() != 0 {
- t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
- }
- if len(*a) != 0 {
- t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
- }
- var b StringVector
- if b.Len() != 0 {
- t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
- }
- if len(b) != 0 {
- t.Errorf("%T: B4) expected 0, got %d", b, len(b))
- }
-}
-
-func TestStrResize(t *testing.T) {
- var a StringVector
- checkSize(t, &a, 0, 0)
- checkSize(t, a.Resize(0, 5), 0, 5)
- checkSize(t, a.Resize(1, 0), 1, 5)
- checkSize(t, a.Resize(10, 0), 10, 10)
- checkSize(t, a.Resize(5, 0), 5, 10)
- checkSize(t, a.Resize(3, 8), 3, 10)
- checkSize(t, a.Resize(0, 100), 0, 100)
- checkSize(t, a.Resize(11, 100), 11, 100)
-}
-
-func TestStrResize2(t *testing.T) {
- var a StringVector
- checkSize(t, &a, 0, 0)
- a.Push(int2StrValue(1))
- a.Push(int2StrValue(2))
- a.Push(int2StrValue(3))
- a.Push(int2StrValue(4))
- checkSize(t, &a, 4, 4)
- checkSize(t, a.Resize(10, 0), 10, 10)
- for i := 4; i < a.Len(); i++ {
- if a.At(i) != strzero {
- t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, strzero, a.At(i))
- }
- }
- for i := 4; i < len(a); i++ {
- if a[i] != strzero {
- t.Errorf("%T: expected a[%d] == %v; found %v", a, i, strzero, a[i])
- }
- }
-}
-
-func checkStrZero(t *testing.T, a *StringVector, i int) {
- for j := 0; j < i; j++ {
- if a.At(j) == strzero {
- t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
- }
- if (*a)[j] == strzero {
- t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
- }
- }
- for ; i < a.Len(); i++ {
- if a.At(i) != strzero {
- t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, strzero, a.At(i))
- }
- if (*a)[i] != strzero {
- t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, strzero, (*a)[i])
- }
- }
-}
-
-func TestStrTrailingElements(t *testing.T) {
- var a StringVector
- for i := 0; i < 10; i++ {
- a.Push(int2StrValue(i + 1))
- }
- checkStrZero(t, &a, 10)
- checkSize(t, &a, 10, 16)
- checkSize(t, a.Resize(5, 0), 5, 16)
- checkSize(t, a.Resize(10, 0), 10, 16)
- checkStrZero(t, &a, 5)
-}
-
-func TestStrAccess(t *testing.T) {
- const n = 100
- var a StringVector
- a.Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2StrValue(val(i)))
- }
- for i := 0; i < n; i++ {
- if elem2StrValue(a.At(i)) != int2StrValue(val(i)) {
- t.Error(i)
- }
- }
- var b StringVector
- b.Resize(n, 0)
- for i := 0; i < n; i++ {
- b[i] = int2StrValue(val(i))
- }
- for i := 0; i < n; i++ {
- if elem2StrValue(b[i]) != int2StrValue(val(i)) {
- t.Error(i)
- }
- }
-}
-
-func TestStrInsertDeleteClear(t *testing.T) {
- const n = 100
- var a StringVector
-
- for i := 0; i < n; i++ {
- if a.Len() != i {
- t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
- }
- a.Insert(0, int2StrValue(val(i)))
- if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
- t.Errorf("%T: B", a)
- }
- }
- for i := n - 1; i >= 0; i-- {
- if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
- t.Errorf("%T: C", a)
- }
- if elem2StrValue(a.At(0)) != int2StrValue(val(i)) {
- t.Errorf("%T: D", a)
- }
- if elem2StrValue(a[0]) != int2StrValue(val(i)) {
- t.Errorf("%T: D2", a)
- }
- a.Delete(0)
- if a.Len() != i {
- t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
- }
- }
-
- if a.Len() != 0 {
- t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
- }
- for i := 0; i < n; i++ {
- a.Push(int2StrValue(val(i)))
- if a.Len() != i+1 {
- t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
- }
- if len(a) != i+1 {
- t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
- }
- if elem2StrValue(a.Last()) != int2StrValue(val(i)) {
- t.Errorf("%T: H", a)
- }
- }
- a.Resize(0, 0)
- if a.Len() != 0 {
- t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
- }
-
- const m = 5
- for j := 0; j < m; j++ {
- a.Push(int2StrValue(j))
- for i := 0; i < n; i++ {
- x := val(i)
- a.Push(int2StrValue(x))
- if elem2StrValue(a.Pop()) != int2StrValue(x) {
- t.Errorf("%T: J", a)
- }
- if a.Len() != j+1 {
- t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
- }
- if len(a) != j+1 {
- t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
- }
- }
- }
- if a.Len() != m {
- t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
- }
- if len(a) != m {
- t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
- }
-}
-
-func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
- for k := i; k < j; k++ {
- if elem2StrValue(x.At(k)) != int2StrValue(elt) {
- t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
- }
- }
-
- s := x.Slice(i, j)
- for k, n := 0, j-i; k < n; k++ {
- if elem2StrValue(s.At(k)) != int2StrValue(elt) {
- t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
- }
- }
-}
-
-func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
- n := a + b + c
- if x.Len() != n {
- t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
- }
- if len(*x) != n {
- t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
- }
- verify_sliceStr(t, x, 0, 0, a)
- verify_sliceStr(t, x, 1, a, a+b)
- verify_sliceStr(t, x, 0, a+b, n)
-}
-
-func make_vectorStr(elt, len int) *StringVector {
- x := new(StringVector).Resize(len, 0)
- for i := 0; i < len; i++ {
- x.Set(i, int2StrValue(elt))
- }
- return x
-}
-
-func TestStrInsertVector(t *testing.T) {
- // 1
- a := make_vectorStr(0, 0)
- b := make_vectorStr(1, 10)
- a.InsertVector(0, b)
- verify_patternStr(t, a, 0, 10, 0)
- // 2
- a = make_vectorStr(0, 10)
- b = make_vectorStr(1, 0)
- a.InsertVector(5, b)
- verify_patternStr(t, a, 5, 0, 5)
- // 3
- a = make_vectorStr(0, 10)
- b = make_vectorStr(1, 3)
- a.InsertVector(3, b)
- verify_patternStr(t, a, 3, 3, 7)
- // 4
- a = make_vectorStr(0, 10)
- b = make_vectorStr(1, 1000)
- a.InsertVector(8, b)
- verify_patternStr(t, a, 8, 1000, 2)
-}
-
-func TestStrDo(t *testing.T) {
- const n = 25
- const salt = 17
- a := new(StringVector).Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2StrValue(salt*i))
- }
- count := 0
- a.Do(func(e string) {
- i := intf2StrValue(e)
- if i != int2StrValue(count*salt) {
- t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(a), "should visit", n, "values; did visit", count)
- }
-
- b := new(StringVector).Resize(n, 0)
- for i := 0; i < n; i++ {
- (*b)[i] = int2StrValue(salt * i)
- }
- count = 0
- b.Do(func(e string) {
- i := intf2StrValue(e)
- if i != int2StrValue(count*salt) {
- t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(b), "b) should visit", n, "values; did visit", count)
- }
-
- var c StringVector
- c.Resize(n, 0)
- for i := 0; i < n; i++ {
- c[i] = int2StrValue(salt * i)
- }
- count = 0
- c.Do(func(e string) {
- i := intf2StrValue(e)
- if i != int2StrValue(count*salt) {
- t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(c), "c) should visit", n, "values; did visit", count)
- }
-
-}
-
-func TestStrVectorCopy(t *testing.T) {
- // verify Copy() returns a copy, not simply a slice of the original vector
- const Len = 10
- var src StringVector
- for i := 0; i < Len; i++ {
- src.Push(int2StrValue(i * i))
- }
- dest := src.Copy()
- for i := 0; i < Len; i++ {
- src[i] = int2StrValue(-1)
- v := elem2StrValue(dest[i])
- if v != int2StrValue(i*i) {
- t.Error(tname(src), "expected", i*i, "got", v)
- }
- }
-}
diff --git a/src/pkg/container/vector/vector.go b/src/pkg/container/vector/vector.go
deleted file mode 100644
index 8470ec067..000000000
--- a/src/pkg/container/vector/vector.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.
-
-// CAUTION: If this file is not vector.go, it was generated
-// automatically from vector.go - DO NOT EDIT in that case!
-
-package vector
-
-func (p *Vector) realloc(length, capacity int) (b []interface{}) {
- if capacity < initialSize {
- capacity = initialSize
- }
- if capacity < length {
- capacity = length
- }
- b = make(Vector, length, capacity)
- copy(b, *p)
- *p = b
- return
-}
-
-// Insert n elements at position i.
-func (p *Vector) Expand(i, n int) {
- a := *p
-
- // make sure we have enough space
- len0 := len(a)
- len1 := len0 + n
- if len1 <= cap(a) {
- // enough space - just expand
- a = a[0:len1]
- } else {
- // not enough space - double capacity
- capb := cap(a) * 2
- if capb < len1 {
- // still not enough - use required length
- capb = len1
- }
- // capb >= len1
- a = p.realloc(len1, capb)
- }
-
- // make a hole
- for j := len0 - 1; j >= i; j-- {
- a[j+n] = a[j]
- }
-
- *p = a
-}
-
-// Insert n elements at the end of a vector.
-func (p *Vector) Extend(n int) { p.Expand(len(*p), n) }
-
-// Resize changes the length and capacity of a vector.
-// If the new length is shorter than the current length, Resize discards
-// trailing elements. If the new length is longer than the current length,
-// Resize adds the respective zero values for the additional elements. The capacity
-// parameter is ignored unless the new length or capacity is longer than the current
-// capacity. The resized vector's capacity may be larger than the requested capacity.
-func (p *Vector) Resize(length, capacity int) *Vector {
- a := *p
-
- if length > cap(a) || capacity > cap(a) {
- // not enough space or larger capacity requested explicitly
- a = p.realloc(length, capacity)
- } else if length < len(a) {
- // clear trailing elements
- for i := range a[length:] {
- var zero interface{}
- a[length+i] = zero
- }
- }
-
- *p = a[0:length]
- return p
-}
-
-// Len returns the number of elements in the vector.
-// Same as len(*p).
-func (p *Vector) Len() int { return len(*p) }
-
-// Cap returns the capacity of the vector; that is, the
-// maximum length the vector can grow without resizing.
-// Same as cap(*p).
-func (p *Vector) Cap() int { return cap(*p) }
-
-// At returns the i'th element of the vector.
-func (p *Vector) At(i int) interface{} { return (*p)[i] }
-
-// Set sets the i'th element of the vector to value x.
-func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
-
-// Last returns the element in the vector of highest index.
-func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
-
-// Copy makes a copy of the vector and returns it.
-func (p *Vector) Copy() Vector {
- arr := make(Vector, len(*p))
- copy(arr, *p)
- return arr
-}
-
-// Insert inserts into the vector an element of value x before
-// the current element at index i.
-func (p *Vector) Insert(i int, x interface{}) {
- p.Expand(i, 1)
- (*p)[i] = x
-}
-
-// Delete deletes the i'th element of the vector. The gap is closed so the old
-// element at index i+1 has index i afterwards.
-func (p *Vector) Delete(i int) {
- a := *p
- n := len(a)
-
- copy(a[i:n-1], a[i+1:n])
- var zero interface{}
- a[n-1] = zero // support GC, zero out entry
- *p = a[0 : n-1]
-}
-
-// InsertVector inserts into the vector the contents of the vector
-// x such that the 0th element of x appears at index i after insertion.
-func (p *Vector) InsertVector(i int, x *Vector) {
- b := *x
-
- p.Expand(i, len(b))
- copy((*p)[i:i+len(b)], b)
-}
-
-// Cut deletes elements i through j-1, inclusive.
-func (p *Vector) Cut(i, j int) {
- a := *p
- n := len(a)
- m := n - (j - i)
-
- copy(a[i:m], a[j:n])
- for k := m; k < n; k++ { //TODO(bflm) don't zero out the elements unless it's a Vector.
- var zero interface{}
- a[k] = zero // support GC, zero out entries
- }
-
- *p = a[0:m]
-}
-
-// Slice returns a new sub-vector by slicing the old one to extract slice [i:j].
-// The elements are copied. The original vector is unchanged.
-func (p *Vector) Slice(i, j int) *Vector {
- var s Vector
- s.realloc(j-i, 0) // will fail in Init() if j < i
- copy(s, (*p)[i:j])
- return &s
-}
-
-// Convenience wrappers
-
-// Push appends x to the end of the vector.
-func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) }
-
-// Pop deletes the last element of the vector.
-func (p *Vector) Pop() interface{} {
- a := *p
-
- i := len(a) - 1
- x := a[i]
- var zero interface{}
- a[i] = zero // support GC, zero out entry
- *p = a[0:i]
- return x
-}
-
-// AppendVector appends the entire vector x to the end of this vector.
-func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) }
-
-// Swap exchanges the elements at indexes i and j.
-func (p *Vector) Swap(i, j int) {
- a := *p
- a[i], a[j] = a[j], a[i]
-}
-
-// Do calls function f for each element of the vector, in order.
-// The behavior of Do is undefined if f changes *p.
-func (p *Vector) Do(f func(elem interface{})) {
- for _, e := range *p {
- f(e)
- }
-}
diff --git a/src/pkg/container/vector/vector_test.go b/src/pkg/container/vector/vector_test.go
deleted file mode 100644
index a7f47b8c2..000000000
--- a/src/pkg/container/vector/vector_test.go
+++ /dev/null
@@ -1,331 +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.
-
-// CAUTION: If this file is not vector_test.go, it was generated
-// automatically from vector_test.go - DO NOT EDIT in that case!
-
-package vector
-
-import "testing"
-
-func TestZeroLen(t *testing.T) {
- a := new(Vector)
- if a.Len() != 0 {
- t.Errorf("%T: B1) expected 0, got %d", a, a.Len())
- }
- if len(*a) != 0 {
- t.Errorf("%T: B2) expected 0, got %d", a, len(*a))
- }
- var b Vector
- if b.Len() != 0 {
- t.Errorf("%T: B3) expected 0, got %d", b, b.Len())
- }
- if len(b) != 0 {
- t.Errorf("%T: B4) expected 0, got %d", b, len(b))
- }
-}
-
-func TestResize(t *testing.T) {
- var a Vector
- checkSize(t, &a, 0, 0)
- checkSize(t, a.Resize(0, 5), 0, 5)
- checkSize(t, a.Resize(1, 0), 1, 5)
- checkSize(t, a.Resize(10, 0), 10, 10)
- checkSize(t, a.Resize(5, 0), 5, 10)
- checkSize(t, a.Resize(3, 8), 3, 10)
- checkSize(t, a.Resize(0, 100), 0, 100)
- checkSize(t, a.Resize(11, 100), 11, 100)
-}
-
-func TestResize2(t *testing.T) {
- var a Vector
- checkSize(t, &a, 0, 0)
- a.Push(int2Value(1))
- a.Push(int2Value(2))
- a.Push(int2Value(3))
- a.Push(int2Value(4))
- checkSize(t, &a, 4, 4)
- checkSize(t, a.Resize(10, 0), 10, 10)
- for i := 4; i < a.Len(); i++ {
- if a.At(i) != zero {
- t.Errorf("%T: expected a.At(%d) == %v; found %v!", a, i, zero, a.At(i))
- }
- }
- for i := 4; i < len(a); i++ {
- if a[i] != zero {
- t.Errorf("%T: expected a[%d] == %v; found %v", a, i, zero, a[i])
- }
- }
-}
-
-func checkZero(t *testing.T, a *Vector, i int) {
- for j := 0; j < i; j++ {
- if a.At(j) == zero {
- t.Errorf("%T: 1 expected a.At(%d) == %d; found %v", a, j, j, a.At(j))
- }
- if (*a)[j] == zero {
- t.Errorf("%T: 2 expected (*a)[%d] == %d; found %v", a, j, j, (*a)[j])
- }
- }
- for ; i < a.Len(); i++ {
- if a.At(i) != zero {
- t.Errorf("%T: 3 expected a.At(%d) == %v; found %v", a, i, zero, a.At(i))
- }
- if (*a)[i] != zero {
- t.Errorf("%T: 4 expected (*a)[%d] == %v; found %v", a, i, zero, (*a)[i])
- }
- }
-}
-
-func TestTrailingElements(t *testing.T) {
- var a Vector
- for i := 0; i < 10; i++ {
- a.Push(int2Value(i + 1))
- }
- checkZero(t, &a, 10)
- checkSize(t, &a, 10, 16)
- checkSize(t, a.Resize(5, 0), 5, 16)
- checkSize(t, a.Resize(10, 0), 10, 16)
- checkZero(t, &a, 5)
-}
-
-func TestAccess(t *testing.T) {
- const n = 100
- var a Vector
- a.Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2Value(val(i)))
- }
- for i := 0; i < n; i++ {
- if elem2Value(a.At(i)) != int2Value(val(i)) {
- t.Error(i)
- }
- }
- var b Vector
- b.Resize(n, 0)
- for i := 0; i < n; i++ {
- b[i] = int2Value(val(i))
- }
- for i := 0; i < n; i++ {
- if elem2Value(b[i]) != int2Value(val(i)) {
- t.Error(i)
- }
- }
-}
-
-func TestInsertDeleteClear(t *testing.T) {
- const n = 100
- var a Vector
-
- for i := 0; i < n; i++ {
- if a.Len() != i {
- t.Errorf("%T: A) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: A) wrong len() %d (expected %d)", a, len(a), i)
- }
- a.Insert(0, int2Value(val(i)))
- if elem2Value(a.Last()) != int2Value(val(0)) {
- t.Errorf("%T: B", a)
- }
- }
- for i := n - 1; i >= 0; i-- {
- if elem2Value(a.Last()) != int2Value(val(0)) {
- t.Errorf("%T: C", a)
- }
- if elem2Value(a.At(0)) != int2Value(val(i)) {
- t.Errorf("%T: D", a)
- }
- if elem2Value(a[0]) != int2Value(val(i)) {
- t.Errorf("%T: D2", a)
- }
- a.Delete(0)
- if a.Len() != i {
- t.Errorf("%T: E) wrong Len() %d (expected %d)", a, a.Len(), i)
- }
- if len(a) != i {
- t.Errorf("%T: E) wrong len() %d (expected %d)", a, len(a), i)
- }
- }
-
- if a.Len() != 0 {
- t.Errorf("%T: F) wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: F) wrong len() %d (expected 0)", a, len(a))
- }
- for i := 0; i < n; i++ {
- a.Push(int2Value(val(i)))
- if a.Len() != i+1 {
- t.Errorf("%T: G) wrong Len() %d (expected %d)", a, a.Len(), i+1)
- }
- if len(a) != i+1 {
- t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
- }
- if elem2Value(a.Last()) != int2Value(val(i)) {
- t.Errorf("%T: H", a)
- }
- }
- a.Resize(0, 0)
- if a.Len() != 0 {
- t.Errorf("%T: I wrong Len() %d (expected 0)", a, a.Len())
- }
- if len(a) != 0 {
- t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
- }
-
- const m = 5
- for j := 0; j < m; j++ {
- a.Push(int2Value(j))
- for i := 0; i < n; i++ {
- x := val(i)
- a.Push(int2Value(x))
- if elem2Value(a.Pop()) != int2Value(x) {
- t.Errorf("%T: J", a)
- }
- if a.Len() != j+1 {
- t.Errorf("%T: K) wrong Len() %d (expected %d)", a, a.Len(), j+1)
- }
- if len(a) != j+1 {
- t.Errorf("%T: K) wrong len() %d (expected %d)", a, len(a), j+1)
- }
- }
- }
- if a.Len() != m {
- t.Errorf("%T: L) wrong Len() %d (expected %d)", a, a.Len(), m)
- }
- if len(a) != m {
- t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
- }
-}
-
-func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
- for k := i; k < j; k++ {
- if elem2Value(x.At(k)) != int2Value(elt) {
- t.Errorf("%T: M) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
- }
- }
-
- s := x.Slice(i, j)
- for k, n := 0, j-i; k < n; k++ {
- if elem2Value(s.At(k)) != int2Value(elt) {
- t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
- }
- }
-}
-
-func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
- n := a + b + c
- if x.Len() != n {
- t.Errorf("%T: O) wrong Len() %d (expected %d)", x, x.Len(), n)
- }
- if len(*x) != n {
- t.Errorf("%T: O) wrong len() %d (expected %d)", x, len(*x), n)
- }
- verify_slice(t, x, 0, 0, a)
- verify_slice(t, x, 1, a, a+b)
- verify_slice(t, x, 0, a+b, n)
-}
-
-func make_vector(elt, len int) *Vector {
- x := new(Vector).Resize(len, 0)
- for i := 0; i < len; i++ {
- x.Set(i, int2Value(elt))
- }
- return x
-}
-
-func TestInsertVector(t *testing.T) {
- // 1
- a := make_vector(0, 0)
- b := make_vector(1, 10)
- a.InsertVector(0, b)
- verify_pattern(t, a, 0, 10, 0)
- // 2
- a = make_vector(0, 10)
- b = make_vector(1, 0)
- a.InsertVector(5, b)
- verify_pattern(t, a, 5, 0, 5)
- // 3
- a = make_vector(0, 10)
- b = make_vector(1, 3)
- a.InsertVector(3, b)
- verify_pattern(t, a, 3, 3, 7)
- // 4
- a = make_vector(0, 10)
- b = make_vector(1, 1000)
- a.InsertVector(8, b)
- verify_pattern(t, a, 8, 1000, 2)
-}
-
-func TestDo(t *testing.T) {
- const n = 25
- const salt = 17
- a := new(Vector).Resize(n, 0)
- for i := 0; i < n; i++ {
- a.Set(i, int2Value(salt*i))
- }
- count := 0
- a.Do(func(e interface{}) {
- i := intf2Value(e)
- if i != int2Value(count*salt) {
- t.Error(tname(a), "value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(a), "should visit", n, "values; did visit", count)
- }
-
- b := new(Vector).Resize(n, 0)
- for i := 0; i < n; i++ {
- (*b)[i] = int2Value(salt * i)
- }
- count = 0
- b.Do(func(e interface{}) {
- i := intf2Value(e)
- if i != int2Value(count*salt) {
- t.Error(tname(b), "b) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(b), "b) should visit", n, "values; did visit", count)
- }
-
- var c Vector
- c.Resize(n, 0)
- for i := 0; i < n; i++ {
- c[i] = int2Value(salt * i)
- }
- count = 0
- c.Do(func(e interface{}) {
- i := intf2Value(e)
- if i != int2Value(count*salt) {
- t.Error(tname(c), "c) value at", count, "should be", count*salt, "not", i)
- }
- count++
- })
- if count != n {
- t.Error(tname(c), "c) should visit", n, "values; did visit", count)
- }
-
-}
-
-func TestVectorCopy(t *testing.T) {
- // verify Copy() returns a copy, not simply a slice of the original vector
- const Len = 10
- var src Vector
- for i := 0; i < Len; i++ {
- src.Push(int2Value(i * i))
- }
- dest := src.Copy()
- for i := 0; i < Len; i++ {
- src[i] = int2Value(-1)
- v := elem2Value(dest[i])
- if v != int2Value(i*i) {
- t.Error(tname(src), "expected", i*i, "got", v)
- }
- }
-}
diff --git a/src/pkg/crypto/Makefile b/src/pkg/crypto/Makefile
deleted file mode 100644
index 738a52062..000000000
--- a/src/pkg/crypto/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=crypto
-GOFILES=\
- crypto.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/crypto/aes/Makefile b/src/pkg/crypto/aes/Makefile
deleted file mode 100644
index 9dc846ee3..000000000
--- a/src/pkg/crypto/aes/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/aes
-GOFILES=\
- block.go\
- cipher.go\
- const.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
index 2136d447d..e500c666d 100644
--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -91,6 +91,7 @@ func TestTe(t *testing.T) {
s2 := mul(s, 2)
s3 := mul(s, 3)
w := s2<<24 | s<<16 | s<<8 | s3
+ te := [][256]uint32{te0, te1, te2, te3}
for j := 0; j < 4; j++ {
if x := te[j][i]; x != w {
t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w)
@@ -110,6 +111,7 @@ func TestTd(t *testing.T) {
sd := mul(s, 0xd)
se := mul(s, 0xe)
w := se<<24 | s9<<16 | sd<<8 | sb
+ td := [][256]uint32{td0, td1, td2, td3}
for j := 0; j < 4; j++ {
if x := td[j][i]; x != w {
t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w)
@@ -348,3 +350,17 @@ func TestCipherDecrypt(t *testing.T) {
}
}
}
+
+func BenchmarkEncrypt(b *testing.B) {
+ b.StopTimer()
+ tt := encryptTests[0]
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.in))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(out, tt.in)
+ }
+}
diff --git a/src/pkg/crypto/aes/block.go b/src/pkg/crypto/aes/block.go
index 130cd011c..b930787ce 100644
--- a/src/pkg/crypto/aes/block.go
+++ b/src/pkg/crypto/aes/block.go
@@ -56,10 +56,10 @@ func encryptBlock(xk []uint32, dst, src []byte) {
nr := len(xk)/4 - 2 // - 2: one above, one more below
k := 4
for r := 0; r < nr; r++ {
- t0 = xk[k+0] ^ te[0][s0>>24] ^ te[1][s1>>16&0xff] ^ te[2][s2>>8&0xff] ^ te[3][s3&0xff]
- t1 = xk[k+1] ^ te[0][s1>>24] ^ te[1][s2>>16&0xff] ^ te[2][s3>>8&0xff] ^ te[3][s0&0xff]
- t2 = xk[k+2] ^ te[0][s2>>24] ^ te[1][s3>>16&0xff] ^ te[2][s0>>8&0xff] ^ te[3][s1&0xff]
- t3 = xk[k+3] ^ te[0][s3>>24] ^ te[1][s0>>16&0xff] ^ te[2][s1>>8&0xff] ^ te[3][s2&0xff]
+ t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)]
+ t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)]
+ t2 = xk[k+2] ^ te0[uint8(s2>>24)] ^ te1[uint8(s3>>16)] ^ te2[uint8(s0>>8)] ^ te3[uint8(s1)]
+ t3 = xk[k+3] ^ te0[uint8(s3>>24)] ^ te1[uint8(s0>>16)] ^ te2[uint8(s1>>8)] ^ te3[uint8(s2)]
k += 4
s0, s1, s2, s3 = t0, t1, t2, t3
}
@@ -101,10 +101,10 @@ func decryptBlock(xk []uint32, dst, src []byte) {
nr := len(xk)/4 - 2 // - 2: one above, one more below
k := 4
for r := 0; r < nr; r++ {
- t0 = xk[k+0] ^ td[0][s0>>24] ^ td[1][s3>>16&0xff] ^ td[2][s2>>8&0xff] ^ td[3][s1&0xff]
- t1 = xk[k+1] ^ td[0][s1>>24] ^ td[1][s0>>16&0xff] ^ td[2][s3>>8&0xff] ^ td[3][s2&0xff]
- t2 = xk[k+2] ^ td[0][s2>>24] ^ td[1][s1>>16&0xff] ^ td[2][s0>>8&0xff] ^ td[3][s3&0xff]
- t3 = xk[k+3] ^ td[0][s3>>24] ^ td[1][s2>>16&0xff] ^ td[2][s1>>8&0xff] ^ td[3][s0&0xff]
+ t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)]
+ t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)]
+ t2 = xk[k+2] ^ td0[uint8(s2>>24)] ^ td1[uint8(s1>>16)] ^ td2[uint8(s0>>8)] ^ td3[uint8(s3)]
+ t3 = xk[k+3] ^ td0[uint8(s3>>24)] ^ td1[uint8(s2>>16)] ^ td2[uint8(s1>>8)] ^ td3[uint8(s0)]
k += 4
s0, s1, s2, s3 = t0, t1, t2, t3
}
@@ -168,7 +168,7 @@ func expandKey(key []byte, enc, dec []uint32) {
for j := 0; j < 4; j++ {
x := enc[ei+j]
if i > 0 && i+4 < n {
- x = td[0][sbox0[x>>24]] ^ td[1][sbox0[x>>16&0xff]] ^ td[2][sbox0[x>>8&0xff]] ^ td[3][sbox0[x&0xff]]
+ x = td0[sbox0[x>>24]] ^ td1[sbox0[x>>16&0xff]] ^ td2[sbox0[x>>8&0xff]] ^ td3[sbox0[x&0xff]]
}
dec[i+j] = x
}
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index 73223531e..7d307c93a 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/crypto/aes/cipher.go
@@ -5,30 +5,30 @@
package aes
import (
- "os"
+ "crypto/cipher"
"strconv"
)
// The AES block size in bytes.
const BlockSize = 16
-// A Cipher is an instance of AES encryption using a particular key.
-type Cipher struct {
+// A cipher is an instance of AES encryption using a particular key.
+type aesCipher struct {
enc []uint32
dec []uint32
}
type KeySizeError int
-func (k KeySizeError) String() string {
+func (k KeySizeError) Error() string {
return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
}
-// NewCipher creates and returns a new Cipher.
+// NewCipher creates and returns a new cipher.Block.
// The key argument should be the AES key,
// either 16, 24, or 32 bytes to select
// AES-128, AES-192, or AES-256.
-func NewCipher(key []byte) (*Cipher, os.Error) {
+func NewCipher(key []byte) (cipher.Block, error) {
k := len(key)
switch k {
default:
@@ -38,34 +38,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
}
n := k + 28
- c := &Cipher{make([]uint32, n), make([]uint32, n)}
+ c := &aesCipher{make([]uint32, n), make([]uint32, n)}
expandKey(key, c.enc, c.dec)
return c, nil
}
-// BlockSize returns the AES block size, 16 bytes.
-// It is necessary to satisfy the Cipher interface in the
-// package "crypto/cipher".
-func (c *Cipher) BlockSize() int { return BlockSize }
+func (c *aesCipher) 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/cipher/cbc.go).
-func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
+func (c *aesCipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
-// Decrypt decrypts the 16-byte buffer src using the key k
-// and stores the result in dst.
-func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) }
-
-// Reset zeros the key data, so that it will no longer
-// appear in the process's memory.
-func (c *Cipher) Reset() {
- for i := 0; i < len(c.enc); i++ {
- c.enc[i] = 0
- }
- for i := 0; i < len(c.dec); i++ {
- c.dec[i] = 0
- }
-}
+func (c *aesCipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) }
diff --git a/src/pkg/crypto/aes/const.go b/src/pkg/crypto/aes/const.go
index 25acd0d17..f0b4eabf6 100644
--- a/src/pkg/crypto/aes/const.go
+++ b/src/pkg/crypto/aes/const.go
@@ -80,283 +80,279 @@ var sbox1 = [256]byte{
// Lookup tables for encryption.
// These can be recomputed by adapting the tests in aes_test.go.
-var te = [4][256]uint32{
- {
- 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
- 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
- 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
- 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
- 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
- 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
- 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
- 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
- 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
- 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
- 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
- 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
- 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
- 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
- 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
- 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
- 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
- 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
- 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
- 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
- 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
- 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
- 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
- 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
- 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
- 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
- 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
- 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
- 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
- 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
- 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
- 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
- },
- {
- 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
- 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
- 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
- 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
- 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
- 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
- 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
- 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
- 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
- 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
- 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
- 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
- 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
- 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
- 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
- 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
- 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
- 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
- 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
- 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
- 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
- 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
- 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
- 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
- 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
- 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
- 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
- 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
- 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
- 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
- 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
- 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
- },
- {
- 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
- 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
- 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
- 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
- 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
- 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
- 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
- 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
- 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
- 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
- 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
- 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
- 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
- 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
- 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
- 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
- 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
- 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
- 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
- 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
- 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
- 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
- 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
- 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
- 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
- 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
- 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
- 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
- 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
- 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
- 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
- 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
- },
- {
- 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
- 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
- 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
- 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
- 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
- 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
- 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
- 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
- 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
- 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
- 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
- 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
- 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
- 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
- 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
- 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
- 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
- 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
- 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
- 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
- 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
- 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
- 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
- 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
- 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
- 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
- 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
- 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
- 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
- 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
- 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
- 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
- },
+var te0 = [256]uint32{
+ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554,
+ 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
+ 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+ 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
+ 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f,
+ 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+ 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5,
+ 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
+ 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+ 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
+ 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed,
+ 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+ 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594,
+ 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
+ 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+ 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
+ 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739,
+ 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+ 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883,
+ 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
+ 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+ 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
+ 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0,
+ 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+ 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651,
+ 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
+ 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+ 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
+ 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7,
+ 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+ 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
+ 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
+}
+var te1 = [256]uint32{
+ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
+ 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
+ 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+ 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
+ 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
+ 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+ 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
+ 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
+ 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+ 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
+ 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
+ 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+ 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
+ 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
+ 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+ 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
+ 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
+ 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+ 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
+ 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
+ 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+ 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
+ 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
+ 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+ 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
+ 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
+ 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+ 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
+ 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
+ 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+ 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
+ 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+}
+var te2 = [256]uint32{
+ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
+ 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
+ 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+ 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
+ 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
+ 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+ 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
+ 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
+ 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+ 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
+ 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
+ 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+ 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
+ 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
+ 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+ 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
+ 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
+ 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+ 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
+ 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
+ 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+ 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
+ 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
+ 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+ 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
+ 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
+ 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+ 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
+ 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
+ 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+ 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
+ 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+}
+var te3 = [256]uint32{
+ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
+ 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
+ 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+ 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
+ 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
+ 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+ 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
+ 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
+ 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+ 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
+ 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
+ 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+ 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
+ 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
+ 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+ 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
+ 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
+ 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+ 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
+ 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
+ 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+ 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
+ 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
+ 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+ 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
+ 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
+ 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+ 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
+ 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
+ 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+ 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
+ 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
}
// Lookup tables for decryption.
// These can be recomputed by adapting the tests in aes_test.go.
-var td = [4][256]uint32{
- {
- 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
- 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
- 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
- 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
- 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
- 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
- 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
- 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
- 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
- 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
- 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
- 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
- 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
- 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
- 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
- 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
- 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
- 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
- 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
- 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
- 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
- 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
- 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
- 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
- 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
- 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
- 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
- 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
- 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
- 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
- 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
- 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
- },
- {
- 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
- 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
- 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
- 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
- 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
- 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
- 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
- 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
- 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
- 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
- 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
- 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
- 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
- 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
- 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
- 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
- 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
- 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
- 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
- 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
- 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
- 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
- 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
- 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
- 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
- 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
- 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
- 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
- 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
- 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
- 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
- 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
- },
- {
- 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
- 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
- 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
- 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
- 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
- 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
- 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
- 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
- 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
- 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
- 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
- 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
- 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
- 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
- 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
- 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
- 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
- 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
- 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
- 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
- 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
- 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
- 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
- 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
- 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
- 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
- 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
- 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
- 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
- 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
- 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
- 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
- },
- {
- 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
- 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
- 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
- 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
- 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
- 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
- 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
- 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
- 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
- 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
- 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
- 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
- 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
- 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
- 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
- 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
- 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
- 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
- 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
- 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
- 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
- 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
- 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
- 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
- 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
- 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
- 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
- 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
- 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
- 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
- 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
- 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
- },
+var td0 = [256]uint32{
+ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393,
+ 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
+ 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6,
+ 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
+ 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4,
+ 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
+ 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a,
+ 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
+ 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
+ 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
+ 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff,
+ 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
+ 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e,
+ 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
+ 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16,
+ 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
+ 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34,
+ 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
+ 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0,
+ 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
+ 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4,
+ 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
+ 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b,
+ 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
+ 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0,
+ 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
+ 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
+ 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
+ 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c,
+ 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
+ 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
+ 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
+}
+var td1 = [256]uint32{
+ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
+ 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
+ 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+ 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
+ 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
+ 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+ 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
+ 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
+ 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+ 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
+ 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
+ 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+ 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
+ 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
+ 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+ 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
+ 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
+ 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+ 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
+ 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
+ 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+ 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
+ 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
+ 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+ 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
+ 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
+ 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+ 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
+ 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
+ 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+ 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
+ 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
+}
+var td2 = [256]uint32{
+ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
+ 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
+ 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+ 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
+ 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
+ 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+ 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
+ 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
+ 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+ 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
+ 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
+ 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+ 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
+ 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
+ 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+ 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
+ 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
+ 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+ 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
+ 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
+ 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+ 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
+ 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
+ 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+ 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
+ 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
+ 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+ 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
+ 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
+ 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+ 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
+ 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
+}
+var td3 = [256]uint32{
+ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
+ 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
+ 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+ 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
+ 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
+ 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+ 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
+ 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
+ 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+ 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
+ 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
+ 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+ 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
+ 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
+ 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+ 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
+ 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
+ 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+ 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
+ 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
+ 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+ 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
+ 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
+ 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+ 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
+ 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
+ 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+ 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
+ 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
+ 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+ 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
+ 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
}
diff --git a/src/pkg/crypto/blowfish/Makefile b/src/pkg/crypto/blowfish/Makefile
deleted file mode 100644
index f370ab28b..000000000
--- a/src/pkg/crypto/blowfish/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/blowfish
-GOFILES=\
- block.go\
- cipher.go\
- const.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/blowfish/block.go b/src/pkg/crypto/blowfish/block.go
deleted file mode 100644
index 7fbe7eefb..000000000
--- a/src/pkg/crypto/blowfish/block.go
+++ /dev/null
@@ -1,101 +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 blowfish
-
-func expandKey(key []byte, c *Cipher) {
- copy(c.p[0:], p[0:])
- copy(c.s0[0:], s0[0:])
- copy(c.s1[0:], s1[0:])
- copy(c.s2[0:], s2[0:])
- copy(c.s3[0:], s3[0:])
-
- j := 0
- for i := 0; i < 18; i++ {
- var d uint32
- for k := 0; k < 4; k++ {
- d = d<<8 | uint32(key[j])&0x000000FF
- j++
- if j >= len(key) {
- j = 0
- }
- }
- c.p[i] ^= d
- }
-
- var l, r uint32
- for i := 0; i < 18; i += 2 {
- l, r = encryptBlock(l, r, c)
- c.p[i], c.p[i+1] = l, r
- }
-
- for i := 0; i < 256; i += 2 {
- l, r = encryptBlock(l, r, c)
- c.s0[i], c.s0[i+1] = l, r
- }
- for i := 0; i < 256; i += 2 {
- l, r = encryptBlock(l, r, c)
- c.s1[i], c.s1[i+1] = l, r
- }
- for i := 0; i < 256; i += 2 {
- l, r = encryptBlock(l, r, c)
- c.s2[i], c.s2[i+1] = l, r
- }
- for i := 0; i < 256; i += 2 {
- l, r = encryptBlock(l, r, c)
- c.s3[i], c.s3[i+1] = l, r
- }
-}
-
-func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
- xl, xr := l, r
- xl ^= c.p[0]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
- xr ^= c.p[17]
- return xr, xl
-}
-
-func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
- xl, xr := l, r
- xl ^= c.p[17]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
- xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
- xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
- xr ^= c.p[0]
- return xr, xl
-}
-
-func zero(x []uint32) {
- for i := range x {
- x[i] = 0
- }
-}
diff --git a/src/pkg/crypto/blowfish/blowfish_test.go b/src/pkg/crypto/blowfish/blowfish_test.go
deleted file mode 100644
index 3a7ab6c2a..000000000
--- a/src/pkg/crypto/blowfish/blowfish_test.go
+++ /dev/null
@@ -1,192 +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 blowfish
-
-import (
- "testing"
-)
-
-type CryptTest struct {
- key []byte
- in []byte
- out []byte
-}
-
-// Test vector values are from http://www.schneier.com/code/vectors.txt.
-var encryptTests = []CryptTest{
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
- {
- []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- []byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
- {
- []byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
- []byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
- {
- []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
- []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
- []byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
-
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
- []byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
- {
- []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
- {
- []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
- {
- []byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
- []byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
- []byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
- {
- []byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
- []byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
- []byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
- {
- []byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
- []byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
- []byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
- {
- []byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
- []byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
- []byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
- {
- []byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
- []byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
- []byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
- {
- []byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
- []byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
- []byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
- {
- []byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
- []byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
- []byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
- {
- []byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
- []byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
- []byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
- {
- []byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
- []byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
- []byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
- {
- []byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
- []byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
- []byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
- {
- []byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
- []byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
- []byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
- {
- []byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
- []byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
- []byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
- {
- []byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
- []byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
- []byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
- {
- []byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
- []byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
- []byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
- {
- []byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
- []byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
- []byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
- {
- []byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
- []byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
- []byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
- {
- []byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
- []byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
- []byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
- {
- []byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
- []byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
- []byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
- {
- []byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
- []byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
- []byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
- {
- []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
- {
- []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
- {
- []byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- []byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
- {
- []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
- {
- []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
- []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
- []byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
-}
-
-func TestCipherEncrypt(t *testing.T) {
- for i, tt := range encryptTests {
- c, err := NewCipher(tt.key)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
- continue
- }
- ct := make([]byte, len(tt.out))
- c.Encrypt(ct, tt.in)
- for j, v := range ct {
- if v != tt.out[j] {
- t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
- break
- }
- }
- }
-}
-
-func TestCipherDecrypt(t *testing.T) {
- for i, tt := range encryptTests {
- c, err := NewCipher(tt.key)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
- continue
- }
- pt := make([]byte, len(tt.in))
- c.Decrypt(pt, tt.out)
- for j, v := range pt {
- if v != tt.in[j] {
- t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
- break
- }
- }
- }
-}
diff --git a/src/pkg/crypto/blowfish/cipher.go b/src/pkg/crypto/blowfish/cipher.go
deleted file mode 100644
index 6c37dfe94..000000000
--- a/src/pkg/crypto/blowfish/cipher.go
+++ /dev/null
@@ -1,79 +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 blowfish implements Bruce Schneier's Blowfish encryption algorithm.
-package blowfish
-
-// The code is a port of Bruce Schneier's C implementation.
-// See http://www.schneier.com/blowfish.html.
-
-import (
- "os"
- "strconv"
-)
-
-// The Blowfish block size in bytes.
-const BlockSize = 8
-
-// A Cipher is an instance of Blowfish encryption using a particular key.
-type Cipher struct {
- p [18]uint32
- s0, s1, s2, s3 [256]uint32
-}
-
-type KeySizeError int
-
-func (k KeySizeError) String() string {
- return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
-}
-
-// NewCipher creates and returns a Cipher.
-// The key argument should be the Blowfish key, 4 to 56 bytes.
-func NewCipher(key []byte) (*Cipher, os.Error) {
- k := len(key)
- if k < 4 || k > 56 {
- return nil, KeySizeError(k)
- }
- var result Cipher
- expandKey(key, &result)
- return &result, nil
-}
-
-// BlockSize returns the Blowfish block size, 8 bytes.
-// It is necessary to satisfy the Cipher interface in the
-// package "crypto/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/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])
- l, r = encryptBlock(l, r, c)
- dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
- dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
-}
-
-// Decrypt decrypts the 8-byte buffer src using the key k
-// and stores the result in dst.
-func (c *Cipher) Decrypt(dst, src []byte) {
- l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
- r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
- l, r = decryptBlock(l, r, c)
- dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
- dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
-}
-
-// Reset zeros the key data, so that it will no longer
-// appear in the process's memory.
-func (c *Cipher) Reset() {
- zero(c.p[0:])
- zero(c.s0[0:])
- zero(c.s1[0:])
- zero(c.s2[0:])
- zero(c.s3[0:])
-}
diff --git a/src/pkg/crypto/blowfish/const.go b/src/pkg/crypto/blowfish/const.go
deleted file mode 100644
index 8c5ee4cb0..000000000
--- a/src/pkg/crypto/blowfish/const.go
+++ /dev/null
@@ -1,199 +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.
-
-// The startup permutation array and substitution boxes.
-// They are the hexadecimal digits of PI; see:
-// http://www.schneier.com/code/constants.txt.
-
-package blowfish
-
-var s0 = [256]uint32{
- 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
- 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
- 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
- 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
- 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
- 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
- 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
- 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
- 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
- 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
- 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
- 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
- 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
- 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
- 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
- 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
- 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
- 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
- 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
- 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
- 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
- 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
- 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
- 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
- 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
- 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
- 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
- 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
- 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
- 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
- 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
- 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
- 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
- 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
- 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
- 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
- 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
- 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
- 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
- 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
- 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
- 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
- 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
-}
-
-var s1 = [256]uint32{
- 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
- 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
- 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
- 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
- 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
- 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
- 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
- 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
- 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
- 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
- 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
- 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
- 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
- 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
- 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
- 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
- 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
- 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
- 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
- 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
- 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
- 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
- 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
- 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
- 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
- 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
- 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
- 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
- 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
- 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
- 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
- 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
- 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
- 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
- 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
- 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
- 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
- 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
- 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
- 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
- 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
- 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
- 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
-}
-
-var s2 = [256]uint32{
- 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
- 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
- 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
- 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
- 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
- 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
- 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
- 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
- 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
- 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
- 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
- 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
- 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
- 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
- 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
- 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
- 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
- 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
- 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
- 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
- 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
- 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
- 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
- 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
- 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
- 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
- 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
- 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
- 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
- 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
- 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
- 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
- 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
- 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
- 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
- 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
- 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
- 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
- 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
- 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
- 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
- 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
- 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
-}
-
-var s3 = [256]uint32{
- 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
- 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
- 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
- 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
- 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
- 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
- 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
- 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
- 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
- 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
- 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
- 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
- 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
- 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
- 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
- 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
- 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
- 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
- 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
- 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
- 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
- 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
- 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
- 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
- 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
- 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
- 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
- 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
- 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
- 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
- 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
- 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
- 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
- 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
- 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
- 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
- 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
- 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
- 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
- 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
- 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
- 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
- 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
-}
-
-var p = [18]uint32{
- 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
- 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
- 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
-}
diff --git a/src/pkg/crypto/cast5/Makefile b/src/pkg/crypto/cast5/Makefile
deleted file mode 100644
index 346fadd94..000000000
--- a/src/pkg/crypto/cast5/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/cast5
-GOFILES=\
- cast5.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/cast5/cast5.go b/src/pkg/crypto/cast5/cast5.go
deleted file mode 100644
index e9d4a24e2..000000000
--- a/src/pkg/crypto/cast5/cast5.go
+++ /dev/null
@@ -1,536 +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 cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
-// OpenPGP cipher.
-package cast5
-
-import (
- "os"
-)
-
-const BlockSize = 8
-const KeySize = 16
-
-type Cipher struct {
- masking [16]uint32
- rotate [16]uint8
-}
-
-func NewCipher(key []byte) (c *Cipher, err os.Error) {
- if len(key) != KeySize {
- return nil, os.NewError("CAST5: keys must be 16 bytes")
- }
-
- c = new(Cipher)
- c.keySchedule(key)
- return
-}
-
-func (c *Cipher) BlockSize() int {
- return BlockSize
-}
-
-// Reset zeros the key material in memory.
-func (c *Cipher) Reset() {
- for i := 0; i < 16; i++ {
- c.masking[i] = 0
- c.rotate[i] = 0
- }
-}
-
-func (c *Cipher) Encrypt(dst, src []byte) {
- l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
- r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
-
- l, r = r, l^f1(r, c.masking[0], c.rotate[0])
- l, r = r, l^f2(r, c.masking[1], c.rotate[1])
- l, r = r, l^f3(r, c.masking[2], c.rotate[2])
- l, r = r, l^f1(r, c.masking[3], c.rotate[3])
-
- l, r = r, l^f2(r, c.masking[4], c.rotate[4])
- l, r = r, l^f3(r, c.masking[5], c.rotate[5])
- l, r = r, l^f1(r, c.masking[6], c.rotate[6])
- l, r = r, l^f2(r, c.masking[7], c.rotate[7])
-
- l, r = r, l^f3(r, c.masking[8], c.rotate[8])
- l, r = r, l^f1(r, c.masking[9], c.rotate[9])
- l, r = r, l^f2(r, c.masking[10], c.rotate[10])
- l, r = r, l^f3(r, c.masking[11], c.rotate[11])
-
- l, r = r, l^f1(r, c.masking[12], c.rotate[12])
- l, r = r, l^f2(r, c.masking[13], c.rotate[13])
- l, r = r, l^f3(r, c.masking[14], c.rotate[14])
- l, r = r, l^f1(r, c.masking[15], c.rotate[15])
-
- dst[0] = uint8(r >> 24)
- dst[1] = uint8(r >> 16)
- dst[2] = uint8(r >> 8)
- dst[3] = uint8(r)
- dst[4] = uint8(l >> 24)
- dst[5] = uint8(l >> 16)
- dst[6] = uint8(l >> 8)
- dst[7] = uint8(l)
-}
-
-func (c *Cipher) Decrypt(dst, src []byte) {
- l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
- r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
-
- l, r = r, l^f1(r, c.masking[15], c.rotate[15])
- l, r = r, l^f3(r, c.masking[14], c.rotate[14])
- l, r = r, l^f2(r, c.masking[13], c.rotate[13])
- l, r = r, l^f1(r, c.masking[12], c.rotate[12])
-
- l, r = r, l^f3(r, c.masking[11], c.rotate[11])
- l, r = r, l^f2(r, c.masking[10], c.rotate[10])
- l, r = r, l^f1(r, c.masking[9], c.rotate[9])
- l, r = r, l^f3(r, c.masking[8], c.rotate[8])
-
- l, r = r, l^f2(r, c.masking[7], c.rotate[7])
- l, r = r, l^f1(r, c.masking[6], c.rotate[6])
- l, r = r, l^f3(r, c.masking[5], c.rotate[5])
- l, r = r, l^f2(r, c.masking[4], c.rotate[4])
-
- l, r = r, l^f1(r, c.masking[3], c.rotate[3])
- l, r = r, l^f3(r, c.masking[2], c.rotate[2])
- l, r = r, l^f2(r, c.masking[1], c.rotate[1])
- l, r = r, l^f1(r, c.masking[0], c.rotate[0])
-
- dst[0] = uint8(r >> 24)
- dst[1] = uint8(r >> 16)
- dst[2] = uint8(r >> 8)
- dst[3] = uint8(r)
- dst[4] = uint8(l >> 24)
- dst[5] = uint8(l >> 16)
- dst[6] = uint8(l >> 8)
- dst[7] = uint8(l)
-}
-
-type keyScheduleA [4][7]uint8
-type keyScheduleB [4][5]uint8
-
-// keyScheduleRound contains the magic values for a round of the key schedule.
-// The keyScheduleA deals with the lines like:
-// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
-// Conceptually, both x and z are in the same array, x first. The first
-// element describes which word of this array gets written to and the
-// second, which word gets read. So, for the line above, it's "4, 0", because
-// it's writing to the first word of z, which, being after x, is word 4, and
-// reading from the first word of x: word 0.
-//
-// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
-// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
-// that it's z that we're indexing.
-//
-// keyScheduleB deals with lines like:
-// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
-// "K1" is ignored because key words are always written in order. So the five
-// elements are the S-box indexes. They use the same form as in keyScheduleA,
-// above.
-
-type keyScheduleRound struct{}
-type keySchedule []keyScheduleRound
-
-var schedule = []struct {
- a keyScheduleA
- b keyScheduleB
-}{
- {
- keyScheduleA{
- {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
- {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
- {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
- {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
- },
- keyScheduleB{
- {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
- {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
- {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
- {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
- },
- },
- {
- keyScheduleA{
- {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
- {1, 4, 0, 2, 1, 3, 16 + 2},
- {2, 5, 7, 6, 5, 4, 16 + 1},
- {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
- },
- keyScheduleB{
- {3, 2, 0xc, 0xd, 8},
- {1, 0, 0xe, 0xf, 0xd},
- {7, 6, 8, 9, 3},
- {5, 4, 0xa, 0xb, 7},
- },
- },
- {
- keyScheduleA{
- {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
- {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
- {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
- {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
- },
- keyScheduleB{
- {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
- {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
- {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
- {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
- },
- },
- {
- keyScheduleA{
- {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
- {1, 4, 0, 2, 1, 3, 16 + 2},
- {2, 5, 7, 6, 5, 4, 16 + 1},
- {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
- },
- keyScheduleB{
- {8, 9, 7, 6, 3},
- {0xa, 0xb, 5, 4, 7},
- {0xc, 0xd, 3, 2, 8},
- {0xe, 0xf, 1, 0, 0xd},
- },
- },
-}
-
-func (c *Cipher) keySchedule(in []byte) {
- var t [8]uint32
- var k [32]uint32
-
- for i := 0; i < 4; i++ {
- j := i * 4
- t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
- }
-
- x := []byte{6, 7, 4, 5}
- ki := 0
-
- for half := 0; half < 2; half++ {
- for _, round := range schedule {
- for j := 0; j < 4; j++ {
- var a [7]uint8
- copy(a[:], round.a[j][:])
- w := t[a[1]]
- w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
- w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
- w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
- w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
- w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
- t[a[0]] = w
- }
-
- for j := 0; j < 4; j++ {
- var b [5]uint8
- copy(b[:], round.b[j][:])
- w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
- w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
- w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
- w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
- w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
- k[ki] = w
- ki++
- }
- }
- }
-
- for i := 0; i < 16; i++ {
- c.masking[i] = k[i]
- c.rotate[i] = uint8(k[16+i] & 0x1f)
- }
-}
-
-// These are the three 'f' functions. See RFC 2144, section 2.2.
-func f1(d, m uint32, r uint8) uint32 {
- t := m + d
- I := (t << r) | (t >> (32 - r))
- return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
-}
-
-func f2(d, m uint32, r uint8) uint32 {
- t := m ^ d
- I := (t << r) | (t >> (32 - r))
- return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
-}
-
-func f3(d, m uint32, r uint8) uint32 {
- t := m - d
- I := (t << r) | (t >> (32 - r))
- return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
-}
-
-var sBox = [8][256]uint32{
- {
- 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
- 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
- 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
- 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
- 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
- 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
- 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
- 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
- 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
- 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
- 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
- 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
- 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
- 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
- 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
- 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
- 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
- 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
- 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
- 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
- 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
- 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
- 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
- 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
- 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
- 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
- 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
- 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
- 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
- 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
- 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
- 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
- },
- {
- 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
- 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
- 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
- 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
- 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
- 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
- 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
- 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
- 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
- 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
- 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
- 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
- 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
- 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
- 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
- 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
- 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
- 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
- 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
- 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
- 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
- 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
- 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
- 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
- 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
- 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
- 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
- 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
- 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
- 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
- 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
- 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
- },
- {
- 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
- 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
- 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
- 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
- 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
- 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
- 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
- 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
- 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
- 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
- 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
- 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
- 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
- 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
- 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
- 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
- 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
- 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
- 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
- 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
- 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
- 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
- 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
- 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
- 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
- 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
- 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
- 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
- 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
- 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
- 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
- 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
- },
- {
- 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
- 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
- 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
- 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
- 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
- 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
- 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
- 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
- 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
- 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
- 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
- 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
- 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
- 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
- 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
- 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
- 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
- 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
- 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
- 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
- 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
- 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
- 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
- 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
- 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
- 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
- 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
- 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
- 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
- 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
- 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
- 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
- },
- {
- 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
- 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
- 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
- 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
- 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
- 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
- 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
- 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
- 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
- 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
- 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
- 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
- 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
- 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
- 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
- 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
- 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
- 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
- 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
- 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
- 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
- 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
- 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
- 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
- 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
- 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
- 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
- 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
- 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
- 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
- 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
- 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
- },
- {
- 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
- 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
- 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
- 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
- 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
- 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
- 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
- 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
- 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
- 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
- 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
- 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
- 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
- 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
- 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
- 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
- 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
- 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
- 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
- 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
- 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
- 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
- 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
- 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
- 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
- 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
- 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
- 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
- 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
- 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
- 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
- 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
- },
- {
- 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
- 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
- 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
- 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
- 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
- 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
- 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
- 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
- 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
- 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
- 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
- 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
- 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
- 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
- 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
- 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
- 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
- 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
- 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
- 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
- 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
- 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
- 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
- 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
- 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
- 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
- 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
- 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
- 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
- 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
- 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
- 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
- },
- {
- 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
- 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
- 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
- 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
- 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
- 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
- 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
- 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
- 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
- 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
- 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
- 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
- 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
- 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
- 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
- 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
- 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
- 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
- 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
- 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
- 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
- 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
- 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
- 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
- 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
- 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
- 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
- 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
- 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
- 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
- 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
- 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
- },
-}
diff --git a/src/pkg/crypto/cast5/cast5_test.go b/src/pkg/crypto/cast5/cast5_test.go
deleted file mode 100644
index 5f7025ff2..000000000
--- a/src/pkg/crypto/cast5/cast5_test.go
+++ /dev/null
@@ -1,104 +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 cast5
-
-import (
- "bytes"
- "encoding/hex"
- "testing"
-)
-
-// This test vector is taken from RFC 2144, App B.1.
-// Since the other two test vectors are for reduced-round variants, we can't
-// use them.
-var basicTests = []struct {
- key, plainText, cipherText string
-}{
- {
- "0123456712345678234567893456789a",
- "0123456789abcdef",
- "238b4fe5847e44b2",
- },
-}
-
-func TestBasic(t *testing.T) {
- for i, test := range basicTests {
- key, _ := hex.DecodeString(test.key)
- plainText, _ := hex.DecodeString(test.plainText)
- expected, _ := hex.DecodeString(test.cipherText)
-
- c, err := NewCipher(key)
- if err != nil {
- t.Errorf("#%d: failed to create Cipher: %s", i, err)
- continue
- }
- var cipherText [BlockSize]byte
- c.Encrypt(cipherText[:], plainText)
- if !bytes.Equal(cipherText[:], expected) {
- t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
- }
-
- var plainTextAgain [BlockSize]byte
- c.Decrypt(plainTextAgain[:], cipherText[:])
- if !bytes.Equal(plainTextAgain[:], plainText) {
- t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
- }
- }
-}
-
-// TestFull performs the test specified in RFC 2144, App B.2.
-// However, due to the length of time taken, it's disabled here and a more
-// limited version is included, below.
-func TestFull(t *testing.T) {
- // This is too slow for normal testing
- return
-
- a, b := iterate(1000000)
-
- const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
- const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
-
- if hex.EncodeToString(a) != expectedA {
- t.Errorf("a: got:%x want:%s", a, expectedA)
- }
- if hex.EncodeToString(b) != expectedB {
- t.Errorf("b: got:%x want:%s", b, expectedB)
- }
-}
-
-func iterate(iterations int) ([]byte, []byte) {
- const initValueHex = "0123456712345678234567893456789a"
-
- initValue, _ := hex.DecodeString(initValueHex)
-
- var a, b [16]byte
- copy(a[:], initValue)
- copy(b[:], initValue)
-
- for i := 0; i < iterations; i++ {
- c, _ := NewCipher(b[:])
- c.Encrypt(a[:8], a[:8])
- c.Encrypt(a[8:], a[8:])
- c, _ = NewCipher(a[:])
- c.Encrypt(b[:8], b[:8])
- c.Encrypt(b[8:], b[8:])
- }
-
- return a[:], b[:]
-}
-
-func TestLimited(t *testing.T) {
- a, b := iterate(1000)
-
- const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
- const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
-
- if hex.EncodeToString(a) != expectedA {
- t.Errorf("a: got:%x want:%s", a, expectedA)
- }
- if hex.EncodeToString(b) != expectedB {
- t.Errorf("b: got:%x want:%s", b, expectedB)
- }
-}
diff --git a/src/pkg/crypto/cipher/Makefile b/src/pkg/crypto/cipher/Makefile
deleted file mode 100644
index 8f61cf20b..000000000
--- a/src/pkg/crypto/cipher/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/cipher
-GOFILES=\
- cbc.go\
- cfb.go\
- cipher.go\
- ctr.go\
- io.go\
- ocfb.go\
- ofb.go
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
index 4632f882a..a48929cf5 100644
--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -56,7 +56,7 @@ type cbcDecrypter cbc
// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
// mode, using the given Block. The length of iv must be the same as the
-// Block's block size as must match the iv used to encrypt the data.
+// Block's block size and must match the iv used to encrypt the data.
func NewCBCDecrypter(b Block, iv []byte) BlockMode {
return (*cbcDecrypter)(newCBC(b, iv))
}
diff --git a/src/pkg/crypto/cipher/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
index 944ca1ba8..cee3a784b 100644
--- a/src/pkg/crypto/cipher/cbc_aes_test.go
+++ b/src/pkg/crypto/cipher/cbc_aes_test.go
@@ -8,11 +8,12 @@
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 24-29.
-package cipher
+package cipher_test
import (
"bytes"
"crypto/aes"
+ "crypto/cipher"
"testing"
)
@@ -72,14 +73,14 @@ func TestCBC_AES(t *testing.T) {
continue
}
- encrypter := NewCBCEncrypter(c, tt.iv)
+ encrypter := cipher.NewCBCEncrypter(c, tt.iv)
d := make([]byte, len(tt.in))
encrypter.CryptBlocks(d, tt.in)
if !bytes.Equal(tt.out, d) {
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
}
- decrypter := NewCBCDecrypter(c, tt.iv)
+ decrypter := cipher.NewCBCDecrypter(c, tt.iv)
p := make([]byte, len(d))
decrypter.CryptBlocks(p, d)
if !bytes.Equal(tt.in, p) {
diff --git a/src/pkg/crypto/cipher/cfb_test.go b/src/pkg/crypto/cipher/cfb_test.go
index 9547bfceb..f704b337e 100644
--- a/src/pkg/crypto/cipher/cfb_test.go
+++ b/src/pkg/crypto/cipher/cfb_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package cipher
+package cipher_test
import (
"bytes"
"crypto/aes"
+ "crypto/cipher"
"crypto/rand"
"testing"
)
@@ -21,11 +22,11 @@ func TestCFB(t *testing.T) {
plaintext := []byte("this is the plaintext")
iv := make([]byte, block.BlockSize())
rand.Reader.Read(iv)
- cfb := NewCFBEncrypter(block, iv)
+ cfb := cipher.NewCFBEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
cfb.XORKeyStream(ciphertext, plaintext)
- cfbdec := NewCFBDecrypter(block, iv)
+ cfbdec := cipher.NewCFBDecrypter(block, iv)
plaintextCopy := make([]byte, len(plaintext))
cfbdec.XORKeyStream(plaintextCopy, ciphertext)
diff --git a/src/pkg/crypto/cipher/common_test.go b/src/pkg/crypto/cipher/common_test.go
index fb755757c..c75c919d1 100644
--- a/src/pkg/crypto/cipher/common_test.go
+++ b/src/pkg/crypto/cipher/common_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 cipher
+package cipher_test
// Common values for tests.
diff --git a/src/pkg/crypto/cipher/ctr_aes_test.go b/src/pkg/crypto/cipher/ctr_aes_test.go
index 8dca9968c..d019ae0d0 100644
--- a/src/pkg/crypto/cipher/ctr_aes_test.go
+++ b/src/pkg/crypto/cipher/ctr_aes_test.go
@@ -8,11 +8,12 @@
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 55-58.
-package cipher
+package cipher_test
import (
"bytes"
"crypto/aes"
+ "crypto/cipher"
"testing"
)
@@ -76,7 +77,7 @@ func TestCTR_AES(t *testing.T) {
for j := 0; j <= 5; j += 5 {
in := tt.in[0 : len(tt.in)-j]
- ctr := NewCTR(c, tt.iv)
+ ctr := cipher.NewCTR(c, tt.iv)
encrypted := make([]byte, len(in))
ctr.XORKeyStream(encrypted, in)
if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
@@ -86,7 +87,7 @@ func TestCTR_AES(t *testing.T) {
for j := 0; j <= 7; j += 7 {
in := tt.out[0 : len(tt.out)-j]
- ctr := NewCTR(c, tt.iv)
+ ctr := cipher.NewCTR(c, tt.iv)
plain := make([]byte, len(in))
ctr.XORKeyStream(plain, in)
if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
diff --git a/src/pkg/crypto/cipher/io.go b/src/pkg/crypto/cipher/io.go
index 97f40b8e7..76048fbf3 100644
--- a/src/pkg/crypto/cipher/io.go
+++ b/src/pkg/crypto/cipher/io.go
@@ -4,37 +4,34 @@
package cipher
-import (
- "os"
- "io"
-)
+import "io"
// The Stream* objects are so simple that all their members are public. Users
// can create them themselves.
-// StreamReader wraps a Stream into an io.Reader. It simply calls XORKeyStream
+// StreamReader wraps a Stream into an io.Reader. It calls XORKeyStream
// to process each slice of data which passes through.
type StreamReader struct {
S Stream
R io.Reader
}
-func (r StreamReader) Read(dst []byte) (n int, err os.Error) {
+func (r StreamReader) Read(dst []byte) (n int, err error) {
n, err = r.R.Read(dst)
r.S.XORKeyStream(dst[:n], dst[:n])
return
}
-// StreamWriter wraps a Stream into an io.Writer. It simply calls XORKeyStream
+// StreamWriter wraps a Stream into an io.Writer. It calls XORKeyStream
// to process each slice of data which passes through. If any Write call
// returns short then the StreamWriter is out of sync and must be discarded.
type StreamWriter struct {
S Stream
W io.Writer
- Err os.Error
+ Err error
}
-func (w StreamWriter) Write(src []byte) (n int, err os.Error) {
+func (w StreamWriter) Write(src []byte) (n int, err error) {
if w.Err != nil {
return 0, w.Err
}
@@ -50,7 +47,7 @@ func (w StreamWriter) Write(src []byte) (n int, err os.Error) {
return
}
-func (w StreamWriter) Close() os.Error {
+func (w StreamWriter) Close() error {
// This saves us from either requiring a WriteCloser or having a
// StreamWriterCloser.
return w.W.(io.Closer).Close()
diff --git a/src/pkg/crypto/cipher/ocfb.go b/src/pkg/crypto/cipher/ocfb.go
deleted file mode 100644
index 031e74a9d..000000000
--- a/src/pkg/crypto/cipher/ocfb.go
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
-
-package cipher
-
-type ocfbEncrypter struct {
- b Block
- fre []byte
- outUsed int
-}
-
-// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
-// performed.
-type OCFBResyncOption bool
-
-const (
- OCFBResync OCFBResyncOption = true
- OCFBNoResync OCFBResyncOption = false
-)
-
-// NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
-// feedback mode using the given Block, and an initial amount of ciphertext.
-// randData must be random bytes and be the same length as the Block's block
-// size. Resync determines if the "resynchronization step" from RFC 4880, 13.9
-// step 7 is performed. Different parts of OpenPGP vary on this point.
-func NewOCFBEncrypter(block Block, randData []byte, resync OCFBResyncOption) (Stream, []byte) {
- blockSize := block.BlockSize()
- if len(randData) != blockSize {
- return nil, nil
- }
-
- x := &ocfbEncrypter{
- b: block,
- fre: make([]byte, blockSize),
- outUsed: 0,
- }
- prefix := make([]byte, blockSize+2)
-
- block.Encrypt(x.fre, x.fre)
- for i := 0; i < blockSize; i++ {
- prefix[i] = randData[i] ^ x.fre[i]
- }
-
- block.Encrypt(x.fre, prefix[:blockSize])
- prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
- prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
-
- if resync {
- block.Encrypt(x.fre, prefix[2:])
- } else {
- x.fre[0] = prefix[blockSize]
- x.fre[1] = prefix[blockSize+1]
- x.outUsed = 2
- }
- return x, prefix
-}
-
-func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.fre) {
- x.b.Encrypt(x.fre, x.fre)
- x.outUsed = 0
- }
-
- x.fre[x.outUsed] ^= src[i]
- dst[i] = x.fre[x.outUsed]
- x.outUsed++
- }
-}
-
-type ocfbDecrypter struct {
- b Block
- fre []byte
- outUsed int
-}
-
-// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
-// feedback mode using the given Block. Prefix must be the first blockSize + 2
-// bytes of the ciphertext, where blockSize is the Block's block size. If an
-// incorrect key is detected then nil is returned. On successful exit,
-// blockSize+2 bytes of decrypted data are written into prefix. Resync
-// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is
-// performed. Different parts of OpenPGP vary on this point.
-func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
- blockSize := block.BlockSize()
- if len(prefix) != blockSize+2 {
- return nil
- }
-
- x := &ocfbDecrypter{
- b: block,
- fre: make([]byte, blockSize),
- outUsed: 0,
- }
- prefixCopy := make([]byte, len(prefix))
- copy(prefixCopy, prefix)
-
- block.Encrypt(x.fre, x.fre)
- for i := 0; i < blockSize; i++ {
- prefixCopy[i] ^= x.fre[i]
- }
-
- block.Encrypt(x.fre, prefix[:blockSize])
- prefixCopy[blockSize] ^= x.fre[0]
- prefixCopy[blockSize+1] ^= x.fre[1]
-
- if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
- prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
- return nil
- }
-
- if resync {
- block.Encrypt(x.fre, prefix[2:])
- } else {
- x.fre[0] = prefix[blockSize]
- x.fre[1] = prefix[blockSize+1]
- x.outUsed = 2
- }
- copy(prefix, prefixCopy)
- return x
-}
-
-func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
- for i := 0; i < len(src); i++ {
- if x.outUsed == len(x.fre) {
- x.b.Encrypt(x.fre, x.fre)
- x.outUsed = 0
- }
-
- c := src[i]
- dst[i] = x.fre[x.outUsed] ^ src[i]
- x.fre[x.outUsed] = c
- x.outUsed++
- }
-}
diff --git a/src/pkg/crypto/cipher/ocfb_test.go b/src/pkg/crypto/cipher/ocfb_test.go
deleted file mode 100644
index 40938b589..000000000
--- a/src/pkg/crypto/cipher/ocfb_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cipher
-
-import (
- "bytes"
- "crypto/aes"
- "crypto/rand"
- "testing"
-)
-
-func testOCFB(t *testing.T, resync OCFBResyncOption) {
- block, err := aes.NewCipher(commonKey128)
- if err != nil {
- t.Error(err)
- return
- }
-
- plaintext := []byte("this is the plaintext, which is long enough to span several blocks.")
- randData := make([]byte, block.BlockSize())
- rand.Reader.Read(randData)
- ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
- ciphertext := make([]byte, len(plaintext))
- ocfb.XORKeyStream(ciphertext, plaintext)
-
- ocfbdec := NewOCFBDecrypter(block, prefix, resync)
- if ocfbdec == nil {
- t.Errorf("NewOCFBDecrypter failed (resync: %t)", resync)
- return
- }
- plaintextCopy := make([]byte, len(plaintext))
- ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
-
- if !bytes.Equal(plaintextCopy, plaintext) {
- t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync)
- }
-}
-
-func TestOCFB(t *testing.T) {
- testOCFB(t, OCFBNoResync)
- testOCFB(t, OCFBResync)
-}
diff --git a/src/pkg/crypto/cipher/ofb_test.go b/src/pkg/crypto/cipher/ofb_test.go
index 9b4495c88..8d3c5d3a3 100644
--- a/src/pkg/crypto/cipher/ofb_test.go
+++ b/src/pkg/crypto/cipher/ofb_test.go
@@ -8,11 +8,12 @@
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 52-55.
-package cipher
+package cipher_test
import (
"bytes"
"crypto/aes"
+ "crypto/cipher"
"testing"
)
@@ -76,7 +77,7 @@ func TestOFB(t *testing.T) {
for j := 0; j <= 5; j += 5 {
plaintext := tt.in[0 : len(tt.in)-j]
- ofb := NewOFB(c, tt.iv)
+ ofb := cipher.NewOFB(c, tt.iv)
ciphertext := make([]byte, len(plaintext))
ofb.XORKeyStream(ciphertext, plaintext)
if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) {
@@ -86,7 +87,7 @@ func TestOFB(t *testing.T) {
for j := 0; j <= 5; j += 5 {
ciphertext := tt.out[0 : len(tt.in)-j]
- ofb := NewOFB(c, tt.iv)
+ ofb := cipher.NewOFB(c, tt.iv)
plaintext := make([]byte, len(ciphertext))
ofb.XORKeyStream(plaintext, ciphertext)
if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) {
diff --git a/src/pkg/crypto/crypto.go b/src/pkg/crypto/crypto.go
index 53672a4da..ecefc6572 100644
--- a/src/pkg/crypto/crypto.go
+++ b/src/pkg/crypto/crypto.go
@@ -14,15 +14,15 @@ import (
type Hash uint
const (
- MD4 Hash = 1 + iota // in package crypto/md4
- MD5 // in package crypto/md5
- SHA1 // in package crypto/sha1
- SHA224 // in package crypto/sha256
- SHA256 // in package crypto/sha256
- SHA384 // in package crypto/sha512
- SHA512 // in package crypto/sha512
+ MD4 Hash = 1 + iota // import code.google.com/p/go.crypto/md4
+ MD5 // import crypto/md5
+ SHA1 // import crypto/sha1
+ SHA224 // import crypto/sha256
+ SHA256 // import crypto/sha256
+ SHA384 // import crypto/sha512
+ SHA512 // import crypto/sha512
MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
- RIPEMD160 // in package crypto/ripemd160
+ RIPEMD160 // import code.google.com/p/go.crypto/ripemd160
maxHash
)
@@ -50,8 +50,8 @@ func (h Hash) Size() int {
var hashes = make([]func() hash.Hash, maxHash)
-// New returns a new hash.Hash calculating the given hash function. If the
-// hash function is not linked into the binary, New returns nil.
+// New returns a new hash.Hash calculating the given hash function. New panics
+// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
if h > 0 && h < maxHash {
f := hashes[h]
@@ -59,7 +59,12 @@ func (h Hash) New() hash.Hash {
return f()
}
}
- return nil
+ panic("crypto: requested hash function is unavailable")
+}
+
+// Available reports whether the given hash function is linked into the binary.
+func (h Hash) Available() bool {
+ return h < maxHash && hashes[h] != nil
}
// RegisterHash registers a function that returns a new instance of the given
@@ -71,3 +76,6 @@ func RegisterHash(h Hash, f func() hash.Hash) {
}
hashes[h] = f
}
+
+// PrivateKey represents a private key using an unspecified algorithm.
+type PrivateKey interface{}
diff --git a/src/pkg/crypto/des/Makefile b/src/pkg/crypto/des/Makefile
deleted file mode 100644
index 94b0fc0fa..000000000
--- a/src/pkg/crypto/des/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/des
-GOFILES=\
- block.go\
- cipher.go\
- const.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/des/block.go b/src/pkg/crypto/des/block.go
index e18eaedf5..c11c62cd7 100644
--- a/src/pkg/crypto/des/block.go
+++ b/src/pkg/crypto/des/block.go
@@ -79,7 +79,7 @@ func ksRotate(in uint32) (out []uint32) {
}
// creates 16 56-bit subkeys from the original key
-func (c *Cipher) generateSubkeys(keyBytes []byte) {
+func (c *desCipher) generateSubkeys(keyBytes []byte) {
// apply PC1 permutation to key
key := binary.BigEndian.Uint64(keyBytes)
permutedKey := permuteBlock(key, permutedChoice1[:])
diff --git a/src/pkg/crypto/des/cipher.go b/src/pkg/crypto/des/cipher.go
index d17a1a783..2f929ca7b 100644
--- a/src/pkg/crypto/des/cipher.go
+++ b/src/pkg/crypto/des/cipher.go
@@ -5,7 +5,7 @@
package des
import (
- "os"
+ "crypto/cipher"
"strconv"
)
@@ -14,90 +14,60 @@ const BlockSize = 8
type KeySizeError int
-func (k KeySizeError) String() string {
+func (k KeySizeError) Error() string {
return "crypto/des: invalid key size " + strconv.Itoa(int(k))
}
-// Cipher is an instance of DES encryption.
-type Cipher struct {
+// desCipher is an instance of DES encryption.
+type desCipher struct {
subkeys [16]uint64
}
-// NewCipher creates and returns a new Cipher.
-func NewCipher(key []byte) (*Cipher, os.Error) {
+// NewCipher creates and returns a new cipher.Block.
+func NewCipher(key []byte) (cipher.Block, error) {
if len(key) != 8 {
return nil, KeySizeError(len(key))
}
- c := new(Cipher)
+ c := new(desCipher)
c.generateSubkeys(key)
return c, nil
}
-// BlockSize returns the DES block size, 8 bytes.
-func (c *Cipher) BlockSize() int { return BlockSize }
+func (c *desCipher) BlockSize() int { return BlockSize }
-// Encrypts the 8-byte buffer src and stores the result in dst.
-// Note that for amounts of data larger than a block,
-// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
-func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
+func (c *desCipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
-// Decrypts the 8-byte buffer src and stores the result in dst.
-func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
+func (c *desCipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
-// Reset zeros the key data, so that it will no longer
-// appear in the process's memory.
-func (c *Cipher) Reset() {
- for i := 0; i < len(c.subkeys); i++ {
- c.subkeys[i] = 0
- }
-}
-
-// A TripleDESCipher is an instance of TripleDES encryption.
-type TripleDESCipher struct {
- cipher1, cipher2, cipher3 Cipher
+// A tripleDESCipher is an instance of TripleDES encryption.
+type tripleDESCipher struct {
+ cipher1, cipher2, cipher3 desCipher
}
-// NewCipher creates and returns a new Cipher.
-func NewTripleDESCipher(key []byte) (*TripleDESCipher, os.Error) {
+// NewTripleDESCipher creates and returns a new cipher.Block.
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
if len(key) != 24 {
return nil, KeySizeError(len(key))
}
- c := new(TripleDESCipher)
+ c := new(tripleDESCipher)
c.cipher1.generateSubkeys(key[:8])
c.cipher2.generateSubkeys(key[8:16])
c.cipher3.generateSubkeys(key[16:])
return c, nil
}
-// BlockSize returns the TripleDES block size, 8 bytes.
-// It is necessary to satisfy the Block interface in the
-// package "crypto/cipher".
-func (c *TripleDESCipher) BlockSize() int { return BlockSize }
+func (c *tripleDESCipher) BlockSize() int { return BlockSize }
-// Encrypts the 8-byte buffer src and stores the result in dst.
-// Note that for amounts of data larger than a block,
-// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
-func (c *TripleDESCipher) Encrypt(dst, src []byte) {
+func (c *tripleDESCipher) Encrypt(dst, src []byte) {
c.cipher1.Encrypt(dst, src)
c.cipher2.Decrypt(dst, dst)
c.cipher3.Encrypt(dst, dst)
}
-// Decrypts the 8-byte buffer src and stores the result in dst.
-func (c *TripleDESCipher) Decrypt(dst, src []byte) {
+func (c *tripleDESCipher) Decrypt(dst, src []byte) {
c.cipher3.Decrypt(dst, src)
c.cipher2.Encrypt(dst, dst)
c.cipher1.Decrypt(dst, dst)
}
-
-// Reset zeros the key data, so that it will no longer
-// appear in the process's memory.
-func (c *TripleDESCipher) Reset() {
- c.cipher1.Reset()
- c.cipher2.Reset()
- c.cipher3.Reset()
-}
diff --git a/src/pkg/crypto/des/des_test.go b/src/pkg/crypto/des/des_test.go
index d1f3aa71a..e9fc23629 100644
--- a/src/pkg/crypto/des/des_test.go
+++ b/src/pkg/crypto/des/des_test.go
@@ -1260,11 +1260,19 @@ var tableA4Tests = []CryptTest{
[]byte{0x63, 0xfa, 0xc0, 0xd0, 0x34, 0xd9, 0xf7, 0x93}},
}
+func newCipher(key []byte) *desCipher {
+ c, err := NewCipher(key)
+ if err != nil {
+ panic("NewCipher failed: " + err.Error())
+ }
+ return c.(*desCipher)
+}
+
// Use the known weak keys to test DES implementation
func TestWeakKeys(t *testing.T) {
for i, tt := range weakKeyTests {
var encrypt = func(in []byte) (out []byte) {
- c, _ := NewCipher(tt.key)
+ c := newCipher(tt.key)
out = make([]byte, len(in))
encryptBlock(c.subkeys[:], out, in)
return
@@ -1285,7 +1293,7 @@ func TestWeakKeys(t *testing.T) {
func TestSemiWeakKeyPairs(t *testing.T) {
for i, tt := range semiWeakKeyTests {
var encrypt = func(key, in []byte) (out []byte) {
- c, _ := NewCipher(key)
+ c := newCipher(key)
out = make([]byte, len(in))
encryptBlock(c.subkeys[:], out, in)
return
@@ -1305,7 +1313,7 @@ func TestSemiWeakKeyPairs(t *testing.T) {
func TestDESEncryptBlock(t *testing.T) {
for i, tt := range encryptDESTests {
- c, _ := NewCipher(tt.key)
+ c := newCipher(tt.key)
out := make([]byte, len(tt.in))
encryptBlock(c.subkeys[:], out, tt.in)
@@ -1317,7 +1325,7 @@ func TestDESEncryptBlock(t *testing.T) {
func TestDESDecryptBlock(t *testing.T) {
for i, tt := range encryptDESTests {
- c, _ := NewCipher(tt.key)
+ c := newCipher(tt.key)
plain := make([]byte, len(tt.in))
decryptBlock(c.subkeys[:], plain, tt.out)
diff --git a/src/pkg/crypto/dsa/Makefile b/src/pkg/crypto/dsa/Makefile
deleted file mode 100644
index fa89d4ab2..000000000
--- a/src/pkg/crypto/dsa/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/dsa
-GOFILES=\
- dsa.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index a5f96fe94..05766a2f1 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3
+// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
package dsa
import (
- "big"
+ "errors"
"io"
- "os"
+ "math/big"
)
// Parameters represents the domain parameters for a key. These parameters can
@@ -29,17 +29,11 @@ type PrivateKey struct {
X *big.Int
}
-type invalidPublicKeyError int
-
-func (invalidPublicKeyError) String() string {
- return "crypto/dsa: invalid public key"
-}
-
-// InvalidPublicKeyError results when a public key is not usable by this code.
+// ErrInvalidPublicKey results when a public key is not usable by this code.
// FIPS is quite strict about the format of DSA keys, but other code may be
// less so. Thus, when using keys which may have been generated by other code,
// this error must be handled.
-var InvalidPublicKeyError = invalidPublicKeyError(0)
+var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key")
// ParameterSizes is a enumeration of the acceptable bit lengths of the primes
// in a set of DSA parameters. See FIPS 186-3, section 4.2.
@@ -58,7 +52,7 @@ const numMRTests = 64
// GenerateParameters puts a random, valid set of DSA parameters into params.
// This function takes many seconds, even on fast machines.
-func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err os.Error) {
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
// This function doesn't follow FIPS 186-3 exactly in that it doesn't
// use a verification seed to generate the primes. The verification
// seed doesn't appear to be exported or used by other code and
@@ -79,7 +73,7 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
L = 3072
N = 256
default:
- return os.NewError("crypto/dsa: invalid ParameterSizes")
+ return errors.New("crypto/dsa: invalid ParameterSizes")
}
qBytes := make([]byte, N/8)
@@ -102,7 +96,7 @@ GeneratePrimes:
qBytes[0] |= 0x80
q.SetBytes(qBytes)
- if !big.ProbablyPrime(q, numMRTests) {
+ if !q.ProbablyPrime(numMRTests) {
continue
}
@@ -123,7 +117,7 @@ GeneratePrimes:
continue
}
- if !big.ProbablyPrime(p, numMRTests) {
+ if !p.ProbablyPrime(numMRTests) {
continue
}
@@ -156,9 +150,9 @@ GeneratePrimes:
// GenerateKey generates a public&private key pair. The Parameters of the
// PrivateKey must already be valid (see GenerateParameters).
-func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
+func GenerateKey(priv *PrivateKey, rand io.Reader) error {
if priv.P == nil || priv.Q == nil || priv.G == nil {
- return os.NewError("crypto/dsa: parameters not set up before generating key")
+ return errors.New("crypto/dsa: parameters not set up before generating key")
}
x := new(big.Int)
@@ -185,12 +179,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
-func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) {
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
// FIPS 186-3, section 4.6
n := priv.Q.BitLen()
if n&7 != 0 {
- err = InvalidPublicKeyError
+ err = ErrInvalidPublicKey
return
}
n >>= 3
@@ -218,10 +216,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.
continue
}
- if n > len(hash) {
- n = len(hash)
- }
- z := k.SetBytes(hash[:n])
+ z := k.SetBytes(hash)
s = new(big.Int).Mul(priv.X, r)
s.Add(s, z)
@@ -238,7 +233,11 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.
}
// Verify verifies the signature in r, s of hash using the public key, pub. It
-// returns true iff the signature is valid.
+// reports whether the signature is valid.
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
// FIPS 186-3, section 4.7
@@ -255,12 +254,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
if n&7 != 0 {
return false
}
- n >>= 3
-
- if n > len(hash) {
- n = len(hash)
- }
- z := new(big.Int).SetBytes(hash[:n])
+ z := new(big.Int).SetBytes(hash)
u1 := new(big.Int).Mul(z, w)
u1.Mod(u1, pub.Q)
diff --git a/src/pkg/crypto/dsa/dsa_test.go b/src/pkg/crypto/dsa/dsa_test.go
index deec08dfd..177aa444d 100644
--- a/src/pkg/crypto/dsa/dsa_test.go
+++ b/src/pkg/crypto/dsa/dsa_test.go
@@ -5,8 +5,8 @@
package dsa
import (
- "big"
"crypto/rand"
+ "math/big"
"testing"
)
diff --git a/src/pkg/crypto/ecdsa/Makefile b/src/pkg/crypto/ecdsa/Makefile
deleted file mode 100644
index 0af24c2f2..000000000
--- a/src/pkg/crypto/ecdsa/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/ecdsa
-GOFILES=\
- ecdsa.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
index 7bce1bc96..b28239b78 100644
--- a/src/pkg/crypto/ecdsa/ecdsa.go
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -7,21 +7,20 @@
package ecdsa
// References:
-// [NSA]: Suite B implementor's guide to FIPS 186-3,
+// [NSA]: Suite B implementer's guide to FIPS 186-3,
// http://www.nsa.gov/ia/_files/ecdsa.pdf
// [SECG]: SECG, SEC1
// http://www.secg.org/download/aid-780/sec1-v2.pdf
import (
- "big"
"crypto/elliptic"
"io"
- "os"
+ "math/big"
)
// PublicKey represents an ECDSA public key.
type PublicKey struct {
- *elliptic.Curve
+ elliptic.Curve
X, Y *big.Int
}
@@ -35,22 +34,23 @@ var one = new(big.Int).SetInt64(1)
// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
-func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) {
- b := make([]byte, c.BitSize/8+8)
+func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
+ params := c.Params()
+ b := make([]byte, params.BitSize/8+8)
_, err = io.ReadFull(rand, b)
if err != nil {
return
}
k = new(big.Int).SetBytes(b)
- n := new(big.Int).Sub(c.N, one)
+ n := new(big.Int).Sub(params.N, one)
k.Mod(k, n)
k.Add(k, one)
return
}
// GenerateKey generates a public&private key pair.
-func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err os.Error) {
+func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
k, err := randFieldElement(c, rand)
if err != nil {
return
@@ -67,8 +67,8 @@ func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err os.Er
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does.
-func hashToInt(hash []byte, c *elliptic.Curve) *big.Int {
- orderBits := c.N.BitLen()
+func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
+ orderBits := c.Params().N.BitLen()
orderBytes := (orderBits + 7) / 8
if len(hash) > orderBytes {
hash = hash[:orderBytes]
@@ -86,9 +86,10 @@ func hashToInt(hash []byte, c *elliptic.Curve) *big.Int {
// larger message) using the private key, priv. It returns the signature as a
// pair of integers. The security of the private key depends on the entropy of
// rand.
-func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) {
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
// See [NSA] 3.4.1
c := priv.PublicKey.Curve
+ N := c.Params().N
var k, kInv *big.Int
for {
@@ -99,9 +100,9 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.
return
}
- kInv = new(big.Int).ModInverse(k, c.N)
+ kInv = new(big.Int).ModInverse(k, N)
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
- r.Mod(r, priv.Curve.N)
+ r.Mod(r, N)
if r.Sign() != 0 {
break
}
@@ -111,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.
s = new(big.Int).Mul(priv.D, r)
s.Add(s, e)
s.Mul(s, kInv)
- s.Mod(s, priv.PublicKey.Curve.N)
+ s.Mod(s, N)
if s.Sign() != 0 {
break
}
@@ -125,15 +126,16 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
// See [NSA] 3.4.2
c := pub.Curve
+ N := c.Params().N
if r.Sign() == 0 || s.Sign() == 0 {
return false
}
- if r.Cmp(c.N) >= 0 || s.Cmp(c.N) >= 0 {
+ if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
return false
}
e := hashToInt(hash, c)
- w := new(big.Int).ModInverse(s, c.N)
+ w := new(big.Int).ModInverse(s, N)
u1 := e.Mul(e, w)
u2 := w.Mul(r, w)
@@ -144,6 +146,6 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
return false
}
x, _ := c.Add(x1, y1, x2, y2)
- x.Mod(x, c.N)
+ x.Mod(x, N)
return x.Cmp(r) == 0
}
diff --git a/src/pkg/crypto/ecdsa/ecdsa_test.go b/src/pkg/crypto/ecdsa/ecdsa_test.go
index d6b403914..3a2b3efba 100644
--- a/src/pkg/crypto/ecdsa/ecdsa_test.go
+++ b/src/pkg/crypto/ecdsa/ecdsa_test.go
@@ -5,15 +5,15 @@
package ecdsa
import (
- "big"
"crypto/elliptic"
- "crypto/sha1"
"crypto/rand"
+ "crypto/sha1"
"encoding/hex"
+ "math/big"
"testing"
)
-func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) {
+func testKeyGeneration(t *testing.T, c elliptic.Curve, tag string) {
priv, err := GenerateKey(c, rand.Reader)
if err != nil {
t.Errorf("%s: error: %s", tag, err)
@@ -34,7 +34,7 @@ func TestKeyGeneration(t *testing.T) {
testKeyGeneration(t, elliptic.P521(), "p521")
}
-func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) {
+func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) {
priv, _ := GenerateKey(c, rand.Reader)
hashed := []byte("testing")
@@ -214,7 +214,7 @@ func TestVectors(t *testing.T) {
msg, _ := hex.DecodeString(test.msg)
sha.Reset()
sha.Write(msg)
- hashed := sha.Sum()
+ hashed := sha.Sum(nil)
r := fromHex(test.r)
s := fromHex(test.s)
if Verify(&pub, hashed, r, s) != test.ok {
diff --git a/src/pkg/crypto/elliptic/Makefile b/src/pkg/crypto/elliptic/Makefile
deleted file mode 100644
index 4db5d7de5..000000000
--- a/src/pkg/crypto/elliptic/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/elliptic
-GOFILES=\
- elliptic.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/elliptic/elliptic.go b/src/pkg/crypto/elliptic/elliptic.go
index 41835f1a9..30835a90b 100644
--- a/src/pkg/crypto/elliptic/elliptic.go
+++ b/src/pkg/crypto/elliptic/elliptic.go
@@ -14,15 +14,32 @@ package elliptic
// reverse the transform than to operate in affine coordinates.
import (
- "big"
"io"
- "os"
+ "math/big"
"sync"
)
// A Curve represents a short-form Weierstrass curve with a=-3.
// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
-type Curve struct {
+type Curve interface {
+ // Params returns the parameters for the curve.
+ Params() *CurveParams
+ // IsOnCurve returns true if the given (x,y) lies on the curve.
+ IsOnCurve(x, y *big.Int) bool
+ // Add returns the sum of (x1,y1) and (x2,y2)
+ Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
+ // Double returns 2*(x,y)
+ Double(x1, y1 *big.Int) (x, y *big.Int)
+ // ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+ ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int)
+ // ScalarBaseMult returns k*G, where G is the base point of the group and k
+ // is an integer in big-endian form.
+ ScalarBaseMult(scalar []byte) (x, y *big.Int)
+}
+
+// CurveParams contains the parameters of an elliptic curve and also provides
+// a generic, non-constant time implementation of Curve.
+type CurveParams struct {
P *big.Int // the order of the underlying field
N *big.Int // the order of the base point
B *big.Int // the constant of the curve equation
@@ -30,8 +47,11 @@ type Curve struct {
BitSize int // the size of the underlying field
}
-// IsOnCurve returns true if the given (x,y) lies on the curve.
-func (curve *Curve) IsOnCurve(x, y *big.Int) bool {
+func (curve *CurveParams) Params() *CurveParams {
+ return curve
+}
+
+func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
// y² = x³ - 3x + b
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.P)
@@ -51,7 +71,7 @@ func (curve *Curve) IsOnCurve(x, y *big.Int) bool {
// affineFromJacobian reverses the Jacobian transform. See the comment at the
// top of the file.
-func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
zinv := new(big.Int).ModInverse(z, curve.P)
zinvsq := new(big.Int).Mul(zinv, zinv)
@@ -63,15 +83,14 @@ func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
return
}
-// Add returns the sum of (x1,y1) and (x2,y2)
-func (curve *Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
z := new(big.Int).SetInt64(1)
return curve.affineFromJacobian(curve.addJacobian(x1, y1, z, x2, y2, z))
}
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
// (x2, y2, z2) and returns their sum, also in Jacobian form.
-func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
z1z1 := new(big.Int).Mul(z1, z1)
z1z1.Mod(z1z1, curve.P)
@@ -134,15 +153,14 @@ func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big
return x3, y3, z3
}
-// Double returns 2*(x,y)
-func (curve *Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
z1 := new(big.Int).SetInt64(1)
return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
}
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
// returns its double, also in Jacobian form.
-func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
delta := new(big.Int).Mul(z, z)
delta.Mod(delta, curve.P)
@@ -200,8 +218,7 @@ func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.I
return x3, y3, z3
}
-// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
-func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
// We have a slight problem in that the identity of the group (the
// point at infinity) cannot be represented in (x, y) form on a finite
// machine. Thus the standard add/double algorithm has to be tweaked
@@ -239,18 +256,17 @@ func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
return curve.affineFromJacobian(x, y, z)
}
-// ScalarBaseMult returns k*G, where G is the base point of the group and k is
-// an integer in big-endian form.
-func (curve *Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
return curve.ScalarMult(curve.Gx, curve.Gy, k)
}
var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
-// GenerateKey returns a public/private key pair. The private key is generated
-// using the given reader, which must return random data.
-func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err os.Error) {
- byteLen := (curve.BitSize + 7) >> 3
+// GenerateKey returns a public/private key pair. The private key is
+// generated using the given reader, which must return random data.
+func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ bitSize := curve.Params().BitSize
+ byteLen := (bitSize + 7) >> 3
priv = make([]byte, byteLen)
for x == nil {
@@ -260,7 +276,7 @@ func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err
}
// We have to mask off any excess bits in the case that the size of the
// underlying field is not a whole number of bytes.
- priv[0] &= mask[curve.BitSize%8]
+ priv[0] &= mask[bitSize%8]
// This is because, in tests, rand will return all zeros and we don't
// want to get the point at infinity and loop forever.
priv[1] ^= 0x42
@@ -269,10 +285,9 @@ func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err
return
}
-// Marshal converts a point into the form specified in section 4.3.6 of ANSI
-// X9.62.
-func (curve *Curve) Marshal(x, y *big.Int) []byte {
- byteLen := (curve.BitSize + 7) >> 3
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI X9.62.
+func Marshal(curve Curve, x, y *big.Int) []byte {
+ byteLen := (curve.Params().BitSize + 7) >> 3
ret := make([]byte, 1+2*byteLen)
ret[0] = 4 // uncompressed point
@@ -284,10 +299,9 @@ func (curve *Curve) Marshal(x, y *big.Int) []byte {
return ret
}
-// 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
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil.
+func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
+ byteLen := (curve.Params().BitSize + 7) >> 3
if len(data) != 1+2*byteLen {
return
}
@@ -300,10 +314,9 @@ func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
}
var initonce sync.Once
-var p224 *Curve
-var p256 *Curve
-var p384 *Curve
-var p521 *Curve
+var p256 *CurveParams
+var p384 *CurveParams
+var p521 *CurveParams
func initAll() {
initP224()
@@ -312,20 +325,9 @@ func initAll() {
initP521()
}
-func initP224() {
- // See FIPS 186-3, section D.2.2
- p224 = new(Curve)
- p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
- p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
- p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
- p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
- p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
- p224.BitSize = 224
-}
-
func initP256() {
// See FIPS 186-3, section D.2.3
- p256 = new(Curve)
+ p256 = new(CurveParams)
p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
@@ -336,7 +338,7 @@ func initP256() {
func initP384() {
// See FIPS 186-3, section D.2.4
- p384 = new(Curve)
+ p384 = new(CurveParams)
p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
@@ -347,7 +349,7 @@ func initP384() {
func initP521() {
// See FIPS 186-3, section D.2.5
- p521 = new(Curve)
+ p521 = new(CurveParams)
p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
@@ -356,26 +358,20 @@ func initP521() {
p521.BitSize = 521
}
-// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
-func P224() *Curve {
- initonce.Do(initAll)
- return p224
-}
-
// P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3)
-func P256() *Curve {
+func P256() Curve {
initonce.Do(initAll)
return p256
}
// P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4)
-func P384() *Curve {
+func P384() Curve {
initonce.Do(initAll)
return p384
}
// P256 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)
-func P521() *Curve {
+func P521() Curve {
initonce.Do(initAll)
return p521
}
diff --git a/src/pkg/crypto/elliptic/elliptic_test.go b/src/pkg/crypto/elliptic/elliptic_test.go
index b7e7f035f..1e3407ee0 100644
--- a/src/pkg/crypto/elliptic/elliptic_test.go
+++ b/src/pkg/crypto/elliptic/elliptic_test.go
@@ -5,15 +5,16 @@
package elliptic
import (
- "big"
"crypto/rand"
+ "encoding/hex"
"fmt"
+ "math/big"
"testing"
)
func TestOnCurve(t *testing.T) {
p224 := P224()
- if !p224.IsOnCurve(p224.Gx, p224.Gy) {
+ if !p224.IsOnCurve(p224.Params().Gx, p224.Params().Gy) {
t.Errorf("FAIL")
}
}
@@ -295,7 +296,25 @@ func TestBaseMult(t *testing.T) {
}
x, y := p224.ScalarBaseMult(k.Bytes())
if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
- t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ }
+ if testing.Short() && i > 5 {
+ break
+ }
+ }
+}
+
+func TestGenericBaseMult(t *testing.T) {
+ // We use the P224 CurveParams directly in order to test the generic implementation.
+ p224 := P224().Params()
+ for i, e := range p224BaseMultTests {
+ k, ok := new(big.Int).SetString(e.k, 10)
+ if !ok {
+ t.Errorf("%d: bad value for k: %s", i, e.k)
+ }
+ x, y := p224.ScalarBaseMult(k.Bytes())
+ if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
+ t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y)
}
if testing.Short() && i > 5 {
break
@@ -316,13 +335,13 @@ func BenchmarkBaseMult(b *testing.B) {
func TestMarshal(t *testing.T) {
p224 := P224()
- _, x, y, err := p224.GenerateKey(rand.Reader)
+ _, x, y, err := GenerateKey(p224, rand.Reader)
if err != nil {
t.Error(err)
return
}
- serialized := p224.Marshal(x, y)
- xx, yy := p224.Unmarshal(serialized)
+ serialized := Marshal(p224, x, y)
+ xx, yy := Unmarshal(p224, serialized)
if xx == nil {
t.Error("failed to unmarshal")
return
@@ -332,3 +351,13 @@ func TestMarshal(t *testing.T) {
return
}
}
+
+func TestP224Overflow(t *testing.T) {
+ // This tests for a specific bug in the P224 implementation.
+ p224 := P224()
+ pointData, _ := hex.DecodeString("049B535B45FB0A2072398A6831834624C7E32CCFD5A4B933BCEAF77F1DD945E08BBE5178F5EDF5E733388F196D2A631D2E075BB16CBFEEA15B")
+ x, y := Unmarshal(p224, pointData)
+ if !p224.IsOnCurve(x, y) {
+ t.Error("P224 failed to validate a correct point")
+ }
+}
diff --git a/src/pkg/crypto/elliptic/p224.go b/src/pkg/crypto/elliptic/p224.go
new file mode 100644
index 000000000..17571c252
--- /dev/null
+++ b/src/pkg/crypto/elliptic/p224.go
@@ -0,0 +1,718 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+// This is a constant-time, 32-bit implementation of P224. See FIPS 186-3,
+// section D.2.2.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+import (
+ "math/big"
+)
+
+var p224 p224Curve
+
+type p224Curve struct {
+ *CurveParams
+ gx, gy, b p224FieldElement
+}
+
+func initP224() {
+ // See FIPS 186-3, section D.2.2
+ p224.CurveParams = new(CurveParams)
+ p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
+ p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
+ p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
+ p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
+ p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
+ p224.BitSize = 224
+
+ p224FromBig(&p224.gx, p224.Gx)
+ p224FromBig(&p224.gy, p224.Gy)
+ p224FromBig(&p224.b, p224.B)
+}
+
+// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
+func P224() Curve {
+ initonce.Do(initAll)
+ return p224
+}
+
+func (curve p224Curve) Params() *CurveParams {
+ return curve.CurveParams
+}
+
+func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool {
+ var x, y p224FieldElement
+ p224FromBig(&x, bigX)
+ p224FromBig(&y, bigY)
+
+ // y² = x³ - 3x + b
+ var tmp p224LargeFieldElement
+ var x3 p224FieldElement
+ p224Square(&x3, &x, &tmp)
+ p224Mul(&x3, &x3, &x, &tmp)
+
+ for i := 0; i < 8; i++ {
+ x[i] *= 3
+ }
+ p224Sub(&x3, &x3, &x)
+ p224Reduce(&x3)
+ p224Add(&x3, &x3, &curve.b)
+ p224Contract(&x3, &x3)
+
+ p224Square(&y, &y, &tmp)
+ p224Contract(&y, &y)
+
+ for i := 0; i < 8; i++ {
+ if y[i] != x3[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (p224Curve) Add(bigX1, bigY1, bigX2, bigY2 *big.Int) (x, y *big.Int) {
+ var x1, y1, z1, x2, y2, z2, x3, y3, z3 p224FieldElement
+
+ p224FromBig(&x1, bigX1)
+ p224FromBig(&y1, bigY1)
+ z1[0] = 1
+ p224FromBig(&x2, bigX2)
+ p224FromBig(&y2, bigY2)
+ z2[0] = 1
+
+ p224AddJacobian(&x3, &y3, &z3, &x1, &y1, &z1, &x2, &y2, &z2)
+ return p224ToAffine(&x3, &y3, &z3)
+}
+
+func (p224Curve) Double(bigX1, bigY1 *big.Int) (x, y *big.Int) {
+ var x1, y1, z1, x2, y2, z2 p224FieldElement
+
+ p224FromBig(&x1, bigX1)
+ p224FromBig(&y1, bigY1)
+ z1[0] = 1
+
+ p224DoubleJacobian(&x2, &y2, &z2, &x1, &y1, &z1)
+ return p224ToAffine(&x2, &y2, &z2)
+}
+
+func (p224Curve) ScalarMult(bigX1, bigY1 *big.Int, scalar []byte) (x, y *big.Int) {
+ var x1, y1, z1, x2, y2, z2 p224FieldElement
+
+ p224FromBig(&x1, bigX1)
+ p224FromBig(&y1, bigY1)
+ z1[0] = 1
+
+ p224ScalarMult(&x2, &y2, &z2, &x1, &y1, &z1, scalar)
+ return p224ToAffine(&x2, &y2, &z2)
+}
+
+func (curve p224Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+ var z1, x2, y2, z2 p224FieldElement
+
+ z1[0] = 1
+ p224ScalarMult(&x2, &y2, &z2, &curve.gx, &curve.gy, &z1, scalar)
+ return p224ToAffine(&x2, &y2, &z2)
+}
+
+// Field element functions.
+//
+// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1.
+//
+// Field elements are represented by a FieldElement, which is a typedef to an
+// array of 8 uint32's. The value of a FieldElement, a, is:
+// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7]
+//
+// Using 28-bit limbs means that there's only 4 bits of headroom, which is less
+// than we would really like. But it has the useful feature that we hit 2**224
+// exactly, making the reflections during a reduce much nicer.
+type p224FieldElement [8]uint32
+
+// p224Add computes *out = a+b
+//
+// a[i] + b[i] < 2**32
+func p224Add(out, a, b *p224FieldElement) {
+ for i := 0; i < 8; i++ {
+ out[i] = a[i] + b[i]
+ }
+}
+
+const two31p3 = 1<<31 + 1<<3
+const two31m3 = 1<<31 - 1<<3
+const two31m15m3 = 1<<31 - 1<<15 - 1<<3
+
+// p224ZeroModP31 is 0 mod p where bit 31 is set in all limbs so that we can
+// subtract smaller amounts without underflow. See the section "Subtraction" in
+// [1] for reasoning.
+var p224ZeroModP31 = []uint32{two31p3, two31m3, two31m3, two31m15m3, two31m3, two31m3, two31m3, two31m3}
+
+// p224Sub computes *out = a-b
+//
+// a[i], b[i] < 2**30
+// out[i] < 2**32
+func p224Sub(out, a, b *p224FieldElement) {
+ for i := 0; i < 8; i++ {
+ out[i] = a[i] + p224ZeroModP31[i] - b[i]
+ }
+}
+
+// LargeFieldElement also represents an element of the field. The limbs are
+// still spaced 28-bits apart and in little-endian order. So the limbs are at
+// 0, 28, 56, ..., 392 bits, each 64-bits wide.
+type p224LargeFieldElement [15]uint64
+
+const two63p35 = 1<<63 + 1<<35
+const two63m35 = 1<<63 - 1<<35
+const two63m35m19 = 1<<63 - 1<<35 - 1<<19
+
+// p224ZeroModP63 is 0 mod p where bit 63 is set in all limbs. See the section
+// "Subtraction" in [1] for why.
+var p224ZeroModP63 = [8]uint64{two63p35, two63m35, two63m35, two63m35, two63m35m19, two63m35, two63m35, two63m35}
+
+const bottom12Bits = 0xfff
+const bottom28Bits = 0xfffffff
+
+// p224Mul computes *out = a*b
+//
+// a[i] < 2**29, b[i] < 2**30 (or vice versa)
+// out[i] < 2**29
+func p224Mul(out, a, b *p224FieldElement, tmp *p224LargeFieldElement) {
+ for i := 0; i < 15; i++ {
+ tmp[i] = 0
+ }
+
+ for i := 0; i < 8; i++ {
+ for j := 0; j < 8; j++ {
+ tmp[i+j] += uint64(a[i]) * uint64(b[j])
+ }
+ }
+
+ p224ReduceLarge(out, tmp)
+}
+
+// Square computes *out = a*a
+//
+// a[i] < 2**29
+// out[i] < 2**29
+func p224Square(out, a *p224FieldElement, tmp *p224LargeFieldElement) {
+ for i := 0; i < 15; i++ {
+ tmp[i] = 0
+ }
+
+ for i := 0; i < 8; i++ {
+ for j := 0; j <= i; j++ {
+ r := uint64(a[i]) * uint64(a[j])
+ if i == j {
+ tmp[i+j] += r
+ } else {
+ tmp[i+j] += r << 1
+ }
+ }
+ }
+
+ p224ReduceLarge(out, tmp)
+}
+
+// ReduceLarge converts a p224LargeFieldElement to a p224FieldElement.
+//
+// in[i] < 2**62
+func p224ReduceLarge(out *p224FieldElement, in *p224LargeFieldElement) {
+ for i := 0; i < 8; i++ {
+ in[i] += p224ZeroModP63[i]
+ }
+
+ // Eliminate the coefficients at 2**224 and greater.
+ for i := 14; i >= 8; i-- {
+ in[i-8] -= in[i]
+ in[i-5] += (in[i] & 0xffff) << 12
+ in[i-4] += in[i] >> 16
+ }
+ in[8] = 0
+ // in[0..8] < 2**64
+
+ // As the values become small enough, we start to store them in |out|
+ // and use 32-bit operations.
+ for i := 1; i < 8; i++ {
+ in[i+1] += in[i] >> 28
+ out[i] = uint32(in[i] & bottom28Bits)
+ }
+ in[0] -= in[8]
+ out[3] += uint32(in[8]&0xffff) << 12
+ out[4] += uint32(in[8] >> 16)
+ // in[0] < 2**64
+ // out[3] < 2**29
+ // out[4] < 2**29
+ // out[1,2,5..7] < 2**28
+
+ out[0] = uint32(in[0] & bottom28Bits)
+ out[1] += uint32((in[0] >> 28) & bottom28Bits)
+ out[2] += uint32(in[0] >> 56)
+ // out[0] < 2**28
+ // out[1..4] < 2**29
+ // out[5..7] < 2**28
+}
+
+// Reduce reduces the coefficients of a to smaller bounds.
+//
+// On entry: a[i] < 2**31 + 2**30
+// On exit: a[i] < 2**29
+func p224Reduce(a *p224FieldElement) {
+ for i := 0; i < 7; i++ {
+ a[i+1] += a[i] >> 28
+ a[i] &= bottom28Bits
+ }
+ top := a[7] >> 28
+ a[7] &= bottom28Bits
+
+ // top < 2**4
+ mask := top
+ mask |= mask >> 2
+ mask |= mask >> 1
+ mask <<= 31
+ mask = uint32(int32(mask) >> 31)
+ // Mask is all ones if top != 0, all zero otherwise
+
+ a[0] -= top
+ a[3] += top << 12
+
+ // We may have just made a[0] negative but, if we did, then we must
+ // have added something to a[3], this it's > 2**12. Therefore we can
+ // carry down to a[0].
+ a[3] -= 1 & mask
+ a[2] += mask & (1<<28 - 1)
+ a[1] += mask & (1<<28 - 1)
+ a[0] += mask & (1 << 28)
+}
+
+// p224Invert calculates *out = in**-1 by computing in**(2**224 - 2**96 - 1),
+// i.e. Fermat's little theorem.
+func p224Invert(out, in *p224FieldElement) {
+ var f1, f2, f3, f4 p224FieldElement
+ var c p224LargeFieldElement
+
+ p224Square(&f1, in, &c) // 2
+ p224Mul(&f1, &f1, in, &c) // 2**2 - 1
+ p224Square(&f1, &f1, &c) // 2**3 - 2
+ p224Mul(&f1, &f1, in, &c) // 2**3 - 1
+ p224Square(&f2, &f1, &c) // 2**4 - 2
+ p224Square(&f2, &f2, &c) // 2**5 - 4
+ p224Square(&f2, &f2, &c) // 2**6 - 8
+ p224Mul(&f1, &f1, &f2, &c) // 2**6 - 1
+ p224Square(&f2, &f1, &c) // 2**7 - 2
+ for i := 0; i < 5; i++ { // 2**12 - 2**6
+ p224Square(&f2, &f2, &c)
+ }
+ p224Mul(&f2, &f2, &f1, &c) // 2**12 - 1
+ p224Square(&f3, &f2, &c) // 2**13 - 2
+ for i := 0; i < 11; i++ { // 2**24 - 2**12
+ p224Square(&f3, &f3, &c)
+ }
+ p224Mul(&f2, &f3, &f2, &c) // 2**24 - 1
+ p224Square(&f3, &f2, &c) // 2**25 - 2
+ for i := 0; i < 23; i++ { // 2**48 - 2**24
+ p224Square(&f3, &f3, &c)
+ }
+ p224Mul(&f3, &f3, &f2, &c) // 2**48 - 1
+ p224Square(&f4, &f3, &c) // 2**49 - 2
+ for i := 0; i < 47; i++ { // 2**96 - 2**48
+ p224Square(&f4, &f4, &c)
+ }
+ p224Mul(&f3, &f3, &f4, &c) // 2**96 - 1
+ p224Square(&f4, &f3, &c) // 2**97 - 2
+ for i := 0; i < 23; i++ { // 2**120 - 2**24
+ p224Square(&f4, &f4, &c)
+ }
+ p224Mul(&f2, &f4, &f2, &c) // 2**120 - 1
+ for i := 0; i < 6; i++ { // 2**126 - 2**6
+ p224Square(&f2, &f2, &c)
+ }
+ p224Mul(&f1, &f1, &f2, &c) // 2**126 - 1
+ p224Square(&f1, &f1, &c) // 2**127 - 2
+ p224Mul(&f1, &f1, in, &c) // 2**127 - 1
+ for i := 0; i < 97; i++ { // 2**224 - 2**97
+ p224Square(&f1, &f1, &c)
+ }
+ p224Mul(out, &f1, &f3, &c) // 2**224 - 2**96 - 1
+}
+
+// p224Contract converts a FieldElement to its unique, minimal form.
+//
+// On entry, in[i] < 2**29
+// On exit, in[i] < 2**28
+func p224Contract(out, in *p224FieldElement) {
+ copy(out[:], in[:])
+
+ for i := 0; i < 7; i++ {
+ out[i+1] += out[i] >> 28
+ out[i] &= bottom28Bits
+ }
+ top := out[7] >> 28
+ out[7] &= bottom28Bits
+
+ out[0] -= top
+ out[3] += top << 12
+
+ // We may just have made out[i] negative. So we carry down. If we made
+ // out[0] negative then we know that out[3] is sufficiently positive
+ // because we just added to it.
+ for i := 0; i < 3; i++ {
+ mask := uint32(int32(out[i]) >> 31)
+ out[i] += (1 << 28) & mask
+ out[i+1] -= 1 & mask
+ }
+
+ // We might have pushed out[3] over 2**28 so we perform another, partial,
+ // carry chain.
+ for i := 3; i < 7; i++ {
+ out[i+1] += out[i] >> 28
+ out[i] &= bottom28Bits
+ }
+ top = out[7] >> 28
+ out[7] &= bottom28Bits
+
+ // Eliminate top while maintaining the same value mod p.
+ out[0] -= top
+ out[3] += top << 12
+
+ // There are two cases to consider for out[3]:
+ // 1) The first time that we eliminated top, we didn't push out[3] over
+ // 2**28. In this case, the partial carry chain didn't change any values
+ // and top is zero.
+ // 2) We did push out[3] over 2**28 the first time that we eliminated top.
+ // The first value of top was in [0..16), therefore, prior to eliminating
+ // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
+ // overflowing and being reduced by the second carry chain, out[3] <=
+ // 0xf000. Thus it cannot have overflowed when we eliminated top for the
+ // second time.
+
+ // Again, we may just have made out[0] negative, so do the same carry down.
+ // As before, if we made out[0] negative then we know that out[3] is
+ // sufficiently positive.
+ for i := 0; i < 3; i++ {
+ mask := uint32(int32(out[i]) >> 31)
+ out[i] += (1 << 28) & mask
+ out[i+1] -= 1 & mask
+ }
+
+ // Now we see if the value is >= p and, if so, subtract p.
+
+ // First we build a mask from the top four limbs, which must all be
+ // equal to bottom28Bits if the whole value is >= p. If top4AllOnes
+ // ends up with any zero bits in the bottom 28 bits, then this wasn't
+ // true.
+ top4AllOnes := uint32(0xffffffff)
+ for i := 4; i < 8; i++ {
+ top4AllOnes &= (out[i] & bottom28Bits) - 1
+ }
+ top4AllOnes |= 0xf0000000
+ // Now we replicate any zero bits to all the bits in top4AllOnes.
+ top4AllOnes &= top4AllOnes >> 16
+ top4AllOnes &= top4AllOnes >> 8
+ top4AllOnes &= top4AllOnes >> 4
+ top4AllOnes &= top4AllOnes >> 2
+ top4AllOnes &= top4AllOnes >> 1
+ top4AllOnes = uint32(int32(top4AllOnes<<31) >> 31)
+
+ // Now we test whether the bottom three limbs are non-zero.
+ bottom3NonZero := out[0] | out[1] | out[2]
+ bottom3NonZero |= bottom3NonZero >> 16
+ bottom3NonZero |= bottom3NonZero >> 8
+ bottom3NonZero |= bottom3NonZero >> 4
+ bottom3NonZero |= bottom3NonZero >> 2
+ bottom3NonZero |= bottom3NonZero >> 1
+ bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
+
+ // Everything depends on the value of out[3].
+ // If it's > 0xffff000 and top4AllOnes != 0 then the whole value is >= p
+ // If it's = 0xffff000 and top4AllOnes != 0 and bottom3NonZero != 0,
+ // then the whole value is >= p
+ // If it's < 0xffff000, then the whole value is < p
+ n := out[3] - 0xffff000
+ out3Equal := n
+ out3Equal |= out3Equal >> 16
+ out3Equal |= out3Equal >> 8
+ out3Equal |= out3Equal >> 4
+ out3Equal |= out3Equal >> 2
+ out3Equal |= out3Equal >> 1
+ out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
+
+ // If out[3] > 0xffff000 then n's MSB will be zero.
+ out3GT := ^uint32(int32(n<<31) >> 31)
+
+ mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
+ out[0] -= 1 & mask
+ out[3] -= 0xffff000 & mask
+ out[4] -= 0xfffffff & mask
+ out[5] -= 0xfffffff & mask
+ out[6] -= 0xfffffff & mask
+ out[7] -= 0xfffffff & mask
+}
+
+// Group element functions.
+//
+// These functions deal with group elements. The group is an elliptic curve
+// group with a = -3 defined in FIPS 186-3, section D.2.2.
+
+// p224AddJacobian computes *out = a+b where a != b.
+func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl
+ var z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v p224FieldElement
+ var c p224LargeFieldElement
+
+ // Z1Z1 = Z1²
+ p224Square(&z1z1, z1, &c)
+ // Z2Z2 = Z2²
+ p224Square(&z2z2, z2, &c)
+ // U1 = X1*Z2Z2
+ p224Mul(&u1, x1, &z2z2, &c)
+ // U2 = X2*Z1Z1
+ p224Mul(&u2, x2, &z1z1, &c)
+ // S1 = Y1*Z2*Z2Z2
+ p224Mul(&s1, z2, &z2z2, &c)
+ p224Mul(&s1, y1, &s1, &c)
+ // S2 = Y2*Z1*Z1Z1
+ p224Mul(&s2, z1, &z1z1, &c)
+ p224Mul(&s2, y2, &s2, &c)
+ // H = U2-U1
+ p224Sub(&h, &u2, &u1)
+ p224Reduce(&h)
+ // I = (2*H)²
+ for j := 0; j < 8; j++ {
+ i[j] = h[j] << 1
+ }
+ p224Reduce(&i)
+ p224Square(&i, &i, &c)
+ // J = H*I
+ p224Mul(&j, &h, &i, &c)
+ // r = 2*(S2-S1)
+ p224Sub(&r, &s2, &s1)
+ p224Reduce(&r)
+ for i := 0; i < 8; i++ {
+ r[i] <<= 1
+ }
+ p224Reduce(&r)
+ // V = U1*I
+ p224Mul(&v, &u1, &i, &c)
+ // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H
+ p224Add(&z1z1, &z1z1, &z2z2)
+ p224Add(&z2z2, z1, z2)
+ p224Reduce(&z2z2)
+ p224Square(&z2z2, &z2z2, &c)
+ p224Sub(z3, &z2z2, &z1z1)
+ p224Reduce(z3)
+ p224Mul(z3, z3, &h, &c)
+ // X3 = r²-J-2*V
+ for i := 0; i < 8; i++ {
+ z1z1[i] = v[i] << 1
+ }
+ p224Add(&z1z1, &j, &z1z1)
+ p224Reduce(&z1z1)
+ p224Square(x3, &r, &c)
+ p224Sub(x3, x3, &z1z1)
+ p224Reduce(x3)
+ // Y3 = r*(V-X3)-2*S1*J
+ for i := 0; i < 8; i++ {
+ s1[i] <<= 1
+ }
+ p224Mul(&s1, &s1, &j, &c)
+ p224Sub(&z1z1, &v, x3)
+ p224Reduce(&z1z1)
+ p224Mul(&z1z1, &z1z1, &r, &c)
+ p224Sub(y3, &z1z1, &s1)
+ p224Reduce(y3)
+}
+
+// p224DoubleJacobian computes *out = a+a.
+func p224DoubleJacobian(x3, y3, z3, x1, y1, z1 *p224FieldElement) {
+ var delta, gamma, beta, alpha, t p224FieldElement
+ var c p224LargeFieldElement
+
+ p224Square(&delta, z1, &c)
+ p224Square(&gamma, y1, &c)
+ p224Mul(&beta, x1, &gamma, &c)
+
+ // alpha = 3*(X1-delta)*(X1+delta)
+ p224Add(&t, x1, &delta)
+ for i := 0; i < 8; i++ {
+ t[i] += t[i] << 1
+ }
+ p224Reduce(&t)
+ p224Sub(&alpha, x1, &delta)
+ p224Reduce(&alpha)
+ p224Mul(&alpha, &alpha, &t, &c)
+
+ // Z3 = (Y1+Z1)²-gamma-delta
+ p224Add(z3, y1, z1)
+ p224Reduce(z3)
+ p224Square(z3, z3, &c)
+ p224Sub(z3, z3, &gamma)
+ p224Reduce(z3)
+ p224Sub(z3, z3, &delta)
+ p224Reduce(z3)
+
+ // X3 = alpha²-8*beta
+ for i := 0; i < 8; i++ {
+ delta[i] = beta[i] << 3
+ }
+ p224Reduce(&delta)
+ p224Square(x3, &alpha, &c)
+ p224Sub(x3, x3, &delta)
+ p224Reduce(x3)
+
+ // Y3 = alpha*(4*beta-X3)-8*gamma²
+ for i := 0; i < 8; i++ {
+ beta[i] <<= 2
+ }
+ p224Sub(&beta, &beta, x3)
+ p224Reduce(&beta)
+ p224Square(&gamma, &gamma, &c)
+ for i := 0; i < 8; i++ {
+ gamma[i] <<= 3
+ }
+ p224Reduce(&gamma)
+ p224Mul(y3, &alpha, &beta, &c)
+ p224Sub(y3, y3, &gamma)
+ p224Reduce(y3)
+}
+
+// p224CopyConditional sets *out = *in iff the least-significant-bit of control
+// is true, and it runs in constant time.
+func p224CopyConditional(out, in *p224FieldElement, control uint32) {
+ control <<= 31
+ control = uint32(int32(control) >> 31)
+
+ for i := 0; i < 8; i++ {
+ out[i] ^= (out[i] ^ in[i]) & control
+ }
+}
+
+func p224ScalarMult(outX, outY, outZ, inX, inY, inZ *p224FieldElement, scalar []byte) {
+ var xx, yy, zz p224FieldElement
+ for i := 0; i < 8; i++ {
+ outZ[i] = 0
+ }
+
+ firstBit := uint32(1)
+ for _, byte := range scalar {
+ for bitNum := uint(0); bitNum < 8; bitNum++ {
+ p224DoubleJacobian(outX, outY, outZ, outX, outY, outZ)
+ bit := uint32((byte >> (7 - bitNum)) & 1)
+ p224AddJacobian(&xx, &yy, &zz, inX, inY, inZ, outX, outY, outZ)
+ p224CopyConditional(outX, inX, firstBit&bit)
+ p224CopyConditional(outY, inY, firstBit&bit)
+ p224CopyConditional(outZ, inZ, firstBit&bit)
+ p224CopyConditional(outX, &xx, ^firstBit&bit)
+ p224CopyConditional(outY, &yy, ^firstBit&bit)
+ p224CopyConditional(outZ, &zz, ^firstBit&bit)
+ firstBit = firstBit & ^bit
+ }
+ }
+}
+
+// p224ToAffine converts from Jacobian to affine form.
+func p224ToAffine(x, y, z *p224FieldElement) (*big.Int, *big.Int) {
+ var zinv, zinvsq, outx, outy p224FieldElement
+ var tmp p224LargeFieldElement
+
+ isPointAtInfinity := true
+ for i := 0; i < 8; i++ {
+ if z[i] != 0 {
+ isPointAtInfinity = false
+ break
+ }
+ }
+
+ if isPointAtInfinity {
+ return nil, nil
+ }
+
+ p224Invert(&zinv, z)
+ p224Square(&zinvsq, &zinv, &tmp)
+ p224Mul(x, x, &zinvsq, &tmp)
+ p224Mul(&zinvsq, &zinvsq, &zinv, &tmp)
+ p224Mul(y, y, &zinvsq, &tmp)
+
+ p224Contract(&outx, x)
+ p224Contract(&outy, y)
+ return p224ToBig(&outx), p224ToBig(&outy)
+}
+
+// get28BitsFromEnd returns the least-significant 28 bits from buf>>shift,
+// where buf is interpreted as a big-endian number.
+func get28BitsFromEnd(buf []byte, shift uint) (uint32, []byte) {
+ var ret uint32
+
+ for i := uint(0); i < 4; i++ {
+ var b byte
+ if l := len(buf); l > 0 {
+ b = buf[l-1]
+ // We don't remove the byte if we're about to return and we're not
+ // reading all of it.
+ if i != 3 || shift == 4 {
+ buf = buf[:l-1]
+ }
+ }
+ ret |= uint32(b) << (8 * i) >> shift
+ }
+ ret &= bottom28Bits
+ return ret, buf
+}
+
+// p224FromBig sets *out = *in.
+func p224FromBig(out *p224FieldElement, in *big.Int) {
+ bytes := in.Bytes()
+ out[0], bytes = get28BitsFromEnd(bytes, 0)
+ out[1], bytes = get28BitsFromEnd(bytes, 4)
+ out[2], bytes = get28BitsFromEnd(bytes, 0)
+ out[3], bytes = get28BitsFromEnd(bytes, 4)
+ out[4], bytes = get28BitsFromEnd(bytes, 0)
+ out[5], bytes = get28BitsFromEnd(bytes, 4)
+ out[6], bytes = get28BitsFromEnd(bytes, 0)
+ out[7], bytes = get28BitsFromEnd(bytes, 4)
+}
+
+// p224ToBig returns in as a big.Int.
+func p224ToBig(in *p224FieldElement) *big.Int {
+ var buf [28]byte
+ buf[27] = byte(in[0])
+ buf[26] = byte(in[0] >> 8)
+ buf[25] = byte(in[0] >> 16)
+ buf[24] = byte(((in[0] >> 24) & 0x0f) | (in[1]<<4)&0xf0)
+
+ buf[23] = byte(in[1] >> 4)
+ buf[22] = byte(in[1] >> 12)
+ buf[21] = byte(in[1] >> 20)
+
+ buf[20] = byte(in[2])
+ buf[19] = byte(in[2] >> 8)
+ buf[18] = byte(in[2] >> 16)
+ buf[17] = byte(((in[2] >> 24) & 0x0f) | (in[3]<<4)&0xf0)
+
+ buf[16] = byte(in[3] >> 4)
+ buf[15] = byte(in[3] >> 12)
+ buf[14] = byte(in[3] >> 20)
+
+ buf[13] = byte(in[4])
+ buf[12] = byte(in[4] >> 8)
+ buf[11] = byte(in[4] >> 16)
+ buf[10] = byte(((in[4] >> 24) & 0x0f) | (in[5]<<4)&0xf0)
+
+ buf[9] = byte(in[5] >> 4)
+ buf[8] = byte(in[5] >> 12)
+ buf[7] = byte(in[5] >> 20)
+
+ buf[6] = byte(in[6])
+ buf[5] = byte(in[6] >> 8)
+ buf[4] = byte(in[6] >> 16)
+ buf[3] = byte(((in[6] >> 24) & 0x0f) | (in[7]<<4)&0xf0)
+
+ buf[2] = byte(in[7] >> 4)
+ buf[1] = byte(in[7] >> 12)
+ buf[0] = byte(in[7] >> 20)
+
+ return new(big.Int).SetBytes(buf[:])
+}
diff --git a/src/pkg/crypto/elliptic/p224_test.go b/src/pkg/crypto/elliptic/p224_test.go
new file mode 100644
index 000000000..4b26d1610
--- /dev/null
+++ b/src/pkg/crypto/elliptic/p224_test.go
@@ -0,0 +1,47 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "math/big"
+ "testing"
+)
+
+var toFromBigTests = []string{
+ "0",
+ "1",
+ "23",
+ "b70e0cb46bb4bf7f321390b94a03c1d356c01122343280d6105c1d21",
+ "706a46d476dcb76798e6046d89474788d164c18032d268fd10704fa6",
+}
+
+func p224AlternativeToBig(in *p224FieldElement) *big.Int {
+ ret := new(big.Int)
+ tmp := new(big.Int)
+
+ for i := uint(0); i < 8; i++ {
+ tmp.SetInt64(int64(in[i]))
+ tmp.Lsh(tmp, 28*i)
+ ret.Add(ret, tmp)
+ }
+ ret.Mod(ret, p224.P)
+ return ret
+}
+
+func TestToFromBig(t *testing.T) {
+ for i, test := range toFromBigTests {
+ n, _ := new(big.Int).SetString(test, 16)
+ var x p224FieldElement
+ p224FromBig(&x, n)
+ m := p224ToBig(&x)
+ if n.Cmp(m) != 0 {
+ t.Errorf("#%d: %x != %x", i, n, m)
+ }
+ q := p224AlternativeToBig(&x)
+ if n.Cmp(q) != 0 {
+ t.Errorf("#%d: %x != %x (alternative)", i, n, m)
+ }
+ }
+}
diff --git a/src/pkg/crypto/hmac/Makefile b/src/pkg/crypto/hmac/Makefile
deleted file mode 100644
index cc69abf60..000000000
--- a/src/pkg/crypto/hmac/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/hmac
-GOFILES=\
- hmac.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go
index 04ec86e9a..a97ce0972 100644
--- a/src/pkg/crypto/hmac/hmac.go
+++ b/src/pkg/crypto/hmac/hmac.go
@@ -9,33 +9,20 @@
package hmac
import (
- "crypto/md5"
- "crypto/sha1"
- "crypto/sha256"
"hash"
- "os"
)
// FIPS 198:
// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
-// key is zero padded to 64 bytes
-// ipad = 0x36 byte repeated to 64 bytes
-// opad = 0x5c byte repeated to 64 bytes
+// key is zero padded to the block size of the hash function
+// ipad = 0x36 byte repeated for key length
+// opad = 0x5c byte repeated for key length
// hmac = H([key ^ opad] H([key ^ ipad] text))
-const (
- // NOTE(rsc): This constant is actually the
- // underlying hash function's block size.
- // HMAC is only conventionally used with
- // MD5 and SHA1, and both use 64-byte blocks.
- // The hash.Hash interface doesn't provide a
- // way to find out the block size.
- padSize = 64
-)
-
type hmac struct {
size int
+ blocksize int
key, tmp []byte
outer, inner hash.Hash
}
@@ -44,57 +31,50 @@ func (h *hmac) tmpPad(xor byte) {
for i, k := range h.key {
h.tmp[i] = xor ^ k
}
- for i := len(h.key); i < padSize; i++ {
+ for i := len(h.key); i < h.blocksize; i++ {
h.tmp[i] = xor
}
}
-func (h *hmac) Sum() []byte {
- sum := h.inner.Sum()
+func (h *hmac) Sum(in []byte) []byte {
+ origLen := len(in)
+ in = h.inner.Sum(in)
h.tmpPad(0x5c)
- for i, b := range sum {
- h.tmp[padSize+i] = b
- }
+ copy(h.tmp[h.blocksize:], in[origLen:])
h.outer.Reset()
h.outer.Write(h.tmp)
- return h.outer.Sum()
+ return h.outer.Sum(in[:origLen])
}
-func (h *hmac) Write(p []byte) (n int, err os.Error) {
+func (h *hmac) Write(p []byte) (n int, err error) {
return h.inner.Write(p)
}
func (h *hmac) Size() int { return h.size }
+func (h *hmac) BlockSize() int { return h.blocksize }
+
func (h *hmac) Reset() {
h.inner.Reset()
h.tmpPad(0x36)
- h.inner.Write(h.tmp[0:padSize])
+ h.inner.Write(h.tmp[0:h.blocksize])
}
-// New returns a new HMAC hash using the given hash generator and key.
+// New returns a new HMAC hash using the given hash.Hash type and key.
func New(h func() hash.Hash, key []byte) hash.Hash {
hm := new(hmac)
hm.outer = h()
hm.inner = h()
hm.size = hm.inner.Size()
- hm.tmp = make([]byte, padSize+hm.size)
- if len(key) > padSize {
+ hm.blocksize = hm.inner.BlockSize()
+ hm.tmp = make([]byte, hm.blocksize+hm.size)
+ if len(key) > hm.blocksize {
// If key is too big, hash it.
hm.outer.Write(key)
- key = hm.outer.Sum()
+ key = hm.outer.Sum(nil)
}
hm.key = make([]byte, len(key))
copy(hm.key, key)
hm.Reset()
return hm
}
-
-// NewMD5 returns a new HMAC-MD5 hash using the given key.
-func NewMD5(key []byte) hash.Hash { return New(md5.New, key) }
-
-// NewSHA1 returns a new HMAC-SHA1 hash using the given key.
-func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) }
-
-// NewSHA256 returns a new HMAC-SHA256 hash using the given key.
-func NewSHA256(key []byte) hash.Hash { return New(sha256.New, key) }
diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go
index bcae63b8a..07957414c 100644
--- a/src/pkg/crypto/hmac/hmac_test.go
+++ b/src/pkg/crypto/hmac/hmac_test.go
@@ -5,13 +5,17 @@
package hmac
import (
- "hash"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
"fmt"
+ "hash"
"testing"
)
type hmacTest struct {
- hash func([]byte) hash.Hash
+ hash func() hash.Hash
key []byte
in []byte
out string
@@ -21,7 +25,7 @@ var hmacTests = []hmacTest{
// Tests from US FIPS 198
// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
{
- NewSHA1,
+ sha1.New,
[]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
@@ -36,7 +40,7 @@ var hmacTests = []hmacTest{
"4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
},
{
- NewSHA1,
+ sha1.New,
[]byte{
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
@@ -46,7 +50,7 @@ var hmacTests = []hmacTest{
"0922d3405faa3d194f82a45830737d5cc6c75d24",
},
{
- NewSHA1,
+ sha1.New,
[]byte{
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
@@ -68,7 +72,7 @@ var hmacTests = []hmacTest{
// Test from Plan 9.
{
- NewMD5,
+ md5.New,
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"750c783e6ab0b503eaa86e310a5db738",
@@ -76,7 +80,7 @@ var hmacTests = []hmacTest{
// Tests from RFC 4231
{
- NewSHA256,
+ sha256.New,
[]byte{
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
@@ -86,13 +90,13 @@ var hmacTests = []hmacTest{
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
},
{
- NewSHA256,
+ sha256.New,
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
},
{
- NewSHA256,
+ sha256.New,
[]byte{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
@@ -110,7 +114,7 @@ var hmacTests = []hmacTest{
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
},
{
- NewSHA256,
+ sha256.New,
[]byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
@@ -129,7 +133,7 @@ var hmacTests = []hmacTest{
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
},
{
- NewSHA256,
+ sha256.New,
[]byte{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
@@ -153,7 +157,7 @@ var hmacTests = []hmacTest{
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
},
{
- NewSHA256,
+ sha256.New,
[]byte{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
@@ -178,11 +182,295 @@ var hmacTests = []hmacTest{
"be hashed before being used by the HMAC algorithm."),
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
},
+
+ // Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html
+ // (truncated tag tests are left out)
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "5fd596ee78d5553c8ff4e72d266dfd192366da29",
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807",
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "2d51b2f7750e410584662e38f133435f4c4fd42a",
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "c7405e3ae058e8cd30b08b4140248581ed174cb34e1224bcc1efc81b",
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe",
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "91c52509e5af8531601ae6230099d90bef88aaefb961f4080abc014d",
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62",
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790",
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d",
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "63c5daa5e651847ca897c95814ab830bededc7d25e83eef9195cd45857a37f448947858f5af50cc2b1b730ddf29671a9",
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0",
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "5b664436df69b0ca22551231a3f0a3d5b4f97991713cfa84bff4d0792eff96c27dccbbb6f79b65d548b40e8564cef594",
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "fc25e240658ca785b7a811a8d3f7b4ca" +
+ "48cfa26a8a366bf2cd1f836b05fcb024bd36853081811d6c" +
+ "ea4216ebad79da1cfcb95ea4586b8a0ce356596a55fb1347",
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "fd44c18bda0bb0a6ce0e82b031bf2818" +
+ "f6539bd56ec00bdc10a8a2d730b3634de2545d639b0f2cf7" +
+ "10d0692c72a1896f1f211c2b922d1a96c392e07e7ea9fedc",
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "d93ec8d2de1ad2a9957cb9b83f14e76a" +
+ "d6b5e0cce285079a127d3b14bccb7aa7286d4ac0d4ce6421" +
+ "5f2bc9e6870b33d97438be4aaa20cda5c5a912b48b8e27f3",
+ },
}
func TestHMAC(t *testing.T) {
for i, tt := range hmacTests {
- h := tt.hash(tt.key)
+ h := New(tt.hash, tt.key)
for j := 0; j < 2; j++ {
n, err := h.Write(tt.in)
if n != len(tt.in) || err != nil {
@@ -192,7 +480,7 @@ func TestHMAC(t *testing.T) {
// Repetitive Sum() calls should return the same value
for k := 0; k < 2; k++ {
- sum := fmt.Sprintf("%x", h.Sum())
+ sum := fmt.Sprintf("%x", h.Sum(nil))
if sum != tt.out {
t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
}
diff --git a/src/pkg/crypto/md4/Makefile b/src/pkg/crypto/md4/Makefile
deleted file mode 100644
index eef05ab70..000000000
--- a/src/pkg/crypto/md4/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/md4
-GOFILES=\
- md4.go\
- md4block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/md4/md4.go b/src/pkg/crypto/md4/md4.go
deleted file mode 100644
index 848d9552d..000000000
--- a/src/pkg/crypto/md4/md4.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 md4 implements the MD4 hash algorithm as defined in RFC 1320.
-package md4
-
-import (
- "crypto"
- "hash"
- "os"
-)
-
-func init() {
- crypto.RegisterHash(crypto.MD4, New)
-}
-
-// The size of an MD4 checksum in bytes.
-const Size = 16
-
-const (
- _Chunk = 64
- _Init0 = 0x67452301
- _Init1 = 0xEFCDAB89
- _Init2 = 0x98BADCFE
- _Init3 = 0x10325476
-)
-
-// digest represents the partial evaluation of a checksum.
-type digest struct {
- s [4]uint32
- x [_Chunk]byte
- nx int
- len uint64
-}
-
-func (d *digest) Reset() {
- d.s[0] = _Init0
- d.s[1] = _Init1
- d.s[2] = _Init2
- d.s[3] = _Init3
- d.nx = 0
- d.len = 0
-}
-
-// New returns a new hash.Hash computing the MD4 checksum.
-func New() hash.Hash {
- d := new(digest)
- d.Reset()
- return d
-}
-
-func (d *digest) Size() int { return Size }
-
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
- nn = len(p)
- d.len += uint64(nn)
- if d.nx > 0 {
- n := len(p)
- if n > _Chunk-d.nx {
- n = _Chunk - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
- d.nx += n
- if d.nx == _Chunk {
- _Block(d, d.x[0:])
- d.nx = 0
- }
- p = p[n:]
- }
- n := _Block(d, p)
- p = p[n:]
- if len(p) > 0 {
- d.nx = copy(d.x[:], p)
- }
- return
-}
-
-func (d0 *digest) Sum() []byte {
- // Make a copy of d0, so that caller can keep writing and summing.
- d := new(digest)
- *d = *d0
-
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- len := d.len
- var tmp [64]byte
- tmp[0] = 0x80
- if len%64 < 56 {
- d.Write(tmp[0 : 56-len%64])
- } else {
- d.Write(tmp[0 : 64+56-len%64])
- }
-
- // Length in bits.
- len <<= 3
- for i := uint(0); i < 8; i++ {
- tmp[i] = byte(len >> (8 * i))
- }
- d.Write(tmp[0:8])
-
- if d.nx != 0 {
- panic("d.nx != 0")
- }
-
- p := make([]byte, 16)
- j := 0
- for _, s := range d.s {
- p[j+0] = byte(s >> 0)
- p[j+1] = byte(s >> 8)
- p[j+2] = byte(s >> 16)
- p[j+3] = byte(s >> 24)
- j += 4
- }
- return p
-}
diff --git a/src/pkg/crypto/md4/md4_test.go b/src/pkg/crypto/md4/md4_test.go
deleted file mode 100644
index 721bd4cbc..000000000
--- a/src/pkg/crypto/md4/md4_test.go
+++ /dev/null
@@ -1,71 +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 md4
-
-import (
- "fmt"
- "io"
- "testing"
-)
-
-type md4Test struct {
- out string
- in string
-}
-
-var golden = []md4Test{
- {"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
- {"bde52cb31de33e46245e05fbdbd6fb24", "a"},
- {"ec388dd78999dfc7cf4632465693b6bf", "ab"},
- {"a448017aaf21d8525fc10ae87aa6729d", "abc"},
- {"41decd8f579255c5200f86a4bb3ba740", "abcd"},
- {"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
- {"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
- {"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
- {"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
- {"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
- {"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
- {"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
- {"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
- {"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
- {"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- {"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
- {"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
- {"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
- {"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
- {"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- {"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- {"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
- {"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
- {"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- {"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
- {"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
- {"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
- {"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
- {"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- {"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- {"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
-}
-
-func TestGolden(t *testing.T) {
- for i := 0; i < len(golden); i++ {
- g := golden[i]
- c := New()
- for j := 0; j < 3; j++ {
- if j < 2 {
- io.WriteString(c, g.in)
- } else {
- io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
- io.WriteString(c, g.in[len(g.in)/2:])
- }
- s := fmt.Sprintf("%x", c.Sum())
- if s != g.out {
- t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
- }
- c.Reset()
- }
- }
-}
diff --git a/src/pkg/crypto/md4/md4block.go b/src/pkg/crypto/md4/md4block.go
deleted file mode 100644
index 3fed475f3..000000000
--- a/src/pkg/crypto/md4/md4block.go
+++ /dev/null
@@ -1,89 +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.
-
-// MD4 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-package md4
-
-var shift1 = []uint{3, 7, 11, 19}
-var shift2 = []uint{3, 5, 9, 13}
-var shift3 = []uint{3, 9, 11, 15}
-
-var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
-var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
-
-func _Block(dig *digest, p []byte) int {
- a := dig.s[0]
- b := dig.s[1]
- c := dig.s[2]
- d := dig.s[3]
- n := 0
- var X [16]uint32
- for len(p) >= _Chunk {
- aa, bb, cc, dd := a, b, c, d
-
- j := 0
- for i := 0; i < 16; i++ {
- X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
- j += 4
- }
-
- // If this needs to be made faster in the future,
- // the usual trick is to unroll each of these
- // loops by a factor of 4; that lets you replace
- // the shift[] lookups with constants and,
- // with suitable variable renaming in each
- // unrolled body, delete the a, b, c, d = d, a, b, c
- // (or you can let the optimizer do the renaming).
- //
- // The index variables are uint so that % by a power
- // of two can be optimized easily by a compiler.
-
- // Round 1.
- for i := uint(0); i < 16; i++ {
- x := i
- s := shift1[i%4]
- f := ((c ^ d) & b) ^ d
- a += f + X[x]
- a = a<<s | a>>(32-s)
- a, b, c, d = d, a, b, c
- }
-
- // Round 2.
- for i := uint(0); i < 16; i++ {
- x := xIndex2[i]
- s := shift2[i%4]
- g := (b & c) | (b & d) | (c & d)
- a += g + X[x] + 0x5a827999
- a = a<<s | a>>(32-s)
- a, b, c, d = d, a, b, c
- }
-
- // Round 3.
- for i := uint(0); i < 16; i++ {
- x := xIndex3[i]
- s := shift3[i%4]
- h := b ^ c ^ d
- a += h + X[x] + 0x6ed9eba1
- a = a<<s | a>>(32-s)
- a, b, c, d = d, a, b, c
- }
-
- a += aa
- b += bb
- c += cc
- d += dd
-
- p = p[_Chunk:]
- n += _Chunk
- }
-
- dig.s[0] = a
- dig.s[1] = b
- dig.s[2] = c
- dig.s[3] = d
- return n
-}
diff --git a/src/pkg/crypto/md5/Makefile b/src/pkg/crypto/md5/Makefile
deleted file mode 100644
index 5cde3e6d6..000000000
--- a/src/pkg/crypto/md5/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/md5
-GOFILES=\
- md5.go\
- md5block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go
index 378faa6ec..cfb728c94 100644
--- a/src/pkg/crypto/md5/md5.go
+++ b/src/pkg/crypto/md5/md5.go
@@ -8,7 +8,6 @@ package md5
import (
"crypto"
"hash"
- "os"
)
func init() {
@@ -18,6 +17,9 @@ func init() {
// The size of an MD5 checksum in bytes.
const Size = 16
+// The blocksize of MD5 in bytes.
+const BlockSize = 64
+
const (
_Chunk = 64
_Init0 = 0x67452301
@@ -52,7 +54,9 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size }
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
@@ -78,10 +82,9 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
- d := new(digest)
- *d = *d0
+ d := *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
@@ -104,14 +107,13 @@ func (d0 *digest) Sum() []byte {
panic("d.nx != 0")
}
- p := make([]byte, 16)
- j := 0
- for _, s := range d.s {
- p[j+0] = byte(s >> 0)
- p[j+1] = byte(s >> 8)
- p[j+2] = byte(s >> 16)
- p[j+3] = byte(s >> 24)
- j += 4
+ var digest [Size]byte
+ for i, s := range d.s {
+ digest[i*4] = byte(s)
+ digest[i*4+1] = byte(s >> 8)
+ digest[i*4+2] = byte(s >> 16)
+ digest[i*4+3] = byte(s >> 24)
}
- return p
+
+ return append(in, digest[:]...)
}
diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
index 857002b70..aae875464 100644
--- a/src/pkg/crypto/md5/md5_test.go
+++ b/src/pkg/crypto/md5/md5_test.go
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package md5
+package md5_test
import (
+ "crypto/md5"
"fmt"
"io"
"testing"
@@ -52,16 +53,16 @@ var golden = []md5Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := New()
+ c := md5.New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
}
@@ -69,3 +70,11 @@ func TestGolden(t *testing.T) {
}
}
}
+
+func ExampleNew() {
+ h := md5.New()
+ io.WriteString(h, "The fog is getting thicker!")
+ io.WriteString(h, "And Leon's getting laaarger!")
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: e2c569be17396eca2a2e3c11578123ed
+}
diff --git a/src/pkg/crypto/ocsp/Makefile b/src/pkg/crypto/ocsp/Makefile
deleted file mode 100644
index 6e132ff9b..000000000
--- a/src/pkg/crypto/ocsp/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/ocsp
-GOFILES=\
- ocsp.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
deleted file mode 100644
index 7ea7a1e82..000000000
--- a/src/pkg/crypto/ocsp/ocsp.go
+++ /dev/null
@@ -1,192 +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 ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
-// are signed messages attesting to the validity of a certificate for a small
-// period of time. This is used to manage revocation for X.509 certificates.
-package ocsp
-
-import (
- "asn1"
- "crypto"
- "crypto/rsa"
- _ "crypto/sha1"
- "crypto/x509"
- "crypto/x509/pkix"
- "os"
- "time"
-)
-
-var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
-var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
-
-// These are internal structures that reflect the ASN.1 structure of an OCSP
-// response. See RFC 2560, section 4.2.
-
-const (
- ocspSuccess = 0
- ocspMalformed = 1
- ocspInternalError = 2
- ocspTryLater = 3
- ocspSigRequired = 4
- ocspUnauthorized = 5
-)
-
-type certID struct {
- HashAlgorithm pkix.AlgorithmIdentifier
- NameHash []byte
- IssuerKeyHash []byte
- SerialNumber asn1.RawValue
-}
-
-type responseASN1 struct {
- Status asn1.Enumerated
- Response responseBytes `asn1:"explicit,tag:0"`
-}
-
-type responseBytes struct {
- ResponseType asn1.ObjectIdentifier
- Response []byte
-}
-
-type basicResponse struct {
- TBSResponseData responseData
- SignatureAlgorithm pkix.AlgorithmIdentifier
- Signature asn1.BitString
- Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
-}
-
-type responseData struct {
- Raw asn1.RawContent
- 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 `asn1:"explicit,tag:0,optional"`
- Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
- Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
- ThisUpdate *time.Time
- NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
-}
-
-type revokedInfo struct {
- RevocationTime *time.Time
- Reason int `asn1:"explicit,tag:0,optional"`
-}
-
-// This is the exposed reflection of the internal OCSP structures.
-
-const (
- // Good means that the certificate is valid.
- Good = iota
- // Revoked means that the certificate has been deliberately revoked.
- Revoked = iota
- // Unknown means that the OCSP responder doesn't know about the certificate.
- Unknown = iota
- // ServerFailed means that the OCSP responder failed to process the request.
- ServerFailed = iota
-)
-
-// Response represents an OCSP response. See RFC 2560.
-type Response struct {
- // Status is one of {Good, Revoked, Unknown, ServerFailed}
- Status int
- SerialNumber []byte
- ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
- RevocationReason int
- Certificate *x509.Certificate
-}
-
-// ParseError results from an invalid OCSP response.
-type ParseError string
-
-func (p ParseError) String() string {
- return string(p)
-}
-
-// ParseResponse parses an OCSP response in DER form. It only supports
-// responses for a single certificate and only those using RSA signatures.
-// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
-// Signature errors or parse failures will result in a ParseError.
-func ParseResponse(bytes []byte) (*Response, os.Error) {
- var resp responseASN1
- rest, err := asn1.Unmarshal(bytes, &resp)
- if err != nil {
- return nil, err
- }
- if len(rest) > 0 {
- return nil, ParseError("trailing data in OCSP response")
- }
-
- ret := new(Response)
- if resp.Status != ocspSuccess {
- ret.Status = ServerFailed
- return ret, nil
- }
-
- if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
- return nil, ParseError("bad OCSP response type")
- }
-
- var basicResp basicResponse
- rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
- if err != nil {
- return nil, err
- }
-
- if len(basicResp.Certificates) != 1 {
- return nil, ParseError("OCSP response contains bad number of certificates")
- }
-
- if len(basicResp.TBSResponseData.Responses) != 1 {
- return nil, ParseError("OCSP response contains bad number of responses")
- }
-
- ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
- if err != nil {
- return nil, err
- }
-
- if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
- return nil, x509.UnsupportedAlgorithmError{}
- }
-
- hashType := crypto.SHA1
- h := hashType.New()
-
- pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
- h.Write(basicResp.TBSResponseData.Raw)
- digest := h.Sum()
- signature := basicResp.Signature.RightAlign()
-
- if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
- return nil, ParseError("bad OCSP signature")
- }
-
- r := basicResp.TBSResponseData.Responses[0]
-
- ret.SerialNumber = r.CertID.SerialNumber.Bytes
-
- switch {
- case bool(r.Good):
- ret.Status = Good
- case bool(r.Unknown):
- ret.Status = Unknown
- default:
- ret.Status = Revoked
- ret.RevokedAt = r.Revoked.RevocationTime
- ret.RevocationReason = r.Revoked.Reason
- }
-
- ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
- ret.ThisUpdate = r.ThisUpdate
- ret.NextUpdate = r.NextUpdate
-
- return ret, nil
-}
diff --git a/src/pkg/crypto/ocsp/ocsp_test.go b/src/pkg/crypto/ocsp/ocsp_test.go
deleted file mode 100644
index f9889790f..000000000
--- a/src/pkg/crypto/ocsp/ocsp_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package ocsp
-
-import (
- "bytes"
- "encoding/hex"
- "reflect"
- "testing"
- "time"
-)
-
-func TestOCSPDecode(t *testing.T) {
- responseBytes, _ := hex.DecodeString(ocspResponseHex)
- resp, err := ParseResponse(responseBytes)
- if err != nil {
- t.Error(err)
- }
-
- expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}}
-
- if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
- t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
- }
-
- if !reflect.DeepEqual(resp.NextUpdate, resp.NextUpdate) {
- t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
- }
-
- if resp.Status != expected.Status {
- t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
- }
-
- if !bytes.Equal(resp.SerialNumber, expected.SerialNumber) {
- t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
- }
-
- if resp.RevocationReason != expected.RevocationReason {
- t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
- }
-}
-
-// This OCSP response was taken from Thawte's public OCSP responder.
-// To recreate:
-// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
-// Copy and paste the first certificate into /tmp/cert.crt and the second into
-// /tmp/intermediate.crt
-// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
-// Then hex encode the result:
-// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
-
-const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
- "c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
- "6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
- "5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
- "2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
- "b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
- "30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
- "000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
- "fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
- "467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
- "4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
- "672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
- "d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
- "17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
- "e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
- "06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
- "040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
- "69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
- "2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
- "746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
- "333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
- "617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
- "2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
- "0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
- "7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
- "a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
- "fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
- "4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
- "ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
- "3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
- "29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
- "01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
- "0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
- "bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
- "6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
- "55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
- "4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
- "13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
- "0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
- "6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
- "6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
- "8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
- "2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
- "1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
- "c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
- "f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
- "a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
- "6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
diff --git a/src/pkg/crypto/openpgp/Makefile b/src/pkg/crypto/openpgp/Makefile
deleted file mode 100644
index b46ac2bba..000000000
--- a/src/pkg/crypto/openpgp/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/openpgp
-GOFILES=\
- canonical_text.go\
- keys.go\
- read.go\
- write.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/armor/Makefile b/src/pkg/crypto/openpgp/armor/Makefile
deleted file mode 100644
index 138e314e9..000000000
--- a/src/pkg/crypto/openpgp/armor/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../../Make.inc
-
-TARG=crypto/openpgp/armor
-GOFILES=\
- armor.go\
- encode.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/armor/armor.go b/src/pkg/crypto/openpgp/armor/armor.go
deleted file mode 100644
index 9c4180d6d..000000000
--- a/src/pkg/crypto/openpgp/armor/armor.go
+++ /dev/null
@@ -1,220 +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 armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
-// very similar to PEM except that it has an additional CRC checksum.
-package armor
-
-import (
- "bufio"
- "bytes"
- "crypto/openpgp/error"
- "encoding/base64"
- "io"
- "os"
-)
-
-// A Block represents an OpenPGP armored structure.
-//
-// The encoded form is:
-// -----BEGIN Type-----
-// Headers
-//
-// base64-encoded Bytes
-// '=' base64 encoded checksum
-// -----END Type-----
-// where Headers is a possibly empty sequence of Key: Value lines.
-//
-// Since the armored data can be very large, this package presents a streaming
-// interface.
-type Block struct {
- Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
- Header map[string]string // Optional headers.
- Body io.Reader // A Reader from which the contents can be read
- lReader lineReader
- oReader openpgpReader
-}
-
-var ArmorCorrupt os.Error = error.StructuralError("armor invalid")
-
-const crc24Init = 0xb704ce
-const crc24Poly = 0x1864cfb
-const crc24Mask = 0xffffff
-
-// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
-func crc24(crc uint32, d []byte) uint32 {
- for _, b := range d {
- crc ^= uint32(b) << 16
- for i := 0; i < 8; i++ {
- crc <<= 1
- if crc&0x1000000 != 0 {
- crc ^= crc24Poly
- }
- }
- }
- return crc
-}
-
-var armorStart = []byte("-----BEGIN ")
-var armorEnd = []byte("-----END ")
-var armorEndOfLine = []byte("-----")
-
-// lineReader wraps a line based reader. It watches for the end of an armor
-// block and records the expected CRC value.
-type lineReader struct {
- in *bufio.Reader
- buf []byte
- eof bool
- crc uint32
-}
-
-func (l *lineReader) Read(p []byte) (n int, err os.Error) {
- if l.eof {
- return 0, os.EOF
- }
-
- if len(l.buf) > 0 {
- n = copy(p, l.buf)
- l.buf = l.buf[n:]
- return
- }
-
- line, isPrefix, err := l.in.ReadLine()
- if err != nil {
- return
- }
- if isPrefix {
- return 0, ArmorCorrupt
- }
-
- if len(line) == 5 && line[0] == '=' {
- // This is the checksum line
- var expectedBytes [3]byte
- var m int
- m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
- if m != 3 || err != nil {
- return
- }
- l.crc = uint32(expectedBytes[0])<<16 |
- uint32(expectedBytes[1])<<8 |
- uint32(expectedBytes[2])
-
- line, _, err = l.in.ReadLine()
- if err != nil && err != os.EOF {
- return
- }
- if !bytes.HasPrefix(line, armorEnd) {
- return 0, ArmorCorrupt
- }
-
- l.eof = true
- return 0, os.EOF
- }
-
- if len(line) > 64 {
- return 0, ArmorCorrupt
- }
-
- n = copy(p, line)
- bytesToSave := len(line) - n
- if bytesToSave > 0 {
- if cap(l.buf) < bytesToSave {
- l.buf = make([]byte, 0, bytesToSave)
- }
- l.buf = l.buf[0:bytesToSave]
- copy(l.buf, line[n:])
- }
-
- return
-}
-
-// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
-// a running CRC of the resulting data and checks the CRC against the value
-// found by the lineReader at EOF.
-type openpgpReader struct {
- lReader *lineReader
- b64Reader io.Reader
- currentCRC uint32
-}
-
-func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
- n, err = r.b64Reader.Read(p)
- r.currentCRC = crc24(r.currentCRC, p[:n])
-
- if err == os.EOF {
- if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
- return 0, ArmorCorrupt
- }
- }
-
- return
-}
-
-// Decode reads a PGP armored block from the given Reader. It will ignore
-// leading garbage. If it doesn't find a block, it will return nil, os.EOF. The
-// given Reader is not usable after calling this function: an 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)
- var line []byte
- ignoreNext := false
-
-TryNextBlock:
- p = nil
-
- // Skip leading garbage
- for {
- ignoreThis := ignoreNext
- line, ignoreNext, err = r.ReadLine()
- if err != nil {
- return
- }
- if ignoreNext || ignoreThis {
- continue
- }
- line = bytes.TrimSpace(line)
- if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
- break
- }
- }
-
- p = new(Block)
- p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
- p.Header = make(map[string]string)
- nextIsContinuation := false
- var lastKey string
-
- // Read headers
- for {
- isContinuation := nextIsContinuation
- line, nextIsContinuation, err = r.ReadLine()
- if err != nil {
- p = nil
- return
- }
- if isContinuation {
- p.Header[lastKey] += string(line)
- continue
- }
- line = bytes.TrimSpace(line)
- if len(line) == 0 {
- break
- }
-
- i := bytes.Index(line, []byte(": "))
- if i == -1 {
- goto TryNextBlock
- }
- lastKey = string(line[:i])
- p.Header[lastKey] = string(line[i+2:])
- }
-
- p.lReader.in = r
- p.oReader.currentCRC = crc24Init
- p.oReader.lReader = &p.lReader
- p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
- p.Body = &p.oReader
-
- return
-}
diff --git a/src/pkg/crypto/openpgp/armor/armor_test.go b/src/pkg/crypto/openpgp/armor/armor_test.go
deleted file mode 100644
index 9334e94e9..000000000
--- a/src/pkg/crypto/openpgp/armor/armor_test.go
+++ /dev/null
@@ -1,95 +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 armor
-
-import (
- "bytes"
- "hash/adler32"
- "io/ioutil"
- "testing"
-)
-
-func TestDecodeEncode(t *testing.T) {
- buf := bytes.NewBuffer([]byte(armorExample1))
- result, err := Decode(buf)
- if err != nil {
- t.Error(err)
- }
- expectedType := "PGP SIGNATURE"
- if result.Type != expectedType {
- t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
- }
- if len(result.Header) != 1 {
- t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
- }
- v, ok := result.Header["Version"]
- if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
- t.Errorf("result.Header: got:%#v", result.Header)
- }
-
- contents, err := ioutil.ReadAll(result.Body)
- if err != nil {
- t.Error(err)
- }
-
- if adler32.Checksum(contents) != 0x27b144be {
- t.Errorf("contents: got: %x", contents)
- }
-
- buf = bytes.NewBuffer(nil)
- w, err := Encode(buf, result.Type, result.Header)
- if err != nil {
- t.Error(err)
- }
- _, err = w.Write(contents)
- if err != nil {
- t.Error(err)
- }
- w.Close()
-
- if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
- t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
- }
-}
-
-func TestLongHeader(t *testing.T) {
- buf := bytes.NewBuffer([]byte(armorLongLine))
- result, err := Decode(buf)
- if err != nil {
- t.Error(err)
- return
- }
- value, ok := result.Header["Version"]
- if !ok {
- t.Errorf("missing Version header")
- }
- if value != longValueExpected {
- t.Errorf("got: %s want: %s", value, longValueExpected)
- }
-}
-
-const armorExample1 = `-----BEGIN PGP SIGNATURE-----
-Version: GnuPG v1.4.10 (GNU/Linux)
-
-iJwEAAECAAYFAk1Fv/0ACgkQo01+GMIMMbsYTwQAiAw+QAaNfY6WBdplZ/uMAccm
-4g+81QPmTSGHnetSb6WBiY13kVzK4HQiZH8JSkmmroMLuGeJwsRTEL4wbjRyUKEt
-p1xwUZDECs234F1xiG5enc5SGlRtP7foLBz9lOsjx+LEcA4sTl5/2eZR9zyFZqWW
-TxRjs+fJCIFuo71xb1g=
-=/teI
------END PGP SIGNATURE-----`
-
-const armorLongLine = `-----BEGIN PGP SIGNATURE-----
-Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
-
-iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
-kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
-cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
-byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
-WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
-okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
-=wfQG
------END PGP SIGNATURE-----`
-
-const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
diff --git a/src/pkg/crypto/openpgp/armor/encode.go b/src/pkg/crypto/openpgp/armor/encode.go
deleted file mode 100644
index 99dee375e..000000000
--- a/src/pkg/crypto/openpgp/armor/encode.go
+++ /dev/null
@@ -1,161 +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 armor
-
-import (
- "encoding/base64"
- "io"
- "os"
-)
-
-var armorHeaderSep = []byte(": ")
-var blockEnd = []byte("\n=")
-var newline = []byte("\n")
-var armorEndOfLineOut = []byte("-----\n")
-
-// writeSlices writes its arguments to the given Writer.
-func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
- for _, s := range slices {
- _, err = out.Write(s)
- if err != nil {
- return err
- }
- }
- return
-}
-
-// lineBreaker breaks data across several lines, all of the same byte length
-// (except possibly the last). Lines are broken with a single '\n'.
-type lineBreaker struct {
- lineLength int
- line []byte
- used int
- out io.Writer
- haveWritten bool
-}
-
-func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
- return &lineBreaker{
- lineLength: lineLength,
- line: make([]byte, lineLength),
- used: 0,
- out: out,
- }
-}
-
-func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
- n = len(b)
-
- if n == 0 {
- return
- }
-
- if l.used == 0 && l.haveWritten {
- _, err = l.out.Write([]byte{'\n'})
- if err != nil {
- return
- }
- }
-
- if l.used+len(b) < l.lineLength {
- l.used += copy(l.line[l.used:], b)
- return
- }
-
- l.haveWritten = true
- _, err = l.out.Write(l.line[0:l.used])
- if err != nil {
- return
- }
- excess := l.lineLength - l.used
- l.used = 0
-
- _, err = l.out.Write(b[0:excess])
- if err != nil {
- return
- }
-
- _, err = l.Write(b[excess:])
- return
-}
-
-func (l *lineBreaker) Close() (err os.Error) {
- if l.used > 0 {
- _, err = l.out.Write(l.line[0:l.used])
- if err != nil {
- return
- }
- }
-
- return
-}
-
-// encoding keeps track of a running CRC24 over the data which has been written
-// to it and outputs a OpenPGP checksum when closed, followed by an armor
-// trailer.
-//
-// It's built into a stack of io.Writers:
-// encoding -> base64 encoder -> lineBreaker -> out
-type encoding struct {
- out io.Writer
- breaker *lineBreaker
- b64 io.WriteCloser
- crc uint32
- blockType []byte
-}
-
-func (e *encoding) Write(data []byte) (n int, err os.Error) {
- e.crc = crc24(e.crc, data)
- return e.b64.Write(data)
-}
-
-func (e *encoding) Close() (err os.Error) {
- err = e.b64.Close()
- if err != nil {
- return
- }
- e.breaker.Close()
-
- var checksumBytes [3]byte
- checksumBytes[0] = byte(e.crc >> 16)
- checksumBytes[1] = byte(e.crc >> 8)
- checksumBytes[2] = byte(e.crc)
-
- var b64ChecksumBytes [4]byte
- base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
-
- return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
-}
-
-// Encode returns a WriteCloser which will encode the data written to it in
-// OpenPGP armor.
-func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
- bType := []byte(blockType)
- err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
- if err != nil {
- return
- }
-
- for k, v := range headers {
- err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
- if err != nil {
- return
- }
- }
-
- _, err = out.Write(newline)
- if err != nil {
- return
- }
-
- e := &encoding{
- out: out,
- breaker: newLineBreaker(out, 64),
- crc: crc24Init,
- blockType: bType,
- }
- e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
- return e, nil
-}
diff --git a/src/pkg/crypto/openpgp/canonical_text.go b/src/pkg/crypto/openpgp/canonical_text.go
deleted file mode 100644
index 293eff354..000000000
--- a/src/pkg/crypto/openpgp/canonical_text.go
+++ /dev/null
@@ -1,58 +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 openpgp
-
-import (
- "hash"
- "os"
-)
-
-// NewCanonicalTextHash reformats text written to it into the canonical
-// form and then applies the hash h. See RFC 4880, section 5.2.1.
-func NewCanonicalTextHash(h hash.Hash) hash.Hash {
- return &canonicalTextHash{h, 0}
-}
-
-type canonicalTextHash struct {
- h hash.Hash
- s int
-}
-
-var newline = []byte{'\r', '\n'}
-
-func (cth *canonicalTextHash) Write(buf []byte) (int, os.Error) {
- start := 0
-
- for i, c := range buf {
- switch cth.s {
- case 0:
- if c == '\r' {
- cth.s = 1
- } else if c == '\n' {
- cth.h.Write(buf[start:i])
- cth.h.Write(newline)
- start = i + 1
- }
- case 1:
- cth.s = 0
- }
- }
-
- cth.h.Write(buf[start:])
- return len(buf), nil
-}
-
-func (cth *canonicalTextHash) Sum() []byte {
- return cth.h.Sum()
-}
-
-func (cth *canonicalTextHash) Reset() {
- cth.h.Reset()
- cth.s = 0
-}
-
-func (cth *canonicalTextHash) Size() int {
- return cth.h.Size()
-}
diff --git a/src/pkg/crypto/openpgp/canonical_text_test.go b/src/pkg/crypto/openpgp/canonical_text_test.go
deleted file mode 100644
index ccf2910cc..000000000
--- a/src/pkg/crypto/openpgp/canonical_text_test.go
+++ /dev/null
@@ -1,49 +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 openpgp
-
-import (
- "bytes"
- "os"
- "testing"
-)
-
-type recordingHash struct {
- buf *bytes.Buffer
-}
-
-func (r recordingHash) Write(b []byte) (n int, err os.Error) {
- return r.buf.Write(b)
-}
-
-func (r recordingHash) Sum() []byte {
- return r.buf.Bytes()
-}
-
-func (r recordingHash) Reset() {
- panic("shouldn't be called")
-}
-
-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)
- c.Write([]byte(input))
- result := c.Sum()
- if expected != string(result) {
- t.Errorf("input: %x got: %x want: %x", input, result, expected)
- }
-}
-
-func TestCanonicalText(t *testing.T) {
- testCanonicalText(t, "foo\n", "foo\r\n")
- testCanonicalText(t, "foo", "foo")
- testCanonicalText(t, "foo\r\n", "foo\r\n")
- testCanonicalText(t, "foo\r\nbar", "foo\r\nbar")
- testCanonicalText(t, "foo\r\nbar\n\n", "foo\r\nbar\r\n\r\n")
-}
diff --git a/src/pkg/crypto/openpgp/elgamal/Makefile b/src/pkg/crypto/openpgp/elgamal/Makefile
deleted file mode 100644
index f730255f8..000000000
--- a/src/pkg/crypto/openpgp/elgamal/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../../Make.inc
-
-TARG=crypto/openpgp/elgamal
-GOFILES=\
- elgamal.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal.go b/src/pkg/crypto/openpgp/elgamal/elgamal.go
deleted file mode 100644
index 99a6e3e1f..000000000
--- a/src/pkg/crypto/openpgp/elgamal/elgamal.go
+++ /dev/null
@@ -1,122 +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 elgamal implements ElGamal encryption, suitable for OpenPGP,
-// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
-// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
-// n. 4, 1985, pp. 469-472.
-//
-// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
-// unsuitable for other protocols. RSA should be used in preference in any
-// case.
-package elgamal
-
-import (
- "big"
- "crypto/rand"
- "crypto/subtle"
- "io"
- "os"
-)
-
-// PublicKey represents an ElGamal public key.
-type PublicKey struct {
- G, P, Y *big.Int
-}
-
-// PrivateKey represents an ElGamal private key.
-type PrivateKey struct {
- PublicKey
- X *big.Int
-}
-
-// Encrypt encrypts the given message to the given public key. The result is a
-// pair of integers. Errors can result from reading random, or because msg is
-// too large to be encrypted to the public key.
-func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) {
- pLen := (pub.P.BitLen() + 7) / 8
- if len(msg) > pLen-11 {
- err = os.NewError("elgamal: message too long")
- return
- }
-
- // EM = 0x02 || PS || 0x00 || M
- em := make([]byte, pLen-1)
- em[0] = 2
- ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
- err = nonZeroRandomBytes(ps, random)
- if err != nil {
- return
- }
- em[len(em)-len(msg)-1] = 0
- copy(mm, msg)
-
- m := new(big.Int).SetBytes(em)
-
- k, err := rand.Int(random, pub.P)
- if err != nil {
- return
- }
-
- c1 = new(big.Int).Exp(pub.G, k, pub.P)
- s := new(big.Int).Exp(pub.Y, k, pub.P)
- c2 = s.Mul(s, m)
- c2.Mod(c2, pub.P)
-
- return
-}
-
-// Decrypt takes two integers, resulting from an ElGamal encryption, and
-// returns the plaintext of the message. An error can result only if the
-// ciphertext is invalid. Users should keep in mind that this is a padding
-// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
-// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
-// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
-// Bleichenbacher, Advances in Cryptology (Crypto '98),
-func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) {
- s := new(big.Int).Exp(c1, priv.X, priv.P)
- s.ModInverse(s, priv.P)
- s.Mul(s, c2)
- s.Mod(s, priv.P)
- em := s.Bytes()
-
- firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
-
- // The remainder of the plaintext must be a string of non-zero random
- // octets, followed by a 0, followed by the message.
- // lookingForIndex: 1 iff we are still looking for the zero.
- // index: the offset of the first zero byte.
- var lookingForIndex, index int
- lookingForIndex = 1
-
- for i := 1; i < len(em); i++ {
- equals0 := subtle.ConstantTimeByteEq(em[i], 0)
- index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
- lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
- }
-
- if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
- return nil, os.NewError("elgamal: decryption error")
- }
- return em[index+1:], nil
-}
-
-// nonZeroRandomBytes fills the given slice with non-zero random octets.
-func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
- _, err = io.ReadFull(rand, s)
- if err != nil {
- return
- }
-
- for i := 0; i < len(s); i++ {
- for s[i] == 0 {
- _, err = io.ReadFull(rand, s[i:i+1])
- if err != nil {
- return
- }
- }
- }
-
- return
-}
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal_test.go b/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
deleted file mode 100644
index 101121aa6..000000000
--- a/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
+++ /dev/null
@@ -1,49 +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 elgamal
-
-import (
- "big"
- "bytes"
- "crypto/rand"
- "testing"
-)
-
-// This is the 1024-bit MODP group from RFC 5114, section 2.1:
-const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
-
-const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
-
-func fromHex(hex string) *big.Int {
- n, ok := new(big.Int).SetString(hex, 16)
- if !ok {
- panic("failed to parse hex number")
- }
- return n
-}
-
-func TestEncryptDecrypt(t *testing.T) {
- priv := &PrivateKey{
- PublicKey: PublicKey{
- G: fromHex(generatorHex),
- P: fromHex(primeHex),
- },
- X: fromHex("42"),
- }
- priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
-
- message := []byte("hello world")
- c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
- if err != nil {
- t.Errorf("error encrypting: %s", err)
- }
- message2, err := Decrypt(priv, c1, c2)
- if err != nil {
- t.Errorf("error decrypting: %s", err)
- }
- if !bytes.Equal(message2, message) {
- t.Errorf("decryption failed, got: %x, want: %x", message2, message)
- }
-}
diff --git a/src/pkg/crypto/openpgp/error/Makefile b/src/pkg/crypto/openpgp/error/Makefile
deleted file mode 100644
index 8c370a089..000000000
--- a/src/pkg/crypto/openpgp/error/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../../Make.inc
-
-TARG=crypto/openpgp/error
-GOFILES=\
- error.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/error/error.go b/src/pkg/crypto/openpgp/error/error.go
deleted file mode 100644
index 3759ce161..000000000
--- a/src/pkg/crypto/openpgp/error/error.go
+++ /dev/null
@@ -1,64 +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 error contains common error types for the OpenPGP packages.
-package error
-
-import (
- "strconv"
-)
-
-// A StructuralError is returned when OpenPGP data is found to be syntactically
-// invalid.
-type StructuralError string
-
-func (s StructuralError) String() string {
- return "OpenPGP data invalid: " + string(s)
-}
-
-// UnsupportedError indicates that, although the OpenPGP data is valid, it
-// makes use of currently unimplemented features.
-type UnsupportedError string
-
-func (s UnsupportedError) String() string {
- return "OpenPGP feature unsupported: " + string(s)
-}
-
-// InvalidArgumentError indicates that the caller is in error and passed an
-// incorrect value.
-type InvalidArgumentError string
-
-func (i InvalidArgumentError) String() string {
- return "OpenPGP argument invalid: " + string(i)
-}
-
-// SignatureError indicates that a syntactically valid signature failed to
-// validate.
-type SignatureError string
-
-func (b SignatureError) String() string {
- return "OpenPGP signature invalid: " + string(b)
-}
-
-type keyIncorrect int
-
-func (ki keyIncorrect) String() string {
- return "the given key was incorrect"
-}
-
-var KeyIncorrectError = keyIncorrect(0)
-
-type unknownIssuer int
-
-func (unknownIssuer) String() string {
- return "signature make by unknown entity"
-}
-
-var UnknownIssuerError = unknownIssuer(0)
-
-type UnknownPacketTypeError uint8
-
-func (upte UnknownPacketTypeError) String() string {
- return "unknown OpenPGP packet type: " + strconv.Itoa(int(upte))
-}
diff --git a/src/pkg/crypto/openpgp/keys.go b/src/pkg/crypto/openpgp/keys.go
deleted file mode 100644
index c70fb7927..000000000
--- a/src/pkg/crypto/openpgp/keys.go
+++ /dev/null
@@ -1,545 +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 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.
-var PublicKeyType = "PGP PUBLIC KEY BLOCK"
-// PrivateKeyType is the armor type for a PGP private key.
-var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
-
-// An Entity represents the components of an OpenPGP key: a primary public key
-// (which must be a signing key), one or more identities claimed by that key,
-// and zero or more subkeys, which may be encryption keys.
-type Entity struct {
- PrimaryKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- Identities map[string]*Identity // indexed by Identity.Name
- Subkeys []Subkey
-}
-
-// An Identity represents an identity claimed by an Entity and zero or more
-// assertions by other entities about that claim.
-type Identity struct {
- Name string // by convention, has the form "Full Name (comment) <email@example.com>"
- UserId *packet.UserId
- SelfSignature *packet.Signature
- Signatures []*packet.Signature
-}
-
-// A Subkey is an additional public key in an Entity. Subkeys can be used for
-// encryption.
-type Subkey struct {
- PublicKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- Sig *packet.Signature
-}
-
-// A Key identifies a specific public key in an Entity. This is either the
-// Entity's primary key or a subkey.
-type Key struct {
- Entity *Entity
- PublicKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- SelfSignature *packet.Signature
-}
-
-// A KeyRing provides access to public and private keys.
-type KeyRing interface {
- // KeysById returns the set of keys that have the given key id.
- KeysById(id uint64) []Key
- // DecryptionKeys returns all private keys that are valid for
- // decryption.
- 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
-
-// KeysById returns the set of keys that have the given key id.
-func (el EntityList) KeysById(id uint64) (keys []Key) {
- for _, e := range el {
- if e.PrimaryKey.KeyId == id {
- var selfSig *packet.Signature
- for _, ident := range e.Identities {
- if selfSig == nil {
- selfSig = ident.SelfSignature
- } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
- selfSig = ident.SelfSignature
- break
- }
- }
- keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
- }
-
- for _, subKey := range e.Subkeys {
- if subKey.PublicKey.KeyId == id {
- keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
- }
- }
- }
- return
-}
-
-// DecryptionKeys returns all private keys that are valid for decryption.
-func (el EntityList) DecryptionKeys() (keys []Key) {
- for _, e := range el {
- for _, subKey := range e.Subkeys {
- if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
- keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
- }
- }
- }
- return
-}
-
-// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
-func ReadArmoredKeyRing(r io.Reader) (EntityList, os.Error) {
- block, err := armor.Decode(r)
- if err == os.EOF {
- return nil, error.InvalidArgumentError("no armored data found")
- }
- if err != nil {
- return nil, err
- }
- if block.Type != PublicKeyType && block.Type != PrivateKeyType {
- return nil, error.InvalidArgumentError("expected public or private key block, got: " + block.Type)
- }
-
- return ReadKeyRing(block.Body)
-}
-
-// ReadKeyRing reads one or more public/private keys. Unsupported keys are
-// ignored as long as at least a single valid key is found.
-func ReadKeyRing(r io.Reader) (el EntityList, err os.Error) {
- packets := packet.NewReader(r)
- var lastUnsupportedError os.Error
-
- for {
- var e *Entity
- e, err = readEntity(packets)
- if err != nil {
- if _, ok := err.(error.UnsupportedError); ok {
- lastUnsupportedError = err
- err = readToNextPublicKey(packets)
- }
- if err == os.EOF {
- err = nil
- break
- }
- if err != nil {
- el = nil
- break
- }
- } else {
- el = append(el, e)
- }
- }
-
- if len(el) == 0 && err == nil {
- err = lastUnsupportedError
- }
- return
-}
-
-// readToNextPublicKey reads packets until the start of the entity and leaves
-// the first packet of the new entity in the Reader.
-func readToNextPublicKey(packets *packet.Reader) (err os.Error) {
- var p packet.Packet
- for {
- p, err = packets.Next()
- if err == os.EOF {
- return
- } else if err != nil {
- if _, ok := err.(error.UnsupportedError); ok {
- err = nil
- continue
- }
- return
- }
-
- if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
- packets.Unread(p)
- return
- }
- }
-
- panic("unreachable")
-}
-
-// readEntity reads an entity (public key, identities, subkeys etc) from the
-// given Reader.
-func readEntity(packets *packet.Reader) (*Entity, os.Error) {
- e := new(Entity)
- e.Identities = make(map[string]*Identity)
-
- p, err := packets.Next()
- if err != nil {
- return nil, err
- }
-
- var ok bool
- if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
- if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
- packets.Unread(p)
- return nil, error.StructuralError("first packet was not a public/private key")
- } else {
- e.PrimaryKey = &e.PrivateKey.PublicKey
- }
- }
-
- if !e.PrimaryKey.PubKeyAlgo.CanSign() {
- return nil, error.StructuralError("primary key cannot be used for signatures")
- }
-
- var current *Identity
-EachPacket:
- for {
- p, err := packets.Next()
- if err == os.EOF {
- break
- } else if err != nil {
- return nil, err
- }
-
- switch pkt := p.(type) {
- case *packet.UserId:
- current = new(Identity)
- current.Name = pkt.Id
- current.UserId = pkt
- e.Identities[pkt.Id] = current
-
- for {
- p, err = packets.Next()
- if err == os.EOF {
- return nil, io.ErrUnexpectedEOF
- } else if err != nil {
- return nil, err
- }
-
- sig, ok := p.(*packet.Signature)
- if !ok {
- return nil, error.StructuralError("user ID packet not followed by self-signature")
- }
-
- 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())
- }
- current.SelfSignature = sig
- break
- }
- current.Signatures = append(current.Signatures, sig)
- }
- case *packet.Signature:
- if current == nil {
- return nil, error.StructuralError("signature packet found before user id packet")
- }
- current.Signatures = append(current.Signatures, pkt)
- case *packet.PrivateKey:
- if pkt.IsSubkey == false {
- packets.Unread(p)
- break EachPacket
- }
- err = addSubkey(e, packets, &pkt.PublicKey, pkt)
- if err != nil {
- return nil, err
- }
- case *packet.PublicKey:
- if pkt.IsSubkey == false {
- packets.Unread(p)
- break EachPacket
- }
- err = addSubkey(e, packets, pkt, nil)
- if err != nil {
- return nil, err
- }
- default:
- // we ignore unknown packets
- }
- }
-
- if len(e.Identities) == 0 {
- return nil, error.StructuralError("entity without any identities")
- }
-
- return e, nil
-}
-
-func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) os.Error {
- var subKey Subkey
- subKey.PublicKey = pub
- subKey.PrivateKey = priv
- p, err := packets.Next()
- if err == os.EOF {
- return io.ErrUnexpectedEOF
- }
- if err != nil {
- return error.StructuralError("subkey signature invalid: " + err.String())
- }
- var ok bool
- subKey.Sig, ok = p.(*packet.Signature)
- if !ok {
- return error.StructuralError("subkey packet not followed by signature")
- }
- if subKey.Sig.SigType != packet.SigTypeSubkeyBinding {
- return error.StructuralError("subkey signature with wrong type")
- }
- err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
- if err != nil {
- return error.StructuralError("subkey signature invalid: " + err.String())
- }
- 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/src/pkg/crypto/openpgp/packet/Makefile b/src/pkg/crypto/openpgp/packet/Makefile
deleted file mode 100644
index 0f0d94eb1..000000000
--- a/src/pkg/crypto/openpgp/packet/Makefile
+++ /dev/null
@@ -1,22 +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.
-
-include ../../../../Make.inc
-
-TARG=crypto/openpgp/packet
-GOFILES=\
- compressed.go\
- encrypted_key.go\
- literal.go\
- one_pass_signature.go\
- packet.go\
- private_key.go\
- public_key.go\
- reader.go\
- signature.go\
- symmetrically_encrypted.go\
- symmetric_key_encrypted.go\
- userid.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/packet/compressed.go b/src/pkg/crypto/openpgp/packet/compressed.go
deleted file mode 100644
index 1c15c24c4..000000000
--- a/src/pkg/crypto/openpgp/packet/compressed.go
+++ /dev/null
@@ -1,39 +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 packet
-
-import (
- "compress/flate"
- "compress/zlib"
- "crypto/openpgp/error"
- "io"
- "os"
- "strconv"
-)
-
-// Compressed represents a compressed OpenPGP packet. The decompressed contents
-// will contain more OpenPGP packets. See RFC 4880, section 5.6.
-type Compressed struct {
- Body io.Reader
-}
-
-func (c *Compressed) parse(r io.Reader) os.Error {
- var buf [1]byte
- _, err := readFull(r, buf[:])
- if err != nil {
- return err
- }
-
- switch buf[0] {
- case 1:
- c.Body = flate.NewReader(r)
- case 2:
- c.Body, err = zlib.NewReader(r)
- default:
- err = error.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
- }
-
- return err
-}
diff --git a/src/pkg/crypto/openpgp/packet/compressed_test.go b/src/pkg/crypto/openpgp/packet/compressed_test.go
deleted file mode 100644
index 24fe501ed..000000000
--- a/src/pkg/crypto/openpgp/packet/compressed_test.go
+++ /dev/null
@@ -1,41 +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 packet
-
-import (
- "bytes"
- "encoding/hex"
- "os"
- "io/ioutil"
- "testing"
-)
-
-func TestCompressed(t *testing.T) {
- packet, err := Read(readerFromHex(compressedHex))
- if err != nil {
- t.Errorf("failed to read Compressed: %s", err)
- return
- }
-
- c, ok := packet.(*Compressed)
- if !ok {
- t.Error("didn't find Compressed packet")
- return
- }
-
- contents, err := ioutil.ReadAll(c.Body)
- if err != nil && err != os.EOF {
- t.Error(err)
- return
- }
-
- expected, _ := hex.DecodeString(compressedExpectedHex)
- if !bytes.Equal(expected, contents) {
- t.Errorf("got:%x want:%x", contents, expected)
- }
-}
-
-const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
-const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key.go b/src/pkg/crypto/openpgp/packet/encrypted_key.go
deleted file mode 100644
index b4730cbc9..000000000
--- a/src/pkg/crypto/openpgp/packet/encrypted_key.go
+++ /dev/null
@@ -1,168 +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 packet
-
-import (
- "big"
- "crypto/openpgp/elgamal"
- "crypto/openpgp/error"
- "crypto/rand"
- "crypto/rsa"
- "encoding/binary"
- "io"
- "os"
- "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
- 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) {
- var buf [10]byte
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
- 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])
- 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
-}
-
-func checksumKeyMaterial(key []byte) uint16 {
- var checksum uint16
- for _, v := range key {
- checksum += uint16(v)
- }
- 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 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])
- checksum := checksumKeyMaterial(e.Key)
- if checksum != expectedChecksum {
- return error.StructuralError("EncryptedKey checksum incorrect")
- }
-
- return nil
-}
-
-// SerializeEncryptedKey serializes an encrypted key packet to w that contains
-// key, encrypted to pub.
-func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error {
- var buf [10]byte
- buf[0] = encryptedKeyVersion
- binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
- buf[9] = byte(pub.PubKeyAlgo)
-
- keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
- keyBlock[0] = byte(cipherFunc)
- copy(keyBlock[1:], key)
- checksum := checksumKeyMaterial(key)
- keyBlock[1+len(key)] = byte(checksum >> 8)
- keyBlock[1+len(key)+1] = byte(checksum)
-
- switch pub.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
- return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
- case PubKeyAlgoElGamal:
- return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
- case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
- return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
- }
-
- return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
-}
-
-func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error {
- cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
- if err != nil {
- return error.InvalidArgumentError("RSA encryption failed: " + err.String())
- }
-
- packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
-
- err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
- if err != nil {
- return err
- }
- _, err = w.Write(header[:])
- if err != nil {
- return err
- }
- return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
-}
-
-func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error {
- c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
- if err != nil {
- return error.InvalidArgumentError("ElGamal encryption failed: " + err.String())
- }
-
- packetLen := 10 /* header length */
- packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
- packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
-
- err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
- if err != nil {
- return err
- }
- _, err = w.Write(header[:])
- if err != nil {
- return err
- }
- err = writeBig(w, c1)
- if err != nil {
- return err
- }
- return writeBig(w, c2)
-}
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
deleted file mode 100644
index b402245bd..000000000
--- a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
+++ /dev/null
@@ -1,126 +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 packet
-
-import (
- "big"
- "bytes"
- "crypto/rand"
- "crypto/rsa"
- "fmt"
- "testing"
-)
-
-func bigFromBase10(s string) *big.Int {
- b, ok := new(big.Int).SetString(s, 10)
- if !ok {
- panic("bigFromBase10 failed")
- }
- return b
-}
-
-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)
- return
- }
- ek, ok := p.(*EncryptedKey)
- if !ok {
- t.Errorf("didn't parse an EncryptedKey, got %#v", p)
- return
- }
-
- if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
- t.Errorf("unexpected EncryptedKey contents: %#v", ek)
- return
- }
-
- 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
- }
-
- if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
- t.Errorf("unexpected EncryptedKey contents: %#v", ek)
- return
- }
-
- err = ek.Decrypt(encryptedKeyPriv)
- if err != nil {
- t.Errorf("error from Decrypt: %s", err)
- return
- }
-
- if ek.CipherFunc != CipherAES128 {
- 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)
- }
-}
diff --git a/src/pkg/crypto/openpgp/packet/literal.go b/src/pkg/crypto/openpgp/packet/literal.go
deleted file mode 100644
index 9411572d7..000000000
--- a/src/pkg/crypto/openpgp/packet/literal.go
+++ /dev/null
@@ -1,90 +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 packet
-
-import (
- "encoding/binary"
- "io"
- "os"
-)
-
-// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
-type LiteralData struct {
- IsBinary bool
- FileName string
- Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
- Body io.Reader
-}
-
-// ForEyesOnly returns whether the contents of the LiteralData have been marked
-// as especially sensitive.
-func (l *LiteralData) ForEyesOnly() bool {
- return l.FileName == "_CONSOLE"
-}
-
-func (l *LiteralData) parse(r io.Reader) (err os.Error) {
- var buf [256]byte
-
- _, err = readFull(r, buf[:2])
- if err != nil {
- return
- }
-
- l.IsBinary = buf[0] == 'b'
- fileNameLen := int(buf[1])
-
- _, err = readFull(r, buf[:fileNameLen])
- if err != nil {
- return
- }
-
- l.FileName = string(buf[:fileNameLen])
-
- _, err = readFull(r, buf[:4])
- if err != nil {
- return
- }
-
- l.Time = binary.BigEndian.Uint32(buf[:4])
- 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/src/pkg/crypto/openpgp/packet/one_pass_signature.go b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
deleted file mode 100644
index ca826e4f4..000000000
--- a/src/pkg/crypto/openpgp/packet/one_pass_signature.go
+++ /dev/null
@@ -1,74 +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 packet
-
-import (
- "crypto"
- "crypto/openpgp/error"
- "crypto/openpgp/s2k"
- "encoding/binary"
- "io"
- "os"
- "strconv"
-)
-
-// OnePassSignature represents a one-pass signature packet. See RFC 4880,
-// section 5.4.
-type OnePassSignature struct {
- SigType SignatureType
- Hash crypto.Hash
- PubKeyAlgo PublicKeyAlgorithm
- KeyId uint64
- IsLast bool
-}
-
-const onePassSignatureVersion = 3
-
-func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
- var buf [13]byte
-
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
- if buf[0] != onePassSignatureVersion {
- err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
- }
-
- var ok bool
- ops.Hash, ok = s2k.HashIdToHash(buf[2])
- if !ok {
- return error.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
- }
-
- ops.SigType = SignatureType(buf[1])
- ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
- ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
- ops.IsLast = buf[12] != 0
- return
-}
-
-// Serialize marshals the given OnePassSignature to w.
-func (ops *OnePassSignature) Serialize(w io.Writer) os.Error {
- var buf [13]byte
- buf[0] = onePassSignatureVersion
- buf[1] = uint8(ops.SigType)
- var ok bool
- buf[2], ok = s2k.HashToHashId(ops.Hash)
- if !ok {
- return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
- }
- buf[3] = uint8(ops.PubKeyAlgo)
- binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
- if ops.IsLast {
- buf[12] = 1
- }
-
- if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
- return err
- }
- _, err := w.Write(buf[:])
- return err
-}
diff --git a/src/pkg/crypto/openpgp/packet/packet.go b/src/pkg/crypto/openpgp/packet/packet.go
deleted file mode 100644
index 1d7297e38..000000000
--- a/src/pkg/crypto/openpgp/packet/packet.go
+++ /dev/null
@@ -1,483 +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 packet implements parsing and serialization of OpenPGP packets, as
-// specified in RFC 4880.
-package packet
-
-import (
- "big"
- "crypto/aes"
- "crypto/cast5"
- "crypto/cipher"
- "crypto/openpgp/error"
- "io"
- "os"
-)
-
-// readFull is the same as io.ReadFull except that reading zero bytes returns
-// ErrUnexpectedEOF rather than EOF.
-func readFull(r io.Reader, buf []byte) (n int, err os.Error) {
- n, err = io.ReadFull(r, buf)
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- return
-}
-
-// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
-func readLength(r io.Reader) (length int64, isPartial bool, err os.Error) {
- var buf [4]byte
- _, err = readFull(r, buf[:1])
- if err != nil {
- return
- }
- switch {
- case buf[0] < 192:
- length = int64(buf[0])
- case buf[0] < 224:
- length = int64(buf[0]-192) << 8
- _, err = readFull(r, buf[0:1])
- if err != nil {
- return
- }
- length += int64(buf[0]) + 192
- case buf[0] < 255:
- length = int64(1) << (buf[0] & 0x1f)
- isPartial = true
- default:
- _, err = readFull(r, buf[0:4])
- if err != nil {
- return
- }
- length = int64(buf[0])<<24 |
- int64(buf[1])<<16 |
- int64(buf[2])<<8 |
- int64(buf[3])
- }
- return
-}
-
-// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
-// The continuation lengths are parsed and removed from the stream and EOF is
-// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
-type partialLengthReader struct {
- r io.Reader
- remaining int64
- isPartial bool
-}
-
-func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
- for r.remaining == 0 {
- if !r.isPartial {
- return 0, os.EOF
- }
- r.remaining, r.isPartial, err = readLength(r.r)
- if err != nil {
- return 0, err
- }
- }
-
- toRead := int64(len(p))
- if toRead > r.remaining {
- toRead = r.remaining
- }
-
- n, err = r.r.Read(p[:int(toRead)])
- r.remaining -= int64(n)
- if n < int(toRead) && err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- 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 {
- r io.Reader
- n int64
-}
-
-func (l *spanReader) Read(p []byte) (n int, err os.Error) {
- if l.n <= 0 {
- return 0, os.EOF
- }
- if int64(len(p)) > l.n {
- p = p[0:l.n]
- }
- n, err = l.r.Read(p)
- l.n -= int64(n)
- if l.n > 0 && err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- return
-}
-
-// readHeader parses a packet header and returns an io.Reader which will return
-// the contents of the packet. See RFC 4880, section 4.2.
-func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err os.Error) {
- var buf [4]byte
- _, err = io.ReadFull(r, buf[:1])
- if err != nil {
- return
- }
- if buf[0]&0x80 == 0 {
- err = error.StructuralError("tag byte does not have MSB set")
- return
- }
- if buf[0]&0x40 == 0 {
- // Old format packet
- tag = packetType((buf[0] & 0x3f) >> 2)
- lengthType := buf[0] & 3
- if lengthType == 3 {
- length = -1
- contents = r
- return
- }
- lengthBytes := 1 << lengthType
- _, err = readFull(r, buf[0:lengthBytes])
- if err != nil {
- return
- }
- for i := 0; i < lengthBytes; i++ {
- length <<= 8
- length |= int64(buf[i])
- }
- contents = &spanReader{r, length}
- return
- }
-
- // New format packet
- tag = packetType(buf[0] & 0x3f)
- length, isPartial, err := readLength(r)
- if err != nil {
- return
- }
- if isPartial {
- contents = &partialLengthReader{
- remaining: length,
- isPartial: true,
- r: r,
- }
- length = -1
- } else {
- contents = &spanReader{r, length}
- }
- return
-}
-
-// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
-// 4.2.
-func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
- var buf [6]byte
- var n int
-
- buf[0] = 0x80 | 0x40 | byte(ptype)
- if length < 192 {
- buf[1] = byte(length)
- n = 2
- } else if length < 8384 {
- length -= 192
- buf[1] = 192 + byte(length>>8)
- buf[2] = byte(length)
- n = 3
- } else {
- buf[1] = 255
- buf[2] = byte(length >> 24)
- buf[3] = byte(length >> 16)
- buf[4] = byte(length >> 8)
- buf[5] = byte(length)
- n = 6
- }
-
- _, err = w.Write(buf[:n])
- 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 {
- parse(io.Reader) os.Error
-}
-
-// consumeAll reads from the given Reader until error, returning the number of
-// bytes read.
-func consumeAll(r io.Reader) (n int64, err os.Error) {
- var m int
- var buf [1024]byte
-
- for {
- m, err = r.Read(buf[:])
- n += int64(m)
- if err == os.EOF {
- err = nil
- return
- }
- if err != nil {
- return
- }
- }
-
- panic("unreachable")
-}
-
-// packetType represents the numeric ids of the different OpenPGP packet types. See
-// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
-type packetType uint8
-
-const (
- packetTypeEncryptedKey packetType = 1
- packetTypeSignature packetType = 2
- packetTypeSymmetricKeyEncrypted packetType = 3
- packetTypeOnePassSignature packetType = 4
- packetTypePrivateKey packetType = 5
- packetTypePublicKey packetType = 6
- packetTypePrivateSubkey packetType = 7
- packetTypeCompressed packetType = 8
- packetTypeSymmetricallyEncrypted packetType = 9
- packetTypeLiteralData packetType = 11
- packetTypeUserId packetType = 13
- packetTypePublicSubkey packetType = 14
- packetTypeSymmetricallyEncryptedMDC packetType = 18
-)
-
-// Read reads a single OpenPGP packet from the given io.Reader. If there is an
-// error parsing a packet, the whole packet is consumed from the input.
-func Read(r io.Reader) (p Packet, err os.Error) {
- tag, _, contents, err := readHeader(r)
- if err != nil {
- return
- }
-
- switch tag {
- case packetTypeEncryptedKey:
- p = new(EncryptedKey)
- case packetTypeSignature:
- p = new(Signature)
- case packetTypeSymmetricKeyEncrypted:
- p = new(SymmetricKeyEncrypted)
- case packetTypeOnePassSignature:
- p = new(OnePassSignature)
- case packetTypePrivateKey, packetTypePrivateSubkey:
- pk := new(PrivateKey)
- if tag == packetTypePrivateSubkey {
- pk.IsSubkey = true
- }
- p = pk
- case packetTypePublicKey, packetTypePublicSubkey:
- pk := new(PublicKey)
- if tag == packetTypePublicSubkey {
- pk.IsSubkey = true
- }
- p = pk
- case packetTypeCompressed:
- p = new(Compressed)
- case packetTypeSymmetricallyEncrypted:
- p = new(SymmetricallyEncrypted)
- case packetTypeLiteralData:
- p = new(LiteralData)
- case packetTypeUserId:
- p = new(UserId)
- case packetTypeSymmetricallyEncryptedMDC:
- se := new(SymmetricallyEncrypted)
- se.MDC = true
- p = se
- default:
- err = error.UnknownPacketTypeError(tag)
- }
- if p != nil {
- err = p.parse(contents)
- }
- if err != nil {
- consumeAll(contents)
- }
- return
-}
-
-// SignatureType represents the different semantic meanings of an OpenPGP
-// signature. See RFC 4880, section 5.2.1.
-type SignatureType uint8
-
-const (
- SigTypeBinary SignatureType = 0
- SigTypeText = 1
- SigTypeGenericCert = 0x10
- SigTypePersonaCert = 0x11
- SigTypeCasualCert = 0x12
- SigTypePositiveCert = 0x13
- SigTypeSubkeyBinding = 0x18
-)
-
-// PublicKeyAlgorithm represents the different public key system specified for
-// OpenPGP. See
-// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
-type PublicKeyAlgorithm uint8
-
-const (
- PubKeyAlgoRSA PublicKeyAlgorithm = 1
- PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
- PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
- 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 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 {
- switch cipher {
- case CipherCAST5:
- return cast5.KeySize
- case CipherAES128:
- return 16
- case CipherAES192:
- return 24
- case CipherAES256:
- return 32
- }
- return 0
-}
-
-// blockSize returns the block size, in bytes, of cipher.
-func (cipher CipherFunction) blockSize() int {
- switch cipher {
- case CipherCAST5:
- return 8
- case CipherAES128, CipherAES192, CipherAES256:
- return 16
- }
- return 0
-}
-
-// new returns a fresh instance of the given cipher.
-func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
- switch cipher {
- case CipherCAST5:
- block, _ = cast5.NewCipher(key)
- case CipherAES128, CipherAES192, CipherAES256:
- block, _ = aes.NewCipher(key)
- }
- return
-}
-
-// readMPI reads a big integer from r. The bit length returned is the bit
-// length that was specified in r. This is preserved so that the integer can be
-// reserialized exactly.
-func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
- var buf [2]byte
- _, err = readFull(r, buf[0:])
- if err != nil {
- return
- }
- bitLength = uint16(buf[0])<<8 | uint16(buf[1])
- numBytes := (int(bitLength) + 7) / 8
- mpi = make([]byte, numBytes)
- _, err = readFull(r, mpi)
- 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)})
- if err == nil {
- _, err = w.Write(mpiBytes)
- }
- return
-}
-
-// writeBig serializes a *big.Int to w.
-func writeBig(w io.Writer, i *big.Int) os.Error {
- return writeMPI(w, uint16(i.BitLen()), i.Bytes())
-}
diff --git a/src/pkg/crypto/openpgp/packet/packet_test.go b/src/pkg/crypto/openpgp/packet/packet_test.go
deleted file mode 100644
index 23d9978ae..000000000
--- a/src/pkg/crypto/openpgp/packet/packet_test.go
+++ /dev/null
@@ -1,256 +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 packet
-
-import (
- "bytes"
- "crypto/openpgp/error"
- "encoding/hex"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "testing"
-)
-
-func TestReadFull(t *testing.T) {
- var out [4]byte
-
- b := bytes.NewBufferString("foo")
- n, err := readFull(b, out[:3])
- if n != 3 || err != nil {
- t.Errorf("full read failed n:%d err:%s", n, err)
- }
-
- b = bytes.NewBufferString("foo")
- n, err = readFull(b, out[:4])
- if n != 3 || err != io.ErrUnexpectedEOF {
- t.Errorf("partial read failed n:%d err:%s", n, err)
- }
-
- b = bytes.NewBuffer(nil)
- n, err = readFull(b, out[:3])
- if n != 0 || err != io.ErrUnexpectedEOF {
- t.Errorf("empty read failed n:%d err:%s", n, err)
- }
-}
-
-func readerFromHex(s string) io.Reader {
- data, err := hex.DecodeString(s)
- if err != nil {
- panic("readerFromHex: bad input")
- }
- return bytes.NewBuffer(data)
-}
-
-var readLengthTests = []struct {
- hexInput string
- length int64
- isPartial bool
- err os.Error
-}{
- {"", 0, false, io.ErrUnexpectedEOF},
- {"1f", 31, false, nil},
- {"c0", 0, false, io.ErrUnexpectedEOF},
- {"c101", 256 + 1 + 192, false, nil},
- {"e0", 1, true, nil},
- {"e1", 2, true, nil},
- {"e2", 4, true, nil},
- {"ff", 0, false, io.ErrUnexpectedEOF},
- {"ff00", 0, false, io.ErrUnexpectedEOF},
- {"ff0000", 0, false, io.ErrUnexpectedEOF},
- {"ff000000", 0, false, io.ErrUnexpectedEOF},
- {"ff00000000", 0, false, nil},
- {"ff01020304", 16909060, false, nil},
-}
-
-func TestReadLength(t *testing.T) {
- for i, test := range readLengthTests {
- length, isPartial, err := readLength(readerFromHex(test.hexInput))
- if test.err != nil {
- if err != test.err {
- t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
- }
- continue
- }
- if err != nil {
- t.Errorf("%d: unexpected error: %s", i, err)
- continue
- }
- if length != test.length || isPartial != test.isPartial {
- t.Errorf("%d: bad result got:(%d,%t) want:(%d,%t)", i, length, isPartial, test.length, test.isPartial)
- }
- }
-}
-
-var partialLengthReaderTests = []struct {
- hexInput string
- err os.Error
- hexOutput string
-}{
- {"e0", io.ErrUnexpectedEOF, ""},
- {"e001", io.ErrUnexpectedEOF, ""},
- {"e0010102", nil, "0102"},
- {"ff00000000", nil, ""},
- {"e10102e1030400", nil, "01020304"},
- {"e101", io.ErrUnexpectedEOF, ""},
-}
-
-func TestPartialLengthReader(t *testing.T) {
- for i, test := range partialLengthReaderTests {
- r := &partialLengthReader{readerFromHex(test.hexInput), 0, true}
- out, err := ioutil.ReadAll(r)
- if test.err != nil {
- if err != test.err {
- t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
- }
- continue
- }
- if err != nil {
- t.Errorf("%d: unexpected error: %s", i, err)
- continue
- }
-
- got := fmt.Sprintf("%x", out)
- if got != test.hexOutput {
- t.Errorf("%d: got:%s want:%s", i, test.hexOutput, got)
- }
- }
-}
-
-var readHeaderTests = []struct {
- hexInput string
- structuralError bool
- unexpectedEOF bool
- tag int
- length int64
- hexOutput string
-}{
- {"", false, false, 0, 0, ""},
- {"7f", true, false, 0, 0, ""},
-
- // Old format headers
- {"80", false, true, 0, 0, ""},
- {"8001", false, true, 0, 1, ""},
- {"800102", false, false, 0, 1, "02"},
- {"81000102", false, false, 0, 1, "02"},
- {"820000000102", false, false, 0, 1, "02"},
- {"860000000102", false, false, 1, 1, "02"},
- {"83010203", false, false, 0, -1, "010203"},
-
- // New format headers
- {"c0", false, true, 0, 0, ""},
- {"c000", false, false, 0, 0, ""},
- {"c00102", false, false, 0, 1, "02"},
- {"c0020203", false, false, 0, 2, "0203"},
- {"c00202", false, true, 0, 2, ""},
- {"c3020203", false, false, 3, 2, "0203"},
-}
-
-func TestReadHeader(t *testing.T) {
- for i, test := range readHeaderTests {
- tag, length, contents, err := readHeader(readerFromHex(test.hexInput))
- if test.structuralError {
- if _, ok := err.(error.StructuralError); ok {
- continue
- }
- t.Errorf("%d: expected StructuralError, got:%s", i, err)
- continue
- }
- if err != nil {
- if len(test.hexInput) == 0 && err == os.EOF {
- continue
- }
- if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
- t.Errorf("%d: unexpected error from readHeader: %s", i, err)
- }
- continue
- }
- if int(tag) != test.tag || length != test.length {
- t.Errorf("%d: got:(%d,%d) want:(%d,%d)", i, int(tag), length, test.tag, test.length)
- continue
- }
-
- body, err := ioutil.ReadAll(contents)
- if err != nil {
- if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
- t.Errorf("%d: unexpected error from contents: %s", i, err)
- }
- continue
- }
- if test.unexpectedEOF {
- t.Errorf("%d: expected ErrUnexpectedEOF from contents but got no error", i)
- continue
- }
- got := fmt.Sprintf("%x", body)
- if got != test.hexOutput {
- t.Errorf("%d: got:%s want:%s", i, got, test.hexOutput)
- }
- }
-}
-
-func TestSerializeHeader(t *testing.T) {
- tag := packetTypePublicKey
- lengths := []int{0, 1, 2, 64, 192, 193, 8000, 8384, 8385, 10000}
-
- for _, length := range lengths {
- buf := bytes.NewBuffer(nil)
- serializeHeader(buf, tag, length)
- tag2, length2, _, err := readHeader(buf)
- if err != nil {
- t.Errorf("length %d, err: %s", length, err)
- }
- if tag2 != tag {
- t.Errorf("length %d, tag incorrect (got %d, want %d)", length, tag2, tag)
- }
- if int(length2) != length {
- t.Errorf("length %d, length incorrect (got %d)", length, length2)
- }
- }
-}
-
-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/src/pkg/crypto/openpgp/packet/private_key.go b/src/pkg/crypto/openpgp/packet/private_key.go
deleted file mode 100644
index 6f8133d98..000000000
--- a/src/pkg/crypto/openpgp/packet/private_key.go
+++ /dev/null
@@ -1,301 +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 packet
-
-import (
- "big"
- "bytes"
- "crypto/cipher"
- "crypto/dsa"
- "crypto/openpgp/elgamal"
- "crypto/openpgp/error"
- "crypto/openpgp/s2k"
- "crypto/rsa"
- "crypto/sha1"
- "io"
- "io/ioutil"
- "os"
- "strconv"
-)
-
-// PrivateKey represents a possibly encrypted private key. See RFC 4880,
-// section 5.5.3.
-type PrivateKey struct {
- PublicKey
- Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
- encryptedData []byte
- cipher CipherFunction
- s2k func(out, in []byte)
- PrivateKey interface{} // An *rsa.PrivateKey.
- sha1Checksum bool
- 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 {
- return
- }
- var buf [1]byte
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
-
- s2kType := buf[0]
-
- switch s2kType {
- case 0:
- pk.s2k = nil
- pk.Encrypted = false
- case 254, 255:
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
- pk.cipher = CipherFunction(buf[0])
- pk.Encrypted = true
- pk.s2k, err = s2k.Parse(r)
- if err != nil {
- return
- }
- if s2kType == 254 {
- pk.sha1Checksum = true
- }
- default:
- return error.UnsupportedError("deprecated s2k function in private key")
- }
-
- if pk.Encrypted {
- blockSize := pk.cipher.blockSize()
- if blockSize == 0 {
- return error.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
- }
- pk.iv = make([]byte, blockSize)
- _, err = readFull(r, pk.iv)
- if err != nil {
- return
- }
- }
-
- pk.encryptedData, err = ioutil.ReadAll(r)
- if err != nil {
- return
- }
-
- if !pk.Encrypted {
- return pk.parsePrivateKey(pk.encryptedData)
- }
-
- 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())
- pk.s2k(key, passphrase)
- block := pk.cipher.new(key)
- cfb := cipher.NewCFBDecrypter(block, pk.iv)
-
- data := pk.encryptedData
- cfb.XORKeyStream(data, data)
-
- if pk.sha1Checksum {
- if len(data) < sha1.Size {
- return error.StructuralError("truncated private key data")
- }
- h := sha1.New()
- h.Write(data[:len(data)-sha1.Size])
- sum := h.Sum()
- if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
- return error.StructuralError("private key checksum failure")
- }
- data = data[:len(data)-sha1.Size]
- } else {
- if len(data) < 2 {
- return error.StructuralError("truncated private key data")
- }
- var sum uint16
- for i := 0; i < len(data)-2; i++ {
- sum += uint16(data[i])
- }
- if data[len(data)-2] != uint8(sum>>8) ||
- data[len(data)-1] != uint8(sum) {
- return error.StructuralError("private key checksum failure")
- }
- data = data[:len(data)-2]
- }
-
- return pk.parsePrivateKey(data)
-}
-
-func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
- switch pk.PublicKey.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
- return pk.parseRSAPrivateKey(data)
- case PubKeyAlgoDSA:
- return pk.parseDSAPrivateKey(data)
- case PubKeyAlgoElGamal:
- return pk.parseElGamalPrivateKey(data)
- }
- panic("impossible")
-}
-
-func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err os.Error) {
- rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
- rsaPriv := new(rsa.PrivateKey)
- rsaPriv.PublicKey = *rsaPub
-
- buf := bytes.NewBuffer(data)
- d, _, err := readMPI(buf)
- if err != nil {
- return
- }
- p, _, err := readMPI(buf)
- if err != nil {
- return
- }
- q, _, err := readMPI(buf)
- if err != nil {
- return
- }
-
- rsaPriv.D = new(big.Int).SetBytes(d)
- rsaPriv.Primes = make([]*big.Int, 2)
- rsaPriv.Primes[0] = new(big.Int).SetBytes(p)
- rsaPriv.Primes[1] = new(big.Int).SetBytes(q)
- rsaPriv.Precompute()
- pk.PrivateKey = rsaPriv
- pk.Encrypted = false
- pk.encryptedData = nil
-
- return nil
-}
-
-func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
- dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
- dsaPriv := new(dsa.PrivateKey)
- dsaPriv.PublicKey = *dsaPub
-
- buf := bytes.NewBuffer(data)
- x, _, err := readMPI(buf)
- if err != nil {
- return
- }
-
- dsaPriv.X = new(big.Int).SetBytes(x)
- pk.PrivateKey = dsaPriv
- pk.Encrypted = false
- pk.encryptedData = nil
-
- return nil
-}
-
-func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) {
- pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
- priv := new(elgamal.PrivateKey)
- priv.PublicKey = *pub
-
- buf := bytes.NewBuffer(data)
- x, _, err := readMPI(buf)
- if err != nil {
- return
- }
-
- priv.X = new(big.Int).SetBytes(x)
- pk.PrivateKey = priv
- pk.Encrypted = false
- pk.encryptedData = nil
-
- return nil
-}
diff --git a/src/pkg/crypto/openpgp/packet/private_key_test.go b/src/pkg/crypto/openpgp/packet/private_key_test.go
deleted file mode 100644
index 60eebaa6b..000000000
--- a/src/pkg/crypto/openpgp/packet/private_key_test.go
+++ /dev/null
@@ -1,57 +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 packet
-
-import (
- "testing"
-)
-
-var privateKeyTests = []struct {
- privateKeyHex string
- creationTime uint32
-}{
- {
- privKeyRSAHex,
- 0x4cc349a8,
- },
- {
- privKeyElGamalHex,
- 0x4df9ee1a,
- },
-}
-
-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 privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
-
-// Generated by `gpg --export-secret-keys` followed by a manual extraction of
-// the ElGamal subkey from the packets.
-const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/src/pkg/crypto/openpgp/packet/public_key.go b/src/pkg/crypto/openpgp/packet/public_key.go
deleted file mode 100644
index e6b0ae5f3..000000000
--- a/src/pkg/crypto/openpgp/packet/public_key.go
+++ /dev/null
@@ -1,393 +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 packet
-
-import (
- "big"
- "crypto/dsa"
- "crypto/openpgp/elgamal"
- "crypto/openpgp/error"
- "crypto/rsa"
- "crypto/sha1"
- "encoding/binary"
- "fmt"
- "hash"
- "io"
- "os"
- "strconv"
-)
-
-// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
-type PublicKey struct {
- CreationTime uint32 // seconds since the epoch
- PubKeyAlgo PublicKeyAlgorithm
- PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey
- Fingerprint [20]byte
- KeyId uint64
- IsSubkey bool
-
- 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
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
- if buf[0] != 4 {
- return error.UnsupportedError("public key version")
- }
- pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4])
- pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
- switch pk.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
- 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)))
- }
- if err != nil {
- return
- }
-
- pk.setFingerPrintAndKeyId()
- return
-}
-
-func (pk *PublicKey) setFingerPrintAndKeyId() {
- // RFC 4880, section 12.2
- fingerPrint := sha1.New()
- pk.SerializeSignaturePrefix(fingerPrint)
- pk.serializeWithoutHeaders(fingerPrint)
- copy(pk.Fingerprint[:], fingerPrint.Sum())
- pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
-}
-
-// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
-// section 5.5.2.
-func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
- pk.n.bytes, pk.n.bitLength, err = readMPI(r)
- if err != nil {
- return
- }
- pk.e.bytes, pk.e.bitLength, err = readMPI(r)
- if err != nil {
- return
- }
-
- if len(pk.e.bytes) > 3 {
- err = error.UnsupportedError("large public exponent")
- return
- }
- rsa := &rsa.PublicKey{
- N: new(big.Int).SetBytes(pk.n.bytes),
- E: 0,
- }
- for i := 0; i < len(pk.e.bytes); i++ {
- rsa.E <<= 8
- rsa.E |= int(pk.e.bytes[i])
- }
- pk.PublicKey = rsa
- return
-}
-
-// 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)
- if err != nil {
- return
- }
- pk.q.bytes, pk.q.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
- }
-
- dsa := new(dsa.PublicKey)
- dsa.P = new(big.Int).SetBytes(pk.p.bytes)
- dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
- dsa.G = new(big.Int).SetBytes(pk.g.bytes)
- dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
- pk.PublicKey = dsa
- 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.
-func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
- var pLength uint16
- switch pk.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
- pLength += 2 + uint16(len(pk.n.bytes))
- pLength += 2 + uint16(len(pk.e.bytes))
- case PubKeyAlgoDSA:
- pLength += 2 + uint16(len(pk.p.bytes))
- 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")
- }
- pLength += 6
- h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
- return
-}
-
-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)
- buf[2] = byte(pk.CreationTime >> 16)
- buf[3] = byte(pk.CreationTime >> 8)
- buf[4] = byte(pk.CreationTime)
- buf[5] = byte(pk.PubKeyAlgo)
-
- _, err = w.Write(buf[:])
- if err != nil {
- return
- }
-
- switch pk.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
- 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
-}
-
-// VerifySignature returns nil iff sig is a valid signature, made by this
-// public key, of the data hashed into signed. signed is mutated by this call.
-func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.Error) {
- if !pk.CanSign() {
- return error.InvalidArgumentError("public key cannot generate signatures")
- }
-
- signed.Write(sig.HashSuffix)
- hashBytes := signed.Sum()
-
- if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
- return error.SignatureError("hash tag doesn't match")
- }
-
- if pk.PubKeyAlgo != sig.PubKeyAlgo {
- return error.InvalidArgumentError("public key and signature use different algorithms")
- }
-
- switch pk.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
- 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, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
- return error.SignatureError("DSA verification failure")
- }
- return nil
- default:
- panic("shouldn't happen")
- }
- panic("unreachable")
-}
-
-// 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 nil, error.UnsupportedError("hash function")
- }
-
- // RFC 4880, section 5.2.4
- pk.SerializeSignaturePrefix(h)
- pk.serializeWithoutHeaders(h)
- signed.SerializeSignaturePrefix(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)
-}
-
-// 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 nil, error.UnsupportedError("hash function")
- }
-
- // RFC 4880, section 5.2.4
- pk.SerializeSignaturePrefix(h)
- pk.serializeWithoutHeaders(h)
-
- var buf [5]byte
- buf[0] = 0xb4
- buf[1] = byte(len(id) >> 24)
- buf[2] = byte(len(id) >> 16)
- buf[3] = byte(len(id) >> 8)
- buf[4] = byte(len(id))
- 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)
-}
-
-// KeyIdString returns the public key's fingerprint in capital hex
-// (e.g. "6C7EE1B8621CC013").
-func (pk *PublicKey) KeyIdString() string {
- return fmt.Sprintf("%X", pk.Fingerprint[12:20])
-}
-
-// KeyIdShortString returns the short form of public key's fingerprint
-// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
-func (pk *PublicKey) KeyIdShortString() string {
- return fmt.Sprintf("%X", pk.Fingerprint[16:20])
-}
-
-// A parsedMPI is used to store the contents of a big integer, along with the
-// bit length that was specified in the original input. This allows the MPI to
-// be reserialized exactly.
-type parsedMPI struct {
- bytes []byte
- bitLength uint16
-}
-
-// 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 {
- err = writeMPI(w, mpi.bitLength, mpi.bytes)
- if err != nil {
- return
- }
- }
- return
-}
diff --git a/src/pkg/crypto/openpgp/packet/public_key_test.go b/src/pkg/crypto/openpgp/packet/public_key_test.go
deleted file mode 100644
index 6e8bfbce6..000000000
--- a/src/pkg/crypto/openpgp/packet/public_key_test.go
+++ /dev/null
@@ -1,98 +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 packet
-
-import (
- "bytes"
- "encoding/hex"
- "testing"
-)
-
-var pubKeyTests = []struct {
- hexData string
- hexFingerprint string
- creationTime uint32
- pubKeyAlgo PublicKeyAlgorithm
- keyId uint64
- keyIdString string
- keyIdShort string
-}{
- {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
- {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
-}
-
-func TestPublicKeyRead(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
- }
- if pk.PubKeyAlgo != test.pubKeyAlgo {
- t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
- }
- if pk.CreationTime != test.creationTime {
- t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime)
- }
- expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
- if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
- t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
- }
- if pk.KeyId != test.keyId {
- t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
- }
- if g, e := pk.KeyIdString(), test.keyIdString; g != e {
- t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
- }
- if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
- t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
- }
- }
-}
-
-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"
-
-const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
-
-const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"
diff --git a/src/pkg/crypto/openpgp/packet/reader.go b/src/pkg/crypto/openpgp/packet/reader.go
deleted file mode 100644
index 5febc3bc8..000000000
--- a/src/pkg/crypto/openpgp/packet/reader.go
+++ /dev/null
@@ -1,63 +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 packet
-
-import (
- "crypto/openpgp/error"
- "io"
- "os"
-)
-
-// Reader reads packets from an io.Reader and allows packets to be 'unread' so
-// that they result from the next call to Next.
-type Reader struct {
- q []Packet
- readers []io.Reader
-}
-
-// Next returns the most recently unread Packet, or reads another packet from
-// the top-most io.Reader. Unknown packet types are skipped.
-func (r *Reader) Next() (p Packet, err os.Error) {
- if len(r.q) > 0 {
- p = r.q[len(r.q)-1]
- r.q = r.q[:len(r.q)-1]
- return
- }
-
- for len(r.readers) > 0 {
- p, err = Read(r.readers[len(r.readers)-1])
- if err == nil {
- return
- }
- if err == os.EOF {
- r.readers = r.readers[:len(r.readers)-1]
- continue
- }
- if _, ok := err.(error.UnknownPacketTypeError); !ok {
- return nil, err
- }
- }
-
- return nil, os.EOF
-}
-
-// Push causes the Reader to start reading from a new io.Reader. When an EOF
-// error is seen from the new io.Reader, it is popped and the Reader continues
-// to read from the next most recent io.Reader.
-func (r *Reader) Push(reader io.Reader) {
- r.readers = append(r.readers, reader)
-}
-
-// Unread causes the given Packet to be returned from the next call to Next.
-func (r *Reader) Unread(p Packet) {
- r.q = append(r.q, p)
-}
-
-func NewReader(r io.Reader) *Reader {
- return &Reader{
- q: nil,
- readers: []io.Reader{r},
- }
-}
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
deleted file mode 100644
index 7577e2875..000000000
--- a/src/pkg/crypto/openpgp/packet/signature.go
+++ /dev/null
@@ -1,558 +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 packet
-
-import (
- "crypto"
- "crypto/dsa"
- "crypto/openpgp/error"
- "crypto/openpgp/s2k"
- "crypto/rand"
- "crypto/rsa"
- "encoding/binary"
- "hash"
- "io"
- "os"
- "strconv"
-)
-
-// Signature represents a signature. See RFC 4880, section 5.2.
-type Signature struct {
- SigType SignatureType
- PubKeyAlgo PublicKeyAlgorithm
- Hash crypto.Hash
-
- // HashSuffix is extra data that is hashed in after the signed data.
- HashSuffix []byte
- // HashTag contains the first two bytes of the hash for fast rejection
- // of bad signed data.
- HashTag [2]byte
- CreationTime uint32 // Unix epoch time
-
- 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.
-
- SigLifetimeSecs, KeyLifetimeSecs *uint32
- PreferredSymmetric, PreferredHash, PreferredCompression []uint8
- IssuerKeyId *uint64
- IsPrimaryId *bool
-
- // FlagsValid is set if any flags were given. See RFC 4880, section
- // 5.2.3.21 for details.
- FlagsValid bool
- FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
-
- outSubpackets []outputSubpacket
-}
-
-func (sig *Signature) parse(r io.Reader) (err os.Error) {
- // RFC 4880, section 5.2.3
- var buf [5]byte
- _, err = readFull(r, buf[:1])
- if err != nil {
- return
- }
- if buf[0] != 4 {
- err = error.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
- return
- }
-
- _, err = readFull(r, buf[:5])
- if err != nil {
- return
- }
- sig.SigType = SignatureType(buf[0])
- sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
- switch sig.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
- default:
- err = error.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
- return
- }
-
- var ok bool
- sig.Hash, ok = s2k.HashIdToHash(buf[2])
- if !ok {
- return error.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
- }
-
- hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
- l := 6 + hashedSubpacketsLength
- sig.HashSuffix = make([]byte, l+6)
- sig.HashSuffix[0] = 4
- copy(sig.HashSuffix[1:], buf[:5])
- hashedSubpackets := sig.HashSuffix[6:l]
- _, err = readFull(r, hashedSubpackets)
- if err != nil {
- return
- }
- // See RFC 4880, section 5.2.4
- trailer := sig.HashSuffix[l:]
- trailer[0] = 4
- trailer[1] = 0xff
- trailer[2] = uint8(l >> 24)
- trailer[3] = uint8(l >> 16)
- trailer[4] = uint8(l >> 8)
- trailer[5] = uint8(l)
-
- err = parseSignatureSubpackets(sig, hashedSubpackets, true)
- if err != nil {
- return
- }
-
- _, err = readFull(r, buf[:2])
- if err != nil {
- return
- }
- unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
- unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
- _, err = readFull(r, unhashedSubpackets)
- if err != nil {
- return
- }
- err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
- if err != nil {
- return
- }
-
- _, err = readFull(r, sig.HashTag[:2])
- if err != nil {
- return
- }
-
- switch sig.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
- case PubKeyAlgoDSA:
- sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
- if err == nil {
- sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
- }
- default:
- panic("unreachable")
- }
- return
-}
-
-// parseSignatureSubpackets parses subpackets of the main signature packet. See
-// RFC 4880, section 5.2.3.1.
-func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err os.Error) {
- for len(subpackets) > 0 {
- subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
- if err != nil {
- return
- }
- }
-
- if sig.CreationTime == 0 {
- err = error.StructuralError("no creation time in signature")
- }
-
- return
-}
-
-type signatureSubpacketType uint8
-
-const (
- creationTimeSubpacket signatureSubpacketType = 2
- signatureExpirationSubpacket signatureSubpacketType = 3
- keyExpirySubpacket signatureSubpacketType = 9
- prefSymmetricAlgosSubpacket signatureSubpacketType = 11
- issuerSubpacket signatureSubpacketType = 16
- prefHashAlgosSubpacket signatureSubpacketType = 21
- prefCompressionSubpacket signatureSubpacketType = 22
- primaryUserIdSubpacket signatureSubpacketType = 25
- keyFlagsSubpacket signatureSubpacketType = 27
-)
-
-// 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
- packetType signatureSubpacketType
- isCritical bool
- )
- switch {
- case subpacket[0] < 192:
- length = uint32(subpacket[0])
- subpacket = subpacket[1:]
- case subpacket[0] < 255:
- if len(subpacket) < 2 {
- goto Truncated
- }
- length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
- subpacket = subpacket[2:]
- default:
- if len(subpacket) < 5 {
- goto Truncated
- }
- length = uint32(subpacket[1])<<24 |
- uint32(subpacket[2])<<16 |
- uint32(subpacket[3])<<8 |
- uint32(subpacket[4])
- subpacket = subpacket[5:]
- }
- if length > uint32(len(subpacket)) {
- goto Truncated
- }
- rest = subpacket[length:]
- subpacket = subpacket[:length]
- if len(subpacket) == 0 {
- err = error.StructuralError("zero length signature subpacket")
- return
- }
- packetType = signatureSubpacketType(subpacket[0] & 0x7f)
- isCritical = subpacket[0]&0x80 == 0x80
- subpacket = subpacket[1:]
- 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")
- return
- }
- if len(subpacket) != 4 {
- err = error.StructuralError("signature creation time not four bytes")
- return
- }
- sig.CreationTime = binary.BigEndian.Uint32(subpacket)
- case signatureExpirationSubpacket:
- // Signature expiration time, section 5.2.3.10
- if !isHashed {
- return
- }
- if len(subpacket) != 4 {
- err = error.StructuralError("expiration subpacket with bad length")
- return
- }
- sig.SigLifetimeSecs = new(uint32)
- *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
- case keyExpirySubpacket:
- // Key expiration time, section 5.2.3.6
- if !isHashed {
- return
- }
- if len(subpacket) != 4 {
- err = error.StructuralError("key expiration subpacket with bad length")
- return
- }
- sig.KeyLifetimeSecs = new(uint32)
- *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
- case prefSymmetricAlgosSubpacket:
- // Preferred symmetric algorithms, section 5.2.3.7
- if !isHashed {
- return
- }
- sig.PreferredSymmetric = make([]byte, len(subpacket))
- copy(sig.PreferredSymmetric, subpacket)
- case issuerSubpacket:
- // Issuer, section 5.2.3.5
- if len(subpacket) != 8 {
- err = error.StructuralError("issuer subpacket with bad length")
- return
- }
- sig.IssuerKeyId = new(uint64)
- *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
- case prefHashAlgosSubpacket:
- // Preferred hash algorithms, section 5.2.3.8
- if !isHashed {
- return
- }
- sig.PreferredHash = make([]byte, len(subpacket))
- copy(sig.PreferredHash, subpacket)
- case prefCompressionSubpacket:
- // Preferred compression algorithms, section 5.2.3.9
- if !isHashed {
- return
- }
- sig.PreferredCompression = make([]byte, len(subpacket))
- copy(sig.PreferredCompression, subpacket)
- case primaryUserIdSubpacket:
- // Primary User ID, section 5.2.3.19
- if !isHashed {
- return
- }
- if len(subpacket) != 1 {
- err = error.StructuralError("primary user id subpacket with bad length")
- return
- }
- sig.IsPrimaryId = new(bool)
- if subpacket[0] > 0 {
- *sig.IsPrimaryId = true
- }
- case keyFlagsSubpacket:
- // Key flags, section 5.2.3.21
- if !isHashed {
- return
- }
- if len(subpacket) == 0 {
- err = error.StructuralError("empty key flags subpacket")
- return
- }
- sig.FlagsValid = true
- if subpacket[0]&1 != 0 {
- sig.FlagCertify = true
- }
- if subpacket[0]&2 != 0 {
- sig.FlagSign = true
- }
- if subpacket[0]&4 != 0 {
- sig.FlagEncryptCommunications = true
- }
- if subpacket[0]&8 != 0 {
- sig.FlagEncryptStorage = true
- }
-
- default:
- if isCritical {
- err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
- return
- }
- }
- return
-
-Truncated:
- err = error.StructuralError("signature subpacket truncated")
- return
-}
-
-// subpacketLengthLength returns the length, in bytes, of an encoded length value.
-func subpacketLengthLength(length int) int {
- if length < 192 {
- return 1
- }
- if length < 16320 {
- return 2
- }
- return 5
-}
-
-// serializeSubpacketLength marshals the given length into to.
-func serializeSubpacketLength(to []byte, length int) int {
- if length < 192 {
- to[0] = byte(length)
- return 1
- }
- if length < 16320 {
- length -= 192
- to[0] = byte(length >> 8)
- to[1] = byte(length)
- return 2
- }
- to[0] = 255
- to[1] = byte(length >> 24)
- to[2] = byte(length >> 16)
- to[3] = byte(length >> 8)
- to[4] = byte(length)
- return 5
-}
-
-// subpacketsLength returns the serialized length, in bytes, of the given
-// subpackets.
-func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
- for _, subpacket := range subpackets {
- if subpacket.hashed == hashed {
- length += subpacketLengthLength(len(subpacket.contents) + 1)
- length += 1 // type byte
- length += len(subpacket.contents)
- }
- }
- return
-}
-
-// serializeSubpackets marshals the given subpackets into to.
-func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
- for _, subpacket := range subpackets {
- if subpacket.hashed == hashed {
- n := serializeSubpacketLength(to, len(subpacket.contents)+1)
- to[n] = byte(subpacket.subpacketType)
- to = to[1+n:]
- n = copy(to, subpacket.contents)
- to = to[n:]
- }
- }
- return
-}
-
-// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
-func (sig *Signature) buildHashSuffix() (err os.Error) {
- hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
-
- var ok bool
- l := 6 + hashedSubpacketsLen
- sig.HashSuffix = make([]byte, l+6)
- sig.HashSuffix[0] = 4
- sig.HashSuffix[1] = uint8(sig.SigType)
- sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
- sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
- if !ok {
- sig.HashSuffix = nil
- 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)
- serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
- trailer := sig.HashSuffix[l:]
- trailer[0] = 4
- trailer[1] = 0xff
- trailer[2] = byte(l >> 24)
- trailer[3] = byte(l >> 16)
- trailer[4] = byte(l >> 8)
- trailer[5] = byte(l)
- return
-}
-
-func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error) {
- err = sig.buildHashSuffix()
- if err != nil {
- return
- }
-
- h.Write(sig.HashSuffix)
- digest = h.Sum()
- copy(sig.HashTag[:], digest)
- return
-}
-
-// 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) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
- sig.outSubpackets = sig.buildSubpackets()
- digest, err := sig.signPrepareHash(h)
- if err != nil {
- return
- }
-
- 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
-}
-
-// 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 nil
- }
- 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 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 = 2 + len(sig.RSASignature.bytes)
- case PubKeyAlgoDSA:
- sigLength = 2 + len(sig.DSASigR.bytes)
- sigLength += 2 + len(sig.DSASigS.bytes)
- default:
- panic("impossible")
- }
-
- unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
- length := len(sig.HashSuffix) - 6 /* trailer not included */ +
- 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
- 2 /* hash tag */ + sigLength
- err = serializeHeader(w, packetTypeSignature, length)
- if err != nil {
- return
- }
-
- _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
- if err != nil {
- return
- }
-
- unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
- unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
- unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
- serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
-
- _, err = w.Write(unhashedSubpackets)
- if err != nil {
- return
- }
- _, err = w.Write(sig.HashTag[:])
- if err != nil {
- return
- }
-
- switch sig.PubKeyAlgo {
- case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- err = writeMPIs(w, sig.RSASignature)
- case PubKeyAlgoDSA:
- err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
- default:
- panic("impossible")
- }
- return
-}
-
-// outputSubpacket represents a subpacket to be marshaled.
-type outputSubpacket struct {
- hashed bool // true if this subpacket is in the hashed area.
- subpacketType signatureSubpacketType
- isCritical bool
- contents []byte
-}
-
-func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
- creationTime := make([]byte, 4)
- creationTime[0] = byte(sig.CreationTime >> 24)
- creationTime[1] = byte(sig.CreationTime >> 16)
- creationTime[2] = byte(sig.CreationTime >> 8)
- creationTime[3] = byte(sig.CreationTime)
- 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, false, keyId})
- }
-
- return
-}
diff --git a/src/pkg/crypto/openpgp/packet/signature_test.go b/src/pkg/crypto/openpgp/packet/signature_test.go
deleted file mode 100644
index c1bbde8b0..000000000
--- a/src/pkg/crypto/openpgp/packet/signature_test.go
+++ /dev/null
@@ -1,42 +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 packet
-
-import (
- "bytes"
- "crypto"
- "encoding/hex"
- "testing"
-)
-
-func TestSignatureRead(t *testing.T) {
- packet, err := Read(readerFromHex(signatureDataHex))
- if err != nil {
- t.Error(err)
- return
- }
- sig, ok := packet.(*Signature)
- if !ok || sig.SigType != SigTypeBinary || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA1 {
- t.Errorf("failed to parse, got: %#v", packet)
- }
-}
-
-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/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
deleted file mode 100644
index ad4f1d621..000000000
--- a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
+++ /dev/null
@@ -1,162 +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 packet
-
-import (
- "bytes"
- "crypto/cipher"
- "crypto/openpgp/error"
- "crypto/openpgp/s2k"
- "io"
- "os"
- "strconv"
-)
-
-// This is the largest session key that we'll support. Since no 512-bit cipher
-// has even been seriously used, this is comfortably large.
-const maxSessionKeySizeInBytes = 64
-
-// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
-// 4880, section 5.3.
-type SymmetricKeyEncrypted struct {
- CipherFunc CipherFunction
- Encrypted bool
- Key []byte // Empty unless Encrypted is false.
- s2k func(out, in []byte)
- encryptedKey []byte
-}
-
-const symmetricKeyEncryptedVersion = 4
-
-func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
- // RFC 4880, section 5.3.
- var buf [2]byte
- _, err = readFull(r, buf[:])
- if err != nil {
- return
- }
- if buf[0] != symmetricKeyEncryptedVersion {
- return error.UnsupportedError("SymmetricKeyEncrypted version")
- }
- ske.CipherFunc = CipherFunction(buf[1])
-
- if ske.CipherFunc.KeySize() == 0 {
- return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
- }
-
- ske.s2k, err = s2k.Parse(r)
- if err != nil {
- return
- }
-
- encryptedKey := make([]byte, maxSessionKeySizeInBytes)
- // The session key may follow. We just have to try and read to find
- // out. If it exists then we limit it to maxSessionKeySizeInBytes.
- n, err := readFull(r, encryptedKey)
- if err != nil && err != io.ErrUnexpectedEOF {
- return
- }
- err = nil
- if n != 0 {
- if n == maxSessionKeySizeInBytes {
- return error.UnsupportedError("oversized encrypted session key")
- }
- ske.encryptedKey = encryptedKey[:n]
- }
-
- ske.Encrypted = true
-
- return
-}
-
-// Decrypt attempts to decrypt an encrypted session key. If it returns nil,
-// ske.Key will contain the session key.
-func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
- if !ske.Encrypted {
- return nil
- }
-
- key := make([]byte, ske.CipherFunc.KeySize())
- ske.s2k(key, passphrase)
-
- if len(ske.encryptedKey) == 0 {
- ske.Key = key
- } else {
- // the IV is all zeros
- iv := make([]byte, ske.CipherFunc.blockSize())
- c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
- c.XORKeyStream(ske.encryptedKey, ske.encryptedKey)
- ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
- if ske.CipherFunc.blockSize() == 0 {
- return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(ske.CipherFunc)))
- }
- ske.CipherFunc = CipherFunction(ske.encryptedKey[0])
- ske.Key = ske.encryptedKey[1:]
- if len(ske.Key)%ske.CipherFunc.blockSize() != 0 {
- ske.Key = nil
- return error.StructuralError("length of decrypted key not a multiple of block size")
- }
- }
-
- 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/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
deleted file mode 100644
index 823ec400d..000000000
--- a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted_test.go
+++ /dev/null
@@ -1,101 +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 packet
-
-import (
- "bytes"
- "crypto/rand"
- "encoding/hex"
- "io/ioutil"
- "os"
- "testing"
-)
-
-func TestSymmetricKeyEncrypted(t *testing.T) {
- buf := readerFromHex(symmetricallyEncryptedHex)
- packet, err := Read(buf)
- if err != nil {
- t.Errorf("failed to read SymmetricKeyEncrypted: %s", err)
- return
- }
- ske, ok := packet.(*SymmetricKeyEncrypted)
- if !ok {
- t.Error("didn't find SymmetricKeyEncrypted packet")
- return
- }
- err = ske.Decrypt([]byte("password"))
- if err != nil {
- t.Error(err)
- return
- }
-
- packet, err = Read(buf)
- if err != nil {
- t.Errorf("failed to read SymmetricallyEncrypted: %s", err)
- return
- }
- se, ok := packet.(*SymmetricallyEncrypted)
- if !ok {
- t.Error("didn't find SymmetricallyEncrypted packet")
- return
- }
- r, err := se.Decrypt(ske.CipherFunc, ske.Key)
- if err != nil {
- t.Error(err)
- return
- }
-
- contents, err := ioutil.ReadAll(r)
- if err != nil && err != os.EOF {
- t.Error(err)
- return
- }
-
- expectedContents, _ := hex.DecodeString(symmetricallyEncryptedContentsHex)
- if !bytes.Equal(expectedContents, contents) {
- t.Errorf("bad contents got:%x want:%x", contents, expectedContents)
- }
-}
-
-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/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
deleted file mode 100644
index e33c9f3a0..000000000
--- a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
+++ /dev/null
@@ -1,291 +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 packet
-
-import (
- "crypto/cipher"
- "crypto/openpgp/error"
- "crypto/rand"
- "crypto/sha1"
- "crypto/subtle"
- "hash"
- "io"
- "os"
- "strconv"
-)
-
-// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
-// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
-// sections 5.7 and 5.13.
-type SymmetricallyEncrypted struct {
- MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
- contents io.Reader
- prefix []byte
-}
-
-const symmetricallyEncryptedVersion = 1
-
-func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
- if se.MDC {
- // See RFC 4880, section 5.13.
- var buf [1]byte
- _, err := readFull(r, buf[:])
- if err != nil {
- return err
- }
- if buf[0] != symmetricallyEncryptedVersion {
- return error.UnsupportedError("unknown SymmetricallyEncrypted version")
- }
- }
- se.contents = r
- return nil
-}
-
-// Decrypt returns a ReadCloser, from which the decrypted contents of the
-// 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()
- if keySize == 0 {
- return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
- }
- if len(key) != keySize {
- return nil, error.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
- }
-
- if se.prefix == nil {
- se.prefix = make([]byte, c.blockSize()+2)
- _, err := readFull(se.contents, se.prefix)
- if err != nil {
- return nil, err
- }
- } else if len(se.prefix) != c.blockSize()+2 {
- return nil, error.InvalidArgumentError("can't try ciphers with different block lengths")
- }
-
- ocfbResync := cipher.OCFBResync
- if se.MDC {
- // MDC packets use a different form of OCFB mode.
- ocfbResync = cipher.OCFBNoResync
- }
-
- s := cipher.NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
- if s == nil {
- return nil, error.KeyIncorrectError
- }
-
- plaintext := cipher.StreamReader{S: s, R: se.contents}
-
- if se.MDC {
- // MDC packets have an embedded hash that we need to check.
- h := sha1.New()
- h.Write(se.prefix)
- return &seMDCReader{in: plaintext, h: h}, nil
- }
-
- // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
- return seReader{plaintext}, nil
-}
-
-// seReader wraps an io.Reader with a no-op Close method.
-type seReader struct {
- in io.Reader
-}
-
-func (ser seReader) Read(buf []byte) (int, os.Error) {
- return ser.in.Read(buf)
-}
-
-func (ser seReader) Close() os.Error {
- return nil
-}
-
-const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
-
-// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
-// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
-// MDC packet containing a hash of the previous contents which is checked
-// against the running hash. See RFC 4880, section 5.13.
-type seMDCReader struct {
- in io.Reader
- h hash.Hash
- trailer [mdcTrailerSize]byte
- scratch [mdcTrailerSize]byte
- trailerUsed int
- error bool
- eof bool
-}
-
-func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) {
- if ser.error {
- err = io.ErrUnexpectedEOF
- return
- }
- if ser.eof {
- err = os.EOF
- return
- }
-
- // If we haven't yet filled the trailer buffer then we must do that
- // first.
- for ser.trailerUsed < mdcTrailerSize {
- n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
- ser.trailerUsed += n
- if err == os.EOF {
- if ser.trailerUsed != mdcTrailerSize {
- n = 0
- err = io.ErrUnexpectedEOF
- ser.error = true
- return
- }
- ser.eof = true
- n = 0
- return
- }
-
- if err != nil {
- n = 0
- return
- }
- }
-
- // If it's a short read then we read into a temporary buffer and shift
- // the data into the caller's buffer.
- if len(buf) <= mdcTrailerSize {
- n, err = readFull(ser.in, ser.scratch[:len(buf)])
- copy(buf, ser.trailer[:n])
- ser.h.Write(buf[:n])
- copy(ser.trailer[:], ser.trailer[n:])
- copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
- if n < len(buf) {
- ser.eof = true
- err = os.EOF
- }
- return
- }
-
- n, err = ser.in.Read(buf[mdcTrailerSize:])
- copy(buf, ser.trailer[:])
- ser.h.Write(buf[:n])
- copy(ser.trailer[:], buf[n:])
-
- if err == os.EOF {
- ser.eof = true
- }
- 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")
- }
-
- for !ser.eof {
- // We haven't seen EOF so we need to read to the end
- var buf [1024]byte
- _, err := ser.Read(buf[:])
- if err == os.EOF {
- break
- }
- if err != nil {
- return error.SignatureError("error during reading")
- }
- }
-
- 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 {
- 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/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
deleted file mode 100644
index 1054fc2f9..000000000
--- a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
+++ /dev/null
@@ -1,124 +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 packet
-
-import (
- "bytes"
- "crypto/openpgp/error"
- "crypto/sha1"
- "encoding/hex"
- "io"
- "io/ioutil"
- "os"
- "testing"
-)
-
-// 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 testMDCReader(t *testing.T) {
- mdcPlaintext, _ := hex.DecodeString(mdcPlaintextHex)
-
- for stride := 1; stride < len(mdcPlaintext)/2; stride++ {
- r := &testReader{data: mdcPlaintext, stride: stride}
- mdcReader := &seMDCReader{in: r, h: sha1.New()}
- body, err := ioutil.ReadAll(mdcReader)
- if err != nil {
- t.Errorf("stride: %d, error: %s", stride, err)
- continue
- }
- if !bytes.Equal(body, mdcPlaintext[:len(mdcPlaintext)-22]) {
- t.Errorf("stride: %d: bad contents %x", stride, body)
- continue
- }
-
- err = mdcReader.Close()
- if err != nil {
- t.Errorf("stride: %d, error on Close: %s", stride, err)
- }
- }
-
- mdcPlaintext[15] ^= 80
-
- r := &testReader{data: mdcPlaintext, stride: 2}
- mdcReader := &seMDCReader{in: r, h: sha1.New()}
- _, err := ioutil.ReadAll(mdcReader)
- if err != nil {
- t.Errorf("corruption test, error: %s", err)
- return
- }
- err = mdcReader.Close()
- if err == nil {
- t.Error("corruption: no error")
- } else if _, ok := err.(*error.SignatureError); !ok {
- t.Errorf("corruption: expected SignatureError, got: %s", err)
- }
-}
-
-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/src/pkg/crypto/openpgp/packet/userid.go b/src/pkg/crypto/openpgp/packet/userid.go
deleted file mode 100644
index 0580ba3ed..000000000
--- a/src/pkg/crypto/openpgp/packet/userid.go
+++ /dev/null
@@ -1,161 +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 packet
-
-import (
- "io"
- "io/ioutil"
- "os"
- "strings"
-)
-
-// UserId contains text that is intended to represent the name and email
-// address of the key holder. See RFC 4880, section 5.11. By convention, this
-// takes the form "Full Name (Comment) <email@example.com>"
-type UserId struct {
- Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
-
- 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)
- if err != nil {
- return
- }
- uid.Id = string(b)
- uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
- 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) {
- var n, c, e struct {
- start, end int
- }
- var state int
-
- for offset, rune := range id {
- switch state {
- case 0:
- // Entering name
- n.start = offset
- state = 1
- fallthrough
- case 1:
- // In name
- if rune == '(' {
- state = 2
- n.end = offset
- } else if rune == '<' {
- state = 5
- n.end = offset
- }
- case 2:
- // Entering comment
- c.start = offset
- state = 3
- fallthrough
- case 3:
- // In comment
- if rune == ')' {
- state = 4
- c.end = offset
- }
- case 4:
- // Between comment and email
- if rune == '<' {
- state = 5
- }
- case 5:
- // Entering email
- e.start = offset
- state = 6
- fallthrough
- case 6:
- // In email
- if rune == '>' {
- state = 7
- e.end = offset
- }
- default:
- // After email
- }
- }
- switch state {
- case 1:
- // ended in the name
- n.end = len(id)
- case 3:
- // ended in comment
- c.end = len(id)
- case 6:
- // ended in email
- e.end = len(id)
- }
-
- name = strings.TrimSpace(id[n.start:n.end])
- comment = strings.TrimSpace(id[c.start:c.end])
- email = strings.TrimSpace(id[e.start:e.end])
- return
-}
diff --git a/src/pkg/crypto/openpgp/packet/userid_test.go b/src/pkg/crypto/openpgp/packet/userid_test.go
deleted file mode 100644
index 296819389..000000000
--- a/src/pkg/crypto/openpgp/packet/userid_test.go
+++ /dev/null
@@ -1,87 +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 packet
-
-import (
- "testing"
-)
-
-var userIdTests = []struct {
- id string
- name, comment, email string
-}{
- {"", "", "", ""},
- {"John Smith", "John Smith", "", ""},
- {"John Smith ()", "John Smith", "", ""},
- {"John Smith () <>", "John Smith", "", ""},
- {"(comment", "", "comment", ""},
- {"(comment)", "", "comment", ""},
- {"<email", "", "", "email"},
- {"<email> sdfk", "", "", "email"},
- {" John Smith ( Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
- {" John Smith < email > lksdfj", "John Smith", "", "email"},
- {"(<foo", "", "<foo", ""},
- {"René Descartes (العربي)", "René Descartes", "العربي", ""},
-}
-
-func TestParseUserId(t *testing.T) {
- for i, test := range userIdTests {
- name, comment, email := parseUserId(test.id)
- if name != test.name {
- t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
- }
- if comment != test.comment {
- t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
- }
- if email != test.email {
- t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
- }
- }
-}
-
-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/src/pkg/crypto/openpgp/read.go b/src/pkg/crypto/openpgp/read.go
deleted file mode 100644
index d95f613c6..000000000
--- a/src/pkg/crypto/openpgp/read.go
+++ /dev/null
@@ -1,415 +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 openpgp implements high level operations on OpenPGP messages.
-package openpgp
-
-import (
- "crypto"
- "crypto/openpgp/armor"
- "crypto/openpgp/error"
- "crypto/openpgp/packet"
- _ "crypto/sha256"
- "hash"
- "io"
- "os"
- "strconv"
-)
-
-// SignatureType is the armor type for a PGP signature.
-var SignatureType = "PGP SIGNATURE"
-
-// readArmored reads an armored block with the given type.
-func readArmored(r io.Reader, expectedType string) (body io.Reader, err os.Error) {
- block, err := armor.Decode(r)
- if err != nil {
- return
- }
-
- if block.Type != expectedType {
- return nil, error.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
- }
-
- return block.Body, nil
-}
-
-// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
-// signed message.
-type MessageDetails struct {
- IsEncrypted bool // true if the message was encrypted.
- EncryptedToKeyIds []uint64 // the list of recipient key ids.
- IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
- 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 available.
- LiteralData *packet.LiteralData // the metadata of the contents
- UnverifiedBody io.Reader // the contents of the message.
-
- // If IsSigned is true and SignedBy is non-zero then the signature will
- // be verified as UnverifiedBody is read. The signature cannot be
- // checked until the whole of UnverifiedBody is read so UnverifiedBody
- // must be consumed until EOF before the data can trusted. Even if a
- // message isn't signed (or the signer is unknown) the data may contain
- // an authentication code that is only checked once UnverifiedBody has
- // 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.
-
- decrypted io.ReadCloser
-}
-
-// A PromptFunction is used as a callback by functions that may need to decrypt
-// a private key, or prompt for a passphrase. It is called with a list of
-// acceptable, encrypted private keys and a boolean that indicates whether a
-// passphrase is usable. It should either decrypt a private key or return a
-// passphrase to try. If the decrypted private key or given passphrase isn't
-// correct, the function will be called again, forever. Any error returned will
-// be passed up.
-type PromptFunction func(keys []Key, symmetric bool) ([]byte, os.Error)
-
-// A keyEnvelopePair is used to store a private key with the envelope that
-// contains a symmetric key, encrypted with that key.
-type keyEnvelopePair struct {
- key Key
- encryptedKey *packet.EncryptedKey
-}
-
-// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
-// The given KeyRing should contain both public keys (for signature
-// verification) and, possibly encrypted, private keys for decrypting.
-func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction) (md *MessageDetails, err os.Error) {
- var p packet.Packet
-
- var symKeys []*packet.SymmetricKeyEncrypted
- var pubKeys []keyEnvelopePair
- var se *packet.SymmetricallyEncrypted
-
- packets := packet.NewReader(r)
- md = new(MessageDetails)
- md.IsEncrypted = true
-
- // The message, if encrypted, starts with a number of packets
- // containing an encrypted decryption key. The decryption key is either
- // encrypted to a public key, or with a passphrase. This loop
- // collects these packets.
-ParsePackets:
- for {
- p, err = packets.Next()
- if err != nil {
- return nil, err
- }
- switch p := p.(type) {
- case *packet.SymmetricKeyEncrypted:
- // This packet contains the decryption key encrypted with a passphrase.
- md.IsSymmetricallyEncrypted = true
- symKeys = append(symKeys, p)
- case *packet.EncryptedKey:
- // This packet contains the decryption key encrypted to a public key.
- md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
- switch p.Algo {
- case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
- break
- default:
- continue
- }
- var keys []Key
- if p.KeyId == 0 {
- keys = keyring.DecryptionKeys()
- } else {
- keys = keyring.KeysById(p.KeyId)
- }
- for _, k := range keys {
- pubKeys = append(pubKeys, keyEnvelopePair{k, p})
- }
- case *packet.SymmetricallyEncrypted:
- se = p
- break ParsePackets
- case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
- // This message isn't encrypted.
- if len(symKeys) != 0 || len(pubKeys) != 0 {
- return nil, error.StructuralError("key material not followed by encrypted message")
- }
- packets.Unread(p)
- return readSignedMessage(packets, nil, keyring)
- }
- }
-
- var candidates []Key
- var decrypted io.ReadCloser
-
- // Now that we have the list of encrypted keys we need to decrypt at
- // least one of them or, if we cannot, we need to call the prompt
- // 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 available
- candidates = candidates[:0]
- candidateFingerprints := make(map[string]bool)
-
- for _, pk := range pubKeys {
- if pk.key.PrivateKey == nil {
- continue
- }
- if !pk.key.PrivateKey.Encrypted {
- if len(pk.encryptedKey.Key) == 0 {
- pk.encryptedKey.Decrypt(pk.key.PrivateKey)
- }
- if len(pk.encryptedKey.Key) == 0 {
- continue
- }
- decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
- if err != nil && err != error.KeyIncorrectError {
- return nil, err
- }
- if decrypted != nil {
- md.DecryptedWith = pk.key
- break FindKey
- }
- } else {
- fpr := string(pk.key.PublicKey.Fingerprint[:])
- if v := candidateFingerprints[fpr]; v {
- continue
- }
- candidates = append(candidates, pk.key)
- candidateFingerprints[fpr] = true
- }
- }
-
- if len(candidates) == 0 && len(symKeys) == 0 {
- return nil, error.KeyIncorrectError
- }
-
- if prompt == nil {
- return nil, error.KeyIncorrectError
- }
-
- passphrase, err := prompt(candidates, len(symKeys) != 0)
- if err != nil {
- return nil, err
- }
-
- // Try the symmetric passphrase first
- if len(symKeys) != 0 && passphrase != nil {
- for _, s := range symKeys {
- err = s.Decrypt(passphrase)
- if err == nil && !s.Encrypted {
- decrypted, err = se.Decrypt(s.CipherFunc, s.Key)
- if err != nil && err != error.KeyIncorrectError {
- return nil, err
- }
- if decrypted != nil {
- break FindKey
- }
- }
-
- }
- }
- }
-
- md.decrypted = decrypted
- packets.Push(decrypted)
- return readSignedMessage(packets, md, keyring)
-}
-
-// 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) {
- if mdin == nil {
- mdin = new(MessageDetails)
- }
- md = mdin
-
- var p packet.Packet
- var h hash.Hash
- var wrappedHash hash.Hash
-FindLiteralData:
- for {
- p, err = packets.Next()
- if err != nil {
- return nil, err
- }
- switch p := p.(type) {
- case *packet.Compressed:
- packets.Push(p.Body)
- case *packet.OnePassSignature:
- if !p.IsLast {
- return nil, error.UnsupportedError("nested signatures")
- }
-
- h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
- if err != nil {
- md = nil
- return
- }
-
- md.IsSigned = true
- md.SignedByKeyId = p.KeyId
- keys := keyring.KeysById(p.KeyId)
- for i, key := range keys {
- if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
- continue
- }
- md.SignedBy = &keys[i]
- break
- }
- case *packet.LiteralData:
- md.LiteralData = p
- break FindLiteralData
- }
- }
-
- if md.SignedBy != nil {
- md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
- } else if md.decrypted != nil {
- md.UnverifiedBody = checkReader{md}
- } else {
- md.UnverifiedBody = md.LiteralData.Body
- }
-
- return md, nil
-}
-
-// 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 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 available: " + strconv.Itoa(int(hashId)))
- }
-
- switch sigType {
- case packet.SigTypeBinary:
- return h, h, nil
- case packet.SigTypeText:
- return h, NewCanonicalTextHash(h), nil
- }
-
- return nil, nil, error.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
-}
-
-// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
-// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
-// MDC checks.
-type checkReader struct {
- md *MessageDetails
-}
-
-func (cr checkReader) Read(buf []byte) (n int, err os.Error) {
- n, err = cr.md.LiteralData.Body.Read(buf)
- if err == os.EOF {
- mdcErr := cr.md.decrypted.Close()
- if mdcErr != nil {
- err = mdcErr
- }
- }
- return
-}
-
-// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
-// the data as it is read. When it sees an EOF from the underlying io.Reader
-// it parses and checks a trailing Signature packet and triggers any MDC checks.
-type signatureCheckReader struct {
- packets *packet.Reader
- h, wrappedHash hash.Hash
- md *MessageDetails
-}
-
-func (scr *signatureCheckReader) Read(buf []byte) (n int, err os.Error) {
- n, err = scr.md.LiteralData.Body.Read(buf)
- scr.wrappedHash.Write(buf[:n])
- if err == os.EOF {
- var p packet.Packet
- p, scr.md.SignatureError = scr.packets.Next()
- if scr.md.SignatureError != nil {
- return
- }
-
- var ok bool
- if scr.md.Signature, ok = p.(*packet.Signature); !ok {
- scr.md.SignatureError = error.StructuralError("LiteralData not followed by Signature")
- return
- }
-
- scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
-
- // The SymmetricallyEncrypted packet, if any, might have an
- // unsigned hash of its own. In order to check this we need to
- // close that Reader.
- if scr.md.decrypted != nil {
- mdcErr := scr.md.decrypted.Close()
- if mdcErr != nil {
- err = mdcErr
- }
- }
- }
- return
-}
-
-// CheckDetachedSignature takes a signed file and a detached signature and
-// returns the signer if the signature is valid. If the signer isn't know,
-// UnknownIssuerError is returned.
-func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err os.Error) {
- p, err := packet.Read(signature)
- if err != nil {
- return
- }
-
- sig, ok := p.(*packet.Signature)
- if !ok {
- return nil, error.StructuralError("non signature packet found")
- }
-
- if sig.IssuerKeyId == nil {
- return nil, error.StructuralError("signature doesn't have an issuer")
- }
-
- keys := keyring.KeysById(*sig.IssuerKeyId)
- if len(keys) == 0 {
- return nil, error.UnknownIssuerError
- }
-
- h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
- if err != nil {
- return
- }
-
- _, err = io.Copy(wrappedHash, signed)
- if err != nil && err != os.EOF {
- return
- }
-
- for _, key := range keys {
- if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
- continue
- }
- err = key.PublicKey.VerifySignature(h, sig)
- if err == nil {
- return key.Entity, nil
- }
- }
-
- if err != nil {
- return
- }
-
- return nil, error.UnknownIssuerError
-}
-
-// CheckArmoredDetachedSignature performs the same actions as
-// CheckDetachedSignature but expects the signature to be armored.
-func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err os.Error) {
- body, err := readArmored(signature, SignatureType)
- if err != nil {
- return
- }
-
- return CheckDetachedSignature(keyring, signed, body)
-}
diff --git a/src/pkg/crypto/openpgp/read_test.go b/src/pkg/crypto/openpgp/read_test.go
deleted file mode 100644
index 4dc290ef2..000000000
--- a/src/pkg/crypto/openpgp/read_test.go
+++ /dev/null
@@ -1,361 +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 openpgp
-
-import (
- "bytes"
- "crypto/openpgp/error"
- "encoding/hex"
- "io"
- "io/ioutil"
- "os"
- "testing"
-)
-
-func readerFromHex(s string) io.Reader {
- data, err := hex.DecodeString(s)
- if err != nil {
- panic("readerFromHex: bad input")
- }
- return bytes.NewBuffer(data)
-}
-
-func TestReadKeyRing(t *testing.T) {
- kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
- if err != nil {
- t.Error(err)
- return
- }
- if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B {
- t.Errorf("bad keyring: %#v", kring)
- }
-}
-
-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 {
- t.Error(err)
- return
- }
- if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B || kring[0].PrimaryKey == nil {
- t.Errorf("bad keyring: %#v", kring)
- }
-}
-
-func TestReadDSAKey(t *testing.T) {
- kring, err := ReadKeyRing(readerFromHex(dsaTestKeyHex))
- if err != nil {
- t.Error(err)
- return
- }
- if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x0CCC0360 {
- t.Errorf("bad parse: %#v", kring)
- }
-}
-
-func TestGetKeyById(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
-
- keys := kring.KeysById(0xa34d7e18c20c31bb)
- if len(keys) != 1 || keys[0].Entity != kring[0] {
- t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
- }
-
- keys = kring.KeysById(0xfd94408d4543314f)
- if len(keys) != 1 || keys[0].Entity != kring[0] {
- t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
- }
-}
-
-func checkSignedMessage(t *testing.T, signedHex, expected string) {
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
-
- md, err := ReadMessage(readerFromHex(signedHex), kring, nil)
- if err != nil {
- t.Error(err)
- return
- }
-
- if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted {
- t.Errorf("bad MessageDetails: %#v", 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)
- }
- if md.SignatureError != nil || md.Signature == nil {
- t.Errorf("failed to validate: %s", md.SignatureError)
- }
-}
-
-func TestSignedMessage(t *testing.T) {
- checkSignedMessage(t, signedMessageHex, signedInput)
-}
-
-func TestTextSignedMessage(t *testing.T) {
- checkSignedMessage(t, signedTextMessageHex, signedTextInput)
-}
-
-var signedEncryptedMessageTests = []struct {
- keyRingHex string
- messageHex string
- signedByKeyId uint64
- encryptedToKeyId uint64
-}{
- {
- testKeys1And2PrivateHex,
- signedEncryptedMessageHex,
- 0xa34d7e18c20c31bb,
- 0x2a67d68660df41c7,
- },
- {
- dsaElGamalTestKeysHex,
- signedEncryptedMessage2Hex,
- 0x33af447ccd759b09,
- 0xcf6a7abcd43e3673,
- },
-}
-
-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
- }
-
- md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt)
- if err != nil {
- t.Errorf("#%d: error reading message: %s", i, err)
- return
- }
-
- 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("#%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("#%d: failed to validate: %s", i, md.SignatureError)
- }
- }
-}
-
-func TestUnspecifiedRecipient(t *testing.T) {
- expected := "Recipient unspecified\n"
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
-
- md, err := ReadMessage(readerFromHex(recipientUnspecifiedHex), kring, nil)
- if err != nil {
- t.Errorf("error reading message: %s", err)
- return
- }
-
- 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)
- }
-}
-
-func TestSymmetricallyEncrypted(t *testing.T) {
- expected := "Symmetrically encrypted.\n"
-
- prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
- if len(keys) != 0 {
- t.Errorf("prompt: len(keys) = %d (want 0)", len(keys))
- }
-
- if !symmetric {
- t.Errorf("symmetric is not set")
- }
-
- return []byte("password"), nil
- }
-
- md, err := ReadMessage(readerFromHex(symmetricallyEncryptedCompressedHex), nil, prompt)
- if err != nil {
- t.Errorf("ReadMessage: %s", err)
- return
- }
-
- contents, err := ioutil.ReadAll(md.UnverifiedBody)
- if err != nil {
- t.Errorf("ReadAll: %s", err)
- }
-
- expectedCreationTime := uint32(1295992998)
- if md.LiteralData.Time != expectedCreationTime {
- t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
- }
-
- if string(contents) != expected {
- t.Errorf("contents got: %s want: %s", string(contents), expected)
- }
-}
-
-func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string, expectedSignerKeyId uint64) {
- signed := bytes.NewBufferString(sigInput)
- signer, err := CheckDetachedSignature(kring, signed, signature)
- if err != nil {
- t.Errorf("%s: signature error: %s", tag, err)
- return
- }
- if signer == nil {
- t.Errorf("%s: signer is nil", tag)
- return
- }
- if signer.PrimaryKey.KeyId != expectedSignerKeyId {
- t.Errorf("%s: wrong signer got:%x want:%x", tag, signer.PrimaryKey.KeyId, expectedSignerKeyId)
- }
-}
-
-func TestDetachedSignature(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
- testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary", testKey1KeyId)
- testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text", testKey1KeyId)
-}
-
-func TestDetachedSignatureDSA(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
- testDetachedSignature(t, kring, readerFromHex(detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
-}
-
-func TestReadingArmoredPrivateKey(t *testing.T) {
- el, err := ReadArmoredKeyRing(bytes.NewBufferString(armoredPrivateKeyBlock))
- if err != nil {
- t.Error(err)
- }
- if len(el) != 1 {
- t.Errorf("got %d entities, wanted 1\n", len(el))
- }
-}
-
-func TestNoArmoredData(t *testing.T) {
- _, err := ReadArmoredKeyRing(bytes.NewBufferString("foo"))
- if _, ok := err.(error.InvalidArgumentError); !ok {
- t.Errorf("error was not an InvalidArgumentError: %s", err)
- }
-}
-
-const testKey1KeyId = 0xA34D7E18C20C31BB
-const testKey3KeyId = 0x338934250CCC0360
-
-const signedInput = "Signed message\nline 2\nline 3\n"
-const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
-
-const recipientUnspecifiedHex = "848c0300000000000000000103ff62d4d578d03cf40c3da998dfe216c074fa6ddec5e31c197c9666ba292830d91d18716a80f699f9d897389a90e6d62d0238f5f07a5248073c0f24920e4bc4a30c2d17ee4e0cae7c3d4aaa4e8dced50e3010a80ee692175fa0385f62ecca4b56ee6e9980aa3ec51b61b077096ac9e800edaf161268593eedb6cc7027ff5cb32745d250010d407a6221ae22ef18469b444f2822478c4d190b24d36371a95cb40087cdd42d9399c3d06a53c0673349bfb607927f20d1e122bde1e2bf3aa6cae6edf489629bcaa0689539ae3b718914d88ededc3b"
-
-const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31bb167603ff57718d09f28a519fdc7b5a68b6a3336da04df85e38c5cd5d5bd2092fa4629848a33d85b1729402a2aab39c3ac19f9d573f773cc62c264dc924c067a79dfd8a863ae06c7c8686120760749f5fd9b1e03a64d20a7df3446ddc8f0aeadeaeba7cbaee5c1e366d65b6a0c6cc749bcb912d2f15013f812795c2e29eb7f7b77f39ce77"
-
-const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
-
-const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
-
-const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
-
-const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
-
-const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
-
-const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
-
-const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
-
-const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
-
-const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
-
-const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
-
-const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
-
-const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
-
-const armoredPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
-Version: GnuPG v1.4.10 (GNU/Linux)
-
-lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
-idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
-vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
-AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
-0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
-IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
-VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
-gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
-TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
-q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
-dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
-CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
-ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
-eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
-AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
-bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
-/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
-A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
-TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
-lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
-rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
-oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
-QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
-nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
-AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
-BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
-AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
-VrM0m72/jnpKo04=
-=zNCn
------END PGP PRIVATE KEY BLOCK-----`
diff --git a/src/pkg/crypto/openpgp/s2k/Makefile b/src/pkg/crypto/openpgp/s2k/Makefile
deleted file mode 100644
index 731d53431..000000000
--- a/src/pkg/crypto/openpgp/s2k/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../../Make.inc
-
-TARG=crypto/openpgp/s2k
-GOFILES=\
- s2k.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/s2k/s2k.go b/src/pkg/crypto/openpgp/s2k/s2k.go
deleted file mode 100644
index da926a76e..000000000
--- a/src/pkg/crypto/openpgp/s2k/s2k.go
+++ /dev/null
@@ -1,180 +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 s2k implements the various OpenPGP string-to-key transforms as
-// specified in RFC 4800 section 3.7.1.
-package s2k
-
-import (
- "crypto"
- "crypto/openpgp/error"
- "hash"
- "io"
- "os"
- "strconv"
-)
-
-// Simple writes to out the result of computing the Simple S2K function (RFC
-// 4880, section 3.7.1.1) using the given hash and input passphrase.
-func Simple(out []byte, h hash.Hash, in []byte) {
- Salted(out, h, in, nil)
-}
-
-var zero [1]byte
-
-// Salted writes to out the result of computing the Salted S2K function (RFC
-// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
-func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
- done := 0
-
- for i := 0; done < len(out); i++ {
- h.Reset()
- for j := 0; j < i; j++ {
- h.Write(zero[:])
- }
- h.Write(salt)
- h.Write(in)
- n := copy(out[done:], h.Sum())
- done += n
- }
-}
-
-// Iterated writes to out the result of computing the Iterated and Salted S2K
-// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
-// salt and iteration count.
-func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
- combined := make([]byte, len(in)+len(salt))
- copy(combined, salt)
- copy(combined[len(salt):], in)
-
- if count < len(combined) {
- count = len(combined)
- }
-
- done := 0
- for i := 0; done < len(out); i++ {
- h.Reset()
- for j := 0; j < i; j++ {
- h.Write(zero[:])
- }
- written := 0
- for written < count {
- if written+len(combined) > count {
- todo := count - written
- h.Write(combined[:todo])
- written = count
- } else {
- h.Write(combined)
- written += len(combined)
- }
- }
- n := copy(out[done:], h.Sum())
- done += n
- }
-}
-
-// Parse reads a binary specification for a string-to-key transformation from r
-// and returns a function which performs that transform.
-func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
- var buf [9]byte
-
- _, err = io.ReadFull(r, buf[:2])
- if err != nil {
- return
- }
-
- hash, ok := HashIdToHash(buf[1])
- if !ok {
- return nil, error.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
- }
- h := hash.New()
- if h == nil {
- return nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
- }
-
- switch buf[0] {
- case 1:
- f := func(out, in []byte) {
- Simple(out, h, in)
- }
- return f, nil
- case 2:
- _, err := io.ReadFull(r, buf[:8])
- if err != nil {
- return
- }
- f := func(out, in []byte) {
- Salted(out, h, in, buf[:8])
- }
- return f, nil
- case 3:
- _, err := io.ReadFull(r, buf[:9])
- if err != nil {
- return
- }
- count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6)
- f := func(out, in []byte) {
- Iterated(out, h, in, buf[:8], count)
- }
- return f, nil
- }
-
- return nil, error.UnsupportedError("S2K function")
-}
-
-// 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 {
- id byte
- hash crypto.Hash
-}{
- {1, crypto.MD5},
- {2, crypto.SHA1},
- {3, crypto.RIPEMD160},
- {8, crypto.SHA256},
- {9, crypto.SHA384},
- {10, crypto.SHA512},
- {11, crypto.SHA224},
-}
-
-// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
-// hash id.
-func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
- for _, m := range hashToHashIdMapping {
- if m.id == id {
- return m.hash, true
- }
- }
- return 0, false
-}
-
-// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
-func HashToHashId(h crypto.Hash) (id byte, ok bool) {
- for _, m := range hashToHashIdMapping {
- if m.hash == h {
- return m.id, true
- }
- }
- return 0, false
-}
diff --git a/src/pkg/crypto/openpgp/s2k/s2k_test.go b/src/pkg/crypto/openpgp/s2k/s2k_test.go
deleted file mode 100644
index ec4012c23..000000000
--- a/src/pkg/crypto/openpgp/s2k/s2k_test.go
+++ /dev/null
@@ -1,118 +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 s2k
-
-import (
- "bytes"
- "crypto/sha1"
- "crypto/rand"
- "encoding/hex"
- "testing"
-)
-
-var saltedTests = []struct {
- in, out string
-}{
- {"hello", "10295ac1"},
- {"world", "ac587a5e"},
- {"foo", "4dda8077"},
- {"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
- {"x", "f1d3f289"},
- {"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
-}
-
-func TestSalted(t *testing.T) {
- h := sha1.New()
- salt := [4]byte{1, 2, 3, 4}
-
- for i, test := range saltedTests {
- expected, _ := hex.DecodeString(test.out)
- out := make([]byte, len(expected))
- Salted(out, h, []byte(test.in), salt[:])
- if !bytes.Equal(expected, out) {
- t.Errorf("#%d, got: %x want: %x", i, out, expected)
- }
- }
-}
-
-var iteratedTests = []struct {
- in, out string
-}{
- {"hello", "83126105"},
- {"world", "6fa317f9"},
- {"foo", "8fbc35b9"},
- {"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
- {"x", "5a684dfe"},
- {"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
-}
-
-func TestIterated(t *testing.T) {
- h := sha1.New()
- salt := [4]byte{4, 3, 2, 1}
-
- for i, test := range iteratedTests {
- expected, _ := hex.DecodeString(test.out)
- out := make([]byte, len(expected))
- Iterated(out, h, []byte(test.in), salt[:], 31)
- if !bytes.Equal(expected, out) {
- t.Errorf("#%d, got: %x want: %x", i, out, expected)
- }
- }
-}
-
-var parseTests = []struct {
- spec, in, out string
-}{
- /* Simple with SHA1 */
- {"0102", "hello", "aaf4c61d"},
- /* Salted with SHA1 */
- {"02020102030405060708", "hello", "f4f7d67e"},
- /* Iterated with SHA1 */
- {"03020102030405060708f1", "hello", "f2a57b7c"},
-}
-
-func TestParse(t *testing.T) {
- for i, test := range parseTests {
- spec, _ := hex.DecodeString(test.spec)
- buf := bytes.NewBuffer(spec)
- f, err := Parse(buf)
- if err != nil {
- t.Errorf("%d: Parse returned error: %s", i, err)
- continue
- }
-
- expected, _ := hex.DecodeString(test.out)
- out := make([]byte, len(expected))
- f(out, []byte(test.in))
- if !bytes.Equal(out, expected) {
- t.Errorf("%d: output got: %x want: %x", i, out, expected)
- }
- if testing.Short() {
- break
- }
- }
-}
-
-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/src/pkg/crypto/openpgp/write.go b/src/pkg/crypto/openpgp/write.go
deleted file mode 100644
index 9884472ce..000000000
--- a/src/pkg/crypto/openpgp/write.go
+++ /dev/null
@@ -1,308 +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 openpgp
-
-import (
- "crypto"
- "crypto/openpgp/armor"
- "crypto/openpgp/error"
- "crypto/openpgp/packet"
- "crypto/openpgp/s2k"
- "crypto/rand"
- _ "crypto/sha256"
- "hash"
- "io"
- "os"
- "strconv"
- "time"
-)
-
-// DetachSign signs message with the private key from signer (which must
-// already have been decrypted) and writes the signature to w.
-func DetachSign(w io.Writer, signer *Entity, message io.Reader) os.Error {
- return detachSign(w, signer, message, packet.SigTypeBinary)
-}
-
-// ArmoredDetachSign signs message with the private key from signer (which
-// must already have been decrypted) and writes an armored signature to w.
-func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader) (err os.Error) {
- return armoredDetachSign(w, signer, message, packet.SigTypeBinary)
-}
-
-// DetachSignText signs message (after canonicalising the line endings) with
-// the private key from signer (which must already have been decrypted) and
-// writes the signature to w.
-func DetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
- return detachSign(w, signer, message, packet.SigTypeText)
-}
-
-// ArmoredDetachSignText signs message (after canonicalising the line endings)
-// with the private key from signer (which must already have been decrypted)
-// and writes an armored signature to w.
-func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
- return armoredDetachSign(w, signer, message, packet.SigTypeText)
-}
-
-func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
- out, err := armor.Encode(w, SignatureType, nil)
- if err != nil {
- return
- }
- err = detachSign(out, signer, message, sigType)
- if err != nil {
- return
- }
- return out.Close()
-}
-
-func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType) (err os.Error) {
- if signer.PrivateKey == nil {
- return error.InvalidArgumentError("signing key doesn't have a private key")
- }
- if signer.PrivateKey.Encrypted {
- return error.InvalidArgumentError("signing key is encrypted")
- }
-
- sig := new(packet.Signature)
- sig.SigType = sigType
- sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
- sig.Hash = crypto.SHA256
- sig.CreationTime = uint32(time.Seconds())
- sig.IssuerKeyId = &signer.PrivateKey.KeyId
-
- h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
- if err != nil {
- return
- }
- io.Copy(wrappedHash, message)
-
- 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)
-}
-
-// intersectPreferences mutates and returns a prefix of a that contains only
-// the values in the intersection of a and b. The order of a is preserved.
-func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
- var j int
- for _, v := range a {
- for _, v2 := range b {
- if v == v2 {
- a[j] = v
- j++
- break
- }
- }
- }
-
- return a[:j]
-}
-
-func hashToHashId(h crypto.Hash) uint8 {
- v, ok := s2k.HashToHashId(h)
- if !ok {
- panic("tried to convert unknown hash")
- }
- return v
-}
-
-// Encrypt encrypts a message to a number of recipients and, optionally, signs
-// it. hints contains optional information, that is also encrypted, that aids
-// the recipients in processing the message. The resulting WriteCloser must
-// be closed after the contents of the file have been written.
-func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
- var signer *packet.PrivateKey
- if signed != nil {
- signer = signed.signingKey().PrivateKey
- if signer == nil || signer.Encrypted {
- return nil, error.InvalidArgumentError("signing key must be decrypted")
- }
- }
-
- // These are the possible ciphers that we'll use for the message.
- candidateCiphers := []uint8{
- uint8(packet.CipherAES128),
- uint8(packet.CipherAES256),
- uint8(packet.CipherCAST5),
- }
- // These are the possible hash functions that we'll use for the signature.
- candidateHashes := []uint8{
- hashToHashId(crypto.SHA256),
- hashToHashId(crypto.SHA512),
- hashToHashId(crypto.SHA1),
- hashToHashId(crypto.RIPEMD160),
- }
- // In the event that a recipient doesn't specify any supported ciphers
- // or hash functions, these are the ones that we assume that every
- // implementation supports.
- defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
- defaultHashes := candidateHashes[len(candidateHashes)-1:]
-
- encryptKeys := make([]Key, len(to))
- for i := range to {
- encryptKeys[i] = to[i].encryptionKey()
- if encryptKeys[i].PublicKey == nil {
- return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
- }
-
- sig := to[i].primaryIdentity().SelfSignature
-
- preferredSymmetric := sig.PreferredSymmetric
- if len(preferredSymmetric) == 0 {
- preferredSymmetric = defaultCiphers
- }
- preferredHashes := sig.PreferredHash
- if len(preferredHashes) == 0 {
- preferredHashes = defaultHashes
- }
- candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
- candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
- }
-
- if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
- return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
- }
-
- cipher := packet.CipherFunction(candidateCiphers[0])
- hash, _ := s2k.HashIdToHash(candidateHashes[0])
- symKey := make([]byte, cipher.KeySize())
- if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
- return nil, err
- }
-
- for _, key := range encryptKeys {
- if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
- return nil, err
- }
- }
-
- encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey)
- if err != nil {
- return
- }
-
- if signer != nil {
- ops := &packet.OnePassSignature{
- SigType: packet.SigTypeBinary,
- Hash: hash,
- PubKeyAlgo: signer.PubKeyAlgo,
- KeyId: signer.KeyId,
- IsLast: true,
- }
- if err := ops.Serialize(encryptedData); err != nil {
- return nil, err
- }
- }
-
- if hints == nil {
- hints = &FileHints{}
- }
-
- w := encryptedData
- if signer != nil {
- // If we need to write a signature packet after the literal
- // data then we need to stop literalData from closing
- // encryptedData.
- w = noOpCloser{encryptedData}
-
- }
- literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
- if err != nil {
- return nil, err
- }
-
- if signer != nil {
- return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
- }
- return literalData, nil
-}
-
-// signatureWriter hashes the contents of a message while passing it along to
-// literalData. When closed, it closes literalData, writes a signature packet
-// to encryptedData and then also closes encryptedData.
-type signatureWriter struct {
- encryptedData io.WriteCloser
- literalData io.WriteCloser
- hashType crypto.Hash
- h hash.Hash
- signer *packet.PrivateKey
-}
-
-func (s signatureWriter) Write(data []byte) (int, os.Error) {
- s.h.Write(data)
- return s.literalData.Write(data)
-}
-
-func (s signatureWriter) Close() os.Error {
- sig := &packet.Signature{
- SigType: packet.SigTypeBinary,
- PubKeyAlgo: s.signer.PubKeyAlgo,
- Hash: s.hashType,
- CreationTime: uint32(time.Seconds()),
- IssuerKeyId: &s.signer.KeyId,
- }
-
- if err := sig.Sign(s.h, s.signer); err != nil {
- return err
- }
- if err := s.literalData.Close(); err != nil {
- return err
- }
- if err := sig.Serialize(s.encryptedData); err != nil {
- return err
- }
- return s.encryptedData.Close()
-}
-
-// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
-// TODO: we have two of these in OpenPGP packages alone. This probably needs
-// to be promoted somewhere more common.
-type noOpCloser struct {
- w io.Writer
-}
-
-func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
- return c.w.Write(data)
-}
-
-func (c noOpCloser) Close() os.Error {
- return nil
-}
diff --git a/src/pkg/crypto/openpgp/write_test.go b/src/pkg/crypto/openpgp/write_test.go
deleted file mode 100644
index c542dfa45..000000000
--- a/src/pkg/crypto/openpgp/write_test.go
+++ /dev/null
@@ -1,233 +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 openpgp
-
-import (
- "bytes"
- "crypto/rand"
- "os"
- "io"
- "io/ioutil"
- "testing"
- "time"
-)
-
-func TestSignDetached(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
- out := bytes.NewBuffer(nil)
- message := bytes.NewBufferString(signedInput)
- err := DetachSign(out, kring[0], message)
- if err != nil {
- t.Error(err)
- }
-
- testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
-}
-
-func TestSignTextDetached(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
- out := bytes.NewBuffer(nil)
- message := bytes.NewBufferString(signedInput)
- err := DetachSignText(out, kring[0], message)
- if err != nil {
- t.Error(err)
- }
-
- testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
-}
-
-func TestSignDetachedDSA(t *testing.T) {
- kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
- out := bytes.NewBuffer(nil)
- message := bytes.NewBufferString(signedInput)
- err := DetachSign(out, kring[0], message)
- if err != nil {
- t.Error(err)
- }
-
- 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/src/pkg/crypto/rand/Makefile b/src/pkg/crypto/rand/Makefile
deleted file mode 100644
index d1a3d45e8..000000000
--- a/src/pkg/crypto/rand/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/rand
-
-GOFILES=\
- rand.go\
- util.go\
-
-GOFILES_freebsd=\
- rand_unix.go\
-
-GOFILES_darwin=\
- rand_unix.go\
-
-GOFILES_linux=\
- rand_unix.go\
-
-GOFILES_openbsd=\
- rand_unix.go\
-
-GOFILES_windows=\
- rand_windows.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/rand/rand.go b/src/pkg/crypto/rand/rand.go
index 42d9da0ef..59759038e 100644
--- a/src/pkg/crypto/rand/rand.go
+++ b/src/pkg/crypto/rand/rand.go
@@ -6,10 +6,7 @@
// pseudorandom number generator.
package rand
-import (
- "io"
- "os"
-)
+import "io"
// Reader is a global, shared instance of a cryptographically
// strong pseudo-random generator.
@@ -18,4 +15,4 @@ import (
var Reader io.Reader
// Read is a helper function that calls Reader.Read.
-func Read(b []byte) (n int, err os.Error) { return Reader.Read(b) }
+func Read(b []byte) (n int, err error) { return Reader.Read(b) }
diff --git a/src/pkg/crypto/rand/rand_test.go b/src/pkg/crypto/rand/rand_test.go
index bfae7ce4f..be3a5a221 100644
--- a/src/pkg/crypto/rand/rand_test.go
+++ b/src/pkg/crypto/rand/rand_test.go
@@ -22,7 +22,7 @@ func TestRead(t *testing.T) {
}
var z bytes.Buffer
- f := flate.NewWriter(&z, 5)
+ f, _ := flate.NewWriter(&z, 5)
f.Write(b)
f.Close()
if z.Len() < len(b)*99/100 {
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
index 3a06aa8b1..5eb4cda2b 100644
--- a/src/pkg/crypto/rand/rand_unix.go
+++ b/src/pkg/crypto/rand/rand_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
// Unix cryptographically secure pseudorandom number
// generator.
@@ -10,6 +12,7 @@ package rand
import (
"bufio"
"crypto/aes"
+ "crypto/cipher"
"io"
"os"
"sync"
@@ -28,7 +31,7 @@ type devReader struct {
mu sync.Mutex
}
-func (r *devReader) Read(b []byte) (n int, err os.Error) {
+func (r *devReader) Read(b []byte) (n int, err error) {
r.mu.Lock()
defer r.mu.Unlock()
if r.f == nil {
@@ -64,12 +67,12 @@ func newReader(entropy io.Reader) io.Reader {
type reader struct {
mu sync.Mutex
budget int // number of bytes that can be generated
- cipher *aes.Cipher
+ cipher cipher.Block
entropy io.Reader
time, seed, dst, key [aes.BlockSize]byte
}
-func (r *reader) Read(b []byte) (n int, err os.Error) {
+func (r *reader) Read(b []byte) (n int, err error) {
r.mu.Lock()
defer r.mu.Unlock()
n = len(b)
@@ -98,7 +101,7 @@ func (r *reader) Read(b []byte) (n int, err os.Error) {
// t = encrypt(time)
// dst = encrypt(t^seed)
// seed = encrypt(t^dst)
- ns := time.Nanoseconds()
+ ns := time.Now().UnixNano()
r.time[0] = byte(ns >> 56)
r.time[1] = byte(ns >> 48)
r.time[2] = byte(ns >> 40)
diff --git a/src/pkg/crypto/rand/rand_windows.go b/src/pkg/crypto/rand/rand_windows.go
index 0eab6b213..2b2bd4bba 100755..100644
--- a/src/pkg/crypto/rand/rand_windows.go
+++ b/src/pkg/crypto/rand/rand_windows.go
@@ -23,21 +23,21 @@ type rngReader struct {
mu sync.Mutex
}
-func (r *rngReader) Read(b []byte) (n int, err os.Error) {
+func (r *rngReader) Read(b []byte) (n int, err error) {
r.mu.Lock()
if r.prov == 0 {
const provType = syscall.PROV_RSA_FULL
const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
- errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
- if errno != 0 {
+ err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+ if err != nil {
r.mu.Unlock()
- return 0, os.NewSyscallError("CryptAcquireContext", errno)
+ return 0, os.NewSyscallError("CryptAcquireContext", err)
}
}
r.mu.Unlock()
- errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
- if errno != 0 {
- return 0, os.NewSyscallError("CryptGenRandom", errno)
+ err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+ if err != nil {
+ return 0, os.NewSyscallError("CryptGenRandom", err)
}
return len(b), nil
}
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
index 77028476e..5391c1829 100644
--- a/src/pkg/crypto/rand/util.go
+++ b/src/pkg/crypto/rand/util.go
@@ -5,16 +5,16 @@
package rand
import (
- "big"
+ "errors"
"io"
- "os"
+ "math/big"
)
// 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) {
+func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
if bits < 1 {
- err = os.EINVAL
+ err = errors.New("crypto/rand: prime size must be positive")
}
b := uint(bits % 8)
@@ -39,7 +39,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
bytes[len(bytes)-1] |= 1
p.SetBytes(bytes)
- if big.ProbablyPrime(p, 20) {
+ if p.ProbablyPrime(20) {
return
}
}
@@ -48,7 +48,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
}
// Int returns a uniform random value in [0, max).
-func Int(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
k := (max.BitLen() + 7) / 8
// b is the number of bits in the most significant byte of max.
diff --git a/src/pkg/crypto/rc4/Makefile b/src/pkg/crypto/rc4/Makefile
deleted file mode 100644
index 50a3b7972..000000000
--- a/src/pkg/crypto/rc4/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/rc4
-GOFILES=\
- rc4.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index 7ee471093..1bb278f74 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -9,10 +9,7 @@ package rc4
// BUG(agl): RC4 is in common use but has design weaknesses that make
// it a poor choice for new protocols.
-import (
- "os"
- "strconv"
-)
+import "strconv"
// A Cipher is an instance of RC4 using a particular key.
type Cipher struct {
@@ -22,13 +19,13 @@ type Cipher struct {
type KeySizeError int
-func (k KeySizeError) String() string {
+func (k KeySizeError) Error() string {
return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a new Cipher. The key argument should be the
// RC4 key, at least 1 byte and at most 256 bytes.
-func NewCipher(key []byte) (*Cipher, os.Error) {
+func NewCipher(key []byte) (*Cipher, error) {
k := len(key)
if k < 1 || k > 256 {
return nil, KeySizeError(k)
diff --git a/src/pkg/crypto/ripemd160/Makefile b/src/pkg/crypto/ripemd160/Makefile
deleted file mode 100644
index 7e529457d..000000000
--- a/src/pkg/crypto/ripemd160/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=crypto/ripemd160
-GOFILES=\
- ripemd160.go\
- ripemd160block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/ripemd160/ripemd160.go b/src/pkg/crypto/ripemd160/ripemd160.go
deleted file mode 100644
index 5aaca59a3..000000000
--- a/src/pkg/crypto/ripemd160/ripemd160.go
+++ /dev/null
@@ -1,118 +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 ripemd160 implements the RIPEMD-160 hash algorithm.
-package ripemd160
-
-// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
-// Preneel with specifications available at:
-// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
-
-import (
- "crypto"
- "hash"
- "os"
-)
-
-func init() {
- crypto.RegisterHash(crypto.RIPEMD160, New)
-}
-
-// The size of the checksum in bytes.
-const Size = 20
-
-// The block size of the hash algorithm in bytes.
-const BlockSize = 64
-
-const (
- _s0 = 0x67452301
- _s1 = 0xefcdab89
- _s2 = 0x98badcfe
- _s3 = 0x10325476
- _s4 = 0xc3d2e1f0
-)
-
-// digest represents the partial evaluation of a checksum.
-type digest struct {
- s [5]uint32 // running context
- x [BlockSize]byte // temporary buffer
- nx int // index into x
- tc uint64 // total count of bytes processed
-}
-
-func (d *digest) Reset() {
- d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
- d.nx = 0
- d.tc = 0
-}
-
-// New returns a new hash.Hash computing the checksum.
-func New() hash.Hash {
- result := new(digest)
- result.Reset()
- return result
-}
-
-func (d *digest) Size() int { return Size }
-
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
- nn = len(p)
- d.tc += uint64(nn)
- if d.nx > 0 {
- n := len(p)
- if n > BlockSize-d.nx {
- n = BlockSize - d.nx
- }
- for i := 0; i < n; i++ {
- d.x[d.nx+i] = p[i]
- }
- d.nx += n
- if d.nx == BlockSize {
- _Block(d, d.x[0:])
- d.nx = 0
- }
- p = p[n:]
- }
- n := _Block(d, p)
- p = p[n:]
- if len(p) > 0 {
- d.nx = copy(d.x[:], p)
- }
- return
-}
-
-func (d0 *digest) Sum() []byte {
- // Make a copy of d0 so that caller can keep writing and summing.
- d := new(digest)
- *d = *d0
-
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
- tc := d.tc
- var tmp [64]byte
- tmp[0] = 0x80
- if tc%64 < 56 {
- d.Write(tmp[0 : 56-tc%64])
- } else {
- d.Write(tmp[0 : 64+56-tc%64])
- }
-
- // Length in bits.
- tc <<= 3
- for i := uint(0); i < 8; i++ {
- tmp[i] = byte(tc >> (8 * i))
- }
- d.Write(tmp[0:8])
-
- if d.nx != 0 {
- panic("d.nx != 0")
- }
-
- p := make([]byte, 20)
- j := 0
- for _, s := range d.s {
- p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24)
- j += 4
- }
- return p
-}
diff --git a/src/pkg/crypto/ripemd160/ripemd160_test.go b/src/pkg/crypto/ripemd160/ripemd160_test.go
deleted file mode 100644
index f4135f5cf..000000000
--- a/src/pkg/crypto/ripemd160/ripemd160_test.go
+++ /dev/null
@@ -1,64 +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 ripemd160
-
-// Test vectors are from:
-// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
-
-import (
- "fmt"
- "io"
- "testing"
-)
-
-type mdTest struct {
- out string
- in string
-}
-
-var vectors = [...]mdTest{
- {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
- {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
- {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
- {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
- {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
- {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
- {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
- {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
-}
-
-func TestVectors(t *testing.T) {
- for i := 0; i < len(vectors); i++ {
- tv := vectors[i]
- md := New()
- for j := 0; j < 3; j++ {
- if j < 2 {
- io.WriteString(md, tv.in)
- } else {
- io.WriteString(md, tv.in[0:len(tv.in)/2])
- md.Sum()
- io.WriteString(md, tv.in[len(tv.in)/2:])
- }
- s := fmt.Sprintf("%x", md.Sum())
- if s != tv.out {
- t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
- }
- md.Reset()
- }
- }
-}
-
-func TestMillionA(t *testing.T) {
- md := New()
- for i := 0; i < 100000; i++ {
- io.WriteString(md, "aaaaaaaaaa")
- }
- out := "52783243c1697bdbe16d37f97f68f08325dc1528"
- s := fmt.Sprintf("%x", md.Sum())
- if s != out {
- t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
- }
- md.Reset()
-}
diff --git a/src/pkg/crypto/ripemd160/ripemd160block.go b/src/pkg/crypto/ripemd160/ripemd160block.go
deleted file mode 100644
index 7bc8e6c48..000000000
--- a/src/pkg/crypto/ripemd160/ripemd160block.go
+++ /dev/null
@@ -1,161 +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.
-
-// RIPEMD-160 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-package ripemd160
-
-// work buffer indices and roll amounts for one line
-var _n = [80]uint{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
- 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
- 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
- 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
-}
-
-var _r = [80]uint{
- 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
- 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
- 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
- 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
- 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
-}
-
-// same for the other parallel one
-var n_ = [80]uint{
- 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
- 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
- 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
- 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
- 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
-}
-
-var r_ = [80]uint{
- 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
- 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
- 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
- 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
- 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
-}
-
-func _Block(md *digest, p []byte) int {
- n := 0
- var x [16]uint32
- var alpha, beta uint32
- for len(p) >= BlockSize {
- a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
- aa, bb, cc, dd, ee := a, b, c, d, e
- j := 0
- for i := 0; i < 16; i++ {
- x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
- j += 4
- }
-
- // round 1
- i := 0
- for i < 16 {
- alpha = a + (b ^ c ^ d) + x[_n[i]]
- s := _r[i]
- alpha = (alpha<<s | alpha>>(32-s)) + e
- beta = c<<10 | c>>22
- a, b, c, d, e = e, alpha, b, beta, d
-
- // parallel line
- alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
- s = r_[i]
- alpha = (alpha<<s | alpha>>(32-s)) + ee
- beta = cc<<10 | cc>>22
- aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
-
- i++
- }
-
- // round 2
- for i < 32 {
- alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
- s := _r[i]
- alpha = (alpha<<s | alpha>>(32-s)) + e
- beta = c<<10 | c>>22
- a, b, c, d, e = e, alpha, b, beta, d
-
- // parallel line
- alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
- s = r_[i]
- alpha = (alpha<<s | alpha>>(32-s)) + ee
- beta = cc<<10 | cc>>22
- aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
-
- i++
- }
-
- // round 3
- for i < 48 {
- alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
- s := _r[i]
- alpha = (alpha<<s | alpha>>(32-s)) + e
- beta = c<<10 | c>>22
- a, b, c, d, e = e, alpha, b, beta, d
-
- // parallel line
- alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
- s = r_[i]
- alpha = (alpha<<s | alpha>>(32-s)) + ee
- beta = cc<<10 | cc>>22
- aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
-
- i++
- }
-
- // round 4
- for i < 64 {
- alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
- s := _r[i]
- alpha = (alpha<<s | alpha>>(32-s)) + e
- beta = c<<10 | c>>22
- a, b, c, d, e = e, alpha, b, beta, d
-
- // parallel line
- alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
- s = r_[i]
- alpha = (alpha<<s | alpha>>(32-s)) + ee
- beta = cc<<10 | cc>>22
- aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
-
- i++
- }
-
- // round 5
- for i < 80 {
- alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
- s := _r[i]
- alpha = (alpha<<s | alpha>>(32-s)) + e
- beta = c<<10 | c>>22
- a, b, c, d, e = e, alpha, b, beta, d
-
- // parallel line
- alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
- s = r_[i]
- alpha = (alpha<<s | alpha>>(32-s)) + ee
- beta = cc<<10 | cc>>22
- aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
-
- i++
- }
-
- // combine results
- dd += c + md.s[1]
- md.s[1] = md.s[2] + d + ee
- md.s[2] = md.s[3] + e + aa
- md.s[3] = md.s[4] + a + bb
- md.s[4] = md.s[0] + b + cc
- md.s[0] = dd
-
- p = p[BlockSize:]
- n += BlockSize
- }
- return n
-}
diff --git a/src/pkg/crypto/rsa/Makefile b/src/pkg/crypto/rsa/Makefile
deleted file mode 100644
index ff26ca6f2..000000000
--- a/src/pkg/crypto/rsa/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/rsa
-GOFILES=\
- rsa.go\
- pkcs1v15.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 600623114..254f4a3da 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -5,11 +5,11 @@
package rsa
import (
- "big"
"crypto"
"crypto/subtle"
+ "errors"
"io"
- "os"
+ "math/big"
)
// This file implements encryption and decryption using PKCS#1 v1.5 padding.
@@ -18,10 +18,10 @@ import (
// The message must be no longer than the length of the public modulus minus 11 bytes.
// WARNING: use of this function to encrypt plaintexts other than session keys
// is dangerous. Use RSA OAEP in new protocols.
-func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err os.Error) {
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-11 {
- err = MessageTooLongError{}
+ err = ErrMessageTooLong
return
}
@@ -44,10 +44,10 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
// If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.
-func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err os.Error) {
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)
if err == nil && valid == 0 {
- err = DecryptionError{}
+ err = ErrDecryption
}
return
@@ -65,11 +65,11 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
// about the plaintext.
// See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
// Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
-// (Crypto '98),
-func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err os.Error) {
+// (Crypto '98).
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
k := (priv.N.BitLen() + 7) / 8
if k-(len(key)+3+8) < 0 {
- err = DecryptionError{}
+ err = ErrDecryption
return
}
@@ -83,10 +83,10 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
return
}
-func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err os.Error) {
+func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid int, msg []byte, err error) {
k := (priv.N.BitLen() + 7) / 8
if k < 11 {
- err = DecryptionError{}
+ err = ErrDecryption
return
}
@@ -119,7 +119,7 @@ func decryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (valid
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
-func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
_, err = io.ReadFull(rand, s)
if err != nil {
return
@@ -161,7 +161,7 @@ var hashPrefixes = map[crypto.Hash][]byte{
// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
// Note that hashed must be the result of hashing the input message using the
// given hash function.
-func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err os.Error) {
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
return
@@ -170,7 +170,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
tLen := len(prefix) + hashLen
k := (priv.N.BitLen() + 7) / 8
if k < tLen+11 {
- return nil, MessageTooLongError{}
+ return nil, ErrMessageTooLong
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
@@ -194,7 +194,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
// hashed is the result of hashing the input message using the given hash
// function and sig is the signature. A valid signature is indicated by
// returning a nil error.
-func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err os.Error) {
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
if err != nil {
return
@@ -203,7 +203,7 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
tLen := len(prefix) + hashLen
k := (pub.N.BitLen() + 7) / 8
if k < tLen+11 {
- err = VerificationError{}
+ err = ErrVerification
return
}
@@ -223,20 +223,20 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
}
if ok != 1 {
- return VerificationError{}
+ return ErrVerification
}
return nil
}
-func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
+func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
hashLen = hash.Size()
if inLen != hashLen {
- return 0, nil, os.NewError("input must be hashed message")
+ return 0, nil, errors.New("input must be hashed message")
}
prefix, ok := hashPrefixes[hash]
if !ok {
- return 0, nil, os.NewError("unsupported hash function")
+ return 0, nil, errors.New("unsupported hash function")
}
return
}
diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
index d69bacfd6..58d5fda19 100644
--- a/src/pkg/crypto/rsa/pkcs1v15_test.go
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -5,7 +5,6 @@
package rsa
import (
- "big"
"bytes"
"crypto"
"crypto/rand"
@@ -13,6 +12,7 @@ import (
"encoding/base64"
"encoding/hex"
"io"
+ "math/big"
"testing"
"testing/quick"
)
@@ -168,7 +168,7 @@ func TestSignPKCS1v15(t *testing.T) {
for i, test := range signPKCS1v15Tests {
h := sha1.New()
h.Write([]byte(test.in))
- digest := h.Sum()
+ digest := h.Sum(nil)
s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest)
if err != nil {
@@ -186,7 +186,7 @@ func TestVerifyPKCS1v15(t *testing.T) {
for i, test := range signPKCS1v15Tests {
h := sha1.New()
h.Write([]byte(test.in))
- digest := h.Sum()
+ digest := h.Sum(nil)
sig, _ := hex.DecodeString(test.out)
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index 6957659f2..ec77e6869 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -8,12 +8,12 @@ package rsa
// TODO(agl): Add support for PSS padding.
import (
- "big"
"crypto/rand"
"crypto/subtle"
+ "errors"
"hash"
"io"
- "os"
+ "math/big"
)
var bigZero = big.NewInt(0)
@@ -55,16 +55,15 @@ type CRTValue struct {
}
// Validate performs basic sanity checks on the key.
-// It returns nil if the key is valid, or else an os.Error describing a problem.
-
-func (priv *PrivateKey) Validate() os.Error {
+// It returns nil if the key is valid, or else an error describing a problem.
+func (priv *PrivateKey) Validate() error {
// Check that the prime factors are actually prime. Note that this is
// just a sanity check. Since the random witnesses chosen by
// ProbablyPrime are deterministic, given the candidate number, it's
// easy for an attack to generate composites that pass this test.
for _, prime := range priv.Primes {
- if !big.ProbablyPrime(prime, 20) {
- return os.NewError("prime factor is composite")
+ if !prime.ProbablyPrime(20) {
+ return errors.New("prime factor is composite")
}
}
@@ -74,7 +73,7 @@ func (priv *PrivateKey) Validate() os.Error {
modulus.Mul(modulus, prime)
}
if modulus.Cmp(priv.N) != 0 {
- return os.NewError("invalid modulus")
+ return errors.New("invalid modulus")
}
// Check that e and totient(Πprimes) are coprime.
totient := new(big.Int).Set(bigOne)
@@ -86,21 +85,21 @@ func (priv *PrivateKey) Validate() os.Error {
gcd := new(big.Int)
x := new(big.Int)
y := new(big.Int)
- big.GcdInt(gcd, x, y, totient, e)
+ gcd.GCD(x, y, totient, e)
if gcd.Cmp(bigOne) != 0 {
- return os.NewError("invalid public exponent E")
+ return errors.New("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.NewError("invalid private exponent D")
+ return errors.New("invalid private exponent D")
}
return nil
}
// GenerateKey generates an RSA keypair of the given bit size.
-func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
return GenerateMultiPrimeKey(random, 2, bits)
}
@@ -114,20 +113,12 @@ func GenerateKey(random 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(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) {
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) {
priv = new(PrivateKey)
- // Smaller public exponents lead to faster public key
- // operations. Since the exponent must be coprime to
- // (p-1)(q-1), the smallest possible value is 3. Some have
- // suggested that a larger exponent (often 2**16+1) be used
- // since previous implementation bugs[1] were avoided when this
- // was the case. However, there are no current reasons not to use
- // small exponents.
- // [1] http://marc.info/?l=cryptography&m=115694833312008&w=2
- priv.E = 3
+ priv.E = 65537
if nprimes < 2 {
- return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
+ return nil, errors.New("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
}
primes := make([]*big.Int, nprimes)
@@ -165,7 +156,7 @@ NextSetOfPrimes:
priv.D = new(big.Int)
y := new(big.Int)
e := big.NewInt(int64(priv.E))
- big.GcdInt(g, priv.D, y, e, totient)
+ g.GCD(priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
priv.D.Add(priv.D, totient)
@@ -198,12 +189,13 @@ func incCounter(c *[4]byte) {
// specified in PKCS#1 v2.1.
func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
var counter [4]byte
+ var digest []byte
done := 0
for done < len(out) {
hash.Write(seed)
hash.Write(counter[0:4])
- digest := hash.Sum()
+ digest = hash.Sum(digest[:0])
hash.Reset()
for i := 0; i < len(digest) && done < len(out); i++ {
@@ -214,13 +206,9 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
}
}
-// MessageTooLongError is returned when attempting to encrypt a message which
-// is too large for the size of the public key.
-type MessageTooLongError struct{}
-
-func (MessageTooLongError) String() string {
- return "message too long for RSA public key size"
-}
+// ErrMessageTooLong is returned when attempting to encrypt a message which is
+// too large for the size of the public key.
+var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA public key size")
func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
e := big.NewInt(int64(pub.E))
@@ -231,16 +219,16 @@ 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, random 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 error) {
hash.Reset()
k := (pub.N.BitLen() + 7) / 8
if len(msg) > k-2*hash.Size()-2 {
- err = MessageTooLongError{}
+ err = ErrMessageTooLong
return
}
hash.Write(label)
- lHash := hash.Sum()
+ lHash := hash.Sum(nil)
hash.Reset()
em := make([]byte, k)
@@ -274,17 +262,13 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
return
}
-// A DecryptionError represents a failure to decrypt a message.
+// ErrDecryption represents a failure to decrypt a message.
// It is deliberately vague to avoid adaptive attacks.
-type DecryptionError struct{}
+var ErrDecryption = errors.New("crypto/rsa: decryption error")
-func (DecryptionError) String() string { return "RSA decryption error" }
-
-// A VerificationError represents a failure to verify a signature.
+// ErrVerification represents a failure to verify a signature.
// It is deliberately vague to avoid adaptive attacks.
-type VerificationError struct{}
-
-func (VerificationError) String() string { return "RSA verification error" }
+var ErrVerification = errors.New("crypto/rsa: verification error")
// modInverse returns ia, the inverse of a in the multiplicative group of prime
// order n. It requires that a be a member of the group (i.e. less than n).
@@ -292,7 +276,7 @@ func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
g := new(big.Int)
x := new(big.Int)
y := new(big.Int)
- big.GcdInt(g, x, y, a, n)
+ g.GCD(x, y, a, n)
if g.Cmp(bigOne) != 0 {
// In this case, a and n aren't coprime and we cannot calculate
// the inverse. This happens because the values of n are nearly
@@ -343,10 +327,10 @@ 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(random 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 error) {
// TODO(agl): can we get away with reusing blinds?
if c.Cmp(priv.N) > 0 {
- err = DecryptionError{}
+ err = ErrDecryption
return
}
@@ -420,12 +404,12 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os
}
// DecryptOAEP decrypts ciphertext using RSA-OAEP.
-// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
-func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) {
+// If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
k := (priv.N.BitLen() + 7) / 8
if len(ciphertext) > k ||
k < hash.Size()*2+2 {
- err = DecryptionError{}
+ err = ErrDecryption
return
}
@@ -437,7 +421,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
}
hash.Write(label)
- lHash := hash.Sum()
+ lHash := hash.Sum(nil)
hash.Reset()
// Converting the plaintext number to bytes will strip any
@@ -481,7 +465,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
}
if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
- err = DecryptionError{}
+ err = ErrDecryption
return
}
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index c36bca1cd..0fb9875d0 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -5,10 +5,10 @@
package rsa
import (
- "big"
"bytes"
"crypto/rand"
"crypto/sha1"
+ "math/big"
"testing"
)
diff --git a/src/pkg/crypto/sha1/Makefile b/src/pkg/crypto/sha1/Makefile
deleted file mode 100644
index 81ac38c0b..000000000
--- a/src/pkg/crypto/sha1/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/sha1
-GOFILES=\
- sha1.go\
- sha1block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 788d1ff55..876e7992a 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -8,7 +8,6 @@ package sha1
import (
"crypto"
"hash"
- "os"
)
func init() {
@@ -18,6 +17,9 @@ func init() {
// The size of a SHA1 checksum in bytes.
const Size = 20
+// The blocksize of SHA1 in bytes.
+const BlockSize = 64
+
const (
_Chunk = 64
_Init0 = 0x67452301
@@ -54,7 +56,9 @@ func New() hash.Hash {
func (d *digest) Size() int { return Size }
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
@@ -80,10 +84,9 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
- d := new(digest)
- *d = *d0
+ d := *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
@@ -106,14 +109,13 @@ func (d0 *digest) Sum() []byte {
panic("d.nx != 0")
}
- p := make([]byte, 20)
- j := 0
- for _, s := range d.h {
- p[j+0] = byte(s >> 24)
- p[j+1] = byte(s >> 16)
- p[j+2] = byte(s >> 8)
- p[j+3] = byte(s >> 0)
- j += 4
+ var digest [Size]byte
+ for i, s := range d.h {
+ digest[i*4] = byte(s >> 24)
+ digest[i*4+1] = byte(s >> 16)
+ digest[i*4+2] = byte(s >> 8)
+ digest[i*4+3] = byte(s)
}
- return p
+
+ return append(in, digest[:]...)
}
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index 2712fe35e..2dc14ac98 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -4,9 +4,10 @@
// SHA1 hash algorithm. See RFC 3174.
-package sha1
+package sha1_test
import (
+ "crypto/sha1"
"fmt"
"io"
"testing"
@@ -54,16 +55,16 @@ var golden = []sha1Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := New()
+ c := sha1.New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
}
@@ -71,3 +72,10 @@ func TestGolden(t *testing.T) {
}
}
}
+
+func ExampleNew() {
+ h := sha1.New()
+ io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+ fmt.Printf("% x", h.Sum(nil))
+ // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
+}
diff --git a/src/pkg/crypto/sha256/Makefile b/src/pkg/crypto/sha256/Makefile
deleted file mode 100644
index 97fe4d8e6..000000000
--- a/src/pkg/crypto/sha256/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/sha256
-GOFILES=\
- sha256.go\
- sha256block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
index a2c058d18..a61e30b42 100644
--- a/src/pkg/crypto/sha256/sha256.go
+++ b/src/pkg/crypto/sha256/sha256.go
@@ -9,7 +9,6 @@ package sha256
import (
"crypto"
"hash"
- "os"
)
func init() {
@@ -23,6 +22,9 @@ const Size = 32
// The size of a SHA224 checksum in bytes.
const Size224 = 28
+// The blocksize of SHA256 and SHA224 in bytes.
+const BlockSize = 64
+
const (
_Chunk = 64
_Init0 = 0x6A09E667
@@ -98,7 +100,9 @@ func (d *digest) Size() int {
return Size224
}
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
@@ -124,10 +128,9 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
- d := new(digest)
- *d = *d0
+ d := *d0
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
len := d.len
@@ -150,17 +153,20 @@ func (d0 *digest) Sum() []byte {
panic("d.nx != 0")
}
- p := make([]byte, 32)
- j := 0
- for _, s := range d.h {
- p[j+0] = byte(s >> 24)
- p[j+1] = byte(s >> 16)
- p[j+2] = byte(s >> 8)
- p[j+3] = byte(s >> 0)
- j += 4
- }
+ h := d.h[:]
+ size := Size
if d.is224 {
- return p[0:28]
+ h = d.h[:7]
+ size = Size224
}
- return p
+
+ var digest [Size]byte
+ for i, s := range h {
+ digest[i*4] = byte(s >> 24)
+ digest[i*4+1] = byte(s >> 16)
+ digest[i*4+2] = byte(s >> 8)
+ digest[i*4+3] = byte(s)
+ }
+
+ return append(in, digest[:size]...)
}
diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
index 42a3fa7a0..a6efb3754 100644
--- a/src/pkg/crypto/sha256/sha256_test.go
+++ b/src/pkg/crypto/sha256/sha256_test.go
@@ -94,10 +94,10 @@ func TestGolden(t *testing.T) {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
}
@@ -112,10 +112,10 @@ func TestGolden(t *testing.T) {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
}
diff --git a/src/pkg/crypto/sha512/Makefile b/src/pkg/crypto/sha512/Makefile
deleted file mode 100644
index 2f7633fa3..000000000
--- a/src/pkg/crypto/sha512/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/sha512
-GOFILES=\
- sha512.go\
- sha512block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
index 78f5fe26f..a245fd68e 100644
--- a/src/pkg/crypto/sha512/sha512.go
+++ b/src/pkg/crypto/sha512/sha512.go
@@ -9,7 +9,6 @@ package sha512
import (
"crypto"
"hash"
- "os"
)
func init() {
@@ -23,6 +22,9 @@ const Size = 64
// The size of a SHA384 checksum in bytes.
const Size384 = 48
+// The blocksize of SHA512 and SHA384 in bytes.
+const BlockSize = 128
+
const (
_Chunk = 128
_Init0 = 0x6a09e667f3bcc908
@@ -98,7 +100,9 @@ func (d *digest) Size() int {
return Size384
}
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
@@ -124,7 +128,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
return
}
-func (d0 *digest) Sum() []byte {
+func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := new(digest)
*d = *d0
@@ -150,21 +154,24 @@ func (d0 *digest) Sum() []byte {
panic("d.nx != 0")
}
- p := make([]byte, 64)
- j := 0
- for _, s := range d.h {
- p[j+0] = byte(s >> 56)
- p[j+1] = byte(s >> 48)
- p[j+2] = byte(s >> 40)
- p[j+3] = byte(s >> 32)
- p[j+4] = byte(s >> 24)
- p[j+5] = byte(s >> 16)
- p[j+6] = byte(s >> 8)
- p[j+7] = byte(s >> 0)
- j += 8
- }
+ h := d.h[:]
+ size := Size
if d.is384 {
- return p[0:48]
+ h = d.h[:6]
+ size = Size384
}
- return p
+
+ var digest [Size]byte
+ for i, s := range h {
+ digest[i*8] = byte(s >> 56)
+ digest[i*8+1] = byte(s >> 48)
+ digest[i*8+2] = byte(s >> 40)
+ digest[i*8+3] = byte(s >> 32)
+ digest[i*8+4] = byte(s >> 24)
+ digest[i*8+5] = byte(s >> 16)
+ digest[i*8+6] = byte(s >> 8)
+ digest[i*8+7] = byte(s)
+ }
+
+ return append(in, digest[:size]...)
}
diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
index dd116dc17..a70f7c54e 100644
--- a/src/pkg/crypto/sha512/sha512_test.go
+++ b/src/pkg/crypto/sha512/sha512_test.go
@@ -94,10 +94,10 @@ func TestGolden(t *testing.T) {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
}
@@ -112,10 +112,10 @@ func TestGolden(t *testing.T) {
io.WriteString(c, g.in)
} else {
io.WriteString(c, g.in[0:len(g.in)/2])
- c.Sum()
+ c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
}
- s := fmt.Sprintf("%x", c.Sum())
+ s := fmt.Sprintf("%x", c.Sum(nil))
if s != g.out {
t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
}
diff --git a/src/pkg/crypto/subtle/Makefile b/src/pkg/crypto/subtle/Makefile
deleted file mode 100644
index 08d8bbfa0..000000000
--- a/src/pkg/crypto/subtle/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/subtle
-GOFILES=\
- constant_time.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/tls/Makefile b/src/pkg/crypto/tls/Makefile
deleted file mode 100644
index 000314be5..000000000
--- a/src/pkg/crypto/tls/Makefile
+++ /dev/null
@@ -1,20 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/tls
-GOFILES=\
- alert.go\
- cipher_suites.go\
- common.go\
- conn.go\
- handshake_client.go\
- handshake_messages.go\
- handshake_server.go\
- key_agreement.go\
- prf.go\
- tls.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/tls/alert.go b/src/pkg/crypto/tls/alert.go
index 3b9e0e241..0856311e4 100644
--- a/src/pkg/crypto/tls/alert.go
+++ b/src/pkg/crypto/tls/alert.go
@@ -71,3 +71,7 @@ func (e alert) String() string {
}
return "alert(" + strconv.Itoa(int(e)) + ")"
}
+
+func (e alert) Error() string {
+ return e.String()
+}
diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go
index bc7b0d32f..00695e7d1 100644
--- a/src/pkg/crypto/tls/cipher_suites.go
+++ b/src/pkg/crypto/tls/cipher_suites.go
@@ -7,11 +7,12 @@ package tls
import (
"crypto/aes"
"crypto/cipher"
+ "crypto/des"
"crypto/hmac"
"crypto/rc4"
+ "crypto/sha1"
"crypto/x509"
"hash"
- "os"
)
// a keyAgreement implements the client and server side of a TLS key agreement
@@ -22,20 +23,21 @@ type keyAgreement interface {
// In the case that the key agreement protocol doesn't use a
// ServerKeyExchange message, generateServerKeyExchange can return nil,
// nil.
- generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error)
- processClientKeyExchange(*Config, *clientKeyExchangeMsg) ([]byte, os.Error)
+ generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+ processClientKeyExchange(*Config, *clientKeyExchangeMsg, uint16) ([]byte, error)
// On the client side, the next two methods are called in order.
// This method may not be called if the server doesn't send a
// ServerKeyExchange message.
- processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) os.Error
- generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error)
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
}
// A cipherSuite is a specific combination of key agreement, cipher and MAC
// function. All cipher suites currently assume RSA key agreement.
type cipherSuite struct {
+ id uint16
// the lengths, in bytes, of the key material needed for each component.
keyLen int
macLen int
@@ -46,14 +48,16 @@ type cipherSuite struct {
// and point format that we can handle.
elliptic bool
cipher func(key, iv []byte, isRead bool) interface{}
- mac func(macKey []byte) hash.Hash
+ mac func(version uint16, macKey []byte) macFunction
}
-var cipherSuites = map[uint16]*cipherSuite{
- TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, hmacSHA1},
- TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, hmacSHA1},
- TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, hmacSHA1},
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, hmacSHA1},
+var cipherSuites = []*cipherSuite{
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1},
+ {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -61,6 +65,14 @@ func cipherRC4(key, iv []byte, isRead bool) interface{} {
return cipher
}
+func cipher3DES(key, iv []byte, isRead bool) interface{} {
+ block, _ := des.NewTripleDESCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
func cipherAES(key, iv []byte, isRead bool) interface{} {
block, _ := aes.NewCipher(key)
if isRead {
@@ -69,8 +81,75 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
return cipher.NewCBCEncrypter(block, iv)
}
-func hmacSHA1(key []byte) hash.Hash {
- return hmac.NewSHA1(key)
+// macSHA1 returns a macFunction for the given protocol version.
+func macSHA1(version uint16, key []byte) macFunction {
+ if version == versionSSL30 {
+ mac := ssl30MAC{
+ h: sha1.New(),
+ key: make([]byte, len(key)),
+ }
+ copy(mac.key, key)
+ return mac
+ }
+ return tls10MAC{hmac.New(sha1.New, key)}
+}
+
+type macFunction interface {
+ Size() int
+ MAC(digestBuf, seq, data []byte) []byte
+}
+
+// ssl30MAC implements the SSLv3 MAC function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
+type ssl30MAC struct {
+ h hash.Hash
+ key []byte
+}
+
+func (s ssl30MAC) Size() int {
+ return s.h.Size()
+}
+
+var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
+
+var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
+
+func (s ssl30MAC) MAC(digestBuf, seq, record []byte) []byte {
+ padLength := 48
+ if s.h.Size() == 20 {
+ padLength = 40
+ }
+
+ s.h.Reset()
+ s.h.Write(s.key)
+ s.h.Write(ssl30Pad1[:padLength])
+ s.h.Write(seq)
+ s.h.Write(record[:1])
+ s.h.Write(record[3:5])
+ s.h.Write(record[recordHeaderLen:])
+ digestBuf = s.h.Sum(digestBuf[:0])
+
+ s.h.Reset()
+ s.h.Write(s.key)
+ s.h.Write(ssl30Pad2[:padLength])
+ s.h.Write(digestBuf)
+ return s.h.Sum(digestBuf[:0])
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
+type tls10MAC struct {
+ h hash.Hash
+}
+
+func (s tls10MAC) Size() int {
+ return s.h.Size()
+}
+
+func (s tls10MAC) MAC(digestBuf, seq, record []byte) []byte {
+ s.h.Reset()
+ s.h.Write(seq)
+ s.h.Write(record)
+ return s.h.Sum(digestBuf[:0])
}
func rsaKA() keyAgreement {
@@ -81,22 +160,29 @@ func ecdheRSAKA() keyAgreement {
return new(ecdheRSAKeyAgreement)
}
-// mutualCipherSuite returns a cipherSuite and its id given a list of supported
+// mutualCipherSuite returns a cipherSuite given a list of supported
// ciphersuites and the id requested by the peer.
-func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) {
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
for _, id := range have {
if id == want {
- return cipherSuites[id], id
+ for _, suite := range cipherSuites {
+ if suite.id == want {
+ return suite
+ }
+ }
+ return nil
}
}
- return
+ return nil
}
// A list of the possible cipher suite ids. Taken from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
- TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
- TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
- TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
)
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index 3efac9c13..4ba0bf874 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -5,11 +5,11 @@
package tls
import (
+ "crypto"
"crypto/rand"
- "crypto/rsa"
"crypto/x509"
"io"
- "io/ioutil"
+ "strings"
"sync"
"time"
)
@@ -20,8 +20,11 @@ const (
recordHeaderLen = 5 // record header length
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
- minVersion = 0x0301 // minimum supported version - TLS 1.0
- maxVersion = 0x0301 // maximum supported version - TLS 1.0
+ versionSSL30 = 0x0300
+ versionTLS10 = 0x0301
+
+ minVersion = versionSSL30
+ maxVersion = versionTLS10
)
// TLS record types.
@@ -98,12 +101,28 @@ type ConnectionState struct {
NegotiatedProtocol string
NegotiatedProtocolIsMutual bool
+ // ServerName contains the server name indicated by the client, if any.
+ // (Only valid for server connections.)
+ ServerName string
+
// the certificate chain that was presented by the other side
PeerCertificates []*x509.Certificate
// the verified certificate chains built from PeerCertificates.
VerifiedChains [][]*x509.Certificate
}
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+ NoClientCert ClientAuthType = iota
+ RequestClientCert
+ RequireAnyClientCert
+ VerifyClientCertIfGiven
+ RequireAndVerifyClientCert
+)
+
// A Config structure is used to configure a TLS client or server. After one
// has been passed to a TLS function it must not be modified.
type Config struct {
@@ -113,14 +132,22 @@ type Config struct {
Rand io.Reader
// Time returns the current time as the number of seconds since the epoch.
- // If Time is nil, TLS uses the system time.Seconds.
- Time func() int64
+ // If Time is nil, TLS uses time.Now.
+ Time func() time.Time
// Certificates contains one or more certificate chains
// to present to the other side of the connection.
// Server configurations must include at least one certificate.
Certificates []Certificate
+ // NameToCertificate maps from a certificate name to an element of
+ // Certificates. Note that a certificate name can be of the form
+ // '*.example.com' and so doesn't have to be a domain name as such.
+ // See Config.BuildNameToCertificate
+ // The nil value causes the first element of Certificates to be used
+ // for all connections.
+ NameToCertificate map[string]*Certificate
+
// RootCAs defines the set of root certificate authorities
// that clients use when verifying server certificates.
// If RootCAs is nil, TLS uses the host's root CA set.
@@ -133,11 +160,22 @@ type Config struct {
// hosting.
ServerName string
- // AuthenticateClient controls whether a server will request a certificate
- // from the client. It does not require that the client send a
- // certificate nor does it require that the certificate sent be
- // anything more than self-signed.
- AuthenticateClient bool
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // InsecureSkipVerify controls whether a client verifies the
+ // server's certificate chain and host name.
+ // If InsecureSkipVerify is true, TLS accepts any certificate
+ // presented by the server and any host name in that certificate.
+ // In this mode, TLS is susceptible to man-in-the-middle attacks.
+ // This should be used only for testing.
+ InsecureSkipVerify bool
// CipherSuites is a list of supported cipher suites. If CipherSuites
// is nil, TLS uses a list of suites supported by the implementation.
@@ -152,22 +190,14 @@ func (c *Config) rand() io.Reader {
return r
}
-func (c *Config) time() int64 {
+func (c *Config) time() time.Time {
t := c.Time
if t == nil {
- t = time.Seconds
+ t = time.Now
}
return t()
}
-func (c *Config) rootCAs() *x509.CertPool {
- s := c.RootCAs
- if s == nil {
- s = defaultRoots()
- }
- return s
-}
-
func (c *Config) cipherSuites() []uint16 {
s := c.CipherSuites
if s == nil {
@@ -176,13 +206,71 @@ func (c *Config) cipherSuites() []uint16 {
return s
}
+// getCertificateForName returns the best certificate for the given name,
+// defaulting to the first element of c.Certificates if there are no good
+// options.
+func (c *Config) getCertificateForName(name string) *Certificate {
+ if len(c.Certificates) == 1 || c.NameToCertificate == nil {
+ // There's only one choice, so no point doing any work.
+ return &c.Certificates[0]
+ }
+
+ name = strings.ToLower(name)
+ for len(name) > 0 && name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+
+ if cert, ok := c.NameToCertificate[name]; ok {
+ return cert
+ }
+
+ // try replacing labels in the name with wildcards until we get a
+ // match.
+ labels := strings.Split(name, ".")
+ for i := range labels {
+ labels[i] = "*"
+ candidate := strings.Join(labels, ".")
+ if cert, ok := c.NameToCertificate[candidate]; ok {
+ return cert
+ }
+ }
+
+ // If nothing matches, return the first certificate.
+ return &c.Certificates[0]
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+func (c *Config) BuildNameToCertificate() {
+ c.NameToCertificate = make(map[string]*Certificate)
+ for i := range c.Certificates {
+ cert := &c.Certificates[i]
+ x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ continue
+ }
+ if len(x509Cert.Subject.CommonName) > 0 {
+ c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+ }
+ for _, san := range x509Cert.DNSNames {
+ c.NameToCertificate[san] = cert
+ }
+ }
+}
+
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
- PrivateKey *rsa.PrivateKey
+ PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey
// OCSPStaple contains an optional OCSP response which will be served
// to clients that request it.
OCSPStaple []byte
+ // Leaf is the parsed form of the leaf certificate, which may be
+ // initialized using x509.ParseCertificate to reduce per-handshake
+ // processing for TLS clients doing client authentication. If nil, the
+ // leaf certificate will be parsed as needed.
+ Leaf *x509.Certificate
}
// A TLS record.
@@ -215,53 +303,19 @@ func defaultConfig() *Config {
return &emptyConfig
}
-// Possible certificate files; stop after finding one.
-// On OS X we should really be using the Directory Services keychain
-// but that requires a lot of Mach goo to get at. Instead we use
-// the same root set that curl uses.
-var certFiles = []string{
- "/etc/ssl/certs/ca-certificates.crt", // Linux etc
- "/usr/share/curl/curl-ca-bundle.crt", // OS X
-}
-
-var once sync.Once
-
-func defaultRoots() *x509.CertPool {
- once.Do(initDefaults)
- return varDefaultRoots
-}
+var (
+ once sync.Once
+ varDefaultCipherSuites []uint16
+)
func defaultCipherSuites() []uint16 {
- once.Do(initDefaults)
+ once.Do(initDefaultCipherSuites)
return varDefaultCipherSuites
}
-func initDefaults() {
- initDefaultRoots()
- initDefaultCipherSuites()
-}
-
-var varDefaultRoots *x509.CertPool
-
-func initDefaultRoots() {
- roots := x509.NewCertPool()
- for _, file := range certFiles {
- data, err := ioutil.ReadFile(file)
- if err == nil {
- roots.AppendCertsFromPEM(data)
- break
- }
- }
- varDefaultRoots = roots
-}
-
-var varDefaultCipherSuites []uint16
-
func initDefaultCipherSuites() {
varDefaultCipherSuites = make([]uint16, len(cipherSuites))
- i := 0
- for id := range cipherSuites {
- varDefaultCipherSuites[i] = id
- i++
+ for i, suite := range cipherSuites {
+ varDefaultCipherSuites[i] = suite.id
}
}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index fac65afd9..2a5115dc6 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -11,11 +11,11 @@ import (
"crypto/cipher"
"crypto/subtle"
"crypto/x509"
- "hash"
+ "errors"
"io"
"net"
- "os"
"sync"
+ "time"
)
// A Conn represents a secured connection.
@@ -37,13 +37,15 @@ type Conn struct {
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
+ // serverName contains the server name indicated by the client, if any.
+ serverName string
clientProtocol string
clientProtocolFallback bool
// first permanent error
errMutex sync.Mutex
- err os.Error
+ err error
// input/output
in, out halfConn // in.Mutex < out.Mutex
@@ -54,7 +56,7 @@ type Conn struct {
tmp [16]byte
}
-func (c *Conn) setError(err os.Error) os.Error {
+func (c *Conn) setError(err error) error {
c.errMutex.Lock()
defer c.errMutex.Unlock()
@@ -64,7 +66,7 @@ func (c *Conn) setError(err os.Error) os.Error {
return err
}
-func (c *Conn) error() os.Error {
+func (c *Conn) error() error {
c.errMutex.Lock()
defer c.errMutex.Unlock()
@@ -85,48 +87,54 @@ func (c *Conn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
-// SetTimeout sets the read deadline associated with the connection.
-// There is no write deadline.
-func (c *Conn) SetTimeout(nsec int64) os.Error {
- return c.conn.SetTimeout(nsec)
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
}
-// SetReadTimeout sets the time (in nanoseconds) that
-// Read will wait for data before returning os.EAGAIN.
-// Setting nsec == 0 (the default) disables the deadline.
-func (c *Conn) SetReadTimeout(nsec int64) os.Error {
- return c.conn.SetReadTimeout(nsec)
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
}
-// SetWriteTimeout exists to satisfy the net.Conn interface
-// but is not implemented by TLS. It always returns an error.
-func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
- return os.NewError("TLS does not support SetWriteTimeout")
+// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return c.conn.SetWriteDeadline(t)
}
// A halfConn represents one direction of the record layer
// connection, either sending or receiving.
type halfConn struct {
sync.Mutex
- cipher interface{} // cipher algorithm
- mac hash.Hash // MAC algorithm
- seq [8]byte // 64-bit sequence number
- bfree *block // list of free blocks
+ version uint16 // protocol version
+ cipher interface{} // cipher algorithm
+ mac macFunction
+ seq [8]byte // 64-bit sequence number
+ bfree *block // list of free blocks
nextCipher interface{} // next encryption state
- nextMac hash.Hash // next MAC algorithm
+ nextMac macFunction // next MAC algorithm
+
+ // used to save allocating a new buffer for each MAC.
+ inDigestBuf, outDigestBuf []byte
}
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
-func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
+ hc.version = version
hc.nextCipher = cipher
hc.nextMac = mac
}
// changeCipherSpec changes the encryption and MAC states
// to the ones previously passed to prepareCipherSpec.
-func (hc *halfConn) changeCipherSpec() os.Error {
+func (hc *halfConn) changeCipherSpec() error {
if hc.nextCipher == nil {
return alertInternalError
}
@@ -197,6 +205,22 @@ func removePadding(payload []byte) ([]byte, byte) {
return payload[:len(payload)-int(toRemove)], good
}
+// removePaddingSSL30 is a replacement for removePadding in the case that the
+// protocol version is SSLv3. In this version, the contents of the padding
+// are random and cannot be checked.
+func removePaddingSSL30(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := int(payload[len(payload)-1]) + 1
+ if paddingLen > len(payload) {
+ return payload, 0
+ }
+
+ return payload[:len(payload)-paddingLen], 255
+}
+
func roundUp(a, b int) int {
return a + (b-a%b)%b
}
@@ -226,7 +250,11 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
}
c.CryptBlocks(payload, payload)
- payload, paddingGood = removePadding(payload)
+ if hc.version == versionSSL30 {
+ payload, paddingGood = removePaddingSSL30(payload)
+ } else {
+ payload, paddingGood = removePadding(payload)
+ }
b.resize(recordHeaderLen + len(payload))
// note that we still have a timing side-channel in the
@@ -256,15 +284,13 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
b.data[4] = byte(n)
b.resize(recordHeaderLen + n)
remoteMAC := payload[n:]
-
- hc.mac.Reset()
- hc.mac.Write(hc.seq[0:])
+ localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data)
hc.incSeq()
- hc.mac.Write(b.data)
- if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
+ if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
return false, alertBadRecordMAC
}
+ hc.inDigestBuf = localMAC
}
return true, 0
@@ -291,14 +317,13 @@ func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
func (hc *halfConn) encrypt(b *block) (bool, alert) {
// mac
if hc.mac != nil {
- hc.mac.Reset()
- hc.mac.Write(hc.seq[0:])
+ mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data)
hc.incSeq()
- hc.mac.Write(b.data)
- mac := hc.mac.Sum()
+
n := len(b.data)
b.resize(n + len(mac))
copy(b.data[n:], mac)
+ hc.outDigestBuf = mac
}
payload := b.data[recordHeaderLen:]
@@ -360,7 +385,7 @@ func (b *block) reserve(n int) {
// readFromUntil reads from r into b until b contains at least n bytes
// or else returns an error.
-func (b *block) readFromUntil(r io.Reader, n int) os.Error {
+func (b *block) readFromUntil(r io.Reader, n int) error {
// quick case
if len(b.data) >= n {
return nil
@@ -381,7 +406,7 @@ func (b *block) readFromUntil(r io.Reader, n int) os.Error {
return nil
}
-func (b *block) Read(p []byte) (n int, err os.Error) {
+func (b *block) Read(p []byte) (n int, err error) {
n = copy(p, b.data[b.off:])
b.off += n
return
@@ -425,7 +450,7 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
// readRecord reads the next TLS record from the connection
// and updates the record layer state.
// c.in.Mutex <= L; c.input == nil.
-func (c *Conn) readRecord(want recordType) os.Error {
+func (c *Conn) readRecord(want recordType) error {
// Caller must be in sync with connection:
// handshake data if handshake not yet completed,
// else application data. (We don't support renegotiation.)
@@ -453,7 +478,7 @@ Again:
// RFC suggests that EOF without an alertCloseNotify is
// an error, but popular web sites seem to do this,
// so we can't make it an error.
- // if err == os.EOF {
+ // if err == io.EOF {
// err = io.ErrUnexpectedEOF
// }
if e, ok := err.(net.Error); !ok || !e.Temporary() {
@@ -470,8 +495,21 @@ Again:
if n > maxCiphertext {
return c.sendAlert(alertRecordOverflow)
}
+ if !c.haveVers {
+ // First message, be extra suspicious:
+ // this might not be a TLS client.
+ // Bail out before reading a full 'body', if possible.
+ // The current max version is 3.1.
+ // If the version is >= 16.0, it's probably not real.
+ // Similarly, a clientHello message encodes in
+ // well under a kilobyte. If the length is >= 12 kB,
+ // it's probably not real.
+ if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ }
if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
if e, ok := err.(net.Error); !ok || !e.Temporary() {
@@ -503,7 +541,7 @@ Again:
break
}
if alert(data[1]) == alertCloseNotify {
- c.setError(os.EOF)
+ c.setError(io.EOF)
break
}
switch data[0] {
@@ -512,7 +550,7 @@ Again:
c.in.freeBlock(b)
goto Again
case alertLevelError:
- c.setError(&net.OpError{Op: "remote error", Error: alert(data[1])})
+ c.setError(&net.OpError{Op: "remote error", Err: alert(data[1])})
default:
c.sendAlert(alertUnexpectedMessage)
}
@@ -551,7 +589,7 @@ Again:
// sendAlert sends a TLS alert message.
// c.out.Mutex <= L.
-func (c *Conn) sendAlertLocked(err alert) os.Error {
+func (c *Conn) sendAlertLocked(err alert) error {
c.tmp[0] = alertLevelError
if err == alertNoRenegotiation {
c.tmp[0] = alertLevelWarning
@@ -560,14 +598,14 @@ func (c *Conn) sendAlertLocked(err alert) os.Error {
c.writeRecord(recordTypeAlert, c.tmp[0:2])
// closeNotify is a special case in that it isn't an error:
if err != alertCloseNotify {
- return c.setError(&net.OpError{Op: "local error", Error: err})
+ return c.setError(&net.OpError{Op: "local error", Err: err})
}
return nil
}
// sendAlert sends a TLS alert message.
// L < c.out.Mutex.
-func (c *Conn) sendAlert(err alert) os.Error {
+func (c *Conn) sendAlert(err alert) error {
c.out.Lock()
defer c.out.Unlock()
return c.sendAlertLocked(err)
@@ -576,7 +614,7 @@ func (c *Conn) sendAlert(err alert) os.Error {
// writeRecord writes a TLS record with the given type and payload
// to the connection and updates the record layer state.
// c.out.Mutex <= L.
-func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
+func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
b := c.out.newBlock()
for len(data) > 0 {
m := len(data)
@@ -612,7 +650,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
c.tmp[0] = alertLevelError
c.tmp[1] = byte(err.(alert))
c.writeRecord(recordTypeAlert, c.tmp[0:2])
- c.err = &net.OpError{Op: "local error", Error: err}
+ c.err = &net.OpError{Op: "local error", Err: err}
return n, c.err
}
}
@@ -622,12 +660,14 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err os.Error) {
// readHandshake reads the next handshake message from
// the record layer.
// c.in.Mutex < L; c.out.Mutex < L.
-func (c *Conn) readHandshake() (interface{}, os.Error) {
+func (c *Conn) readHandshake() (interface{}, error) {
for c.hand.Len() < 4 {
if c.err != nil {
return nil, c.err
}
- c.readRecord(recordTypeHandshake)
+ if err := c.readRecord(recordTypeHandshake); err != nil {
+ return nil, err
+ }
}
data := c.hand.Bytes()
@@ -640,7 +680,9 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
if c.err != nil {
return nil, c.err
}
- c.readRecord(recordTypeHandshake)
+ if err := c.readRecord(recordTypeHandshake); err != nil {
+ return nil, err
+ }
}
data = c.hand.Next(4 + n)
var m handshakeMessage
@@ -685,9 +727,13 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
}
// Write writes data to the connection.
-func (c *Conn) Write(b []byte) (n int, err os.Error) {
- if err = c.Handshake(); err != nil {
- return
+func (c *Conn) Write(b []byte) (int, error) {
+ if c.err != nil {
+ return 0, c.err
+ }
+
+ if c.err = c.Handshake(); c.err != nil {
+ return 0, c.err
}
c.out.Lock()
@@ -696,15 +742,15 @@ func (c *Conn) Write(b []byte) (n int, err os.Error) {
if !c.handshakeComplete {
return 0, alertInternalError
}
- if c.err != nil {
- return 0, c.err
- }
- return c.writeRecord(recordTypeApplicationData, b)
+
+ var n int
+ n, c.err = c.writeRecord(recordTypeApplicationData, b)
+ return n, c.err
}
-// Read can be made to time out and return err == os.EAGAIN
-// after a fixed time limit; see SetTimeout and SetReadTimeout.
-func (c *Conn) Read(b []byte) (n int, err os.Error) {
+// Read can be made to time out and return a net.Error with Timeout() == true
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
return
}
@@ -730,18 +776,26 @@ func (c *Conn) Read(b []byte) (n int, err os.Error) {
}
// Close closes the connection.
-func (c *Conn) Close() os.Error {
- if err := c.Handshake(); err != nil {
+func (c *Conn) Close() error {
+ var alertErr error
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if c.handshakeComplete {
+ alertErr = c.sendAlert(alertCloseNotify)
+ }
+
+ if err := c.conn.Close(); err != nil {
return err
}
- return c.sendAlert(alertCloseNotify)
+ return alertErr
}
// Handshake runs the client or server handshake
// protocol if it has not yet been run.
// Most uses of this package need not call Handshake
// explicitly: the first Read or Write will call it automatically.
-func (c *Conn) Handshake() os.Error {
+func (c *Conn) Handshake() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if err := c.error(); err != nil {
@@ -769,6 +823,7 @@ func (c *Conn) ConnectionState() ConnectionState {
state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates
state.VerifiedChains = c.verifiedChains
+ state.ServerName = c.serverName
}
return state
@@ -784,16 +839,16 @@ func (c *Conn) OCSPResponse() []byte {
}
// VerifyHostname checks that the peer certificate chain is valid for
-// connecting to host. If so, it returns nil; if not, it returns an os.Error
+// connecting to host. If so, it returns nil; if not, it returns an error
// describing the problem.
-func (c *Conn) VerifyHostname(host string) os.Error {
+func (c *Conn) VerifyHostname(host string) error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return os.NewError("VerifyHostname called on TLS server connection")
+ return errors.New("VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return os.NewError("TLS handshake has not yet been performed")
+ return errors.New("TLS handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/src/pkg/crypto/tls/conn_test.go b/src/pkg/crypto/tls/conn_test.go
index f44a50bed..5c555147c 100644
--- a/src/pkg/crypto/tls/conn_test.go
+++ b/src/pkg/crypto/tls/conn_test.go
@@ -50,3 +50,57 @@ func TestRemovePadding(t *testing.T) {
}
}
}
+
+var certExampleCom = `308201403081eda003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313138353835325a170d3132303933303138353835325a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31a301830160603551d11040f300d820b6578616d706c652e636f6d300b06092a864886f70d0101050341001a0b419d2c74474c6450654e5f10b32bf426ffdf55cad1c52602e7a9151513a3424c70f5960dcd682db0c33769cc1daa3fcdd3db10809d2392ed4a1bf50ced18`
+
+var certWildcardExampleCom = `308201423081efa003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303034365a170d3132303933303139303034365a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31c301a30180603551d110411300f820d2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001676f0c9e7c33c1b656ed5a6476c4e2ee9ec8e62df7407accb1875272b2edd0a22096cb2c22598d11604104d604f810eb4b5987ca6bb319c7e6ce48725c54059`
+
+var certFooExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303131345a170d3132303933303139303131345a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f666f6f2e6578616d706c652e636f6d300b06092a864886f70d010105034100646a2a51f2aa2477add854b462cf5207ba16d3213ffb5d3d0eed473fbf09935019192d1d5b8ca6a2407b424cf04d97c4cd9197c83ecf81f0eab9464a1109d09f`
+
+var certDoubleWildcardExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303134315a170d3132303933303139303134315a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f2a2e2a2e6578616d706c652e636f6d300b06092a864886f70d0101050341001c3de267975f56ef57771c6218ef95ecc65102e57bd1defe6f7efea90d9b26cf40de5bd7ad75e46201c7f2a92aaa3e907451e9409f65e28ddb6db80d726290f6`
+
+func TestCertificateSelection(t *testing.T) {
+ config := Config{
+ Certificates: []Certificate{
+ {
+ Certificate: [][]byte{fromHex(certExampleCom)},
+ },
+ {
+ Certificate: [][]byte{fromHex(certWildcardExampleCom)},
+ },
+ {
+ Certificate: [][]byte{fromHex(certFooExampleCom)},
+ },
+ {
+ Certificate: [][]byte{fromHex(certDoubleWildcardExampleCom)},
+ },
+ },
+ }
+
+ config.BuildNameToCertificate()
+
+ pointerToIndex := func(c *Certificate) int {
+ for i := range config.Certificates {
+ if c == &config.Certificates[i] {
+ return i
+ }
+ }
+ return -1
+ }
+
+ if n := pointerToIndex(config.getCertificateForName("example.com")); n != 0 {
+ t.Errorf("example.com returned certificate %d, not 0", n)
+ }
+ if n := pointerToIndex(config.getCertificateForName("bar.example.com")); n != 1 {
+ t.Errorf("bar.example.com returned certificate %d, not 1", n)
+ }
+ if n := pointerToIndex(config.getCertificateForName("foo.example.com")); n != 2 {
+ t.Errorf("foo.example.com returned certificate %d, not 2", n)
+ }
+ if n := pointerToIndex(config.getCertificateForName("foo.bar.example.com")); n != 3 {
+ t.Errorf("foo.bar.example.com returned certificate %d, not 3", n)
+ }
+ if n := pointerToIndex(config.getCertificateForName("foo.bar.baz.example.com")); n != 0 {
+ t.Errorf("foo.bar.baz.example.com returned certificate %d, not 0", n)
+ }
+}
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
index 41206e276..84be5bfd8 100644
--- a/src/pkg/crypto/tls/generate_cert.go
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -2,20 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
// Generate a self-signed X.509 certificate for a TLS server. Outputs to
// 'cert.pem' and 'key.pem' and will overwrite existing files.
package main
import (
- "big"
- "crypto/x509/pkix"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
+ "crypto/x509/pkix"
"encoding/pem"
"flag"
"log"
+ "math/big"
"os"
"time"
)
@@ -31,7 +33,7 @@ func main() {
return
}
- now := time.Seconds()
+ now := time.Now()
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0),
@@ -39,8 +41,8 @@ func main() {
CommonName: *hostName,
Organization: []string{"Acme Co"},
},
- NotBefore: time.SecondsToUTC(now - 300),
- NotAfter: time.SecondsToUTC(now + 60*60*24*365), // valid for 1 year.
+ NotBefore: now.Add(-5 * time.Minute).UTC(),
+ NotAfter: now.AddDate(1, 0, 0).UTC(), // valid for 1 year.
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 15604cea7..2877f1738 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -5,16 +5,18 @@
package tls
import (
+ "bytes"
"crypto"
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
+ "errors"
"io"
- "os"
+ "strconv"
)
-func (c *Conn) clientHandshake() os.Error {
- finishedHash := newFinishedHash()
+func (c *Conn) clientHandshake() error {
+ finishedHash := newFinishedHash(versionTLS10)
if c.config == nil {
c.config = defaultConfig()
@@ -32,7 +34,7 @@ func (c *Conn) clientHandshake() os.Error {
nextProtoNeg: len(c.config.NextProtos) > 0,
}
- t := uint32(c.config.time())
+ t := uint32(c.config.time().Unix())
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
hello.random[2] = byte(t >> 8)
@@ -40,7 +42,7 @@ func (c *Conn) clientHandshake() os.Error {
_, err := io.ReadFull(c.config.rand(), hello.random[4:])
if err != nil {
c.sendAlert(alertInternalError)
- return os.NewError("short read from Rand")
+ return errors.New("short read from Rand")
}
finishedHash.Write(hello.marshal())
@@ -57,7 +59,8 @@ func (c *Conn) clientHandshake() os.Error {
finishedHash.Write(serverHello.marshal())
vers, ok := mutualVersion(serverHello.vers)
- if !ok {
+ if !ok || vers < versionTLS10 {
+ // TLS 1.0 is the minimum version supported as a client.
return c.sendAlert(alertProtocolVersion)
}
c.vers = vers
@@ -69,10 +72,10 @@ func (c *Conn) clientHandshake() os.Error {
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
c.sendAlert(alertHandshakeFailure)
- return os.NewError("server advertised unrequested NPN")
+ return errors.New("server advertised unrequested NPN")
}
- suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
if suite == nil {
return c.sendAlert(alertHandshakeFailure)
}
@@ -92,14 +95,12 @@ func (c *Conn) clientHandshake() os.Error {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.NewError("failed to parse certificate from server: " + err.String())
+ return errors.New("failed to parse certificate from server: " + err.Error())
}
certs[i] = cert
}
- // If we don't have a root CA set configured then anything is accepted.
- // TODO(rsc): Find certificates for OS X 10.6.
- if c.config.RootCAs != nil {
+ if !c.config.InsecureSkipVerify {
opts := x509.VerifyOptions{
Roots: c.config.RootCAs,
CurrentTime: c.config.time(),
@@ -164,10 +165,26 @@ func (c *Conn) clientHandshake() os.Error {
}
}
- transmitCert := false
+ var certToSend *Certificate
+ var certRequested bool
certReq, ok := msg.(*certificateRequestMsg)
if ok {
- // We only accept certificates with RSA keys.
+ certRequested = true
+
+ // RFC 4346 on the certificateAuthorities field:
+ // A list of the distinguished names of acceptable certificate
+ // authorities. These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA;
+ // thus, this message can be used to describe both known roots
+ // and a desired authorization space. If the
+ // certificate_authorities list is empty then the client MAY
+ // send any certificate of the appropriate
+ // ClientCertificateType, unless there is some external
+ // arrangement to the contrary.
+
+ finishedHash.Write(certReq.marshal())
+
+ // For now, we only know how to sign challenges with RSA
rsaAvail := false
for _, certType := range certReq.certificateTypes {
if certType == certTypeRSASign {
@@ -176,23 +193,41 @@ func (c *Conn) clientHandshake() os.Error {
}
}
- // For now, only send a certificate back if the server gives us an
- // empty list of certificateAuthorities.
- //
- // RFC 4346 on the certificateAuthorities field:
- // A list of the distinguished names of acceptable certificate
- // authorities. These distinguished names may specify a desired
- // distinguished name for a root CA or for a subordinate CA; thus,
- // this message can be used to describe both known roots and a
- // desired authorization space. If the certificate_authorities
- // list is empty then the client MAY send any certificate of the
- // appropriate ClientCertificateType, unless there is some
- // external arrangement to the contrary.
- if rsaAvail && len(certReq.certificateAuthorities) == 0 {
- transmitCert = true
- }
+ // We need to search our list of client certs for one
+ // where SignatureAlgorithm is RSA and the Issuer is in
+ // certReq.certificateAuthorities
+ findCert:
+ for i, cert := range c.config.Certificates {
+ if !rsaAvail {
+ continue
+ }
- finishedHash.Write(certReq.marshal())
+ leaf := cert.Leaf
+ if leaf == nil {
+ if leaf, err = x509.ParseCertificate(cert.Certificate[0]); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+ }
+ }
+
+ if leaf.PublicKeyAlgorithm != x509.RSA {
+ continue
+ }
+
+ if len(certReq.certificateAuthorities) == 0 {
+ // they gave us an empty list, so just take the
+ // first RSA cert from c.config.Certificates
+ certToSend = &cert
+ break
+ }
+
+ for _, ca := range certReq.certificateAuthorities {
+ if bytes.Equal(leaf.RawIssuer, ca) {
+ certToSend = &cert
+ break findCert
+ }
+ }
+ }
msg, err = c.readHandshake()
if err != nil {
@@ -206,16 +241,13 @@ func (c *Conn) clientHandshake() os.Error {
}
finishedHash.Write(shd.marshal())
- var cert *x509.Certificate
- if transmitCert {
+ // If the server requested a certificate then we have to send a
+ // Certificate message, even if it's empty because we don't have a
+ // certificate to send.
+ if certRequested {
certMsg = new(certificateMsg)
- if len(c.config.Certificates) > 0 {
- cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0])
- if err == nil && cert.PublicKeyAlgorithm == x509.RSA {
- certMsg.certificates = c.config.Certificates[0].Certificate
- } else {
- cert = nil
- }
+ if certToSend != nil {
+ certMsg.certificates = certToSend.Certificate
}
finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -231,12 +263,12 @@ func (c *Conn) clientHandshake() os.Error {
c.writeRecord(recordTypeHandshake, ckx.marshal())
}
- if cert != nil {
+ if certToSend != nil {
certVerify := new(certificateVerifyMsg)
- var digest [36]byte
- copy(digest[0:16], finishedHash.serverMD5.Sum())
- copy(digest[16:36], finishedHash.serverSHA1.Sum())
- signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:])
+ digest := make([]byte, 0, 36)
+ digest = finishedHash.serverMD5.Sum(digest)
+ digest = finishedHash.serverSHA1.Sum(digest)
+ signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, digest)
if err != nil {
return c.sendAlert(alertInternalError)
}
@@ -247,11 +279,11 @@ func (c *Conn) clientHandshake() os.Error {
}
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
- keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+ keysFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
- clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
- clientHash := suite.mac(clientMAC)
- c.out.prepareCipherSpec(clientCipher, clientHash)
+ clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash := suite.mac(c.vers, clientMAC)
+ c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
if serverHello.nextProtoNeg {
@@ -270,9 +302,9 @@ func (c *Conn) clientHandshake() os.Error {
finishedHash.Write(finished.marshal())
c.writeRecord(recordTypeHandshake, finished.marshal())
- serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
- serverHash := suite.mac(serverMAC)
- c.in.prepareCipherSpec(serverCipher, serverHash)
+ serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash := suite.mac(c.vers, serverMAC)
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.readRecord(recordTypeChangeCipherSpec)
if c.err != nil {
return c.err
@@ -294,7 +326,7 @@ func (c *Conn) clientHandshake() os.Error {
}
c.handshakeComplete = true
- c.cipherSuite = suiteId
+ c.cipherSuite = suite.id
return nil
}
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 3f91c7acf..8c56daaf6 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -18,6 +18,7 @@ func testClientScript(t *testing.T, name string, clientScript [][]byte, config *
go func() {
cli.Write([]byte("hello\n"))
cli.Close()
+ c.Close()
}()
defer c.Close()
@@ -61,7 +62,7 @@ func TestRunClient(t *testing.T) {
// Script of interaction with gnutls implementation.
// The values for this test are obtained by building and running in client mode:
-// % gotest -test.run "TestRunClient" -connect
+// % go test -run "TestRunClient" -connect
// and then:
// % gnutls-serv -p 10443 --debug 100 --x509keyfile key.pem --x509certfile cert.pem -a > /tmp/log 2>&1
// % python parse-gnutls-cli-debug-log.py < /tmp/log
diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go
index 6645adce4..e1517cc79 100644
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -4,6 +4,8 @@
package tls
+import "bytes"
+
type clientHelloMsg struct {
raw []byte
vers uint16
@@ -18,6 +20,25 @@ type clientHelloMsg struct {
supportedPoints []uint8
}
+func (m *clientHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*clientHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.vers == m1.vers &&
+ bytes.Equal(m.random, m1.random) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+ bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
+ m.nextProtoNeg == m1.nextProtoNeg &&
+ m.serverName == m1.serverName &&
+ m.ocspStapling == m1.ocspStapling &&
+ eqUint16s(m.supportedCurves, m1.supportedCurves) &&
+ bytes.Equal(m.supportedPoints, m1.supportedPoints)
+}
+
func (m *clientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -309,6 +330,23 @@ type serverHelloMsg struct {
ocspStapling bool
}
+func (m *serverHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*serverHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.vers == m1.vers &&
+ bytes.Equal(m.random, m1.random) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ m.cipherSuite == m1.cipherSuite &&
+ m.compressionMethod == m1.compressionMethod &&
+ m.nextProtoNeg == m1.nextProtoNeg &&
+ eqStrings(m.nextProtos, m1.nextProtos) &&
+ m.ocspStapling == m1.ocspStapling
+}
+
func (m *serverHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -463,6 +501,16 @@ type certificateMsg struct {
certificates [][]byte
}
+func (m *certificateMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ eqByteSlices(m.certificates, m1.certificates)
+}
+
func (m *certificateMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -540,6 +588,16 @@ type serverKeyExchangeMsg struct {
key []byte
}
+func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
+ m1, ok := i.(*serverKeyExchangeMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.key, m1.key)
+}
+
func (m *serverKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -571,6 +629,17 @@ type certificateStatusMsg struct {
response []byte
}
+func (m *certificateStatusMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateStatusMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.statusType == m1.statusType &&
+ bytes.Equal(m.response, m1.response)
+}
+
func (m *certificateStatusMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -622,6 +691,11 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool {
type serverHelloDoneMsg struct{}
+func (m *serverHelloDoneMsg) equal(i interface{}) bool {
+ _, ok := i.(*serverHelloDoneMsg)
+ return ok
+}
+
func (m *serverHelloDoneMsg) marshal() []byte {
x := make([]byte, 4)
x[0] = typeServerHelloDone
@@ -637,6 +711,16 @@ type clientKeyExchangeMsg struct {
ciphertext []byte
}
+func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
+ m1, ok := i.(*clientKeyExchangeMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.ciphertext, m1.ciphertext)
+}
+
func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -671,14 +755,24 @@ type finishedMsg struct {
verifyData []byte
}
+func (m *finishedMsg) equal(i interface{}) bool {
+ m1, ok := i.(*finishedMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.verifyData, m1.verifyData)
+}
+
func (m *finishedMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
}
- x = make([]byte, 16)
+ x = make([]byte, 4+len(m.verifyData))
x[0] = typeFinished
- x[3] = 12
+ x[3] = byte(len(m.verifyData))
copy(x[4:], m.verifyData)
m.raw = x
return
@@ -686,7 +780,7 @@ func (m *finishedMsg) marshal() (x []byte) {
func (m *finishedMsg) unmarshal(data []byte) bool {
m.raw = data
- if len(data) != 4+12 {
+ if len(data) < 4 {
return false
}
m.verifyData = data[4:]
@@ -698,6 +792,16 @@ type nextProtoMsg struct {
proto string
}
+func (m *nextProtoMsg) equal(i interface{}) bool {
+ m1, ok := i.(*nextProtoMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.proto == m1.proto
+}
+
func (m *nextProtoMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -759,6 +863,17 @@ type certificateRequestMsg struct {
certificateAuthorities [][]byte
}
+func (m *certificateRequestMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateRequestMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
+ eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities)
+}
+
func (m *certificateRequestMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -766,9 +881,11 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
// See http://tools.ietf.org/html/rfc4346#section-7.4.4
length := 1 + len(m.certificateTypes) + 2
+ casLength := 0
for _, ca := range m.certificateAuthorities {
- length += 2 + len(ca)
+ casLength += 2 + len(ca)
}
+ length += casLength
x = make([]byte, 4+length)
x[0] = typeCertificateRequest
@@ -780,10 +897,8 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
copy(x[5:], m.certificateTypes)
y := x[5+len(m.certificateTypes):]
-
- numCA := len(m.certificateAuthorities)
- y[0] = uint8(numCA >> 8)
- y[1] = uint8(numCA)
+ y[0] = uint8(casLength >> 8)
+ y[1] = uint8(casLength)
y = y[2:]
for _, ca := range m.certificateAuthorities {
y[0] = uint8(len(ca) >> 8)
@@ -794,7 +909,6 @@ func (m *certificateRequestMsg) marshal() (x []byte) {
}
m.raw = x
-
return
}
@@ -822,31 +936,34 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
}
data = data[numCertTypes:]
+
if len(data) < 2 {
return false
}
-
- numCAs := uint16(data[0])<<16 | uint16(data[1])
+ casLength := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
+ if len(data) < int(casLength) {
+ return false
+ }
+ cas := make([]byte, casLength)
+ copy(cas, data)
+ data = data[casLength:]
- m.certificateAuthorities = make([][]byte, numCAs)
- for i := uint16(0); i < numCAs; i++ {
- if len(data) < 2 {
+ m.certificateAuthorities = nil
+ for len(cas) > 0 {
+ if len(cas) < 2 {
return false
}
- caLen := uint16(data[0])<<16 | uint16(data[1])
+ caLen := uint16(cas[0])<<8 | uint16(cas[1])
+ cas = cas[2:]
- data = data[2:]
- if len(data) < int(caLen) {
+ if len(cas) < int(caLen) {
return false
}
- ca := make([]byte, caLen)
- copy(ca, data)
- m.certificateAuthorities[i] = ca
- data = data[caLen:]
+ m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+ cas = cas[caLen:]
}
-
if len(data) > 0 {
return false
}
@@ -859,6 +976,16 @@ type certificateVerifyMsg struct {
signature []byte
}
+func (m *certificateVerifyMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateVerifyMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.signature, m1.signature)
+}
+
func (m *certificateVerifyMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -902,3 +1029,39 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
return true
}
+
+func eqUint16s(x, y []uint16) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqStrings(x, y []string) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqByteSlices(x, y [][]byte) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if !bytes.Equal(v, y[i]) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
index 23f729dd9..e62a9d581 100644
--- a/src/pkg/crypto/tls/handshake_messages_test.go
+++ b/src/pkg/crypto/tls/handshake_messages_test.go
@@ -5,7 +5,7 @@
package tls
import (
- "rand"
+ "math/rand"
"reflect"
"testing"
"testing/quick"
@@ -14,23 +14,25 @@ import (
var tests = []interface{}{
&clientHelloMsg{},
&serverHelloMsg{},
+ &finishedMsg{},
&certificateMsg{},
&certificateRequestMsg{},
&certificateVerifyMsg{},
&certificateStatusMsg{},
&clientKeyExchangeMsg{},
- &finishedMsg{},
&nextProtoMsg{},
}
type testMessage interface {
marshal() []byte
unmarshal([]byte) bool
+ equal(interface{}) bool
}
func TestMarshalUnmarshal(t *testing.T) {
rand := rand.New(rand.NewSource(0))
+
for i, iface := range tests {
ty := reflect.ValueOf(iface).Type()
@@ -54,16 +56,17 @@ func TestMarshalUnmarshal(t *testing.T) {
}
m2.marshal() // to fill any marshal cache in the message
- if !reflect.DeepEqual(m1, m2) {
+ if !m1.equal(m2) {
t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
break
}
- if i >= 2 {
- // The first two message types (ClientHello and
- // ServerHello) are allowed to have parsable
- // prefixes because the extension data is
- // optional.
+ if i >= 3 {
+ // The first three message types (ClientHello,
+ // ServerHello and Finished) are allowed to
+ // have parsable prefixes because the extension
+ // data is optional and the length of the
+ // Finished varies across versions.
for j := 0; j < len(marshaled); j++ {
if m2.unmarshal(marshaled[0:j]) {
t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 44a324041..77e56a754 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -9,11 +9,11 @@ import (
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
+ "errors"
"io"
- "os"
)
-func (c *Conn) serverHandshake() os.Error {
+func (c *Conn) serverHandshake() error {
config := c.config
msg, err := c.readHandshake()
if err != nil {
@@ -30,7 +30,7 @@ func (c *Conn) serverHandshake() os.Error {
c.vers = vers
c.haveVers = true
- finishedHash := newFinishedHash()
+ finishedHash := newFinishedHash(vers)
finishedHash.Write(clientHello.marshal())
hello := new(serverHelloMsg)
@@ -56,18 +56,27 @@ Curves:
ellipticOk := supportedCurve && supportedPointFormat
var suite *cipherSuite
- var suiteId uint16
FindCipherSuite:
for _, id := range clientHello.cipherSuites {
for _, supported := range config.cipherSuites() {
if id == supported {
- suite = cipherSuites[id]
+ var candidate *cipherSuite
+
+ for _, s := range cipherSuites {
+ if s.id == id {
+ candidate = s
+ break
+ }
+ }
+ if candidate == nil {
+ continue
+ }
// Don't select a ciphersuite which we can't
// support for this client.
- if suite.elliptic && !ellipticOk {
+ if candidate.elliptic && !ellipticOk {
continue
}
- suiteId = id
+ suite = candidate
break FindCipherSuite
}
}
@@ -87,8 +96,8 @@ FindCipherSuite:
}
hello.vers = vers
- hello.cipherSuite = suiteId
- t := uint32(config.time())
+ hello.cipherSuite = suite.id
+ t := uint32(config.time().Unix())
hello.random = make([]byte, 32)
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
@@ -115,7 +124,12 @@ FindCipherSuite:
}
certMsg := new(certificateMsg)
- certMsg.certificates = config.Certificates[0].Certificate
+ if len(clientHello.serverName) > 0 {
+ c.serverName = clientHello.serverName
+ certMsg.certificates = config.getCertificateForName(clientHello.serverName).Certificate
+ } else {
+ certMsg.certificates = config.Certificates[0].Certificate
+ }
finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -128,7 +142,6 @@ FindCipherSuite:
}
keyAgreement := suite.ka()
-
skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
@@ -139,14 +152,19 @@ FindCipherSuite:
c.writeRecord(recordTypeHandshake, skx.marshal())
}
- if config.AuthenticateClient {
+ if config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := new(certificateRequestMsg)
certReq.certificateTypes = []byte{certTypeRSASign}
+
// An empty list of certificateAuthorities signals to
// the client that it may send any certificate in response
- // to our request.
-
+ // to our request. When we know the CAs we trust, then
+ // we can send them down, so that the client can choose
+ // an appropriate certificate to give to us.
+ if config.ClientCAs != nil {
+ certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ }
finishedHash.Write(certReq.marshal())
c.writeRecord(recordTypeHandshake, certReq.marshal())
}
@@ -155,52 +173,87 @@ FindCipherSuite:
finishedHash.Write(helloDone.marshal())
c.writeRecord(recordTypeHandshake, helloDone.marshal())
- var pub *rsa.PublicKey
- if config.AuthenticateClient {
- // Get client certificate
- msg, err = c.readHandshake()
- if err != nil {
- return err
- }
- certMsg, ok = msg.(*certificateMsg)
- if !ok {
- return c.sendAlert(alertUnexpectedMessage)
+ var pub *rsa.PublicKey // public key for client auth, if any
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message, even if it's empty.
+ if config.ClientAuth >= RequestClientCert {
+ if certMsg, ok = msg.(*certificateMsg); !ok {
+ return c.sendAlert(alertHandshakeFailure)
}
finishedHash.Write(certMsg.marshal())
+ if len(certMsg.certificates) == 0 {
+ // The client didn't actually send a certificate
+ switch config.ClientAuth {
+ case RequireAnyClientCert, RequireAndVerifyClientCert:
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: client didn't provide a certificate")
+ }
+ }
+
certs := make([]*x509.Certificate, len(certMsg.certificates))
for i, asn1Data := range certMsg.certificates {
- cert, err := x509.ParseCertificate(asn1Data)
- if err != nil {
+ if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
c.sendAlert(alertBadCertificate)
- return os.NewError("could not parse client's certificate: " + err.String())
+ return errors.New("tls: failed to parse client certificate: " + err.Error())
}
- certs[i] = cert
}
- // TODO(agl): do better validation of certs: max path length, name restrictions etc.
- for i := 1; i < len(certs); i++ {
- if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
+ if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+ opts := x509.VerifyOptions{
+ Roots: c.config.ClientCAs,
+ CurrentTime: c.config.time(),
+ Intermediates: x509.NewCertPool(),
+ }
+
+ for i, cert := range certs {
+ if i == 0 {
+ continue
+ }
+ opts.Intermediates.AddCert(cert)
+ }
+
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
c.sendAlert(alertBadCertificate)
- return os.NewError("could not validate certificate signature: " + err.String())
+ return errors.New("tls: failed to verify client's certificate: " + err.Error())
+ }
+
+ ok := false
+ for _, ku := range certs[0].ExtKeyUsage {
+ if ku == x509.ExtKeyUsageClientAuth {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
}
+
+ c.verifiedChains = chains
}
if len(certs) > 0 {
- key, ok := certs[0].PublicKey.(*rsa.PublicKey)
- if !ok {
+ if pub, ok = certs[0].PublicKey.(*rsa.PublicKey); !ok {
return c.sendAlert(alertUnsupportedCertificate)
}
- pub = key
c.peerCertificates = certs
}
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
}
// Get client key exchange
- msg, err = c.readHandshake()
- if err != nil {
- return err
- }
ckx, ok := msg.(*clientKeyExchangeMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
@@ -223,30 +276,30 @@ FindCipherSuite:
return c.sendAlert(alertUnexpectedMessage)
}
- digest := make([]byte, 36)
- copy(digest[0:16], finishedHash.serverMD5.Sum())
- copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ digest := make([]byte, 0, 36)
+ digest = finishedHash.serverMD5.Sum(digest)
+ digest = finishedHash.serverSHA1.Sum(digest)
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.NewError("could not validate signature of connection nonces: " + err.String())
+ return errors.New("could not validate signature of connection nonces: " + err.Error())
}
finishedHash.Write(certVerify.marshal())
}
- preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx, c.vers)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
- keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
+ keysFromPreMasterSecret(c.vers, preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
- clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
- clientHash := suite.mac(clientMAC)
- c.in.prepareCipherSpec(clientCipher, clientHash)
+ clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash := suite.mac(c.vers, clientMAC)
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.readRecord(recordTypeChangeCipherSpec)
if err := c.error(); err != nil {
return err
@@ -282,9 +335,9 @@ FindCipherSuite:
finishedHash.Write(clientFinished.marshal())
- serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
- serverHash := suite.mac(serverMAC)
- c.out.prepareCipherSpec(serverCipher, serverHash)
+ serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash := suite.mac(c.vers, serverMAC)
+ c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
finished := new(finishedMsg)
@@ -292,7 +345,7 @@ FindCipherSuite:
c.writeRecord(recordTypeHandshake, finished.marshal())
c.handshakeComplete = true
- c.cipherSuite = suiteId
+ c.cipherSuite = suite.id
return nil
}
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index b77646e43..08a0ccb09 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -5,20 +5,25 @@
package tls
import (
- "big"
"bytes"
"crypto/rsa"
+ "crypto/x509"
"encoding/hex"
+ "encoding/pem"
"flag"
"io"
+ "log"
+ "math/big"
"net"
- "os"
+ "strconv"
+ "strings"
"testing"
+ "time"
)
type zeroSource struct{}
-func (zeroSource) Read(b []byte) (n int, err os.Error) {
+func (zeroSource) Read(b []byte) (n int, err error) {
for i := range b {
b[i] = 0
}
@@ -30,15 +35,16 @@ var testConfig *Config
func init() {
testConfig = new(Config)
- testConfig.Time = func() int64 { return 0 }
+ testConfig.Time = func() time.Time { return time.Unix(0, 0) }
testConfig.Rand = zeroSource{}
testConfig.Certificates = make([]Certificate, 1)
testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
testConfig.Certificates[0].PrivateKey = testPrivateKey
testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+ testConfig.InsecureSkipVerify = true
}
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
// Create in-memory network connection,
// send message to server. Should return
// expected error.
@@ -53,7 +59,7 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error)
}()
err := Server(s, testConfig).Handshake()
s.Close()
- if e, ok := err.(*net.OpError); !ok || e.Error != expected {
+ if e, ok := err.(*net.OpError); !ok || e.Err != expected {
t.Errorf("Got error: %s; expected: %s", err, expected)
}
}
@@ -62,7 +68,7 @@ func TestSimpleError(t *testing.T) {
testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
}
-var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, 0x0300}
+var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
func TestRejectBadProtocolVersion(t *testing.T) {
for _, v := range badProtocolVersions {
@@ -90,7 +96,7 @@ func TestAlertForwarding(t *testing.T) {
err := Server(s, testConfig).Handshake()
s.Close()
- if e, ok := err.(*net.OpError); !ok || e.Error != os.Error(alertUnknownCA) {
+ if e, ok := err.(*net.OpError); !ok || e.Err != error(alertUnknownCA) {
t.Errorf("Got error: %s; expected: %s", err, alertUnknownCA)
}
}
@@ -101,54 +107,115 @@ func TestClose(t *testing.T) {
err := Server(s, testConfig).Handshake()
s.Close()
- if err != os.EOF {
- t.Errorf("Got error: %s; expected: %s", err, os.EOF)
+ if err != io.EOF {
+ t.Errorf("Got error: %s; expected: %s", err, io.EOF)
}
}
-func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
+func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config, peers []*x509.Certificate) {
c, s := net.Pipe()
srv := Server(s, config)
+ pchan := make(chan []*x509.Certificate, 1)
go func() {
srv.Write([]byte("hello, world\n"))
srv.Close()
+ s.Close()
+ st := srv.ConnectionState()
+ pchan <- st.PeerCertificates
}()
- defer c.Close()
for i, b := range serverScript {
if i%2 == 0 {
c.Write(b)
continue
}
bb := make([]byte, len(b))
- _, err := io.ReadFull(c, bb)
+ n, err := io.ReadFull(c, bb)
if err != nil {
- t.Fatalf("%s #%d: %s", name, i, err)
+ t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", name, i, err, n, len(bb), bb[:n], b)
}
if !bytes.Equal(b, bb) {
t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
}
}
+ c.Close()
+
+ if peers != nil {
+ gotpeers := <-pchan
+ if len(peers) == len(gotpeers) {
+ for i := range peers {
+ if !peers[i].Equal(gotpeers[i]) {
+ t.Fatalf("%s: mismatch on peer cert %d", name, i)
+ }
+ }
+ } else {
+ t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", name, len(peers), len(gotpeers))
+ }
+ }
}
func TestHandshakeServerRC4(t *testing.T) {
- testServerScript(t, "RC4", rc4ServerScript, testConfig)
+ testServerScript(t, "RC4", rc4ServerScript, testConfig, nil)
+}
+
+func TestHandshakeServer3DES(t *testing.T) {
+ des3Config := new(Config)
+ *des3Config = *testConfig
+ des3Config.CipherSuites = []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA}
+ testServerScript(t, "3DES", des3ServerScript, des3Config, nil)
}
func TestHandshakeServerAES(t *testing.T) {
aesConfig := new(Config)
*aesConfig = *testConfig
aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
- testServerScript(t, "AES", aesServerScript, aesConfig)
+ testServerScript(t, "AES", aesServerScript, aesConfig, nil)
+}
+
+func TestHandshakeServerSSLv3(t *testing.T) {
+ testServerScript(t, "SSLv3", sslv3ServerScript, testConfig, nil)
+}
+
+type clientauthTest struct {
+ name string
+ clientauth ClientAuthType
+ peers []*x509.Certificate
+ script [][]byte
+}
+
+func TestClientAuth(t *testing.T) {
+ for _, cat := range clientauthTests {
+ t.Log("running", cat.name)
+ cfg := new(Config)
+ *cfg = *testConfig
+ cfg.ClientAuth = cat.clientauth
+ testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+ }
}
var serve = flag.Bool("serve", false, "run a TLS server on :10443")
+var testCipherSuites = flag.String("ciphersuites",
+ "0x"+strconv.FormatInt(int64(TLS_RSA_WITH_RC4_128_SHA), 16),
+ "cipher suites to accept in serving mode")
+var testClientAuth = flag.Int("clientauth", 0, "value for tls.Config.ClientAuth")
func TestRunServer(t *testing.T) {
if !*serve {
return
}
+ suites := strings.Split(*testCipherSuites, ",")
+ testConfig.CipherSuites = make([]uint16, len(suites))
+ for i := range suites {
+ suite, err := strconv.ParseUint(suites[i], 0, 64)
+ if err != nil {
+ panic(err)
+ }
+ testConfig.CipherSuites[i] = uint16(suite)
+ }
+
+ testConfig.ClientAuth = ClientAuthType(*testClientAuth)
+
l, err := Listen("tcp", ":10443", testConfig)
if err != nil {
t.Fatal(err)
@@ -157,13 +224,23 @@ func TestRunServer(t *testing.T) {
for {
c, err := l.Accept()
if err != nil {
+ log.Printf("error from TLS handshake: %s", err)
break
}
+
_, err = c.Write([]byte("hello, world\n"))
if err != nil {
- t.Errorf("error from TLS: %s", err)
- break
+ log.Printf("error from TLS: %s", err)
+ continue
+ }
+
+ st := c.(*Conn).ConnectionState()
+ if len(st.PeerCertificates) > 0 {
+ log.Print("Handling request from client ", st.PeerCertificates[0].Subject.CommonName)
+ } else {
+ log.Print("Handling request from anon client")
}
+
c.Close()
}
}
@@ -193,31 +270,42 @@ var testPrivateKey = &rsa.PrivateKey{
},
}
+func loadPEMCert(in string) *x509.Certificate {
+ block, _ := pem.Decode([]byte(in))
+ if block.Type == "CERTIFICATE" && len(block.Headers) == 0 {
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err == nil {
+ return cert
+ }
+ panic("error parsing cert")
+ }
+ panic("error parsing PEM")
+}
+
// Script of interaction with gnutls implementation.
// The values for this test are obtained by building and running in server mode:
-// % gotest -test.run "TestRunServer" -serve
+// % go test -run "TestRunServer" -serve
// and then:
// % gnutls-cli --insecure --debug 100 -p 10443 localhost > /tmp/log 2>&1
// % python parse-gnutls-cli-debug-log.py < /tmp/log
var rc4ServerScript = [][]byte{
{
- 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
- 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a,
- 0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88,
- 0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0,
- 0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb,
- 0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00,
+ 0x76, 0x03, 0x02, 0x4e, 0xdd, 0xe6, 0xa5, 0xf7,
+ 0x00, 0x36, 0xf7, 0x83, 0xec, 0x93, 0x7c, 0xd2,
+ 0x4d, 0xe7, 0x7b, 0xf5, 0x4c, 0xf7, 0xe3, 0x86,
+ 0xe8, 0xec, 0x3b, 0xbd, 0x2c, 0x9a, 0x3f, 0x57,
+ 0xf0, 0xa4, 0xd4, 0x00, 0x00, 0x34, 0x00, 0x33,
0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
- 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09,
0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
- 0x01, 0x00, 0x01, 0x00,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
},
{
@@ -321,38 +409,219 @@ var rc4ServerScript = [][]byte{
{
0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
- 0x82, 0x00, 0x80, 0x3c, 0x13, 0xd7, 0x12, 0xc1,
- 0x6a, 0xf0, 0x3f, 0x8c, 0xa1, 0x35, 0x5d, 0xc5,
- 0x89, 0x1e, 0x9e, 0xcd, 0x32, 0xc7, 0x9e, 0xe6,
- 0xae, 0xd5, 0xf1, 0xbf, 0x70, 0xd7, 0xa9, 0xef,
- 0x2c, 0x4c, 0xf4, 0x22, 0xbc, 0x17, 0x17, 0xaa,
- 0x05, 0xf3, 0x9f, 0x80, 0xf2, 0xe9, 0x82, 0x2f,
- 0x2a, 0x15, 0x54, 0x0d, 0x16, 0x0e, 0x77, 0x4c,
- 0x28, 0x3c, 0x03, 0x2d, 0x2d, 0xd7, 0xc8, 0x64,
- 0xd9, 0x59, 0x4b, 0x1c, 0xf4, 0xde, 0xff, 0x2f,
- 0xbc, 0x94, 0xaf, 0x18, 0x26, 0x37, 0xce, 0x4f,
- 0x84, 0x74, 0x2e, 0x45, 0x66, 0x7c, 0x0c, 0x54,
- 0x46, 0x36, 0x5f, 0x65, 0x21, 0x7b, 0x83, 0x8c,
- 0x6d, 0x76, 0xcd, 0x0d, 0x9f, 0xda, 0x1c, 0xa4,
- 0x6e, 0xfe, 0xb1, 0xf7, 0x09, 0x0d, 0xfb, 0x74,
- 0x66, 0x34, 0x99, 0x89, 0x7f, 0x5f, 0x77, 0x87,
- 0x4a, 0x66, 0x4b, 0xa9, 0x59, 0x57, 0xe3, 0x56,
- 0x0d, 0xdd, 0xd8, 0x14, 0x03, 0x01, 0x00, 0x01,
- 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc0, 0x4e,
- 0xd3, 0x0f, 0xb5, 0xc0, 0x57, 0xa6, 0x18, 0x80,
- 0x80, 0x6b, 0x49, 0xfe, 0xbd, 0x3a, 0x7a, 0x2c,
- 0xef, 0x70, 0xb5, 0x1c, 0xd2, 0xdf, 0x5f, 0x78,
- 0x5a, 0xd8, 0x4f, 0xa0, 0x95, 0xb4, 0xb3, 0xb5,
- 0xaa, 0x3b,
+ 0x82, 0x00, 0x80, 0x39, 0xe2, 0x0f, 0x49, 0xa0,
+ 0xe6, 0xe4, 0x3b, 0x0c, 0x5f, 0xce, 0x39, 0x97,
+ 0x6c, 0xb6, 0x41, 0xd9, 0xe1, 0x52, 0x8f, 0x43,
+ 0xb3, 0xc6, 0x4f, 0x9a, 0xe2, 0x1e, 0xb9, 0x3b,
+ 0xe3, 0x72, 0x17, 0x68, 0xb2, 0x0d, 0x7b, 0x71,
+ 0x33, 0x96, 0x5c, 0xf9, 0xfe, 0x18, 0x8f, 0x2f,
+ 0x2b, 0x82, 0xec, 0x03, 0xf2, 0x16, 0xa8, 0xf8,
+ 0x39, 0xf9, 0xbb, 0x5a, 0xd3, 0x0c, 0xc1, 0x2a,
+ 0x52, 0xa1, 0x90, 0x20, 0x6b, 0x24, 0xc9, 0x55,
+ 0xee, 0x05, 0xd8, 0xb3, 0x43, 0x58, 0xf6, 0x7f,
+ 0x68, 0x2d, 0xb3, 0xd1, 0x1b, 0x30, 0xaa, 0xdf,
+ 0xfc, 0x85, 0xf1, 0xab, 0x14, 0x51, 0x91, 0x78,
+ 0x29, 0x35, 0x65, 0xe0, 0x9c, 0xf6, 0xb7, 0x35,
+ 0x33, 0xdb, 0x28, 0x93, 0x4d, 0x86, 0xbc, 0xfe,
+ 0xaa, 0xd1, 0xc0, 0x2e, 0x4d, 0xec, 0xa2, 0x98,
+ 0xca, 0x08, 0xb2, 0x91, 0x14, 0xde, 0x97, 0x3a,
+ 0xc4, 0x6b, 0x49, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x7a, 0xcb,
+ 0x3b, 0x0e, 0xbb, 0x7a, 0x56, 0x39, 0xaf, 0x83,
+ 0xae, 0xfd, 0x25, 0xfd, 0x64, 0xb4, 0x0c, 0x0c,
+ 0x17, 0x46, 0x54, 0x2c, 0x6a, 0x07, 0x83, 0xc6,
+ 0x46, 0x08, 0x0b, 0xcd, 0x15, 0x53, 0xef, 0x40,
+ 0x4e, 0x56,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0xd3, 0x72, 0xeb, 0x29, 0xb9,
+ 0x15, 0x29, 0xb5, 0xe5, 0xb7, 0xef, 0x5c, 0xb2,
+ 0x9d, 0xf6, 0xc8, 0x47, 0xd6, 0xa0, 0x84, 0xf0,
+ 0x8c, 0xcb, 0xe6, 0xbe, 0xbc, 0xfb, 0x38, 0x90,
+ 0x89, 0x60, 0xa2, 0xe8, 0xaa, 0xb3, 0x12, 0x17,
+ 0x03, 0x01, 0x00, 0x21, 0x67, 0x4a, 0x3d, 0x31,
+ 0x6c, 0x5a, 0x1c, 0xf9, 0x6e, 0xf1, 0xd8, 0x12,
+ 0x0e, 0xb9, 0xfd, 0xfc, 0x66, 0x91, 0xd1, 0x1d,
+ 0x6e, 0xe4, 0x55, 0xdd, 0x11, 0xb9, 0xb8, 0xa2,
+ 0x65, 0xa1, 0x95, 0x64, 0x1c, 0x15, 0x03, 0x01,
+ 0x00, 0x16, 0x9b, 0xa0, 0x24, 0xe3, 0xcb, 0xae,
+ 0xad, 0x51, 0xb3, 0x63, 0x59, 0x78, 0x49, 0x24,
+ 0x06, 0x6e, 0xee, 0x7a, 0xd7, 0x74, 0x53, 0x04,
+ },
+}
+
+var des3ServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00,
+ 0x76, 0x03, 0x02, 0x4e, 0x84, 0xf4, 0x3c, 0xe4,
+ 0xb8, 0xc7, 0xa0, 0x30, 0x55, 0x2a, 0xbc, 0xb7,
+ 0x04, 0x6b, 0x6f, 0x87, 0x93, 0x96, 0xbd, 0x1a,
+ 0x7a, 0x1e, 0xce, 0xd2, 0x0d, 0xf3, 0x01, 0x03,
+ 0xbe, 0x7b, 0x17, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0xae, 0xcf, 0x4f, 0x70, 0x0e,
+ 0xe5, 0xe7, 0xba, 0xef, 0x0c, 0x66, 0xe9, 0xae,
+ 0x76, 0xf4, 0xe0, 0xbc, 0x1c, 0x22, 0x5b, 0x72,
+ 0xc9, 0x68, 0x63, 0x44, 0xec, 0x72, 0xc2, 0xca,
+ 0xac, 0xc2, 0xf5, 0x5c, 0x28, 0xa1, 0xaf, 0xd0,
+ 0xc2, 0xf7, 0x79, 0x71, 0x32, 0x73, 0x86, 0xea,
+ 0x39, 0xf6, 0x04, 0x26, 0x19, 0x84, 0x1d, 0x7d,
+ 0xa1, 0x21, 0xa6, 0x88, 0xbf, 0x33, 0x5a, 0x64,
+ 0xb0, 0xc2, 0xcc, 0x19, 0x7a, 0x8b, 0x6e, 0x94,
+ 0x9e, 0x2e, 0x20, 0xbe, 0xdc, 0xe9, 0x8e, 0xae,
+ 0x5c, 0x39, 0xc8, 0xcd, 0x0e, 0x19, 0x9a, 0xa2,
+ 0xfc, 0x3f, 0x61, 0x9a, 0xca, 0x58, 0x69, 0x0d,
+ 0xa8, 0x7b, 0xbe, 0x98, 0x8f, 0xb9, 0x9d, 0x8b,
+ 0x68, 0x65, 0xa9, 0x74, 0xcc, 0x8d, 0x0c, 0xb2,
+ 0xc4, 0x0f, 0xdc, 0x56, 0x3e, 0x44, 0x61, 0x0a,
+ 0x26, 0x93, 0x99, 0xef, 0x67, 0xff, 0x6e, 0x73,
+ 0x01, 0xa1, 0x90, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x60, 0x49, 0x36,
+ 0xc8, 0x38, 0x95, 0xe4, 0x5d, 0x8e, 0x80, 0x10,
+ 0x26, 0x9f, 0x87, 0x7d, 0xcd, 0xb9, 0x32, 0x6c,
+ 0xff, 0xaa, 0xe0, 0x07, 0xec, 0x33, 0xe2, 0x36,
+ 0x9d, 0xd5, 0x83, 0x2c, 0xf0, 0x0a, 0xa0, 0xa8,
+ 0x12, 0x9f, 0xca, 0x72, 0xda, 0x70, 0x7d, 0x76,
+ 0x80, 0x12, 0x88, 0x07, 0xaa, 0x27, 0x62, 0x33,
+ 0xab, 0x55, 0xad, 0x3c, 0x2b, 0x54, 0xc4, 0x1c,
+ 0x91, 0xfd, 0x8f, 0x9c, 0xa7, 0x8b, 0x75, 0x10,
+ 0xa8, 0x6e, 0xfc, 0x30, 0x52, 0x8a, 0x61, 0x02,
+ 0xdb, 0x9c, 0x6f, 0xc8, 0x19, 0x93, 0x5d, 0x41,
+ 0x1d, 0x36, 0x68, 0x0b, 0xec, 0x30, 0xae, 0xfb,
+ 0x90, 0xdb, 0x6d, 0x83, 0xb0, 0xf2,
},
{
0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
- 0x01, 0x00, 0x24, 0x9d, 0xc9, 0xda, 0xdf, 0xeb,
- 0xc8, 0xdb, 0xf8, 0x94, 0xa5, 0xef, 0xd5, 0xfc,
- 0x89, 0x01, 0x64, 0x30, 0x77, 0x5a, 0x18, 0x4b,
- 0x16, 0x79, 0x9c, 0xf6, 0xf5, 0x09, 0x22, 0x12,
- 0x4c, 0x3e, 0xa8, 0x8e, 0x91, 0xa5, 0x24,
+ 0x01, 0x00, 0x28, 0x07, 0xf3, 0x33, 0x84, 0xb1,
+ 0x5d, 0x2b, 0x52, 0xa4, 0x63, 0x3c, 0x32, 0xe0,
+ 0x0d, 0x22, 0xf5, 0x23, 0xec, 0xf9, 0xa6, 0xec,
+ 0xc0, 0x12, 0x69, 0x88, 0xf6, 0x7d, 0x37, 0xcd,
+ 0xc2, 0x74, 0x2f, 0xef, 0xf6, 0x49, 0x15, 0xea,
+ 0x88, 0x3f, 0x55, 0x17, 0x03, 0x01, 0x00, 0x28,
+ 0xaf, 0x00, 0x84, 0xff, 0x11, 0x01, 0x6d, 0xba,
+ 0x39, 0x5e, 0x45, 0xe1, 0x52, 0x5e, 0xc1, 0xab,
+ 0xde, 0x5b, 0x16, 0xdd, 0xd6, 0x61, 0x57, 0xb8,
+ 0x66, 0x8b, 0x2d, 0xde, 0x51, 0x41, 0xc5, 0x09,
+ 0xb3, 0x6a, 0x06, 0x43, 0xb4, 0x73, 0x5c, 0xf1,
+ 0x15, 0x03, 0x01, 0x00, 0x18, 0xbd, 0x65, 0xb2,
+ 0xce, 0x77, 0x2e, 0xf9, 0x11, 0xc4, 0x80, 0x43,
+ 0x5a, 0x73, 0x8b, 0x73, 0xdd, 0xf0, 0x54, 0x44,
+ 0x7c, 0x56, 0x19, 0x54, 0xda,
},
}
@@ -515,3 +784,787 @@ var aesServerScript = [][]byte{
0xcd, 0x84, 0xf0,
},
}
+
+var sslv3ServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00,
+ 0x3d, 0x03, 0x00, 0x4e, 0x70, 0xe2, 0x18, 0x86,
+ 0xd6, 0xc6, 0x6f, 0xf3, 0xc8, 0xf4, 0x02, 0xd6,
+ 0x4d, 0xee, 0x17, 0x32, 0x4b, 0xd2, 0x78, 0xd8,
+ 0xa1, 0x03, 0x5d, 0x68, 0x82, 0x89, 0xbe, 0xfd,
+ 0x12, 0xb9, 0x06, 0x00, 0x00, 0x16, 0x00, 0x33,
+ 0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38,
+ 0x00, 0x13, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a,
+ 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x00, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00,
+ 0x80, 0x74, 0x0e, 0x3a, 0xcf, 0xba, 0x9f, 0x1a,
+ 0x9b, 0xb2, 0xa4, 0xc7, 0x5d, 0xf3, 0x0c, 0x80,
+ 0x06, 0x80, 0xf3, 0x57, 0xb2, 0xd9, 0x36, 0x24,
+ 0x6a, 0x06, 0x13, 0x40, 0xf9, 0x7c, 0xb9, 0x3e,
+ 0x4b, 0x68, 0x4f, 0x21, 0x90, 0x2d, 0xbd, 0xca,
+ 0xd4, 0x83, 0xf0, 0x7a, 0xeb, 0x7a, 0x74, 0x1b,
+ 0xcd, 0xfe, 0x69, 0xef, 0xc0, 0x86, 0xa0, 0x24,
+ 0x31, 0x65, 0x40, 0xd2, 0xdd, 0x6f, 0xb9, 0xd7,
+ 0x8d, 0xc1, 0x69, 0x60, 0x44, 0x7a, 0x75, 0xfb,
+ 0x42, 0x6a, 0x0f, 0x66, 0x45, 0x10, 0x73, 0xee,
+ 0x87, 0x28, 0x37, 0x83, 0x86, 0xd8, 0x5a, 0xc8,
+ 0x60, 0x87, 0xda, 0x33, 0x87, 0xaf, 0x34, 0x8b,
+ 0xf5, 0x61, 0x63, 0x7a, 0x5c, 0x60, 0x26, 0xb9,
+ 0xdb, 0xa1, 0xb7, 0xe3, 0x60, 0x38, 0x94, 0x5c,
+ 0x83, 0x23, 0xd6, 0x8d, 0xc2, 0x14, 0x4a, 0x0f,
+ 0x0e, 0x4f, 0xf9, 0x4e, 0x7b, 0x15, 0xcd, 0x18,
+ 0x04, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16,
+ 0x03, 0x00, 0x00, 0x3c, 0xbd, 0xbc, 0xec, 0xdc,
+ 0x79, 0xb1, 0xae, 0x16, 0xc9, 0x26, 0x9a, 0xc0,
+ 0xc0, 0x2c, 0x33, 0x36, 0x13, 0x91, 0x58, 0x5d,
+ 0x7d, 0xee, 0x4e, 0xd8, 0x7e, 0xac, 0x88, 0x87,
+ 0x0a, 0x75, 0x66, 0xb1, 0x44, 0x79, 0x2f, 0x42,
+ 0xe8, 0x92, 0x74, 0x4c, 0xab, 0x36, 0xc8, 0x17,
+ 0x5f, 0x02, 0x8a, 0x20, 0x53, 0xe9, 0x1d, 0xb4,
+ 0xfe, 0x5c, 0x2b, 0xd9, 0x0a, 0xfb, 0xc6, 0x63,
+ },
+
+ {
+ 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x00, 0x00, 0x3c, 0xaa, 0xa1, 0x98, 0xc4, 0x6b,
+ 0x5a, 0x16, 0x3f, 0x5f, 0xa4, 0x96, 0x3e, 0x78,
+ 0xe4, 0x6f, 0x49, 0x05, 0x47, 0xc4, 0x05, 0x60,
+ 0xeb, 0x0b, 0x45, 0xe3, 0xbc, 0x50, 0x11, 0x24,
+ 0x5f, 0x01, 0xd7, 0xb8, 0x8f, 0x60, 0x63, 0x66,
+ 0xbd, 0x3e, 0xd9, 0xa8, 0x80, 0x43, 0x9f, 0x0b,
+ 0x51, 0x61, 0xed, 0x13, 0xc6, 0x21, 0xd0, 0xfe,
+ 0xbc, 0x17, 0x3c, 0x36, 0xb0, 0x82, 0x7f, 0x17,
+ 0x03, 0x00, 0x00, 0x21, 0xee, 0x44, 0xf3, 0xa6,
+ 0x88, 0x9d, 0x78, 0x44, 0xde, 0xdf, 0xeb, 0xc5,
+ 0xad, 0xc4, 0xcc, 0x56, 0x5c, 0x54, 0x96, 0x52,
+ 0x3f, 0xd9, 0x40, 0x6e, 0x79, 0xd8, 0x58, 0x78,
+ 0x4f, 0x5a, 0xe9, 0x06, 0xef, 0x15, 0x03, 0x00,
+ 0x00, 0x16, 0xd3, 0xc2, 0x52, 0x99, 0x2a, 0x84,
+ 0xc4, 0x52, 0x5f, 0x3b, 0x19, 0xe7, 0xfc, 0x65,
+ 0xaf, 0xd3, 0xb7, 0xa3, 0xcc, 0x4a, 0x1d, 0x2e,
+ },
+}
+
+var clientauthTests = []clientauthTest{
+ // Server doesn't asks for cert
+ // go test -run "TestRunServer" -serve -clientauth 0
+ // gnutls-cli --insecure --debug 100 -p 10443 localhost 2>&1 |
+ // python parse-gnutls-cli-debug-log.py
+ {"NoClientCert", NoClientCert, nil,
+ [][]byte{{
+ 0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00,
+ 0x76, 0x03, 0x02, 0x4e, 0xe0, 0x92, 0x5d, 0xcd,
+ 0xfe, 0x0c, 0x69, 0xd4, 0x7d, 0x8e, 0xa6, 0x88,
+ 0xde, 0x72, 0x04, 0x29, 0x6a, 0x4a, 0x16, 0x23,
+ 0xd7, 0x8f, 0xbc, 0xfa, 0x80, 0x73, 0x2e, 0x12,
+ 0xb7, 0x0b, 0x39, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x10, 0xe1, 0x00, 0x3d, 0x0a,
+ 0x6b, 0x02, 0x7f, 0x97, 0xde, 0xfb, 0x65, 0x46,
+ 0x1a, 0x50, 0x4e, 0x34, 0x9a, 0xae, 0x14, 0x7e,
+ 0xec, 0xef, 0x85, 0x15, 0x3b, 0x39, 0xc2, 0x45,
+ 0x04, 0x40, 0x92, 0x71, 0xd6, 0x7e, 0xf6, 0xfd,
+ 0x4d, 0x84, 0xf7, 0xc4, 0x77, 0x99, 0x3d, 0xe2,
+ 0xc3, 0x8d, 0xb0, 0x4c, 0x74, 0xc8, 0x51, 0xec,
+ 0xb2, 0xe8, 0x6b, 0xa1, 0xd2, 0x4d, 0xd8, 0x61,
+ 0x92, 0x7a, 0x24, 0x57, 0x44, 0x4f, 0xa2, 0x1e,
+ 0x74, 0x0b, 0x06, 0x4b, 0x80, 0x34, 0x8b, 0xfe,
+ 0xc2, 0x0e, 0xc1, 0xcd, 0xab, 0x0c, 0x3f, 0x54,
+ 0xe2, 0x44, 0xe9, 0x6c, 0x2b, 0xba, 0x7b, 0x64,
+ 0xf1, 0x93, 0x65, 0x75, 0xf2, 0x35, 0xff, 0x27,
+ 0x03, 0xd5, 0x64, 0xe6, 0x8e, 0xe7, 0x7b, 0x56,
+ 0xb6, 0x61, 0x73, 0xeb, 0xa2, 0xdc, 0xa4, 0x6e,
+ 0x52, 0xac, 0xbc, 0xba, 0x11, 0xa3, 0xd2, 0x61,
+ 0x4a, 0xe0, 0xbb, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xd2, 0x5a,
+ 0x0c, 0x2a, 0x27, 0x96, 0xba, 0xa9, 0x67, 0xd2,
+ 0x51, 0x68, 0x32, 0x68, 0x22, 0x1f, 0xb9, 0x27,
+ 0x79, 0x59, 0x28, 0xdf, 0x38, 0x1f, 0x92, 0x21,
+ 0x5d, 0x0f, 0xf4, 0xc0, 0xee, 0xb7, 0x10, 0x5a,
+ 0xa9, 0x45,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0x13, 0x6f, 0x6c, 0x71, 0x83,
+ 0x59, 0xcf, 0x32, 0x72, 0xe9, 0xce, 0xcc, 0x7a,
+ 0x6c, 0xf0, 0x72, 0x39, 0x16, 0xae, 0x40, 0x61,
+ 0xfa, 0x92, 0x4c, 0xe7, 0xf2, 0x1a, 0xd7, 0x0c,
+ 0x84, 0x76, 0x6c, 0xe9, 0x11, 0x43, 0x19, 0x17,
+ 0x03, 0x01, 0x00, 0x21, 0xc0, 0xa2, 0x13, 0x28,
+ 0x94, 0x8c, 0x5c, 0xd6, 0x79, 0xb9, 0xfe, 0xae,
+ 0x45, 0x4b, 0xc0, 0x7c, 0xae, 0x2d, 0xb4, 0x0d,
+ 0x31, 0xc4, 0xad, 0x22, 0xd7, 0x1e, 0x99, 0x1c,
+ 0x4c, 0x69, 0xab, 0x42, 0x61, 0x15, 0x03, 0x01,
+ 0x00, 0x16, 0xe1, 0x0c, 0x67, 0xf3, 0xf4, 0xb9,
+ 0x8e, 0x81, 0x8e, 0x01, 0xb8, 0xa0, 0x69, 0x8c,
+ 0x03, 0x11, 0x43, 0x3e, 0xee, 0xb7, 0x4d, 0x69,
+ }}},
+ // Server asks for cert with empty CA list, client doesn't give it.
+ // go test -run "TestRunServer" -serve -clientauth 1
+ // gnutls-cli --insecure --debug 100 -p 10443 localhost
+ {"RequestClientCert, none given", RequestClientCert, nil,
+ [][]byte{{
+ 0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00,
+ 0x76, 0x03, 0x02, 0x4e, 0xe0, 0x93, 0xe2, 0x47,
+ 0x06, 0xa0, 0x61, 0x0c, 0x51, 0xdd, 0xf0, 0xef,
+ 0xf4, 0x30, 0x72, 0xe1, 0xa6, 0x50, 0x68, 0x82,
+ 0x3c, 0xfb, 0xcb, 0x72, 0x5e, 0x73, 0x9d, 0xda,
+ 0x27, 0x35, 0x72, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d,
+ 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16,
+ 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00,
+ 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x64,
+ 0x28, 0xb9, 0x3f, 0x48, 0xaf, 0x06, 0x22, 0x39,
+ 0x56, 0xd8, 0x6f, 0x63, 0x5d, 0x03, 0x48, 0x63,
+ 0x01, 0x13, 0xa2, 0xd6, 0x76, 0xc0, 0xab, 0xda,
+ 0x25, 0x30, 0x75, 0x6c, 0xaa, 0xb4, 0xdc, 0x35,
+ 0x72, 0xdc, 0xf2, 0x43, 0xe4, 0x1d, 0x82, 0xfb,
+ 0x6c, 0x64, 0xe2, 0xa7, 0x8f, 0x32, 0x67, 0x6b,
+ 0xcd, 0xd2, 0xb2, 0x36, 0x94, 0xbc, 0x6f, 0x46,
+ 0x79, 0x29, 0x42, 0xe3, 0x1a, 0xbf, 0xfb, 0x41,
+ 0xd5, 0xe3, 0xb4, 0x2a, 0xf6, 0x95, 0x6f, 0x0c,
+ 0x87, 0xb9, 0x03, 0x18, 0xa1, 0xea, 0x4a, 0xe2,
+ 0x2e, 0x0f, 0x50, 0x00, 0xc1, 0xe8, 0x8c, 0xc8,
+ 0xa2, 0xf6, 0xa4, 0x05, 0xf4, 0x38, 0x3e, 0xd9,
+ 0x6e, 0x63, 0x96, 0x0c, 0x34, 0x73, 0x90, 0x03,
+ 0x55, 0xa6, 0x34, 0xb0, 0x5e, 0x8c, 0x48, 0x40,
+ 0x25, 0x45, 0x84, 0xa6, 0x21, 0x3f, 0x81, 0x97,
+ 0xa7, 0x11, 0x09, 0x14, 0x95, 0xa5, 0xe5, 0x14,
+ 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
+ 0x00, 0x24, 0x16, 0xaa, 0x01, 0x2c, 0xa8, 0xc1,
+ 0x28, 0xaf, 0x35, 0xc1, 0xc1, 0xf3, 0x0a, 0x25,
+ 0x66, 0x6e, 0x27, 0x11, 0xa3, 0xa4, 0xd9, 0xe9,
+ 0xea, 0x15, 0x09, 0x9d, 0x28, 0xe3, 0x5b, 0x2b,
+ 0xa6, 0x25, 0xa7, 0x14, 0x24, 0x3a,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0x9a, 0xa8, 0xd6, 0x77, 0x46,
+ 0x45, 0x68, 0x9d, 0x5d, 0xa9, 0x68, 0x03, 0xe5,
+ 0xaf, 0xe8, 0xc8, 0x21, 0xc5, 0xc6, 0xc1, 0x50,
+ 0xe0, 0xd8, 0x52, 0xce, 0xa3, 0x4f, 0x2d, 0xf4,
+ 0xe3, 0xa7, 0x7d, 0x35, 0x80, 0x84, 0x12, 0x17,
+ 0x03, 0x01, 0x00, 0x21, 0x8a, 0x82, 0x0c, 0x54,
+ 0x1b, 0xeb, 0x77, 0x90, 0x2c, 0x3e, 0xbc, 0xf0,
+ 0x23, 0xcc, 0xa8, 0x9f, 0x25, 0x08, 0x12, 0xed,
+ 0x43, 0xf1, 0xf9, 0x06, 0xad, 0xa9, 0x4b, 0x97,
+ 0x82, 0xb7, 0xc4, 0x0b, 0x4c, 0x15, 0x03, 0x01,
+ 0x00, 0x16, 0x05, 0x2d, 0x9d, 0x45, 0x03, 0xb7,
+ 0xc2, 0xd1, 0xb5, 0x1a, 0x43, 0xcf, 0x1a, 0x37,
+ 0xf4, 0x70, 0xcc, 0xb4, 0xed, 0x07, 0x76, 0x3a,
+ }}},
+ // Server asks for cert with empty CA list, client gives one
+ // go test -run "TestRunServer" -serve -clientauth 1
+ // gnutls-cli --insecure --debug 100 -p 10443 localhost
+ {"RequestClientCert, client gives it", RequestClientCert,
+ []*x509.Certificate{clicert},
+ [][]byte{{
+ 0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00,
+ 0x76, 0x03, 0x02, 0x4e, 0xe7, 0x44, 0xda, 0x58,
+ 0x7d, 0x46, 0x4a, 0x48, 0x97, 0x9f, 0xe5, 0x91,
+ 0x11, 0x64, 0xa7, 0x1e, 0x4d, 0xb7, 0xfe, 0x9b,
+ 0xc6, 0x63, 0xf8, 0xa4, 0xb5, 0x0b, 0x18, 0xb5,
+ 0xbd, 0x19, 0xb3, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d,
+ 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16,
+ 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01,
+ 0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
+ 0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
+ 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
+ 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
+ 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
+ 0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
+ 0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
+ 0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
+ 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+ 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
+ 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
+ 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
+ 0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
+ 0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
+ 0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
+ 0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
+ 0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
+ 0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
+ 0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
+ 0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
+ 0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
+ 0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
+ 0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
+ 0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
+ 0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
+ 0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
+ 0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
+ 0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
+ 0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
+ 0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
+ 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+ 0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
+ 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
+ 0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
+ 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
+ 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
+ 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
+ 0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
+ 0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
+ 0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
+ 0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
+ 0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
+ 0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
+ 0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
+ 0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
+ 0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
+ 0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
+ 0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
+ 0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
+ 0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
+ 0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
+ 0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
+ 0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0xa7, 0x2f, 0xed, 0xfa, 0xc2,
+ 0xbd, 0x46, 0xa1, 0xf2, 0x69, 0xc5, 0x1d, 0xa1,
+ 0x34, 0xd6, 0xd0, 0x84, 0xf5, 0x5d, 0x8c, 0x82,
+ 0x8d, 0x98, 0x82, 0x9c, 0xd9, 0x07, 0xe0, 0xf7,
+ 0x55, 0x49, 0x4d, 0xa1, 0x48, 0x59, 0x02, 0xd3,
+ 0x84, 0x37, 0xaf, 0x01, 0xb3, 0x3a, 0xf4, 0xed,
+ 0x99, 0xbe, 0x67, 0x36, 0x19, 0x55, 0xf3, 0xf9,
+ 0xcb, 0x94, 0xe5, 0x7b, 0x8b, 0x77, 0xf2, 0x5f,
+ 0x4c, 0xfe, 0x01, 0x1f, 0x7b, 0xd7, 0x23, 0x49,
+ 0x0c, 0xcb, 0x6c, 0xb0, 0xe7, 0x77, 0xd6, 0xcf,
+ 0xa8, 0x7d, 0xdb, 0xa7, 0x14, 0xe2, 0xf5, 0xf3,
+ 0xff, 0xba, 0x23, 0xd2, 0x9a, 0x36, 0x14, 0x60,
+ 0x2a, 0x91, 0x5d, 0x2b, 0x35, 0x3b, 0xb6, 0xdd,
+ 0xcb, 0x6b, 0xdc, 0x18, 0xdc, 0x33, 0xb8, 0xb3,
+ 0xc7, 0x27, 0x7e, 0xfc, 0xd2, 0xf7, 0x97, 0x90,
+ 0x5e, 0x17, 0xac, 0x14, 0x8e, 0x0f, 0xca, 0xb5,
+ 0x6f, 0xc9, 0x2d, 0x16, 0x03, 0x01, 0x00, 0x86,
+ 0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x44, 0x7f,
+ 0xa2, 0x59, 0x60, 0x0b, 0x5a, 0xc4, 0xaf, 0x1e,
+ 0x60, 0xa5, 0x24, 0xea, 0xc1, 0xc3, 0x22, 0x21,
+ 0x6b, 0x22, 0x8b, 0x2a, 0x11, 0x82, 0x68, 0x7d,
+ 0xb9, 0xdd, 0x9c, 0x27, 0x4c, 0xc2, 0xc8, 0xa2,
+ 0x8b, 0x6b, 0x77, 0x8d, 0x3a, 0x2b, 0x8d, 0x2f,
+ 0x6a, 0x2b, 0x43, 0xd2, 0xd1, 0xc6, 0x41, 0x79,
+ 0xa2, 0x4f, 0x2b, 0xc2, 0xf7, 0xb2, 0x10, 0xad,
+ 0xa6, 0x01, 0x51, 0x51, 0x25, 0xe7, 0x58, 0x7a,
+ 0xcf, 0x3b, 0xc4, 0x29, 0xb5, 0xe5, 0xa7, 0x83,
+ 0xe6, 0xcb, 0x1e, 0xf3, 0x02, 0x0f, 0x53, 0x3b,
+ 0xb5, 0x39, 0xef, 0x9c, 0x42, 0xe0, 0xa6, 0x9b,
+ 0x2b, 0xdd, 0x60, 0xae, 0x0a, 0x73, 0x35, 0xbe,
+ 0x26, 0x10, 0x1b, 0xe9, 0xe9, 0x61, 0xab, 0x20,
+ 0xa5, 0x48, 0xc6, 0x60, 0xa6, 0x50, 0x3c, 0xfb,
+ 0xa7, 0xca, 0xb0, 0x80, 0x95, 0x1e, 0xce, 0xc7,
+ 0xbb, 0x68, 0x44, 0xdc, 0x0e, 0x0e, 0x14, 0x03,
+ 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
+ 0x24, 0xb6, 0xcd, 0x0c, 0x78, 0xfd, 0xd6, 0xff,
+ 0xbe, 0x97, 0xd5, 0x0a, 0x7d, 0x4f, 0xa1, 0x03,
+ 0x78, 0xc8, 0x61, 0x6f, 0xf2, 0x4b, 0xa8, 0x56,
+ 0x4f, 0x3c, 0xa2, 0xd9, 0xd0, 0x20, 0x13, 0x1b,
+ 0x8b, 0x36, 0xb7, 0x33, 0x9c,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0xa3, 0x43, 0x94, 0xe7, 0xdf,
+ 0xb6, 0xc3, 0x03, 0x9f, 0xc1, 0x59, 0x0c, 0xc3,
+ 0x13, 0xae, 0xed, 0xcf, 0xff, 0xf1, 0x80, 0xf3,
+ 0x13, 0x63, 0x1c, 0xf0, 0xca, 0xad, 0x9e, 0x71,
+ 0x46, 0x5f, 0x6b, 0xeb, 0x10, 0x3f, 0xe3, 0x17,
+ 0x03, 0x01, 0x00, 0x21, 0xe9, 0x80, 0x95, 0x6e,
+ 0x05, 0x55, 0x2f, 0xed, 0x4d, 0xde, 0x17, 0x3a,
+ 0x32, 0x9b, 0x2a, 0x74, 0x30, 0x4f, 0xe0, 0x9f,
+ 0x4e, 0xd3, 0x06, 0xbd, 0x3a, 0x43, 0x75, 0x8b,
+ 0x5b, 0x9a, 0xd8, 0x2e, 0x56, 0x15, 0x03, 0x01,
+ 0x00, 0x16, 0x53, 0xf5, 0xff, 0xe0, 0xa1, 0x6c,
+ 0x33, 0xf4, 0x4e, 0x89, 0x68, 0xe1, 0xf7, 0x61,
+ 0x13, 0xb3, 0x12, 0xa1, 0x8e, 0x5a, 0x7a, 0x02,
+ }}},
+}
+
+// cert.pem and key.pem were generated with generate_cert.go
+// Thus, they have no ExtKeyUsage fields and trigger an error
+// when verification is turned on.
+
+var clicert = loadPEMCert(`
+-----BEGIN CERTIFICATE-----
+MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
+bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
+MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
+MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
+hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
+ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
+E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
+p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
+hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
+GFGNEH5PlGffo05wc46QkYU=
+-----END CERTIFICATE-----
+`)
+
+/* corresponding key.pem for cert.pem is:
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
+NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
+DNBNbocuXMXSu01LT862LPd+iOx81wKRdKYeDBra40paLt4TnExAiFmTAgMBAAEC
+gYBxvXd8yNteFTns8A/2yomEMC4yeosJJSpp1CsN3BJ7g8/qTnrVPxBy+RU+qr63
+t2WquaOu/cr5P8iEsa6lk20tf8pjKLNXeX0b1RTzK8rJLbS7nGzP3tvOhL096VtQ
+dAo4ROEaro0TzYpHmpciSvxVIeEIAAdFDObDJPKqcJAxyQJBAJizfYgK8Gzx9fsx
+hxp+VteCbVPg2euASH5Yv3K5LukRdKoSzHE2grUVQgN/LafC0eZibRanxHegYSr7
+7qaswKUCQQCEIWor/X4XTMdVj3Oj+vpiw75y/S9gh682+myZL+d/02IEkwnB098P
+RkKVpenBHyrGg0oeN5La7URILWKj7CPXAkBKo6F+d+phNjwIFoN1Xb/RA32w/D1I
+saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
+Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
+qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
+1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvAMAA=
+-----END RSA PRIVATE KEY-----
+*/
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index a40d18fd9..a931d8fb5 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -5,26 +5,26 @@
package tls
import (
- "big"
"crypto"
"crypto/elliptic"
"crypto/md5"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
+ "errors"
"io"
- "os"
+ "math/big"
)
// rsaKeyAgreement implements the standard TLS key agreement where the client
// encrypts the pre-master secret to the server's public key.
type rsaKeyAgreement struct{}
-func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
return nil, nil
}
-func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
preMasterSecret := make([]byte, 48)
_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
if err != nil {
@@ -32,15 +32,19 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
if len(ckx.ciphertext) < 2 {
- return nil, os.NewError("bad ClientKeyExchange")
+ return nil, errors.New("bad ClientKeyExchange")
}
- ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
- if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, os.NewError("bad ClientKeyExchange")
+
+ ciphertext := ckx.ciphertext
+ if version != versionSSL30 {
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, errors.New("bad ClientKeyExchange")
+ }
+ ciphertext = ckx.ciphertext[2:]
}
- ciphertext := ckx.ciphertext[2:]
- err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
+ err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
if err != nil {
return nil, err
}
@@ -53,11 +57,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
return preMasterSecret, nil
}
-func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
- return os.NewError("unexpected ServerKeyExchange")
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ return errors.New("unexpected ServerKeyExchange")
}
-func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
preMasterSecret := make([]byte, 48)
preMasterSecret[0] = byte(clientHello.vers >> 8)
preMasterSecret[1] = byte(clientHello.vers)
@@ -86,13 +90,13 @@ func md5SHA1Hash(slices ...[]byte) []byte {
for _, slice := range slices {
hmd5.Write(slice)
}
- copy(md5sha1, hmd5.Sum())
+ copy(md5sha1, hmd5.Sum(nil))
hsha1 := sha1.New()
for _, slice := range slices {
hsha1.Write(slice)
}
- copy(md5sha1[md5.Size:], hsha1.Sum())
+ copy(md5sha1[md5.Size:], hsha1.Sum(nil))
return md5sha1
}
@@ -101,11 +105,11 @@ func md5SHA1Hash(slices ...[]byte) []byte {
// pre-master secret is then calculated using ECDH.
type ecdheRSAKeyAgreement struct {
privateKey []byte
- curve *elliptic.Curve
+ curve elliptic.Curve
x, y *big.Int
}
-func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
var curveid uint16
Curve:
@@ -126,13 +130,17 @@ Curve:
}
}
+ if curveid == 0 {
+ return nil, errors.New("tls: no supported elliptic curves offered")
+ }
+
var x, y *big.Int
- var err os.Error
- ka.privateKey, x, y, err = ka.curve.GenerateKey(config.rand())
+ var err error
+ ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
if err != nil {
return nil, err
}
- ecdhePublic := ka.curve.Marshal(x, y)
+ ecdhePublic := elliptic.Marshal(ka.curve, x, y)
// http://tools.ietf.org/html/rfc4492#section-5.4
serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
@@ -143,9 +151,9 @@ Curve:
copy(serverECDHParams[4:], ecdhePublic)
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
- sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
+ sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
if err != nil {
- return nil, os.NewError("failed to sign ECDHE parameters: " + err.String())
+ return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
}
skx := new(serverKeyExchangeMsg)
@@ -159,30 +167,30 @@ Curve:
return skx, nil
}
-func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
+func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, os.NewError("bad ClientKeyExchange")
+ return nil, errors.New("bad ClientKeyExchange")
}
- x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
+ x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
if x == nil {
- return nil, os.NewError("bad ClientKeyExchange")
+ return nil, errors.New("bad ClientKeyExchange")
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
- preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
return preMasterSecret, nil
}
-var errServerKeyExchange = os.NewError("invalid ServerKeyExchange")
+var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
-func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
if len(skx.key) < 4 {
return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return os.NewError("server selected unsupported curve")
+ return errors.New("server selected unsupported curve")
}
curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
@@ -194,14 +202,14 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
case curveP521:
ka.curve = elliptic.P521()
default:
- return os.NewError("server selected unsupported curve")
+ return errors.New("server selected unsupported curve")
}
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
return errServerKeyExchange
}
- ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
+ ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen])
if ka.x == nil {
return errServerKeyExchange
}
@@ -221,20 +229,20 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
}
-func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
if ka.curve == nil {
- return nil, nil, os.NewError("missing ServerKeyExchange message")
+ return nil, nil, errors.New("missing ServerKeyExchange message")
}
- priv, mx, my, err := ka.curve.GenerateKey(config.rand())
+ priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
if err != nil {
return nil, nil, err
}
x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
- preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
- serialized := ka.curve.Marshal(mx, my)
+ serialized := elliptic.Marshal(ka.curve, mx, my)
ckx := new(clientKeyExchangeMsg)
ckx.ciphertext = make([]byte, 1+len(serialized))
diff --git a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py
index c03eaa6ea..5692bd32f 100644
--- a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py
+++ b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py
@@ -35,6 +35,8 @@ for line in sys.stdin.readlines():
bs = line.split()
for b in bs:
currentBlock.append(int(b, 16))
+ elif line.startswith("|<7>| RB-PEEK: Read 1 bytes"):
+ currentBlock = currentBlock[:-1]
if len(currentBlock) > 0:
blocks.append(currentBlock)
diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go
index 478cf65f9..637ef03e2 100644
--- a/src/pkg/crypto/tls/prf.go
+++ b/src/pkg/crypto/tls/prf.go
@@ -9,7 +9,6 @@ import (
"crypto/md5"
"crypto/sha1"
"hash"
- "os"
)
// Split a premaster secret in two as specified in RFC 4346, section 5.
@@ -23,14 +22,14 @@ func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h := hmac.New(hash, secret)
h.Write(seed)
- a := h.Sum()
+ a := h.Sum(nil)
j := 0
for j < len(result) {
h.Reset()
h.Write(a)
h.Write(seed)
- b := h.Sum()
+ b := h.Sum(nil)
todo := len(b)
if j+todo > len(result) {
todo = len(result) - j
@@ -40,7 +39,7 @@ func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h.Reset()
h.Write(a)
- a = h.Sum()
+ a = h.Sum(nil)
}
}
@@ -63,6 +62,39 @@ func pRF10(result, secret, label, seed []byte) {
}
}
+// pRF30 implements the SSL 3.0 pseudo-random function, as defined in
+// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
+func pRF30(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New()
+ hashMD5 := md5.New()
+
+ done := 0
+ i := 0
+ // RFC5246 section 6.3 says that the largest PRF output needed is 128
+ // bytes. Since no more ciphersuites will be added to SSLv3, this will
+ // remain true. Each iteration gives us 16 bytes so 10 iterations will
+ // be sufficient.
+ var b [11]byte
+ for done < len(result) {
+ for j := 0; j <= i; j++ {
+ b[j] = 'A' + byte(i)
+ }
+
+ hashSHA1.Reset()
+ hashSHA1.Write(b[:i+1])
+ hashSHA1.Write(secret)
+ hashSHA1.Write(seed)
+ digest := hashSHA1.Sum(nil)
+
+ hashMD5.Reset()
+ hashMD5.Write(secret)
+ hashMD5.Write(digest)
+
+ done += copy(result[done:], hashMD5.Sum(nil))
+ i++
+ }
+}
+
const (
tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
@@ -77,19 +109,24 @@ var serverFinishedLabel = []byte("server finished")
// keysFromPreMasterSecret generates the connection keys from the pre master
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
// RFC 2246, section 6.3.
-func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+func keysFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ prf := pRF10
+ if version == versionSSL30 {
+ prf = pRF30
+ }
+
var seed [tlsRandomLength * 2]byte
copy(seed[0:len(clientRandom)], clientRandom)
copy(seed[len(clientRandom):], serverRandom)
masterSecret = make([]byte, masterSecretLength)
- pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+ prf(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
copy(seed[0:len(clientRandom)], serverRandom)
copy(seed[len(serverRandom):], clientRandom)
n := 2*macLen + 2*keyLen + 2*ivLen
keyMaterial := make([]byte, n)
- pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+ prf(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
clientMAC = keyMaterial[:macLen]
keyMaterial = keyMaterial[macLen:]
serverMAC = keyMaterial[:macLen]
@@ -104,6 +141,10 @@ func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byt
return
}
+func newFinishedHash(version uint16) finishedHash {
+ return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New(), version}
+}
+
// A finishedHash calculates the hash of a set of handshake messages suitable
// for including in a Finished message.
type finishedHash struct {
@@ -111,13 +152,10 @@ type finishedHash struct {
clientSHA1 hash.Hash
serverMD5 hash.Hash
serverSHA1 hash.Hash
+ version uint16
}
-func newFinishedHash() finishedHash {
- return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}
-}
-
-func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
+func (h finishedHash) Write(msg []byte) (n int, err error) {
h.clientMD5.Write(msg)
h.clientSHA1.Write(msg)
h.serverMD5.Write(msg)
@@ -125,9 +163,10 @@ func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
return len(msg), nil
}
-// finishedSum calculates the contents of the verify_data member of a Finished
-// message given the MD5 and SHA1 hashes of a set of handshake messages.
-func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
+// finishedSum10 calculates the contents of the verify_data member of a TLSv1
+// Finished message given the MD5 and SHA1 hashes of a set of handshake
+// messages.
+func finishedSum10(md5, sha1, label, masterSecret []byte) []byte {
seed := make([]byte, len(md5)+len(sha1))
copy(seed, md5)
copy(seed[len(md5):], sha1)
@@ -136,18 +175,61 @@ func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
return out
}
+// finishedSum30 calculates the contents of the verify_data member of a SSLv3
+// Finished message given the MD5 and SHA1 hashes of a set of handshake
+// messages.
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
+ md5.Write(magic[:])
+ md5.Write(masterSecret)
+ md5.Write(ssl30Pad1[:])
+ md5Digest := md5.Sum(nil)
+
+ md5.Reset()
+ md5.Write(masterSecret)
+ md5.Write(ssl30Pad2[:])
+ md5.Write(md5Digest)
+ md5Digest = md5.Sum(nil)
+
+ sha1.Write(magic[:])
+ sha1.Write(masterSecret)
+ sha1.Write(ssl30Pad1[:40])
+ sha1Digest := sha1.Sum(nil)
+
+ sha1.Reset()
+ sha1.Write(masterSecret)
+ sha1.Write(ssl30Pad2[:40])
+ sha1.Write(sha1Digest)
+ sha1Digest = sha1.Sum(nil)
+
+ ret := make([]byte, len(md5Digest)+len(sha1Digest))
+ copy(ret, md5Digest)
+ copy(ret[len(md5Digest):], sha1Digest)
+ return ret
+}
+
+var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
+var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
+
// clientSum returns the contents of the verify_data member of a client's
// Finished message.
func (h finishedHash) clientSum(masterSecret []byte) []byte {
- md5 := h.clientMD5.Sum()
- sha1 := h.clientSHA1.Sum()
- return finishedSum(md5, sha1, clientFinishedLabel, masterSecret)
+ if h.version == versionSSL30 {
+ return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic)
+ }
+
+ md5 := h.clientMD5.Sum(nil)
+ sha1 := h.clientSHA1.Sum(nil)
+ return finishedSum10(md5, sha1, clientFinishedLabel, masterSecret)
}
// serverSum returns the contents of the verify_data member of a server's
// Finished message.
func (h finishedHash) serverSum(masterSecret []byte) []byte {
- md5 := h.serverMD5.Sum()
- sha1 := h.serverSHA1.Sum()
- return finishedSum(md5, sha1, serverFinishedLabel, masterSecret)
+ if h.version == versionSSL30 {
+ return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic)
+ }
+
+ md5 := h.serverMD5.Sum(nil)
+ sha1 := h.serverSHA1.Sum(nil)
+ return finishedSum10(md5, sha1, serverFinishedLabel, masterSecret)
}
diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go
index f8c4acb9d..a32392cef 100644
--- a/src/pkg/crypto/tls/prf_test.go
+++ b/src/pkg/crypto/tls/prf_test.go
@@ -34,6 +34,7 @@ func TestSplitPreMasterSecret(t *testing.T) {
}
type testKeysFromTest struct {
+ version uint16
preMasterSecret string
clientRandom, serverRandom string
masterSecret string
@@ -47,7 +48,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
in, _ := hex.DecodeString(test.preMasterSecret)
clientRandom, _ := hex.DecodeString(test.clientRandom)
serverRandom, _ := hex.DecodeString(test.serverRandom)
- master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+ master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret(test.version, in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
masterString := hex.EncodeToString(master)
clientMACString := hex.EncodeToString(clientMAC)
serverMACString := hex.EncodeToString(serverMAC)
@@ -58,7 +59,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
serverMACString != test.serverMAC ||
clientKeyString != test.clientKey ||
serverKeyString != test.serverKey {
- t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverMACString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
+ t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s, %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverKeyString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
}
}
}
@@ -66,6 +67,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
var testKeysFromTests = []testKeysFromTest{
{
+ versionTLS10,
"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -78,6 +80,7 @@ var testKeysFromTests = []testKeysFromTest{
16,
},
{
+ versionTLS10,
"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -90,6 +93,7 @@ var testKeysFromTests = []testKeysFromTest{
16,
},
{
+ versionTLS10,
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -101,4 +105,17 @@ var testKeysFromTests = []testKeysFromTest{
20,
16,
},
+ {
+ versionSSL30,
+ "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
+ "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
+ "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
+ "a614863e56299dcffeea2938f22c2ba023768dbe4b3f6877bc9c346c6ae529b51d9cb87ff9695ea4d01f2205584405b2",
+ "2c450d5b6f6e2013ac6bea6a0b32200d4e1ffb94",
+ "7a7a7438769536f2fb1ae49a61f0703b79b2dc53",
+ "f8f6b26c10f12855c9aafb1e0e839ccf",
+ "2b9d4b4a60cb7f396780ebff50650419",
+ 20,
+ 16,
+ },
}
diff --git a/src/pkg/crypto/tls/root_test.go b/src/pkg/crypto/tls/root_test.go
new file mode 100644
index 000000000..e61c21851
--- /dev/null
+++ b/src/pkg/crypto/tls/root_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 tls
+
+import (
+ "crypto/x509"
+ "runtime"
+ "testing"
+)
+
+var tlsServers = []string{
+ "google.com",
+ "github.com",
+ "twitter.com",
+}
+
+func TestOSCertBundles(t *testing.T) {
+ if testing.Short() {
+ t.Logf("skipping certificate tests in short mode")
+ return
+ }
+
+ for _, addr := range tlsServers {
+ conn, err := Dial("tcp", addr+":443", &Config{ServerName: addr})
+ if err != nil {
+ t.Errorf("unable to verify %v: %v", addr, err)
+ continue
+ }
+ err = conn.Close()
+ if err != nil {
+ t.Error(err)
+ }
+ }
+}
+
+func TestCertHostnameVerifyWindows(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ return
+ }
+
+ if testing.Short() {
+ t.Logf("skipping certificate tests in short mode")
+ return
+ }
+
+ for _, addr := range tlsServers {
+ cfg := &Config{ServerName: "example.com"}
+ conn, err := Dial("tcp", addr+":443", cfg)
+ if err == nil {
+ conn.Close()
+ t.Errorf("should fail to verify for example.com: %v", addr)
+ continue
+ }
+ _, ok := err.(x509.HostnameError)
+ if !ok {
+ t.Errorf("error type mismatch, got: %v", err)
+ }
+ }
+}
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 4f0859fee..09df5ad44 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package tls partially implements the TLS 1.1 protocol, as specified in RFC
-// 4346.
+// Package tls partially implements TLS 1.0, as specified in RFC 2246.
package tls
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
+ "errors"
"io/ioutil"
"net"
- "os"
"strings"
)
@@ -33,16 +32,16 @@ func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
-// A Listener implements a network listener (net.Listener) for TLS connections.
-type Listener struct {
- listener net.Listener
- config *Config
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+ net.Listener
+ config *Config
}
// Accept waits for and returns the next incoming TLS connection.
// The returned connection c is a *tls.Conn.
-func (l *Listener) Accept() (c net.Conn, err os.Error) {
- c, err = l.listener.Accept()
+func (l *listener) Accept() (c net.Conn, err error) {
+ c, err = l.Listener.Accept()
if err != nil {
return
}
@@ -50,30 +49,24 @@ func (l *Listener) Accept() (c net.Conn, err os.Error) {
return
}
-// Close closes the listener.
-func (l *Listener) Close() os.Error { return l.listener.Close() }
-
-// Addr returns the listener's network address.
-func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
-
// NewListener creates a Listener which accepts connections from an inner
// Listener and wraps each connection with Server.
// The configuration config must be non-nil and must have
// at least one certificate.
-func NewListener(listener net.Listener, config *Config) (l *Listener) {
- l = new(Listener)
- l.listener = listener
+func NewListener(inner net.Listener, config *Config) net.Listener {
+ l := new(listener)
+ l.Listener = inner
l.config = config
- return
+ return l
}
// Listen creates a TLS listener accepting connections on the
// given network address using net.Listen.
// The configuration config must be non-nil and must have
// at least one certificate.
-func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
if config == nil || len(config.Certificates) == 0 {
- return nil, os.NewError("tls.Listen: no certificates in configuration")
+ return nil, errors.New("tls.Listen: no certificates in configuration")
}
l, err := net.Listen(network, laddr)
if err != nil {
@@ -88,7 +81,7 @@ func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
// Dial interprets a nil configuration as equivalent to
// the zero configuration; see the documentation of Config
// for the defaults.
-func Dial(network, addr string, config *Config) (*Conn, os.Error) {
+func Dial(network, addr string, config *Config) (*Conn, error) {
raddr := addr
c, err := net.Dial(network, raddr)
if err != nil {
@@ -104,7 +97,9 @@ func Dial(network, addr string, config *Config) (*Conn, os.Error) {
if config == nil {
config = defaultConfig()
}
- if config.ServerName != "" {
+ // If no ServerName is set, infer the ServerName
+ // from the hostname we're connecting to.
+ if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
c := *config
c.ServerName = hostname
@@ -120,7 +115,7 @@ func Dial(network, addr string, config *Config) (*Conn, os.Error) {
// LoadX509KeyPair reads and parses a public/private key pair from a pair of
// files. The files must contain PEM encoded data.
-func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
+func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
certPEMBlock, err := ioutil.ReadFile(certFile)
if err != nil {
return
@@ -134,7 +129,7 @@ func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.
// X509KeyPair parses a public/private key pair from a pair of
// PEM encoded data.
-func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Error) {
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
var certDERBlock *pem.Block
for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
@@ -147,20 +142,31 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if len(cert.Certificate) == 0 {
- err = os.NewError("crypto/tls: failed to parse certificate PEM data")
+ err = errors.New("crypto/tls: failed to parse certificate PEM data")
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
- err = os.NewError("crypto/tls: failed to parse key PEM data")
+ err = errors.New("crypto/tls: failed to parse key PEM data")
return
}
- key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
- if err != nil {
- err = os.NewError("crypto/tls: failed to parse key: " + err.String())
- return
+ // OpenSSL 0.9.8 generates PKCS#1 private keys by default, while
+ // OpenSSL 1.0.0 generates PKCS#8 keys. We try both.
+ var key *rsa.PrivateKey
+ if key, err = x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes); err != nil {
+ var privKey interface{}
+ if privKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes); err != nil {
+ err = errors.New("crypto/tls: failed to parse key: " + err.Error())
+ return
+ }
+
+ var ok bool
+ if key, ok = privKey.(*rsa.PrivateKey); !ok {
+ err = errors.New("crypto/tls: found non-RSA private key in PKCS#8 wrapping")
+ return
+ }
}
cert.PrivateKey = key
@@ -173,7 +179,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.NewError("crypto/tls: private key does not match public key")
+ err = errors.New("crypto/tls: private key does not match public key")
return
}
diff --git a/src/pkg/crypto/twofish/Makefile b/src/pkg/crypto/twofish/Makefile
deleted file mode 100644
index aec61659d..000000000
--- a/src/pkg/crypto/twofish/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/twofish
-GOFILES=\
- twofish.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/twofish/twofish.go b/src/pkg/crypto/twofish/twofish.go
deleted file mode 100644
index 2e537c606..000000000
--- a/src/pkg/crypto/twofish/twofish.go
+++ /dev/null
@@ -1,358 +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 twofish implements Bruce Schneier's Twofish encryption algorithm.
-package twofish
-
-// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
-
-// This code is a port of the LibTom C implementation.
-// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
-// LibTomCrypt is free for all purposes under the public domain.
-// It was heavily inspired by the go blowfish package.
-
-import (
- "os"
- "strconv"
-)
-
-// BlockSize is the constant block size of Twofish.
-const BlockSize = 16
-
-const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
-const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
-
-// A Cipher is an instance of Twofish encryption using a particular key.
-type Cipher struct {
- s [4][256]uint32
- k [40]uint32
-}
-
-type KeySizeError int
-
-func (k KeySizeError) String() string {
- return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
-}
-
-// NewCipher creates and returns a Cipher.
-// The key argument should be the Twofish key, 16, 24 or 32 bytes.
-func NewCipher(key []byte) (*Cipher, os.Error) {
- keylen := len(key)
-
- if keylen != 16 && keylen != 24 && keylen != 32 {
- return nil, KeySizeError(keylen)
- }
-
- // k is the number of 64 bit words in key
- k := keylen / 8
-
- // Create the S[..] words
- var S [4 * 4]byte
- for i := 0; i < k; i++ {
- // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
- for j, rsRow := range rs {
- for k, rsVal := range rsRow {
- S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
- }
- }
- }
-
- // Calculate subkeys
- c := new(Cipher)
- var tmp [4]byte
- for i := byte(0); i < 20; i++ {
- // A = h(p * 2x, Me)
- for j := range tmp {
- tmp[j] = 2 * i
- }
- A := h(tmp[:], key, 0)
-
- // B = rolc(h(p * (2x + 1), Mo), 8)
- for j := range tmp {
- tmp[j] = 2*i + 1
- }
- B := h(tmp[:], key, 1)
- B = rol(B, 8)
-
- c.k[2*i] = A + B
-
- // K[2i+1] = (A + 2B) <<< 9
- c.k[2*i+1] = rol(2*B+A, 9)
- }
-
- // Calculate sboxes
- switch k {
- case 2:
- for i := range c.s[0] {
- c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
- c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
- c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
- c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
- }
- case 3:
- for i := range c.s[0] {
- c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
- c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
- c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
- c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
- }
- default:
- for i := range c.s[0] {
- c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
- c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
- c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
- c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
- }
- }
-
- return c, nil
-}
-
-// Reset zeros the key data, so that it will no longer appear in the process's
-// memory.
-func (c *Cipher) Reset() {
- for i := range c.k {
- c.k[i] = 0
- }
- for i := range c.s {
- for j := 0; j < 256; j++ {
- c.s[i][j] = 0
- }
- }
-}
-
-// BlockSize returns the Twofish block size, 16 bytes.
-func (c *Cipher) BlockSize() int { return BlockSize }
-
-// store32l stores src in dst in little-endian form.
-func store32l(dst []byte, src uint32) {
- dst[0] = byte(src)
- dst[1] = byte(src >> 8)
- dst[2] = byte(src >> 16)
- dst[3] = byte(src >> 24)
- return
-}
-
-// load32l reads a little-endian uint32 from src.
-func load32l(src []byte) uint32 {
- return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
-}
-
-// rol returns x after a left circular rotation of y bits.
-func rol(x, y uint32) uint32 {
- return (x << (y & 31)) | (x >> (32 - (y & 31)))
-}
-
-// ror returns x after a right circular rotation of y bits.
-func ror(x, y uint32) uint32 {
- return (x >> (y & 31)) | (x << (32 - (y & 31)))
-}
-
-// The RS matrix. See [TWOFISH] 4.3
-var rs = [4][8]byte{
- {0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
- {0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
- {0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
- {0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
-}
-
-// sbox tables
-var sbox = [2][256]byte{
- {
- 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
- 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
- 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
- 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
- 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
- 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
- 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
- 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
- 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
- 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
- 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
- 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
- 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
- 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
- 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
- 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
- },
- {
- 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
- 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
- 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
- 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
- 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
- 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
- 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
- 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
- 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
- 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
- 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
- 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
- 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
- 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
- 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
- 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
- },
-}
-
-// gfMult returns a·b in GF(2^8)/p
-func gfMult(a, b byte, p uint32) byte {
- B := [2]uint32{0, uint32(b)}
- P := [2]uint32{0, p}
- var result uint32
-
- // branchless GF multiplier
- for i := 0; i < 7; i++ {
- result ^= B[a&1]
- a >>= 1
- B[1] = P[B[1]>>7] ^ (B[1] << 1)
- }
- result ^= B[a&1]
- return byte(result)
-}
-
-// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
-func mdsColumnMult(in byte, col int) uint32 {
- mul01 := in
- mul5B := gfMult(in, 0x5B, mdsPolynomial)
- mulEF := gfMult(in, 0xEF, mdsPolynomial)
-
- switch col {
- case 0:
- return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
- case 1:
- return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
- case 2:
- return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
- case 3:
- return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
- }
-
- panic("unreachable")
-}
-
-// h implements the S-box generation function. See [TWOFISH] 4.3.5
-func h(in, key []byte, offset int) uint32 {
- var y [4]byte
- for x := range y {
- y[x] = in[x]
- }
- switch len(key) / 8 {
- case 4:
- y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
- y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
- y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
- y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
- fallthrough
- case 3:
- y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
- y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
- y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
- y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
- fallthrough
- case 2:
- y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
- y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
- y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
- y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
- }
- // [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
- var mdsMult uint32
- for i := range y {
- mdsMult ^= mdsColumnMult(y[i], i)
- }
- return mdsMult
-}
-
-// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
-// Note that for amounts of data larger than a block,
-// it is not safe to just call Encrypt on successive blocks;
-// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
-func (c *Cipher) Encrypt(dst, src []byte) {
- S1 := c.s[0]
- S2 := c.s[1]
- S3 := c.s[2]
- S4 := c.s[3]
-
- // Load input
- ia := load32l(src[0:4])
- ib := load32l(src[4:8])
- ic := load32l(src[8:12])
- id := load32l(src[12:16])
-
- // Pre-whitening
- ia ^= c.k[0]
- ib ^= c.k[1]
- ic ^= c.k[2]
- id ^= c.k[3]
-
- for i := 0; i < 8; i++ {
- k := c.k[8+i*4 : 12+i*4]
- t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
- t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
- ic = ror(ic^(t1+k[0]), 1)
- id = rol(id, 1) ^ (t2 + t1 + k[1])
-
- t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
- t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
- ia = ror(ia^(t1+k[2]), 1)
- ib = rol(ib, 1) ^ (t2 + t1 + k[3])
- }
-
- // Output with "undo last swap"
- ta := ic ^ c.k[4]
- tb := id ^ c.k[5]
- tc := ia ^ c.k[6]
- td := ib ^ c.k[7]
-
- store32l(dst[0:4], ta)
- store32l(dst[4:8], tb)
- store32l(dst[8:12], tc)
- store32l(dst[12:16], td)
-}
-
-// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
-func (c *Cipher) Decrypt(dst, src []byte) {
- S1 := c.s[0]
- S2 := c.s[1]
- S3 := c.s[2]
- S4 := c.s[3]
-
- // Load input
- ta := load32l(src[0:4])
- tb := load32l(src[4:8])
- tc := load32l(src[8:12])
- td := load32l(src[12:16])
-
- // Undo undo final swap
- ia := tc ^ c.k[6]
- ib := td ^ c.k[7]
- ic := ta ^ c.k[4]
- id := tb ^ c.k[5]
-
- for i := 8; i > 0; i-- {
- k := c.k[4+i*4 : 8+i*4]
- t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
- t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
- ia = rol(ia, 1) ^ (t1 + k[2])
- ib = ror(ib^(t2+t1+k[3]), 1)
-
- t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
- t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
- ic = rol(ic, 1) ^ (t1 + k[0])
- id = ror(id^(t2+t1+k[1]), 1)
- }
-
- // Undo pre-whitening
- ia ^= c.k[0]
- ib ^= c.k[1]
- ic ^= c.k[2]
- id ^= c.k[3]
-
- store32l(dst[0:4], ia)
- store32l(dst[4:8], ib)
- store32l(dst[8:12], ic)
- store32l(dst[12:16], id)
-}
diff --git a/src/pkg/crypto/twofish/twofish_test.go b/src/pkg/crypto/twofish/twofish_test.go
deleted file mode 100644
index 303081f3f..000000000
--- a/src/pkg/crypto/twofish/twofish_test.go
+++ /dev/null
@@ -1,129 +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 twofish
-
-import (
- "bytes"
- "testing"
-)
-
-var qbox = [2][4][16]byte{
- {
- {0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4},
- {0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD},
- {0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1},
- {0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA},
- },
- {
- {0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5},
- {0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8},
- {0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF},
- {0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA},
- },
-}
-
-// genSbox generates the variable sbox
-func genSbox(qi int, x byte) byte {
- a0, b0 := x/16, x%16
- for i := 0; i < 2; i++ {
- a1 := a0 ^ b0
- b1 := (a0 ^ ((b0 << 3) | (b0 >> 1)) ^ (a0 << 3)) & 15
- a0 = qbox[qi][2*i][a1]
- b0 = qbox[qi][2*i+1][b1]
- }
- return (b0 << 4) + a0
-}
-
-func TestSbox(t *testing.T) {
- for n := range sbox {
- for m := range sbox[n] {
- if genSbox(n, byte(m)) != sbox[n][m] {
- t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m)))
- }
- }
- }
-}
-
-var testVectors = []struct {
- key []byte
- dec []byte
- enc []byte
-}{
- // These tests are extracted from LibTom
- {
- []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
- []byte{0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19},
- []byte{0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3},
- },
- {
- []byte{0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
- 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44},
- []byte{0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2},
- []byte{0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65},
- },
- {
- []byte{0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
- 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F},
- []byte{0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6},
- []byte{0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA},
- },
- // These test are derived from http://www.schneier.com/code/ecb_ival.txt
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
- },
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- },
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48},
- },
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
- },
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20},
- },
-}
-
-func TestCipher(t *testing.T) {
- for n, tt := range testVectors {
- // Test if the plaintext (dec) is encrypts to the given
- // ciphertext (enc) using the given key. Test also if enc can
- // be decrypted again into dec.
- c, err := NewCipher(tt.key)
- if err != nil {
- t.Errorf("#%d: NewCipher: %v", n, err)
- return
- }
-
- buf := make([]byte, 16)
- c.Encrypt(buf, tt.dec)
- if !bytes.Equal(buf, tt.enc) {
- t.Errorf("#%d: encrypt = %x want %x", n, buf, tt.enc)
- }
- c.Decrypt(buf, tt.enc)
- if !bytes.Equal(buf, tt.dec) {
- t.Errorf("#%d: decrypt = %x want %x", n, buf, tt.dec)
- }
-
- // Test that 16 zero bytes, encrypted 1000 times then decrypted
- // 1000 times results in zero bytes again.
- zero := make([]byte, 16)
- buf = make([]byte, 16)
- for i := 0; i < 1000; i++ {
- c.Encrypt(buf, buf)
- }
- for i := 0; i < 1000; i++ {
- c.Decrypt(buf, buf)
- }
- if !bytes.Equal(buf, zero) {
- t.Errorf("#%d: encrypt/decrypt 1000: have %x want %x", n, buf, zero)
- }
- }
-}
diff --git a/src/pkg/crypto/x509/Makefile b/src/pkg/crypto/x509/Makefile
deleted file mode 100644
index 14ffd095f..000000000
--- a/src/pkg/crypto/x509/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/x509
-GOFILES=\
- cert_pool.go\
- verify.go\
- x509.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/x509/cert_pool.go b/src/pkg/crypto/x509/cert_pool.go
index 16cd92efc..616a0b3c1 100644
--- a/src/pkg/crypto/x509/cert_pool.go
+++ b/src/pkg/crypto/x509/cert_pool.go
@@ -5,12 +5,10 @@
package x509
import (
- "crypto/x509/pkix"
"encoding/pem"
- "strings"
)
-// Roots is a set of certificates.
+// CertPool is a set of certificates.
type CertPool struct {
bySubjectKeyId map[string][]int
byName map[string][]int
@@ -26,21 +24,20 @@ func NewCertPool() *CertPool {
}
}
-func nameToKey(name *pkix.Name) string {
- return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
-}
-
// findVerifiedParents attempts to find certificates in s which have signed the
// given certificate. If no such certificate can be found or the signature
// doesn't match, it returns nil.
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int) {
+ if s == nil {
+ return
+ }
var candidates []int
if len(cert.AuthorityKeyId) > 0 {
candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
}
if len(candidates) == 0 {
- candidates = s.byName[nameToKey(&cert.Issuer)]
+ candidates = s.byName[string(cert.RawIssuer)]
}
for _, c := range candidates {
@@ -72,15 +69,15 @@ func (s *CertPool) AddCert(cert *Certificate) {
keyId := string(cert.SubjectKeyId)
s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
}
- name := nameToKey(&cert.Subject)
+ name := string(cert.RawSubject)
s.byName[name] = append(s.byName[name], n)
}
-// AppendCertsFromPEM attempts to parse a series of PEM encoded root
-// certificates. It appends any certificates found to s and returns true if any
-// certificates were successfully parsed.
+// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
+// It appends any certificates found to s and returns true if any certificates
+// were successfully parsed.
//
-// On many Linux systems, /etc/ssl/cert.pem will contains the system wide set
+// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
// of root CAs in a format suitable for this function.
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
for len(pemCerts) > 0 {
@@ -104,3 +101,13 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
return
}
+
+// Subjects returns a list of the DER-encoded subjects of
+// all of the certificates in the pool.
+func (s *CertPool) Subjects() (res [][]byte) {
+ res = make([][]byte, len(s.certs))
+ for i, c := range s.certs {
+ res[i] = c.RawSubject
+ }
+ return
+}
diff --git a/src/pkg/crypto/x509/pkcs1.go b/src/pkg/crypto/x509/pkcs1.go
new file mode 100644
index 000000000..873d3966e
--- /dev/null
+++ b/src/pkg/crypto/x509/pkcs1.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 x509
+
+import (
+ "crypto/rsa"
+ "encoding/asn1"
+ "errors"
+ "math/big"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+ Version int
+ N *big.Int
+ E int
+ D *big.Int
+ P *big.Int
+ Q *big.Int
+ // We ignore these values, if present, because rsa will calculate them.
+ Dp *big.Int `asn1:"optional"`
+ Dq *big.Int `asn1:"optional"`
+ Qinv *big.Int `asn1:"optional"`
+
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
+}
+
+type pkcs1AdditionalRSAPrime struct {
+ Prime *big.Int
+
+ // We ignore these values because rsa will calculate them.
+ Exp *big.Int
+ Coeff *big.Int
+}
+
+// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
+func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
+ var priv pkcs1PrivateKey
+ rest, err := asn1.Unmarshal(der, &priv)
+ if len(rest) > 0 {
+ err = asn1.SyntaxError{Msg: "trailing data"}
+ return
+ }
+ if err != nil {
+ return
+ }
+
+ if priv.Version > 1 {
+ return nil, errors.New("x509: unsupported private key version")
+ }
+
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, errors.New("private key contains zero or negative value")
+ }
+
+ key = new(rsa.PrivateKey)
+ key.PublicKey = rsa.PublicKey{
+ E: priv.E,
+ N: priv.N,
+ }
+
+ key.D = priv.D
+ key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
+ for i, a := range priv.AdditionalPrimes {
+ if a.Prime.Sign() <= 0 {
+ return nil, errors.New("private key contains zero or negative prime")
+ }
+ key.Primes[i+2] = a.Prime
+ // We ignore the other two values because rsa will calculate
+ // them as needed.
+ }
+
+ err = key.Validate()
+ if err != nil {
+ return nil, err
+ }
+ key.Precompute()
+
+ return
+}
+
+// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+ key.Precompute()
+
+ version := 0
+ if len(key.Primes) > 2 {
+ version = 1
+ }
+
+ priv := pkcs1PrivateKey{
+ Version: version,
+ N: key.N,
+ E: key.PublicKey.E,
+ 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([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
+ for i, values := range key.Precomputed.CRTValues {
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
+ }
+
+ b, _ := asn1.Marshal(priv)
+ return b
+}
+
+// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key.
+type rsaPublicKey struct {
+ N *big.Int
+ E int
+}
diff --git a/src/pkg/crypto/x509/pkcs8.go b/src/pkg/crypto/x509/pkcs8.go
new file mode 100644
index 000000000..4d8e0518e
--- /dev/null
+++ b/src/pkg/crypto/x509/pkcs8.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+)
+
+// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn.
+type pkcs8 struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ PrivateKey []byte
+ // optional attributes omitted.
+}
+
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
+// http://www.rsa.com/rsalabs/node.asp?id=2130
+func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
+ var privKey pkcs8
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ return nil, err
+ }
+ switch {
+ case privKey.Algo.Algorithm.Equal(oidRSA):
+ key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
+ if err != nil {
+ return nil, errors.New("crypto/x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
+ }
+ return key, nil
+ default:
+ return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+ }
+
+ panic("unreachable")
+}
diff --git a/src/pkg/crypto/x509/pkcs8_test.go b/src/pkg/crypto/x509/pkcs8_test.go
new file mode 100644
index 000000000..372005f90
--- /dev/null
+++ b/src/pkg/crypto/x509/pkcs8_test.go
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
+
+func TestPKCS8(t *testing.T) {
+ derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex)
+ _, err := ParsePKCS8PrivateKey(derBytes)
+ if err != nil {
+ t.Errorf("failed to decode PKCS8 key: %s", err)
+ }
+}
diff --git a/src/pkg/crypto/x509/pkix/Makefile b/src/pkg/crypto/x509/pkix/Makefile
deleted file mode 100644
index e29b74c01..000000000
--- a/src/pkg/crypto/x509/pkix/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../../Make.inc
-
-TARG=crypto/x509/pkix
-GOFILES=\
- pkix.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
index 266fd557a..738659011 100644
--- a/src/pkg/crypto/x509/pkix/pkix.go
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -7,8 +7,8 @@
package pkix
import (
- "asn1"
- "big"
+ "encoding/asn1"
+ "math/big"
"time"
)
@@ -23,6 +23,8 @@ type RDNSequence []RelativeDistinguishedNameSET
type RelativeDistinguishedNameSET []AttributeTypeAndValue
+// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
+// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
type AttributeTypeAndValue struct {
Type asn1.ObjectIdentifier
Value interface{}
@@ -43,6 +45,8 @@ type Name struct {
Locality, Province []string
StreetAddress, PostalCode []string
SerialNumber, CommonName string
+
+ Names []AttributeTypeAndValue
}
func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
@@ -51,6 +55,7 @@ func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
continue
}
atv := rdn[0]
+ n.Names = append(n.Names, atv)
value, ok := atv.Value.(string)
if !ok {
continue
@@ -139,10 +144,9 @@ type CertificateList struct {
SignatureValue asn1.BitString
}
-// HasExpired returns true iff currentTimeSeconds is past the expiry time of
-// certList.
-func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
- return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+// HasExpired returns true iff now is past the expiry time of certList.
+func (certList *CertificateList) HasExpired(now time.Time) bool {
+ return now.After(certList.TBSCertList.NextUpdate)
}
// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
@@ -152,8 +156,8 @@ type TBSCertificateList struct {
Version int `asn1:"optional,default:2"`
Signature AlgorithmIdentifier
Issuer RDNSequence
- ThisUpdate *time.Time
- NextUpdate *time.Time
+ ThisUpdate time.Time
+ NextUpdate time.Time
RevokedCertificates []RevokedCertificate `asn1:"optional"`
Extensions []Extension `asn1:"tag:0,optional,explicit"`
}
@@ -162,6 +166,6 @@ type TBSCertificateList struct {
// 5280, section 5.1.
type RevokedCertificate struct {
SerialNumber *big.Int
- RevocationTime *time.Time
+ RevocationTime time.Time
Extensions []Extension `asn1:"optional"`
}
diff --git a/src/pkg/crypto/x509/root.go b/src/pkg/crypto/x509/root.go
new file mode 100644
index 000000000..8aae14e09
--- /dev/null
+++ b/src/pkg/crypto/x509/root.go
@@ -0,0 +1,17 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import "sync"
+
+var (
+ once sync.Once
+ systemRoots *CertPool
+)
+
+func systemRootsPool() *CertPool {
+ once.Do(initSystemRoots)
+ return systemRoots
+}
diff --git a/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
new file mode 100644
index 000000000..0f99581e8
--- /dev/null
+++ b/src/pkg/crypto/x509/root_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.
+
+package x509
+
+/*
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+//
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
+ if (pemRoots == NULL) {
+ return -1;
+ }
+
+ CFArrayRef certs = NULL;
+ OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+ if (err != noErr) {
+ return -1;
+ }
+
+ CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+ int i, ncerts = CFArrayGetCount(certs);
+ for (i = 0; i < ncerts; i++) {
+ CFDataRef data = NULL;
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+ if (cert == NULL) {
+ continue;
+ }
+
+ // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+ // Once we support weak imports via cgo we should prefer that, and fall back to this
+ // for older systems.
+ err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+ if (err != noErr) {
+ continue;
+ }
+
+ if (data != NULL) {
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFRelease(data);
+ }
+ }
+
+ CFRelease(certs);
+
+ *pemRoots = combinedData;
+ return 0;
+}
+*/
+import "C"
+import "unsafe"
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ roots := NewCertPool()
+
+ var data C.CFDataRef = nil
+ err := C.FetchPEMRoots(&data)
+ if err != -1 {
+ defer C.CFRelease(C.CFTypeRef(data))
+ buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
+ roots.AppendCertsFromPEM(buf)
+ }
+
+ systemRoots = roots
+}
diff --git a/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go
new file mode 100644
index 000000000..568004108
--- /dev/null
+++ b/src/pkg/crypto/x509/root_stub.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.
+
+// +build plan9 darwin,!cgo
+
+package x509
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ systemRoots = NewCertPool()
+}
diff --git a/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go
new file mode 100644
index 000000000..76e79f494
--- /dev/null
+++ b/src/pkg/crypto/x509/root_unix.go
@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd linux openbsd netbsd
+
+package x509
+
+import "io/ioutil"
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/etc/ssl/certs/ca-certificates.crt", // Linux etc
+ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
+ "/etc/ssl/ca-bundle.pem", // OpenSUSE
+ "/etc/ssl/cert.pem", // OpenBSD
+ "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
+}
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ roots := NewCertPool()
+ for _, file := range certFiles {
+ data, err := ioutil.ReadFile(file)
+ if err == nil {
+ roots.AppendCertsFromPEM(data)
+ break
+ }
+ }
+
+ systemRoots = roots
+}
diff --git a/src/pkg/crypto/x509/root_windows.go b/src/pkg/crypto/x509/root_windows.go
new file mode 100644
index 000000000..7e8f2af4b
--- /dev/null
+++ b/src/pkg/crypto/x509/root_windows.go
@@ -0,0 +1,226 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "errors"
+ "syscall"
+ "unsafe"
+)
+
+// Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
+// certificate store containing itself and all of the intermediate certificates specified
+// in the opts.Intermediates CertPool.
+//
+// A pointer to the in-memory store is available in the returned CertContext's Store field.
+// The store is automatically freed when the CertContext is freed using
+// syscall.CertFreeCertificateContext.
+func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
+ var storeCtx *syscall.CertContext
+
+ leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(leafCtx)
+
+ handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertCloseStore(handle, 0)
+
+ err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts.Intermediates != nil {
+ for _, intermediate := range opts.Intermediates.certs {
+ ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
+ if err != nil {
+ return nil, err
+ }
+
+ err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
+ syscall.CertFreeCertificateContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return storeCtx, nil
+}
+
+// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
+func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
+ if simpleChain == nil || count == 0 {
+ return nil, errors.New("x509: invalid simple chain")
+ }
+
+ simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
+ lastChain := simpleChains[count-1]
+ elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
+ for i := 0; i < int(lastChain.NumElements); i++ {
+ // Copy the buf, since ParseCertificate does not create its own copy.
+ cert := elements[i].CertContext
+ encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
+ buf := make([]byte, cert.Length)
+ copy(buf, encodedCert[:])
+ parsedCert, err := ParseCertificate(buf)
+ if err != nil {
+ return nil, err
+ }
+ chain = append(chain, parsedCert)
+ }
+
+ return chain, nil
+}
+
+// checkChainTrustStatus checks the trust status of the certificate chain, translating
+// any errors it finds into Go errors in the process.
+func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
+ if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
+ status := chainCtx.TrustStatus.ErrorStatus
+ switch status {
+ case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
+ return CertificateInvalidError{c, Expired}
+ default:
+ return UnknownAuthorityError{c}
+ }
+ }
+ return nil
+}
+
+// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
+// use as a certificate chain for a SSL/TLS server.
+func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
+ sslPara := &syscall.SSLExtraCertChainPolicyPara{
+ AuthType: syscall.AUTHTYPE_SERVER,
+ ServerName: syscall.StringToUTF16Ptr(opts.DNSName),
+ }
+ sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
+
+ para := &syscall.CertChainPolicyPara{
+ ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
+ }
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ status := syscall.CertChainPolicyStatus{}
+ err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
+ if err != nil {
+ return err
+ }
+
+ // TODO(mkrautz): use the lChainIndex and lElementIndex fields
+ // of the CertChainPolicyStatus to provide proper context, instead
+ // using c.
+ if status.Error != 0 {
+ switch status.Error {
+ case syscall.CERT_E_EXPIRED:
+ return CertificateInvalidError{c, Expired}
+ case syscall.CERT_E_CN_NO_MATCH:
+ return HostnameError{c, opts.DNSName}
+ case syscall.CERT_E_UNTRUSTEDROOT:
+ return UnknownAuthorityError{c}
+ default:
+ return UnknownAuthorityError{c}
+ }
+ }
+
+ return nil
+}
+
+// systemVerify is like Verify, except that it uses CryptoAPI calls
+// to build certificate chains and verify them.
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ hasDNSName := opts != nil && len(opts.DNSName) > 0
+
+ storeCtx, err := createStoreContext(c, opts)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(storeCtx)
+
+ para := new(syscall.CertChainPara)
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ // If there's a DNSName set in opts, assume we're verifying
+ // a certificate from a TLS server.
+ if hasDNSName {
+ oids := []*byte{
+ &syscall.OID_PKIX_KP_SERVER_AUTH[0],
+ // Both IE and Chrome allow certificates with
+ // Server Gated Crypto as well. Some certificates
+ // in the wild require them.
+ &syscall.OID_SERVER_GATED_CRYPTO[0],
+ &syscall.OID_SGC_NETSCAPE[0],
+ }
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
+ para.RequestedUsage.Usage.Length = uint32(len(oids))
+ para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
+ } else {
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
+ para.RequestedUsage.Usage.Length = 0
+ para.RequestedUsage.Usage.UsageIdentifiers = nil
+ }
+
+ var verifyTime *syscall.Filetime
+ if opts != nil && !opts.CurrentTime.IsZero() {
+ ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
+ verifyTime = &ft
+ }
+
+ // CertGetCertificateChain will traverse Windows's root stores
+ // in an attempt to build a verified certificate chain. Once
+ // it has found a verified chain, it stops. MSDN docs on
+ // CERT_CHAIN_CONTEXT:
+ //
+ // When a CERT_CHAIN_CONTEXT is built, the first simple chain
+ // begins with an end certificate and ends with a self-signed
+ // certificate. If that self-signed certificate is not a root
+ // or otherwise trusted certificate, an attempt is made to
+ // build a new chain. CTLs are used to create the new chain
+ // beginning with the self-signed certificate from the original
+ // chain as the end certificate of the new chain. This process
+ // continues building additional simple chains until the first
+ // self-signed certificate is a trusted certificate or until
+ // an additional simple chain cannot be built.
+ //
+ // The result is that we'll only get a single trusted chain to
+ // return to our caller.
+ var chainCtx *syscall.CertChainContext
+ err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateChain(chainCtx)
+
+ err = checkChainTrustStatus(c, chainCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if hasDNSName {
+ err = checkChainSSLServerPolicy(c, chainCtx, opts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
+ if err != nil {
+ return nil, err
+ }
+
+ chains = append(chains, chain)
+
+ return chains, nil
+}
+
+func initSystemRoots() {
+ systemRoots = NewCertPool()
+}
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 4c0fecccb..307c5ef03 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -5,9 +5,10 @@
package x509
import (
- "os"
+ "runtime"
"strings"
"time"
+ "unicode/utf8"
)
type InvalidReason int
@@ -23,6 +24,9 @@ const (
// certificate has a name constraint which doesn't include the name
// being checked.
CANotAuthorizedForThisName
+ // TooManyIntermediates results when a path length constraint is
+ // violated.
+ TooManyIntermediates
)
// CertificateInvalidError results when an odd error occurs. Users of this
@@ -32,7 +36,7 @@ type CertificateInvalidError struct {
Reason InvalidReason
}
-func (e CertificateInvalidError) String() string {
+func (e CertificateInvalidError) Error() string {
switch e.Reason {
case NotAuthorizedToSign:
return "x509: certificate is not authorized to sign other other certificates"
@@ -40,6 +44,8 @@ func (e CertificateInvalidError) String() string {
return "x509: certificate has expired or is not yet valid"
case CANotAuthorizedForThisName:
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
+ case TooManyIntermediates:
+ return "x509: too many intermediates for path length constraint"
}
return "x509: unknown error"
}
@@ -51,7 +57,7 @@ type HostnameError struct {
Host string
}
-func (h HostnameError) String() string {
+func (h HostnameError) Error() string {
var valid string
c := h.Certificate
if len(c.DNSNames) > 0 {
@@ -67,7 +73,7 @@ type UnknownAuthorityError struct {
cert *Certificate
}
-func (e UnknownAuthorityError) String() string {
+func (e UnknownAuthorityError) Error() string {
return "x509: certificate signed by unknown authority"
}
@@ -76,8 +82,8 @@ func (e UnknownAuthorityError) String() string {
type VerifyOptions struct {
DNSName string
Intermediates *CertPool
- Roots *CertPool
- CurrentTime int64 // if 0, the current system time is used.
+ Roots *CertPool // if nil, the system roots are used
+ CurrentTime time.Time // if zero, the current time is used
}
const (
@@ -87,9 +93,12 @@ const (
)
// isValid performs validity checks on the c.
-func (c *Certificate) isValid(certType int, opts *VerifyOptions) os.Error {
- if opts.CurrentTime < c.NotBefore.Seconds() ||
- opts.CurrentTime > c.NotAfter.Seconds() {
+func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
+ now := opts.CurrentTime
+ if now.IsZero() {
+ now = time.Now()
+ }
+ if now.Before(c.NotBefore) || now.After(c.NotAfter) {
return CertificateInvalidError{c, Expired}
}
@@ -127,29 +136,44 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) os.Error {
return CertificateInvalidError{c, NotAuthorizedToSign}
}
+ if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
+ numIntermediates := len(currentChain) - 1
+ if numIntermediates > c.MaxPathLen {
+ return CertificateInvalidError{c, TooManyIntermediates}
+ }
+ }
+
return nil
}
// Verify attempts to verify c by building one or more chains from c to a
-// certificate in opts.roots, using certificates in opts.Intermediates if
-// needed. If successful, it returns one or chains where the first element of
-// the chain is c and the last element is from opts.Roots.
+// certificate in opts.Roots, using certificates in opts.Intermediates if
+// needed. If successful, it returns one or more chains where the first
+// element of the chain is c and the last element is from opts.Roots.
//
// WARNING: this doesn't do any revocation checking.
-func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err os.Error) {
- if opts.CurrentTime == 0 {
- opts.CurrentTime = time.Seconds()
+func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
+ // Use Windows's own verification and chain building.
+ if opts.Roots == nil && runtime.GOOS == "windows" {
+ return c.systemVerify(&opts)
+ }
+
+ if opts.Roots == nil {
+ opts.Roots = systemRootsPool()
}
- err = c.isValid(leafCertificate, &opts)
+
+ err = c.isValid(leafCertificate, nil, &opts)
if err != nil {
return
}
+
if len(opts.DNSName) > 0 {
err = c.VerifyHostname(opts.DNSName)
if err != nil {
return
}
}
+
return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
}
@@ -160,10 +184,10 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
return n
}
-func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err os.Error) {
+func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
for _, rootNum := range opts.Roots.findVerifiedParents(c) {
root := opts.Roots.certs[rootNum]
- err = root.isValid(rootCertificate, opts)
+ err = root.isValid(rootCertificate, currentChain, opts)
if err != nil {
continue
}
@@ -178,7 +202,7 @@ nextIntermediate:
continue nextIntermediate
}
}
- err = intermediate.isValid(intermediateCertificate, opts)
+ err = intermediate.isValid(intermediateCertificate, currentChain, opts)
if err != nil {
continue
}
@@ -226,17 +250,51 @@ func matchHostnames(pattern, host string) bool {
return true
}
+// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
+// an explicitly ASCII function to avoid any sharp corners resulting from
+// performing Unicode operations on DNS labels.
+func toLowerCaseASCII(in string) string {
+ // If the string is already lower-case then there's nothing to do.
+ isAlreadyLowerCase := true
+ for _, c := range in {
+ if c == utf8.RuneError {
+ // If we get a UTF-8 error then there might be
+ // upper-case ASCII bytes in the invalid sequence.
+ isAlreadyLowerCase = false
+ break
+ }
+ if 'A' <= c && c <= 'Z' {
+ isAlreadyLowerCase = false
+ break
+ }
+ }
+
+ if isAlreadyLowerCase {
+ return in
+ }
+
+ out := []byte(in)
+ for i, c := range out {
+ if 'A' <= c && c <= 'Z' {
+ out[i] += 'a' - 'A'
+ }
+ }
+ return string(out)
+}
+
// VerifyHostname returns nil if c is a valid certificate for the named host.
-// Otherwise it returns an os.Error describing the mismatch.
-func (c *Certificate) VerifyHostname(h string) os.Error {
+// Otherwise it returns an error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) error {
+ lowered := toLowerCaseASCII(h)
+
if len(c.DNSNames) > 0 {
for _, match := range c.DNSNames {
- if matchHostnames(match, h) {
+ if matchHostnames(toLowerCaseASCII(match), lowered) {
return nil
}
}
// If Subject Alt Name is given, we ignore the common name.
- } else if matchHostnames(c.Subject.CommonName, h) {
+ } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
return nil
}
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index 111f60eb1..7b171b291 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -5,10 +5,13 @@
package x509
import (
+ "crypto/x509/pkix"
"encoding/pem"
- "os"
+ "errors"
+ "runtime"
"strings"
"testing"
+ "time"
)
type verifyTest struct {
@@ -17,8 +20,9 @@ type verifyTest struct {
roots []string
currentTime int64
dnsName string
+ systemSkip bool
- errorCallback func(*testing.T, int, os.Error) bool
+ errorCallback func(*testing.T, int, error) bool
expectedChains [][]string
}
@@ -31,7 +35,18 @@ var verifyTests = []verifyTest{
dnsName: "www.google.com",
expectedChains: [][]string{
- []string{"Google", "Thawte", "VeriSign"},
+ {"Google", "Thawte", "VeriSign"},
+ },
+ },
+ {
+ leaf: googleLeaf,
+ intermediates: []string{thawteIntermediate},
+ roots: []string{verisignRoot},
+ currentTime: 1302726541,
+ dnsName: "WwW.GooGLE.coM",
+
+ expectedChains: [][]string{
+ {"Google", "Thawte", "VeriSign"},
},
},
{
@@ -58,6 +73,9 @@ var verifyTests = []verifyTest{
currentTime: 1302726541,
dnsName: "www.google.com",
+ // Skip when using systemVerify, since Windows
+ // *will* find the missing intermediate cert.
+ systemSkip: true,
errorCallback: expectAuthorityUnknown,
},
{
@@ -68,7 +86,7 @@ var verifyTests = []verifyTest{
dnsName: "www.google.com",
expectedChains: [][]string{
- []string{"Google", "Thawte", "VeriSign"},
+ {"Google", "Thawte", "VeriSign"},
},
},
{
@@ -78,7 +96,7 @@ var verifyTests = []verifyTest{
currentTime: 1302726541,
expectedChains: [][]string{
- []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
},
},
{
@@ -87,14 +105,17 @@ var verifyTests = []verifyTest{
roots: []string{startComRoot},
currentTime: 1302726541,
+ // Skip when using systemVerify, since Windows
+ // can only return a single chain to us (for now).
+ systemSkip: true,
expectedChains: [][]string{
- []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
- []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
},
},
}
-func expectHostnameError(t *testing.T, i int, err os.Error) (ok bool) {
+func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
if _, ok := err.(HostnameError); !ok {
t.Errorf("#%d: error was not a HostnameError: %s", i, err)
return false
@@ -102,7 +123,7 @@ func expectHostnameError(t *testing.T, i int, err os.Error) (ok bool) {
return true
}
-func expectExpired(t *testing.T, i int, err os.Error) (ok bool) {
+func expectExpired(t *testing.T, i int, err error) (ok bool) {
if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
t.Errorf("#%d: error was not Expired: %s", i, err)
return false
@@ -110,7 +131,7 @@ func expectExpired(t *testing.T, i int, err os.Error) (ok bool) {
return true
}
-func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
+func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {
if _, ok := err.(UnknownAuthorityError); !ok {
t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err)
return false
@@ -118,28 +139,34 @@ func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
return true
}
-func certificateFromPEM(pemBytes string) (*Certificate, os.Error) {
+func certificateFromPEM(pemBytes string) (*Certificate, error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
- return nil, os.NewError("failed to decode PEM")
+ return nil, errors.New("failed to decode PEM")
}
return ParseCertificate(block.Bytes)
}
-func TestVerify(t *testing.T) {
+func testVerify(t *testing.T, useSystemRoots bool) {
for i, test := range verifyTests {
+ if useSystemRoots && test.systemSkip {
+ continue
+ }
+
opts := VerifyOptions{
- Roots: NewCertPool(),
Intermediates: NewCertPool(),
DNSName: test.dnsName,
- CurrentTime: test.currentTime,
+ CurrentTime: time.Unix(test.currentTime, 0),
}
- for j, root := range test.roots {
- ok := opts.Roots.AppendCertsFromPEM([]byte(root))
- if !ok {
- t.Errorf("#%d: failed to parse root #%d", i, j)
- return
+ if !useSystemRoots {
+ opts.Roots = NewCertPool()
+ for j, root := range test.roots {
+ ok := opts.Roots.AppendCertsFromPEM([]byte(root))
+ if !ok {
+ t.Errorf("#%d: failed to parse root #%d", i, j)
+ return
+ }
}
}
@@ -200,6 +227,19 @@ func TestVerify(t *testing.T) {
}
}
+func TestGoVerify(t *testing.T) {
+ testVerify(t, false)
+}
+
+func TestSystemVerify(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ t.Logf("skipping verify test using system APIs on %q", runtime.GOOS)
+ return
+ }
+
+ testVerify(t, true)
+}
+
func chainToDebugString(chain []*Certificate) string {
var chainStr string
for _, cert := range chain {
@@ -211,6 +251,10 @@ func chainToDebugString(chain []*Certificate) string {
return chainStr
}
+func nameToKey(name *pkix.Name) string {
+ return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+}
+
const verisignRoot = `-----BEGIN CERTIFICATE-----
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 8fda47159..8dae7e7fc 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -6,122 +6,73 @@
package x509
import (
- "asn1"
- "big"
"bytes"
"crypto"
"crypto/dsa"
"crypto/rsa"
"crypto/sha1"
"crypto/x509/pkix"
+ "encoding/asn1"
"encoding/pem"
+ "errors"
"io"
- "os"
+ "math/big"
"time"
)
-// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
-type pkcs1PrivateKey struct {
- Version int
- N *big.Int
- E int
- D *big.Int
- P *big.Int
- Q *big.Int
- // We ignore these values, if present, because rsa will calculate them.
- Dp *big.Int `asn1:"optional"`
- Dq *big.Int `asn1:"optional"`
- Qinv *big.Int `asn1:"optional"`
-
- AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
+// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
+// in RFC 3280.
+type pkixPublicKey struct {
+ Algo pkix.AlgorithmIdentifier
+ BitString asn1.BitString
}
-type pkcs1AdditionalRSAPrime struct {
- Prime *big.Int
-
- // We ignore these values because rsa will calculate them.
- Exp *big.Int
- Coeff *big.Int
-}
-
-// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
-func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
- var priv pkcs1PrivateKey
- rest, err := asn1.Unmarshal(der, &priv)
- if len(rest) > 0 {
- err = asn1.SyntaxError{"trailing data"}
+// ParsePKIXPublicKey parses a DER encoded public key. These values are
+// typically found in PEM blocks with "BEGIN PUBLIC KEY".
+func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
+ var pki publicKeyInfo
+ if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
return
}
- if err != nil {
- return
- }
-
- if priv.Version > 1 {
- return nil, os.NewError("x509: unsupported private key version")
- }
-
- if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
- return nil, os.NewError("private key contains zero or negative value")
- }
-
- key = new(rsa.PrivateKey)
- key.PublicKey = rsa.PublicKey{
- E: priv.E,
- N: priv.N,
- }
-
- key.D = priv.D
- key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
- key.Primes[0] = priv.P
- key.Primes[1] = priv.Q
- for i, a := range priv.AdditionalPrimes {
- if a.Prime.Sign() <= 0 {
- return nil, os.NewError("private key contains zero or negative prime")
- }
- key.Primes[i+2] = a.Prime
- // We ignore the other two values because rsa will calculate
- // them as needed.
- }
-
- err = key.Validate()
- if err != nil {
- return nil, err
+ algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
+ if algo == UnknownPublicKeyAlgorithm {
+ return nil, errors.New("ParsePKIXPublicKey: unknown public key algorithm")
}
- key.Precompute()
-
- return
+ return parsePublicKey(algo, &pki)
}
-// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
-func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
- key.Precompute()
-
- version := 0
- if len(key.Primes) > 2 {
- version = 1
- }
+// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.
+func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
+ var pubBytes []byte
- priv := pkcs1PrivateKey{
- Version: version,
- N: key.N,
- E: key.PublicKey.E,
- D: key.D,
- P: key.Primes[0],
- Q: key.Primes[1],
- Dp: key.Precomputed.Dp,
- Dq: key.Precomputed.Dq,
- Qinv: key.Precomputed.Qinv,
+ switch pub := pub.(type) {
+ case *rsa.PublicKey:
+ pubBytes, _ = asn1.Marshal(rsaPublicKey{
+ N: pub.N,
+ E: pub.E,
+ })
+ default:
+ return nil, errors.New("MarshalPKIXPublicKey: unknown public key type")
}
- priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
- for i, values := range key.Precomputed.CRTValues {
- priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
- priv.AdditionalPrimes[i].Exp = values.Exp
- priv.AdditionalPrimes[i].Coeff = values.Coeff
+ pkix := pkixPublicKey{
+ Algo: pkix.AlgorithmIdentifier{
+ Algorithm: []int{1, 2, 840, 113549, 1, 1, 1},
+ // This is a NULL parameters value which is technically
+ // superfluous, but most other code includes it and, by
+ // doing this, we match their public key hashes.
+ Parameters: asn1.RawValue{
+ Tag: 5,
+ },
+ },
+ BitString: asn1.BitString{
+ Bytes: pubBytes,
+ BitLength: 8 * len(pubBytes),
+ },
}
- b, _ := asn1.Marshal(priv)
- return b
+ ret, _ := asn1.Marshal(pkix)
+ return ret, nil
}
// These structures reflect the ASN.1 structure of X.509 certificates.:
@@ -138,9 +89,9 @@ type tbsCertificate struct {
Version int `asn1:"optional,explicit,default:1,tag:0"`
SerialNumber *big.Int
SignatureAlgorithm pkix.AlgorithmIdentifier
- Issuer pkix.RDNSequence
+ Issuer asn1.RawValue
Validity validity
- Subject pkix.RDNSequence
+ Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
@@ -156,7 +107,7 @@ type dsaSignature struct {
}
type validity struct {
- NotBefore, NotAfter *time.Time
+ NotBefore, NotAfter time.Time
}
type publicKeyInfo struct {
@@ -202,7 +153,7 @@ const (
//
// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
//
-// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
+// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
//
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
//
@@ -221,9 +172,9 @@ const (
//
// RFC 5758 3.1 DSA Signature Algorithms
//
-// dsaWithSha356 OBJECT IDENTIFER ::= {
+// dsaWithSha256 OBJECT IDENTIFIER ::= {
// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
-// algorithms(4) id-dsa-with-sha2(3) 2}
+// csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
//
var (
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
@@ -339,6 +290,8 @@ type Certificate struct {
Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content.
RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+ RawSubject []byte // DER encoded Subject
+ RawIssuer []byte // DER encoded Issuer
Signature []byte
SignatureAlgorithm SignatureAlgorithm
@@ -350,7 +303,7 @@ type Certificate struct {
SerialNumber *big.Int
Issuer pkix.Name
Subject pkix.Name
- NotBefore, NotAfter *time.Time // Validity bounds.
+ NotBefore, NotAfter time.Time // Validity bounds.
KeyUsage KeyUsage
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
@@ -374,21 +327,17 @@ type Certificate struct {
PolicyIdentifiers []asn1.ObjectIdentifier
}
-// UnsupportedAlgorithmError results from attempting to perform an operation
-// that involves algorithms that are not currently implemented.
-type UnsupportedAlgorithmError struct{}
-
-func (UnsupportedAlgorithmError) String() string {
- return "cannot verify signature: algorithm unimplemented"
-}
+// ErrUnsupportedAlgorithm results from attempting to perform an operation that
+// involves algorithms that are not currently implemented.
+var ErrUnsupportedAlgorithm = errors.New("crypto/x509: cannot verify signature: algorithm unimplemented")
// ConstraintViolationError results when a requested usage is not permitted by
// a certificate. For example: checking a signature when the public key isn't a
// certificate signing key.
type ConstraintViolationError struct{}
-func (ConstraintViolationError) String() string {
- return "invalid signature: parent certificate cannot sign this kind of certificate"
+func (ConstraintViolationError) Error() string {
+ return "crypto/x509: invalid signature: parent certificate cannot sign this kind of certificate"
}
func (c *Certificate) Equal(other *Certificate) bool {
@@ -397,7 +346,7 @@ func (c *Certificate) Equal(other *Certificate) bool {
// CheckSignatureFrom verifies that the signature on c is a valid signature
// from parent.
-func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
// RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not
@@ -413,7 +362,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
}
if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
- return UnsupportedAlgorithmError{}
+ return ErrUnsupportedAlgorithm
}
// TODO(agl): don't ignore the path length constraint.
@@ -423,7 +372,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
// 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) {
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
var hashType crypto.Hash
switch algo {
@@ -436,16 +385,16 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
case SHA512WithRSA:
hashType = crypto.SHA512
default:
- return UnsupportedAlgorithmError{}
+ return ErrUnsupportedAlgorithm
}
h := hashType.New()
if h == nil {
- return UnsupportedAlgorithmError{}
+ return ErrUnsupportedAlgorithm
}
h.Write(signed)
- digest := h.Sum()
+ digest := h.Sum(nil)
switch pub := c.PublicKey.(type) {
case *rsa.PublicKey:
@@ -456,36 +405,31 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
return err
}
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
- return os.NewError("DSA signature contained zero or negative values")
+ return errors.New("DSA signature contained zero or negative values")
}
if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
- return os.NewError("DSA verification failure")
+ return errors.New("DSA verification failure")
}
return
}
- return UnsupportedAlgorithmError{}
+ return ErrUnsupportedAlgorithm
}
// CheckCRLSignature checks that the signature in crl is from c.
-func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) {
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err error) {
algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
type UnhandledCriticalExtension struct{}
-func (h UnhandledCriticalExtension) String() string {
+func (h UnhandledCriticalExtension) Error() string {
return "unhandled critical extension"
}
type basicConstraints struct {
IsCA bool `asn1:"optional"`
- MaxPathLen int `asn1:"optional"`
-}
-
-type rsaPublicKey struct {
- N *big.Int
- E int
+ MaxPathLen int `asn1:"optional,default:-1"`
}
// RFC 5280 4.2.1.4
@@ -506,7 +450,7 @@ type generalSubtree struct {
Max int `asn1:"optional,tag:1"`
}
-func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) {
+func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
@@ -534,7 +478,7 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
return nil, err
}
if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
- return nil, os.NewError("zero or negative DSA parameter")
+ return nil, errors.New("zero or negative DSA parameter")
}
pub := &dsa.PublicKey{
Parameters: dsa.Parameters{
@@ -551,11 +495,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
panic("unreachable")
}
-func parseCertificate(in *certificate) (*Certificate, os.Error) {
+func parseCertificate(in *certificate) (*Certificate, error) {
out := new(Certificate)
out.Raw = in.Raw
out.RawTBSCertificate = in.TBSCertificate.Raw
out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
+ out.RawSubject = in.TBSCertificate.Subject.FullBytes
+ out.RawIssuer = in.TBSCertificate.Issuer.FullBytes
out.Signature = in.SignatureValue.RightAlign()
out.SignatureAlgorithm =
@@ -563,20 +509,30 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
- var err os.Error
+ var err error
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")
+ return nil, errors.New("negative serial number")
}
out.Version = in.TBSCertificate.Version + 1
out.SerialNumber = in.TBSCertificate.SerialNumber
- out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer)
- out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject)
+
+ var issuer, subject pkix.RDNSequence
+ if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
+ return nil, err
+ }
+ if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
+ return nil, err
+ }
+
+ out.Issuer.FillFromRDNSequence(&issuer)
+ out.Subject.FillFromRDNSequence(&subject)
+
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
@@ -632,7 +588,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
return nil, err
}
if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
- return nil, asn1.StructuralError{"bad SAN sequence"}
+ return nil, asn1.StructuralError{Msg: "bad SAN sequence"}
}
parsedName := false
@@ -777,14 +733,14 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
}
// ParseCertificate parses a single certificate from the given ASN.1 DER data.
-func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
+func ParseCertificate(asn1Data []byte) (*Certificate, error) {
var cert certificate
rest, err := asn1.Unmarshal(asn1Data, &cert)
if err != nil {
return nil, err
}
if len(rest) > 0 {
- return nil, asn1.SyntaxError{"trailing data"}
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
}
return parseCertificate(&cert)
@@ -792,12 +748,12 @@ 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) {
+func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
var v []*certificate
for len(asn1Data) > 0 {
cert := new(certificate)
- var err os.Error
+ var err error
asn1Data, err = asn1.Unmarshal(asn1Data, cert)
if err != nil {
return nil, err
@@ -834,8 +790,8 @@ var (
oidExtensionNameConstraints = []int{2, 5, 29, 30}
)
-func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) {
- ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )
+func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
+ ret = make([]pkix.Extension, 7 /* maximum number of elements. */)
n := 0
if template.KeyUsage != 0 {
@@ -939,21 +895,41 @@ var (
oidRSA = []int{1, 2, 840, 113549, 1, 1, 1}
)
-// CreateSelfSignedCertificate creates a new certificate based on
-// a template. The following members of template are used: SerialNumber,
-// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA,
-// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+func subjectBytes(cert *Certificate) ([]byte, error) {
+ if len(cert.RawSubject) > 0 {
+ return cert.RawSubject, nil
+ }
+
+ return asn1.Marshal(cert.Subject.ToRDNSequence())
+}
+
+// CreateCertificate creates a new certificate based on a template. The
+// following members of template are used: SerialNumber, Subject, NotBefore,
+// NotAfter, KeyUsage, BasicConstraintsValid, IsCA, MaxPathLen, SubjectKeyId,
+// DNSNames, PermittedDNSDomainsCritical, PermittedDNSDomains.
//
// The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the
// signee and priv is the private key of the signer.
//
// The returned slice is the certificate in DER encoding.
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
+//
+// The only supported key type is RSA (*rsa.PublicKey for pub, *rsa.PrivateKey
+// for priv).
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
+ rsaPub, ok := pub.(*rsa.PublicKey)
+ if !ok {
+ return nil, errors.New("x509: non-RSA public keys not supported")
+ }
+
+ rsaPriv, ok := priv.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("x509: non-RSA private keys not supported")
+ }
+
asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
- N: pub.N,
- E: pub.E,
+ N: rsaPub.N,
+ E: rsaPub.E,
})
if err != nil {
return
@@ -968,14 +944,24 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
return
}
+ asn1Issuer, err := subjectBytes(parent)
+ if err != nil {
+ return
+ }
+
+ asn1Subject, err := subjectBytes(template)
+ if err != nil {
+ return
+ }
+
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
c := tbsCertificate{
Version: 2,
SerialNumber: template.SerialNumber,
SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
- Issuer: parent.Subject.ToRDNSequence(),
+ Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore, template.NotAfter},
- Subject: template.Subject.ToRDNSequence(),
+ Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
Extensions: extensions,
}
@@ -989,9 +975,9 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
h := sha1.New()
h.Write(tbsCertContents)
- digest := h.Sum()
+ digest := h.Sum(nil)
- signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
if err != nil {
return
}
@@ -1008,6 +994,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
// 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"
@@ -1015,7 +1002,7 @@ var pemType = "X509 CRL"
// 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) {
+func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
block, _ := pem.Decode(crlBytes)
if block != nil && block.Type == pemType {
@@ -1026,7 +1013,7 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) {
}
// ParseDERCRL parses a DER encoded CRL from the given bytes.
-func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
certList = new(pkix.CertificateList)
_, err = asn1.Unmarshal(derBytes, certList)
if err != nil {
@@ -1037,7 +1024,13 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error)
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates.
-func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) {
+//
+// The only supported key type is RSA (*rsa.PrivateKey for priv).
+func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
+ rsaPriv, ok := priv.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("x509: non-RSA private keys not supported")
+ }
tbsCertList := pkix.TBSCertificateList{
Version: 2,
Signature: pkix.AlgorithmIdentifier{
@@ -1056,9 +1049,9 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCer
h := sha1.New()
h.Write(tbsCertListContents)
- digest := h.Sum()
+ digest := h.Sum(nil)
- signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
if err != nil {
return
}
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index dc216505e..f0327b012 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -5,15 +5,16 @@
package x509
import (
- "asn1"
- "big"
+ "bytes"
"crypto/dsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509/pkix"
+ "encoding/asn1"
"encoding/base64"
"encoding/hex"
"encoding/pem"
+ "math/big"
"testing"
"time"
)
@@ -34,6 +35,40 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
}
}
+func TestParsePKIXPublicKey(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPublicKey))
+ pub, err := ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse RSA public key: %s", err)
+ return
+ }
+ rsaPub, ok := pub.(*rsa.PublicKey)
+ if !ok {
+ t.Errorf("Value returned from ParsePKIXPublicKey was not an RSA public key")
+ return
+ }
+
+ pubBytes2, err := MarshalPKIXPublicKey(rsaPub)
+ if err != nil {
+ t.Errorf("Failed to marshal RSA public key for the second time: %s", err)
+ return
+ }
+ if !bytes.Equal(pubBytes2, block.Bytes) {
+ t.Errorf("Reserialization of public key didn't match. got %x, want %x", pubBytes2, block.Bytes)
+ }
+}
+
+var pemPublicKey = `-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VoPN9PKUjKFLMwOge6+
+wnDi8sbETGIx2FKXGgqtAKpzmem53kRGEQg8WeqRmp12wgp74TGpkEXsGae7RS1k
+enJCnma4fii+noGH7R0qKgHvPrI2Bwa9hzsH8tHxpyM3qrXslOmD45EH9SxIDUBJ
+FehNdaPbLP1gFyahKMsdfxFJLUvbUycuZSJ2ZnIgeVxwm4qbSvZInL9Iu4FzuPtg
+fINKcbbovy1qq4KvPIrXzhbY3PWDc6btxCf3SE0JdE1MCPThntB62/bLMSQ7xdDR
+FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
++QIDAQAB
+-----END PUBLIC KEY-----
+`
+
var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
@@ -208,14 +243,15 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
return
}
+ commonName := "test.example.com"
template := Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
- CommonName: "test.example.com",
+ CommonName: commonName,
Organization: []string{"Acme Co"},
},
- NotBefore: time.SecondsToUTC(1000),
- NotAfter: time.SecondsToUTC(100000),
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
SubjectKeyId: []byte{1, 2, 3, 4},
KeyUsage: KeyUsageCertSign,
@@ -248,6 +284,14 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains)
}
+ if cert.Subject.CommonName != commonName {
+ t.Errorf("Subject wasn't correctly copied from the template. Got %s, want %s", cert.Subject.CommonName, commonName)
+ }
+
+ if cert.Issuer.CommonName != commonName {
+ t.Errorf("Issuer wasn't correctly copied from the template. Got %s, want %s", cert.Issuer.CommonName, commonName)
+ }
+
err = cert.CheckSignatureFrom(cert)
if err != nil {
t.Errorf("Signature verification failed: %s", err)
@@ -352,8 +396,8 @@ func TestCRLCreation(t *testing.T) {
block, _ = pem.Decode([]byte(pemCertificate))
cert, _ := ParseCertificate(block.Bytes)
- now := time.SecondsToUTC(1000)
- expiry := time.SecondsToUTC(10000)
+ now := time.Unix(1000, 0)
+ expiry := time.Unix(10000, 0)
revokedCerts := []pkix.RevokedCertificate{
{
@@ -399,7 +443,7 @@ func TestParseDERCRL(t *testing.T) {
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
}
- if certList.HasExpired(1302517272) {
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
t.Errorf("CRL has expired (but shouldn't have)")
}
@@ -419,7 +463,7 @@ func TestParsePEMCRL(t *testing.T) {
t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
}
- if certList.HasExpired(1302517272) {
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
t.Errorf("CRL has expired (but shouldn't have)")
}
diff --git a/src/pkg/crypto/xtea/Makefile b/src/pkg/crypto/xtea/Makefile
deleted file mode 100644
index 301621168..000000000
--- a/src/pkg/crypto/xtea/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=crypto/xtea
-GOFILES=\
- cipher.go\
- block.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/crypto/xtea/block.go b/src/pkg/crypto/xtea/block.go
deleted file mode 100644
index bf5d24599..000000000
--- a/src/pkg/crypto/xtea/block.go
+++ /dev/null
@@ -1,66 +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.
-
-/*
- Implementation adapted from Needham and Wheeler's paper:
- http://www.cix.co.uk/~klockstone/xtea.pdf
-
- A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
-*/
-
-package xtea
-
-// XTEA is based on 64 rounds.
-const numRounds = 64
-
-// blockToUint32 reads an 8 byte slice into two uint32s.
-// The block is treated as big endian.
-func blockToUint32(src []byte) (uint32, uint32) {
- r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
- r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
- return r0, r1
-}
-
-// uint32ToBlock writes two 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)
- dst[1] = byte(v0 >> 16)
- dst[2] = byte(v0 >> 8)
- dst[3] = byte(v0)
- dst[4] = byte(v1 >> 24)
- dst[5] = byte(v1 >> 16)
- dst[6] = byte(v1 >> 8)
- dst[7] = byte(v1 >> 0)
-}
-
-// encryptBlock encrypts a single 8 byte block using XTEA.
-func encryptBlock(c *Cipher, dst, src []byte) {
- v0, v1 := blockToUint32(src)
-
- // Two rounds of XTEA applied per loop
- for i := 0; i < numRounds; {
- v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
- i++
- v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
- i++
- }
-
- uint32ToBlock(v0, v1, dst)
-}
-
-// decryptBlock decrypt a single 8 byte block using XTEA.
-func decryptBlock(c *Cipher, dst, src []byte) {
- v0, v1 := blockToUint32(src)
-
- // Two rounds of XTEA applied per loop
- for i := numRounds; i > 0; {
- i--
- v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
- i--
- v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
- }
-
- uint32ToBlock(v0, v1, dst)
-}
diff --git a/src/pkg/crypto/xtea/cipher.go b/src/pkg/crypto/xtea/cipher.go
deleted file mode 100644
index b3fba3c84..000000000
--- a/src/pkg/crypto/xtea/cipher.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 xtea implements XTEA encryption, as defined in Needham and Wheeler's
-// 1997 technical report, "Tea extensions."
-package xtea
-
-// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
-
-import (
- "os"
- "strconv"
-)
-
-// The XTEA block size in bytes.
-const BlockSize = 8
-
-// A Cipher is an instance of an XTEA cipher using a particular key.
-// table contains a series of precalculated values that are used each round.
-type Cipher struct {
- table [64]uint32
-}
-
-type KeySizeError int
-
-func (k KeySizeError) String() string {
- return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
-}
-
-// NewCipher creates and returns a new Cipher.
-// The key argument should be the XTEA key.
-// XTEA only supports 128 bit (16 byte) keys.
-func NewCipher(key []byte) (*Cipher, os.Error) {
- k := len(key)
- switch k {
- default:
- return nil, KeySizeError(k)
- case 16:
- break
- }
-
- c := new(Cipher)
- initCipher(c, key)
-
- return c, nil
-}
-
-// BlockSize returns the XTEA block size, 8 bytes.
-// It is necessary to satisfy the Cipher interface in the
-// package "crypto/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/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.
-func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
-
-// Reset zeros the table, so that it will no longer appear in the process's memory.
-func (c *Cipher) Reset() {
- for i := 0; i < len(c.table); i++ {
- c.table[i] = 0
- }
-}
-
-// initCipher initializes the cipher context by creating a look up table
-// of precalculated values that are based on the key.
-func initCipher(c *Cipher, key []byte) {
- // Load the key into four uint32s
- var k [4]uint32
- for i := 0; i < len(k); i++ {
- j := i << 2 // Multiply by 4
- k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
- }
-
- // Precalculate the table
- const delta = 0x9E3779B9
- var sum uint32 = 0
-
- // Two rounds of XTEA applied per loop
- for i := 0; i < numRounds; {
- c.table[i] = sum + k[sum&3]
- i++
- sum += delta
- c.table[i] = sum + k[(sum>>11)&3]
- i++
- }
-}
diff --git a/src/pkg/crypto/xtea/xtea_test.go b/src/pkg/crypto/xtea/xtea_test.go
deleted file mode 100644
index 217d96adc..000000000
--- a/src/pkg/crypto/xtea/xtea_test.go
+++ /dev/null
@@ -1,246 +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 xtea
-
-import (
- "testing"
-)
-
-// 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
-func TestBlocksize(t *testing.T) {
- if BlockSize != 8 {
- t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
- return
- }
-
- c, err := NewCipher(testKey)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
- return
- }
-
- result := c.BlockSize()
- if result != 8 {
- t.Errorf("BlockSize function - expected 8, got %d", result)
- return
- }
-}
-
-// 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,
- 0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
- 0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
- 0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
- 0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
- 0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
- 0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
-}
-
-// Test that the cipher context is initialized correctly
-func TestCipherInit(t *testing.T) {
- c, err := NewCipher(testKey)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
- return
- }
-
- for i := 0; i < len(c.table); i++ {
- if c.table[i] != testTable[i] {
- t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
- break
- }
- }
-}
-
-// Test that invalid key sizes return an error
-func TestInvalidKeySize(t *testing.T) {
- // Test a long key
- key := []byte{
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
- }
-
- _, err := NewCipher(key)
- if err == nil {
- t.Errorf("Invalid key size %d didn't result in an error.", len(key))
- }
-
- // Test a short key
- key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
-
- _, err = NewCipher(key)
- if err == nil {
- t.Errorf("Invalid key size %d didn't result in an error.", len(key))
- }
-}
-
-// Test that we can correctly decode some bytes we have encoded
-func TestEncodeDecode(t *testing.T) {
- original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
- input := original
- output := make([]byte, BlockSize)
-
- c, err := NewCipher(testKey)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
- return
- }
-
- // Encrypt the input block
- c.Encrypt(output, input)
-
- // Check that the output does not match the input
- differs := false
- for i := 0; i < len(input); i++ {
- if output[i] != input[i] {
- differs = true
- break
- }
- }
- if differs == false {
- t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
- return
- }
-
- // Decrypt the block we just encrypted
- input = output
- output = make([]byte, BlockSize)
- c.Decrypt(output, input)
-
- // Check that the output from decrypt matches our initial input
- for i := 0; i < len(input); i++ {
- if output[i] != original[i] {
- t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
- return
- }
- }
-}
-
-// Test Vectors
-type CryptTest struct {
- key []byte
- plainText []byte
- cipherText []byte
-}
-
-var CryptTests = []CryptTest{
- // These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
- {
- []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
- []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
- []byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
- },
- {
- []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
- []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
- []byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
- },
- {
- []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
- []byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
- []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
- },
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
- []byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
- },
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
- []byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
- },
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
- []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
- },
-
- // These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
- },
- {
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
- []byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
- },
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
- []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- []byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
- },
- {
- []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
- []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
- []byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
- },
-}
-
-// Test encryption
-func TestCipherEncrypt(t *testing.T) {
- for i, tt := range CryptTests {
- c, err := NewCipher(tt.key)
- if err != nil {
- t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
- continue
- }
-
- out := make([]byte, len(tt.plainText))
- c.Encrypt(out, tt.plainText)
-
- for j := 0; j < len(out); j++ {
- if out[j] != tt.cipherText[j] {
- t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
- break
- }
- }
- }
-}
-
-// Test decryption
-func TestCipherDecrypt(t *testing.T) {
- for i, tt := range CryptTests {
- c, err := NewCipher(tt.key)
- if err != nil {
- t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
- continue
- }
-
- out := make([]byte, len(tt.cipherText))
- c.Decrypt(out, tt.cipherText)
-
- for j := 0; j < len(out); j++ {
- if out[j] != tt.plainText[j] {
- t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
- break
- }
- }
- }
-}
-
-// Test resetting the cipher context
-func TestReset(t *testing.T) {
- c, err := NewCipher(testKey)
- if err != nil {
- t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
- return
- }
-
- c.Reset()
- for i := 0; i < len(c.table); i++ {
- if c.table[i] != 0 {
- t.Errorf("Cipher.Reset: Failed to clear Cipher.table[%d]. expected 0, got %08X", i, c.table[i])
- return
- }
- }
-}
diff --git a/src/pkg/csv/Makefile b/src/pkg/csv/Makefile
deleted file mode 100644
index e364d51d2..000000000
--- a/src/pkg/csv/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=csv
-GOFILES=\
- reader.go\
- writer.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
new file mode 100644
index 000000000..bfcb03ccf
--- /dev/null
+++ b/src/pkg/database/sql/convert.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.
+
+// Type conversions for Scan.
+
+package sql
+
+import (
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+// subsetTypeArgs takes a slice of arguments from callers of the sql
+// package and converts them into a slice of the driver package's
+// "subset types".
+func subsetTypeArgs(args []interface{}) ([]driver.Value, error) {
+ out := make([]driver.Value, len(args))
+ for n, arg := range args {
+ var err error
+ out[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ if err != nil {
+ return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n+1, err)
+ }
+ }
+ return out, nil
+}
+
+// convertAssign copies to dest the value in src, converting it if possible.
+// An error is returned if the copy would result in loss of information.
+// dest should be a pointer type.
+func convertAssign(dest, src interface{}) error {
+ // Common cases, without reflect. Fall through.
+ switch s := src.(type) {
+ case string:
+ switch d := dest.(type) {
+ case *string:
+ *d = s
+ return nil
+ case *[]byte:
+ *d = []byte(s)
+ return nil
+ }
+ case []byte:
+ switch d := dest.(type) {
+ case *string:
+ *d = string(s)
+ return nil
+ case *interface{}:
+ bcopy := make([]byte, len(s))
+ copy(bcopy, s)
+ *d = bcopy
+ return nil
+ case *[]byte:
+ *d = s
+ return nil
+ }
+ case nil:
+ switch d := dest.(type) {
+ case *[]byte:
+ *d = nil
+ return nil
+ }
+ }
+
+ var sv reflect.Value
+
+ switch d := dest.(type) {
+ case *string:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = fmt.Sprintf("%v", src)
+ return nil
+ }
+ case *bool:
+ bv, err := driver.Bool.ConvertValue(src)
+ if err == nil {
+ *d = bv.(bool)
+ }
+ return err
+ case *interface{}:
+ *d = src
+ return nil
+ }
+
+ if scanner, ok := dest.(Scanner); ok {
+ return scanner.Scan(src)
+ }
+
+ dpv := reflect.ValueOf(dest)
+ if dpv.Kind() != reflect.Ptr {
+ return errors.New("destination not a pointer")
+ }
+
+ if !sv.IsValid() {
+ sv = reflect.ValueOf(src)
+ }
+
+ dv := reflect.Indirect(dpv)
+ if dv.Kind() == sv.Kind() {
+ dv.Set(sv)
+ return nil
+ }
+
+ switch dv.Kind() {
+ case reflect.Ptr:
+ if src == nil {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ } else {
+ dv.Set(reflect.New(dv.Type().Elem()))
+ return convertAssign(dv.Interface(), src)
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ s := asString(src)
+ i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
+ if err != nil {
+ return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+ }
+ dv.SetInt(i64)
+ return nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ s := asString(src)
+ u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
+ if err != nil {
+ return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+ }
+ dv.SetUint(u64)
+ return nil
+ case reflect.Float32, reflect.Float64:
+ s := asString(src)
+ f64, err := strconv.ParseFloat(s, dv.Type().Bits())
+ if err != nil {
+ return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err)
+ }
+ dv.SetFloat(f64)
+ return nil
+ }
+
+ return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
+}
+
+func asString(src interface{}) string {
+ switch v := src.(type) {
+ case string:
+ return v
+ case []byte:
+ return string(v)
+ }
+ return fmt.Sprintf("%v", src)
+}
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
new file mode 100644
index 000000000..9c362d732
--- /dev/null
+++ b/src/pkg/database/sql/convert_test.go
@@ -0,0 +1,250 @@
+// 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 sql
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+ "testing"
+ "time"
+)
+
+var someTime = time.Unix(123, 0)
+var answer int64 = 42
+
+type conversionTest struct {
+ s, d interface{} // source and destination
+
+ // following are used if they're non-zero
+ wantint int64
+ wantuint uint64
+ wantstr string
+ wantf32 float32
+ wantf64 float64
+ wanttime time.Time
+ wantbool bool // used if d is of type *bool
+ wanterr string
+ wantiface interface{}
+ wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr
+ wantnil bool // if true, *d must be *int64(nil)
+}
+
+// Target variables for scanning into.
+var (
+ scanstr string
+ scanint int
+ scanint8 int8
+ scanint16 int16
+ scanint32 int32
+ scanuint8 uint8
+ scanuint16 uint16
+ scanbool bool
+ scanf32 float32
+ scanf64 float64
+ scantime time.Time
+ scanptr *int64
+ scaniface interface{}
+)
+
+var conversionTests = []conversionTest{
+ // Exact conversions (destination pointer type matches source type)
+ {s: "foo", d: &scanstr, wantstr: "foo"},
+ {s: 123, d: &scanint, wantint: 123},
+ {s: someTime, d: &scantime, wanttime: someTime},
+
+ // To strings
+ {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
+ {s: 123, d: &scanstr, wantstr: "123"},
+ {s: int8(123), d: &scanstr, wantstr: "123"},
+ {s: int64(123), d: &scanstr, wantstr: "123"},
+ {s: uint8(123), d: &scanstr, wantstr: "123"},
+ {s: uint16(123), d: &scanstr, wantstr: "123"},
+ {s: uint32(123), d: &scanstr, wantstr: "123"},
+ {s: uint64(123), d: &scanstr, wantstr: "123"},
+ {s: 1.5, d: &scanstr, wantstr: "1.5"},
+
+ // Strings to integers
+ {s: "255", d: &scanuint8, wantuint: 255},
+ {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
+ {s: "256", d: &scanuint16, wantuint: 256},
+ {s: "-1", d: &scanint, wantint: -1},
+ {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`},
+
+ // True bools
+ {s: true, d: &scanbool, wantbool: true},
+ {s: "True", d: &scanbool, wantbool: true},
+ {s: "TRUE", d: &scanbool, wantbool: true},
+ {s: "1", d: &scanbool, wantbool: true},
+ {s: 1, d: &scanbool, wantbool: true},
+ {s: int64(1), d: &scanbool, wantbool: true},
+ {s: uint16(1), d: &scanbool, wantbool: true},
+
+ // False bools
+ {s: false, d: &scanbool, wantbool: false},
+ {s: "false", d: &scanbool, wantbool: false},
+ {s: "FALSE", d: &scanbool, wantbool: false},
+ {s: "0", d: &scanbool, wantbool: false},
+ {s: 0, d: &scanbool, wantbool: false},
+ {s: int64(0), d: &scanbool, wantbool: false},
+ {s: uint16(0), d: &scanbool, wantbool: false},
+
+ // Not bools
+ {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
+ {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
+
+ // Floats
+ {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
+ {s: int64(1), d: &scanf64, wantf64: float64(1)},
+ {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
+ {s: "1.5", d: &scanf32, wantf32: float32(1.5)},
+ {s: "1.5", d: &scanf64, wantf64: float64(1.5)},
+
+ // Pointers
+ {s: interface{}(nil), d: &scanptr, wantnil: true},
+ {s: int64(42), d: &scanptr, wantptr: &answer},
+
+ // To interface{}
+ {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
+ {s: int64(1), d: &scaniface, wantiface: int64(1)},
+ {s: "str", d: &scaniface, wantiface: "str"},
+ {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
+ {s: true, d: &scaniface, wantiface: true},
+ {s: nil, d: &scaniface},
+}
+
+func intPtrValue(intptr interface{}) interface{} {
+ return reflect.Indirect(reflect.Indirect(reflect.ValueOf(intptr))).Int()
+}
+
+func intValue(intptr interface{}) int64 {
+ return reflect.Indirect(reflect.ValueOf(intptr)).Int()
+}
+
+func uintValue(intptr interface{}) uint64 {
+ return reflect.Indirect(reflect.ValueOf(intptr)).Uint()
+}
+
+func float64Value(ptr interface{}) float64 {
+ return *(ptr.(*float64))
+}
+
+func float32Value(ptr interface{}) float32 {
+ return *(ptr.(*float32))
+}
+
+func timeValue(ptr interface{}) time.Time {
+ return *(ptr.(*time.Time))
+}
+
+func TestConversions(t *testing.T) {
+ for n, ct := range conversionTests {
+ err := convertAssign(ct.d, ct.s)
+ errstr := ""
+ if err != nil {
+ errstr = err.Error()
+ }
+ errf := func(format string, args ...interface{}) {
+ base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d)
+ t.Errorf(base+format, args...)
+ }
+ if errstr != ct.wanterr {
+ errf("got error %q, want error %q", errstr, ct.wanterr)
+ }
+ if ct.wantstr != "" && ct.wantstr != scanstr {
+ errf("want string %q, got %q", ct.wantstr, scanstr)
+ }
+ if ct.wantint != 0 && ct.wantint != intValue(ct.d) {
+ errf("want int %d, got %d", ct.wantint, intValue(ct.d))
+ }
+ if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) {
+ errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d))
+ }
+ if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) {
+ errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d))
+ }
+ if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) {
+ errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d))
+ }
+ if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" {
+ errf("want bool %v, got %v", ct.wantbool, *bp)
+ }
+ if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
+ errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
+ }
+ if ct.wantnil && *ct.d.(**int64) != nil {
+ errf("want nil, got %v", intPtrValue(ct.d))
+ }
+ if ct.wantptr != nil {
+ if *ct.d.(**int64) == nil {
+ errf("want pointer to %v, got nil", *ct.wantptr)
+ } else if *ct.wantptr != intPtrValue(ct.d) {
+ errf("want pointer to %v, got %v", *ct.wantptr, intPtrValue(ct.d))
+ }
+ }
+ if ifptr, ok := ct.d.(*interface{}); ok {
+ if !reflect.DeepEqual(ct.wantiface, scaniface) {
+ errf("want interface %#v, got %#v", ct.wantiface, scaniface)
+ continue
+ }
+ if srcBytes, ok := ct.s.([]byte); ok {
+ dstBytes := (*ifptr).([]byte)
+ if &dstBytes[0] == &srcBytes[0] {
+ errf("copy into interface{} didn't copy []byte data")
+ }
+ }
+ }
+ }
+}
+
+func TestNullString(t *testing.T) {
+ var ns NullString
+ convertAssign(&ns, []byte("foo"))
+ if !ns.Valid {
+ t.Errorf("expecting not null")
+ }
+ if ns.String != "foo" {
+ t.Errorf("expecting foo; got %q", ns.String)
+ }
+ convertAssign(&ns, nil)
+ if ns.Valid {
+ t.Errorf("expecting null on nil")
+ }
+ if ns.String != "" {
+ t.Errorf("expecting blank on nil; got %q", ns.String)
+ }
+}
+
+type valueConverterTest struct {
+ c driver.ValueConverter
+ in, out interface{}
+ err string
+}
+
+var valueConverterTests = []valueConverterTest{
+ {driver.DefaultParameterConverter, NullString{"hi", true}, "hi", ""},
+ {driver.DefaultParameterConverter, NullString{"", false}, nil, ""},
+}
+
+func TestValueConverters(t *testing.T) {
+ for i, tt := range valueConverterTests {
+ out, err := tt.c.ConvertValue(tt.in)
+ goterr := ""
+ if err != nil {
+ goterr = err.Error()
+ }
+ if goterr != tt.err {
+ t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q",
+ i, tt.c, tt.in, tt.in, goterr, tt.err)
+ }
+ if tt.err != "" {
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)",
+ i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/database/sql/doc.txt b/src/pkg/database/sql/doc.txt
new file mode 100644
index 000000000..fb1659548
--- /dev/null
+++ b/src/pkg/database/sql/doc.txt
@@ -0,0 +1,46 @@
+Goals of the sql and sql/driver packages:
+
+* Provide a generic database API for a variety of SQL or SQL-like
+ databases. There currently exist Go libraries for SQLite, MySQL,
+ and Postgres, but all with a very different feel, and often
+ a non-Go-like feel.
+
+* Feel like Go.
+
+* Care mostly about the common cases. Common SQL should be portable.
+ SQL edge cases or db-specific extensions can be detected and
+ conditionally used by the application. It is a non-goal to care
+ about every particular db's extension or quirk.
+
+* Separate out the basic implementation of a database driver
+ (implementing the sql/driver interfaces) vs the implementation
+ of all the user-level types and convenience methods.
+ In a nutshell:
+
+ User Code ---> sql package (concrete types) ---> sql/driver (interfaces)
+ Database Driver -> sql (to register) + sql/driver (implement interfaces)
+
+* Make type casting/conversions consistent between all drivers. To
+ achieve this, most of the conversions are done in the db package,
+ not in each driver. The drivers then only have to deal with a
+ smaller set of types.
+
+* Be flexible with type conversions, but be paranoid about silent
+ truncation or other loss of precision.
+
+* Handle concurrency well. Users shouldn't need to care about the
+ database's per-connection thread safety issues (or lack thereof),
+ and shouldn't have to maintain their own free pools of connections.
+ The 'db' package should deal with that bookkeeping as needed. Given
+ an *sql.DB, it should be possible to share that instance between
+ multiple goroutines, without any extra synchronization.
+
+* Push complexity, where necessary, down into the sql+driver packages,
+ rather than exposing it to users. Said otherwise, the sql package
+ should expose an ideal database that's not finnicky about how it's
+ accessed, even if that's not true.
+
+* Provide optional interfaces in sql/driver for drivers to implement
+ for special cases or fastpaths. But the only party that knows about
+ those is the sql package. To user code, some stuff just might start
+ working or start working slightly faster.
diff --git a/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
new file mode 100644
index 000000000..2f5280db8
--- /dev/null
+++ b/src/pkg/database/sql/driver/driver.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.
+
+// Package driver defines interfaces to be implemented by database
+// drivers as used by package sql.
+//
+// Most code should use package sql.
+package driver
+
+import "errors"
+
+// A driver Value is a value that drivers must be able to handle.
+// A Value is either nil or an instance of one of these types:
+//
+// int64
+// float64
+// bool
+// []byte
+// string [*] everywhere except from Rows.Next.
+// time.Time
+type Value interface{}
+
+// Driver is the interface that must be implemented by a database
+// driver.
+type Driver interface {
+ // Open returns a new connection to the database.
+ // The name is a string in a driver-specific format.
+ //
+ // Open may return a cached connection (one previously
+ // closed), but doing so is unnecessary; the sql package
+ // maintains a pool of idle connections for efficient re-use.
+ //
+ // The returned connection is only used by one goroutine at a
+ // time.
+ Open(name string) (Conn, error)
+}
+
+// ErrSkip may be returned by some optional interfaces' methods to
+// indicate at runtime that the fast path is unavailable and the sql
+// package should continue as if the optional interface was not
+// implemented. ErrSkip is only supported where explicitly
+// documented.
+var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
+
+// ErrBadConn should be returned by a driver to signal to the sql
+// package that a driver.Conn is in a bad state (such as the server
+// having earlier closed the connection) and the sql package should
+// retry on a new connection.
+//
+// To prevent duplicate operations, ErrBadConn should NOT be returned
+// if there's a possibility that the database server might have
+// performed the operation. Even if the server sends back an error,
+// you shouldn't return ErrBadConn.
+var ErrBadConn = errors.New("driver: bad connection")
+
+// Execer is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement Execer, the db package's DB.Exec will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// Exec may return ErrSkip.
+type Execer interface {
+ Exec(query string, args []Value) (Result, error)
+}
+
+// Conn is a connection to a database. It is not used concurrently
+// by multiple goroutines.
+//
+// Conn is assumed to be stateful.
+type Conn interface {
+ // Prepare returns a prepared statement, bound to this connection.
+ Prepare(query string) (Stmt, error)
+
+ // Close invalidates and potentially stops any current
+ // prepared statements and transactions, marking this
+ // connection as no longer in use.
+ //
+ // Because the sql package maintains a free pool of
+ // connections and only calls Close when there's a surplus of
+ // idle connections, it shouldn't be necessary for drivers to
+ // do their own connection caching.
+ Close() error
+
+ // Begin starts and returns a new transaction.
+ Begin() (Tx, error)
+}
+
+// Result is the result of a query execution.
+type Result interface {
+ // LastInsertId returns the database's auto-generated ID
+ // after, for example, an INSERT into a table with primary
+ // key.
+ LastInsertId() (int64, error)
+
+ // RowsAffected returns the number of rows affected by the
+ // query.
+ RowsAffected() (int64, error)
+}
+
+// Stmt is a prepared statement. It is bound to a Conn and not
+// used by multiple goroutines concurrently.
+type Stmt interface {
+ // Close closes the statement.
+ //
+ // Closing a statement should not interrupt any outstanding
+ // query created from that statement. That is, the following
+ // order of operations is valid:
+ //
+ // * create a driver statement
+ // * call Query on statement, returning Rows
+ // * close the statement
+ // * read from Rows
+ //
+ // If closing a statement invalidates currently-running
+ // queries, the final step above will incorrectly fail.
+ //
+ // TODO(bradfitz): possibly remove the restriction above, if
+ // enough driver authors object and find it complicates their
+ // code too much. The sql package could be smarter about
+ // refcounting the statement and closing it at the appropriate
+ // time.
+ Close() error
+
+ // NumInput returns the number of placeholder parameters.
+ //
+ // If NumInput returns >= 0, the sql package will sanity check
+ // argument counts from callers and return errors to the caller
+ // before the statement's Exec or Query methods are called.
+ //
+ // NumInput may also return -1, if the driver doesn't know
+ // its number of placeholders. In that case, the sql package
+ // will not sanity check Exec or Query argument counts.
+ NumInput() int
+
+ // Exec executes a query that doesn't return rows, such
+ // as an INSERT or UPDATE.
+ Exec(args []Value) (Result, error)
+
+ // Exec executes a query that may return rows, such as a
+ // SELECT.
+ Query(args []Value) (Rows, error)
+}
+
+// ColumnConverter may be optionally implemented by Stmt if the
+// the statement is aware of its own columns' types and can
+// convert from any type to a driver Value.
+type ColumnConverter interface {
+ // ColumnConverter returns a ValueConverter for the provided
+ // column index. If the type of a specific column isn't known
+ // or shouldn't be handled specially, DefaultValueConverter
+ // can be returned.
+ ColumnConverter(idx int) ValueConverter
+}
+
+// Rows is an iterator over an executed query's results.
+type Rows interface {
+ // Columns returns the names of the columns. The number of
+ // columns of the result is inferred from the length of the
+ // slice. If a particular column name isn't known, an empty
+ // string should be returned for that entry.
+ Columns() []string
+
+ // Close closes the rows iterator.
+ Close() error
+
+ // Next is called to populate the next row of data into
+ // the provided slice. The provided slice will be the same
+ // size as the Columns() are wide.
+ //
+ // The dest slice may be populated only with
+ // a driver Value type, but excluding string.
+ // All string values must be converted to []byte.
+ //
+ // Next should return io.EOF when there are no more rows.
+ Next(dest []Value) error
+}
+
+// Tx is a transaction.
+type Tx interface {
+ Commit() error
+ Rollback() error
+}
+
+// RowsAffected implements Result for an INSERT or UPDATE operation
+// which mutates a number of rows.
+type RowsAffected int64
+
+var _ Result = RowsAffected(0)
+
+func (RowsAffected) LastInsertId() (int64, error) {
+ return 0, errors.New("no LastInsertId available")
+}
+
+func (v RowsAffected) RowsAffected() (int64, error) {
+ return int64(v), nil
+}
+
+// ResultNoRows is a pre-defined Result for drivers to return when a DDL
+// command (such as a CREATE TABLE) succeeds. It returns an error for both
+// LastInsertId and RowsAffected.
+var ResultNoRows noRows
+
+type noRows struct{}
+
+var _ Result = noRows{}
+
+func (noRows) LastInsertId() (int64, error) {
+ return 0, errors.New("no LastInsertId available after DDL statement")
+}
+
+func (noRows) RowsAffected() (int64, error) {
+ return 0, errors.New("no RowsAffected available after DDL statement")
+}
diff --git a/src/pkg/database/sql/driver/types.go b/src/pkg/database/sql/driver/types.go
new file mode 100644
index 000000000..3305354df
--- /dev/null
+++ b/src/pkg/database/sql/driver/types.go
@@ -0,0 +1,252 @@
+// 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 driver
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+ "time"
+)
+
+// ValueConverter is the interface providing the ConvertValue method.
+//
+// Various implementations of ValueConverter are provided by the
+// driver package to provide consistent implementations of conversions
+// between drivers. The ValueConverters have several uses:
+//
+// * converting from the Value types as provided by the sql package
+// into a database table's specific column type and making sure it
+// fits, such as making sure a particular int64 fits in a
+// table's uint16 column.
+//
+// * converting a value as given from the database into one of the
+// driver Value types.
+//
+// * by the sql package, for converting from a driver's Value type
+// to a user's type in a scan.
+type ValueConverter interface {
+ // ConvertValue converts a value to a driver Value.
+ ConvertValue(v interface{}) (Value, error)
+}
+
+// Valuer is the interface providing the Value method.
+//
+// Types implementing Valuer interface are able to convert
+// themselves to a driver Value.
+type Valuer interface {
+ // Value returns a driver Value.
+ Value() (Value, error)
+}
+
+// Bool is a ValueConverter that converts input values to bools.
+//
+// The conversion rules are:
+// - booleans are returned unchanged
+// - for integer types,
+// 1 is true
+// 0 is false,
+// other integers are an error
+// - for strings and []byte, same rules as strconv.ParseBool
+// - all other types are an error
+var Bool boolType
+
+type boolType struct{}
+
+var _ ValueConverter = boolType{}
+
+func (boolType) String() string { return "Bool" }
+
+func (boolType) ConvertValue(src interface{}) (Value, error) {
+ switch s := src.(type) {
+ case bool:
+ return s, nil
+ case string:
+ b, err := strconv.ParseBool(s)
+ if err != nil {
+ return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
+ }
+ return b, nil
+ case []byte:
+ b, err := strconv.ParseBool(string(s))
+ if err != nil {
+ return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
+ }
+ return b, nil
+ }
+
+ sv := reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ iv := sv.Int()
+ if iv == 1 || iv == 0 {
+ return iv == 1, nil
+ }
+ return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ uv := sv.Uint()
+ if uv == 1 || uv == 0 {
+ return uv == 1, nil
+ }
+ return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv)
+ }
+
+ return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src)
+}
+
+// Int32 is a ValueConverter that converts input values to int64,
+// respecting the limits of an int32 value.
+var Int32 int32Type
+
+type int32Type struct{}
+
+var _ ValueConverter = int32Type{}
+
+func (int32Type) ConvertValue(v interface{}) (Value, error) {
+ rv := reflect.ValueOf(v)
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ i64 := rv.Int()
+ if i64 > (1<<31)-1 || i64 < -(1<<31) {
+ return nil, fmt.Errorf("sql/driver: value %d overflows int32", v)
+ }
+ return i64, nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ u64 := rv.Uint()
+ if u64 > (1<<31)-1 {
+ return nil, fmt.Errorf("sql/driver: value %d overflows int32", v)
+ }
+ return int64(u64), nil
+ case reflect.String:
+ i, err := strconv.Atoi(rv.String())
+ if err != nil {
+ return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v)
+ }
+ return int64(i), nil
+ }
+ return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v)
+}
+
+// String is a ValueConverter that converts its input to a string.
+// If the value is already a string or []byte, it's unchanged.
+// If the value is of another type, conversion to string is done
+// with fmt.Sprintf("%v", v).
+var String stringType
+
+type stringType struct{}
+
+func (stringType) ConvertValue(v interface{}) (Value, error) {
+ switch v.(type) {
+ case string, []byte:
+ return v, nil
+ }
+ return fmt.Sprintf("%v", v), nil
+}
+
+// Null is a type that implements ValueConverter by allowing nil
+// values but otherwise delegating to another ValueConverter.
+type Null struct {
+ Converter ValueConverter
+}
+
+func (n Null) ConvertValue(v interface{}) (Value, error) {
+ if v == nil {
+ return nil, nil
+ }
+ return n.Converter.ConvertValue(v)
+}
+
+// NotNull is a type that implements ValueConverter by disallowing nil
+// values but otherwise delegating to another ValueConverter.
+type NotNull struct {
+ Converter ValueConverter
+}
+
+func (n NotNull) ConvertValue(v interface{}) (Value, error) {
+ if v == nil {
+ return nil, fmt.Errorf("nil value not allowed")
+ }
+ return n.Converter.ConvertValue(v)
+}
+
+// IsValue reports whether v is a valid Value parameter type.
+// Unlike IsScanValue, IsValue permits the string type.
+func IsValue(v interface{}) bool {
+ if IsScanValue(v) {
+ return true
+ }
+ if _, ok := v.(string); ok {
+ return true
+ }
+ return false
+}
+
+// IsScanValue reports whether v is a valid Value scan type.
+// Unlike IsValue, IsScanValue does not permit the string type.
+func IsScanValue(v interface{}) bool {
+ if v == nil {
+ return true
+ }
+ switch v.(type) {
+ case int64, float64, []byte, bool, time.Time:
+ return true
+ }
+ return false
+}
+
+// DefaultParameterConverter is the default implementation of
+// ValueConverter that's used when a Stmt doesn't implement
+// ColumnConverter.
+//
+// DefaultParameterConverter returns the given value directly if
+// IsValue(value). Otherwise integer type are converted to
+// int64, floats to float64, and strings to []byte. Other types are
+// an error.
+var DefaultParameterConverter defaultConverter
+
+type defaultConverter struct{}
+
+var _ ValueConverter = defaultConverter{}
+
+func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
+ if IsValue(v) {
+ return v, nil
+ }
+
+ if svi, ok := v.(Valuer); ok {
+ sv, err := svi.Value()
+ if err != nil {
+ return nil, err
+ }
+ if !IsValue(sv) {
+ return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
+ }
+ return sv, nil
+ }
+
+ rv := reflect.ValueOf(v)
+ switch rv.Kind() {
+ case reflect.Ptr:
+ // indirect pointers
+ if rv.IsNil() {
+ return nil, nil
+ } else {
+ return defaultConverter{}.ConvertValue(rv.Elem().Interface())
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return rv.Int(), nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+ return int64(rv.Uint()), nil
+ case reflect.Uint64:
+ u64 := rv.Uint()
+ if u64 >= 1<<63 {
+ return nil, fmt.Errorf("uint64 values with high bit set are not supported")
+ }
+ return int64(u64), nil
+ case reflect.Float32, reflect.Float64:
+ return rv.Float(), nil
+ }
+ return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
+}
diff --git a/src/pkg/database/sql/driver/types_test.go b/src/pkg/database/sql/driver/types_test.go
new file mode 100644
index 000000000..ab82bca71
--- /dev/null
+++ b/src/pkg/database/sql/driver/types_test.go
@@ -0,0 +1,65 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package driver
+
+import (
+ "reflect"
+ "testing"
+ "time"
+)
+
+type valueConverterTest struct {
+ c ValueConverter
+ in interface{}
+ out interface{}
+ err string
+}
+
+var now = time.Now()
+var answer int64 = 42
+
+var valueConverterTests = []valueConverterTest{
+ {Bool, "true", true, ""},
+ {Bool, "True", true, ""},
+ {Bool, []byte("t"), true, ""},
+ {Bool, true, true, ""},
+ {Bool, "1", true, ""},
+ {Bool, 1, true, ""},
+ {Bool, int64(1), true, ""},
+ {Bool, uint16(1), true, ""},
+ {Bool, "false", false, ""},
+ {Bool, false, false, ""},
+ {Bool, "0", false, ""},
+ {Bool, 0, false, ""},
+ {Bool, int64(0), false, ""},
+ {Bool, uint16(0), false, ""},
+ {c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
+ {c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"},
+ {DefaultParameterConverter, now, now, ""},
+ {DefaultParameterConverter, (*int64)(nil), nil, ""},
+ {DefaultParameterConverter, &answer, answer, ""},
+ {DefaultParameterConverter, &now, now, ""},
+}
+
+func TestValueConverters(t *testing.T) {
+ for i, tt := range valueConverterTests {
+ out, err := tt.c.ConvertValue(tt.in)
+ goterr := ""
+ if err != nil {
+ goterr = err.Error()
+ }
+ if goterr != tt.err {
+ t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q",
+ i, tt.c, tt.in, tt.in, goterr, tt.err)
+ }
+ if tt.err != "" {
+ continue
+ }
+ if !reflect.DeepEqual(out, tt.out) {
+ t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)",
+ i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
new file mode 100644
index 000000000..184e7756c
--- /dev/null
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -0,0 +1,629 @@
+// 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 sql
+
+import (
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+var _ = log.Printf
+
+// fakeDriver is a fake database that implements Go's driver.Driver
+// interface, just for testing.
+//
+// It speaks a query language that's semantically similar to but
+// syntantically different and simpler than SQL. The syntax is as
+// follows:
+//
+// WIPE
+// CREATE|<tablename>|<col>=<type>,<col>=<type>,...
+// where types are: "string", [u]int{8,16,32,64}, "bool"
+// INSERT|<tablename>|col=val,col2=val2,col3=?
+// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
+//
+// When opening a a fakeDriver's database, it starts empty with no
+// tables. All tables and data are stored in memory only.
+type fakeDriver struct {
+ mu sync.Mutex
+ openCount int
+ dbs map[string]*fakeDB
+}
+
+type fakeDB struct {
+ name string
+
+ mu sync.Mutex
+ free []*fakeConn
+ tables map[string]*table
+}
+
+type table struct {
+ mu sync.Mutex
+ colname []string
+ coltype []string
+ rows []*row
+}
+
+func (t *table) columnIndex(name string) int {
+ for n, nname := range t.colname {
+ if name == nname {
+ return n
+ }
+ }
+ return -1
+}
+
+type row struct {
+ cols []interface{} // must be same size as its table colname + coltype
+}
+
+func (r *row) clone() *row {
+ nrow := &row{cols: make([]interface{}, len(r.cols))}
+ copy(nrow.cols, r.cols)
+ return nrow
+}
+
+type fakeConn struct {
+ db *fakeDB // where to return ourselves to
+
+ currTx *fakeTx
+
+ // Stats for tests:
+ mu sync.Mutex
+ stmtsMade int
+ stmtsClosed int
+ numPrepare int
+}
+
+func (c *fakeConn) incrStat(v *int) {
+ c.mu.Lock()
+ *v++
+ c.mu.Unlock()
+}
+
+type fakeTx struct {
+ c *fakeConn
+}
+
+type fakeStmt struct {
+ c *fakeConn
+ q string // just for debugging
+
+ cmd string
+ table string
+
+ closed bool
+
+ colName []string // used by CREATE, INSERT, SELECT (selected columns)
+ colType []string // used by CREATE
+ colValue []interface{} // used by INSERT (mix of strings and "?" for bound params)
+ placeholders int // used by INSERT/SELECT: number of ? params
+
+ whereCol []string // used by SELECT (all placeholders)
+
+ placeholderConverter []driver.ValueConverter // used by INSERT
+}
+
+var fdriver driver.Driver = &fakeDriver{}
+
+func init() {
+ Register("test", fdriver)
+}
+
+// Supports dsn forms:
+// <dbname>
+// <dbname>;<opts> (no currently supported options)
+func (d *fakeDriver) Open(dsn string) (driver.Conn, error) {
+ parts := strings.Split(dsn, ";")
+ if len(parts) < 1 {
+ return nil, errors.New("fakedb: no database name")
+ }
+ name := parts[0]
+
+ db := d.getDB(name)
+
+ d.mu.Lock()
+ d.openCount++
+ d.mu.Unlock()
+ return &fakeConn{db: db}, nil
+}
+
+func (d *fakeDriver) getDB(name string) *fakeDB {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.dbs == nil {
+ d.dbs = make(map[string]*fakeDB)
+ }
+ db, ok := d.dbs[name]
+ if !ok {
+ db = &fakeDB{name: name}
+ d.dbs[name] = db
+ }
+ return db
+}
+
+func (db *fakeDB) wipe() {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ db.tables = nil
+}
+
+func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if db.tables == nil {
+ db.tables = make(map[string]*table)
+ }
+ if _, exist := db.tables[name]; exist {
+ return fmt.Errorf("table %q already exists", name)
+ }
+ if len(columnNames) != len(columnTypes) {
+ return fmt.Errorf("create table of %q len(names) != len(types): %d vs %d",
+ name, len(columnNames), len(columnTypes))
+ }
+ db.tables[name] = &table{colname: columnNames, coltype: columnTypes}
+ return nil
+}
+
+// must be called with db.mu lock held
+func (db *fakeDB) table(table string) (*table, bool) {
+ if db.tables == nil {
+ return nil, false
+ }
+ t, ok := db.tables[table]
+ return t, ok
+}
+
+func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ t, ok := db.table(table)
+ if !ok {
+ return
+ }
+ for n, cname := range t.colname {
+ if cname == column {
+ return t.coltype[n], true
+ }
+ }
+ return "", false
+}
+
+func (c *fakeConn) Begin() (driver.Tx, error) {
+ if c.currTx != nil {
+ return nil, errors.New("already in a transaction")
+ }
+ c.currTx = &fakeTx{c: c}
+ return c.currTx, nil
+}
+
+func (c *fakeConn) Close() error {
+ if c.currTx != nil {
+ return errors.New("can't close fakeConn; in a Transaction")
+ }
+ if c.db == nil {
+ return errors.New("can't close fakeConn; already closed")
+ }
+ if c.stmtsMade > c.stmtsClosed {
+ return errors.New("can't close; dangling statement(s)")
+ }
+ c.db = nil
+ return nil
+}
+
+func checkSubsetTypes(args []driver.Value) error {
+ for n, arg := range args {
+ switch arg.(type) {
+ case int64, float64, bool, nil, []byte, string, time.Time:
+ default:
+ return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
+ }
+ }
+ return nil
+}
+
+func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ // This is an optional interface, but it's implemented here
+ // just to check that all the args of of the proper types.
+ // ErrSkip is returned so the caller acts as if we didn't
+ // implement this at all.
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+ return nil, driver.ErrSkip
+}
+
+func errf(msg string, args ...interface{}) error {
+ return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
+}
+
+// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=?
+// (note that where where columns must always contain ? marks,
+// just a limitation for fakedb)
+func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+ if len(parts) != 3 {
+ stmt.Close()
+ return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
+ }
+ stmt.table = parts[0]
+ stmt.colName = strings.Split(parts[1], ",")
+ for n, colspec := range strings.Split(parts[2], ",") {
+ if colspec == "" {
+ continue
+ }
+ nameVal := strings.Split(colspec, "=")
+ if len(nameVal) != 2 {
+ stmt.Close()
+ return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
+ }
+ column, value := nameVal[0], nameVal[1]
+ _, ok := c.db.columnType(stmt.table, column)
+ if !ok {
+ stmt.Close()
+ return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
+ }
+ if value != "?" {
+ stmt.Close()
+ return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
+ stmt.table, column)
+ }
+ stmt.whereCol = append(stmt.whereCol, column)
+ stmt.placeholders++
+ }
+ return stmt, nil
+}
+
+// parts are table|col=type,col2=type2
+func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+ if len(parts) != 2 {
+ stmt.Close()
+ return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
+ }
+ stmt.table = parts[0]
+ for n, colspec := range strings.Split(parts[1], ",") {
+ nameType := strings.Split(colspec, "=")
+ if len(nameType) != 2 {
+ stmt.Close()
+ return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
+ }
+ stmt.colName = append(stmt.colName, nameType[0])
+ stmt.colType = append(stmt.colType, nameType[1])
+ }
+ return stmt, nil
+}
+
+// parts are table|col=?,col2=val
+func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+ if len(parts) != 2 {
+ stmt.Close()
+ return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
+ }
+ stmt.table = parts[0]
+ for n, colspec := range strings.Split(parts[1], ",") {
+ nameVal := strings.Split(colspec, "=")
+ if len(nameVal) != 2 {
+ stmt.Close()
+ return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
+ }
+ column, value := nameVal[0], nameVal[1]
+ ctype, ok := c.db.columnType(stmt.table, column)
+ if !ok {
+ stmt.Close()
+ return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column)
+ }
+ stmt.colName = append(stmt.colName, column)
+
+ if value != "?" {
+ var subsetVal interface{}
+ // Convert to driver subset type
+ switch ctype {
+ case "string":
+ subsetVal = []byte(value)
+ case "blob":
+ subsetVal = []byte(value)
+ case "int32":
+ i, err := strconv.Atoi(value)
+ if err != nil {
+ stmt.Close()
+ return nil, errf("invalid conversion to int32 from %q", value)
+ }
+ subsetVal = int64(i) // int64 is a subset type, but not int32
+ default:
+ stmt.Close()
+ return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype)
+ }
+ stmt.colValue = append(stmt.colValue, subsetVal)
+ } else {
+ stmt.placeholders++
+ stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype))
+ stmt.colValue = append(stmt.colValue, "?")
+ }
+ }
+ return stmt, nil
+}
+
+func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
+ c.numPrepare++
+ if c.db == nil {
+ panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
+ }
+ parts := strings.Split(query, "|")
+ if len(parts) < 1 {
+ return nil, errf("empty query")
+ }
+ cmd := parts[0]
+ parts = parts[1:]
+ stmt := &fakeStmt{q: query, c: c, cmd: cmd}
+ c.incrStat(&c.stmtsMade)
+ switch cmd {
+ case "WIPE":
+ // Nothing
+ case "SELECT":
+ return c.prepareSelect(stmt, parts)
+ case "CREATE":
+ return c.prepareCreate(stmt, parts)
+ case "INSERT":
+ return c.prepareInsert(stmt, parts)
+ default:
+ stmt.Close()
+ return nil, errf("unsupported command type %q", cmd)
+ }
+ return stmt, nil
+}
+
+func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
+ return s.placeholderConverter[idx]
+}
+
+func (s *fakeStmt) Close() error {
+ if !s.closed {
+ s.c.incrStat(&s.c.stmtsClosed)
+ s.closed = true
+ }
+ return nil
+}
+
+var errClosed = errors.New("fakedb: statement has been closed")
+
+func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
+ if s.closed {
+ return nil, errClosed
+ }
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+
+ db := s.c.db
+ switch s.cmd {
+ case "WIPE":
+ db.wipe()
+ return driver.ResultNoRows, nil
+ case "CREATE":
+ if err := db.createTable(s.table, s.colName, s.colType); err != nil {
+ return nil, err
+ }
+ return driver.ResultNoRows, nil
+ case "INSERT":
+ return s.execInsert(args)
+ }
+ fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s)
+ return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd)
+}
+
+func (s *fakeStmt) execInsert(args []driver.Value) (driver.Result, error) {
+ db := s.c.db
+ if len(args) != s.placeholders {
+ panic("error in pkg db; should only get here if size is correct")
+ }
+ db.mu.Lock()
+ t, ok := db.table(s.table)
+ db.mu.Unlock()
+ if !ok {
+ return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
+ }
+
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ cols := make([]interface{}, len(t.colname))
+ argPos := 0
+ for n, colname := range s.colName {
+ colidx := t.columnIndex(colname)
+ if colidx == -1 {
+ return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname)
+ }
+ var val interface{}
+ if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" {
+ val = args[argPos]
+ argPos++
+ } else {
+ val = s.colValue[n]
+ }
+ cols[colidx] = val
+ }
+
+ t.rows = append(t.rows, &row{cols: cols})
+ return driver.RowsAffected(1), nil
+}
+
+func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
+ if s.closed {
+ return nil, errClosed
+ }
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+
+ db := s.c.db
+ if len(args) != s.placeholders {
+ panic("error in pkg db; should only get here if size is correct")
+ }
+
+ db.mu.Lock()
+ t, ok := db.table(s.table)
+ db.mu.Unlock()
+ if !ok {
+ return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
+ }
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ colIdx := make(map[string]int) // select column name -> column index in table
+ for _, name := range s.colName {
+ idx := t.columnIndex(name)
+ if idx == -1 {
+ return nil, fmt.Errorf("fakedb: unknown column name %q", name)
+ }
+ colIdx[name] = idx
+ }
+
+ mrows := []*row{}
+rows:
+ for _, trow := range t.rows {
+ // Process the where clause, skipping non-match rows. This is lazy
+ // and just uses fmt.Sprintf("%v") to test equality. Good enough
+ // for test code.
+ for widx, wcol := range s.whereCol {
+ idx := t.columnIndex(wcol)
+ if idx == -1 {
+ return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
+ }
+ tcol := trow.cols[idx]
+ if bs, ok := tcol.([]byte); ok {
+ // lazy hack to avoid sprintf %v on a []byte
+ tcol = string(bs)
+ }
+ if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) {
+ continue rows
+ }
+ }
+ mrow := &row{cols: make([]interface{}, len(s.colName))}
+ for seli, name := range s.colName {
+ mrow.cols[seli] = trow.cols[colIdx[name]]
+ }
+ mrows = append(mrows, mrow)
+ }
+
+ cursor := &rowsCursor{
+ pos: -1,
+ rows: mrows,
+ cols: s.colName,
+ }
+ return cursor, nil
+}
+
+func (s *fakeStmt) NumInput() int {
+ return s.placeholders
+}
+
+func (tx *fakeTx) Commit() error {
+ tx.c.currTx = nil
+ return nil
+}
+
+func (tx *fakeTx) Rollback() error {
+ tx.c.currTx = nil
+ return nil
+}
+
+type rowsCursor struct {
+ cols []string
+ pos int
+ rows []*row
+ closed bool
+
+ // a clone of slices to give out to clients, indexed by the
+ // the original slice's first byte address. we clone them
+ // just so we're able to corrupt them on close.
+ bytesClone map[*byte][]byte
+}
+
+func (rc *rowsCursor) Close() error {
+ if !rc.closed {
+ for _, bs := range rc.bytesClone {
+ bs[0] = 255 // first byte corrupted
+ }
+ }
+ rc.closed = true
+ return nil
+}
+
+func (rc *rowsCursor) Columns() []string {
+ return rc.cols
+}
+
+func (rc *rowsCursor) Next(dest []driver.Value) error {
+ if rc.closed {
+ return errors.New("fakedb: cursor is closed")
+ }
+ rc.pos++
+ if rc.pos >= len(rc.rows) {
+ return io.EOF // per interface spec
+ }
+ for i, v := range rc.rows[rc.pos].cols {
+ // TODO(bradfitz): convert to subset types? naah, I
+ // think the subset types should only be input to
+ // driver, but the sql package should be able to handle
+ // a wider range of types coming out of drivers. all
+ // for ease of drivers, and to prevent drivers from
+ // messing up conversions or doing them differently.
+ dest[i] = v
+
+ if bs, ok := v.([]byte); ok {
+ if rc.bytesClone == nil {
+ rc.bytesClone = make(map[*byte][]byte)
+ }
+ clone, ok := rc.bytesClone[&bs[0]]
+ if !ok {
+ clone = make([]byte, len(bs))
+ copy(clone, bs)
+ rc.bytesClone[&bs[0]] = clone
+ }
+ dest[i] = clone
+ }
+ }
+ return nil
+}
+
+func converterForType(typ string) driver.ValueConverter {
+ switch typ {
+ case "bool":
+ return driver.Bool
+ case "nullbool":
+ return driver.Null{Converter: driver.Bool}
+ case "int32":
+ return driver.Int32
+ case "string":
+ return driver.NotNull{Converter: driver.String}
+ case "nullstring":
+ return driver.Null{Converter: driver.String}
+ case "int64":
+ // TODO(coopernurse): add type-specific converter
+ return driver.NotNull{Converter: driver.DefaultParameterConverter}
+ case "nullint64":
+ // TODO(coopernurse): add type-specific converter
+ return driver.Null{Converter: driver.DefaultParameterConverter}
+ case "float64":
+ // TODO(coopernurse): add type-specific converter
+ return driver.NotNull{Converter: driver.DefaultParameterConverter}
+ case "nullfloat64":
+ // TODO(coopernurse): add type-specific converter
+ return driver.Null{Converter: driver.DefaultParameterConverter}
+ case "datetime":
+ return driver.DefaultParameterConverter
+ }
+ panic("invalid fakedb column type of " + typ)
+}
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
new file mode 100644
index 000000000..51a357b37
--- /dev/null
+++ b/src/pkg/database/sql/sql.go
@@ -0,0 +1,1063 @@
+// 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 sql provides a generic interface around SQL (or SQL-like)
+// databases.
+package sql
+
+import (
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "io"
+ "sync"
+)
+
+var drivers = make(map[string]driver.Driver)
+
+// Register makes a database driver available by the provided name.
+// If Register is called twice with the same name or if driver is nil,
+// it panics.
+func Register(name string, driver driver.Driver) {
+ if driver == nil {
+ panic("sql: Register driver is nil")
+ }
+ if _, dup := drivers[name]; dup {
+ panic("sql: Register called twice for driver " + name)
+ }
+ drivers[name] = driver
+}
+
+// RawBytes is a byte slice that holds a reference to memory owned by
+// the database itself. After a Scan into a RawBytes, the slice is only
+// valid until the next call to Next, Scan, or Close.
+type RawBytes []byte
+
+// NullString represents a string that may be null.
+// NullString implements the Scanner interface so
+// it can be used as a scan destination:
+//
+// var s NullString
+// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
+// ...
+// if s.Valid {
+// // use s.String
+// } else {
+// // NULL value
+// }
+//
+type NullString struct {
+ String string
+ Valid bool // Valid is true if String is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (ns *NullString) Scan(value interface{}) error {
+ if value == nil {
+ ns.String, ns.Valid = "", false
+ return nil
+ }
+ ns.Valid = true
+ return convertAssign(&ns.String, value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullString) Value() (driver.Value, error) {
+ if !ns.Valid {
+ return nil, nil
+ }
+ return ns.String, nil
+}
+
+// NullInt64 represents an int64 that may be null.
+// NullInt64 implements the Scanner interface so
+// it can be used as a scan destination, similar to NullString.
+type NullInt64 struct {
+ Int64 int64
+ Valid bool // Valid is true if Int64 is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (n *NullInt64) Scan(value interface{}) error {
+ if value == nil {
+ n.Int64, n.Valid = 0, false
+ return nil
+ }
+ n.Valid = true
+ return convertAssign(&n.Int64, value)
+}
+
+// Value implements the driver Valuer interface.
+func (n NullInt64) Value() (driver.Value, error) {
+ if !n.Valid {
+ return nil, nil
+ }
+ return n.Int64, nil
+}
+
+// NullFloat64 represents a float64 that may be null.
+// NullFloat64 implements the Scanner interface so
+// it can be used as a scan destination, similar to NullString.
+type NullFloat64 struct {
+ Float64 float64
+ Valid bool // Valid is true if Float64 is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (n *NullFloat64) Scan(value interface{}) error {
+ if value == nil {
+ n.Float64, n.Valid = 0, false
+ return nil
+ }
+ n.Valid = true
+ return convertAssign(&n.Float64, value)
+}
+
+// Value implements the driver Valuer interface.
+func (n NullFloat64) Value() (driver.Value, error) {
+ if !n.Valid {
+ return nil, nil
+ }
+ return n.Float64, nil
+}
+
+// NullBool represents a bool that may be null.
+// NullBool implements the Scanner interface so
+// it can be used as a scan destination, similar to NullString.
+type NullBool struct {
+ Bool bool
+ Valid bool // Valid is true if Bool is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (n *NullBool) Scan(value interface{}) error {
+ if value == nil {
+ n.Bool, n.Valid = false, false
+ return nil
+ }
+ n.Valid = true
+ return convertAssign(&n.Bool, value)
+}
+
+// Value implements the driver Valuer interface.
+func (n NullBool) Value() (driver.Value, error) {
+ if !n.Valid {
+ return nil, nil
+ }
+ return n.Bool, nil
+}
+
+// Scanner is an interface used by Scan.
+type Scanner interface {
+ // Scan assigns a value from a database driver.
+ //
+ // The src value will be of one of the following restricted
+ // set of types:
+ //
+ // int64
+ // float64
+ // bool
+ // []byte
+ // string
+ // time.Time
+ // nil - for NULL values
+ //
+ // An error should be returned if the value can not be stored
+ // without loss of information.
+ Scan(src interface{}) error
+}
+
+// ErrNoRows is returned by Scan when QueryRow doesn't return a
+// row. In such a case, QueryRow returns a placeholder *Row value that
+// defers this error until a Scan.
+var ErrNoRows = errors.New("sql: no rows in result set")
+
+// DB is a database handle. It's safe for concurrent use by multiple
+// goroutines.
+//
+// If the underlying database driver has the concept of a connection
+// and per-connection session state, the sql package manages creating
+// and freeing connections automatically, including maintaining a free
+// pool of idle connections. If observing session state is required,
+// either do not share a *DB between multiple concurrent goroutines or
+// create and observe all state only within a transaction. Once
+// DB.Open is called, the returned Tx is bound to a single isolated
+// connection. Once Tx.Commit or Tx.Rollback is called, that
+// connection is returned to DB's idle connection pool.
+type DB struct {
+ driver driver.Driver
+ dsn string
+
+ mu sync.Mutex // protects freeConn and closed
+ freeConn []driver.Conn
+ closed bool
+}
+
+// Open opens a database specified by its database driver name and a
+// driver-specific data source name, usually consisting of at least a
+// database name and connection information.
+//
+// Most users will open a database via a driver-specific connection
+// helper function that returns a *DB.
+func Open(driverName, dataSourceName string) (*DB, error) {
+ driver, ok := drivers[driverName]
+ if !ok {
+ return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
+ }
+ return &DB{driver: driver, dsn: dataSourceName}, nil
+}
+
+// Close closes the database, releasing any open resources.
+func (db *DB) Close() error {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ var err error
+ for _, c := range db.freeConn {
+ err1 := c.Close()
+ if err1 != nil {
+ err = err1
+ }
+ }
+ db.freeConn = nil
+ db.closed = true
+ return err
+}
+
+func (db *DB) maxIdleConns() int {
+ const defaultMaxIdleConns = 2
+ // TODO(bradfitz): ask driver, if supported, for its default preference
+ // TODO(bradfitz): let users override?
+ return defaultMaxIdleConns
+}
+
+// conn returns a newly-opened or cached driver.Conn
+func (db *DB) conn() (driver.Conn, error) {
+ db.mu.Lock()
+ if db.closed {
+ db.mu.Unlock()
+ return nil, errors.New("sql: database is closed")
+ }
+ if n := len(db.freeConn); n > 0 {
+ conn := db.freeConn[n-1]
+ db.freeConn = db.freeConn[:n-1]
+ db.mu.Unlock()
+ return conn, nil
+ }
+ db.mu.Unlock()
+ return db.driver.Open(db.dsn)
+}
+
+func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ for i, conn := range db.freeConn {
+ if conn != wanted {
+ continue
+ }
+ db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
+ db.freeConn = db.freeConn[:len(db.freeConn)-1]
+ return wanted, true
+ }
+ return nil, false
+}
+
+// putConnHook is a hook for testing.
+var putConnHook func(*DB, driver.Conn)
+
+// putConn adds a connection to the db's free pool.
+// err is optionally the last error that occured on this connection.
+func (db *DB) putConn(c driver.Conn, err error) {
+ if err == driver.ErrBadConn {
+ // Don't reuse bad connections.
+ return
+ }
+ db.mu.Lock()
+ if putConnHook != nil {
+ putConnHook(db, c)
+ }
+ if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
+ db.freeConn = append(db.freeConn, c)
+ db.mu.Unlock()
+ return
+ }
+ // TODO: check to see if we need this Conn for any prepared
+ // statements which are still active?
+ db.mu.Unlock()
+ c.Close()
+}
+
+// Prepare creates a prepared statement for later execution.
+func (db *DB) Prepare(query string) (*Stmt, error) {
+ var stmt *Stmt
+ var err error
+ for i := 0; i < 10; i++ {
+ stmt, err = db.prepare(query)
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return stmt, err
+}
+
+func (db *DB) prepare(query string) (stmt *Stmt, err error) {
+ // TODO: check if db.driver supports an optional
+ // driver.Preparer interface and call that instead, if so,
+ // otherwise we make a prepared statement that's bound
+ // to a connection, and to execute this prepared statement
+ // we either need to use this connection (if it's free), else
+ // get a new connection + re-prepare + execute on that one.
+ ci, err := db.conn()
+ if err != nil {
+ return nil, err
+ }
+ defer db.putConn(ci, err)
+ si, err := ci.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ stmt = &Stmt{
+ db: db,
+ query: query,
+ css: []connStmt{{ci, si}},
+ }
+ return stmt, nil
+}
+
+// Exec executes a query without returning any rows.
+func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
+ sargs, err := subsetTypeArgs(args)
+ var res Result
+ for i := 0; i < 10; i++ {
+ res, err = db.exec(query, sargs)
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return res, err
+}
+
+func (db *DB) exec(query string, sargs []driver.Value) (res Result, err error) {
+ ci, err := db.conn()
+ if err != nil {
+ return nil, err
+ }
+ defer db.putConn(ci, err)
+
+ if execer, ok := ci.(driver.Execer); ok {
+ resi, err := execer.Exec(query, sargs)
+ if err != driver.ErrSkip {
+ if err != nil {
+ return nil, err
+ }
+ return result{resi}, nil
+ }
+ }
+
+ sti, err := ci.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ defer sti.Close()
+
+ resi, err := sti.Exec(sargs)
+ if err != nil {
+ return nil, err
+ }
+ return result{resi}, nil
+}
+
+// Query executes a query that returns rows, typically a SELECT.
+func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+ stmt, err := db.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ rows, err := stmt.Query(args...)
+ if err != nil {
+ stmt.Close()
+ return nil, err
+ }
+ rows.closeStmt = stmt
+ return rows, nil
+}
+
+// QueryRow executes a query that is expected to return at most one row.
+// QueryRow always return a non-nil value. Errors are deferred until
+// Row's Scan method is called.
+func (db *DB) QueryRow(query string, args ...interface{}) *Row {
+ rows, err := db.Query(query, args...)
+ return &Row{rows: rows, err: err}
+}
+
+// Begin starts a transaction. The isolation level is dependent on
+// the driver.
+func (db *DB) Begin() (*Tx, error) {
+ var tx *Tx
+ var err error
+ for i := 0; i < 10; i++ {
+ tx, err = db.begin()
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return tx, err
+}
+
+func (db *DB) begin() (tx *Tx, err error) {
+ ci, err := db.conn()
+ if err != nil {
+ return nil, err
+ }
+ txi, err := ci.Begin()
+ if err != nil {
+ db.putConn(ci, err)
+ return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err)
+ }
+ return &Tx{
+ db: db,
+ ci: ci,
+ txi: txi,
+ }, nil
+}
+
+// Driver returns the database's underlying driver.
+func (db *DB) Driver() driver.Driver {
+ return db.driver
+}
+
+// Tx is an in-progress database transaction.
+//
+// A transaction must end with a call to Commit or Rollback.
+//
+// After a call to Commit or Rollback, all operations on the
+// transaction fail with ErrTxDone.
+type Tx struct {
+ db *DB
+
+ // ci is owned exclusively until Commit or Rollback, at which point
+ // it's returned with putConn.
+ ci driver.Conn
+ txi driver.Tx
+
+ // cimu is held while somebody is using ci (between grabConn
+ // and releaseConn)
+ cimu sync.Mutex
+
+ // done transitions from false to true exactly once, on Commit
+ // or Rollback. once done, all operations fail with
+ // ErrTxDone.
+ done bool
+}
+
+var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
+
+func (tx *Tx) close() {
+ if tx.done {
+ panic("double close") // internal error
+ }
+ tx.done = true
+ tx.db.putConn(tx.ci, nil)
+ tx.ci = nil
+ tx.txi = nil
+}
+
+func (tx *Tx) grabConn() (driver.Conn, error) {
+ if tx.done {
+ return nil, ErrTxDone
+ }
+ tx.cimu.Lock()
+ return tx.ci, nil
+}
+
+func (tx *Tx) releaseConn() {
+ tx.cimu.Unlock()
+}
+
+// Commit commits the transaction.
+func (tx *Tx) Commit() error {
+ if tx.done {
+ return ErrTxDone
+ }
+ defer tx.close()
+ return tx.txi.Commit()
+}
+
+// Rollback aborts the transaction.
+func (tx *Tx) Rollback() error {
+ if tx.done {
+ return ErrTxDone
+ }
+ defer tx.close()
+ return tx.txi.Rollback()
+}
+
+// Prepare creates a prepared statement for use within a transaction.
+//
+// The returned statement operates within the transaction and can no longer
+// be used once the transaction has been committed or rolled back.
+//
+// To use an existing prepared statement on this transaction, see Tx.Stmt.
+func (tx *Tx) Prepare(query string) (*Stmt, error) {
+ // TODO(bradfitz): We could be more efficient here and either
+ // provide a method to take an existing Stmt (created on
+ // perhaps a different Conn), and re-create it on this Conn if
+ // necessary. Or, better: keep a map in DB of query string to
+ // Stmts, and have Stmt.Execute do the right thing and
+ // re-prepare if the Conn in use doesn't have that prepared
+ // statement. But we'll want to avoid caching the statement
+ // in the case where we only call conn.Prepare implicitly
+ // (such as in db.Exec or tx.Exec), but the caller package
+ // can't be holding a reference to the returned statement.
+ // Perhaps just looking at the reference count (by noting
+ // Stmt.Close) would be enough. We might also want a finalizer
+ // on Stmt to drop the reference count.
+ ci, err := tx.grabConn()
+ if err != nil {
+ return nil, err
+ }
+ defer tx.releaseConn()
+
+ si, err := ci.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+
+ stmt := &Stmt{
+ db: tx.db,
+ tx: tx,
+ txsi: si,
+ query: query,
+ }
+ return stmt, nil
+}
+
+// Stmt returns a transaction-specific prepared statement from
+// an existing statement.
+//
+// Example:
+// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
+// ...
+// tx, err := db.Begin()
+// ...
+// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+ // TODO(bradfitz): optimize this. Currently this re-prepares
+ // each time. This is fine for now to illustrate the API but
+ // we should really cache already-prepared statements
+ // per-Conn. See also the big comment in Tx.Prepare.
+
+ if tx.db != stmt.db {
+ return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
+ }
+ ci, err := tx.grabConn()
+ if err != nil {
+ return &Stmt{stickyErr: err}
+ }
+ defer tx.releaseConn()
+ si, err := ci.Prepare(stmt.query)
+ return &Stmt{
+ db: tx.db,
+ tx: tx,
+ txsi: si,
+ query: stmt.query,
+ stickyErr: err,
+ }
+}
+
+// Exec executes a query that doesn't return rows.
+// For example: an INSERT and UPDATE.
+func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
+ ci, err := tx.grabConn()
+ if err != nil {
+ return nil, err
+ }
+ defer tx.releaseConn()
+
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
+ }
+
+ if execer, ok := ci.(driver.Execer); ok {
+ resi, err := execer.Exec(query, sargs)
+ if err == nil {
+ return result{resi}, nil
+ }
+ if err != driver.ErrSkip {
+ return nil, err
+ }
+ }
+
+ sti, err := ci.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ defer sti.Close()
+
+ resi, err := sti.Exec(sargs)
+ if err != nil {
+ return nil, err
+ }
+ return result{resi}, nil
+}
+
+// Query executes a query that returns rows, typically a SELECT.
+func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
+ if tx.done {
+ return nil, ErrTxDone
+ }
+ stmt, err := tx.Prepare(query)
+ if err != nil {
+ return nil, err
+ }
+ rows, err := stmt.Query(args...)
+ if err != nil {
+ stmt.Close()
+ return nil, err
+ }
+ rows.closeStmt = stmt
+ return rows, err
+}
+
+// QueryRow executes a query that is expected to return at most one row.
+// QueryRow always return a non-nil value. Errors are deferred until
+// Row's Scan method is called.
+func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
+ rows, err := tx.Query(query, args...)
+ return &Row{rows: rows, err: err}
+}
+
+// connStmt is a prepared statement on a particular connection.
+type connStmt struct {
+ ci driver.Conn
+ si driver.Stmt
+}
+
+// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
+type Stmt struct {
+ // Immutable:
+ db *DB // where we came from
+ query string // that created the Stmt
+ stickyErr error // if non-nil, this error is returned for all operations
+
+ // If in a transaction, else both nil:
+ tx *Tx
+ txsi driver.Stmt
+
+ mu sync.Mutex // protects the rest of the fields
+ closed bool
+
+ // css is a list of underlying driver statement interfaces
+ // that are valid on particular connections. This is only
+ // used if tx == nil and one is found that has idle
+ // connections. If tx != nil, txsi is always used.
+ css []connStmt
+}
+
+// Exec executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+func (s *Stmt) Exec(args ...interface{}) (Result, error) {
+ _, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ return nil, err
+ }
+ defer releaseConn(nil)
+
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
+ if want := si.NumInput(); want != -1 && len(args) != want {
+ return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
+ }
+
+ sargs := make([]driver.Value, len(args))
+
+ // Convert args to subset types.
+ if cc, ok := si.(driver.ColumnConverter); ok {
+ for n, arg := range args {
+ // First, see if the value itself knows how to convert
+ // itself to a driver type. For example, a NullString
+ // struct changing into a string or nil.
+ if svi, ok := arg.(driver.Valuer); ok {
+ sv, err := svi.Value()
+ if err != nil {
+ return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err)
+ }
+ if !driver.IsValue(sv) {
+ return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv)
+ }
+ arg = sv
+ }
+
+ // Second, ask the column to sanity check itself. For
+ // example, drivers might use this to make sure that
+ // an int64 values being inserted into a 16-bit
+ // integer field is in range (before getting
+ // truncated), or that a nil can't go into a NOT NULL
+ // column before going across the network to get the
+ // same error.
+ sargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ if err != nil {
+ return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
+ }
+ if !driver.IsValue(sargs[n]) {
+ return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
+ arg, sargs[n])
+ }
+ }
+ } else {
+ for n, arg := range args {
+ sargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ if err != nil {
+ return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
+ }
+ }
+ }
+
+ resi, err := si.Exec(sargs)
+ if err != nil {
+ return nil, err
+ }
+ return result{resi}, nil
+}
+
+// connStmt returns a free driver connection on which to execute the
+// statement, a function to call to release the connection, and a
+// statement bound to that connection.
+func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.Stmt, err error) {
+ if err = s.stickyErr; err != nil {
+ return
+ }
+ s.mu.Lock()
+ if s.closed {
+ s.mu.Unlock()
+ err = errors.New("sql: statement is closed")
+ return
+ }
+
+ // In a transaction, we always use the connection that the
+ // transaction was created on.
+ if s.tx != nil {
+ s.mu.Unlock()
+ ci, err = s.tx.grabConn() // blocks, waiting for the connection.
+ if err != nil {
+ return
+ }
+ releaseConn = func(error) { s.tx.releaseConn() }
+ return ci, releaseConn, s.txsi, nil
+ }
+
+ var cs connStmt
+ match := false
+ for _, v := range s.css {
+ // TODO(bradfitz): lazily clean up entries in this
+ // list with dead conns while enumerating
+ if _, match = s.db.connIfFree(v.ci); match {
+ cs = v
+ break
+ }
+ }
+ s.mu.Unlock()
+
+ // Make a new conn if all are busy.
+ // TODO(bradfitz): or wait for one? make configurable later?
+ if !match {
+ for i := 0; ; i++ {
+ ci, err := s.db.conn()
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ si, err := ci.Prepare(s.query)
+ if err == driver.ErrBadConn && i < 10 {
+ continue
+ }
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ s.mu.Lock()
+ cs = connStmt{ci, si}
+ s.css = append(s.css, cs)
+ s.mu.Unlock()
+ break
+ }
+ }
+
+ conn := cs.ci
+ releaseConn = func(err error) { s.db.putConn(conn, err) }
+ return conn, releaseConn, cs.si, nil
+}
+
+// Query executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
+ ci, releaseConn, si, err := s.connStmt()
+ if err != nil {
+ return nil, err
+ }
+
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
+ if want := si.NumInput(); want != -1 && len(args) != want {
+ return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
+ }
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
+ }
+ rowsi, err := si.Query(sargs)
+ if err != nil {
+ releaseConn(err)
+ return nil, err
+ }
+ // Note: ownership of ci passes to the *Rows, to be freed
+ // with releaseConn.
+ rows := &Rows{
+ db: s.db,
+ ci: ci,
+ releaseConn: releaseConn,
+ rowsi: rowsi,
+ }
+ return rows, nil
+}
+
+// QueryRow executes a prepared query statement with the given arguments.
+// If an error occurs during the execution of the statement, that error will
+// be returned by a call to Scan on the returned *Row, which is always non-nil.
+// If the query selects no rows, the *Row's Scan will return ErrNoRows.
+// Otherwise, the *Row's Scan scans the first selected row and discards
+// the rest.
+//
+// Example usage:
+//
+// var name string
+// err := nameByUseridStmt.QueryRow(id).Scan(&name)
+func (s *Stmt) QueryRow(args ...interface{}) *Row {
+ rows, err := s.Query(args...)
+ if err != nil {
+ return &Row{err: err}
+ }
+ return &Row{rows: rows}
+}
+
+// Close closes the statement.
+func (s *Stmt) Close() error {
+ if s.stickyErr != nil {
+ return s.stickyErr
+ }
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.closed {
+ return nil
+ }
+ s.closed = true
+
+ if s.tx != nil {
+ s.txsi.Close()
+ } else {
+ for _, v := range s.css {
+ if ci, match := s.db.connIfFree(v.ci); match {
+ v.si.Close()
+ s.db.putConn(ci, nil)
+ } else {
+ // TODO(bradfitz): care that we can't close
+ // this statement because the statement's
+ // connection is in use?
+ }
+ }
+ }
+ return nil
+}
+
+// Rows is the result of a query. Its cursor starts before the first row
+// of the result set. Use Next to advance through the rows:
+//
+// rows, err := db.Query("SELECT ...")
+// ...
+// for rows.Next() {
+// var id int
+// var name string
+// err = rows.Scan(&id, &name)
+// ...
+// }
+// err = rows.Err() // get any error encountered during iteration
+// ...
+type Rows struct {
+ db *DB
+ ci driver.Conn // owned; must call putconn when closed to release
+ releaseConn func(error)
+ rowsi driver.Rows
+
+ closed bool
+ lastcols []driver.Value
+ lasterr error
+ closeStmt *Stmt // if non-nil, statement to Close on close
+}
+
+// Next prepares the next result row for reading with the Scan method.
+// It returns true on success, false if there is no next result row.
+// Every call to Scan, even the first one, must be preceded by a call
+// to Next.
+func (rs *Rows) Next() bool {
+ if rs.closed {
+ return false
+ }
+ if rs.lasterr != nil {
+ return false
+ }
+ if rs.lastcols == nil {
+ rs.lastcols = make([]driver.Value, len(rs.rowsi.Columns()))
+ }
+ rs.lasterr = rs.rowsi.Next(rs.lastcols)
+ if rs.lasterr == io.EOF {
+ rs.Close()
+ }
+ return rs.lasterr == nil
+}
+
+// Err returns the error, if any, that was encountered during iteration.
+func (rs *Rows) Err() error {
+ if rs.lasterr == io.EOF {
+ return nil
+ }
+ return rs.lasterr
+}
+
+// Columns returns the column names.
+// Columns returns an error if the rows are closed, or if the rows
+// are from QueryRow and there was a deferred error.
+func (rs *Rows) Columns() ([]string, error) {
+ if rs.closed {
+ return nil, errors.New("sql: Rows are closed")
+ }
+ if rs.rowsi == nil {
+ return nil, errors.New("sql: no Rows available")
+ }
+ return rs.rowsi.Columns(), nil
+}
+
+// Scan copies the columns in the current row into the values pointed
+// at by dest.
+//
+// If an argument has type *[]byte, Scan saves in that argument a copy
+// of the corresponding data. The copy is owned by the caller and can
+// be modified and held indefinitely. The copy can be avoided by using
+// an argument of type *RawBytes instead; see the documentation for
+// RawBytes for restrictions on its use.
+//
+// If an argument has type *interface{}, Scan copies the value
+// provided by the underlying driver without conversion. If the value
+// is of type []byte, a copy is made and the caller owns the result.
+func (rs *Rows) Scan(dest ...interface{}) error {
+ if rs.closed {
+ return errors.New("sql: Rows closed")
+ }
+ if rs.lasterr != nil {
+ return rs.lasterr
+ }
+ if rs.lastcols == nil {
+ return errors.New("sql: Scan called without calling Next")
+ }
+ if len(dest) != len(rs.lastcols) {
+ return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
+ }
+ for i, sv := range rs.lastcols {
+ err := convertAssign(dest[i], sv)
+ if err != nil {
+ return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
+ }
+ }
+ for _, dp := range dest {
+ b, ok := dp.(*[]byte)
+ if !ok {
+ continue
+ }
+ if *b == nil {
+ // If the []byte is now nil (for a NULL value),
+ // don't fall through to below which would
+ // turn it into a non-nil 0-length byte slice
+ continue
+ }
+ if _, ok = dp.(*RawBytes); ok {
+ continue
+ }
+ clone := make([]byte, len(*b))
+ copy(clone, *b)
+ *b = clone
+ }
+ return nil
+}
+
+// Close closes the Rows, preventing further enumeration. If the
+// end is encountered, the Rows are closed automatically. Close
+// is idempotent.
+func (rs *Rows) Close() error {
+ if rs.closed {
+ return nil
+ }
+ rs.closed = true
+ err := rs.rowsi.Close()
+ rs.releaseConn(err)
+ if rs.closeStmt != nil {
+ rs.closeStmt.Close()
+ }
+ return err
+}
+
+// Row is the result of calling QueryRow to select a single row.
+type Row struct {
+ // One of these two will be non-nil:
+ err error // deferred error for easy chaining
+ rows *Rows
+}
+
+// Scan copies the columns from the matched row into the values
+// pointed at by dest. If more than one row matches the query,
+// Scan uses the first row and discards the rest. If no row matches
+// the query, Scan returns ErrNoRows.
+func (r *Row) Scan(dest ...interface{}) error {
+ if r.err != nil {
+ return r.err
+ }
+
+ // TODO(bradfitz): for now we need to defensively clone all
+ // []byte that the driver returned (not permitting
+ // *RawBytes in Rows.Scan), since we're about to close
+ // the Rows in our defer, when we return from this function.
+ // the contract with the driver.Next(...) interface is that it
+ // can return slices into read-only temporary memory that's
+ // only valid until the next Scan/Close. But the TODO is that
+ // for a lot of drivers, this copy will be unnecessary. We
+ // should provide an optional interface for drivers to
+ // implement to say, "don't worry, the []bytes that I return
+ // from Next will not be modified again." (for instance, if
+ // they were obtained from the network anyway) But for now we
+ // don't care.
+ for _, dp := range dest {
+ if _, ok := dp.(*RawBytes); ok {
+ return errors.New("sql: RawBytes isn't allowed on Row.Scan")
+ }
+ }
+
+ defer r.rows.Close()
+ if !r.rows.Next() {
+ return ErrNoRows
+ }
+ err := r.rows.Scan(dest...)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// A Result summarizes an executed SQL command.
+type Result interface {
+ LastInsertId() (int64, error)
+ RowsAffected() (int64, error)
+}
+
+type result struct {
+ driver.Result
+}
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
new file mode 100644
index 000000000..b29670586
--- /dev/null
+++ b/src/pkg/database/sql/sql_test.go
@@ -0,0 +1,614 @@
+// 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 sql
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+func init() {
+ type dbConn struct {
+ db *DB
+ c driver.Conn
+ }
+ freedFrom := make(map[dbConn]string)
+ putConnHook = func(db *DB, c driver.Conn) {
+ for _, oc := range db.freeConn {
+ if oc == c {
+ // print before panic, as panic may get lost due to conflicting panic
+ // (all goroutines asleep) elsewhere, since we might not unlock
+ // the mutex in freeConn here.
+ println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
+ panic("double free of conn.")
+ }
+ }
+ freedFrom[dbConn{db, c}] = stack()
+ }
+}
+
+const fakeDBName = "foo"
+
+var chrisBirthday = time.Unix(123456789, 0)
+
+func newTestDB(t *testing.T, name string) *DB {
+ db, err := Open("test", fakeDBName)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ if _, err := db.Exec("WIPE"); err != nil {
+ t.Fatalf("exec wipe: %v", err)
+ }
+ if name == "people" {
+ exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime")
+ exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1)
+ exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
+ exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
+ }
+ return db
+}
+
+func exec(t *testing.T, db *DB, query string, args ...interface{}) {
+ _, err := db.Exec(query, args...)
+ if err != nil {
+ t.Fatalf("Exec of %q: %v", query, err)
+ }
+}
+
+func closeDB(t *testing.T, db *DB) {
+ err := db.Close()
+ if err != nil {
+ t.Fatalf("error closing DB: %v", err)
+ }
+}
+
+// numPrepares assumes that db has exactly 1 idle conn and returns
+// its count of calls to Prepare
+func numPrepares(t *testing.T, db *DB) int {
+ if n := len(db.freeConn); n != 1 {
+ t.Fatalf("free conns = %d; want 1", n)
+ }
+ return db.freeConn[0].(*fakeConn).numPrepare
+}
+
+func TestQuery(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ for rows.Next() {
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got = append(got, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want := []row{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ {age: 3, name: "Chris"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ if n := len(db.freeConn); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func TestByteOwnership(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|name,photo|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ name []byte
+ photo RawBytes
+ }
+ got := []row{}
+ for rows.Next() {
+ var r row
+ err = rows.Scan(&r.name, &r.photo)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got = append(got, r)
+ }
+ corruptMemory := []byte("\xffPHOTO")
+ want := []row{
+ {name: []byte("Alice"), photo: corruptMemory},
+ {name: []byte("Bob"), photo: corruptMemory},
+ {name: []byte("Chris"), photo: corruptMemory},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ var photo RawBytes
+ err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
+ if err == nil {
+ t.Error("want error scanning into RawBytes from QueryRow")
+ }
+}
+
+func TestRowsColumns(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ cols, err := rows.Columns()
+ if err != nil {
+ t.Fatalf("Columns: %v", err)
+ }
+ want := []string{"age", "name"}
+ if !reflect.DeepEqual(cols, want) {
+ t.Errorf("got %#v; want %#v", cols, want)
+ }
+}
+
+func TestQueryRow(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ var name string
+ var age int
+ var birthday time.Time
+
+ err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age)
+ if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") {
+ t.Errorf("expected error from wrong number of arguments; actually got: %v", err)
+ }
+
+ err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday)
+ if err != nil || !birthday.Equal(chrisBirthday) {
+ t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday)
+ }
+
+ err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name)
+ if err != nil {
+ t.Fatalf("age QueryRow+Scan: %v", err)
+ }
+ if name != "Bob" {
+ t.Errorf("expected name Bob, got %q", name)
+ }
+ if age != 2 {
+ t.Errorf("expected age 2, got %d", age)
+ }
+
+ err = db.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age, &name)
+ if err != nil {
+ t.Fatalf("name QueryRow+Scan: %v", err)
+ }
+ if name != "Alice" {
+ t.Errorf("expected name Alice, got %q", name)
+ }
+ if age != 1 {
+ t.Errorf("expected age 1, got %d", age)
+ }
+
+ var photo []byte
+ err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo)
+ if err != nil {
+ t.Fatalf("photo QueryRow+Scan: %v", err)
+ }
+ want := []byte("APHOTO")
+ if !reflect.DeepEqual(photo, want) {
+ t.Errorf("photo = %q; want %q", photo, want)
+ }
+}
+
+func TestStatementErrorAfterClose(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ stmt, err := db.Prepare("SELECT|people|age|name=?")
+ if err != nil {
+ t.Fatalf("Prepare: %v", err)
+ }
+ err = stmt.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ var name string
+ err = stmt.QueryRow("foo").Scan(&name)
+ if err == nil {
+ t.Errorf("expected error from QueryRow.Scan after Stmt.Close")
+ }
+}
+
+func TestStatementQueryRow(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ stmt, err := db.Prepare("SELECT|people|age|name=?")
+ if err != nil {
+ t.Fatalf("Prepare: %v", err)
+ }
+ defer stmt.Close()
+ var age int
+ for n, tt := range []struct {
+ name string
+ want int
+ }{
+ {"Alice", 1},
+ {"Bob", 2},
+ {"Chris", 3},
+ } {
+ if err := stmt.QueryRow(tt.name).Scan(&age); err != nil {
+ t.Errorf("%d: on %q, QueryRow/Scan: %v", n, tt.name, err)
+ } else if age != tt.want {
+ t.Errorf("%d: age=%d, want %d", n, age, tt.want)
+ }
+ }
+
+}
+
+// just a test of fakedb itself
+func TestBogusPreboundParameters(t *testing.T) {
+ db := newTestDB(t, "foo")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ _, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion")
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ if err.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` {
+ t.Errorf("unexpected error: %v", err)
+ }
+}
+
+func TestExec(t *testing.T) {
+ db := newTestDB(t, "foo")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+ if err != nil {
+ t.Errorf("Stmt, err = %v, %v", stmt, err)
+ }
+ defer stmt.Close()
+
+ type execTest struct {
+ args []interface{}
+ wantErr string
+ }
+ execTests := []execTest{
+ // Okay:
+ {[]interface{}{"Brad", 31}, ""},
+ {[]interface{}{"Brad", int64(31)}, ""},
+ {[]interface{}{"Bob", "32"}, ""},
+ {[]interface{}{7, 9}, ""},
+
+ // Invalid conversions:
+ {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
+ {[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+
+ // Wrong number of args:
+ {[]interface{}{}, "sql: expected 2 arguments, got 0"},
+ {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
+ }
+ for n, et := range execTests {
+ _, err := stmt.Exec(et.args...)
+ errStr := ""
+ if err != nil {
+ errStr = err.Error()
+ }
+ if errStr != et.wantErr {
+ t.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q",
+ n, et.args, errStr, et.wantErr)
+ }
+ }
+}
+
+func TestTxStmt(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
+ if err != nil {
+ t.Fatalf("Stmt, err = %v, %v", stmt, err)
+ }
+ defer stmt.Close()
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatalf("Begin = %v", err)
+ }
+ txs := tx.Stmt(stmt)
+ defer txs.Close()
+ _, err = txs.Exec("Bobby", 7)
+ if err != nil {
+ t.Fatalf("Exec = %v", err)
+ }
+ err = tx.Commit()
+ if err != nil {
+ t.Fatalf("Commit = %v", err)
+ }
+}
+
+// Issue: http://golang.org/issue/2784
+// This test didn't fail before because we got luckly with the fakedb driver.
+// It was failing, and now not, in github.com/bradfitz/go-sql-test
+func TestTxQuery(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+ exec(t, db, "INSERT|t1|name=Alice")
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ r, err := tx.Query("SELECT|t1|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+
+ if !r.Next() {
+ if r.Err() != nil {
+ t.Fatal(r.Err())
+ }
+ t.Fatal("expected one row")
+ }
+
+ var x string
+ err = r.Scan(&x)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestTxQueryInvalid(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ _, err = tx.Query("SELECT|t1|name|")
+ if err == nil {
+ t.Fatal("Error expected")
+ }
+}
+
+// Tests fix for issue 2542, that we release a lock when querying on
+// a closed connection.
+func TestIssue2542Deadlock(t *testing.T) {
+ db := newTestDB(t, "people")
+ closeDB(t, db)
+ for i := 0; i < 2; i++ {
+ _, err := db.Query("SELECT|people|age,name|")
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ }
+}
+
+// Tests fix for issue 2788, that we bind nil to a []byte if the
+// value in the column is sql null
+func TestNullByteSlice(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t|id=int32,name=nullstring")
+ exec(t, db, "INSERT|t|id=10,name=?", nil)
+
+ var name []byte
+
+ err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if name != nil {
+ t.Fatalf("name []byte should be nil for null column value, got: %#v", name)
+ }
+
+ exec(t, db, "INSERT|t|id=11,name=?", "bob")
+ err = db.QueryRow("SELECT|t|name|id=?", 11).Scan(&name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(name) != "bob" {
+ t.Fatalf("name []byte should be bob, got: %q", string(name))
+ }
+}
+
+func TestPointerParamsAndScans(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, "CREATE|t|id=int32,name=nullstring")
+
+ bob := "bob"
+ var name *string
+
+ name = &bob
+ exec(t, db, "INSERT|t|id=10,name=?", name)
+ name = nil
+ exec(t, db, "INSERT|t|id=20,name=?", name)
+
+ err := db.QueryRow("SELECT|t|name|id=?", 10).Scan(&name)
+ if err != nil {
+ t.Fatalf("querying id 10: %v", err)
+ }
+ if name == nil {
+ t.Errorf("id 10's name = nil; want bob")
+ } else if *name != "bob" {
+ t.Errorf("id 10's name = %q; want bob", *name)
+ }
+
+ err = db.QueryRow("SELECT|t|name|id=?", 20).Scan(&name)
+ if err != nil {
+ t.Fatalf("querying id 20: %v", err)
+ }
+ if name != nil {
+ t.Errorf("id 20 = %q; want nil", *name)
+ }
+}
+
+func TestQueryRowClosingStmt(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ var name string
+ var age int
+ err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(db.freeConn) != 1 {
+ t.Fatalf("expected 1 free conn")
+ }
+ fakeConn := db.freeConn[0].(*fakeConn)
+ if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
+ t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
+ }
+}
+
+type nullTestRow struct {
+ nullParam interface{}
+ notNullParam interface{}
+ scanNullVal interface{}
+}
+
+type nullTestSpec struct {
+ nullType string
+ notNullType string
+ rows [6]nullTestRow
+}
+
+func TestNullStringParam(t *testing.T) {
+ spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
+ {NullString{"aqua", true}, "", NullString{"aqua", true}},
+ {NullString{"brown", false}, "", NullString{"", false}},
+ {"chartreuse", "", NullString{"chartreuse", true}},
+ {NullString{"darkred", true}, "", NullString{"darkred", true}},
+ {NullString{"eel", false}, "", NullString{"", false}},
+ {"foo", NullString{"black", false}, nil},
+ }}
+ nullTestRun(t, spec)
+}
+
+func TestNullInt64Param(t *testing.T) {
+ spec := nullTestSpec{"nullint64", "int64", [6]nullTestRow{
+ {NullInt64{31, true}, 1, NullInt64{31, true}},
+ {NullInt64{-22, false}, 1, NullInt64{0, false}},
+ {22, 1, NullInt64{22, true}},
+ {NullInt64{33, true}, 1, NullInt64{33, true}},
+ {NullInt64{222, false}, 1, NullInt64{0, false}},
+ {0, NullInt64{31, false}, nil},
+ }}
+ nullTestRun(t, spec)
+}
+
+func TestNullFloat64Param(t *testing.T) {
+ spec := nullTestSpec{"nullfloat64", "float64", [6]nullTestRow{
+ {NullFloat64{31.2, true}, 1, NullFloat64{31.2, true}},
+ {NullFloat64{13.1, false}, 1, NullFloat64{0, false}},
+ {-22.9, 1, NullFloat64{-22.9, true}},
+ {NullFloat64{33.81, true}, 1, NullFloat64{33.81, true}},
+ {NullFloat64{222, false}, 1, NullFloat64{0, false}},
+ {10, NullFloat64{31.2, false}, nil},
+ }}
+ nullTestRun(t, spec)
+}
+
+func TestNullBoolParam(t *testing.T) {
+ spec := nullTestSpec{"nullbool", "bool", [6]nullTestRow{
+ {NullBool{false, true}, true, NullBool{false, true}},
+ {NullBool{true, false}, false, NullBool{false, false}},
+ {true, true, NullBool{true, true}},
+ {NullBool{true, true}, false, NullBool{true, true}},
+ {NullBool{true, false}, true, NullBool{false, false}},
+ {true, NullBool{true, false}, nil},
+ }}
+ nullTestRun(t, spec)
+}
+
+func nullTestRun(t *testing.T, spec nullTestSpec) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+ exec(t, db, fmt.Sprintf("CREATE|t|id=int32,name=string,nullf=%s,notnullf=%s", spec.nullType, spec.notNullType))
+
+ // Inserts with db.Exec:
+ exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 1, "alice", spec.rows[0].nullParam, spec.rows[0].notNullParam)
+ exec(t, db, "INSERT|t|id=?,name=?,nullf=?,notnullf=?", 2, "bob", spec.rows[1].nullParam, spec.rows[1].notNullParam)
+
+ // Inserts with a prepared statement:
+ stmt, err := db.Prepare("INSERT|t|id=?,name=?,nullf=?,notnullf=?")
+ if err != nil {
+ t.Fatalf("prepare: %v", err)
+ }
+ defer stmt.Close()
+ if _, err := stmt.Exec(3, "chris", spec.rows[2].nullParam, spec.rows[2].notNullParam); err != nil {
+ t.Errorf("exec insert chris: %v", err)
+ }
+ if _, err := stmt.Exec(4, "dave", spec.rows[3].nullParam, spec.rows[3].notNullParam); err != nil {
+ t.Errorf("exec insert dave: %v", err)
+ }
+ if _, err := stmt.Exec(5, "eleanor", spec.rows[4].nullParam, spec.rows[4].notNullParam); err != nil {
+ t.Errorf("exec insert eleanor: %v", err)
+ }
+
+ // Can't put null val into non-null col
+ if _, err := stmt.Exec(6, "bob", spec.rows[5].nullParam, spec.rows[5].notNullParam); err == nil {
+ t.Errorf("expected error inserting nil val with prepared statement Exec")
+ }
+
+ _, err = db.Exec("INSERT|t|id=?,name=?,nullf=?", 999, nil, nil)
+ if err == nil {
+ // TODO: this test fails, but it's just because
+ // fakeConn implements the optional Execer interface,
+ // so arguably this is the correct behavior. But
+ // maybe I should flesh out the fakeConn.Exec
+ // implementation so this properly fails.
+ // t.Errorf("expected error inserting nil name with Exec")
+ }
+
+ paramtype := reflect.TypeOf(spec.rows[0].nullParam)
+ bindVal := reflect.New(paramtype).Interface()
+
+ for i := 0; i < 5; i++ {
+ id := i + 1
+ if err := db.QueryRow("SELECT|t|nullf|id=?", id).Scan(bindVal); err != nil {
+ t.Errorf("id=%d Scan: %v", id, err)
+ }
+ bindValDeref := reflect.ValueOf(bindVal).Elem().Interface()
+ if !reflect.DeepEqual(bindValDeref, spec.rows[i].scanNullVal) {
+ t.Errorf("id=%d got %#v, want %#v", id, bindValDeref, spec.rows[i].scanNullVal)
+ }
+ }
+}
+
+func stack() string {
+ buf := make([]byte, 1024)
+ return string(buf[:runtime.Stack(buf, false)])
+}
diff --git a/src/pkg/debug/dwarf/Makefile b/src/pkg/debug/dwarf/Makefile
deleted file mode 100644
index c4203188e..000000000
--- a/src/pkg/debug/dwarf/Makefile
+++ /dev/null
@@ -1,16 +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.
-
-include ../../../Make.inc
-
-TARG=debug/dwarf
-GOFILES=\
- buf.go\
- const.go\
- entry.go\
- open.go\
- type.go\
- unit.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/debug/dwarf/buf.go b/src/pkg/debug/dwarf/buf.go
index 2d29cebdd..6dc28d256 100644
--- a/src/pkg/debug/dwarf/buf.go
+++ b/src/pkg/debug/dwarf/buf.go
@@ -8,7 +8,6 @@ package dwarf
import (
"encoding/binary"
- "os"
"strconv"
)
@@ -20,7 +19,7 @@ type buf struct {
off Offset
data []byte
addrsize int
- err os.Error
+ err error
}
func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
@@ -146,9 +145,9 @@ func (b *buf) error(s string) {
type DecodeError struct {
Name string
Offset Offset
- Error string
+ Err string
}
-func (e DecodeError) String() string {
- return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.Itob64(int64(e.Offset), 16) + ": " + e.Error
+func (e DecodeError) Error() string {
+ return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err
}
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
index 1a3fec155..918b153d0 100644
--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/debug/dwarf/const.go
@@ -178,7 +178,7 @@ func (a Attr) GoString() string {
return "dwarf.Attr" + s
}
}
- return "dwarf.Attr(" + strconv.Itoa64(int64(a)) + ")"
+ return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")"
}
// A format is a DWARF data encoding format.
@@ -347,7 +347,7 @@ func (t Tag) GoString() string {
return "dwarf.Tag" + s
}
}
- return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")"
+ return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")"
}
// Location expression operators.
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index 549e5c2cc..2885d8fa2 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -10,7 +10,7 @@
package dwarf
-import "os"
+import "errors"
// a single entry's description: a sequence of attributes
type abbrev struct {
@@ -29,7 +29,7 @@ type abbrevTable map[uint32]abbrev
// ParseAbbrev returns the abbreviation table that starts at byte off
// in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32) (abbrevTable, os.Error) {
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
if m, ok := d.abbrevCache[off]; ok {
return m, nil
}
@@ -232,7 +232,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
type Reader struct {
b buf
d *Data
- err os.Error
+ err error
unit int
lastChildren bool // .Children of last entry returned by Next
lastSibling Offset // .Val(AttrSibling) of last entry returned by Next
@@ -273,7 +273,7 @@ func (r *Reader) Seek(off Offset) {
return
}
}
- r.err = os.NewError("offset out of range")
+ r.err = errors.New("offset out of range")
}
// maybeNextUnit advances to the next unit if this one is finished.
@@ -289,7 +289,7 @@ func (r *Reader) maybeNextUnit() {
// It returns nil, nil when it reaches the end of the section.
// It returns an error if the current offset is invalid or the data at the
// offset cannot be decoded as a valid Entry.
-func (r *Reader) Next() (*Entry, os.Error) {
+func (r *Reader) Next() (*Entry, error) {
if r.err != nil {
return nil, r.err
}
diff --git a/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
index d9525f788..37a518b6d 100644
--- a/src/pkg/debug/dwarf/open.go
+++ b/src/pkg/debug/dwarf/open.go
@@ -7,10 +7,7 @@
// http://dwarfstd.org/doc/dwarf-2.0.0.pdf
package dwarf
-import (
- "encoding/binary"
- "os"
-)
+import "encoding/binary"
// Data represents the DWARF debugging information
// loaded from an executable file (for example, an ELF or Mach-O executable).
@@ -34,13 +31,14 @@ type Data struct {
}
// New returns a new Data object initialized from the given parameters.
-// Clients should typically use [TODO(rsc): method to be named later] instead of calling
-// New directly.
+// Rather than calling this function directly, clients should typically use
+// the DWARF method of the File type of the appropriate package debug/elf,
+// debug/macho, or debug/pe.
//
// The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of
// the ".debug_abbrev" section.
-func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, os.Error) {
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
d := &Data{
abbrev: abbrev,
aranges: aranges,
diff --git a/src/pkg/debug/dwarf/testdata/typedef.c b/src/pkg/debug/dwarf/testdata/typedef.c
index 664d021ce..f05f01564 100644
--- a/src/pkg/debug/dwarf/testdata/typedef.c
+++ b/src/pkg/debug/dwarf/testdata/typedef.c
@@ -28,8 +28,13 @@ typedef struct my_struct {
volatile int vi;
char x : 1;
int y : 4;
+ int z[0];
long long array[40];
+ int zz[0];
} t_my_struct;
+typedef struct my_struct1 {
+ int zz [1];
+} t_my_struct1;
typedef union my_union {
volatile int vi;
char x : 1;
@@ -65,7 +70,8 @@ t_func_void_of_char *a9;
t_func_void_of_void *a10;
t_func_void_of_ptr_char_dots *a11;
t_my_struct *a12;
-t_my_union *a12a;
+t_my_struct1 *a12a;
+t_my_union *a12b;
t_my_enum *a13;
t_my_list *a14;
t_my_tree *a15;
diff --git a/src/pkg/debug/dwarf/testdata/typedef.elf b/src/pkg/debug/dwarf/testdata/typedef.elf
index 44df8da9b..b2062d2c4 100755
--- a/src/pkg/debug/dwarf/testdata/typedef.elf
+++ b/src/pkg/debug/dwarf/testdata/typedef.elf
Binary files differ
diff --git a/src/pkg/debug/dwarf/testdata/typedef.macho b/src/pkg/debug/dwarf/testdata/typedef.macho
index 41019c1e1..f75afcccb 100644
--- a/src/pkg/debug/dwarf/testdata/typedef.macho
+++ b/src/pkg/debug/dwarf/testdata/typedef.macho
Binary files differ
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index f35365ebe..450235502 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -8,10 +8,7 @@
package dwarf
-import (
- "os"
- "strconv"
-)
+import "strconv"
// A Type conventionally represents a pointer to any of the
// specific Type structures (CharType, StructType, etc.).
@@ -113,7 +110,7 @@ type ArrayType struct {
}
func (t *ArrayType) String() string {
- return "[" + strconv.Itoa64(t.Count) + "]" + t.Type.String()
+ return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String()
}
func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() }
@@ -174,10 +171,10 @@ func (t *StructType) Defn() string {
s += "; "
}
s += f.Name + " " + f.Type.String()
- s += "@" + strconv.Itoa64(f.ByteOffset)
+ s += "@" + strconv.FormatInt(f.ByteOffset, 10)
if f.BitSize > 0 {
- s += " : " + strconv.Itoa64(f.BitSize)
- s += "@" + strconv.Itoa64(f.BitOffset)
+ s += " : " + strconv.FormatInt(f.BitSize, 10)
+ s += "@" + strconv.FormatInt(f.BitOffset, 10)
}
}
s += "}"
@@ -209,7 +206,7 @@ func (t *EnumType) String() string {
if i > 0 {
s += "; "
}
- s += v.Name + "=" + strconv.Itoa64(v.Val)
+ s += v.Name + "=" + strconv.FormatInt(v.Val, 10)
}
s += "}"
return s
@@ -254,7 +251,7 @@ func (t *TypedefType) String() string { return t.Name }
func (t *TypedefType) Size() int64 { return t.Type.Size() }
-func (d *Data) Type(off Offset) (Type, os.Error) {
+func (d *Data) Type(off Offset) (Type, error) {
if t, ok := d.typeCache[off]; ok {
return t, nil
}
@@ -429,6 +426,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
t.StructName, _ = e.Val(AttrName).(string)
t.Incomplete = e.Val(AttrDeclaration) != nil
t.Field = make([]*StructField, 0, 8)
+ var lastFieldType Type
+ var lastFieldBitOffset int64
for kid := next(); kid != nil; kid = next() {
if kid.Tag == TagMember {
f := new(StructField)
@@ -447,11 +446,32 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
goto Error
}
}
+
+ haveBitOffset := false
f.Name, _ = kid.Val(AttrName).(string)
f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
- f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
+ f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64)
f.BitSize, _ = kid.Val(AttrBitSize).(int64)
t.Field = append(t.Field, f)
+
+ bito := f.BitOffset
+ if !haveBitOffset {
+ bito = f.ByteOffset * 8
+ }
+ if bito == lastFieldBitOffset && t.Kind != "union" {
+ // Last field was zero width. Fix array length.
+ // (DWARF writes out 0-length arrays as if they were 1-length arrays.)
+ zeroArray(lastFieldType)
+ }
+ lastFieldType = f.Type
+ lastFieldBitOffset = bito
+ }
+ }
+ if t.Kind != "union" {
+ b, ok := e.Val(AttrByteSize).(int64)
+ if ok && b*8 == lastFieldBitOffset {
+ // Final field must be zero width. Fix array length.
+ zeroArray(lastFieldType)
}
}
@@ -579,6 +599,17 @@ Error:
// If the parse fails, take the type out of the cache
// so that the next call with this offset doesn't hit
// the cache and return success.
- d.typeCache[off] = nil, false
+ delete(d.typeCache, off)
return nil, err
}
+
+func zeroArray(t Type) {
+ for {
+ at, ok := t.(*ArrayType)
+ if !ok {
+ break
+ }
+ at.Count = 0
+ t = at.Type
+ }
+}
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
index b9470a4fc..b5b255f6f 100644
--- a/src/pkg/debug/dwarf/type_test.go
+++ b/src/pkg/debug/dwarf/type_test.go
@@ -25,13 +25,22 @@ var typedefTests = map[string]string{
"t_func_void_of_char": "func(char) void",
"t_func_void_of_void": "func() void",
"t_func_void_of_ptr_char_dots": "func(*char, ...) void",
- "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
+ "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}",
+ "t_my_struct1": "struct my_struct1 {zz [1]int@0}",
"t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
"t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
"t_my_list": "struct list {val short int@0; next *t_my_list@8}",
"t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}",
}
+// As Apple converts gcc to a clang-based front end
+// they keep breaking the DWARF output. This map lists the
+// conversion from real answer to Apple answer.
+var machoBug = map[string]string{
+ "func(*char, ...) void": "func(*char) void",
+ "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}": "enum my_enum {e1=1; e2=2; e3=-5; e4=-1530494976}",
+}
+
func elfData(t *testing.T, name string) *Data {
f, err := elf.Open(name)
if err != nil {
@@ -58,13 +67,13 @@ func machoData(t *testing.T, name string) *Data {
return d
}
-func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
+func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") }
func TestTypedefsMachO(t *testing.T) {
- testTypedefs(t, machoData(t, "testdata/typedef.macho"))
+ testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
}
-func testTypedefs(t *testing.T, d *Data) {
+func testTypedefs(t *testing.T, d *Data, kind string) {
r := d.Reader()
seen := make(map[string]bool)
for {
@@ -93,7 +102,7 @@ func testTypedefs(t *testing.T, d *Data) {
t.Errorf("multiple definitions for %s", t1.Name)
}
seen[t1.Name] = true
- if typstr != want {
+ if typstr != want && (kind != "macho" || typstr != machoBug[want]) {
t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want)
}
}
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
index 02cb363b4..c10d75dbd 100644
--- a/src/pkg/debug/dwarf/unit.go
+++ b/src/pkg/debug/dwarf/unit.go
@@ -4,10 +4,7 @@
package dwarf
-import (
- "os"
- "strconv"
-)
+import "strconv"
// DWARF debug info is split into a sequence of compilation units.
// Each unit has its own abbreviation table and address size.
@@ -20,7 +17,7 @@ type unit struct {
addrsize int
}
-func (d *Data) parseUnits() ([]unit, os.Error) {
+func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
b := makeBuf(d, "info", 0, d.info, 0)
diff --git a/src/pkg/debug/elf/Makefile b/src/pkg/debug/elf/Makefile
deleted file mode 100644
index dd431f653..000000000
--- a/src/pkg/debug/elf/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=debug/elf
-GOFILES=\
- elf.go\
- file.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index c71b230bd..03e42b034 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -1490,11 +1490,11 @@ func stringName(i uint32, names []intName, goSyntax bool) string {
if goSyntax {
s = "elf." + s
}
- return s + "+" + strconv.Uitoa64(uint64(i-n.i))
+ return s + "+" + strconv.FormatUint(uint64(i-n.i), 10)
}
}
- return strconv.Uitoa64(uint64(i))
+ return strconv.FormatUint(uint64(i), 10)
}
func flagName(i uint32, names []intName, goSyntax bool) string {
@@ -1512,10 +1512,10 @@ func flagName(i uint32, names []intName, goSyntax bool) string {
}
}
if len(s) == 0 {
- return "0x" + strconv.Uitob64(uint64(i), 16)
+ return "0x" + strconv.FormatUint(uint64(i), 16)
}
if i != 0 {
- s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ s += "+0x" + strconv.FormatUint(uint64(i), 16)
}
return s
}
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index a0ddb1fc7..184ca8375 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -9,6 +9,7 @@ import (
"bytes"
"debug/dwarf"
"encoding/binary"
+ "errors"
"fmt"
"io"
"os"
@@ -71,7 +72,7 @@ type Section struct {
}
// Data reads and returns the contents of the ELF section.
-func (s *Section) Data() ([]byte, os.Error) {
+func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
return dat[0:n], err
@@ -79,9 +80,9 @@ func (s *Section) Data() ([]byte, os.Error) {
// stringTable reads and returns the string table given by the
// specified link value.
-func (f *File) stringTable(link uint32) ([]byte, os.Error) {
+func (f *File) stringTable(link uint32) ([]byte, error) {
if link <= 0 || link >= uint32(len(f.Sections)) {
- return nil, os.NewError("section has invalid string table link")
+ return nil, errors.New("section has invalid string table link")
}
return f.Sections[link].Data()
}
@@ -136,7 +137,7 @@ type FormatError struct {
val interface{}
}
-func (e *FormatError) String() string {
+func (e *FormatError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v' ", e.val)
@@ -146,7 +147,7 @@ func (e *FormatError) String() string {
}
// Open opens the named file using os.Open and prepares it for use as an ELF binary.
-func Open(name string) (*File, os.Error) {
+func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
@@ -163,8 +164,8 @@ func Open(name string) (*File, os.Error) {
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
-func (f *File) Close() os.Error {
- var err os.Error
+func (f *File) Close() error {
+ var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
@@ -185,7 +186,7 @@ func (f *File) SectionByType(typ SectionType) *Section {
// NewFile creates a new File for accessing an ELF binary in an underlying reader.
// The ELF binary is expected to start at position 0 in the ReaderAt.
-func NewFile(r io.ReaderAt) (*File, os.Error) {
+func NewFile(r io.ReaderAt) (*File, error) {
sr := io.NewSectionReader(r, 0, 1<<63-1)
// Read and decode ELF identifier
var ident [16]uint8
@@ -381,7 +382,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
// getSymbols returns a slice of Symbols from parsing the symbol table
// with the given type, along with the associated string table.
-func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
+func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
switch f.Class {
case ELFCLASS64:
return f.getSymbols64(typ)
@@ -390,27 +391,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
return f.getSymbols32(typ)
}
- return nil, nil, os.NewError("not implemented")
+ return nil, nil, errors.New("not implemented")
}
-func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
+func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.NewError("no symbol section")
+ return nil, nil, errors.New("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.NewError("cannot load symbol section")
+ return nil, nil, errors.New("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym32Size != 0 {
- return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
+ return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.NewError("cannot load string table section")
+ return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
@@ -436,24 +437,24 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
return symbols, strdata, nil
}
-func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
+func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.NewError("no symbol section")
+ return nil, nil, errors.New("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.NewError("cannot load symbol section")
+ return nil, nil, errors.New("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym64Size != 0 {
- return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
+ return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.NewError("cannot load string table section")
+ return nil, nil, errors.New("cannot load string table section")
}
// The first entry is all zeros.
@@ -506,17 +507,17 @@ func (f *File) Section(name string) *Section {
// applyRelocations applies relocations to dst. rels is a relocations section
// in RELA format.
-func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
+func (f *File) applyRelocations(dst []byte, rels []byte) error {
if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
return f.applyRelocationsAMD64(dst, rels)
}
- return os.NewError("not implemented")
+ return errors.New("not implemented")
}
-func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
+func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
if len(rels)%Sym64Size != 0 {
- return os.NewError("length of relocation section is not a multiple of Sym64Size")
+ return errors.New("length of relocation section is not a multiple of Sym64Size")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -558,7 +559,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
return nil
}
-func (f *File) DWARF() (*dwarf.Data, os.Error) {
+func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them.
@@ -596,7 +597,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
}
// Symbols returns the symbol table for f.
-func (f *File) Symbols() ([]Symbol, os.Error) {
+func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
}
@@ -611,7 +612,7 @@ type ImportedSymbol struct {
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
-func (f *File) ImportedSymbols() ([]ImportedSymbol, os.Error) {
+func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
sym, str, err := f.getSymbols(SHT_DYNSYM)
if err != nil {
return nil, err
@@ -721,7 +722,7 @@ func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
-func (f *File) ImportedLibraries() ([]string, os.Error) {
+func (f *File) ImportedLibraries() ([]string, error) {
ds := f.SectionByType(SHT_DYNAMIC)
if ds == nil {
// not dynamic, so no libraries
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 451d3d514..98f2723c8 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -227,6 +227,9 @@ func TestNoSectionOverlaps(t *testing.T) {
}
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 {
diff --git a/src/pkg/debug/gosym/Makefile b/src/pkg/debug/gosym/Makefile
deleted file mode 100644
index 4f420e729..000000000
--- a/src/pkg/debug/gosym/Makefile
+++ /dev/null
@@ -1,19 +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.
-
-include ../../../Make.inc
-
-TARG=debug/gosym
-GOFILES=\
- pclntab.go\
- symtab.go\
-
-include ../../../Make.pkg
-
-test: make-pclinetest
-
-testshort: make-pclinetest
-
-make-pclinetest:
- @if [ "`uname`-`uname -m`" = Linux-x86_64 -a $(GOARCH) = amd64 ]; then mkdir -p _test && $(AS) pclinetest.s && $(LD) -E main -o _test/pclinetest pclinetest.$O; fi
diff --git a/src/pkg/debug/gosym/pclinetest.s b/src/pkg/debug/gosym/pclinetest.asm
index 6305435b0..6305435b0 100644
--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.asm
diff --git a/src/pkg/debug/gosym/pclinetest.h b/src/pkg/debug/gosym/pclinetest.h
index a6c40e76c..156c0b87b 100644
--- a/src/pkg/debug/gosym/pclinetest.h
+++ b/src/pkg/debug/gosym/pclinetest.h
@@ -1,3 +1,5 @@
+// +build ignore
+
// Empty include file to generate z symbols
diff --git a/src/pkg/debug/gosym/pclntab_test.go b/src/pkg/debug/gosym/pclntab_test.go
index c83e64eab..b2400bb3b 100644
--- a/src/pkg/debug/gosym/pclntab_test.go
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -6,14 +6,37 @@ package gosym
import (
"debug/elf"
+ "fmt"
"os"
+ "os/exec"
+ "runtime"
+ "strings"
"testing"
- "syscall"
)
+var pclinetestBinary string
+
func dotest() bool {
// For now, only works on ELF platforms.
- return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ return false
+ }
+ if pclinetestBinary != "" {
+ return true
+ }
+ // This command builds pclinetest from pclinetest.asm;
+ // the resulting binary looks like it was built from pclinetest.s,
+ // but we have renamed it to keep it away from the go tool.
+ pclinetestBinary = os.TempDir() + "/pclinetest"
+ command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -E main -o %s %s.6",
+ pclinetestBinary, pclinetestBinary, pclinetestBinary)
+ cmd := exec.Command("sh", "-c", command)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ panic(err)
+ }
+ return true
}
func getTable(t *testing.T) *Table {
@@ -148,7 +171,7 @@ func TestPCLine(t *testing.T) {
return
}
- f, tab := crack("_test/pclinetest", t)
+ f, tab := crack(pclinetestBinary, t)
text := f.Section(".text")
textdat, err := text.Data()
if err != nil {
@@ -162,10 +185,13 @@ func TestPCLine(t *testing.T) {
file, line, fn := tab.PCToLine(pc)
off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
wantLine += int(textdat[off])
+ t.Logf("off is %d", off)
if fn == nil {
t.Errorf("failed to get line of PC %#x", pc)
- } else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
- t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+ } else if !strings.HasSuffix(file, "pclinetest.asm") {
+ t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.asm", sym.Name, pc, file, fn.Name)
+ } else if line != wantLine || fn != sym {
+ t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
}
}
diff --git a/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
index dea460d71..52d7d55a3 100644
--- a/src/pkg/debug/gosym/symtab.go
+++ b/src/pkg/debug/gosym/symtab.go
@@ -15,7 +15,6 @@ package gosym
import (
"encoding/binary"
"fmt"
- "os"
"strconv"
"strings"
)
@@ -105,7 +104,7 @@ type sym struct {
name []byte
}
-func walksymtab(data []byte, fn func(sym) os.Error) os.Error {
+func walksymtab(data []byte, fn func(sym) error) error {
var s sym
p := data
for len(p) >= 6 {
@@ -149,9 +148,9 @@ func walksymtab(data []byte, fn func(sym) os.Error) os.Error {
// NewTable decodes the Go symbol table in data,
// returning an in-memory representation.
-func NewTable(symtab []byte, pcln *LineTable) (*Table, os.Error) {
+func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
var n int
- err := walksymtab(symtab, func(s sym) os.Error {
+ err := walksymtab(symtab, func(s sym) error {
n++
return nil
})
@@ -165,7 +164,7 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, os.Error) {
nf := 0
nz := 0
lasttyp := uint8(0)
- err = walksymtab(symtab, func(s sym) os.Error {
+ err = walksymtab(symtab, func(s sym) error {
n := len(t.Syms)
t.Syms = t.Syms[0 : n+1]
ts := &t.Syms[n]
@@ -355,7 +354,7 @@ func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
// LineToPC looks up the first program counter on the given line in
// the named file. Returns UnknownPathError or UnknownLineError if
// there is an error looking up this line.
-func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err os.Error) {
+func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
obj, ok := t.Files[file]
if !ok {
return 0, nil, UnknownFileError(file)
@@ -466,7 +465,7 @@ pathloop:
return tos.path, aline - tos.start - tos.offset + 1
}
-func (o *Obj) alineFromLine(path string, line int) (int, os.Error) {
+func (o *Obj) alineFromLine(path string, line int) (int, error) {
if line < 1 {
return 0, &UnknownLineError{path, line}
}
@@ -516,7 +515,7 @@ func (o *Obj) alineFromLine(path string, line int) (int, os.Error) {
// the symbol table.
type UnknownFileError string
-func (e UnknownFileError) String() string { return "unknown file: " + string(e) }
+func (e UnknownFileError) Error() string { return "unknown file: " + string(e) }
// UnknownLineError represents a failure to map a line to a program
// counter, either because the line is beyond the bounds of the file
@@ -526,7 +525,7 @@ type UnknownLineError struct {
Line int
}
-func (e *UnknownLineError) String() string {
+func (e *UnknownLineError) Error() string {
return "no code at " + e.File + ":" + strconv.Itoa(e.Line)
}
@@ -538,7 +537,7 @@ type DecodingError struct {
val interface{}
}
-func (e *DecodingError) String() string {
+func (e *DecodingError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v'", e.val)
diff --git a/src/pkg/debug/macho/Makefile b/src/pkg/debug/macho/Makefile
deleted file mode 100644
index 5fbbf1efe..000000000
--- a/src/pkg/debug/macho/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=debug/macho
-GOFILES=\
- macho.go\
- file.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index 721a4c416..fa73a315c 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/debug/macho/file.go
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package macho implements access to Mach-O object files, as defined by
-// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html.
+// Package macho implements access to Mach-O object files.
package macho
// High level access to low level data structures.
@@ -12,6 +11,7 @@ import (
"bytes"
"debug/dwarf"
"encoding/binary"
+ "errors"
"fmt"
"io"
"os"
@@ -71,7 +71,7 @@ type Segment struct {
}
// Data reads and returns the contents of the segment.
-func (s *Segment) Data() ([]byte, os.Error) {
+func (s *Segment) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
return dat[0:n], err
@@ -106,7 +106,7 @@ type Section struct {
}
// Data reads and returns the contents of the Mach-O section.
-func (s *Section) Data() ([]byte, os.Error) {
+func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
return dat[0:n], err
@@ -148,7 +148,7 @@ type FormatError struct {
val interface{}
}
-func (e *FormatError) String() string {
+func (e *FormatError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v'", e.val)
@@ -158,7 +158,7 @@ func (e *FormatError) String() string {
}
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
-func Open(name string) (*File, os.Error) {
+func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
@@ -175,8 +175,8 @@ func Open(name string) (*File, os.Error) {
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
-func (f *File) Close() os.Error {
- var err os.Error
+func (f *File) Close() error {
+ var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
@@ -186,7 +186,7 @@ func (f *File) Close() os.Error {
// 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) {
+func NewFile(r io.ReaderAt) (*File, error) {
f := new(File)
sr := io.NewSectionReader(r, 0, 1<<63-1)
@@ -391,7 +391,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return f, nil
}
-func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, os.Error) {
+func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
bo := f.ByteOrder
symtab := make([]Symbol, hdr.Nsyms)
b := bytes.NewBuffer(symdat)
@@ -463,7 +463,7 @@ func (f *File) Section(name string) *Section {
}
// DWARF returns the DWARF debug information for the Mach-O file.
-func (f *File) DWARF() (*dwarf.Data, os.Error) {
+func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them.
@@ -473,7 +473,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
name = "__debug_" + name
s := f.Section(name)
if s == nil {
- return nil, os.NewError("missing Mach-O section " + name)
+ return nil, errors.New("missing Mach-O section " + name)
}
b, err := s.Data()
if err != nil && uint64(len(b)) < s.Size {
@@ -489,7 +489,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
// ImportedSymbols returns the names of all symbols
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
-func (f *File) ImportedSymbols() ([]string, os.Error) {
+func (f *File) ImportedSymbols() ([]string, error) {
if f.Dysymtab == nil || f.Symtab == nil {
return nil, &FormatError{0, "missing symbol table", nil}
}
@@ -506,7 +506,7 @@ func (f *File) ImportedSymbols() ([]string, os.Error) {
// ImportedLibraries returns the paths of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
-func (f *File) ImportedLibraries() ([]string, os.Error) {
+func (f *File) ImportedLibraries() ([]string, error) {
var all []string
for _, l := range f.Loads {
if lib, ok := l.(*Dylib); ok {
diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
index 56d8a20be..640225b32 100644
--- a/src/pkg/debug/macho/file_test.go
+++ b/src/pkg/debug/macho/file_test.go
@@ -21,11 +21,11 @@ var fileTests = []fileTest{
"testdata/gcc-386-darwin-exec",
FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
[]*SegmentHeader{
- &SegmentHeader{LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- &SegmentHeader{LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
- &SegmentHeader{LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
- &SegmentHeader{LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
- &SegmentHeader{LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
+ {LoadCmdSegment, 0x38, "__PAGEZERO", 0x0, 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {LoadCmdSegment, 0xc0, "__TEXT", 0x1000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x2, 0x0},
+ {LoadCmdSegment, 0xc0, "__DATA", 0x2000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x2, 0x0},
+ {LoadCmdSegment, 0x7c, "__IMPORT", 0x3000, 0x1000, 0x2000, 0x1000, 0x7, 0x7, 0x1, 0x0},
+ {LoadCmdSegment, 0x38, "__LINKEDIT", 0x4000, 0x1000, 0x3000, 0x12c, 0x7, 0x1, 0x0, 0x0},
nil,
nil,
nil,
@@ -35,21 +35,21 @@ var fileTests = []fileTest{
nil,
},
[]*SectionHeader{
- &SectionHeader{"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
- &SectionHeader{"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
- &SectionHeader{"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
- &SectionHeader{"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
- &SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
+ {"__text", "__TEXT", 0x1f68, 0x88, 0xf68, 0x2, 0x0, 0x0, 0x80000400},
+ {"__cstring", "__TEXT", 0x1ff0, 0xd, 0xff0, 0x0, 0x0, 0x0, 0x2},
+ {"__data", "__DATA", 0x2000, 0x14, 0x1000, 0x2, 0x0, 0x0, 0x0},
+ {"__dyld", "__DATA", 0x2014, 0x1c, 0x1014, 0x2, 0x0, 0x0, 0x0},
+ {"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
},
},
{
"testdata/gcc-amd64-darwin-exec",
FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
[]*SegmentHeader{
- &SegmentHeader{LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
- &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
- &SegmentHeader{LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
+ {LoadCmdSegment64, 0x48, "__PAGEZERO", 0x0, 0x100000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x1000, 0x7, 0x5, 0x5, 0x0},
+ {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x1000, 0x1000, 0x7, 0x3, 0x3, 0x0},
+ {LoadCmdSegment64, 0x48, "__LINKEDIT", 0x100002000, 0x1000, 0x2000, 0x140, 0x7, 0x1, 0x0, 0x0},
nil,
nil,
nil,
@@ -59,14 +59,14 @@ var fileTests = []fileTest{
nil,
},
[]*SectionHeader{
- &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
- &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
- &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
- &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
- &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
- &SectionHeader{"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
- &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
- &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
+ {"__text", "__TEXT", 0x100000f14, 0x6d, 0xf14, 0x2, 0x0, 0x0, 0x80000400},
+ {"__symbol_stub1", "__TEXT", 0x100000f81, 0xc, 0xf81, 0x0, 0x0, 0x0, 0x80000408},
+ {"__stub_helper", "__TEXT", 0x100000f90, 0x18, 0xf90, 0x2, 0x0, 0x0, 0x0},
+ {"__cstring", "__TEXT", 0x100000fa8, 0xd, 0xfa8, 0x0, 0x0, 0x0, 0x2},
+ {"__eh_frame", "__TEXT", 0x100000fb8, 0x48, 0xfb8, 0x3, 0x0, 0x0, 0x6000000b},
+ {"__data", "__DATA", 0x100001000, 0x1c, 0x1000, 0x3, 0x0, 0x0, 0x0},
+ {"__dyld", "__DATA", 0x100001020, 0x38, 0x1020, 0x3, 0x0, 0x0, 0x0},
+ {"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
},
},
{
@@ -74,26 +74,26 @@ var fileTests = []fileTest{
FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
[]*SegmentHeader{
nil,
- &SegmentHeader{LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
- &SegmentHeader{LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
- &SegmentHeader{LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
+ {LoadCmdSegment64, 0x1d8, "__TEXT", 0x100000000, 0x1000, 0x0, 0x0, 0x7, 0x5, 0x5, 0x0},
+ {LoadCmdSegment64, 0x138, "__DATA", 0x100001000, 0x1000, 0x0, 0x0, 0x7, 0x3, 0x3, 0x0},
+ {LoadCmdSegment64, 0x278, "__DWARF", 0x100002000, 0x1000, 0x1000, 0x1bc, 0x7, 0x3, 0x7, 0x0},
},
[]*SectionHeader{
- &SectionHeader{"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
- &SectionHeader{"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
- &SectionHeader{"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
- &SectionHeader{"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
- &SectionHeader{"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
- &SectionHeader{"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
- &SectionHeader{"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
- &SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
- &SectionHeader{"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
- &SectionHeader{"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
+ {"__text", "__TEXT", 0x100000f14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x80000400},
+ {"__symbol_stub1", "__TEXT", 0x100000f81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80000408},
+ {"__stub_helper", "__TEXT", 0x100000f90, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0},
+ {"__cstring", "__TEXT", 0x100000fa8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
+ {"__eh_frame", "__TEXT", 0x100000fb8, 0x0, 0x0, 0x3, 0x0, 0x0, 0x6000000b},
+ {"__data", "__DATA", 0x100001000, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ {"__dyld", "__DATA", 0x100001020, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0},
+ {"__la_symbol_ptr", "__DATA", 0x100001058, 0x0, 0x0, 0x2, 0x0, 0x0, 0x7},
+ {"__debug_abbrev", "__DWARF", 0x100002000, 0x36, 0x1000, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_aranges", "__DWARF", 0x100002036, 0x30, 0x1036, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_frame", "__DWARF", 0x100002066, 0x40, 0x1066, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_info", "__DWARF", 0x1000020a6, 0x54, 0x10a6, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_line", "__DWARF", 0x1000020fa, 0x47, 0x10fa, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_pubnames", "__DWARF", 0x100002141, 0x1b, 0x1141, 0x0, 0x0, 0x0, 0x0},
+ {"__debug_str", "__DWARF", 0x10000215c, 0x60, 0x115c, 0x0, 0x0, 0x0, 0x0},
},
},
}
diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
index 1386f5acf..bc14226c5 100644
--- a/src/pkg/debug/macho/macho.go
+++ b/src/pkg/debug/macho/macho.go
@@ -278,7 +278,7 @@ func stringName(i uint32, names []intName, goSyntax bool) string {
return n.s
}
}
- return strconv.Uitoa64(uint64(i))
+ return strconv.FormatUint(uint64(i), 10)
}
func flagName(i uint32, names []intName, goSyntax bool) string {
@@ -296,10 +296,10 @@ func flagName(i uint32, names []intName, goSyntax bool) string {
}
}
if len(s) == 0 {
- return "0x" + strconv.Uitob64(uint64(i), 16)
+ return "0x" + strconv.FormatUint(uint64(i), 16)
}
if i != 0 {
- s += "+0x" + strconv.Uitob64(uint64(i), 16)
+ s += "+0x" + strconv.FormatUint(uint64(i), 16)
}
return s
}
diff --git a/src/pkg/debug/pe/Makefile b/src/pkg/debug/pe/Makefile
deleted file mode 100644
index 998e6a418..000000000
--- a/src/pkg/debug/pe/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=debug/pe
-GOFILES=\
- pe.go\
- file.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index d86d916f5..6b98a5f45 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -8,6 +8,7 @@ package pe
import (
"debug/dwarf"
"encoding/binary"
+ "errors"
"fmt"
"io"
"os"
@@ -59,7 +60,7 @@ type ImportDirectory struct {
}
// Data reads and returns the contents of the PE section.
-func (s *Section) Data() ([]byte, os.Error) {
+func (s *Section) Data() ([]byte, error) {
dat := make([]byte, s.sr.Size())
n, err := s.sr.ReadAt(dat, 0)
return dat[0:n], err
@@ -74,7 +75,7 @@ type FormatError struct {
val interface{}
}
-func (e *FormatError) String() string {
+func (e *FormatError) Error() string {
msg := e.msg
if e.val != nil {
msg += fmt.Sprintf(" '%v'", e.val)
@@ -84,7 +85,7 @@ func (e *FormatError) String() string {
}
// Open opens the named file using os.Open and prepares it for use as a PE binary.
-func Open(name string) (*File, os.Error) {
+func Open(name string) (*File, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
@@ -101,8 +102,8 @@ func Open(name string) (*File, os.Error) {
// Close closes the File.
// If the File was created using NewFile directly instead of Open,
// Close has no effect.
-func (f *File) Close() os.Error {
- var err os.Error
+func (f *File) Close() error {
+ var err error
if f.closer != nil {
err = f.closer.Close()
f.closer = nil
@@ -111,7 +112,7 @@ func (f *File) Close() os.Error {
}
// NewFile creates a new File for accessing a PE binary in an underlying reader.
-func NewFile(r io.ReaderAt) (*File, os.Error) {
+func NewFile(r io.ReaderAt) (*File, error) {
f := new(File)
sr := io.NewSectionReader(r, 0, 1<<63-1)
@@ -124,7 +125,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
var sign [4]byte
r.ReadAt(sign[0:], int64(dosheader[0x3c]))
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
- return nil, os.NewError("Invalid PE File Format.")
+ return nil, errors.New("Invalid PE File Format.")
}
base = int64(dosheader[0x3c]) + 4
} else {
@@ -135,7 +136,7 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return nil, err
}
if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
- return nil, os.NewError("Invalid PE File Format.")
+ return nil, errors.New("Invalid PE File Format.")
}
// get symbol string table
sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
@@ -215,7 +216,7 @@ func (f *File) Section(name string) *Section {
return nil
}
-func (f *File) DWARF() (*dwarf.Data, os.Error) {
+func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them.
@@ -242,7 +243,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
// referred to by the binary f that are expected to be
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
-func (f *File) ImportedSymbols() ([]string, os.Error) {
+func (f *File) ImportedSymbols() ([]string, error) {
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
ds := f.Section(".idata")
if ds == nil {
@@ -308,7 +309,7 @@ func (f *File) ImportedSymbols() ([]string, os.Error) {
// ImportedLibraries returns the names of all libraries
// referred to by the binary f that are expected to be
// linked with the binary at dynamic link time.
-func (f *File) ImportedLibraries() ([]string, os.Error) {
+func (f *File) ImportedLibraries() ([]string, error) {
// TODO
// cgo -dynimport don't use this for windows PE, so just return.
return nil, nil
diff --git a/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go
index 2c5c25b8c..2815d720b 100644
--- a/src/pkg/debug/pe/file_test.go
+++ b/src/pkg/debug/pe/file_test.go
@@ -20,39 +20,39 @@ var fileTests = []fileTest{
"testdata/gcc-386-mingw-obj",
FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
[]*SectionHeader{
- &SectionHeader{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
- &SectionHeader{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
- &SectionHeader{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
- &SectionHeader{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
- &SectionHeader{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
- &SectionHeader{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
- &SectionHeader{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
- &SectionHeader{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
- &SectionHeader{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
- &SectionHeader{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
- &SectionHeader{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
- &SectionHeader{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
+ {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
+ {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
+ {".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
+ {".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
+ {".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
+ {".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
+ {".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
+ {".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
+ {".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
+ {".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
+ {".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
+ {".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
},
},
{
"testdata/gcc-386-mingw-exec",
FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
[]*SectionHeader{
- &SectionHeader{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
- &SectionHeader{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- &SectionHeader{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
- &SectionHeader{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
- &SectionHeader{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- &SectionHeader{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- &SectionHeader{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
- &SectionHeader{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
- &SectionHeader{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
- &SectionHeader{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
+ {Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ {Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
+ {Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
+ {Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ {Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ {Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ {Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ {Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
+ {Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
},
},
}
diff --git a/src/pkg/deps.bash b/src/pkg/deps.bash
deleted file mode 100755
index 2095ec1d8..000000000
--- a/src/pkg/deps.bash
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-eval $(gomake --no-print-directory -f ../Make.inc go-env)
-
-OUT="Make.deps"
-TMP="Make.deps.tmp"
-
-if [ -f $OUT ] && ! [ -w $OUT ]; then
- echo "$0: $OUT is read-only; aborting." 1>&2
- exit 1
-fi
-
-# Get list of directories from Makefile
-dirs=$(gomake --no-print-directory echo-dirs)
-dirpat=$(echo $dirs C | awk '{
- for(i=1;i<=NF;i++){
- x=$i
- gsub("/", "\\/", x)
- printf("/^(%s)$/\n", x)
- }
-}')
-
-for dir in $dirs; do (
- cd $dir || exit 1
-
- sources=$(sed -n 's/^[ ]*\([^ ]*\.go\)[ ]*\\*[ ]*$/\1/p' Makefile)
- sources=$(echo $sources | sed 's/\$(GOOS)/'$GOOS'/g')
- sources=$(echo $sources | sed 's/\$(GOARCH)/'$GOARCH'/g')
- # /dev/null here means we get an empty dependency list if $sources is empty
- # instead of listing every file in the directory.
- sources=$(ls $sources /dev/null 2> /dev/null) # remove .s, .c, etc.
-
- deps=$(
- sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
- cut -d '"' -f2 |
- awk "$dirpat" |
- grep -v "^$dir\$" |
- sed 's/$/.install/' |
- sed 's;^C\.install;runtime/cgo.install;' |
- sort -u
- )
-
- echo $dir.install: $deps
-) done > $TMP
-
-mv $TMP $OUT
diff --git a/src/pkg/ebnf/Makefile b/src/pkg/ebnf/Makefile
deleted file mode 100644
index f5555d272..000000000
--- a/src/pkg/ebnf/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=ebnf
-GOFILES=\
- ebnf.go\
- parser.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go
deleted file mode 100644
index 69da11767..000000000
--- a/src/pkg/ebnf/ebnf.go
+++ /dev/null
@@ -1,245 +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 ebnf is a library for EBNF grammars. The input is text ([]byte)
-// satisfying the following grammar (represented itself in EBNF):
-//
-// Production = name "=" [ Expression ] "." .
-// Expression = Alternative { "|" Alternative } .
-// Alternative = Term { Term } .
-// Term = name | token [ "…" token ] | Group | Option | Repetition .
-// Group = "(" Expression ")" .
-// Option = "[" Expression "]" .
-// Repetition = "{" Expression "}" .
-//
-// A name is a Go identifier, a token is a Go string, and comments
-// and white space follow the same rules as for the Go language.
-// Production names starting with an uppercase Unicode letter denote
-// non-terminal productions (i.e., productions which allow white-space
-// and comments between tokens); all other production names denote
-// lexical productions.
-//
-package ebnf
-
-import (
- "go/scanner"
- "go/token"
- "os"
- "unicode"
- "utf8"
-)
-
-// ----------------------------------------------------------------------------
-// Internal representation
-
-type (
- // An Expression node represents a production expression.
- Expression interface {
- // Pos is the position of the first character of the syntactic construct
- Pos() token.Pos
- }
-
- // An Alternative node represents a non-empty list of alternative expressions.
- Alternative []Expression // x | y | z
-
- // A Sequence node represents a non-empty list of sequential expressions.
- Sequence []Expression // x y z
-
- // A Name node represents a production name.
- Name struct {
- StringPos token.Pos
- String string
- }
-
- // A Token node represents a literal.
- Token struct {
- StringPos token.Pos
- String string
- }
-
- // A List node represents a range of characters.
- Range struct {
- Begin, End *Token // begin ... end
- }
-
- // A Group node represents a grouped expression.
- Group struct {
- Lparen token.Pos
- Body Expression // (body)
- }
-
- // An Option node represents an optional expression.
- Option struct {
- Lbrack token.Pos
- Body Expression // [body]
- }
-
- // A Repetition node represents a repeated expression.
- Repetition struct {
- Lbrace token.Pos
- Body Expression // {body}
- }
-
- // A 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
- Expr Expression
- }
-
- // A Grammar is a set of EBNF productions. The map
- // is indexed by production name.
- //
- Grammar map[string]*Production
-)
-
-func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative
-func (x Sequence) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Sequences
-func (x *Name) Pos() token.Pos { return x.StringPos }
-func (x *Token) Pos() token.Pos { return x.StringPos }
-func (x *Range) Pos() token.Pos { return x.Begin.Pos() }
-func (x *Group) Pos() token.Pos { return x.Lparen }
-func (x *Option) Pos() token.Pos { return x.Lbrack }
-func (x *Repetition) Pos() token.Pos { return x.Lbrace }
-func (x *Bad) Pos() token.Pos { return x.TokPos }
-func (x *Production) Pos() token.Pos { return x.Name.Pos() }
-
-// ----------------------------------------------------------------------------
-// Grammar verification
-
-func isLexical(name string) bool {
- ch, _ := utf8.DecodeRuneInString(name)
- return !unicode.IsUpper(ch)
-}
-
-type verifier struct {
- fset *token.FileSet
- scanner.ErrorVector
- worklist []*Production
- reached Grammar // set of productions reached from (and including) the root production
- grammar Grammar
-}
-
-func (v *verifier) error(pos token.Pos, msg string) {
- v.Error(v.fset.Position(pos), msg)
-}
-
-func (v *verifier) push(prod *Production) {
- name := prod.Name.String
- if _, found := v.reached[name]; !found {
- v.worklist = append(v.worklist, prod)
- v.reached[name] = prod
- }
-}
-
-func (v *verifier) verifyChar(x *Token) int {
- s := x.String
- if utf8.RuneCountInString(s) != 1 {
- v.error(x.Pos(), "single char expected, found "+s)
- return 0
- }
- ch, _ := utf8.DecodeRuneInString(s)
- return ch
-}
-
-func (v *verifier) verifyExpr(expr Expression, lexical bool) {
- switch x := expr.(type) {
- case nil:
- // empty expression
- case Alternative:
- for _, e := range x {
- v.verifyExpr(e, lexical)
- }
- case Sequence:
- for _, e := range x {
- v.verifyExpr(e, lexical)
- }
- case *Name:
- // a production with this name must exist;
- // add it to the worklist if not yet processed
- if prod, found := v.grammar[x.String]; found {
- v.push(prod)
- } else {
- v.error(x.Pos(), "missing production "+x.String)
- }
- // within a lexical production references
- // to non-lexical productions are invalid
- if lexical && !isLexical(x.String) {
- v.error(x.Pos(), "reference to non-lexical production "+x.String)
- }
- case *Token:
- // nothing to do for now
- case *Range:
- i := v.verifyChar(x.Begin)
- j := v.verifyChar(x.End)
- if i >= j {
- v.error(x.Pos(), "decreasing character range")
- }
- case *Group:
- v.verifyExpr(x.Body, lexical)
- case *Option:
- v.verifyExpr(x.Body, lexical)
- case *Repetition:
- v.verifyExpr(x.Body, lexical)
- default:
- panic("unreachable")
- }
-}
-
-func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
- // find root production
- root, found := grammar[start]
- if !found {
- // token.NoPos doesn't require a file set;
- // ok to set v.fset only afterwards
- v.error(token.NoPos, "no start production "+start)
- return
- }
-
- // initialize verifier
- v.fset = fset
- v.ErrorVector.Reset()
- v.worklist = v.worklist[0:0]
- v.reached = make(Grammar)
- v.grammar = grammar
-
- // work through the worklist
- v.push(root)
- for {
- n := len(v.worklist) - 1
- if n < 0 {
- break
- }
- prod := v.worklist[n]
- v.worklist = v.worklist[0:n]
- v.verifyExpr(prod.Expr, isLexical(prod.Name.String))
- }
-
- // check if all productions were reached
- if len(v.reached) < len(v.grammar) {
- for name, prod := range v.grammar {
- if _, found := v.reached[name]; !found {
- v.error(prod.Pos(), name+" is unreachable")
- }
- }
- }
-}
-
-// Verify checks that:
-// - all productions used are defined
-// - all productions defined are used when beginning at start
-// - lexical productions refer only to other lexical productions
-//
-// Position information is interpreted relative to the file set fset.
-//
-func Verify(fset *token.FileSet, grammar Grammar, start string) os.Error {
- var v verifier
- v.verify(fset, grammar, start)
- return v.GetError(scanner.Sorted)
-}
diff --git a/src/pkg/ebnf/ebnf_test.go b/src/pkg/ebnf/ebnf_test.go
deleted file mode 100644
index b086facc3..000000000
--- a/src/pkg/ebnf/ebnf_test.go
+++ /dev/null
@@ -1,87 +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 ebnf
-
-import (
- "go/token"
- "io/ioutil"
- "testing"
-)
-
-var fset = token.NewFileSet()
-
-var goodGrammars = []string{
- `Program = .`,
-
- `Program = foo .
- foo = "foo" .`,
-
- `Program = "a" | "b" "c" .`,
-
- `Program = "a" … "z" .`,
-
- `Program = Song .
- Song = { Note } .
- Note = Do | (Re | Mi | Fa | So | La) | Ti .
- Do = "c" .
- Re = "d" .
- Mi = "e" .
- Fa = "f" .
- So = "g" .
- La = "a" .
- Ti = ti .
- ti = "b" .`,
-}
-
-var badGrammars = []string{
- `Program = | .`,
- `Program = | b .`,
- `Program = a … b .`,
- `Program = "a" … .`,
- `Program = … "b" .`,
- `Program = () .`,
- `Program = [] .`,
- `Program = {} .`,
-}
-
-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)
- }
- if err = Verify(fset, grammar, "Program"); err != nil {
- t.Errorf("Verify(%s) failed: %v", src, err)
- }
-}
-
-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 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)
- }
- checkGood(t, filename, src)
- }
-}
diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go
deleted file mode 100644
index ef2fac000..000000000
--- a/src/pkg/ebnf/parser.go
+++ /dev/null
@@ -1,197 +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 ebnf
-
-import (
- "go/scanner"
- "go/token"
- "os"
- "strconv"
-)
-
-type parser struct {
- fset *token.FileSet
- scanner.ErrorVector
- scanner scanner.Scanner
- pos token.Pos // token position
- tok token.Token // one token look-ahead
- lit string // token literal
-}
-
-func (p *parser) next() {
- p.pos, p.tok, p.lit = p.scanner.Scan()
- if p.tok.IsKeyword() {
- // TODO Should keyword mapping always happen outside scanner?
- // Or should there be a flag to scanner to enable keyword mapping?
- p.tok = token.IDENT
- }
-}
-
-func (p *parser) error(pos token.Pos, msg string) {
- p.Error(p.fset.Position(pos), msg)
-}
-
-func (p *parser) errorExpected(pos token.Pos, msg string) {
- msg = "expected " + msg
- if pos == p.pos {
- // the error happened at the current position;
- // make the error message more specific
- msg += ", found '" + p.tok.String() + "'"
- if p.tok.IsLiteral() {
- msg += " " + p.lit
- }
- }
- p.error(pos, msg)
-}
-
-func (p *parser) expect(tok token.Token) token.Pos {
- pos := p.pos
- if p.tok != tok {
- p.errorExpected(pos, "'"+tok.String()+"'")
- }
- p.next() // make progress in any case
- return pos
-}
-
-func (p *parser) parseIdentifier() *Name {
- pos := p.pos
- name := p.lit
- p.expect(token.IDENT)
- return &Name{pos, name}
-}
-
-func (p *parser) parseToken() *Token {
- pos := p.pos
- value := ""
- if p.tok == token.STRING {
- value, _ = strconv.Unquote(p.lit)
- // Unquote may fail with an error, but only if the scanner found
- // an illegal string in the first place. In this case the error
- // has already been reported.
- p.next()
- } else {
- p.expect(token.STRING)
- }
- return &Token{pos, value}
-}
-
-// ParseTerm returns nil if no term was found.
-func (p *parser) parseTerm() (x Expression) {
- pos := p.pos
-
- switch p.tok {
- case token.IDENT:
- x = p.parseIdentifier()
-
- case token.STRING:
- tok := p.parseToken()
- x = tok
- const ellipsis = "…" // U+2026, the horizontal ellipsis character
- if p.tok == token.ILLEGAL && p.lit == ellipsis {
- p.next()
- x = &Range{tok, p.parseToken()}
- }
-
- case token.LPAREN:
- p.next()
- x = &Group{pos, p.parseExpression()}
- p.expect(token.RPAREN)
-
- case token.LBRACK:
- p.next()
- x = &Option{pos, p.parseExpression()}
- p.expect(token.RBRACK)
-
- case token.LBRACE:
- p.next()
- x = &Repetition{pos, p.parseExpression()}
- p.expect(token.RBRACE)
- }
-
- return x
-}
-
-func (p *parser) parseSequence() Expression {
- var list Sequence
-
- for x := p.parseTerm(); x != nil; x = p.parseTerm() {
- list = append(list, x)
- }
-
- // no need for a sequence if list.Len() < 2
- switch len(list) {
- case 0:
- p.errorExpected(p.pos, "term")
- return &Bad{p.pos, "term expected"}
- case 1:
- return list[0]
- }
-
- return list
-}
-
-func (p *parser) parseExpression() Expression {
- var list Alternative
-
- for {
- 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
- if len(list) == 1 {
- return list[0]
- }
-
- return list
-}
-
-func (p *parser) parseProduction() *Production {
- name := p.parseIdentifier()
- p.expect(token.ASSIGN)
- 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, scanner.AllowIllegalChars)
- p.next() // initializes pos, tok, lit
-
- grammar := make(Grammar)
- for p.tok != token.EOF {
- prod := p.parseProduction()
- name := prod.Name.String
- if _, found := grammar[name]; !found {
- grammar[name] = prod
- } else {
- p.error(prod.Pos(), name+" declared already")
- }
- }
-
- return grammar
-}
-
-// Parse parses a set of EBNF productions from source src.
-// It returns a set of productions. Errors are reported
-// for incorrect syntax and if a production is declared
-// more than once. Position information is recorded relative
-// to the file set fset.
-//
-func Parse(fset *token.FileSet, filename string, src []byte) (Grammar, os.Error) {
- var p parser
- grammar := p.parse(fset, filename, src)
- return grammar, p.GetError(scanner.Sorted)
-}
diff --git a/src/pkg/encoding/ascii85/Makefile b/src/pkg/encoding/ascii85/Makefile
deleted file mode 100644
index 412383efd..000000000
--- a/src/pkg/encoding/ascii85/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/ascii85
-GOFILES=\
- ascii85.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
index ead0c2475..7d004b5e5 100644
--- a/src/pkg/encoding/ascii85/ascii85.go
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -8,7 +8,6 @@ package ascii85
import (
"io"
- "os"
"strconv"
)
@@ -93,14 +92,14 @@ func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
type encoder struct {
- err os.Error
+ err error
w io.Writer
buf [4]byte // buffered data waiting to be encoded
nbuf int // number of bytes in buf
out [1024]byte // output buffer
}
-func (e *encoder) Write(p []byte) (n int, err os.Error) {
+func (e *encoder) Write(p []byte) (n int, err error) {
if e.err != nil {
return 0, e.err
}
@@ -152,7 +151,7 @@ func (e *encoder) Write(p []byte) (n int, err os.Error) {
// Close flushes any pending output from the encoder.
// It is an error to call Write after calling Close.
-func (e *encoder) Close() os.Error {
+func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
nout := Encode(e.out[0:], e.buf[0:e.nbuf])
@@ -168,8 +167,8 @@ func (e *encoder) Close() os.Error {
type CorruptInputError int64
-func (e CorruptInputError) String() string {
- return "illegal ascii85 data at input byte " + strconv.Itoa64(int64(e))
+func (e CorruptInputError) Error() string {
+ return "illegal ascii85 data at input byte " + strconv.FormatInt(int64(e), 10)
}
// Decode decodes src into dst, returning both the number
@@ -186,7 +185,7 @@ func (e CorruptInputError) String() string {
//
// NewDecoder wraps an io.Reader interface around Decode.
//
-func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err os.Error) {
+func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err error) {
var v uint32
var nb int
for i, b := range src {
@@ -246,8 +245,8 @@ func Decode(dst, src []byte, flush bool) (ndst, nsrc int, err os.Error) {
func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
type decoder struct {
- err os.Error
- readErr os.Error
+ err error
+ readErr error
r io.Reader
end bool // saw end of message
buf [1024]byte // leftover input
@@ -256,7 +255,7 @@ type decoder struct {
outbuf [1024]byte
}
-func (d *decoder) Read(p []byte) (n int, err os.Error) {
+func (d *decoder) Read(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, nil
}
diff --git a/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
index fdfeb889f..70e67d8b0 100644
--- a/src/pkg/encoding/ascii85/ascii85_test.go
+++ b/src/pkg/encoding/ascii85/ascii85_test.go
@@ -6,8 +6,8 @@ package ascii85
import (
"bytes"
+ "io"
"io/ioutil"
- "os"
"testing"
)
@@ -83,11 +83,11 @@ func TestEncoderBuffering(t *testing.T) {
end = len(input)
}
n, err := encoder.Write(input[pos:end])
- testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
}
err := encoder.Close()
- testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Close gave error %v, want %v", err, error(nil))
testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, strip85(bb.String()), strip85(bigtest.encoded))
}
}
@@ -96,7 +96,7 @@ func TestDecode(t *testing.T) {
for _, p := range pairs {
dbuf := make([]byte, 4*len(p.encoded))
ndst, nsrc, err := Decode(dbuf, []byte(p.encoded), true)
- testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
testEqual(t, "Decode(%q) = nsrc %v, want %v", p.encoded, nsrc, len(p.encoded))
testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
@@ -113,7 +113,7 @@ func TestDecoder(t *testing.T) {
testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
if err != nil {
- testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
}
}
}
@@ -125,7 +125,7 @@ func TestDecoderBuffering(t *testing.T) {
var total int
for total = 0; total < len(bigtest.decoded); {
n, err := decoder.Read(buf[total : total+bs])
- testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, error(nil))
total += n
}
testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/encoding/asn1/asn1.go
index 39b676b41..3bf81a68c 100644
--- a/src/pkg/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -20,9 +20,8 @@ package asn1
// everything by any means.
import (
- "big"
"fmt"
- "os"
+ "math/big"
"reflect"
"time"
)
@@ -33,20 +32,20 @@ type StructuralError struct {
Msg string
}
-func (e StructuralError) String() string { return "ASN.1 structure error: " + e.Msg }
+func (e StructuralError) Error() string { return "ASN.1 structure error: " + e.Msg }
// A SyntaxError suggests that the ASN.1 data is invalid.
type SyntaxError struct {
Msg string
}
-func (e SyntaxError) String() string { return "ASN.1 syntax error: " + e.Msg }
+func (e SyntaxError) Error() string { return "ASN.1 syntax error: " + e.Msg }
// We start by dealing with each of the primitive types in turn.
// BOOLEAN
-func parseBool(bytes []byte) (ret bool, err os.Error) {
+func parseBool(bytes []byte) (ret bool, err error) {
if len(bytes) != 1 {
err = SyntaxError{"invalid boolean"}
return
@@ -59,7 +58,7 @@ func parseBool(bytes []byte) (ret bool, err os.Error) {
// parseInt64 treats the given bytes as a big-endian, signed integer and
// returns the result.
-func parseInt64(bytes []byte) (ret int64, err os.Error) {
+func parseInt64(bytes []byte) (ret int64, err error) {
if len(bytes) > 8 {
// We'll overflow an int64 in this case.
err = StructuralError{"integer too large"}
@@ -78,7 +77,7 @@ func parseInt64(bytes []byte) (ret int64, err os.Error) {
// parseInt treats the given bytes as a big-endian, signed integer and returns
// the result.
-func parseInt(bytes []byte) (int, os.Error) {
+func parseInt(bytes []byte) (int, error) {
ret64, err := parseInt64(bytes)
if err != nil {
return 0, err
@@ -150,7 +149,7 @@ func (b BitString) RightAlign() []byte {
}
// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
-func parseBitString(bytes []byte) (ret BitString, err os.Error) {
+func parseBitString(bytes []byte) (ret BitString, err error) {
if len(bytes) == 0 {
err = SyntaxError{"zero length BIT STRING"}
return
@@ -189,7 +188,7 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
// 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) {
+func parseObjectIdentifier(bytes []byte) (s []int, err error) {
if len(bytes) == 0 {
err = SyntaxError{"zero length OBJECT IDENTIFIER"}
return
@@ -227,7 +226,7 @@ type Flag bool
// parseBase128Int parses a base-128 encoded int from the given offset in the
// given byte slice. It returns the value and the new offset.
-func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
+func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
offset = initOffset
for shifted := 0; offset < len(bytes); shifted++ {
if shifted > 4 {
@@ -248,19 +247,23 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Erro
// UTCTime
-func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
+func parseUTCTime(bytes []byte) (ret time.Time, err error) {
s := string(bytes)
ret, err = time.Parse("0601021504Z0700", s)
- if err == nil {
- return
+ if err != nil {
+ ret, err = time.Parse("060102150405Z0700", s)
}
- ret, err = time.Parse("060102150405Z0700", s)
+ if err == nil && ret.Year() >= 2050 {
+ // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
+ ret = ret.AddDate(-100, 0, 0)
+ }
+
return
}
// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
// and returns the resulting time.
-func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
return time.Parse("20060102150405Z0700", string(bytes))
}
@@ -268,7 +271,7 @@ func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
// parsePrintableString parses a ASN.1 PrintableString from the given byte
// array and returns it.
-func parsePrintableString(bytes []byte) (ret string, err os.Error) {
+func parsePrintableString(bytes []byte) (ret string, err error) {
for _, b := range bytes {
if !isPrintable(b) {
err = SyntaxError{"PrintableString contains invalid character"}
@@ -300,7 +303,7 @@ func isPrintable(b byte) bool {
// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
// byte slice and returns it.
-func parseIA5String(bytes []byte) (ret string, err os.Error) {
+func parseIA5String(bytes []byte) (ret string, err error) {
for _, b := range bytes {
if b >= 0x80 {
err = SyntaxError{"IA5String contains invalid character"}
@@ -315,7 +318,7 @@ func parseIA5String(bytes []byte) (ret string, err os.Error) {
// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
// byte slice and returns it.
-func parseT61String(bytes []byte) (ret string, err os.Error) {
+func parseT61String(bytes []byte) (ret string, err error) {
return string(bytes), nil
}
@@ -323,7 +326,7 @@ func parseT61String(bytes []byte) (ret string, err os.Error) {
// 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) {
+func parseUTF8String(bytes []byte) (ret string, err error) {
return string(bytes), nil
}
@@ -346,7 +349,7 @@ type RawContent []byte
// 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) {
+func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) {
offset = initOffset
b := bytes[offset]
offset++
@@ -402,7 +405,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 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) {
+func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err error) {
expectedTag, compoundType, ok := getUniversalType(elemType)
if !ok {
err = StructuralError{"unknown Go type for slice"}
@@ -451,7 +454,7 @@ var (
objectIdentifierType = reflect.TypeOf(ObjectIdentifier{})
enumeratedType = reflect.TypeOf(Enumerated(0))
flagType = reflect.TypeOf(Flag(false))
- timeType = reflect.TypeOf(&time.Time{})
+ timeType = reflect.TypeOf(time.Time{})
rawValueType = reflect.TypeOf(RawValue{})
rawContentsType = reflect.TypeOf(RawContent(nil))
bigIntType = reflect.TypeOf(new(big.Int))
@@ -466,7 +469,7 @@ func invalidLength(offset, length, sliceLength int) bool {
// 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) {
+func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err error) {
offset = initOffset
fieldType := v.Type()
@@ -516,6 +519,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
result, err = parseIA5String(innerBytes)
case tagT61String:
result, err = parseT61String(innerBytes)
+ case tagUTF8String:
+ result, err = parseUTF8String(innerBytes)
case tagInteger:
result, err = parseInt64(innerBytes)
case tagBitString:
@@ -646,8 +651,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
err = err1
return
case timeType:
- var time *time.Time
- var err1 os.Error
+ var time time.Time
+ var err1 error
if universalTag == tagUTCTime {
time, err1 = parseUTCTime(innerBytes)
} else {
@@ -785,7 +790,8 @@ 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, int32 or int64.
+// An ASN.1 INTEGER can be written to an int, int32, int64,
+// or *big.Int (from the math/big package).
// If the encoded value does not fit in the Go type,
// Unmarshal returns a parse error.
//
@@ -798,7 +804,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
//
// An ASN.1 ENUMERATED can be written to an Enumerated.
//
-// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time.
//
// An ASN.1 PrintableString or IA5String can be written to a string.
//
@@ -824,13 +830,13 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
//
// Other ASN.1 types are not supported; if it encounters them,
// Unmarshal returns a parse error.
-func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
+func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
return UnmarshalWithParams(b, val, "")
}
// UnmarshalWithParams allows field parameters to be specified for the
// top-level element. The form of the params is the same as the field tags.
-func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) {
+func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err error) {
v := reflect.ValueOf(val).Elem()
offset, err := parseField(v, b, 0, parseFieldParameters(params))
if err != nil {
diff --git a/src/pkg/asn1/asn1_test.go b/src/pkg/encoding/asn1/asn1_test.go
index 9f48f7bdd..93803f435 100644
--- a/src/pkg/asn1/asn1_test.go
+++ b/src/pkg/encoding/asn1/asn1_test.go
@@ -6,6 +6,7 @@ package asn1
import (
"bytes"
+ "math/big"
"reflect"
"testing"
"time"
@@ -202,43 +203,51 @@ func TestObjectIdentifier(t *testing.T) {
type timeTest struct {
in string
ok bool
- out *time.Time
+ out time.Time
}
var utcTestData = []timeTest{
- {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 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},
- {"910506a34540Z", false, nil},
- {"910506334a40Z", false, nil},
- {"91050633444aZ", false, nil},
- {"910506334461Z", false, nil},
- {"910506334400Za", false, nil},
+ {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))},
+ {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
+ {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
+ {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
+ {"a10506234540Z", false, time.Time{}},
+ {"91a506234540Z", false, time.Time{}},
+ {"9105a6234540Z", false, time.Time{}},
+ {"910506a34540Z", false, time.Time{}},
+ {"910506334a40Z", false, time.Time{}},
+ {"91050633444aZ", false, time.Time{}},
+ {"910506334461Z", false, time.Time{}},
+ {"910506334400Za", false, time.Time{}},
}
func TestUTCTime(t *testing.T) {
for i, test := range utcTestData {
ret, err := parseUTCTime([]byte(test.in))
- if (err == nil) != test.ok {
- t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
- }
- if err == nil {
- if !reflect.DeepEqual(test.out, ret) {
- t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ if err != nil {
+ if test.ok {
+ t.Errorf("#%d: parseUTCTime(%q) = error %v", i, test.in, err)
}
+ continue
+ }
+ if !test.ok {
+ t.Errorf("#%d: parseUTCTime(%q) succeeded, should have failed", i, test.in)
+ continue
+ }
+ const format = "Jan _2 15:04:05 -0700 2006" // ignore zone name, just offset
+ have := ret.Format(format)
+ want := test.out.Format(format)
+ if have != want {
+ t.Errorf("#%d: parseUTCTime(%q) = %s, want %s", i, test.in, have, want)
}
}
}
var generalizedTimeTestData = []timeTest{
- {"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, 0, 6*60*60 + 7*60, ""}},
- {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, -6*60*60 - 7*60, ""}},
+ {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
+ {"20100102030405", false, time.Time{}},
+ {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
+ {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
}
func TestGeneralizedTime(t *testing.T) {
@@ -312,7 +321,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
{"default:42", fieldParameters{defaultValue: newInt64(42)}},
{"tag:17", fieldParameters{tag: newInt(17)}},
{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
- {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false}},
+ {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}},
{"set", fieldParameters{set: true}},
}
@@ -343,6 +352,10 @@ type TestElementsAfterString struct {
A, B int
}
+type TestBigInt struct {
+ X *big.Int
+}
+
var unmarshalTestData = []struct {
in []byte
out interface{}
@@ -361,6 +374,7 @@ var unmarshalTestData = []struct {
{[]byte{0x01, 0x01, 0x00}, newBool(false)},
{[]byte{0x01, 0x01, 0x01}, newBool(true)},
{[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
+ {[]byte{0x30, 0x05, 0x02, 0x03, 0x12, 0x34, 0x56}, &TestBigInt{big.NewInt(0x123456)}},
}
func TestUnmarshal(t *testing.T) {
@@ -407,7 +421,7 @@ type AttributeTypeAndValue struct {
}
type Validity struct {
- NotBefore, NotAfter *time.Time
+ NotBefore, NotAfter time.Time
}
type PublicKeyInfo struct {
@@ -475,7 +489,10 @@ var derEncodedSelfSignedCert = Certificate{
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}},
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}},
},
- Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}},
+ Validity: Validity{
+ NotBefore: time.Date(2009, 10, 8, 00, 25, 53, 0, time.UTC),
+ NotAfter: time.Date(2010, 10, 8, 00, 25, 53, 0, time.UTC),
+ },
Subject: RDNSequence{
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
diff --git a/src/pkg/asn1/common.go b/src/pkg/encoding/asn1/common.go
index 01f4f7b6e..03856bc55 100644
--- a/src/pkg/asn1/common.go
+++ b/src/pkg/encoding/asn1/common.go
@@ -75,6 +75,7 @@ type fieldParameters struct {
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
stringType int // the string tag to use when marshaling.
set bool // true iff this should be encoded as a SET
+ omitEmpty bool // true iff this should be omitted if empty when marshaling.
// Invariants:
// if explicit is set, tag is non-nil.
@@ -98,7 +99,7 @@ func parseFieldParameters(str string) (ret fieldParameters) {
case part == "printable":
ret.stringType = tagPrintableString
case strings.HasPrefix(part, "default:"):
- i, err := strconv.Atoi64(part[8:])
+ i, err := strconv.ParseInt(part[8:], 10, 64)
if err == nil {
ret.defaultValue = new(int64)
*ret.defaultValue = i
@@ -116,6 +117,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
if ret.tag == nil {
ret.tag = new(int)
}
+ case part == "omitempty":
+ ret.omitEmpty = true
}
}
return
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index d7eb63bf8..163bca575 100644
--- a/src/pkg/asn1/marshal.go
+++ b/src/pkg/encoding/asn1/marshal.go
@@ -5,11 +5,10 @@
package asn1
import (
- "big"
"bytes"
"fmt"
"io"
- "os"
+ "math/big"
"reflect"
"time"
)
@@ -25,7 +24,7 @@ type forkableWriter struct {
}
func newForkableWriter() *forkableWriter {
- return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
+ return &forkableWriter{new(bytes.Buffer), nil, nil}
}
func (f *forkableWriter) fork() (pre, post *forkableWriter) {
@@ -48,7 +47,7 @@ func (f *forkableWriter) Len() (l int) {
return
}
-func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
+func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
n, err = out.Write(f.Bytes())
if err != nil {
return
@@ -71,7 +70,7 @@ func (f *forkableWriter) writeTo(out io.Writer) (n int, err os.Error) {
return
}
-func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
+func marshalBase128Int(out *forkableWriter, n int64) (err error) {
if n == 0 {
err = out.WriteByte(0)
return
@@ -97,7 +96,7 @@ func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
return nil
}
-func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
+func marshalInt64(out *forkableWriter, i int64) (err error) {
n := int64Length(i)
for ; n > 0; n-- {
@@ -126,7 +125,7 @@ func int64Length(i int64) (numBytes int) {
return
}
-func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) {
+func marshalBigInt(out *forkableWriter, n *big.Int) (err 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
@@ -163,7 +162,7 @@ func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) {
return
}
-func marshalLength(out *forkableWriter, i int) (err os.Error) {
+func marshalLength(out *forkableWriter, i int) (err error) {
n := lengthLength(i)
for ; n > 0; n-- {
@@ -185,7 +184,7 @@ func lengthLength(i int) (numBytes int) {
return
}
-func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
+func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
b := uint8(t.class) << 6
if t.isCompound {
b |= 0x20
@@ -228,7 +227,7 @@ func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err os.Error) {
return nil
}
-func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
+func marshalBitString(out *forkableWriter, b BitString) (err error) {
paddingBits := byte((8 - b.BitLength%8) % 8)
err = out.WriteByte(paddingBits)
if err != nil {
@@ -238,7 +237,7 @@ func marshalBitString(out *forkableWriter, b BitString) (err os.Error) {
return
}
-func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
+func marshalObjectIdentifier(out *forkableWriter, oid []int) (err error) {
if len(oid) < 2 || oid[0] > 6 || oid[1] >= 40 {
return StructuralError{"invalid object identifier"}
}
@@ -257,7 +256,7 @@ func marshalObjectIdentifier(out *forkableWriter, oid []int) (err os.Error) {
return
}
-func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
+func marshalPrintableString(out *forkableWriter, s string) (err error) {
b := []byte(s)
for _, c := range b {
if !isPrintable(c) {
@@ -269,7 +268,7 @@ func marshalPrintableString(out *forkableWriter, s string) (err os.Error) {
return
}
-func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
+func marshalIA5String(out *forkableWriter, s string) (err error) {
b := []byte(s)
for _, c := range b {
if c > 127 {
@@ -281,7 +280,7 @@ func marshalIA5String(out *forkableWriter, s string) (err os.Error) {
return
}
-func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
+func marshalTwoDigits(out *forkableWriter, v int) (err error) {
err = out.WriteByte(byte('0' + (v/10)%10))
if err != nil {
return
@@ -289,52 +288,58 @@ func marshalTwoDigits(out *forkableWriter, v int) (err os.Error) {
return out.WriteByte(byte('0' + v%10))
}
-func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
+func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
+ utc := t.UTC()
+ year, month, day := utc.Date()
+
switch {
- case 1950 <= t.Year && t.Year < 2000:
- err = marshalTwoDigits(out, int(t.Year-1900))
- case 2000 <= t.Year && t.Year < 2050:
- err = marshalTwoDigits(out, int(t.Year-2000))
+ case 1950 <= year && year < 2000:
+ err = marshalTwoDigits(out, int(year-1900))
+ case 2000 <= year && year < 2050:
+ err = marshalTwoDigits(out, int(year-2000))
default:
return StructuralError{"Cannot represent time as UTCTime"}
}
-
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Month)
+ err = marshalTwoDigits(out, int(month))
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Day)
+ err = marshalTwoDigits(out, day)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Hour)
+ hour, min, sec := utc.Clock()
+
+ err = marshalTwoDigits(out, hour)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Minute)
+ err = marshalTwoDigits(out, min)
if err != nil {
return
}
- err = marshalTwoDigits(out, t.Second)
+ err = marshalTwoDigits(out, sec)
if err != nil {
return
}
+ _, offset := t.Zone()
+
switch {
- case t.ZoneOffset/60 == 0:
+ case offset/60 == 0:
err = out.WriteByte('Z')
return
- case t.ZoneOffset > 0:
+ case offset > 0:
err = out.WriteByte('+')
- case t.ZoneOffset < 0:
+ case offset < 0:
err = out.WriteByte('-')
}
@@ -342,7 +347,7 @@ func marshalUTCTime(out *forkableWriter, t *time.Time) (err os.Error) {
return
}
- offsetMinutes := t.ZoneOffset / 60
+ offsetMinutes := offset / 60
if offsetMinutes < 0 {
offsetMinutes = -offsetMinutes
}
@@ -364,10 +369,10 @@ func stripTagAndLength(in []byte) []byte {
return in[offset:]
}
-func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err os.Error) {
+func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() {
case timeType:
- return marshalUTCTime(out, value.Interface().(*time.Time))
+ return marshalUTCTime(out, value.Interface().(time.Time))
case bitStringType:
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
@@ -452,23 +457,31 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
return StructuralError{"unknown Go type"}
}
-func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err os.Error) {
+func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
// If the field is an interface{} then recurse into it.
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
return marshalField(out, v.Elem(), params)
}
+ if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
+ return
+ }
+
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})
- if err != nil {
- return
+ if len(rv.FullBytes) != 0 {
+ _, err = out.Write(rv.FullBytes)
+ } else {
+ err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
+ if err != nil {
+ return
+ }
+ _, err = out.Write(rv.Bytes)
}
- _, err = out.Write(rv.Bytes)
return
}
@@ -531,7 +544,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
}
// Marshal returns the ASN.1 encoding of val.
-func Marshal(val interface{}) ([]byte, os.Error) {
+func Marshal(val interface{}) ([]byte, error) {
var out bytes.Buffer
v := reflect.ValueOf(val)
f := newForkableWriter()
diff --git a/src/pkg/asn1/marshal_test.go b/src/pkg/encoding/asn1/marshal_test.go
index 03df5f1e1..f43bcae68 100644
--- a/src/pkg/asn1/marshal_test.go
+++ b/src/pkg/encoding/asn1/marshal_test.go
@@ -7,6 +7,7 @@ package asn1
import (
"bytes"
"encoding/hex"
+ "math/big"
"testing"
"time"
)
@@ -20,6 +21,10 @@ type twoIntStruct struct {
B int
}
+type bigIntStruct struct {
+ A *big.Int
+}
+
type nestedStruct struct {
A intStruct
}
@@ -49,12 +54,13 @@ type optionalRawValueTest struct {
A RawValue `asn1:"optional"`
}
+type omitEmptyTest struct {
+ A []string `asn1:"omitempty"`
+}
+
type testSET []int
-func setPST(t *time.Time) *time.Time {
- t.ZoneOffset = -28800
- return t
-}
+var PST = time.FixedZone("PST", -8*60*60)
type marshalTest struct {
in interface{}
@@ -68,14 +74,15 @@ var marshalTests = []marshalTest{
{-128, "020180"},
{-129, "0202ff7f"},
{intStruct{64}, "3003020140"},
+ {bigIntStruct{big.NewInt(0x123456)}, "30050203123456"},
{twoIntStruct{64, 65}, "3006020140020141"},
{nestedStruct{intStruct{127}}, "3005300302017f"},
{[]byte{1, 2, 3}, "0403010203"},
{implicitTagTest{64}, "3003850140"},
{explicitTagTest{64}, "3005a503020140"},
- {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
- {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
- {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+ {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
+ {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
+ {time.Unix(1258325776, 0).In(PST), "17113039313131353232353631362d30383030"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
@@ -113,6 +120,8 @@ var marshalTests = []marshalTest{
{rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
{RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
{testSET([]int{10}), "310302010a"},
+ {omitEmptyTest{[]string{}}, "3000"},
+ {omitEmptyTest{[]string{"1"}}, "30053003130131"},
}
func TestMarshal(t *testing.T) {
@@ -123,7 +132,8 @@ func TestMarshal(t *testing.T) {
}
out, _ := hex.DecodeString(test.out)
if bytes.Compare(out, data) != 0 {
- t.Errorf("#%d got: %x want %x", i, data, out)
+ t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
+
}
}
}
diff --git a/src/pkg/encoding/base32/Makefile b/src/pkg/encoding/base32/Makefile
deleted file mode 100644
index c0e85b644..000000000
--- a/src/pkg/encoding/base32/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include $(GOROOT)/src/Make.inc
-
-TARG=encoding/base32
-GOFILES=\
- base32.go\
-
-include $(GOROOT)/src/Make.pkg
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
index acace30d6..71da6e22b 100644
--- a/src/pkg/encoding/base32/base32.go
+++ b/src/pkg/encoding/base32/base32.go
@@ -7,7 +7,6 @@ package base32
import (
"io"
- "os"
"strconv"
)
@@ -126,8 +125,15 @@ func (enc *Encoding) Encode(dst, src []byte) {
}
}
+// EncodeToString returns the base32 encoding of src.
+func (enc *Encoding) EncodeToString(src []byte) string {
+ buf := make([]byte, enc.EncodedLen(len(src)))
+ enc.Encode(buf, src)
+ return string(buf)
+}
+
type encoder struct {
- err os.Error
+ err error
enc *Encoding
w io.Writer
buf [5]byte // buffered data waiting to be encoded
@@ -135,7 +141,7 @@ type encoder struct {
out [1024]byte // output buffer
}
-func (e *encoder) Write(p []byte) (n int, err os.Error) {
+func (e *encoder) Write(p []byte) (n int, err error) {
if e.err != nil {
return 0, e.err
}
@@ -187,7 +193,7 @@ func (e *encoder) Write(p []byte) (n int, err os.Error) {
// Close flushes any pending output from the encoder.
// It is an error to call Write after calling Close.
-func (e *encoder) Close() os.Error {
+func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
@@ -216,30 +222,38 @@ func (enc *Encoding) EncodedLen(n int) int { return (n + 4) / 5 * 8 }
type CorruptInputError int64
-func (e CorruptInputError) String() string {
- return "illegal base32 data at input byte " + strconv.Itoa64(int64(e))
+func (e CorruptInputError) Error() string {
+ return "illegal base32 data at input byte " + strconv.FormatInt(int64(e), 10)
}
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error. decode also assumes len(src)%8==0,
-// since it is meant for internal use.
-func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
- for i := 0; i < len(src)/8 && !end; i++ {
+// additional data is an error.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
+ osrc := src
+ for len(src) > 0 && !end {
// Decode quantum using the base32 alphabet
var dbuf [8]byte
dlen := 8
// do the top bytes contain any data?
dbufloop:
- for j := 0; j < 8; j++ {
- in := src[i*8+j]
- if in == '=' && j >= 2 && i == len(src)/8-1 {
+ for j := 0; j < 8; {
+ if len(src) == 0 {
+ return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ }
+ in := src[0]
+ src = src[1:]
+ if in == '\r' || in == '\n' {
+ // Ignore this character.
+ continue
+ }
+ if in == '=' && j >= 2 && len(src) < 8 {
// We've reached the end and there's
// padding, the rest should be padded
- for k := j; k < 8; k++ {
- if src[i*8+k] != '=' {
- return n, false, CorruptInputError(i*8 + j)
+ for k := 0; k < 8-j-1; k++ {
+ if len(src) > k && src[k] != '=' {
+ return n, false, CorruptInputError(len(osrc) - len(src) + k - 1)
}
}
dlen = j
@@ -248,28 +262,30 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(i*8 + j)
+ return n, false, CorruptInputError(len(osrc) - len(src) - 1)
}
+ j++
}
// Pack 8x 5-bit source blocks into 5 byte destination
// quantum
switch dlen {
case 7, 8:
- dst[i*5+4] = dbuf[6]<<5 | dbuf[7]
+ dst[4] = dbuf[6]<<5 | dbuf[7]
fallthrough
case 6, 5:
- dst[i*5+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
+ dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
fallthrough
case 4:
- dst[i*5+2] = dbuf[3]<<4 | dbuf[4]>>1
+ dst[2] = dbuf[3]<<4 | dbuf[4]>>1
fallthrough
case 3:
- dst[i*5+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
+ dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
fallthrough
case 2:
- dst[i*5+0] = dbuf[0]<<3 | dbuf[1]>>2
+ dst[0] = dbuf[0]<<3 | dbuf[1]>>2
}
+ dst = dst[5:]
switch dlen {
case 2:
n += 1
@@ -290,17 +306,21 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
// DecodedLen(len(src)) bytes to dst and returns the number of bytes
// written. If src contains invalid base32 data, it will return the
// number of bytes successfully written and CorruptInputError.
-func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
- if len(src)%8 != 0 {
- return 0, CorruptInputError(len(src) / 8 * 8)
- }
-
+// New line characters (\r and \n) are ignored.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
n, _, err = enc.decode(dst, src)
return
}
+// DecodeString returns the bytes represented by the base32 string s.
+func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+ dbuf := make([]byte, enc.DecodedLen(len(s)))
+ n, err := enc.Decode(dbuf, []byte(s))
+ return dbuf[:n], err
+}
+
type decoder struct {
- err os.Error
+ err error
enc *Encoding
r io.Reader
end bool // saw end of message
@@ -310,7 +330,7 @@ type decoder struct {
outbuf [1024 / 8 * 5]byte
}
-func (d *decoder) Read(p []byte) (n int, err os.Error) {
+func (d *decoder) Read(p []byte) (n int, err error) {
if d.err != nil {
return 0, d.err
}
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 3fa1c2b26..98365e18c 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -6,8 +6,8 @@ package base32
import (
"bytes"
+ "io"
"io/ioutil"
- "os"
"testing"
)
@@ -51,9 +51,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
func TestEncode(t *testing.T) {
for _, p := range pairs {
- buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
- StdEncoding.Encode(buf, []byte(p.decoded))
- testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ got := StdEncoding.EncodeToString([]byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
}
}
@@ -78,11 +77,11 @@ func TestEncoderBuffering(t *testing.T) {
end = len(input)
}
n, err := encoder.Write(input[pos:end])
- testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
}
err := encoder.Close()
- testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Close gave error %v, want %v", err, error(nil))
testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
}
}
@@ -91,7 +90,7 @@ func TestDecode(t *testing.T) {
for _, p := range pairs {
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
- testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
if len(p.encoded) > 0 {
testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
@@ -99,6 +98,10 @@ func TestDecode(t *testing.T) {
testEqual(t, "Decode(%q) = %q, want %q", p.encoded,
string(dbuf[0:count]),
p.decoded)
+
+ dbuf, err = StdEncoding.DecodeString(p.encoded)
+ testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
+ testEqual(t, "DecodeString(%q) = %q, want %q", p.encoded, string(dbuf), p.decoded)
}
}
@@ -107,15 +110,15 @@ func TestDecoder(t *testing.T) {
decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
- if err != nil && err != os.EOF {
+ if err != nil && err != io.EOF {
t.Fatal("Read failed", err)
}
testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
- if err != os.EOF {
+ if err != io.EOF {
count, err = decoder.Read(dbuf)
}
- testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
}
}
@@ -126,7 +129,7 @@ func TestDecoderBuffering(t *testing.T) {
var total int
for total = 0; total < len(bigtest.decoded); {
n, err := decoder.Read(buf[total : total+bs])
- testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, error(nil))
total += n
}
testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
@@ -191,3 +194,29 @@ func TestBig(t *testing.T) {
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}
+
+func TestNewLineCharacters(t *testing.T) {
+ // Each of these should decode to the string "sure", without errors.
+ const expected = "sure"
+ examples := []string{
+ "ON2XEZI=",
+ "ON2XEZI=\r",
+ "ON2XEZI=\n",
+ "ON2XEZI=\r\n",
+ "ON2XEZ\r\nI=",
+ "ON2X\rEZ\nI=",
+ "ON2X\nEZ\rI=",
+ "ON2XEZ\nI=",
+ "ON2XEZI\n=",
+ }
+ for _, e := range examples {
+ buf, err := StdEncoding.DecodeString(e)
+ if err != nil {
+ t.Errorf("Decode(%q) failed: %v", e, err)
+ continue
+ }
+ if s := string(buf); s != expected {
+ t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
+ }
+ }
+}
diff --git a/src/pkg/encoding/base64/Makefile b/src/pkg/encoding/base64/Makefile
deleted file mode 100644
index 2f54ed839..000000000
--- a/src/pkg/encoding/base64/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/base64
-GOFILES=\
- base64.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
index c6b2a13e4..55f9f67a4 100644
--- a/src/pkg/encoding/base64/base64.go
+++ b/src/pkg/encoding/base64/base64.go
@@ -7,7 +7,6 @@ package base64
import (
"io"
- "os"
"strconv"
)
@@ -114,7 +113,7 @@ func (enc *Encoding) EncodeToString(src []byte) string {
}
type encoder struct {
- err os.Error
+ err error
enc *Encoding
w io.Writer
buf [3]byte // buffered data waiting to be encoded
@@ -122,7 +121,7 @@ type encoder struct {
out [1024]byte // output buffer
}
-func (e *encoder) Write(p []byte) (n int, err os.Error) {
+func (e *encoder) Write(p []byte) (n int, err error) {
if e.err != nil {
return 0, e.err
}
@@ -174,7 +173,7 @@ func (e *encoder) Write(p []byte) (n int, err os.Error) {
// Close flushes any pending output from the encoder.
// It is an error to call Write after calling Close.
-func (e *encoder) Close() os.Error {
+func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
@@ -203,28 +202,36 @@ func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
type CorruptInputError int64
-func (e CorruptInputError) String() string {
- return "illegal base64 data at input byte " + strconv.Itoa64(int64(e))
+func (e CorruptInputError) Error() string {
+ return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error. decode also assumes len(src)%4==0,
-// since it is meant for internal use.
-func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
- for i := 0; i < len(src)/4 && !end; i++ {
+// additional data is an error.
+func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
+ osrc := src
+ for len(src) > 0 && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
dlen := 4
dbufloop:
- for j := 0; j < 4; j++ {
- in := src[i*4+j]
- if in == '=' && j >= 2 && i == len(src)/4-1 {
+ for j := 0; j < 4; {
+ if len(src) == 0 {
+ return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ }
+ in := src[0]
+ src = src[1:]
+ if in == '\r' || in == '\n' {
+ // Ignore this character.
+ continue
+ }
+ if in == '=' && j >= 2 && len(src) < 4 {
// We've reached the end and there's
// padding
- if src[i*4+3] != '=' {
- return n, false, CorruptInputError(i*4 + 2)
+ if len(src) > 0 && src[0] != '=' {
+ return n, false, CorruptInputError(len(osrc) - len(src) - 1)
}
dlen = j
end = true
@@ -232,22 +239,24 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(i*4 + j)
+ return n, false, CorruptInputError(len(osrc) - len(src) - 1)
}
+ j++
}
// Pack 4x 6-bit source blocks into 3 byte destination
// quantum
switch dlen {
case 4:
- dst[i*3+2] = dbuf[2]<<6 | dbuf[3]
+ dst[2] = dbuf[2]<<6 | dbuf[3]
fallthrough
case 3:
- dst[i*3+1] = dbuf[1]<<4 | dbuf[2]>>2
+ dst[1] = dbuf[1]<<4 | dbuf[2]>>2
fallthrough
case 2:
- dst[i*3+0] = dbuf[0]<<2 | dbuf[1]>>4
+ dst[0] = dbuf[0]<<2 | dbuf[1]>>4
}
+ dst = dst[3:]
n += dlen - 1
}
@@ -258,24 +267,21 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) {
// DecodedLen(len(src)) bytes to dst and returns the number of bytes
// written. If src contains invalid base64 data, it will return the
// number of bytes successfully written and CorruptInputError.
-func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
- if len(src)%4 != 0 {
- return 0, CorruptInputError(len(src) / 4 * 4)
- }
-
+// New line characters (\r and \n) are ignored.
+func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base64 string s.
-func (enc *Encoding) DecodeString(s string) ([]byte, os.Error) {
+func (enc *Encoding) DecodeString(s string) ([]byte, error) {
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
}
type decoder struct {
- err os.Error
+ err error
enc *Encoding
r io.Reader
end bool // saw end of message
@@ -285,7 +291,7 @@ type decoder struct {
outbuf [1024 / 4 * 3]byte
}
-func (d *decoder) Read(p []byte) (n int, err os.Error) {
+func (d *decoder) Read(p []byte) (n int, err error) {
if d.err != nil {
return 0, d.err
}
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index c163dae84..3e9a84393 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -6,8 +6,8 @@ package base64
import (
"bytes"
+ "io"
"io/ioutil"
- "os"
"testing"
)
@@ -82,11 +82,11 @@ func TestEncoderBuffering(t *testing.T) {
end = len(input)
}
n, err := encoder.Write(input[pos:end])
- testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
+ testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil))
testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
}
err := encoder.Close()
- testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
+ testEqual(t, "Close gave error %v, want %v", err, error(nil))
testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded)
}
}
@@ -95,7 +95,7 @@ func TestDecode(t *testing.T) {
for _, p := range pairs {
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
- testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
if len(p.encoded) > 0 {
testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
@@ -103,7 +103,7 @@ func TestDecode(t *testing.T) {
testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
dbuf, err = StdEncoding.DecodeString(p.encoded)
- testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
}
}
@@ -113,15 +113,15 @@ func TestDecoder(t *testing.T) {
decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
count, err := decoder.Read(dbuf)
- if err != nil && err != os.EOF {
+ if err != nil && err != io.EOF {
t.Fatal("Read failed", err)
}
testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded))
testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
- if err != os.EOF {
+ if err != io.EOF {
count, err = decoder.Read(dbuf)
}
- testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
+ testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF)
}
}
@@ -132,7 +132,7 @@ func TestDecoderBuffering(t *testing.T) {
var total int
for total = 0; total < len(bigtest.decoded); {
n, err := decoder.Read(buf[total : total+bs])
- testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil))
+ testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, error(nil))
total += n
}
testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded)
@@ -197,3 +197,29 @@ func TestBig(t *testing.T) {
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}
+
+func TestNewLineCharacters(t *testing.T) {
+ // Each of these should decode to the string "sure", without errors.
+ const expected = "sure"
+ examples := []string{
+ "c3VyZQ==",
+ "c3VyZQ==\r",
+ "c3VyZQ==\n",
+ "c3VyZQ==\r\n",
+ "c3VyZ\r\nQ==",
+ "c3V\ryZ\nQ==",
+ "c3V\nyZ\rQ==",
+ "c3VyZ\nQ==",
+ "c3VyZQ\n==",
+ }
+ for _, e := range examples {
+ buf, err := StdEncoding.DecodeString(e)
+ if err != nil {
+ t.Errorf("Decode(%q) failed: %v", e, err)
+ continue
+ }
+ if s := string(buf); s != expected {
+ t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
+ }
+ }
+}
diff --git a/src/pkg/encoding/binary/Makefile b/src/pkg/encoding/binary/Makefile
deleted file mode 100644
index dc46abe90..000000000
--- a/src/pkg/encoding/binary/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/binary
-GOFILES=\
- binary.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index 8e55cb23b..712e490e6 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -2,41 +2,45 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package binary implements translation between
-// unsigned integer values and byte sequences
-// and the reading and writing of fixed-size values.
+// Package binary implements translation between numbers and byte sequences
+// and encoding and decoding of varints.
+//
+// Numbers are translated by reading and writing fixed-size values.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+//
+// Varints are a method of encoding integers using one or more bytes;
+// numbers with smaller absolute value take a smaller number of bytes.
+// For a specification, see http://code.google.com/apis/protocolbuffers/docs/encoding.html.
package binary
import (
- "math"
+ "errors"
"io"
- "os"
+ "math"
"reflect"
)
// A ByteOrder specifies how to convert byte sequences into
// 16-, 32-, or 64-bit unsigned integers.
type ByteOrder interface {
- Uint16(b []byte) uint16
- Uint32(b []byte) uint32
- Uint64(b []byte) uint64
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ Uint64([]byte) uint64
PutUint16([]byte, uint16)
PutUint32([]byte, uint32)
PutUint64([]byte, uint64)
String() string
}
-// This is byte instead of struct{} so that it can be compared,
-// allowing, e.g., order == binary.LittleEndian.
-type unused byte
-
// LittleEndian is the little-endian implementation of ByteOrder.
var LittleEndian littleEndian
// BigEndian is the big-endian implementation of ByteOrder.
var BigEndian bigEndian
-type littleEndian unused
+type littleEndian struct{}
func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
@@ -76,7 +80,7 @@ func (littleEndian) String() string { return "LittleEndian" }
func (littleEndian) GoString() string { return "binary.LittleEndian" }
-type bigEndian unused
+type bigEndian struct{}
func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
@@ -119,12 +123,9 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// Read reads structured binary data from r into data.
// Data must be a pointer to a fixed-size value or a slice
// of fixed-size values.
-// A fixed-size value is either a fixed-size arithmetic
-// type (int8, uint8, int16, float32, complex64, ...)
-// or an array or struct containing only fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
-func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
+func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types.
if n := intDestSize(data); n != 0 {
var b [8]byte
@@ -161,11 +162,11 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
case reflect.Slice:
v = d
default:
- return os.NewError("binary.Read: invalid type " + d.Type().String())
+ return errors.New("binary.Read: invalid type " + d.Type().String())
}
- size := TotalSize(v)
+ size := dataSize(v)
if size < 0 {
- return os.NewError("binary.Read: invalid type " + v.Type().String())
+ return errors.New("binary.Read: invalid type " + v.Type().String())
}
d := &decoder{order: order, buf: make([]byte, size)}
if _, err := io.ReadFull(r, d.buf); err != nil {
@@ -176,14 +177,11 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
}
// Write writes the binary representation of data into w.
-// Data must be a fixed-size value or a pointer to
-// a fixed-size value.
-// A fixed-size value is either a fixed-size arithmetic
-// type (int8, uint8, int16, float32, complex64, ...)
-// or an array or struct containing only fixed-size values.
+// Data must be a fixed-size value or a slice of fixed-size
+// values, or a pointer to such data.
// 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 {
+func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fast path for basic types.
var b [8]byte
var bs []byte
@@ -242,9 +240,9 @@ func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
return err
}
v := reflect.Indirect(reflect.ValueOf(data))
- size := TotalSize(v)
+ size := dataSize(v)
if size < 0 {
- return os.NewError("binary.Write: invalid type " + v.Type().String())
+ return errors.New("binary.Write: invalid type " + v.Type().String())
}
buf := make([]byte, size)
e := &encoder{order: order, buf: buf}
@@ -253,7 +251,17 @@ func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
return err
}
-func TotalSize(v reflect.Value) int {
+// Size returns how many bytes Write would generate to encode the value v, which
+// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
+func Size(v interface{}) int {
+ return dataSize(reflect.Indirect(reflect.ValueOf(v)))
+}
+
+// dataSize returns the number of bytes the actual data represented by v occupies in memory.
+// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
+// it returns the length of the slice times the element size and does not count the memory
+// occupied by the header.
+func dataSize(v reflect.Value) int {
if v.Kind() == reflect.Slice {
elem := sizeof(v.Type().Elem())
if elem < 0 {
@@ -369,6 +377,7 @@ func (d *decoder) value(v reflect.Value) {
for i := 0; i < l; i++ {
d.value(v.Index(i))
}
+
case reflect.Struct:
l := v.NumField()
for i := 0; i < l; i++ {
@@ -424,11 +433,13 @@ func (e *encoder) value(v reflect.Value) {
for i := 0; i < l; i++ {
e.value(v.Index(i))
}
+
case reflect.Struct:
l := v.NumField()
for i := 0; i < l; i++ {
e.value(v.Field(i))
}
+
case reflect.Slice:
l := v.Len()
for i := 0; i < l; i++ {
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index b266996f6..ff361b7e3 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -5,9 +5,8 @@
package binary
import (
- "io"
- "os"
"bytes"
+ "io"
"math"
"reflect"
"testing"
@@ -99,7 +98,7 @@ var little = []byte{
var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
var res = []int32{0x01020304, 0x05060708}
-func checkResult(t *testing.T, dir string, order, err os.Error, have, want interface{}) {
+func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, want interface{}) {
if err != nil {
t.Errorf("%v %v: %v", dir, order, err)
return
@@ -166,17 +165,48 @@ type byteSliceReader struct {
remain []byte
}
-func (br *byteSliceReader) Read(p []byte) (int, os.Error) {
+func (br *byteSliceReader) Read(p []byte) (int, error) {
n := copy(p, br.remain)
br.remain = br.remain[n:]
return n, nil
}
-func BenchmarkRead(b *testing.B) {
+func BenchmarkReadSlice1000Int32s(b *testing.B) {
+ bsr := &byteSliceReader{}
+ slice := make([]int32, 1000)
+ buf := make([]byte, len(slice)*4)
+ b.SetBytes(int64(len(buf)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bsr.remain = buf
+ Read(bsr, BigEndian, slice)
+ }
+}
+
+func BenchmarkReadStruct(b *testing.B) {
+ bsr := &byteSliceReader{}
+ var buf bytes.Buffer
+ Write(&buf, BigEndian, &s)
+ n := dataSize(reflect.ValueOf(s))
+ b.SetBytes(int64(n))
+ t := s
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bsr.remain = buf.Bytes()
+ Read(bsr, BigEndian, &t)
+ }
+ b.StopTimer()
+ if !reflect.DeepEqual(s, t) {
+ b.Fatal("no match")
+ }
+}
+
+func BenchmarkReadInts(b *testing.B) {
var ls Struct
bsr := &byteSliceReader{}
var r io.Reader = bsr
-
+ b.SetBytes(2 * (1 + 2 + 4 + 8))
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
bsr.remain = big
Read(r, BigEndian, &ls.Int8)
@@ -197,25 +227,19 @@ func BenchmarkRead(b *testing.B) {
for i := range want.Array {
want.Array[i] = 0
}
+ b.StopTimer()
if !reflect.DeepEqual(ls, want) {
panic("no match")
}
}
-func BenchmarkWrite(b *testing.B) {
+func BenchmarkWriteInts(b *testing.B) {
buf := new(bytes.Buffer)
var w io.Writer = buf
-
+ b.SetBytes(2 * (1 + 2 + 4 + 8))
+ b.ResetTimer()
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)
@@ -225,11 +249,8 @@ func BenchmarkWrite(b *testing.B) {
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")
+ b.StopTimer()
+ if !bytes.Equal(buf.Bytes(), big[:30]) {
+ b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
}
}
diff --git a/src/pkg/encoding/binary/example_test.go b/src/pkg/encoding/binary/example_test.go
new file mode 100644
index 000000000..dec12ebf5
--- /dev/null
+++ b/src/pkg/encoding/binary/example_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 binary_test
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math"
+)
+
+func ExampleWrite() {
+ buf := new(bytes.Buffer)
+ var pi float64 = math.Pi
+ err := binary.Write(buf, binary.LittleEndian, pi)
+ if err != nil {
+ fmt.Println("binary.Write failed:", err)
+ }
+ fmt.Printf("% x", buf.Bytes())
+ // Output: 18 2d 44 54 fb 21 09 40
+}
+
+func ExampleWrite_multi() {
+ buf := new(bytes.Buffer)
+ var data = []interface{}{
+ uint16(61374),
+ int8(-54),
+ uint8(254),
+ }
+ for _, v := range data {
+ err := binary.Write(buf, binary.LittleEndian, v)
+ if err != nil {
+ fmt.Println("binary.Write failed:", err)
+ }
+ }
+ fmt.Printf("%x", buf.Bytes())
+ // Output: beefcafe
+}
+
+func ExampleRead() {
+ var pi float64
+ b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
+ buf := bytes.NewBuffer(b)
+ err := binary.Read(buf, binary.LittleEndian, &pi)
+ if err != nil {
+ fmt.Println("binary.Read failed:", err)
+ }
+ fmt.Print(pi)
+ // Output: 3.141592653589793
+}
diff --git a/src/pkg/encoding/binary/varint.go b/src/pkg/encoding/binary/varint.go
new file mode 100644
index 000000000..b756afdd0
--- /dev/null
+++ b/src/pkg/encoding/binary/varint.go
@@ -0,0 +1,134 @@
+// 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 binary
+
+// This file implements "varint" encoding of 64-bit integers.
+// The encoding is:
+// - unsigned integers are serialized 7 bits at a time, starting with the
+// least significant bits
+// - the most significant bit (msb) in each output byte indicates if there
+// is a continuation byte (msb = 1)
+// - signed integers are mapped to unsigned integers using "zig-zag"
+// encoding: Positive values x are written as 2*x + 0, negative values
+// are written as 2*(^x) + 1; that is, negative numbers are complemented
+// and whether to complement is encoded in bit 0.
+//
+// Design note:
+// At most 10 bytes are needed for 64-bit values. The encoding could
+// be more dense: a full 64-bit value needs an extra byte just to hold bit 63.
+// Instead, the msb of the previous byte could be used to hold bit 63 since we
+// know there can't be more than 64 bits. This is a trivial improvement and
+// would reduce the maximum encoding length to 9 bytes. However, it breaks the
+// invariant that the msb is always the "continuation bit" and thus makes the
+// format incompatible with a varint encoding for larger numbers (say 128-bit).
+
+import (
+ "errors"
+ "io"
+)
+
+// MaxVarintLenN is the maximum length of a varint-encoded N-bit integer.
+const (
+ MaxVarintLen16 = 3
+ MaxVarintLen32 = 5
+ MaxVarintLen64 = 10
+)
+
+// PutUvarint encodes a uint64 into buf and returns the number of bytes written.
+// If the buffer is too small, PutUvarint will panic.
+func PutUvarint(buf []byte, x uint64) int {
+ i := 0
+ for x >= 0x80 {
+ buf[i] = byte(x) | 0x80
+ x >>= 7
+ i++
+ }
+ buf[i] = byte(x)
+ return i + 1
+}
+
+// Uvarint decodes a uint64 from buf and returns that value and the
+// number of bytes read (> 0). If an error occurred, the value is 0
+// and the number of bytes n is <= 0 meaning:
+//
+// n == 0: buf too small
+// n < 0: value larger than 64 bits (overflow)
+// and -n is the number of bytes read
+//
+func Uvarint(buf []byte) (uint64, int) {
+ var x uint64
+ var s uint
+ for i, b := range buf {
+ if b < 0x80 {
+ if i > 9 || i == 9 && b > 1 {
+ return 0, -(i + 1) // overflow
+ }
+ return x | uint64(b)<<s, i + 1
+ }
+ x |= uint64(b&0x7f) << s
+ s += 7
+ }
+ return 0, 0
+}
+
+// PutVarint encodes an int64 into buf and returns the number of bytes written.
+// If the buffer is too small, PutVarint will panic.
+func PutVarint(buf []byte, x int64) int {
+ ux := uint64(x) << 1
+ if x < 0 {
+ ux = ^ux
+ }
+ return PutUvarint(buf, ux)
+}
+
+// Varint decodes an int64 from buf and returns that value and the
+// number of bytes read (> 0). If an error occurred, the value is 0
+// and the number of bytes n is <= 0 with the following meaning:
+//
+// n == 0: buf too small
+// n < 0: value larger than 64 bits (overflow)
+// and -n is the number of bytes read
+//
+func Varint(buf []byte) (int64, int) {
+ ux, n := Uvarint(buf) // ok to continue in presence of error
+ x := int64(ux >> 1)
+ if ux&1 != 0 {
+ x = ^x
+ }
+ return x, n
+}
+
+var overflow = errors.New("binary: varint overflows a 64-bit integer")
+
+// ReadUvarint reads an encoded unsigned integer from r and returns it as a uint64.
+func ReadUvarint(r io.ByteReader) (uint64, error) {
+ var x uint64
+ var s uint
+ for i := 0; ; i++ {
+ b, err := r.ReadByte()
+ if err != nil {
+ return x, err
+ }
+ if b < 0x80 {
+ if i > 9 || i == 9 && b > 1 {
+ return x, overflow
+ }
+ return x | uint64(b)<<s, nil
+ }
+ x |= uint64(b&0x7f) << s
+ s += 7
+ }
+ panic("unreachable")
+}
+
+// ReadVarint reads an encoded unsigned integer from r and returns it as a uint64.
+func ReadVarint(r io.ByteReader) (int64, error) {
+ ux, err := ReadUvarint(r) // ok to continue in presence of error
+ x := int64(ux >> 1)
+ if ux&1 != 0 {
+ x = ^x
+ }
+ return x, err
+}
diff --git a/src/pkg/encoding/binary/varint_test.go b/src/pkg/encoding/binary/varint_test.go
new file mode 100644
index 000000000..9476bd5fb
--- /dev/null
+++ b/src/pkg/encoding/binary/varint_test.go
@@ -0,0 +1,168 @@
+// 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 binary
+
+import (
+ "bytes"
+ "io"
+ "testing"
+)
+
+func testConstant(t *testing.T, w uint, max int) {
+ buf := make([]byte, MaxVarintLen64)
+ n := PutUvarint(buf, 1<<w-1)
+ if n != max {
+ t.Errorf("MaxVarintLen%d = %d; want %d", w, max, n)
+ }
+}
+
+func TestConstants(t *testing.T) {
+ testConstant(t, 16, MaxVarintLen16)
+ testConstant(t, 32, MaxVarintLen32)
+ testConstant(t, 64, MaxVarintLen64)
+}
+
+func testVarint(t *testing.T, x int64) {
+ buf := make([]byte, MaxVarintLen64)
+ n := PutVarint(buf, x)
+ y, m := Varint(buf[0:n])
+ if x != y {
+ t.Errorf("Varint(%d): got %d", x, y)
+ }
+ if n != m {
+ t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
+ }
+
+ y, err := ReadVarint(bytes.NewBuffer(buf))
+ if err != nil {
+ t.Errorf("ReadVarint(%d): %s", x, err)
+ }
+ if x != y {
+ t.Errorf("ReadVarint(%d): got %d", x, y)
+ }
+}
+
+func testUvarint(t *testing.T, x uint64) {
+ buf := make([]byte, MaxVarintLen64)
+ n := PutUvarint(buf, x)
+ y, m := Uvarint(buf[0:n])
+ if x != y {
+ t.Errorf("Uvarint(%d): got %d", x, y)
+ }
+ if n != m {
+ t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
+ }
+
+ y, err := ReadUvarint(bytes.NewBuffer(buf))
+ if err != nil {
+ t.Errorf("ReadUvarint(%d): %s", x, err)
+ }
+ if x != y {
+ t.Errorf("ReadUvarint(%d): got %d", x, y)
+ }
+}
+
+var tests = []int64{
+ -1 << 63,
+ -1<<63 + 1,
+ -1,
+ 0,
+ 1,
+ 2,
+ 10,
+ 20,
+ 63,
+ 64,
+ 65,
+ 127,
+ 128,
+ 129,
+ 255,
+ 256,
+ 257,
+ 1<<63 - 1,
+}
+
+func TestVarint(t *testing.T) {
+ for _, x := range tests {
+ testVarint(t, x)
+ testVarint(t, -x)
+ }
+ for x := int64(0x7); x != 0; x <<= 1 {
+ testVarint(t, x)
+ testVarint(t, -x)
+ }
+}
+
+func TestUvarint(t *testing.T) {
+ for _, x := range tests {
+ testUvarint(t, uint64(x))
+ }
+ for x := uint64(0x7); x != 0; x <<= 1 {
+ testUvarint(t, x)
+ }
+}
+
+func TestBufferTooSmall(t *testing.T) {
+ buf := []byte{0x80, 0x80, 0x80, 0x80}
+ for i := 0; i <= len(buf); i++ {
+ buf := buf[0:i]
+ x, n := Uvarint(buf)
+ if x != 0 || n != 0 {
+ t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
+ }
+
+ x, err := ReadUvarint(bytes.NewBuffer(buf))
+ if x != 0 || err != io.EOF {
+ t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
+ }
+ }
+}
+
+func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) {
+ x, n := Uvarint(buf)
+ if x != 0 || n != n0 {
+ t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
+ }
+
+ x, err := ReadUvarint(bytes.NewBuffer(buf))
+ if x != 0 || err != err0 {
+ t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
+ }
+}
+
+func TestOverflow(t *testing.T) {
+ testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, -10, overflow)
+ testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, -13, overflow)
+}
+
+func TestNonCanonicalZero(t *testing.T) {
+ buf := []byte{0x80, 0x80, 0x80, 0}
+ x, n := Uvarint(buf)
+ if x != 0 || n != 4 {
+ t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, 4", buf, x, n)
+
+ }
+}
+
+func BenchmarkPutUvarint32(b *testing.B) {
+ buf := make([]byte, MaxVarintLen32)
+ b.SetBytes(4)
+ for i := 0; i < b.N; i++ {
+ for j := uint(0); j < MaxVarintLen32; j++ {
+ PutUvarint(buf, 1<<(j*7))
+ }
+ }
+}
+
+func BenchmarkPutUvarint64(b *testing.B) {
+ buf := make([]byte, MaxVarintLen64)
+ b.SetBytes(8)
+ for i := 0; i < b.N; i++ {
+ for j := uint(0); j < MaxVarintLen64; j++ {
+ PutUvarint(buf, 1<<(j*7))
+ }
+ }
+}
diff --git a/src/pkg/csv/reader.go b/src/pkg/encoding/csv/reader.go
index ea2c266a4..db4d98852 100644
--- a/src/pkg/csv/reader.go
+++ b/src/pkg/encoding/csv/reader.go
@@ -52,30 +52,30 @@ package csv
import (
"bufio"
"bytes"
+ "errors"
"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
+ Line int // Line where the error occurred
+ Column int // Column (rune index) where the error occurred
+ Err error // The actual error
}
-func (e *ParseError) String() string {
- return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Error)
+func (e *ParseError) Error() string {
+ return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Err)
}
// 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")
+ ErrTrailingComma = errors.New("extra delimiter at end of line")
+ ErrBareQuote = errors.New("bare \" in non-quoted-field")
+ ErrQuote = errors.New("extraneous \" in field")
+ ErrFieldCount = errors.New("wrong number of fields in line")
)
// A Reader reads records from a CSV-encoded file.
@@ -92,7 +92,8 @@ var (
// 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.
+// have the same field count. If FieldsPerRecord is negative, no check is
+// made and records may have a variable number of fields.
//
// If LazyQuotes is true, a quote may appear in an unquoted field and a
// non-doubled quote may appear in a quoted field.
@@ -101,8 +102,8 @@ var (
//
// 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
+ Comma rune // Field delimiter (set to ',' by NewReader)
+ Comment rune // Comment character for start of line
FieldsPerRecord int // Number of expected fields per record
LazyQuotes bool // Allow lazy quotes
TrailingComma bool // Allow trailing comma
@@ -122,17 +123,17 @@ func NewReader(r io.Reader) *Reader {
}
// error creates a new ParseError based on err.
-func (r *Reader) error(err os.Error) os.Error {
+func (r *Reader) error(err error) error {
return &ParseError{
Line: r.line,
Column: r.column,
- Error: err,
+ Err: 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) {
+func (r *Reader) Read() (record []string, err error) {
for {
record, err = r.parseRecord()
if record != nil {
@@ -156,10 +157,13 @@ func (r *Reader) Read() (record []string, err os.Error) {
// ReadAll reads all the remaining records from r.
// Each record is a slice of fields.
-func (r *Reader) ReadAll() (records [][]string, err os.Error) {
+// A successful call returns err == nil, not err == EOF. Because ReadAll is
+// defined to read until EOF, it does not treat end of file as an error to be
+// reported.
+func (r *Reader) ReadAll() (records [][]string, err error) {
for {
record, err := r.Read()
- if err == os.EOF {
+ if err == io.EOF {
return records, nil
}
if err != nil {
@@ -173,23 +177,23 @@ func (r *Reader) ReadAll() (records [][]string, err os.Error) {
// 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()
+func (r *Reader) readRune() (rune, error) {
+ r1, _, 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 r1 == '\r' {
+ r1, _, err = r.r.ReadRune()
if err == nil {
- if rune != '\n' {
+ if r1 != '\n' {
r.r.UnreadRune()
- rune = '\r'
+ r1 = '\r'
}
}
}
r.column++
- return rune, err
+ return r1, err
}
// unreadRune puts the last rune read from r back.
@@ -199,13 +203,13 @@ func (r *Reader) unreadRune() {
}
// skip reads runes up to and including the rune delim or until error.
-func (r *Reader) skip(delim int) os.Error {
+func (r *Reader) skip(delim rune) error {
for {
- rune, err := r.readRune()
+ r1, err := r.readRune()
if err != nil {
return err
}
- if rune == delim {
+ if r1 == delim {
return nil
}
}
@@ -213,7 +217,7 @@ func (r *Reader) skip(delim int) os.Error {
}
// parseRecord reads and parses a single csv record from r.
-func (r *Reader) parseRecord() (fields []string, err os.Error) {
+func (r *Reader) parseRecord() (fields []string, err 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.
@@ -224,12 +228,12 @@ func (r *Reader) parseRecord() (fields []string, err os.Error) {
// If we are support comments and it is the comment character
// then skip to the end of line.
- rune, _, err := r.r.ReadRune()
+ r1, _, err := r.r.ReadRune()
if err != nil {
return nil, err
}
- if r.Comment != 0 && rune == r.Comment {
+ if r.Comment != 0 && r1 == r.Comment {
return nil, r.skip('\n')
}
r.r.UnreadRune()
@@ -240,7 +244,7 @@ func (r *Reader) parseRecord() (fields []string, err os.Error) {
if haveField {
fields = append(fields, r.field.String())
}
- if delim == '\n' || err == os.EOF {
+ if delim == '\n' || err == io.EOF {
return fields, err
} else if err != nil {
return nil, err
@@ -252,47 +256,47 @@ func (r *Reader) parseRecord() (fields []string, err os.Error) {
// 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) {
+func (r *Reader) parseField() (haveField bool, delim rune, err error) {
r.field.Reset()
- rune, err := r.readRune()
+ r1, 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 {
+ if err == io.EOF && r.column != 0 {
return true, 0, err
}
return false, 0, err
}
if r.TrimLeadingSpace {
- for unicode.IsSpace(rune) {
- rune, err = r.readRune()
+ for r1 != '\n' && unicode.IsSpace(r1) {
+ r1, err = r.readRune()
if err != nil {
return false, 0, err
}
}
}
- switch rune {
+ switch r1 {
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 false, r1, nil
}
- return true, rune, nil
+ return true, r1, nil
case '"':
// quoted field
Quoted:
for {
- rune, err = r.readRune()
+ r1, err = r.readRune()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
if r.LazyQuotes {
return true, 0, err
}
@@ -300,16 +304,16 @@ func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
}
return false, 0, err
}
- switch rune {
+ switch r1 {
case '"':
- rune, err = r.readRune()
- if err != nil || rune == r.Comma {
+ r1, err = r.readRune()
+ if err != nil || r1 == r.Comma {
break Quoted
}
- if rune == '\n' {
- return true, rune, nil
+ if r1 == '\n' {
+ return true, r1, nil
}
- if rune != '"' {
+ if r1 != '"' {
if !r.LazyQuotes {
r.column--
return false, 0, r.error(ErrQuote)
@@ -321,28 +325,28 @@ func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
r.line++
r.column = -1
}
- r.field.WriteRune(rune)
+ r.field.WriteRune(r1)
}
default:
// unquoted field
for {
- r.field.WriteRune(rune)
- rune, err = r.readRune()
- if err != nil || rune == r.Comma {
+ r.field.WriteRune(r1)
+ r1, err = r.readRune()
+ if err != nil || r1 == r.Comma {
break
}
- if rune == '\n' {
- return true, rune, nil
+ if r1 == '\n' {
+ return true, r1, nil
}
- if !r.LazyQuotes && rune == '"' {
+ if !r.LazyQuotes && r1 == '"' {
return false, 0, r.error(ErrBareQuote)
}
}
}
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
return true, 0, err
}
return false, 0, err
@@ -353,20 +357,20 @@ func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
// are at the end of the line (being mindful
// of trimming spaces).
c := r.column
- rune, err = r.readRune()
+ r1, err = r.readRune()
if r.TrimLeadingSpace {
- for unicode.IsSpace(rune) {
- rune, err = r.readRune()
+ for r1 != '\n' && unicode.IsSpace(r1) {
+ r1, err = r.readRune()
if err != nil {
break
}
}
}
- if err == os.EOF || rune == '\n' {
+ if err == io.EOF || r1 == '\n' {
r.column = c // report the comma
return false, 0, r.error(ErrTrailingComma)
}
r.unreadRune()
}
- return true, rune, nil
+ return true, r1, nil
}
diff --git a/src/pkg/csv/reader_test.go b/src/pkg/encoding/csv/reader_test.go
index 0068bad1d..5fd84a76b 100644
--- a/src/pkg/csv/reader_test.go
+++ b/src/pkg/encoding/csv/reader_test.go
@@ -17,8 +17,8 @@ var readTests = []struct {
UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
// These fields are copied into the Reader
- Comma int
- Comment int
+ Comma rune
+ Comment rune
FieldsPerRecord int
LazyQuotes bool
TrailingComma bool
@@ -127,10 +127,9 @@ field"`,
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: "BadDoubleQuotes",
+ Input: `a""b,c`,
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
},
{
Name: "TrimQuote",
@@ -231,6 +230,23 @@ x,,,
{"", "", "", ""},
},
},
+ {
+ Name: "Issue 2366",
+ TrailingComma: true,
+ TrimLeadingSpace: true,
+ Input: "a,b,\nc,d,e",
+ Output: [][]string{
+ {"a", "b", ""},
+ {"c", "d", "e"},
+ },
+ },
+ {
+ Name: "Issue 2366a",
+ TrailingComma: false,
+ TrimLeadingSpace: true,
+ Input: "a,b,\nc,d,e",
+ Error: "extra delimiter at end of line",
+ },
}
func TestRead(t *testing.T) {
@@ -251,7 +267,7 @@ func TestRead(t *testing.T) {
out, err := r.ReadAll()
perr, _ := err.(*ParseError)
if tt.Error != "" {
- if err == nil || !strings.Contains(err.String(), tt.Error) {
+ if err == nil || !strings.Contains(err.Error(), 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)
diff --git a/src/pkg/csv/writer.go b/src/pkg/encoding/csv/writer.go
index ccf703f0f..c4dcba566 100644
--- a/src/pkg/csv/writer.go
+++ b/src/pkg/encoding/csv/writer.go
@@ -7,10 +7,9 @@ package csv
import (
"bufio"
"io"
- "os"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// A Writer writes records to a CSV encoded file.
@@ -23,7 +22,7 @@ import (
//
// 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)
+ Comma rune // Field delimiter (set to to ',' by NewWriter)
UseCRLF bool // True to use \r\n as the line terminator
w *bufio.Writer
}
@@ -38,7 +37,7 @@ func NewWriter(w io.Writer) *Writer {
// 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) {
+func (w *Writer) Write(record []string) (err error) {
for n, field := range record {
if n > 0 {
if _, err = w.w.WriteRune(w.Comma); err != nil {
@@ -58,8 +57,8 @@ func (w *Writer) Write(record []string) (err os.Error) {
return
}
- for _, rune := range field {
- switch rune {
+ for _, r1 := range field {
+ switch r1 {
case '"':
_, err = w.w.WriteString(`""`)
case '\r':
@@ -73,7 +72,7 @@ func (w *Writer) Write(record []string) (err os.Error) {
err = w.w.WriteByte('\n')
}
default:
- _, err = w.w.WriteRune(rune)
+ _, err = w.w.WriteRune(r1)
}
if err != nil {
return
@@ -98,7 +97,7 @@ func (w *Writer) Flush() {
}
// WriteAll writes multiple CSV records to w using Write and then calls Flush.
-func (w *Writer) WriteAll(records [][]string) (err os.Error) {
+func (w *Writer) WriteAll(records [][]string) (err error) {
for _, record := range records {
err = w.Write(record)
if err != nil {
@@ -117,6 +116,6 @@ func (w *Writer) fieldNeedsQuotes(field string) bool {
return true
}
- rune, _ := utf8.DecodeRuneInString(field)
- return unicode.IsSpace(rune)
+ r1, _ := utf8.DecodeRuneInString(field)
+ return unicode.IsSpace(r1)
}
diff --git a/src/pkg/csv/writer_test.go b/src/pkg/encoding/csv/writer_test.go
index 578959007..578959007 100644
--- a/src/pkg/csv/writer_test.go
+++ b/src/pkg/encoding/csv/writer_test.go
diff --git a/src/pkg/encoding/git85/Makefile b/src/pkg/encoding/git85/Makefile
deleted file mode 100644
index fbd003454..000000000
--- a/src/pkg/encoding/git85/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/git85
-GOFILES=\
- git.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/git85/git.go b/src/pkg/encoding/git85/git.go
deleted file mode 100644
index 6bb74f46c..000000000
--- a/src/pkg/encoding/git85/git.go
+++ /dev/null
@@ -1,277 +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 git85 implements the radix 85 data encoding
-// used in the Git version control system.
-package git85
-
-import (
- "bytes"
- "io"
- "os"
- "strconv"
-)
-
-type CorruptInputError int64
-
-func (e CorruptInputError) String() string {
- return "illegal git85 data at input byte " + strconv.Itoa64(int64(e))
-}
-
-const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
-
-// The decodings are 1+ the actual value, so that the
-// default zero value can be used to mean "not valid".
-var decode = [256]uint8{
- '0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
- 'A': 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 'a': 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
- 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
- '!': 63,
- '#': 64, 65, 66, 67,
- '(': 68, 69, 70, 71,
- '-': 72,
- ';': 73,
- '<': 74, 75, 76, 77,
- '@': 78,
- '^': 79, 80, 81,
- '{': 82, 83, 84, 85,
-}
-
-// Encode encodes src into EncodedLen(len(src))
-// bytes of dst. As a convenience, it returns the number
-// of bytes written to dst, but this value is always EncodedLen(len(src)).
-// Encode implements the radix 85 encoding used in the
-// Git version control tool.
-//
-// The encoding splits src into chunks of at most 52 bytes
-// and encodes each chunk on its own line.
-func Encode(dst, src []byte) int {
- ndst := 0
- for len(src) > 0 {
- n := len(src)
- if n > 52 {
- n = 52
- }
- if n <= 27 {
- dst[ndst] = byte('A' + n - 1)
- } else {
- dst[ndst] = byte('a' + n - 26 - 1)
- }
- ndst++
- for i := 0; i < n; i += 4 {
- var v uint32
- for j := 0; j < 4 && i+j < n; j++ {
- v |= uint32(src[i+j]) << uint(24-j*8)
- }
- for j := 4; j >= 0; j-- {
- dst[ndst+j] = encode[v%85]
- v /= 85
- }
- ndst += 5
- }
- dst[ndst] = '\n'
- ndst++
- src = src[n:]
- }
- return ndst
-}
-
-// EncodedLen returns the length of an encoding of n source bytes.
-func EncodedLen(n int) int {
- if n == 0 {
- return 0
- }
- // 5 bytes per 4 bytes of input, rounded up.
- // 2 extra bytes for each line of 52 src bytes, rounded up.
- return (n+3)/4*5 + (n+51)/52*2
-}
-
-var newline = []byte{'\n'}
-
-// Decode decodes src into at most MaxDecodedLen(len(src))
-// bytes, returning the actual number of bytes written to dst.
-//
-// If Decode encounters invalid input, it returns a CorruptInputError.
-//
-func Decode(dst, src []byte) (n int, err os.Error) {
- ndst := 0
- nsrc := 0
- for nsrc < len(src) {
- var l int
- switch ch := int(src[nsrc]); {
- case 'A' <= ch && ch <= 'Z':
- l = ch - 'A' + 1
- case 'a' <= ch && ch <= 'z':
- l = ch - 'a' + 26 + 1
- default:
- return ndst, CorruptInputError(nsrc)
- }
- if nsrc+1+l > len(src) {
- return ndst, CorruptInputError(nsrc)
- }
- el := (l + 3) / 4 * 5 // encoded len
- if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' {
- return ndst, CorruptInputError(nsrc)
- }
- line := src[nsrc+1 : nsrc+1+el]
- for i := 0; i < el; i += 5 {
- var v uint32
- for j := 0; j < 5; j++ {
- ch := decode[line[i+j]]
- if ch == 0 {
- return ndst, CorruptInputError(nsrc + 1 + i + j)
- }
- v = v*85 + uint32(ch-1)
- }
- for j := 0; j < 4; j++ {
- dst[ndst] = byte(v >> 24)
- v <<= 8
- ndst++
- }
- }
- // Last fragment may have run too far (but there was room in dst).
- // Back up.
- if l%4 != 0 {
- ndst -= 4 - l%4
- }
- nsrc += 1 + el + 1
- }
- return ndst, nil
-}
-
-func MaxDecodedLen(n int) int { return n / 5 * 4 }
-
-// NewEncoder returns a new Git base85 stream encoder. Data written to
-// the returned writer will be encoded and then written to w.
-// The Git encoding operates on 52-byte blocks; when finished
-// writing, the caller must Close the returned encoder to flush any
-// partially written blocks.
-func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} }
-
-type encoder struct {
- w io.Writer
- err os.Error
- buf [52]byte
- nbuf int
- out [1024]byte
- nout int
-}
-
-func (e *encoder) Write(p []byte) (n int, err os.Error) {
- if e.err != nil {
- return 0, e.err
- }
-
- // Leading fringe.
- if e.nbuf > 0 {
- var i int
- for i = 0; i < len(p) && e.nbuf < 52; i++ {
- e.buf[e.nbuf] = p[i]
- e.nbuf++
- }
- n += i
- p = p[i:]
- if e.nbuf < 52 {
- return
- }
- nout := Encode(e.out[0:], e.buf[0:])
- if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
- return n, e.err
- }
- e.nbuf = 0
- }
-
- // Large interior chunks.
- for len(p) >= 52 {
- nn := len(e.out) / (1 + 52/4*5 + 1) * 52
- if nn > len(p) {
- nn = len(p) / 52 * 52
- }
- if nn > 0 {
- nout := Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil {
- return n, e.err
- }
- }
- n += nn
- p = p[nn:]
- }
-
- // Trailing fringe.
- for i := 0; i < len(p); i++ {
- e.buf[i] = p[i]
- }
- e.nbuf = len(p)
- n += len(p)
- return
-}
-
-func (e *encoder) Close() os.Error {
- // If there's anything left in the buffer, flush it out
- if e.err == nil && e.nbuf > 0 {
- nout := Encode(e.out[0:], e.buf[0:e.nbuf])
- e.nbuf = 0
- _, e.err = e.w.Write(e.out[0:nout])
- }
- return e.err
-}
-
-// NewDecoder returns a new Git base85 stream decoder.
-func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} }
-
-type decoder struct {
- r io.Reader
- err os.Error
- readErr os.Error
- buf [1024]byte
- nbuf int
- out []byte
- outbuf [1024]byte
- off int64
-}
-
-func (d *decoder) Read(p []byte) (n int, err os.Error) {
- if len(p) == 0 {
- return 0, nil
- }
-
- for {
- // Copy leftover output from last decode.
- if len(d.out) > 0 {
- n = copy(p, d.out)
- d.out = d.out[n:]
- return
- }
-
- // Out of decoded output. Check errors.
- if d.err != nil {
- return 0, d.err
- }
- if d.readErr != nil {
- d.err = d.readErr
- return 0, d.err
- }
-
- // Read and decode more input.
- var nn int
- nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
- d.nbuf += nn
-
- // Send complete lines to Decode.
- nl := bytes.LastIndex(d.buf[0:d.nbuf], newline)
- if nl < 0 {
- continue
- }
- nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1])
- if e, ok := d.err.(CorruptInputError); ok {
- d.err = CorruptInputError(int64(e) + d.off)
- }
- d.out = d.outbuf[0:nn]
- d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
- d.off += int64(nl + 1)
- }
- panic("unreachable")
-}
diff --git a/src/pkg/encoding/git85/git_test.go b/src/pkg/encoding/git85/git_test.go
deleted file mode 100644
index c76385c35..000000000
--- a/src/pkg/encoding/git85/git_test.go
+++ /dev/null
@@ -1,194 +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 git85
-
-import (
- "bytes"
- "io/ioutil"
- "os"
- "testing"
-)
-
-type testpair struct {
- decoded, encoded string
-}
-
-func testEqual(t *testing.T, msg string, args ...interface{}) bool {
- if args[len(args)-2] != args[len(args)-1] {
- t.Errorf(msg, args...)
- return false
- }
- return true
-}
-
-func TestGitTable(t *testing.T) {
- var saw [256]bool
- for i, c := range encode {
- if decode[c] != uint8(i+1) {
- t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1)
- }
- saw[c] = true
- }
- for i, b := range saw {
- if !b && decode[i] != 0 {
- t.Errorf("decode[%d] = %d, want 0", i, decode[i])
- }
- }
-}
-
-var gitPairs = []testpair{
- // Wikipedia example, adapted.
- {
- "Man is distinguished, not only by his reason, but by this singular passion from " +
- "other animals, which is a lust of the mind, that by a perseverance of delight in " +
- "the continued and indefatigable generation of knowledge, exceeds the short " +
- "vehemence of any carnal pleasure.",
-
- "zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" +
- "zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" +
- "zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" +
- "zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" +
- "zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" +
- "IaBO8^b9HiME&u=k\n",
- },
-}
-
-var gitBigtest = gitPairs[len(gitPairs)-1]
-
-func TestEncode(t *testing.T) {
- for _, p := range gitPairs {
- buf := make([]byte, EncodedLen(len(p.decoded)))
- n := Encode(buf, []byte(p.decoded))
- if n != len(buf) {
- t.Errorf("EncodedLen does not agree with Encode")
- }
- buf = buf[0:n]
- testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
- }
-}
-
-func TestEncoder(t *testing.T) {
- for _, p := range gitPairs {
- bb := &bytes.Buffer{}
- encoder := NewEncoder(bb)
- encoder.Write([]byte(p.decoded))
- encoder.Close()
- testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded)
- }
-}
-
-func TestEncoderBuffering(t *testing.T) {
- input := []byte(gitBigtest.decoded)
- for bs := 1; bs <= 12; bs++ {
- bb := &bytes.Buffer{}
- encoder := NewEncoder(bb)
- for pos := 0; pos < len(input); pos += bs {
- end := pos + bs
- if end > len(input) {
- end = len(input)
- }
- n, err := encoder.Write(input[pos:end])
- testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil))
- testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos)
- }
- err := encoder.Close()
- testEqual(t, "Close gave error %v, want %v", err, os.Error(nil))
- testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded)
- }
-}
-
-func TestDecode(t *testing.T) {
- for _, p := range gitPairs {
- dbuf := make([]byte, 4*len(p.encoded))
- ndst, err := Decode(dbuf, []byte(p.encoded))
- testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
- testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded))
- testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded)
- }
-}
-
-func TestDecoder(t *testing.T) {
- for _, p := range gitPairs {
- decoder := NewDecoder(bytes.NewBufferString(p.encoded))
- dbuf, err := ioutil.ReadAll(decoder)
- if err != nil {
- t.Fatal("Read failed", err)
- }
- testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded))
- testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded)
- if err != nil {
- testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF)
- }
- }
-}
-
-func TestDecoderBuffering(t *testing.T) {
- for bs := 1; bs <= 12; bs++ {
- decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded))
- buf := make([]byte, len(gitBigtest.decoded)+12)
- var total int
- for total = 0; total < len(gitBigtest.decoded); {
- n, err := decoder.Read(buf[total : total+bs])
- testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, os.Error(nil))
- total += n
- }
- testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded)
- }
-}
-
-func TestDecodeCorrupt(t *testing.T) {
- type corrupt struct {
- e string
- p int
- }
- examples := []corrupt{
- {"v", 0},
- {"!z!!!!!!!!!", 0},
- }
-
- for _, e := range examples {
- dbuf := make([]byte, 2*len(e.e))
- _, err := Decode(dbuf, []byte(e.e))
- switch err := err.(type) {
- case CorruptInputError:
- testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
- default:
- t.Error("Decoder failed to detect corruption in", e)
- }
- }
-}
-
-func TestGitBig(t *testing.T) {
- n := 3*1000 + 1
- raw := make([]byte, n)
- const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- for i := 0; i < n; i++ {
- raw[i] = alpha[i%len(alpha)]
- }
- encoded := new(bytes.Buffer)
- w := NewEncoder(encoded)
- nn, err := w.Write(raw)
- if nn != n || err != nil {
- t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n)
- }
- err = w.Close()
- if err != nil {
- t.Fatalf("Encoder.Close() = %v want nil", err)
- }
- decoded, err := ioutil.ReadAll(NewDecoder(encoded))
- if err != nil {
- t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err)
- }
-
- if !bytes.Equal(raw, decoded) {
- var i int
- for i = 0; i < len(decoded) && i < len(raw); i++ {
- if decoded[i] != raw[i] {
- break
- }
- }
- t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
- }
-}
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index a5fb91cda..ebcbb78eb 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -6,11 +6,13 @@ package gob
import (
"bytes"
+ "errors"
"math"
- "os"
+ "math/rand"
"reflect"
"strings"
"testing"
+ "time"
"unsafe"
)
@@ -41,7 +43,7 @@ var encodeT = []EncodeT{
// plain test.Error call.
func testError(t *testing.T) {
if e := recover(); e != nil {
- t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+ t.Error(e.(gobError).err) // Will re-panic if not one of our errors, such as a runtime error.
}
return
}
@@ -102,12 +104,15 @@ func TestIntCodec(t *testing.T) {
// The result of encoding a true boolean with field number 7
var boolResult = []byte{0x07, 0x01}
+
// The result of encoding a number 17 with field number 7
var signedResult = []byte{0x07, 2 * 17}
var unsignedResult = []byte{0x07, 17}
var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+
// The result of encoding a number 17+19i with field number 7
var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+
// The result of encoding "hello" with field number 7
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
@@ -330,7 +335,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.NewError("overflow")
+ ovfl := errors.New("overflow")
// bool
{
@@ -544,7 +549,7 @@ func TestScalarDecInstructions(t *testing.T) {
var data struct {
a []byte
}
- instr := &decInstr{decUint8Array, 6, 0, 0, ovfl}
+ instr := &decInstr{decUint8Slice, 6, 0, 0, ovfl}
state := newDecodeStateFromData(bytesResult)
execDec("bytes", instr, state, t, unsafe.Pointer(&data))
if string(data.a) != "hello" {
@@ -633,7 +638,7 @@ func TestOverflow(t *testing.T) {
Minc complex128
}
var it inputT
- var err os.Error
+ var err error
b := new(bytes.Buffer)
enc := NewEncoder(b)
dec := NewDecoder(b)
@@ -650,7 +655,7 @@ func TestOverflow(t *testing.T) {
var o1 outi8
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "Maxi" out of range` {
+ if err == nil || err.Error() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int8:", err)
}
it = inputT{
@@ -659,7 +664,7 @@ func TestOverflow(t *testing.T) {
b.Reset()
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "Mini" out of range` {
+ if err == nil || err.Error() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int8:", err)
}
@@ -675,7 +680,7 @@ func TestOverflow(t *testing.T) {
var o2 outi16
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "Maxi" out of range` {
+ if err == nil || err.Error() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int16:", err)
}
it = inputT{
@@ -684,7 +689,7 @@ func TestOverflow(t *testing.T) {
b.Reset()
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "Mini" out of range` {
+ if err == nil || err.Error() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int16:", err)
}
@@ -700,7 +705,7 @@ func TestOverflow(t *testing.T) {
var o3 outi32
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "Maxi" out of range` {
+ if err == nil || err.Error() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int32:", err)
}
it = inputT{
@@ -709,7 +714,7 @@ func TestOverflow(t *testing.T) {
b.Reset()
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "Mini" out of range` {
+ if err == nil || err.Error() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int32:", err)
}
@@ -724,7 +729,7 @@ func TestOverflow(t *testing.T) {
var o4 outu8
enc.Encode(it)
err = dec.Decode(&o4)
- if err == nil || err.String() != `value for "Maxu" out of range` {
+ if err == nil || err.Error() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint8:", err)
}
@@ -739,7 +744,7 @@ func TestOverflow(t *testing.T) {
var o5 outu16
enc.Encode(it)
err = dec.Decode(&o5)
- if err == nil || err.String() != `value for "Maxu" out of range` {
+ if err == nil || err.Error() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint16:", err)
}
@@ -754,7 +759,7 @@ func TestOverflow(t *testing.T) {
var o6 outu32
enc.Encode(it)
err = dec.Decode(&o6)
- if err == nil || err.String() != `value for "Maxu" out of range` {
+ if err == nil || err.Error() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint32:", err)
}
@@ -770,7 +775,7 @@ func TestOverflow(t *testing.T) {
var o7 outf32
enc.Encode(it)
err = dec.Decode(&o7)
- if err == nil || err.String() != `value for "Maxf" out of range` {
+ if err == nil || err.Error() != `value for "Maxf" out of range` {
t.Error("wrong overflow error for float32:", err)
}
@@ -786,7 +791,7 @@ func TestOverflow(t *testing.T) {
var o8 outc64
enc.Encode(it)
err = dec.Decode(&o8)
- if err == nil || err.String() != `value for "Maxc" out of range` {
+ if err == nil || err.Error() != `value for "Maxc" out of range` {
t.Error("wrong overflow error for complex64:", err)
}
}
@@ -995,7 +1000,7 @@ func TestBadRecursiveType(t *testing.T) {
err := NewEncoder(b).Encode(&rec)
if err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.String(), "recursive") < 0 {
+ } else if strings.Index(err.Error(), "recursive") < 0 {
t.Error("expected recursive type error; got", err)
}
// Can't test decode easily because we can't encode one, so we can't pass one to a Decoder.
@@ -1014,7 +1019,7 @@ func TestInvalidField(t *testing.T) {
dummyEncoder.encode(b, reflect.ValueOf(&bad0), userType(reflect.TypeOf(&bad0)))
if err := dummyEncoder.err; err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.String(), "type") < 0 {
+ } else if strings.Index(err.Error(), "type") < 0 {
t.Error("expected type error; got", err)
}
}
@@ -1404,3 +1409,63 @@ func TestDebugStruct(t *testing.T) {
}
debugFunc(debugBuffer)
}
+
+func encFuzzDec(rng *rand.Rand, in interface{}) error {
+ buf := new(bytes.Buffer)
+ enc := NewEncoder(buf)
+ if err := enc.Encode(&in); err != nil {
+ return err
+ }
+
+ b := buf.Bytes()
+ for i, bi := range b {
+ if rng.Intn(10) < 3 {
+ b[i] = bi + uint8(rng.Intn(256))
+ }
+ }
+
+ dec := NewDecoder(buf)
+ var e interface{}
+ if err := dec.Decode(&e); err != nil {
+ return err
+ }
+ return nil
+}
+
+// This does some "fuzz testing" by attempting to decode a sequence of random bytes.
+func TestFuzz(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ // all possible inputs
+ input := []interface{}{
+ new(int),
+ new(float32),
+ new(float64),
+ new(complex128),
+ &ByteStruct{255},
+ &ArrayStruct{},
+ &StringStruct{"hello"},
+ &GobTest1{0, &StringStruct{"hello"}},
+ }
+ testFuzz(t, time.Now().UnixNano(), 100, input...)
+}
+
+func TestFuzzRegressions(t *testing.T) {
+ // An instance triggering a type name of length ~102 GB.
+ testFuzz(t, 1328492090837718000, 100, new(float32))
+ // An instance triggering a type name of 1.6 GB.
+ // Commented out because it takes 5m to run.
+ //testFuzz(t, 1330522872628565000, 100, new(int))
+}
+
+func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
+ for _, e := range input {
+ t.Logf("seed=%d n=%d e=%T", seed, n, e)
+ rng := rand.New(rand.NewSource(seed))
+ for i := 0; i < n; i++ {
+ encFuzzDec(rng, e)
+ }
+ }
+}
diff --git a/src/pkg/gob/debug.go b/src/pkg/encoding/gob/debug.go
index ce8a6ff5e..31d1351fc 100644
--- a/src/pkg/gob/debug.go
+++ b/src/pkg/encoding/gob/debug.go
@@ -1,9 +1,17 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Delete the next line to include in the gob package.
+// +build ignore
+
package gob
// This file is not normally included in the gob package. Used only for debugging the package itself.
-// Add debug.go to the files listed in the Makefile to add Debug to the gob package.
// Except for reading uints, it is an implementation of a reader that is independent of
// the one implemented by Decoder.
+// To enable the Debug function, delete the +build ignore line above and do
+// go install
import (
"bytes"
@@ -56,7 +64,7 @@ func newPeekReader(r io.Reader) *peekReader {
}
// Read is the usual method. It will first take data that has been read ahead.
-func (p *peekReader) Read(b []byte) (n int, err os.Error) {
+func (p *peekReader) Read(b []byte) (n int, err error) {
if len(p.data) == 0 {
return p.r.Read(b)
}
@@ -70,7 +78,7 @@ func (p *peekReader) Read(b []byte) (n int, err os.Error) {
// peek returns as many bytes as possible from the unread
// portion of the stream, up to the length of b.
-func (p *peekReader) peek(b []byte) (n int, err os.Error) {
+func (p *peekReader) peek(b []byte) (n int, err error) {
if len(p.data) > 0 {
n = copy(b, p.data)
if n == len(b) {
@@ -92,7 +100,7 @@ func (p *peekReader) peek(b []byte) (n int, err os.Error) {
if n > 0 {
e = nil
} else {
- e = os.EOF
+ e = io.EOF
}
}
return n, e
@@ -154,6 +162,7 @@ func (deb *debugger) dump(format string, args ...interface{}) {
}
// Debug prints a human-readable representation of the gob data read from r.
+// It is a no-op unless debugging was enabled when the package was built.
func Debug(r io.Reader) {
err := debug(r)
if err != nil {
@@ -163,7 +172,7 @@ func Debug(r io.Reader) {
// debug implements Debug, but catches panics and returns
// them as errors to be printed by Debug.
-func debug(r io.Reader) (err os.Error) {
+func debug(r io.Reader) (err error) {
defer catchError(&err)
fmt.Fprintln(os.Stderr, "Start of debugging")
deb := &debugger{
@@ -237,7 +246,7 @@ func (deb *debugger) delimitedMessage(indent tab) bool {
func (deb *debugger) loadBlock(eofOK bool) int {
n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF
if err != nil {
- if eofOK && err == os.EOF {
+ if eofOK && err == io.EOF {
return -1
}
errorf("debug: unexpected error: %s", err)
diff --git a/src/pkg/gob/decode.go b/src/pkg/encoding/gob/decode.go
index bf7cb95f2..e32a178ab 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -9,17 +9,17 @@ package gob
import (
"bytes"
+ "errors"
"io"
"math"
- "os"
"reflect"
"unsafe"
)
var (
- 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")
+ errBadUint = errors.New("gob: encoded unsigned integer out of range")
+ errBadType = errors.New("gob: unknown type id or corrupted data")
+ errRange = errors.New("gob: bad data: field numbers out of bounds")
)
// decoderState is the execution state of an instance of the decoder. A new state
@@ -54,13 +54,13 @@ func (dec *Decoder) freeDecoderState(d *decoderState) {
dec.freeList = d
}
-func overflow(name string) os.Error {
- return os.NewError(`value for "` + name + `" out of range`)
+func overflow(name string) error {
+ return errors.New(`value for "` + name + `" out of range`)
}
// decodeUintReader reads an encoded unsigned integer from an io.Reader.
// Used only by the Decoder to read the message length.
-func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err os.Error) {
+func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err error) {
width = 1
_, err = r.Read(buf[0:width])
if err != nil {
@@ -70,25 +70,23 @@ func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err os.Erro
if b <= 0x7f {
return uint64(b), width, nil
}
- nb := -int(int8(b))
- if nb > uint64Size {
+ n := -int(int8(b))
+ if n > uint64Size {
err = errBadUint
return
}
- var n int
- n, err = io.ReadFull(r, buf[0:nb])
+ width, err = io.ReadFull(r, buf[0:n])
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return
}
// Could check that the high byte is zero but it's not worth it.
- for i := 0; i < n; i++ {
- x <<= 8
- x |= uint64(buf[i])
- width++
+ for _, b := range buf[0:width] {
+ x = x<<8 | uint64(b)
}
+ width++ // +1 for length byte
return
}
@@ -97,24 +95,23 @@ func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err os.Erro
func (state *decoderState) decodeUint() (x uint64) {
b, err := state.b.ReadByte()
if err != nil {
- error(err)
+ error_(err)
}
if b <= 0x7f {
return uint64(b)
}
- nb := -int(int8(b))
- if nb > uint64Size {
- error(errBadUint)
+ n := -int(int8(b))
+ if n > uint64Size {
+ error_(errBadUint)
}
- n, err := state.b.Read(state.buf[0:nb])
+ width, err := state.b.Read(state.buf[0:n])
if err != nil {
- error(err)
+ error_(err)
}
// Don't need to check error; it's safe to loop regardless.
// Could check that the high byte is zero but it's not worth it.
- for i := 0; i < n; i++ {
- x <<= 8
- x |= uint64(state.buf[i])
+ for _, b := range state.buf[0:width] {
+ x = x<<8 | uint64(b)
}
return x
}
@@ -135,10 +132,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.Error // 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 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
@@ -193,7 +190,7 @@ func decInt8(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeInt()
if v < math.MinInt8 || math.MaxInt8 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*int8)(p) = int8(v)
}
@@ -209,7 +206,7 @@ func decUint8(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeUint()
if math.MaxUint8 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*uint8)(p) = uint8(v)
}
@@ -225,7 +222,7 @@ func decInt16(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeInt()
if v < math.MinInt16 || math.MaxInt16 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*int16)(p) = int16(v)
}
@@ -241,7 +238,7 @@ func decUint16(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeUint()
if math.MaxUint16 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*uint16)(p) = uint16(v)
}
@@ -257,7 +254,7 @@ func decInt32(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeInt()
if v < math.MinInt32 || math.MaxInt32 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*int32)(p) = int32(v)
}
@@ -273,7 +270,7 @@ func decUint32(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
v := state.decodeUint()
if math.MaxUint32 < v {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*uint32)(p) = uint32(v)
}
@@ -326,7 +323,7 @@ func storeFloat32(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
- error(i.ovfl)
+ error_(i.ovfl)
} else {
*(*float32)(p) = float32(v)
}
@@ -385,19 +382,29 @@ func decComplex128(i *decInstr, state *decoderState, p unsafe.Pointer) {
*(*complex128)(p) = complex(real, imag)
}
-// decUint8Array decodes byte array and stores through p a slice header
+// decUint8Slice decodes a byte slice and stores through p a slice header
// describing the data.
-// uint8 arrays are encoded as an unsigned count followed by the raw bytes.
-func decUint8Array(i *decInstr, state *decoderState, p unsafe.Pointer) {
+// uint8 slices are encoded as an unsigned count followed by the raw bytes.
+func decUint8Slice(i *decInstr, state *decoderState, p unsafe.Pointer) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
*(*unsafe.Pointer)(p) = unsafe.Pointer(new([]uint8))
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]uint8, state.decodeUint())
- state.b.Read(b)
- *(*[]uint8)(p) = b
+ n := state.decodeUint()
+ if n > uint64(state.b.Len()) {
+ errorf("length of []byte exceeds input size (%d bytes)", n)
+ }
+ slice := (*[]uint8)(p)
+ if uint64(cap(*slice)) < n {
+ *slice = make([]uint8, n)
+ } else {
+ *slice = (*slice)[0:n]
+ }
+ if _, err := state.b.Read(*slice); err != nil {
+ errorf("error decoding []byte: %s", err)
+ }
}
// decString decodes byte array and stores through p a string header
@@ -410,7 +417,11 @@ func decString(i *decInstr, state *decoderState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]byte, state.decodeUint())
+ n := state.decodeUint()
+ if n > uint64(state.b.Len()) {
+ errorf("string length exceeds input size (%d bytes)", n)
+ }
+ b := make([]byte, n)
state.b.Read(b)
// It would be a shame to do the obvious thing here,
// *(*string)(p) = string(b)
@@ -449,7 +460,7 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
}
if *(*unsafe.Pointer)(up) == nil {
// Allocate object.
- *(*unsafe.Pointer)(up) = unsafe.New(rtyp)
+ *(*unsafe.Pointer)(up) = unsafe.Pointer(reflect.New(rtyp).Pointer())
}
return *(*uintptr)(up)
}
@@ -457,30 +468,26 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
// decodeSingle decodes a top-level value that is not a struct and stores it through p.
// Such values are preceded by a zero, making them have the memory layout of a
// struct field (although with an illegal field number).
-func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr) (err os.Error) {
- indir := ut.indir
- if ut.isGobDecoder {
- indir = int(ut.decIndir)
- }
- p = allocate(ut.base, p, indir)
+func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) {
state := dec.newDecoderState(&dec.buf)
state.fieldnum = singletonField
- basep := p
delta := int(state.decodeUint())
if delta != 0 {
errorf("decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
+ if instr.indir != ut.indir {
+ errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir)
+ }
ptr := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 1 {
ptr = decIndirect(ptr, instr.indir)
}
instr.op(instr, state, ptr)
dec.freeDecoderState(state)
- return nil
}
-// decodeSingle decodes a top-level struct and stores it through p.
+// decodeStruct decodes a top-level struct and stores it through p.
// Indir is for the value, not the type. At the time of the call it may
// differ from ut.indir, which was computed when the engine was built.
// This state cannot arise for decodeSingle, which is called directly
@@ -500,7 +507,7 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr,
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- error(errRange)
+ error_(errRange)
break
}
instr := &engine.instr[fieldnum]
@@ -528,7 +535,7 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) {
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- error(errRange)
+ error_(errRange)
}
instr := &engine.instr[fieldnum]
instr.op(instr, state, unsafe.Pointer(nil))
@@ -552,7 +559,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.Error) {
+func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl error) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
for i := 0; i < length; i++ {
up := unsafe.Pointer(p)
@@ -567,7 +574,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.Error) {
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl error) {
if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -579,7 +586,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.Error) reflect.Value {
+func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl error) reflect.Value {
instr := &decInstr{op, 0, indir, 0, ovfl}
up := unsafe.Pointer(unsafeAddr(v))
if indir > 1 {
@@ -593,7 +600,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.Error) {
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl error) {
if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -605,7 +612,7 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr,
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
- v := reflect.ValueOf(unsafe.Unreflect(mtyp, unsafe.Pointer(p)))
+ v := reflect.NewAt(mtyp, unsafe.Pointer(p)).Elem()
n := int(state.decodeUint())
for i := 0; i < n; i++ {
key := decodeIntoValue(state, keyOp, keyIndir, allocValue(mtyp.Key()), ovfl)
@@ -616,7 +623,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.NewError("no error")}
+ instr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")}
for i := 0; i < length; i++ {
elemOp(instr, state, nil)
}
@@ -633,8 +640,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.NewError("no error")}
- elemInstr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
+ keyInstr := &decInstr{keyOp, 0, 0, 0, errors.New("no error")}
+ elemInstr := &decInstr{elemOp, 0, 0, 0, errors.New("no error")}
for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil)
elemOp(elemInstr, state, nil)
@@ -643,8 +650,12 @@ 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.Error) {
- n := int(uintptr(state.decodeUint()))
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
+ nr := state.decodeUint()
+ if nr > uint64(state.b.Len()) {
+ errorf("length of slice exceeds input size (%d elements)", nr)
+ }
+ n := int(nr)
if indir > 0 {
up := unsafe.Pointer(p)
if *(*unsafe.Pointer)(up) == nil {
@@ -653,12 +664,15 @@ func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintpt
}
p = *(*uintptr)(up)
}
- // Allocate storage for the slice elements, that is, the underlying array.
+ // Allocate storage for the slice elements, that is, the underlying array,
+ // if the existing slice does not have the capacity.
// Always write a header at p.
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
- hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
+ if hdrp.Cap < n {
+ hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
+ hdrp.Cap = n
+ }
hdrp.Len = n
- hdrp.Cap = n
dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
}
@@ -683,15 +697,25 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
// Create a writable interface reflect.Value. We need one even for the nil case.
ivalue := allocValue(ityp)
// Read the name of the concrete type.
- b := make([]byte, state.decodeUint())
+ nr := state.decodeUint()
+ if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
+ errorf("invalid type name length %d", nr)
+ }
+ b := make([]byte, nr)
state.b.Read(b)
name := string(b)
if name == "" {
// Copy the representation of the nil interface value to the target.
// This is horribly unsafe and special.
+ if indir > 0 {
+ p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
*(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
return
}
+ if len(name) > 1024 {
+ errorf("name too long (%d bytes): %.20q...", len(name), name)
+ }
// The concrete type must be registered.
typ, ok := nameToConcreteType[name]
if !ok {
@@ -700,7 +724,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
// Read the type id of the concrete value.
concreteId := dec.decodeTypeSequence(true)
if concreteId < 0 {
- error(dec.err)
+ error_(dec.err)
}
// Byte count of value is next; we don't care what it is (it's there
// in case we want to ignore the value by skipping it completely).
@@ -709,7 +733,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
value := allocValue(typ)
dec.decodeValue(concreteId, value)
if dec.err != nil {
- error(dec.err)
+ error_(dec.err)
}
// Allocate the destination interface value.
if indir > 0 {
@@ -729,11 +753,11 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
if err != nil {
- error(err)
+ error_(err)
}
id := dec.decodeTypeSequence(true)
if id < 0 {
- error(dec.err)
+ error_(dec.err)
}
// At this point, the decoder buffer contains a delimited value. Just toss it.
state.b.Next(int(state.decodeUint()))
@@ -746,12 +770,12 @@ func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) {
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
if err != nil {
- error(err)
+ error_(err)
}
// We know it's a GobDecoder, so just call the method directly.
err = v.Interface().(GobDecoder).GobDecode(b)
if err != nil {
- error(err)
+ error_(err)
}
}
@@ -761,7 +785,7 @@ func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
if err != nil {
- error(err)
+ error_(err)
}
}
@@ -828,11 +852,10 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
}
case reflect.Map:
- name = "element of " + name
keyId := dec.wireType[wireId].MapT.Key
elemId := dec.wireType[wireId].MapT.Elem
- keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name, inProgress)
- elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress)
ovfl := overflow(name)
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
up := unsafe.Pointer(p)
@@ -842,7 +865,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
case reflect.Slice:
name = "element of " + name
if t.Elem().Kind() == reflect.Uint8 {
- op = decUint8Array
+ op = decUint8Slice
break
}
var elemId typeId
@@ -861,7 +884,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getDecEnginePtr(wireId, userType(typ))
if err != nil {
- error(err)
+ error_(err)
}
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs.
@@ -874,7 +897,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
}
}
if op == nil {
- errorf("decode can't handle type %s", rt.String())
+ errorf("decode can't handle type %s", rt)
}
return &op, indir
}
@@ -923,7 +946,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getIgnoreEnginePtr(wireId)
if err != nil {
- error(err)
+ error_(err)
}
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
@@ -958,16 +981,16 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
// Caller has gotten us to within one indirection of our value.
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
- *(*unsafe.Pointer)(p) = unsafe.New(ut.base)
+ *(*unsafe.Pointer)(p) = unsafe.Pointer(reflect.New(ut.base).Pointer())
}
}
// Now p is a pointer to the base type. Do we need to climb out to
// get to the receiver type?
var v reflect.Value
if ut.decIndir == -1 {
- v = reflect.ValueOf(unsafe.Unreflect(rcvrType, unsafe.Pointer(&p)))
+ v = reflect.NewAt(rcvrType, unsafe.Pointer(&p)).Elem()
} else {
- v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p))
+ v = reflect.NewAt(rcvrType, p).Elem()
}
state.dec.decodeGobDecoder(state, v)
}
@@ -1032,9 +1055,9 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re
// Extract and compare element types.
var sw *sliceType
if tt, ok := builtinIdToType[fw]; ok {
- sw = tt.(*sliceType)
- } else {
- sw = dec.wireType[fw].SliceT
+ sw, _ = tt.(*sliceType)
+ } else if wire != nil {
+ sw = wire.SliceT
}
elem := userType(t.Elem()).base
return sw != nil && dec.compatibleType(elem, sw.Elem, inProgress)
@@ -1055,26 +1078,28 @@ func (dec *Decoder) typeString(remoteId typeId) string {
// compileSingle compiles the decoder engine for a non-struct top-level value, including
// GobDecoders.
-func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
- rt := ut.base
- if ut.isGobDecoder {
- rt = ut.user
- }
+func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
+ rt := ut.user
engine = new(decEngine)
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.NewError("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
+ remoteType := dec.typeString(remoteId)
+ // Common confusing case: local interface type, remote concrete type.
+ if ut.base.Kind() == reflect.Interface && remoteId != tInterface {
+ return nil, errors.New("gob: local interface type " + name + " can only be decoded from remote interface type; received concrete type " + remoteType)
+ }
+ return nil, errors.New("gob: decoding into local type " + name + ", received remote type " + remoteType)
}
op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
- ovfl := os.NewError(`value for "` + name + `" out of range`)
+ ovfl := errors.New(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl}
engine.numInstr = 1
return
}
// compileIgnoreSingle compiles the decoder engine for a non-struct top-level value that will be discarded.
-func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err os.Error) {
+func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err error) {
engine = new(decEngine)
engine.instr = make([]decInstr, 1) // one item
op := dec.decIgnoreOpFor(remoteId)
@@ -1086,7 +1111,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
// compileDec compiles the decoder engine for a value. If the value is not a struct,
// it calls out to compileSingle.
-func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err os.Error) {
+func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
rt := ut.base
srt := rt
if srt.Kind() != reflect.Struct ||
@@ -1101,12 +1126,12 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
} else {
wire := dec.wireType[remoteId]
if wire == nil {
- error(errBadType)
+ error_(errBadType)
}
wireStruct = wire.StructT
}
if wireStruct == nil {
- errorf("type mismatch in decoder: want struct type %s; got non-struct", rt.String())
+ errorf("type mismatch in decoder: want struct type %s; got non-struct", rt)
}
engine = new(decEngine)
engine.instr = make([]decInstr, len(wireStruct.Field))
@@ -1137,8 +1162,8 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
}
// getDecEnginePtr returns the engine for the specified type.
-func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err os.Error) {
- rt := ut.base
+func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) {
+ rt := ut.user
decoderMap, ok := dec.decoderCache[rt]
if !ok {
decoderMap = make(map[typeId]**decEngine)
@@ -1150,7 +1175,7 @@ func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePt
decoderMap[remoteId] = enginePtr
*enginePtr, err = dec.compileDec(remoteId, ut)
if err != nil {
- decoderMap[remoteId] = nil, false
+ delete(decoderMap, remoteId)
}
}
return
@@ -1162,7 +1187,7 @@ type emptyStruct struct{}
var emptyStructType = reflect.TypeOf(emptyStruct{})
// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
-func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err os.Error) {
+func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) {
var ok bool
if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
// To handle recursive types, mark this engine as underway before compiling.
@@ -1175,7 +1200,7 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er
*enginePtr, err = dec.compileIgnoreSingle(wireId)
}
if err != nil {
- dec.ignorerCache[wireId] = nil, false
+ delete(dec.ignorerCache, wireId)
}
}
return
@@ -1189,7 +1214,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
dec.decodeIgnoredValue(wireId)
return
}
- // Dereference down to the underlying struct type.
+ // Dereference down to the underlying type.
ut := userType(val.Type())
base := ut.base
var enginePtr **decEngine
diff --git a/src/pkg/gob/decoder.go b/src/pkg/encoding/gob/decoder.go
index 281947132..c5c7d3fdb 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/encoding/gob/decoder.go
@@ -7,8 +7,8 @@ package gob
import (
"bufio"
"bytes"
+ "errors"
"io"
- "os"
"reflect"
"sync"
)
@@ -25,13 +25,19 @@ type Decoder struct {
freeList *decoderState // list of free decoderStates; avoids reallocation
countBuf []byte // used for decoding integers while parsing messages
tmp []byte // temporary storage for i/o; saves reallocating
- err os.Error
+ err error
}
// NewDecoder returns a new decoder that reads from the io.Reader.
+// If r does not also implement io.ByteReader, it will be wrapped in a
+// bufio.Reader.
func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
- dec.r = bufio.NewReader(r)
+ // We use the ability to read bytes as a plausible surrogate for buffering.
+ if _, ok := r.(io.ByteReader); !ok {
+ r = bufio.NewReader(r)
+ }
+ dec.r = r
dec.wireType = make(map[typeId]*wireType)
dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
dec.ignorerCache = make(map[typeId]**decEngine)
@@ -44,7 +50,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.NewError("gob: duplicate type received")
+ dec.err = errors.New("gob: duplicate type received")
return
}
@@ -58,6 +64,8 @@ func (dec *Decoder) recvType(id typeId) {
dec.wireType[id] = wire
}
+var errBadCount = errors.New("invalid message length")
+
// recvMessage reads the next count-delimited item from the input. It is the converse
// of Encoder.writeMessage. It returns false on EOF or other error reading the message.
func (dec *Decoder) recvMessage() bool {
@@ -67,6 +75,12 @@ func (dec *Decoder) recvMessage() bool {
dec.err = err
return false
}
+ // Upper limit of 1GB, allowing room to grow a little without overflow.
+ // TODO: We might want more control over this limit.
+ if nbytes >= 1<<30 {
+ dec.err = errBadCount
+ return false
+ }
dec.readMessage(int(nbytes))
return dec.err == nil
}
@@ -82,7 +96,7 @@ func (dec *Decoder) readMessage(nbytes int) {
// Read the data
_, dec.err = io.ReadFull(dec.r, dec.tmp)
if dec.err != nil {
- if dec.err == os.EOF {
+ if dec.err == io.EOF {
dec.err = io.ErrUnexpectedEOF
}
return
@@ -121,7 +135,7 @@ func (dec *Decoder) nextUint() uint64 {
// and returns the type id of the next value. It returns -1 at
// EOF. Upon return, the remainder of dec.buf is the value to be
// decoded. If this is an interface value, it can be ignored by
-// simply resetting that buffer.
+// resetting that buffer.
func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
for dec.err == nil {
if dec.buf.Len() == 0 {
@@ -143,7 +157,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.NewError("extra data in buffer")
+ dec.err = errors.New("extra data in buffer")
break
}
dec.nextUint()
@@ -157,7 +171,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// If e is nil, the value will be discarded. Otherwise,
// 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 {
+func (dec *Decoder) Decode(e interface{}) error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
}
@@ -165,7 +179,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.NewError("gob: attempt to decode into a non-pointer")
+ dec.err = errors.New("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
@@ -175,12 +189,12 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
// Otherwise, it stores the value into v. In that case, v must represent
// a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
-func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
+func (dec *Decoder) DecodeValue(v reflect.Value) error {
if v.IsValid() {
if v.Kind() == reflect.Ptr && !v.IsNil() {
// That's okay, we'll store through the pointer.
} else if !v.CanSet() {
- return os.NewError("gob: DecodeValue of unassignable value")
+ return errors.New("gob: DecodeValue of unassignable value")
}
}
// Make sure we're single-threaded through here.
diff --git a/src/pkg/gob/doc.go b/src/pkg/encoding/gob/doc.go
index a9284ced7..96885f8de 100644
--- a/src/pkg/gob/doc.go
+++ b/src/pkg/encoding/gob/doc.go
@@ -68,7 +68,10 @@ the destination variable must be able to represent the value or the decode
operation will fail.
Structs, arrays and slices are also supported. Strings and arrays of bytes are
-supported with a special, efficient representation (see below).
+supported with a special, efficient representation (see below). When a slice is
+decoded, if the existing slice has capacity the slice will be extended in place;
+if not, a new array is allocated. Regardless, the length of the resulting slice
+reports the number of elements decoded.
Functions and channels cannot be sent in a gob. Attempting
to encode a value that contains one will fail.
@@ -159,7 +162,7 @@ description, constructed from these types:
StructT *StructType
MapT *MapType
}
- type ArrayType struct {
+ type arrayType struct {
CommonType
Elem typeId
Len int
@@ -168,19 +171,19 @@ description, constructed from these types:
Name string // the name of the struct type
Id int // the id of the type, repeated so it's inside the type
}
- type SliceType struct {
+ type sliceType struct {
CommonType
Elem typeId
}
- type StructType struct {
+ type structType struct {
CommonType
Field []*fieldType // the fields of the struct.
}
- type FieldType struct {
+ type fieldType struct {
Name string // the name of the field.
Id int // the type id of the field, which must be already defined
}
- type MapType struct {
+ type mapType struct {
CommonType
Key typeId
Elem typeId
@@ -223,7 +226,7 @@ where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
See "Gobs of data" for a design discussion of the gob wire format:
-http://blog.golang.org/2011/03/gobs-of-data.html
+http://golang.org/doc/articles/gobs_of_data.html
*/
package gob
@@ -305,15 +308,15 @@ reserved).
// Set the field number implicitly to -1; this is done at the beginning
// of every struct, including nested structs.
03 // Add 3 to field number; now 2 (wireType.structType; this is a struct).
- // structType starts with an embedded commonType, which appears
+ // structType starts with an embedded CommonType, which appears
// as a regular structure here too.
- 01 // add 1 to field number (now 0); start of embedded commonType.
+ 01 // add 1 to field number (now 0); start of embedded CommonType.
01 // add 1 to field number (now 0, the name of the type)
05 // string is (unsigned) 5 bytes long
- 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
+ 50 6f 69 6e 74 // wireType.structType.CommonType.name = "Point"
01 // add 1 to field number (now 1, the id of the type)
- ff 82 // wireType.structType.commonType._id = 65
- 00 // end of embedded wiretype.structType.commonType struct
+ ff 82 // wireType.structType.CommonType._id = 65
+ 00 // end of embedded wiretype.structType.CommonType struct
01 // add 1 to field number (now 1, the field array in wireType.structType)
02 // There are two fields in the type (len(structType.field))
01 // Start of first field structure; add 1 to get field number 0: field[0].name
diff --git a/src/pkg/gob/dump.go b/src/pkg/encoding/gob/dump.go
index 1555f0fbb..17238c98d 100644
--- a/src/pkg/gob/dump.go
+++ b/src/pkg/encoding/gob/dump.go
@@ -1,15 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
package main
// Need to compile package gob with debug.go to build this program.
+// See comments in debug.go for how to do this.
import (
+ "encoding/gob"
"fmt"
- "gob"
"os"
)
func main() {
- var err os.Error
+ var err error
file := os.Stdin
if len(os.Args) > 1 {
file, err = os.Open(os.Args[1])
diff --git a/src/pkg/gob/encode.go b/src/pkg/encoding/gob/encode.go
index 317014efd..168e08b13 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/encoding/gob/encode.go
@@ -55,21 +55,20 @@ func (state *encoderState) encodeUint(x uint64) {
if x <= 0x7F {
err := state.b.WriteByte(uint8(x))
if err != nil {
- error(err)
+ error_(err)
}
return
}
- var n, m int
- m = uint64Size
- for n = 1; x > 0; n++ {
- state.buf[m] = uint8(x)
+ i := uint64Size
+ for x > 0 {
+ state.buf[i] = uint8(x)
x >>= 8
- m--
+ i--
}
- state.buf[m] = uint8(-(n - 1))
- n, err := state.b.Write(state.buf[m : uint64Size+1])
+ state.buf[i] = uint8(i - uint64Size) // = loop count, negated
+ _, err := state.b.Write(state.buf[i : uint64Size+1])
if err != nil {
- error(err)
+ error_(err)
}
}
@@ -444,7 +443,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
state.encodeUint(uint64(len(name)))
_, err := state.b.WriteString(name)
if err != nil {
- error(err)
+ error_(err)
}
// Define the type id if necessary.
enc.sendTypeDescriptor(enc.writer(), state, ut)
@@ -454,14 +453,15 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
// should be written to b, before the encoded value.
enc.pushWriter(b)
data := new(bytes.Buffer)
+ data.Write(spaceForLength)
enc.encode(data, iv.Elem(), ut)
if enc.err != nil {
- error(enc.err)
+ error_(enc.err)
}
enc.popWriter()
enc.writeMessage(b, data)
if enc.err != nil {
- error(err)
+ error_(err)
}
enc.freeEncoderState(state)
}
@@ -469,7 +469,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
// 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:
+ case reflect.Array:
+ for i := 0; i < val.Len(); i++ {
+ if !isZero(val.Index(i)) {
+ return false
+ }
+ }
+ return true
+ case reflect.Map, reflect.Slice, reflect.String:
return val.Len() == 0
case reflect.Bool:
return !val.Bool()
@@ -483,6 +490,13 @@ func isZero(val reflect.Value) bool {
return val.Float() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return val.Uint() == 0
+ case reflect.Struct:
+ for i := 0; i < val.NumField(); i++ {
+ if !isZero(val.Field(i)) {
+ return false
+ }
+ }
+ return true
}
panic("unknown type in isZero " + val.Type().String())
}
@@ -494,7 +508,7 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value) {
// We know it's a GobEncoder, so just call the method directly.
data, err := v.Interface().(GobEncoder).GobEncode()
if err != nil {
- error(err)
+ error_(err)
}
state := enc.newEncoderState(b)
state.fieldnum = -1
@@ -576,7 +590,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
- v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
mv := reflect.Indirect(v)
// We send zero-length (but non-nil) maps because the
// receiver might want to use the map. (Maps don't use append.)
@@ -599,7 +613,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
// Interfaces transmit the name and contents of the concrete
// value they contain.
- v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
+ v := reflect.NewAt(t, unsafe.Pointer(p)).Elem()
iv := reflect.Indirect(v)
if !state.sendZero && (!iv.IsValid() || iv.IsNil()) {
return
@@ -610,7 +624,7 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
}
}
if op == nil {
- errorf("can't happen: encode type %s", rt.String())
+ errorf("can't happen: encode type %s", rt)
}
return &op, indir
}
@@ -631,9 +645,9 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
var v reflect.Value
if ut.encIndir == -1 {
// Need to climb up one level to turn value into pointer.
- v = reflect.ValueOf(unsafe.Unreflect(rt, unsafe.Pointer(&p)))
+ v = reflect.NewAt(rt, unsafe.Pointer(&p)).Elem()
} else {
- v = reflect.ValueOf(unsafe.Unreflect(rt, p))
+ v = reflect.NewAt(rt, p).Elem()
}
if !state.sendZero && isZero(v) {
return
@@ -681,7 +695,7 @@ func (enc *Encoder) compileEnc(ut *userTypeInfo) *encEngine {
func (enc *Encoder) getEncEngine(ut *userTypeInfo) *encEngine {
info, err1 := getTypeInfo(ut)
if err1 != nil {
- error(err1)
+ error_(err1)
}
if info.encoder == nil {
// mark this engine as underway before compiling to handle recursive types.
diff --git a/src/pkg/gob/encoder.go b/src/pkg/encoding/gob/encoder.go
index 96101d92b..a15b5a1f9 100644
--- a/src/pkg/gob/encoder.go
+++ b/src/pkg/encoding/gob/encoder.go
@@ -6,8 +6,8 @@ package gob
import (
"bytes"
+ "errors"
"io"
- "os"
"reflect"
"sync"
)
@@ -20,11 +20,16 @@ type Encoder struct {
sent map[reflect.Type]typeId // which types we've already sent
countState *encoderState // stage for writing counts
freeList *encoderState // list of free encoderStates; avoids reallocation
- buf []byte // for collecting the output.
byteBuf bytes.Buffer // buffer for top-level encoderState
- err os.Error
+ err error
}
+// Before we encode a message, we reserve space at the head of the
+// buffer in which to encode its length. This means we can use the
+// buffer to assemble the message without another allocation.
+const maxLength = 9 // Maximum size of an encoded length.
+var spaceForLength = make([]byte, maxLength)
+
// NewEncoder returns a new encoder that will transmit on the io.Writer.
func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
@@ -50,10 +55,10 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.NewError("gob: can't encode type " + rt.String()))
+ enc.setError(errors.New("gob: can't encode type " + rt.String()))
}
-func (enc *Encoder) setError(err os.Error) {
+func (enc *Encoder) setError(err error) {
if enc.err == nil { // remember the first.
enc.err = err
}
@@ -61,20 +66,22 @@ func (enc *Encoder) setError(err os.Error) {
// writeMessage sends the data item preceded by a unsigned count of its length.
func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) {
- enc.countState.encodeUint(uint64(b.Len()))
- // Build the buffer.
- countLen := enc.countState.b.Len()
- total := countLen + b.Len()
- if total > len(enc.buf) {
- enc.buf = make([]byte, total+1000) // extra for growth
- }
- // Place the length before the data.
- // TODO(r): avoid the extra copy here.
- enc.countState.b.Read(enc.buf[0:countLen])
- // Now the data.
- b.Read(enc.buf[countLen:total])
+ // Space has been reserved for the length at the head of the message.
+ // This is a little dirty: we grab the slice from the bytes.Buffer and massage
+ // it by hand.
+ message := b.Bytes()
+ messageLen := len(message) - maxLength
+ // Encode the length.
+ enc.countState.b.Reset()
+ enc.countState.encodeUint(uint64(messageLen))
+ // Copy the length to be a prefix of the message.
+ offset := maxLength - enc.countState.b.Len()
+ copy(message[offset:], enc.countState.b.Bytes())
// Write the data.
- _, err := w.Write(enc.buf[0:total])
+ _, err := w.Write(message[offset:])
+ // Drain the buffer and restore the space at the front for the count of the next message.
+ b.Reset()
+ b.Write(spaceForLength)
if err != nil {
enc.setError(err)
}
@@ -112,7 +119,9 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp
switch st := actual; st.Kind() {
case reflect.Struct:
for i := 0; i < st.NumField(); i++ {
- enc.sendType(w, state, st.Field(i).Type)
+ if isExported(st.Field(i).Name) {
+ enc.sendType(w, state, st.Field(i).Type)
+ }
}
case reflect.Array, reflect.Slice:
enc.sendType(w, state, st.Elem())
@@ -164,7 +173,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
// Encode transmits the data item represented by the empty interface value,
// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) Encode(e interface{}) os.Error {
+func (enc *Encoder) Encode(e interface{}) error {
return enc.EncodeValue(reflect.ValueOf(e))
}
@@ -208,7 +217,7 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
// EncodeValue transmits the data item represented by the reflection value,
// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
+func (enc *Encoder) EncodeValue(value reflect.Value) error {
// Make sure we're single-threaded through here, so multiple
// goroutines can share an encoder.
enc.mutex.Lock()
@@ -224,6 +233,7 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
enc.err = nil
enc.byteBuf.Reset()
+ enc.byteBuf.Write(spaceForLength)
state := enc.newEncoderState(&enc.byteBuf)
enc.sendTypeDescriptor(enc.writer(), state, ut)
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go
index f5ee423cb..c4947cbb8 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/encoding/gob/encoder_test.go
@@ -8,7 +8,6 @@ import (
"bytes"
"fmt"
"io"
- "os"
"reflect"
"strings"
"testing"
@@ -116,7 +115,7 @@ func TestWrongTypeDecoder(t *testing.T) {
badTypeCheck(new(ET4), true, "different type of field", t)
}
-func corruptDataCheck(s string, err os.Error, t *testing.T) {
+func corruptDataCheck(s string, err error, t *testing.T) {
b := bytes.NewBufferString(s)
dec := NewDecoder(b)
err1 := dec.Decode(new(ET2))
@@ -127,7 +126,7 @@ func corruptDataCheck(s string, err os.Error, t *testing.T) {
// Check that we survive bad data.
func TestBadData(t *testing.T) {
- corruptDataCheck("", os.EOF, t)
+ corruptDataCheck("", io.EOF, t)
corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
corruptDataCheck("\x03now is the time for all good men", errBadType, t)
}
@@ -149,7 +148,7 @@ func TestUnsupported(t *testing.T) {
}
}
-func encAndDec(in, out interface{}) os.Error {
+func encAndDec(in, out interface{}) error {
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(in)
@@ -225,7 +224,7 @@ func TestValueError(t *testing.T) {
}
t4p := &Type4{3}
var t4 Type4 // note: not a pointer.
- if err := encAndDec(t4p, t4); err == nil || strings.Index(err.String(), "pointer") < 0 {
+ if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 {
t.Error("expected error about pointer; got", err)
}
}
@@ -310,7 +309,7 @@ var singleTests = []SingleTest{
{[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
// Decode errors
- {172, &testFloat32, "wrong type"},
+ {172, &testFloat32, "type"},
}
func TestSingletons(t *testing.T) {
@@ -333,7 +332,7 @@ func TestSingletons(t *testing.T) {
t.Errorf("expected error decoding %v: %s", test.in, test.err)
continue
case err != nil && test.err != "":
- if strings.Index(err.String(), test.err) < 0 {
+ if strings.Index(err.Error(), test.err) < 0 {
t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
}
continue
@@ -359,7 +358,7 @@ func TestStructNonStruct(t *testing.T) {
var ns NonStruct
if err := encAndDec(s, &ns); err == nil {
t.Error("should get error for struct/non-struct")
- } else if strings.Index(err.String(), "type") < 0 {
+ } else if strings.Index(err.Error(), "type") < 0 {
t.Error("for struct/non-struct expected type error; got", err)
}
// Now try the other way
@@ -369,7 +368,7 @@ func TestStructNonStruct(t *testing.T) {
}
if err := encAndDec(ns, &s); err == nil {
t.Error("should get error for non-struct/struct")
- } else if strings.Index(err.String(), "type") < 0 {
+ } else if strings.Index(err.Error(), "type") < 0 {
t.Error("for non-struct/struct expected type error; got", err)
}
}
@@ -524,7 +523,7 @@ type Bug1Elem struct {
type Bug1StructMap map[string]Bug1Elem
-func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) os.Error {
+func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) error {
return nil
}
@@ -571,10 +570,169 @@ func TestGobMapInterfaceEncode(t *testing.T) {
"bo": []bool{false},
"st": []string{"s"},
}
- buf := bytes.NewBuffer(nil)
- enc := NewEncoder(buf)
+ enc := NewEncoder(new(bytes.Buffer))
err := enc.Encode(m)
if err != nil {
- t.Errorf("gob.Encode map: %s", err)
+ t.Errorf("encode map: %s", err)
+ }
+}
+
+func TestSliceReusesMemory(t *testing.T) {
+ buf := new(bytes.Buffer)
+ // Bytes
+ {
+ x := []byte("abcd")
+ enc := NewEncoder(buf)
+ err := enc.Encode(x)
+ if err != nil {
+ t.Errorf("bytes: encode: %s", err)
+ }
+ // Decode into y, which is big enough.
+ y := []byte("ABCDE")
+ addr := &y[0]
+ dec := NewDecoder(buf)
+ err = dec.Decode(&y)
+ if err != nil {
+ t.Fatal("bytes: decode:", err)
+ }
+ if !bytes.Equal(x, y) {
+ t.Errorf("bytes: expected %q got %q\n", x, y)
+ }
+ if addr != &y[0] {
+ t.Errorf("bytes: unnecessary reallocation")
+ }
+ }
+ // general slice
+ {
+ x := []rune("abcd")
+ enc := NewEncoder(buf)
+ err := enc.Encode(x)
+ if err != nil {
+ t.Errorf("ints: encode: %s", err)
+ }
+ // Decode into y, which is big enough.
+ y := []rune("ABCDE")
+ addr := &y[0]
+ dec := NewDecoder(buf)
+ err = dec.Decode(&y)
+ if err != nil {
+ t.Fatal("ints: decode:", err)
+ }
+ if !reflect.DeepEqual(x, y) {
+ t.Errorf("ints: expected %q got %q\n", x, y)
+ }
+ if addr != &y[0] {
+ t.Errorf("ints: unnecessary reallocation")
+ }
+ }
+}
+
+// Used to crash: negative count in recvMessage.
+func TestBadCount(t *testing.T) {
+ b := []byte{0xfb, 0xa5, 0x82, 0x2f, 0xca, 0x1}
+ if err := NewDecoder(bytes.NewBuffer(b)).Decode(nil); err == nil {
+ t.Error("expected error from bad count")
+ } else if err.Error() != errBadCount.Error() {
+ t.Error("expected bad count error; got", err)
+ }
+}
+
+// Verify that sequential Decoders built on a single input will
+// succeed if the input implements ReadByte and there is no
+// type information in the stream.
+func TestSequentialDecoder(t *testing.T) {
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ const count = 10
+ for i := 0; i < count; i++ {
+ s := fmt.Sprintf("%d", i)
+ if err := enc.Encode(s); err != nil {
+ t.Error("encoder fail:", err)
+ }
+ }
+ for i := 0; i < count; i++ {
+ dec := NewDecoder(b)
+ var s string
+ if err := dec.Decode(&s); err != nil {
+ t.Fatal("decoder fail:", err)
+ }
+ if s != fmt.Sprintf("%d", i) {
+ t.Fatalf("decode expected %d got %s", i, s)
+ }
+ }
+}
+
+// Should be able to have unrepresentable fields (chan, func) as long as they
+// are unexported.
+type Bug2 struct {
+ A int
+ b chan int
+}
+
+func TestUnexportedChan(t *testing.T) {
+ b := Bug2{23, make(chan int)}
+ var stream bytes.Buffer
+ enc := NewEncoder(&stream)
+ if err := enc.Encode(b); err != nil {
+ t.Fatalf("error encoding unexported channel: %s", err)
+ }
+}
+
+func TestSliceIncompatibility(t *testing.T) {
+ var in = []byte{1, 2, 3}
+ var out []int
+ if err := encAndDec(in, &out); err == nil {
+ t.Error("expected compatibility error")
+ }
+}
+
+// Mutually recursive slices of structs caused problems.
+type Bug3 struct {
+ Num int
+ Children []*Bug3
+}
+
+func TestGobPtrSlices(t *testing.T) {
+ in := []*Bug3{
+ {1, nil},
+ {2, nil},
+ }
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(&in)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+
+ var out []*Bug3
+ err = NewDecoder(b).Decode(&out)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(in, out) {
+ t.Fatalf("got %v; wanted %v", out, in)
+ }
+}
+
+// getDecEnginePtr cached engine for ut.base instead of ut.user so we passed
+// a *map and then tried to reuse its engine to decode the inner map.
+func TestPtrToMapOfMap(t *testing.T) {
+ Register(make(map[string]interface{}))
+ subdata := make(map[string]interface{})
+ subdata["bar"] = "baz"
+ data := make(map[string]interface{})
+ data["foo"] = subdata
+
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(data)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ var newData map[string]interface{}
+ err = NewDecoder(b).Decode(&newData)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(data, newData) {
+ t.Fatalf("expected %v got %v", data, newData)
}
}
diff --git a/src/pkg/gob/error.go b/src/pkg/encoding/gob/error.go
index bfd38fc16..92cc0c615 100644
--- a/src/pkg/gob/error.go
+++ b/src/pkg/encoding/gob/error.go
@@ -4,39 +4,40 @@
package gob
-import (
- "fmt"
- "os"
-)
+import "fmt"
// Errors in decoding and encoding are handled using panic and recover.
// Panics caused by user error (that is, everything except run-time panics
// such as "index out of bounds" errors) do not leave the file that caused
-// them, but are instead turned into plain os.Error returns. Encoding and
-// decoding functions and methods that do not return an os.Error either use
+// them, but are instead turned into plain error returns. Encoding and
+// decoding functions and methods that do not return an error either use
// panic to report an error or are guaranteed error-free.
-// A gobError wraps an os.Error and is used to distinguish errors (panics) generated in this package.
+// A gobError is used to distinguish errors (panics) generated in this package.
type gobError struct {
- os.Error
+ err error
}
-// errorf is like error but takes Printf-style arguments to construct an os.Error.
+// errorf is like error_ but takes Printf-style arguments to construct an error.
// It always prefixes the message with "gob: ".
func errorf(format string, args ...interface{}) {
- error(fmt.Errorf("gob: "+format, args...))
+ error_(fmt.Errorf("gob: "+format, args...))
}
// error wraps the argument error and uses it as the argument to panic.
-func error(err os.Error) {
- panic(gobError{Error: err})
+func error_(err error) {
+ panic(gobError{err})
}
// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
-// plain os.Error. It overwrites the error return of the function that deferred its call.
-func catchError(err *os.Error) {
+// plain error. It overwrites the error return of the function that deferred its call.
+func catchError(err *error) {
if e := recover(); e != nil {
- *err = e.(gobError).Error // Will re-panic if not one of our errors, such as a runtime error.
+ ge, ok := e.(gobError)
+ if !ok {
+ panic(e)
+ }
+ *err = ge.err
}
return
}
diff --git a/src/pkg/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go
index 371a43c8f..45240d764 100644
--- a/src/pkg/gob/gobencdec_test.go
+++ b/src/pkg/encoding/gob/gobencdec_test.go
@@ -8,10 +8,12 @@ package gob
import (
"bytes"
+ "errors"
"fmt"
- "os"
+ "io"
"strings"
"testing"
+ "time"
)
// Types that implement the GobEncoder/Decoder interfaces.
@@ -34,7 +36,7 @@ type ValueGobber string // encodes with a value, decodes with a pointer.
// The relevant methods
-func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
+func (g *ByteStruct) GobEncode() ([]byte, error) {
b := make([]byte, 3)
b[0] = g.a
b[1] = g.a + 1
@@ -42,68 +44,68 @@ func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
return b, nil
}
-func (g *ByteStruct) GobDecode(data []byte) os.Error {
+func (g *ByteStruct) GobDecode(data []byte) error {
if g == nil {
- return os.NewError("NIL RECEIVER")
+ return errors.New("NIL RECEIVER")
}
// Expect N sequential-valued bytes.
if len(data) == 0 {
- return os.EOF
+ return io.EOF
}
g.a = data[0]
for i, c := range data {
if c != g.a+byte(i) {
- return os.NewError("invalid data sequence")
+ return errors.New("invalid data sequence")
}
}
return nil
}
-func (g *StringStruct) GobEncode() ([]byte, os.Error) {
+func (g *StringStruct) GobEncode() ([]byte, error) {
return []byte(g.s), nil
}
-func (g *StringStruct) GobDecode(data []byte) os.Error {
+func (g *StringStruct) GobDecode(data []byte) error {
// Expect N sequential-valued bytes.
if len(data) == 0 {
- return os.EOF
+ return io.EOF
}
a := data[0]
for i, c := range data {
if c != a+byte(i) {
- return os.NewError("invalid data sequence")
+ return errors.New("invalid data sequence")
}
}
g.s = string(data)
return nil
}
-func (a *ArrayStruct) GobEncode() ([]byte, os.Error) {
+func (a *ArrayStruct) GobEncode() ([]byte, error) {
return a.a[:], nil
}
-func (a *ArrayStruct) GobDecode(data []byte) os.Error {
+func (a *ArrayStruct) GobDecode(data []byte) error {
if len(data) != len(a.a) {
- return os.NewError("wrong length in array decode")
+ return errors.New("wrong length in array decode")
}
copy(a.a[:], data)
return nil
}
-func (g *Gobber) GobEncode() ([]byte, os.Error) {
+func (g *Gobber) GobEncode() ([]byte, error) {
return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
}
-func (g *Gobber) GobDecode(data []byte) os.Error {
+func (g *Gobber) GobDecode(data []byte) error {
_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
return err
}
-func (v ValueGobber) GobEncode() ([]byte, os.Error) {
+func (v ValueGobber) GobEncode() ([]byte, error) {
return []byte(fmt.Sprintf("VALUE=%s", v)), nil
}
-func (v *ValueGobber) GobDecode(data []byte) os.Error {
+func (v *ValueGobber) GobDecode(data []byte) error {
_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
return err
}
@@ -372,7 +374,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
}
- if strings.Index(err.String(), "type") < 0 {
+ if strings.Index(err.Error(), "type") < 0 {
t.Fatal("expected type error; got", err)
}
// Non-encoder to GobDecoder: error
@@ -386,7 +388,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
if err == nil {
t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
}
- if strings.Index(err.String(), "type") < 0 {
+ if strings.Index(err.Error(), "type") < 0 {
t.Fatal("expected type error; got", err)
}
}
@@ -424,7 +426,7 @@ func TestGobEncoderNonStructSingleton(t *testing.T) {
t.Fatal("decode error:", err)
}
if x != 1234 {
- t.Errorf("expected 1234 got %c", x)
+ t.Errorf("expected 1234 got %d", x)
}
}
@@ -488,3 +490,105 @@ func TestGobEncoderIgnoreNilEncoder(t *testing.T) {
t.Errorf("expected x.G = nil, got %v", x.G)
}
}
+
+type gobDecoderBug0 struct {
+ foo, bar string
+}
+
+func (br *gobDecoderBug0) String() string {
+ return br.foo + "-" + br.bar
+}
+
+func (br *gobDecoderBug0) GobEncode() ([]byte, error) {
+ return []byte(br.String()), nil
+}
+
+func (br *gobDecoderBug0) GobDecode(b []byte) error {
+ br.foo = "foo"
+ br.bar = "bar"
+ return nil
+}
+
+// This was a bug: the receiver has a different indirection level
+// than the variable.
+func TestGobEncoderExtraIndirect(t *testing.T) {
+ gdb := &gobDecoderBug0{"foo", "bar"}
+ buf := new(bytes.Buffer)
+ e := NewEncoder(buf)
+ if err := e.Encode(gdb); err != nil {
+ t.Fatalf("encode: %v", err)
+ }
+ d := NewDecoder(buf)
+ var got *gobDecoderBug0
+ if err := d.Decode(&got); err != nil {
+ t.Fatalf("decode: %v", err)
+ }
+ if got.foo != gdb.foo || got.bar != gdb.bar {
+ t.Errorf("got = %q, want %q", got, gdb)
+ }
+}
+
+// Another bug: this caused a crash with the new Go1 Time type.
+// We throw in a gob-encoding array, to test another case of isZero
+
+type isZeroBug struct {
+ T time.Time
+ S string
+ I int
+ A isZeroBugArray
+}
+
+type isZeroBugArray [2]uint8
+
+// Receiver is value, not pointer, to test isZero of array.
+func (a isZeroBugArray) GobEncode() (b []byte, e error) {
+ b = append(b, a[:]...)
+ return b, nil
+}
+
+func (a *isZeroBugArray) GobDecode(data []byte) error {
+ if len(data) != len(a) {
+ return io.EOF
+ }
+ a[0] = data[0]
+ a[1] = data[1]
+ return nil
+}
+
+func TestGobEncodeIsZero(t *testing.T) {
+ x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err := enc.Encode(x)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ var y isZeroBug
+ dec := NewDecoder(b)
+ err = dec.Decode(&y)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if x != y {
+ t.Fatalf("%v != %v", x, y)
+ }
+}
+
+func TestGobEncodePtrError(t *testing.T) {
+ var err error
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err = enc.Encode(&err)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ dec := NewDecoder(b)
+ err2 := fmt.Errorf("foo")
+ err = dec.Decode(&err2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if err2 != nil {
+ t.Fatalf("expected nil, got %v", err2)
+ }
+}
diff --git a/src/pkg/gob/timing_test.go b/src/pkg/encoding/gob/timing_test.go
index 2a2be7336..b9371c423 100644
--- a/src/pkg/gob/timing_test.go
+++ b/src/pkg/encoding/gob/timing_test.go
@@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
func BenchmarkEndToEndPipe(b *testing.B) {
r, w, err := os.Pipe()
if err != nil {
- panic("can't get pipe:" + err.String())
+ b.Fatal("can't get pipe:", err)
}
benchmarkEndToEnd(r, w, b)
}
@@ -53,8 +53,9 @@ func TestCountEncodeMallocs(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
- runtime.UpdateMemStats()
- mallocs := 0 - runtime.MemStats.Mallocs
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ mallocs := 0 - memstats.Mallocs
const count = 1000
for i := 0; i < count; i++ {
err := enc.Encode(bench)
@@ -62,8 +63,8 @@ func TestCountEncodeMallocs(t *testing.T) {
t.Fatal("encode:", err)
}
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
+ runtime.ReadMemStats(memstats)
+ mallocs += memstats.Mallocs
fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
}
@@ -79,8 +80,9 @@ func TestCountDecodeMallocs(t *testing.T) {
}
}
dec := NewDecoder(&buf)
- runtime.UpdateMemStats()
- mallocs := 0 - runtime.MemStats.Mallocs
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ mallocs := 0 - memstats.Mallocs
for i := 0; i < count; i++ {
*bench = Bench{}
err := dec.Decode(&bench)
@@ -88,7 +90,7 @@ func TestCountDecodeMallocs(t *testing.T) {
t.Fatal("decode:", err)
}
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
+ runtime.ReadMemStats(memstats)
+ mallocs += memstats.Mallocs
fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
}
diff --git a/src/pkg/gob/type.go b/src/pkg/encoding/gob/type.go
index b2f716c4b..0dd7a0a77 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/encoding/gob/type.go
@@ -5,12 +5,13 @@
package gob
import (
+ "errors"
"fmt"
"os"
"reflect"
"sync"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// userTypeInfo stores the information associated with a type the user has handed
@@ -36,7 +37,7 @@ var (
// validType returns, and saves, the information associated with user-provided type rt.
// If the user type is not valid, err will be non-nil. To be used when the error handler
// is not set up.
-func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
+func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
userTypeLock.RLock()
ut = userTypeCache[rt]
userTypeLock.RUnlock()
@@ -67,7 +68,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.NewError("can't represent recursive pointer type " + ut.base.String())
+ return nil, errors.New("can't represent recursive pointer type " + ut.base.String())
}
if ut.indir%2 == 0 {
slowpoke = slowpoke.Elem()
@@ -125,10 +126,11 @@ func implementsInterface(typ, gobEncDecType reflect.Type) (success bool, indir i
func userType(rt reflect.Type) *userTypeInfo {
ut, err := validUserType(rt)
if err != nil {
- error(err)
+ error_(err)
}
return ut
}
+
// A typeId represents a gob Type as an integer that can be passed on the wire.
// Internally, typeIds are used as keys to a map to recover the underlying type info.
type typeId int32
@@ -150,6 +152,10 @@ var idToType = make(map[typeId]gobType)
var builtinIdToType map[typeId]gobType // set in init() after builtins are established
func setTypeId(typ gobType) {
+ // When building recursive types, someone may get there before us.
+ if typ.id() != 0 {
+ return
+ }
nextId++
typ.setId(nextId)
idToType[nextId] = typ
@@ -178,7 +184,10 @@ func (t typeId) name() string {
return t.gobType().name()
}
-// Common elements of all types.
+// CommonType holds elements of all types.
+// It is a historical artifact, kept for binary compatibility and exported
+// only for the benefit of the package's encoding of type descriptors. It is
+// not intended for direct use by clients.
type CommonType struct {
Name string
Id typeId
@@ -341,6 +350,11 @@ func newSliceType(name string) *sliceType {
func (s *sliceType) init(elem gobType) {
// Set our type id before evaluating the element's, in case it's our own.
setTypeId(s)
+ // See the comments about ids in newTypeObject. Only slices and
+ // structs have mutual recursion.
+ if elem.id() == 0 {
+ setTypeId(elem)
+ }
s.Elem = elem.id()
}
@@ -396,16 +410,16 @@ func newStructType(name string) *structType {
// of ut.
// This is only called from the encoding side. The decoding side
// works through typeIds and userTypeInfos alone.
-func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {
// Does this type implement GobEncoder?
if ut.isGobEncoder {
return newGobEncoderType(name), nil
}
- var err os.Error
+ var err error
var type0, type1 gobType
defer func() {
if err != nil {
- types[rt] = nil, false
+ delete(types, rt)
}
}()
// Install the top-level type before the subtypes (e.g. struct before
@@ -498,12 +512,19 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
if err != nil {
return nil, err
}
+ // Some mutually recursive types can cause us to be here while
+ // still defining the element. Fix the element type id here.
+ // We could do this more neatly by setting the id at the start of
+ // building every type, but that would break binary compatibility.
+ if gt.id() == 0 {
+ setTypeId(gt)
+ }
st.Field = append(st.Field, &fieldType{f.Name, gt.id()})
}
return st, nil
default:
- return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
@@ -516,7 +537,7 @@ func isExported(name string) bool {
// getBaseType returns the Gob type describing the given reflect.Type's base type.
// typeLock must be held.
-func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
+func getBaseType(name string, rt reflect.Type) (gobType, error) {
ut := userType(rt)
return getType(name, ut, ut.base)
}
@@ -526,7 +547,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
// which may be pointers. All other types are handled through the
// base type, never a pointer.
// typeLock must be held.
-func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
+func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {
typ, present := types[rt]
if present {
return typ, nil
@@ -609,7 +630,7 @@ type typeInfo struct {
var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
// typeLock must be held.
-func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
+func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {
rt := ut.base
if ut.isGobEncoder {
// We want the user type, not the base type.
@@ -658,7 +679,7 @@ func getTypeInfo(ut *userTypeInfo) (*typeInfo, os.Error) {
func mustGetTypeInfo(rt reflect.Type) *typeInfo {
t, err := getTypeInfo(userType(rt))
if err != nil {
- panic("getTypeInfo: " + err.String())
+ panic("getTypeInfo: " + err.Error())
}
return t
}
@@ -678,7 +699,7 @@ type GobEncoder interface {
// GobEncode returns a byte slice representing the encoding of the
// receiver for transmission to a GobDecoder, usually of the same
// concrete type.
- GobEncode() ([]byte, os.Error)
+ GobEncode() ([]byte, error)
}
// GobDecoder is the interface describing data that provides its own
@@ -687,7 +708,7 @@ type GobDecoder interface {
// GobDecode overwrites the receiver, which must be a pointer,
// with the value represented by the byte slice, which was written
// by GobEncode, usually for the same concrete type.
- GobDecode([]byte) os.Error
+ GobDecode([]byte) error
}
var (
@@ -702,18 +723,19 @@ func RegisterName(name string, value interface{}) {
// reserved for nil
panic("attempt to register empty name")
}
- base := userType(reflect.TypeOf(value)).base
- // Check for incompatible duplicates.
- if t, ok := nameToConcreteType[name]; ok && t != base {
- panic("gob: registering duplicate types for " + name)
+ ut := userType(reflect.TypeOf(value))
+ // Check for incompatible duplicates. The name must refer to the
+ // same user type, and vice versa.
+ if t, ok := nameToConcreteType[name]; ok && t != ut.user {
+ panic(fmt.Sprintf("gob: registering duplicate types for %q: %s != %s", name, t, ut.user))
}
- if n, ok := concreteTypeToName[base]; ok && n != name {
- panic("gob: registering duplicate names for " + base.String())
+ if n, ok := concreteTypeToName[ut.base]; ok && n != name {
+ panic(fmt.Sprintf("gob: registering duplicate names for %s: %q != %q", ut.user, n, name))
}
// Store the name and type provided by the user....
nameToConcreteType[name] = reflect.TypeOf(value)
// but the flattened type in the type table, since that's what decode needs.
- concreteTypeToName[base] = name
+ concreteTypeToName[ut.base] = name
}
// Register records a type, identified by a value for that type, under its
diff --git a/src/pkg/gob/type_test.go b/src/pkg/encoding/gob/type_test.go
index 411ffb797..42bdb4cf7 100644
--- a/src/pkg/gob/type_test.go
+++ b/src/pkg/encoding/gob/type_test.go
@@ -28,7 +28,7 @@ func getTypeUnlocked(name string, rt reflect.Type) gobType {
defer typeLock.Unlock()
t, err := getBaseType(name, rt)
if err != nil {
- panic("getTypeUnlocked: " + err.String())
+ panic("getTypeUnlocked: " + err.Error())
}
return t
}
@@ -151,3 +151,11 @@ func TestStructType(t *testing.T) {
t.Errorf("struct printed as %q; expected %q", str, expected)
}
}
+
+// Should be OK to register the same type multiple times, as long as they're
+// at the same level of indirection.
+func TestRegistration(t *testing.T) {
+ type T struct{ a int }
+ Register(new(T))
+ Register(new(T))
+}
diff --git a/src/pkg/encoding/hex/Makefile b/src/pkg/encoding/hex/Makefile
deleted file mode 100644
index 22049f43b..000000000
--- a/src/pkg/encoding/hex/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/hex
-GOFILES=\
- hex.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index e7ea8b0f2..167d00e03 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/encoding/hex/hex.go
@@ -7,9 +7,9 @@ package hex
import (
"bytes"
+ "errors"
+ "fmt"
"io"
- "os"
- "strconv"
)
const hextable = "0123456789abcdef"
@@ -30,16 +30,14 @@ func Encode(dst, src []byte) int {
return len(src) * 2
}
-// OddLengthInputError results from decoding an odd length slice.
-type OddLengthInputError struct{}
+// ErrLength results from decoding an odd length slice.
+var ErrLength = errors.New("encoding/hex: odd length hex string")
-func (OddLengthInputError) String() string { return "odd length hex string" }
+// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
+type InvalidByteError byte
-// InvalidHexCharError results from finding an invalid character in a hex string.
-type InvalidHexCharError byte
-
-func (e InvalidHexCharError) String() string {
- return "invalid hex char: " + strconv.Itoa(int(e))
+func (e InvalidByteError) Error() string {
+ return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
}
func DecodedLen(x int) int { return x / 2 }
@@ -47,21 +45,20 @@ func DecodedLen(x int) int { return x / 2 }
// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
// number of bytes written to dst.
//
-// If Decode encounters invalid input, it returns an OddLengthInputError or an
-// InvalidHexCharError.
-func Decode(dst, src []byte) (int, os.Error) {
+// If Decode encounters invalid input, it returns an error describing the failure.
+func Decode(dst, src []byte) (int, error) {
if len(src)%2 == 1 {
- return 0, OddLengthInputError{}
+ return 0, ErrLength
}
for i := 0; i < len(src)/2; i++ {
a, ok := fromHexChar(src[i*2])
if !ok {
- return 0, InvalidHexCharError(src[i*2])
+ return 0, InvalidByteError(src[i*2])
}
b, ok := fromHexChar(src[i*2+1])
if !ok {
- return 0, InvalidHexCharError(src[i*2+1])
+ return 0, InvalidByteError(src[i*2+1])
}
dst[i] = (a << 4) | b
}
@@ -91,7 +88,7 @@ func EncodeToString(src []byte) string {
}
// DecodeString returns the bytes represented by the hexadecimal string s.
-func DecodeString(s string) ([]byte, os.Error) {
+func DecodeString(s string) ([]byte, error) {
src := []byte(s)
dst := make([]byte, DecodedLen(len(src)))
_, err := Decode(dst, src)
@@ -104,8 +101,8 @@ func DecodeString(s string) ([]byte, os.Error) {
// Dump returns a string that contains a hex dump of the given data. The format
// of the hex dump matches the output of `hexdump -C` on the command line.
func Dump(data []byte) string {
- buf := bytes.NewBuffer(nil)
- dumper := Dumper(buf)
+ var buf bytes.Buffer
+ dumper := Dumper(&buf)
dumper.Write(data)
dumper.Close()
return string(buf.Bytes())
@@ -133,7 +130,7 @@ func toChar(b byte) byte {
return b
}
-func (h *dumper) Write(data []byte) (n int, err os.Error) {
+func (h *dumper) Write(data []byte) (n int, err 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.
@@ -185,7 +182,7 @@ func (h *dumper) Write(data []byte) (n int, err os.Error) {
return
}
-func (h *dumper) Close() (err os.Error) {
+func (h *dumper) Close() (err error) {
// See the comments in Write() for the details of this format.
if h.used == 0 {
return
diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
index 8e1838e51..456f9eac7 100644
--- a/src/pkg/encoding/hex/hex_test.go
+++ b/src/pkg/encoding/hex/hex_test.go
@@ -9,141 +9,98 @@ import (
"testing"
)
-type encodeTest struct {
- in, out []byte
+type encDecTest struct {
+ enc string
+ dec []byte
}
-var encodeTests = []encodeTest{
- {[]byte{}, []byte{}},
- {[]byte{0x01}, []byte{'0', '1'}},
- {[]byte{0xff}, []byte{'f', 'f'}},
- {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
- {[]byte{0}, []byte{'0', '0'}},
- {[]byte{1}, []byte{'0', '1'}},
- {[]byte{2}, []byte{'0', '2'}},
- {[]byte{3}, []byte{'0', '3'}},
- {[]byte{4}, []byte{'0', '4'}},
- {[]byte{5}, []byte{'0', '5'}},
- {[]byte{6}, []byte{'0', '6'}},
- {[]byte{7}, []byte{'0', '7'}},
- {[]byte{8}, []byte{'0', '8'}},
- {[]byte{9}, []byte{'0', '9'}},
- {[]byte{10}, []byte{'0', 'a'}},
- {[]byte{11}, []byte{'0', 'b'}},
- {[]byte{12}, []byte{'0', 'c'}},
- {[]byte{13}, []byte{'0', 'd'}},
- {[]byte{14}, []byte{'0', 'e'}},
- {[]byte{15}, []byte{'0', 'f'}},
+var encDecTests = []encDecTest{
+ {"", []byte{}},
+ {"0001020304050607", []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+ {"08090a0b0c0d0e0f", []byte{8, 9, 10, 11, 12, 13, 14, 15}},
+ {"f0f1f2f3f4f5f6f7", []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7}},
+ {"f8f9fafbfcfdfeff", []byte{0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}},
+ {"67", []byte{'g'}},
+ {"e3a1", []byte{0xe3, 0xa1}},
}
func TestEncode(t *testing.T) {
- for i, test := range encodeTests {
- dst := make([]byte, EncodedLen(len(test.in)))
- n := Encode(dst, test.in)
+ for i, test := range encDecTests {
+ dst := make([]byte, EncodedLen(len(test.dec)))
+ n := Encode(dst, test.dec)
if n != len(dst) {
t.Errorf("#%d: bad return value: got: %d want: %d", i, n, len(dst))
}
- if bytes.Compare(dst, test.out) != 0 {
- t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ if string(dst) != test.enc {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.enc)
}
}
}
-type decodeTest struct {
- in, out []byte
- ok bool
-}
-
-var decodeTests = []decodeTest{
- {[]byte{}, []byte{}, true},
- {[]byte{'0'}, []byte{}, false},
- {[]byte{'0', 'g'}, []byte{}, false},
- {[]byte{'0', '\x01'}, []byte{}, false},
- {[]byte{'0', '0'}, []byte{0}, true},
- {[]byte{'0', '1'}, []byte{1}, true},
- {[]byte{'0', '2'}, []byte{2}, true},
- {[]byte{'0', '3'}, []byte{3}, true},
- {[]byte{'0', '4'}, []byte{4}, true},
- {[]byte{'0', '5'}, []byte{5}, true},
- {[]byte{'0', '6'}, []byte{6}, true},
- {[]byte{'0', '7'}, []byte{7}, true},
- {[]byte{'0', '8'}, []byte{8}, true},
- {[]byte{'0', '9'}, []byte{9}, true},
- {[]byte{'0', 'a'}, []byte{10}, true},
- {[]byte{'0', 'b'}, []byte{11}, true},
- {[]byte{'0', 'c'}, []byte{12}, true},
- {[]byte{'0', 'd'}, []byte{13}, true},
- {[]byte{'0', 'e'}, []byte{14}, true},
- {[]byte{'0', 'f'}, []byte{15}, true},
- {[]byte{'0', 'A'}, []byte{10}, true},
- {[]byte{'0', 'B'}, []byte{11}, true},
- {[]byte{'0', 'C'}, []byte{12}, true},
- {[]byte{'0', 'D'}, []byte{13}, true},
- {[]byte{'0', 'E'}, []byte{14}, true},
- {[]byte{'0', 'F'}, []byte{15}, true},
-}
-
func TestDecode(t *testing.T) {
- for i, test := range decodeTests {
- dst := make([]byte, DecodedLen(len(test.in)))
- n, err := Decode(dst, test.in)
- if err == nil && n != len(dst) {
+ for i, test := range encDecTests {
+ dst := make([]byte, DecodedLen(len(test.enc)))
+ n, err := Decode(dst, []byte(test.enc))
+ if err != nil {
t.Errorf("#%d: bad return value: got:%d want:%d", i, n, len(dst))
- }
- if test.ok != (err == nil) {
- t.Errorf("#%d: unexpected err value: %s", i, err)
- }
- if err == nil && bytes.Compare(dst, test.out) != 0 {
- t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+ } else if !bytes.Equal(dst, test.dec) {
+ t.Errorf("#%d: got: %#v want: %#v", i, dst, test.dec)
}
}
}
-type encodeStringTest struct {
- in []byte
- out string
-}
-
-var encodeStringTests = []encodeStringTest{
- {[]byte{}, ""},
- {[]byte{0}, "00"},
- {[]byte{0, 1}, "0001"},
- {[]byte{0, 1, 255}, "0001ff"},
+func TestEncodeToString(t *testing.T) {
+ for i, test := range encDecTests {
+ s := EncodeToString(test.dec)
+ if s != test.enc {
+ t.Errorf("#%d got:%s want:%s", i, s, test.enc)
+ }
+ }
}
-func TestEncodeToString(t *testing.T) {
- for i, test := range encodeStringTests {
- s := EncodeToString(test.in)
- if s != test.out {
- t.Errorf("#%d got:%s want:%s", i, s, test.out)
+func TestDecodeString(t *testing.T) {
+ for i, test := range encDecTests {
+ dst, err := DecodeString(test.enc)
+ if err != nil {
+ t.Errorf("#%d: unexpected err value: %s", i, err)
+ continue
+ }
+ if bytes.Compare(dst, test.dec) != 0 {
+ t.Errorf("#%d: got: %#v want: #%v", i, dst, test.dec)
}
}
}
-type decodeStringTest struct {
+type errTest struct {
in string
- out []byte
- ok bool
+ err string
}
-var decodeStringTests = []decodeStringTest{
- {"", []byte{}, true},
- {"0", []byte{}, false},
- {"00", []byte{0}, true},
- {"0\x01", []byte{}, false},
- {"0g", []byte{}, false},
- {"00ff00", []byte{0, 255, 0}, true},
- {"0000ff", []byte{0, 0, 255}, true},
+var errTests = []errTest{
+ {"0", "encoding/hex: odd length hex string"},
+ {"0g", "encoding/hex: invalid byte: U+0067 'g'"},
+ {"0\x01", "encoding/hex: invalid byte: U+0001"},
}
-func TestDecodeString(t *testing.T) {
- for i, test := range decodeStringTests {
- dst, err := DecodeString(test.in)
- if test.ok != (err == nil) {
- t.Errorf("#%d: unexpected err value: %s", i, err)
+func TestInvalidErr(t *testing.T) {
+ for i, test := range errTests {
+ dst := make([]byte, DecodedLen(len(test.in)))
+ _, err := Decode(dst, []byte(test.in))
+ if err == nil {
+ t.Errorf("#%d: expected error; got none", i)
+ } else if err.Error() != test.err {
+ t.Errorf("#%d: got: %v want: %v", i, err, test.err)
}
- if err == nil && bytes.Compare(dst, test.out) != 0 {
- t.Errorf("#%d: got: %#v want: #%v", i, dst, test.out)
+ }
+}
+
+func TestInvalidStringErr(t *testing.T) {
+ for i, test := range errTests {
+ _, err := DecodeString(test.in)
+ if err == nil {
+ t.Errorf("#%d: expected error; got none", i)
+ } else if err.Error() != test.err {
+ t.Errorf("#%d: got: %v want: %v", i, err, test.err)
}
}
}
@@ -155,8 +112,8 @@ func TestDumper(t *testing.T) {
}
for stride := 1; stride < len(in); stride++ {
- out := bytes.NewBuffer(nil)
- dumper := Dumper(out)
+ var out bytes.Buffer
+ dumper := Dumper(&out)
done := 0
for done < len(in) {
todo := done + stride
diff --git a/src/pkg/encoding/json/bench_test.go b/src/pkg/encoding/json/bench_test.go
new file mode 100644
index 000000000..333c1c0ce
--- /dev/null
+++ b/src/pkg/encoding/json/bench_test.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.
+
+// Large data benchmark.
+// The JSON data is a summary of agl's changes in the
+// go, webkit, and chromium open source projects.
+// We benchmark converting between the JSON form
+// and in-memory data structures.
+
+package json
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type codeResponse struct {
+ Tree *codeNode `json:"tree"`
+ Username string `json:"username"`
+}
+
+type codeNode struct {
+ Name string `json:"name"`
+ Kids []*codeNode `json:"kids"`
+ CLWeight float64 `json:"cl_weight"`
+ Touches int `json:"touches"`
+ MinT int64 `json:"min_t"`
+ MaxT int64 `json:"max_t"`
+ MeanT int64 `json:"mean_t"`
+}
+
+var codeJSON []byte
+var codeStruct codeResponse
+
+func codeInit() {
+ f, err := os.Open("testdata/code.json.gz")
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+ gz, err := gzip.NewReader(f)
+ if err != nil {
+ panic(err)
+ }
+ data, err := ioutil.ReadAll(gz)
+ if err != nil {
+ panic(err)
+ }
+
+ codeJSON = data
+
+ if err := Unmarshal(codeJSON, &codeStruct); err != nil {
+ panic("unmarshal code.json: " + err.Error())
+ }
+
+ if data, err = Marshal(&codeStruct); err != nil {
+ panic("marshal code.json: " + err.Error())
+ }
+
+ if !bytes.Equal(data, codeJSON) {
+ println("different lengths", len(data), len(codeJSON))
+ for i := 0; i < len(data) && i < len(codeJSON); i++ {
+ if data[i] != codeJSON[i] {
+ println("re-marshal: changed at byte", i)
+ println("orig: ", string(codeJSON[i-10:i+10]))
+ println("new: ", string(data[i-10:i+10]))
+ break
+ }
+ }
+ panic("re-marshal code.json: different result")
+ }
+}
+
+func BenchmarkCodeEncoder(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ enc := NewEncoder(ioutil.Discard)
+ for i := 0; i < b.N; i++ {
+ if err := enc.Encode(&codeStruct); err != nil {
+ b.Fatal("Encode:", err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeMarshal(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ for i := 0; i < b.N; i++ {
+ if _, err := Marshal(&codeStruct); err != nil {
+ b.Fatal("Marshal:", err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeDecoder(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ var buf bytes.Buffer
+ dec := NewDecoder(&buf)
+ var r codeResponse
+ for i := 0; i < b.N; i++ {
+ buf.Write(codeJSON)
+ // hide EOF
+ buf.WriteByte('\n')
+ buf.WriteByte('\n')
+ buf.WriteByte('\n')
+ if err := dec.Decode(&r); err != nil {
+ b.Fatal("Decode:", err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshal(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ for i := 0; i < b.N; i++ {
+ var r codeResponse
+ if err := Unmarshal(codeJSON, &r); err != nil {
+ b.Fatal("Unmmarshal:", err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshalReuse(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ var r codeResponse
+ for i := 0; i < b.N; i++ {
+ if err := Unmarshal(codeJSON, &r); err != nil {
+ b.Fatal("Unmmarshal:", err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
diff --git a/src/pkg/json/decode.go b/src/pkg/encoding/json/decode.go
index b7129f984..110c6fd62 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/encoding/json/decode.go
@@ -9,30 +9,34 @@ package json
import (
"encoding/base64"
- "os"
+ "errors"
+ "fmt"
"reflect"
"runtime"
"strconv"
"strings"
"unicode"
- "utf16"
- "utf8"
+ "unicode/utf16"
+ "unicode/utf8"
)
// Unmarshal parses the JSON-encoded data and stores the result
// in the value pointed to by v.
//
-// Unmarshal traverses the value v recursively.
-// If an encountered value implements the Unmarshaler interface,
-// Unmarshal calls its UnmarshalJSON method with a well-formed
-// JSON encoding.
-//
-// Otherwise, Unmarshal uses the inverse of the encodings that
+// Unmarshal uses the inverse of the encodings that
// Marshal uses, allocating maps, slices, and pointers as necessary,
// with the following additional rules:
//
-// To unmarshal a JSON value into a nil interface value, the
-// type stored in the interface value is one of:
+// To unmarshal JSON into a pointer, Unmarshal first handles the case of
+// the JSON being the JSON literal null. In that case, Unmarshal sets
+// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
+// the value pointed at by the pointer. If the pointer is nil, Unmarshal
+// allocates a new value for it to point to.
+//
+// To unmarshal JSON into an interface value, Unmarshal unmarshals
+// the JSON into the concrete value contained in the interface value.
+// If the interface value is nil, that is, has no concrete value stored in it,
+// Unmarshal stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
@@ -47,7 +51,7 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
-func Unmarshal(data []byte, v interface{}) os.Error {
+func Unmarshal(data []byte, v interface{}) error {
d := new(decodeState).init(data)
// Quick check for well-formedness.
@@ -67,7 +71,7 @@ func Unmarshal(data []byte, v interface{}) os.Error {
// encoding. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
type Unmarshaler interface {
- UnmarshalJSON([]byte) os.Error
+ UnmarshalJSON([]byte) error
}
// An UnmarshalTypeError describes a JSON value that was
@@ -77,7 +81,7 @@ type UnmarshalTypeError struct {
Type reflect.Type // type of Go value it could not be assigned to
}
-func (e *UnmarshalTypeError) String() string {
+func (e *UnmarshalTypeError) Error() string {
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
}
@@ -89,7 +93,7 @@ type UnmarshalFieldError struct {
Field reflect.StructField
}
-func (e *UnmarshalFieldError) String() string {
+func (e *UnmarshalFieldError) Error() string {
return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
}
@@ -99,7 +103,7 @@ type InvalidUnmarshalError struct {
Type reflect.Type
}
-func (e *InvalidUnmarshalError) String() string {
+func (e *InvalidUnmarshalError) Error() string {
if e.Type == nil {
return "json: Unmarshal(nil)"
}
@@ -110,13 +114,13 @@ func (e *InvalidUnmarshalError) String() string {
return "json: Unmarshal(nil " + e.Type.String() + ")"
}
-func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
+func (d *decodeState) unmarshal(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
- err = r.(os.Error)
+ err = r.(error)
}
}()
@@ -139,14 +143,14 @@ type decodeState struct {
off int // read offset in data
scan scanner
nextscan scanner // for calls to nextValue
- savedError os.Error
+ savedError error
tempstr string // scratch space to avoid some allocations
}
// errPhase is used for errors that should not happen unless
// there is a bug in the JSON decoder or something is editing
// the data slice while the decoder executes.
-var errPhase = os.NewError("JSON decoder out of sync - data changing underfoot?")
+var errPhase = errors.New("JSON decoder out of sync - data changing underfoot?")
func (d *decodeState) init(data []byte) *decodeState {
d.data = data
@@ -156,13 +160,13 @@ func (d *decodeState) init(data []byte) *decodeState {
}
// error aborts the decoding by panicking with err.
-func (d *decodeState) error(err os.Error) {
+func (d *decodeState) error(err error) {
panic(err)
}
// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
-func (d *decodeState) saveError(err os.Error) {
+func (d *decodeState) saveError(err error) {
if d.savedError == nil {
d.savedError = err
}
@@ -224,8 +228,10 @@ func (d *decodeState) value(v reflect.Value) {
// d.scan thinks we're still at the beginning of the item.
// Feed in an empty string - the shortest, simplest value -
// so that it knows we got to the end of the value.
- if d.scan.step == stateRedo {
- panic("redo")
+ if d.scan.redo {
+ // rewind.
+ d.scan.redo = false
+ d.scan.step = stateBeginValue
}
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
@@ -250,8 +256,8 @@ func (d *decodeState) value(v reflect.Value) {
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
-// if wantptr is true, indirect stops at the last pointer.
-func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
+func (d *decodeState) indirect(v reflect.Value, decodingNull 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.
@@ -277,7 +283,7 @@ func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, refl
break
}
- if pv.Elem().Kind() != reflect.Ptr && wantptr && pv.CanSet() && !isUnmarshaler {
+ if pv.Elem().Kind() != reflect.Ptr && decodingNull && pv.CanSet() {
return nil, pv
}
if pv.IsNil() {
@@ -314,25 +320,22 @@ func (d *decodeState) array(v reflect.Value) {
}
v = pv
- // Decoding into nil interface? Switch to non-reflect code.
- iv := v
- ok := iv.Kind() == reflect.Interface
- if ok {
- iv.Set(reflect.ValueOf(d.arrayInterface()))
- return
- }
-
// Check type of target.
- av := v
- if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
+ switch v.Kind() {
+ default:
d.saveError(&UnmarshalTypeError{"array", v.Type()})
d.off--
d.next()
return
+ case reflect.Interface:
+ // Decoding into nil interface? Switch to non-reflect code.
+ v.Set(reflect.ValueOf(d.arrayInterface()))
+ return
+ case reflect.Array:
+ case reflect.Slice:
+ break
}
- sv := v
-
i := 0
for {
// Look ahead for ] - can only happen on first iteration.
@@ -346,23 +349,25 @@ func (d *decodeState) array(v reflect.Value) {
d.scan.undo(op)
// Get element of array, growing if necessary.
- if i >= av.Cap() && sv.IsValid() {
- newcap := sv.Cap() + sv.Cap()/2
- if newcap < 4 {
- newcap = 4
+ if v.Kind() == reflect.Slice {
+ // Grow slice if necessary
+ if i >= v.Cap() {
+ newcap := v.Cap() + v.Cap()/2
+ if newcap < 4 {
+ newcap = 4
+ }
+ newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
+ reflect.Copy(newv, v)
+ v.Set(newv)
+ }
+ if i >= v.Len() {
+ v.SetLen(i + 1)
}
- newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
- reflect.Copy(newv, sv)
- sv.Set(newv)
- }
- if i >= av.Len() && sv.IsValid() {
- // Must be slice; gave up on array during i >= av.Cap().
- sv.SetLen(i + 1)
}
- // Decode into element.
- if i < av.Len() {
- d.value(av.Index(i))
+ if i < v.Len() {
+ // Decode into element.
+ d.value(v.Index(i))
} else {
// Ran out of fixed array: skip.
d.value(reflect.Value{})
@@ -378,22 +383,21 @@ func (d *decodeState) array(v reflect.Value) {
d.error(errPhase)
}
}
- if i < av.Len() {
- if !sv.IsValid() {
+
+ if i < v.Len() {
+ if v.Kind() == reflect.Array {
// Array. Zero the rest.
- z := reflect.Zero(av.Type().Elem())
- for ; i < av.Len(); i++ {
- av.Index(i).Set(z)
+ z := reflect.Zero(v.Type().Elem())
+ for ; i < v.Len(); i++ {
+ v.Index(i).Set(z)
}
} else {
- sv.SetLen(i)
+ v.SetLen(i)
}
}
-}
-
-// matchName returns true if key should be written to a field named name.
-func matchName(key, name string) bool {
- return strings.ToLower(key) == strings.ToLower(name)
+ if i == 0 && v.Kind() == reflect.Slice {
+ v.Set(reflect.MakeSlice(v.Type(), 0, 0))
+ }
}
// object consumes an object from d.data[d.off-1:], decoding into the value v.
@@ -485,24 +489,37 @@ func (d *decodeState) object(v reflect.Value) {
var f reflect.StructField
var ok bool
st := sv.Type()
- // First try for field with that tag.
- if isValidTag(key) {
- for i := 0; i < sv.NumField(); i++ {
- f = st.Field(i)
- tagName, _ := parseTag(f.Tag.Get("json"))
- if tagName == key {
- ok = true
- break
- }
+ for i := 0; i < sv.NumField(); i++ {
+ sf := st.Field(i)
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ // Pretend this field doesn't exist.
+ continue
+ }
+ if sf.Anonymous {
+ // Pretend this field doesn't exist,
+ // so that we can do a good job with
+ // these in a later version.
+ continue
+ }
+ // First, tag match
+ tagName, _ := parseTag(tag)
+ if tagName == key {
+ f = sf
+ ok = true
+ break // no better match possible
+ }
+ // Second, exact field name match
+ if sf.Name == key {
+ f = sf
+ ok = true
+ }
+ // Third, case-insensitive field name match,
+ // but only if a better match hasn't already been seen
+ if !ok && strings.EqualFold(sf.Name, key) {
+ f = sf
+ ok = true
}
- }
- if !ok {
- // Second, exact match.
- f, ok = st.FieldByName(key)
- }
- if !ok {
- // Third, case-insensitive match.
- f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
}
// Extract value; name must be exported.
@@ -528,7 +545,7 @@ func (d *decodeState) object(v reflect.Value) {
// Read value.
if destring {
d.value(reflect.ValueOf(&d.tempstr))
- d.literalStore([]byte(d.tempstr), subv)
+ d.literalStore([]byte(d.tempstr), subv, true)
} else {
d.value(subv)
}
@@ -561,11 +578,15 @@ func (d *decodeState) literal(v reflect.Value) {
d.off--
d.scan.undo(op)
- d.literalStore(d.data[start:d.off], v)
+ d.literalStore(d.data[start:d.off], v, false)
}
// literalStore decodes a literal stored in item into v.
-func (d *decodeState) literalStore(item []byte, v reflect.Value) {
+//
+// fromQuoted indicates whether this literal came from unwrapping a
+// string from the ",string" struct tag option. this is used only to
+// produce more helpful error messages.
+func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) {
// Check for unmarshaler.
wantptr := item[0] == 'n' // null
unmarshaler, pv := d.indirect(v, wantptr)
@@ -583,7 +604,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
switch v.Kind() {
default:
d.saveError(&UnmarshalTypeError{"null", v.Type()})
- case reflect.Interface, reflect.Ptr, reflect.Map:
+ case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
v.Set(reflect.Zero(v.Type()))
}
@@ -591,7 +612,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
value := c == 't'
switch v.Kind() {
default:
- d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ if fromQuoted {
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ } else {
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ }
case reflect.Bool:
v.SetBool(value)
case reflect.Interface:
@@ -601,7 +626,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
case '"': // string
s, ok := unquoteBytes(item)
if !ok {
- d.error(errPhase)
+ if fromQuoted {
+ d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ } else {
+ d.error(errPhase)
+ }
}
switch v.Kind() {
default:
@@ -626,14 +655,22 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
default: // number
if c != '-' && (c < '0' || c > '9') {
- d.error(errPhase)
+ if fromQuoted {
+ d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ } else {
+ d.error(errPhase)
+ }
}
s := string(item)
switch v.Kind() {
default:
- d.error(&UnmarshalTypeError{"number", v.Type()})
+ if fromQuoted {
+ d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ } else {
+ d.error(&UnmarshalTypeError{"number", v.Type()})
+ }
case reflect.Interface:
- n, err := strconv.Atof64(s)
+ n, err := strconv.ParseFloat(s, 64)
if err != nil {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
break
@@ -641,7 +678,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
v.Set(reflect.ValueOf(n))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- n, err := strconv.Atoi64(s)
+ n, err := strconv.ParseInt(s, 10, 64)
if err != nil || v.OverflowInt(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
break
@@ -649,7 +686,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
v.SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- n, err := strconv.Atoui64(s)
+ n, err := strconv.ParseUint(s, 10, 64)
if err != nil || v.OverflowUint(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
break
@@ -657,7 +694,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
v.SetUint(n)
case reflect.Float32, reflect.Float64:
- n, err := strconv.AtofN(s, v.Type().Bits())
+ n, err := strconv.ParseFloat(s, v.Type().Bits())
if err != nil || v.OverflowFloat(n) {
d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
break
@@ -789,7 +826,7 @@ func (d *decodeState) literalInterface() interface{} {
if c != '-' && (c < '0' || c > '9') {
d.error(errPhase)
}
- n, err := strconv.Atof64(string(item))
+ n, err := strconv.ParseFloat(string(item), 64)
if err != nil {
d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.TypeOf(0.0)})
}
@@ -800,15 +837,15 @@ func (d *decodeState) literalInterface() interface{} {
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
// or it returns -1.
-func getu4(s []byte) int {
+func getu4(s []byte) rune {
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
return -1
}
- rune, err := strconv.Btoui64(string(s[2:6]), 16)
+ r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
if err != nil {
return -1
}
- return int(rune)
+ return rune(r)
}
// unquote converts a quoted JSON string literal s into an actual string t.
@@ -838,8 +875,8 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
r++
continue
}
- rune, size := utf8.DecodeRune(s[r:])
- if rune == utf8.RuneError && size == 1 {
+ rr, size := utf8.DecodeRune(s[r:])
+ if rr == utf8.RuneError && size == 1 {
break
}
r += size
@@ -894,23 +931,23 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
w++
case 'u':
r--
- rune := getu4(s[r:])
- if rune < 0 {
+ rr := getu4(s[r:])
+ if rr < 0 {
return
}
r += 6
- if utf16.IsSurrogate(rune) {
- rune1 := getu4(s[r:])
- if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
+ if utf16.IsSurrogate(rr) {
+ rr1 := getu4(s[r:])
+ if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
// A valid pair; consume.
r += 6
w += utf8.EncodeRune(b[w:], dec)
break
}
// Invalid surrogate; fall back to replacement rune.
- rune = unicode.ReplacementChar
+ rr = unicode.ReplacementChar
}
- w += utf8.EncodeRune(b[w:], rune)
+ w += utf8.EncodeRune(b[w:], rr)
}
// Quote, control characters are invalid.
@@ -925,10 +962,18 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
// Coerce to well-formed UTF-8.
default:
- rune, size := utf8.DecodeRune(s[r:])
+ rr, size := utf8.DecodeRune(s[r:])
r += size
- w += utf8.EncodeRune(b[w:], rune)
+ w += utf8.EncodeRune(b[w:], rr)
}
}
return b[0:w], true
}
+
+// The following is issue 3069.
+
+// BUG(rsc): This package ignores anonymous (embedded) struct fields
+// during encoding and decoding. A future version may assign meaning
+// to them. To force an anonymous field to be ignored in all future
+// versions of this package, use an explicit `json:"-"` tag in the struct
+// definition.
diff --git a/src/pkg/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index 5f6c3f5b8..d758758d9 100644
--- a/src/pkg/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -6,7 +6,7 @@ package json
import (
"bytes"
- "os"
+ "fmt"
"reflect"
"strings"
"testing"
@@ -15,6 +15,7 @@ import (
type T struct {
X string
Y int
+ Z int `json:"-"`
}
type tx struct {
@@ -29,7 +30,7 @@ type unmarshaler struct {
T bool
}
-func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
+func (u *unmarshaler) UnmarshalJSON(b []byte) error {
*u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
return nil
}
@@ -42,7 +43,7 @@ var (
um0, um1 unmarshaler // target2 of unmarshaling
ump = &um1
umtrue = unmarshaler{true}
- umslice = []unmarshaler{unmarshaler{true}}
+ umslice = []unmarshaler{{true}}
umslicep = new([]unmarshaler)
umstruct = ustruct{unmarshaler{true}}
)
@@ -51,7 +52,7 @@ type unmarshalTest struct {
in string
ptr interface{}
out interface{}
- err os.Error
+ err error
}
var unmarshalTests = []unmarshalTest{
@@ -68,8 +69,17 @@ 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)}},
+ // Z has a "-" tag.
+ {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
+
// syntax errors
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
+ {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
+
+ // array tests
+ {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
+ {`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
+ {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
// composite tests
{allValueIndent, new(All), allValue, nil},
@@ -229,17 +239,36 @@ func TestEscape(t *testing.T) {
}
}
-func TestHTMLEscape(t *testing.T) {
- b, err := MarshalForHTML("foobarbaz<>&quux")
- if err != nil {
- t.Fatalf("MarshalForHTML error: %v", err)
- }
- if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
- t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
+// WrongString is a struct that's misusing the ,string modifier.
+type WrongString struct {
+ Message string `json:"result,string"`
+}
+
+type wrongStringTest struct {
+ in, err string
+}
+
+var wrongStringTests = []wrongStringTest{
+ {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
+ {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
+ {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
+}
+
+// If people misuse the ,string modifier, the error message should be
+// helpful, telling the user that they're doing it wrong.
+func TestErrorMessageFromMisusedString(t *testing.T) {
+ for n, tt := range wrongStringTests {
+ r := strings.NewReader(tt.in)
+ var s WrongString
+ err := NewDecoder(r).Decode(&s)
+ got := fmt.Sprintf("%v", err)
+ if got != tt.err {
+ t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
+ }
}
}
-func noSpace(c int) int {
+func noSpace(c rune) rune {
if isSpace(c) {
return -1
}
@@ -342,12 +371,12 @@ var allValue = All{
"18": {Tag: "tag18"},
},
MapP: map[string]*Small{
- "19": &Small{Tag: "tag19"},
+ "19": {Tag: "tag19"},
"20": nil,
},
EmptyMap: map[string]Small{},
Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
- SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
+ SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
EmptySlice: []Small{},
StringSlice: []string{"str24", "str25", "str26"},
ByteSlice: []byte{27, 28, 29},
@@ -452,7 +481,7 @@ var allValueIndent = `{
"PSlice": null,
"PSliceP": null,
"EmptySlice": [],
- "NilSlice": [],
+ "NilSlice": null,
"StringSlice": [
"str24",
"str25",
@@ -524,8 +553,8 @@ var pallValueIndent = `{
},
"EmptyMap": null,
"NilMap": null,
- "Slice": [],
- "SliceP": [],
+ "Slice": null,
+ "SliceP": null,
"PSlice": [
{
"Tag": "tag20"
@@ -543,10 +572,10 @@ var pallValueIndent = `{
"Tag": "tag23"
}
],
- "EmptySlice": [],
- "NilSlice": [],
- "StringSlice": [],
- "ByteSlice": "",
+ "EmptySlice": null,
+ "NilSlice": null,
+ "StringSlice": null,
+ "ByteSlice": null,
"Small": {
"Tag": ""
},
@@ -559,3 +588,53 @@ var pallValueIndent = `{
}`
var pallValueCompact = strings.Map(noSpace, pallValueIndent)
+
+func TestRefUnmarshal(t *testing.T) {
+ type S struct {
+ // Ref is defined in encode_test.go.
+ R0 Ref
+ R1 *Ref
+ }
+ want := S{
+ R0: 12,
+ R1: new(Ref),
+ }
+ *want.R1 = 12
+
+ var got S
+ if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("got %+v, want %+v", got, want)
+ }
+}
+
+// Test that anonymous fields are ignored.
+// We may assign meaning to them later.
+func TestAnonymous(t *testing.T) {
+ type S struct {
+ T
+ N int
+ }
+
+ data, err := Marshal(new(S))
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := `{"N":0}`
+ if string(data) != want {
+ t.Fatalf("Marshal = %#q, want %#q", string(data), want)
+ }
+
+ var s S
+ if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if s.N != 2 {
+ t.Fatal("Unmarshal: did not set N")
+ }
+ if s.T.Y != 0 {
+ t.Fatal("Unmarshal: did set T.Y")
+ }
+}
diff --git a/src/pkg/json/encode.go b/src/pkg/encoding/json/encode.go
index 16be5e2af..14957b848 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -6,26 +6,30 @@
// RFC 4627.
//
// See "JSON and Go" for an introduction to this package:
-// http://blog.golang.org/2011/01/json-and-go.html
+// http://golang.org/doc/articles/json_and_go.html
package json
import (
"bytes"
"encoding/base64"
- "os"
+ "math"
"reflect"
"runtime"
"sort"
"strconv"
+ "sync"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// Marshal returns the JSON encoding of v.
//
// Marshal traverses the value v recursively.
-// If an encountered value implements the Marshaler interface,
-// Marshal calls its MarshalJSON method to produce JSON.
+// If an encountered value implements the Marshaler interface
+// and is not a nil pointer, Marshal calls its MarshalJSON method
+// to produce JSON. The nil pointer exception is not strictly necessary
+// but mimics a similar, necessary exception in the behavior of
+// UnmarshalJSON.
//
// Otherwise, Marshal uses the following type-dependent default encodings:
//
@@ -35,23 +39,31 @@ import (
//
// String values encode as JSON strings, with each invalid UTF-8 sequence
// replaced by the encoding of the Unicode replacement character U+FFFD.
+// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
+// to keep some browsers from misinterpreting JSON output as HTML.
//
// Array and slice values encode as JSON arrays, except that
-// []byte encodes as a base64-encoded string.
+// []byte encodes as a base64-encoded string, and a nil slice
+// encodes as the null JSON object.
//
// 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
+// becomes a member of the object unless
+// - the field's tag is "-", or
+// - 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 is ignored by this package.
+// Field int `json:"-"`
+//
+// // Field appears in JSON as key "myName".
// Field int `json:"myName"`
//
-// // Specifies that Field appears in JSON as key "myName" and
+// // 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"`
@@ -68,7 +80,8 @@ import (
// Int64String int64 `json:",string"`
//
// The key name will be used if it's a non-empty string consisting of
-// only Unicode letters, digits, dollar signs, hyphens, and underscores.
+// only Unicode letters, digits, dollar signs, percent signs, hyphens,
+// underscores and slashes.
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
@@ -88,7 +101,7 @@ import (
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
-func Marshal(v interface{}) ([]byte, os.Error) {
+func Marshal(v interface{}) ([]byte, error) {
e := &encodeState{}
err := e.marshal(v)
if err != nil {
@@ -98,7 +111,7 @@ func Marshal(v interface{}) ([]byte, os.Error) {
}
// MarshalIndent is like Marshal but applies Indent to format the output.
-func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
b, err := Marshal(v)
if err != nil {
return nil, err
@@ -111,17 +124,6 @@ func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
return buf.Bytes(), nil
}
-// MarshalForHTML is like Marshal but applies HTMLEscape to the output.
-func MarshalForHTML(v interface{}) ([]byte, os.Error) {
- b, err := Marshal(v)
- if err != nil {
- return nil, err
- }
- var buf bytes.Buffer
- HTMLEscape(&buf, b)
- return buf.Bytes(), nil
-}
-
// HTMLEscape appends to dst the JSON-encoded src with <, >, and &
// characters inside string literals changed to \u003c, \u003e, \u0026
// so that the JSON will be safe to embed inside HTML <script> tags.
@@ -151,37 +153,41 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) {
// Marshaler is the interface implemented by objects that
// can marshal themselves into valid JSON.
type Marshaler interface {
- MarshalJSON() ([]byte, os.Error)
+ MarshalJSON() ([]byte, error)
}
type UnsupportedTypeError struct {
Type reflect.Type
}
-func (e *UnsupportedTypeError) String() string {
+func (e *UnsupportedTypeError) Error() string {
return "json: unsupported type: " + e.Type.String()
}
+type UnsupportedValueError struct {
+ Value reflect.Value
+ Str string
+}
+
+func (e *UnsupportedValueError) Error() string {
+ return "json: unsupported value: " + e.Str
+}
+
type InvalidUTF8Error struct {
S string
}
-func (e *InvalidUTF8Error) String() string {
+func (e *InvalidUTF8Error) Error() string {
return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
}
type MarshalerError struct {
- Type reflect.Type
- Error os.Error
-}
-
-func (e *MarshalerError) String() string {
- return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
+ Type reflect.Type
+ Err error
}
-type interfaceOrPtrValue interface {
- IsNil() bool
- Elem() reflect.Value
+func (e *MarshalerError) Error() string {
+ return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error()
}
var hex = "0123456789abcdef"
@@ -189,22 +195,23 @@ var hex = "0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
type encodeState struct {
bytes.Buffer // accumulated output
+ scratch [64]byte
}
-func (e *encodeState) marshal(v interface{}) (err os.Error) {
+func (e *encodeState) marshal(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
- err = r.(os.Error)
+ err = r.(error)
}
}()
e.reflectValue(reflect.ValueOf(v))
return nil
}
-func (e *encodeState) error(err os.Error) {
+func (e *encodeState) error(err error) {
panic(err)
}
@@ -240,11 +247,21 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
return
}
- if j, ok := v.Interface().(Marshaler); ok {
- b, err := j.MarshalJSON()
+ m, ok := v.Interface().(Marshaler)
+ if !ok {
+ // T doesn't match the interface. Check against *T too.
+ if v.Kind() != reflect.Ptr && v.CanAddr() {
+ m, ok = v.Addr().Interface().(Marshaler)
+ if ok {
+ v = v.Addr()
+ }
+ }
+ }
+ if ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
+ b, err := m.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
- err = Compact(&e.Buffer, b)
+ err = compact(&e.Buffer, b, true)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err})
@@ -267,14 +284,30 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- writeString(e, strconv.Itoa64(v.Int()))
-
+ b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- writeString(e, strconv.Uitoa64(v.Uint()))
-
+ b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.Float32, reflect.Float64:
- writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
-
+ f := v.Float()
+ if math.IsInf(f, 0) || math.IsNaN(f) {
+ e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, v.Type().Bits())})
+ }
+ b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, v.Type().Bits())
+ if quoted {
+ writeString(e, string(b))
+ } else {
+ e.Write(b)
+ }
case reflect.String:
if quoted {
sb, err := Marshal(v.String())
@@ -288,25 +321,10 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
case reflect.Struct:
e.WriteByte('{')
- t := v.Type()
- n := v.NumField()
first := true
- for i := 0; i < n; i++ {
- f := t.Field(i)
- if f.PkgPath != "" {
- continue
- }
- tag, omitEmpty, quoted := f.Name, false, false
- if tv := f.Tag.Get("json"); tv != "" {
- name, opts := parseTag(tv)
- if isValidTag(name) {
- tag = name
- }
- omitEmpty = opts.Contains("omitempty")
- quoted = opts.Contains("string")
- }
- fieldValue := v.Field(i)
- if omitEmpty && isEmptyValue(fieldValue) {
+ for _, ef := range encodeFields(v.Type()) {
+ fieldValue := v.Field(ef.i)
+ if ef.omitEmpty && isEmptyValue(fieldValue) {
continue
}
if first {
@@ -314,9 +332,9 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
} else {
e.WriteByte(',')
}
- e.string(tag)
+ e.string(ef.tag)
e.WriteByte(':')
- e.reflectValueQuoted(fieldValue, quoted)
+ e.reflectValueQuoted(fieldValue, ef.quoted)
}
e.WriteByte('}')
@@ -341,10 +359,15 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
}
e.WriteByte('}')
- case reflect.Array, reflect.Slice:
- if v.Type() == byteSliceType {
+ case reflect.Slice:
+ if v.IsNil() {
+ e.WriteString("null")
+ break
+ }
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Byte slices get special treatment; arrays don't.
+ s := v.Bytes()
e.WriteByte('"')
- s := v.Interface().([]byte)
if len(s) < 1024 {
// for small buffers, using Encode directly is much faster.
dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
@@ -360,6 +383,10 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
e.WriteByte('"')
break
}
+ // Slices can be marshalled as nil, but otherwise are handled
+ // as arrays.
+ fallthrough
+ case reflect.Array:
e.WriteByte('[')
n := v.Len()
for i := 0; i < n; i++ {
@@ -388,8 +415,13 @@ func isValidTag(s string) bool {
return false
}
for _, c := range s {
- if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
- return false
+ switch c {
+ case '$', '-', '_', '/', '%':
+ // Acceptable
+ default:
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
}
}
return true
@@ -404,7 +436,7 @@ func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
func (sv stringValues) get(i int) string { return sv[i].String() }
-func (e *encodeState) string(s string) (int, os.Error) {
+func (e *encodeState) string(s string) (int, error) {
len0 := e.Len()
e.WriteByte('"')
start := 0
@@ -452,3 +484,68 @@ func (e *encodeState) string(s string) (int, os.Error) {
e.WriteByte('"')
return e.Len() - len0, nil
}
+
+// encodeField contains information about how to encode a field of a
+// struct.
+type encodeField struct {
+ i int // field index in struct
+ tag string
+ quoted bool
+ omitEmpty bool
+}
+
+var (
+ typeCacheLock sync.RWMutex
+ encodeFieldsCache = make(map[reflect.Type][]encodeField)
+)
+
+// encodeFields returns a slice of encodeField for a given
+// struct type.
+func encodeFields(t reflect.Type) []encodeField {
+ typeCacheLock.RLock()
+ fs, ok := encodeFieldsCache[t]
+ typeCacheLock.RUnlock()
+ if ok {
+ return fs
+ }
+
+ typeCacheLock.Lock()
+ defer typeCacheLock.Unlock()
+ fs, ok = encodeFieldsCache[t]
+ if ok {
+ return fs
+ }
+
+ v := reflect.Zero(t)
+ n := v.NumField()
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ if f.Anonymous {
+ // We want to do a better job with these later,
+ // so for now pretend they don't exist.
+ continue
+ }
+ var ef encodeField
+ ef.i = i
+ ef.tag = f.Name
+
+ tv := f.Tag.Get("json")
+ if tv != "" {
+ if tv == "-" {
+ continue
+ }
+ name, opts := parseTag(tv)
+ if isValidTag(name) {
+ ef.tag = name
+ }
+ ef.omitEmpty = opts.Contains("omitempty")
+ ef.quoted = opts.Contains("string")
+ }
+ fs = append(fs, ef)
+ }
+ encodeFieldsCache[t] = fs
+ return fs
+}
diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
new file mode 100644
index 000000000..cb1c77eb5
--- /dev/null
+++ b/src/pkg/encoding/json/encode_test.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 json
+
+import (
+ "bytes"
+ "math"
+ "reflect"
+ "testing"
+)
+
+type Optionals struct {
+ Sr string `json:"sr"`
+ So string `json:"so,omitempty"`
+ Sw string `json:"-"`
+
+ 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": null,
+ "mr": {}
+}`
+
+func TestOmitEmpty(t *testing.T) {
+ var o Optionals
+ o.Sw = "something"
+ 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)
+ }
+}
+
+type StringTag struct {
+ BoolStr bool `json:",string"`
+ IntStr int64 `json:",string"`
+ StrStr string `json:",string"`
+}
+
+var stringTagExpected = `{
+ "BoolStr": "true",
+ "IntStr": "42",
+ "StrStr": "\"xzbit\""
+}`
+
+func TestStringTag(t *testing.T) {
+ var s StringTag
+ s.BoolStr = true
+ s.IntStr = 42
+ s.StrStr = "xzbit"
+ got, err := MarshalIndent(&s, "", " ")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got := string(got); got != stringTagExpected {
+ t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
+ }
+
+ // Verify that it round-trips.
+ var s2 StringTag
+ err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+ if !reflect.DeepEqual(s, s2) {
+ t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
+ }
+}
+
+// byte slices are special even if they're renamed types.
+type renamedByte byte
+type renamedByteSlice []byte
+type renamedRenamedByteSlice []renamedByte
+
+func TestEncodeRenamedByteSlice(t *testing.T) {
+ s := renamedByteSlice("abc")
+ result, err := Marshal(s)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expect := `"YWJj"`
+ if string(result) != expect {
+ t.Errorf(" got %s want %s", result, expect)
+ }
+ r := renamedRenamedByteSlice("abc")
+ result, err = Marshal(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(result) != expect {
+ t.Errorf(" got %s want %s", result, expect)
+ }
+}
+
+var unsupportedValues = []interface{}{
+ math.NaN(),
+ math.Inf(-1),
+ math.Inf(1),
+}
+
+func TestUnsupportedValues(t *testing.T) {
+ for _, v := range unsupportedValues {
+ if _, err := Marshal(v); err != nil {
+ if _, ok := err.(*UnsupportedValueError); !ok {
+ t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
+ }
+ } else {
+ t.Errorf("for %v, expected error", v)
+ }
+ }
+}
+
+// Ref has Marshaler and Unmarshaler methods with pointer receiver.
+type Ref int
+
+func (*Ref) MarshalJSON() ([]byte, error) {
+ return []byte(`"ref"`), nil
+}
+
+func (r *Ref) UnmarshalJSON([]byte) error {
+ *r = 12
+ return nil
+}
+
+// Val has Marshaler methods with value receiver.
+type Val int
+
+func (Val) MarshalJSON() ([]byte, error) {
+ return []byte(`"val"`), nil
+}
+
+func TestRefValMarshal(t *testing.T) {
+ var s = struct {
+ R0 Ref
+ R1 *Ref
+ V0 Val
+ V1 *Val
+ }{
+ R0: 12,
+ R1: new(Ref),
+ V0: 13,
+ V1: new(Val),
+ }
+ const want = `{"R0":"ref","R1":"ref","V0":"val","V1":"val"}`
+ b, err := Marshal(&s)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if got := string(b); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
+
+// C implements Marshaler and returns unescaped JSON.
+type C int
+
+func (C) MarshalJSON() ([]byte, error) {
+ return []byte(`"<&>"`), nil
+}
+
+func TestMarshalerEscaping(t *testing.T) {
+ var c C
+ const want = `"\u003c\u0026\u003e"`
+ b, err := Marshal(c)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if got := string(b); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go
new file mode 100644
index 000000000..b8d150eda
--- /dev/null
+++ b/src/pkg/encoding/json/example_test.go
@@ -0,0 +1,83 @@
+// 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_test
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+func ExampleMarshal() {
+ type ColorGroup struct {
+ ID int
+ Name string
+ Colors []string
+ }
+ group := ColorGroup{
+ ID: 1,
+ Name: "Reds",
+ Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
+ }
+ b, err := json.Marshal(group)
+ if err != nil {
+ fmt.Println("error:", err)
+ }
+ os.Stdout.Write(b)
+ // Output:
+ // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
+}
+
+func ExampleUnmarshal() {
+ var jsonBlob = []byte(`[
+ {"Name": "Platypus", "Order": "Monotremata"},
+ {"Name": "Quoll", "Order": "Dasyuromorphia"}
+ ]`)
+ type Animal struct {
+ Name string
+ Order string
+ }
+ var animals []Animal
+ err := json.Unmarshal(jsonBlob, &animals)
+ if err != nil {
+ fmt.Println("error:", err)
+ }
+ fmt.Printf("%+v", animals)
+ // Output:
+ // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
+}
+
+// This example uses a Decoder to decode a stream of distinct JSON values.
+func ExampleDecoder() {
+ const jsonStream = `
+ {"Name": "Ed", "Text": "Knock knock."}
+ {"Name": "Sam", "Text": "Who's there?"}
+ {"Name": "Ed", "Text": "Go fmt."}
+ {"Name": "Sam", "Text": "Go fmt who?"}
+ {"Name": "Ed", "Text": "Go fmt yourself!"}
+ `
+ type Message struct {
+ Name, Text string
+ }
+ dec := json.NewDecoder(strings.NewReader(jsonStream))
+ for {
+ var m Message
+ if err := dec.Decode(&m); err == io.EOF {
+ break
+ } else if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s: %s\n", m.Name, m.Text)
+ }
+ // Output:
+ // Ed: Knock knock.
+ // Sam: Who's there?
+ // Ed: Go fmt.
+ // Sam: Go fmt who?
+ // Ed: Go fmt yourself!
+}
diff --git a/src/pkg/json/indent.go b/src/pkg/encoding/json/indent.go
index 000da42f6..e8dfa4ec4 100644
--- a/src/pkg/json/indent.go
+++ b/src/pkg/encoding/json/indent.go
@@ -4,19 +4,29 @@
package json
-import (
- "bytes"
- "os"
-)
+import "bytes"
// Compact appends to dst the JSON-encoded src with
// insignificant space characters elided.
-func Compact(dst *bytes.Buffer, src []byte) os.Error {
+func Compact(dst *bytes.Buffer, src []byte) error {
+ return compact(dst, src, false)
+}
+
+func compact(dst *bytes.Buffer, src []byte, escape bool) error {
origLen := dst.Len()
var scan scanner
scan.reset()
start := 0
for i, c := range src {
+ if escape && (c == '<' || c == '>' || c == '&') {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
v := scan.step(&scan, int(c))
if v >= scanSkipSpace {
if v == scanError {
@@ -52,13 +62,14 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
// copies of indent according to the indentation nesting.
// The data appended to dst has no trailing newline, to make it easier
// to embed inside other formatted JSON data.
-func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) os.Error {
+func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
origLen := dst.Len()
var scan scanner
scan.reset()
needIndent := false
depth := 0
for _, c := range src {
+ scan.bytes++
v := scan.step(&scan, int(c))
if v == scanSkipSpace {
continue
diff --git a/src/pkg/json/scanner.go b/src/pkg/encoding/json/scanner.go
index 49c2edd54..054b6b3d5 100644
--- a/src/pkg/json/scanner.go
+++ b/src/pkg/encoding/json/scanner.go
@@ -13,14 +13,11 @@ package json
// This file starts with two simple examples using the scanner
// before diving into the scanner itself.
-import (
- "os"
- "strconv"
-)
+import "strconv"
// checkValid verifies that data is valid JSON-encoded data.
// scan is passed in for use by checkValid to avoid an allocation.
-func checkValid(data []byte, scan *scanner) os.Error {
+func checkValid(data []byte, scan *scanner) error {
scan.reset()
for _, c := range data {
scan.bytes++
@@ -37,7 +34,7 @@ func checkValid(data []byte, scan *scanner) os.Error {
// nextValue splits data after the next whole JSON value,
// returning that value and the bytes that follow it as separate slices.
// scan is passed in for use by nextValue to avoid an allocation.
-func nextValue(data []byte, scan *scanner) (value, rest []byte, err os.Error) {
+func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
scan.reset()
for i, c := range data {
v := scan.step(scan, int(c))
@@ -62,7 +59,7 @@ type SyntaxError struct {
Offset int64 // error occurred after reading Offset bytes
}
-func (e *SyntaxError) String() string { return e.msg }
+func (e *SyntaxError) Error() string { return e.msg }
// A scanner is a JSON scanning state machine.
// Callers call scan.reset() and then pass bytes in one at a time
@@ -83,13 +80,17 @@ type scanner struct {
// on a 64-bit Mac Mini, and it's nicer to read.
step func(*scanner, int) int
+ // Reached end of top-level value.
+ endTop bool
+
// Stack of what we're in the middle of - array values, object keys, object values.
parseState []int
// Error that happened, if any.
- err os.Error
+ err error
// 1-byte redo (see undo method)
+ redo bool
redoCode int
redoState func(*scanner, int) int
@@ -138,6 +139,8 @@ func (s *scanner) reset() {
s.step = stateBeginValue
s.parseState = s.parseState[0:0]
s.err = nil
+ s.redo = false
+ s.endTop = false
}
// eof tells the scanner that the end of input has been reached.
@@ -146,11 +149,11 @@ func (s *scanner) eof() int {
if s.err != nil {
return scanError
}
- if s.step == stateEndTop {
+ if s.endTop {
return scanEnd
}
s.step(s, ' ')
- if s.step == stateEndTop {
+ if s.endTop {
return scanEnd
}
if s.err == nil {
@@ -169,29 +172,22 @@ func (s *scanner) pushParseState(p int) {
func (s *scanner) popParseState() {
n := len(s.parseState) - 1
s.parseState = s.parseState[0:n]
+ s.redo = false
if n == 0 {
s.step = stateEndTop
+ s.endTop = true
} else {
s.step = stateEndValue
}
}
-func isSpace(c int) bool {
+func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
}
-// NOTE(rsc): The various instances of
-//
-// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-//
-// below should all be if c <= ' ' && isSpace(c), but inlining
-// the checks makes a significant difference (>10%) in tight loops
-// such as nextValue. These should be rewritten with the clearer
-// function call once 6g knows to inline the call.
-
// stateBeginValueOrEmpty is the state after reading `[`.
func stateBeginValueOrEmpty(s *scanner, c int) int {
- if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if c <= ' ' && isSpace(rune(c)) {
return scanSkipSpace
}
if c == ']' {
@@ -202,7 +198,7 @@ func stateBeginValueOrEmpty(s *scanner, c int) int {
// stateBeginValue is the state at the beginning of the input.
func stateBeginValue(s *scanner, c int) int {
- if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if c <= ' ' && isSpace(rune(c)) {
return scanSkipSpace
}
switch c {
@@ -242,7 +238,7 @@ func stateBeginValue(s *scanner, c int) int {
// stateBeginStringOrEmpty is the state after reading `{`.
func stateBeginStringOrEmpty(s *scanner, c int) int {
- if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if c <= ' ' && isSpace(rune(c)) {
return scanSkipSpace
}
if c == '}' {
@@ -255,7 +251,7 @@ func stateBeginStringOrEmpty(s *scanner, c int) int {
// stateBeginString is the state after reading `{"key": value,`.
func stateBeginString(s *scanner, c int) int {
- if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if c <= ' ' && isSpace(rune(c)) {
return scanSkipSpace
}
if c == '"' {
@@ -272,9 +268,10 @@ func stateEndValue(s *scanner, c int) int {
if n == 0 {
// Completed top-level before the current byte.
s.step = stateEndTop
+ s.endTop = true
return stateEndTop(s, c)
}
- if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if c <= ' ' && isSpace(rune(c)) {
s.step = stateEndValue
return scanSkipSpace
}
@@ -609,16 +606,18 @@ func quoteChar(c int) string {
// undo causes the scanner to return scanCode from the next state transition.
// This gives callers a simple 1-byte undo mechanism.
func (s *scanner) undo(scanCode int) {
- if s.step == stateRedo {
- panic("invalid use of scanner")
+ if s.redo {
+ panic("json: invalid use of scanner")
}
s.redoCode = scanCode
s.redoState = s.step
s.step = stateRedo
+ s.redo = true
}
// stateRedo helps implement the scanner's 1-byte undo.
func stateRedo(s *scanner, c int) int {
+ s.redo = false
s.step = s.redoState
return s.redoCode
}
diff --git a/src/pkg/json/scanner_test.go b/src/pkg/encoding/json/scanner_test.go
index 023e7c81e..14d850865 100644
--- a/src/pkg/json/scanner_test.go
+++ b/src/pkg/encoding/json/scanner_test.go
@@ -7,7 +7,8 @@ package json
import (
"bytes"
"math"
- "rand"
+ "math/rand"
+ "reflect"
"testing"
)
@@ -136,6 +137,29 @@ func TestIndentBig(t *testing.T) {
}
}
+type indentErrorTest struct {
+ in string
+ err error
+}
+
+var indentErrorTests = []indentErrorTest{
+ {`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
+ {`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
+}
+
+func TestIndentErrors(t *testing.T) {
+ for i, tt := range indentErrorTests {
+ slice := make([]uint8, 0)
+ buf := bytes.NewBuffer(slice)
+ if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: Indent: %#v", i, err)
+ continue
+ }
+ }
+ }
+}
+
func TestNextValueBig(t *testing.T) {
initBig()
var scan scanner
@@ -150,7 +174,7 @@ func TestNextValueBig(t *testing.T) {
t.Errorf("invalid rest: %d", len(rest))
}
- item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
+ item, rest, err = nextValue(append(jsonBig, "HELLO WORLD"...), &scan)
if err != nil {
t.Fatalf("nextValue extra: %s", err)
}
@@ -162,11 +186,12 @@ func TestNextValueBig(t *testing.T) {
}
}
+var benchScan scanner
+
func BenchmarkSkipValue(b *testing.B) {
initBig()
- var scan scanner
for i := 0; i < b.N; i++ {
- nextValue(jsonBig, &scan)
+ nextValue(jsonBig, &benchScan)
}
b.SetBytes(int64(len(jsonBig)))
}
@@ -235,20 +260,20 @@ func genValue(n int) interface{} {
}
func genString(stddev float64) string {
- n := int(math.Fabs(rand.NormFloat64()*stddev + stddev/2))
- c := make([]int, n)
+ n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
+ c := make([]rune, n)
for i := range c {
- f := math.Fabs(rand.NormFloat64()*64 + 32)
+ f := math.Abs(rand.NormFloat64()*64 + 32)
if f > 0x10ffff {
f = 0x10ffff
}
- c[i] = int(f)
+ c[i] = rune(f)
}
return string(c)
}
func genArray(n int) []interface{} {
- f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
@@ -263,7 +288,7 @@ func genArray(n int) []interface{} {
}
func genMap(n int) map[string]interface{} {
- f := int(math.Fabs(rand.NormFloat64()) * math.Fmin(10, float64(n/2)))
+ f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
diff --git a/src/pkg/json/stream.go b/src/pkg/encoding/json/stream.go
index f143b3f0a..7d1cc5f11 100644
--- a/src/pkg/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -5,8 +5,8 @@
package json
import (
+ "errors"
"io"
- "os"
)
// A Decoder reads and decodes JSON objects from an input stream.
@@ -15,10 +15,13 @@ type Decoder struct {
buf []byte
d decodeState
scan scanner
- err os.Error
+ err error
}
// NewDecoder returns a new decoder that reads from r.
+//
+// The decoder introduces its own buffering and may
+// read data from r beyond the JSON values requested.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
@@ -28,7 +31,7 @@ func NewDecoder(r io.Reader) *Decoder {
//
// See the documentation for Unmarshal for details about
// the conversion of JSON into a Go value.
-func (dec *Decoder) Decode(v interface{}) os.Error {
+func (dec *Decoder) Decode(v interface{}) error {
if dec.err != nil {
return dec.err
}
@@ -53,11 +56,11 @@ func (dec *Decoder) Decode(v interface{}) os.Error {
// readValue reads a JSON value into dec.buf.
// It returns the length of the encoding.
-func (dec *Decoder) readValue() (int, os.Error) {
+func (dec *Decoder) readValue() (int, error) {
dec.scan.reset()
scanp := 0
- var err os.Error
+ var err error
Input:
for {
// Look in the buffer for a new value.
@@ -85,7 +88,7 @@ Input:
// Did the last read have an error?
// Delayed until now to allow buffer scan.
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
if dec.scan.step(&dec.scan, ' ') == scanEnd {
break Input
}
@@ -115,7 +118,7 @@ Input:
func nonSpace(b []byte) bool {
for _, c := range b {
- if !isSpace(int(c)) {
+ if !isSpace(rune(c)) {
return true
}
}
@@ -126,7 +129,7 @@ func nonSpace(b []byte) bool {
type Encoder struct {
w io.Writer
e encodeState
- err os.Error
+ err error
}
// NewEncoder returns a new encoder that writes to w.
@@ -138,7 +141,7 @@ func NewEncoder(w io.Writer) *Encoder {
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
-func (enc *Encoder) Encode(v interface{}) os.Error {
+func (enc *Encoder) Encode(v interface{}) error {
if enc.err != nil {
return enc.err
}
@@ -168,14 +171,14 @@ func (enc *Encoder) Encode(v interface{}) os.Error {
type RawMessage []byte
// MarshalJSON returns *m as the JSON encoding of m.
-func (m *RawMessage) MarshalJSON() ([]byte, os.Error) {
+func (m *RawMessage) MarshalJSON() ([]byte, error) {
return *m, nil
}
// UnmarshalJSON sets *m to a copy of data.
-func (m *RawMessage) UnmarshalJSON(data []byte) os.Error {
+func (m *RawMessage) UnmarshalJSON(data []byte) error {
if m == nil {
- return os.NewError("json.RawMessage: UnmarshalJSON on nil pointer")
+ return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
}
*m = append((*m)[0:0], data...)
return nil
diff --git a/src/pkg/json/stream_test.go b/src/pkg/encoding/json/stream_test.go
index 6ddaed9fe..ce5a7e6d6 100644
--- a/src/pkg/json/stream_test.go
+++ b/src/pkg/encoding/json/stream_test.go
@@ -120,3 +120,28 @@ func TestRawMessage(t *testing.T) {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
+
+func TestNullRawMessage(t *testing.T) {
+ // TODO(rsc): Should not need the * in *RawMessage
+ var data struct {
+ X float64
+ Id *RawMessage
+ Y float32
+ }
+ data.Id = new(RawMessage)
+ const msg = `{"X":0.1,"Id":null,"Y":0.2}`
+ err := Unmarshal([]byte(msg), &data)
+ if err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if data.Id != nil {
+ t.Fatalf("Raw mismatch: have non-nil, want nil")
+ }
+ b, err := Marshal(&data)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if string(b) != msg {
+ t.Fatalf("Marshal: have %#q want %#q", b, msg)
+ }
+}
diff --git a/src/pkg/json/tagkey_test.go b/src/pkg/encoding/json/tagkey_test.go
index 31fe2be36..bba573035 100644
--- a/src/pkg/json/tagkey_test.go
+++ b/src/pkg/encoding/json/tagkey_test.go
@@ -9,7 +9,7 @@ import (
)
type basicLatin2xTag struct {
- V string `json:"$-"`
+ V string `json:"$%-/"`
}
type basicLatin3xTag struct {
@@ -36,6 +36,10 @@ type miscPlaneTag struct {
V string `json:"色は匂へど"`
}
+type percentSlashTag struct {
+ V string `json:"text/html%"` // http://golang.org/issue/2718
+}
+
type emptyTag struct {
W string
}
@@ -49,7 +53,7 @@ type badFormatTag struct {
}
type badCodeTag struct {
- Z string `json:" !\"#%&'()*+,./"`
+ Z string `json:" !\"#&'()*+,."`
}
var structTagObjectKeyTests = []struct {
@@ -57,7 +61,7 @@ var structTagObjectKeyTests = []struct {
value string
key string
}{
- {basicLatin2xTag{"2x"}, "2x", "$-"},
+ {basicLatin2xTag{"2x"}, "2x", "$%-/"},
{basicLatin3xTag{"3x"}, "3x", "0123456789"},
{basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
{basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
@@ -68,6 +72,7 @@ var structTagObjectKeyTests = []struct {
{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+ {percentSlashTag{"brut"}, "brut", "text/html%"},
}
func TestStructTagObjectKey(t *testing.T) {
@@ -88,7 +93,7 @@ func TestStructTagObjectKey(t *testing.T) {
t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
}
default:
- t.Fatalf("Unexpected key: %#q", i)
+ t.Fatalf("Unexpected key: %#q, from %#q", i, b)
}
}
}
diff --git a/src/pkg/json/tags.go b/src/pkg/encoding/json/tags.go
index 58cda2027..58cda2027 100644
--- a/src/pkg/json/tags.go
+++ b/src/pkg/encoding/json/tags.go
diff --git a/src/pkg/json/tags_test.go b/src/pkg/encoding/json/tags_test.go
index 91fb18831..91fb18831 100644
--- a/src/pkg/json/tags_test.go
+++ b/src/pkg/encoding/json/tags_test.go
diff --git a/src/pkg/encoding/json/testdata/code.json.gz b/src/pkg/encoding/json/testdata/code.json.gz
new file mode 100644
index 000000000..0e2895b53
--- /dev/null
+++ b/src/pkg/encoding/json/testdata/code.json.gz
Binary files differ
diff --git a/src/pkg/encoding/pem/Makefile b/src/pkg/encoding/pem/Makefile
deleted file mode 100644
index 527670380..000000000
--- a/src/pkg/encoding/pem/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=encoding/pem
-GOFILES=\
- pem.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
index 12689b57b..38afbb42a 100644
--- a/src/pkg/encoding/pem/pem.go
+++ b/src/pkg/encoding/pem/pem.go
@@ -11,7 +11,6 @@ import (
"bytes"
"encoding/base64"
"io"
- "os"
)
// A Block represents a PEM encoded structure.
@@ -170,7 +169,7 @@ type lineBreaker struct {
out io.Writer
}
-func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+func (l *lineBreaker) Write(b []byte) (n int, err error) {
if l.used+len(b) < pemLineLength {
copy(l.line[l.used:], b)
l.used += len(b)
@@ -197,7 +196,7 @@ func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
return l.Write(b[excess:])
}
-func (l *lineBreaker) Close() (err os.Error) {
+func (l *lineBreaker) Close() (err error) {
if l.used > 0 {
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
@@ -209,7 +208,7 @@ func (l *lineBreaker) Close() (err os.Error) {
return
}
-func Encode(out io.Writer, b *Block) (err os.Error) {
+func Encode(out io.Writer, b *Block) (err error) {
_, err = out.Write(pemStart[1:])
if err != nil {
return
@@ -252,7 +251,7 @@ func Encode(out io.Writer, b *Block) (err os.Error) {
}
func EncodeToMemory(b *Block) []byte {
- buf := bytes.NewBuffer(nil)
- Encode(buf, b)
+ var buf bytes.Buffer
+ Encode(&buf, b)
return buf.Bytes()
}
diff --git a/src/pkg/encoding/pem/pem_test.go b/src/pkg/encoding/pem/pem_test.go
index 11efe5544..9ae1578a5 100644
--- a/src/pkg/encoding/pem/pem_test.go
+++ b/src/pkg/encoding/pem/pem_test.go
@@ -73,7 +73,7 @@ var lineBreakerTests = []lineBreakerTest{
func TestLineBreaker(t *testing.T) {
for i, test := range lineBreakerTests {
- buf := bytes.NewBuffer(nil)
+ buf := new(bytes.Buffer)
var breaker lineBreaker
breaker.out = buf
_, err := breaker.Write([]byte(test.in))
@@ -93,7 +93,7 @@ func TestLineBreaker(t *testing.T) {
}
for i, test := range lineBreakerTests {
- buf := bytes.NewBuffer(nil)
+ buf := new(bytes.Buffer)
var breaker lineBreaker
breaker.out = buf
diff --git a/src/pkg/encoding/xml/atom_test.go b/src/pkg/encoding/xml/atom_test.go
new file mode 100644
index 000000000..a71284312
--- /dev/null
+++ b/src/pkg/encoding/xml/atom_test.go
@@ -0,0 +1,56 @@
+// 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 "time"
+
+var atomValue = &Feed{
+ XMLName: Name{"http://www.w3.org/2005/Atom", "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" updated="2003-12-13T18:30:02Z">` +
+ `<title>Example Feed</title>` +
+ `<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>` +
+ `<link href="http://example.org/"></link>` +
+ `<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.Time {
+ t, err := time.Parse(time.RFC3339, str)
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+func NewText(text string) Text {
+ return Text{
+ Body: text,
+ }
+}
diff --git a/src/pkg/encoding/xml/example_test.go b/src/pkg/encoding/xml/example_test.go
new file mode 100644
index 000000000..97c8c0b0d
--- /dev/null
+++ b/src/pkg/encoding/xml/example_test.go
@@ -0,0 +1,111 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml_test
+
+import (
+ "encoding/xml"
+ "fmt"
+ "os"
+)
+
+func ExampleMarshalIndent() {
+ type Address struct {
+ City, State string
+ }
+ type Person struct {
+ XMLName xml.Name `xml:"person"`
+ Id int `xml:"id,attr"`
+ FirstName string `xml:"name>first"`
+ LastName string `xml:"name>last"`
+ Age int `xml:"age"`
+ Height float32 `xml:"height,omitempty"`
+ Married bool
+ Address
+ Comment string `xml:",comment"`
+ }
+
+ v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}
+ v.Comment = " Need more details. "
+ v.Address = Address{"Hanga Roa", "Easter Island"}
+
+ output, err := xml.MarshalIndent(v, " ", " ")
+ if err != nil {
+ fmt.Printf("error: %v\n", err)
+ }
+
+ os.Stdout.Write(output)
+ // Output:
+ // <person id="13">
+ // <name>
+ // <first>John</first>
+ // <last>Doe</last>
+ // </name>
+ // <age>42</age>
+ // <Married>false</Married>
+ // <City>Hanga Roa</City>
+ // <State>Easter Island</State>
+ // <!-- Need more details. -->
+ // </person>
+}
+
+// This example demonstrates unmarshaling an XML excerpt into a value with
+// some preset fields. Note that the Phone field isn't modified and that
+// the XML <Company> element is ignored. Also, the Groups field is assigned
+// considering the element path provided in its tag.
+func ExampleUnmarshal() {
+ type Email struct {
+ Where string `xml:"where,attr"`
+ Addr string
+ }
+ type Address struct {
+ City, State string
+ }
+ type Result struct {
+ XMLName xml.Name `xml:"Person"`
+ Name string `xml:"FullName"`
+ Phone string
+ Email []Email
+ Groups []string `xml:"Group>Value"`
+ Address
+ }
+ v := Result{Name: "none", Phone: "none"}
+
+ data := `
+ <Person>
+ <FullName>Grace R. Emlin</FullName>
+ <Company>Example Inc.</Company>
+ <Email where="home">
+ <Addr>gre@example.com</Addr>
+ </Email>
+ <Email where='work'>
+ <Addr>gre@work.com</Addr>
+ </Email>
+ <Group>
+ <Value>Friends</Value>
+ <Value>Squash</Value>
+ </Group>
+ <City>Hanga Roa</City>
+ <State>Easter Island</State>
+ </Person>
+ `
+ err := xml.Unmarshal([]byte(data), &v)
+ if err != nil {
+ fmt.Printf("error: %v", err)
+ return
+ }
+ fmt.Printf("XMLName: %#v\n", v.XMLName)
+ fmt.Printf("Name: %q\n", v.Name)
+ fmt.Printf("Phone: %q\n", v.Phone)
+ fmt.Printf("Email: %v\n", v.Email)
+ fmt.Printf("Groups: %v\n", v.Groups)
+ fmt.Printf("Address: %v\n", v.Address)
+ // Output:
+ // XMLName: xml.Name{Space:"", Local:"Person"}
+ // Name: "Grace R. Emlin"
+ // Phone: "none"
+ // Email: [{home gre@example.com} {work gre@work.com}]
+ // Groups: [Friends Squash]
+ // Address: {Hanga Roa Easter Island}
+}
diff --git a/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go
new file mode 100644
index 000000000..6c3170bdd
--- /dev/null
+++ b/src/pkg/encoding/xml/marshal.go
@@ -0,0 +1,447 @@
+// 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"
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ // A generic XML header suitable for use with the output of Marshal.
+ // 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"
+)
+
+// Marshal returns the XML encoding of v.
+//
+// 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 one or more XML
+// elements containing the data.
+//
+// The name for the XML elements is taken from, in order of preference:
+// - the tag on the XMLName field, if the data is a struct
+// - the value of the 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 of the marshalled type
+//
+// 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 "-" is omitted.
+// - a field with tag "name,attr" becomes an attribute with
+// the given name in the XML element.
+// - a field with tag ",attr" becomes an attribute with the
+// field name in the 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.
+// - a field with tag ",comment" is written as an XML comment, not
+// subject to the usual marshalling procedure. It must not contain
+// the "--" string within it.
+// - a field with a tag including the "omitempty" option is omitted
+// if the field value is empty. The empty values are false, 0, any
+// nil pointer or interface value, and any array, slice, map, or
+// string of length zero.
+// - a non-pointer anonymous struct field is handled as if the
+// fields of its value were part of the outer struct.
+//
+// If a field uses a tag "a>b>c", then the element c will be nested inside
+// parent elements a and b. Fields that appear next to each other that name
+// the same parent will be enclosed in one XML element.
+//
+// See MarshalIndent for an example.
+//
+// Marshal will return an error if asked to marshal a channel, function, or map.
+func Marshal(v interface{}) ([]byte, error) {
+ var b bytes.Buffer
+ if err := NewEncoder(&b).Encode(v); err != nil {
+ return nil, err
+ }
+ return b.Bytes(), nil
+}
+
+// MarshalIndent works like Marshal, but each XML element begins on a new
+// indented line that starts with prefix and is followed by one or more
+// copies of indent according to the nesting depth.
+func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
+ var b bytes.Buffer
+ enc := NewEncoder(&b)
+ enc.prefix = prefix
+ enc.indent = indent
+ err := enc.marshalValue(reflect.ValueOf(v), nil)
+ enc.Flush()
+ if err != nil {
+ return nil, err
+ }
+ return b.Bytes(), nil
+}
+
+// An Encoder writes XML data to an output stream.
+type Encoder struct {
+ printer
+}
+
+// NewEncoder returns a new encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{printer{Writer: bufio.NewWriter(w)}}
+}
+
+// Encode writes the XML encoding of v to the stream.
+//
+// See the documentation for Marshal for details about the conversion
+// of Go values to XML.
+func (enc *Encoder) Encode(v interface{}) error {
+ err := enc.marshalValue(reflect.ValueOf(v), nil)
+ enc.Flush()
+ return err
+}
+
+type printer struct {
+ *bufio.Writer
+ indent string
+ prefix string
+ depth int
+ indentedIn bool
+}
+
+// marshalValue writes one or more XML elements representing val.
+// If val was obtained from a struct field, finfo must have its details.
+func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
+ if !val.IsValid() {
+ return nil
+ }
+ if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
+ return nil
+ }
+
+ kind := val.Kind()
+ typ := val.Type()
+
+ // Drill into pointers/interfaces
+ if kind == reflect.Ptr || kind == reflect.Interface {
+ if val.IsNil() {
+ return nil
+ }
+ return p.marshalValue(val.Elem(), finfo)
+ }
+
+ // 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), finfo); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ tinfo, err := getTypeInfo(typ)
+ if err != nil {
+ return err
+ }
+
+ // Precedence for the XML element name is:
+ // 1. XMLName field in underlying struct;
+ // 2. field name/tag in the struct field; and
+ // 3. type name
+ var xmlns, name string
+ if tinfo.xmlname != nil {
+ xmlname := tinfo.xmlname
+ if xmlname.name != "" {
+ xmlns, name = xmlname.xmlns, xmlname.name
+ } else if v, ok := val.FieldByIndex(xmlname.idx).Interface().(Name); ok && v.Local != "" {
+ xmlns, name = v.Space, v.Local
+ }
+ }
+ if name == "" && finfo != nil {
+ xmlns, name = finfo.xmlns, finfo.name
+ }
+ if name == "" {
+ name = typ.Name()
+ if name == "" {
+ return &UnsupportedTypeError{typ}
+ }
+ }
+
+ p.writeIndent(1)
+ p.WriteByte('<')
+ p.WriteString(name)
+
+ if xmlns != "" {
+ p.WriteString(` xmlns="`)
+ // TODO: EscapeString, to avoid the allocation.
+ Escape(p, []byte(xmlns))
+ p.WriteByte('"')
+ }
+
+ // Attributes
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ if finfo.flags&fAttr == 0 {
+ continue
+ }
+ fv := val.FieldByIndex(finfo.idx)
+ if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
+ continue
+ }
+ p.WriteByte(' ')
+ p.WriteString(finfo.name)
+ p.WriteString(`="`)
+ if err := p.marshalSimple(fv.Type(), fv); err != nil {
+ return err
+ }
+ p.WriteByte('"')
+ }
+ p.WriteByte('>')
+
+ if val.Kind() == reflect.Struct {
+ err = p.marshalStruct(tinfo, val)
+ } else {
+ err = p.marshalSimple(typ, val)
+ }
+ if err != nil {
+ return err
+ }
+
+ p.writeIndent(-1)
+ p.WriteByte('<')
+ p.WriteByte('/')
+ p.WriteString(name)
+ p.WriteByte('>')
+
+ return nil
+}
+
+var timeType = reflect.TypeOf(time.Time{})
+
+func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error {
+ // Normally we don't see structs, but this can happen for an attribute.
+ if val.Type() == timeType {
+ p.WriteString(val.Interface().(time.Time).Format(time.RFC3339Nano))
+ return nil
+ }
+ switch val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.WriteString(strconv.FormatInt(val.Int(), 10))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p.WriteString(strconv.FormatUint(val.Uint(), 10))
+ case reflect.Float32, reflect.Float64:
+ p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64))
+ case reflect.String:
+ // TODO: Add EscapeString.
+ Escape(p, []byte(val.String()))
+ case reflect.Bool:
+ p.WriteString(strconv.FormatBool(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
+ Escape(p, val.Bytes())
+ default:
+ return &UnsupportedTypeError{typ}
+ }
+ return nil
+}
+
+var ddBytes = []byte("--")
+
+func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
+ if val.Type() == timeType {
+ p.WriteString(val.Interface().(time.Time).Format(time.RFC3339Nano))
+ return nil
+ }
+ s := parentStack{printer: p}
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ if finfo.flags&(fAttr|fAny) != 0 {
+ continue
+ }
+ vf := val.FieldByIndex(finfo.idx)
+ switch finfo.flags & fMode {
+ case fCharData:
+ switch vf.Kind() {
+ case reflect.String:
+ Escape(p, []byte(vf.String()))
+ case reflect.Slice:
+ if elem, ok := vf.Interface().([]byte); ok {
+ Escape(p, elem)
+ }
+ }
+ continue
+
+ case fComment:
+ k := vf.Kind()
+ if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
+ return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
+ }
+ if vf.Len() == 0 {
+ continue
+ }
+ p.writeIndent(0)
+ p.WriteString("<!--")
+ dashDash := false
+ dashLast := false
+ switch k {
+ case reflect.String:
+ s := vf.String()
+ dashDash = strings.Index(s, "--") >= 0
+ dashLast = s[len(s)-1] == '-'
+ if !dashDash {
+ p.WriteString(s)
+ }
+ case reflect.Slice:
+ b := vf.Bytes()
+ dashDash = bytes.Index(b, ddBytes) >= 0
+ dashLast = b[len(b)-1] == '-'
+ if !dashDash {
+ p.Write(b)
+ }
+ default:
+ panic("can't happen")
+ }
+ if dashDash {
+ return fmt.Errorf(`xml: comments must not contain "--"`)
+ }
+ if dashLast {
+ // "--->" is invalid grammar. Make it "- -->"
+ p.WriteByte(' ')
+ }
+ p.WriteString("-->")
+ continue
+
+ case fInnerXml:
+ iface := vf.Interface()
+ switch raw := iface.(type) {
+ case []byte:
+ p.Write(raw)
+ continue
+ case string:
+ p.WriteString(raw)
+ continue
+ }
+
+ case fElement:
+ s.trim(finfo.parents)
+ if len(finfo.parents) > len(s.stack) {
+ if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
+ s.push(finfo.parents[len(s.stack):])
+ }
+ }
+ }
+ if err := p.marshalValue(vf, finfo); err != nil {
+ return err
+ }
+ }
+ s.trim(nil)
+ return nil
+}
+
+func (p *printer) writeIndent(depthDelta int) {
+ if len(p.prefix) == 0 && len(p.indent) == 0 {
+ return
+ }
+ if depthDelta < 0 {
+ p.depth--
+ if p.indentedIn {
+ p.indentedIn = false
+ return
+ }
+ p.indentedIn = false
+ }
+ p.WriteByte('\n')
+ if len(p.prefix) > 0 {
+ p.WriteString(p.prefix)
+ }
+ if len(p.indent) > 0 {
+ for i := 0; i < p.depth; i++ {
+ p.WriteString(p.indent)
+ }
+ }
+ if depthDelta > 0 {
+ p.depth++
+ p.indentedIn = true
+ }
+}
+
+type parentStack struct {
+ *printer
+ stack []string
+}
+
+// trim updates the XML context to match the longest common prefix of the stack
+// and the given parents. A closing tag will be written for every parent
+// popped. Passing a zero slice or nil will close all the elements.
+func (s *parentStack) trim(parents []string) {
+ split := 0
+ for ; split < len(parents) && split < len(s.stack); split++ {
+ if parents[split] != s.stack[split] {
+ break
+ }
+ }
+ for i := len(s.stack) - 1; i >= split; i-- {
+ s.writeIndent(-1)
+ s.WriteString("</")
+ s.WriteString(s.stack[i])
+ s.WriteByte('>')
+ }
+ s.stack = parents[:split]
+}
+
+// push adds parent elements to the stack and writes open tags.
+func (s *parentStack) push(parents []string) {
+ for i := 0; i < len(parents); i++ {
+ s.writeIndent(1)
+ s.WriteByte('<')
+ s.WriteString(parents[i])
+ s.WriteByte('>')
+ }
+ s.stack = append(s.stack, parents...)
+}
+
+// A MarshalXMLError is returned when Marshal encounters a type
+// that cannot be converted into XML.
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) Error() string {
+ return "xml: unsupported type: " + e.Type.String()
+}
+
+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
+}
diff --git a/src/pkg/encoding/xml/marshal_test.go b/src/pkg/encoding/xml/marshal_test.go
new file mode 100644
index 000000000..b6978a1e6
--- /dev/null
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -0,0 +1,793 @@
+// 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"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+)
+
+type DriveType int
+
+const (
+ HyperDrive DriveType = iota
+ ImprobabilityDrive
+)
+
+type Passenger struct {
+ Name []string `xml:"name"`
+ Weight float32 `xml:"weight"`
+}
+
+type Ship struct {
+ XMLName struct{} `xml:"spaceship"`
+
+ Name string `xml:"name,attr"`
+ Pilot string `xml:"pilot,attr"`
+ Drive DriveType `xml:"drive"`
+ Age uint `xml:"age"`
+ Passenger []*Passenger `xml:"passenger"`
+ secret string
+}
+
+type NamedType string
+
+type Port struct {
+ XMLName struct{} `xml:"port"`
+ Type string `xml:"type,attr,omitempty"`
+ Comment string `xml:",comment"`
+ Number string `xml:",chardata"`
+}
+
+type Domain struct {
+ XMLName struct{} `xml:"domain"`
+ Country string `xml:",attr,omitempty"`
+ Name []byte `xml:",chardata"`
+ Comment []byte `xml:",comment"`
+}
+
+type Book struct {
+ XMLName struct{} `xml:"book"`
+ Title string `xml:",chardata"`
+}
+
+type SecretAgent struct {
+ XMLName struct{} `xml:"agent"`
+ Handle string `xml:"handle,attr"`
+ Identity string
+ Obfuscate string `xml:",innerxml"`
+}
+
+type NestedItems struct {
+ XMLName struct{} `xml:"result"`
+ Items []string `xml:">item"`
+ Item1 []string `xml:"Items>item1"`
+}
+
+type NestedOrder struct {
+ XMLName struct{} `xml:"result"`
+ Field1 string `xml:"parent>c"`
+ Field2 string `xml:"parent>b"`
+ Field3 string `xml:"parent>a"`
+}
+
+type MixedNested struct {
+ XMLName struct{} `xml:"result"`
+ A string `xml:"parent1>a"`
+ B string `xml:"b"`
+ C string `xml:"parent1>parent2>c"`
+ D string `xml:"parent1>d"`
+}
+
+type NilTest struct {
+ A interface{} `xml:"parent1>parent2>a"`
+ B interface{} `xml:"parent1>b"`
+ C interface{} `xml:"parent1>parent2>c"`
+}
+
+type Service struct {
+ XMLName struct{} `xml:"service"`
+ Domain *Domain `xml:"host>domain"`
+ Port *Port `xml:"host>port"`
+ Extra1 interface{}
+ Extra2 interface{} `xml:"host>extra2"`
+}
+
+var nilStruct *Ship
+
+type EmbedA struct {
+ EmbedC
+ EmbedB EmbedB
+ FieldA string
+}
+
+type EmbedB struct {
+ FieldB string
+ EmbedC
+}
+
+type EmbedC struct {
+ FieldA1 string `xml:"FieldA>A1"`
+ FieldA2 string `xml:"FieldA>A2"`
+ FieldB string
+ FieldC string
+}
+
+type NameCasing struct {
+ XMLName struct{} `xml:"casing"`
+ Xy string
+ XY string
+ XyA string `xml:"Xy,attr"`
+ XYA string `xml:"XY,attr"`
+}
+
+type NamePrecedence struct {
+ XMLName Name `xml:"Parent"`
+ FromTag XMLNameWithoutTag `xml:"InTag"`
+ FromNameVal XMLNameWithoutTag
+ FromNameTag XMLNameWithTag
+ InFieldName string
+}
+
+type XMLNameWithTag struct {
+ XMLName Name `xml:"InXMLNameTag"`
+ Value string `xml:",chardata"`
+}
+
+type XMLNameWithoutTag struct {
+ XMLName Name
+ Value string `xml:",chardata"`
+}
+
+type NameInField struct {
+ Foo Name `xml:"ns foo"`
+}
+
+type AttrTest struct {
+ Int int `xml:",attr"`
+ Named int `xml:"int,attr"`
+ Float float64 `xml:",attr"`
+ Uint8 uint8 `xml:",attr"`
+ Bool bool `xml:",attr"`
+ Str string `xml:",attr"`
+ Bytes []byte `xml:",attr"`
+}
+
+type OmitAttrTest struct {
+ Int int `xml:",attr,omitempty"`
+ Named int `xml:"int,attr,omitempty"`
+ Float float64 `xml:",attr,omitempty"`
+ Uint8 uint8 `xml:",attr,omitempty"`
+ Bool bool `xml:",attr,omitempty"`
+ Str string `xml:",attr,omitempty"`
+ Bytes []byte `xml:",attr,omitempty"`
+}
+
+type OmitFieldTest struct {
+ Int int `xml:",omitempty"`
+ Named int `xml:"int,omitempty"`
+ Float float64 `xml:",omitempty"`
+ Uint8 uint8 `xml:",omitempty"`
+ Bool bool `xml:",omitempty"`
+ Str string `xml:",omitempty"`
+ Bytes []byte `xml:",omitempty"`
+ Ptr *PresenceTest `xml:",omitempty"`
+}
+
+type AnyTest struct {
+ XMLName struct{} `xml:"a"`
+ Nested string `xml:"nested>value"`
+ AnyField AnyHolder `xml:",any"`
+}
+
+type AnyHolder struct {
+ XMLName Name
+ XML string `xml:",innerxml"`
+}
+
+type RecurseA struct {
+ A string
+ B *RecurseB
+}
+
+type RecurseB struct {
+ A *RecurseA
+ B string
+}
+
+type PresenceTest struct {
+ Exists *struct{}
+}
+
+type IgnoreTest struct {
+ PublicSecret string `xml:"-"`
+}
+
+type MyBytes []byte
+
+type Data struct {
+ Bytes []byte
+ Attr []byte `xml:",attr"`
+ Custom MyBytes
+}
+
+type Plain struct {
+ V interface{}
+}
+
+// Unless explicitly stated as such (or *Plain), all of the
+// tests below are two-way tests. When introducing new tests,
+// please try to make them two-way as well to ensure that
+// marshalling and unmarshalling are as symmetrical as feasible.
+var marshalTests = []struct {
+ Value interface{}
+ ExpectXML string
+ MarshalOnly bool
+ UnmarshalOnly bool
+}{
+ // Test nil marshals to nothing
+ {Value: nil, ExpectXML: ``, MarshalOnly: true},
+ {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
+
+ // Test value types
+ {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
+ {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
+ {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
+ {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
+ {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
+ {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
+ {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
+ {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
+ {Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
+ {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
+ {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
+ {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
+ {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
+ {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
+
+ // Test time.
+ {
+ Value: &Plain{time.Unix(1e9, 123456789).UTC()},
+ ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
+ },
+
+ // A pointer to struct{} may be used to test for an element's presence.
+ {
+ Value: &PresenceTest{new(struct{})},
+ ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
+ },
+ {
+ Value: &PresenceTest{},
+ ExpectXML: `<PresenceTest></PresenceTest>`,
+ },
+
+ // A pointer to struct{} may be used to test for an element's presence.
+ {
+ Value: &PresenceTest{new(struct{})},
+ ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
+ },
+ {
+ Value: &PresenceTest{},
+ ExpectXML: `<PresenceTest></PresenceTest>`,
+ },
+
+ // A []byte field is only nil if the element was not found.
+ {
+ Value: &Data{},
+ ExpectXML: `<Data></Data>`,
+ UnmarshalOnly: true,
+ },
+ {
+ Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
+ ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
+ UnmarshalOnly: true,
+ },
+
+ // Check that []byte works, including named []byte types.
+ {
+ Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
+ ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
+ },
+
+ // Test innerxml
+ {
+ Value: &SecretAgent{
+ Handle: "007",
+ Identity: "James Bond",
+ Obfuscate: "<redacted/>",
+ },
+ ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &SecretAgent{
+ Handle: "007",
+ Identity: "James Bond",
+ Obfuscate: "<Identity>James Bond</Identity><redacted/>",
+ },
+ ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
+ UnmarshalOnly: true,
+ },
+
+ // 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: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
+ {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
+ {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
+ {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &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{
+ {
+ Name: []string{"Zaphod", "Beeblebrox"},
+ Weight: 7.25,
+ },
+ {
+ Name: []string{"Trisha", "McMillen"},
+ Weight: 5.5,
+ },
+ {
+ Name: []string{"Ford", "Prefect"},
+ Weight: 7,
+ },
+ {
+ 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>`,
+ },
+
+ // Test a>b
+ {
+ Value: &NestedItems{Items: nil, Item1: nil},
+ ExpectXML: `<result>` +
+ `<Items>` +
+ `</Items>` +
+ `</result>`,
+ },
+ {
+ Value: &NestedItems{Items: []string{}, Item1: []string{}},
+ ExpectXML: `<result>` +
+ `<Items>` +
+ `</Items>` +
+ `</result>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &NestedItems{Items: nil, Item1: []string{"A"}},
+ ExpectXML: `<result>` +
+ `<Items>` +
+ `<item1>A</item1>` +
+ `</Items>` +
+ `</result>`,
+ },
+ {
+ Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
+ ExpectXML: `<result>` +
+ `<Items>` +
+ `<item>A</item>` +
+ `<item>B</item>` +
+ `</Items>` +
+ `</result>`,
+ },
+ {
+ Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
+ ExpectXML: `<result>` +
+ `<Items>` +
+ `<item>A</item>` +
+ `<item>B</item>` +
+ `<item1>C</item1>` +
+ `</Items>` +
+ `</result>`,
+ },
+ {
+ Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
+ ExpectXML: `<result>` +
+ `<parent>` +
+ `<c>C</c>` +
+ `<b>B</b>` +
+ `<a>A</a>` +
+ `</parent>` +
+ `</result>`,
+ },
+ {
+ Value: &NilTest{A: "A", B: nil, C: "C"},
+ ExpectXML: `<NilTest>` +
+ `<parent1>` +
+ `<parent2><a>A</a></parent2>` +
+ `<parent2><c>C</c></parent2>` +
+ `</parent1>` +
+ `</NilTest>`,
+ MarshalOnly: true, // Uses interface{}
+ },
+ {
+ Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
+ ExpectXML: `<result>` +
+ `<parent1><a>A</a></parent1>` +
+ `<b>B</b>` +
+ `<parent1>` +
+ `<parent2><c>C</c></parent2>` +
+ `<d>D</d>` +
+ `</parent1>` +
+ `</result>`,
+ },
+ {
+ Value: &Service{Port: &Port{Number: "80"}},
+ ExpectXML: `<service><host><port>80</port></host></service>`,
+ },
+ {
+ Value: &Service{},
+ ExpectXML: `<service></service>`,
+ },
+ {
+ Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
+ ExpectXML: `<service>` +
+ `<host><port>80</port></host>` +
+ `<Extra1>A</Extra1>` +
+ `<host><extra2>B</extra2></host>` +
+ `</service>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
+ ExpectXML: `<service>` +
+ `<host><port>80</port></host>` +
+ `<host><extra2>example</extra2></host>` +
+ `</service>`,
+ MarshalOnly: true,
+ },
+
+ // Test struct embedding
+ {
+ Value: &EmbedA{
+ EmbedC: EmbedC{
+ FieldA1: "", // Shadowed by A.A
+ FieldA2: "", // Shadowed by A.A
+ FieldB: "A.C.B",
+ FieldC: "A.C.C",
+ },
+ EmbedB: EmbedB{
+ FieldB: "A.B.B",
+ EmbedC: EmbedC{
+ FieldA1: "A.B.C.A1",
+ FieldA2: "A.B.C.A2",
+ FieldB: "", // Shadowed by A.B.B
+ FieldC: "A.B.C.C",
+ },
+ },
+ FieldA: "A.A",
+ },
+ ExpectXML: `<EmbedA>` +
+ `<FieldB>A.C.B</FieldB>` +
+ `<FieldC>A.C.C</FieldC>` +
+ `<EmbedB>` +
+ `<FieldB>A.B.B</FieldB>` +
+ `<FieldA>` +
+ `<A1>A.B.C.A1</A1>` +
+ `<A2>A.B.C.A2</A2>` +
+ `</FieldA>` +
+ `<FieldC>A.B.C.C</FieldC>` +
+ `</EmbedB>` +
+ `<FieldA>A.A</FieldA>` +
+ `</EmbedA>`,
+ },
+
+ // Test that name casing matters
+ {
+ Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
+ ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
+ },
+
+ // Test the order in which the XML element name is chosen
+ {
+ Value: &NamePrecedence{
+ FromTag: XMLNameWithoutTag{Value: "A"},
+ FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
+ FromNameTag: XMLNameWithTag{Value: "C"},
+ InFieldName: "D",
+ },
+ ExpectXML: `<Parent>` +
+ `<InTag>A</InTag>` +
+ `<InXMLName>B</InXMLName>` +
+ `<InXMLNameTag>C</InXMLNameTag>` +
+ `<InFieldName>D</InFieldName>` +
+ `</Parent>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &NamePrecedence{
+ XMLName: Name{Local: "Parent"},
+ FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
+ FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
+ FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
+ InFieldName: "D",
+ },
+ ExpectXML: `<Parent>` +
+ `<InTag>A</InTag>` +
+ `<FromNameVal>B</FromNameVal>` +
+ `<InXMLNameTag>C</InXMLNameTag>` +
+ `<InFieldName>D</InFieldName>` +
+ `</Parent>`,
+ UnmarshalOnly: true,
+ },
+
+ // xml.Name works in a plain field as well.
+ {
+ Value: &NameInField{Name{Space: "ns", Local: "foo"}},
+ ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
+ },
+ {
+ Value: &NameInField{Name{Space: "ns", Local: "foo"}},
+ ExpectXML: `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
+ UnmarshalOnly: true,
+ },
+
+ // Marshaling zero xml.Name uses the tag or field name.
+ {
+ Value: &NameInField{},
+ ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
+ MarshalOnly: true,
+ },
+
+ // Test attributes
+ {
+ Value: &AttrTest{
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ },
+ ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
+ ` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
+ },
+ {
+ Value: &AttrTest{Bytes: []byte{}},
+ ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
+ ` Bool="false" Str="" Bytes=""></AttrTest>`,
+ },
+ {
+ Value: &OmitAttrTest{
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ },
+ ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
+ ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
+ },
+ {
+ Value: &OmitAttrTest{},
+ ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
+ },
+
+ // omitempty on fields
+ {
+ Value: &OmitFieldTest{
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ Ptr: &PresenceTest{},
+ },
+ ExpectXML: `<OmitFieldTest>` +
+ `<Int>8</Int>` +
+ `<int>9</int>` +
+ `<Float>23.5</Float>` +
+ `<Uint8>255</Uint8>` +
+ `<Bool>true</Bool>` +
+ `<Str>str</Str>` +
+ `<Bytes>byt</Bytes>` +
+ `<Ptr></Ptr>` +
+ `</OmitFieldTest>`,
+ },
+ {
+ Value: &OmitFieldTest{},
+ ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
+ },
+
+ // Test ",any"
+ {
+ ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
+ Value: &AnyTest{
+ Nested: "known",
+ AnyField: AnyHolder{
+ XMLName: Name{Local: "other"},
+ XML: "<sub>unknown</sub>",
+ },
+ },
+ UnmarshalOnly: true,
+ },
+ {
+ Value: &AnyTest{Nested: "known", AnyField: AnyHolder{XML: "<unknown/>"}},
+ ExpectXML: `<a><nested><value>known</value></nested></a>`,
+ MarshalOnly: true,
+ },
+
+ // Test recursive types.
+ {
+ Value: &RecurseA{
+ A: "a1",
+ B: &RecurseB{
+ A: &RecurseA{"a2", nil},
+ B: "b1",
+ },
+ },
+ ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
+ },
+
+ // Test ignoring fields via "-" tag
+ {
+ ExpectXML: `<IgnoreTest></IgnoreTest>`,
+ Value: &IgnoreTest{},
+ },
+ {
+ ExpectXML: `<IgnoreTest></IgnoreTest>`,
+ Value: &IgnoreTest{PublicSecret: "can't tell"},
+ MarshalOnly: true,
+ },
+ {
+ ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
+ Value: &IgnoreTest{},
+ UnmarshalOnly: true,
+ },
+}
+
+func TestMarshal(t *testing.T) {
+ for idx, test := range marshalTests {
+ if test.UnmarshalOnly {
+ continue
+ }
+ data, err := Marshal(test.Value)
+ if err != nil {
+ t.Errorf("#%d: Error: %s", idx, err)
+ continue
+ }
+ if got, want := string(data), test.ExpectXML; got != want {
+ if strings.Contains(want, "\n") {
+ t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
+ } else {
+ t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
+ }
+ }
+ }
+}
+
+var marshalErrorTests = []struct {
+ Value interface{}
+ Err string
+ Kind reflect.Kind
+}{
+ {
+ Value: make(chan bool),
+ Err: "xml: unsupported type: chan bool",
+ Kind: reflect.Chan,
+ },
+ {
+ Value: map[string]string{
+ "question": "What do you get when you multiply six by nine?",
+ "answer": "42",
+ },
+ Err: "xml: unsupported type: map[string]string",
+ Kind: reflect.Map,
+ },
+ {
+ Value: map[*Ship]bool{nil: false},
+ Err: "xml: unsupported type: map[*xml.Ship]bool",
+ Kind: reflect.Map,
+ },
+ {
+ Value: &Domain{Comment: []byte("f--bar")},
+ Err: `xml: comments must not contain "--"`,
+ },
+}
+
+func TestMarshalErrors(t *testing.T) {
+ for idx, test := range marshalErrorTests {
+ _, err := Marshal(test.Value)
+ if err == nil || err.Error() != test.Err {
+ t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
+ }
+ if test.Kind != reflect.Invalid {
+ if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
+ t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
+ }
+ }
+ }
+}
+
+// Do invertibility testing on the various structures that we test
+func TestUnmarshal(t *testing.T) {
+ for i, test := range marshalTests {
+ if test.MarshalOnly {
+ continue
+ }
+ if _, ok := test.Value.(*Plain); ok {
+ continue
+ }
+
+ vt := reflect.TypeOf(test.Value)
+ dest := reflect.New(vt.Elem()).Interface()
+ err := Unmarshal([]byte(test.ExpectXML), dest)
+
+ switch fix := dest.(type) {
+ case *Feed:
+ 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(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
+ }
+ }
+}
+
+func BenchmarkMarshal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Marshal(atomValue)
+ }
+}
+
+func BenchmarkUnmarshal(b *testing.B) {
+ xml := []byte(atomXml)
+ for i := 0; i < b.N; i++ {
+ Unmarshal(xml, &Feed{})
+ }
+}
diff --git a/src/pkg/encoding/xml/read.go b/src/pkg/encoding/xml/read.go
new file mode 100644
index 000000000..c21682420
--- /dev/null
+++ b/src/pkg/encoding/xml/read.go
@@ -0,0 +1,531 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xml
+
+import (
+ "bytes"
+ "errors"
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
+// an XML element is an order-dependent collection of anonymous
+// values, while a data structure is an order-independent collection
+// of named values.
+// See package json for a textual representation more suitable
+// to data structures.
+
+// Unmarshal parses the XML-encoded data and stores the result in
+// the value pointed to by v, which must be an arbitrary struct,
+// slice, or string. Well-formed data that does not fit into v is
+// discarded.
+//
+// Because Unmarshal uses the reflect package, it can only assign
+// to exported (upper case) fields. Unmarshal uses a case-sensitive
+// comparison to match XML element names to tag values and struct
+// field names.
+//
+// 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 in that field. The rest of the rules still apply.
+//
+// * If the struct has a field named XMLName of type xml.Name,
+// Unmarshal records the element name in that field.
+//
+// * If the XMLName field has an associated tag 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
+// struct field name with an associated tag containing ",attr" or
+// the explicit name in a struct field tag of the form "name,attr",
+// Unmarshal records the attribute value in that field.
+//
+// * If the XML element contains character data, that data is
+// accumulated in the first struct field that has tag "chardata".
+// The struct field may have type []byte or string.
+// If there is no such field, the character data is discarded.
+//
+// * If the XML element contains 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 tag formatted as "a" or "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 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's XMLName tag and the struct field has no
+// explicit name tag as per the previous rule, unmarshal maps
+// the sub-element to that struct field.
+//
+// * If the XML element contains a sub-element whose name matches a
+// field without any mode flags (",attr", ",chardata", etc), Unmarshal
+// maps the sub-element to that struct field.
+//
+// * If the XML element contains a sub-element that hasn't matched any
+// of the above rules and the struct has a field with tag ",any",
+// unmarshal maps the sub-element to that struct field.
+//
+// * A non-pointer anonymous struct field is handled as if the
+// fields of its value were part of the outer struct.
+//
+// * A struct field with tag "-" is never unmarshalled into.
+//
+// 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. The saved []byte is never nil.
+//
+// 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 or attribute value to a bool by
+// setting it to the boolean value represented by the string.
+//
+// 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.
+//
+// Unmarshal maps an XML element to a pointer by setting the pointer
+// to a freshly allocated value and then mapping the element to that value.
+//
+func Unmarshal(data []byte, v interface{}) error {
+ return NewDecoder(bytes.NewBuffer(data)).Decode(v)
+}
+
+// Decode works like xml.Unmarshal, except it reads the decoder
+// stream to find the start element.
+func (d *Decoder) Decode(v interface{}) error {
+ return d.DecodeElement(v, nil)
+}
+
+// DecodeElement works like xml.Unmarshal except that it takes
+// a pointer to the start XML element to decode into v.
+// It is useful when a client reads some raw XML tokens itself
+// but also wants to defer to Unmarshal for some elements.
+func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
+ val := reflect.ValueOf(v)
+ if val.Kind() != reflect.Ptr {
+ return errors.New("non-pointer passed to Unmarshal")
+ }
+ return d.unmarshal(val.Elem(), start)
+}
+
+// An UnmarshalError represents an error in the unmarshalling process.
+type UnmarshalError string
+
+func (e UnmarshalError) Error() string { return string(e) }
+
+// Unmarshal a single XML element into val.
+func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
+ // Find start element if we need it.
+ if start == nil {
+ for {
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ if t, ok := tok.(StartElement); ok {
+ start = &t
+ break
+ }
+ }
+ }
+
+ if pv := val; pv.Kind() == reflect.Ptr {
+ if pv.IsNil() {
+ pv.Set(reflect.New(pv.Type().Elem()))
+ }
+ val = pv.Elem()
+ }
+
+ var (
+ data []byte
+ saveData reflect.Value
+ comment []byte
+ saveComment reflect.Value
+ saveXML reflect.Value
+ saveXMLIndex int
+ saveXMLData []byte
+ saveAny reflect.Value
+ sv reflect.Value
+ tinfo *typeInfo
+ err error
+ )
+
+ switch v := val; v.Kind() {
+ default:
+ return errors.New("unknown type " + v.Type().String())
+
+ case reflect.Interface:
+ // TODO: For now, simply ignore the field. In the near
+ // future we may choose to unmarshal the start
+ // element on it, if not nil.
+ return p.Skip()
+
+ case reflect.Slice:
+ typ := v.Type()
+ if typ.Elem().Kind() == reflect.Uint8 {
+ // []byte
+ saveData = v
+ break
+ }
+
+ // Slice of element values.
+ // Grow slice.
+ n := v.Len()
+ if n >= v.Cap() {
+ ncap := 2 * n
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(typ, n, ncap)
+ reflect.Copy(new, v)
+ v.Set(new)
+ }
+ v.SetLen(n + 1)
+
+ // Recur to read element into slice.
+ if err := p.unmarshal(v.Index(n), start); err != nil {
+ v.SetLen(n)
+ return err
+ }
+ return nil
+
+ case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
+ saveData = v
+
+ case reflect.Struct:
+ typ := v.Type()
+ if typ == nameType {
+ v.Set(reflect.ValueOf(start.Name))
+ break
+ }
+ if typ == timeType {
+ saveData = v
+ break
+ }
+
+ sv = v
+ tinfo, err = getTypeInfo(typ)
+ if err != nil {
+ return err
+ }
+
+ // Validate and assign element name.
+ if tinfo.xmlname != nil {
+ finfo := tinfo.xmlname
+ if finfo.name != "" && finfo.name != start.Name.Local {
+ return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">")
+ }
+ if finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
+ e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have "
+ if start.Name.Space == "" {
+ e += "no name space"
+ } else {
+ e += start.Name.Space
+ }
+ return UnmarshalError(e)
+ }
+ fv := sv.FieldByIndex(finfo.idx)
+ if _, ok := fv.Interface().(Name); ok {
+ fv.Set(reflect.ValueOf(start.Name))
+ }
+ }
+
+ // Assign attributes.
+ // Also, determine whether we need to save character data or comments.
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ switch finfo.flags & fMode {
+ case fAttr:
+ strv := sv.FieldByIndex(finfo.idx)
+ // Look for attribute.
+ for _, a := range start.Attr {
+ if a.Name.Local == finfo.name {
+ copyValue(strv, []byte(a.Value))
+ break
+ }
+ }
+
+ case fCharData:
+ if !saveData.IsValid() {
+ saveData = sv.FieldByIndex(finfo.idx)
+ }
+
+ case fComment:
+ if !saveComment.IsValid() {
+ saveComment = sv.FieldByIndex(finfo.idx)
+ }
+
+ case fAny:
+ if !saveAny.IsValid() {
+ saveAny = sv.FieldByIndex(finfo.idx)
+ }
+
+ case fInnerXml:
+ if !saveXML.IsValid() {
+ saveXML = sv.FieldByIndex(finfo.idx)
+ if p.saved == nil {
+ saveXMLIndex = 0
+ p.saved = new(bytes.Buffer)
+ } else {
+ saveXMLIndex = p.savedOffset()
+ }
+ }
+ }
+ }
+ }
+
+ // Find end element.
+ // Process sub-elements along the way.
+Loop:
+ for {
+ var savedOffset int
+ if saveXML.IsValid() {
+ savedOffset = p.savedOffset()
+ }
+ tok, err := p.Token()
+ if err != nil {
+ return err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ consumed := false
+ if sv.IsValid() {
+ consumed, err = p.unmarshalPath(tinfo, sv, nil, &t)
+ if err != nil {
+ return err
+ }
+ if !consumed && saveAny.IsValid() {
+ consumed = true
+ if err := p.unmarshal(saveAny, &t); err != nil {
+ return err
+ }
+ }
+ }
+ if !consumed {
+ if err := p.Skip(); err != nil {
+ return err
+ }
+ }
+
+ case EndElement:
+ if saveXML.IsValid() {
+ saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
+ if saveXMLIndex == 0 {
+ p.saved = nil
+ }
+ }
+ break Loop
+
+ case CharData:
+ if saveData.IsValid() {
+ data = append(data, t...)
+ }
+
+ case Comment:
+ if saveComment.IsValid() {
+ comment = append(comment, t...)
+ }
+ }
+ }
+
+ 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 error) {
+ // Helper functions for integer and unsigned integer conversions
+ var itmp int64
+ getInt64 := func() bool {
+ itmp, err = strconv.ParseInt(string(src), 10, 64)
+ // TODO: should check sizes
+ return err == nil
+ }
+ var utmp uint64
+ getUint64 := func() bool {
+ utmp, err = strconv.ParseUint(string(src), 10, 64)
+ // TODO: check for overflow?
+ return err == nil
+ }
+ var ftmp float64
+ getFloat64 := func() bool {
+ ftmp, err = strconv.ParseFloat(string(src), 64)
+ // TODO: check for overflow?
+ return err == nil
+ }
+
+ // Save accumulated data.
+ switch t := dst; t.Kind() {
+ case reflect.Invalid:
+ // Probably a comment.
+ default:
+ return errors.New("cannot happen: unknown type " + t.Type().String())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if !getInt64() {
+ return err
+ }
+ t.SetInt(itmp)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ if !getUint64() {
+ return err
+ }
+ t.SetUint(utmp)
+ case reflect.Float32, reflect.Float64:
+ if !getFloat64() {
+ return err
+ }
+ t.SetFloat(ftmp)
+ case reflect.Bool:
+ value, err := strconv.ParseBool(strings.TrimSpace(string(src)))
+ if err != nil {
+ return err
+ }
+ t.SetBool(value)
+ case reflect.String:
+ t.SetString(string(src))
+ case reflect.Slice:
+ if len(src) == 0 {
+ // non-nil to flag presence
+ src = []byte{}
+ }
+ t.SetBytes(src)
+ case reflect.Struct:
+ if t.Type() == timeType {
+ tv, err := time.Parse(time.RFC3339, string(src))
+ if err != nil {
+ return err
+ }
+ t.Set(reflect.ValueOf(tv))
+ }
+ }
+ return nil
+}
+
+// unmarshalPath walks down an XML structure looking for wanted
+// paths, and calls unmarshal on them.
+// The consumed result tells whether XML elements have been consumed
+// from the Decoder until start's matching end element, or if it's
+// still untouched because start is uninteresting for sv's fields.
+func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
+ recurse := false
+Loop:
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) {
+ continue
+ }
+ for j := range parents {
+ if parents[j] != finfo.parents[j] {
+ continue Loop
+ }
+ }
+ if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
+ // It's a perfect match, unmarshal the field.
+ return true, p.unmarshal(sv.FieldByIndex(finfo.idx), start)
+ }
+ if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
+ // It's a prefix for the field. Break and recurse
+ // since it's not ok for one field path to be itself
+ // the prefix for another field path.
+ recurse = true
+
+ // We can reuse the same slice as long as we
+ // don't try to append to it.
+ parents = finfo.parents[:len(parents)+1]
+ break
+ }
+ }
+ if !recurse {
+ // We have no business with this element.
+ return false, nil
+ }
+ // The element is not a perfect match for any field, but one
+ // or more fields have the path to this element as a parent
+ // prefix. Recurse and attempt to match these.
+ for {
+ var tok Token
+ tok, err = p.Token()
+ if err != nil {
+ return true, err
+ }
+ switch t := tok.(type) {
+ case StartElement:
+ consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t)
+ if err != nil {
+ return true, err
+ }
+ if !consumed2 {
+ if err := p.Skip(); err != nil {
+ return true, err
+ }
+ }
+ case EndElement:
+ return true, nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Skip reads tokens until it has consumed the end element
+// matching the most recent start element already consumed.
+// It recurs if it encounters a start element, so it can be used to
+// skip nested structures.
+// It returns nil if it finds an end element matching the start
+// element; otherwise it returns an error describing the problem.
+func (d *Decoder) Skip() error {
+ for {
+ tok, err := d.Token()
+ if err != nil {
+ return err
+ }
+ switch tok.(type) {
+ case StartElement:
+ if err := d.Skip(); err != nil {
+ return err
+ }
+ case EndElement:
+ return nil
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/xml/read_test.go b/src/pkg/encoding/xml/read_test.go
index 2126da3c7..8df09b3cc 100644
--- a/src/pkg/xml/read_test.go
+++ b/src/pkg/encoding/xml/read_test.go
@@ -7,13 +7,14 @@ package xml
import (
"reflect"
"testing"
+ "time"
)
// Stripped down Atom feed data structures.
func TestUnmarshalFeed(t *testing.T) {
var f Feed
- if err := Unmarshal(StringReader(atomFeedString), &f); err != nil {
+ if err := Unmarshal([]byte(atomFeedString), &f); err != nil {
t.Fatalf("Unmarshal: %s", err)
}
if !reflect.DeepEqual(f, atomFeed) {
@@ -24,8 +25,8 @@ func TestUnmarshalFeed(t *testing.T) {
// hget http://codereview.appspot.com/rss/mine/rsc
const atomFeedString = `
<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><li-nk href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></li-nk><id>http://codereview.appspot.com/</id><updated>2009-10-04T01:35:58+00:00</updated><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
-</title><link hre-f="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
+<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us" updated="2009-10-04T01:35:58+00:00"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
+</title><link href="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
An attempt at adding pubsubhubbub support to Rietveld.
http://code.google.com/p/pubsubhubbub
http://code.google.com/p/rietveld/issues/detail?id=155
@@ -78,43 +79,41 @@ not being used from outside intra_region_diff.py.
</summary></entry></feed> `
type Feed struct {
- XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
- Title string
- Id string
- Link []Link
- Updated Time
- Author Person
- Entry []Entry
+ XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
+ Title string `xml:"title"`
+ Id string `xml:"id"`
+ Link []Link `xml:"link"`
+ Updated time.Time `xml:"updated,attr"`
+ Author Person `xml:"author"`
+ Entry []Entry `xml:"entry"`
}
type Entry struct {
- Title string
- Id string
- Link []Link
- Updated Time
- Author Person
- Summary Text
+ Title string `xml:"title"`
+ Id string `xml:"id"`
+ Link []Link `xml:"link"`
+ Updated time.Time `xml:"updated"`
+ Author Person `xml:"author"`
+ Summary Text `xml:"summary"`
}
type Link struct {
- Rel string `xml:"attr"`
- Href string `xml:"attr"`
+ Rel string `xml:"rel,attr,omitempty"`
+ Href string `xml:"href,attr"`
}
type Person struct {
- Name string
- URI string
- Email string
- InnerXML string `xml:"innerxml"`
+ Name string `xml:"name"`
+ URI string `xml:"uri"`
+ Email string `xml:"email"`
+ InnerXML string `xml:",innerxml"`
}
type Text struct {
- Type string `xml:"attr"`
- Body string `xml:"chardata"`
+ Type string `xml:"type,attr,omitempty"`
+ Body string `xml:",chardata"`
}
-type Time string
-
var atomFeed = Feed{
XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
Title: "Code Review - My issues",
@@ -123,7 +122,7 @@ var atomFeed = Feed{
{Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
},
Id: "http://codereview.appspot.com/",
- Updated: "2009-10-04T01:35:58+00:00",
+ Updated: ParseTime("2009-10-04T01:35:58+00:00"),
Author: Person{
Name: "rietveld<>",
InnerXML: "<name>rietveld&lt;&gt;</name>",
@@ -134,7 +133,7 @@ var atomFeed = Feed{
Link: []Link{
{Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
},
- Updated: "2009-10-04T01:35:58+00:00",
+ Updated: ParseTime("2009-10-04T01:35:58+00:00"),
Author: Person{
Name: "email-address-removed",
InnerXML: "<name>email-address-removed</name>",
@@ -181,7 +180,7 @@ the top of feeds.py marked NOTE(rsc).
Link: []Link{
{Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
},
- Updated: "2009-10-03T23:02:17+00:00",
+ Updated: ParseTime("2009-10-03T23:02:17+00:00"),
Author: Person{
Name: "email-address-removed",
InnerXML: "<name>email-address-removed</name>",
@@ -213,41 +212,26 @@ not being used from outside intra_region_diff.py.
},
}
-type FieldNameTest struct {
- in, out string
-}
-
-var FieldNameTests = []FieldNameTest{
- {"Profile-Image", "profileimage"},
- {"_score", "score"},
-}
-
-func TestFieldName(t *testing.T) {
- for _, tt := range FieldNameTests {
- a := fieldName(tt.in)
- if a != tt.out {
- t.Fatalf("have %#v\nwant %#v\n\n", a, tt.out)
- }
- }
-}
-
const pathTestString = `
-<result>
- <before>1</before>
- <items>
- <item1>
- <value>A</value>
- </item1>
- <item2>
- <value>B</value>
- </item2>
+<Result>
+ <Before>1</Before>
+ <Items>
+ <Item1>
+ <Value>A</Value>
+ </Item1>
+ <Item2>
+ <Value>B</Value>
+ </Item2>
<Item1>
<Value>C</Value>
<Value>D</Value>
</Item1>
- </items>
- <after>2</after>
-</result>
+ <_>
+ <Value>E</Value>
+ </_>
+ </Items>
+ <After>2</After>
+</Result>
`
type PathTestItem struct {
@@ -255,18 +239,18 @@ type PathTestItem struct {
}
type PathTestA struct {
- Items []PathTestItem `xml:">item1"`
+ Items []PathTestItem `xml:">Item1"`
Before, After string
}
type PathTestB struct {
- Other []PathTestItem `xml:"items>Item1"`
+ Other []PathTestItem `xml:"Items>Item1"`
Before, After string
}
type PathTestC struct {
- Values1 []string `xml:"items>item1>value"`
- Values2 []string `xml:"items>item2>value"`
+ Values1 []string `xml:"Items>Item1>Value"`
+ Values2 []string `xml:"Items>Item2>Value"`
Before, After string
}
@@ -275,7 +259,12 @@ type PathTestSet struct {
}
type PathTestD struct {
- Other PathTestSet `xml:"items>"`
+ Other PathTestSet `xml:"Items"`
+ Before, After string
+}
+
+type PathTestE struct {
+ Underline string `xml:"Items>_>Value"`
Before, After string
}
@@ -284,12 +273,13 @@ var pathTests = []interface{}{
&PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
&PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"},
&PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"},
+ &PathTestE{Underline: "E", Before: "1", After: "2"},
}
func TestUnmarshalPaths(t *testing.T) {
for _, pt := range pathTests {
v := reflect.New(reflect.TypeOf(pt).Elem()).Interface()
- if err := Unmarshal(StringReader(pathTestString), v); err != nil {
+ if err := Unmarshal([]byte(pathTestString), v); err != nil {
t.Fatalf("Unmarshal: %s", err)
}
if !reflect.DeepEqual(v, pt) {
@@ -301,7 +291,7 @@ func TestUnmarshalPaths(t *testing.T) {
type BadPathTestA struct {
First string `xml:"items>item1"`
Other string `xml:"items>item2"`
- Second string `xml:"items>"`
+ Second string `xml:"items"`
}
type BadPathTestB struct {
@@ -310,62 +300,58 @@ type BadPathTestB struct {
Second string `xml:"items>item1>value"`
}
+type BadPathTestC struct {
+ First string
+ Second string `xml:"First"`
+}
+
+type BadPathTestD struct {
+ BadPathEmbeddedA
+ BadPathEmbeddedB
+}
+
+type BadPathEmbeddedA struct {
+ First string
+}
+
+type BadPathEmbeddedB struct {
+ Second string `xml:"First"`
+}
+
var badPathTests = []struct {
v, e interface{}
}{
- {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items>"}},
+ {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items"}},
{&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
+ {&BadPathTestC{}, &TagPathError{reflect.TypeOf(BadPathTestC{}), "First", "", "Second", "First"}},
+ {&BadPathTestD{}, &TagPathError{reflect.TypeOf(BadPathTestD{}), "First", "", "Second", "First"}},
}
func TestUnmarshalBadPaths(t *testing.T) {
for _, tt := range badPathTests {
- err := Unmarshal(StringReader(pathTestString), tt.v)
+ err := Unmarshal([]byte(pathTestString), tt.v)
if !reflect.DeepEqual(err, tt.e) {
- t.Fatalf("Unmarshal with %#v didn't fail properly: %#v", tt.v, err)
+ t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e)
}
}
}
-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"`
-}
+const OK = "OK"
+const withoutNameTypeData = `
+<?xml version="1.0" charset="utf-8"?>
+<Test3 Attr="OK" />`
-type Test2 struct {
- Bool bool `xml:"attr"`
+type TestThree struct {
+ XMLName Name `xml:"Test3"`
+ Attr string `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,
- },
+func TestUnmarshalWithoutNameType(t *testing.T) {
+ var x TestThree
+ if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if x.Attr != OK {
+ t.Fatalf("have %v\nwant %v", x.Attr, OK)
+ }
}
diff --git a/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
new file mode 100644
index 000000000..8e2e4508b
--- /dev/null
+++ b/src/pkg/encoding/xml/typeinfo.go
@@ -0,0 +1,329 @@
+// 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 (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+)
+
+// typeInfo holds details for the xml representation of a type.
+type typeInfo struct {
+ xmlname *fieldInfo
+ fields []fieldInfo
+}
+
+// fieldInfo holds details for the xml representation of a single field.
+type fieldInfo struct {
+ idx []int
+ name string
+ xmlns string
+ flags fieldFlags
+ parents []string
+}
+
+type fieldFlags int
+
+const (
+ fElement fieldFlags = 1 << iota
+ fAttr
+ fCharData
+ fInnerXml
+ fComment
+ fAny
+
+ fOmitEmpty
+
+ fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
+)
+
+var tinfoMap = make(map[reflect.Type]*typeInfo)
+var tinfoLock sync.RWMutex
+
+var nameType = reflect.TypeOf(Name{})
+
+// getTypeInfo returns the typeInfo structure with details necessary
+// for marshalling and unmarshalling typ.
+func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
+ tinfoLock.RLock()
+ tinfo, ok := tinfoMap[typ]
+ tinfoLock.RUnlock()
+ if ok {
+ return tinfo, nil
+ }
+ tinfo = &typeInfo{}
+ if typ.Kind() == reflect.Struct && typ != nameType {
+ n := typ.NumField()
+ for i := 0; i < n; i++ {
+ f := typ.Field(i)
+ if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
+ continue // Private field
+ }
+
+ // For embedded structs, embed its fields.
+ if f.Anonymous {
+ if f.Type.Kind() != reflect.Struct {
+ continue
+ }
+ inner, err := getTypeInfo(f.Type)
+ if err != nil {
+ return nil, err
+ }
+ for _, finfo := range inner.fields {
+ finfo.idx = append([]int{i}, finfo.idx...)
+ if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
+ return nil, err
+ }
+ }
+ continue
+ }
+
+ finfo, err := structFieldInfo(typ, &f)
+ if err != nil {
+ return nil, err
+ }
+
+ if f.Name == "XMLName" {
+ tinfo.xmlname = finfo
+ continue
+ }
+
+ // Add the field if it doesn't conflict with other fields.
+ if err := addFieldInfo(typ, tinfo, finfo); err != nil {
+ return nil, err
+ }
+ }
+ }
+ tinfoLock.Lock()
+ tinfoMap[typ] = tinfo
+ tinfoLock.Unlock()
+ return tinfo, nil
+}
+
+// structFieldInfo builds and returns a fieldInfo for f.
+func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) {
+ finfo := &fieldInfo{idx: f.Index}
+
+ // Split the tag from the xml namespace if necessary.
+ tag := f.Tag.Get("xml")
+ if i := strings.Index(tag, " "); i >= 0 {
+ finfo.xmlns, tag = tag[:i], tag[i+1:]
+ }
+
+ // Parse flags.
+ tokens := strings.Split(tag, ",")
+ if len(tokens) == 1 {
+ finfo.flags = fElement
+ } else {
+ tag = tokens[0]
+ for _, flag := range tokens[1:] {
+ switch flag {
+ case "attr":
+ finfo.flags |= fAttr
+ case "chardata":
+ finfo.flags |= fCharData
+ case "innerxml":
+ finfo.flags |= fInnerXml
+ case "comment":
+ finfo.flags |= fComment
+ case "any":
+ finfo.flags |= fAny
+ case "omitempty":
+ finfo.flags |= fOmitEmpty
+ }
+ }
+
+ // Validate the flags used.
+ valid := true
+ switch mode := finfo.flags & fMode; mode {
+ case 0:
+ finfo.flags |= fElement
+ case fAttr, fCharData, fInnerXml, fComment, fAny:
+ if f.Name == "XMLName" || tag != "" && mode != fAttr {
+ valid = false
+ }
+ default:
+ // This will also catch multiple modes in a single field.
+ valid = false
+ }
+ if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 {
+ valid = false
+ }
+ if !valid {
+ return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q",
+ f.Name, typ, f.Tag.Get("xml"))
+ }
+ }
+
+ // Use of xmlns without a name is not allowed.
+ if finfo.xmlns != "" && tag == "" {
+ return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q",
+ f.Name, typ, f.Tag.Get("xml"))
+ }
+
+ if f.Name == "XMLName" {
+ // The XMLName field records the XML element name. Don't
+ // process it as usual because its name should default to
+ // empty rather than to the field name.
+ finfo.name = tag
+ return finfo, nil
+ }
+
+ if tag == "" {
+ // If the name part of the tag is completely empty, get
+ // default from XMLName of underlying struct if feasible,
+ // or field name otherwise.
+ if xmlname := lookupXMLName(f.Type); xmlname != nil {
+ finfo.xmlns, finfo.name = xmlname.xmlns, xmlname.name
+ } else {
+ finfo.name = f.Name
+ }
+ return finfo, nil
+ }
+
+ // Prepare field name and parents.
+ tokens = strings.Split(tag, ">")
+ if tokens[0] == "" {
+ tokens[0] = f.Name
+ }
+ if tokens[len(tokens)-1] == "" {
+ return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ)
+ }
+ finfo.name = tokens[len(tokens)-1]
+ if len(tokens) > 1 {
+ finfo.parents = tokens[:len(tokens)-1]
+ }
+
+ // If the field type has an XMLName field, the names must match
+ // so that the behavior of both marshalling and unmarshalling
+ // is straightforward and unambiguous.
+ if finfo.flags&fElement != 0 {
+ ftyp := f.Type
+ xmlname := lookupXMLName(ftyp)
+ if xmlname != nil && xmlname.name != finfo.name {
+ return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName",
+ finfo.name, typ, f.Name, xmlname.name, ftyp)
+ }
+ }
+ return finfo, nil
+}
+
+// lookupXMLName returns the fieldInfo for typ's XMLName field
+// in case it exists and has a valid xml field tag, otherwise
+// it returns nil.
+func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) {
+ for typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ }
+ if typ.Kind() != reflect.Struct {
+ return nil
+ }
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ f := typ.Field(i)
+ if f.Name != "XMLName" {
+ continue
+ }
+ finfo, err := structFieldInfo(typ, &f)
+ if finfo.name != "" && err == nil {
+ return finfo
+ }
+ // Also consider errors as a non-existent field tag
+ // and let getTypeInfo itself report the error.
+ break
+ }
+ return nil
+}
+
+func min(a, b int) int {
+ if a <= b {
+ return a
+ }
+ return b
+}
+
+// addFieldInfo adds finfo to tinfo.fields if there are no
+// conflicts, or if conflicts arise from previous fields that were
+// obtained from deeper embedded structures than finfo. In the latter
+// case, the conflicting entries are dropped.
+// A conflict occurs when the path (parent + name) to a field is
+// itself a prefix of another path, or when two paths match exactly.
+// It is okay for field paths to share a common, shorter prefix.
+func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error {
+ var conflicts []int
+Loop:
+ // First, figure all conflicts. Most working code will have none.
+ for i := range tinfo.fields {
+ oldf := &tinfo.fields[i]
+ if oldf.flags&fMode != newf.flags&fMode {
+ continue
+ }
+ minl := min(len(newf.parents), len(oldf.parents))
+ for p := 0; p < minl; p++ {
+ if oldf.parents[p] != newf.parents[p] {
+ continue Loop
+ }
+ }
+ if len(oldf.parents) > len(newf.parents) {
+ if oldf.parents[len(newf.parents)] == newf.name {
+ conflicts = append(conflicts, i)
+ }
+ } else if len(oldf.parents) < len(newf.parents) {
+ if newf.parents[len(oldf.parents)] == oldf.name {
+ conflicts = append(conflicts, i)
+ }
+ } else {
+ if newf.name == oldf.name {
+ conflicts = append(conflicts, i)
+ }
+ }
+ }
+ // Without conflicts, add the new field and return.
+ if conflicts == nil {
+ tinfo.fields = append(tinfo.fields, *newf)
+ return nil
+ }
+
+ // If any conflict is shallower, ignore the new field.
+ // This matches the Go field resolution on embedding.
+ for _, i := range conflicts {
+ if len(tinfo.fields[i].idx) < len(newf.idx) {
+ return nil
+ }
+ }
+
+ // Otherwise, if any of them is at the same depth level, it's an error.
+ for _, i := range conflicts {
+ oldf := &tinfo.fields[i]
+ if len(oldf.idx) == len(newf.idx) {
+ f1 := typ.FieldByIndex(oldf.idx)
+ f2 := typ.FieldByIndex(newf.idx)
+ return &TagPathError{typ, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
+ }
+ }
+
+ // Otherwise, the new field is shallower, and thus takes precedence,
+ // so drop the conflicting fields from tinfo and append the new one.
+ for c := len(conflicts) - 1; c >= 0; c-- {
+ i := conflicts[c]
+ copy(tinfo.fields[i:], tinfo.fields[i+1:])
+ tinfo.fields = tinfo.fields[:len(tinfo.fields)-1]
+ }
+ tinfo.fields = append(tinfo.fields, *newf)
+ return nil
+}
+
+// A TagPathError represents an error in the unmarshalling process
+// caused by the use of field tags with conflicting paths.
+type TagPathError struct {
+ Struct reflect.Type
+ Field1, Tag1 string
+ Field2, Tag2 string
+}
+
+func (e *TagPathError) Error() string {
+ return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
+}
diff --git a/src/pkg/xml/xml.go b/src/pkg/encoding/xml/xml.go
index e7ba44e4a..5066f5c01 100644
--- a/src/pkg/xml/xml.go
+++ b/src/pkg/encoding/xml/xml.go
@@ -18,11 +18,10 @@ import (
"bytes"
"fmt"
"io"
- "os"
"strconv"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// A SyntaxError represents a syntax error in the XML input stream.
@@ -31,13 +30,13 @@ type SyntaxError struct {
Line int
}
-func (e *SyntaxError) String() string {
+func (e *SyntaxError) Error() string {
return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg
}
// A Name represents an XML name (Local) annotated
// with a name space identifier (Space).
-// In tokens returned by Parser.Token, the Space identifier
+// In tokens returned by Decoder.Token, the Space identifier
// is given as a canonical URL, not the short prefix used
// in the document being parsed.
type Name struct {
@@ -62,7 +61,7 @@ type StartElement struct {
func (e StartElement) Copy() StartElement {
attrs := make([]Attr, len(e.Attr))
- copy(e.Attr, attrs)
+ copy(attrs, e.Attr)
e.Attr = attrs
return e
}
@@ -125,9 +124,9 @@ func CopyToken(t Token) Token {
return t
}
-// A Parser represents an XML parser reading a particular input stream.
+// A Decoder represents an XML parser reading a particular input stream.
// The parser assumes that its input is encoded in UTF-8.
-type Parser struct {
+type Decoder struct {
// Strict defaults to true, enforcing the requirements
// of the XML specification.
// If set to false, the parser allows input containing common
@@ -140,9 +139,9 @@ type Parser struct {
//
// Setting:
//
- // p.Strict = false;
- // p.AutoClose = HTMLAutoClose;
- // p.Entity = HTMLEntity
+ // d.Strict = false;
+ // d.AutoClose = HTMLAutoClose;
+ // d.Entity = HTMLEntity
//
// creates a parser that can handle typical HTML.
Strict bool
@@ -168,7 +167,7 @@ type Parser struct {
// non-UTF-8 charset into UTF-8. If CharsetReader is nil or
// returns an error, parsing stops with an error. One of the
// the CharsetReader's result values must be non-nil.
- CharsetReader func(charset string, input io.Reader) (io.Reader, os.Error)
+ CharsetReader func(charset string, input io.Reader) (io.Reader, error)
r io.ByteReader
buf bytes.Buffer
@@ -180,25 +179,25 @@ type Parser struct {
nextToken Token
nextByte int
ns map[string]string
- err os.Error
+ err error
line int
tmp [32]byte
}
-// NewParser creates a new XML parser reading from r.
-func NewParser(r io.Reader) *Parser {
- p := &Parser{
+// NewDecoder creates a new XML parser reading from r.
+func NewDecoder(r io.Reader) *Decoder {
+ d := &Decoder{
ns: make(map[string]string),
nextByte: -1,
line: 1,
Strict: true,
}
- p.switchToReader(r)
- return p
+ d.switchToReader(r)
+ return d
}
// Token returns the next XML token in the input stream.
-// At the end of the input stream, Token returns nil, os.EOF.
+// At the end of the input stream, Token returns nil, io.EOF.
//
// Slices of bytes in the returned token data refer to the
// parser's internal buffer and remain valid only until the next
@@ -219,17 +218,17 @@ func NewParser(r io.Reader) *Parser {
// set to the URL identifying its name space when known.
// If Token encounters an unrecognized name space prefix,
// it uses the prefix as the Space rather than report an error.
-func (p *Parser) Token() (t Token, err os.Error) {
- if p.nextToken != nil {
- t = p.nextToken
- p.nextToken = nil
- } else if t, err = p.RawToken(); err != nil {
+func (d *Decoder) Token() (t Token, err error) {
+ if d.nextToken != nil {
+ t = d.nextToken
+ d.nextToken = nil
+ } else if t, err = d.RawToken(); err != nil {
return
}
- if !p.Strict {
- if t1, ok := p.autoClose(t); ok {
- p.nextToken = t
+ if !d.Strict {
+ if t1, ok := d.autoClose(t); ok {
+ d.nextToken = t
t = t1
}
}
@@ -241,29 +240,29 @@ func (p *Parser) Token() (t Token, err os.Error) {
// the translations first.
for _, a := range t1.Attr {
if a.Name.Space == "xmlns" {
- v, ok := p.ns[a.Name.Local]
- p.pushNs(a.Name.Local, v, ok)
- p.ns[a.Name.Local] = a.Value
+ v, ok := d.ns[a.Name.Local]
+ d.pushNs(a.Name.Local, v, ok)
+ d.ns[a.Name.Local] = a.Value
}
if a.Name.Space == "" && a.Name.Local == "xmlns" {
// Default space for untagged names
- v, ok := p.ns[""]
- p.pushNs("", v, ok)
- p.ns[""] = a.Value
+ v, ok := d.ns[""]
+ d.pushNs("", v, ok)
+ d.ns[""] = a.Value
}
}
- p.translate(&t1.Name, true)
+ d.translate(&t1.Name, true)
for i := range t1.Attr {
- p.translate(&t1.Attr[i].Name, false)
+ d.translate(&t1.Attr[i].Name, false)
}
- p.pushElement(t1.Name)
+ d.pushElement(t1.Name)
t = t1
case EndElement:
- p.translate(&t1.Name, true)
- if !p.popElement(&t1) {
- return nil, p.err
+ d.translate(&t1.Name, true)
+ if !d.popElement(&t1) {
+ return nil, d.err
}
t = t1
}
@@ -273,7 +272,7 @@ func (p *Parser) Token() (t Token, err os.Error) {
// Apply name space translation to name n.
// The default name space (for Space=="")
// applies only to element names, not to attribute names.
-func (p *Parser) translate(n *Name, isElementName bool) {
+func (d *Decoder) translate(n *Name, isElementName bool) {
switch {
case n.Space == "xmlns":
return
@@ -282,20 +281,20 @@ func (p *Parser) translate(n *Name, isElementName bool) {
case n.Space == "" && n.Local == "xmlns":
return
}
- if v, ok := p.ns[n.Space]; ok {
+ if v, ok := d.ns[n.Space]; ok {
n.Space = v
}
}
-func (p *Parser) switchToReader(r io.Reader) {
+func (d *Decoder) switchToReader(r io.Reader) {
// Get efficient byte at a time reader.
// Assume that if reader has its own
// ReadByte, it's efficient enough.
// Otherwise, use bufio.
if rb, ok := r.(io.ByteReader); ok {
- p.r = rb
+ d.r = rb
} else {
- p.r = bufio.NewReader(r)
+ d.r = bufio.NewReader(r)
}
}
@@ -315,47 +314,47 @@ const (
stkNs
)
-func (p *Parser) push(kind int) *stack {
- s := p.free
+func (d *Decoder) push(kind int) *stack {
+ s := d.free
if s != nil {
- p.free = s.next
+ d.free = s.next
} else {
s = new(stack)
}
- s.next = p.stk
+ s.next = d.stk
s.kind = kind
- p.stk = s
+ d.stk = s
return s
}
-func (p *Parser) pop() *stack {
- s := p.stk
+func (d *Decoder) pop() *stack {
+ s := d.stk
if s != nil {
- p.stk = s.next
- s.next = p.free
- p.free = s
+ d.stk = s.next
+ s.next = d.free
+ d.free = s
}
return s
}
// Record that we are starting an element with the given name.
-func (p *Parser) pushElement(name Name) {
- s := p.push(stkStart)
+func (d *Decoder) pushElement(name Name) {
+ s := d.push(stkStart)
s.name = name
}
// Record that we are changing the value of ns[local].
// The old value is url, ok.
-func (p *Parser) pushNs(local string, url string, ok bool) {
- s := p.push(stkNs)
+func (d *Decoder) pushNs(local string, url string, ok bool) {
+ s := d.push(stkNs)
s.name.Local = local
s.name.Space = url
s.ok = ok
}
// Creates a SyntaxError with the current line number.
-func (p *Parser) syntaxError(msg string) os.Error {
- return &SyntaxError{Msg: msg, Line: p.line}
+func (d *Decoder) syntaxError(msg string) error {
+ return &SyntaxError{Msg: msg, Line: d.line}
}
// Record that we are ending an element with the given name.
@@ -364,33 +363,37 @@ func (p *Parser) syntaxError(msg string) os.Error {
// After popping the element, apply any undo records from
// the stack to restore the name translations that existed
// before we saw this element.
-func (p *Parser) popElement(t *EndElement) bool {
- s := p.pop()
+func (d *Decoder) popElement(t *EndElement) bool {
+ s := d.pop()
name := t.Name
switch {
case s == nil || s.kind != stkStart:
- p.err = p.syntaxError("unexpected end element </" + name.Local + ">")
+ d.err = d.syntaxError("unexpected end element </" + name.Local + ">")
return false
case s.name.Local != name.Local:
- if !p.Strict {
- p.needClose = true
- p.toClose = t.Name
+ if !d.Strict {
+ d.needClose = true
+ d.toClose = t.Name
t.Name = s.name
return true
}
- p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
+ d.err = d.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">")
return false
case s.name.Space != name.Space:
- p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
+ d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space +
"closed by </" + name.Local + "> in space " + name.Space)
return false
}
// Pop stack until a Start is on the top, undoing the
// translations that were associated with the element we just closed.
- for p.stk != nil && p.stk.kind != stkStart {
- s := p.pop()
- p.ns[s.name.Local] = s.name.Space, s.ok
+ for d.stk != nil && d.stk.kind != stkStart {
+ s := d.pop()
+ if s.ok {
+ d.ns[s.name.Local] = s.name.Space
+ } else {
+ delete(d.ns, s.name.Local)
+ }
}
return true
@@ -398,17 +401,17 @@ func (p *Parser) popElement(t *EndElement) bool {
// If the top element on the stack is autoclosing and
// t is not the end tag, invent the end tag.
-func (p *Parser) autoClose(t Token) (Token, bool) {
- if p.stk == nil || p.stk.kind != stkStart {
+func (d *Decoder) autoClose(t Token) (Token, bool) {
+ if d.stk == nil || d.stk.kind != stkStart {
return nil, false
}
- name := strings.ToLower(p.stk.name.Local)
- for _, s := range p.AutoClose {
+ name := strings.ToLower(d.stk.name.Local)
+ for _, s := range d.AutoClose {
if strings.ToLower(s) == name {
// This one should be auto closed if t doesn't close it.
et, ok := t.(EndElement)
if !ok || et.Name.Local != name {
- return EndElement{p.stk.name}, true
+ return EndElement{d.stk.name}, true
}
break
}
@@ -419,53 +422,53 @@ func (p *Parser) autoClose(t Token) (Token, bool) {
// RawToken is like Token but does not verify that
// start and end elements match and does not translate
// name space prefixes to their corresponding URLs.
-func (p *Parser) RawToken() (Token, os.Error) {
- if p.err != nil {
- return nil, p.err
+func (d *Decoder) RawToken() (Token, error) {
+ if d.err != nil {
+ return nil, d.err
}
- if p.needClose {
+ if d.needClose {
// The last element we read was self-closing and
// we returned just the StartElement half.
// Return the EndElement half now.
- p.needClose = false
- return EndElement{p.toClose}, nil
+ d.needClose = false
+ return EndElement{d.toClose}, nil
}
- b, ok := p.getc()
+ b, ok := d.getc()
if !ok {
- return nil, p.err
+ return nil, d.err
}
if b != '<' {
// Text section.
- p.ungetc(b)
- data := p.text(-1, false)
+ d.ungetc(b)
+ data := d.text(-1, false)
if data == nil {
- return nil, p.err
+ return nil, d.err
}
return CharData(data), nil
}
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
switch b {
case '/':
// </: End element
var name Name
- if name, ok = p.nsname(); !ok {
- if p.err == nil {
- p.err = p.syntaxError("expected element name after </")
+ if name, ok = d.nsname(); !ok {
+ if d.err == nil {
+ d.err = d.syntaxError("expected element name after </")
}
- return nil, p.err
+ return nil, d.err
}
- p.space()
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ d.space()
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b != '>' {
- p.err = p.syntaxError("invalid characters between </" + name.Local + " and >")
- return nil, p.err
+ d.err = d.syntaxError("invalid characters between </" + name.Local + " and >")
+ return nil, d.err
}
return EndElement{name}, nil
@@ -474,95 +477,95 @@ func (p *Parser) RawToken() (Token, os.Error) {
// TODO(rsc): Should parse the <?xml declaration to make sure
// the version is 1.0 and the encoding is UTF-8.
var target string
- if target, ok = p.name(); !ok {
- if p.err == nil {
- p.err = p.syntaxError("expected target name after <?")
+ if target, ok = d.name(); !ok {
+ if d.err == nil {
+ d.err = d.syntaxError("expected target name after <?")
}
- return nil, p.err
+ return nil, d.err
}
- p.space()
- p.buf.Reset()
+ d.space()
+ d.buf.Reset()
var b0 byte
for {
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
if b0 == '?' && b == '>' {
break
}
b0 = b
}
- data := p.buf.Bytes()
+ data := d.buf.Bytes()
data = data[0 : len(data)-2] // chop ?>
if target == "xml" {
enc := procInstEncoding(string(data))
if enc != "" && enc != "utf-8" && enc != "UTF-8" {
- if p.CharsetReader == nil {
- p.err = fmt.Errorf("xml: encoding %q declared but Parser.CharsetReader is nil", enc)
- return nil, p.err
+ if d.CharsetReader == nil {
+ d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
+ return nil, d.err
}
- newr, err := p.CharsetReader(enc, p.r.(io.Reader))
+ newr, err := d.CharsetReader(enc, d.r.(io.Reader))
if err != nil {
- p.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
- return nil, p.err
+ d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
+ return nil, d.err
}
if newr == nil {
panic("CharsetReader returned a nil Reader for charset " + enc)
}
- p.switchToReader(newr)
+ d.switchToReader(newr)
}
}
return ProcInst{target, data}, nil
case '!':
// <!: Maybe comment, maybe CDATA.
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
switch b {
case '-': // <!-
// Probably <!-- for a comment.
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b != '-' {
- p.err = p.syntaxError("invalid sequence <!- not part of <!--")
- return nil, p.err
+ d.err = d.syntaxError("invalid sequence <!- not part of <!--")
+ return nil, d.err
}
// Look for terminator.
- p.buf.Reset()
+ d.buf.Reset()
var b0, b1 byte
for {
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
if b0 == '-' && b1 == '-' && b == '>' {
break
}
b0, b1 = b1, b
}
- data := p.buf.Bytes()
+ data := d.buf.Bytes()
data = data[0 : len(data)-3] // chop -->
return Comment(data), nil
case '[': // <![
// Probably <![CDATA[.
for i := 0; i < 6; i++ {
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b != "CDATA["[i] {
- p.err = p.syntaxError("invalid <![ sequence")
- return nil, p.err
+ d.err = d.syntaxError("invalid <![ sequence")
+ return nil, d.err
}
}
// Have <![CDATA[. Read text until ]]>.
- data := p.text(-1, true)
+ data := d.text(-1, true)
if data == nil {
- return nil, p.err
+ return nil, d.err
}
return CharData(data), nil
}
@@ -570,18 +573,18 @@ func (p *Parser) RawToken() (Token, os.Error) {
// Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc.
// We don't care, but accumulate for caller. Quoted angle
// brackets do not count for nesting.
- p.buf.Reset()
- p.buf.WriteByte(b)
+ d.buf.Reset()
+ d.buf.WriteByte(b)
inquote := uint8(0)
depth := 0
for {
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if inquote == 0 && b == '>' && depth == 0 {
break
}
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
switch {
case b == inquote:
inquote = 0
@@ -599,45 +602,45 @@ func (p *Parser) RawToken() (Token, os.Error) {
depth++
}
}
- return Directive(p.buf.Bytes()), nil
+ return Directive(d.buf.Bytes()), nil
}
// Must be an open element like <a href="foo">
- p.ungetc(b)
+ d.ungetc(b)
var (
name Name
empty bool
attr []Attr
)
- if name, ok = p.nsname(); !ok {
- if p.err == nil {
- p.err = p.syntaxError("expected element name after <")
+ if name, ok = d.nsname(); !ok {
+ if d.err == nil {
+ d.err = d.syntaxError("expected element name after <")
}
- return nil, p.err
+ return nil, d.err
}
attr = make([]Attr, 0, 4)
for {
- p.space()
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ d.space()
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b == '/' {
empty = true
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b != '>' {
- p.err = p.syntaxError("expected /> in element")
- return nil, p.err
+ d.err = d.syntaxError("expected /> in element")
+ return nil, d.err
}
break
}
if b == '>' {
break
}
- p.ungetc(b)
+ d.ungetc(b)
n := len(attr)
if n >= cap(attr) {
@@ -647,85 +650,85 @@ func (p *Parser) RawToken() (Token, os.Error) {
}
attr = attr[0 : n+1]
a := &attr[n]
- if a.Name, ok = p.nsname(); !ok {
- if p.err == nil {
- p.err = p.syntaxError("expected attribute name in element")
+ if a.Name, ok = d.nsname(); !ok {
+ if d.err == nil {
+ d.err = d.syntaxError("expected attribute name in element")
}
- return nil, p.err
+ return nil, d.err
}
- p.space()
- if b, ok = p.mustgetc(); !ok {
- return nil, p.err
+ d.space()
+ if b, ok = d.mustgetc(); !ok {
+ return nil, d.err
}
if b != '=' {
- if p.Strict {
- p.err = p.syntaxError("attribute name without = in element")
- return nil, p.err
+ if d.Strict {
+ d.err = d.syntaxError("attribute name without = in element")
+ return nil, d.err
} else {
- p.ungetc(b)
+ d.ungetc(b)
a.Value = a.Name.Local
}
} else {
- p.space()
- data := p.attrval()
+ d.space()
+ data := d.attrval()
if data == nil {
- return nil, p.err
+ return nil, d.err
}
a.Value = string(data)
}
}
if empty {
- p.needClose = true
- p.toClose = name
+ d.needClose = true
+ d.toClose = name
}
return StartElement{name, attr}, nil
}
-func (p *Parser) attrval() []byte {
- b, ok := p.mustgetc()
+func (d *Decoder) attrval() []byte {
+ b, ok := d.mustgetc()
if !ok {
return nil
}
// Handle quoted attribute values
if b == '"' || b == '\'' {
- return p.text(int(b), false)
+ return d.text(int(b), false)
}
// Handle unquoted attribute values for strict parsers
- if p.Strict {
- p.err = p.syntaxError("unquoted or missing attribute value in element")
+ if d.Strict {
+ d.err = d.syntaxError("unquoted or missing attribute value in element")
return nil
}
// Handle unquoted attribute values for unstrict parsers
- p.ungetc(b)
- p.buf.Reset()
+ d.ungetc(b)
+ d.buf.Reset()
for {
- b, ok = p.mustgetc()
+ b, ok = d.mustgetc()
if !ok {
return nil
}
// http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' ||
'0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' {
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
} else {
- p.ungetc(b)
+ d.ungetc(b)
break
}
}
- return p.buf.Bytes()
+ return d.buf.Bytes()
}
// Skip spaces if any
-func (p *Parser) space() {
+func (d *Decoder) space() {
for {
- b, ok := p.getc()
+ b, ok := d.getc()
if !ok {
return
}
switch b {
case ' ', '\r', '\n', '\t':
default:
- p.ungetc(b)
+ d.ungetc(b)
return
}
}
@@ -733,35 +736,35 @@ func (p *Parser) space() {
// Read a single byte.
// If there is no byte to read, return ok==false
-// and leave the error in p.err.
+// and leave the error in d.err.
// Maintain line number.
-func (p *Parser) getc() (b byte, ok bool) {
- if p.err != nil {
+func (d *Decoder) getc() (b byte, ok bool) {
+ if d.err != nil {
return 0, false
}
- if p.nextByte >= 0 {
- b = byte(p.nextByte)
- p.nextByte = -1
+ if d.nextByte >= 0 {
+ b = byte(d.nextByte)
+ d.nextByte = -1
} else {
- b, p.err = p.r.ReadByte()
- if p.err != nil {
+ b, d.err = d.r.ReadByte()
+ if d.err != nil {
return 0, false
}
- if p.saved != nil {
- p.saved.WriteByte(b)
+ if d.saved != nil {
+ d.saved.WriteByte(b)
}
}
if b == '\n' {
- p.line++
+ d.line++
}
return b, true
}
// Return saved offset.
// If we did ungetc (nextByte >= 0), have to back up one.
-func (p *Parser) savedOffset() int {
- n := p.saved.Len()
- if p.nextByte >= 0 {
+func (d *Decoder) savedOffset() int {
+ n := d.saved.Len()
+ if d.nextByte >= 0 {
n--
}
return n
@@ -769,23 +772,23 @@ func (p *Parser) savedOffset() int {
// Must read a single byte.
// If there is no byte to read,
-// set p.err to SyntaxError("unexpected EOF")
+// set d.err to SyntaxError("unexpected EOF")
// and return ok==false
-func (p *Parser) mustgetc() (b byte, ok bool) {
- if b, ok = p.getc(); !ok {
- if p.err == os.EOF {
- p.err = p.syntaxError("unexpected EOF")
+func (d *Decoder) mustgetc() (b byte, ok bool) {
+ if b, ok = d.getc(); !ok {
+ if d.err == io.EOF {
+ d.err = d.syntaxError("unexpected EOF")
}
}
return
}
// Unread a single byte.
-func (p *Parser) ungetc(b byte) {
+func (d *Decoder) ungetc(b byte) {
if b == '\n' {
- p.line--
+ d.line--
}
- p.nextByte = int(b)
+ d.nextByte = int(b)
}
var entity = map[string]int{
@@ -799,18 +802,18 @@ var entity = map[string]int{
// Read plain text section (XML calls it character data).
// If quote >= 0, we are in a quoted string and need to find the matching quote.
// If cdata == true, we are in a <![CDATA[ section and need to find ]]>.
-// On failure return nil and leave the error in p.err.
-func (p *Parser) text(quote int, cdata bool) []byte {
+// On failure return nil and leave the error in d.err.
+func (d *Decoder) text(quote int, cdata bool) []byte {
var b0, b1 byte
var trunc int
- p.buf.Reset()
+ d.buf.Reset()
Input:
for {
- b, ok := p.getc()
+ b, ok := d.getc()
if !ok {
if cdata {
- if p.err == os.EOF {
- p.err = p.syntaxError("unexpected EOF in CDATA section")
+ if d.err == io.EOF {
+ d.err = d.syntaxError("unexpected EOF in CDATA section")
}
return nil
}
@@ -824,17 +827,17 @@ Input:
trunc = 2
break Input
}
- p.err = p.syntaxError("unescaped ]]> not in CDATA section")
+ d.err = d.syntaxError("unescaped ]]> not in CDATA section")
return nil
}
// Stop reading text if we see a <.
if b == '<' && !cdata {
if quote >= 0 {
- p.err = p.syntaxError("unescaped < inside quoted string")
+ d.err = d.syntaxError("unescaped < inside quoted string")
return nil
}
- p.ungetc('<')
+ d.ungetc('<')
break Input
}
if quote >= 0 && b == byte(quote) {
@@ -847,16 +850,16 @@ Input:
// Parsers are required to recognize lt, gt, amp, apos, and quot
// even if they have not been declared. That's all we allow.
var i int
- for i = 0; i < len(p.tmp); i++ {
+ for i = 0; i < len(d.tmp); i++ {
var ok bool
- p.tmp[i], ok = p.getc()
+ d.tmp[i], ok = d.getc()
if !ok {
- if p.err == os.EOF {
- p.err = p.syntaxError("unexpected EOF")
+ if d.err == io.EOF {
+ d.err = d.syntaxError("unexpected EOF")
}
return nil
}
- c := p.tmp[i]
+ c := d.tmp[i]
if c == ';' {
break
}
@@ -866,29 +869,29 @@ Input:
c == '_' || c == '#' {
continue
}
- p.ungetc(c)
+ d.ungetc(c)
break
}
- s := string(p.tmp[0:i])
- if i >= len(p.tmp) {
- if !p.Strict {
+ s := string(d.tmp[0:i])
+ if i >= len(d.tmp) {
+ if !d.Strict {
b0, b1 = 0, 0
- p.buf.WriteByte('&')
- p.buf.Write(p.tmp[0:i])
+ d.buf.WriteByte('&')
+ d.buf.Write(d.tmp[0:i])
continue Input
}
- p.err = p.syntaxError("character entity expression &" + s + "... too long")
+ d.err = d.syntaxError("character entity expression &" + s + "... too long")
return nil
}
var haveText bool
var text string
if i >= 2 && s[0] == '#' {
var n uint64
- var err os.Error
+ var err error
if i >= 3 && s[1] == 'x' {
- n, err = strconv.Btoui64(s[2:], 16)
+ n, err = strconv.ParseUint(s[2:], 16, 64)
} else {
- n, err = strconv.Btoui64(s[1:], 10)
+ n, err = strconv.ParseUint(s[1:], 10, 64)
}
if err == nil && n <= unicode.MaxRune {
text = string(n)
@@ -898,28 +901,28 @@ Input:
if r, ok := entity[s]; ok {
text = string(r)
haveText = true
- } else if p.Entity != nil {
- text, haveText = p.Entity[s]
+ } else if d.Entity != nil {
+ text, haveText = d.Entity[s]
}
}
if !haveText {
- if !p.Strict {
+ if !d.Strict {
b0, b1 = 0, 0
- p.buf.WriteByte('&')
- p.buf.Write(p.tmp[0:i])
+ d.buf.WriteByte('&')
+ d.buf.Write(d.tmp[0:i])
continue Input
}
- p.err = p.syntaxError("invalid character entity &" + s + ";")
+ d.err = d.syntaxError("invalid character entity &" + s + ";")
return nil
}
- p.buf.Write([]byte(text))
+ d.buf.Write([]byte(text))
b0, b1 = 0, 0
continue Input
}
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
b0, b1 = b1, b
}
- data := p.buf.Bytes()
+ data := d.buf.Bytes()
data = data[0 : len(data)-trunc]
// Inspect each rune for being a disallowed character.
@@ -927,12 +930,12 @@ Input:
for len(buf) > 0 {
r, size := utf8.DecodeRune(buf)
if r == utf8.RuneError && size == 1 {
- p.err = p.syntaxError("invalid UTF-8")
+ d.err = d.syntaxError("invalid UTF-8")
return nil
}
buf = buf[size:]
if !isInCharacterRange(r) {
- p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r))
+ d.err = d.syntaxError(fmt.Sprintf("illegal character code %U", r))
return nil
}
}
@@ -956,19 +959,19 @@ Input:
// Decide whether the given rune is in the XML Character Range, per
// the Char production of http://www.xml.com/axml/testaxml.htm,
// Section 2.2 Characters.
-func isInCharacterRange(rune int) (inrange bool) {
- return rune == 0x09 ||
- rune == 0x0A ||
- rune == 0x0D ||
- rune >= 0x20 && rune <= 0xDF77 ||
- rune >= 0xE000 && rune <= 0xFFFD ||
- rune >= 0x10000 && rune <= 0x10FFFF
+func isInCharacterRange(r rune) (inrange bool) {
+ return r == 0x09 ||
+ r == 0x0A ||
+ r == 0x0D ||
+ r >= 0x20 && r <= 0xDF77 ||
+ r >= 0xE000 && r <= 0xFFFD ||
+ r >= 0x10000 && r <= 0x10FFFF
}
// Get name space name: name with a : stuck in the middle.
// The part before the : is the name space identifier.
-func (p *Parser) nsname() (name Name, ok bool) {
- s, ok := p.name()
+func (d *Decoder) nsname() (name Name, ok bool) {
+ s, ok := d.name()
if !ok {
return
}
@@ -983,37 +986,37 @@ func (p *Parser) nsname() (name Name, ok bool) {
}
// Get name: /first(first|second)*/
-// Do not set p.err if the name is missing (unless unexpected EOF is received):
+// Do not set d.err if the name is missing (unless unexpected EOF is received):
// let the caller provide better context.
-func (p *Parser) name() (s string, ok bool) {
+func (d *Decoder) name() (s string, ok bool) {
var b byte
- if b, ok = p.mustgetc(); !ok {
+ if b, ok = d.mustgetc(); !ok {
return
}
// As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]*
if b < utf8.RuneSelf && !isNameByte(b) {
- p.ungetc(b)
+ d.ungetc(b)
return "", false
}
- p.buf.Reset()
- p.buf.WriteByte(b)
+ d.buf.Reset()
+ d.buf.WriteByte(b)
for {
- if b, ok = p.mustgetc(); !ok {
+ if b, ok = d.mustgetc(); !ok {
return
}
if b < utf8.RuneSelf && !isNameByte(b) {
- p.ungetc(b)
+ d.ungetc(b)
break
}
- p.buf.WriteByte(b)
+ d.buf.WriteByte(b)
}
// Then we check the characters.
- s = p.buf.String()
+ s = d.buf.String()
for i, c := range s {
if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) {
- p.err = p.syntaxError("invalid XML name: " + s)
+ d.err = d.syntaxError("invalid XML name: " + s)
return "", false
}
}
@@ -1686,7 +1689,7 @@ func procInstEncoding(s string) string {
if v[0] != '\'' && v[0] != '"' {
return ""
}
- idx = strings.IndexRune(v[1:], int(v[0]))
+ idx = strings.IndexRune(v[1:], rune(v[0]))
if idx == -1 {
return ""
}
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/encoding/xml/xml_test.go
index 640762405..1d0696ce0 100644
--- a/src/pkg/xml/xml_test.go
+++ b/src/pkg/encoding/xml/xml_test.go
@@ -5,9 +5,7 @@
package xml
import (
- "bytes"
"io"
- "os"
"reflect"
"strings"
"testing"
@@ -30,71 +28,69 @@ const testInput = `
</body><!-- missing final newline -->`
var rawTokens = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ CharData("\n"),
+ Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
- ),
- CharData([]byte("\n")),
+ CharData("\n"),
StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
- CharData([]byte("World <>'\" 白鵬翔")),
+ CharData("World <>'\" 白鵬翔"),
EndElement{Name{"", "hello"}},
- CharData([]byte("\n ")),
- StartElement{Name{"", "goodbye"}, nil},
+ CharData("\n "),
+ StartElement{Name{"", "goodbye"}, []Attr{}},
EndElement{Name{"", "goodbye"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
- CharData([]byte("\n ")),
- StartElement{Name{"", "inner"}, nil},
+ CharData("\n "),
+ StartElement{Name{"", "inner"}, []Attr{}},
EndElement{Name{"", "inner"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
EndElement{Name{"", "outer"}},
- CharData([]byte("\n ")),
- StartElement{Name{"tag", "name"}, nil},
- CharData([]byte("\n ")),
- CharData([]byte("Some text here.")),
- CharData([]byte("\n ")),
+ CharData("\n "),
+ StartElement{Name{"tag", "name"}, []Attr{}},
+ CharData("\n "),
+ CharData("Some text here."),
+ CharData("\n "),
EndElement{Name{"tag", "name"}},
- CharData([]byte("\n")),
+ CharData("\n"),
EndElement{Name{"", "body"}},
- Comment([]byte(" missing final newline ")),
+ Comment(" missing final newline "),
}
var cookedTokens = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ CharData("\n"),
+ Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
- ),
- CharData([]byte("\n")),
+ CharData("\n"),
StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
- CharData([]byte("World <>'\" 白鵬翔")),
+ CharData("World <>'\" 白鵬翔"),
EndElement{Name{"ns2", "hello"}},
- CharData([]byte("\n ")),
- StartElement{Name{"ns2", "goodbye"}, nil},
+ CharData("\n "),
+ StartElement{Name{"ns2", "goodbye"}, []Attr{}},
EndElement{Name{"ns2", "goodbye"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
- CharData([]byte("\n ")),
- StartElement{Name{"ns2", "inner"}, nil},
+ CharData("\n "),
+ StartElement{Name{"ns2", "inner"}, []Attr{}},
EndElement{Name{"ns2", "inner"}},
- CharData([]byte("\n ")),
+ CharData("\n "),
EndElement{Name{"ns2", "outer"}},
- CharData([]byte("\n ")),
- StartElement{Name{"ns3", "name"}, nil},
- CharData([]byte("\n ")),
- CharData([]byte("Some text here.")),
- CharData([]byte("\n ")),
+ CharData("\n "),
+ StartElement{Name{"ns3", "name"}, []Attr{}},
+ CharData("\n "),
+ CharData("Some text here."),
+ CharData("\n "),
EndElement{Name{"ns3", "name"}},
- CharData([]byte("\n")),
+ CharData("\n"),
EndElement{Name{"ns2", "body"}},
- Comment([]byte(" missing final newline ")),
+ Comment(" missing final newline "),
}
const testInputAltEncoding = `
@@ -102,11 +98,11 @@ const testInputAltEncoding = `
<TAG>VALUE</TAG>`
var rawTokensAltEncoding = []Token{
- CharData([]byte("\n")),
+ CharData("\n"),
ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
- CharData([]byte("\n")),
- StartElement{Name{"", "tag"}, nil},
- CharData([]byte("value")),
+ CharData("\n"),
+ StartElement{Name{"", "tag"}, []Attr{}},
+ CharData("value"),
EndElement{Name{"", "tag"}},
}
@@ -157,37 +153,9 @@ var xmlInput = []string{
"<t>cdata]]></t>",
}
-type stringReader struct {
- s string
- off int
-}
-
-func (r *stringReader) Read(b []byte) (n int, err os.Error) {
- if r.off >= len(r.s) {
- return 0, os.EOF
- }
- for r.off < len(r.s) && n < len(b) {
- b[n] = r.s[r.off]
- n++
- r.off++
- }
- return
-}
-
-func (r *stringReader) ReadByte() (b byte, err os.Error) {
- if r.off >= len(r.s) {
- return 0, os.EOF
- }
- b = r.s[r.off]
- r.off++
- return
-}
-
-func StringReader(s string) io.Reader { return &stringReader{s, 0} }
-
func TestRawToken(t *testing.T) {
- p := NewParser(StringReader(testInput))
- testRawToken(t, p, rawTokens)
+ d := NewDecoder(strings.NewReader(testInput))
+ testRawToken(t, d, rawTokens)
}
type downCaser struct {
@@ -195,7 +163,7 @@ type downCaser struct {
r io.ByteReader
}
-func (d *downCaser) ReadByte() (c byte, err os.Error) {
+func (d *downCaser) ReadByte() (c byte, err error) {
c, err = d.r.ReadByte()
if c >= 'A' && c <= 'Z' {
c += 'a' - 'A'
@@ -203,34 +171,34 @@ func (d *downCaser) ReadByte() (c byte, err os.Error) {
return
}
-func (d *downCaser) Read(p []byte) (int, os.Error) {
+func (d *downCaser) Read(p []byte) (int, error) {
d.t.Fatalf("unexpected Read call on downCaser reader")
- return 0, os.EINVAL
+ panic("unreachable")
}
func TestRawTokenAltEncoding(t *testing.T) {
sawEncoding := ""
- p := NewParser(StringReader(testInputAltEncoding))
- p.CharsetReader = func(charset string, input io.Reader) (io.Reader, os.Error) {
+ d := NewDecoder(strings.NewReader(testInputAltEncoding))
+ d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
sawEncoding = charset
if charset != "x-testing-uppercase" {
t.Fatalf("unexpected charset %q", charset)
}
return &downCaser{t, input.(io.ByteReader)}, nil
}
- testRawToken(t, p, rawTokensAltEncoding)
+ testRawToken(t, d, rawTokensAltEncoding)
}
func TestRawTokenAltEncodingNoConverter(t *testing.T) {
- p := NewParser(StringReader(testInputAltEncoding))
- token, err := p.RawToken()
+ d := NewDecoder(strings.NewReader(testInputAltEncoding))
+ token, err := d.RawToken()
if token == nil {
t.Fatalf("expected a token on first RawToken call")
}
if err != nil {
t.Fatal(err)
}
- token, err = p.RawToken()
+ token, err = d.RawToken()
if token != nil {
t.Errorf("expected a nil token; got %#v", token)
}
@@ -238,15 +206,15 @@ func TestRawTokenAltEncodingNoConverter(t *testing.T) {
t.Fatalf("expected an error on second RawToken call")
}
const encoding = "x-testing-uppercase"
- if !strings.Contains(err.String(), encoding) {
+ if !strings.Contains(err.Error(), encoding) {
t.Errorf("expected error to contain %q; got error: %v",
encoding, err)
}
}
-func testRawToken(t *testing.T, p *Parser, rawTokens []Token) {
+func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) {
for i, want := range rawTokens {
- have, err := p.RawToken()
+ have, err := d.RawToken()
if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err)
}
@@ -271,28 +239,28 @@ var nestedDirectivesInput = `
`
var nestedDirectivesTokens = []Token{
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
- CharData([]byte("\n")),
- Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
- CharData([]byte("\n")),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt ">">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt "<">]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '>'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '<'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt '">'>]`),
+ CharData("\n"),
+ Directive(`DOCTYPE [<!ENTITY xlt "'<">]`),
+ CharData("\n"),
}
func TestNestedDirectives(t *testing.T) {
- p := NewParser(StringReader(nestedDirectivesInput))
+ d := NewDecoder(strings.NewReader(nestedDirectivesInput))
for i, want := range nestedDirectivesTokens {
- have, err := p.Token()
+ have, err := d.Token()
if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err)
}
@@ -303,10 +271,10 @@ func TestNestedDirectives(t *testing.T) {
}
func TestToken(t *testing.T) {
- p := NewParser(StringReader(testInput))
+ d := NewDecoder(strings.NewReader(testInput))
for i, want := range cookedTokens {
- have, err := p.Token()
+ have, err := d.Token()
if err != nil {
t.Fatalf("token %d: unexpected error: %s", i, err)
}
@@ -318,9 +286,9 @@ func TestToken(t *testing.T) {
func TestSyntax(t *testing.T) {
for i := range xmlInput {
- p := NewParser(StringReader(xmlInput[i]))
- var err os.Error
- for _, err = p.Token(); err == nil; _, err = p.Token() {
+ d := NewDecoder(strings.NewReader(xmlInput[i]))
+ var err error
+ for _, err = d.Token(); err == nil; _, err = d.Token() {
}
if _, ok := err.(*SyntaxError); !ok {
t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
@@ -375,32 +343,31 @@ var all = allScalars{
var sixteen = "16"
const testScalarsInput = `<allscalars>
- <true1>true</true1>
- <true2>1</true2>
- <false1>false</false1>
- <false2>0</false2>
- <int>1</int>
- <int8>-2</int8>
- <int16>3</int16>
- <int32>-4</int32>
- <int64>5</int64>
- <uint>6</uint>
- <uint8>7</uint8>
- <uint16>8</uint16>
- <uint32>9</uint32>
- <uint64>10</uint64>
- <uintptr>11</uintptr>
- <float>12.0</float>
- <float32>13.0</float32>
- <float64>14.0</float64>
- <string>15</string>
- <ptrstring>16</ptrstring>
+ <True1>true</True1>
+ <True2>1</True2>
+ <False1>false</False1>
+ <False2>0</False2>
+ <Int>1</Int>
+ <Int8>-2</Int8>
+ <Int16>3</Int16>
+ <Int32>-4</Int32>
+ <Int64>5</Int64>
+ <Uint>6</Uint>
+ <Uint8>7</Uint8>
+ <Uint16>8</Uint16>
+ <Uint32>9</Uint32>
+ <Uint64>10</Uint64>
+ <Uintptr>11</Uintptr>
+ <Float>12.0</Float>
+ <Float32>13.0</Float32>
+ <Float64>14.0</Float64>
+ <String>15</String>
+ <PtrString>16</PtrString>
</allscalars>`
func TestAllScalars(t *testing.T) {
var a allScalars
- buf := bytes.NewBufferString(testScalarsInput)
- err := Unmarshal(buf, &a)
+ err := Unmarshal([]byte(testScalarsInput), &a)
if err != nil {
t.Fatal(err)
@@ -415,10 +382,9 @@ type item struct {
}
func TestIssue569(t *testing.T) {
- data := `<item><field_a>abcd</field_a></item>`
+ data := `<item><Field_a>abcd</Field_a></item>`
var i item
- buf := bytes.NewBufferString(data)
- err := Unmarshal(buf, &i)
+ err := Unmarshal([]byte(data), &i)
if err != nil || i.Field_a != "abcd" {
t.Fatal("Expecting abcd")
@@ -427,9 +393,9 @@ func TestIssue569(t *testing.T) {
func TestUnquotedAttrs(t *testing.T) {
data := "<tag attr=azAZ09:-_\t>"
- p := NewParser(StringReader(data))
- p.Strict = false
- token, err := p.Token()
+ d := NewDecoder(strings.NewReader(data))
+ d.Strict = false
+ token, err := d.Token()
if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err)
}
@@ -453,9 +419,9 @@ func TestValuelessAttrs(t *testing.T) {
{"<input checked />", "input", "checked"},
}
for _, test := range tests {
- p := NewParser(StringReader(test[0]))
- p.Strict = false
- token, err := p.Token()
+ d := NewDecoder(strings.NewReader(test[0]))
+ d.Strict = false
+ token, err := d.Token()
if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err)
}
@@ -489,10 +455,13 @@ func TestCopyTokenStartElement(t *testing.T) {
elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
var tok1 Token = elt
tok2 := CopyToken(tok1)
+ if tok1.(StartElement).Attr[0].Value != "en" {
+ t.Error("CopyToken overwrote Attr[0]")
+ }
if !reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(StartElement) != StartElement")
}
- elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
+ tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"}
if reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(CharData) uses same buffer.")
}
@@ -500,9 +469,9 @@ func TestCopyTokenStartElement(t *testing.T) {
func TestSyntaxErrorLineNum(t *testing.T) {
testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
- p := NewParser(StringReader(testInput))
- var err os.Error
- for _, err = p.Token(); err == nil; _, err = p.Token() {
+ d := NewDecoder(strings.NewReader(testInput))
+ var err error
+ for _, err = d.Token(); err == nil; _, err = d.Token() {
}
synerr, ok := err.(*SyntaxError)
if !ok {
@@ -515,41 +484,41 @@ func TestSyntaxErrorLineNum(t *testing.T) {
func TestTrailingRawToken(t *testing.T) {
input := `<FOO></FOO> `
- p := NewParser(StringReader(input))
- var err os.Error
- for _, err = p.RawToken(); err == nil; _, err = p.RawToken() {
+ d := NewDecoder(strings.NewReader(input))
+ var err error
+ for _, err = d.RawToken(); err == nil; _, err = d.RawToken() {
}
- if err != os.EOF {
- t.Fatalf("p.RawToken() = _, %v, want _, os.EOF", err)
+ if err != io.EOF {
+ t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err)
}
}
func TestTrailingToken(t *testing.T) {
input := `<FOO></FOO> `
- p := NewParser(StringReader(input))
- var err os.Error
- for _, err = p.Token(); err == nil; _, err = p.Token() {
+ d := NewDecoder(strings.NewReader(input))
+ var err error
+ for _, err = d.Token(); err == nil; _, err = d.Token() {
}
- if err != os.EOF {
- t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ if err != io.EOF {
+ t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
}
}
func TestEntityInsideCDATA(t *testing.T) {
input := `<test><![CDATA[ &val=foo ]]></test>`
- p := NewParser(StringReader(input))
- var err os.Error
- for _, err = p.Token(); err == nil; _, err = p.Token() {
+ d := NewDecoder(strings.NewReader(input))
+ var err error
+ for _, err = d.Token(); err == nil; _, err = d.Token() {
}
- if err != os.EOF {
- t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ if err != io.EOF {
+ t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
}
}
// The last three tests (respectively one for characters in attribute
// names and two for character entities) pass not because of code
// changed for issue 1259, but instead pass with the given messages
-// from other parts of xml.Parser. I provide these to note the
+// from other parts of xml.Decoder. I provide these to note the
// current behavior of situations where one might think that character
// range checking would detect the error, but it does not in fact.
@@ -569,15 +538,15 @@ var characterTests = []struct {
func TestDisallowedCharacters(t *testing.T) {
for i, tt := range characterTests {
- p := NewParser(StringReader(tt.in))
- var err os.Error
+ d := NewDecoder(strings.NewReader(tt.in))
+ var err error
for err == nil {
- _, err = p.Token()
+ _, err = d.Token()
}
synerr, ok := err.(*SyntaxError)
if !ok {
- t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err)
+ t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
}
if synerr.Msg != tt.err {
t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
diff --git a/src/pkg/errors/errors.go b/src/pkg/errors/errors.go
new file mode 100644
index 000000000..3085a7962
--- /dev/null
+++ b/src/pkg/errors/errors.go
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package errors implements functions to manipulate errors.
+package errors
+
+// New returns an error that formats as the given text.
+func New(text string) error {
+ return &errorString{text}
+}
+
+// errorString is a trivial implementation of error.
+type errorString struct {
+ s string
+}
+
+func (e *errorString) Error() string {
+ return e.s
+}
diff --git a/src/pkg/errors/errors_test.go b/src/pkg/errors/errors_test.go
new file mode 100644
index 000000000..63c05d718
--- /dev/null
+++ b/src/pkg/errors/errors_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 errors_test
+
+import (
+ "errors"
+ "fmt"
+ "testing"
+)
+
+func TestNewEqual(t *testing.T) {
+ // Different allocations should not be equal.
+ if errors.New("abc") == errors.New("abc") {
+ t.Errorf(`New("abc") == New("abc")`)
+ }
+ if errors.New("abc") == errors.New("xyz") {
+ t.Errorf(`New("abc") == New("xyz")`)
+ }
+
+ // Same allocation should be equal to itself (not crash).
+ err := errors.New("jkl")
+ if err != err {
+ t.Errorf(`err != err`)
+ }
+}
+
+func TestErrorMethod(t *testing.T) {
+ err := errors.New("abc")
+ if err.Error() != "abc" {
+ t.Errorf(`New("abc").Error() = %q, want %q`, err.Error(), "abc")
+ }
+}
+
+func ExampleNew() {
+ err := errors.New("emit macho dwarf: elf header corrupted")
+ if err != nil {
+ fmt.Print(err)
+ }
+ // Output: emit macho dwarf: elf header corrupted
+}
+
+// The fmt package's Errorf function lets us use the package's formatting
+// features to create descriptive error messages.
+func ExampleNew_errorf() {
+ const name, id = "bimmler", 17
+ err := fmt.Errorf("user %q (id %d) not found", name, id)
+ if err != nil {
+ fmt.Print(err)
+ }
+ // Output: user "bimmler" (id 17) not found
+}
diff --git a/src/pkg/errors/example_test.go b/src/pkg/errors/example_test.go
new file mode 100644
index 000000000..0e86828f4
--- /dev/null
+++ b/src/pkg/errors/example_test.go
@@ -0,0 +1,34 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package errors_test
+
+import (
+ "fmt"
+ "time"
+)
+
+// MyError is an error implementation that includes a time and message.
+type MyError struct {
+ When time.Time
+ What string
+}
+
+func (e MyError) Error() string {
+ return fmt.Sprintf("%v: %v", e.When, e.What)
+}
+
+func oops() error {
+ return MyError{
+ time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
+ "the file system has gone away",
+ }
+}
+
+func Example() {
+ if err := oops(); err != nil {
+ fmt.Println(err)
+ }
+ // Output: 1989-03-15 22:30:00 +0000 UTC: the file system has gone away
+}
diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile
deleted file mode 100644
index ba19d0e4d..000000000
--- a/src/pkg/exec/Makefile
+++ /dev/null
@@ -1,31 +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.
-
-include ../../Make.inc
-
-TARG=exec
-GOFILES=\
- exec.go\
-
-GOFILES_freebsd=\
- lp_unix.go\
-
-GOFILES_darwin=\
- lp_unix.go\
-
-GOFILES_linux=\
- lp_unix.go\
-
-GOFILES_openbsd=\
- lp_unix.go\
-
-GOFILES_windows=\
- lp_windows.go\
-
-GOFILES_plan9=\
- lp_plan9.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../Make.pkg
diff --git a/src/pkg/exp/README b/src/pkg/exp/README
deleted file mode 100644
index e602e3ac9..000000000
--- a/src/pkg/exp/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory tree contains experimental packages and
-unfinished code that is subject to even more change than the
-rest of the Go tree.
diff --git a/src/pkg/exp/gui/Makefile b/src/pkg/exp/gui/Makefile
deleted file mode 100644
index af065e4a5..000000000
--- a/src/pkg/exp/gui/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=exp/gui
-GOFILES=\
- gui.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/exp/gui/gui.go b/src/pkg/exp/gui/gui.go
deleted file mode 100644
index 171499186..000000000
--- a/src/pkg/exp/gui/gui.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package gui defines a basic graphical user interface programming model.
-package gui
-
-import (
- "image"
- "image/draw"
- "os"
-)
-
-// A Window represents a single graphics window.
-type Window interface {
- // Screen returns an editable Image for the window.
- Screen() draw.Image
- // FlushImage flushes changes made to Screen() back to screen.
- FlushImage()
- // EventChan returns a channel carrying UI events such as key presses,
- // mouse movements and window resizes.
- EventChan() <-chan interface{}
- // Close closes the window.
- Close() os.Error
-}
-
-// A KeyEvent is sent for a key press or release.
-type KeyEvent struct {
- // The value k represents key k being pressed.
- // The value -k represents key k being released.
- // The specific set of key values is not specified,
- // but ordinary characters represent themselves.
- Key int
-}
-
-// A MouseEvent is sent for a button press or release or for a mouse movement.
-type MouseEvent struct {
- // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right.
- // It represents button state and not necessarily the state delta: bit 0
- // being on means that the left mouse button is down, but does not imply
- // that the same button was up in the previous MouseEvent.
- Buttons int
- // Loc is the location of the cursor.
- Loc image.Point
- // Nsec is the event's timestamp.
- Nsec int64
-}
-
-// A ConfigEvent is sent each time the window's color model or size changes.
-// The client should respond by calling Window.Screen to obtain a new image.
-type ConfigEvent struct {
- Config image.Config
-}
-
-// An ErrEvent is sent when an error occurs.
-type ErrEvent struct {
- Err os.Error
-}
diff --git a/src/pkg/exp/gui/x11/Makefile b/src/pkg/exp/gui/x11/Makefile
deleted file mode 100644
index 88cc1e23b..000000000
--- a/src/pkg/exp/gui/x11/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../../Make.inc
-
-TARG=exp/gui/x11
-GOFILES=\
- auth.go\
- conn.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/exp/gui/x11/auth.go b/src/pkg/exp/gui/x11/auth.go
deleted file mode 100644
index d48936ac1..000000000
--- a/src/pkg/exp/gui/x11/auth.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package x11
-
-import (
- "bufio"
- "io"
- "os"
-)
-
-// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer.
-func readU16BE(r io.Reader, b []byte) (uint16, os.Error) {
- _, err := io.ReadFull(r, b[0:2])
- if err != nil {
- return 0, err
- }
- return uint16(b[0])<<8 + uint16(b[1]), nil
-}
-
-// readStr reads a length-prefixed string from r, using b as a scratch buffer.
-func readStr(r io.Reader, b []byte) (string, os.Error) {
- n, err := readU16BE(r, b)
- if err != nil {
- return "", err
- }
- if int(n) > len(b) {
- return "", os.NewError("Xauthority entry too long for buffer")
- }
- _, err = io.ReadFull(r, b[0:n])
- if err != nil {
- return "", err
- }
- return string(b[0:n]), nil
-}
-
-// readAuth reads the X authority file and returns the name/data pair for the display.
-// displayStr is the "12" out of a $DISPLAY like ":12.0".
-func readAuth(displayStr string) (name, data string, err os.Error) {
- // b is a scratch buffer to use and should be at least 256 bytes long
- // (i.e. it should be able to hold a hostname).
- var b [256]byte
- // As per /usr/include/X11/Xauth.h.
- const familyLocal = 256
-
- fn := os.Getenv("XAUTHORITY")
- if fn == "" {
- home := os.Getenv("HOME")
- if home == "" {
- err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set")
- return
- }
- fn = home + "/.Xauthority"
- }
- r, err := os.Open(fn)
- if err != nil {
- return
- }
- defer r.Close()
- br := bufio.NewReader(r)
-
- hostname, err := os.Hostname()
- if err != nil {
- return
- }
- for {
- family, err := readU16BE(br, b[0:2])
- if err != nil {
- return
- }
- addr, err := readStr(br, b[0:])
- if err != nil {
- return
- }
- disp, err := readStr(br, b[0:])
- if err != nil {
- return
- }
- name0, err := readStr(br, b[0:])
- if err != nil {
- return
- }
- data0, err := readStr(br, b[0:])
- if err != nil {
- return
- }
- if family == familyLocal && addr == hostname && disp == displayStr {
- return name0, data0, nil
- }
- }
- panic("unreachable")
-}
diff --git a/src/pkg/exp/gui/x11/conn.go b/src/pkg/exp/gui/x11/conn.go
deleted file mode 100644
index 1d237816a..000000000
--- a/src/pkg/exp/gui/x11/conn.go
+++ /dev/null
@@ -1,627 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package x11 implements an X11 backend for the exp/gui package.
-//
-// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
-// A summary of the wire format can be found in XCB's xproto.xml.
-package x11
-
-import (
- "bufio"
- "exp/gui"
- "image"
- "image/draw"
- "io"
- "log"
- "net"
- "os"
- "strconv"
- "strings"
- "time"
-)
-
-type resID uint32 // X resource IDs.
-
-// TODO(nigeltao): Handle window resizes.
-const (
- windowHeight = 600
- windowWidth = 800
-)
-
-const (
- keymapLo = 8
- keymapHi = 255
-)
-
-type conn struct {
- c io.Closer
- r *bufio.Reader
- w *bufio.Writer
-
- gc, window, root, visual resID
-
- img *image.RGBA
- eventc chan interface{}
- mouseState gui.MouseEvent
-
- buf [256]byte // General purpose scratch buffer.
-
- flush chan bool
- flushBuf0 [24]byte
- flushBuf1 [4 * 1024]byte
-}
-
-// writeSocket runs in its own goroutine, serving both FlushImage calls
-// directly from the exp/gui client and indirectly from X expose events.
-// It paints c.img to the X server via PutImage requests.
-func (c *conn) writeSocket() {
- defer c.c.Close()
- for _ = range c.flush {
- b := c.img.Bounds()
- if b.Empty() {
- continue
- }
- // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
- // this limit, we send PutImage for each row of the image, rather than trying to paint
- // the entire image in one X request. This approach could easily be optimized (or the
- // X protocol may have an escape sequence to delimit very large requests).
- // TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
- units := 6 + b.Dx()
- if units > 0xffff || b.Dy() > 0xffff {
- log.Print("x11: window is too large for PutImage")
- return
- }
-
- c.flushBuf0[0] = 0x48 // PutImage opcode.
- c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP.
- c.flushBuf0[2] = uint8(units)
- c.flushBuf0[3] = uint8(units >> 8)
- setU32LE(c.flushBuf0[4:8], uint32(c.window))
- setU32LE(c.flushBuf0[8:12], uint32(c.gc))
- setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
- c.flushBuf0[21] = 0x18 // depth = 24 bits.
-
- for y := b.Min.Y; y < b.Max.Y; y++ {
- setU32LE(c.flushBuf0[16:20], uint32(y<<16))
- if _, err := c.w.Write(c.flushBuf0[:24]); err != nil {
- if err != os.EOF {
- log.Println("x11:", err.String())
- }
- return
- }
- p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
- for x, dx := 0, 4*b.Dx(); x < dx; {
- nx := dx - x
- if nx > len(c.flushBuf1) {
- nx = len(c.flushBuf1) &^ 3
- }
- for i := 0; i < nx; i += 4 {
- // X11's order is BGRX, not RGBA.
- c.flushBuf1[i+0] = p[x+i+2]
- c.flushBuf1[i+1] = p[x+i+1]
- c.flushBuf1[i+2] = p[x+i+0]
- }
- x += nx
- if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
- if err != os.EOF {
- log.Println("x11:", err.String())
- }
- return
- }
- }
- }
- if err := c.w.Flush(); err != nil {
- if err != os.EOF {
- log.Println("x11:", err.String())
- }
- return
- }
- }
-}
-
-func (c *conn) Screen() draw.Image { return c.img }
-
-func (c *conn) FlushImage() {
- select {
- case c.flush <- false:
- // Flush notification sent.
- default:
- // Could not send.
- // Flush notification must be pending already.
- }
-}
-
-func (c *conn) Close() os.Error {
- // Shut down the writeSocket goroutine. This will close the socket to the
- // X11 server, which will cause c.eventc to close.
- close(c.flush)
- for _ = range c.eventc {
- // Drain the channel to allow the readSocket goroutine to shut down.
- }
- return nil
-}
-
-func (c *conn) EventChan() <-chan interface{} { return c.eventc }
-
-// readSocket runs in its own goroutine, reading X events and sending gui
-// events on c's EventChan.
-func (c *conn) readSocket() {
- var (
- keymap [256][]int
- keysymsPerKeycode int
- )
- defer close(c.eventc)
- for {
- // X events are always 32 bytes long.
- if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil {
- if err != os.EOF {
- c.eventc <- gui.ErrEvent{err}
- }
- return
- }
- switch c.buf[0] {
- case 0x01: // Reply from a request (e.g. GetKeyboardMapping).
- cookie := int(c.buf[3])<<8 | int(c.buf[2])
- if cookie != 1 {
- // We issued only one request (GetKeyboardMapping) with a cookie of 1,
- // so we shouldn't get any other reply from the X server.
- c.eventc <- gui.ErrEvent{os.NewError("x11: unexpected cookie")}
- return
- }
- keysymsPerKeycode = int(c.buf[1])
- b := make([]int, 256*keysymsPerKeycode)
- for i := range keymap {
- keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode]
- }
- for i := keymapLo; i <= keymapHi; i++ {
- m := keymap[i]
- for j := range m {
- u, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- if err != os.EOF {
- c.eventc <- gui.ErrEvent{err}
- }
- return
- }
- m[j] = int(u)
- }
- }
- case 0x02, 0x03: // Key press, key release.
- // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html
- // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature
- // or is that some no-longer-used X construct?
- if keysymsPerKeycode < 2 {
- // Either we haven't yet received the GetKeyboardMapping reply or
- // the X server has sent one that's too short.
- continue
- }
- keycode := int(c.buf[1])
- shift := int(c.buf[28]) & 0x01
- keysym := keymap[keycode][shift]
- if keysym == 0 {
- keysym = keymap[keycode][0]
- }
- // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
- // the same int down the channel as the sent on just the A key?
- // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
- // is that outside the scope of the gui.Window interface?
- if c.buf[0] == 0x03 {
- keysym = -keysym
- }
- c.eventc <- gui.KeyEvent{keysym}
- case 0x04, 0x05: // Button press, button release.
- mask := 1 << (c.buf[1] - 1)
- if c.buf[0] == 0x04 {
- c.mouseState.Buttons |= mask
- } else {
- c.mouseState.Buttons &^= mask
- }
- c.mouseState.Nsec = time.Nanoseconds()
- c.eventc <- c.mouseState
- case 0x06: // Motion notify.
- c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24]))
- c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26]))
- c.mouseState.Nsec = time.Nanoseconds()
- c.eventc <- c.mouseState
- case 0x0c: // Expose.
- // A single user action could trigger multiple expose events (e.g. if moving another
- // window with XShape'd rounded corners over our window). In that case, the X server will
- // send a uint16 count (in bytes 16-17) of the number of additional expose events coming.
- // We could parse each event for the (x, y, width, height) and maintain a minimal dirty
- // rectangle, but for now, the simplest approach is to paint the entire window, when
- // receiving the final event in the series.
- if c.buf[17] == 0 && c.buf[16] == 0 {
- // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window
- // will trigger expose, but until the first c.FlushImage call, there's probably nothing to
- // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about
- // 2MB over the socket.
- c.FlushImage()
- }
- // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events?
- // What about EnterNotify (0x07) and LeaveNotify (0x08)?
- }
- }
-}
-
-// connect connects to the X server given by the full X11 display name (e.g.
-// ":12.0") and returns the connection as well as the portion of the full name
-// that is the display number (e.g. "12").
-// Examples:
-// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1"
-// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0"
-// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2"
-// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1"
-func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
- colonIdx := strings.LastIndex(display, ":")
- if colonIdx < 0 {
- return nil, "", os.NewError("bad display: " + display)
- }
- // Parse the section before the colon.
- var protocol, host, socket string
- if display[0] == '/' {
- socket = display[:colonIdx]
- } else {
- if i := strings.LastIndex(display, "/"); i < 0 {
- // The default protocol is TCP.
- protocol = "tcp"
- host = display[:colonIdx]
- } else {
- protocol = display[:i]
- host = display[i+1 : colonIdx]
- }
- }
- // Parse the section after the colon.
- after := display[colonIdx+1:]
- if after == "" {
- return nil, "", os.NewError("bad display: " + display)
- }
- if i := strings.LastIndex(after, "."); i < 0 {
- displayStr = after
- } else {
- displayStr = after[:i]
- }
- displayInt, err := strconv.Atoi(displayStr)
- if err != nil || displayInt < 0 {
- return nil, "", os.NewError("bad display: " + display)
- }
- // Make the connection.
- if socket != "" {
- conn, err = net.Dial("unix", socket+":"+displayStr)
- } else if host != "" {
- conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt))
- } else {
- conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr)
- }
- if err != nil {
- return nil, "", os.NewError("cannot connect to " + display + ": " + err.String())
- }
- return
-}
-
-// authenticate authenticates ourselves with the X server.
-// displayStr is the "12" out of ":12.0".
-func authenticate(w *bufio.Writer, displayStr string) os.Error {
- key, value, err := readAuth(displayStr)
- if err != nil {
- return err
- }
- // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
- if len(key) != 18 || len(value) != 16 {
- return os.NewError("unsupported Xauth")
- }
- // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0.
- // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16.
- // The final 0x0000 is padding, so that the string length is a multiple of 4.
- _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
- if err != nil {
- return err
- }
- _, err = io.WriteString(w, key)
- if err != nil {
- return err
- }
- // Again, the 0x0000 is padding.
- _, err = io.WriteString(w, "\x00\x00")
- if err != nil {
- return err
- }
- _, err = io.WriteString(w, value)
- if err != nil {
- return err
- }
- err = w.Flush()
- if err != nil {
- return err
- }
- return nil
-}
-
-// readU8 reads a uint8 from r, using b as a scratch buffer.
-func readU8(r io.Reader, b []byte) (uint8, os.Error) {
- _, err := io.ReadFull(r, b[:1])
- if err != nil {
- return 0, err
- }
- return uint8(b[0]), nil
-}
-
-// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer.
-func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
- _, err := io.ReadFull(r, b[:2])
- if err != nil {
- return 0, err
- }
- return uint16(b[0]) | uint16(b[1])<<8, nil
-}
-
-// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer.
-func readU32LE(r io.Reader, b []byte) (uint32, os.Error) {
- _, err := io.ReadFull(r, b[:4])
- if err != nil {
- return 0, err
- }
- return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
-}
-
-// setU32LE sets b[:4] to be the little-endian representation of u.
-func setU32LE(b []byte, u uint32) {
- b[0] = byte((u >> 0) & 0xff)
- b[1] = byte((u >> 8) & 0xff)
- b[2] = byte((u >> 16) & 0xff)
- b[3] = byte((u >> 24) & 0xff)
-}
-
-// checkPixmapFormats checks that we have an agreeable X pixmap Format.
-func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) {
- for i := 0; i < n; i++ {
- _, err = io.ReadFull(r, b[:8])
- if err != nil {
- return
- }
- // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding.
- if b[0] == 24 && b[1] == 32 {
- agree = true
- }
- }
- return
-}
-
-// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType).
-func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) {
- for i := 0; i < n; i++ {
- depth, err := readU16LE(r, b)
- if err != nil {
- return
- }
- depth &= 0xff
- visualsLen, err := readU16LE(r, b)
- if err != nil {
- return
- }
- // Ignore 4 bytes of padding.
- _, err = io.ReadFull(r, b[:4])
- if err != nil {
- return
- }
- for j := 0; j < int(visualsLen); j++ {
- // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2),
- // red mask(4), green mask(4), blue mask(4), padding(4).
- v, err := readU32LE(r, b)
- _, err = readU32LE(r, b)
- rm, err := readU32LE(r, b)
- gm, err := readU32LE(r, b)
- bm, err := readU32LE(r, b)
- _, err = readU32LE(r, b)
- if err != nil {
- return
- }
- if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 {
- agree = true
- }
- }
- }
- return
-}
-
-// checkScreens checks that we have an agreeable X Screen.
-func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) {
- for i := 0; i < n; i++ {
- root0, err := readU32LE(r, b)
- if err != nil {
- return
- }
- // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks,
- // width and height (pixels), width and height (mm), min and max installed maps.
- _, err = io.ReadFull(r, b[:28])
- if err != nil {
- return
- }
- visual0, err := readU32LE(r, b)
- if err != nil {
- return
- }
- // Next 4 bytes: backing stores, save unders, root depth, allowed depths length.
- x, err := readU32LE(r, b)
- if err != nil {
- return
- }
- nDepths := int(x >> 24)
- agree, err := checkDepths(r, b, nDepths, visual0)
- if err != nil {
- return
- }
- if agree && root == 0 {
- root = root0
- visual = visual0
- }
- }
- return
-}
-
-// handshake performs the protocol handshake with the X server, and ensures
-// that the server provides a compatible Screen, Depth, etc.
-func (c *conn) handshake() os.Error {
- _, err := io.ReadFull(c.r, c.buf[:8])
- if err != nil {
- return err
- }
- // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
- if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
- return os.NewError("unsupported X version")
- }
- // Ignore the release number.
- _, err = io.ReadFull(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the resource ID base.
- resourceIdBase, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the resource ID mask.
- resourceIdMask, err := readU32LE(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- if resourceIdMask < 256 {
- return os.NewError("X resource ID mask is too small")
- }
- // Ignore the motion buffer size.
- _, err = io.ReadFull(c.r, c.buf[:4])
- if err != nil {
- return err
- }
- // Read the vendor length and round it up to a multiple of 4,
- // for X11 protocol alignment reasons.
- vendorLen, err := readU16LE(c.r, c.buf[:2])
- if err != nil {
- return err
- }
- vendorLen = (vendorLen + 3) &^ 3
- // Read the maximum request length.
- maxReqLen, err := readU16LE(c.r, c.buf[:2])
- if err != nil {
- return err
- }
- if maxReqLen != 0xffff {
- return os.NewError("unsupported X maximum request length")
- }
- // Read the roots length.
- rootsLen, err := readU8(c.r, c.buf[:1])
- if err != nil {
- return err
- }
- // Read the pixmap formats length.
- pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
- if err != nil {
- return err
- }
- // Ignore some things that we don't care about (totaling 10 + vendorLen bytes):
- // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
- // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
- if 10+int(vendorLen) > cap(c.buf) {
- return os.NewError("unsupported X vendor")
- }
- _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
- if err != nil {
- return err
- }
- // Check that we have an agreeable pixmap format.
- agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
- if err != nil {
- return err
- }
- if !agree {
- return os.NewError("unsupported X pixmap formats")
- }
- // Check that we have an agreeable screen.
- root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
- if err != nil {
- return err
- }
- if root == 0 || visual == 0 {
- return os.NewError("unsupported X screen")
- }
- c.gc = resID(resourceIdBase)
- c.window = resID(resourceIdBase + 1)
- c.root = resID(root)
- c.visual = resID(visual)
- return nil
-}
-
-// NewWindow calls NewWindowDisplay with $DISPLAY.
-func NewWindow() (gui.Window, os.Error) {
- display := os.Getenv("DISPLAY")
- if len(display) == 0 {
- return nil, os.NewError("$DISPLAY not set")
- }
- return NewWindowDisplay(display)
-}
-
-// NewWindowDisplay returns a new gui.Window, backed by a newly created and
-// mapped X11 window. The X server to connect to is specified by the display
-// string, such as ":1".
-func NewWindowDisplay(display string) (gui.Window, os.Error) {
- socket, displayStr, err := connect(display)
- if err != nil {
- return nil, err
- }
- c := new(conn)
- c.c = socket
- c.r = bufio.NewReader(socket)
- c.w = bufio.NewWriter(socket)
- err = authenticate(c.w, displayStr)
- if err != nil {
- return nil, err
- }
- err = c.handshake()
- if err != nil {
- return nil, err
- }
-
- // Now that we're connected, show a window, via three X protocol messages.
- // First, issue a GetKeyboardMapping request. This is the first request, and
- // will be associated with a cookie of 1.
- setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long.
- setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo))
- // Second, create a graphics context (GC).
- setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long.
- setU32LE(c.buf[12:16], uint32(c.gc))
- setU32LE(c.buf[16:20], uint32(c.root))
- setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES.
- setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black.
- setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused.
- // Third, create the window.
- setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long.
- setU32LE(c.buf[36:40], uint32(c.window))
- setU32LE(c.buf[40:44], uint32(c.root))
- setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0).
- setU32LE(c.buf[48:52], windowHeight<<16|windowWidth)
- setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1.
- setU32LE(c.buf[56:60], uint32(c.visual))
- setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK.
- setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black.
- setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks.
- // Fourth, map the window.
- setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long.
- setU32LE(c.buf[76:80], uint32(c.window))
- // Write the bytes.
- _, err = c.w.Write(c.buf[:80])
- if err != nil {
- return nil, err
- }
- err = c.w.Flush()
- if err != nil {
- return nil, err
- }
-
- c.img = image.NewRGBA(windowWidth, windowHeight)
- c.eventc = make(chan interface{}, 16)
- c.flush = make(chan bool, 1)
- go c.readSocket()
- go c.writeSocket()
- return c, nil
-}
diff --git a/src/pkg/exp/norm/Makefile b/src/pkg/exp/norm/Makefile
deleted file mode 100644
index a4dfb43f7..000000000
--- a/src/pkg/exp/norm/Makefile
+++ /dev/null
@@ -1,44 +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.
-
-include ../../../Make.inc
-
-TARG=exp/norm
-GOFILES=\
- composition.go\
- forminfo.go\
- normalize.go\
- tables.go\
- trie.go\
-
-include ../../../Make.pkg
-
-CLEANFILES+=maketables maketesttables
-
-maketables: maketables.go triegen.go
- $(GC) maketables.go triegen.go
- $(LD) -o maketables maketables.$O
-
-maketesttables: maketesttables.go triegen.go
- $(GC) maketesttables.go triegen.go
- $(LD) -o maketesttables maketesttables.$O
-
-tables: maketables
- ./maketables > tables.go
- gofmt -w tables.go
-
-trietesttables: maketesttables
- ./maketesttables > triedata_test.go
- gofmt -w triedata_test.go
-
-# Build (but do not run) maketables during testing,
-# just to make sure it still compiles.
-testshort: maketables maketesttables
-
-# Downloads from www.unicode.org, so not part
-# of standard test scripts.
-test: testtables
-
-testtables: maketables
- ./maketables -test -tables=
diff --git a/src/pkg/exp/norm/composition.go b/src/pkg/exp/norm/composition.go
deleted file mode 100644
index b2d2abaf6..000000000
--- a/src/pkg/exp/norm/composition.go
+++ /dev/null
@@ -1,344 +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 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/src/pkg/exp/norm/composition_test.go b/src/pkg/exp/norm/composition_test.go
deleted file mode 100644
index 195a0c1e8..000000000
--- a/src/pkg/exp/norm/composition_test.go
+++ /dev/null
@@ -1,138 +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 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/src/pkg/exp/norm/forminfo.go b/src/pkg/exp/norm/forminfo.go
deleted file mode 100644
index ee3edb8ea..000000000
--- a/src/pkg/exp/norm/forminfo.go
+++ /dev/null
@@ -1,188 +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 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/src/pkg/exp/norm/maketables.go b/src/pkg/exp/norm/maketables.go
deleted file mode 100644
index e3e5700a6..000000000
--- a/src/pkg/exp/norm/maketables.go
+++ /dev/null
@@ -1,855 +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.
-
-// 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/src/pkg/exp/norm/maketesttables.go b/src/pkg/exp/norm/maketesttables.go
deleted file mode 100644
index c5f6a6436..000000000
--- a/src/pkg/exp/norm/maketesttables.go
+++ /dev/null
@@ -1,42 +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.
-
-// 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/src/pkg/exp/norm/norm_test.go b/src/pkg/exp/norm/norm_test.go
deleted file mode 100644
index 12dacfcf3..000000000
--- a/src/pkg/exp/norm/norm_test.go
+++ /dev/null
@@ -1,14 +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 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/src/pkg/exp/norm/normalize.go b/src/pkg/exp/norm/normalize.go
deleted file mode 100644
index e9d18dd9e..000000000
--- a/src/pkg/exp/norm/normalize.go
+++ /dev/null
@@ -1,99 +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 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/src/pkg/exp/norm/tables.go b/src/pkg/exp/norm/tables.go
deleted file mode 100644
index 76995c2fa..000000000
--- a/src/pkg/exp/norm/tables.go
+++ /dev/null
@@ -1,6580 +0,0 @@
-// 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/src/pkg/exp/norm/trie.go b/src/pkg/exp/norm/trie.go
deleted file mode 100644
index 6b6540187..000000000
--- a/src/pkg/exp/norm/trie.go
+++ /dev/null
@@ -1,234 +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 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/src/pkg/exp/norm/trie_test.go b/src/pkg/exp/norm/trie_test.go
deleted file mode 100644
index ad87d972b..000000000
--- a/src/pkg/exp/norm/trie_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-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/src/pkg/exp/norm/triedata_test.go b/src/pkg/exp/norm/triedata_test.go
deleted file mode 100644
index f886e6004..000000000
--- a/src/pkg/exp/norm/triedata_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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/src/pkg/exp/norm/triegen.go b/src/pkg/exp/norm/triegen.go
deleted file mode 100644
index 2b7eeee17..000000000
--- a/src/pkg/exp/norm/triegen.go
+++ /dev/null
@@ -1,211 +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.
-
-// 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/src/pkg/exp/regexp/Makefile b/src/pkg/exp/regexp/Makefile
deleted file mode 100644
index fc90df320..000000000
--- a/src/pkg/exp/regexp/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=exp/regexp
-GOFILES=\
- exec.go\
- regexp.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/exp/regexp/all_test.go b/src/pkg/exp/regexp/all_test.go
deleted file mode 100644
index 77f32ca1a..000000000
--- a/src/pkg/exp/regexp/all_test.go
+++ /dev/null
@@ -1,429 +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 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/src/pkg/exp/regexp/find_test.go b/src/pkg/exp/regexp/find_test.go
deleted file mode 100644
index dddc3484c..000000000
--- a/src/pkg/exp/regexp/find_test.go
+++ /dev/null
@@ -1,472 +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 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/src/pkg/exp/regexp/regexp.go b/src/pkg/exp/regexp/regexp.go
deleted file mode 100644
index 1b75900f8..000000000
--- a/src/pkg/exp/regexp/regexp.go
+++ /dev/null
@@ -1,795 +0,0 @@
-// 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/src/pkg/exp/regexp/syntax/Makefile b/src/pkg/exp/regexp/syntax/Makefile
deleted file mode 100644
index 97d4ad6ca..000000000
--- a/src/pkg/exp/regexp/syntax/Makefile
+++ /dev/null
@@ -1,16 +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.
-
-include ../../../../Make.inc
-
-TARG=exp/regexp/syntax
-GOFILES=\
- compile.go\
- parse.go\
- perl_groups.go\
- prog.go\
- regexp.go\
- simplify.go\
-
-include ../../../../Make.pkg
diff --git a/src/pkg/exp/template/html/Makefile b/src/pkg/exp/template/html/Makefile
deleted file mode 100644
index 2f107da11..000000000
--- a/src/pkg/exp/template/html/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../../Make.inc
-
-TARG=exp/template/html
-GOFILES=\
- escape.go
-
-include ../../../../Make.pkg
diff --git a/src/pkg/exp/template/html/context.go b/src/pkg/exp/template/html/context.go
deleted file mode 100644
index 411006883..000000000
--- a/src/pkg/exp/template/html/context.go
+++ /dev/null
@@ -1,98 +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 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/src/pkg/exp/template/html/escape.go b/src/pkg/exp/template/html/escape.go
deleted file mode 100644
index e0e87b98d..000000000
--- a/src/pkg/exp/template/html/escape.go
+++ /dev/null
@@ -1,105 +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 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/src/pkg/exp/template/html/escape_test.go b/src/pkg/exp/template/html/escape_test.go
deleted file mode 100644
index 345a752a8..000000000
--- a/src/pkg/exp/template/html/escape_test.go
+++ /dev/null
@@ -1,75 +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 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/src/pkg/exp/wingui/Makefile b/src/pkg/exp/wingui/Makefile
deleted file mode 100644
index 00f7d234d..000000000
--- a/src/pkg/exp/wingui/Makefile
+++ /dev/null
@@ -1,29 +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.
-
-GOOS=windows
-
-include ../../../Make.inc
-
-LD:=$(LD) -Hwindowsgui
-
-TARG=wingui
-
-GOFILES=\
- gui.go\
- winapi.go\
- zwinapi.go\
-
-include ../../../Make.cmd
-
-zwinapi.go: winapi.go
- $(GOROOT)/src/pkg/syscall/mksyscall_windows.pl $< \
- | sed 's/^package.*syscall$$/package main/' \
- | sed '/^import/a \
- import "syscall"' \
- | sed 's/Syscall/syscall.Syscall/' \
- | sed 's/NewLazyDLL/syscall.NewLazyDLL/' \
- | sed 's/EINVAL/syscall.EINVAL/' \
- | gofmt \
- > $@
diff --git a/src/pkg/exp/wingui/gui.go b/src/pkg/exp/wingui/gui.go
deleted file mode 100644
index cf392934c..000000000
--- a/src/pkg/exp/wingui/gui.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "fmt"
- "syscall"
- "os"
- "unsafe"
-)
-
-// some help functions
-
-func abortf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stdout, format, a...)
- os.Exit(1)
-}
-
-func abortErrNo(funcname string, err int) {
- abortf("%s failed: %d %s\n", funcname, err, syscall.Errstr(err))
-}
-
-// global vars
-
-var (
- mh uint32
- bh uint32
-)
-
-// WinProc called by windows to notify us of all windows events we might be interested in.
-func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr {
- var rc int32
- switch msg {
- case WM_CREATE:
- var e int
- // CreateWindowEx
- bh, e = CreateWindowEx(
- 0,
- syscall.StringToUTF16Ptr("button"),
- syscall.StringToUTF16Ptr("Quit"),
- WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
- 75, 70, 140, 25,
- hwnd, 1, mh, 0)
- if e != 0 {
- abortErrNo("CreateWindowEx", e)
- }
- fmt.Printf("button handle is %x\n", bh)
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- case WM_COMMAND:
- switch uint32(lparam) {
- case bh:
- e := PostMessage(hwnd, WM_CLOSE, 0, 0)
- if e != 0 {
- abortErrNo("PostMessage", e)
- }
- default:
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- }
- case WM_CLOSE:
- DestroyWindow(hwnd)
- case WM_DESTROY:
- PostQuitMessage(0)
- default:
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- }
- //fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc)
- return uintptr(rc)
-}
-
-func rungui() int {
- var e int
-
- // GetModuleHandle
- mh, e = GetModuleHandle(nil)
- if e != 0 {
- abortErrNo("GetModuleHandle", e)
- }
-
- // Get icon we're going to use.
- myicon, e := LoadIcon(0, IDI_APPLICATION)
- if e != 0 {
- abortErrNo("LoadIcon", e)
- }
-
- // Get cursor we're going to use.
- mycursor, e := LoadCursor(0, IDC_ARROW)
- if e != 0 {
- abortErrNo("LoadCursor", e)
- }
-
- // Create callback
- wproc := syscall.NewCallback(WndProc)
-
- // RegisterClassEx
- wcname := syscall.StringToUTF16Ptr("myWindowClass")
- var wc Wndclassex
- wc.Size = uint32(unsafe.Sizeof(wc))
- wc.WndProc = wproc
- wc.Instance = mh
- wc.Icon = myicon
- wc.Cursor = mycursor
- wc.Background = COLOR_BTNFACE + 1
- wc.MenuName = nil
- wc.ClassName = wcname
- wc.IconSm = myicon
- if _, e := RegisterClassEx(&wc); e != 0 {
- abortErrNo("RegisterClassEx", e)
- }
-
- // CreateWindowEx
- wh, e := CreateWindowEx(
- WS_EX_CLIENTEDGE,
- wcname,
- syscall.StringToUTF16Ptr("My window"),
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
- 0, 0, mh, 0)
- if e != 0 {
- abortErrNo("CreateWindowEx", e)
- }
- fmt.Printf("main window handle is %x\n", wh)
-
- // ShowWindow
- ShowWindow(wh, SW_SHOWDEFAULT)
-
- // UpdateWindow
- if e := UpdateWindow(wh); e != 0 {
- abortErrNo("UpdateWindow", e)
- }
-
- // Process all windows messages until WM_QUIT.
- var m Msg
- for {
- r, e := GetMessage(&m, 0, 0, 0)
- if e != 0 {
- abortErrNo("GetMessage", e)
- }
- if r == 0 {
- // WM_QUIT received -> get out
- break
- }
- TranslateMessage(&m)
- DispatchMessage(&m)
- }
- return int(m.Wparam)
-}
-
-func main() {
- rc := rungui()
- os.Exit(rc)
-}
diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go
deleted file mode 100644
index 31b57a2cc..000000000
--- a/src/pkg/exp/wingui/winapi.go
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "unsafe"
-)
-
-type Wndclassex struct {
- Size uint32
- Style uint32
- WndProc uintptr
- ClsExtra int32
- WndExtra int32
- Instance uint32
- Icon uint32
- Cursor uint32
- Background uint32
- MenuName *uint16
- ClassName *uint16
- IconSm uint32
-}
-
-type Point struct {
- X int32
- Y int32
-}
-
-type Msg struct {
- Hwnd uint32
- Message uint32
- Wparam int32
- Lparam int32
- Time uint32
- Pt Point
-}
-
-const (
- // Window styles
- WS_OVERLAPPED = 0
- WS_POPUP = 0x80000000
- WS_CHILD = 0x40000000
- WS_MINIMIZE = 0x20000000
- WS_VISIBLE = 0x10000000
- WS_DISABLED = 0x8000000
- WS_CLIPSIBLINGS = 0x4000000
- WS_CLIPCHILDREN = 0x2000000
- WS_MAXIMIZE = 0x1000000
- WS_CAPTION = WS_BORDER | WS_DLGFRAME
- WS_BORDER = 0x800000
- WS_DLGFRAME = 0x400000
- WS_VSCROLL = 0x200000
- WS_HSCROLL = 0x100000
- WS_SYSMENU = 0x80000
- WS_THICKFRAME = 0x40000
- WS_GROUP = 0x20000
- WS_TABSTOP = 0x10000
- WS_MINIMIZEBOX = 0x20000
- WS_MAXIMIZEBOX = 0x10000
- WS_TILED = WS_OVERLAPPED
- WS_ICONIC = WS_MINIMIZE
- WS_SIZEBOX = WS_THICKFRAME
- // Common Window Styles
- WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
- WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
- WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU
- WS_CHILDWINDOW = WS_CHILD
-
- WS_EX_CLIENTEDGE = 0x200
-
- // Some windows messages
- WM_CREATE = 1
- WM_DESTROY = 2
- WM_CLOSE = 16
- WM_COMMAND = 273
-
- // Some button control styles
- BS_DEFPUSHBUTTON = 1
-
- // Some color constants
- COLOR_WINDOW = 5
- COLOR_BTNFACE = 15
-
- // Default window position
- CW_USEDEFAULT = 0x80000000 - 0x100000000
-
- // Show window default style
- SW_SHOWDEFAULT = 10
-)
-
-var (
- // Some globally known cursors
- IDC_ARROW = MakeIntResource(32512)
- IDC_IBEAM = MakeIntResource(32513)
- IDC_WAIT = MakeIntResource(32514)
- IDC_CROSS = MakeIntResource(32515)
-
- // Some globally known icons
- IDI_APPLICATION = MakeIntResource(32512)
- IDI_HAND = MakeIntResource(32513)
- IDI_QUESTION = MakeIntResource(32514)
- IDI_EXCLAMATION = MakeIntResource(32515)
- IDI_ASTERISK = MakeIntResource(32516)
- IDI_WINLOGO = MakeIntResource(32517)
- IDI_WARNING = IDI_EXCLAMATION
- IDI_ERROR = IDI_HAND
- IDI_INFORMATION = IDI_ASTERISK
-)
-
-//sys GetModuleHandle(modname *uint16) (handle uint32, errno int) = GetModuleHandleW
-//sys RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) = user32.RegisterClassExW
-//sys 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) = user32.CreateWindowExW
-//sys DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.DefWindowProcW
-//sys DestroyWindow(hwnd uint32) (errno int) = user32.DestroyWindow
-//sys PostQuitMessage(exitcode int32) = user32.PostQuitMessage
-//sys ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) = user32.ShowWindow
-//sys UpdateWindow(hwnd uint32) (errno int) = user32.UpdateWindow
-//sys GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) [failretval==-1] = user32.GetMessageW
-//sys TranslateMessage(msg *Msg) (done bool) = user32.TranslateMessage
-//sys DispatchMessage(msg *Msg) (ret int32) = user32.DispatchMessageW
-//sys LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) = user32.LoadIconW
-//sys LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) = user32.LoadCursorW
-//sys SetCursor(cursor uint32) (precursor uint32, errno int) = user32.SetCursor
-//sys SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.SendMessageW
-//sys PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) = user32.PostMessageW
-
-func MakeIntResource(id uint16) *uint16 {
- return (*uint16)(unsafe.Pointer(uintptr(id)))
-}
diff --git a/src/pkg/exp/wingui/zwinapi.go b/src/pkg/exp/wingui/zwinapi.go
deleted file mode 100644
index 4c009dd69..000000000
--- a/src/pkg/exp/wingui/zwinapi.go
+++ /dev/null
@@ -1,211 +0,0 @@
-// mksyscall_windows.pl winapi.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-package main
-
-import "unsafe"
-import "syscall"
-
-var (
- 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.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
- handle = uint32(r0)
- if handle == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
- r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
- atom = uint16(r0)
- if atom == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-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.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 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
- 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.Addr(), 1, uintptr(hwnd), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func PostQuitMessage(exitcode int32) {
- syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
- return
-}
-
-func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) {
- 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.Addr(), 1, uintptr(hwnd), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) {
- 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 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func TranslateMessage(msg *Msg) (done bool) {
- 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.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.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
- icon = uint32(r0)
- if icon == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
- cursor = uint32(r0)
- if cursor == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func SetCursor(cursor uint32) (precursor uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
- precursor = uint32(r0)
- if precursor == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
-
-func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
- 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.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- errno = int(e1)
- } else {
- errno = syscall.EINVAL
- }
- } else {
- errno = 0
- }
- return
-}
diff --git a/src/pkg/expvar/Makefile b/src/pkg/expvar/Makefile
deleted file mode 100644
index 5619630d1..000000000
--- a/src/pkg/expvar/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=expvar
-GOFILES=\
- expvar.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index 7b733faf6..b06599505 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -16,17 +16,17 @@
//
// The package is sometimes only imported for the side effect of
// registering its HTTP handler and the above variables. To use it
-// this way, simply link this package into your program:
+// this way, link this package into your program:
// import _ "expvar"
//
package expvar
import (
"bytes"
+ "encoding/json"
"fmt"
- "http"
- "json"
"log"
+ "net/http"
"os"
"runtime"
"strconv"
@@ -41,10 +41,14 @@ type Var interface {
// Int is a 64-bit integer variable that satisfies the Var interface.
type Int struct {
i int64
- mu sync.Mutex
+ mu sync.RWMutex
}
-func (v *Int) String() string { return strconv.Itoa64(v.i) }
+func (v *Int) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.FormatInt(v.i, 10)
+}
func (v *Int) Add(delta int64) {
v.mu.Lock()
@@ -61,10 +65,14 @@ func (v *Int) Set(value int64) {
// Float is a 64-bit float variable that satisfies the Var interface.
type Float struct {
f float64
- mu sync.Mutex
+ mu sync.RWMutex
}
-func (v *Float) String() string { return strconv.Ftoa64(v.f, 'g', -1) }
+func (v *Float) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.FormatFloat(v.f, 'g', -1, 64)
+}
// Add adds delta to v.
func (v *Float) Add(delta float64) {
@@ -83,7 +91,7 @@ func (v *Float) Set(value float64) {
// Map is a string-to-Var map variable that satisfies the Var interface.
type Map struct {
m map[string]Var
- mu sync.Mutex
+ mu sync.RWMutex
}
// KeyValue represents a single entry in a Map.
@@ -93,19 +101,19 @@ type KeyValue struct {
}
func (v *Map) String() string {
- v.mu.Lock()
- defer v.mu.Unlock()
- b := new(bytes.Buffer)
- fmt.Fprintf(b, "{")
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "{")
first := true
for key, val := range v.m {
if !first {
- fmt.Fprintf(b, ", ")
+ fmt.Fprintf(&b, ", ")
}
- fmt.Fprintf(b, "\"%s\": %v", key, val.String())
+ fmt.Fprintf(&b, "\"%s\": %v", key, val)
first = false
}
- fmt.Fprintf(b, "}")
+ fmt.Fprintf(&b, "}")
return b.String()
}
@@ -115,8 +123,8 @@ func (v *Map) Init() *Map {
}
func (v *Map) Get(key string) Var {
- v.mu.Lock()
- defer v.mu.Unlock()
+ v.mu.RLock()
+ defer v.mu.RUnlock()
return v.m[key]
}
@@ -127,12 +135,17 @@ func (v *Map) Set(key string, av Var) {
}
func (v *Map) Add(key string, delta int64) {
- v.mu.Lock()
- defer v.mu.Unlock()
+ v.mu.RLock()
av, ok := v.m[key]
+ v.mu.RUnlock()
if !ok {
- av = new(Int)
- v.m[key] = av
+ // check again under the write lock
+ v.mu.Lock()
+ if _, ok = v.m[key]; !ok {
+ av = new(Int)
+ v.m[key] = av
+ }
+ v.mu.Unlock()
}
// Add to Int; ignore otherwise.
@@ -143,12 +156,17 @@ func (v *Map) Add(key string, delta int64) {
// AddFloat adds delta to the *Float value stored under the given map key.
func (v *Map) AddFloat(key string, delta float64) {
- v.mu.Lock()
- defer v.mu.Unlock()
+ v.mu.RLock()
av, ok := v.m[key]
+ v.mu.RUnlock()
if !ok {
- av = new(Float)
- v.m[key] = av
+ // check again under the write lock
+ v.mu.Lock()
+ if _, ok = v.m[key]; !ok {
+ av = new(Float)
+ v.m[key] = av
+ }
+ v.mu.Unlock()
}
// Add to Float; ignore otherwise.
@@ -157,28 +175,34 @@ func (v *Map) AddFloat(key string, delta float64) {
}
}
-// TODO(rsc): Make sure map access in separate thread is safe.
-func (v *Map) iterate(c chan<- KeyValue) {
+// Do calls f for each entry in the map.
+// The map is locked during the iteration,
+// but existing entries may be concurrently updated.
+func (v *Map) Do(f func(KeyValue)) {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
for k, v := range v.m {
- c <- KeyValue{k, v}
+ f(KeyValue{k, v})
}
- close(c)
-}
-
-func (v *Map) Iter() <-chan KeyValue {
- c := make(chan KeyValue)
- go v.iterate(c)
- return c
}
// String is a string variable, and satisfies the Var interface.
type String struct {
- s string
+ s string
+ mu sync.RWMutex
}
-func (v *String) String() string { return strconv.Quote(v.s) }
+func (v *String) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.Quote(v.s)
+}
-func (v *String) Set(value string) { v.s = value }
+func (v *String) Set(value string) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.s = value
+}
// Func implements Var by calling the function
// and formatting the returned value using JSON.
@@ -190,10 +214,12 @@ func (f Func) String() string {
}
// All published variables.
-var vars map[string]Var = make(map[string]Var)
-var mutex sync.Mutex
+var (
+ mutex sync.RWMutex
+ vars map[string]Var = make(map[string]Var)
+)
-// Publish declares an named exported variable. This should be called from a
+// Publish declares a named exported variable. This should be called from a
// package's init function when it creates its Vars. If the name is already
// registered then this will log.Panic.
func Publish(name string, v Var) {
@@ -207,17 +233,11 @@ func Publish(name string, v Var) {
// Get retrieves a named exported variable.
func Get(name string) Var {
+ mutex.RLock()
+ defer mutex.RUnlock()
return vars[name]
}
-// RemoveAll removes all exported variables.
-// This is for tests; don't call this on a real server.
-func RemoveAll() {
- mutex.Lock()
- defer mutex.Unlock()
- vars = make(map[string]Var)
-}
-
// Convenience functions for creating new exported variables.
func NewInt(name string) *Int {
@@ -244,31 +264,28 @@ func NewString(name string) *String {
return v
}
-// TODO(rsc): Make sure map access in separate thread is safe.
-func iterate(c chan<- KeyValue) {
+// Do calls f for each exported variable.
+// The global variable map is locked during the iteration,
+// but existing entries may be concurrently updated.
+func Do(f func(KeyValue)) {
+ mutex.RLock()
+ defer mutex.RUnlock()
for k, v := range vars {
- c <- KeyValue{k, v}
+ f(KeyValue{k, v})
}
- close(c)
-}
-
-func Iter() <-chan KeyValue {
- c := make(chan KeyValue)
- go iterate(c)
- return c
}
func expvarHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
fmt.Fprintf(w, "{\n")
first := true
- for name, value := range vars {
+ Do(func(kv KeyValue) {
if !first {
fmt.Fprintf(w, ",\n")
}
first = false
- fmt.Fprintf(w, "%q: %s", name, value)
- }
+ fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
+ })
fmt.Fprintf(w, "\n}\n")
}
@@ -277,11 +294,13 @@ func cmdline() interface{} {
}
func memstats() interface{} {
- return runtime.MemStats
+ stats := new(runtime.MemStats)
+ runtime.ReadMemStats(stats)
+ return *stats
}
func init() {
- http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
+ http.HandleFunc("/debug/vars", expvarHandler)
Publish("cmdline", Func(cmdline))
Publish("memstats", Func(memstats))
}
diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
index 8f7a48168..bbd9dd8d6 100644
--- a/src/pkg/expvar/expvar_test.go
+++ b/src/pkg/expvar/expvar_test.go
@@ -5,10 +5,18 @@
package expvar
import (
- "json"
+ "encoding/json"
"testing"
)
+// RemoveAll removes all exported variables.
+// This is for tests only.
+func RemoveAll() {
+ mutex.Lock()
+ defer mutex.Unlock()
+ vars = make(map[string]Var)
+}
+
func TestInt(t *testing.T) {
reqs := NewInt("requests")
if reqs.i != 0 {
diff --git a/src/pkg/flag/Makefile b/src/pkg/flag/Makefile
deleted file mode 100644
index 3408ca474..000000000
--- a/src/pkg/flag/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=flag
-GOFILES=\
- flag.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/flag/example_test.go b/src/pkg/flag/example_test.go
new file mode 100644
index 000000000..04a0d20ee
--- /dev/null
+++ b/src/pkg/flag/example_test.go
@@ -0,0 +1,83 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// These examples demonstrate more intricate uses of the flag package.
+package flag_test
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "strings"
+ "time"
+)
+
+// Example 1: A single string flag called "species" with default value "gopher".
+var species = flag.String("species", "gopher", "the species we are studying")
+
+// Example 2: Two flags sharing a variable, so we can have a shorthand.
+// The order of initialization is undefined, so make sure both use the
+// same default value. They must be set up with an init function.
+var gopherType string
+
+func init() {
+ const (
+ defaultGopher = "pocket"
+ usage = "the variety of gopher"
+ )
+ flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
+ flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
+}
+
+// Example 3: A user-defined flag type, a slice of durations.
+type interval []time.Duration
+
+// String is the method to format the flag's value, part of the flag.Value interface.
+// The String method's output will be used in diagnostics.
+func (i *interval) String() string {
+ return fmt.Sprint(*i)
+}
+
+// Set is the method to set the flag value, part of the flag.Value interface.
+// Set's argument is a string to be parsed to set the flag.
+// It's a comma-separated list, so we split it.
+func (i *interval) Set(value string) error {
+ // If we wanted to allow the flag to be set multiple times,
+ // accumulating values, we would delete this if statement.
+ // That would permit usages such as
+ // -deltaT 10s -deltaT 15s
+ // and other combinations.
+ if len(*i) > 0 {
+ return errors.New("interval flag already set")
+ }
+ for _, dt := range strings.Split(value, ",") {
+ duration, err := time.ParseDuration(dt)
+ if err != nil {
+ return err
+ }
+ *i = append(*i, duration)
+ }
+ return nil
+}
+
+// Define a flag to accumulate durations. Because it has a special type,
+// we need to use the Var function and therefore create the flag during
+// init.
+
+var intervalFlag interval
+
+func init() {
+ // Tie the command-line flag to the intervalFlag variable and
+ // set a usage message.
+ flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
+}
+
+func Example() {
+ // All the interesting pieces are with the variables declared above, but
+ // to enable the flag package to see the flags defined there, one must
+ // execute, typically at the start of main (not init!):
+ // flag.Parse()
+ // We don't run it here because this is not a main function and
+ // the testing suite has already parsed the flags.
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index 01bbc3770..c28d0e720 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -49,6 +49,7 @@
Integer flags accept 1234, 0664, 0x1234 and may be negative.
Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+ Duration flags accept any input valid for time.ParseDuration.
The default set of command-line flags is controlled by
top-level functions. The FlagSet type allows one to define
@@ -60,16 +61,19 @@
package flag
import (
+ "errors"
"fmt"
+ "io"
"os"
"sort"
"strconv"
+ "time"
)
// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
-var ErrHelp = os.NewError("flag: help requested")
+var ErrHelp = errors.New("flag: help requested")
-// -- Bool Value
+// -- bool Value
type boolValue bool
func newBoolValue(val bool, p *bool) *boolValue {
@@ -77,15 +81,15 @@ func newBoolValue(val bool, p *bool) *boolValue {
return (*boolValue)(p)
}
-func (b *boolValue) Set(s string) bool {
- v, err := strconv.Atob(s)
+func (b *boolValue) Set(s string) error {
+ v, err := strconv.ParseBool(s)
*b = boolValue(v)
- return err == nil
+ return err
}
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
-// -- Int Value
+// -- int Value
type intValue int
func newIntValue(val int, p *int) *intValue {
@@ -93,15 +97,15 @@ func newIntValue(val int, p *int) *intValue {
return (*intValue)(p)
}
-func (i *intValue) Set(s string) bool {
- v, err := strconv.Btoi64(s, 0)
+func (i *intValue) Set(s string) error {
+ v, err := strconv.ParseInt(s, 0, 64)
*i = intValue(v)
- return err == nil
+ return err
}
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
-// -- Int64 Value
+// -- int64 Value
type int64Value int64
func newInt64Value(val int64, p *int64) *int64Value {
@@ -109,15 +113,15 @@ func newInt64Value(val int64, p *int64) *int64Value {
return (*int64Value)(p)
}
-func (i *int64Value) Set(s string) bool {
- v, err := strconv.Btoi64(s, 0)
+func (i *int64Value) Set(s string) error {
+ v, err := strconv.ParseInt(s, 0, 64)
*i = int64Value(v)
- return err == nil
+ return err
}
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
-// -- Uint Value
+// -- uint Value
type uintValue uint
func newUintValue(val uint, p *uint) *uintValue {
@@ -125,10 +129,10 @@ func newUintValue(val uint, p *uint) *uintValue {
return (*uintValue)(p)
}
-func (i *uintValue) Set(s string) bool {
- v, err := strconv.Btoui64(s, 0)
+func (i *uintValue) Set(s string) error {
+ v, err := strconv.ParseUint(s, 0, 64)
*i = uintValue(v)
- return err == nil
+ return err
}
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
@@ -141,10 +145,10 @@ func newUint64Value(val uint64, p *uint64) *uint64Value {
return (*uint64Value)(p)
}
-func (i *uint64Value) Set(s string) bool {
- v, err := strconv.Btoui64(s, 0)
+func (i *uint64Value) Set(s string) error {
+ v, err := strconv.ParseUint(s, 0, 64)
*i = uint64Value(v)
- return err == nil
+ return err
}
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
@@ -157,14 +161,14 @@ func newStringValue(val string, p *string) *stringValue {
return (*stringValue)(p)
}
-func (s *stringValue) Set(val string) bool {
+func (s *stringValue) Set(val string) error {
*s = stringValue(val)
- return true
+ return nil
}
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
-// -- Float64 Value
+// -- float64 Value
type float64Value float64
func newFloat64Value(val float64, p *float64) *float64Value {
@@ -172,19 +176,35 @@ func newFloat64Value(val float64, p *float64) *float64Value {
return (*float64Value)(p)
}
-func (f *float64Value) Set(s string) bool {
- v, err := strconv.Atof64(s)
+func (f *float64Value) Set(s string) error {
+ v, err := strconv.ParseFloat(s, 64)
*f = float64Value(v)
- return err == nil
+ return err
}
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+// -- time.Duration Value
+type durationValue time.Duration
+
+func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
+ *p = val
+ return (*durationValue)(p)
+}
+
+func (d *durationValue) Set(s string) error {
+ v, err := time.ParseDuration(s)
+ *d = durationValue(v)
+ return err
+}
+
+func (d *durationValue) String() string { return (*time.Duration)(d).String() }
+
// Value is the interface to the dynamic value stored in a flag.
// (The default value is represented as a string.)
type Value interface {
String() string
- Set(string) bool
+ Set(string) error
}
// ErrorHandling defines how to handle flag parsing errors.
@@ -204,11 +224,13 @@ type FlagSet struct {
Usage func()
name string
+ parsed bool
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
+ output io.Writer // nil means stderr; use out() accessor
}
// A Flag represents the state of a flag.
@@ -235,6 +257,19 @@ func sortFlags(flags map[string]*Flag) []*Flag {
return result
}
+func (f *FlagSet) out() io.Writer {
+ if f.output == nil {
+ return os.Stderr
+ }
+ return f.output
+}
+
+// SetOutput sets the destination for usage and error messages.
+// If output is nil, os.Stderr is used.
+func (f *FlagSet) SetOutput(output io.Writer) {
+ f.output = output
+}
+
// VisitAll visits the flags in lexicographical order, calling fn for each.
// It visits all flags, even those not set.
func (f *FlagSet) VisitAll(fn func(*Flag)) {
@@ -274,36 +309,38 @@ func Lookup(name string) *Flag {
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 (f *FlagSet) Set(name, value string) bool {
+// Set sets the value of the named flag.
+func (f *FlagSet) Set(name, value string) error {
flag, ok := f.formal[name]
if !ok {
- return false
+ return fmt.Errorf("no such flag -%v", name)
}
- ok = flag.Value.Set(value)
- if !ok {
- return false
+ err := flag.Value.Set(value)
+ if err != nil {
+ return err
+ }
+ if f.actual == nil {
+ f.actual = make(map[string]*Flag)
}
f.actual[name] = flag
- return true
+ return nil
}
-// 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 {
+// Set sets the value of the named command-line flag.
+func Set(name, value string) error {
return commandLine.Set(name, value)
}
-// PrintDefaults prints to standard error the default values of all defined flags in the set.
+// PrintDefaults prints, to standard error unless configured
+// otherwise, the default values of all defined flags in the set.
func (f *FlagSet) PrintDefaults() {
- f.VisitAll(func(f *Flag) {
+ f.VisitAll(func(flag *Flag) {
format := " -%s=%s: %s\n"
- if _, ok := f.Value.(*stringValue); ok {
+ if _, ok := flag.Value.(*stringValue); ok {
// put quotes on the value
format = " -%s=%q: %s\n"
}
- fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
+ fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
})
}
@@ -314,14 +351,19 @@ func PrintDefaults() {
// defaultUsage is the default function to print a usage message.
func defaultUsage(f *FlagSet) {
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name)
+ fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
f.PrintDefaults()
}
+// NOTE: Usage is not just defaultUsage(commandLine)
+// because it serves (via godoc flag Usage) as the example
+// for how to write your own usage function.
+
// 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() {
- defaultUsage(commandLine)
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ PrintDefaults()
}
// NFlag returns the number of flags that have been set.
@@ -533,12 +575,38 @@ func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
return p
}
-// Float64 defines an int flag with specified name, default value, and usage string.
+// 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 {
return commandLine.Float64(name, value, usage)
}
+// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
+// The argument p points to a time.Duration variable in which to store the value of the flag.
+func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
+ f.Var(newDurationValue(value, p), name, usage)
+}
+
+// DurationVar defines a time.Duration flag with specified name, default value, and usage string.
+// The argument p points to a time.Duration variable in which to store the value of the flag.
+func DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
+ commandLine.Var(newDurationValue(value, p), name, usage)
+}
+
+// Duration defines a time.Duration flag with specified name, default value, and usage string.
+// The return value is the address of a time.Duration variable that stores the value of the flag.
+func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration {
+ p := new(time.Duration)
+ f.DurationVar(p, name, value, usage)
+ return p
+}
+
+// Duration defines a time.Duration flag with specified name, default value, and usage string.
+// The return value is the address of a time.Duration variable that stores the value of the flag.
+func Duration(name string, value time.Duration, usage string) *time.Duration {
+ return commandLine.Duration(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
@@ -550,9 +618,12 @@ func (f *FlagSet) Var(value Value, name string, usage string) {
flag := &Flag{name, usage, value, value.String()}
_, alreadythere := f.formal[name]
if alreadythere {
- fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name)
+ fmt.Fprintf(f.out(), "%s flag redefined: %s\n", f.name, name)
panic("flag redefinition") // Happens only if flags are declared with identical names
}
+ if f.formal == nil {
+ f.formal = make(map[string]*Flag)
+ }
f.formal[name] = flag
}
@@ -568,9 +639,9 @@ func Var(value Value, name string, usage string) {
// 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 {
+func (f *FlagSet) failf(format string, a ...interface{}) error {
err := fmt.Errorf(format, a...)
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(f.out(), err)
f.usage()
return err
}
@@ -580,13 +651,15 @@ func (f *FlagSet) failf(format string, a ...interface{}) os.Error {
func (f *FlagSet) usage() {
if f == commandLine {
Usage()
+ } else if f.Usage == nil {
+ defaultUsage(f)
} else {
f.Usage()
}
}
// parseOne parses one flag. It returns whether a flag was seen.
-func (f *FlagSet) parseOne() (bool, os.Error) {
+func (f *FlagSet) parseOne() (bool, error) {
if len(f.args) == 0 {
return false, nil
}
@@ -630,8 +703,8 @@ func (f *FlagSet) parseOne() (bool, os.Error) {
}
if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
if has_value {
- if !fv.Set(value) {
- f.failf("invalid boolean value %q for flag: -%s", value, name)
+ if err := fv.Set(value); err != nil {
+ f.failf("invalid boolean value %q for -%s: %v", value, name, err)
}
} else {
fv.Set("true")
@@ -646,11 +719,13 @@ func (f *FlagSet) parseOne() (bool, os.Error) {
if !has_value {
return false, f.failf("flag needs an argument: -%s", name)
}
- ok = flag.Value.Set(value)
- if !ok {
- return false, f.failf("invalid value %q for flag: -%s", value, name)
+ if err := flag.Value.Set(value); err != nil {
+ return false, f.failf("invalid value %q for flag -%s: %v", value, name, err)
}
}
+ if f.actual == nil {
+ f.actual = make(map[string]*Flag)
+ }
f.actual[name] = flag
return true, nil
}
@@ -659,7 +734,8 @@ func (f *FlagSet) parseOne() (bool, os.Error) {
// 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 {
+func (f *FlagSet) Parse(arguments []string) error {
+ f.parsed = true
f.args = arguments
for {
seen, err := f.parseOne()
@@ -681,6 +757,11 @@ func (f *FlagSet) Parse(arguments []string) os.Error {
return nil
}
+// Parsed reports whether f.Parse has been called.
+func (f *FlagSet) Parsed() bool {
+ return f.parsed
+}
+
// 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() {
@@ -688,6 +769,11 @@ func Parse() {
commandLine.Parse(os.Args[1:])
}
+// Parsed returns true if the command-line flags have been parsed.
+func Parsed() bool {
+ return commandLine.Parsed()
+}
+
// The default set of command-line flags, parsed from os.Args.
var commandLine = NewFlagSet(os.Args[0], ExitOnError)
@@ -696,10 +782,15 @@ var commandLine = NewFlagSet(os.Args[0], ExitOnError)
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
}
+
+// Init sets the name and error handling property for a flag set.
+// By default, the zero FlagSet uses an empty name and the
+// ContinueOnError error handling policy.
+func (f *FlagSet) Init(name string, errorHandling ErrorHandling) {
+ f.name = name
+ f.errorHandling = errorHandling
+}
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
index 63d0a9fc8..a9561f269 100644
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -5,21 +5,25 @@
package flag_test
import (
+ "bytes"
. "flag"
"fmt"
"os"
"sort"
+ "strings"
"testing"
+ "time"
)
var (
- test_bool = Bool("test_bool", false, "bool value")
- test_int = Int("test_int", 0, "int value")
- test_int64 = Int64("test_int64", 0, "int64 value")
- test_uint = Uint("test_uint", 0, "uint value")
- test_uint64 = Uint64("test_uint64", 0, "uint64 value")
- test_string = String("test_string", "0", "string value")
- test_float64 = Float64("test_float64", 0, "float64 value")
+ test_bool = Bool("test_bool", false, "bool value")
+ test_int = Int("test_int", 0, "int value")
+ test_int64 = Int64("test_int64", 0, "int64 value")
+ test_uint = Uint("test_uint", 0, "uint value")
+ test_uint64 = Uint64("test_uint64", 0, "uint64 value")
+ test_string = String("test_string", "0", "string value")
+ test_float64 = Float64("test_float64", 0, "float64 value")
+ test_duration = Duration("test_duration", 0, "time.Duration value")
)
func boolString(s string) string {
@@ -41,6 +45,8 @@ func TestEverything(t *testing.T) {
ok = true
case f.Name == "test_bool" && f.Value.String() == boolString(desired):
ok = true
+ case f.Name == "test_duration" && f.Value.String() == desired+"s":
+ ok = true
}
if !ok {
t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
@@ -48,7 +54,7 @@ func TestEverything(t *testing.T) {
}
}
VisitAll(visitor)
- if len(m) != 7 {
+ if len(m) != 8 {
t.Error("VisitAll misses some flags")
for k, v := range m {
t.Log(k, *v)
@@ -70,9 +76,10 @@ func TestEverything(t *testing.T) {
Set("test_uint64", "1")
Set("test_string", "1")
Set("test_float64", "1")
+ Set("test_duration", "1s")
desired = "1"
Visit(visitor)
- if len(m) != 7 {
+ if len(m) != 8 {
t.Error("Visit fails after set")
for k, v := range m {
t.Log(k, *v)
@@ -98,6 +105,9 @@ func TestUsage(t *testing.T) {
}
func testParse(f *FlagSet, t *testing.T) {
+ if f.Parsed() {
+ t.Error("f.Parse() = true before Parse")
+ }
boolFlag := f.Bool("bool", false, "bool value")
bool2Flag := f.Bool("bool2", false, "bool2 value")
intFlag := f.Int("int", 0, "int value")
@@ -106,6 +116,7 @@ func testParse(f *FlagSet, t *testing.T) {
uint64Flag := f.Uint64("uint64", 0, "uint64 value")
stringFlag := f.String("string", "0", "string value")
float64Flag := f.Float64("float64", 0, "float64 value")
+ durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
extra := "one-extra-argument"
args := []string{
"-bool",
@@ -116,11 +127,15 @@ func testParse(f *FlagSet, t *testing.T) {
"--uint64", "25",
"-string", "hello",
"-float64", "2718e28",
+ "-duration", "2m",
extra,
}
if err := f.Parse(args); err != nil {
t.Fatal(err)
}
+ if !f.Parsed() {
+ t.Error("f.Parse() = false after Parse")
+ }
if *boolFlag != true {
t.Error("bool flag should be true, is ", *boolFlag)
}
@@ -145,6 +160,9 @@ func testParse(f *FlagSet, t *testing.T) {
if *float64Flag != 2718e28 {
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
}
+ if *durationFlag != 2*time.Minute {
+ t.Error("duration flag should be 2m, is ", *durationFlag)
+ }
if len(f.Args()) != 1 {
t.Error("expected one argument, got", len(f.Args()))
} else if f.Args()[0] != extra {
@@ -168,13 +186,14 @@ func (f *flagVar) String() string {
return fmt.Sprint([]string(*f))
}
-func (f *flagVar) Set(value string) bool {
+func (f *flagVar) Set(value string) error {
*f = append(*f, value)
- return true
+ return nil
}
func TestUserDefined(t *testing.T) {
- flags := NewFlagSet("test", ContinueOnError)
+ var flags FlagSet
+ flags.Init("test", ContinueOnError)
var v flagVar
flags.Var(&v, "v", "usage")
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
@@ -189,6 +208,17 @@ func TestUserDefined(t *testing.T) {
}
}
+func TestSetOutput(t *testing.T) {
+ var flags FlagSet
+ var buf bytes.Buffer
+ flags.SetOutput(&buf)
+ flags.Init("test", ContinueOnError)
+ flags.Parse([]string{"-unknown"})
+ if out := buf.String(); !strings.Contains(out, "-unknown") {
+ t.Logf("expected output mentioning unknown; got %q", out)
+ }
+}
+
// This tests that one can reset the flags. This still works but not well, and is
// superseded by FlagSet.
func TestChangingArgs(t *testing.T) {
diff --git a/src/pkg/fmt/Makefile b/src/pkg/fmt/Makefile
deleted file mode 100644
index 44b48bc67..000000000
--- a/src/pkg/fmt/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../Make.inc
-
-TARG=fmt
-GOFILES=\
- doc.go\
- format.go\
- print.go\
- scan.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 35a11e19f..9660370c2 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -7,7 +7,8 @@
to C's printf and scanf. The format 'verbs' are derived from C's but
are simpler.
- Printing:
+
+ Printing
The verbs:
@@ -30,8 +31,9 @@
%X base 16, with upper-case letters for A-F
%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
+ %b decimalless scientific notation with exponent a power of two,
+ in the manner of strconv.FormatFloat with the 'b' format,
+ e.g. -123456p-78
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
@@ -89,14 +91,22 @@
If an operand implements interface Formatter, that interface
can be used for fine control of formatting.
- If an operand implements method String() string that method
+ If the format (which is implicitly %v for Println etc.) is valid
+ for a string (%s %q %v %x %X), the following two rules also apply:
+
+ 1. If an operand implements the error interface, the Error method
+ will be used to convert the object to a string, which will then
+ be formatted as required by the verb (if any).
+
+ 2. If an operand implements method String() string, that method
will be used to convert the object to a string, which will then
- be formatted as required by the verb (if any). To avoid
- recursion in cases such as
- type X int
- func (x X) String() string { return Sprintf("%d", x) }
- cast the value before recurring:
- func (x X) String() string { return Sprintf("%d", int(x)) }
+ be formatted as required by the verb (if any).
+
+ To avoid recursion in cases such as
+ type X string
+ func (x X) String() string { return Sprintf("<%s>", x) }
+ convert the value before recurring:
+ func (x X) String() string { return Sprintf("<%s>", string(x)) }
Format errors:
@@ -118,11 +128,12 @@
by a single character (the verb) and end with a parenthesized
description.
- Scanning:
+
+ Scanning
An analogous set of functions scans formatted text to yield
values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
- Fscanf and Fscanln read from a specified os.Reader; Sscan,
+ Fscanf and Fscanln read from a specified io.Reader; Sscan,
Sscanf and Sscanln read from an argument string. Scanln,
Fscanln and Sscanln stop scanning at a newline and require that
the items be followed by one; Sscanf, Fscanf and Sscanf require
diff --git a/src/pkg/syscall/syscall_386.go b/src/pkg/fmt/export_test.go
index cb948b87a..89d57ee6c 100644
--- a/src/pkg/syscall/syscall_386.go
+++ b/src/pkg/fmt/export_test.go
@@ -1,7 +1,7 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package syscall
+package fmt
-const ARCH = "386"
+var IsSpace = isSpace
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 38218dfdc..758fc50d0 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -5,12 +5,15 @@
package fmt_test
import (
+ "bytes"
. "fmt"
"io"
"math"
"runtime" // for the malloc count test only
"strings"
"testing"
+ "time"
+ "unicode"
)
type (
@@ -46,8 +49,10 @@ func TestFmtInterface(t *testing.T) {
const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1
-var array = []int{1, 2, 3, 4, 5}
-var iarray = []interface{}{1, "hello", 2.5, nil}
+var array = [5]int{1, 2, 3, 4, 5}
+var iarray = [4]interface{}{1, "hello", 2.5, nil}
+var slice = array[:]
+var islice = iarray[:]
type A struct {
i int
@@ -72,7 +77,7 @@ type C struct {
type F int
-func (f F) Format(s State, c int) {
+func (f F) Format(s State, c rune) {
Fprintf(s, "<%c=F(%d)>", c, int(f))
}
@@ -87,6 +92,10 @@ type S struct {
G G // a struct field that GoStrings
}
+type SI struct {
+ I interface{}
+}
+
// A type with a String method with pointer receiver for testing %p
type P int
@@ -322,6 +331,12 @@ var fmttests = []struct {
{"%v", &array, "&[1 2 3 4 5]"},
{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+ // slices
+ {"%v", slice, "[1 2 3 4 5]"},
+ {"%v", islice, "[1 hello 2.5 <nil>]"},
+ {"%v", &slice, "&[1 2 3 4 5]"},
+ {"%v", &islice, "&[1 hello 2.5 <nil>]"},
+
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
{"%v", complex64(1 + 2i), "(1+2i)"},
@@ -339,7 +354,7 @@ var fmttests = []struct {
{"%s", I(23), `<23>`},
{"%q", I(23), `"<23>"`},
{"%x", I(23), `3c32333e`},
- {"%d", I(23), `%!d(string=<23>)`},
+ {"%d", I(23), `23`}, // Stringer applies only to string formats.
// go syntax
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
@@ -348,9 +363,18 @@ var fmttests = []struct {
{"%#v", make(chan int), "(chan int)(0xPTR)"},
{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
{"%#v", 1000000000, "1000000000"},
- {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
- {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{I:1, j:2}, "b":fmt_test.B{I:3, j:4}}`},
+ {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`},
+ {"%#v", map[string]B{"a": {1, 2}}, `map[string]fmt_test.B{"a":fmt_test.B{I:1, j:2}}`},
{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+ {"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`},
+ {"%#v", []int(nil), `[]int(nil)`},
+ {"%#v", []int{}, `[]int{}`},
+ {"%#v", array, `[5]int{1, 2, 3, 4, 5}`},
+ {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`},
+ {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
+ {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
+ {"%#v", map[int]byte(nil), `map[int]uint8(nil)`},
+ {"%#v", map[int]byte{}, `map[int]uint8{}`},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -400,6 +424,7 @@ var fmttests = []struct {
{"p0=%p", new(int), "p0=0xPTR"},
{"p1=%s", &pValue, "p1=String(p)"}, // String method...
{"p2=%p", &pValue, "p2=0xPTR"}, // ... not called with %p
+ {"p3=%p", (*int)(nil), "p3=0x0"},
{"p4=%#p", new(int), "p4=PTR"},
// %p on non-pointers
@@ -408,6 +433,18 @@ var fmttests = []struct {
{"%p", make([]int, 1), "0xPTR"},
{"%p", 27, "%!p(int=27)"}, // not a pointer at all
+ // %q on pointers
+ {"%q", (*int)(nil), "%!q(*int=<nil>)"},
+ {"%q", new(int), "%!q(*int=0xPTR)"},
+
+ // %v on pointers formats 0 as <nil>
+ {"%v", (*int)(nil), "<nil>"},
+ {"%v", new(int), "0xPTR"},
+
+ // %d on Stringer should give integer if possible
+ {"%s", time.Time{}.Month(), "January"},
+ {"%d", time.Time{}.Month(), "1"},
+
// erroneous things
{"%s %", "hello", "hello %!(NOVERB)"},
{"%s %.2", "hello", "hello %!(NOVERB)"},
@@ -416,6 +453,14 @@ var fmttests = []struct {
{"%s", nil, "%!s(<nil>)"},
{"%T", nil, "<nil>"},
{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+
+ // The "<nil>" show up because maps are printed by
+ // first obtaining a list of keys and then looking up
+ // each key. Since NaNs can be map keys but cannot
+ // be fetched directly, the lookup fails and returns a
+ // zero reflect.Value, which formats as <nil>.
+ // This test is just to check that it shows the two NaNs at all.
+ {"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
}
func TestSprintf(t *testing.T) {
@@ -473,47 +518,53 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) {
}
}
-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)
+func BenchmarkSprintfFloat(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%g", 5.23184)
}
- 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)
+}
+
+var mallocBuf bytes.Buffer
+
+var mallocTest = []struct {
+ count int
+ desc string
+ fn func()
+}{
+ {0, `Sprintf("")`, func() { Sprintf("") }},
+ {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
+ {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
+ {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
+ {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
+ // For %g we use a float32, not float64, to guarantee passing the argument
+ // does not need to allocate memory to store the result in a pointer-sized word.
+ {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }},
+ {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+ {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+}
+
+var _ bytes.Buffer
+
+func TestCountMallocs(t *testing.T) {
+ for _, mt := range mallocTest {
+ const N = 100
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ mallocs := 0 - memstats.Mallocs
+ for i := 0; i < N; i++ {
+ mt.fn()
+ }
+ runtime.ReadMemStats(memstats)
+ mallocs += memstats.Mallocs
+ if mallocs/N > uint64(mt.count) {
+ t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
+ }
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
}
type flagPrinter struct{}
-func (*flagPrinter) Format(f State, c int) {
+func (*flagPrinter) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
@@ -713,7 +764,7 @@ type PanicF struct {
}
// Value receiver.
-func (p PanicF) Format(f State, c int) {
+func (p PanicF) Format(f State, c rune) {
panic(p.message)
}
@@ -723,9 +774,9 @@ var panictests = []struct {
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)"},
+ {"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%s", Panic{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", Panic{3}, "%s(PANIC=3)"},
// GoString
{"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
{"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
@@ -744,3 +795,47 @@ func TestPanics(t *testing.T) {
}
}
}
+
+// Test that erroneous String routine doesn't cause fatal recursion.
+var recurCount = 0
+
+type Recur struct {
+ i int
+ failed *bool
+}
+
+func (r Recur) String() string {
+ if recurCount++; recurCount > 10 {
+ *r.failed = true
+ return "FAIL"
+ }
+ // This will call badVerb. Before the fix, that would cause us to recur into
+ // this routine to print %!p(value). Now we don't call the user's method
+ // during an error.
+ return Sprintf("recur@%p value: %d", r, r.i)
+}
+
+func TestBadVerbRecursion(t *testing.T) {
+ failed := false
+ r := Recur{3, &failed}
+ Sprintf("recur@%p value: %d\n", &r, r.i)
+ if failed {
+ t.Error("fail with pointer")
+ }
+ failed = false
+ r = Recur{4, &failed}
+ Sprintf("recur@%p, value: %d\n", r, r.i)
+ if failed {
+ t.Error("fail with value")
+ }
+}
+
+func TestIsSpace(t *testing.T) {
+ // This tests the internal isSpace function.
+ // IsSpace = isSpace is defined in export_test.go.
+ for i := rune(0); i <= unicode.MaxRune; i++ {
+ if IsSpace(i) != unicode.IsSpace(i) {
+ t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))
+ }
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 24b15a286..2186f334b 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -5,10 +5,8 @@
package fmt
import (
- "bytes"
"strconv"
- "unicode"
- "utf8"
+ "unicode/utf8"
)
const (
@@ -36,10 +34,10 @@ func init() {
}
// A fmt is the raw formatter used by Printf etc.
-// It prints into a bytes.Buffer that must be set up externally.
+// It prints into a buffer that must be set up separately.
type fmt struct {
intbuf [nByte]byte
- buf *bytes.Buffer
+ buf *buffer
// width, precision
wid int
prec int
@@ -69,7 +67,7 @@ func (f *fmt) clearflags() {
f.zero = false
}
-func (f *fmt) init(buf *bytes.Buffer) {
+func (f *fmt) init(buf *buffer) {
f.buf = buf
f.clearflags()
}
@@ -154,12 +152,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
return i - 1
}
+var (
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+)
+
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
- f.padString("true")
+ f.pad(trueBytes)
} else {
- f.padString("false")
+ f.pad(falseBytes)
}
}
@@ -242,8 +245,8 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
}
// 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))
+ if f.unicode && f.uniQuote && a >= 0 && a <= utf8.MaxRune && strconv.IsPrint(rune(a)) {
+ runeWidth := utf8.RuneLen(rune(a))
width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
i -= width
@@ -253,7 +256,7 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
j++
buf[j] = '\''
j++
- utf8.EncodeRune(buf[j:], int(a))
+ utf8.EncodeRune(buf[j:], rune(a))
j += runeWidth
buf[j] = '\''
}
@@ -283,31 +286,17 @@ func (f *fmt) fmt_s(s string) {
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s string) {
- t := ""
+func (f *fmt) fmt_sx(s, digits string) {
+ // TODO: Avoid buffer by pre-padding.
+ var b []byte
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
- t += " "
+ b = append(b, ' ')
}
v := s[i]
- t += string(ldigits[v>>4])
- t += string(ldigits[v&0xF])
+ b = append(b, digits[v>>4], digits[v&0xF])
}
- f.padString(t)
-}
-
-// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sX(s string) {
- t := ""
- for i := 0; i < len(s); i++ {
- if i > 0 && f.space {
- t += " "
- }
- v := s[i]
- t += string(udigits[v>>4])
- t += string(udigits[v&0xF])
- }
- f.padString(t)
+ f.pad(b)
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
@@ -329,13 +318,13 @@ func (f *fmt) fmt_q(s string) {
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmt_qc(c int64) {
- var quoted string
+ var quoted []byte
if f.plus {
- quoted = strconv.QuoteRuneToASCII(int(c))
+ quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
} else {
- quoted = strconv.QuoteRune(int(c))
+ quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
}
- f.padString(quoted)
+ f.pad(quoted)
}
// floating-point
@@ -347,60 +336,73 @@ func doPrec(f *fmt, def int) int {
return def
}
-// Add a plus sign or space to the floating-point string representation if missing and required.
-func (f *fmt) plusSpace(s string) {
- if s[0] != '-' {
+// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
+func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
+ // We leave one byte at the beginning of f.intbuf for a sign if needed,
+ // and make it a space, which we might be able to use.
+ f.intbuf[0] = ' '
+ slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ // Add a plus sign or space to the floating-point string representation if missing and required.
+ // The formatted number starts at slice[1].
+ switch slice[1] {
+ case '-', '+':
+ // We're set; drop the leading space.
+ slice = slice[1:]
+ default:
+ // There's no sign, but we might need one.
if f.plus {
- s = "+" + s
+ slice[0] = '+'
} else if f.space {
- s = " " + s
+ // space is already there
+ } else {
+ slice = slice[1:]
}
}
- f.padString(s)
+ f.pad(slice)
}
// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
+func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
+func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
+func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
+func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
+func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
+func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
+func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
+func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
+func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
+func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
+func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
-func (f *fmt) fmt_c64(v complex64, verb int) {
+func (f *fmt) fmt_c64(v complex64, verb rune) {
f.buf.WriteByte('(')
r := real(v)
for i := 0; ; i++ {
@@ -426,7 +428,7 @@ func (f *fmt) fmt_c64(v complex64, verb int) {
}
// fmt_c128 formats a complex128 according to the verb.
-func (f *fmt) fmt_c128(v complex128, verb int) {
+func (f *fmt) fmt_c128(v complex128, verb rune) {
f.buf.WriteByte('(')
r := real(v)
for i := 0; ; i++ {
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 136aebd33..13438243c 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -5,12 +5,12 @@
package fmt
import (
- "bytes"
+ "errors"
"io"
"os"
"reflect"
- "unicode"
- "utf8"
+ "sync"
+ "unicode/utf8"
)
// Some constants in the form of bytes, to avoid string overhead.
@@ -36,7 +36,7 @@ var (
// the flags and options for the operand's format specifier.
type State interface {
// Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err os.Error)
+ Write(b []byte) (ret int, err error)
// Width returns the value of the width option and whether it has been set.
Width() (wid int, ok bool)
// Precision returns the value of the precision option and whether it has been set.
@@ -50,7 +50,7 @@ type State interface {
// The implementation of Format may call Sprintf or Fprintf(f) etc.
// to generate its output.
type Formatter interface {
- Format(f State, c int)
+ Format(f State, c rune)
}
// Stringer is implemented by any value that has a String method,
@@ -69,43 +69,86 @@ type GoStringer interface {
GoString() string
}
+// Use simple []byte instead of bytes.Buffer to avoid large dependency.
+type buffer []byte
+
+func (b *buffer) Write(p []byte) (n int, err error) {
+ *b = append(*b, p...)
+ return len(p), nil
+}
+
+func (b *buffer) WriteString(s string) (n int, err error) {
+ *b = append(*b, s...)
+ return len(s), nil
+}
+
+func (b *buffer) WriteByte(c byte) error {
+ *b = append(*b, c)
+ return nil
+}
+
+func (bp *buffer) WriteRune(r rune) error {
+ if r < utf8.RuneSelf {
+ *bp = append(*bp, byte(r))
+ return nil
+ }
+
+ b := *bp
+ n := len(b)
+ for n+utf8.UTFMax > cap(b) {
+ b = append(b, 0)
+ }
+ w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
+ *bp = b[:n+w]
+ return nil
+}
+
type pp struct {
n int
panicking bool
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ erroring bool // printing an error condition
+ buf buffer
+ // field holds the current item, as an interface{}.
+ field interface{}
+ // value holds the current item, as a reflect.Value, and will be
+ // the zero Value if the item has not been reflected.
+ value reflect.Value
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
}
// A cache holds a set of reusable objects.
-// The buffered channel holds the currently available objects.
+// The slice is a stack (LIFO).
// If more are needed, the cache creates them by calling new.
type cache struct {
- saved chan interface{}
+ mu sync.Mutex
+ saved []interface{}
new func() interface{}
}
func (c *cache) put(x interface{}) {
- select {
- case c.saved <- x:
- // saved in cache
- default:
- // discard
+ c.mu.Lock()
+ if len(c.saved) < cap(c.saved) {
+ c.saved = append(c.saved, x)
}
+ c.mu.Unlock()
}
func (c *cache) get() interface{} {
- select {
- case x := <-c.saved:
- return x // reused from cache
- default:
+ c.mu.Lock()
+ n := len(c.saved)
+ if n == 0 {
+ c.mu.Unlock()
return c.new()
}
- panic("not reached")
+ x := c.saved[n-1]
+ c.saved = c.saved[0 : n-1]
+ c.mu.Unlock()
+ return x
}
func newCache(f func() interface{}) *cache {
- return &cache{make(chan interface{}, 100), f}
+ return &cache{saved: make([]interface{}, 0, 100), new: f}
}
var ppFree = newCache(func() interface{} { return new(pp) })
@@ -114,6 +157,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
func newPrinter() *pp {
p := ppFree.get().(*pp)
p.panicking = false
+ p.erroring = false
p.fmt.init(&p.buf)
return p
}
@@ -121,10 +165,12 @@ func newPrinter() *pp {
// Save used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
// Don't hold on to pp structs with large buffers.
- if cap(p.buf.Bytes()) > 1024 {
+ if cap(p.buf) > 1024 {
return
}
- p.buf.Reset()
+ p.buf = p.buf[:0]
+ p.field = nil
+ p.value = reflect.Value{}
ppFree.put(p)
}
@@ -148,13 +194,13 @@ func (p *pp) Flag(b int) bool {
return false
}
-func (p *pp) add(c int) {
+func (p *pp) add(c rune) {
p.buf.WriteRune(c)
}
// Implement Write so we can call Fprintf on a pp (through State), for
// recursive use in custom verbs.
-func (p *pp) Write(b []byte) (ret int, err os.Error) {
+func (p *pp) Write(b []byte) (ret int, err error) {
return p.buf.Write(b)
}
@@ -162,17 +208,17 @@ 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, err os.Error) {
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
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, err os.Error) {
+func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
@@ -180,15 +226,15 @@ func Printf(format string, a ...interface{}) (n int, err os.Error) {
func Sprintf(format string, a ...interface{}) string {
p := newPrinter()
p.doPrintf(format, a)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
// Errorf formats according to a format specifier and returns the string
-// converted to an os.ErrorString, which satisfies the os.Error interface.
-func Errorf(format string, a ...interface{}) os.Error {
- return os.NewError(Sprintf(format, a...))
+// as a value that satisfies error.
+func Errorf(format string, a ...interface{}) error {
+ return errors.New(Sprintf(format, a...))
}
// These routines do not take a format string
@@ -196,10 +242,10 @@ 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, err os.Error) {
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, false, false)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
return int(n64), err
}
@@ -207,7 +253,7 @@ func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
// Print formats using the default formats for its operands and writes to standard output.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, err os.Error) {
+func Print(a ...interface{}) (n int, err error) {
return Fprint(os.Stdout, a...)
}
@@ -216,7 +262,7 @@ func Print(a ...interface{}) (n int, err os.Error) {
func Sprint(a ...interface{}) string {
p := newPrinter()
p.doPrint(a, false, false)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
@@ -228,10 +274,10 @@ 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, err os.Error) {
+func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, true, true)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
return int(n64), err
}
@@ -239,7 +285,7 @@ func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, err os.Error) {
+func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
@@ -248,7 +294,7 @@ func Println(a ...interface{}) (n int, err os.Error) {
func Sprintln(a ...interface{}) string {
p := newPrinter()
p.doPrint(a, true, true)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
@@ -286,46 +332,48 @@ func (p *pp) unknownType(v interface{}) {
p.buf.WriteByte('?')
}
-func (p *pp) badVerb(verb int, val interface{}, val1 reflect.Value) {
+func (p *pp) badVerb(verb rune) {
+ p.erroring = true
p.add('%')
p.add('!')
p.add(verb)
p.add('(')
switch {
- case val != nil:
- p.buf.WriteString(reflect.TypeOf(val).String())
+ case p.field != nil:
+ p.buf.WriteString(reflect.TypeOf(p.field).String())
p.add('=')
- p.printField(val, 'v', false, false, 0)
- case val1.IsValid():
- p.buf.WriteString(val1.Type().String())
+ p.printField(p.field, 'v', false, false, 0)
+ case p.value.IsValid():
+ p.buf.WriteString(p.value.Type().String())
p.add('=')
- p.printValue(val1, 'v', false, false, 0)
+ p.printValue(p.value, 'v', false, false, 0)
default:
p.buf.Write(nilAngleBytes)
}
p.add(')')
+ p.erroring = false
}
-func (p *pp) fmtBool(v bool, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtBool(v bool, verb rune) {
switch verb {
case 't', 'v':
p.fmt.fmt_boolean(v)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
// fmtC formats a rune for the 'c' format.
func (p *pp) fmtC(c int64) {
- rune := int(c) // Check for overflow.
- if int64(rune) != c {
- rune = utf8.RuneError
+ r := rune(c) // Check for overflow.
+ if int64(r) != c {
+ r = utf8.RuneError
}
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
p.fmt.pad(p.runeBuf[0:w])
}
-func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtInt64(v int64, verb rune) {
switch verb {
case 'b':
p.fmt.integer(v, 2, signed, ldigits)
@@ -336,10 +384,10 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value
case 'o':
p.fmt.integer(v, 8, signed, ldigits)
case 'q':
- if 0 <= v && v <= unicode.MaxRune {
+ if 0 <= v && v <= utf8.MaxRune {
p.fmt.fmt_qc(v)
} else {
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
@@ -348,7 +396,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}, value1 reflect.Value
case 'X':
p.fmt.integer(v, 16, signed, udigits)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
@@ -383,7 +431,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.sharp = sharp
}
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
@@ -400,10 +448,10 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, val
case 'o':
p.fmt.integer(int64(v), 8, unsigned, ldigits)
case 'q':
- if 0 <= v && v <= unicode.MaxRune {
+ if 0 <= v && v <= utf8.MaxRune {
p.fmt.fmt_qc(int64(v))
} else {
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
@@ -412,11 +460,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}, val
case 'U':
p.fmtUnicode(int64(v))
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtFloat32(v float32, verb rune) {
switch verb {
case 'b':
p.fmt.fmt_fb32(v)
@@ -431,11 +479,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}, value1 reflect.V
case 'G':
p.fmt.fmt_G32(v)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtFloat64(v float64, verb rune) {
switch verb {
case 'b':
p.fmt.fmt_fb64(v)
@@ -450,33 +498,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}, value1 reflect.V
case 'G':
p.fmt.fmt_G64(v)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtComplex64(v complex64, verb rune) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c64(v, verb)
case 'v':
p.fmt.fmt_c64(v, 'g')
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtComplex128(v complex128, verb rune) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c128(v, verb)
case 'v':
p.fmt.fmt_c128(v, 'g')
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
switch verb {
case 'v':
if goSyntax {
@@ -487,17 +535,17 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}, val
case 's':
p.fmt.fmt_s(v)
case 'x':
- p.fmt.fmt_sx(v)
+ p.fmt.fmt_sx(v, ldigits)
case 'X':
- p.fmt.fmt_sX(v)
+ p.fmt.fmt_sx(v, udigits)
case 'q':
p.fmt.fmt_q(v)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}, value1 reflect.Value) {
+func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
if verb == 'v' || verb == 'd' {
if goSyntax {
p.buf.Write(bytesBytes)
@@ -526,25 +574,34 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
case 's':
p.fmt.fmt_s(s)
case 'x':
- p.fmt.fmt_sx(s)
+ p.fmt.fmt_sx(s, ldigits)
case 'X':
- p.fmt.fmt_sX(s)
+ p.fmt.fmt_sx(s, udigits)
case 'q':
p.fmt.fmt_q(s)
default:
- p.badVerb(verb, value, value1)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
+ switch verb {
+ case 'p', 'v', 'b', 'd', 'o', 'x', 'X':
+ // ok
+ default:
+ p.badVerb(verb)
+ return
+ }
+
var u uintptr
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
u = value.Pointer()
default:
- p.badVerb(verb, field, value)
+ p.badVerb(verb)
return
}
+
if goSyntax {
p.add('(')
p.buf.WriteString(value.Type().String())
@@ -556,6 +613,8 @@ func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSynt
p.fmt0x64(uint64(u), true)
}
p.add(')')
+ } else if verb == 'v' && u == 0 {
+ p.buf.Write(nilAngleBytes)
} else {
p.fmt0x64(uint64(u), !p.fmt.sharp)
}
@@ -568,12 +627,12 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
-func (p *pp) catchPanic(val interface{}, verb int) {
+func (p *pp) catchPanic(field interface{}, verb rune) {
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() {
+ if v := reflect.ValueOf(field); v.Kind() == reflect.Ptr && v.IsNil() {
p.buf.Write(nilAngleBytes)
return
}
@@ -593,12 +652,15 @@ func (p *pp) catchPanic(val interface{}, verb int) {
}
}
-func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString, handled bool) {
+func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) {
+ if p.erroring {
+ return
+ }
// Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
+ if formatter, ok := p.field.(Formatter); ok {
handled = true
wasString = false
- defer p.catchPanic(field, verb)
+ defer p.catchPanic(p.field, verb)
formatter.Format(p, verb)
return
}
@@ -610,38 +672,57 @@ func (p *pp) handleMethods(field interface{}, verb int, plus, goSyntax bool, dep
// If we're doing Go syntax and the field knows how to supply it, take care of it now.
if goSyntax {
p.fmt.sharp = false
- if stringer, ok := field.(GoStringer); ok {
+ if stringer, ok := p.field.(GoStringer); ok {
wasString = false
handled = true
- defer p.catchPanic(field, verb)
+ defer p.catchPanic(p.field, verb)
// Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false, field, reflect.Value{})
+ p.fmtString(stringer.GoString(), 's', false)
return
}
} else {
- // Is it a Stringer?
- if stringer, ok := field.(Stringer); ok {
- wasString = false
- handled = true
- defer p.catchPanic(field, verb)
- p.printField(stringer.String(), verb, plus, false, depth)
- return
+ // If a string is acceptable according to the format, see if
+ // the value satisfies one of the string-valued interfaces.
+ // Println etc. set verb to %v, which is "stringable".
+ switch verb {
+ case 'v', 's', 'x', 'X', 'q':
+ // Is it an error or Stringer?
+ // The duplication in the bodies is necessary:
+ // setting wasString and handled, and deferring catchPanic,
+ // must happen before calling the method.
+ switch v := p.field.(type) {
+ case error:
+ wasString = false
+ handled = true
+ defer p.catchPanic(p.field, verb)
+ p.printField(v.Error(), verb, plus, false, depth)
+ return
+
+ case Stringer:
+ wasString = false
+ handled = true
+ defer p.catchPanic(p.field, verb)
+ p.printField(v.String(), verb, plus, false, depth)
+ return
+ }
}
}
handled = false
return
}
-func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes)
} else {
- p.badVerb(verb, field, reflect.Value{})
+ p.badVerb(verb)
}
return false
}
+ p.field = field
+ p.value = reflect.Value{}
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
@@ -649,83 +730,69 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
p.printField(reflect.TypeOf(field).String(), 's', false, false, 0)
return false
case 'p':
- p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
+ p.fmtPointer(reflect.ValueOf(field), verb, goSyntax)
return false
}
- if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled {
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
return wasString
}
// Some types can be done without reflection.
switch f := field.(type) {
case bool:
- p.fmtBool(f, verb, field, reflect.Value{})
- return false
+ p.fmtBool(f, verb)
case float32:
- p.fmtFloat32(f, verb, field, reflect.Value{})
- return false
+ p.fmtFloat32(f, verb)
case float64:
- p.fmtFloat64(f, verb, field, reflect.Value{})
- return false
+ p.fmtFloat64(f, verb)
case complex64:
- p.fmtComplex64(complex64(f), verb, field, reflect.Value{})
- return false
+ p.fmtComplex64(complex64(f), verb)
case complex128:
- p.fmtComplex128(f, verb, field, reflect.Value{})
- return false
+ p.fmtComplex128(f, verb)
case int:
- p.fmtInt64(int64(f), verb, field, reflect.Value{})
- return false
+ p.fmtInt64(int64(f), verb)
case int8:
- p.fmtInt64(int64(f), verb, field, reflect.Value{})
- return false
+ p.fmtInt64(int64(f), verb)
case int16:
- p.fmtInt64(int64(f), verb, field, reflect.Value{})
- return false
+ p.fmtInt64(int64(f), verb)
case int32:
- p.fmtInt64(int64(f), verb, field, reflect.Value{})
- return false
+ p.fmtInt64(int64(f), verb)
case int64:
- p.fmtInt64(f, verb, field, reflect.Value{})
- return false
+ p.fmtInt64(f, verb)
case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint64:
- p.fmtUint64(f, verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(f, verb, goSyntax)
case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field, reflect.Value{})
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case string:
- p.fmtString(f, verb, goSyntax, field, reflect.Value{})
- return verb == 's' || verb == 'v'
+ p.fmtString(f, verb, goSyntax)
+ wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field, reflect.Value{})
- return verb == 's'
+ p.fmtBytes(f, verb, goSyntax, depth)
+ wasString = verb == 's'
+ default:
+ // Need to use reflection
+ return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
}
-
- // Need to use reflection
- return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
+ p.field = nil
+ return
}
// printValue is like printField but starts with a reflect value, not an interface{} value.
-func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
if !value.IsValid() {
if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes)
} else {
- p.badVerb(verb, nil, value)
+ p.badVerb(verb)
}
return false
}
@@ -737,17 +804,17 @@ func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, dept
p.printField(value.Type().String(), 's', false, false, 0)
return false
case 'p':
- p.fmtPointer(nil, value, verb, goSyntax)
+ p.fmtPointer(value, verb, goSyntax)
return false
}
// Handle values with special methods.
// Call always, even when field == nil, because handleMethods clears p.fmt.plus for us.
- var field interface{}
+ p.field = nil // Make sure it's cleared, for safety.
if value.CanInterface() {
- field = value.Interface()
+ p.field = value.Interface()
}
- if wasString, handled := p.handleMethods(field, verb, plus, goSyntax, depth); handled {
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
return wasString
}
@@ -756,32 +823,38 @@ func (p *pp) printValue(value reflect.Value, verb int, plus, goSyntax bool, dept
// printReflectValue is the fallback for both printField and printValue.
// It uses reflect to print the value.
-func (p *pp) printReflectValue(value reflect.Value, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+ oldValue := p.value
+ p.value = value
BigSwitch:
switch f := value; f.Kind() {
case reflect.Bool:
- p.fmtBool(f.Bool(), verb, nil, value)
+ p.fmtBool(f.Bool(), verb)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, nil, value)
+ p.fmtInt64(f.Int(), verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(uint64(f.Uint()), verb, goSyntax, nil, value)
+ p.fmtUint64(uint64(f.Uint()), verb, goSyntax)
case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb, nil, value)
+ p.fmtFloat32(float32(f.Float()), verb)
} else {
- p.fmtFloat64(float64(f.Float()), verb, nil, value)
+ p.fmtFloat64(float64(f.Float()), verb)
}
case reflect.Complex64, reflect.Complex128:
if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb, nil, value)
+ p.fmtComplex64(complex64(f.Complex()), verb)
} else {
- p.fmtComplex128(complex128(f.Complex()), verb, nil, value)
+ p.fmtComplex128(complex128(f.Complex()), verb)
}
case reflect.String:
- p.fmtString(f.String(), verb, goSyntax, nil, value)
+ p.fmtString(f.String(), verb, goSyntax)
case reflect.Map:
if goSyntax {
p.buf.WriteString(f.Type().String())
+ if f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.Write(mapBytes)
@@ -832,13 +905,13 @@ BigSwitch:
value := f.Elem()
if !value.IsValid() {
if goSyntax {
- p.buf.WriteString(value.Type().String())
+ p.buf.WriteString(f.Type().String())
p.buf.Write(nilParenBytes)
} else {
p.buf.Write(nilAngleBytes)
}
} else {
- return p.printValue(value, verb, plus, goSyntax, depth+1)
+ wasString = p.printValue(value, verb, plus, goSyntax, depth+1)
}
case reflect.Array, reflect.Slice:
// Byte slices are special.
@@ -854,11 +927,16 @@ BigSwitch:
for i := range bytes {
bytes[i] = byte(f.Index(i).Uint())
}
- p.fmtBytes(bytes, verb, goSyntax, depth, nil, value)
- return verb == 's'
+ p.fmtBytes(bytes, verb, goSyntax, depth)
+ wasString = verb == 's'
+ break
}
if goSyntax {
p.buf.WriteString(value.Type().String())
+ if f.Kind() == reflect.Slice && f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
@@ -894,30 +972,14 @@ BigSwitch:
break BigSwitch
}
}
- if goSyntax {
- p.buf.WriteByte('(')
- p.buf.WriteString(value.Type().String())
- p.buf.WriteByte(')')
- p.buf.WriteByte('(')
- if v == 0 {
- p.buf.Write(nilBytes)
- } else {
- p.fmt0x64(uint64(v), true)
- }
- p.buf.WriteByte(')')
- break
- }
- if v == 0 {
- p.buf.Write(nilAngleBytes)
- break
- }
- p.fmt0x64(uint64(v), true)
+ fallthrough
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(nil, value, verb, goSyntax)
+ p.fmtPointer(value, verb, goSyntax)
default:
p.unknownType(f)
}
- return false
+ p.value = oldValue
+ return wasString
}
// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 259451d02..0b3e04069 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -5,15 +5,13 @@
package fmt
import (
- "bytes"
+ "errors"
"io"
"math"
"os"
"reflect"
"strconv"
- "strings"
- "unicode"
- "utf8"
+ "unicode/utf8"
)
// runeUnreader is the interface to something that can unread runes.
@@ -21,7 +19,7 @@ import (
// a local buffer will be used to back up the input, but its contents
// will be lost when Scan returns.
type runeUnreader interface {
- UnreadRune() os.Error
+ UnreadRune() error
}
// ScanState represents the scanner state passed to custom scanners.
@@ -32,9 +30,9 @@ type ScanState interface {
// If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
// return EOF after returning the first '\n' or when reading beyond
// the specified width.
- ReadRune() (rune int, size int, err os.Error)
+ ReadRune() (r rune, size int, err error)
// UnreadRune causes the next call to ReadRune to return the same rune.
- UnreadRune() os.Error
+ UnreadRune() 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.
@@ -47,14 +45,14 @@ type ScanState interface {
// EOF. The returned slice points to shared data that may be overwritten
// by the next call to Token, a call to a Scan function using the ScanState
// as input, or when the calling Scan method returns.
- Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
+ Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
// Width returns the value of the width option and whether it has been set.
// The unit is Unicode code points.
Width() (wid int, ok bool)
// Because ReadRune is implemented by the interface, Read should never be
// called by the scanning routines and a valid implementation of
// ScanState may choose always to return an error from Read.
- Read(buf []byte) (n int, err os.Error)
+ Read(buf []byte) (n int, err error)
}
// Scanner is implemented by any value that has a Scan method, which scans
@@ -62,56 +60,67 @@ type ScanState interface {
// receiver, which must be a pointer to be useful. The Scan method is called
// for any argument to Scan, Scanf, or Scanln that implements it.
type Scanner interface {
- Scan(state ScanState, verb int) os.Error
+ Scan(state ScanState, verb rune) error
}
// Scan scans text read from standard input, storing successive
// space-separated values into successive arguments. Newlines count
// as space. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
-func Scan(a ...interface{}) (n int, err os.Error) {
+func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
}
// Scanln is similar to Scan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Scanln(a ...interface{}) (n int, err os.Error) {
+func Scanln(a ...interface{}) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
// the format. It returns the number of items successfully scanned.
-func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
+type stringReader string
+
+func (r *stringReader) Read(b []byte) (n int, err error) {
+ n = copy(b, *r)
+ *r = (*r)[n:]
+ if n == 0 {
+ err = io.EOF
+ }
+ return
+}
+
// Sscan scans the argument string, storing successive space-separated
// values into successive arguments. Newlines count as space. It
// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
-func Sscan(str string, a ...interface{}) (n int, err os.Error) {
- return Fscan(strings.NewReader(str), a...)
+func Sscan(str string, a ...interface{}) (n int, err error) {
+ return Fscan((*stringReader)(&str), a...)
}
// Sscanln is similar to Sscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
- return Fscanln(strings.NewReader(str), a...)
+func Sscanln(str string, a ...interface{}) (n int, err error) {
+ return Fscanln((*stringReader)(&str), a...)
}
// Sscanf scans the argument string, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
-func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(strings.NewReader(str), format, a...)
+func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
+ return Fscanf((*stringReader)(&str), format, a...)
}
// Fscan scans text read from r, storing successive space-separated
// values into successive arguments. Newlines count as space. It
// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
-func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, true, false)
n, err = s.doScan(a)
s.free(old)
@@ -120,7 +129,7 @@ func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
// Fscanln is similar to Fscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, false, true)
n, err = s.doScan(a)
s.free(old)
@@ -130,7 +139,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
// Fscanf scans text read from r, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
-func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
s, old := newScanState(r, false, false)
n, err = s.doScanf(format, a)
s.free(old)
@@ -140,7 +149,7 @@ func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error)
// scanError represents an error generated by the scanning software.
// It's used as a unique signature to identify such errors when recovering.
type scanError struct {
- err os.Error
+ err error
}
const eof = -1
@@ -148,9 +157,9 @@ const eof = -1
// ss is the internal implementation of ScanState.
type ss struct {
rr io.RuneReader // where to read input
- buf bytes.Buffer // token accumulator
- peekRune int // one-rune lookahead
- prevRune int // last rune returned by ReadRune
+ buf buffer // token accumulator
+ peekRune rune // one-rune lookahead
+ prevRune rune // last rune returned by ReadRune
count int // runes consumed so far.
atEOF bool // already read EOF
ssave
@@ -170,29 +179,29 @@ type ssave struct {
// The Read method is only in ScanState so that ScanState
// 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.NewError("ScanState's Read should not be called. Use ReadRune")
+func (s *ss) Read(buf []byte) (n int, err error) {
+ return 0, errors.New("ScanState's Read should not be called. Use ReadRune")
}
-func (s *ss) ReadRune() (rune int, size int, err os.Error) {
+func (s *ss) ReadRune() (r rune, size int, err error) {
if s.peekRune >= 0 {
s.count++
- rune = s.peekRune
- size = utf8.RuneLen(rune)
- s.prevRune = rune
+ r = s.peekRune
+ size = utf8.RuneLen(r)
+ s.prevRune = r
s.peekRune = -1
return
}
if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
- err = os.EOF
+ err = io.EOF
return
}
- rune, size, err = s.rr.ReadRune()
+ r, size, err = s.rr.ReadRune()
if err == nil {
s.count++
- s.prevRune = rune
- } else if err == os.EOF {
+ s.prevRune = r
+ } else if err == io.EOF {
s.atEOF = true
}
return
@@ -207,10 +216,10 @@ func (s *ss) Width() (wid int, ok bool) {
// The public method returns an error; this private one panics.
// If getRune reaches EOF, the return value is EOF (-1).
-func (s *ss) getRune() (rune int) {
- rune, _, err := s.ReadRune()
+func (s *ss) getRune() (r rune) {
+ r, _, err := s.ReadRune()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
return eof
}
s.error(err)
@@ -218,18 +227,18 @@ func (s *ss) getRune() (rune int) {
return
}
-// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// mustReadRune turns io.EOF into a panic(io.ErrUnexpectedEOF).
// It is called in cases such as string scanning where an EOF is a
// syntax error.
-func (s *ss) mustReadRune() (rune int) {
- rune = s.getRune()
- if rune == eof {
+func (s *ss) mustReadRune() (r rune) {
+ r = s.getRune()
+ if r == eof {
s.error(io.ErrUnexpectedEOF)
}
return
}
-func (s *ss) UnreadRune() os.Error {
+func (s *ss) UnreadRune() error {
if u, ok := s.rr.(runeUnreader); ok {
u.UnreadRune()
} else {
@@ -240,15 +249,15 @@ func (s *ss) UnreadRune() os.Error {
return nil
}
-func (s *ss) error(err os.Error) {
+func (s *ss) error(err error) {
panic(scanError{err})
}
func (s *ss) errorString(err string) {
- panic(scanError{os.NewError(err)})
+ panic(scanError{errors.New(err)})
}
-func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
+func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) {
defer func() {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok {
@@ -261,14 +270,46 @@ func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error)
if f == nil {
f = notSpace
}
- s.buf.Reset()
+ s.buf = s.buf[:0]
tok = s.token(skipSpace, f)
return
}
+// space is a copy of the unicode.White_Space ranges,
+// to avoid depending on package unicode.
+var space = [][2]uint16{
+ {0x0009, 0x000d},
+ {0x0020, 0x0020},
+ {0x0085, 0x0085},
+ {0x00a0, 0x00a0},
+ {0x1680, 0x1680},
+ {0x180e, 0x180e},
+ {0x2000, 0x200a},
+ {0x2028, 0x2029},
+ {0x202f, 0x202f},
+ {0x205f, 0x205f},
+ {0x3000, 0x3000},
+}
+
+func isSpace(r rune) bool {
+ if r >= 1<<16 {
+ return false
+ }
+ rx := uint16(r)
+ for _, rng := range space {
+ if rx < rng[0] {
+ return false
+ }
+ if rx <= rng[1] {
+ return true
+ }
+ }
+ return false
+}
+
// notSpace is the default scanning function used in Token.
-func notSpace(r int) bool {
- return !unicode.IsSpace(r)
+func notSpace(r rune) bool {
+ return !isSpace(r)
}
// skipSpace provides Scan() methods the ability to skip space and newline characters
@@ -289,7 +330,7 @@ type readRune struct {
// readByte returns the next byte from the input, which may be
// left over from a previous read if the UTF-8 was ill-formed.
-func (r *readRune) readByte() (b byte, err os.Error) {
+func (r *readRune) readByte() (b byte, err error) {
if r.pending > 0 {
b = r.pendBuf[0]
copy(r.pendBuf[0:], r.pendBuf[1:])
@@ -308,27 +349,27 @@ func (r *readRune) unread(buf []byte) {
// ReadRune returns the next UTF-8 encoded code point from the
// io.Reader inside r.
-func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+func (r *readRune) ReadRune() (rr rune, size int, err error) {
r.buf[0], err = r.readByte()
if err != nil {
return 0, 0, err
}
if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
- rune = int(r.buf[0])
+ rr = rune(r.buf[0])
return
}
var n int
for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
r.buf[n], err = r.readByte()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = nil
break
}
return
}
}
- rune, size = utf8.DecodeRune(r.buf[0:n])
+ rr, size = utf8.DecodeRune(r.buf[0:n])
if size < n { // an error
r.unread(r.buf[size:n])
}
@@ -365,6 +406,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
s.fieldLimit = hugeWid
s.maxWid = hugeWid
s.validSave = true
+ s.count = 0
return
}
@@ -376,10 +418,10 @@ func (s *ss) free(old ssave) {
return
}
// Don't hold on to ss structs with large buffers.
- if cap(s.buf.Bytes()) > 1024 {
+ if cap(s.buf) > 1024 {
return
}
- s.buf.Reset()
+ s.buf = s.buf[:0]
s.rr = nil
ssFree.put(s)
}
@@ -387,11 +429,11 @@ func (s *ss) free(old ssave) {
// skipSpace skips spaces and maybe newlines.
func (s *ss) skipSpace(stopAtNewline bool) {
for {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
return
}
- if rune == '\n' {
+ if r == '\n' {
if stopAtNewline {
break
}
@@ -401,7 +443,7 @@ func (s *ss) skipSpace(stopAtNewline bool) {
s.errorString("unexpected newline")
return
}
- if !unicode.IsSpace(rune) {
+ if !isSpace(r) {
s.UnreadRune()
break
}
@@ -411,23 +453,23 @@ 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.
-func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
if skipSpace {
s.skipSpace(false)
}
// read until white space or newline
for {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
break
}
- if !f(rune) {
+ if !f(r) {
s.UnreadRune()
break
}
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
- return s.buf.Bytes()
+ return s.buf
}
// typeError indicates that the type of the operand did not match the format
@@ -435,23 +477,32 @@ 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.NewError("syntax error scanning complex number")
-var boolError = os.NewError("syntax error scanning boolean")
+var complexError = errors.New("syntax error scanning complex number")
+var boolError = errors.New("syntax error scanning boolean")
+
+func indexRune(s string, r rune) int {
+ for i, c := range s {
+ if c == r {
+ return i
+ }
+ }
+ return -1
+}
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
func (s *ss) consume(ok string, accept bool) bool {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
return false
}
- if strings.IndexRune(ok, rune) >= 0 {
+ if indexRune(ok, r) >= 0 {
if accept {
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
return true
}
- if rune != eof && accept {
+ if r != eof && accept {
s.UnreadRune()
}
return false
@@ -459,17 +510,17 @@ func (s *ss) consume(ok string, accept bool) bool {
// peek reports whether the next character is in the ok string, without consuming it.
func (s *ss) peek(ok string) bool {
- rune := s.getRune()
- if rune != eof {
+ r := s.getRune()
+ if r != eof {
s.UnreadRune()
}
- return strings.IndexRune(ok, rune) >= 0
+ return indexRune(ok, r) >= 0
}
func (s *ss) notEOF() {
// Guarantee there is data to be read.
- if rune := s.getRune(); rune == eof {
- panic(os.EOF)
+ if r := s.getRune(); r == eof {
+ panic(io.EOF)
}
s.UnreadRune()
}
@@ -481,7 +532,7 @@ func (s *ss) accept(ok string) bool {
}
// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
-func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+func (s *ss) okVerb(verb rune, okVerbs, typ string) bool {
for _, v := range okVerbs {
if v == verb {
return true
@@ -492,7 +543,7 @@ 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 {
+func (s *ss) scanBool(verb rune) bool {
s.skipSpace(false)
s.notEOF()
if !s.okVerb(verb, "tv", "boolean") {
@@ -510,7 +561,7 @@ func (s *ss) scanBool(verb int) bool {
}
return true
case 'f', 'F':
- if s.accept("aL") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
+ if s.accept("aA") && (!s.accept("lL") || !s.accept("sS") || !s.accept("eE")) {
s.error(boolError)
}
return false
@@ -530,7 +581,7 @@ const (
)
// getBase returns the numeric base represented by the verb and its digit string.
-func (s *ss) getBase(verb int) (base int, digits string) {
+func (s *ss) getBase(verb rune) (base int, digits string) {
s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
base = 10
digits = decimalDigits
@@ -558,19 +609,19 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string {
}
for s.accept(digits) {
}
- return s.buf.String()
+ return string(s.buf)
}
// scanRune returns the next rune value in the input.
func (s *ss) scanRune(bitSize int) int64 {
s.notEOF()
- rune := int64(s.getRune())
+ r := int64(s.getRune())
n := uint(bitSize)
- x := (rune << (64 - n)) >> (64 - n)
- if x != rune {
- s.errorString("overflow on character value " + string(rune))
+ x := (r << (64 - n)) >> (64 - n)
+ if x != r {
+ s.errorString("overflow on character value " + string(r))
}
- return rune
+ return r
}
// scanBasePrefix reports whether the integer begins with a 0 or 0x,
@@ -593,7 +644,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
// scanInt returns the value of the integer represented by the next
// token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanInt(verb int, bitSize int) int64 {
+func (s *ss) scanInt(verb rune, bitSize int) int64 {
if verb == 'c' {
return s.scanRune(bitSize)
}
@@ -612,7 +663,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
}
}
tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoi64(tok, base)
+ i, err := strconv.ParseInt(tok, base, 64)
if err != nil {
s.error(err)
}
@@ -626,7 +677,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
// scanUint returns the value of the unsigned integer represented
// by the next token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanUint(verb int, bitSize int) uint64 {
+func (s *ss) scanUint(verb rune, bitSize int) uint64 {
if verb == 'c' {
return uint64(s.scanRune(bitSize))
}
@@ -642,7 +693,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
base, digits, haveDigits = s.scanBasePrefix()
}
tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoui64(tok, base)
+ i, err := strconv.ParseUint(tok, base, 64)
if err != nil {
s.error(err)
}
@@ -658,16 +709,16 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
// if the width is specified. It's not rigorous about syntax because it doesn't check that
// we have at least some digits, but Atof will do that.
func (s *ss) floatToken() string {
- s.buf.Reset()
+ s.buf = s.buf[:0]
// NaN?
if s.accept("nN") && s.accept("aA") && s.accept("nN") {
- return s.buf.String()
+ return string(s.buf)
}
// leading sign?
s.accept(sign)
// Inf?
if s.accept("iI") && s.accept("nN") && s.accept("fF") {
- return s.buf.String()
+ return string(s.buf)
}
// digits?
for s.accept(decimalDigits) {
@@ -686,7 +737,7 @@ func (s *ss) floatToken() string {
for s.accept(decimalDigits) {
}
}
- return s.buf.String()
+ return string(s.buf)
}
// complexTokens returns the real and imaginary parts of the complex number starting here.
@@ -696,13 +747,13 @@ func (s *ss) complexTokens() (real, imag string) {
// TODO: accept N and Ni independently?
parens := s.accept("(")
real = s.floatToken()
- s.buf.Reset()
+ s.buf = s.buf[:0]
// Must now have a sign.
if !s.accept("+-") {
s.error(complexError)
}
// Sign is now in buffer
- imagSign := s.buf.String()
+ imagSign := string(s.buf)
imag = s.floatToken()
if !s.accept("i") {
s.error(complexError)
@@ -715,10 +766,10 @@ func (s *ss) complexTokens() (real, imag string) {
// convertFloat converts the string to a float64value.
func (s *ss) convertFloat(str string, n int) float64 {
- if p := strings.Index(str, "p"); p >= 0 {
+ if p := indexRune(str, 'p'); p >= 0 {
// Atof doesn't handle power-of-2 exponents,
// but they're easy to evaluate.
- f, err := strconv.AtofN(str[:p], n)
+ f, err := strconv.ParseFloat(str[:p], n)
if err != nil {
// Put full string into error.
if e, ok := err.(*strconv.NumError); ok {
@@ -736,7 +787,7 @@ func (s *ss) convertFloat(str string, n int) float64 {
}
return math.Ldexp(f, n)
}
- f, err := strconv.AtofN(str, n)
+ f, err := strconv.ParseFloat(str, n)
if err != nil {
s.error(err)
}
@@ -747,7 +798,7 @@ func (s *ss) convertFloat(str string, n int) float64 {
// The atof argument is a type-specific reader for the underlying type.
// If we're reading complex64, atof will parse float32s and convert them
// to float64's to avoid reproducing this code for each complex type.
-func (s *ss) scanComplex(verb int, n int) complex128 {
+func (s *ss) scanComplex(verb rune, n int) complex128 {
if !s.okVerb(verb, floatVerbs, "complex") {
return 0
}
@@ -761,7 +812,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 {
// convertString returns the string represented by the next input characters.
// The format of the input is determined by the verb.
-func (s *ss) convertString(verb int) (str string) {
+func (s *ss) convertString(verb rune) (str string) {
if !s.okVerb(verb, "svqx", "string") {
return ""
}
@@ -786,30 +837,30 @@ func (s *ss) quotedString() string {
case '`':
// Back-quoted: Anything goes until EOF or back quote.
for {
- rune := s.mustReadRune()
- if rune == quote {
+ r := s.mustReadRune()
+ if r == quote {
break
}
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
- return s.buf.String()
+ return string(s.buf)
case '"':
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
s.buf.WriteRune(quote)
for {
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- if rune == '\\' {
+ r := s.mustReadRune()
+ s.buf.WriteRune(r)
+ if r == '\\' {
// In a legal backslash escape, no matter how long, only the character
// immediately after the escape can itself be a backslash or quote.
// Thus we only need to protect the first character after the backslash.
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- } else if rune == '"' {
+ r := s.mustReadRune()
+ s.buf.WriteRune(r)
+ } else if r == '"' {
break
}
}
- result, err := strconv.Unquote(s.buf.String())
+ result, err := strconv.Unquote(string(s.buf))
if err != nil {
s.error(err)
}
@@ -821,7 +872,8 @@ func (s *ss) quotedString() string {
}
// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(digit int) int {
+func (s *ss) hexDigit(d rune) int {
+ digit := int(d)
switch digit {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return digit - '0'
@@ -841,7 +893,7 @@ func (s *ss) hexByte() (b byte, ok bool) {
if rune1 == eof {
return
}
- if unicode.IsSpace(rune1) {
+ if isSpace(rune1) {
s.UnreadRune()
return
}
@@ -859,11 +911,11 @@ func (s *ss) hexString() string {
}
s.buf.WriteByte(b)
}
- if s.buf.Len() == 0 {
+ if len(s.buf) == 0 {
s.errorString("Scan: no hex data for %x string")
return ""
}
- return s.buf.String()
+ return string(s.buf)
}
const floatVerbs = "beEfFgGv"
@@ -871,14 +923,14 @@ const floatVerbs = "beEfFgGv"
const hugeWid = 1 << 30
// scanOne scans a single value, deriving the scanner from the type of the argument.
-func (s *ss) scanOne(verb int, field interface{}) {
- s.buf.Reset()
- var err os.Error
+func (s *ss) scanOne(verb rune, field interface{}) {
+ s.buf = s.buf[:0]
+ var err error
// If the parameter has its own Scan method, use that.
if v, ok := field.(Scanner); ok {
err = v.Scan(s, verb)
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
s.error(err)
@@ -975,11 +1027,11 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
// errorHandler turns local panics into error returns.
-func errorHandler(errp *os.Error) {
+func errorHandler(errp *error) {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok { // catch local error
*errp = se.err
- } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input
+ } else if eof, ok := e.(error); ok && eof == io.EOF { // out of input
*errp = eof
} else {
panic(e)
@@ -988,7 +1040,7 @@ func errorHandler(errp *os.Error) {
}
// doScan does the real work for scanning without a format string.
-func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
for _, field := range a {
s.scanOne('v', field)
@@ -997,11 +1049,11 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
// Check for newline if required.
if !s.nlIsSpace {
for {
- rune := s.getRune()
- if rune == '\n' || rune == eof {
+ r := s.getRune()
+ if r == '\n' || r == eof {
break
}
- if !unicode.IsSpace(rune) {
+ if !isSpace(r) {
s.errorString("Scan: expected newline")
break
}
@@ -1029,7 +1081,7 @@ func (s *ss) advance(format string) (i int) {
i += w // skip the first %
}
sawSpace := false
- for unicode.IsSpace(fmtc) && i < len(format) {
+ for isSpace(fmtc) && i < len(format) {
sawSpace = true
i += w
fmtc, w = utf8.DecodeRuneInString(format[i:])
@@ -1041,7 +1093,7 @@ func (s *ss) advance(format string) (i int) {
if inputc == eof {
return
}
- if !unicode.IsSpace(inputc) {
+ if !isSpace(inputc) {
// Space in format but not in input: error
s.errorString("expected space in input to match format")
}
@@ -1060,7 +1112,7 @@ func (s *ss) advance(format string) (i int) {
// doScanf does the real work when scanning with a format string.
// At the moment, it handles only pointers to basic types.
-func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
end := len(format) - 1
// We process one item per non-trivial format
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 3f06e5725..320857b73 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -7,15 +7,15 @@ package fmt_test
import (
"bufio"
"bytes"
+ "errors"
. "fmt"
"io"
"math"
- "os"
"reflect"
"regexp"
"strings"
"testing"
- "utf8"
+ "unicode/utf8"
)
type ScanTest struct {
@@ -56,6 +56,7 @@ var (
stringVal string
stringVal1 string
bytesVal []byte
+ runeVal rune
complex64Val complex64
complex128Val complex128
renamedBoolVal renamedBool
@@ -87,14 +88,14 @@ type FloatTest struct {
// Xs accepts any non-empty run of the verb character
type Xs string
-func (x *Xs) Scan(state ScanState, verb int) os.Error {
- tok, err := state.Token(true, func(r int) bool { return r == verb })
+func (x *Xs) Scan(state ScanState, verb rune) error {
+ tok, err := state.Token(true, func(r rune) bool { return r == verb })
if err != nil {
return err
}
s := string(tok)
if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
- return os.NewError("syntax error for xs")
+ return errors.New("syntax error for xs")
}
*x = Xs(s)
return nil
@@ -109,7 +110,7 @@ type IntString struct {
s string
}
-func (s *IntString) Scan(state ScanState, verb int) os.Error {
+func (s *IntString) Scan(state ScanState, verb rune) error {
if _, err := Fscan(state, &s.i); err != nil {
return err
}
@@ -130,7 +131,7 @@ type myStringReader struct {
r *strings.Reader
}
-func (s *myStringReader) Read(p []byte) (n int, err os.Error) {
+func (s *myStringReader) Read(p []byte) (n int, err error) {
return s.r.Read(p)
}
@@ -225,9 +226,9 @@ var scanfTests = []ScanfTest{
{"%v", "0377\n", &intVal, 0377},
{"%v", "0x44\n", &intVal, 0x44},
{"%d", "72\n", &intVal, 72},
- {"%c", "a\n", &intVal, 'a'},
- {"%c", "\u5072\n", &intVal, 0x5072},
- {"%c", "\u1234\n", &intVal, '\u1234'},
+ {"%c", "a\n", &runeVal, 'a'},
+ {"%c", "\u5072\n", &runeVal, '\u5072'},
+ {"%c", "\u1234\n", &runeVal, '\u1234'},
{"%d", "73\n", &int8Val, int8(73)},
{"%d", "+74\n", &int16Val, int16(74)},
{"%d", "75\n", &int32Val, int32(75)},
@@ -316,15 +317,17 @@ var overflowTests = []ScanTest{
{"(1-1e500i)", &complex128Val, 0},
}
+var truth bool
var i, j, k int
var f float64
var s, t string
var c complex128
var x, y Xs
var z IntString
+var r1, r2, r3 rune
var multiTests = []ScanfMultiTest{
- {"", "", nil, nil, ""},
+ {"", "", []interface{}{}, []interface{}{}, ""},
{"%d", "23", args(&i), args(23), ""},
{"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
{"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
@@ -333,7 +336,7 @@ var multiTests = []ScanfMultiTest{
{"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
{"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
{"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
- {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
+ {"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
// Custom scanners.
{"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
@@ -347,10 +350,13 @@ var multiTests = []ScanfMultiTest{
{"X%d", "10X", args(&intVal), nil, "input does not match format"},
// Bad UTF-8: should see every byte.
- {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+ {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+
+ // Fixed bugs
+ {"%v%v", "FALSE23", args(&truth, &i), args(false, 23), ""},
}
-func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
+func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
for _, test := range scanTests {
var r io.Reader
if name == "StringReader" {
@@ -378,7 +384,7 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
}
}
}
@@ -417,7 +423,7 @@ func TestScanf(t *testing.T) {
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
}
}
}
@@ -431,7 +437,7 @@ func TestScanOverflow(t *testing.T) {
t.Errorf("expected overflow scanning %q", test.text)
continue
}
- if !re.MatchString(err.String()) {
+ if !re.MatchString(err.Error()) {
t.Errorf("expected overflow error scanning %q: %s", test.text, err)
}
}
@@ -500,7 +506,7 @@ func testScanfMulti(name string, t *testing.T) {
if err != nil {
if test.err == "" {
t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
- } else if strings.Index(err.String(), test.err) < 0 {
+ } else if strings.Index(err.Error(), test.err) < 0 {
t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
}
continue
@@ -520,7 +526,7 @@ func testScanfMulti(name string, t *testing.T) {
}
result := resultVal.Interface()
if !reflect.DeepEqual(result, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v", test.format, test.text, test.out, result)
}
}
}
@@ -594,7 +600,7 @@ func TestScanNotPointer(t *testing.T) {
_, err := Fscan(r, a)
if err == nil {
t.Error("expected error scanning non-pointer")
- } else if strings.Index(err.String(), "pointer") < 0 {
+ } else if strings.Index(err.Error(), "pointer") < 0 {
t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
}
}
@@ -604,7 +610,7 @@ func TestScanlnNoNewline(t *testing.T) {
_, err := Sscanln("1 x\n", &a)
if err == nil {
t.Error("expected error scanning string missing newline")
- } else if strings.Index(err.String(), "newline") < 0 {
+ } else if strings.Index(err.Error(), "newline") < 0 {
t.Errorf("expected newline error scanning string missing newline, got: %s", err)
}
}
@@ -615,7 +621,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
_, err := Fscanln(r, &a, &b)
if err == nil {
t.Error("expected error scanning string with extra newline")
- } else if strings.Index(err.String(), "newline") < 0 {
+ } else if strings.Index(err.Error(), "newline") < 0 {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
@@ -626,7 +632,7 @@ type eofCounter struct {
eofCount int
}
-func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
+func (ec *eofCounter) Read(b []byte) (n int, err error) {
n, err = ec.reader.Read(b)
if n == 0 {
ec.eofCount++
@@ -670,14 +676,14 @@ func TestEOFAtEndOfInput(t *testing.T) {
if n != 1 || i != 23 {
t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
}
- if err != os.EOF {
+ if err != io.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 {
+ if err != io.EOF {
t.Errorf("Sscan expected EOF; got %q", err)
}
// Trailing space is tougher.
@@ -685,7 +691,7 @@ func TestEOFAtEndOfInput(t *testing.T) {
if n != 1 || i != 234 {
t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
}
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("Sscan expected EOF; got %q", err)
}
}
@@ -715,10 +721,10 @@ var eofTests = []struct {
func TestEOFAllTypes(t *testing.T) {
for i, test := range eofTests {
- if _, err := Sscanf("", test.format, test.v); err != os.EOF {
+ if _, err := Sscanf("", test.format, test.v); err != io.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 {
+ if _, err := Sscanf(" ", test.format, test.v); err != io.EOF {
t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
}
}
@@ -749,8 +755,8 @@ type TwoLines string
// Attempt to read two lines into the object. Scanln should prevent this
// because it stops at newline; Scan and Scanf should be fine.
-func (t *TwoLines) Scan(state ScanState, verb int) os.Error {
- chars := make([]int, 0, 100)
+func (t *TwoLines) Scan(state ScanState, verb rune) error {
+ chars := make([]rune, 0, 100)
for nlCount := 0; nlCount < 2; {
c, _, err := state.ReadRune()
if err != nil {
@@ -804,7 +810,7 @@ func TestMultiLine(t *testing.T) {
}
}
-// RecursiveInt accepts an string matching %d.%d.%d....
+// RecursiveInt accepts a string matching %d.%d.%d....
// and parses it into a linked list.
// It allows us to benchmark recursive descent style scanners.
type RecursiveInt struct {
@@ -812,7 +818,7 @@ type RecursiveInt struct {
next *RecursiveInt
}
-func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
+func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
_, err = Fscan(state, &r.i)
if err != nil {
return
@@ -820,7 +826,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.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == io.ErrUnexpectedEOF {
err = nil
}
return
@@ -832,16 +838,15 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
// Perform the same scanning task as RecursiveInt.Scan
// but without recurring through scanner, so we can compare
// performance more directly.
-func scanInts(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+func scanInts(r *RecursiveInt, b *bytes.Buffer) (err error) {
r.next = nil
_, err = Fscan(b, &r.i)
if err != nil {
return
}
- var c int
- c, _, err = b.ReadRune()
+ c, _, err := b.ReadRune()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = nil
}
return
@@ -868,7 +873,7 @@ func makeInts(n int) []byte {
func TestScanInts(t *testing.T) {
testScanInts(t, scanInts)
- testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+ testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err error) {
_, err = Fscan(b, r)
return
})
@@ -878,7 +883,7 @@ func TestScanInts(t *testing.T) {
// platform that does not support split stack.
const intCount = 800
-func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error) {
+func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) error) {
r := new(RecursiveInt)
ints := makeInts(intCount)
buf := bytes.NewBuffer(ints)
diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile
deleted file mode 100644
index 40be10208..000000000
--- a/src/pkg/go/ast/Makefile
+++ /dev/null
@@ -1,16 +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.
-
-include ../../../Make.inc
-
-TARG=go/ast
-GOFILES=\
- ast.go\
- filter.go\
- print.go\
- resolve.go\
- scope.go\
- walk.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go
index 22bd5ee22..7123fe58f 100644
--- a/src/pkg/go/ast/ast.go
+++ b/src/pkg/go/ast/ast.go
@@ -9,8 +9,9 @@ package ast
import (
"go/token"
+ "strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// ----------------------------------------------------------------------------
@@ -76,6 +77,74 @@ type CommentGroup struct {
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() }
+func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
+
+func stripTrailingWhitespace(s string) string {
+ i := len(s)
+ for i > 0 && isWhitespace(s[i-1]) {
+ i--
+ }
+ return s[0:i]
+}
+
+// Text returns the text of the comment,
+// with the comment markers - //, /*, and */ - removed.
+func (g *CommentGroup) Text() string {
+ if g == nil {
+ return ""
+ }
+ comments := make([]string, len(g.List))
+ for i, c := range g.List {
+ comments[i] = string(c.Text)
+ }
+
+ lines := make([]string, 0, 10) // most comments are less than 10 lines
+ for _, c := range comments {
+ // Remove comment markers.
+ // The parser has given us exactly the comment text.
+ switch c[1] {
+ case '/':
+ //-style comment
+ c = c[2:]
+ // Remove leading space after //, if there is one.
+ // TODO(gri) This appears to be necessary in isolated
+ // cases (bignum.RatFromString) - why?
+ if len(c) > 0 && c[0] == ' ' {
+ c = c[1:]
+ }
+ case '*':
+ /*-style comment */
+ c = c[2 : len(c)-2]
+ }
+
+ // Split on newlines.
+ cl := strings.Split(c, "\n")
+
+ // Walk lines, stripping trailing white space and adding to list.
+ for _, l := range cl {
+ lines = append(lines, stripTrailingWhitespace(l))
+ }
+ }
+
+ // Remove leading blank lines; convert runs of
+ // interior blank lines to a single blank line.
+ n := 0
+ for _, line := range lines {
+ if line != "" || n > 0 && lines[n-1] != "" {
+ lines[n] = line
+ n++
+ }
+ }
+ lines = lines[0:n]
+
+ // Add final "" entry to get trailing newline from Join.
+ if n > 0 && lines[n-1] != "" {
+ lines = append(lines, "")
+ }
+
+ return strings.Join(lines, "\n")
+}
+
// ----------------------------------------------------------------------------
// Expressions and types
@@ -412,29 +481,29 @@ func (x *ChanType) End() token.Pos { return x.Value.End() }
// exprNode() ensures that only expression/type nodes can be
// assigned to an ExprNode.
//
-func (x *BadExpr) exprNode() {}
-func (x *Ident) exprNode() {}
-func (x *Ellipsis) exprNode() {}
-func (x *BasicLit) exprNode() {}
-func (x *FuncLit) exprNode() {}
-func (x *CompositeLit) exprNode() {}
-func (x *ParenExpr) exprNode() {}
-func (x *SelectorExpr) exprNode() {}
-func (x *IndexExpr) exprNode() {}
-func (x *SliceExpr) exprNode() {}
-func (x *TypeAssertExpr) exprNode() {}
-func (x *CallExpr) exprNode() {}
-func (x *StarExpr) exprNode() {}
-func (x *UnaryExpr) exprNode() {}
-func (x *BinaryExpr) exprNode() {}
-func (x *KeyValueExpr) exprNode() {}
-
-func (x *ArrayType) exprNode() {}
-func (x *StructType) exprNode() {}
-func (x *FuncType) exprNode() {}
-func (x *InterfaceType) exprNode() {}
-func (x *MapType) exprNode() {}
-func (x *ChanType) exprNode() {}
+func (*BadExpr) exprNode() {}
+func (*Ident) exprNode() {}
+func (*Ellipsis) exprNode() {}
+func (*BasicLit) exprNode() {}
+func (*FuncLit) exprNode() {}
+func (*CompositeLit) exprNode() {}
+func (*ParenExpr) exprNode() {}
+func (*SelectorExpr) exprNode() {}
+func (*IndexExpr) exprNode() {}
+func (*SliceExpr) exprNode() {}
+func (*TypeAssertExpr) exprNode() {}
+func (*CallExpr) exprNode() {}
+func (*StarExpr) exprNode() {}
+func (*UnaryExpr) exprNode() {}
+func (*BinaryExpr) exprNode() {}
+func (*KeyValueExpr) exprNode() {}
+
+func (*ArrayType) exprNode() {}
+func (*StructType) exprNode() {}
+func (*FuncType) exprNode() {}
+func (*InterfaceType) exprNode() {}
+func (*MapType) exprNode() {}
+func (*ChanType) exprNode() {}
// ----------------------------------------------------------------------------
// Convenience functions for Idents
@@ -711,27 +780,27 @@ func (s *RangeStmt) End() token.Pos { return s.Body.End() }
// stmtNode() ensures that only statement nodes can be
// assigned to a StmtNode.
//
-func (s *BadStmt) stmtNode() {}
-func (s *DeclStmt) stmtNode() {}
-func (s *EmptyStmt) stmtNode() {}
-func (s *LabeledStmt) stmtNode() {}
-func (s *ExprStmt) stmtNode() {}
-func (s *SendStmt) stmtNode() {}
-func (s *IncDecStmt) stmtNode() {}
-func (s *AssignStmt) stmtNode() {}
-func (s *GoStmt) stmtNode() {}
-func (s *DeferStmt) stmtNode() {}
-func (s *ReturnStmt) stmtNode() {}
-func (s *BranchStmt) stmtNode() {}
-func (s *BlockStmt) stmtNode() {}
-func (s *IfStmt) stmtNode() {}
-func (s *CaseClause) stmtNode() {}
-func (s *SwitchStmt) stmtNode() {}
-func (s *TypeSwitchStmt) stmtNode() {}
-func (s *CommClause) stmtNode() {}
-func (s *SelectStmt) stmtNode() {}
-func (s *ForStmt) stmtNode() {}
-func (s *RangeStmt) stmtNode() {}
+func (*BadStmt) stmtNode() {}
+func (*DeclStmt) stmtNode() {}
+func (*EmptyStmt) stmtNode() {}
+func (*LabeledStmt) stmtNode() {}
+func (*ExprStmt) stmtNode() {}
+func (*SendStmt) stmtNode() {}
+func (*IncDecStmt) stmtNode() {}
+func (*AssignStmt) stmtNode() {}
+func (*GoStmt) stmtNode() {}
+func (*DeferStmt) stmtNode() {}
+func (*ReturnStmt) stmtNode() {}
+func (*BranchStmt) stmtNode() {}
+func (*BlockStmt) stmtNode() {}
+func (*IfStmt) stmtNode() {}
+func (*CaseClause) stmtNode() {}
+func (*SwitchStmt) stmtNode() {}
+func (*TypeSwitchStmt) stmtNode() {}
+func (*CommClause) stmtNode() {}
+func (*SelectStmt) stmtNode() {}
+func (*ForStmt) stmtNode() {}
+func (*RangeStmt) stmtNode() {}
// ----------------------------------------------------------------------------
// Declarations
@@ -752,6 +821,7 @@ type (
Name *Ident // local package name (including "."); or nil
Path *BasicLit // import path
Comment *CommentGroup // line comments; or nil
+ EndPos token.Pos // end of spec (overrides Path.Pos if nonzero)
}
// A ValueSpec node represents a constant or variable declaration
@@ -785,7 +855,13 @@ 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 *ImportSpec) End() token.Pos {
+ if s.EndPos != 0 {
+ return s.EndPos
+ }
+ return s.Path.End()
+}
+
func (s *ValueSpec) End() token.Pos {
if n := len(s.Values); n > 0 {
return s.Values[n-1].End()
@@ -800,9 +876,9 @@ func (s *TypeSpec) End() token.Pos { return s.Type.End() }
// specNode() ensures that only spec nodes can be
// assigned to a Spec.
//
-func (s *ImportSpec) specNode() {}
-func (s *ValueSpec) specNode() {}
-func (s *TypeSpec) specNode() {}
+func (*ImportSpec) specNode() {}
+func (*ValueSpec) specNode() {}
+func (*TypeSpec) specNode() {}
// A declaration is represented by one of the following declaration nodes.
//
@@ -868,9 +944,9 @@ func (d *FuncDecl) End() token.Pos {
// declNode() ensures that only declaration nodes can be
// assigned to a DeclNode.
//
-func (d *BadDecl) declNode() {}
-func (d *GenDecl) declNode() {}
-func (d *FuncDecl) declNode() {}
+func (*BadDecl) declNode() {}
+func (*GenDecl) declNode() {}
+func (*FuncDecl) declNode() {}
// ----------------------------------------------------------------------------
// Files and packages
diff --git a/src/pkg/go/ast/example_test.go b/src/pkg/go/ast/example_test.go
new file mode 100644
index 000000000..632bfcfd0
--- /dev/null
+++ b/src/pkg/go/ast/example_test.go
@@ -0,0 +1,136 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ast_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+)
+
+// This example demonstrates how to inspect the AST of a Go program.
+func ExampleInspect() {
+ // src is the input for which we want to inspect the AST.
+ src := `
+package p
+const c = 1.0
+var X = f(3.14)*2 + c
+`
+
+ // Create the AST by parsing src.
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "src.go", src, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ // Inspect the AST and print all identifiers and literals.
+ ast.Inspect(f, func(n ast.Node) bool {
+ var s string
+ switch x := n.(type) {
+ case *ast.BasicLit:
+ s = x.Value
+ case *ast.Ident:
+ s = x.Name
+ }
+ if s != "" {
+ fmt.Printf("%s:\t%s\n", fset.Position(n.Pos()), s)
+ }
+ return true
+ })
+
+ // output:
+ // src.go:2:9: p
+ // src.go:3:7: c
+ // src.go:3:11: 1.0
+ // src.go:4:5: X
+ // src.go:4:9: f
+ // src.go:4:11: 3.14
+ // src.go:4:17: 2
+ // src.go:4:21: c
+}
+
+// This example shows what an AST looks like when printed for debugging.
+func ExamplePrint() {
+ // src is the input for which we want to print the AST.
+ src := `
+package main
+func main() {
+ println("Hello, World!")
+}
+`
+
+ // Create the AST by parsing src.
+ fset := token.NewFileSet() // positions are relative to fset
+ f, err := parser.ParseFile(fset, "", src, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ // Print the AST.
+ ast.Print(fset, f)
+
+ // output:
+ // 0 *ast.File {
+ // 1 . Package: 2:1
+ // 2 . Name: *ast.Ident {
+ // 3 . . NamePos: 2:9
+ // 4 . . Name: "main"
+ // 5 . }
+ // 6 . Decls: []ast.Decl (len = 1) {
+ // 7 . . 0: *ast.FuncDecl {
+ // 8 . . . Name: *ast.Ident {
+ // 9 . . . . NamePos: 3:6
+ // 10 . . . . Name: "main"
+ // 11 . . . . Obj: *ast.Object {
+ // 12 . . . . . Kind: func
+ // 13 . . . . . Name: "main"
+ // 14 . . . . . Decl: *(obj @ 7)
+ // 15 . . . . }
+ // 16 . . . }
+ // 17 . . . Type: *ast.FuncType {
+ // 18 . . . . Func: 3:1
+ // 19 . . . . Params: *ast.FieldList {
+ // 20 . . . . . Opening: 3:10
+ // 21 . . . . . Closing: 3:11
+ // 22 . . . . }
+ // 23 . . . }
+ // 24 . . . Body: *ast.BlockStmt {
+ // 25 . . . . Lbrace: 3:13
+ // 26 . . . . List: []ast.Stmt (len = 1) {
+ // 27 . . . . . 0: *ast.ExprStmt {
+ // 28 . . . . . . X: *ast.CallExpr {
+ // 29 . . . . . . . Fun: *ast.Ident {
+ // 30 . . . . . . . . NamePos: 4:2
+ // 31 . . . . . . . . Name: "println"
+ // 32 . . . . . . . }
+ // 33 . . . . . . . Lparen: 4:9
+ // 34 . . . . . . . Args: []ast.Expr (len = 1) {
+ // 35 . . . . . . . . 0: *ast.BasicLit {
+ // 36 . . . . . . . . . ValuePos: 4:10
+ // 37 . . . . . . . . . Kind: STRING
+ // 38 . . . . . . . . . Value: "\"Hello, World!\""
+ // 39 . . . . . . . . }
+ // 40 . . . . . . . }
+ // 41 . . . . . . . Ellipsis: -
+ // 42 . . . . . . . Rparen: 4:25
+ // 43 . . . . . . }
+ // 44 . . . . . }
+ // 45 . . . . }
+ // 46 . . . . Rbrace: 5:1
+ // 47 . . . }
+ // 48 . . }
+ // 49 . }
+ // 50 . Scope: *ast.Scope {
+ // 51 . . Objects: map[string]*ast.Object (len = 1) {
+ // 52 . . . "main": *(obj @ 11)
+ // 53 . . }
+ // 54 . }
+ // 55 . Unresolved: []*ast.Ident (len = 1) {
+ // 56 . . 0: *(obj @ 29)
+ // 57 . }
+ // 58 }
+}
diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go
index 26733430d..4a89b8909 100644
--- a/src/pkg/go/ast/filter.go
+++ b/src/pkg/go/ast/filter.go
@@ -4,15 +4,52 @@
package ast
-import "go/token"
+import (
+ "go/token"
+ "sort"
+)
// ----------------------------------------------------------------------------
// Export filtering
-func identListExports(list []*Ident) []*Ident {
+// exportFilter is a special filter function to extract exported nodes.
+func exportFilter(name string) bool {
+ return IsExported(name)
+}
+
+// FileExports trims the AST for a Go source file in place such that
+// only exported nodes remain: all top-level identifiers which are not exported
+// and their associated information (such as type, initial value, or function
+// body) are removed. Non-exported fields and methods of exported types are
+// stripped. The File.Comments list is not changed.
+//
+// FileExports returns true if there are exported declarations;
+// it returns false otherwise.
+//
+func FileExports(src *File) bool {
+ return filterFile(src, exportFilter, true)
+}
+
+// PackageExports trims the AST for a Go package in place such that
+// only exported nodes remain. The pkg.Files list is not changed, so that
+// file names and top-level package comments don't get lost.
+//
+// PackageExports returns true if there are exported declarations;
+// it returns false otherwise.
+//
+func PackageExports(pkg *Package) bool {
+ return filterPackage(pkg, exportFilter, true)
+}
+
+// ----------------------------------------------------------------------------
+// General filtering
+
+type Filter func(string) bool
+
+func filterIdentList(list []*Ident, f Filter) []*Ident {
j := 0
for _, x := range list {
- if x.IsExported() {
+ if f(x.Name) {
list[j] = x
j++
}
@@ -38,33 +75,30 @@ func fieldName(x Expr) *Ident {
return nil
}
-func fieldListExports(fields *FieldList) (removedFields bool) {
+func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) {
if fields == nil {
- return
+ return false
}
list := fields.List
j := 0
for _, f := range list {
- exported := false
+ keepField := false
if len(f.Names) == 0 {
// anonymous field
- // (Note that a non-exported anonymous field
- // may still refer to a type with exported
- // fields, so this is not absolutely correct.
- // However, this cannot be done w/o complete
- // type information.)
name := fieldName(f.Type)
- exported = name != nil && name.IsExported()
+ keepField = name != nil && filter(name.Name)
} else {
n := len(f.Names)
- f.Names = identListExports(f.Names)
+ f.Names = filterIdentList(f.Names, filter)
if len(f.Names) < n {
removedFields = true
}
- exported = len(f.Names) > 0
+ keepField = len(f.Names) > 0
}
- if exported {
- typeExports(f.Type)
+ if keepField {
+ if export {
+ filterType(f.Type, filter, export)
+ }
list[j] = f
j++
}
@@ -76,194 +110,84 @@ func fieldListExports(fields *FieldList) (removedFields bool) {
return
}
-func paramListExports(fields *FieldList) {
+func filterParamList(fields *FieldList, filter Filter, export bool) bool {
if fields == nil {
- return
+ return false
}
+ var b bool
for _, f := range fields.List {
- typeExports(f.Type)
+ if filterType(f.Type, filter, export) {
+ b = true
+ }
}
+ return b
}
-func typeExports(typ Expr) {
+func filterType(typ Expr, f Filter, export bool) bool {
switch t := typ.(type) {
+ case *Ident:
+ return f(t.Name)
+ case *ParenExpr:
+ return filterType(t.X, f, export)
case *ArrayType:
- typeExports(t.Elt)
+ return filterType(t.Elt, f, export)
case *StructType:
- if fieldListExports(t.Fields) {
+ if filterFieldList(t.Fields, f, export) {
t.Incomplete = true
}
+ return len(t.Fields.List) > 0
case *FuncType:
- paramListExports(t.Params)
- paramListExports(t.Results)
+ b1 := filterParamList(t.Params, f, export)
+ b2 := filterParamList(t.Results, f, export)
+ return b1 || b2
case *InterfaceType:
- if fieldListExports(t.Methods) {
+ if filterFieldList(t.Methods, f, export) {
t.Incomplete = true
}
+ return len(t.Methods.List) > 0
case *MapType:
- typeExports(t.Key)
- typeExports(t.Value)
+ b1 := filterType(t.Key, f, export)
+ b2 := filterType(t.Value, f, export)
+ return b1 || b2
case *ChanType:
- typeExports(t.Value)
+ return filterType(t.Value, f, export)
}
+ return false
}
-func specExports(spec Spec) bool {
+func filterSpec(spec Spec, f Filter, export bool) bool {
switch s := spec.(type) {
case *ValueSpec:
- s.Names = identListExports(s.Names)
+ s.Names = filterIdentList(s.Names, f)
if len(s.Names) > 0 {
- typeExports(s.Type)
- return true
- }
- case *TypeSpec:
- if s.Name.IsExported() {
- typeExports(s.Type)
- return true
- }
- }
- return false
-}
-
-func specListExports(list []Spec) []Spec {
- j := 0
- for _, s := range list {
- if specExports(s) {
- list[j] = s
- j++
- }
- }
- return list[0:j]
-}
-
-func declExports(decl Decl) bool {
- switch d := decl.(type) {
- case *GenDecl:
- d.Specs = specListExports(d.Specs)
- return len(d.Specs) > 0
- case *FuncDecl:
- d.Body = nil // strip body
- return d.Name.IsExported()
- }
- return false
-}
-
-// FileExports trims the AST for a Go source file in place such that only
-// exported nodes remain: all top-level identifiers which are not exported
-// and their associated information (such as type, initial value, or function
-// body) are removed. Non-exported fields and methods of exported types are
-// stripped, and the function bodies of exported functions are set to nil.
-// The File.comments list is not changed.
-//
-// FileExports returns true if there is an exported declaration; it returns
-// false otherwise.
-//
-func FileExports(src *File) bool {
- j := 0
- for _, d := range src.Decls {
- if declExports(d) {
- src.Decls[j] = d
- j++
- }
- }
- src.Decls = src.Decls[0:j]
- return j > 0
-}
-
-// PackageExports trims the AST for a Go package in place such that only
-// exported nodes remain. The pkg.Files list is not changed, so that file
-// names and top-level package comments don't get lost.
-//
-// PackageExports returns true if there is an exported declaration; it
-// returns false otherwise.
-//
-func PackageExports(pkg *Package) bool {
- hasExports := false
- for _, f := range pkg.Files {
- if FileExports(f) {
- hasExports = true
- }
- }
- return hasExports
-}
-
-// ----------------------------------------------------------------------------
-// General filtering
-
-type Filter func(string) bool
-
-func filterIdentList(list []*Ident, f Filter) []*Ident {
- j := 0
- for _, x := range list {
- if f(x.Name) {
- list[j] = x
- j++
- }
- }
- return list[0:j]
-}
-
-func 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
+ if export {
+ filterType(s.Type, f, export)
}
- keepField = len(f.Names) > 0
- }
- if keepField {
- list[j] = f
- j++
+ return true
}
- }
- if j < len(list) {
- removedFields = true
- }
- fields.List = list[0:j]
- return
-}
-
-func filterSpec(spec Spec, f Filter) bool {
- switch s := spec.(type) {
- case *ValueSpec:
- s.Names = filterIdentList(s.Names, f)
- return len(s.Names) > 0
case *TypeSpec:
if f(s.Name.Name) {
+ if export {
+ filterType(s.Type, f, export)
+ }
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
+ if !export {
+ // For general filtering (not just exports),
+ // filter type even if name is not filtered
+ // out.
+ // If the type contains filtered elements,
+ // keep the declaration.
+ return filterType(s.Type, f, export)
}
}
return false
}
-func filterSpecList(list []Spec, f Filter) []Spec {
+func filterSpecList(list []Spec, f Filter, export bool) []Spec {
j := 0
for _, s := range list {
- if filterSpec(s, f) {
+ if filterSpec(s, f, export) {
list[j] = s
j++
}
@@ -279,9 +203,13 @@ func filterSpecList(list []Spec, f Filter) []Spec {
// filtering; it returns false otherwise.
//
func FilterDecl(decl Decl, f Filter) bool {
+ return filterDecl(decl, f, false)
+}
+
+func filterDecl(decl Decl, f Filter, export bool) bool {
switch d := decl.(type) {
case *GenDecl:
- d.Specs = filterSpecList(d.Specs, f)
+ d.Specs = filterSpecList(d.Specs, f, export)
return len(d.Specs) > 0
case *FuncDecl:
return f(d.Name.Name)
@@ -293,16 +221,20 @@ func FilterDecl(decl Decl, f Filter) bool {
// 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.
+// the declaration is removed from the AST. The File.Comments list
+// is not changed.
//
// FilterFile returns true if there are any top-level declarations
// left after filtering; it returns false otherwise.
//
func FilterFile(src *File, f Filter) bool {
+ return filterFile(src, f, false)
+}
+
+func filterFile(src *File, f Filter, export bool) bool {
j := 0
for _, d := range src.Decls {
- if FilterDecl(d, f) {
+ if filterDecl(d, f, export) {
src.Decls[j] = d
j++
}
@@ -311,21 +243,25 @@ 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 (including struct field and
+// FilterPackage trims the AST for a Go package in place by removing
+// all 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.
+// the declaration is removed from the AST. The pkg.Files list is not
+// changed, so that file names and top-level package comments don't get
+// lost.
//
// FilterPackage returns true if there are any top-level declarations
// left after filtering; it returns false otherwise.
//
func FilterPackage(pkg *Package, f Filter) bool {
+ return filterPackage(pkg, f, false)
+}
+
+func filterPackage(pkg *Package, f Filter, export bool) bool {
hasDecls := false
for _, src := range pkg.Files {
- if FilterFile(src, f) {
+ if filterFile(src, f, export) {
hasDecls = true
}
}
@@ -344,6 +280,8 @@ const (
// If set, comments that are not associated with a specific
// AST node (as Doc or Comment) are excluded.
FilterUnassociatedComments
+ // If set, duplicate import declarations are excluded.
+ FilterImportDuplicates
)
// separator is an empty //-style comment that is interspersed between
@@ -356,29 +294,35 @@ var separator = &Comment{noPos, "//"}
//
func MergePackageFiles(pkg *Package, mode MergeMode) *File {
// Count the number of package docs, comments and declarations across
- // all package files.
+ // all package files. Also, compute sorted list of filenames, so that
+ // subsequent iterations can always iterate in the same order.
ndocs := 0
ncomments := 0
ndecls := 0
- for _, f := range pkg.Files {
+ filenames := make([]string, len(pkg.Files))
+ i := 0
+ for filename, f := range pkg.Files {
+ filenames[i] = filename
+ i++
if f.Doc != nil {
ndocs += len(f.Doc.List) + 1 // +1 for separator
}
ncomments += len(f.Comments)
ndecls += len(f.Decls)
}
+ sort.Strings(filenames)
// Collect package comments from all package files into a single
- // CommentGroup - the collected package documentation. The order
- // is unspecified. In general there should be only one file with
- // a package comment; but it's better to collect extra comments
- // than drop them on the floor.
+ // CommentGroup - the collected package documentation. In general
+ // there should be only one file with a package comment; but it's
+ // better to collect extra comments than drop them on the floor.
var doc *CommentGroup
var pos token.Pos
if ndocs > 0 {
list := make([]*Comment, ndocs-1) // -1: no separator before first group
i := 0
- for _, f := range pkg.Files {
+ for _, filename := range filenames {
+ f := pkg.Files[filename]
if f.Doc != nil {
if i > 0 {
// not the first group - add separator
@@ -407,7 +351,8 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
funcs := make(map[string]int) // map of global function name -> decls index
i := 0 // current index
n := 0 // number of filtered entries
- for _, f := range pkg.Files {
+ for _, filename := range filenames {
+ f := pkg.Files[filename]
for _, d := range f.Decls {
if mode&FilterFuncDuplicates != 0 {
// A language entity may be declared multiple
@@ -459,6 +404,32 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
}
}
+ // Collect import specs from all package files.
+ var imports []*ImportSpec
+ if mode&FilterImportDuplicates != 0 {
+ seen := make(map[string]bool)
+ for _, filename := range filenames {
+ f := pkg.Files[filename]
+ for _, imp := range f.Imports {
+ if path := imp.Path.Value; !seen[path] {
+ // TODO: consider handling cases where:
+ // - 2 imports exist with the same import path but
+ // have different local names (one should probably
+ // keep both of them)
+ // - 2 imports exist but only one has a comment
+ // - 2 imports exist and they both have (possibly
+ // different) comments
+ imports = append(imports, imp)
+ seen[path] = true
+ }
+ }
+ }
+ } else {
+ for _, f := range pkg.Files {
+ imports = append(imports, f.Imports...)
+ }
+ }
+
// Collect comments from all package files.
var comments []*CommentGroup
if mode&FilterUnassociatedComments == 0 {
@@ -469,7 +440,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
}
}
- // TODO(gri) need to compute pkgScope and unresolved identifiers!
- // TODO(gri) need to compute imports!
- return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, nil, comments}
+ // TODO(gri) need to compute unresolved identifiers!
+ return &File{doc, pos, NewIdent(pkg.Name), decls, pkg.Scope, imports, nil, comments}
}
diff --git a/src/pkg/go/ast/import.go b/src/pkg/go/ast/import.go
new file mode 100644
index 000000000..2d4f69aae
--- /dev/null
+++ b/src/pkg/go/ast/import.go
@@ -0,0 +1,134 @@
+// 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 ast
+
+import (
+ "go/token"
+ "sort"
+ "strconv"
+)
+
+// SortImports sorts runs of consecutive import lines in import blocks in f.
+func SortImports(fset *token.FileSet, f *File) {
+ for _, d := range f.Decls {
+ d, ok := d.(*GenDecl)
+ if !ok || d.Tok != token.IMPORT {
+ // Not an import declaration, so we're done.
+ // Imports are always first.
+ break
+ }
+
+ if d.Lparen == token.NoPos {
+ // Not a block: sorted by default.
+ continue
+ }
+
+ // Identify and sort runs of specs on successive lines.
+ i := 0
+ for j, s := range d.Specs {
+ if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
+ // j begins a new run. End this one.
+ sortSpecs(fset, f, d.Specs[i:j])
+ i = j
+ }
+ }
+ sortSpecs(fset, f, d.Specs[i:])
+ }
+}
+
+func importPath(s Spec) string {
+ t, err := strconv.Unquote(s.(*ImportSpec).Path.Value)
+ if err == nil {
+ return t
+ }
+ return ""
+}
+
+type posSpan struct {
+ Start token.Pos
+ End token.Pos
+}
+
+func sortSpecs(fset *token.FileSet, f *File, specs []Spec) {
+ // Avoid work if already sorted (also catches < 2 entries).
+ sorted := true
+ for i, s := range specs {
+ if i > 0 && importPath(specs[i-1]) > importPath(s) {
+ sorted = false
+ break
+ }
+ }
+ if sorted {
+ return
+ }
+
+ // Record positions for specs.
+ pos := make([]posSpan, len(specs))
+ for i, s := range specs {
+ pos[i] = posSpan{s.Pos(), s.End()}
+ }
+
+ // Identify comments in this range.
+ // Any comment from pos[0].Start to the final line counts.
+ lastLine := fset.Position(pos[len(pos)-1].End).Line
+ cstart := len(f.Comments)
+ cend := len(f.Comments)
+ for i, g := range f.Comments {
+ if g.Pos() < pos[0].Start {
+ continue
+ }
+ if i < cstart {
+ cstart = i
+ }
+ if fset.Position(g.End()).Line > lastLine {
+ cend = i
+ break
+ }
+ }
+ comments := f.Comments[cstart:cend]
+
+ // Assign each comment to the import spec preceding it.
+ importComment := map[*ImportSpec][]*CommentGroup{}
+ specIndex := 0
+ for _, g := range comments {
+ for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() {
+ specIndex++
+ }
+ s := specs[specIndex].(*ImportSpec)
+ importComment[s] = append(importComment[s], g)
+ }
+
+ // Sort the import specs by import path.
+ // Reassign the import paths to have the same position sequence.
+ // Reassign each comment to abut the end of its spec.
+ // Sort the comments by new position.
+ sort.Sort(byImportPath(specs))
+ for i, s := range specs {
+ s := s.(*ImportSpec)
+ if s.Name != nil {
+ s.Name.NamePos = pos[i].Start
+ }
+ s.Path.ValuePos = pos[i].Start
+ s.EndPos = pos[i].End
+ for _, g := range importComment[s] {
+ for _, c := range g.List {
+ c.Slash = pos[i].End
+ }
+ }
+ }
+ sort.Sort(byCommentPos(comments))
+}
+
+type byImportPath []Spec // slice of *ImportSpec
+
+func (x byImportPath) Len() int { return len(x) }
+func (x byImportPath) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byImportPath) Less(i, j int) bool { return importPath(x[i]) < importPath(x[j]) }
+
+type byCommentPos []*CommentGroup
+
+func (x byCommentPos) Len() int { return len(x) }
+func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() }
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
index 62a30481d..02cf9e022 100644
--- a/src/pkg/go/ast/print.go
+++ b/src/pkg/go/ast/print.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 contains printing suppport for ASTs.
+// This file contains printing support for ASTs.
package ast
@@ -36,7 +36,7 @@ func NotNilFilter(_ string, v reflect.Value) bool {
// struct fields for which f(fieldname, fieldvalue) is true are
// are printed; all others are filtered from the output.
//
-func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
// setup printer
p := printer{
output: w,
@@ -48,7 +48,6 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
// install error handler
defer func() {
- n = p.written
if e := recover(); e != nil {
err = e.(localError).err // re-panics if it's not a localError
}
@@ -67,24 +66,23 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
// 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) {
+func Print(fset *token.FileSet, x interface{}) error {
return Fprint(os.Stdout, fset, x, NotNilFilter)
}
type printer struct {
- output io.Writer
- fset *token.FileSet
- filter FieldFilter
- ptrmap map[interface{}]int // *T -> line number
- written int // number of bytes written to output
- indent int // current indentation level
- last byte // the last byte processed by Write
- line int // current line number
+ output io.Writer
+ fset *token.FileSet
+ filter FieldFilter
+ ptrmap map[interface{}]int // *T -> line number
+ indent int // current indentation level
+ last byte // the last byte processed by Write
+ line int // current line number
}
var indent = []byte(". ")
-func (p *printer) Write(data []byte) (n int, err os.Error) {
+func (p *printer) Write(data []byte) (n int, err error) {
var m int
for i, b := range data {
// invariant: data[0:n] has been written
@@ -114,17 +112,15 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
return
}
-// localError wraps locally caught os.Errors so we can distinguish
+// localError wraps locally caught errors so we can distinguish
// them from genuine panics which we don't want to return as errors.
type localError struct {
- err os.Error
+ err error
}
// printf is a convenience wrapper that takes care of print errors.
func (p *printer) printf(format string, args ...interface{}) {
- n, err := fmt.Fprintf(p, format, args...)
- p.written += n
- if err != nil {
+ if _, err := fmt.Fprintf(p, format, args...); err != nil {
panic(localError{err})
}
}
@@ -149,7 +145,7 @@ func (p *printer) print(x reflect.Value) {
p.print(x.Elem())
case reflect.Map:
- p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
+ p.printf("%s (len = %d) {\n", x.Type(), x.Len())
p.indent++
for _, key := range x.MapKeys() {
p.print(key)
@@ -178,7 +174,7 @@ func (p *printer) print(x reflect.Value) {
p.printf("%#q", s)
return
}
- p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
+ p.printf("%s (len = %d) {\n", x.Type(), x.Len())
p.indent++
for i, n := 0, x.Len(); i < n; i++ {
p.printf("%d: ", i)
@@ -189,7 +185,7 @@ func (p *printer) print(x reflect.Value) {
p.printf("}")
case reflect.Struct:
- p.printf("%s {\n", x.Type().String())
+ p.printf("%s {\n", x.Type())
p.indent++
t := x.Type()
for i, n := 0, t.NumField(); i < n; i++ {
diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go
index f4e8f7a78..71c028e75 100644
--- a/src/pkg/go/ast/print_test.go
+++ b/src/pkg/go/ast/print_test.go
@@ -23,11 +23,10 @@ var tests = []struct {
{"foobar", "0 \"foobar\""},
// maps
- {map[string]int{"a": 1, "b": 2},
- `0 map[string] int (len = 2) {
+ {map[string]int{"a": 1},
+ `0 map[string]int (len = 1) {
1 . "a": 1
- 2 . "b": 2
- 3 }`},
+ 2 }`},
// pointers
{new(int), "0 *0"},
@@ -41,10 +40,10 @@ var tests = []struct {
4 }`},
// structs
- {struct{ x, y int }{42, 991},
- `0 struct { x int; y int } {
- 1 . x: 42
- 2 . y: 991
+ {struct{ X, Y int }{42, 991},
+ `0 struct { X int; Y int } {
+ 1 . X: 42
+ 2 . Y: 991
3 }`},
}
@@ -67,7 +66,7 @@ func TestPrint(t *testing.T) {
var buf bytes.Buffer
for _, test := range tests {
buf.Reset()
- if _, err := Fprint(&buf, nil, test.x, nil); err != nil {
+ if err := Fprint(&buf, nil, test.x, nil); err != nil {
t.Errorf("Fprint failed: %s", err)
}
if s, ts := trim(buf.String()), trim(test.s); s != ts {
diff --git a/src/pkg/go/ast/resolve.go b/src/pkg/go/ast/resolve.go
index 3927a799e..908e61c5d 100644
--- a/src/pkg/go/ast/resolve.go
+++ b/src/pkg/go/ast/resolve.go
@@ -10,17 +10,16 @@ import (
"fmt"
"go/scanner"
"go/token"
- "os"
"strconv"
)
type pkgBuilder struct {
- scanner.ErrorVector
- fset *token.FileSet
+ fset *token.FileSet
+ errors scanner.ErrorList
}
func (p *pkgBuilder) error(pos token.Pos, msg string) {
- p.Error(p.fset.Position(pos), msg)
+ p.errors.Add(p.fset.Position(pos), msg)
}
func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
@@ -61,7 +60,7 @@ func resolve(scope *Scope, ident *Ident) bool {
// 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)
+type Importer func(imports map[string]*Object, path string) (pkg *Object, err 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
@@ -72,7 +71,7 @@ type Importer func(imports map[string]*Object, path string) (pkg *Object, err os
// 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) {
+func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) {
var p pkgBuilder
p.fset = fset
@@ -114,7 +113,7 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
importErrors = true
continue
}
- path, _ := strconv.Unquote(string(spec.Path.Value))
+ path, _ := strconv.Unquote(spec.Path.Value)
pkg, err := importer(imports, path)
if err != nil {
p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
@@ -170,5 +169,6 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
pkgScope.Outer = universe // reset universe scope
}
- return &Package{pkgName, pkgScope, imports, files}, p.GetError(scanner.Sorted)
+ p.errors.Sort()
+ return &Package{pkgName, pkgScope, imports, files}, p.errors.Err()
}
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go
index 92e366980..11e6b13f1 100644
--- a/src/pkg/go/ast/scope.go
+++ b/src/pkg/go/ast/scope.go
@@ -80,7 +80,7 @@ func (s *Scope) String() string {
type Object struct {
Kind ObjKind
Name string // declared name
- Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
}
@@ -125,6 +125,14 @@ func (obj *Object) Pos() token.Pos {
if d.Label.Name == name {
return d.Label.Pos()
}
+ case *AssignStmt:
+ for _, x := range d.Lhs {
+ if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
+ return ident.Pos()
+ }
+ }
+ case *Scope:
+ // predeclared object - nothing to do for now
}
return token.NoPos
}
diff --git a/src/pkg/go/build/Makefile b/src/pkg/go/build/Makefile
deleted file mode 100644
index 349e00e80..000000000
--- a/src/pkg/go/build/Makefile
+++ /dev/null
@@ -1,22 +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.
-
-include ../../../Make.inc
-
-TARG=go/build
-GOFILES=\
- build.go\
- dir.go\
- path.go\
- syslist.go\
-
-CLEANFILES+=syslist.go pkgtest/_obj cmdtest/_obj cgotest/_obj
-
-include ../../../Make.pkg
-
-syslist.go: ../../../Make.inc Makefile
- echo '// Generated automatically by make.' >$@
- echo 'package build' >>$@
- echo 'const goosList = "$(GOOS_LIST)"' >>$@
- echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 97f92bfb6..d749aef15 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -2,250 +2,978 @@
// 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"
+ "errors"
"fmt"
+ "go/ast"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "log"
"os"
+ pathpkg "path"
"path/filepath"
- "regexp"
"runtime"
+ "sort"
+ "strconv"
"strings"
+ "unicode"
)
-// 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),
+// A Context specifies the supporting context for a build.
+type Context struct {
+ GOARCH string // target architecture
+ GOOS string // target operating system
+ GOROOT string // Go root
+ GOPATH string // Go path
+ CgoEnabled bool // whether cgo can be used
+ BuildTags []string // additional tags to recognize in +build lines
+ UseAllFiles bool // use files regardless of +build lines, file names
+ Compiler string // compiler to assume when computing target paths
+
+ // By default, Import uses the operating system's file system calls
+ // to read directories and files. To read from other sources,
+ // callers can set the following functions. They all have default
+ // behaviors that use the local file system, so clients need only set
+ // the functions whose behaviors they wish to change.
+
+ // JoinPath joins the sequence of path fragments into a single path.
+ // If JoinPath is nil, Import uses filepath.Join.
+ JoinPath func(elem ...string) string
+
+ // SplitPathList splits the path list into a slice of individual paths.
+ // If SplitPathList is nil, Import uses filepath.SplitList.
+ SplitPathList func(list string) []string
+
+ // IsAbsPath reports whether path is an absolute path.
+ // If IsAbsPath is nil, Import uses filepath.IsAbs.
+ IsAbsPath func(path string) bool
+
+ // IsDir reports whether the path names a directory.
+ // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
+ IsDir func(path string) bool
+
+ // HasSubdir reports whether dir is a subdirectory of
+ // (perhaps multiple levels below) root.
+ // If so, HasSubdir sets rel to a slash-separated path that
+ // can be joined to root to produce a path equivalent to dir.
+ // If HasSubdir is nil, Import uses an implementation built on
+ // filepath.EvalSymlinks.
+ HasSubdir func(root, dir string) (rel string, ok bool)
+
+ // ReadDir returns a slice of os.FileInfo, sorted by Name,
+ // describing the content of the named directory.
+ // If ReadDir is nil, Import uses io.ReadDir.
+ ReadDir func(dir string) (fi []os.FileInfo, err error)
+
+ // OpenFile opens a file (not a directory) for reading.
+ // If OpenFile is nil, Import uses os.Open.
+ OpenFile func(path string) (r io.ReadCloser, err error)
+}
+
+// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
+func (ctxt *Context) joinPath(elem ...string) string {
+ if f := ctxt.JoinPath; f != nil {
+ return f(elem...)
}
- b.obj = b.abs("_obj") + string(filepath.Separator)
+ return filepath.Join(elem...)
+}
- b.goarch = runtime.GOARCH
- if g := os.Getenv("GOARCH"); g != "" {
- b.goarch = g
+// splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
+func (ctxt *Context) splitPathList(s string) []string {
+ if f := ctxt.SplitPathList; f != nil {
+ return f(s)
}
- var err os.Error
- b.arch, err = ArchChar(b.goarch)
- if err != nil {
- return nil, err
+ return filepath.SplitList(s)
+}
+
+// isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs.
+func (ctxt *Context) isAbsPath(path string) bool {
+ if f := ctxt.IsAbsPath; f != nil {
+ return f(path)
}
+ return filepath.IsAbs(path)
+}
- // 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"))
+// isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
+func (ctxt *Context) isDir(path string) bool {
+ if f := ctxt.IsDir; f != nil {
+ return f(path)
}
+ fi, err := os.Stat(path)
+ return err == nil && fi.IsDir()
+}
- // .go files to be built with gc
- gofiles := b.abss(info.GoFiles...)
- s.addInput(gofiles...)
+// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
+// the local file system to answer the question.
+func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
+ if f := ctxt.HasSubdir; f != nil {
+ return f(root, dir)
+ }
- var ofiles []string // object files to be linked or packed
+ if p, err := filepath.EvalSymlinks(root); err == nil {
+ root = p
+ }
+ if p, err := filepath.EvalSymlinks(dir); err == nil {
+ dir = p
+ }
+ const sep = string(filepath.Separator)
+ root = filepath.Clean(root)
+ if !strings.HasSuffix(root, sep) {
+ root += sep
+ }
+ dir = filepath.Clean(dir)
+ if !strings.HasPrefix(dir, root) {
+ return "", false
+ }
+ return filepath.ToSlash(dir[len(root):]), true
+}
- // make build directory
- b.mkdir(b.obj)
- s.addIntermediate(b.obj)
+// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
+func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
+ if f := ctxt.ReadDir; f != nil {
+ return f(path)
+ }
+ return ioutil.ReadDir(path)
+}
- // 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...)
+// openFile calls ctxt.OpenFile (if not nil) or else os.Open.
+func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
+ if fn := ctxt.OpenFile; fn != nil {
+ return fn(path)
}
- // compile
- if len(gofiles) > 0 {
- ofile := b.obj + "_go_." + b.arch
- b.gc(ofile, gofiles...)
- ofiles = append(ofiles, ofile)
- s.addIntermediate(ofile)
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err // nil interface
}
+ return f, nil
+}
- // 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)
+// isFile determines whether path is a file by trying to open it.
+// It reuses openFile instead of adding another function to the
+// list in Context.
+func (ctxt *Context) isFile(path string) bool {
+ f, err := ctxt.openFile(path)
+ if err != nil {
+ return false
}
+ f.Close()
+ return true
+}
- if len(ofiles) == 0 {
- return nil, os.NewError("make: no object files to build")
+// gopath returns the list of Go path directories.
+func (ctxt *Context) gopath() []string {
+ var all []string
+ for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
+ if p == "" || p == ctxt.GOROOT {
+ // Empty paths are uninteresting.
+ // If the path is the GOROOT, ignore it.
+ // People sometimes set GOPATH=$GOROOT, which is useless
+ // but would cause us to find packages with import paths
+ // like "pkg/math".
+ // Do not get confused by this common mistake.
+ continue
+ }
+ all = append(all, p)
}
+ return all
+}
- // 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"
+// SrcDirs returns a list of package source root directories.
+// It draws from the current Go root and Go path but omits directories
+// that do not exist.
+func (ctxt *Context) SrcDirs() []string {
+ var all []string
+ if ctxt.GOROOT != "" {
+ dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ if ctxt.isDir(dir) {
+ all = append(all, dir)
}
- targ = filepath.Join(tree.BinDir(), bin)
- } else {
- targ = filepath.Join(tree.PkgDir(), pkg+".a")
}
+ for _, p := range ctxt.gopath() {
+ dir := ctxt.joinPath(p, "src")
+ if ctxt.isDir(dir) {
+ all = append(all, dir)
+ }
+ }
+ return all
+}
- // make target directory
- targDir, _ := filepath.Split(targ)
- b.mkdir(targDir)
+// Default is the default Context for builds.
+// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
+// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
+var Default Context = defaultContext()
+
+var cgoEnabled = map[string]bool{
+ "darwin/386": true,
+ "darwin/amd64": true,
+ "linux/386": true,
+ "linux/amd64": true,
+ "freebsd/386": true,
+ "freebsd/amd64": true,
+ "windows/386": true,
+ "windows/amd64": true,
+}
- // link binary or pack object
- if info.IsCommand() {
- b.ld(targ, ofiles...)
- } else {
- b.gopack(targ, ofiles...)
+func defaultContext() Context {
+ var c Context
+
+ c.GOARCH = envOr("GOARCH", runtime.GOARCH)
+ c.GOOS = envOr("GOOS", runtime.GOOS)
+ c.GOROOT = runtime.GOROOT()
+ c.GOPATH = envOr("GOPATH", "")
+ c.Compiler = runtime.Compiler
+
+ switch os.Getenv("CGO_ENABLED") {
+ case "1":
+ c.CgoEnabled = true
+ case "0":
+ c.CgoEnabled = false
+ default:
+ c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
}
- s.Output = append(s.Output, targ)
- return b.script, nil
+ return c
}
-// 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 envOr(name, def string) string {
+ s := os.Getenv(name)
+ if s == "" {
+ return def
+ }
+ return s
}
-func (s *Script) addInput(file ...string) {
- s.Input = append(s.Input, file...)
+// An ImportMode controls the behavior of the Import method.
+type ImportMode uint
+
+const (
+ // If FindOnly is set, Import stops after locating the directory
+ // that should contain the sources for a package. It does not
+ // read any files in the directory.
+ FindOnly ImportMode = 1 << iota
+
+ // If AllowBinary is set, Import can be satisfied by a compiled
+ // package object without corresponding sources.
+ AllowBinary
+)
+
+// A Package describes the Go package found in a directory.
+type Package struct {
+ Dir string // directory containing package sources
+ Name string // package name
+ Doc string // documentation synopsis
+ ImportPath string // import path of package ("" if unknown)
+ Root string // root of Go tree where this package lives
+ SrcRoot string // package source root directory ("" if unknown)
+ PkgRoot string // package install root directory ("" if unknown)
+ BinDir string // command install directory ("" if unknown)
+ Goroot bool // package found in Go root
+ PkgObj string // installed .a file
+
+ // Source files
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go source files that import "C"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso system object files to add to archive
+
+ // Cgo directives
+ CgoPkgConfig []string // Cgo pkg-config directives
+ CgoCFLAGS []string // Cgo CFLAGS directives
+ CgoLDFLAGS []string // Cgo LDFLAGS directives
+
+ // Dependency information
+ Imports []string // imports from GoFiles, CgoFiles
+ ImportPos map[string][]token.Position // line information for Imports
+
+ // Test information
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ TestImportPos map[string][]token.Position // line information for TestImports
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
+ XTestImportPos map[string][]token.Position // line information for XTestImports
}
-func (s *Script) addIntermediate(file ...string) {
- s.Intermediate = append(s.Intermediate, file...)
+// IsCommand reports whether the package is considered a
+// command to be installed (not just a library).
+// Packages named "main" are treated as commands.
+func (p *Package) IsCommand() bool {
+ return p.Name == "main"
}
-// 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
+// ImportDir is like Import but processes the Go package found in
+// the named directory.
+func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
+ return ctxt.Import(".", dir, mode)
+}
+
+// NoGoError is the error used by Import to describe a directory
+// containing no Go source files.
+type NoGoError struct {
+ Dir string
+}
+
+func (e *NoGoError) Error() string {
+ return "no Go source files in " + e.Dir
+}
+
+// Import returns details about the Go package named by the import path,
+// interpreting local import paths relative to the srcDir directory.
+// If the path is a local import path naming a package that can be imported
+// using a standard import path, the returned package will set p.ImportPath
+// to that path.
+//
+// In the directory containing the package, .go, .c, .h, and .s files are
+// considered part of the package except for:
+//
+// - .go files in package documentation
+// - files starting with _ or . (likely editor temporary files)
+// - files with build constraints not satisfied by the context
+//
+// If an error occurs, Import returns a non-nil error also returns a non-nil
+// *Package containing partial information.
+//
+func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
+ p := &Package{
+ ImportPath: path,
+ }
+
+ var pkga string
+ var pkgerr error
+ switch ctxt.Compiler {
+ case "gccgo":
+ dir, elem := pathpkg.Split(p.ImportPath)
+ pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
+ case "gc":
+ pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
+ default:
+ // Save error for end of function.
+ pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
+ }
+
+ binaryOnly := false
+ if IsLocalImport(path) {
+ pkga = "" // local imports have no installed path
+ if srcDir == "" {
+ return p, fmt.Errorf("import %q: import relative to unknown directory", path)
+ }
+ if !ctxt.isAbsPath(path) {
+ p.Dir = ctxt.joinPath(srcDir, path)
+ }
+ // Determine canonical import path, if any.
+ if ctxt.GOROOT != "" {
+ root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
+ if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
+ p.Goroot = true
+ p.ImportPath = sub
+ p.Root = ctxt.GOROOT
+ goto Found
+ }
+ }
+ all := ctxt.gopath()
+ for i, root := range all {
+ rootsrc := ctxt.joinPath(root, "src")
+ if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
+ // We found a potential import path for dir,
+ // but check that using it wouldn't find something
+ // else first.
+ if ctxt.GOROOT != "" {
+ if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
+ goto Found
+ }
+ }
+ for _, earlyRoot := range all[:i] {
+ if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
+ goto Found
+ }
+ }
+
+ // sub would not name some other directory instead of this one.
+ // Record it.
+ p.ImportPath = sub
+ p.Root = root
+ goto Found
+ }
+ }
+ // It's okay that we didn't find a root containing dir.
+ // Keep going with the information we have.
+ } else {
+ if strings.HasPrefix(path, "/") {
+ return p, fmt.Errorf("import %q: cannot import absolute path", path)
+ }
+ // Determine directory from import path.
+ if ctxt.GOROOT != "" {
+ dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
+ isDir := ctxt.isDir(dir)
+ binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
+ if isDir || binaryOnly {
+ p.Dir = dir
+ p.Goroot = true
+ p.Root = ctxt.GOROOT
+ goto Found
+ }
+ }
+ for _, root := range ctxt.gopath() {
+ dir := ctxt.joinPath(root, "src", path)
+ isDir := ctxt.isDir(dir)
+ binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
+ if isDir || binaryOnly {
+ p.Dir = dir
+ p.Root = root
+ goto Found
+ }
+ }
+ return p, fmt.Errorf("import %q: cannot find package", path)
+ }
+
+Found:
+ if p.Root != "" {
+ if p.Goroot {
+ p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
+ } else {
+ p.SrcRoot = ctxt.joinPath(p.Root, "src")
+ }
+ p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
+ p.BinDir = ctxt.joinPath(p.Root, "bin")
+ if pkga != "" {
+ p.PkgObj = ctxt.joinPath(p.Root, pkga)
}
}
- 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 mode&FindOnly != 0 {
+ return p, pkgerr
+ }
+ if binaryOnly && (mode&AllowBinary) != 0 {
+ return p, pkgerr
+ }
+
+ dirs, err := ctxt.readDir(p.Dir)
+ if err != nil {
+ return p, err
+ }
+
+ var Sfiles []string // files with ".S" (capital S)
+ var firstFile string
+ imported := make(map[string][]token.Position)
+ testImported := make(map[string][]token.Position)
+ xTestImported := make(map[string][]token.Position)
+ fset := token.NewFileSet()
+ for _, d := range dirs {
+ if d.IsDir() {
+ continue
+ }
+ name := d.Name()
+ if strings.HasPrefix(name, "_") ||
+ strings.HasPrefix(name, ".") {
+ continue
+ }
+ if !ctxt.UseAllFiles && !ctxt.goodOSArchFile(name) {
+ continue
+ }
+
+ i := strings.LastIndex(name, ".")
+ if i < 0 {
+ i = len(name)
+ }
+ ext := name[i:]
+ switch ext {
+ case ".go", ".c", ".s", ".h", ".S":
+ // tentatively okay - read to make sure
+ case ".syso":
+ // binary objects to add to package archive
+ // Likely of the form foo_windows.syso, but
+ // the name was vetted above with goodOSArchFile.
+ p.SysoFiles = append(p.SysoFiles, name)
+ continue
+ default:
+ // skip
+ continue
+ }
+
+ filename := ctxt.joinPath(p.Dir, name)
+ f, err := ctxt.openFile(filename)
if err != nil {
- // any error reading output files means stale
- return true
+ return p, err
}
- if m := fi.Mtime_ns; m > latest {
- latest = m
+ data, err := ioutil.ReadAll(f)
+ f.Close()
+ if err != nil {
+ return p, fmt.Errorf("read %s: %v", filename, err)
}
- }
- 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
+
+ // Look for +build comments to accept or reject the file.
+ if !ctxt.UseAllFiles && !ctxt.shouldBuild(data) {
+ continue
+ }
+
+ // Going to save the file. For non-Go files, can stop here.
+ switch ext {
+ case ".c":
+ p.CFiles = append(p.CFiles, name)
+ continue
+ case ".h":
+ p.HFiles = append(p.HFiles, name)
+ continue
+ case ".s":
+ p.SFiles = append(p.SFiles, name)
+ continue
+ case ".S":
+ Sfiles = append(Sfiles, name)
+ continue
+ }
+
+ pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
+ if err != nil {
+ return p, err
+ }
+
+ pkg := string(pf.Name.Name)
+ if pkg == "documentation" {
+ continue
+ }
+
+ isTest := strings.HasSuffix(name, "_test.go")
+ isXTest := false
+ if isTest && strings.HasSuffix(pkg, "_test") {
+ isXTest = true
+ pkg = pkg[:len(pkg)-len("_test")]
+ }
+
+ if p.Name == "" {
+ p.Name = pkg
+ firstFile = name
+ } else if pkg != p.Name {
+ return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
+ }
+ if pf.Doc != nil && p.Doc == "" {
+ p.Doc = doc.Synopsis(pf.Doc.Text())
+ }
+
+ // Record imports and information about cgo.
+ isCgo := false
+ for _, decl := range pf.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ continue
+ }
+ for _, dspec := range d.Specs {
+ spec, ok := dspec.(*ast.ImportSpec)
+ if !ok {
+ continue
+ }
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ if isXTest {
+ xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos()))
+ } else if isTest {
+ testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
+ } else {
+ imported[path] = append(imported[path], fset.Position(spec.Pos()))
+ }
+ if path == "C" {
+ if isTest {
+ return p, fmt.Errorf("use of cgo in test %s not supported", filename)
+ }
+ cg := spec.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
+ }
+ if cg != nil {
+ if err := ctxt.saveCgo(filename, p, cg); err != nil {
+ return p, err
+ }
+ }
+ isCgo = true
+ }
+ }
+ }
+ if isCgo {
+ if ctxt.CgoEnabled {
+ p.CgoFiles = append(p.CgoFiles, name)
+ }
+ } else if isXTest {
+ p.XTestGoFiles = append(p.XTestGoFiles, name)
+ } else if isTest {
+ p.TestGoFiles = append(p.TestGoFiles, name)
+ } else {
+ p.GoFiles = append(p.GoFiles, name)
}
}
- return false
+ if p.Name == "" {
+ return p, &NoGoError{p.Dir}
+ }
+
+ p.Imports, p.ImportPos = cleanImports(imported)
+ p.TestImports, p.TestImportPos = cleanImports(testImported)
+ p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
+
+ // add the .S files only if we are using cgo
+ // (which means gcc will compile them).
+ // The standard assemblers expect .s files.
+ if len(p.CgoFiles) > 0 {
+ p.SFiles = append(p.SFiles, Sfiles...)
+ sort.Strings(p.SFiles)
+ }
+
+ return p, pkgerr
}
-// 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
- }
+func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
+ all := make([]string, 0, len(m))
+ for path := range m {
+ all = append(all, path)
}
- return
+ sort.Strings(all)
+ return all, m
+}
+
+// Import is shorthand for Default.Import.
+func Import(path, srcDir string, mode ImportMode) (*Package, error) {
+ return Default.Import(path, srcDir, mode)
}
-// 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
+// ImportDir is shorthand for Default.ImportDir.
+func ImportDir(dir string, mode ImportMode) (*Package, error) {
+ return Default.ImportDir(dir, mode)
+}
+
+var slashslash = []byte("//")
+
+// shouldBuild reports whether it is okay to use this file,
+// The rule is that in the file's leading run of // comments
+// and blank lines, which must be followed by a blank line
+// (to avoid including a Go package clause doc comment),
+// lines beginning with '// +build' are taken as build directives.
+//
+// The file is accepted only if each such line lists something
+// matching the file. For example:
+//
+// // +build windows linux
+//
+// marks the file as applicable only on Windows and Linux.
+//
+func (ctxt *Context) shouldBuild(content []byte) bool {
+ // Pass 1. Identify leading run of // comments and blank lines,
+ // which must be followed by a blank line.
+ end := 0
+ p := content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 { // Blank line
+ end = cap(content) - cap(line) // &line[0] - &content[0]
+ continue
+ }
+ if !bytes.HasPrefix(line, slashslash) { // Not comment line
+ break
}
}
- if e := s.Clean(); err == nil {
- err = e
+ content = content[:end]
+
+ // Pass 2. Process each line in the run.
+ p = content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if bytes.HasPrefix(line, slashslash) {
+ line = bytes.TrimSpace(line[len(slashslash):])
+ if len(line) > 0 && line[0] == '+' {
+ // Looks like a comment +line.
+ f := strings.Fields(string(line))
+ if f[0] == "+build" {
+ ok := false
+ for _, tok := range f[1:] {
+ if ctxt.match(tok) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ return false // this one doesn't match
+ }
+ }
+ }
+ }
}
- return
+ return true // everything matches
}
-// 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
+// saveCgo saves the information from the #cgo lines in the import "C" comment.
+// These lines set CFLAGS and LDFLAGS and pkg-config directives that affect
+// the way cgo's C code is built.
+//
+// TODO(rsc): This duplicates code in cgo.
+// Once the dust settles, remove this code from cgo.
+func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
+ text := cg.Text()
+ for _, line := range strings.Split(text, "\n") {
+ orig := line
+
+ // Line is
+ // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
+ //
+ line = strings.TrimSpace(line)
+ if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
+ continue
+ }
+
+ // Split at colon.
+ line = strings.TrimSpace(line[4:])
+ i := strings.Index(line, ":")
+ if i < 0 {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+ line, argstr := line[:i], line[i+1:]
+
+ // Parse GOOS/GOARCH stuff.
+ f := strings.Fields(line)
+ if len(f) < 1 {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+
+ cond, verb := f[:len(f)-1], f[len(f)-1]
+ if len(cond) > 0 {
+ ok := false
+ for _, c := range cond {
+ if ctxt.match(c) {
+ ok = true
+ break
+ }
+ }
+ if !ok {
+ continue
+ }
+ }
+
+ args, err := splitQuoted(argstr)
+ if err != nil {
+ return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
+ }
+ for _, arg := range args {
+ if !safeName(arg) {
+ return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
+ }
+ }
+
+ switch verb {
+ case "CFLAGS":
+ di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
+ case "LDFLAGS":
+ di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
+ case "pkg-config":
+ di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
+ default:
+ return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
+ }
+ }
+ return nil
}
-func (c *Cmd) String() string {
- return strings.Join(c.Args, " ")
+var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
+
+func safeName(s string) bool {
+ if s == "" {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+ return false
+ }
+ }
+ return true
}
-// 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)
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// a b:"c d" 'e''f' "g\""
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+//
+func splitQuoted(s string) (r []string, err error) {
+ var args []string
+ arg := make([]rune, len(s))
+ escaped := false
+ quoted := false
+ quote := '\x00'
+ i := 0
+ for _, rune := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case rune == '\\':
+ escaped = true
+ continue
+ case quote != '\x00':
+ if rune == quote {
+ quote = '\x00'
+ continue
+ }
+ case rune == '"' || rune == '\'':
+ quoted = true
+ quote = rune
+ continue
+ case unicode.IsSpace(rune):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
}
+ continue
}
- return nil
+ arg[i] = rune
+ i++
}
- 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
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = errors.New("unclosed quote")
+ } else if escaped {
+ err = errors.New("unfinished escaping")
+ }
+ return args, err
+}
+
+// match returns true if the name is one of:
+//
+// $GOOS
+// $GOARCH
+// cgo (if cgo is enabled)
+// !cgo (if cgo is disabled)
+// tag (if tag is listed in ctxt.BuildTags)
+// !tag (if tag is not listed in ctxt.BuildTags)
+// a comma-separated list of any of these
+//
+func (ctxt *Context) match(name string) bool {
+ if name == "" {
+ return false
+ }
+ if i := strings.Index(name, ","); i >= 0 {
+ // comma-separated list
+ return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
+ }
+ if strings.HasPrefix(name, "!!") { // bad syntax, reject always
+ return false
+ }
+ if strings.HasPrefix(name, "!") { // negation
+ return len(name) > 1 && !ctxt.match(name[1:])
+ }
+
+ // Tags must be letters, digits, underscores.
+ // Unlike in Go identifiers, all digits are fine (e.g., "386").
+ for _, c := range name {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
+ return false
}
- defer f.Close()
- cmd.Stdout = f
}
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("command %q: %v\n%v", c, err, out)
+
+ // special tags
+ if ctxt.CgoEnabled && name == "cgo" {
+ return true
}
- return nil
+ if name == ctxt.GOOS || name == ctxt.GOARCH {
+ return true
+ }
+
+ // other tags
+ for _, tag := range ctxt.BuildTags {
+ if tag == name {
+ return true
+ }
+ }
+
+ return false
+}
+
+// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized name formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+// name_$(GOOS)_test.*
+// name_$(GOARCH)_test.*
+// name_$(GOOS)_$(GOARCH)_test.*
+//
+func (ctxt *Context) goodOSArchFile(name string) bool {
+ if dot := strings.Index(name, "."); dot != -1 {
+ name = name[:dot]
+ }
+ l := strings.Split(name, "_")
+ if n := len(l); n > 0 && l[n-1] == "test" {
+ l = l[:n-1]
+ }
+ n := len(l)
+ if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
+ return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
+ }
+ if n >= 1 && knownOS[l[n-1]] {
+ return l[n-1] == ctxt.GOOS
+ }
+ if n >= 1 && knownArch[l[n-1]] {
+ return l[n-1] == ctxt.GOARCH
+ }
+ return true
+}
+
+var knownOS = make(map[string]bool)
+var knownArch = make(map[string]bool)
+
+func init() {
+ for _, v := range strings.Fields(goosList) {
+ knownOS[v] = true
+ }
+ for _, v := range strings.Fields(goarchList) {
+ knownArch[v] = true
+ }
+}
+
+// ToolDir is the directory containing build tools.
+var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
+
+// IsLocalImport reports whether the import path is
+// a local import path, like ".", "..", "./foo", or "../foo".
+func IsLocalImport(path string) bool {
+ return path == "." || path == ".." ||
+ strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
}
// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
-func ArchChar(goarch string) (string, os.Error) {
+func ArchChar(goarch string) (string, error) {
switch goarch {
case "386":
return "8", nil
@@ -254,191 +982,5 @@ func ArchChar(goarch string) (string, os.Error) {
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
+ return "", errors.New("unsupported GOARCH " + goarch)
}
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index e59d87672..560ebad5c 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -5,57 +5,73 @@
package build
import (
- "exec"
+ "os"
"path/filepath"
+ "runtime"
"testing"
)
-var buildPkgs = []string{
- "go/build/pkgtest",
- "go/build/cmdtest",
- "go/build/cgotest",
-}
-
-const cmdtestOutput = "3"
+func TestMatch(t *testing.T) {
+ ctxt := Default
+ what := "default"
+ match := func(tag string) {
+ if !ctxt.match(tag) {
+ t.Errorf("%s context should match %s, does not", what, tag)
+ }
+ }
+ nomatch := func(tag string) {
+ if ctxt.match(tag) {
+ t.Errorf("%s context should NOT match %s, does", what, tag)
+ }
+ }
-func TestBuild(t *testing.T) {
- for _, pkg := range buildPkgs {
- tree := Path[0] // Goroot
- dir := filepath.Join(tree.SrcDir(), pkg)
+ match(runtime.GOOS + "," + runtime.GOARCH)
+ match(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",foo")
- info, err := ScanDir(dir, true)
- if err != nil {
- t.Error("ScanDir:", err)
- continue
- }
+ what = "modified"
+ ctxt.BuildTags = []string{"foo"}
+ match(runtime.GOOS + "," + runtime.GOARCH)
+ match(runtime.GOOS + "," + runtime.GOARCH + ",foo")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
+ match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
+ nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
+ nomatch("!")
+}
- s, err := Build(tree, pkg, info)
- if err != nil {
- t.Error("Build:", err)
- continue
- }
+func TestDotSlashImport(t *testing.T) {
+ p, err := ImportDir("testdata/other", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(p.Imports) != 1 || p.Imports[0] != "./file" {
+ t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
+ }
- if err := s.Run(); err != nil {
- t.Error("Run:", err)
- continue
- }
+ p1, err := Import("./file", "testdata/other", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p1.Name != "file" {
+ t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
+ }
+ dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
+ if p1.Dir != dir {
+ t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
+ }
+}
- 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)
- }
- }
+func TestLocalDirectory(t *testing.T) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
- defer func(s *Script) {
- if err := s.Nuke(); err != nil {
- t.Errorf("nuking: %v", err)
- }
- }(s)
+ p, err := ImportDir(cwd, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p.ImportPath != "go/build" {
+ t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "go/build")
}
}
diff --git a/src/pkg/go/build/cgotest/cgotest.go b/src/pkg/go/build/cgotest/cgotest.go
deleted file mode 100644
index 93bbf0688..000000000
--- a/src/pkg/go/build/cgotest/cgotest.go
+++ /dev/null
@@ -1,19 +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 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/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
new file mode 100644
index 000000000..4e9f32a03
--- /dev/null
+++ b/src/pkg/go/build/deps_test.go
@@ -0,0 +1,424 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file exercises the import parser but also checks that
+// some low-level packages do not have new dependencies added.
+
+package build_test
+
+import (
+ "go/build"
+ "sort"
+ "testing"
+)
+
+// pkgDeps defines the expected dependencies between packages in
+// the Go source tree. It is a statement of policy.
+// Changes should not be made to this map without prior discussion.
+//
+// The map contains two kinds of entries:
+// 1) Lower-case keys are standard import paths and list the
+// allowed imports in that package.
+// 2) Upper-case keys define aliases for package sets, which can then
+// be used as dependencies by other rules.
+//
+// DO NOT CHANGE THIS DATA TO FIX BUILDS.
+//
+var pkgDeps = map[string][]string{
+ // L0 is the lowest level, core, nearly unavoidable packages.
+ "errors": {},
+ "io": {"errors", "sync"},
+ "runtime": {"unsafe"},
+ "sync": {"sync/atomic"},
+ "sync/atomic": {"unsafe"},
+ "unsafe": {},
+
+ "L0": {
+ "errors",
+ "io",
+ "runtime",
+ "sync",
+ "sync/atomic",
+ "unsafe",
+ },
+
+ // L1 adds simple functions and strings processing,
+ // but not Unicode tables.
+ "math": {"unsafe"},
+ "math/cmplx": {"math"},
+ "math/rand": {"L0", "math"},
+ "sort": {"math"},
+ "strconv": {"L0", "unicode/utf8", "math"},
+ "unicode/utf16": {},
+ "unicode/utf8": {},
+
+ "L1": {
+ "L0",
+ "math",
+ "math/cmplx",
+ "math/rand",
+ "sort",
+ "strconv",
+ "unicode/utf16",
+ "unicode/utf8",
+ },
+
+ // L2 adds Unicode and strings processing.
+ "bufio": {"L0", "unicode/utf8", "bytes"},
+ "bytes": {"L0", "unicode", "unicode/utf8"},
+ "path": {"L0", "unicode/utf8", "strings"},
+ "strings": {"L0", "unicode", "unicode/utf8"},
+ "unicode": {},
+
+ "L2": {
+ "L1",
+ "bufio",
+ "bytes",
+ "path",
+ "strings",
+ "unicode",
+ },
+
+ // L3 adds reflection and some basic utility packages
+ // and interface definitions, but nothing that makes
+ // system calls.
+ "crypto": {"L2", "hash"}, // interfaces
+ "crypto/cipher": {"L2"}, // interfaces
+ "encoding/base32": {"L2"},
+ "encoding/base64": {"L2"},
+ "encoding/binary": {"L2", "reflect"},
+ "hash": {"L2"}, // interfaces
+ "hash/adler32": {"L2", "hash"},
+ "hash/crc32": {"L2", "hash"},
+ "hash/crc64": {"L2", "hash"},
+ "hash/fnv": {"L2", "hash"},
+ "image": {"L2", "image/color"}, // interfaces
+ "image/color": {"L2"}, // interfaces
+ "reflect": {"L2"},
+
+ "L3": {
+ "L2",
+ "crypto",
+ "crypto/cipher",
+ "encoding/base32",
+ "encoding/base64",
+ "encoding/binary",
+ "hash",
+ "hash/adler32",
+ "hash/crc32",
+ "hash/crc64",
+ "hash/fnv",
+ "image",
+ "image/color",
+ "reflect",
+ },
+
+ // End of linear dependency definitions.
+
+ // Operating system access.
+ "syscall": {"L0", "unicode/utf16"},
+ "time": {"L0", "syscall"},
+ "os": {"L1", "os", "syscall", "time"},
+ "path/filepath": {"L2", "os", "syscall"},
+ "io/ioutil": {"L2", "os", "path/filepath", "time"},
+ "os/exec": {"L2", "os", "syscall"},
+ "os/signal": {"L2", "os", "syscall"},
+
+ // OS enables basic operating system functionality,
+ // but not direct use of package syscall, nor os/signal.
+ "OS": {
+ "io/ioutil",
+ "os",
+ "os/exec",
+ "path/filepath",
+ "time",
+ },
+
+ // Formatted I/O: few dependencies (L1) but we must add reflect.
+ "fmt": {"L1", "os", "reflect"},
+ "log": {"L1", "os", "fmt", "time"},
+
+ // Packages used by testing must be low-level (L2+fmt).
+ "regexp": {"L2", "regexp/syntax"},
+ "regexp/syntax": {"L2"},
+ "runtime/debug": {"L2", "fmt", "io/ioutil", "os"},
+ "runtime/pprof": {"L2", "fmt", "text/tabwriter"},
+ "text/tabwriter": {"L2"},
+
+ "testing": {"L2", "flag", "fmt", "os", "runtime/pprof", "time"},
+ "testing/iotest": {"L2", "log"},
+ "testing/quick": {"L2", "flag", "fmt", "reflect"},
+
+ // L4 is defined as L3+fmt+log+time, because in general once
+ // you're using L3 packages, use of fmt, log, or time is not a big deal.
+ "L4": {
+ "L3",
+ "fmt",
+ "log",
+ "time",
+ },
+
+ // Go parser.
+ "go/ast": {"L4", "OS", "go/scanner", "go/token"},
+ "go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"},
+ "go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
+ "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
+ "go/scanner": {"L4", "OS", "go/token"},
+ "go/token": {"L4"},
+
+ "GOPARSER": {
+ "go/ast",
+ "go/doc",
+ "go/parser",
+ "go/printer",
+ "go/scanner",
+ "go/token",
+ },
+
+ // One of a kind.
+ "archive/tar": {"L4", "OS"},
+ "archive/zip": {"L4", "OS", "compress/flate"},
+ "compress/bzip2": {"L4"},
+ "compress/flate": {"L4"},
+ "compress/gzip": {"L4", "compress/flate"},
+ "compress/lzw": {"L4"},
+ "compress/zlib": {"L4", "compress/flate"},
+ "database/sql": {"L4", "database/sql/driver"},
+ "database/sql/driver": {"L4", "time"},
+ "debug/dwarf": {"L4"},
+ "debug/elf": {"L4", "OS", "debug/dwarf"},
+ "debug/gosym": {"L4"},
+ "debug/macho": {"L4", "OS", "debug/dwarf"},
+ "debug/pe": {"L4", "OS", "debug/dwarf"},
+ "encoding/ascii85": {"L4"},
+ "encoding/asn1": {"L4", "math/big"},
+ "encoding/csv": {"L4"},
+ "encoding/gob": {"L4", "OS"},
+ "encoding/hex": {"L4"},
+ "encoding/json": {"L4"},
+ "encoding/pem": {"L4"},
+ "encoding/xml": {"L4"},
+ "flag": {"L4", "OS"},
+ "go/build": {"L4", "OS", "GOPARSER"},
+ "html": {"L4"},
+ "image/draw": {"L4"},
+ "image/gif": {"L4", "compress/lzw"},
+ "image/jpeg": {"L4"},
+ "image/png": {"L4", "compress/zlib"},
+ "index/suffixarray": {"L4", "regexp"},
+ "math/big": {"L4"},
+ "mime": {"L4", "OS", "syscall"},
+ "net/url": {"L4"},
+ "text/scanner": {"L4", "OS"},
+ "text/template/parse": {"L4"},
+
+ "html/template": {
+ "L4", "OS", "encoding/json", "html", "text/template",
+ "text/template/parse",
+ },
+ "text/template": {
+ "L4", "OS", "net/url", "text/template/parse",
+ },
+
+ // Cgo.
+ "runtime/cgo": {"L0", "C"},
+ "CGO": {"C", "runtime/cgo"},
+
+ // Fake entry to satisfy the pseudo-import "C"
+ // that shows up in programs that use cgo.
+ "C": {},
+
+ "os/user": {"L4", "CGO", "syscall"},
+
+ // Basic networking.
+ // Because net must be used by any package that wants to
+ // do networking portably, it must have a small dependency set: just L1+basic os.
+ "net": {"L1", "CGO", "os", "syscall", "time"},
+
+ // NET enables use of basic network-related packages.
+ "NET": {
+ "net",
+ "mime",
+ "net/textproto",
+ "net/url",
+ },
+
+ // Uses of networking.
+ "log/syslog": {"L4", "OS", "net"},
+ "net/mail": {"L4", "NET", "OS"},
+ "net/textproto": {"L4", "OS", "net"},
+
+ // Core crypto.
+ "crypto/aes": {"L3"},
+ "crypto/des": {"L3"},
+ "crypto/hmac": {"L3"},
+ "crypto/md5": {"L3"},
+ "crypto/rc4": {"L3"},
+ "crypto/sha1": {"L3"},
+ "crypto/sha256": {"L3"},
+ "crypto/sha512": {"L3"},
+ "crypto/subtle": {"L3"},
+
+ "CRYPTO": {
+ "crypto/aes",
+ "crypto/des",
+ "crypto/hmac",
+ "crypto/md5",
+ "crypto/rc4",
+ "crypto/sha1",
+ "crypto/sha256",
+ "crypto/sha512",
+ "crypto/subtle",
+ },
+
+ // Random byte, number generation.
+ // This would be part of core crypto except that it imports
+ // math/big, which imports fmt.
+ "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall"},
+
+ // Mathematical crypto: dependencies on fmt (L4) and math/big.
+ // We could avoid some of the fmt, but math/big imports fmt anyway.
+ "crypto/dsa": {"L4", "CRYPTO", "math/big"},
+ "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big"},
+ "crypto/elliptic": {"L4", "CRYPTO", "math/big"},
+ "crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
+
+ "CRYPTO-MATH": {
+ "CRYPTO",
+ "crypto/dsa",
+ "crypto/ecdsa",
+ "crypto/elliptic",
+ "crypto/rand",
+ "crypto/rsa",
+ "encoding/asn1",
+ "math/big",
+ },
+
+ // SSL/TLS.
+ "crypto/tls": {
+ "L4", "CRYPTO-MATH", "CGO", "OS",
+ "crypto/x509", "encoding/pem", "net", "syscall",
+ },
+ "crypto/x509": {"L4", "CRYPTO-MATH", "OS", "CGO", "crypto/x509/pkix", "encoding/pem", "syscall"},
+ "crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
+
+ // Simple net+crypto-aware packages.
+ "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto"},
+ "net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"},
+
+ // HTTP, kingpin of dependencies.
+ "net/http": {
+ "L4", "NET", "OS",
+ "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+ },
+
+ // HTTP-using packages.
+ "expvar": {"L4", "OS", "encoding/json", "net/http"},
+ "net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
+ "net/http/fcgi": {"L4", "NET", "OS", "net/http", "net/http/cgi"},
+ "net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
+ "net/http/httputil": {"L4", "NET", "OS", "net/http"},
+ "net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof"},
+ "net/rpc": {"L4", "NET", "encoding/gob", "net/http", "text/template"},
+ "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
+}
+
+// isMacro reports whether p is a package dependency macro
+// (uppercase name).
+func isMacro(p string) bool {
+ return 'A' <= p[0] && p[0] <= 'Z'
+}
+
+func allowed(pkg string) map[string]bool {
+ m := map[string]bool{}
+ var allow func(string)
+ allow = func(p string) {
+ if m[p] {
+ return
+ }
+ m[p] = true // set even for macros, to avoid loop on cycle
+
+ // Upper-case names are macro-expanded.
+ if isMacro(p) {
+ for _, pp := range pkgDeps[p] {
+ allow(pp)
+ }
+ }
+ }
+ for _, pp := range pkgDeps[pkg] {
+ allow(pp)
+ }
+ return m
+}
+
+var bools = []bool{false, true}
+var geese = []string{"darwin", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}
+var goarches = []string{"386", "amd64", "arm"}
+
+type osPkg struct {
+ goos, pkg string
+}
+
+// allowedErrors are the operating systems and packages known to contain errors
+// (currently just "no Go source files")
+var allowedErrors = map[osPkg]bool{
+ osPkg{"windows", "log/syslog"}: true,
+ osPkg{"plan9", "log/syslog"}: true,
+}
+
+func TestDependencies(t *testing.T) {
+ var all []string
+
+ for k := range pkgDeps {
+ all = append(all, k)
+ }
+ sort.Strings(all)
+
+ ctxt := build.Default
+ test := func(mustImport bool) {
+ for _, pkg := range all {
+ if isMacro(pkg) {
+ continue
+ }
+ p, err := ctxt.Import(pkg, "", 0)
+ if err != nil {
+ if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
+ continue
+ }
+ // Some of the combinations we try might not
+ // be reasonable (like arm,plan9,cgo), so ignore
+ // errors for the auto-generated combinations.
+ if !mustImport {
+ continue
+ }
+ t.Errorf("%s/%s/cgo=%v %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, err)
+ continue
+ }
+ ok := allowed(pkg)
+ var bad []string
+ for _, imp := range p.Imports {
+ if !ok[imp] {
+ bad = append(bad, imp)
+ }
+ }
+ if bad != nil {
+ t.Errorf("%s/%s/cgo=%v unexpected dependency: %s imports %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, pkg, bad)
+ }
+ }
+ }
+ test(true)
+
+ if testing.Short() {
+ t.Logf("skipping other systems")
+ return
+ }
+
+ for _, ctxt.GOOS = range geese {
+ for _, ctxt.GOARCH = range goarches {
+ for _, ctxt.CgoEnabled = range bools {
+ test(false)
+ }
+ }
+ }
+}
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
deleted file mode 100644
index e0000b534..000000000
--- a/src/pkg/go/build/dir.go
+++ /dev/null
@@ -1,172 +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 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/src/pkg/go/build/doc.go b/src/pkg/go/build/doc.go
new file mode 100644
index 000000000..67c26ac7f
--- /dev/null
+++ b/src/pkg/go/build/doc.go
@@ -0,0 +1,109 @@
+// 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 gathers information about Go packages.
+//
+// Go Path
+//
+// The Go path is a list of directory trees containing Go source code.
+// It is consulted to resolve imports that cannot be found in the standard
+// Go tree. The default path is the value of the GOPATH environment
+// variable, interpreted as a path list appropriate to the operating system
+// (on Unix, the variable is a colon-separated string;
+// on Windows, a semicolon-separated string;
+// on Plan 9, a list).
+//
+// Each directory listed in the Go path must have a prescribed structure:
+//
+// The src/ directory holds source code. The path below 'src' determines
+// the import path or executable name.
+//
+// The pkg/ directory holds installed package objects.
+// As in the Go tree, each target operating system and
+// architecture pair has its own subdirectory of pkg
+// (pkg/GOOS_GOARCH).
+//
+// If DIR is a directory listed in the Go path, a package with
+// source in DIR/src/foo/bar can be imported as "foo/bar" and
+// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
+// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
+//
+// The bin/ directory holds compiled commands.
+// Each command is named for its source directory, but only
+// using the final element, not the entire path. That is, the
+// command with source in DIR/src/foo/quux is installed into
+// DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
+// so that you can add DIR/bin to your PATH to get at the
+// installed commands.
+//
+// Here's an example directory layout:
+//
+// GOPATH=/home/user/gocode
+//
+// /home/user/gocode/
+// src/
+// foo/
+// bar/ (go code in package bar)
+// x.go
+// quux/ (go code in package main)
+// y.go
+// bin/
+// quux (installed command)
+// pkg/
+// linux_amd64/
+// foo/
+// bar.a (installed package object)
+//
+// Build Constraints
+//
+// A build constraint is a line comment beginning with the directive +build
+// that lists the conditions under which a file should be included in the package.
+// Constraints may appear in any kind of source file (not just Go), but
+// they must be appear near the top of the file, preceded
+// only by blank lines and other line comments.
+//
+// A build constraint is evaluated as the OR of space-separated options;
+// each option evaluates as the AND of its comma-separated terms;
+// and each term is an alphanumeric word or, preceded by !, its negation.
+// That is, the build constraint:
+//
+// // +build linux,386 darwin,!cgo
+//
+// corresponds to the boolean formula:
+//
+// (linux AND 386) OR (darwin AND (NOT cgo))
+//
+// During a particular build, the following words are satisfied:
+//
+// - the target operating system, as spelled by runtime.GOOS
+// - the target architecture, as spelled by runtime.GOARCH
+// - "cgo", if ctxt.CgoEnabled is true
+// - any additional words listed in ctxt.BuildTags
+//
+// If a file's name, after stripping the extension and a possible _test suffix,
+// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
+// system and architecture values, then the file is considered to have an implicit
+// build constraint requiring those terms.
+//
+// To keep a file from being considered for the build:
+//
+// // +build ignore
+//
+// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
+//
+// To build a file only when using cgo, and only on Linux and OS X:
+//
+// // +build linux,cgo darwin,cgo
+//
+// Such a file is usually paired with another file implementing the
+// default functionality for other systems, which in this case would
+// carry the constraint:
+//
+// // +build !linux !darwin !cgo
+//
+// Naming a file dns_windows.go will cause it to be included only when
+// building the package for Windows; similarly, math_386.s will be included
+// only when building the package for 32-bit x86.
+//
+package build
diff --git a/src/pkg/go/build/path.go b/src/pkg/go/build/path.go
deleted file mode 100644
index e39b5f8fa..000000000
--- a/src/pkg/go/build/path.go
+++ /dev/null
@@ -1,182 +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 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/src/pkg/go/build/pkgtest/sqrt_386.s b/src/pkg/go/build/pkgtest/sqrt_386.s
deleted file mode 100644
index d0a428d52..000000000
--- a/src/pkg/go/build/pkgtest/sqrt_386.s
+++ /dev/null
@@ -1,10 +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.
-
-// func Sqrt(x float64) float64
-TEXT ·Sqrt(SB),7,$0
- FMOVD x+0(FP),F0
- FSQRT
- FMOVDP F0,r+8(FP)
- RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_amd64.s b/src/pkg/go/build/pkgtest/sqrt_amd64.s
deleted file mode 100644
index f5b329e70..000000000
--- a/src/pkg/go/build/pkgtest/sqrt_amd64.s
+++ /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.
-
-// func Sqrt(x float64) float64
-TEXT ·Sqrt(SB),7,$0
- SQRTSD x+0(FP), X0
- MOVSD X0, r+8(FP)
- RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_arm.s b/src/pkg/go/build/pkgtest/sqrt_arm.s
deleted file mode 100644
index befbb8a89..000000000
--- a/src/pkg/go/build/pkgtest/sqrt_arm.s
+++ /dev/null
@@ -1,10 +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.
-
-// func Sqrt(x float64) float64
-TEXT ·Sqrt(SB),7,$0
- MOVD x+0(FP),F0
- SQRTD F0,F0
- MOVD F0,r+8(FP)
- RET
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
new file mode 100644
index 000000000..ea21f3c74
--- /dev/null
+++ b/src/pkg/go/build/syslist.go
@@ -0,0 +1,8 @@
+// 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
+
+const goosList = "darwin freebsd linux netbsd openbsd plan9 windows "
+const goarchList = "386 amd64 arm "
diff --git a/src/pkg/go/build/syslist_test.go b/src/pkg/go/build/syslist_test.go
index eb0e5dcb6..9157faf8c 100644
--- a/src/pkg/go/build/syslist_test.go
+++ b/src/pkg/go/build/syslist_test.go
@@ -55,8 +55,8 @@ var tests = []GoodFileTest{
func TestGoodOSArch(t *testing.T) {
for _, test := range tests {
- if goodOSArch(test.name) != test.result {
- t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
+ if Default.goodOSArchFile(test.name) != test.result {
+ t.Fatalf("goodOSArchFile(%q) != %v", test.name, test.result)
}
}
}
diff --git a/src/pkg/go/build/testdata/other/file/file.go b/src/pkg/go/build/testdata/other/file/file.go
new file mode 100644
index 000000000..bbfd3e9e5
--- /dev/null
+++ b/src/pkg/go/build/testdata/other/file/file.go
@@ -0,0 +1,5 @@
+// Test data - not compiled.
+
+package file
+
+func F() {}
diff --git a/src/pkg/go/build/testdata/other/main.go b/src/pkg/go/build/testdata/other/main.go
new file mode 100644
index 000000000..e0904357c
--- /dev/null
+++ b/src/pkg/go/build/testdata/other/main.go
@@ -0,0 +1,11 @@
+// Test data - not compiled.
+
+package main
+
+import (
+ "./file"
+)
+
+func main() {
+ file.F()
+}
diff --git a/src/pkg/go/doc/Makefile b/src/pkg/go/doc/Makefile
index a5152c793..ca4948f91 100644
--- a/src/pkg/go/doc/Makefile
+++ b/src/pkg/go/doc/Makefile
@@ -2,11 +2,6 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.inc
-
-TARG=go/doc
-GOFILES=\
- comment.go\
- doc.go\
-
-include ../../../Make.pkg
+# Script to test heading detection heuristic
+headscan: headscan.go
+ go build headscan.go
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index e1989226b..6f0edd4ba 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -7,114 +7,14 @@
package doc
import (
- "go/ast"
"io"
"regexp"
"strings"
- "template" // for HTMLEscape
+ "text/template" // for HTMLEscape
+ "unicode"
+ "unicode/utf8"
)
-func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
-
-func stripTrailingWhitespace(s string) string {
- i := len(s)
- for i > 0 && isWhitespace(s[i-1]) {
- i--
- }
- return s[0:i]
-}
-
-// CommentText returns the text of comment,
-// with the comment markers - //, /*, and */ - removed.
-func CommentText(comment *ast.CommentGroup) string {
- if comment == nil {
- return ""
- }
- comments := make([]string, len(comment.List))
- for i, c := range comment.List {
- comments[i] = string(c.Text)
- }
-
- lines := make([]string, 0, 10) // most comments are less than 10 lines
- for _, c := range comments {
- // Remove comment markers.
- // The parser has given us exactly the comment text.
- switch c[1] {
- case '/':
- //-style comment
- c = c[2:]
- // Remove leading space after //, if there is one.
- // TODO(gri) This appears to be necessary in isolated
- // cases (bignum.RatFromString) - why?
- if len(c) > 0 && c[0] == ' ' {
- c = c[1:]
- }
- case '*':
- /*-style comment */
- c = c[2 : len(c)-2]
- }
-
- // Split on newlines.
- cl := strings.Split(c, "\n")
-
- // Walk lines, stripping trailing white space and adding to list.
- for _, l := range cl {
- lines = append(lines, stripTrailingWhitespace(l))
- }
- }
-
- // Remove leading blank lines; convert runs of
- // interior blank lines to a single blank line.
- n := 0
- for _, line := range lines {
- if line != "" || n > 0 && lines[n-1] != "" {
- lines[n] = line
- n++
- }
- }
- lines = lines[0:n]
-
- // Add final "" entry to get trailing newline from Join.
- if n > 0 && lines[n-1] != "" {
- lines = append(lines, "")
- }
-
- return strings.Join(lines, "\n")
-}
-
-// Split bytes into lines.
-func split(text []byte) [][]byte {
- // count lines
- n := 0
- last := 0
- for i, c := range text {
- if c == '\n' {
- last = i + 1
- n++
- }
- }
- if last < len(text) {
- n++
- }
-
- // split
- out := make([][]byte, n)
- last = 0
- n = 0
- for i, c := range text {
- if c == '\n' {
- out[n] = text[last : i+1]
- last = i + 1
- n++
- }
- }
- if last < len(text) {
- out[n] = text[last:]
- }
-
- return out
-}
-
var (
ldquo = []byte("&ldquo;")
rdquo = []byte("&rdquo;")
@@ -122,13 +22,13 @@ var (
// Escape comment text for HTML. If nice is set,
// also turn `` into &ldquo; and '' into &rdquo;.
-func commentEscape(w io.Writer, s []byte, nice bool) {
+func commentEscape(w io.Writer, text string, nice bool) {
last := 0
if nice {
- for i := 0; i < len(s)-1; i++ {
- ch := s[i]
- if ch == s[i+1] && (ch == '`' || ch == '\'') {
- template.HTMLEscape(w, s[last:i])
+ for i := 0; i < len(text)-1; i++ {
+ ch := text[i]
+ if ch == text[i+1] && (ch == '`' || ch == '\'') {
+ template.HTMLEscape(w, []byte(text[last:i]))
last = i + 2
switch ch {
case '`':
@@ -140,7 +40,7 @@ func commentEscape(w io.Writer, s []byte, nice bool) {
}
}
}
- template.HTMLEscape(w, s[last:])
+ template.HTMLEscape(w, []byte(text[last:]))
}
const (
@@ -156,7 +56,7 @@ const (
filePart + `([:.,]` + filePart + `)*`
)
-var matchRx = regexp.MustCompile(`(` + identRx + `)|(` + urlRx + `)`)
+var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
var (
html_a = []byte(`<a href="`)
@@ -168,6 +68,9 @@ var (
html_endp = []byte("</p>\n")
html_pre = []byte("<pre>")
html_endpre = []byte("</pre>\n")
+ html_h = []byte(`<h3 id="`)
+ html_hq = []byte(`">`)
+ html_endh = []byte("</h3>\n")
)
// Emphasize and escape a line of text for HTML. URLs are converted into links;
@@ -178,13 +81,13 @@ var (
// and the word is converted into a link. If nice is set, the remaining text's
// appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
// and '' into &rdquo;).
-func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
+func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
for {
- m := matchRx.FindSubmatchIndex(line)
+ m := matchRx.FindStringSubmatchIndex(line)
if m == nil {
break
}
- // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
+ // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is urlRx)
// write text before match
commentEscape(w, line[0:m[0]], nice)
@@ -196,8 +99,8 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
if words != nil {
url, italics = words[string(match)]
}
- if m[2] < 0 {
- // didn't match against first parenthesized sub-regexp; must be match against urlRx
+ if m[2] >= 0 {
+ // match against first parenthesized sub-regexp; must be match against urlRx
if !italics {
// no alternative URL in words list, use match instead
url = string(match)
@@ -228,7 +131,7 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
commentEscape(w, line, nice)
}
-func indentLen(s []byte) int {
+func indentLen(s string) int {
i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
i++
@@ -236,9 +139,11 @@ func indentLen(s []byte) int {
return i
}
-func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
+func isBlank(s string) bool {
+ return len(s) == 0 || (len(s) == 1 && s[0] == '\n')
+}
-func commonPrefix(a, b []byte) []byte {
+func commonPrefix(a, b string) string {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] {
i++
@@ -246,7 +151,7 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-func unindent(block [][]byte) {
+func unindent(block []string) {
if len(block) == 0 {
return
}
@@ -268,7 +173,66 @@ func unindent(block [][]byte) {
}
}
-// Convert comment text to formatted HTML.
+// heading returns the trimmed line if it passes as a section heading;
+// otherwise it returns the empty string.
+func heading(line string) string {
+ line = strings.TrimSpace(line)
+ if len(line) == 0 {
+ return ""
+ }
+
+ // a heading must start with an uppercase letter
+ r, _ := utf8.DecodeRuneInString(line)
+ if !unicode.IsLetter(r) || !unicode.IsUpper(r) {
+ return ""
+ }
+
+ // it must end in a letter or digit:
+ r, _ = utf8.DecodeLastRuneInString(line)
+ if !unicode.IsLetter(r) && !unicode.IsDigit(r) {
+ return ""
+ }
+
+ // exclude lines with illegal characters
+ if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
+ return ""
+ }
+
+ // allow "'" for possessive "'s" only
+ for b := line; ; {
+ i := strings.IndexRune(b, '\'')
+ if i < 0 {
+ break
+ }
+ if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') {
+ return "" // not followed by "s "
+ }
+ b = b[i+2:]
+ }
+
+ return line
+}
+
+type op int
+
+const (
+ opPara op = iota
+ opHead
+ opPre
+)
+
+type block struct {
+ op op
+ lines []string
+}
+
+var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`)
+
+func anchorID(line string) string {
+ return nonAlphaNumRx.ReplaceAllString(line, "_")
+}
+
+// ToHTML converts comment text to formatted HTML.
// The comment was prepared by DocReader,
// so it is known not to have leading, trailing blank lines
// nor to have trailing spaces at the end of lines.
@@ -276,6 +240,7 @@ func unindent(block [][]byte) {
//
// Turn each run of multiple \n into </p><p>.
// Turn each run of indented lines into a <pre> block without indent.
+// Enclose headings with header tags.
//
// URLs in the comment text are converted into links; if the URL also appears
// in the words map, the link is taken from the map (if the corresponding map
@@ -284,23 +249,57 @@ func unindent(block [][]byte) {
// Go identifiers that appear in the words map are italicized; if the corresponding
// map value is not the empty string, it is considered a URL and the word is converted
// into a link.
-func ToHTML(w io.Writer, s []byte, words map[string]string) {
- inpara := false
-
- close := func() {
- if inpara {
+func ToHTML(w io.Writer, text string, words map[string]string) {
+ for _, b := range blocks(text) {
+ switch b.op {
+ case opPara:
+ w.Write(html_p)
+ for _, line := range b.lines {
+ emphasize(w, line, words, true)
+ }
w.Write(html_endp)
- inpara = false
+ case opHead:
+ w.Write(html_h)
+ id := ""
+ for _, line := range b.lines {
+ if id == "" {
+ id = anchorID(line)
+ w.Write([]byte(id))
+ w.Write(html_hq)
+ }
+ commentEscape(w, line, true)
+ }
+ if id == "" {
+ w.Write(html_hq)
+ }
+ w.Write(html_endh)
+ case opPre:
+ w.Write(html_pre)
+ for _, line := range b.lines {
+ emphasize(w, line, nil, false)
+ }
+ w.Write(html_endpre)
}
}
- open := func() {
- if !inpara {
- w.Write(html_p)
- inpara = true
+}
+
+func blocks(text string) []block {
+ var (
+ out []block
+ para []string
+
+ lastWasBlank = false
+ lastWasHeading = false
+ )
+
+ close := func() {
+ if para != nil {
+ out = append(out, block{opPara, para})
+ para = nil
}
}
- lines := split(s)
+ lines := strings.SplitAfter(text, "\n")
unindent(lines)
for i := 0; i < len(lines); {
line := lines[i]
@@ -308,6 +307,7 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
// close paragraph
close()
i++
+ lastWasBlank = true
continue
}
if indentLen(line) > 0 {
@@ -323,23 +323,119 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
for j > i && isBlank(lines[j-1]) {
j--
}
- block := lines[i:j]
+ pre := lines[i:j]
i = j
- unindent(block)
+ unindent(pre)
// put those lines in a pre block
- w.Write(html_pre)
- for _, line := range block {
- emphasize(w, line, nil, false) // no nice text formatting
- }
- w.Write(html_endpre)
+ out = append(out, block{opPre, pre})
+ lastWasHeading = false
continue
}
+
+ if lastWasBlank && !lastWasHeading && i+2 < len(lines) &&
+ isBlank(lines[i+1]) && !isBlank(lines[i+2]) && indentLen(lines[i+2]) == 0 {
+ // current line is non-blank, surrounded by blank lines
+ // and the next non-blank line is not indented: this
+ // might be a heading.
+ if head := heading(line); head != "" {
+ close()
+ out = append(out, block{opHead, []string{head}})
+ i += 2
+ lastWasHeading = true
+ continue
+ }
+ }
+
// open paragraph
- open()
- emphasize(w, lines[i], words, true) // nice text formatting
+ lastWasBlank = false
+ lastWasHeading = false
+ para = append(para, lines[i])
i++
}
close()
+
+ return out
+}
+
+// ToText prepares comment text for presentation in textual output.
+// It wraps paragraphs of text to width or fewer Unicode code points
+// and then prefixes each line with the indent. In preformatted sections
+// (such as program text), it prefixes each non-blank line with preIndent.
+func ToText(w io.Writer, text string, indent, preIndent string, width int) {
+ l := lineWrapper{
+ out: w,
+ width: width,
+ indent: indent,
+ }
+ for _, b := range blocks(text) {
+ switch b.op {
+ case opPara:
+ // l.write will add leading newline if required
+ for _, line := range b.lines {
+ l.write(line)
+ }
+ l.flush()
+ case opHead:
+ w.Write(nl)
+ for _, line := range b.lines {
+ l.write(line + "\n")
+ }
+ l.flush()
+ case opPre:
+ w.Write(nl)
+ for _, line := range b.lines {
+ if !isBlank(line) {
+ w.Write([]byte(preIndent))
+ w.Write([]byte(line))
+ }
+ }
+ }
+ }
+}
+
+type lineWrapper struct {
+ out io.Writer
+ printed bool
+ width int
+ indent string
+ n int
+ pendSpace int
+}
+
+var nl = []byte("\n")
+var space = []byte(" ")
+
+func (l *lineWrapper) write(text string) {
+ if l.n == 0 && l.printed {
+ l.out.Write(nl) // blank line before new paragraph
+ }
+ l.printed = true
+
+ for _, f := range strings.Fields(text) {
+ w := utf8.RuneCountInString(f)
+ // wrap if line is too long
+ if l.n > 0 && l.n+l.pendSpace+w > l.width {
+ l.out.Write(nl)
+ l.n = 0
+ l.pendSpace = 0
+ }
+ if l.n == 0 {
+ l.out.Write([]byte(l.indent))
+ }
+ l.out.Write(space[:l.pendSpace])
+ l.out.Write([]byte(f))
+ l.n += l.pendSpace + w
+ l.pendSpace = 1
+ }
+}
+
+func (l *lineWrapper) flush() {
+ if l.n == 0 {
+ return
+ }
+ l.out.Write(nl)
+ l.pendSpace = 0
+ l.n = 0
}
diff --git a/src/pkg/go/doc/comment_test.go b/src/pkg/go/doc/comment_test.go
new file mode 100644
index 000000000..aa21b8d1b
--- /dev/null
+++ b/src/pkg/go/doc/comment_test.go
@@ -0,0 +1,109 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+ "bytes"
+ "reflect"
+ "testing"
+)
+
+var headingTests = []struct {
+ line string
+ ok bool
+}{
+ {"Section", true},
+ {"A typical usage", true},
+ {"ΔΛΞ is Greek", true},
+ {"Foo 42", true},
+ {"", false},
+ {"section", false},
+ {"A typical usage:", false},
+ {"This code:", false},
+ {"δ is Greek", false},
+ {"Foo §", false},
+ {"Fermat's Last Sentence", true},
+ {"Fermat's", true},
+ {"'sX", false},
+ {"Ted 'Too' Bar", false},
+ {"Use n+m", false},
+ {"Scanning:", false},
+ {"N:M", false},
+}
+
+func TestIsHeading(t *testing.T) {
+ for _, tt := range headingTests {
+ if h := heading(tt.line); (len(h) > 0) != tt.ok {
+ t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok)
+ }
+ }
+}
+
+var blocksTests = []struct {
+ in string
+ out []block
+}{
+ {
+ in: `Para 1.
+Para 1 line 2.
+
+Para 2.
+
+Section
+
+Para 3.
+
+ pre
+ pre1
+
+Para 4.
+ pre
+ pre2
+`,
+ out: []block{
+ {opPara, []string{"Para 1.\n", "Para 1 line 2.\n"}},
+ {opPara, []string{"Para 2.\n"}},
+ {opHead, []string{"Section"}},
+ {opPara, []string{"Para 3.\n"}},
+ {opPre, []string{"pre\n", "pre1\n"}},
+ {opPara, []string{"Para 4.\n"}},
+ {opPre, []string{"pre\n", "pre2\n"}},
+ },
+ },
+}
+
+func TestBlocks(t *testing.T) {
+ for i, tt := range blocksTests {
+ b := blocks(tt.in)
+ if !reflect.DeepEqual(b, tt.out) {
+ t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, b, tt.out)
+ }
+ }
+}
+
+var emphasizeTests = []struct {
+ in string
+ out string
+}{
+ {"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
+ {"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
+ {"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
+ {"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`},
+ {"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`},
+ {"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
+ {"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
+ {"javascript://is/not/linked", "javascript://is/not/linked"},
+}
+
+func TestEmphasize(t *testing.T) {
+ for i, tt := range emphasizeTests {
+ var buf bytes.Buffer
+ emphasize(&buf, tt.in, nil, true)
+ out := buf.String()
+ if out != tt.out {
+ t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index c7fed9784..9c606315d 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -8,634 +8,90 @@ package doc
import (
"go/ast"
"go/token"
- "regexp"
- "sort"
)
-// ----------------------------------------------------------------------------
+// Package is the documentation for an entire package.
+type Package struct {
+ Doc string
+ Name string
+ ImportPath string
+ Imports []string
+ Filenames []string
+ Bugs []string
-type typeDoc struct {
- // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
- // if the type declaration hasn't been seen yet, decl is nil
- decl *ast.GenDecl
- // values, factory functions, and methods associated with the type
- values []*ast.GenDecl // consts and vars
- factories map[string]*ast.FuncDecl
- methods map[string]*ast.FuncDecl
+ // declarations
+ Consts []*Value
+ Types []*Type
+ Vars []*Value
+ Funcs []*Func
}
-// docReader accumulates documentation for a single package.
-// It modifies the AST: Comments (declaration documentation)
-// that have been collected by the DocReader are set to nil
-// in the respective AST nodes so that they are not printed
-// twice (once when printing the documentation and once when
-// printing the corresponding AST node).
-//
-type docReader struct {
- doc *ast.CommentGroup // package documentation, if any
- pkgName string
- values []*ast.GenDecl // consts and vars
- types map[string]*typeDoc
- funcs map[string]*ast.FuncDecl
- bugs []*ast.CommentGroup
-}
-
-func (doc *docReader) init(pkgName string) {
- doc.pkgName = pkgName
- doc.types = make(map[string]*typeDoc)
- doc.funcs = make(map[string]*ast.FuncDecl)
-}
-
-func (doc *docReader) addDoc(comments *ast.CommentGroup) {
- if doc.doc == nil {
- // common case: just one package comment
- doc.doc = comments
- return
- }
-
- // More than one package comment: Usually there will be only
- // one file with a package comment, but it's better to collect
- // all comments than drop them on the floor.
- // (This code isn't particularly clever - no amortized doubling is
- // used - but this situation occurs rarely and is not time-critical.)
- n1 := len(doc.doc.List)
- n2 := len(comments.List)
- list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
- copy(list, doc.doc.List)
- list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
- copy(list[n1+1:], comments.List)
- doc.doc = &ast.CommentGroup{list}
-}
-
-func (doc *docReader) addType(decl *ast.GenDecl) {
- spec := decl.Specs[0].(*ast.TypeSpec)
- typ := doc.lookupTypeDoc(spec.Name.Name)
- // typ should always be != nil since declared types
- // are always named - be conservative and check
- if typ != nil {
- // a type should be added at most once, so typ.decl
- // should be nil - if it isn't, simply overwrite it
- typ.decl = decl
- }
-}
-
-func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
- if name == "" {
- return nil // no type docs for anonymous types
- }
- if tdoc, found := doc.types[name]; found {
- return tdoc
- }
- // type wasn't found - add one without declaration
- tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
- doc.types[name] = tdoc
- return tdoc
-}
-
-func baseTypeName(typ ast.Expr) string {
- switch t := typ.(type) {
- case *ast.Ident:
- // if the type is not exported, the effect to
- // a client is as if there were no type name
- if t.IsExported() {
- return t.Name
- }
- case *ast.StarExpr:
- return baseTypeName(t.X)
- }
- return ""
-}
-
-func (doc *docReader) addValue(decl *ast.GenDecl) {
- // determine if decl should be associated with a type
- // Heuristic: For each typed entry, determine the type name, if any.
- // If there is exactly one type name that is sufficiently
- // frequent, associate the decl with the respective type.
- domName := ""
- domFreq := 0
- prev := ""
- for _, s := range decl.Specs {
- if v, ok := s.(*ast.ValueSpec); ok {
- name := ""
- switch {
- case v.Type != nil:
- // a type is present; determine its name
- name = baseTypeName(v.Type)
- case decl.Tok == token.CONST:
- // no type is present but we have a constant declaration;
- // use the previous type name (w/o more type information
- // we cannot handle the case of unnamed variables with
- // initializer expressions except for some trivial cases)
- name = prev
- }
- if name != "" {
- // entry has a named type
- if domName != "" && domName != name {
- // more than one type name - do not associate
- // with any type
- domName = ""
- break
- }
- domName = name
- domFreq++
- }
- prev = name
- }
- }
-
- // determine values list
- const threshold = 0.75
- values := &doc.values
- if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
- // typed entries are sufficiently frequent
- typ := doc.lookupTypeDoc(domName)
- if typ != nil {
- values = &typ.values // associate with that type
- }
- }
-
- *values = append(*values, decl)
-}
-
-// Helper function to set the table entry for function f. Makes sure that
-// at least one f with associated documentation is stored in table, if there
-// are multiple f's with the same name.
-func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
- name := f.Name.Name
- if g, exists := table[name]; exists && g.Doc != nil {
- // a function with the same name has already been registered;
- // since it has documentation, assume f is simply another
- // implementation and ignore it
- // TODO(gri) consider collecting all functions, or at least
- // all comments
- return
- }
- // function doesn't exist or has no documentation; use f
- table[name] = f
-}
-
-func (doc *docReader) addFunc(fun *ast.FuncDecl) {
- name := fun.Name.Name
-
- // determine if it should be associated with a type
- if fun.Recv != nil {
- // method
- typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
- if typ != nil {
- // exported receiver type
- setFunc(typ.methods, fun)
- }
- // otherwise don't show the method
- // TODO(gri): There may be exported methods of non-exported types
- // that can be called because of exported values (consts, vars, or
- // function results) of that type. Could determine if that is the
- // case and then show those methods in an appropriate section.
- return
- }
-
- // perhaps a factory function
- // determine result type, if any
- if fun.Type.Results.NumFields() >= 1 {
- res := fun.Type.Results.List[0]
- if len(res.Names) <= 1 {
- // exactly one (named or anonymous) result associated
- // with the first type in result signature (there may
- // be more than one result)
- tname := baseTypeName(res.Type)
- typ := doc.lookupTypeDoc(tname)
- if typ != nil {
- // named and exported result type
-
- // Work-around for failure of heuristic: In package os
- // too many functions are considered factory functions
- // for the Error type. Eliminate manually for now as
- // this appears to be the only important case in the
- // current library where the heuristic fails.
- if doc.pkgName == "os" && tname == "Error" &&
- name != "NewError" && name != "NewSyscallError" {
- // not a factory function for os.Error
- setFunc(doc.funcs, fun) // treat as ordinary function
- return
- }
-
- setFunc(typ.factories, fun)
- return
- }
- }
- }
-
- // ordinary function
- setFunc(doc.funcs, fun)
-}
-
-func (doc *docReader) addDecl(decl ast.Decl) {
- switch d := decl.(type) {
- case *ast.GenDecl:
- if len(d.Specs) > 0 {
- switch d.Tok {
- case token.CONST, token.VAR:
- // constants and variables are always handled as a group
- doc.addValue(d)
- case token.TYPE:
- // types are handled individually
- for _, spec := range d.Specs {
- // make a (fake) GenDecl node for this TypeSpec
- // (we need to do this here - as opposed to just
- // for printing - so we don't lose the GenDecl
- // documentation)
- //
- // TODO(gri): Consider just collecting the TypeSpec
- // node (and copy in the GenDecl.doc if there is no
- // doc in the TypeSpec - this is currently done in
- // makeTypeDocs below). Simpler data structures, but
- // would lose GenDecl documentation if the TypeSpec
- // has documentation as well.
- doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
- // A new GenDecl node is created, no need to nil out d.Doc.
- }
- }
- }
- case *ast.FuncDecl:
- doc.addFunc(d)
- }
-}
-
-func copyCommentList(list []*ast.Comment) []*ast.Comment {
- return append([]*ast.Comment(nil), list...)
-}
-
-var (
- bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
- bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char
-)
-
-// addFile adds the AST for a source file to the docReader.
-// Adding the same AST multiple times is a no-op.
-//
-func (doc *docReader) addFile(src *ast.File) {
- // add package documentation
- if src.Doc != nil {
- doc.addDoc(src.Doc)
- src.Doc = nil // doc consumed - remove from ast.File node
- }
-
- // add all declarations
- for _, decl := range src.Decls {
- doc.addDecl(decl)
- }
-
- // collect BUG(...) comments
- for _, c := range src.Comments {
- text := c.List[0].Text
- if m := bug_markers.FindStringIndex(text); m != nil {
- // found a BUG comment; maybe empty
- if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
- // non-empty BUG comment; collect comment without BUG prefix
- list := copyCommentList(c.List)
- list[0].Text = text[m[1]:]
- doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
- }
- }
- }
- src.Comments = nil // consumed unassociated comments - remove from ast.File node
-}
-
-func NewFileDoc(file *ast.File) *PackageDoc {
- var r docReader
- r.init(file.Name.Name)
- r.addFile(file)
- return r.newDoc("", nil)
-}
-
-func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
- var r docReader
- r.init(pkg.Name)
- filenames := make([]string, len(pkg.Files))
- i := 0
- for filename, f := range pkg.Files {
- r.addFile(f)
- filenames[i] = filename
- i++
- }
- return r.newDoc(importpath, filenames)
-}
-
-// ----------------------------------------------------------------------------
-// Conversion to external representation
-
-// ValueDoc is the documentation for a group of declared
-// values, either vars or consts.
-//
-type ValueDoc struct {
+// Value is the documentation for a (possibly grouped) var or const declaration.
+type Value struct {
Doc string
+ Names []string // var or const names in declaration order
Decl *ast.GenDecl
- order int
-}
-
-type sortValueDoc []*ValueDoc
-func (p sortValueDoc) Len() int { return len(p) }
-func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-
-func declName(d *ast.GenDecl) string {
- if len(d.Specs) != 1 {
- return ""
- }
-
- switch v := d.Specs[0].(type) {
- case *ast.ValueSpec:
- return v.Names[0].Name
- case *ast.TypeSpec:
- return v.Name.Name
- }
-
- return ""
+ order int
}
-func (p sortValueDoc) Less(i, j int) bool {
- // sort by name
- // pull blocks (name = "") up to top
- // in original order
- if ni, nj := declName(p[i].Decl), declName(p[j].Decl); ni != nj {
- return ni < nj
- }
- return p[i].order < p[j].order
-}
+// Type is the documentation for a type declaration.
+type Type struct {
+ Doc string
+ Name string
+ Decl *ast.GenDecl
-func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
- d := make([]*ValueDoc, len(list)) // big enough in any case
- n := 0
- for i, decl := range list {
- if decl.Tok == tok {
- d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
- n++
- decl.Doc = nil // doc consumed - removed from AST
- }
- }
- d = d[0:n]
- sort.Sort(sortValueDoc(d))
- return d
+ // associated declarations
+ Consts []*Value // sorted list of constants of (mostly) this type
+ Vars []*Value // sorted list of variables of (mostly) this type
+ Funcs []*Func // sorted list of functions returning this type
+ Methods []*Func // sorted list of methods (including embedded ones) of this type
}
-// FuncDoc is the documentation for a func declaration,
-// either a top-level function or a method function.
-//
-type FuncDoc struct {
+// Func is the documentation for a func declaration.
+type Func struct {
Doc string
- Recv ast.Expr // TODO(rsc): Would like string here
Name string
Decl *ast.FuncDecl
-}
-
-type sortFuncDoc []*FuncDoc
-func (p sortFuncDoc) Len() int { return len(p) }
-func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
-
-func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
- d := make([]*FuncDoc, len(m))
- i := 0
- for _, f := range m {
- doc := new(FuncDoc)
- doc.Doc = CommentText(f.Doc)
- f.Doc = nil // doc consumed - remove from ast.FuncDecl node
- if f.Recv != nil {
- doc.Recv = f.Recv.List[0].Type
- }
- doc.Name = f.Name.Name
- doc.Decl = f
- d[i] = doc
- i++
- }
- sort.Sort(sortFuncDoc(d))
- return d
+ // methods
+ // (for functions, these fields have the respective zero value)
+ Recv string // actual receiver "T" or "*T"
+ Orig string // original receiver "T" or "*T"
+ Level int // embedding level; 0 means not embedded
}
-// TypeDoc is the documentation for a declared type.
-// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
-// Factories is a sorted list of factory functions that return that type.
-// Methods is a sorted list of method functions on that type.
-type TypeDoc struct {
- Doc string
- Type *ast.TypeSpec
- Consts []*ValueDoc
- Vars []*ValueDoc
- Factories []*FuncDoc
- Methods []*FuncDoc
- Decl *ast.GenDecl
- order int
-}
+// Mode values control the operation of New.
+type Mode int
-type sortTypeDoc []*TypeDoc
+const (
+ // extract documentation for all package-level declarations,
+ // not just exported ones
+ AllDecls Mode = 1 << iota
-func (p sortTypeDoc) Len() int { return len(p) }
-func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-func (p sortTypeDoc) Less(i, j int) bool {
- // sort by name
- // pull blocks (name = "") up to top
- // in original order
- if ni, nj := p[i].Type.Name.Name, p[j].Type.Name.Name; ni != nj {
- return ni < nj
- }
- return p[i].order < p[j].order
-}
-
-// NOTE(rsc): This would appear not to be correct for type ( )
-// blocks, but the doc extractor above has split them into
-// individual declarations.
-func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
- d := make([]*TypeDoc, len(m))
- i := 0
- for _, old := range m {
- // all typeDocs should have a declaration associated with
- // them after processing an entire package - be conservative
- // and check
- if decl := old.decl; decl != nil {
- typespec := decl.Specs[0].(*ast.TypeSpec)
- t := new(TypeDoc)
- doc := typespec.Doc
- typespec.Doc = nil // doc consumed - remove from ast.TypeSpec node
- if doc == nil {
- // no doc associated with the spec, use the declaration doc, if any
- doc = decl.Doc
- }
- decl.Doc = nil // doc consumed - remove from ast.Decl node
- t.Doc = CommentText(doc)
- t.Type = typespec
- t.Consts = makeValueDocs(old.values, token.CONST)
- t.Vars = makeValueDocs(old.values, token.VAR)
- t.Factories = makeFuncDocs(old.factories)
- t.Methods = makeFuncDocs(old.methods)
- t.Decl = old.decl
- t.order = i
- d[i] = t
- i++
- } else {
- // no corresponding type declaration found - move any associated
- // values, factory functions, and methods back to the top-level
- // so that they are not lost (this should only happen if a package
- // file containing the explicit type declaration is missing or if
- // an unqualified type name was used after a "." import)
- // 1) move values
- doc.values = append(doc.values, old.values...)
- // 2) move factory functions
- for name, f := range old.factories {
- doc.funcs[name] = f
- }
- // 3) move methods
- for name, f := range old.methods {
- // don't overwrite functions with the same name
- if _, found := doc.funcs[name]; !found {
- doc.funcs[name] = f
- }
- }
- }
- }
- d = d[0:i] // some types may have been ignored
- sort.Sort(sortTypeDoc(d))
- return d
-}
-
-func makeBugDocs(list []*ast.CommentGroup) []string {
- d := make([]string, len(list))
- for i, g := range list {
- d[i] = CommentText(g)
- }
- return d
-}
-
-// PackageDoc is the documentation for an entire package.
-//
-type PackageDoc struct {
- PackageName string
- ImportPath string
- Filenames []string
- Doc string
- Consts []*ValueDoc
- Types []*TypeDoc
- Vars []*ValueDoc
- Funcs []*FuncDoc
- Bugs []string
-}
+ // show all embedded methods, not just the ones of
+ // invisible (unexported) anonymous fields
+ AllMethods
+)
-// newDoc returns the accumulated documentation for the package.
+// New computes the package documentation for the given package AST.
+// New takes ownership of the AST pkg and may edit or overwrite it.
//
-func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
- p := new(PackageDoc)
- p.PackageName = doc.pkgName
- p.ImportPath = importpath
- sort.Strings(filenames)
- p.Filenames = filenames
- p.Doc = CommentText(doc.doc)
- // makeTypeDocs may extend the list of doc.values and
- // doc.funcs and thus must be called before any other
- // function consuming those lists
- p.Types = doc.makeTypeDocs(doc.types)
- p.Consts = makeValueDocs(doc.values, token.CONST)
- p.Vars = makeValueDocs(doc.values, token.VAR)
- p.Funcs = makeFuncDocs(doc.funcs)
- p.Bugs = makeBugDocs(doc.bugs)
- return p
-}
-
-// ----------------------------------------------------------------------------
-// Filtering by name
-
-type Filter func(string) bool
-
-func 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
- }
- }
- }
+func New(pkg *ast.Package, importPath string, mode Mode) *Package {
+ var r reader
+ r.readPackage(pkg, mode)
+ r.computeMethodSets()
+ r.cleanupTypes()
+ return &Package{
+ Doc: r.doc,
+ Name: pkg.Name,
+ ImportPath: importPath,
+ Imports: sortedKeys(r.imports),
+ Filenames: r.filenames,
+ Bugs: r.bugs,
+ Consts: sortedValues(r.values, token.CONST),
+ Types: sortedTypes(r.types, mode&AllMethods != 0),
+ Vars: sortedValues(r.values, token.VAR),
+ Funcs: sortedFuncs(r.funcs, true),
}
- return false
-}
-
-func matchDecl(d *ast.GenDecl, f Filter) bool {
- for _, d := range d.Specs {
- switch v := d.(type) {
- case *ast.ValueSpec:
- for _, name := range v.Names {
- if f(name.Name) {
- return true
- }
- }
- case *ast.TypeSpec:
- if f(v.Name.Name) {
- return true
- }
- 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 {
- if matchDecl(vd.Decl, f) {
- a[w] = vd
- w++
- }
- }
- return a[0:w]
-}
-
-func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
- w := 0
- for _, fd := range a {
- if f(fd.Name) {
- a[w] = fd
- w++
- }
- }
- return a[0:w]
-}
-
-func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
- w := 0
- for _, td := range a {
- n := 0 // number of matches
- if matchDecl(td.Decl, f) {
- n = 1
- } else {
- // type name doesn't match, but we may have matching consts, vars, factories or methods
- td.Consts = filterValueDocs(td.Consts, f)
- td.Vars = filterValueDocs(td.Vars, f)
- td.Factories = filterFuncDocs(td.Factories, f)
- td.Methods = filterFuncDocs(td.Methods, f)
- n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
- }
- if n > 0 {
- a[w] = td
- w++
- }
- }
- return a[0:w]
-}
-
-// Filter eliminates documentation for names that don't pass through the filter f.
-// TODO: Recognize "Type.Method" as a name.
-//
-func (p *PackageDoc) Filter(f Filter) {
- p.Consts = filterValueDocs(p.Consts, f)
- p.Vars = filterValueDocs(p.Vars, f)
- p.Types = filterTypeDocs(p.Types, f)
- p.Funcs = filterFuncDocs(p.Funcs, f)
- p.Doc = "" // don't show top-level package doc
}
diff --git a/src/pkg/go/doc/doc_test.go b/src/pkg/go/doc/doc_test.go
new file mode 100644
index 000000000..f957ede4a
--- /dev/null
+++ b/src/pkg/go/doc/doc_test.go
@@ -0,0 +1,136 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+ "text/template"
+)
+
+var update = flag.Bool("update", false, "update golden (.out) files")
+var files = flag.String("files", "", "consider only Go test files matching this regular expression")
+
+const dataDir = "testdata"
+
+var templateTxt = readTemplate("template.txt")
+
+func readTemplate(filename string) *template.Template {
+ t := template.New(filename)
+ t.Funcs(template.FuncMap{
+ "node": nodeFmt,
+ "synopsis": synopsisFmt,
+ })
+ return template.Must(t.ParseFiles(filepath.Join(dataDir, filename)))
+}
+
+func nodeFmt(node interface{}, fset *token.FileSet) string {
+ var buf bytes.Buffer
+ printer.Fprint(&buf, fset, node)
+ return strings.Replace(strings.TrimSpace(buf.String()), "\n", "\n\t", -1)
+}
+
+func synopsisFmt(s string) string {
+ const n = 64
+ if len(s) > n {
+ // cut off excess text and go back to a word boundary
+ s = s[0:n]
+ if i := strings.LastIndexAny(s, "\t\n "); i >= 0 {
+ s = s[0:i]
+ }
+ s = strings.TrimSpace(s) + " ..."
+ }
+ return "// " + strings.Replace(s, "\n", " ", -1)
+}
+
+func isGoFile(fi os.FileInfo) bool {
+ name := fi.Name()
+ return !fi.IsDir() &&
+ len(name) > 0 && name[0] != '.' && // ignore .files
+ filepath.Ext(name) == ".go"
+}
+
+type bundle struct {
+ *Package
+ FSet *token.FileSet
+}
+
+func test(t *testing.T, mode Mode) {
+ // determine file filter
+ filter := isGoFile
+ if *files != "" {
+ rx, err := regexp.Compile(*files)
+ if err != nil {
+ t.Fatal(err)
+ }
+ filter = func(fi os.FileInfo) bool {
+ return isGoFile(fi) && rx.MatchString(fi.Name())
+ }
+ }
+
+ // get packages
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, dataDir, filter, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // test packages
+ for _, pkg := range pkgs {
+ importpath := dataDir + "/" + pkg.Name
+ doc := New(pkg, importpath, mode)
+
+ // golden files always use / in filenames - canonicalize them
+ for i, filename := range doc.Filenames {
+ doc.Filenames[i] = filepath.ToSlash(filename)
+ }
+
+ // print documentation
+ var buf bytes.Buffer
+ if err := templateTxt.Execute(&buf, bundle{doc, fset}); err != nil {
+ t.Error(err)
+ continue
+ }
+ got := buf.Bytes()
+
+ // update golden file if necessary
+ golden := filepath.Join(dataDir, fmt.Sprintf("%s.%d.golden", pkg.Name, mode))
+ if *update {
+ err := ioutil.WriteFile(golden, got, 0644)
+ if err != nil {
+ t.Error(err)
+ }
+ continue
+ }
+
+ // get golden file
+ want, err := ioutil.ReadFile(golden)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ // compare
+ if bytes.Compare(got, want) != 0 {
+ t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want)
+ }
+ }
+}
+
+func Test(t *testing.T) {
+ test(t, 0)
+ test(t, AllDecls)
+ test(t, AllMethods)
+}
diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go
new file mode 100644
index 000000000..a7e0e250a
--- /dev/null
+++ b/src/pkg/go/doc/example.go
@@ -0,0 +1,117 @@
+// 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.
+
+// Extract example functions from file ASTs.
+
+package doc
+
+import (
+ "go/ast"
+ "go/token"
+ "regexp"
+ "sort"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type Example struct {
+ Name string // name of the item being exemplified
+ Doc string // example function doc string
+ Code ast.Node
+ Comments []*ast.CommentGroup
+ Output string // expected output
+}
+
+func Examples(files ...*ast.File) []*Example {
+ var list []*Example
+ for _, file := range files {
+ hasTests := false // file contains tests or benchmarks
+ numDecl := 0 // number of non-import declarations in the file
+ var flist []*Example
+ for _, decl := range file.Decls {
+ if g, ok := decl.(*ast.GenDecl); ok && g.Tok != token.IMPORT {
+ numDecl++
+ continue
+ }
+ f, ok := decl.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ numDecl++
+ name := f.Name.Name
+ if isTest(name, "Test") || isTest(name, "Benchmark") {
+ hasTests = true
+ continue
+ }
+ if !isTest(name, "Example") {
+ continue
+ }
+ var doc string
+ if f.Doc != nil {
+ doc = f.Doc.Text()
+ }
+ flist = append(flist, &Example{
+ Name: name[len("Example"):],
+ Doc: doc,
+ Code: f.Body,
+ Comments: file.Comments,
+ Output: exampleOutput(f, file.Comments),
+ })
+ }
+ if !hasTests && numDecl > 1 && len(flist) == 1 {
+ // If this file only has one example function, some
+ // other top-level declarations, and no tests or
+ // benchmarks, use the whole file as the example.
+ flist[0].Code = file
+ }
+ list = append(list, flist...)
+ }
+ sort.Sort(exampleByName(list))
+ return list
+}
+
+var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
+
+func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string {
+ // find the last comment in the function
+ var last *ast.CommentGroup
+ for _, cg := range comments {
+ if cg.Pos() < fun.Pos() {
+ continue
+ }
+ if cg.End() > fun.End() {
+ break
+ }
+ last = cg
+ }
+ if last != nil {
+ // test that it begins with the correct prefix
+ text := last.Text()
+ if loc := outputPrefix.FindStringIndex(text); loc != nil {
+ return strings.TrimSpace(text[loc[1]:])
+ }
+ }
+ return "" // no suitable comment found
+}
+
+// isTest tells whether name looks like a test, example, or benchmark.
+// It is a Test (say) if there is a character after Test that is not a
+// lower-case letter. (We don't want Testiness.)
+func isTest(name, prefix string) bool {
+ if !strings.HasPrefix(name, prefix) {
+ return false
+ }
+ if len(name) == len(prefix) { // "Test" is ok
+ return true
+ }
+ rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
+ return !unicode.IsLower(rune)
+}
+
+type exampleByName []*Example
+
+func (s exampleByName) Len() int { return len(s) }
+func (s exampleByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s exampleByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
diff --git a/src/pkg/go/doc/exports.go b/src/pkg/go/doc/exports.go
new file mode 100644
index 000000000..146be5d87
--- /dev/null
+++ b/src/pkg/go/doc/exports.go
@@ -0,0 +1,199 @@
+// 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 export filtering of an AST.
+
+package doc
+
+import "go/ast"
+
+// filterIdentList removes unexported names from list in place
+// and returns the resulting list.
+//
+func filterIdentList(list []*ast.Ident) []*ast.Ident {
+ j := 0
+ for _, x := range list {
+ if ast.IsExported(x.Name) {
+ list[j] = x
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+// removeErrorField removes anonymous fields named "error" from an interface.
+// This is called when "error" has been determined to be a local name,
+// not the predeclared type.
+//
+func removeErrorField(ityp *ast.InterfaceType) {
+ list := ityp.Methods.List // we know that ityp.Methods != nil
+ j := 0
+ for _, field := range list {
+ keepField := true
+ if n := len(field.Names); n == 0 {
+ // anonymous field
+ if fname, _ := baseTypeName(field.Type); fname == "error" {
+ keepField = false
+ }
+ }
+ if keepField {
+ list[j] = field
+ j++
+ }
+ }
+ if j < len(list) {
+ ityp.Incomplete = true
+ }
+ ityp.Methods.List = list[0:j]
+}
+
+// filterFieldList removes unexported fields (field names) from the field list
+// in place and returns true if fields were removed. Anonymous fields are
+// recorded with the parent type. filterType is called with the types of
+// all remaining fields.
+//
+func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) {
+ if fields == nil {
+ return
+ }
+ list := fields.List
+ j := 0
+ for _, field := range list {
+ keepField := false
+ if n := len(field.Names); n == 0 {
+ // anonymous field
+ fname := r.recordAnonymousField(parent, field.Type)
+ if ast.IsExported(fname) {
+ keepField = true
+ } else if ityp != nil && fname == "error" {
+ // possibly the predeclared error interface; keep
+ // it for now but remember this interface so that
+ // it can be fixed if error is also defined locally
+ keepField = true
+ r.remember(ityp)
+ }
+ } else {
+ field.Names = filterIdentList(field.Names)
+ if len(field.Names) < n {
+ removedFields = true
+ }
+ if len(field.Names) > 0 {
+ keepField = true
+ }
+ }
+ if keepField {
+ r.filterType(nil, field.Type)
+ list[j] = field
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
+
+// filterParamList applies filterType to each parameter type in fields.
+//
+func (r *reader) filterParamList(fields *ast.FieldList) {
+ if fields != nil {
+ for _, f := range fields.List {
+ r.filterType(nil, f.Type)
+ }
+ }
+}
+
+// filterType strips any unexported struct fields or method types from typ
+// in place. If fields (or methods) have been removed, the corresponding
+// struct or interface type has the Incomplete field set to true.
+//
+func (r *reader) filterType(parent *namedType, typ ast.Expr) {
+ switch t := typ.(type) {
+ case *ast.Ident:
+ // nothing to do
+ case *ast.ParenExpr:
+ r.filterType(nil, t.X)
+ case *ast.ArrayType:
+ r.filterType(nil, t.Elt)
+ case *ast.StructType:
+ if r.filterFieldList(parent, t.Fields, nil) {
+ t.Incomplete = true
+ }
+ case *ast.FuncType:
+ r.filterParamList(t.Params)
+ r.filterParamList(t.Results)
+ case *ast.InterfaceType:
+ if r.filterFieldList(parent, t.Methods, t) {
+ t.Incomplete = true
+ }
+ case *ast.MapType:
+ r.filterType(nil, t.Key)
+ r.filterType(nil, t.Value)
+ case *ast.ChanType:
+ r.filterType(nil, t.Value)
+ }
+}
+
+func (r *reader) filterSpec(spec ast.Spec) bool {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // always keep imports so we can collect them
+ return true
+ case *ast.ValueSpec:
+ s.Names = filterIdentList(s.Names)
+ if len(s.Names) > 0 {
+ r.filterType(nil, s.Type)
+ return true
+ }
+ case *ast.TypeSpec:
+ if name := s.Name.Name; ast.IsExported(name) {
+ r.filterType(r.lookupType(s.Name.Name), s.Type)
+ return true
+ } else if name == "error" {
+ // special case: remember that error is declared locally
+ r.errorDecl = true
+ }
+ }
+ return false
+}
+
+func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec {
+ j := 0
+ for _, s := range list {
+ if r.filterSpec(s) {
+ list[j] = s
+ j++
+ }
+ }
+ return list[0:j]
+}
+
+func (r *reader) filterDecl(decl ast.Decl) bool {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ d.Specs = r.filterSpecList(d.Specs)
+ return len(d.Specs) > 0
+ case *ast.FuncDecl:
+ // ok to filter these methods early because any
+ // conflicting method will be filtered here, too -
+ // thus, removing these methods early will not lead
+ // to the false removal of possible conflicts
+ return ast.IsExported(d.Name.Name)
+ }
+ return false
+}
+
+// fileExports removes unexported declarations from src in place.
+//
+func (r *reader) fileExports(src *ast.File) {
+ j := 0
+ for _, d := range src.Decls {
+ if r.filterDecl(d) {
+ src.Decls[j] = d
+ j++
+ }
+ }
+ src.Decls = src.Decls[0:j]
+}
diff --git a/src/pkg/go/doc/filter.go b/src/pkg/go/doc/filter.go
new file mode 100644
index 000000000..02b66ccef
--- /dev/null
+++ b/src/pkg/go/doc/filter.go
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import "go/ast"
+
+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 {
+ switch v := d.(type) {
+ case *ast.ValueSpec:
+ for _, name := range v.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ case *ast.TypeSpec:
+ if f(v.Name.Name) {
+ return true
+ }
+ 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 filterValues(a []*Value, f Filter) []*Value {
+ w := 0
+ for _, vd := range a {
+ if matchDecl(vd.Decl, f) {
+ a[w] = vd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterFuncs(a []*Func, f Filter) []*Func {
+ w := 0
+ for _, fd := range a {
+ if f(fd.Name) {
+ a[w] = fd
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+func filterTypes(a []*Type, f Filter) []*Type {
+ w := 0
+ for _, td := range a {
+ n := 0 // number of matches
+ if matchDecl(td.Decl, f) {
+ n = 1
+ } else {
+ // type name doesn't match, but we may have matching consts, vars, factories or methods
+ td.Consts = filterValues(td.Consts, f)
+ td.Vars = filterValues(td.Vars, f)
+ td.Funcs = filterFuncs(td.Funcs, f)
+ td.Methods = filterFuncs(td.Methods, f)
+ n += len(td.Consts) + len(td.Vars) + len(td.Funcs) + len(td.Methods)
+ }
+ if n > 0 {
+ a[w] = td
+ w++
+ }
+ }
+ return a[0:w]
+}
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *Package) Filter(f Filter) {
+ p.Consts = filterValues(p.Consts, f)
+ p.Vars = filterValues(p.Vars, f)
+ p.Types = filterTypes(p.Types, f)
+ p.Funcs = filterFuncs(p.Funcs, f)
+ p.Doc = "" // don't show top-level package doc
+}
diff --git a/src/pkg/go/doc/headscan.go b/src/pkg/go/doc/headscan.go
new file mode 100644
index 000000000..f55934763
--- /dev/null
+++ b/src/pkg/go/doc/headscan.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.
+
+// +build ignore
+
+/*
+ The headscan command extracts comment headings from package files;
+ it is used to detect false positives which may require an adjustment
+ to the comment formatting heuristics in comment.go.
+
+ Usage: headscan [-root root_directory]
+
+ By default, the $GOROOT/src directory is scanned.
+*/
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+var (
+ root = flag.String("root", filepath.Join(runtime.GOROOT(), "src"), "root of filesystem tree to scan")
+ verbose = flag.Bool("v", false, "verbose mode")
+)
+
+const (
+ html_h = "<h3>"
+ html_endh = "</h3>\n"
+)
+
+func isGoFile(fi os.FileInfo) bool {
+ return strings.HasSuffix(fi.Name(), ".go") &&
+ !strings.HasSuffix(fi.Name(), "_test.go")
+}
+
+func appendHeadings(list []string, comment string) []string {
+ var buf bytes.Buffer
+ doc.ToHTML(&buf, comment, nil)
+ for s := buf.String(); ; {
+ i := strings.Index(s, html_h)
+ if i < 0 {
+ break
+ }
+ i += len(html_h)
+ j := strings.Index(s, html_endh)
+ if j < 0 {
+ list = append(list, s[i:]) // incorrect HTML
+ break
+ }
+ list = append(list, s[i:j])
+ s = s[j+len(html_endh):]
+ }
+ return list
+}
+
+func main() {
+ flag.Parse()
+ fset := token.NewFileSet()
+ nheadings := 0
+ err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error {
+ if !fi.IsDir() {
+ return nil
+ }
+ pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments)
+ if err != nil {
+ if *verbose {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ return nil
+ }
+ for _, pkg := range pkgs {
+ d := doc.New(pkg, path, doc.Mode(0))
+ list := appendHeadings(nil, d.Doc)
+ for _, d := range d.Consts {
+ list = appendHeadings(list, d.Doc)
+ }
+ for _, d := range d.Types {
+ list = appendHeadings(list, d.Doc)
+ }
+ for _, d := range d.Vars {
+ list = appendHeadings(list, d.Doc)
+ }
+ for _, d := range d.Funcs {
+ list = appendHeadings(list, d.Doc)
+ }
+ if len(list) > 0 {
+ // directories may contain multiple packages;
+ // print path and package name
+ fmt.Printf("%s (package %s)\n", path, pkg.Name)
+ for _, h := range list {
+ fmt.Printf("\t%s\n", h)
+ }
+ nheadings += len(list)
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ fmt.Println(nheadings, "headings found")
+}
diff --git a/src/pkg/go/doc/reader.go b/src/pkg/go/doc/reader.go
new file mode 100644
index 000000000..5eaae37b7
--- /dev/null
+++ b/src/pkg/go/doc/reader.go
@@ -0,0 +1,774 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+ "go/ast"
+ "go/token"
+ "regexp"
+ "sort"
+ "strconv"
+)
+
+// ----------------------------------------------------------------------------
+// function/method sets
+//
+// Internally, we treat functions like methods and collect them in method sets.
+
+// A methodSet describes a set of methods. Entries where Decl == nil are conflict
+// entries (more then one method with the same name at the same embedding level).
+//
+type methodSet map[string]*Func
+
+// recvString returns a string representation of recv of the
+// form "T", "*T", or "BADRECV" (if not a proper receiver type).
+//
+func recvString(recv ast.Expr) string {
+ switch t := recv.(type) {
+ case *ast.Ident:
+ return t.Name
+ case *ast.StarExpr:
+ return "*" + recvString(t.X)
+ }
+ return "BADRECV"
+}
+
+// set creates the corresponding Func for f and adds it to mset.
+// If there are multiple f's with the same name, set keeps the first
+// one with documentation; conflicts are ignored.
+//
+func (mset methodSet) set(f *ast.FuncDecl) {
+ name := f.Name.Name
+ if g := mset[name]; g != nil && g.Doc != "" {
+ // A function with the same name has already been registered;
+ // since it has documentation, assume f is simply another
+ // implementation and ignore it. This does not happen if the
+ // caller is using go/build.ScanDir to determine the list of
+ // files implementing a package.
+ return
+ }
+ // function doesn't exist or has no documentation; use f
+ recv := ""
+ if f.Recv != nil {
+ var typ ast.Expr
+ // be careful in case of incorrect ASTs
+ if list := f.Recv.List; len(list) == 1 {
+ typ = list[0].Type
+ }
+ recv = recvString(typ)
+ }
+ mset[name] = &Func{
+ Doc: f.Doc.Text(),
+ Name: name,
+ Decl: f,
+ Recv: recv,
+ Orig: recv,
+ }
+ f.Doc = nil // doc consumed - remove from AST
+}
+
+// add adds method m to the method set; m is ignored if the method set
+// already contains a method with the same name at the same or a higher
+// level then m.
+//
+func (mset methodSet) add(m *Func) {
+ old := mset[m.Name]
+ if old == nil || m.Level < old.Level {
+ mset[m.Name] = m
+ return
+ }
+ if old != nil && m.Level == old.Level {
+ // conflict - mark it using a method with nil Decl
+ mset[m.Name] = &Func{
+ Name: m.Name,
+ Level: m.Level,
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Named types
+
+// baseTypeName returns the name of the base type of x (or "")
+// and whether the type is imported or not.
+//
+func baseTypeName(x ast.Expr) (name string, imported bool) {
+ switch t := x.(type) {
+ case *ast.Ident:
+ return t.Name, false
+ case *ast.SelectorExpr:
+ if _, ok := t.X.(*ast.Ident); ok {
+ // only possible for qualified type names;
+ // assume type is imported
+ return t.Sel.Name, true
+ }
+ case *ast.StarExpr:
+ return baseTypeName(t.X)
+ }
+ return
+}
+
+// An embeddedSet describes a set of embedded types.
+type embeddedSet map[*namedType]bool
+
+// A namedType represents a named unqualified (package local, or possibly
+// predeclared) type. The namedType for a type name is always found via
+// reader.lookupType.
+//
+type namedType struct {
+ doc string // doc comment for type
+ name string // type name
+ decl *ast.GenDecl // nil if declaration hasn't been seen yet
+
+ isEmbedded bool // true if this type is embedded
+ isStruct bool // true if this type is a struct
+ embedded embeddedSet // true if the embedded type is a pointer
+
+ // associated declarations
+ values []*Value // consts and vars
+ funcs methodSet
+ methods methodSet
+}
+
+// ----------------------------------------------------------------------------
+// AST reader
+
+// reader accumulates documentation for a single package.
+// It modifies the AST: Comments (declaration documentation)
+// that have been collected by the reader are set to nil
+// in the respective AST nodes so that they are not printed
+// twice (once when printing the documentation and once when
+// printing the corresponding AST node).
+//
+type reader struct {
+ mode Mode
+
+ // package properties
+ doc string // package documentation, if any
+ filenames []string
+ bugs []string
+
+ // declarations
+ imports map[string]int
+ values []*Value // consts and vars
+ types map[string]*namedType
+ funcs methodSet
+
+ // support for package-local error type declarations
+ errorDecl bool // if set, type "error" was declared locally
+ fixlist []*ast.InterfaceType // list of interfaces containing anonymous field "error"
+}
+
+func (r *reader) isVisible(name string) bool {
+ return r.mode&AllDecls != 0 || ast.IsExported(name)
+}
+
+// lookupType returns the base type with the given name.
+// If the base type has not been encountered yet, a new
+// type with the given name but no associated declaration
+// is added to the type map.
+//
+func (r *reader) lookupType(name string) *namedType {
+ if name == "" || name == "_" {
+ return nil // no type docs for anonymous types
+ }
+ if typ, found := r.types[name]; found {
+ return typ
+ }
+ // type not found - add one without declaration
+ typ := &namedType{
+ name: name,
+ embedded: make(embeddedSet),
+ funcs: make(methodSet),
+ methods: make(methodSet),
+ }
+ r.types[name] = typ
+ return typ
+}
+
+// recordAnonymousField registers fieldType as the type of an
+// anonymous field in the parent type. If the field is imported
+// (qualified name) or the parent is nil, the field is ignored.
+// The function returns the field name.
+//
+func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) {
+ fname, imp := baseTypeName(fieldType)
+ if parent == nil || imp {
+ return
+ }
+ if ftype := r.lookupType(fname); ftype != nil {
+ ftype.isEmbedded = true
+ _, ptr := fieldType.(*ast.StarExpr)
+ parent.embedded[ftype] = ptr
+ }
+ return
+}
+
+func (r *reader) readDoc(comment *ast.CommentGroup) {
+ // By convention there should be only one package comment
+ // but collect all of them if there are more then one.
+ text := comment.Text()
+ if r.doc == "" {
+ r.doc = text
+ return
+ }
+ r.doc += "\n" + text
+}
+
+func (r *reader) remember(typ *ast.InterfaceType) {
+ r.fixlist = append(r.fixlist, typ)
+}
+
+func specNames(specs []ast.Spec) []string {
+ names := make([]string, 0, len(specs)) // reasonable estimate
+ for _, s := range specs {
+ // s guaranteed to be an *ast.ValueSpec by readValue
+ for _, ident := range s.(*ast.ValueSpec).Names {
+ names = append(names, ident.Name)
+ }
+ }
+ return names
+}
+
+// readValue processes a const or var declaration.
+//
+func (r *reader) readValue(decl *ast.GenDecl) {
+ // determine if decl should be associated with a type
+ // Heuristic: For each typed entry, determine the type name, if any.
+ // If there is exactly one type name that is sufficiently
+ // frequent, associate the decl with the respective type.
+ domName := ""
+ domFreq := 0
+ prev := ""
+ n := 0
+ for _, spec := range decl.Specs {
+ s, ok := spec.(*ast.ValueSpec)
+ if !ok {
+ continue // should not happen, but be conservative
+ }
+ name := ""
+ switch {
+ case s.Type != nil:
+ // a type is present; determine its name
+ if n, imp := baseTypeName(s.Type); !imp {
+ name = n
+ }
+ case decl.Tok == token.CONST:
+ // no type is present but we have a constant declaration;
+ // use the previous type name (w/o more type information
+ // we cannot handle the case of unnamed variables with
+ // initializer expressions except for some trivial cases)
+ name = prev
+ }
+ if name != "" {
+ // entry has a named type
+ if domName != "" && domName != name {
+ // more than one type name - do not associate
+ // with any type
+ domName = ""
+ break
+ }
+ domName = name
+ domFreq++
+ }
+ prev = name
+ n++
+ }
+
+ // nothing to do w/o a legal declaration
+ if n == 0 {
+ return
+ }
+
+ // determine values list with which to associate the Value for this decl
+ values := &r.values
+ const threshold = 0.75
+ if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) {
+ // typed entries are sufficiently frequent
+ if typ := r.lookupType(domName); typ != nil {
+ values = &typ.values // associate with that type
+ }
+ }
+
+ *values = append(*values, &Value{
+ Doc: decl.Doc.Text(),
+ Names: specNames(decl.Specs),
+ Decl: decl,
+ order: len(*values),
+ })
+ decl.Doc = nil // doc consumed - remove from AST
+}
+
+// fields returns a struct's fields or an interface's methods.
+//
+func fields(typ ast.Expr) (list []*ast.Field, isStruct bool) {
+ var fields *ast.FieldList
+ switch t := typ.(type) {
+ case *ast.StructType:
+ fields = t.Fields
+ isStruct = true
+ case *ast.InterfaceType:
+ fields = t.Methods
+ }
+ if fields != nil {
+ list = fields.List
+ }
+ return
+}
+
+// readType processes a type declaration.
+//
+func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
+ typ := r.lookupType(spec.Name.Name)
+ if typ == nil {
+ return // no name or blank name - ignore the type
+ }
+
+ // A type should be added at most once, so typ.decl
+ // should be nil - if it is not, simply overwrite it.
+ typ.decl = decl
+
+ // compute documentation
+ doc := spec.Doc
+ spec.Doc = nil // doc consumed - remove from AST
+ if doc == nil {
+ // no doc associated with the spec, use the declaration doc, if any
+ doc = decl.Doc
+ }
+ decl.Doc = nil // doc consumed - remove from AST
+ typ.doc = doc.Text()
+
+ // record anonymous fields (they may contribute methods)
+ // (some fields may have been recorded already when filtering
+ // exports, but that's ok)
+ var list []*ast.Field
+ list, typ.isStruct = fields(spec.Type)
+ for _, field := range list {
+ if len(field.Names) == 0 {
+ r.recordAnonymousField(typ, field.Type)
+ }
+ }
+}
+
+// readFunc processes a func or method declaration.
+//
+func (r *reader) readFunc(fun *ast.FuncDecl) {
+ // strip function body
+ fun.Body = nil
+
+ // associate methods with the receiver type, if any
+ if fun.Recv != nil {
+ // method
+ recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
+ if imp {
+ // should not happen (incorrect AST);
+ // don't show this method
+ return
+ }
+ if typ := r.lookupType(recvTypeName); typ != nil {
+ typ.methods.set(fun)
+ }
+ // otherwise ignore the method
+ // TODO(gri): There may be exported methods of non-exported types
+ // that can be called because of exported values (consts, vars, or
+ // function results) of that type. Could determine if that is the
+ // case and then show those methods in an appropriate section.
+ return
+ }
+
+ // associate factory functions with the first visible result type, if any
+ if fun.Type.Results.NumFields() >= 1 {
+ res := fun.Type.Results.List[0]
+ if len(res.Names) <= 1 {
+ // exactly one (named or anonymous) result associated
+ // with the first type in result signature (there may
+ // be more than one result)
+ if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) {
+ if typ := r.lookupType(n); typ != nil {
+ // associate function with typ
+ typ.funcs.set(fun)
+ return
+ }
+ }
+ }
+ }
+
+ // just an ordinary function
+ r.funcs.set(fun)
+}
+
+var (
+ bug_markers = regexp.MustCompile("^/[/*][ \t]*BUG\\(.*\\):[ \t]*") // BUG(uid):
+ bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char
+)
+
+// readFile adds the AST for a source file to the reader.
+//
+func (r *reader) readFile(src *ast.File) {
+ // add package documentation
+ if src.Doc != nil {
+ r.readDoc(src.Doc)
+ src.Doc = nil // doc consumed - remove from AST
+ }
+
+ // add all declarations
+ for _, decl := range src.Decls {
+ switch d := decl.(type) {
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.IMPORT:
+ // imports are handled individually
+ for _, spec := range d.Specs {
+ if s, ok := spec.(*ast.ImportSpec); ok {
+ if import_, err := strconv.Unquote(s.Path.Value); err == nil {
+ r.imports[import_] = 1
+ }
+ }
+ }
+ case token.CONST, token.VAR:
+ // constants and variables are always handled as a group
+ r.readValue(d)
+ case token.TYPE:
+ // types are handled individually
+ if len(d.Specs) == 1 && !d.Lparen.IsValid() {
+ // common case: single declaration w/o parentheses
+ // (if a single declaration is parenthesized,
+ // create a new fake declaration below, so that
+ // go/doc type declarations always appear w/o
+ // parentheses)
+ if s, ok := d.Specs[0].(*ast.TypeSpec); ok {
+ r.readType(d, s)
+ }
+ break
+ }
+ for _, spec := range d.Specs {
+ if s, ok := spec.(*ast.TypeSpec); ok {
+ // use an individual (possibly fake) declaration
+ // for each type; this also ensures that each type
+ // gets to (re-)use the declaration documentation
+ // if there's none associated with the spec itself
+ fake := &ast.GenDecl{
+ Doc: d.Doc,
+ // don't use the existing TokPos because it
+ // will lead to the wrong selection range for
+ // the fake declaration if there are more
+ // than one type in the group (this affects
+ // src/cmd/godoc/godoc.go's posLink_urlFunc)
+ TokPos: s.Pos(),
+ Tok: token.TYPE,
+ Specs: []ast.Spec{s},
+ }
+ r.readType(fake, s)
+ }
+ }
+ }
+ case *ast.FuncDecl:
+ r.readFunc(d)
+ }
+ }
+
+ // collect BUG(...) comments
+ for _, c := range src.Comments {
+ text := c.List[0].Text
+ if m := bug_markers.FindStringIndex(text); m != nil {
+ // found a BUG comment; maybe empty
+ if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
+ // non-empty BUG comment; collect comment without BUG prefix
+ list := append([]*ast.Comment(nil), c.List...) // make a copy
+ list[0].Text = text[m[1]:]
+ r.bugs = append(r.bugs, (&ast.CommentGroup{List: list}).Text())
+ }
+ }
+ }
+ src.Comments = nil // consumed unassociated comments - remove from AST
+}
+
+func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
+ // initialize reader
+ r.filenames = make([]string, len(pkg.Files))
+ r.imports = make(map[string]int)
+ r.mode = mode
+ r.types = make(map[string]*namedType)
+ r.funcs = make(methodSet)
+
+ // sort package files before reading them so that the
+ // result result does not depend on map iteration order
+ i := 0
+ for filename := range pkg.Files {
+ r.filenames[i] = filename
+ i++
+ }
+ sort.Strings(r.filenames)
+
+ // process files in sorted order
+ for _, filename := range r.filenames {
+ f := pkg.Files[filename]
+ if mode&AllDecls == 0 {
+ r.fileExports(f)
+ }
+ r.readFile(f)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+var predeclaredTypes = map[string]bool{
+ "bool": true,
+ "byte": true,
+ "complex64": true,
+ "complex128": true,
+ "error": true,
+ "float32": true,
+ "float64": true,
+ "int": true,
+ "int8": true,
+ "int16": true,
+ "int32": true,
+ "int64": true,
+ "rune": true,
+ "string": true,
+ "uint": true,
+ "uint8": true,
+ "uint16": true,
+ "uint32": true,
+ "uint64": true,
+ "uintptr": true,
+}
+
+func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func {
+ if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 {
+ return f // shouldn't happen, but be safe
+ }
+
+ // copy existing receiver field and set new type
+ newField := *f.Decl.Recv.List[0]
+ _, origRecvIsPtr := newField.Type.(*ast.StarExpr)
+ var typ ast.Expr = ast.NewIdent(recvTypeName)
+ if !embeddedIsPtr && origRecvIsPtr {
+ typ = &ast.StarExpr{X: typ}
+ }
+ newField.Type = typ
+
+ // copy existing receiver field list and set new receiver field
+ newFieldList := *f.Decl.Recv
+ newFieldList.List = []*ast.Field{&newField}
+
+ // copy existing function declaration and set new receiver field list
+ newFuncDecl := *f.Decl
+ newFuncDecl.Recv = &newFieldList
+
+ // copy existing function documentation and set new declaration
+ newF := *f
+ newF.Decl = &newFuncDecl
+ newF.Recv = recvString(typ)
+ // the Orig field never changes
+ newF.Level = level
+
+ return &newF
+}
+
+// collectEmbeddedMethods collects the embedded methods of typ in mset.
+//
+func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited embeddedSet) {
+ visited[typ] = true
+ for embedded, isPtr := range typ.embedded {
+ // Once an embedded type is embedded as a pointer type
+ // all embedded types in those types are treated like
+ // pointer types for the purpose of the receiver type
+ // computation; i.e., embeddedIsPtr is sticky for this
+ // embedding hierarchy.
+ thisEmbeddedIsPtr := embeddedIsPtr || isPtr
+ for _, m := range embedded.methods {
+ // only top-level methods are embedded
+ if m.Level == 0 {
+ mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
+ }
+ }
+ if !visited[embedded] {
+ r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
+ }
+ }
+ delete(visited, typ)
+}
+
+// computeMethodSets determines the actual method sets for each type encountered.
+//
+func (r *reader) computeMethodSets() {
+ for _, t := range r.types {
+ // collect embedded methods for t
+ if t.isStruct {
+ // struct
+ r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(embeddedSet))
+ } else {
+ // interface
+ // TODO(gri) fix this
+ }
+ }
+
+ // if error was declared locally, don't treat it as exported field anymore
+ if r.errorDecl {
+ for _, ityp := range r.fixlist {
+ removeErrorField(ityp)
+ }
+ }
+}
+
+// cleanupTypes removes the association of functions and methods with
+// types that have no declaration. Instead, these functions and methods
+// are shown at the package level. It also removes types with missing
+// declarations or which are not visible.
+//
+func (r *reader) cleanupTypes() {
+ for _, t := range r.types {
+ visible := r.isVisible(t.name)
+ if t.decl == nil && (predeclaredTypes[t.name] || t.isEmbedded && visible) {
+ // t.name is a predeclared type (and was not redeclared in this package),
+ // or it was embedded somewhere but its declaration is missing (because
+ // the AST is incomplete): move any associated values, funcs, and methods
+ // back to the top-level so that they are not lost.
+ // 1) move values
+ r.values = append(r.values, t.values...)
+ // 2) move factory functions
+ for name, f := range t.funcs {
+ // in a correct AST, package-level function names
+ // are all different - no need to check for conflicts
+ r.funcs[name] = f
+ }
+ // 3) move methods
+ for name, m := range t.methods {
+ // don't overwrite functions with the same name - drop them
+ if _, found := r.funcs[name]; !found {
+ r.funcs[name] = m
+ }
+ }
+ }
+ // remove types w/o declaration or which are not visible
+ if t.decl == nil || !visible {
+ delete(r.types, t.name)
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Sorting
+
+type data struct {
+ n int
+ swap func(i, j int)
+ less func(i, j int) bool
+}
+
+func (d *data) Len() int { return d.n }
+func (d *data) Swap(i, j int) { d.swap(i, j) }
+func (d *data) Less(i, j int) bool { return d.less(i, j) }
+
+// sortBy is a helper function for sorting
+func sortBy(less func(i, j int) bool, swap func(i, j int), n int) {
+ sort.Sort(&data{n, swap, less})
+}
+
+func sortedKeys(m map[string]int) []string {
+ list := make([]string, len(m))
+ i := 0
+ for key := range m {
+ list[i] = key
+ i++
+ }
+ sort.Strings(list)
+ return list
+}
+
+// sortingName returns the name to use when sorting d into place.
+//
+func sortingName(d *ast.GenDecl) string {
+ if len(d.Specs) == 1 {
+ if s, ok := d.Specs[0].(*ast.ValueSpec); ok {
+ return s.Names[0].Name
+ }
+ }
+ return ""
+}
+
+func sortedValues(m []*Value, tok token.Token) []*Value {
+ list := make([]*Value, len(m)) // big enough in any case
+ i := 0
+ for _, val := range m {
+ if val.Decl.Tok == tok {
+ list[i] = val
+ i++
+ }
+ }
+ list = list[0:i]
+
+ sortBy(
+ func(i, j int) bool {
+ if ni, nj := sortingName(list[i].Decl), sortingName(list[j].Decl); ni != nj {
+ return ni < nj
+ }
+ return list[i].order < list[j].order
+ },
+ func(i, j int) { list[i], list[j] = list[j], list[i] },
+ len(list),
+ )
+
+ return list
+}
+
+func sortedTypes(m map[string]*namedType, allMethods bool) []*Type {
+ list := make([]*Type, len(m))
+ i := 0
+ for _, t := range m {
+ list[i] = &Type{
+ Doc: t.doc,
+ Name: t.name,
+ Decl: t.decl,
+ Consts: sortedValues(t.values, token.CONST),
+ Vars: sortedValues(t.values, token.VAR),
+ Funcs: sortedFuncs(t.funcs, true),
+ Methods: sortedFuncs(t.methods, allMethods),
+ }
+ i++
+ }
+
+ sortBy(
+ func(i, j int) bool { return list[i].Name < list[j].Name },
+ func(i, j int) { list[i], list[j] = list[j], list[i] },
+ len(list),
+ )
+
+ return list
+}
+
+func removeStar(s string) string {
+ if len(s) > 0 && s[0] == '*' {
+ return s[1:]
+ }
+ return s
+}
+
+func sortedFuncs(m methodSet, allMethods bool) []*Func {
+ list := make([]*Func, len(m))
+ i := 0
+ for _, m := range m {
+ // determine which methods to include
+ switch {
+ case m.Decl == nil:
+ // exclude conflict entry
+ case allMethods, m.Level == 0, !ast.IsExported(removeStar(m.Orig)):
+ // forced inclusion, method not embedded, or method
+ // embedded but original receiver type not exported
+ list[i] = m
+ i++
+ }
+ }
+ list = list[0:i]
+ sortBy(
+ func(i, j int) bool { return list[i].Name < list[j].Name },
+ func(i, j int) { list[i], list[j] = list[j], list[i] },
+ len(list),
+ )
+ return list
+}
diff --git a/src/pkg/go/doc/synopsis.go b/src/pkg/go/doc/synopsis.go
new file mode 100644
index 000000000..2192d78c0
--- /dev/null
+++ b/src/pkg/go/doc/synopsis.go
@@ -0,0 +1,52 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import "unicode"
+
+// firstSentenceLen returns the length of the first sentence in s.
+// The sentence ends after the first period followed by space and
+// not preceded by exactly one uppercase letter.
+//
+func firstSentenceLen(s string) int {
+ var ppp, pp, p rune
+ for i, q := range s {
+ if q == '\n' || q == '\r' || q == '\t' {
+ q = ' '
+ }
+ if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) {
+ return i
+ }
+ ppp, pp, p = pp, p, q
+ }
+ return len(s)
+}
+
+// Synopsis returns a cleaned version of the first sentence in s.
+// That sentence ends after the first period followed by space and
+// not preceded by exactly one uppercase letter. The result string
+// has no \n, \r, or \t characters and uses only single spaces between
+// words.
+//
+func Synopsis(s string) string {
+ n := firstSentenceLen(s)
+ var b []byte
+ p := byte(' ')
+ for i := 0; i < n; i++ {
+ q := s[i]
+ if q == '\n' || q == '\r' || q == '\t' {
+ q = ' '
+ }
+ if q != ' ' || p != ' ' {
+ b = append(b, q)
+ p = q
+ }
+ }
+ // remove trailing blank, if any
+ if n := len(b); n > 0 && p == ' ' {
+ b = b[0 : n-1]
+ }
+ return string(b)
+}
diff --git a/src/pkg/go/doc/synopsis_test.go b/src/pkg/go/doc/synopsis_test.go
new file mode 100644
index 000000000..dfc6598af
--- /dev/null
+++ b/src/pkg/go/doc/synopsis_test.go
@@ -0,0 +1,44 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import "testing"
+
+var tests = []struct {
+ txt string
+ fsl int
+ syn string
+}{
+ {"", 0, ""},
+ {"foo", 3, "foo"},
+ {"foo.", 4, "foo."},
+ {"foo.bar", 7, "foo.bar"},
+ {" foo. ", 6, "foo."},
+ {" foo\t bar.\n", 12, "foo bar."},
+ {" foo\t bar.\n", 12, "foo bar."},
+ {"a b\n\nc\r\rd\t\t", 12, "a b c d"},
+ {"a b\n\nc\r\rd\t\t . BLA", 15, "a b c d ."},
+ {"Package poems by T.S.Eliot. To rhyme...", 27, "Package poems by T.S.Eliot."},
+ {"Package poems by T. S. Eliot. To rhyme...", 29, "Package poems by T. S. Eliot."},
+ {"foo implements the foo ABI. The foo ABI is...", 27, "foo implements the foo ABI."},
+ {"Package\nfoo. ..", 12, "Package foo."},
+ {"P . Q.", 3, "P ."},
+ {"P. Q. ", 8, "P. Q."},
+ {"Package Καλημέρα κόσμε.", 36, "Package Καλημέρα κόσμε."},
+ {"Package こんにちは 世界\n", 31, "Package こんにちは 世界"},
+}
+
+func TestSynopsis(t *testing.T) {
+ for _, e := range tests {
+ fsl := firstSentenceLen(e.txt)
+ if fsl != e.fsl {
+ t.Errorf("got fsl = %d; want %d for %q\n", fsl, e.fsl, e.txt)
+ }
+ syn := Synopsis(e.txt)
+ if syn != e.syn {
+ t.Errorf("got syn = %q; want %q for %q\n", syn, e.syn, e.txt)
+ }
+ }
+}
diff --git a/src/pkg/go/doc/testdata/a.0.golden b/src/pkg/go/doc/testdata/a.0.golden
new file mode 100644
index 000000000..24db02d34
--- /dev/null
+++ b/src/pkg/go/doc/testdata/a.0.golden
@@ -0,0 +1,13 @@
+// comment 0 comment 1
+PACKAGE a
+
+IMPORTPATH
+ testdata/a
+
+FILENAMES
+ testdata/a0.go
+ testdata/a1.go
+
+BUGS
+ // bug0
+ // bug1
diff --git a/src/pkg/go/doc/testdata/a.1.golden b/src/pkg/go/doc/testdata/a.1.golden
new file mode 100644
index 000000000..24db02d34
--- /dev/null
+++ b/src/pkg/go/doc/testdata/a.1.golden
@@ -0,0 +1,13 @@
+// comment 0 comment 1
+PACKAGE a
+
+IMPORTPATH
+ testdata/a
+
+FILENAMES
+ testdata/a0.go
+ testdata/a1.go
+
+BUGS
+ // bug0
+ // bug1
diff --git a/src/pkg/go/doc/testdata/a.2.golden b/src/pkg/go/doc/testdata/a.2.golden
new file mode 100644
index 000000000..24db02d34
--- /dev/null
+++ b/src/pkg/go/doc/testdata/a.2.golden
@@ -0,0 +1,13 @@
+// comment 0 comment 1
+PACKAGE a
+
+IMPORTPATH
+ testdata/a
+
+FILENAMES
+ testdata/a0.go
+ testdata/a1.go
+
+BUGS
+ // bug0
+ // bug1
diff --git a/src/pkg/syscall/syscall_amd64.go b/src/pkg/go/doc/testdata/a0.go
index 75c3eac6f..dc552989e 100644
--- a/src/pkg/syscall/syscall_amd64.go
+++ b/src/pkg/go/doc/testdata/a0.go
@@ -1,7 +1,8 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package syscall
+// comment 0
+package a
-const ARCH = "amd64"
+//BUG(uid): bug0
diff --git a/src/pkg/syscall/syscall_arm.go b/src/pkg/go/doc/testdata/a1.go
index b9d1ca0c0..098776c1b 100644
--- a/src/pkg/syscall/syscall_arm.go
+++ b/src/pkg/go/doc/testdata/a1.go
@@ -1,7 +1,8 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package syscall
+// comment 1
+package a
-const ARCH = "arm"
+//BUG(uid): bug1
diff --git a/src/pkg/go/doc/testdata/b.0.golden b/src/pkg/go/doc/testdata/b.0.golden
new file mode 100644
index 000000000..9d93392ea
--- /dev/null
+++ b/src/pkg/go/doc/testdata/b.0.golden
@@ -0,0 +1,71 @@
+//
+PACKAGE b
+
+IMPORTPATH
+ testdata/b
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/b.go
+
+CONSTANTS
+ //
+ const (
+ C1 notExported = iota
+ C2
+
+ C4
+ C5
+ )
+
+ //
+ const C notExported = 0
+
+ //
+ const Pi = 3.14 // Pi
+
+
+VARIABLES
+ //
+ var (
+ U1, U2, U4, U5 notExported
+
+ U7 notExported = 7
+ )
+
+ //
+ var MaxInt int // MaxInt
+
+ //
+ var V notExported
+
+ //
+ var V1, V2, V4, V5 notExported
+
+
+FUNCTIONS
+ //
+ func F(x int) int
+
+ //
+ func F1() notExported
+
+ // Always under the package functions list.
+ func NotAFactory() int
+
+ // Associated with uint type if AllDecls is set.
+ func UintFactory() uint
+
+
+TYPES
+ //
+ type T struct{} // T
+
+ //
+ var V T // v
+
+ //
+ func (x *T) M()
+
diff --git a/src/pkg/go/doc/testdata/b.1.golden b/src/pkg/go/doc/testdata/b.1.golden
new file mode 100644
index 000000000..66c47b5c2
--- /dev/null
+++ b/src/pkg/go/doc/testdata/b.1.golden
@@ -0,0 +1,83 @@
+//
+PACKAGE b
+
+IMPORTPATH
+ testdata/b
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/b.go
+
+CONSTANTS
+ //
+ const Pi = 3.14 // Pi
+
+
+VARIABLES
+ //
+ var MaxInt int // MaxInt
+
+
+FUNCTIONS
+ //
+ func F(x int) int
+
+ // Always under the package functions list.
+ func NotAFactory() int
+
+
+TYPES
+ //
+ type T struct{} // T
+
+ //
+ var V T // v
+
+ //
+ func (x *T) M()
+
+ //
+ type notExported int
+
+ //
+ const (
+ C1 notExported = iota
+ C2
+ c3
+ C4
+ C5
+ )
+
+ //
+ const C notExported = 0
+
+ //
+ var (
+ U1, U2, u3, U4, U5 notExported
+ u6 notExported
+ U7 notExported = 7
+ )
+
+ //
+ var V notExported
+
+ //
+ var V1, V2, v3, V4, V5 notExported
+
+ //
+ func F1() notExported
+
+ //
+ func f2() notExported
+
+ // Should only appear if AllDecls is set.
+ type uint struct{} // overrides a predeclared type uint
+
+ // Associated with uint type if AllDecls is set.
+ func UintFactory() uint
+
+ // Associated with uint type if AllDecls is set.
+ func uintFactory() uint
+
diff --git a/src/pkg/go/doc/testdata/b.2.golden b/src/pkg/go/doc/testdata/b.2.golden
new file mode 100644
index 000000000..9d93392ea
--- /dev/null
+++ b/src/pkg/go/doc/testdata/b.2.golden
@@ -0,0 +1,71 @@
+//
+PACKAGE b
+
+IMPORTPATH
+ testdata/b
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/b.go
+
+CONSTANTS
+ //
+ const (
+ C1 notExported = iota
+ C2
+
+ C4
+ C5
+ )
+
+ //
+ const C notExported = 0
+
+ //
+ const Pi = 3.14 // Pi
+
+
+VARIABLES
+ //
+ var (
+ U1, U2, U4, U5 notExported
+
+ U7 notExported = 7
+ )
+
+ //
+ var MaxInt int // MaxInt
+
+ //
+ var V notExported
+
+ //
+ var V1, V2, V4, V5 notExported
+
+
+FUNCTIONS
+ //
+ func F(x int) int
+
+ //
+ func F1() notExported
+
+ // Always under the package functions list.
+ func NotAFactory() int
+
+ // Associated with uint type if AllDecls is set.
+ func UintFactory() uint
+
+
+TYPES
+ //
+ type T struct{} // T
+
+ //
+ var V T // v
+
+ //
+ func (x *T) M()
+
diff --git a/src/pkg/go/doc/testdata/b.go b/src/pkg/go/doc/testdata/b.go
new file mode 100644
index 000000000..e50663b3d
--- /dev/null
+++ b/src/pkg/go/doc/testdata/b.go
@@ -0,0 +1,58 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "a"
+
+// ----------------------------------------------------------------------------
+// Basic declarations
+
+const Pi = 3.14 // Pi
+var MaxInt int // MaxInt
+type T struct{} // T
+var V T // v
+func F(x int) int {} // F
+func (x *T) M() {} // M
+
+// Corner cases: association with (presumed) predeclared types
+
+// Always under the package functions list.
+func NotAFactory() int {}
+
+// Associated with uint type if AllDecls is set.
+func UintFactory() uint {}
+
+// Associated with uint type if AllDecls is set.
+func uintFactory() uint {}
+
+// Should only appear if AllDecls is set.
+type uint struct{} // overrides a predeclared type uint
+
+// ----------------------------------------------------------------------------
+// Exported declarations associated with non-exported types must always be shown.
+
+type notExported int
+
+const C notExported = 0
+
+const (
+ C1 notExported = iota
+ C2
+ c3
+ C4
+ C5
+)
+
+var V notExported
+var V1, V2, v3, V4, V5 notExported
+
+var (
+ U1, U2, u3, U4, U5 notExported
+ u6 notExported
+ U7 notExported = 7
+)
+
+func F1() notExported {}
+func f2() notExported {}
diff --git a/src/pkg/go/doc/testdata/benchmark.go b/src/pkg/go/doc/testdata/benchmark.go
new file mode 100644
index 000000000..0aded5bb4
--- /dev/null
+++ b/src/pkg/go/doc/testdata/benchmark.go
@@ -0,0 +1,293 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "time"
+)
+
+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 go test.
+type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+}
+
+// B is a type passed to Benchmark functions to manage benchmark
+// timing and to specify the number of iterations to run.
+type B struct {
+ common
+ N int
+ benchmark InternalBenchmark
+ bytes int64
+ timerOn bool
+ result BenchmarkResult
+}
+
+// StartTimer starts timing a test. This function is called automatically
+// before a benchmark starts, but it can also used to resume timing after
+// a call to StopTimer.
+func (b *B) StartTimer() {
+ if !b.timerOn {
+ b.start = time.Now()
+ b.timerOn = true
+ }
+}
+
+// StopTimer stops timing a test. This can be used to pause the timer
+// while performing complex initialization that you don't
+// want to measure.
+func (b *B) StopTimer() {
+ if b.timerOn {
+ b.duration += time.Now().Sub(b.start)
+ b.timerOn = false
+ }
+}
+
+// ResetTimer sets the elapsed benchmark time to zero.
+// It does not affect whether the timer is running.
+func (b *B) ResetTimer() {
+ if b.timerOn {
+ b.start = time.Now()
+ }
+ b.duration = 0
+}
+
+// SetBytes records the number of bytes processed in a single operation.
+// If this is called, the benchmark will report ns/op and MB/s.
+func (b *B) SetBytes(n int64) { b.bytes = n }
+
+func (b *B) nsPerOp() int64 {
+ if b.N <= 0 {
+ return 0
+ }
+ return b.duration.Nanoseconds() / int64(b.N)
+}
+
+// runN runs a single benchmark for the specified number of iterations.
+func (b *B) runN(n int) {
+ // Try to get a comparable environment for each run
+ // by clearing garbage from previous runs.
+ runtime.GC()
+ b.N = n
+ b.ResetTimer()
+ b.StartTimer()
+ b.benchmark.F(b)
+ b.StopTimer()
+}
+
+func min(x, y int) int {
+ if x > y {
+ return y
+ }
+ return x
+}
+
+func max(x, y int) int {
+ if x < y {
+ return y
+ }
+ return x
+}
+
+// roundDown10 rounds a number down to the nearest power of 10.
+func roundDown10(n int) int {
+ var tens = 0
+ // tens = floor(log_10(n))
+ for n > 10 {
+ n = n / 10
+ tens++
+ }
+ // result = 10^tens
+ result := 1
+ for i := 0; i < tens; i++ {
+ result *= 10
+ }
+ return result
+}
+
+// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+func roundUp(n int) int {
+ base := roundDown10(n)
+ if n < (2 * base) {
+ return 2 * base
+ }
+ if n < (5 * base) {
+ return 5 * base
+ }
+ return 10 * base
+}
+
+// run times the benchmark function in a separate goroutine.
+func (b *B) run() BenchmarkResult {
+ go b.launch()
+ <-b.signal
+ return b.result
+}
+
+// launch launches the benchmark function. It gradually increases the number
+// of benchmark iterations until the benchmark runs for a second in order
+// to get a reasonable measurement. It prints timing information in this form
+// testing.BenchmarkHello 100000 19 ns/op
+// launch is run by the fun function as a separate goroutine.
+func (b *B) launch() {
+ // Run the benchmark for a single iteration in case it's expensive.
+ n := 1
+
+ // Signal that we're done whether we return normally
+ // or by FailNow's runtime.Goexit.
+ defer func() {
+ b.signal <- b
+ }()
+
+ b.runN(n)
+ // Run the benchmark for at least the specified amount of time.
+ d := time.Duration(*benchTime * float64(time.Second))
+ for !b.failed && b.duration < d && n < 1e9 {
+ last := n
+ // Predict iterations/sec.
+ if b.nsPerOp() == 0 {
+ n = 1e9
+ } else {
+ n = int(d.Nanoseconds() / b.nsPerOp())
+ }
+ // Run more iterations than we think we'll need for a second (1.5x).
+ // Don't grow too fast in case we had timing errors previously.
+ // Be sure to run at least one more than last time.
+ n = max(min(n+n/2, 100*last), last+1)
+ // Round up to something easy to read.
+ n = roundUp(n)
+ b.runN(n)
+ }
+ b.result = BenchmarkResult{b.N, b.duration, b.bytes}
+}
+
+// The results of a benchmark run.
+type BenchmarkResult struct {
+ N int // The number of iterations.
+ T time.Duration // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
+}
+
+func (r BenchmarkResult) NsPerOp() int64 {
+ if r.N <= 0 {
+ return 0
+ }
+ return r.T.Nanoseconds() / int64(r.N)
+}
+
+func (r BenchmarkResult) mbPerSec() float64 {
+ if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 {
+ return 0
+ }
+ return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
+}
+
+func (r BenchmarkResult) String() string {
+ mbs := r.mbPerSec()
+ mb := ""
+ if mbs != 0 {
+ mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
+ }
+ 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.T.Nanoseconds())/float64(r.N))
+ } else {
+ ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
+ }
+ }
+ return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of go test.
+func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
+ // If no flag was specified, don't run benchmarks.
+ if len(*matchBenchmarks) == 0 {
+ return
+ }
+ for _, Benchmark := range benchmarks {
+ matched, err := matchString(*matchBenchmarks, Benchmark.Name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: Benchmark,
+ }
+ benchName := Benchmark.Name
+ if procs != 1 {
+ benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+ }
+ fmt.Printf("%s\t", benchName)
+ r := b.run()
+ if b.failed {
+ // The output could be very long here, but probably isn't.
+ // We print it all, regardless, because we don't want to trim the reason
+ // the benchmark failed.
+ fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
+ continue
+ }
+ fmt.Printf("%v\n", r)
+ // Unlike with tests, we ignore the -chatty flag and always print output for
+ // benchmarks since the output generation time will skew the results.
+ if len(b.output) > 0 {
+ b.trimOutput()
+ fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
+ }
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
+ }
+ }
+ }
+}
+
+// trimOutput shortens the output from a benchmark, which can be very long.
+func (b *B) trimOutput() {
+ // The output is likely to appear multiple times because the benchmark
+ // is run multiple times, but at least it will be seen. This is not a big deal
+ // because benchmarks rarely print, but just in case, we trim it if it's too long.
+ const maxNewlines = 10
+ for nlCount, j := 0, 0; j < len(b.output); j++ {
+ if b.output[j] == '\n' {
+ nlCount++
+ if nlCount >= maxNewlines {
+ b.output = append(b.output[:j], "\n\t... [output truncated]\n"...)
+ break
+ }
+ }
+ }
+}
+
+// Benchmark benchmarks a single function. Useful for creating
+// custom benchmarks that do not use go test.
+func Benchmark(f func(b *B)) BenchmarkResult {
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: InternalBenchmark{"", f},
+ }
+ return b.run()
+}
diff --git a/src/pkg/go/doc/testdata/c.0.golden b/src/pkg/go/doc/testdata/c.0.golden
new file mode 100644
index 000000000..e21959b19
--- /dev/null
+++ b/src/pkg/go/doc/testdata/c.0.golden
@@ -0,0 +1,48 @@
+//
+PACKAGE c
+
+IMPORTPATH
+ testdata/c
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/c.go
+
+TYPES
+ // A (should see this)
+ type A struct{}
+
+ // B (should see this)
+ type B struct{}
+
+ // C (should see this)
+ type C struct{}
+
+ // D (should see this)
+ type D struct{}
+
+ // E1 (should see this)
+ type E1 struct{}
+
+ // E (should see this for E2 and E3)
+ type E2 struct{}
+
+ // E (should see this for E2 and E3)
+ type E3 struct{}
+
+ // E4 (should see this)
+ type E4 struct{}
+
+ //
+ type T1 struct{}
+
+ //
+ func (t1 *T1) M()
+
+ // T2 must not show methods of local T1
+ type T2 struct {
+ a.T1 // not the same as locally declared T1
+ }
+
diff --git a/src/pkg/go/doc/testdata/c.1.golden b/src/pkg/go/doc/testdata/c.1.golden
new file mode 100644
index 000000000..e21959b19
--- /dev/null
+++ b/src/pkg/go/doc/testdata/c.1.golden
@@ -0,0 +1,48 @@
+//
+PACKAGE c
+
+IMPORTPATH
+ testdata/c
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/c.go
+
+TYPES
+ // A (should see this)
+ type A struct{}
+
+ // B (should see this)
+ type B struct{}
+
+ // C (should see this)
+ type C struct{}
+
+ // D (should see this)
+ type D struct{}
+
+ // E1 (should see this)
+ type E1 struct{}
+
+ // E (should see this for E2 and E3)
+ type E2 struct{}
+
+ // E (should see this for E2 and E3)
+ type E3 struct{}
+
+ // E4 (should see this)
+ type E4 struct{}
+
+ //
+ type T1 struct{}
+
+ //
+ func (t1 *T1) M()
+
+ // T2 must not show methods of local T1
+ type T2 struct {
+ a.T1 // not the same as locally declared T1
+ }
+
diff --git a/src/pkg/go/doc/testdata/c.2.golden b/src/pkg/go/doc/testdata/c.2.golden
new file mode 100644
index 000000000..e21959b19
--- /dev/null
+++ b/src/pkg/go/doc/testdata/c.2.golden
@@ -0,0 +1,48 @@
+//
+PACKAGE c
+
+IMPORTPATH
+ testdata/c
+
+IMPORTS
+ a
+
+FILENAMES
+ testdata/c.go
+
+TYPES
+ // A (should see this)
+ type A struct{}
+
+ // B (should see this)
+ type B struct{}
+
+ // C (should see this)
+ type C struct{}
+
+ // D (should see this)
+ type D struct{}
+
+ // E1 (should see this)
+ type E1 struct{}
+
+ // E (should see this for E2 and E3)
+ type E2 struct{}
+
+ // E (should see this for E2 and E3)
+ type E3 struct{}
+
+ // E4 (should see this)
+ type E4 struct{}
+
+ //
+ type T1 struct{}
+
+ //
+ func (t1 *T1) M()
+
+ // T2 must not show methods of local T1
+ type T2 struct {
+ a.T1 // not the same as locally declared T1
+ }
+
diff --git a/src/pkg/go/doc/testdata/c.go b/src/pkg/go/doc/testdata/c.go
new file mode 100644
index 000000000..e0f39196d
--- /dev/null
+++ b/src/pkg/go/doc/testdata/c.go
@@ -0,0 +1,62 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import "a"
+
+// ----------------------------------------------------------------------------
+// Test that empty declarations don't cause problems
+
+const ()
+
+type ()
+
+var ()
+
+// ----------------------------------------------------------------------------
+// Test that types with documentation on both, the Decl and the Spec node
+// are handled correctly.
+
+// A (should see this)
+type A struct{}
+
+// B (should see this)
+type (
+ B struct{}
+)
+
+type (
+ // C (should see this)
+ C struct{}
+)
+
+// D (should not see this)
+type (
+ // D (should see this)
+ D struct{}
+)
+
+// E (should see this for E2 and E3)
+type (
+ // E1 (should see this)
+ E1 struct{}
+ E2 struct{}
+ E3 struct{}
+ // E4 (should see this)
+ E4 struct{}
+)
+
+// ----------------------------------------------------------------------------
+// Test that local and imported types are different when
+// handling anonymous fields.
+
+type T1 struct{}
+
+func (t1 *T1) M() {}
+
+// T2 must not show methods of local T1
+type T2 struct {
+ a.T1 // not the same as locally declared T1
+}
diff --git a/src/pkg/go/doc/testdata/d.0.golden b/src/pkg/go/doc/testdata/d.0.golden
new file mode 100644
index 000000000..c00519953
--- /dev/null
+++ b/src/pkg/go/doc/testdata/d.0.golden
@@ -0,0 +1,104 @@
+//
+PACKAGE d
+
+IMPORTPATH
+ testdata/d
+
+FILENAMES
+ testdata/d1.go
+ testdata/d2.go
+
+CONSTANTS
+ // CBx constants should appear before CAx constants.
+ const (
+ CB2 = iota // before CB1
+ CB1 // before CB0
+ CB0 // at end
+ )
+
+ // CAx constants should appear after CBx constants.
+ const (
+ CA2 = iota // before CA1
+ CA1 // before CA0
+ CA0 // at end
+ )
+
+ // C0 should be first.
+ const C0 = 0
+
+ // C1 should be second.
+ const C1 = 1
+
+ // C2 should be third.
+ const C2 = 2
+
+ //
+ const (
+ // Single const declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Cungrouped = 0
+ )
+
+
+VARIABLES
+ // VBx variables should appear before VAx variables.
+ var (
+ VB2 int // before VB1
+ VB1 int // before VB0
+ VB0 int // at end
+ )
+
+ // VAx variables should appear after VBx variables.
+ var (
+ VA2 int // before VA1
+ VA1 int // before VA0
+ VA0 int // at end
+ )
+
+ // V0 should be first.
+ var V0 uintptr
+
+ // V1 should be second.
+ var V1 uint
+
+ // V2 should be third.
+ var V2 int
+
+ //
+ var (
+ // Single var declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Vungrouped = 0
+ )
+
+
+FUNCTIONS
+ // F0 should be first.
+ func F0()
+
+ // F1 should be second.
+ func F1()
+
+ // F2 should be third.
+ func F2()
+
+
+TYPES
+ // T0 should be first.
+ type T0 struct{}
+
+ // T1 should be second.
+ type T1 struct{}
+
+ // T2 should be third.
+ type T2 struct{}
+
+ // TG0 should be first.
+ type TG0 struct{}
+
+ // TG1 should be second.
+ type TG1 struct{}
+
+ // TG2 should be third.
+ type TG2 struct{}
+
diff --git a/src/pkg/go/doc/testdata/d.1.golden b/src/pkg/go/doc/testdata/d.1.golden
new file mode 100644
index 000000000..c00519953
--- /dev/null
+++ b/src/pkg/go/doc/testdata/d.1.golden
@@ -0,0 +1,104 @@
+//
+PACKAGE d
+
+IMPORTPATH
+ testdata/d
+
+FILENAMES
+ testdata/d1.go
+ testdata/d2.go
+
+CONSTANTS
+ // CBx constants should appear before CAx constants.
+ const (
+ CB2 = iota // before CB1
+ CB1 // before CB0
+ CB0 // at end
+ )
+
+ // CAx constants should appear after CBx constants.
+ const (
+ CA2 = iota // before CA1
+ CA1 // before CA0
+ CA0 // at end
+ )
+
+ // C0 should be first.
+ const C0 = 0
+
+ // C1 should be second.
+ const C1 = 1
+
+ // C2 should be third.
+ const C2 = 2
+
+ //
+ const (
+ // Single const declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Cungrouped = 0
+ )
+
+
+VARIABLES
+ // VBx variables should appear before VAx variables.
+ var (
+ VB2 int // before VB1
+ VB1 int // before VB0
+ VB0 int // at end
+ )
+
+ // VAx variables should appear after VBx variables.
+ var (
+ VA2 int // before VA1
+ VA1 int // before VA0
+ VA0 int // at end
+ )
+
+ // V0 should be first.
+ var V0 uintptr
+
+ // V1 should be second.
+ var V1 uint
+
+ // V2 should be third.
+ var V2 int
+
+ //
+ var (
+ // Single var declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Vungrouped = 0
+ )
+
+
+FUNCTIONS
+ // F0 should be first.
+ func F0()
+
+ // F1 should be second.
+ func F1()
+
+ // F2 should be third.
+ func F2()
+
+
+TYPES
+ // T0 should be first.
+ type T0 struct{}
+
+ // T1 should be second.
+ type T1 struct{}
+
+ // T2 should be third.
+ type T2 struct{}
+
+ // TG0 should be first.
+ type TG0 struct{}
+
+ // TG1 should be second.
+ type TG1 struct{}
+
+ // TG2 should be third.
+ type TG2 struct{}
+
diff --git a/src/pkg/go/doc/testdata/d.2.golden b/src/pkg/go/doc/testdata/d.2.golden
new file mode 100644
index 000000000..c00519953
--- /dev/null
+++ b/src/pkg/go/doc/testdata/d.2.golden
@@ -0,0 +1,104 @@
+//
+PACKAGE d
+
+IMPORTPATH
+ testdata/d
+
+FILENAMES
+ testdata/d1.go
+ testdata/d2.go
+
+CONSTANTS
+ // CBx constants should appear before CAx constants.
+ const (
+ CB2 = iota // before CB1
+ CB1 // before CB0
+ CB0 // at end
+ )
+
+ // CAx constants should appear after CBx constants.
+ const (
+ CA2 = iota // before CA1
+ CA1 // before CA0
+ CA0 // at end
+ )
+
+ // C0 should be first.
+ const C0 = 0
+
+ // C1 should be second.
+ const C1 = 1
+
+ // C2 should be third.
+ const C2 = 2
+
+ //
+ const (
+ // Single const declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Cungrouped = 0
+ )
+
+
+VARIABLES
+ // VBx variables should appear before VAx variables.
+ var (
+ VB2 int // before VB1
+ VB1 int // before VB0
+ VB0 int // at end
+ )
+
+ // VAx variables should appear after VBx variables.
+ var (
+ VA2 int // before VA1
+ VA1 int // before VA0
+ VA0 int // at end
+ )
+
+ // V0 should be first.
+ var V0 uintptr
+
+ // V1 should be second.
+ var V1 uint
+
+ // V2 should be third.
+ var V2 int
+
+ //
+ var (
+ // Single var declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Vungrouped = 0
+ )
+
+
+FUNCTIONS
+ // F0 should be first.
+ func F0()
+
+ // F1 should be second.
+ func F1()
+
+ // F2 should be third.
+ func F2()
+
+
+TYPES
+ // T0 should be first.
+ type T0 struct{}
+
+ // T1 should be second.
+ type T1 struct{}
+
+ // T2 should be third.
+ type T2 struct{}
+
+ // TG0 should be first.
+ type TG0 struct{}
+
+ // TG1 should be second.
+ type TG1 struct{}
+
+ // TG2 should be third.
+ type TG2 struct{}
+
diff --git a/src/pkg/go/doc/testdata/d1.go b/src/pkg/go/doc/testdata/d1.go
new file mode 100644
index 000000000..ebd694195
--- /dev/null
+++ b/src/pkg/go/doc/testdata/d1.go
@@ -0,0 +1,57 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases for sort order of declarations.
+
+package d
+
+// C2 should be third.
+const C2 = 2
+
+// V2 should be third.
+var V2 int
+
+// CBx constants should appear before CAx constants.
+const (
+ CB2 = iota // before CB1
+ CB1 // before CB0
+ CB0 // at end
+)
+
+// VBx variables should appear before VAx variables.
+var (
+ VB2 int // before VB1
+ VB1 int // before VB0
+ VB0 int // at end
+)
+
+const (
+ // Single const declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Cungrouped = 0
+)
+
+var (
+ // Single var declarations inside ()'s are considered ungrouped
+ // and show up in sorted order.
+ Vungrouped = 0
+)
+
+// T2 should be third.
+type T2 struct{}
+
+// Grouped types are sorted nevertheless.
+type (
+ // TG2 should be third.
+ TG2 struct{}
+
+ // TG1 should be second.
+ TG1 struct{}
+
+ // TG0 should be first.
+ TG0 struct{}
+)
+
+// F2 should be third.
+func F2() {}
diff --git a/src/pkg/go/doc/testdata/d2.go b/src/pkg/go/doc/testdata/d2.go
new file mode 100644
index 000000000..2f56f4fa4
--- /dev/null
+++ b/src/pkg/go/doc/testdata/d2.go
@@ -0,0 +1,45 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test cases for sort order of declarations.
+
+package d
+
+// C1 should be second.
+const C1 = 1
+
+// C0 should be first.
+const C0 = 0
+
+// V1 should be second.
+var V1 uint
+
+// V0 should be first.
+var V0 uintptr
+
+// CAx constants should appear after CBx constants.
+const (
+ CA2 = iota // before CA1
+ CA1 // before CA0
+ CA0 // at end
+)
+
+// VAx variables should appear after VBx variables.
+var (
+ VA2 int // before VA1
+ VA1 int // before VA0
+ VA0 int // at end
+)
+
+// T1 should be second.
+type T1 struct{}
+
+// T0 should be first.
+type T0 struct{}
+
+// F1 should be second.
+func F1() {}
+
+// F0 should be first.
+func F0() {}
diff --git a/src/pkg/go/doc/testdata/e.0.golden b/src/pkg/go/doc/testdata/e.0.golden
new file mode 100644
index 000000000..6987e5867
--- /dev/null
+++ b/src/pkg/go/doc/testdata/e.0.golden
@@ -0,0 +1,109 @@
+// The package e is a go/doc test for embedded methods.
+PACKAGE e
+
+IMPORTPATH
+ testdata/e
+
+FILENAMES
+ testdata/e.go
+
+TYPES
+ // T1 has no embedded (level 1) M method due to conflict.
+ type T1 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T2 has only M as top-level method.
+ type T2 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T2.M should appear as method of T2.
+ func (T2) M()
+
+ // T3 has only M as top-level method.
+ type T3 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T3.M should appear as method of T3.
+ func (T3) M()
+
+ //
+ type T4 struct{}
+
+ // T4.M should appear as method of T5 only if AllMethods is set.
+ func (*T4) M()
+
+ //
+ type T5 struct {
+ T4
+ }
+
+ //
+ type U1 struct {
+ *U1
+ }
+
+ // U1.M should appear as method of U1.
+ func (*U1) M()
+
+ //
+ type U2 struct {
+ *U3
+ }
+
+ // U2.M should appear as method of U2 and as method of U3 only if ...
+ func (*U2) M()
+
+ //
+ type U3 struct {
+ *U2
+ }
+
+ // U3.N should appear as method of U3 and as method of U2 only if ...
+ func (*U3) N()
+
+ //
+ type U4 struct {
+ // contains filtered or unexported fields
+ }
+
+ // U4.M should appear as method of U4.
+ func (*U4) M()
+
+ //
+ type V1 struct {
+ *V2
+ *V5
+ }
+
+ //
+ type V2 struct {
+ *V3
+ }
+
+ //
+ type V3 struct {
+ *V4
+ }
+
+ //
+ type V4 struct {
+ *V5
+ }
+
+ // V4.M should appear as method of V2 and V3 if AllMethods is set.
+ func (*V4) M()
+
+ //
+ type V5 struct {
+ *V6
+ }
+
+ //
+ type V6 struct{}
+
+ // V6.M should appear as method of V1 and V5 if AllMethods is set.
+ func (*V6) M()
+
diff --git a/src/pkg/go/doc/testdata/e.1.golden b/src/pkg/go/doc/testdata/e.1.golden
new file mode 100644
index 000000000..cbe22e0bf
--- /dev/null
+++ b/src/pkg/go/doc/testdata/e.1.golden
@@ -0,0 +1,144 @@
+// The package e is a go/doc test for embedded methods.
+PACKAGE e
+
+IMPORTPATH
+ testdata/e
+
+FILENAMES
+ testdata/e.go
+
+TYPES
+ // T1 has no embedded (level 1) M method due to conflict.
+ type T1 struct {
+ t1
+ t2
+ }
+
+ // T2 has only M as top-level method.
+ type T2 struct {
+ t1
+ }
+
+ // T2.M should appear as method of T2.
+ func (T2) M()
+
+ // T3 has only M as top-level method.
+ type T3 struct {
+ t1e
+ t2e
+ }
+
+ // T3.M should appear as method of T3.
+ func (T3) M()
+
+ //
+ type T4 struct{}
+
+ // T4.M should appear as method of T5 only if AllMethods is set.
+ func (*T4) M()
+
+ //
+ type T5 struct {
+ T4
+ }
+
+ //
+ type U1 struct {
+ *U1
+ }
+
+ // U1.M should appear as method of U1.
+ func (*U1) M()
+
+ //
+ type U2 struct {
+ *U3
+ }
+
+ // U2.M should appear as method of U2 and as method of U3 only if ...
+ func (*U2) M()
+
+ //
+ type U3 struct {
+ *U2
+ }
+
+ // U3.N should appear as method of U3 and as method of U2 only if ...
+ func (*U3) N()
+
+ //
+ type U4 struct {
+ *u5
+ }
+
+ // U4.M should appear as method of U4.
+ func (*U4) M()
+
+ //
+ type V1 struct {
+ *V2
+ *V5
+ }
+
+ //
+ type V2 struct {
+ *V3
+ }
+
+ //
+ type V3 struct {
+ *V4
+ }
+
+ //
+ type V4 struct {
+ *V5
+ }
+
+ // V4.M should appear as method of V2 and V3 if AllMethods is set.
+ func (*V4) M()
+
+ //
+ type V5 struct {
+ *V6
+ }
+
+ //
+ type V6 struct{}
+
+ // V6.M should appear as method of V1 and V5 if AllMethods is set.
+ func (*V6) M()
+
+ //
+ type t1 struct{}
+
+ // t1.M should not appear as method in a Tx type.
+ func (t1) M()
+
+ //
+ type t1e struct {
+ t1
+ }
+
+ // t1.M should not appear as method in a Tx type.
+ func (t1e) M()
+
+ //
+ type t2 struct{}
+
+ // t2.M should not appear as method in a Tx type.
+ func (t2) M()
+
+ //
+ type t2e struct {
+ t2
+ }
+
+ // t2.M should not appear as method in a Tx type.
+ func (t2e) M()
+
+ //
+ type u5 struct {
+ *U4
+ }
+
diff --git a/src/pkg/go/doc/testdata/e.2.golden b/src/pkg/go/doc/testdata/e.2.golden
new file mode 100644
index 000000000..e7b05e80f
--- /dev/null
+++ b/src/pkg/go/doc/testdata/e.2.golden
@@ -0,0 +1,130 @@
+// The package e is a go/doc test for embedded methods.
+PACKAGE e
+
+IMPORTPATH
+ testdata/e
+
+FILENAMES
+ testdata/e.go
+
+TYPES
+ // T1 has no embedded (level 1) M method due to conflict.
+ type T1 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T2 has only M as top-level method.
+ type T2 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T2.M should appear as method of T2.
+ func (T2) M()
+
+ // T3 has only M as top-level method.
+ type T3 struct {
+ // contains filtered or unexported fields
+ }
+
+ // T3.M should appear as method of T3.
+ func (T3) M()
+
+ //
+ type T4 struct{}
+
+ // T4.M should appear as method of T5 only if AllMethods is set.
+ func (*T4) M()
+
+ //
+ type T5 struct {
+ T4
+ }
+
+ // T4.M should appear as method of T5 only if AllMethods is set.
+ func (*T5) M()
+
+ //
+ type U1 struct {
+ *U1
+ }
+
+ // U1.M should appear as method of U1.
+ func (*U1) M()
+
+ //
+ type U2 struct {
+ *U3
+ }
+
+ // U2.M should appear as method of U2 and as method of U3 only if ...
+ func (*U2) M()
+
+ // U3.N should appear as method of U3 and as method of U2 only if ...
+ func (U2) N()
+
+ //
+ type U3 struct {
+ *U2
+ }
+
+ // U2.M should appear as method of U2 and as method of U3 only if ...
+ func (U3) M()
+
+ // U3.N should appear as method of U3 and as method of U2 only if ...
+ func (*U3) N()
+
+ //
+ type U4 struct {
+ // contains filtered or unexported fields
+ }
+
+ // U4.M should appear as method of U4.
+ func (*U4) M()
+
+ //
+ type V1 struct {
+ *V2
+ *V5
+ }
+
+ // V6.M should appear as method of V1 and V5 if AllMethods is set.
+ func (V1) M()
+
+ //
+ type V2 struct {
+ *V3
+ }
+
+ // V4.M should appear as method of V2 and V3 if AllMethods is set.
+ func (V2) M()
+
+ //
+ type V3 struct {
+ *V4
+ }
+
+ // V4.M should appear as method of V2 and V3 if AllMethods is set.
+ func (V3) M()
+
+ //
+ type V4 struct {
+ *V5
+ }
+
+ // V4.M should appear as method of V2 and V3 if AllMethods is set.
+ func (*V4) M()
+
+ //
+ type V5 struct {
+ *V6
+ }
+
+ // V6.M should appear as method of V1 and V5 if AllMethods is set.
+ func (V5) M()
+
+ //
+ type V6 struct{}
+
+ // V6.M should appear as method of V1 and V5 if AllMethods is set.
+ func (*V6) M()
+
diff --git a/src/pkg/go/doc/testdata/e.go b/src/pkg/go/doc/testdata/e.go
new file mode 100644
index 000000000..19dd138cf
--- /dev/null
+++ b/src/pkg/go/doc/testdata/e.go
@@ -0,0 +1,147 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The package e is a go/doc test for embedded methods.
+package e
+
+// ----------------------------------------------------------------------------
+// Conflicting methods M must not show up.
+
+type t1 struct{}
+
+// t1.M should not appear as method in a Tx type.
+func (t1) M() {}
+
+type t2 struct{}
+
+// t2.M should not appear as method in a Tx type.
+func (t2) M() {}
+
+// T1 has no embedded (level 1) M method due to conflict.
+type T1 struct {
+ t1
+ t2
+}
+
+// ----------------------------------------------------------------------------
+// Higher-level method M wins over lower-level method M.
+
+// T2 has only M as top-level method.
+type T2 struct {
+ t1
+}
+
+// T2.M should appear as method of T2.
+func (T2) M() {}
+
+// ----------------------------------------------------------------------------
+// Higher-level method M wins over lower-level conflicting methods M.
+
+type t1e struct {
+ t1
+}
+
+type t2e struct {
+ t2
+}
+
+// T3 has only M as top-level method.
+type T3 struct {
+ t1e
+ t2e
+}
+
+// T3.M should appear as method of T3.
+func (T3) M() {}
+
+// ----------------------------------------------------------------------------
+// Don't show conflicting methods M embedded via an exported and non-exported
+// type.
+
+// T1 has no embedded (level 1) M method due to conflict.
+type T4 struct {
+ t2
+ T2
+}
+
+// ----------------------------------------------------------------------------
+// Don't show embedded methods of exported anonymous fields unless AllMethods
+// is set.
+
+type T4 struct{}
+
+// T4.M should appear as method of T5 only if AllMethods is set.
+func (*T4) M() {}
+
+type T5 struct {
+ T4
+}
+
+// ----------------------------------------------------------------------------
+// Recursive type declarations must not lead to endless recursion.
+
+type U1 struct {
+ *U1
+}
+
+// U1.M should appear as method of U1.
+func (*U1) M() {}
+
+type U2 struct {
+ *U3
+}
+
+// U2.M should appear as method of U2 and as method of U3 only if AllMethods is set.
+func (*U2) M() {}
+
+type U3 struct {
+ *U2
+}
+
+// U3.N should appear as method of U3 and as method of U2 only if AllMethods is set.
+func (*U3) N() {}
+
+type U4 struct {
+ *u5
+}
+
+// U4.M should appear as method of U4.
+func (*U4) M() {}
+
+type u5 struct {
+ *U4
+}
+
+// ----------------------------------------------------------------------------
+// A higher-level embedded type (and its methods) wins over the same type (and
+// its methods) embedded at a lower level.
+
+type V1 struct {
+ *V2
+ *V5
+}
+
+type V2 struct {
+ *V3
+}
+
+type V3 struct {
+ *V4
+}
+
+type V4 struct {
+ *V5
+}
+
+type V5 struct {
+ *V6
+}
+
+type V6 struct{}
+
+// V4.M should appear as method of V2 and V3 if AllMethods is set.
+func (*V4) M() {}
+
+// V6.M should appear as method of V1 and V5 if AllMethods is set.
+func (*V6) M() {}
diff --git a/src/pkg/go/doc/testdata/error1.0.golden b/src/pkg/go/doc/testdata/error1.0.golden
new file mode 100644
index 000000000..6c6fe5d49
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error1.0.golden
@@ -0,0 +1,30 @@
+//
+PACKAGE error1
+
+IMPORTPATH
+ testdata/error1
+
+FILENAMES
+ testdata/error1.go
+
+TYPES
+ //
+ type I0 interface {
+ // When embedded, the predeclared error interface
+ // must remain visible in interface types.
+ error
+ }
+
+ //
+ type S0 struct {
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // error should be visible
+ error
+ }
+ }
+
diff --git a/src/pkg/go/doc/testdata/error1.1.golden b/src/pkg/go/doc/testdata/error1.1.golden
new file mode 100644
index 000000000..a8dc2e71d
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error1.1.golden
@@ -0,0 +1,32 @@
+//
+PACKAGE error1
+
+IMPORTPATH
+ testdata/error1
+
+FILENAMES
+ testdata/error1.go
+
+TYPES
+ //
+ type I0 interface {
+ // When embedded, the predeclared error interface
+ // must remain visible in interface types.
+ error
+ }
+
+ //
+ type S0 struct {
+ // In struct types, an embedded error must only be visible
+ // if AllDecls is set.
+ error
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // error should be visible
+ error
+ }
+ }
+
diff --git a/src/pkg/go/doc/testdata/error1.2.golden b/src/pkg/go/doc/testdata/error1.2.golden
new file mode 100644
index 000000000..6c6fe5d49
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error1.2.golden
@@ -0,0 +1,30 @@
+//
+PACKAGE error1
+
+IMPORTPATH
+ testdata/error1
+
+FILENAMES
+ testdata/error1.go
+
+TYPES
+ //
+ type I0 interface {
+ // When embedded, the predeclared error interface
+ // must remain visible in interface types.
+ error
+ }
+
+ //
+ type S0 struct {
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // error should be visible
+ error
+ }
+ }
+
diff --git a/src/pkg/go/doc/testdata/error1.go b/src/pkg/go/doc/testdata/error1.go
new file mode 100644
index 000000000..3c777a780
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error1.go
@@ -0,0 +1,24 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package error1
+
+type I0 interface {
+ // When embedded, the predeclared error interface
+ // must remain visible in interface types.
+ error
+}
+
+type T0 struct {
+ ExportedField interface {
+ // error should be visible
+ error
+ }
+}
+
+type S0 struct {
+ // In struct types, an embedded error must only be visible
+ // if AllDecls is set.
+ error
+}
diff --git a/src/pkg/go/doc/testdata/error2.0.golden b/src/pkg/go/doc/testdata/error2.0.golden
new file mode 100644
index 000000000..dedfe412a
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error2.0.golden
@@ -0,0 +1,27 @@
+//
+PACKAGE error2
+
+IMPORTPATH
+ testdata/error2
+
+FILENAMES
+ testdata/error2.go
+
+TYPES
+ //
+ type I0 interface {
+ // contains filtered or unexported methods
+ }
+
+ //
+ type S0 struct {
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // contains filtered or unexported methods
+ }
+ }
+
diff --git a/src/pkg/go/doc/testdata/error2.1.golden b/src/pkg/go/doc/testdata/error2.1.golden
new file mode 100644
index 000000000..776bd1b3e
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error2.1.golden
@@ -0,0 +1,37 @@
+//
+PACKAGE error2
+
+IMPORTPATH
+ testdata/error2
+
+FILENAMES
+ testdata/error2.go
+
+TYPES
+ //
+ type I0 interface {
+ // When embedded, the the locally declared error interface
+ // is only visible if all declarations are shown.
+ error
+ }
+
+ //
+ type S0 struct {
+ // In struct types, an embedded error must only be visible
+ // if AllDecls is set.
+ error
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // error should not be visible
+ error
+ }
+ }
+
+ // This error declaration shadows the predeclared error type.
+ type error interface {
+ Error() string
+ }
+
diff --git a/src/pkg/go/doc/testdata/error2.2.golden b/src/pkg/go/doc/testdata/error2.2.golden
new file mode 100644
index 000000000..dedfe412a
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error2.2.golden
@@ -0,0 +1,27 @@
+//
+PACKAGE error2
+
+IMPORTPATH
+ testdata/error2
+
+FILENAMES
+ testdata/error2.go
+
+TYPES
+ //
+ type I0 interface {
+ // contains filtered or unexported methods
+ }
+
+ //
+ type S0 struct {
+ // contains filtered or unexported fields
+ }
+
+ //
+ type T0 struct {
+ ExportedField interface {
+ // contains filtered or unexported methods
+ }
+ }
+
diff --git a/src/pkg/go/doc/testdata/error2.go b/src/pkg/go/doc/testdata/error2.go
new file mode 100644
index 000000000..6cc36feef
--- /dev/null
+++ b/src/pkg/go/doc/testdata/error2.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package error2
+
+type I0 interface {
+ // When embedded, the the locally declared error interface
+ // is only visible if all declarations are shown.
+ error
+}
+
+type T0 struct {
+ ExportedField interface {
+ // error should not be visible
+ error
+ }
+}
+
+type S0 struct {
+ // In struct types, an embedded error must only be visible
+ // if AllDecls is set.
+ error
+}
+
+// This error declaration shadows the predeclared error type.
+type error interface {
+ Error() string
+}
diff --git a/src/pkg/go/doc/testdata/example.go b/src/pkg/go/doc/testdata/example.go
new file mode 100644
index 000000000..fdeda137e
--- /dev/null
+++ b/src/pkg/go/doc/testdata/example.go
@@ -0,0 +1,81 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+type InternalExample struct {
+ Name string
+ F func()
+ Output string
+}
+
+func RunExamples(examples []InternalExample) (ok bool) {
+ ok = true
+
+ var eg InternalExample
+
+ stdout, stderr := os.Stdout, os.Stderr
+ defer func() {
+ os.Stdout, os.Stderr = stdout, stderr
+ if e := recover(); e != nil {
+ fmt.Printf("--- FAIL: %s\npanic: %v\n", eg.Name, e)
+ os.Exit(1)
+ }
+ }()
+
+ for _, eg = range examples {
+ if *chatty {
+ fmt.Printf("=== RUN: %s\n", eg.Name)
+ }
+
+ // capture stdout and stderr
+ r, w, err := os.Pipe()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ os.Stdout, os.Stderr = w, w
+ outC := make(chan string)
+ go func() {
+ buf := new(bytes.Buffer)
+ _, err := io.Copy(buf, r)
+ if err != nil {
+ fmt.Fprintf(stderr, "testing: copying pipe: %v\n", err)
+ os.Exit(1)
+ }
+ outC <- buf.String()
+ }()
+
+ // run example
+ t0 := time.Now()
+ eg.F()
+ dt := time.Now().Sub(t0)
+
+ // close pipe, restore stdout/stderr, get output
+ w.Close()
+ os.Stdout, os.Stderr = stdout, stderr
+ out := <-outC
+
+ // report any errors
+ tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
+ if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
+ fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
+ eg.Name, tstr, g, e)
+ ok = false
+ } else if *chatty {
+ fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
+ }
+ }
+
+ return
+}
diff --git a/src/pkg/go/doc/testdata/f.0.golden b/src/pkg/go/doc/testdata/f.0.golden
new file mode 100644
index 000000000..817590186
--- /dev/null
+++ b/src/pkg/go/doc/testdata/f.0.golden
@@ -0,0 +1,13 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+ testdata/f
+
+FILENAMES
+ testdata/f.go
+
+FUNCTIONS
+ // Exported must always be visible. Was issue 2824.
+ func Exported() private
+
diff --git a/src/pkg/go/doc/testdata/f.1.golden b/src/pkg/go/doc/testdata/f.1.golden
new file mode 100644
index 000000000..ba68e884c
--- /dev/null
+++ b/src/pkg/go/doc/testdata/f.1.golden
@@ -0,0 +1,16 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+ testdata/f
+
+FILENAMES
+ testdata/f.go
+
+TYPES
+ //
+ type private struct{}
+
+ // Exported must always be visible. Was issue 2824.
+ func Exported() private
+
diff --git a/src/pkg/go/doc/testdata/f.2.golden b/src/pkg/go/doc/testdata/f.2.golden
new file mode 100644
index 000000000..817590186
--- /dev/null
+++ b/src/pkg/go/doc/testdata/f.2.golden
@@ -0,0 +1,13 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+ testdata/f
+
+FILENAMES
+ testdata/f.go
+
+FUNCTIONS
+ // Exported must always be visible. Was issue 2824.
+ func Exported() private
+
diff --git a/src/pkg/go/doc/testdata/f.go b/src/pkg/go/doc/testdata/f.go
new file mode 100644
index 000000000..7e9add907
--- /dev/null
+++ b/src/pkg/go/doc/testdata/f.go
@@ -0,0 +1,14 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The package f is a go/doc test for functions and factory methods.
+package f
+
+// ----------------------------------------------------------------------------
+// Factory functions for non-exported types must not get lost.
+
+type private struct{}
+
+// Exported must always be visible. Was issue 2824.
+func Exported() private {}
diff --git a/src/pkg/go/doc/testdata/template.txt b/src/pkg/go/doc/testdata/template.txt
new file mode 100644
index 000000000..32e331cdd
--- /dev/null
+++ b/src/pkg/go/doc/testdata/template.txt
@@ -0,0 +1,65 @@
+{{synopsis .Doc}}
+PACKAGE {{.Name}}
+
+IMPORTPATH
+ {{.ImportPath}}
+
+{{with .Imports}}IMPORTS
+{{range .}} {{.}}
+{{end}}
+{{end}}{{/*
+
+*/}}FILENAMES
+{{range .Filenames}} {{.}}
+{{end}}{{/*
+
+*/}}{{with .Consts}}
+CONSTANTS
+{{range .}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{end}}{{/*
+
+*/}}{{with .Vars}}
+VARIABLES
+{{range .}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{end}}{{/*
+
+*/}}{{with .Funcs}}
+FUNCTIONS
+{{range .}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{end}}{{/*
+
+*/}}{{with .Types}}
+TYPES
+{{range .}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{range .Consts}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{/*
+
+*/}}{{range .Vars}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{/*
+
+*/}}{{range .Funcs}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{/*
+
+*/}}{{range .Methods}} {{synopsis .Doc}}
+ {{node .Decl $.FSet}}
+
+{{end}}{{end}}{{end}}{{/*
+
+*/}}{{with .Bugs}}
+BUGS
+{{range .}} {{synopsis .}}
+{{end}}{{end}} \ No newline at end of file
diff --git a/src/pkg/go/doc/testdata/testing.0.golden b/src/pkg/go/doc/testdata/testing.0.golden
new file mode 100644
index 000000000..15a903986
--- /dev/null
+++ b/src/pkg/go/doc/testdata/testing.0.golden
@@ -0,0 +1,156 @@
+// Package testing provides support for automated testing of Go ...
+PACKAGE testing
+
+IMPORTPATH
+ testdata/testing
+
+IMPORTS
+ bytes
+ flag
+ fmt
+ io
+ os
+ runtime
+ runtime/pprof
+ strconv
+ strings
+ time
+
+FILENAMES
+ testdata/benchmark.go
+ testdata/example.go
+ testdata/testing.go
+
+FUNCTIONS
+ // An internal function but exported because it is cross-package; ...
+ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
+
+ // An internal function but exported because it is cross-package; ...
+ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
+
+ //
+ func RunExamples(examples []InternalExample) (ok bool)
+
+ //
+ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
+
+ // Short reports whether the -test.short flag is set.
+ func Short() bool
+
+
+TYPES
+ // B is a type passed to Benchmark functions to manage benchmark ...
+ type B struct {
+ N int
+ // contains filtered or unexported fields
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *B) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *B) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *B) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *B) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *B) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *B) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *B) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *B) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *B) Logf(format string, args ...interface{})
+
+ // ResetTimer sets the elapsed benchmark time to zero. It does not ...
+ func (b *B) ResetTimer()
+
+ // SetBytes records the number of bytes processed in a single ...
+ func (b *B) SetBytes(n int64)
+
+ // StartTimer starts timing a test. This function is called ...
+ func (b *B) StartTimer()
+
+ // StopTimer stops timing a test. This can be used to pause the ...
+ func (b *B) StopTimer()
+
+ // The results of a benchmark run.
+ type BenchmarkResult struct {
+ N int // The number of iterations.
+ T time.Duration // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
+ }
+
+ // Benchmark benchmarks a single function. Useful for creating ...
+ func Benchmark(f func(b *B)) BenchmarkResult
+
+ //
+ func (r BenchmarkResult) NsPerOp() int64
+
+ //
+ func (r BenchmarkResult) String() string
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+ }
+
+ //
+ type InternalExample struct {
+ Name string
+ F func()
+ Output string
+ }
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalTest struct {
+ Name string
+ F func(*T)
+ }
+
+ // T is a type passed to Test functions to manage test state and ...
+ type T struct {
+ // contains filtered or unexported fields
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *T) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *T) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *T) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *T) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *T) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *T) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *T) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *T) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *T) Logf(format string, args ...interface{})
+
+ // Parallel signals that this test is to be run in parallel with ...
+ func (t *T) Parallel()
+
diff --git a/src/pkg/go/doc/testdata/testing.1.golden b/src/pkg/go/doc/testdata/testing.1.golden
new file mode 100644
index 000000000..d26a4685c
--- /dev/null
+++ b/src/pkg/go/doc/testdata/testing.1.golden
@@ -0,0 +1,298 @@
+// Package testing provides support for automated testing of Go ...
+PACKAGE testing
+
+IMPORTPATH
+ testdata/testing
+
+IMPORTS
+ bytes
+ flag
+ fmt
+ io
+ os
+ runtime
+ runtime/pprof
+ strconv
+ strings
+ time
+
+FILENAMES
+ testdata/benchmark.go
+ testdata/example.go
+ testdata/testing.go
+
+VARIABLES
+ //
+ var (
+ // The short flag requests that tests run more quickly, but its functionality
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
+ // efficient, but by default the flag is off so a plain "go test" will do a
+ // full test of the package.
+ short = flag.Bool("test.short", false, "run smaller test suite to save time")
+
+ // Report as tests are run; default is silent for success.
+ chatty = flag.Bool("test.v", false, "verbose: print additional output")
+ match = flag.String("test.run", "", "regular expression to select tests to run")
+ memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
+ 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.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+ parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+
+ cpuList []int
+ )
+
+ //
+ var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds")
+
+ //
+ var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
+
+ //
+ var timer *time.Timer
+
+
+FUNCTIONS
+ // An internal function but exported because it is cross-package; ...
+ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
+
+ // An internal function but exported because it is cross-package; ...
+ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
+
+ //
+ func RunExamples(examples []InternalExample) (ok bool)
+
+ //
+ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
+
+ // Short reports whether the -test.short flag is set.
+ func Short() bool
+
+ // after runs after all testing.
+ func after()
+
+ // alarm is called if the timeout expires.
+ func alarm()
+
+ // before runs before all testing.
+ func before()
+
+ // decorate inserts the final newline if needed and indentation ...
+ func decorate(s string, addFileLine bool) string
+
+ //
+ func max(x, y int) int
+
+ //
+ func min(x, y int) int
+
+ //
+ func parseCpuList()
+
+ // roundDown10 rounds a number down to the nearest power of 10.
+ func roundDown10(n int) int
+
+ // roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
+ func roundUp(n int) int
+
+ // startAlarm starts an alarm if requested.
+ func startAlarm()
+
+ // stopAlarm turns off the alarm.
+ func stopAlarm()
+
+ //
+ func tRunner(t *T, test *InternalTest)
+
+
+TYPES
+ // B is a type passed to Benchmark functions to manage benchmark ...
+ type B struct {
+ common
+ N int
+ benchmark InternalBenchmark
+ bytes int64
+ timerOn bool
+ result BenchmarkResult
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *B) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *B) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *B) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *B) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *B) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *B) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *B) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *B) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *B) Logf(format string, args ...interface{})
+
+ // ResetTimer sets the elapsed benchmark time to zero. It does not ...
+ func (b *B) ResetTimer()
+
+ // SetBytes records the number of bytes processed in a single ...
+ func (b *B) SetBytes(n int64)
+
+ // StartTimer starts timing a test. This function is called ...
+ func (b *B) StartTimer()
+
+ // StopTimer stops timing a test. This can be used to pause the ...
+ func (b *B) StopTimer()
+
+ // launch launches the benchmark function. It gradually increases ...
+ func (b *B) launch()
+
+ // log generates the output. It's always at the same stack depth.
+ func (c *B) log(s string)
+
+ //
+ func (b *B) nsPerOp() int64
+
+ // run times the benchmark function in a separate goroutine.
+ func (b *B) run() BenchmarkResult
+
+ // runN runs a single benchmark for the specified number of ...
+ func (b *B) runN(n int)
+
+ // trimOutput shortens the output from a benchmark, which can be ...
+ func (b *B) trimOutput()
+
+ // The results of a benchmark run.
+ type BenchmarkResult struct {
+ N int // The number of iterations.
+ T time.Duration // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
+ }
+
+ // Benchmark benchmarks a single function. Useful for creating ...
+ func Benchmark(f func(b *B)) BenchmarkResult
+
+ //
+ func (r BenchmarkResult) NsPerOp() int64
+
+ //
+ func (r BenchmarkResult) String() string
+
+ //
+ func (r BenchmarkResult) mbPerSec() float64
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+ }
+
+ //
+ type InternalExample struct {
+ Name string
+ F func()
+ Output string
+ }
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalTest struct {
+ Name string
+ F func(*T)
+ }
+
+ // T is a type passed to Test functions to manage test state and ...
+ type T struct {
+ common
+ name string // Name of test.
+ startParallel chan bool // Parallel tests will wait on this.
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *T) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *T) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *T) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *T) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *T) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *T) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *T) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *T) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *T) Logf(format string, args ...interface{})
+
+ // Parallel signals that this test is to be run in parallel with ...
+ func (t *T) Parallel()
+
+ // log generates the output. It's always at the same stack depth.
+ func (c *T) log(s string)
+
+ //
+ func (t *T) report()
+
+ // common holds the elements common between T and B and captures ...
+ type common struct {
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ start time.Time // Time test or benchmark started
+ duration time.Duration
+ self interface{} // To be sent on signal channel when done.
+ signal chan interface{} // Output for serial tests.
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *common) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *common) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *common) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *common) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *common) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *common) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *common) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *common) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *common) Logf(format string, args ...interface{})
+
+ // log generates the output. It's always at the same stack depth.
+ func (c *common) log(s string)
+
diff --git a/src/pkg/go/doc/testdata/testing.2.golden b/src/pkg/go/doc/testdata/testing.2.golden
new file mode 100644
index 000000000..15a903986
--- /dev/null
+++ b/src/pkg/go/doc/testdata/testing.2.golden
@@ -0,0 +1,156 @@
+// Package testing provides support for automated testing of Go ...
+PACKAGE testing
+
+IMPORTPATH
+ testdata/testing
+
+IMPORTS
+ bytes
+ flag
+ fmt
+ io
+ os
+ runtime
+ runtime/pprof
+ strconv
+ strings
+ time
+
+FILENAMES
+ testdata/benchmark.go
+ testdata/example.go
+ testdata/testing.go
+
+FUNCTIONS
+ // An internal function but exported because it is cross-package; ...
+ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
+
+ // An internal function but exported because it is cross-package; ...
+ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
+
+ //
+ func RunExamples(examples []InternalExample) (ok bool)
+
+ //
+ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
+
+ // Short reports whether the -test.short flag is set.
+ func Short() bool
+
+
+TYPES
+ // B is a type passed to Benchmark functions to manage benchmark ...
+ type B struct {
+ N int
+ // contains filtered or unexported fields
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *B) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *B) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *B) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *B) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *B) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *B) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *B) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *B) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *B) Logf(format string, args ...interface{})
+
+ // ResetTimer sets the elapsed benchmark time to zero. It does not ...
+ func (b *B) ResetTimer()
+
+ // SetBytes records the number of bytes processed in a single ...
+ func (b *B) SetBytes(n int64)
+
+ // StartTimer starts timing a test. This function is called ...
+ func (b *B) StartTimer()
+
+ // StopTimer stops timing a test. This can be used to pause the ...
+ func (b *B) StopTimer()
+
+ // The results of a benchmark run.
+ type BenchmarkResult struct {
+ N int // The number of iterations.
+ T time.Duration // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
+ }
+
+ // Benchmark benchmarks a single function. Useful for creating ...
+ func Benchmark(f func(b *B)) BenchmarkResult
+
+ //
+ func (r BenchmarkResult) NsPerOp() int64
+
+ //
+ func (r BenchmarkResult) String() string
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalBenchmark struct {
+ Name string
+ F func(b *B)
+ }
+
+ //
+ type InternalExample struct {
+ Name string
+ F func()
+ Output string
+ }
+
+ // An internal type but exported because it is cross-package; part ...
+ type InternalTest struct {
+ Name string
+ F func(*T)
+ }
+
+ // T is a type passed to Test functions to manage test state and ...
+ type T struct {
+ // contains filtered or unexported fields
+ }
+
+ // Error is equivalent to Log() followed by Fail().
+ func (c *T) Error(args ...interface{})
+
+ // Errorf is equivalent to Logf() followed by Fail().
+ func (c *T) Errorf(format string, args ...interface{})
+
+ // Fail marks the function as having failed but continues ...
+ func (c *T) Fail()
+
+ // FailNow marks the function as having failed and stops its ...
+ func (c *T) FailNow()
+
+ // Failed returns whether the function has failed.
+ func (c *T) Failed() bool
+
+ // Fatal is equivalent to Log() followed by FailNow().
+ func (c *T) Fatal(args ...interface{})
+
+ // Fatalf is equivalent to Logf() followed by FailNow().
+ func (c *T) Fatalf(format string, args ...interface{})
+
+ // Log formats its arguments using default formatting, analogous ...
+ func (c *T) Log(args ...interface{})
+
+ // Logf formats its arguments according to the format, analogous ...
+ func (c *T) Logf(format string, args ...interface{})
+
+ // Parallel signals that this test is to be run in parallel with ...
+ func (t *T) Parallel()
+
diff --git a/src/pkg/go/doc/testdata/testing.go b/src/pkg/go/doc/testdata/testing.go
new file mode 100644
index 000000000..71c1d1eaf
--- /dev/null
+++ b/src/pkg/go/doc/testdata/testing.go
@@ -0,0 +1,404 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package testing provides support for automated testing of Go packages.
+// It is intended to be used in concert with the ``go test'' utility, which automates
+// execution of any function of the form
+// func TestXxx(*testing.T)
+// where Xxx can be any alphanumeric string (but the first letter must not be in
+// [a-z]) and serves to identify the test routine.
+// These TestXxx routines should be declared within the package they are testing.
+//
+// Functions of the form
+// func BenchmarkXxx(*testing.B)
+// are considered benchmarks, and are executed by go test when the -test.bench
+// flag is provided.
+//
+// A sample benchmark function looks like this:
+// func BenchmarkHello(b *testing.B) {
+// for i := 0; i < b.N; i++ {
+// fmt.Sprintf("hello")
+// }
+// }
+// The benchmark package will vary b.N until the benchmark function lasts
+// long enough to be timed reliably. The output
+// testing.BenchmarkHello 10000000 282 ns/op
+// means that the loop ran 10000000 times at a speed of 282 ns per loop.
+//
+// If a benchmark needs some expensive setup before running, the timer
+// may be stopped:
+// func BenchmarkBigLen(b *testing.B) {
+// b.StopTimer()
+// big := NewBig()
+// b.StartTimer()
+// for i := 0; i < b.N; i++ {
+// big.Len()
+// }
+// }
+package testing
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var (
+ // The short flag requests that tests run more quickly, but its functionality
+ // is provided by test writers themselves. The testing package is just its
+ // home. The all.bash installation script sets it to make installation more
+ // efficient, but by default the flag is off so a plain "go test" will do a
+ // full test of the package.
+ short = flag.Bool("test.short", false, "run smaller test suite to save time")
+
+ // Report as tests are run; default is silent for success.
+ chatty = flag.Bool("test.v", false, "verbose: print additional output")
+ match = flag.String("test.run", "", "regular expression to select tests to run")
+ memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
+ 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.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+ parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+
+ cpuList []int
+)
+
+// common holds the elements common between T and B and
+// captures common methods such as Errorf.
+type common struct {
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ start time.Time // Time test or benchmark started
+ duration time.Duration
+ self interface{} // To be sent on signal channel when done.
+ signal chan interface{} // Output for serial tests.
+}
+
+// Short reports whether the -test.short flag is set.
+func Short() bool {
+ return *short
+}
+
+// decorate inserts the final newline if needed and indentation tabs for formatting.
+// If addFileLine is true, it also prefixes the string with the file and line of the call site.
+func decorate(s string, addFileLine bool) string {
+ if addFileLine {
+ _, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+ if ok {
+ // Truncate file name at last file name separator.
+ if index := strings.LastIndex(file, "/"); index >= 0 {
+ file = file[index+1:]
+ } else if index = strings.LastIndex(file, "\\"); index >= 0 {
+ file = file[index+1:]
+ }
+ } else {
+ file = "???"
+ line = 1
+ }
+ s = fmt.Sprintf("%s:%d: %s", file, line, s)
+ }
+ s = "\t" + s // Every line is indented at least one tab.
+ n := len(s)
+ if n > 0 && s[n-1] != '\n' {
+ s += "\n"
+ n++
+ }
+ for i := 0; i < n-1; i++ { // -1 to avoid final newline
+ if s[i] == '\n' {
+ // Second and subsequent lines are indented an extra tab.
+ return s[0:i+1] + "\t" + decorate(s[i+1:n], false)
+ }
+ }
+ return s
+}
+
+// T is a type passed to Test functions to manage test state and support formatted test logs.
+// Logs are accumulated during execution and dumped to standard error when done.
+type T struct {
+ common
+ name string // Name of test.
+ startParallel chan bool // Parallel tests will wait on this.
+}
+
+// Fail marks the function as having failed but continues execution.
+func (c *common) Fail() { c.failed = true }
+
+// Failed returns whether the function has failed.
+func (c *common) Failed() bool { return c.failed }
+
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (c *common) FailNow() {
+ c.Fail()
+
+ // Calling runtime.Goexit will exit the goroutine, which
+ // will run the deferred functions in this goroutine,
+ // which will eventually run the deferred lines in tRunner,
+ // which will signal to the test loop that this test is done.
+ //
+ // A previous version of this code said:
+ //
+ // c.duration = ...
+ // c.signal <- c.self
+ // runtime.Goexit()
+ //
+ // This previous version duplicated code (those lines are in
+ // tRunner no matter what), but worse the goroutine teardown
+ // implicit in runtime.Goexit was not guaranteed to complete
+ // before the test exited. If a test deferred an important cleanup
+ // function (like removing temporary files), there was no guarantee
+ // it would run on a test failure. Because we send on c.signal during
+ // a top-of-stack deferred function now, we know that the send
+ // only happens after any other stacked defers have completed.
+ runtime.Goexit()
+}
+
+// log generates the output. It's always at the same stack depth.
+func (c *common) log(s string) {
+ c.output = append(c.output, decorate(s, true)...)
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
+// and records the text in the error log.
+func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
+
+// Error is equivalent to Log() followed by Fail().
+func (c *common) Error(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.Fail()
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (c *common) Errorf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.Fail()
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (c *common) Fatal(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.FailNow()
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (c *common) Fatalf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.FailNow()
+}
+
+// Parallel signals that this test is to be run in parallel with (and only with)
+// other parallel tests in this CPU group.
+func (t *T) Parallel() {
+ t.signal <- (*T)(nil) // Release main testing loop
+ <-t.startParallel // Wait for serial tests to finish
+}
+
+// An internal type but exported because it is cross-package; part of the implementation
+// of go test.
+type InternalTest struct {
+ Name string
+ F func(*T)
+}
+
+func tRunner(t *T, test *InternalTest) {
+ t.start = time.Now()
+
+ // When this goroutine is done, either because test.F(t)
+ // returned normally or because a test failure triggered
+ // a call to runtime.Goexit, record the duration and send
+ // a signal saying that the test is done.
+ defer func() {
+ t.duration = time.Now().Sub(t.start)
+ t.signal <- t
+ }()
+
+ test.F(t)
+}
+
+// An internal function but exported because it is cross-package; part of the implementation
+// of go test.
+func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
+ flag.Parse()
+ parseCpuList()
+
+ before()
+ startAlarm()
+ testOk := RunTests(matchString, tests)
+ exampleOk := RunExamples(examples)
+ if !testOk || !exampleOk {
+ fmt.Println("FAIL")
+ os.Exit(1)
+ }
+ fmt.Println("PASS")
+ stopAlarm()
+ RunBenchmarks(matchString, benchmarks)
+ after()
+}
+
+func (t *T) report() {
+ tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
+ format := "--- %s: %s %s\n%s"
+ if t.failed {
+ fmt.Printf(format, "FAIL", t.name, tstr, t.output)
+ } else if *chatty {
+ fmt.Printf(format, "PASS", t.name, tstr, t.output)
+ }
+}
+
+func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
+ ok = true
+ if len(tests) == 0 {
+ fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
+ return
+ }
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ // We build a new channel tree for each run of the loop.
+ // collector merges in one channel all the upstream signals from parallel tests.
+ // If all tests pump to the same channel, a bug can occur where a test
+ // kicks off a goroutine that Fails, yet the test still delivers a completion signal,
+ // which skews the counting.
+ var collector = make(chan interface{})
+
+ numParallel := 0
+ startParallel := make(chan bool)
+
+ for i := 0; i < len(tests); i++ {
+ matched, err := matchString(*match, tests[i].Name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ testName := tests[i].Name
+ if procs != 1 {
+ testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
+ }
+ t := &T{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ name: testName,
+ startParallel: startParallel,
+ }
+ t.self = t
+ if *chatty {
+ fmt.Printf("=== RUN %s\n", t.name)
+ }
+ go tRunner(t, &tests[i])
+ out := (<-t.signal).(*T)
+ if out == nil { // Parallel run.
+ go func() {
+ collector <- <-t.signal
+ }()
+ numParallel++
+ continue
+ }
+ t.report()
+ ok = ok && !out.failed
+ }
+
+ running := 0
+ for numParallel+running > 0 {
+ if running < *parallel && numParallel > 0 {
+ startParallel <- true
+ running++
+ numParallel--
+ continue
+ }
+ t := (<-collector).(*T)
+ t.report()
+ ok = ok && !t.failed
+ running--
+ }
+ }
+ return
+}
+
+// before runs before all testing.
+func before() {
+ if *memProfileRate > 0 {
+ runtime.MemProfileRate = *memProfileRate
+ }
+ if *cpuProfile != "" {
+ f, err := os.Create(*cpuProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s", err)
+ return
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
+ f.Close()
+ return
+ }
+ // Could save f so after can call f.Close; not worth the effort.
+ }
+
+}
+
+// after runs after all testing.
+func after() {
+ if *cpuProfile != "" {
+ pprof.StopCPUProfile() // flushes profile to disk
+ }
+ if *memProfile != "" {
+ f, err := os.Create(*memProfile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s", err)
+ return
+ }
+ if err = pprof.WriteHeapProfile(f); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err)
+ }
+ f.Close()
+ }
+}
+
+var timer *time.Timer
+
+// startAlarm starts an alarm if requested.
+func startAlarm() {
+ if *timeout > 0 {
+ timer = time.AfterFunc(*timeout, alarm)
+ }
+}
+
+// stopAlarm turns off the alarm.
+func stopAlarm() {
+ if *timeout > 0 {
+ timer.Stop()
+ }
+}
+
+// alarm is called if the timeout expires.
+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 {
+ fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val)
+ os.Exit(1)
+ }
+ cpuList = append(cpuList, cpu)
+ }
+ }
+}
diff --git a/src/pkg/go/parser/Makefile b/src/pkg/go/parser/Makefile
deleted file mode 100644
index d301f41eb..000000000
--- a/src/pkg/go/parser/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=go/parser
-GOFILES=\
- interface.go\
- parser.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
new file mode 100644
index 000000000..377c8b80c
--- /dev/null
+++ b/src/pkg/go/parser/error_test.go
@@ -0,0 +1,166 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a parser test harness. The files in the testdata
+// directory are parsed and the errors reported are compared against the
+// error messages expected in the test files. The test files must end in
+// .src rather than .go so that they are not disturbed by gofmt runs.
+//
+// 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.
+//
+// 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 parser
+
+import (
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+const testdata = "testdata"
+
+// getFile assumes that each filename occurs at most once
+func getFile(filename string) (file *token.File) {
+ fset.Iterate(func(f *token.File) bool {
+ if f.Name() == filename {
+ if file != nil {
+ panic(filename + " used multiple times")
+ }
+ file = f
+ }
+ return true
+ })
+ return file
+}
+
+func getPos(filename string, offset int) token.Pos {
+ if f := getFile(filename); f != nil {
+ return f.Pos(offset)
+ }
+ return token.NoPos
+}
+
+// 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, filename string, src []byte) map[token.Pos]string {
+ errors := make(map[token.Pos]string)
+
+ 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, non-semicolon token
+
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ return errors
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ errors[prev] = string(s[1])
+ }
+ default:
+ prev = pos
+ }
+ }
+
+ panic("unreachable")
+}
+
+// compareErrors compares the map of expected error messages with the list
+// of found errors and reports discrepancies.
+//
+func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) {
+ for _, error := range found {
+ // error.Pos is a token.Position, but we want
+ // a token.Pos so we can do a map lookup
+ 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
+ delete(expected, pos)
+ } 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: unexpected error: %s", error.Pos, error.Msg)
+ }
+ }
+
+ // there should be no expected errors left
+ if len(expected) > 0 {
+ t.Errorf("%d errors not reported:", len(expected))
+ for pos, msg := range expected {
+ t.Errorf("%s: %s\n", fset.Position(pos), msg)
+ }
+ }
+}
+
+func checkErrors(t *testing.T, filename string, input interface{}) {
+ src, err := readSource(filename, input)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ _, err = ParseFile(fset, filename, src, DeclarationErrors)
+ found, ok := err.(scanner.ErrorList)
+ if err != nil && !ok {
+ t.Error(err)
+ return
+ }
+
+ // we are expecting the following errors
+ // (collect these after parsing a file so that it is found in the file set)
+ expected := expectedErrors(t, filename, src)
+
+ // verify errors returned by the parser
+ compareErrors(t, expected, found)
+}
+
+func TestErrors(t *testing.T) {
+ list, err := ioutil.ReadDir(testdata)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, fi := range list {
+ name := fi.Name()
+ if !fi.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".src") {
+ checkErrors(t, filepath.Join(testdata, name), nil)
+ }
+ }
+}
diff --git a/src/pkg/go/parser/example_test.go b/src/pkg/go/parser/example_test.go
new file mode 100644
index 000000000..3c58e63a9
--- /dev/null
+++ b/src/pkg/go/parser/example_test.go
@@ -0,0 +1,34 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parser_test
+
+import (
+ "fmt"
+ "go/parser"
+ "go/token"
+)
+
+func ExampleParseFile() {
+ fset := token.NewFileSet() // positions are relative to fset
+
+ // Parse the file containing this very example
+ // but stop after processing the imports.
+ f, err := parser.ParseFile(fset, "example_test.go", nil, parser.ImportsOnly)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ // Print the imports from the file's AST.
+ for _, s := range f.Imports {
+ fmt.Println(s.Path.Value)
+ }
+
+ // output:
+ //
+ // "fmt"
+ // "go/parser"
+ // "go/token"
+}
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 4f980fc65..5c203a784 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -8,8 +8,8 @@ package parser
import (
"bytes"
+ "errors"
"go/ast"
- "go/scanner"
"go/token"
"io"
"io/ioutil"
@@ -21,7 +21,7 @@ import (
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
-func readSource(filename string, src interface{}) ([]byte, os.Error) {
+func readSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch s := src.(type) {
case string:
@@ -35,86 +35,30 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
}
case io.Reader:
var buf bytes.Buffer
- _, err := io.Copy(&buf, s)
- if err != nil {
+ if _, err := io.Copy(&buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
- default:
- return nil, os.NewError("invalid source")
}
+ return nil, errors.New("invalid source")
}
-
return ioutil.ReadFile(filename)
}
-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
-// may be nil or contain a partial AST.
-//
-func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, os.Error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- x := p.parseRhs()
- if p.tok == token.SEMICOLON {
- p.next() // consume automatically inserted semicolon, if any
- }
- 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
-// interpretation as for ParseFile. If there is an error, the node
-// list may be nil or contain partial ASTs.
+// A Mode value is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
//
-func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, os.Error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- 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
-// interpretation as for ParseFile. If there is an error, the node
-// list may be nil or contain partial ASTs.
-//
-func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, os.Error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- list := p.parseDeclList()
- p.expect(token.EOF)
-
- return list, p.errors()
-}
+type Mode uint
+
+const (
+ PackageClauseOnly Mode = 1 << iota // parsing stops after package clause
+ ImportsOnly // parsing stops after import declarations
+ ParseComments // parse comments and add them to AST
+ Trace // print a trace of parsed productions
+ DeclarationErrors // report declaration errors
+ SpuriousErrors // report all (not just the first) errors per line
+)
// 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
@@ -123,7 +67,6 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
// If src != nil, ParseFile parses the source from src and the filename is
// only used when recording position information. The type of the argument
// for the src parameter must be string, []byte, or io.Reader.
-//
// If src == nil, ParseFile parses the file specified by filename.
//
// The mode parameter controls the amount of source text parsed and other
@@ -132,49 +75,30 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
-// errors were found, the result is a partial AST (with ast.BadX nodes
+// errors were found, the result is a partial AST (with ast.Bad* nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
-func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
- data, err := readSource(filename, src)
+func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (*ast.File, error) {
+ // get source
+ text, err := readSource(filename, src)
if err != nil {
return nil, err
}
+ // parse source
var p parser
- p.init(fset, filename, data, mode)
- file := p.parseFile() // parseFile reads to EOF
+ p.init(fset, filename, text, mode)
+ f := p.parseFile()
- 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
-// bits are passed to ParseFile unchanged. Position information is recorded
-// in the file set fset.
-//
-// Files with parse errors are ignored. In this case the map of packages may
-// be incomplete (missing packages and/or incomplete packages) and the first
-// error encountered is returned.
-//
-func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
- pkgs = make(map[string]*ast.Package)
- for _, filename := range filenames {
- if src, err := ParseFile(fset, filename, nil, mode); err == nil {
- name := src.Name.Name
- pkg, found := pkgs[name]
- if !found {
- // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
- pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
- pkgs[name] = pkg
- }
- pkg.Files[filename] = src
- } else if first == nil {
- first = err
- }
+ // sort errors
+ if p.mode&SpuriousErrors == 0 {
+ p.errors.RemoveMultiples()
+ } else {
+ p.errors.Sort()
}
- return
+
+ return f, p.errors.Err()
}
// ParseDir calls ParseFile for the files in the directory specified by path and
@@ -185,9 +109,9 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occurred, a non-nil but incomplete map and the
-// error are returned.
+// first error encountered are returned.
//
-func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
+func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) {
fd, err := os.Open(path)
if err != nil {
return nil, err
@@ -199,16 +123,41 @@ func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool,
return nil, err
}
- filenames := make([]string, len(list))
- n := 0
- for i := 0; i < len(list); i++ {
- d := &list[i]
+ pkgs = make(map[string]*ast.Package)
+ for _, d := range list {
if filter == nil || filter(d) {
- filenames[n] = filepath.Join(path, d.Name)
- n++
+ filename := filepath.Join(path, d.Name())
+ if src, err := ParseFile(fset, filename, nil, mode); err == nil {
+ name := src.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ pkg = &ast.Package{
+ Name: name,
+ Files: make(map[string]*ast.File),
+ }
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = src
+ } else if first == nil {
+ first = err
+ }
}
}
- filenames = filenames[0:n]
- return ParseFiles(fset, filenames, mode)
+ return
+}
+
+// ParseExpr is a convenience function for obtaining the AST of an expression x.
+// The position information recorded in the AST is undefined.
+//
+func ParseExpr(x string) (ast.Expr, error) {
+ // parse x within the context of a complete package for correct scopes;
+ // use //line directive for correct positions in error messages and put
+ // x alone on a separate line (handles line comments), followed by a ';'
+ // to force an error if the expression is incomplete
+ file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+"\n;}", 0)
+ if err != nil {
+ return nil, err
+ }
+ return file.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt).Rhs[0], nil
}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index 9c14d1667..e362e13a7 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -14,29 +14,19 @@ import (
"go/ast"
"go/scanner"
"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.
-//
-const (
- PackageClauseOnly uint = 1 << iota // parsing stops after package clause
- ImportsOnly // parsing stops after import declarations
- ParseComments // parse comments and add them to AST
- Trace // print a trace of parsed productions
- DeclarationErrors // report declaration errors
- SpuriousErrors // report all (not just the first) errors per line
+ "strconv"
+ "strings"
+ "unicode"
)
// The parser structure holds the parser's internal state.
type parser struct {
- file *token.File
- scanner.ErrorVector
+ file *token.File
+ errors scanner.ErrorList
scanner scanner.Scanner
// Tracing/debugging
- mode uint // parsing mode
+ mode Mode // parsing mode
trace bool // == (mode & Trace != 0)
indent uint // indentation used for tracing output
@@ -50,6 +40,13 @@ type parser struct {
tok token.Token // one token look-ahead
lit string // token literal
+ // Error recovery
+ // (used to limit the number of calls to syncXXX functions
+ // w/o making scanning progress - avoids potential endless
+ // loops across multiple parser functions during error recovery)
+ syncPos token.Pos // last synchronization position
+ syncCnt int // number of calls to syncXXX without progress
+
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
@@ -65,18 +62,14 @@ 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
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mode) {
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
+ var m scanner.Mode
if mode&ParseComments != 0 {
- m |= scanner.ScanComments
+ m = scanner.ScanComments
}
- return m
-}
-
-func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
- p.file = fset.AddFile(filename, fset.Base(), len(src))
- p.scanner.Init(p.file, src, p, scannerMode(mode))
+ eh := func(pos token.Position, msg string) { p.errors.Add(pos, msg) }
+ p.scanner.Init(p.file, src, eh, m)
p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
@@ -144,28 +137,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
}
}
-func (p *parser) shortVarDecl(idents []*ast.Ident) {
+func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
// Go spec: 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 non-blank variables is new.
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 != "_" {
- if alt := p.topScope.Insert(obj); alt != nil {
- ident.Obj = alt // redeclaration
- } else {
- n++ // new declaration
+ for _, x := range list {
+ if ident, isIdent := x.(*ast.Ident); isIdent {
+ assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // remember corresponding assignment for other tools
+ obj.Decl = decl
+ ident.Obj = obj
+ if ident.Name != "_" {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
+ n++ // new declaration
+ }
}
+ } else {
+ p.errorExpected(x.Pos(), "identifier")
}
}
if n == 0 && p.mode&DeclarationErrors != 0 {
- p.error(idents[0].Pos(), "no new variables on left side of :=")
+ p.error(list[0].Pos(), "no new variables on left side of :=")
}
}
@@ -263,7 +259,7 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
}
}
- comment = &ast.Comment{p.pos, p.lit}
+ comment = &ast.Comment{Slash: p.pos, Text: p.lit}
p.next0()
return
@@ -284,7 +280,7 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
}
// add comment group to the comments list
- comments = &ast.CommentGroup{list}
+ comments = &ast.CommentGroup{List: list}
p.comments = append(p.comments, comments)
return
@@ -341,7 +337,7 @@ func (p *parser) next() {
}
func (p *parser) error(pos token.Pos, msg string) {
- p.Error(p.file.Position(pos), msg)
+ p.errors.Add(p.file.Position(pos), msg)
}
func (p *parser) errorExpected(pos token.Pos, msg string) {
@@ -349,7 +345,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
- if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+ if p.tok == token.SEMICOLON && p.lit == "\n" {
msg += ", found newline"
} else {
msg += ", found '" + p.tok.String() + "'"
@@ -370,10 +366,39 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
+// expectClosing is like expect but provides a better error message
+// for the common case of a missing comma before a newline.
+//
+func (p *parser) expectClosing(tok token.Token, context string) token.Pos {
+ if p.tok != tok && p.tok == token.SEMICOLON && p.lit == "\n" {
+ p.error(p.pos, "missing ',' before newline in "+context)
+ p.next()
+ }
+ return p.expect(tok)
+}
+
func (p *parser) expectSemi() {
+ // semicolon is optional before a closing ')' or '}'
if p.tok != token.RPAREN && p.tok != token.RBRACE {
- p.expect(token.SEMICOLON)
+ if p.tok == token.SEMICOLON {
+ p.next()
+ } else {
+ p.errorExpected(p.pos, "';'")
+ syncStmt(p)
+ }
+ }
+}
+
+func (p *parser) atComma(context string) bool {
+ if p.tok == token.COMMA {
+ return true
}
+ if p.tok == token.SEMICOLON && p.lit == "\n" {
+ p.error(p.pos, "missing ',' before newline in "+context)
+ return true // "insert" the comma and continue
+
+ }
+ return false
}
func assert(cond bool, msg string) {
@@ -382,6 +407,68 @@ func assert(cond bool, msg string) {
}
}
+// syncStmt advances to the next statement.
+// Used for synchronization after an error.
+//
+func syncStmt(p *parser) {
+ for {
+ switch p.tok {
+ case token.BREAK, token.CONST, token.CONTINUE, token.DEFER,
+ token.FALLTHROUGH, token.FOR, token.GO, token.GOTO,
+ token.IF, token.RETURN, token.SELECT, token.SWITCH,
+ token.TYPE, token.VAR:
+ // Return only if parser made some progress since last
+ // sync or if it has not reached 10 sync calls without
+ // progress. Otherwise consume at least one token to
+ // avoid an endless parser loop (it is possible that
+ // both parseOperand and parseStmt call syncStmt and
+ // correctly do not advance, thus the need for the
+ // invocation limit p.syncCnt).
+ if p.pos == p.syncPos && p.syncCnt < 10 {
+ p.syncCnt++
+ return
+ }
+ if p.pos > p.syncPos {
+ p.syncPos = p.pos
+ p.syncCnt = 0
+ return
+ }
+ // Reaching here indicates a parser bug, likely an
+ // incorrect token list in this function, but it only
+ // leads to skipping of possibly correct code if a
+ // previous error is present, and thus is preferred
+ // over a non-terminating parse.
+ case token.EOF:
+ return
+ }
+ p.next()
+ }
+}
+
+// syncDecl advances to the next declaration.
+// Used for synchronization after an error.
+//
+func syncDecl(p *parser) {
+ for {
+ switch p.tok {
+ case token.CONST, token.TYPE, token.VAR:
+ // see comments in syncStmt
+ if p.pos == p.syncPos && p.syncCnt < 10 {
+ p.syncCnt++
+ return
+ }
+ if p.pos > p.syncPos {
+ p.syncPos = p.pos
+ p.syncCnt = 0
+ return
+ }
+ case token.EOF:
+ return
+ }
+ p.next()
+ }
+}
+
// ----------------------------------------------------------------------------
// Identifiers
@@ -394,7 +481,7 @@ func (p *parser) parseIdent() *ast.Ident {
} else {
p.expect(token.IDENT) // use expect() error handling
}
- return &ast.Ident{pos, name, nil}
+ return &ast.Ident{NamePos: pos, Name: name}
}
func (p *parser) parseIdentList() (list []*ast.Ident) {
@@ -434,7 +521,9 @@ func (p *parser) parseLhsList() []ast.Expr {
switch p.tok {
case token.DEFINE:
// lhs of a short variable declaration
- p.shortVarDecl(p.makeIdentList(list))
+ // but doesn't enter scope until later:
+ // caller must call p.shortVarDecl(p.makeIdentList(list))
+ // at appropriate time.
case token.COLON:
// lhs of a label declaration or a communication clause of a select
// statement (parseLhsList is not called when parsing the case clause
@@ -470,7 +559,7 @@ func (p *parser) parseType() ast.Expr {
pos := p.pos
p.errorExpected(pos, "type")
p.next() // make progress
- return &ast.BadExpr{pos, p.pos}
+ return &ast.BadExpr{From: pos, To: p.pos}
}
return typ
@@ -490,7 +579,7 @@ func (p *parser) parseTypeName() ast.Expr {
p.next()
p.resolve(ident)
sel := p.parseIdent()
- return &ast.SelectorExpr{ident, sel}
+ return &ast.SelectorExpr{X: ident, Sel: sel}
}
return ident
@@ -504,7 +593,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
lbrack := p.expect(token.LBRACK)
var len ast.Expr
if ellipsisOk && p.tok == token.ELLIPSIS {
- len = &ast.Ellipsis{p.pos, nil}
+ len = &ast.Ellipsis{Ellipsis: p.pos}
p.next()
} else if p.tok != token.RBRACK {
len = p.parseRhs()
@@ -512,7 +601,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
p.expect(token.RBRACK)
elt := p.parseType()
- return &ast.ArrayType{lbrack, len, elt}
+ return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}
}
func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
@@ -520,9 +609,11 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
for i, x := range list {
ident, isIdent := x.(*ast.Ident)
if !isIdent {
- pos := x.(ast.Expr).Pos()
- p.errorExpected(pos, "identifier")
- ident = &ast.Ident{pos, "_", nil}
+ if _, isBad := x.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(x.Pos(), "identifier")
+ }
+ ident = &ast.Ident{NamePos: x.Pos(), Name: "_"}
}
idents[i] = ident
}
@@ -542,7 +633,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
// optional tag
var tag *ast.BasicLit
if p.tok == token.STRING {
- tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+ tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
}
@@ -558,13 +649,13 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if n := len(list); n > 1 || !isTypeName(deref(typ)) {
pos := typ.Pos()
p.errorExpected(pos, "anonymous field")
- typ = &ast.BadExpr{pos, list[n-1].End()}
+ typ = &ast.BadExpr{From: pos, To: list[n-1].End()}
}
}
p.expectSemi() // call before accessing p.linecomment
- field := &ast.Field{doc, idents, typ, tag, p.lineComment}
+ field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
p.declare(field, nil, scope, ast.Var, idents...)
return field
@@ -587,8 +678,14 @@ func (p *parser) parseStructType() *ast.StructType {
}
rbrace := p.expect(token.RBRACE)
- // TODO(gri): store struct scope in AST
- return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+ return &ast.StructType{
+ Struct: pos,
+ Fields: &ast.FieldList{
+ Opening: lbrace,
+ List: list,
+ Closing: rbrace,
+ },
+ }
}
func (p *parser) parsePointerType() *ast.StarExpr {
@@ -599,7 +696,7 @@ func (p *parser) parsePointerType() *ast.StarExpr {
star := p.expect(token.MUL)
base := p.parseType()
- return &ast.StarExpr{star, base}
+ return &ast.StarExpr{Star: star, X: base}
}
func (p *parser) tryVarType(isParam bool) ast.Expr {
@@ -609,12 +706,9 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
if typ == nil {
p.error(pos, "'...' parameter is missing type")
- typ = &ast.BadExpr{pos, p.pos}
+ typ = &ast.BadExpr{From: pos, To: p.pos}
}
- if p.tok != token.RPAREN {
- p.error(pos, "can use '...' with last parameter type only")
- }
- return &ast.Ellipsis{pos, typ}
+ return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
}
return p.tryIdentOrType(false)
}
@@ -625,7 +719,7 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
pos := p.pos
p.errorExpected(pos, "type")
p.next() // make progress
- typ = &ast.BadExpr{pos, p.pos}
+ typ = &ast.BadExpr{From: pos, To: p.pos}
}
return typ
}
@@ -636,21 +730,21 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
}
// a list of identifiers looks like a list of type names
- for {
- // parseVarType accepts any type (including parenthesized ones)
- // even though the syntax does not permit them here: we
- // accept them all for more robust parsing and complain
- // afterwards
- list = append(list, p.parseVarType(isParam))
+ //
+ // parse/tryVarType accepts any type (including parenthesized
+ // ones) even though the syntax does not permit them here: we
+ // accept them all for more robust parsing and complain later
+ for typ := p.parseVarType(isParam); typ != nil; {
+ list = append(list, typ)
if p.tok != token.COMMA {
break
}
p.next()
+ typ = p.tryVarType(isParam) // maybe nil as in: func f(int,) {}
}
// if we had a list of identifiers, it must be followed by a type
- typ = p.tryVarType(isParam)
- if typ != nil {
+ if typ = p.tryVarType(isParam); typ != nil {
p.resolve(typ)
}
@@ -666,7 +760,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
if typ != nil {
// IdentifierList Type
idents := p.makeIdentList(list)
- field := &ast.Field{nil, idents, typ, nil, nil}
+ field := &ast.Field{Names: idents, Type: typ}
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
@@ -678,12 +772,12 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
for p.tok != token.RPAREN && p.tok != token.EOF {
idents := p.parseIdentList()
typ := p.parseVarType(ellipsisOk)
- field := &ast.Field{nil, idents, typ, nil, nil}
+ field := &ast.Field{Names: idents, Type: typ}
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, nil, scope, ast.Var, idents...)
- if p.tok != token.COMMA {
+ if !p.atComma("parameter list") {
break
}
p.next()
@@ -713,7 +807,7 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
}
rparen := p.expect(token.RPAREN)
- return &ast.FieldList{lparen, params, rparen}
+ return &ast.FieldList{Opening: lparen, List: params, Closing: rparen}
}
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
@@ -755,7 +849,7 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
scope := ast.NewScope(p.topScope) // function scope
params, results := p.parseSignature(scope)
- return &ast.FuncType{pos, params, results}, scope
+ return &ast.FuncType{Func: pos, Params: params, Results: results}, scope
}
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
@@ -772,7 +866,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
idents = []*ast.Ident{ident}
scope := ast.NewScope(nil) // method scope
params, results := p.parseSignature(scope)
- typ = &ast.FuncType{token.NoPos, params, results}
+ typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
} else {
// embedded interface
typ = x
@@ -780,7 +874,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
}
p.expectSemi() // call before accessing p.linecomment
- spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
+ spec := &ast.Field{Doc: doc, Names: idents, Type: typ, Comment: p.lineComment}
p.declare(spec, nil, scope, ast.Fun, idents...)
return spec
@@ -800,8 +894,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
}
rbrace := p.expect(token.RBRACE)
- // TODO(gri): store interface scope in AST
- return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
+ return &ast.InterfaceType{
+ Interface: pos,
+ Methods: &ast.FieldList{
+ Opening: lbrace,
+ List: list,
+ Closing: rbrace,
+ },
+ }
}
func (p *parser) parseMapType() *ast.MapType {
@@ -815,7 +915,7 @@ func (p *parser) parseMapType() *ast.MapType {
p.expect(token.RBRACK)
value := p.parseType()
- return &ast.MapType{pos, key, value}
+ return &ast.MapType{Map: pos, Key: key, Value: value}
}
func (p *parser) parseChanType() *ast.ChanType {
@@ -838,7 +938,7 @@ func (p *parser) parseChanType() *ast.ChanType {
}
value := p.parseType()
- return &ast.ChanType{pos, dir, value}
+ return &ast.ChanType{Begin: pos, Dir: dir, Value: value}
}
// If the result is an identifier, it is not resolved.
@@ -866,7 +966,7 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
p.next()
typ := p.parseType()
rparen := p.expect(token.RPAREN)
- return &ast.ParenExpr{lparen, typ, rparen}
+ return &ast.ParenExpr{Lparen: lparen, X: typ, Rparen: rparen}
}
// no type found
@@ -909,7 +1009,7 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
p.closeScope()
rbrace := p.expect(token.RBRACE)
- return &ast.BlockStmt{lbrace, list, rbrace}
+ return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
func (p *parser) parseBlockStmt() *ast.BlockStmt {
@@ -923,7 +1023,7 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
p.closeScope()
rbrace := p.expect(token.RBRACE)
- return &ast.BlockStmt{lbrace, list, rbrace}
+ return &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
}
// ----------------------------------------------------------------------------
@@ -944,7 +1044,7 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
body := p.parseBody(scope)
p.exprLev--
- return &ast.FuncLit{typ, body}
+ return &ast.FuncLit{Type: typ, Body: body}
}
// parseOperand may return an expression or a raw type (incl. array
@@ -965,7 +1065,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return x
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
- x := &ast.BasicLit{p.pos, p.tok, p.lit}
+ x := &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
return x
@@ -976,24 +1076,24 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
x := p.parseRhsOrType() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
- return &ast.ParenExpr{lparen, x, rparen}
+ return &ast.ParenExpr{Lparen: lparen, X: x, Rparen: rparen}
case token.FUNC:
return p.parseFuncTypeOrLit()
+ }
- default:
- if typ := p.tryIdentOrType(true); typ != nil {
- // could be type for composite literal or conversion
- _, isIdent := typ.(*ast.Ident)
- assert(!isIdent, "type cannot be identifier")
- return typ
- }
+ if typ := p.tryIdentOrType(true); typ != nil {
+ // could be type for composite literal or conversion
+ _, isIdent := typ.(*ast.Ident)
+ assert(!isIdent, "type cannot be identifier")
+ return typ
}
+ // we have an error
pos := p.pos
p.errorExpected(pos, "operand")
- p.next() // make progress
- return &ast.BadExpr{pos, p.pos}
+ syncStmt(p)
+ return &ast.BadExpr{From: pos, To: p.pos}
}
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
@@ -1003,7 +1103,7 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
sel := p.parseIdent()
- return &ast.SelectorExpr{x, sel}
+ return &ast.SelectorExpr{X: x, Sel: sel}
}
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
@@ -1021,7 +1121,7 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
}
p.expect(token.RPAREN)
- return &ast.TypeAssertExpr{x, typ}
+ return &ast.TypeAssertExpr{X: x, Type: typ}
}
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
@@ -1047,9 +1147,9 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
rbrack := p.expect(token.RBRACK)
if isSlice {
- return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: low, High: high, Rbrack: rbrack}
}
- return &ast.IndexExpr{x, lbrack, low, rbrack}
+ return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: low, Rbrack: rbrack}
}
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
@@ -1067,15 +1167,15 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
ellipsis = p.pos
p.next()
}
- if p.tok != token.COMMA {
+ if !p.atComma("argument list") {
break
}
p.next()
}
p.exprLev--
- rparen := p.expect(token.RPAREN)
+ rparen := p.expectClosing(token.RPAREN, "argument list")
- return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
+ return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen}
}
func (p *parser) parseElement(keyOk bool) ast.Expr {
@@ -1092,7 +1192,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.tok == token.COLON {
colon := p.pos
p.next()
- return &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+ return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)}
}
p.resolve(x) // not a map key
}
@@ -1107,7 +1207,7 @@ func (p *parser) parseElementList() (list []ast.Expr) {
for p.tok != token.RBRACE && p.tok != token.EOF {
list = append(list, p.parseElement(true))
- if p.tok != token.COMMA {
+ if !p.atComma("composite literal") {
break
}
p.next()
@@ -1128,13 +1228,13 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
elts = p.parseElementList()
}
p.exprLev--
- rbrace := p.expect(token.RBRACE)
- return &ast.CompositeLit{typ, lbrace, elts, rbrace}
+ rbrace := p.expectClosing(token.RBRACE, "composite literal")
+ return &ast.CompositeLit{Type: typ, Lbrace: lbrace, Elts: elts, Rbrace: 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) {
+ switch unparen(x).(type) {
case *ast.BadExpr:
case *ast.Ident:
case *ast.BasicLit:
@@ -1158,7 +1258,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos(), x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: x.End()}
}
return x
}
@@ -1221,7 +1321,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
p.error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{x.Pos(), x.End()}
+ x = &ast.BadExpr{From: x.Pos(), To: x.End()}
}
}
@@ -1251,9 +1351,9 @@ L:
x = p.parseTypeAssertion(p.checkExpr(x))
default:
pos := p.pos
- p.next() // make progress
p.errorExpected(pos, "selector or type assertion")
- x = &ast.BadExpr{pos, p.pos}
+ p.next() // make progress
+ x = &ast.BadExpr{From: pos, To: p.pos}
}
case token.LBRACK:
if lhs {
@@ -1294,7 +1394,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
pos, op := p.pos, p.tok
p.next()
x := p.parseUnaryExpr(false)
- return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: pos, Op: op, X: p.checkExpr(x)}
case token.ARROW:
// channel type or receive expression
@@ -1303,18 +1403,18 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.tok == token.CHAN {
p.next()
value := p.parseType()
- return &ast.ChanType{pos, ast.RECV, value}
+ return &ast.ChanType{Begin: pos, Dir: ast.RECV, Value: value}
}
x := p.parseUnaryExpr(false)
- return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
+ return &ast.UnaryExpr{OpPos: pos, Op: token.ARROW, X: p.checkExpr(x)}
case token.MUL:
// pointer type or unary "*" expression
pos := p.pos
p.next()
x := p.parseUnaryExpr(false)
- return &ast.StarExpr{pos, p.checkExprOrType(x)}
+ return &ast.StarExpr{Star: pos, X: p.checkExprOrType(x)}
}
return p.parsePrimaryExpr(lhs)
@@ -1336,7 +1436,7 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
lhs = false
}
y := p.parseBinaryExpr(false, prec+1)
- x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
+ x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
}
}
@@ -1398,12 +1498,16 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
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()}}
+ y = []ast.Expr{&ast.UnaryExpr{OpPos: pos, Op: token.RANGE, X: p.parseRhs()}}
isRange = true
} else {
y = p.parseRhsList()
}
- return &ast.AssignStmt{x, pos, tok, y}, isRange
+ as := &ast.AssignStmt{Lhs: x, TokPos: pos, Tok: tok, Rhs: y}
+ if tok == token.DEFINE {
+ p.shortVarDecl(as, x)
+ }
+ return as, isRange
}
if len(x) > 1 {
@@ -1420,7 +1524,7 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
// 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()}
+ stmt := &ast.LabeledStmt{Label: label, Colon: colon, Stmt: p.parseStmt()}
p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
return stmt, false
}
@@ -1431,24 +1535,24 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
// 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
+ return &ast.BadStmt{From: x[0].Pos(), To: colon + 1}, false
case token.ARROW:
// send statement
arrow := p.pos
- p.next() // consume "<-"
+ p.next()
y := p.parseRhs()
- return &ast.SendStmt{x[0], arrow, y}, false
+ return &ast.SendStmt{Chan: x[0], Arrow: arrow, Value: y}, false
case token.INC, token.DEC:
// increment or decrement
- s := &ast.IncDecStmt{x[0], p.pos, p.tok}
- p.next() // consume "++" or "--"
+ s := &ast.IncDecStmt{X: x[0], TokPos: p.pos, Tok: p.tok}
+ p.next()
return s, false
}
// expression
- return &ast.ExprStmt{x[0]}, false
+ return &ast.ExprStmt{X: x[0]}, false
}
func (p *parser) parseCallExpr() *ast.CallExpr {
@@ -1456,7 +1560,10 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
- p.errorExpected(x.Pos(), "function/method call")
+ if _, isBad := x.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(x.Pos(), "function/method call")
+ }
return nil
}
@@ -1469,10 +1576,10 @@ func (p *parser) parseGoStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos, pos + 2} // len("go")
+ return &ast.BadStmt{From: pos, To: pos + 2} // len("go")
}
- return &ast.GoStmt{pos, call}
+ return &ast.GoStmt{Go: pos, Call: call}
}
func (p *parser) parseDeferStmt() ast.Stmt {
@@ -1484,10 +1591,10 @@ func (p *parser) parseDeferStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos, pos + 5} // len("defer")
+ return &ast.BadStmt{From: pos, To: pos + 5} // len("defer")
}
- return &ast.DeferStmt{pos, call}
+ return &ast.DeferStmt{Defer: pos, Call: call}
}
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
@@ -1503,7 +1610,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
}
p.expectSemi()
- return &ast.ReturnStmt{pos, x}
+ return &ast.ReturnStmt{Return: pos, Results: x}
}
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
@@ -1521,7 +1628,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
}
p.expectSemi()
- return &ast.BranchStmt{pos, tok, label}
+ return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
}
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
@@ -1532,7 +1639,7 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return p.checkExpr(es.X)
}
p.error(s.Pos(), "expected condition, found simple statement")
- return &ast.BadExpr{s.Pos(), s.End()}
+ return &ast.BadExpr{From: s.Pos(), To: s.End()}
}
func (p *parser) parseIfStmt() *ast.IfStmt {
@@ -1574,7 +1681,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.expectSemi()
}
- return &ast.IfStmt{pos, s, x, body, else_}
+ return &ast.IfStmt{If: pos, Init: s, Cond: x, Body: body, Else: else_}
}
func (p *parser) parseTypeList() (list []ast.Expr) {
@@ -1591,7 +1698,7 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return
}
-func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
+func (p *parser) parseCaseClause(typeSwitch bool) *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
}
@@ -1600,10 +1707,10 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
var list []ast.Expr
if p.tok == token.CASE {
p.next()
- if exprSwitch {
- list = p.parseRhsList()
- } else {
+ if typeSwitch {
list = p.parseTypeList()
+ } else {
+ list = p.parseRhsList()
}
} else {
p.expect(token.DEFAULT)
@@ -1614,18 +1721,22 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
body := p.parseStmtList()
p.closeScope()
- return &ast.CaseClause{pos, list, colon, body}
+ return &ast.CaseClause{Case: pos, List: list, Colon: colon, Body: body}
}
-func isExprSwitch(s ast.Stmt) bool {
- if s == nil {
- return true
- }
- if e, ok := s.(*ast.ExprStmt); ok {
- if a, ok := e.X.(*ast.TypeAssertExpr); ok {
- return a.Type != nil // regular type assertion
- }
- return true
+func isTypeSwitchAssert(x ast.Expr) bool {
+ a, ok := x.(*ast.TypeAssertExpr)
+ return ok && a.Type == nil
+}
+
+func isTypeSwitchGuard(s ast.Stmt) bool {
+ switch t := s.(type) {
+ case *ast.ExprStmt:
+ // x.(nil)
+ return isTypeSwitchAssert(t.X)
+ case *ast.AssignStmt:
+ // v := x.(nil)
+ return len(t.Lhs) == 1 && t.Tok == token.DEFINE && len(t.Rhs) == 1 && isTypeSwitchAssert(t.Rhs[0])
}
return false
}
@@ -1651,28 +1762,41 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
s1 = s2
s2 = nil
if p.tok != token.LBRACE {
+ // A TypeSwitchGuard may declare a variable in addition
+ // to the variable declared in the initial SimpleStmt.
+ // Introduce extra scope to avoid redeclaration errors:
+ //
+ // switch t := 0; t := x.(T) { ... }
+ //
+ // (this code is not valid Go because the first t will
+ // cannot be accessed and thus is never used, the extra
+ // scope is needed for the correct error message).
+ //
+ // If we don't have a type switch, s2 must be an expression.
+ // Having the extra nested but empty scope won't affect it.
+ p.openScope()
+ defer p.closeScope()
s2, _ = p.parseSimpleStmt(basic)
}
}
p.exprLev = prevLev
}
- exprSwitch := isExprSwitch(s2)
+ typeSwitch := isTypeSwitchGuard(s2)
lbrace := p.expect(token.LBRACE)
var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT {
- list = append(list, p.parseCaseClause(exprSwitch))
+ list = append(list, p.parseCaseClause(typeSwitch))
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, list, rbrace}
+ body := &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
- if exprSwitch {
- return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+ if typeSwitch {
+ return &ast.TypeSwitchStmt{Switch: pos, Init: s1, Assign: s2, Body: body}
}
- // type switch
- // TODO(gri): do all the checks!
- return &ast.TypeSwitchStmt{pos, s1, s2, body}
+
+ return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2), Body: body}
}
func (p *parser) parseCommClause() *ast.CommClause {
@@ -1695,34 +1819,31 @@ func (p *parser) parseCommClause() *ast.CommClause {
arrow := p.pos
p.next()
rhs := p.parseRhs()
- comm = &ast.SendStmt{lhs[0], arrow, rhs}
+ comm = &ast.SendStmt{Chan: lhs[0], Arrow: arrow, Value: rhs}
} else {
// RecvStmt
- pos := p.pos
- tok := p.tok
- var rhs ast.Expr
- if tok == token.ASSIGN || tok == token.DEFINE {
+ if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
// RecvStmt with assignment
if len(lhs) > 2 {
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
// continue with first two expressions
lhs = lhs[0:2]
}
+ pos := p.pos
p.next()
- rhs = p.parseRhs()
+ rhs := p.parseRhs()
+ as := &ast.AssignStmt{Lhs: lhs, TokPos: pos, Tok: tok, Rhs: []ast.Expr{rhs}}
+ if tok == token.DEFINE {
+ p.shortVarDecl(as, lhs)
+ }
+ comm = as
} else {
- // rhs must be single receive operation
+ // lhs must be single receive operation
if len(lhs) > 1 {
p.errorExpected(lhs[0].Pos(), "1 expression")
// continue with first expression
}
- rhs = lhs[0]
- lhs = nil // there is no lhs
- }
- if lhs != nil {
- comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
- } else {
- comm = &ast.ExprStmt{rhs}
+ comm = &ast.ExprStmt{X: lhs[0]}
}
}
} else {
@@ -1733,7 +1854,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
body := p.parseStmtList()
p.closeScope()
- return &ast.CommClause{pos, comm, colon, body}
+ return &ast.CommClause{Case: pos, Comm: comm, Colon: colon, Body: body}
}
func (p *parser) parseSelectStmt() *ast.SelectStmt {
@@ -1749,9 +1870,9 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, list, rbrace}
+ body := &ast.BlockStmt{Lbrace: lbrace, List: list, Rbrace: rbrace}
- return &ast.SelectStmt{pos, body}
+ return &ast.SelectStmt{Select: pos, Body: body}
}
func (p *parser) parseForStmt() ast.Stmt {
@@ -1800,16 +1921,30 @@ func (p *parser) parseForStmt() ast.Stmt {
key = as.Lhs[0]
default:
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
- return &ast.BadStmt{pos, body.End()}
+ return &ast.BadStmt{From: pos, To: 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}
+ return &ast.RangeStmt{
+ For: pos,
+ Key: key,
+ Value: value,
+ TokPos: as.TokPos,
+ Tok: as.Tok,
+ X: x,
+ Body: body,
+ }
}
// regular for statement
- return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+ return &ast.ForStmt{
+ For: pos,
+ Init: s1,
+ Cond: p.makeExpr(s2),
+ Post: s3,
+ Body: body,
+ }
}
func (p *parser) parseStmt() (s ast.Stmt) {
@@ -1819,12 +1954,12 @@ func (p *parser) parseStmt() (s ast.Stmt) {
switch p.tok {
case token.CONST, token.TYPE, token.VAR:
- s = &ast.DeclStmt{p.parseDecl()}
+ s = &ast.DeclStmt{Decl: p.parseDecl(syncStmt)}
case
- // tokens that may start a top-level expression
- token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
- token.LBRACK, token.STRUCT, // composite type
- token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
+ // tokens that may start an expression
+ token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
+ token.LBRACK, token.STRUCT, // composite types
+ token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators
s, _ = p.parseSimpleStmt(labelOk)
// because of the required look-ahead, labeled statements are
// parsed by parseSimpleStmt - don't expect a semicolon after
@@ -1852,17 +1987,17 @@ func (p *parser) parseStmt() (s ast.Stmt) {
case token.FOR:
s = p.parseForStmt()
case token.SEMICOLON:
- s = &ast.EmptyStmt{p.pos}
+ s = &ast.EmptyStmt{Semicolon: p.pos}
p.next()
case token.RBRACE:
// a semicolon may be omitted before a closing "}"
- s = &ast.EmptyStmt{p.pos}
+ s = &ast.EmptyStmt{Semicolon: p.pos}
default:
// no statement found
pos := p.pos
p.errorExpected(pos, "statement")
- p.next() // make progress
- s = &ast.BadStmt{pos, p.pos}
+ syncStmt(p)
+ s = &ast.BadStmt{From: pos, To: p.pos}
}
return
@@ -1873,6 +2008,17 @@ func (p *parser) parseStmt() (s ast.Stmt) {
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
+func isValidImport(lit string) bool {
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ s, _ := strconv.Unquote(lit) // go/scanner returns a legal string literal
+ for _, r := range s {
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return false
+ }
+ }
+ return s != ""
+}
+
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1881,7 +2027,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var ident *ast.Ident
switch p.tok {
case token.PERIOD:
- ident = &ast.Ident{p.pos, ".", nil}
+ ident = &ast.Ident{NamePos: p.pos, Name: "."}
p.next()
case token.IDENT:
ident = p.parseIdent()
@@ -1889,7 +2035,10 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
var path *ast.BasicLit
if p.tok == token.STRING {
- path = &ast.BasicLit{p.pos, p.tok, p.lit}
+ if !isValidImport(p.lit) {
+ p.error(p.pos, "invalid import path: "+p.lit)
+ }
+ path = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
p.next()
} else {
p.expect(token.STRING) // use expect() error handling
@@ -1897,7 +2046,12 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
p.expectSemi() // call before accessing p.linecomment
// collect imports
- spec := &ast.ImportSpec{doc, ident, path, p.lineComment}
+ spec := &ast.ImportSpec{
+ Doc: doc,
+ Name: ident,
+ Path: path,
+ Comment: p.lineComment,
+ }
p.imports = append(p.imports, spec)
return spec
@@ -1921,7 +2075,13 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
// a function begins at the end of the ConstSpec or VarSpec and ends at
// 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}
+ spec := &ast.ValueSpec{
+ Doc: doc,
+ Names: idents,
+ Type: typ,
+ Values: values,
+ Comment: p.lineComment,
+ }
p.declare(spec, iota, p.topScope, ast.Con, idents...)
return spec
@@ -1938,7 +2098,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// at the identifier in the TypeSpec and ends at the end of the innermost
// containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
- spec := &ast.TypeSpec{doc, ident, nil, nil}
+ spec := &ast.TypeSpec{Doc: doc, Name: ident}
p.declare(spec, nil, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
@@ -1966,7 +2126,13 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// a function begins at the end of the ConstSpec or VarSpec and ends at
// 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}
+ spec := &ast.ValueSpec{
+ Doc: doc,
+ Names: idents,
+ Type: typ,
+ Values: values,
+ Comment: p.lineComment,
+ }
p.declare(spec, nil, p.topScope, ast.Var, idents...)
return spec
@@ -1993,7 +2159,14 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
list = append(list, f(p, nil, 0))
}
- return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
+ return &ast.GenDecl{
+ Doc: doc,
+ TokPos: pos,
+ Tok: keyword,
+ Lparen: lparen,
+ Specs: list,
+ Rparen: rparen,
+ }
}
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
@@ -2001,14 +2174,12 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
defer un(trace(p, "Receiver"))
}
- pos := p.pos
par := p.parseParameters(scope, false)
// must have exactly one receiver
if par.NumFields() != 1 {
- p.errorExpected(pos, "exactly one receiver")
- // TODO determine a better range for BadExpr below
- par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ p.errorExpected(par.Opening, "exactly one receiver")
+ par.List = []*ast.Field{{Type: &ast.BadExpr{From: par.Opening, To: par.Closing + 1}}}
return par
}
@@ -2016,8 +2187,13 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
recv := par.List[0]
base := deref(recv.Type)
if _, isIdent := base.(*ast.Ident); !isIdent {
- p.errorExpected(base.Pos(), "(unqualified) identifier")
- par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ if _, isBad := base.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ }
+ par.List = []*ast.Field{
+ {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
+ }
}
return par
@@ -2047,7 +2223,17 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
}
p.expectSemi()
- decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+ decl := &ast.FuncDecl{
+ Doc: doc,
+ Recv: recv,
+ Name: ident,
+ Type: &ast.FuncType{
+ Func: pos,
+ Params: params,
+ Results: results,
+ },
+ Body: body,
+ }
if recv == nil {
// Go spec: The scope of an identifier denoting a constant, type,
// variable, or function (but not method) declared at top level
@@ -2063,7 +2249,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
return decl
}
-func (p *parser) parseDecl() ast.Decl {
+func (p *parser) parseDecl(sync func(*parser)) ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
}
@@ -2085,26 +2271,13 @@ func (p *parser) parseDecl() ast.Decl {
default:
pos := p.pos
p.errorExpected(pos, "declaration")
- p.next() // make progress
- decl := &ast.BadDecl{pos, p.pos}
- return decl
+ sync(p)
+ return &ast.BadDecl{From: pos, To: p.pos}
}
return p.parseGenDecl(p.tok, f)
}
-func (p *parser) parseDeclList() (list []ast.Decl) {
- if p.trace {
- defer un(trace(p, "DeclList"))
- }
-
- for p.tok != token.EOF {
- list = append(list, p.parseDecl())
- }
-
- return
-}
-
// ----------------------------------------------------------------------------
// Source files
@@ -2129,7 +2302,7 @@ func (p *parser) parseFile() *ast.File {
// Don't bother parsing the rest if we had errors already.
// Likely not a Go source file at all.
- if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
+ if p.errors.Len() == 0 && p.mode&PackageClauseOnly == 0 {
// import decls
for p.tok == token.IMPORT {
decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
@@ -2138,7 +2311,7 @@ func (p *parser) parseFile() *ast.File {
if p.mode&ImportsOnly == 0 {
// rest of package body
for p.tok != token.EOF {
- decls = append(decls, p.parseDecl())
+ decls = append(decls, p.parseDecl(syncDecl))
}
}
}
@@ -2157,5 +2330,14 @@ func (p *parser) parseFile() *ast.File {
}
}
- return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
+ return &ast.File{
+ Doc: doc,
+ Package: pos,
+ Name: ident,
+ Decls: decls,
+ Scope: p.pkgScope,
+ Imports: p.imports,
+ Unresolved: p.unresolved[0:i],
+ Comments: p.comments,
+ }
}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 39a78e515..5e45acd00 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -5,6 +5,8 @@
package parser
import (
+ "fmt"
+ "go/ast"
"go/token"
"os"
"testing"
@@ -12,81 +14,14 @@ import (
var fset = token.NewFileSet()
-var illegalInputs = []interface{}{
- nil,
- 3.14,
- []byte(nil),
- "foo!",
- `package p; func f() { if /* should have condition */ {} };`,
- `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)
- if err == nil {
- t.Errorf("ParseFile(%v) should have failed", src)
- }
- }
-}
-
-var validPrograms = []interface{}{
- "package p\n",
- `package p;`,
- `package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
- `package p; func f() { if f(T{}) {} };`,
- `package p; func f() { _ = (<-chan int)(x) };`,
- `package p; func f() { _ = (<-chan <-chan int)(x) };`,
- `package p; func f(func() func() func());`,
- `package p; func f(...T);`,
- `package p; func f(float, ...int);`,
- `package p; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
- `package p; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
- `package p; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
- `package p; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
- `package p; var a = T{{1, 2}, {3, 4}}`,
- `package p; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
- `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)
- if err != nil {
- t.Errorf("ParseFile(%q): %v", src, err)
- }
- }
-}
-
var validFiles = []string{
"parser.go",
"parser_test.go",
+ "error_test.go",
+ "short_test.go",
}
-func TestParse3(t *testing.T) {
+func TestParse(t *testing.T) {
for _, filename := range validFiles {
_, err := ParseFile(fset, filename, nil, DeclarationErrors)
if err != nil {
@@ -106,9 +41,9 @@ func nameFilter(filename string) bool {
return true
}
-func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
+func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
-func TestParse4(t *testing.T) {
+func TestParseDir(t *testing.T) {
path := "."
pkgs, err := ParseDir(fset, path, dirFilter, 0)
if err != nil {
@@ -128,3 +63,117 @@ func TestParse4(t *testing.T) {
}
}
}
+
+func TestParseExpr(t *testing.T) {
+ // just kicking the tires:
+ // a valid expression
+ src := "a + b"
+ x, err := ParseExpr(src)
+ if err != nil {
+ t.Errorf("ParseExpr(%s): %v", src, err)
+ }
+ // sanity check
+ if _, ok := x.(*ast.BinaryExpr); !ok {
+ t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+ }
+
+ // an invalid expression
+ src = "a + *"
+ _, err = ParseExpr(src)
+ if err == nil {
+ t.Errorf("ParseExpr(%s): %v", src, err)
+ }
+
+ // it must not crash
+ for _, src := range valids {
+ ParseExpr(src)
+ }
+}
+
+func TestColonEqualsScope(t *testing.T) {
+ f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0)
+ if err != nil {
+ t.Errorf("parse: %s", err)
+ }
+
+ // RHS refers to undefined globals; LHS does not.
+ as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
+ for _, v := range as.Rhs {
+ id := v.(*ast.Ident)
+ if id.Obj != nil {
+ t.Errorf("rhs %s has Obj, should not", id.Name)
+ }
+ }
+ for _, v := range as.Lhs {
+ id := v.(*ast.Ident)
+ if id.Obj == nil {
+ t.Errorf("lhs %s does not have Obj, should", id.Name)
+ }
+ }
+}
+
+func TestVarScope(t *testing.T) {
+ f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0)
+ if err != nil {
+ t.Errorf("parse: %s", err)
+ }
+
+ // RHS refers to undefined globals; LHS does not.
+ as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
+ for _, v := range as.Values {
+ id := v.(*ast.Ident)
+ if id.Obj != nil {
+ t.Errorf("rhs %s has Obj, should not", id.Name)
+ }
+ }
+ for _, id := range as.Names {
+ if id.Obj == nil {
+ t.Errorf("lhs %s does not have Obj, should", id.Name)
+ }
+ }
+}
+
+var imports = map[string]bool{
+ `"a"`: true,
+ "`a`": true,
+ `"a/b"`: true,
+ `"a.b"`: true,
+ `"m\x61th"`: true,
+ `"greek/αβ"`: true,
+ `""`: false,
+
+ // Each of these pairs tests both `` vs "" strings
+ // and also use of invalid characters spelled out as
+ // escape sequences and written directly.
+ // For example `"\x00"` tests import "\x00"
+ // while "`\x00`" tests import `<actual-NUL-byte>`.
+ `"\x00"`: false,
+ "`\x00`": false,
+ `"\x7f"`: false,
+ "`\x7f`": false,
+ `"a!"`: false,
+ "`a!`": false,
+ `"a b"`: false,
+ "`a b`": false,
+ `"a\\b"`: false,
+ "`a\\b`": false,
+ "\"`a`\"": false,
+ "`\"a\"`": false,
+ `"\x80\x80"`: false,
+ "`\x80\x80`": false,
+ `"\xFFFD"`: false,
+ "`\xFFFD`": false,
+}
+
+func TestImports(t *testing.T) {
+ for path, isValid := range imports {
+ src := fmt.Sprintf("package p; import %s", path)
+ _, err := ParseFile(fset, "", src, 0)
+ switch {
+ case err != nil && isValid:
+ t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
+ case err == nil && !isValid:
+ t.Errorf("ParseFile(%s): got no error; expected one", src)
+ }
+ }
+}
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
new file mode 100644
index 000000000..238492bf3
--- /dev/null
+++ b/src/pkg/go/parser/short_test.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains test cases for short valid and invalid programs.
+
+package parser
+
+import "testing"
+
+var valids = []string{
+ "package p\n",
+ `package p;`,
+ `package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
+ `package p; func f() { if f(T{}) {} };`,
+ `package p; func f() { _ = (<-chan int)(x) };`,
+ `package p; func f() { _ = (<-chan <-chan int)(x) };`,
+ `package p; func f(func() func() func());`,
+ `package p; func f(...T);`,
+ `package p; func f(float, ...int);`,
+ `package p; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+ `package p; func f(int,) {};`,
+ `package p; func f(...int,) {};`,
+ `package p; func f(x ...int,) {};`,
+ `package p; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+ `package p; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+ `package p; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+ `package p; var a = T{{1, 2}, {3, 4}}`,
+ `package p; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
+ `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 TestValid(t *testing.T) {
+ for _, src := range valids {
+ checkErrors(t, src, src)
+ }
+}
+
+var invalids = []string{
+ `foo /* ERROR "expected 'package'" */ !`,
+ `package p; func f() { if { /* ERROR "expected operand" */ } };`,
+ `package p; func f() { if ; { /* ERROR "expected operand" */ } };`,
+ `package p; func f() { if f(); { /* ERROR "expected operand" */ } };`,
+ `package p; const c; /* ERROR "expected '='" */`,
+ `package p; func f() { if _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { switch _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
+ `package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
+ `package p; func f() { for ; _ /* ERROR "expected condition" */ = range x ; {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ , t = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type), t {} };`,
+ `package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
+ `package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
+ `package p; var a = struct /* ERROR "expected expression" */ {}`,
+ `package p; var a = func /* ERROR "expected expression" */ ();`,
+ `package p; var a = interface /* ERROR "expected expression" */ {}`,
+ `package p; var a = [ /* ERROR "expected expression" */ ]int`,
+ `package p; var a = map /* ERROR "expected expression" */ [int]int`,
+ `package p; var a = chan /* ERROR "expected expression" */ int;`,
+ `package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
+ `package p; var a = ( /* ERROR "expected expression" */ []int);`,
+ `package p; var a = a[[ /* ERROR "expected expression" */ ]int:[]int];`,
+ `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
+ `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
+}
+
+func TestInvalid(t *testing.T) {
+ for _, src := range invalids {
+ checkErrors(t, src, src)
+ }
+}
diff --git a/src/pkg/go/parser/testdata/commas.src b/src/pkg/go/parser/testdata/commas.src
new file mode 100644
index 000000000..af6e70645
--- /dev/null
+++ b/src/pkg/go/parser/testdata/commas.src
@@ -0,0 +1,19 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for error messages/parser synchronization
+// after missing commas.
+
+package p
+
+var _ = []int{
+ 0 /* ERROR "missing ','" */
+}
+
+var _ = []int{
+ 0,
+ 1,
+ 2,
+ 3 /* ERROR "missing ','" */
+}
diff --git a/src/pkg/go/parser/testdata/issue3106.src b/src/pkg/go/parser/testdata/issue3106.src
new file mode 100644
index 000000000..82796c8ce
--- /dev/null
+++ b/src/pkg/go/parser/testdata/issue3106.src
@@ -0,0 +1,46 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 3106: Better synchronization of
+// parser after certain syntax errors.
+
+package main
+
+func f() {
+ var m Mutex
+ c := MakeCond(&m)
+ percent := 0
+ const step = 10
+ for i := 0; i < 5; i++ {
+ go func() {
+ for {
+ // Emulates some useful work.
+ time.Sleep(1e8)
+ m.Lock()
+ defer
+ if /* ERROR "expected operand, found 'if'" */ percent == 100 {
+ m.Unlock()
+ break
+ }
+ percent++
+ if percent % step == 0 {
+ //c.Signal()
+ }
+ m.Unlock()
+ }
+ }()
+ }
+ for {
+ m.Lock()
+ if percent == 0 || percent % step != 0 {
+ c.Wait()
+ }
+ fmt.Print(",")
+ if percent == 100 {
+ m.Unlock()
+ break
+ }
+ m.Unlock()
+ }
+}
diff --git a/src/pkg/go/printer/Makefile b/src/pkg/go/printer/Makefile
deleted file mode 100644
index 6a71efc93..000000000
--- a/src/pkg/go/printer/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=go/printer
-GOFILES=\
- printer.go\
- nodes.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/printer/example_test.go b/src/pkg/go/printer/example_test.go
new file mode 100644
index 000000000..e570040ba
--- /dev/null
+++ b/src/pkg/go/printer/example_test.go
@@ -0,0 +1,67 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package printer_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "strings"
+ "testing"
+)
+
+// Dummy test function so that godoc does not use the entire file as example.
+func Test(*testing.T) {}
+
+func parseFunc(filename, functionname string) (fun *ast.FuncDecl, fset *token.FileSet) {
+ fset = token.NewFileSet()
+ if file, err := parser.ParseFile(fset, filename, nil, 0); err == nil {
+ for _, d := range file.Decls {
+ if f, ok := d.(*ast.FuncDecl); ok && f.Name.Name == functionname {
+ fun = f
+ return
+ }
+ }
+ }
+ panic("function not found")
+}
+
+func ExampleFprint() {
+ // Parse source file and extract the AST without comments for
+ // this function, with position information referring to the
+ // file set fset.
+ funcAST, fset := parseFunc("example_test.go", "ExampleFprint")
+
+ // Print the function body into buffer buf.
+ // The file set is provided to the printer so that it knows
+ // about the original source formatting and can add additional
+ // line breaks where they were present in the source.
+ var buf bytes.Buffer
+ printer.Fprint(&buf, fset, funcAST.Body)
+
+ // Remove braces {} enclosing the function body, unindent,
+ // and trim leading and trailing white space.
+ s := buf.String()
+ s = s[1 : len(s)-1]
+ s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))
+
+ // Print the cleaned-up body text to stdout.
+ fmt.Println(s)
+
+ // output:
+ // funcAST, fset := parseFunc("example_test.go", "ExampleFprint")
+ //
+ // var buf bytes.Buffer
+ // printer.Fprint(&buf, fset, funcAST.Body)
+ //
+ // s := buf.String()
+ // s = s[1 : len(s)-1]
+ // s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))
+ //
+ // fmt.Println(s)
+}
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 9cd975ec1..727d2a371 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -12,9 +12,10 @@ import (
"bytes"
"go/ast"
"go/token"
+ "unicode/utf8"
)
-// Other formatting issues:
+// Formatting issues:
// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
// when the comment spans multiple lines; if such a comment is just two lines, formatting is
// not idempotent
@@ -39,7 +40,10 @@ import (
// future (not yet interspersed) comments in this function.
//
func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
- n := p.nlines(line-p.pos.Line, min)
+ n := nlimit(line - p.pos.Line)
+ if n < min {
+ n = min
+ }
if n > 0 {
p.print(ws)
if newSection {
@@ -69,74 +73,61 @@ func (p *printer) setComment(g *ast.CommentGroup) {
// for some reason there are pending comments; this
// should never happen - handle gracefully and flush
// all comments up to g, ignore anything after that
- p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
+ p.flush(p.posFor(g.List[0].Pos()), token.ILLEGAL)
}
p.comments[0] = g
p.cindex = 0
+ p.nextComment() // get comment ready for use
}
type exprListMode uint
const (
- blankStart exprListMode = 1 << iota // print a blank before a non-empty list
- blankEnd // print a blank after a non-empty list
- commaSep // elements are separated by commas
- commaTerm // list is optionally terminated by a comma
- noIndent // no extra indentation in multi-line lists
- periodSep // elements are separated by periods
+ commaTerm exprListMode = 1 << iota // list is optionally terminated by a comma
+ noIndent // no extra indentation in multi-line lists
)
-// Sets multiLine to true if the identifier list spans multiple lines.
// If indent is set, a multi-line identifier list is indented after the
// first linebreak encountered.
-func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
+func (p *printer) identList(list []*ast.Ident, indent bool) {
// convert into an expression list so we can re-use exprList formatting
xlist := make([]ast.Expr, len(list))
for i, x := range list {
xlist[i] = x
}
- mode := commaSep
+ var mode exprListMode
if !indent {
- mode |= noIndent
+ mode = noIndent
}
- p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
+ p.exprList(token.NoPos, xlist, 1, mode, 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
-// lines.
+// expressions.
//
// TODO(gri) Consider rewriting this to be independent of []ast.Expr
// so that we can use the algorithm for any kind of list
// (e.g., pass list via a channel over which to range).
-func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
+func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos) {
if len(list) == 0 {
return
}
- if mode&blankStart != 0 {
- p.print(blank)
- }
-
- prev := p.fset.Position(prev0)
- next := p.fset.Position(next0)
- line := p.fset.Position(list[0].Pos()).Line
- endLine := p.fset.Position(list[len(list)-1].End()).Line
+ prev := p.posFor(prev0)
+ next := p.posFor(next0)
+ line := p.lineFor(list[0].Pos())
+ endLine := p.lineFor(list[len(list)-1].End())
if prev.IsValid() && prev.Line == line && line == endLine {
// all list entries on a single line
for i, x := range list {
if i > 0 {
- if mode&commaSep != 0 {
- p.print(token.COMMA)
- }
- p.print(blank)
+ // use position of expression following the comma as
+ // comma position for correct comment placement
+ p.print(x.Pos(), token.COMMA, blank)
}
- p.expr0(x, depth, multiLine)
- }
- if mode&blankEnd != 0 {
- p.print(blank)
+ p.expr0(x, depth)
}
return
}
@@ -156,7 +147,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
prevBreak := -1 // index of last expression that was followed by a linebreak
if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
ws = ignore
- *multiLine = true
prevBreak = 0
}
@@ -166,7 +156,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// print all list elements
for i, x := range list {
prevLine := line
- line = p.fset.Position(x.Pos()).Line
+ line = p.lineFor(x.Pos())
// determine if the next linebreak, if any, needs to use formfeed:
// in general, use the entire node size to make the decision; for
@@ -209,20 +199,21 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
if i > 0 {
- switch {
- case mode&commaSep != 0:
- p.print(token.COMMA)
- case mode&periodSep != 0:
- p.print(token.PERIOD)
+ needsLinebreak := prevLine < line && prevLine > 0 && line > 0
+ // use position of expression following the comma as
+ // comma position for correct comment placement, but
+ // only if the expression is on the same line
+ if !needsLinebreak {
+ p.print(x.Pos())
}
- needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
- if prevLine < line && prevLine > 0 && line > 0 {
+ p.print(token.COMMA)
+ needsBlank := true
+ if needsLinebreak {
// lines are broken using newlines so comments remain aligned
// unless forceFF is set or there are multiple expressions on
// the same line in which case formfeed is used
if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
ws = ignore
- *multiLine = true
prevBreak = i
needsBlank = false // we got a line break instead
}
@@ -236,11 +227,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
// we have a key:value expression that fits onto one line and
// is in a list with more then one entry: use a column for the
// key such that consecutive entries can align if possible
- p.expr(pair.Key, multiLine)
+ p.expr(pair.Key)
p.print(pair.Colon, token.COLON, vtab)
- p.expr(pair.Value, multiLine)
+ p.expr(pair.Value)
} else {
- p.expr0(x, depth, multiLine)
+ p.expr0(x, depth)
}
}
@@ -255,67 +246,95 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
return
}
- if mode&blankEnd != 0 {
- p.print(blank)
- }
-
if ws == ignore && mode&noIndent == 0 {
// unindent if we indented
p.print(unindent)
}
}
-// Sets multiLine to true if the the parameter list spans multiple lines.
-func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
+func (p *printer) parameters(fields *ast.FieldList) {
p.print(fields.Opening, token.LPAREN)
if len(fields.List) > 0 {
- var prevLine, line int
+ prevLine := p.lineFor(fields.Opening)
+ ws := indent
for i, par := range fields.List {
+ // determine par begin and end line (may be different
+ // if there are multiple parameter names for this par
+ // or the type is on a separate line)
+ var parLineBeg int
+ var parLineEnd = p.lineFor(par.Type.Pos())
+ if len(par.Names) > 0 {
+ parLineBeg = p.lineFor(par.Names[0].Pos())
+ } else {
+ parLineBeg = parLineEnd
+ }
+ // separating "," if needed
+ needsLinebreak := 0 < prevLine && prevLine < parLineBeg
if i > 0 {
- p.print(token.COMMA)
- if len(par.Names) > 0 {
- line = p.fset.Position(par.Names[0].Pos()).Line
- } else {
- line = p.fset.Position(par.Type.Pos()).Line
- }
- if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ignore, true) {
- *multiLine = true
- } else {
- p.print(blank)
+ // use position of parameter following the comma as
+ // comma position for correct comma placement, but
+ // only if the next parameter is on the same line
+ if !needsLinebreak {
+ p.print(par.Pos())
}
+ p.print(token.COMMA)
}
+ // separator if needed (linebreak or blank)
+ if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) {
+ // break line if the opening "(" or previous parameter ended on a different line
+ ws = ignore
+ } else if i > 0 {
+ p.print(blank)
+ }
+ // parameter names
if len(par.Names) > 0 {
- p.identList(par.Names, false, multiLine)
+ // Very subtle: If we indented before (ws == ignore), identList
+ // won't indent again. If we didn't (ws == indent), identList will
+ // indent if the identList spans multiple lines, and it will outdent
+ // again at the end (and still ws == indent). Thus, a subsequent indent
+ // by a linebreak call after a type, or in the next multi-line identList
+ // will do the right thing.
+ p.identList(par.Names, ws == indent)
p.print(blank)
}
- p.expr(par.Type, multiLine)
- prevLine = p.fset.Position(par.Type.Pos()).Line
+ // parameter type
+ p.expr(par.Type)
+ prevLine = parLineEnd
+ }
+ // if the closing ")" is on a separate line from the last parameter,
+ // print an additional "," and line break
+ if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
+ p.print(token.COMMA)
+ p.linebreak(closing, 0, ignore, true)
+ }
+ // unindent if we indented
+ if ws == ignore {
+ p.print(unindent)
}
}
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)
+func (p *printer) signature(params, result *ast.FieldList) {
+ p.parameters(params)
n := result.NumFields()
if n > 0 {
p.print(blank)
if n == 1 && result.List[0].Names == nil {
// single anonymous result; no ()'s
- p.expr(result.List[0].Type, multiLine)
+ p.expr(result.List[0].Type)
return
}
- p.parameters(result, multiLine)
+ p.parameters(result)
}
}
func identListSize(list []*ast.Ident, maxSize int) (size int) {
for i, x := range list {
if i > 0 {
- size += 2 // ", "
+ size += len(", ")
}
- size += len(x.Name)
+ size += utf8.RuneCountInString(x.Name)
if size >= maxSize {
break
}
@@ -342,16 +361,21 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
}
func (p *printer) setLineComment(text string) {
- p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
+ p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
+}
+
+func (p *printer) isMultiLine(n ast.Node) bool {
+ return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
}
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
- srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
+ hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
+ srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
- if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
+ if !hasComments && srcIsOneLine {
// possibly a one-line struct/interface
if len(list) == 0 {
// no blank between keyword and {} in this case
@@ -364,44 +388,48 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
f := list[0]
for i, x := range f.Names {
if i > 0 {
+ // no comments so no need for comma position
p.print(token.COMMA, blank)
}
- p.expr(x, ignoreMultiLine)
+ p.expr(x)
}
if len(f.Names) > 0 {
p.print(blank)
}
- p.expr(f.Type, ignoreMultiLine)
+ p.expr(f.Type)
p.print(blank, rbrace, token.RBRACE)
return
}
}
+ // hasComments || !srcIsOneLine
+
+ p.print(blank, lbrace, token.LBRACE, indent)
+ if hasComments || len(list) > 0 {
+ p.print(formfeed)
+ }
- // at least one entry or incomplete
- p.print(blank, lbrace, token.LBRACE, indent, formfeed)
if isStruct {
sep := vtab
if len(list) == 1 {
sep = blank
}
- var ml bool
+ newSection := false
for i, f := range list {
if i > 0 {
- p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
- ml = false
extraTabs := 0
p.setComment(f.Doc)
if len(f.Names) > 0 {
// named fields
- p.identList(f.Names, false, &ml)
+ p.identList(f.Names, false)
p.print(sep)
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
extraTabs = 1
} else {
// anonymous field
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
extraTabs = 2
}
if f.Tag != nil {
@@ -409,7 +437,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
p.print(sep)
}
p.print(sep)
- p.expr(f.Tag, &ml)
+ p.expr(f.Tag)
extraTabs = 0
}
if f.Comment != nil {
@@ -418,39 +446,40 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
}
p.setComment(f.Comment)
}
+ newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
p.setLineComment("// contains filtered or unexported fields")
}
} else { // interface
- var ml bool
+ newSection := false
for i, f := range list {
if i > 0 {
- p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
}
- ml = false
p.setComment(f.Doc)
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
// method
- p.expr(f.Names[0], &ml)
- p.signature(ftyp.Params, ftyp.Results, &ml)
+ p.expr(f.Names[0])
+ p.signature(ftyp.Params, ftyp.Results)
} else {
// embedded interface
- p.expr(f.Type, &ml)
+ p.expr(f.Type)
}
p.setComment(f.Comment)
+ newSection = p.isMultiLine(f)
}
if isIncomplete {
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.flush(p.posFor(rbrace), token.RBRACE) // make sure we don't lose the last line comment
p.setLineComment("// contains filtered or unexported methods")
}
@@ -585,15 +614,14 @@ func reduceDepth(depth int) int {
// cutoff is 6 (always use spaces) in Normal mode
// and 4 (never use spaces) in Compact mode.
//
-// Sets multiLine to true if the binary expression spans multiple lines.
-func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
+func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
prec := x.Op.Precedence()
if prec < prec1 {
// parenthesis needed
// Note: The parser inserts an ast.ParenExpr node; thus this case
// can only occur if the AST is created in a different way.
p.print(token.LPAREN)
- p.expr0(x, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth
p.print(token.RPAREN)
return
}
@@ -601,26 +629,25 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
printBlank := prec < cutoff
ws := indent
- p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
+ p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
if printBlank {
p.print(blank)
}
xline := p.pos.Line // before the operator (it may be on the next line!)
- yline := p.fset.Position(x.Y.Pos()).Line
+ yline := p.lineFor(x.Y.Pos())
p.print(x.OpPos, x.Op)
if xline != yline && xline > 0 && yline > 0 {
// at least one line break, but respect an extra empty line
// in the source
if p.linebreak(yline, 1, ws, true) {
ws = ignore
- *multiLine = true
printBlank = false // no blank after line break
}
}
if printBlank {
p.print(blank)
}
- p.expr1(x.Y, prec+1, depth+1, multiLine)
+ p.expr1(x.Y, prec+1, depth+1)
if ws == ignore {
p.print(unindent)
}
@@ -631,65 +658,7 @@ func isBinary(expr ast.Expr) bool {
return ok
}
-// If the expression contains one or more selector expressions, splits it into
-// two expressions at the rightmost period. Writes entire expr to suffix when
-// selector isn't found. Rewrites AST nodes for calls, index expressions and
-// type assertions, all of which may be found in selector chains, to make them
-// parts of the chain.
-func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
- switch x := expr.(type) {
- case *ast.SelectorExpr:
- body, suffix = x.X, x.Sel
- return
- case *ast.CallExpr:
- body, suffix = splitSelector(x.Fun)
- if body != nil {
- suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Ellipsis, x.Rparen}
- return
- }
- case *ast.IndexExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.IndexExpr{suffix, x.Lbrack, x.Index, x.Rbrack}
- return
- }
- case *ast.SliceExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
- return
- }
- case *ast.TypeAssertExpr:
- body, suffix = splitSelector(x.X)
- if body != nil {
- suffix = &ast.TypeAssertExpr{suffix, x.Type}
- return
- }
- }
- suffix = expr
- return
-}
-
-// Convert an expression into an expression list split at the periods of
-// selector expressions.
-func selectorExprList(expr ast.Expr) (list []ast.Expr) {
- // split expression
- for expr != nil {
- var suffix ast.Expr
- expr, suffix = splitSelector(expr)
- list = append(list, suffix)
- }
-
- // reverse list
- for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
- list[i], list[j] = list[j], list[i]
- }
-
- return
-}
-
-// Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
+func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.print(expr.Pos())
switch x := expr.(type) {
@@ -704,12 +673,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.internalError("depth < 1:", depth)
depth = 1
}
- p.binaryExpr(x, prec1, cutoff(x, depth), depth, multiLine)
+ p.binaryExpr(x, prec1, cutoff(x, depth), depth)
case *ast.KeyValueExpr:
- p.expr(x.Key, multiLine)
+ p.expr(x.Key)
p.print(x.Colon, token.COLON, blank)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
case *ast.StarExpr:
const prec = token.UnaryPrec
@@ -717,12 +686,12 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// parenthesis needed
p.print(token.LPAREN)
p.print(token.MUL)
- p.expr(x.X, multiLine)
+ p.expr(x.X)
p.print(token.RPAREN)
} else {
// no parenthesis needed
p.print(token.MUL)
- p.expr(x.X, multiLine)
+ p.expr(x.X)
}
case *ast.UnaryExpr:
@@ -730,7 +699,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if prec < prec1 {
// parenthesis needed
p.print(token.LPAREN)
- p.expr(x, multiLine)
+ p.expr(x)
p.print(token.RPAREN)
} else {
// no parenthesis needed
@@ -739,36 +708,41 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
// TODO(gri) Remove this code if it cannot be reached.
p.print(blank)
}
- p.expr1(x.X, prec, depth, multiLine)
+ p.expr1(x.X, prec, depth)
}
case *ast.BasicLit:
p.print(x)
case *ast.FuncLit:
- p.expr(x.Type, multiLine)
- p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
+ p.expr(x.Type)
+ p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true)
case *ast.ParenExpr:
if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
// don't print parentheses around an already parenthesized expression
// TODO(gri) consider making this more general and incorporate precedence levels
- p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
} else {
p.print(token.LPAREN)
- p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
p.print(x.Rparen, token.RPAREN)
}
case *ast.SelectorExpr:
- parts := selectorExprList(expr)
- p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
+ p.expr1(x.X, token.HighestPrec, depth)
+ p.print(token.PERIOD)
+ if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
+ p.print(indent, newline, x.Sel.Pos(), x.Sel, unindent)
+ } else {
+ p.print(x.Sel.Pos(), x.Sel)
+ }
case *ast.TypeAssertExpr:
- p.expr1(x.X, token.HighestPrec, depth, multiLine)
+ p.expr1(x.X, token.HighestPrec, depth)
p.print(token.PERIOD, token.LPAREN)
if x.Type != nil {
- p.expr(x.Type, multiLine)
+ p.expr(x.Type)
} else {
p.print(token.TYPE)
}
@@ -776,17 +750,17 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.IndexExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
- p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
- p.expr0(x.Index, depth+1, multiLine)
+ p.expr0(x.Index, depth+1)
p.print(x.Rbrack, token.RBRACK)
case *ast.SliceExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
- p.expr1(x.X, token.HighestPrec, 1, multiLine)
+ p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK)
if x.Low != nil {
- p.expr0(x.Low, depth+1, multiLine)
+ p.expr0(x.Low, depth+1)
}
// blanks around ":" if both sides exist and either side is a binary expression
if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
@@ -795,7 +769,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.COLON)
}
if x.High != nil {
- p.expr0(x.High, depth+1, multiLine)
+ p.expr0(x.High, depth+1)
}
p.print(x.Rbrack, token.RBRACK)
@@ -803,21 +777,26 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
if len(x.Args) > 1 {
depth++
}
- p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
+ p.expr1(x.Fun, token.HighestPrec, depth)
p.print(x.Lparen, token.LPAREN)
- p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
if x.Ellipsis.IsValid() {
+ p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis)
p.print(x.Ellipsis, token.ELLIPSIS)
+ if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
+ p.print(token.COMMA, formfeed)
+ }
+ } else {
+ p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen)
}
p.print(x.Rparen, token.RPAREN)
case *ast.CompositeLit:
// composite literal elements that are composite literals themselves may have the type omitted
if x.Type != nil {
- p.expr1(x.Type, token.HighestPrec, depth, multiLine)
+ p.expr1(x.Type, token.HighestPrec, depth)
}
p.print(x.Lbrace, token.LBRACE)
- p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
+ p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
// do not insert extra line breaks because of comments before
// the closing '}' as it might break the code if there is no
// trailing ','
@@ -826,16 +805,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.Ellipsis:
p.print(token.ELLIPSIS)
if x.Elt != nil {
- p.expr(x.Elt, multiLine)
+ p.expr(x.Elt)
}
case *ast.ArrayType:
p.print(token.LBRACK)
if x.Len != nil {
- p.expr(x.Len, multiLine)
+ p.expr(x.Len)
}
p.print(token.RBRACK)
- p.expr(x.Elt, multiLine)
+ p.expr(x.Elt)
case *ast.StructType:
p.print(token.STRUCT)
@@ -843,7 +822,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.FuncType:
p.print(token.FUNC)
- p.signature(x.Params, x.Results, multiLine)
+ p.signature(x.Params, x.Results)
case *ast.InterfaceType:
p.print(token.INTERFACE)
@@ -851,9 +830,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
case *ast.MapType:
p.print(token.MAP, token.LBRACK)
- p.expr(x.Key, multiLine)
+ p.expr(x.Key)
p.print(token.RBRACK)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
case *ast.ChanType:
switch x.Dir {
@@ -865,7 +844,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(token.CHAN, token.ARROW)
}
p.print(blank)
- p.expr(x.Value, multiLine)
+ p.expr(x.Value)
default:
panic("unreachable")
@@ -874,14 +853,13 @@ 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)
+func (p *printer) expr0(x ast.Expr, depth int) {
+ p.expr1(x, token.LowestPrec, depth)
}
-// Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr(x ast.Expr, multiLine *bool) {
+func (p *printer) expr(x ast.Expr) {
const depth = 1
- p.expr1(x, token.LowestPrec, depth, multiLine)
+ p.expr1(x, token.LowestPrec, depth)
}
// ----------------------------------------------------------------------------
@@ -895,13 +873,13 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
if _indent > 0 {
p.print(indent)
}
- var multiLine bool
+ multiLine := false
for i, s := range list {
// _indent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, i == 0 || _indent == 0 || multiLine)
- multiLine = false
- p.stmt(s, nextIsRBrace && i == len(list)-1, &multiLine)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || _indent == 0 || multiLine)
+ p.stmt(s, nextIsRBrace && i == len(list)-1)
+ multiLine = p.isMultiLine(s)
}
if _indent > 0 {
p.print(unindent)
@@ -912,7 +890,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
func (p *printer) block(s *ast.BlockStmt, indent int) {
p.print(s.Pos(), token.LBRACE)
p.stmtList(s.List, indent, true)
- p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
+ p.linebreak(p.lineFor(s.Rbrace), 1, ignore, true)
p.print(s.Rbrace, token.RBRACE)
}
@@ -958,25 +936,25 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
if init == nil && post == nil {
// no semicolons required
if expr != nil {
- p.expr(stripParens(expr), ignoreMultiLine)
+ p.expr(stripParens(expr))
needsBlank = true
}
} else {
// all semicolons required
// (they are not separators, print them explicitly)
if init != nil {
- p.stmt(init, false, ignoreMultiLine)
+ p.stmt(init, false)
}
p.print(token.SEMICOLON, blank)
if expr != nil {
- p.expr(stripParens(expr), ignoreMultiLine)
+ p.expr(stripParens(expr))
needsBlank = true
}
if isForStmt {
p.print(token.SEMICOLON, blank)
needsBlank = false
if post != nil {
- p.stmt(post, false, ignoreMultiLine)
+ p.stmt(post, false)
needsBlank = true
}
}
@@ -986,8 +964,42 @@ 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) {
+// indentList reports whether an expression list would look better if it
+// were indented wholesale (starting with the very first element, rather
+// than starting at the first line break).
+//
+func (p *printer) indentList(list []ast.Expr) bool {
+ // Heuristic: indentList returns true if there are more than one multi-
+ // line element in the list, or if there is any element that is not
+ // starting on the same line as the previous one ends.
+ if len(list) >= 2 {
+ var b = p.lineFor(list[0].Pos())
+ var e = p.lineFor(list[len(list)-1].End())
+ if 0 < b && b < e {
+ // list spans multiple lines
+ n := 0 // multi-line element count
+ line := b
+ for _, x := range list {
+ xb := p.lineFor(x.Pos())
+ xe := p.lineFor(x.End())
+ if line < xb {
+ // x is not starting on the same
+ // line as the previous one ended
+ return true
+ }
+ if xb < xe {
+ // x is a multi-line element
+ n++
+ }
+ line = xe
+ }
+ return n > 1
+ }
+ }
+ return false
+}
+
+func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(stmt.Pos())
switch s := stmt.(type) {
@@ -995,7 +1007,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print("BadStmt")
case *ast.DeclStmt:
- p.decl(s.Decl, multiLine)
+ p.decl(s.Decl)
case *ast.EmptyStmt:
// nothing to do
@@ -1005,7 +1017,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
// is applied before the line break if there is no comment
// between (see writeWhitespace)
p.print(unindent)
- p.expr(s.Label, multiLine)
+ p.expr(s.Label)
p.print(s.Colon, token.COLON, indent)
if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
if !nextIsRBrace {
@@ -1013,23 +1025,23 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
break
}
} else {
- p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
+ p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
}
- p.stmt(s.Stmt, nextIsRBrace, multiLine)
+ p.stmt(s.Stmt, nextIsRBrace)
case *ast.ExprStmt:
const depth = 1
- p.expr0(s.X, depth, multiLine)
+ p.expr0(s.X, depth)
case *ast.SendStmt:
const depth = 1
- p.expr0(s.Chan, depth, multiLine)
+ p.expr0(s.Chan, depth)
p.print(blank, s.Arrow, token.ARROW, blank)
- p.expr0(s.Value, depth, multiLine)
+ p.expr0(s.Value, depth)
case *ast.IncDecStmt:
const depth = 1
- p.expr0(s.X, depth+1, multiLine)
+ p.expr0(s.X, depth+1)
p.print(s.TokPos, s.Tok)
case *ast.AssignStmt:
@@ -1037,56 +1049,66 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
depth++
}
- p.exprList(s.Pos(), s.Lhs, depth, commaSep, multiLine, s.TokPos)
- p.print(blank, s.TokPos, s.Tok)
- p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
+ p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos)
+ p.print(blank, s.TokPos, s.Tok, blank)
+ p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos)
case *ast.GoStmt:
p.print(token.GO, blank)
- p.expr(s.Call, multiLine)
+ p.expr(s.Call)
case *ast.DeferStmt:
p.print(token.DEFER, blank)
- p.expr(s.Call, multiLine)
+ p.expr(s.Call)
case *ast.ReturnStmt:
p.print(token.RETURN)
if s.Results != nil {
- p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(blank)
+ // Use indentList heuristic to make corner cases look
+ // better (issue 1207). A more systematic approach would
+ // always indent, but this would cause significant
+ // reformatting of the code base and not necessarily
+ // lead to more nicely formatted code in general.
+ if p.indentList(s.Results) {
+ p.print(indent)
+ p.exprList(s.Pos(), s.Results, 1, noIndent, token.NoPos)
+ p.print(unindent)
+ } else {
+ p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos)
+ }
}
case *ast.BranchStmt:
p.print(s.Tok)
if s.Label != nil {
p.print(blank)
- p.expr(s.Label, multiLine)
+ p.expr(s.Label)
}
case *ast.BlockStmt:
p.block(s, 1)
- *multiLine = true
case *ast.IfStmt:
p.print(token.IF)
p.controlClause(false, s.Init, s.Cond, nil)
p.block(s.Body, 1)
- *multiLine = true
if s.Else != nil {
p.print(blank, token.ELSE, blank)
switch s.Else.(type) {
case *ast.BlockStmt, *ast.IfStmt:
- p.stmt(s.Else, nextIsRBrace, ignoreMultiLine)
+ p.stmt(s.Else, nextIsRBrace)
default:
p.print(token.LBRACE, indent, formfeed)
- p.stmt(s.Else, true, ignoreMultiLine)
+ p.stmt(s.Else, true)
p.print(unindent, formfeed, token.RBRACE)
}
}
case *ast.CaseClause:
if s.List != nil {
- p.print(token.CASE)
- p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
+ p.print(token.CASE, blank)
+ p.exprList(s.Pos(), s.List, 1, 0, s.Colon)
} else {
p.print(token.DEFAULT)
}
@@ -1097,25 +1119,23 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(token.SWITCH)
p.controlClause(false, s.Init, s.Tag, nil)
p.block(s.Body, 0)
- *multiLine = true
case *ast.TypeSwitchStmt:
p.print(token.SWITCH)
if s.Init != nil {
p.print(blank)
- p.stmt(s.Init, false, ignoreMultiLine)
+ p.stmt(s.Init, false)
p.print(token.SEMICOLON)
}
p.print(blank)
- p.stmt(s.Assign, false, ignoreMultiLine)
+ p.stmt(s.Assign, false)
p.print(blank)
p.block(s.Body, 0)
- *multiLine = true
case *ast.CommClause:
if s.Comm != nil {
p.print(token.CASE, blank)
- p.stmt(s.Comm, false, ignoreMultiLine)
+ p.stmt(s.Comm, false)
} else {
p.print(token.DEFAULT)
}
@@ -1125,32 +1145,31 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.SelectStmt:
p.print(token.SELECT, blank)
body := s.Body
- if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ if len(body.List) == 0 && !p.commentBefore(p.posFor(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)
p.controlClause(true, s.Init, s.Cond, s.Post)
p.block(s.Body, 1)
- *multiLine = true
case *ast.RangeStmt:
p.print(token.FOR, blank)
- p.expr(s.Key, multiLine)
+ p.expr(s.Key)
if s.Value != nil {
- p.print(token.COMMA, blank)
- p.expr(s.Value, multiLine)
+ // use position of value following the comma as
+ // comma position for correct comment placement
+ p.print(s.Value.Pos(), token.COMMA, blank)
+ p.expr(s.Value)
}
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
- p.expr(stripParens(s.X), multiLine)
+ p.expr(stripParens(s.X))
p.print(blank)
p.block(s.Body, 1)
- *multiLine = true
default:
panic("unreachable")
@@ -1227,20 +1246,20 @@ func keepTypeColumn(specs []ast.Spec) []bool {
return m
}
-func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
p.setComment(s.Doc)
- p.identList(s.Names, doIndent, multiLine) // always present
+ p.identList(s.Names, false) // always present
extraTabs := 3
if s.Type != nil || keepType {
p.print(vtab)
extraTabs--
}
if s.Type != nil {
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
}
if s.Values != nil {
- p.print(vtab, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(vtab, token.ASSIGN, blank)
+ p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos)
extraTabs--
}
if s.Comment != nil {
@@ -1254,44 +1273,44 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine
// The parameter n is the number of specs in the group. If doIndent is set,
// multi-line identifier lists in the spec are indented when the first
// linebreak is encountered.
-// Sets multiLine to true if the spec spans multiple lines.
//
-func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
switch s := spec.(type) {
case *ast.ImportSpec:
p.setComment(s.Doc)
if s.Name != nil {
- p.expr(s.Name, multiLine)
+ p.expr(s.Name)
p.print(blank)
}
- p.expr(s.Path, multiLine)
+ p.expr(s.Path)
p.setComment(s.Comment)
+ p.print(s.EndPos)
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
+ p.identList(s.Names, doIndent) // always present
if s.Type != nil {
p.print(blank)
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
}
if s.Values != nil {
- p.print(blank, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ p.print(blank, token.ASSIGN, blank)
+ p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos)
}
p.setComment(s.Comment)
case *ast.TypeSpec:
p.setComment(s.Doc)
- p.expr(s.Name, multiLine)
+ p.expr(s.Name)
if n == 1 {
p.print(blank)
} else {
p.print(vtab)
}
- p.expr(s.Type, multiLine)
+ p.expr(s.Type)
p.setComment(s.Comment)
default:
@@ -1299,8 +1318,7 @@ 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) {
+func (p *printer) genDecl(d *ast.GenDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), d.Tok, blank)
@@ -1313,32 +1331,31 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
// two or more grouped const/var declarations:
// determine if the type column must be kept
keepType := keepTypeColumn(d.Specs)
- var ml bool
+ newSection := false
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
- ml = false
- p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
+ p.valueSpec(s.(*ast.ValueSpec), keepType[i])
+ newSection = p.isMultiLine(s)
}
} else {
- var ml bool
+ newSection := false
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
- ml = false
- p.spec(s, n, false, &ml)
+ p.spec(s, n, false)
+ newSection = p.isMultiLine(s)
}
}
p.print(unindent, formfeed)
- *multiLine = true
}
p.print(d.Rparen, token.RPAREN)
} else {
// single declaration
- p.spec(d.Specs[0], 1, true, multiLine)
+ p.spec(d.Specs[0], 1, true)
}
}
@@ -1364,7 +1381,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
// in RawFormat
cfg := Config{Mode: RawFormat}
var buf bytes.Buffer
- if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
+ if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
return
}
if buf.Len() <= maxSize {
@@ -1382,11 +1399,11 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
pos1 := b.Pos()
pos2 := b.Rbrace
- if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
+ if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
// opening and closing brace are on different lines - don't make it a one-liner
return false
}
- if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
+ if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
// too many statements or there is a comment inside - don't make it a one-liner
return false
}
@@ -1402,8 +1419,7 @@ 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) {
+func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool) {
if b == nil {
return
}
@@ -1420,7 +1436,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
if i > 0 {
p.print(token.SEMICOLON, blank)
}
- p.stmt(s, i == len(b.List)-1, ignoreMultiLine)
+ p.stmt(s, i == len(b.List)-1)
}
p.print(blank)
}
@@ -1430,42 +1446,39 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
p.print(blank)
p.block(b, 1)
- *multiLine = true
}
// distance returns the column difference between from and to if both
// are on the same line; if they are on different lines (or unknown)
// the result is infinity.
func (p *printer) distance(from0 token.Pos, to token.Position) int {
- from := p.fset.Position(from0)
+ from := p.posFor(from0)
if from.IsValid() && to.IsValid() && from.Line == to.Line {
return to.Column - from.Column
}
return infinity
}
-// Sets multiLine to true if the declaration spans multiple lines.
-func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
+func (p *printer) funcDecl(d *ast.FuncDecl) {
p.setComment(d.Doc)
p.print(d.Pos(), token.FUNC, blank)
if d.Recv != nil {
- p.parameters(d.Recv, multiLine) // method: print receiver
+ p.parameters(d.Recv) // method: print receiver
p.print(blank)
}
- p.expr(d.Name, multiLine)
- p.signature(d.Type.Params, d.Type.Results, multiLine)
- p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
+ p.expr(d.Name)
+ p.signature(d.Type.Params, d.Type.Results)
+ p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false)
}
-// Sets multiLine to true if the declaration spans multiple lines.
-func (p *printer) decl(decl ast.Decl, multiLine *bool) {
+func (p *printer) decl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.BadDecl:
p.print(d.Pos(), "BadDecl")
case *ast.GenDecl:
- p.genDecl(d, multiLine)
+ p.genDecl(d)
case *ast.FuncDecl:
- p.funcDecl(d, multiLine)
+ p.funcDecl(d)
default:
panic("unreachable")
}
@@ -1488,7 +1501,7 @@ func declToken(decl ast.Decl) (tok token.Token) {
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
- p.expr(src.Name, ignoreMultiLine)
+ p.expr(src.Name)
if len(src.Decls) > 0 {
tok := token.ILLEGAL
@@ -1496,13 +1509,18 @@ func (p *printer) file(src *ast.File) {
prev := tok
tok = declToken(d)
// if the declaration token changed (e.g., from CONST to TYPE)
+ // or the next declaration has documentation associated with it,
// print an empty line between top-level declarations
+ // (because p.linebreak is called with the position of d, which
+ // is past any documentation, the minimum requirement is satisfied
+ // even w/o the extra getDoc(d) nil-check - leave it in case the
+ // linebreak logic improves - there's already a TODO).
min := 1
- if prev != tok {
+ if prev != tok || getDoc(d) != nil {
min = 2
}
- p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
- p.decl(d, ignoreMultiLine)
+ p.linebreak(p.lineFor(d.Pos()), min, ignore, false)
+ p.decl(d)
}
}
diff --git a/src/pkg/go/printer/performance_test.go b/src/pkg/go/printer/performance_test.go
index 84fb2808e..0c6a4e71f 100644
--- a/src/pkg/go/printer/performance_test.go
+++ b/src/pkg/go/printer/performance_test.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// This file implements a simple printer performance benchmark:
-// gotest -bench=BenchmarkPrint
+// go test -bench=BenchmarkPrint
package printer
@@ -20,7 +20,7 @@ import (
var testfile *ast.File
func testprint(out io.Writer, file *ast.File) {
- if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
+ if err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
log.Fatalf("print error: %s", err)
}
}
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 871fefa0c..a027d32da 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -6,21 +6,23 @@
package printer
import (
- "bytes"
"fmt"
"go/ast"
"go/token"
"io"
"os"
- "path/filepath"
- "runtime"
- "tabwriter"
+ "strconv"
+ "strings"
+ "text/tabwriter"
)
-const debug = false // enable for debugging
-
+const (
+ maxNewlines = 2 // max. number of newlines between source text
+ debug = false // enable for debugging
+ infinity = 1 << 30
+)
-type whiteSpace int
+type whiteSpace byte
const (
ignore = whiteSpace(0)
@@ -32,72 +34,98 @@ const (
unindent = whiteSpace('<')
)
-var (
- esc = []byte{tabwriter.Escape}
- htab = []byte{'\t'}
- htabs = []byte("\t\t\t\t\t\t\t\t")
- newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
- formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
-)
-
-// Special positions
-var noPos token.Position // use noPos when a position is needed but not known
-var infinity = 1 << 30
-
-// Use ignoreMultiLine if the multiLine information is not important.
-var ignoreMultiLine = new(bool)
-
// A pmode value represents the current printer mode.
type pmode int
const (
- inLiteral pmode = 1 << iota
- noExtraLinebreak
+ noExtraLinebreak pmode = 1 << iota
)
type printer struct {
// Configuration (does not change after initialization)
- output io.Writer
Config
- fset *token.FileSet
- errors chan os.Error
+ fset *token.FileSet
// Current state
- written int // number of bytes written
- indent int // current indentation
- mode pmode // current printer mode
- lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
-
- // Reused buffers
- wsbuf []whiteSpace // delayed white space
- litbuf bytes.Buffer // for creation of escaped literals and comments
-
- // The (possibly estimated) position in the generated output;
- // in AST space (i.e., pos is set whenever a token position is
- // known accurately, and updated dependending on what has been
- // written).
- pos token.Position
-
- // The value of pos immediately after the last item has been
- // written using writeItem.
- last token.Position
+ output []byte // raw printer result
+ indent int // current indentation
+ mode pmode // current printer mode
+ impliedSemi bool // if set, a linebreak implies a semicolon
+ lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
+ wsbuf []whiteSpace // delayed white space
+
+ // Positions
+ // The out position differs from the pos position when the result
+ // formatting differs from the source formatting (in the amount of
+ // white space). If there's a difference and SourcePos is set in
+ // ConfigMode, //line comments are used in the output to restore
+ // original source positions for a reader.
+ pos token.Position // current position in AST (source) space
+ out token.Position // current position in output space
+ last token.Position // value of pos after calling writeString
// The list of all source comments, in order of appearance.
comments []*ast.CommentGroup // may be nil
cindex int // current comment index
useNodeComments bool // if not set, ignore lead and line comments of nodes
+ // Information about p.comments[p.cindex]; set up by nextComment.
+ comment *ast.CommentGroup // = p.comments[p.cindex]; or nil
+ commentOffset int // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
+ commentNewline bool // true if the comment group contains newlines
+
// Cache of already computed node sizes.
nodeSizes map[ast.Node]int
+
+ // Cache of most recently computed line position.
+ cachedPos token.Pos
+ cachedLine int // line corresponding to cachedPos
}
-func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
- p.output = output
+func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
p.Config = *cfg
p.fset = fset
- p.errors = make(chan os.Error)
+ p.pos = token.Position{Line: 1, Column: 1}
+ p.out = token.Position{Line: 1, Column: 1}
p.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short
p.nodeSizes = nodeSizes
+ p.cachedPos = -1
+}
+
+// commentsHaveNewline reports whether a list of comments belonging to
+// an *ast.CommentGroup contains newlines. Because the position information
+// may only be partially correct, we also have to read the comment text.
+func (p *printer) commentsHaveNewline(list []*ast.Comment) bool {
+ // len(list) > 0
+ line := p.lineFor(list[0].Pos())
+ for i, c := range list {
+ if i > 0 && p.lineFor(list[i].Pos()) != line {
+ // not all comments on the same line
+ return true
+ }
+ if t := c.Text; len(t) >= 2 && (t[1] == '/' || strings.Contains(t, "\n")) {
+ return true
+ }
+ }
+ _ = line
+ return false
+}
+
+func (p *printer) nextComment() {
+ for p.cindex < len(p.comments) {
+ c := p.comments[p.cindex]
+ p.cindex++
+ if list := c.List; len(list) > 0 {
+ p.comment = c
+ p.commentOffset = p.posFor(list[0].Pos()).Offset
+ p.commentNewline = p.commentsHaveNewline(list)
+ return
+ }
+ // we should not reach here (correct ASTs don't have empty
+ // ast.CommentGroup nodes), but be conservative and try again
+ }
+ // no more comments
+ p.commentOffset = infinity
}
func (p *printer) internalError(msg ...interface{}) {
@@ -108,137 +136,139 @@ func (p *printer) internalError(msg ...interface{}) {
}
}
-// escape escapes string s by bracketing it with tabwriter.Escape.
-// Escaped strings pass through tabwriter unchanged. (Note that
-// valid Go programs cannot contain tabwriter.Escape bytes since
-// they do not appear in legal UTF-8 sequences).
-//
-func (p *printer) escape(s string) string {
- p.litbuf.Reset()
- p.litbuf.WriteByte(tabwriter.Escape)
- p.litbuf.WriteString(s)
- p.litbuf.WriteByte(tabwriter.Escape)
- return p.litbuf.String()
+func (p *printer) posFor(pos token.Pos) token.Position {
+ // not used frequently enough to cache entire token.Position
+ return p.fset.Position(pos)
}
-// nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max.
-//
-func (p *printer) nlines(n, min int) int {
- const max = 2 // max. number of newlines
- switch {
- case n < min:
- return min
- case n > max:
- return max
+func (p *printer) lineFor(pos token.Pos) int {
+ if pos != p.cachedPos {
+ p.cachedPos = pos
+ p.cachedLine = p.fset.Position(pos).Line
}
- return n
+ return p.cachedLine
}
-// write0 writes raw (uninterpreted) data to p.output and handles errors.
-// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
-//
-func (p *printer) write0(data []byte) {
- if len(data) > 0 {
- n, err := p.output.Write(data)
- p.written += n
- if err != nil {
- p.errors <- err
- runtime.Goexit()
- }
+// atLineBegin emits a //line comment if necessary and prints indentation.
+func (p *printer) atLineBegin(pos token.Position) {
+ // write a //line comment if necessary
+ if p.Config.Mode&SourcePos != 0 && pos.IsValid() && (p.out.Line != pos.Line || p.out.Filename != pos.Filename) {
+ p.output = append(p.output, tabwriter.Escape) // protect '\n' in //line from tabwriter interpretation
+ p.output = append(p.output, fmt.Sprintf("//line %s:%d\n", pos.Filename, pos.Line)...)
+ p.output = append(p.output, tabwriter.Escape)
+ // p.out must match the //line comment
+ p.out.Filename = pos.Filename
+ p.out.Line = pos.Line
}
-}
-
-// 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.
-//
-func (p *printer) write(data []byte) {
- i0 := 0
- for i, b := range data {
- switch b {
- case '\n', '\f':
- // write segment ending in b
- p.write0(data[i0 : i+1])
-
- // update p.pos
- p.pos.Offset += i + 1 - i0
- p.pos.Line++
- p.pos.Column = 1
-
- if p.mode&inLiteral == 0 {
- // write indentation
- // use "hard" htabs - indentation columns
- // must not be discarded by the tabwriter
- j := p.indent
- for ; j > len(htabs); j -= len(htabs) {
- p.write0(htabs)
- }
- p.write0(htabs[0:j])
- // update p.pos
- p.pos.Offset += p.indent
- p.pos.Column += p.indent
- }
-
- // next segment start
- i0 = i + 1
+ // write indentation
+ // use "hard" htabs - indentation columns
+ // must not be discarded by the tabwriter
+ for i := 0; i < p.indent; i++ {
+ p.output = append(p.output, '\t')
+ }
- case tabwriter.Escape:
- p.mode ^= inLiteral
+ // update positions
+ i := p.indent
+ p.pos.Offset += i
+ p.pos.Column += i
+ p.out.Column += i
+}
- // ignore escape chars introduced by printer - they are
- // invisible and must not affect p.pos (was issue #1089)
- p.pos.Offset--
- p.pos.Column--
- }
+// writeByte writes ch n times to p.output and updates p.pos.
+func (p *printer) writeByte(ch byte, n int) {
+ if p.out.Column == 1 {
+ p.atLineBegin(p.pos)
}
- // write remaining segment
- p.write0(data[i0:])
-
- // update p.pos
- d := len(data) - i0
- p.pos.Offset += d
- p.pos.Column += d
-}
+ for i := 0; i < n; i++ {
+ p.output = append(p.output, ch)
+ }
-func (p *printer) writeNewlines(n int, useFF bool) {
- if n > 0 {
- n = p.nlines(n, 0)
- if useFF {
- p.write(formfeeds[0:n])
- } else {
- p.write(newlines[0:n])
- }
+ // update positions
+ p.pos.Offset += n
+ if ch == '\n' || ch == '\f' {
+ p.pos.Line += n
+ p.out.Line += n
+ p.pos.Column = 1
+ p.out.Column = 1
+ return
}
+ p.pos.Column += n
+ p.out.Column += n
}
-// writeItem writes data at position pos. data is the text corresponding to
-// a single lexical token, but may also be comment text. pos is the actual
-// (or at least very accurately estimated) position of the data in the original
-// source text. writeItem updates p.last to the position immediately following
-// the data.
+// writeString writes the string s to p.output and updates p.pos, p.out,
+// and p.last. If isLit is set, s is escaped w/ tabwriter.Escape characters
+// to protect s from being interpreted by the tabwriter.
//
-func (p *printer) writeItem(pos token.Position, data string) {
+// Note: writeString is only used to write Go tokens, literals, and
+// comments, all of which must be written literally. Thus, it is correct
+// to always set isLit = true. However, setting it explicitly only when
+// needed (i.e., when we don't know that s contains no tabs or line breaks)
+// avoids processing extra escape characters and reduces run time of the
+// printer benchmark by up to 10%.
+//
+func (p *printer) writeString(pos token.Position, s string, isLit bool) {
+ if p.out.Column == 1 {
+ p.atLineBegin(pos)
+ }
+
if pos.IsValid() {
- // continue with previous position if we don't have a valid pos
+ // update p.pos (if pos is invalid, continue with existing p.pos)
+ // Note: Must do this after handling line beginnings because
+ // atLineBegin updates p.pos if there's indentation, but p.pos
+ // is the position of s.
+ p.pos = pos
+ // reset state if the file changed
+ // (used when printing merged ASTs of different files
+ // e.g., the result of ast.MergePackageFiles)
if p.last.IsValid() && p.last.Filename != pos.Filename {
- // the file has changed - reset state
- // (used when printing merged ASTs of different files
- // e.g., the result of ast.MergePackageFiles)
p.indent = 0
p.mode = 0
p.wsbuf = p.wsbuf[0:0]
}
- p.pos = pos
}
+
+ if isLit {
+ // Protect s such that is passes through the tabwriter
+ // unchanged. Note that valid Go programs cannot contain
+ // tabwriter.Escape bytes since they do not appear in legal
+ // UTF-8 sequences.
+ p.output = append(p.output, tabwriter.Escape)
+ }
+
if debug {
- // do not update p.pos - use write0
- _, filename := filepath.Split(pos.Filename)
- p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
+ p.output = append(p.output, fmt.Sprintf("/*%s*/", pos)...) // do not update p.pos!
+ }
+ p.output = append(p.output, s...)
+
+ // update positions
+ nlines := 0
+ var li int // index of last newline; valid if nlines > 0
+ for i := 0; i < len(s); i++ {
+ // Go tokens cannot contain '\f' - no need to look for it
+ if s[i] == '\n' {
+ nlines++
+ li = i
+ }
+ }
+ p.pos.Offset += len(s)
+ if nlines > 0 {
+ p.pos.Line += nlines
+ p.out.Line += nlines
+ c := len(s) - li
+ p.pos.Column = c
+ p.out.Column = c
+ } else {
+ p.pos.Column += len(s)
+ p.out.Column += len(s)
+ }
+
+ if isLit {
+ p.output = append(p.output, tabwriter.Escape)
}
- p.write([]byte(data))
+
p.last = p.pos
}
@@ -247,18 +277,17 @@ func (p *printer) writeItem(pos token.Position, data string) {
// it as is likely to help position the comment nicely.
// pos is the comment position, next the position of the item
// after all pending comments, prev is the previous comment in
-// a group of comments (or nil), and isKeyword indicates if the
-// next item is a keyword.
+// a group of comments (or nil), and tok is the next token.
//
-func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
- if p.written == 0 {
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, tok token.Token) {
+ if len(p.output) == 0 {
// the comment is the first item to be printed - don't write any whitespace
return
}
if pos.IsValid() && pos.Filename != p.last.Filename {
- // comment in a different file - separate with newlines (writeNewlines will limit the number)
- p.writeNewlines(10, true)
+ // comment in a different file - separate with newlines
+ p.writeByte('\f', maxNewlines)
return
}
@@ -291,82 +320,106 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
}
// make sure there is at least one separator
if !hasSep {
+ sep := byte('\t')
if pos.Line == next.Line {
// next item is on the same line as the comment
// (which must be a /*-style comment): separate
// with a blank instead of a tab
- p.write([]byte{' '})
- } else {
- p.write(htab)
+ sep = ' '
}
+ p.writeByte(sep, 1)
}
} else {
// comment on a different line:
// separate with at least one line break
- if prev == nil {
- // first comment of a comment group
- j := 0
- for i, ch := range p.wsbuf {
- switch ch {
- case blank, vtab:
- // ignore any horizontal whitespace before line breaks
- p.wsbuf[i] = ignore
+ droppedLinebreak := false
+ j := 0
+ for i, ch := range p.wsbuf {
+ switch ch {
+ case blank, vtab:
+ // ignore any horizontal whitespace before line breaks
+ p.wsbuf[i] = ignore
+ continue
+ case indent:
+ // apply pending indentation
+ continue
+ case unindent:
+ // if this is not the last unindent, apply it
+ // as it is (likely) belonging to the last
+ // construct (e.g., a multi-line expression list)
+ // and is not part of closing a block
+ if i+1 < len(p.wsbuf) && p.wsbuf[i+1] == unindent {
continue
- case indent:
- // apply pending indentation
+ }
+ // if the next token is not a closing }, apply the unindent
+ // if it appears that the comment is aligned with the
+ // token; otherwise assume the unindent is part of a
+ // closing block and stop (this scenario appears with
+ // comments before a case label where the comments
+ // apply to the next case instead of the current one)
+ if tok != token.RBRACE && pos.Column == next.Column {
continue
- case unindent:
- // if the next token is a keyword, apply the outdent
- // if it appears that the comment is aligned with the
- // keyword; otherwise assume the outdent is part of a
- // closing block and stop (this scenario appears with
- // comments before a case label where the comments
- // apply to the next case instead of the current one)
- if isKeyword && pos.Column == next.Column {
- continue
- }
- case newline, formfeed:
- // TODO(gri): may want to keep formfeed info in some cases
- p.wsbuf[i] = ignore
}
- j = i
- break
+ case newline, formfeed:
+ p.wsbuf[i] = ignore
+ droppedLinebreak = prev == nil // record only if first comment of a group
+ }
+ j = i
+ break
+ }
+ p.writeWhitespace(j)
+
+ // determine number of linebreaks before the comment
+ n := 0
+ if pos.IsValid() && p.last.IsValid() {
+ n = pos.Line - p.last.Line
+ if n < 0 { // should never happen
+ n = 0
}
- p.writeWhitespace(j)
}
- // use formfeeds to break columns before a comment;
- // this is analogous to using formfeeds to separate
- // individual lines of /*-style comments - but make
- // sure there is at least one line break if the previous
- // comment was a line comment
- n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
- if n <= 0 && prev != nil && prev.Text[1] == '/' {
+
+ // at the package scope level only (p.indent == 0),
+ // add an extra newline if we dropped one before:
+ // this preserves a blank line before documentation
+ // comments at the package scope level (issue 2570)
+ if p.indent == 0 && droppedLinebreak {
+ n++
+ }
+
+ // make sure there is at least one line break
+ // if the previous comment was a line comment
+ if n == 0 && prev != nil && prev.Text[1] == '/' {
n = 1
}
- p.writeNewlines(n, true)
+
+ if n > 0 {
+ // use formfeeds to break columns before a comment;
+ // this is analogous to using formfeeds to separate
+ // individual lines of /*-style comments
+ p.writeByte('\f', nlimit(n))
+ }
}
}
-// TODO(gri): It should be possible to convert the code below from using
-// []byte to string and in the process eliminate some conversions.
-
// Split comment text into lines
-func split(text []byte) [][]byte {
+// (using strings.Split(text, "\n") is significantly slower for
+// this specific purpose, as measured with: go test -bench=Print)
+func split(text string) []string {
// count lines (comment text never ends in a newline)
n := 1
- for _, c := range text {
- if c == '\n' {
+ for i := 0; i < len(text); i++ {
+ if text[i] == '\n' {
n++
}
}
// split
- lines := make([][]byte, n)
+ lines := make([]string, n)
n = 0
i := 0
- for j, c := range text {
- if c == '\n' {
+ for j := 0; j < len(text); j++ {
+ if text[j] == '\n' {
lines[n] = text[i:j] // exclude newline
i = j + 1 // discard newline
n++
@@ -377,16 +430,18 @@ func split(text []byte) [][]byte {
return lines
}
-func isBlank(s []byte) bool {
- for _, b := range s {
- if b > ' ' {
+// Returns true if s contains only white space
+// (only tabs and blanks can appear in the printer's context).
+func isBlank(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] > ' ' {
return false
}
}
return true
}
-func commonPrefix(a, b []byte) []byte {
+func commonPrefix(a, b string) string {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
i++
@@ -394,7 +449,7 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-func stripCommonPrefix(lines [][]byte) {
+func stripCommonPrefix(lines []string) {
if len(lines) < 2 {
return // at most one line - nothing to do
}
@@ -418,19 +473,21 @@ func stripCommonPrefix(lines [][]byte) {
// Note that the first and last line are never empty (they
// contain the opening /* and closing */ respectively) and
// thus they can be ignored by the blank line check.
- var prefix []byte
+ var prefix string
if len(lines) > 2 {
+ first := true
for i, line := range lines[1 : len(lines)-1] {
switch {
case isBlank(line):
- lines[1+i] = nil // range starts at line 1
- case prefix == nil:
+ lines[1+i] = "" // range starts at line 1
+ case first:
prefix = commonPrefix(line, line)
+ first = false
default:
prefix = commonPrefix(prefix, line)
}
}
- } else { // len(lines) == 2
+ } else { // len(lines) == 2, lines cannot be blank (contain /* and */)
line := lines[1]
prefix = commonPrefix(line, line)
}
@@ -439,7 +496,7 @@ func stripCommonPrefix(lines [][]byte) {
* Check for vertical "line of stars" and correct prefix accordingly.
*/
lineOfStars := false
- if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
+ if i := strings.Index(prefix, "*"); i >= 0 {
// Line of stars present.
if i > 0 && prefix[i-1] == ' ' {
i-- // remove trailing blank from prefix so stars remain aligned
@@ -487,7 +544,7 @@ func stripCommonPrefix(lines [][]byte) {
}
// Shorten the computed common prefix by the length of
// suffix, if it is found as suffix of the prefix.
- if bytes.HasSuffix(prefix, suffix) {
+ if strings.HasSuffix(prefix, string(suffix)) {
prefix = prefix[0 : len(prefix)-len(suffix)]
}
}
@@ -497,19 +554,18 @@ func stripCommonPrefix(lines [][]byte) {
// with the opening /*, otherwise align the text with the other
// lines.
last := lines[len(lines)-1]
- closing := []byte("*/")
- i := bytes.Index(last, closing)
+ closing := "*/"
+ i := strings.Index(last, closing) // i >= 0 (closing is always present)
if isBlank(last[0:i]) {
// last line only contains closing */
- var sep []byte
if lineOfStars {
- // insert an aligning blank
- sep = []byte{' '}
+ closing = " */" // add blank to align final star
}
- lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep)
+ lines[len(lines)-1] = prefix + closing
} else {
// last line contains more comment text - assume
- // it is aligned like the other lines
+ // it is aligned like the other lines and include
+ // in prefix computation
prefix = commonPrefix(prefix, last)
}
@@ -523,29 +579,50 @@ func stripCommonPrefix(lines [][]byte) {
func (p *printer) writeComment(comment *ast.Comment) {
text := comment.Text
+ pos := p.posFor(comment.Pos())
+
+ const linePrefix = "//line "
+ if strings.HasPrefix(text, linePrefix) && (!pos.IsValid() || pos.Column == 1) {
+ // possibly a line directive
+ ldir := strings.TrimSpace(text[len(linePrefix):])
+ if i := strings.LastIndex(ldir, ":"); i >= 0 {
+ if line, err := strconv.Atoi(ldir[i+1:]); err == nil && line > 0 {
+ // The line directive we are about to print changed
+ // the Filename and Line number used for subsequent
+ // tokens. We have to update our AST-space position
+ // accordingly and suspend indentation temporarily.
+ indent := p.indent
+ p.indent = 0
+ defer func() {
+ p.pos.Filename = ldir[:i]
+ p.pos.Line = line
+ p.pos.Column = 1
+ p.indent = indent
+ }()
+ }
+ }
+ }
// shortcut common case of //-style comments
if text[1] == '/' {
- p.writeItem(p.fset.Position(comment.Pos()), p.escape(text))
+ p.writeString(pos, text, true)
return
}
// for /*-style comments, print line by line and let the
// write function take care of the proper indentation
- lines := split([]byte(text))
+ lines := split(text)
stripCommonPrefix(lines)
// write comment lines, separated by formfeed,
// without a line break after the last line
- linebreak := formfeeds[0:1]
- pos := p.fset.Position(comment.Pos())
for i, line := range lines {
if i > 0 {
- p.write(linebreak)
+ p.writeByte('\f', 1)
pos = p.pos
}
if len(line) > 0 {
- p.writeItem(pos, p.escape(string(line)))
+ p.writeString(pos, line, true)
}
}
}
@@ -553,10 +630,11 @@ 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
-// pending whitespace. writeCommentSuffix returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// pending whitespace. The writeCommentSuffix result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace
+// buffer.
//
-func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, droppedFF bool) {
for i, ch := range p.wsbuf {
switch ch {
case blank, vtab:
@@ -569,6 +647,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// but remember if we dropped any formfeeds
if needsLinebreak {
needsLinebreak = false
+ wroteNewline = true
} else {
if ch == formfeed {
droppedFF = true
@@ -581,7 +660,8 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// make sure we have a line break
if needsLinebreak {
- p.write([]byte{'\n'})
+ p.writeByte('\n', 1)
+ wroteNewline = true
}
return
@@ -590,24 +670,27 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// intersperseComments consumes all comments that appear before the next token
// tok and prints it together with the buffered whitespace (i.e., the whitespace
// that needs to be written before the next token). A heuristic is used to mix
-// the comments and whitespace. intersperseComments returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// the comments and whitespace. The intersperseComments result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace buffer.
//
-func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
var last *ast.Comment
- for ; p.commentBefore(next); p.cindex++ {
- for _, c := range p.comments[p.cindex].List {
- p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, tok.IsKeyword())
+ for p.commentBefore(next) {
+ for _, c := range p.comment.List {
+ p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok)
p.writeComment(c)
last = c
}
+ p.nextComment()
}
if last != nil {
- if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line {
- // the last comment is a /*-style comment and the next item
- // follows on the same line: separate with an extra blank
- p.write([]byte{' '})
+ // if the last comment is a /*-style comment and the next item
+ // follows on the same line but is not a comma or a "closing"
+ // token, add an extra blank for separation
+ if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
+ tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
+ p.writeByte(' ', 1)
}
// ensure that there is a line break after a //-style comment,
// before a closing '}' unless explicitly disabled, or at eof
@@ -621,13 +704,12 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
// no comment was written - we should never reach here since
// intersperseComments should not be called in that case
p.internalError("intersperseComments called without pending comments")
- return false
+ return
}
// whiteWhitespace writes the first n whitespace entries.
func (p *printer) writeWhitespace(n int) {
// write entries
- var data [1]byte
for i := 0; i < n; i++ {
switch ch := p.wsbuf[i]; ch {
case ignore:
@@ -659,8 +741,7 @@ func (p *printer) writeWhitespace(n int) {
}
fallthrough
default:
- data[0] = byte(ch)
- p.write(data[0:])
+ p.writeByte(byte(ch), 1)
}
}
@@ -676,6 +757,13 @@ func (p *printer) writeWhitespace(n int) {
// ----------------------------------------------------------------------------
// Printing interface
+// nlines limits n to maxNewlines.
+func nlimit(n int) int {
+ if n > maxNewlines {
+ n = maxNewlines
+ }
+ return n
+}
func mayCombine(prev token.Token, next byte) (b bool) {
switch prev {
@@ -707,21 +795,24 @@ func mayCombine(prev token.Token, next byte) (b bool) {
// printed, followed by the actual token.
//
func (p *printer) print(args ...interface{}) {
- for _, f := range args {
- next := p.pos // estimated position of next item
+ for _, arg := range args {
+ // information about the current arg
var data string
- var tok token.Token
+ var isLit bool
+ var impliedSemi bool // value for p.impliedSemi after this arg
- switch x := f.(type) {
+ switch x := arg.(type) {
case pmode:
// toggle printer mode
p.mode ^= x
+ continue
+
case whiteSpace:
if x == ignore {
// don't add ignore's to the buffer; they
// may screw up "correcting" unindents (see
// LabeledStmt)
- break
+ continue
}
i := len(p.wsbuf)
if i == cap(p.wsbuf) {
@@ -733,12 +824,27 @@ func (p *printer) print(args ...interface{}) {
}
p.wsbuf = p.wsbuf[0 : i+1]
p.wsbuf[i] = x
+ if x == newline || x == formfeed {
+ // newlines affect the current state (p.impliedSemi)
+ // and not the state after printing arg (impliedSemi)
+ // because comments can be interspersed before the arg
+ // in this case
+ p.impliedSemi = false
+ }
+ p.lastTok = token.ILLEGAL
+ continue
+
case *ast.Ident:
data = x.Name
- tok = token.IDENT
+ impliedSemi = true
+ p.lastTok = token.IDENT
+
case *ast.BasicLit:
- data = p.escape(x.Value)
- tok = x.Kind
+ data = x.Value
+ isLit = true
+ impliedSemi = true
+ p.lastTok = x.Kind
+
case token.Token:
s := x.String()
if mayCombine(p.lastTok, s[0]) {
@@ -755,50 +861,77 @@ func (p *printer) print(args ...interface{}) {
p.wsbuf[0] = ' '
}
data = s
- tok = x
+ // some keywords followed by a newline imply a semicolon
+ switch x {
+ case token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN,
+ token.INC, token.DEC, token.RPAREN, token.RBRACK, token.RBRACE:
+ impliedSemi = true
+ }
+ p.lastTok = x
+
case token.Pos:
if x.IsValid() {
- next = p.fset.Position(x) // accurate position of next item
+ p.pos = p.posFor(x) // accurate position of next item
}
- tok = p.lastTok
+ continue
+
+ case string:
+ // incorrect AST - print error message
+ data = x
+ isLit = true
+ impliedSemi = true
+ p.lastTok = token.STRING
+
default:
- fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
+ fmt.Fprintf(os.Stderr, "print: unsupported argument %v (%T)\n", arg, arg)
panic("go/printer type")
}
- p.lastTok = tok
- p.pos = next
-
- if data != "" {
- droppedFF := p.flush(next, tok)
-
- // intersperse extra newlines if present in the source
- // (don't do this in flush as it will cause extra newlines
- // at the end of a file) - use formfeeds if we dropped one
- // before
- p.writeNewlines(next.Line-p.pos.Line, droppedFF)
-
- p.writeItem(next, data)
+ // data != ""
+
+ next := p.pos // estimated/accurate position of next item
+ wroteNewline, droppedFF := p.flush(next, p.lastTok)
+
+ // intersperse extra newlines if present in the source and
+ // if they don't cause extra semicolons (don't do this in
+ // flush as it will cause extra newlines at the end of a file)
+ if !p.impliedSemi {
+ n := nlimit(next.Line - p.pos.Line)
+ // don't exceed maxNewlines if we already wrote one
+ if wroteNewline && n == maxNewlines {
+ n = maxNewlines - 1
+ }
+ if n > 0 {
+ ch := byte('\n')
+ if droppedFF {
+ ch = '\f' // use formfeed since we dropped one before
+ }
+ p.writeByte(ch, n)
+ impliedSemi = false
+ }
}
+
+ p.writeString(next, data, isLit)
+ p.impliedSemi = impliedSemi
}
}
-// commentBefore returns true iff the current comment occurs
-// before the next position in the source code.
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
//
-func (p *printer) commentBefore(next token.Position) bool {
- return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
+func (p *printer) commentBefore(next token.Position) (result bool) {
+ return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
}
-// Flush prints any pending comments and whitespace occurring
-// textually before the position of the next token tok. Flush
-// returns true if a pending formfeed character was dropped
-// from the whitespace buffer as a result of interspersing
-// comments.
+// flush prints any pending comments and whitespace occurring textually
+// before the position of the next token tok. The flush result indicates
+// if a newline was written or if a formfeed was dropped from the whitespace
+// buffer.
//
-func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
if p.commentBefore(next) {
// if there are comments before the next item, intersperse them
- droppedFF = p.intersperseComments(next, tok)
+ wroteNewline, droppedFF = p.intersperseComments(next, tok)
} else {
// otherwise, write any leftover whitespace
p.writeWhitespace(len(p.wsbuf))
@@ -806,6 +939,101 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
return
}
+// getNode returns the ast.CommentGroup associated with n, if any.
+func getDoc(n ast.Node) *ast.CommentGroup {
+ switch n := n.(type) {
+ case *ast.Field:
+ return n.Doc
+ case *ast.ImportSpec:
+ return n.Doc
+ case *ast.ValueSpec:
+ return n.Doc
+ case *ast.TypeSpec:
+ return n.Doc
+ case *ast.GenDecl:
+ return n.Doc
+ case *ast.FuncDecl:
+ return n.Doc
+ case *ast.File:
+ return n.Doc
+ }
+ return nil
+}
+
+func (p *printer) printNode(node interface{}) error {
+ // unpack *CommentedNode, if any
+ var comments []*ast.CommentGroup
+ if cnode, ok := node.(*CommentedNode); ok {
+ node = cnode.Node
+ comments = cnode.Comments
+ }
+
+ if comments != nil {
+ // commented node - restrict comment list to relevant range
+ n, ok := node.(ast.Node)
+ if !ok {
+ goto unsupported
+ }
+ beg := n.Pos()
+ end := n.End()
+ // if the node has associated documentation,
+ // include that commentgroup in the range
+ // (the comment list is sorted in the order
+ // of the comment appearance in the source code)
+ if doc := getDoc(n); doc != nil {
+ beg = doc.Pos()
+ }
+ // token.Pos values are global offsets, we can
+ // compare them directly
+ i := 0
+ for i < len(comments) && comments[i].End() < beg {
+ i++
+ }
+ j := i
+ for j < len(comments) && comments[j].Pos() < end {
+ j++
+ }
+ if i < j {
+ p.comments = comments[i:j]
+ }
+ } else if n, ok := node.(*ast.File); ok {
+ // use ast.File comments, if any
+ p.comments = n.Comments
+ }
+
+ // if there are no comments, use node comments
+ p.useNodeComments = p.comments == nil
+
+ // get comments ready for use
+ p.nextComment()
+
+ // format node
+ switch n := node.(type) {
+ case ast.Expr:
+ p.expr(n)
+ case ast.Stmt:
+ // A labeled statement will un-indent to position the
+ // label. Set indent to 1 so we don't get indent "underflow".
+ if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
+ p.indent = 1
+ }
+ p.stmt(n, false)
+ case ast.Decl:
+ p.decl(n)
+ case ast.Spec:
+ p.spec(n, 1, false)
+ case *ast.File:
+ p.file(n)
+ default:
+ goto unsupported
+ }
+
+ return nil
+
+unsupported:
+ return fmt.Errorf("go/printer: unsupported node type %T", node)
+}
+
// ----------------------------------------------------------------------------
// Trimmer
@@ -818,7 +1046,7 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
type trimmer struct {
output io.Writer
state int
- space bytes.Buffer
+ space []byte
}
// trimmer is implemented as a state machine.
@@ -829,13 +1057,20 @@ const (
inText // inside text
)
+func (p *trimmer) resetSpace() {
+ p.state = inSpace
+ p.space = p.space[0:0]
+}
+
// Design note: It is tempting to eliminate extra blanks occurring in
// whitespace in this function as it could simplify some
// of the blanks logic in the node printing functions.
// However, this would mess up any formatting done by
// the tabwriter.
-func (p *trimmer) Write(data []byte) (n int, err os.Error) {
+var aNewline = []byte("\n")
+
+func (p *trimmer) Write(data []byte) (n int, err error) {
// invariants:
// p.state == inSpace:
// p.space is unwritten
@@ -851,37 +1086,34 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
case inSpace:
switch b {
case '\t', ' ':
- p.space.WriteByte(b) // WriteByte returns no errors
+ p.space = append(p.space, b)
case '\n', '\f':
- p.space.Reset() // discard trailing space
- _, err = p.output.Write(newlines[0:1]) // write newline
+ p.resetSpace() // discard trailing space
+ _, err = p.output.Write(aNewline)
case tabwriter.Escape:
- _, err = p.output.Write(p.space.Bytes())
+ _, err = p.output.Write(p.space)
p.state = inEscape
m = n + 1 // +1: skip tabwriter.Escape
default:
- _, err = p.output.Write(p.space.Bytes())
+ _, err = p.output.Write(p.space)
p.state = inText
m = n
}
case inEscape:
if b == tabwriter.Escape {
_, err = p.output.Write(data[m:n])
- p.state = inSpace
- p.space.Reset()
+ p.resetSpace()
}
case inText:
switch b {
case '\t', ' ':
_, err = p.output.Write(data[m:n])
- p.state = inSpace
- p.space.Reset()
- p.space.WriteByte(b) // WriteByte returns no errors
+ p.resetSpace()
+ p.space = append(p.space, b)
case '\n', '\f':
_, err = p.output.Write(data[m:n])
- p.state = inSpace
- p.space.Reset()
- _, err = p.output.Write(newlines[0:1]) // write newline
+ p.resetSpace()
+ _, err = p.output.Write(aNewline)
case tabwriter.Escape:
_, err = p.output.Write(data[m:n])
p.state = inEscape
@@ -899,8 +1131,7 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
switch p.state {
case inEscape, inText:
_, err = p.output.Write(data[m:n])
- p.state = inSpace
- p.space.Reset()
+ p.resetSpace()
}
return
@@ -909,29 +1140,41 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
// ----------------------------------------------------------------------------
// Public interface
-// General printing is controlled with these Config.Mode flags.
+// A Mode value is a set of flags (or 0). They coontrol printing.
+type Mode uint
+
const (
- RawFormat uint = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
+ RawFormat Mode = 1 << iota // do not use a tabwriter; if set, UseSpaces is ignored
TabIndent // use tabs for indentation independent of UseSpaces
UseSpaces // use spaces instead of tabs for alignment
+ SourcePos // emit //line comments to preserve original source positions
)
// A Config node controls the output of Fprint.
type Config struct {
- Mode uint // default: 0
+ Mode Mode // 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) {
+func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (err error) {
+ // print node
+ var p printer
+ p.init(cfg, fset, nodeSizes)
+ if err = p.printNode(node); err != nil {
+ return
+ }
+ // print outstanding comments
+ p.impliedSemi = false // EOF acts like a newline
+ p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
+
// redirect output through a trimmer to eliminate trailing whitespace
// (Input to a tabwriter must be untrimmed since trailing tabs provide
// formatting information. The tabwriter could provide trimming
// functionality but no tabwriter is used when RawFormat is set.)
output = &trimmer{output: output}
- // setup tabwriter if needed and redirect output
- var tw *tabwriter.Writer
+ // redirect output through a tabwriter if necessary
if cfg.Mode&RawFormat == 0 {
minwidth := cfg.Tabwidth
@@ -946,67 +1189,42 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
twmode |= tabwriter.TabIndent
}
- tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode)
- output = tw
+ output = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode)
}
- // setup printer and print node
- var p printer
- p.init(output, cfg, fset, nodeSizes)
- go func() {
- switch n := node.(type) {
- case ast.Expr:
- p.useNodeComments = true
- p.expr(n, ignoreMultiLine)
- case ast.Stmt:
- p.useNodeComments = true
- // A labeled statement will un-indent to position the
- // label. Set indent to 1 so we don't get indent "underflow".
- if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt {
- p.indent = 1
- }
- p.stmt(n, false, ignoreMultiLine)
- case ast.Decl:
- p.useNodeComments = true
- p.decl(n, ignoreMultiLine)
- case ast.Spec:
- p.useNodeComments = true
- p.spec(n, 1, false, ignoreMultiLine)
- case *ast.File:
- p.comments = n.Comments
- p.useNodeComments = n.Comments == nil
- p.file(n)
- default:
- p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n)
- runtime.Goexit()
- }
- p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
- p.errors <- nil // no errors
- }()
- err := <-p.errors // wait for completion of goroutine
+ // write printer result via tabwriter/trimmer to output
+ if _, err = output.Write(p.output); err != nil {
+ return
+ }
// flush tabwriter, if any
- if tw != nil {
- tw.Flush() // ignore errors
+ if tw, _ := (output).(*tabwriter.Writer); tw != nil {
+ err = tw.Flush()
}
- return p.written, err
+ return
+}
+
+// A CommentedNode bundles an AST node and corresponding comments.
+// It may be provided as argument to any of the Fprint functions.
+//
+type CommentedNode struct {
+ Node interface{} // *ast.File, or ast.Expr, ast.Decl, ast.Spec, or ast.Stmt
+ Comments []*ast.CommentGroup
}
-// Fprint "pretty-prints" an AST node to output and returns the number
-// of bytes written and an error (if any) for a given configuration cfg.
+// Fprint "pretty-prints" an AST node to output for a given configuration cfg.
// Position information is interpreted relative to the file set fset.
-// The node type must be *ast.File, or assignment-compatible to ast.Expr,
-// ast.Decl, ast.Spec, or ast.Stmt.
+// The node type must be *ast.File, *CommentedNode, or assignment-compatible
+// to ast.Expr, ast.Decl, ast.Spec, or ast.Stmt.
//
-func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
+func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
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.
//
-func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error {
- _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't care about number of bytes written
- return err
+func Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
+ return (&Config{Tabwidth: 8}).Fprint(output, fset, node)
}
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index ff2d906b5..497d671f2 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -7,10 +7,10 @@ package printer
import (
"bytes"
"flag"
- "io/ioutil"
"go/ast"
"go/parser"
"go/token"
+ "io/ioutil"
"path/filepath"
"testing"
"time"
@@ -62,11 +62,18 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
// format source
var buf bytes.Buffer
- if _, err := cfg.Fprint(&buf, fset, prog); err != nil {
+ if err := cfg.Fprint(&buf, fset, prog); err != nil {
t.Error(err)
}
res := buf.Bytes()
+ // formatted source must be valid
+ if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
+ t.Error(err)
+ t.Logf("\n%s", res)
+ return
+ }
+
// update golden files if necessary
if *update {
if err := ioutil.WriteFile(golden, res, 0644); err != nil {
@@ -107,7 +114,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
// start a timer to produce a time-out signal
tc := make(chan int)
go func() {
- time.Sleep(10e9) // plenty of a safety margin, even for very slow machines
+ time.Sleep(10 * time.Second) // plenty of a safety margin, even for very slow machines
tc <- 0
}()
@@ -133,7 +140,7 @@ type entry struct {
mode checkMode
}
-// Use gotest -update to create/update the respective golden files.
+// Use go test -update to create/update the respective golden files.
var data = []entry{
{"empty.input", "empty.golden", 0},
{"comments.input", "comments.golden", 0},
@@ -147,15 +154,12 @@ var data = []entry{
}
func TestFiles(t *testing.T) {
- for i, e := range data {
+ for _, e := range data {
source := filepath.Join(dataDir, e.source)
golden := filepath.Join(dataDir, e.golden)
check(t, source, golden, e.mode)
// TODO(gri) check that golden is idempotent
//check(t, golden, golden, e.mode)
- if testing.Short() && i >= 3 {
- break
- }
}
}
@@ -171,14 +175,14 @@ func TestLineComments(t *testing.T) {
`
fset := token.NewFileSet()
- ast1, err1 := parser.ParseFile(fset, "", src, parser.ParseComments)
- if err1 != nil {
- panic(err1)
+ f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+ if err != nil {
+ panic(err) // error in test
}
var buf bytes.Buffer
fset = token.NewFileSet() // use the wrong file set
- Fprint(&buf, fset, ast1)
+ Fprint(&buf, fset, f)
nlines := 0
for _, ch := range buf.Bytes() {
@@ -190,5 +194,219 @@ func TestLineComments(t *testing.T) {
const expected = 3
if nlines < expected {
t.Errorf("got %d, expected %d\n", nlines, expected)
+ t.Errorf("result:\n%s", buf.Bytes())
+ }
+}
+
+// Verify that the printer can be invoked during initialization.
+func init() {
+ const name = "foobar"
+ var buf bytes.Buffer
+ if err := Fprint(&buf, fset, &ast.Ident{Name: name}); err != nil {
+ panic(err) // error in test
+ }
+ // in debug mode, the result contains additional information;
+ // ignore it
+ if s := buf.String(); !debug && s != name {
+ panic("got " + s + ", want " + name)
+ }
+}
+
+// Verify that the printer doesn't crash if the AST contains BadXXX nodes.
+func TestBadNodes(t *testing.T) {
+ const src = "package p\n("
+ const res = "package p\nBadDecl\n"
+ f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+ if err == nil {
+ t.Error("expected illegal program") // error in test
+ }
+ var buf bytes.Buffer
+ Fprint(&buf, fset, f)
+ if buf.String() != res {
+ t.Errorf("got %q, expected %q", buf.String(), res)
+ }
+}
+
+// testComment verifies that f can be parsed again after printing it
+// with its first comment set to comment at any possible source offset.
+func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) {
+ f.Comments[0].List[0] = comment
+ var buf bytes.Buffer
+ for offs := 0; offs <= srclen; offs++ {
+ buf.Reset()
+ // Printing f should result in a correct program no
+ // matter what the (incorrect) comment position is.
+ if err := Fprint(&buf, fset, f); err != nil {
+ t.Error(err)
+ }
+ if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil {
+ t.Fatalf("incorrect program for pos = %d:\n%s", comment.Slash, buf.String())
+ }
+ // Position information is just an offset.
+ // Move comment one byte down in the source.
+ comment.Slash++
+ }
+}
+
+// Verify that the printer produces always produces a correct program
+// even if the position information of comments introducing newlines
+// is incorrect.
+func TestBadComments(t *testing.T) {
+ const src = `
+// first comment - text and position changed by test
+package p
+import "fmt"
+const pi = 3.14 // rough circle
+var (
+ x, y, z int = 1, 2, 3
+ u, v float64
+)
+func fibo(n int) {
+ if n < 2 {
+ return n /* seed values */
+ }
+ return fibo(n-1) + fibo(n-2)
+}
+`
+
+ f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+ if err != nil {
+ t.Error(err) // error in test
+ }
+
+ comment := f.Comments[0].List[0]
+ pos := comment.Pos()
+ if fset.Position(pos).Offset != 1 {
+ t.Error("expected offset 1") // error in test
+ }
+
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "//-style comment"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style comment */"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style \n comment */"})
+ testComment(t, f, len(src), &ast.Comment{Slash: pos, Text: "/*-style comment \n\n\n */"})
+}
+
+type visitor chan *ast.Ident
+
+func (v visitor) Visit(n ast.Node) (w ast.Visitor) {
+ if ident, ok := n.(*ast.Ident); ok {
+ v <- ident
+ }
+ return v
+}
+
+// idents is an iterator that returns all idents in f via the result channel.
+func idents(f *ast.File) <-chan *ast.Ident {
+ v := make(visitor)
+ go func() {
+ ast.Walk(v, f)
+ close(v)
+ }()
+ return v
+}
+
+// identCount returns the number of identifiers found in f.
+func identCount(f *ast.File) int {
+ n := 0
+ for _ = range idents(f) {
+ n++
}
+ return n
+}
+
+// Verify that the SourcePos mode emits correct //line comments
+// by testing that position information for matching identifiers
+// is maintained.
+func TestSourcePos(t *testing.T) {
+ const src = `
+package p
+import ( "go/printer"; "math" )
+const pi = 3.14; var x = 0
+type t struct{ x, y, z int; u, v, w float32 }
+func (t *t) foo(a, b, c int) int {
+ return a*t.x + b*t.y +
+ // two extra lines here
+ // ...
+ c*t.z
+}
+`
+
+ // parse original
+ f1, err := parser.ParseFile(fset, "src", src, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // pretty-print original
+ var buf bytes.Buffer
+ err = (&Config{Mode: UseSpaces | SourcePos, Tabwidth: 8}).Fprint(&buf, fset, f1)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // parse pretty printed original
+ // (//line comments must be interpreted even w/o parser.ParseComments set)
+ f2, err := parser.ParseFile(fset, "", buf.Bytes(), 0)
+ if err != nil {
+ t.Fatalf("%s\n%s", err, buf.Bytes())
+ }
+
+ // At this point the position information of identifiers in f2 should
+ // match the position information of corresponding identifiers in f1.
+
+ // number of identifiers must be > 0 (test should run) and must match
+ n1 := identCount(f1)
+ n2 := identCount(f2)
+ if n1 == 0 {
+ t.Fatal("got no idents")
+ }
+ if n2 != n1 {
+ t.Errorf("got %d idents; want %d", n2, n1)
+ }
+
+ // verify that all identifiers have correct line information
+ i2range := idents(f2)
+ for i1 := range idents(f1) {
+ i2 := <-i2range
+
+ if i2.Name != i1.Name {
+ t.Errorf("got ident %s; want %s", i2.Name, i1.Name)
+ }
+
+ l1 := fset.Position(i1.Pos()).Line
+ l2 := fset.Position(i2.Pos()).Line
+ if l2 != l1 {
+ t.Errorf("got line %d; want %d for %s", l2, l1, i1.Name)
+ }
+ }
+
+ if t.Failed() {
+ t.Logf("\n%s", buf.Bytes())
+ }
+}
+
+// TextX is a skeleton test that can be filled in for debugging one-off cases.
+// Do not remove.
+func TestX(t *testing.T) {
+ const src = `
+package p
+func _() {}
+`
+ // parse original
+ f, err := parser.ParseFile(fset, "src", src, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // pretty-print original
+ var buf bytes.Buffer
+ if err = (&Config{Mode: UseSpaces, Tabwidth: 8}).Fprint(&buf, fset, f); err != nil {
+ t.Fatal(err)
+ }
+
+ // parse pretty printed original
+ if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil {
+ t.Fatalf("%s\n%s", err, buf.Bytes())
+ }
+
}
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index 7b332252c..d9aa2d82f 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -106,7 +106,7 @@ type S3 struct {
var x int // x
var ()
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
func f0() {
const pi = 3.14 // pi
var s1 struct{} /* an empty struct */ /* foo */
@@ -115,8 +115,9 @@ func f0() {
var s2 struct{} = struct{}{}
x := pi
}
+
//
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
//
func f1() {
f0()
@@ -167,6 +168,91 @@ func typeswitch(x interface{}) {
// this comment should not be indented
}
+//
+// Indentation of comments after possibly indented multi-line constructs
+// (test cases for issue 3147).
+//
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+ _ = 0
+}
+
+// Test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // should be aligned with f()
+ f()
+}
+
+// Modified test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // may not be aligned with f() (source is not aligned)
+ f()
+}
+
+//
+// Test cases for alignment of lines in general comments.
+//
+
func _() {
/* freestanding comment
aligned line
@@ -403,17 +489,18 @@ func _() {
*/
}
-// Some interesting interspersed comments
+// Some interesting interspersed comments.
+// See below for more common cases.
func _( /* this */ x /* is */ /* an */ int) {
}
-func _( /* no params */ ) {}
+func _( /* no params */) {}
func _() {
- f( /* no args */ )
+ f( /* no args */)
}
-func ( /* comment1 */ T /* comment2 */ ) _() {}
+func ( /* comment1 */ T /* comment2 */) _() {}
func _() { /* one-line functions with comments are formatted as multi-line functions */
}
@@ -424,11 +511,32 @@ func _() {
}
func _() {
- _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
+ _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
+}
+
+// Test cases from issue 1542:
+// Comments must not be placed before commas and cause invalid programs.
+func _() {
+ var a = []int{1, 2 /*jasldf*/}
+ _ = a
+}
+
+func _() {
+ var a = []int{1, 2}/*jasldf
+ */
+
+ _ = a
+}
+
+func _() {
+ var a = []int{1, 2}// jasldf
+
+ _ = a
}
-// Comments immediately adjacent to punctuation (for which the go/printer
-// may only have estimated position information) must remain after the punctuation.
+// Comments immediately adjacent to punctuation followed by a newline
+// remain after the punctuation (looks better and permits alignment of
+// comments).
func _() {
_ = T{
1, // comment after comma
@@ -458,6 +566,54 @@ func _() {
}
}
+// If there is no newline following punctuation, commas move before the punctuation.
+// This way, commas interspersed in lists stay with the respective expression.
+func f(x /* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
+ f(x /* comment */, y)
+ f(x, /* comment */
+ y)
+ f(
+ x, /* comment */
+ )
+}
+
+func g(
+ x int, /* comment */
+) {
+}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+func _() {
+ for a /* comment */, b := range x {
+ }
+}
+
+// Print line directives correctly.
+
+// The following is a legal line directive.
+//line foo:1
+func _() {
+ _ = 0
+ // The following is a legal line directive. It must not be indented:
+//line foo:2
+ _ = 1
+
+ // The following is not a legal line directive (it doesn't start in column 1):
+ //line foo:2
+ _ = 2
+
+ // The following is not a legal line directive (negative line number):
+ //line foo:-3
+ _ = 3
+}
+
// Line comments with tabs
func _() {
var finput *bufio.Reader // input file
diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
index 2a9a86b68..6084b3fe4 100644
--- a/src/pkg/go/printer/testdata/comments.input
+++ b/src/pkg/go/printer/testdata/comments.input
@@ -107,7 +107,7 @@ var x int // x
var ()
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
func f0() {
const pi = 3.14 // pi
var s1 struct {} /* an empty struct */ /* foo */
@@ -117,7 +117,7 @@ func f0() {
x := pi
}
//
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
//
func f1() {
f0()
@@ -130,7 +130,7 @@ func f1() {
func _() {
- // this comment should be properly indented
+// this comment should be properly indented
}
@@ -171,6 +171,91 @@ func typeswitch(x interface{}) {
// this comment should not be indented
}
+//
+// Indentation of comments after possibly indented multi-line constructs
+// (test cases for issue 3147).
+//
+
+func _() {
+ s := 1 +
+ 2
+// should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+// should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+}
+
+func _() {
+ s := 1 +
+ 2 // comment
+
+ // should be indented like s
+ _ = 0
+}
+
+func _() {
+ s := 1 +
+ 2
+
+ // should be indented like s
+ _ = 0
+}
+
+// Test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // should be aligned with f()
+ f()
+}
+
+// Modified test case from issue 3147.
+func f() {
+ templateText := "a" + // A
+ "b" + // B
+ "c" // C
+
+ // may not be aligned with f() (source is not aligned)
+ f()
+}
+
+//
+// Test cases for alignment of lines in general comments.
+//
+
func _() {
/* freestanding comment
aligned line
@@ -410,7 +495,8 @@ func _() {
}
-// Some interesting interspersed comments
+// Some interesting interspersed comments.
+// See below for more common cases.
func _(/* this */x/* is *//* an */ int) {
}
@@ -432,9 +518,30 @@ func _() {
_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
}
+// Test cases from issue 1542:
+// Comments must not be placed before commas and cause invalid programs.
+func _() {
+ var a = []int{1, 2, /*jasldf*/
+ }
+ _ = a
+}
+
+func _() {
+ var a = []int{1, 2, /*jasldf
+ */
+ }
+ _ = a
+}
-// Comments immediately adjacent to punctuation (for which the go/printer
-// may only have estimated position information) must remain after the punctuation.
+func _() {
+ var a = []int{1, 2, // jasldf
+ }
+ _ = a
+}
+
+// Comments immediately adjacent to punctuation followed by a newline
+// remain after the punctuation (looks better and permits alignment of
+// comments).
func _() {
_ = T{
1, // comment after comma
@@ -466,6 +573,50 @@ func _() {
}
}
+// If there is no newline following punctuation, commas move before the punctuation.
+// This way, commas interspersed in lists stay with the respective expression.
+func f(x/* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
+ f(x /* comment */, y)
+ f(x /* comment */,
+ y)
+ f(
+ x /* comment */,
+ )
+}
+
+func g(
+ x int /* comment */,
+) {}
+
+type _ struct {
+ a, b /* comment */, c int
+}
+
+type _ struct { a, b /* comment */, c int }
+
+func _() {
+ for a /* comment */, b := range x {
+ }
+}
+
+// Print line directives correctly.
+
+// The following is a legal line directive.
+//line foo:1
+func _() {
+ _ = 0
+// The following is a legal line directive. It must not be indented:
+//line foo:2
+ _ = 1
+
+// The following is not a legal line directive (it doesn't start in column 1):
+ //line foo:2
+ _ = 2
+
+// The following is not a legal line directive (negative line number):
+//line foo:-3
+ _ = 3
+}
// Line comments with tabs
func _() {
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 970533e8c..71ed32ed1 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -83,13 +83,13 @@ import (
// more import examples
import (
"xxx"
- "much longer name" // comment
- "short name" // comment
+ "much_longer_name" // comment
+ "short_name" // comment
)
import (
_ "xxx"
- "much longer name" // comment
+ "much_longer_name" // comment
)
import (
@@ -115,6 +115,18 @@ import _ "io"
var _ int
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+
+// T2 comment
+type T2 struct {
+} // should be a two-line struct
+
+// T3 comment
+type T2 struct {
+} // should be a two-line struct
+
// printing of constant literals
const (
_ = "foobar"
@@ -286,6 +298,15 @@ type _ struct {
}
}
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{}
+type _ struct {
+}
+
+type _ interface{}
+type _ interface {
+}
+
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
@@ -545,6 +566,17 @@ var (
a4, b4, c4 int // this line should be indented
)
+// Test case from issue 3304: multi-line declarations must end
+// a formatting section and not influence indentation of the
+// next line.
+var (
+ minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
+ "minimum time window between two refreshes for a given user.")
+ x = flag.Int64("refresh_user_rollout_percent", 100,
+ "temporary flag to ramp up the refresh user rpc")
+ aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
+)
+
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{},
@@ -692,56 +724,137 @@ func _(x ...chan int)
// these parameter lists must remain multi-line since they are multi-line in the source
func _(bool,
-int) {
+ int) {
}
func _(x bool,
-y int) {
+ y int) {
}
func _(x,
-y bool) {
+ y bool) {
}
func _(bool, // comment
-int) {
+ int) {
}
func _(x bool, // comment
-y int) {
+ y int) {
}
func _(x, // comment
-y bool) {
+ y bool) {
}
func _(bool, // comment
-// comment
-int) {
+ // comment
+ int) {
}
func _(x bool, // comment
-// comment
-y int) {
+ // comment
+ y int) {
}
func _(x, // comment
-// comment
-y bool) {
+ // comment
+ y bool) {
}
func _(bool,
-// comment
-int) {
+ // comment
+ int) {
}
func _(x bool,
-// comment
-y int) {
+ // comment
+ y int) {
}
func _(x,
-// comment
-y bool) {
+ // comment
+ y bool) {
}
func _(x, // comment
-y, // comment
-z bool) {
+ y, // comment
+ z bool) {
}
func _(x, // comment
-y, // comment
-z bool) {
+ y, // comment
+ z bool) {
}
func _(x int, // comment
-y float, // comment
-z bool) {
+ y float, // comment
+ z bool) {
+}
+
+// properly indent multi-line signatures
+func ManageStatus(in <-chan *Status, req <-chan Request,
+ stat chan<- *TargetInfo,
+ TargetHistorySize int) {
+}
+
+func MultiLineSignature0(
+ a, b, c int,
+) {
+}
+
+func MultiLineSignature1(
+ a, b, c int,
+ u, v, w float,
+) {
+}
+
+func MultiLineSignature2(
+ a, b,
+ c int,
+) {
+}
+
+func MultiLineSignature3(
+ a, b,
+ c int, u, v,
+ w float,
+ x ...int) {
+}
+
+func MultiLineSignature4(
+ a, b, c int,
+ u, v,
+ w float,
+ x ...int) {
+}
+
+func MultiLineSignature5(
+ a, b, c int,
+ u, v, w float,
+ p, q,
+ r string,
+ x ...int) {
+}
+
+// make sure it also works for methods in interfaces
+type _ interface {
+ MultiLineSignature0(
+ a, b, c int,
+ )
+
+ MultiLineSignature1(
+ a, b, c int,
+ u, v, w float,
+ )
+
+ MultiLineSignature2(
+ a, b,
+ c int,
+ )
+
+ MultiLineSignature3(
+ a, b,
+ c int, u, v,
+ w float,
+ x ...int)
+
+ MultiLineSignature4(
+ a, b, c int,
+ u, v,
+ w float,
+ x ...int)
+
+ MultiLineSignature5(
+ a, b, c int,
+ u, v, w float,
+ p, q,
+ r string,
+ x ...int)
}
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index c6134096b..d74cff25d 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -84,13 +84,13 @@ import (
// more import examples
import (
"xxx"
- "much longer name" // comment
- "short name" // comment
+ "much_longer_name" // comment
+ "short_name" // comment
)
import (
_ "xxx"
- "much longer name" // comment
+ "much_longer_name" // comment
)
import (
@@ -115,6 +115,20 @@ import (
import _ "io"
var _ int
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+// T2 comment
+type T2 struct {
+} // should be a two-line struct
+
+
+// T3 comment
+type T2 struct {
+
+
+} // should be a two-line struct
+
// printing of constant literals
const (
@@ -293,6 +307,18 @@ type _ struct {
}
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{ }
+type _ struct {
+
+}
+
+type _ interface{ }
+type _ interface {
+
+}
+
+
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
@@ -551,6 +577,16 @@ c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented
)
+// Test case from issue 3304: multi-line declarations must end
+// a formatting section and not influence indentation of the
+// next line.
+var (
+ minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
+ "minimum time window between two refreshes for a given user.")
+ x = flag.Int64("refresh_user_rollout_percent", 100,
+ "temporary flag to ramp up the refresh user rpc")
+ aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
+)
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
@@ -755,3 +791,79 @@ func _(x int, // comment
y float, // comment
z bool) {
}
+
+
+// properly indent multi-line signatures
+func ManageStatus(in <-chan *Status, req <-chan Request,
+stat chan<- *TargetInfo,
+TargetHistorySize int) {
+}
+
+func MultiLineSignature0(
+a, b, c int,
+) {}
+
+func MultiLineSignature1(
+a, b, c int,
+u, v, w float,
+) {}
+
+func MultiLineSignature2(
+a, b,
+c int,
+) {}
+
+func MultiLineSignature3(
+a, b,
+c int, u, v,
+w float,
+ x ...int) {}
+
+func MultiLineSignature4(
+a, b, c int,
+u, v,
+w float,
+ x ...int) {}
+
+func MultiLineSignature5(
+a, b, c int,
+u, v, w float,
+p, q,
+r string,
+ x ...int) {}
+
+// make sure it also works for methods in interfaces
+type _ interface {
+MultiLineSignature0(
+a, b, c int,
+)
+
+MultiLineSignature1(
+a, b, c int,
+u, v, w float,
+)
+
+MultiLineSignature2(
+a, b,
+c int,
+)
+
+MultiLineSignature3(
+a, b,
+c int, u, v,
+w float,
+ x ...int)
+
+MultiLineSignature4(
+a, b, c int,
+u, v,
+w float,
+ x ...int)
+
+MultiLineSignature5(
+a, b, c int,
+u, v, w float,
+p, q,
+r string,
+ x ...int)
+}
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
index d0cf24ad6..45fa4d97a 100644
--- a/src/pkg/go/printer/testdata/expressions.golden
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -545,7 +545,7 @@ func _() {
// handle multiline argument list correctly
_ = new(T).
foo(
- 1).
+ 1).
foo(2)
_ = new(T).foo(
@@ -587,12 +587,12 @@ func _() {
_ = new(T).
Field.
Array[3+
- 4].
+ 4].
Table["foo"].
Blob.(*Type).
Slices[1:4].
Method(1, 2,
- 3).
+ 3).
Thingy
_ = a.b.c
@@ -625,3 +625,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/src/pkg/go/printer/testdata/expressions.input b/src/pkg/go/printer/testdata/expressions.input
index d11314983..f545c6605 100644
--- a/src/pkg/go/printer/testdata/expressions.input
+++ b/src/pkg/go/printer/testdata/expressions.input
@@ -654,3 +654,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
index d7819a3ba..87a4b0083 100644
--- a/src/pkg/go/printer/testdata/expressions.raw
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -545,7 +545,7 @@ func _() {
// handle multiline argument list correctly
_ = new(T).
foo(
- 1).
+ 1).
foo(2)
_ = new(T).foo(
@@ -587,12 +587,12 @@ func _() {
_ = new(T).
Field.
Array[3+
- 4].
+ 4].
Table["foo"].
Blob.(*Type).
Slices[1:4].
Method(1, 2,
- 3).
+ 3).
Thingy
_ = a.b.c
@@ -625,3 +625,25 @@ func f() {
log.Fatal(err)
}
}
+
+// Handle multi-line argument lists ending in ... correctly.
+// Was issue 3130.
+func _() {
+ _ = append(s, a...)
+ _ = append(
+ s, a...)
+ _ = append(s,
+ a...)
+ _ = append(
+ s,
+ a...)
+ _ = append(s, a...,
+ )
+ _ = append(s,
+ a...,
+ )
+ _ = append(
+ s,
+ a...,
+ )
+}
diff --git a/src/pkg/go/printer/testdata/linebreaks.golden b/src/pkg/go/printer/testdata/linebreaks.golden
index be780da67..006cf1718 100644
--- a/src/pkg/go/printer/testdata/linebreaks.golden
+++ b/src/pkg/go/printer/testdata/linebreaks.golden
@@ -220,4 +220,56 @@ testLoop:
}
}
+// Respect line breaks in function calls.
+func _() {
+ f(x)
+ f(x,
+ x)
+ f(x,
+ x,
+ )
+ f(
+ x,
+ x)
+ f(
+ x,
+ x,
+ )
+}
+
+// Respect line breaks in function declarations.
+func _(x T) {}
+func _(x T,
+ y T) {
+}
+func _(x T,
+ y T,
+) {
+}
+func _(
+ x T,
+ y T) {
+}
+func _(
+ x T,
+ y T,
+) {
+}
+
+// Example from issue 2597.
+func ManageStatus0(
+ in <-chan *Status,
+ req <-chan Request,
+ stat chan<- *TargetInfo,
+ TargetHistorySize int) {
+}
+
+func ManageStatus1(
+ in <-chan *Status,
+ req <-chan Request,
+ stat chan<- *TargetInfo,
+ TargetHistorySize int,
+) {
+}
+
// There should be exactly one linebreak after this comment.
diff --git a/src/pkg/go/printer/testdata/linebreaks.input b/src/pkg/go/printer/testdata/linebreaks.input
index 457b491e6..e782bb044 100644
--- a/src/pkg/go/printer/testdata/linebreaks.input
+++ b/src/pkg/go/printer/testdata/linebreaks.input
@@ -220,4 +220,52 @@ testLoop:
}
}
+// Respect line breaks in function calls.
+func _() {
+ f(x)
+ f(x,
+ x)
+ f(x,
+ x,
+ )
+ f(
+ x,
+ x)
+ f(
+ x,
+ x,
+ )
+}
+
+// Respect line breaks in function declarations.
+func _(x T) {}
+func _(x T,
+ y T) {}
+func _(x T,
+ y T,
+) {}
+func _(
+ x T,
+ y T) {}
+func _(
+ x T,
+ y T,
+) {}
+
+// Example from issue 2597.
+func ManageStatus0(
+ in <-chan *Status,
+ req <-chan Request,
+ stat chan<- *TargetInfo,
+ TargetHistorySize int) {
+}
+
+func ManageStatus1(
+ in <-chan *Status,
+ req <-chan Request,
+ stat chan<- *TargetInfo,
+ TargetHistorySize int,
+) {
+}
+
// There should be exactly one linebreak after this comment.
diff --git a/src/pkg/go/printer/testdata/parser.go b/src/pkg/go/printer/testdata/parser.go
index 2d27af499..dba8bbd43 100644
--- a/src/pkg/go/printer/testdata/parser.go
+++ b/src/pkg/go/printer/testdata/parser.go
@@ -6,7 +6,7 @@
// provided in a variety of forms (see the various Parse* functions); the
// output is an abstract syntax tree (AST) representing the Go source. The
// parser is invoked through one of the Parse* functions.
-//
+
package parser
import (
@@ -52,7 +52,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
@@ -1999,7 +1999,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
if par.NumFields() != 1 {
p.errorExpected(pos, "exactly one receiver")
// TODO determine a better range for BadExpr below
- par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ par.List = []*ast.Field{{Type: &ast.BadExpr{pos, pos}}}
return par
}
@@ -2008,7 +2008,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
base := deref(recv.Type)
if _, isIdent := base.(*ast.Ident); !isIdent {
p.errorExpected(base.Pos(), "(unqualified) identifier")
- par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
+ par.List = []*ast.Field{{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
}
return par
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
index a6d85107f..4d70617bf 100644
--- a/src/pkg/go/printer/testdata/statements.golden
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -8,6 +8,125 @@ var expr bool
func use(x interface{}) {}
+// Formatting of multi-line return statements.
+func _f() {
+ return
+ return x, y, z
+ return T{}
+ return T{1, 2, 3},
+ x, y, z
+ return T{1, 2, 3},
+ x, y,
+ z
+ return T{1,
+ 2,
+ 3}
+ return T{1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ 3}
+ return T{
+ 1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ T{1, 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2,
+ 3},
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ },
+ nil
+ return x + y +
+ z
+ return func() {}
+ return func() {
+ _ = 0
+ }, T{
+ 1, 2,
+ }
+ return func() {
+ _ = 0
+ }
+ return func() T {
+ return T{
+ 1, 2,
+ }
+ }
+}
+
+// Formatting of multi-line returns: test cases from issue 1207.
+func F() (*T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ nil
+}
+
+func G() (*T, *T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ &T{
+ X: 3,
+ Y: 4,
+ },
+ nil
+}
+
+func _() interface{} {
+ return &fileStat{
+ name: basename(file.name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSysFromFI(&d),
+ }, nil
+}
+
// Formatting of if-statement headers.
func _() {
if true {
@@ -271,7 +390,6 @@ func _() {
// Known bug: The first use call may have more than one empty line before
// (see go/printer/nodes.go, func linebreak).
-
use(x)
if x < x {
@@ -386,7 +504,6 @@ L: // A comment on the same line as the label, followed by a single empty line.
// Known bug: There may be more than one empty line before MoreCode()
// (see go/printer/nodes.go, func linebreak).
-
MoreCode()
}
diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input
index 86a753c5a..bd03bc98b 100644
--- a/src/pkg/go/printer/testdata/statements.input
+++ b/src/pkg/go/printer/testdata/statements.input
@@ -8,6 +8,125 @@ var expr bool
func use(x interface{}) {}
+// Formatting of multi-line return statements.
+func _f() {
+ return
+ return x, y, z
+ return T{}
+ return T{1, 2, 3},
+ x, y, z
+ return T{1, 2, 3},
+ x, y,
+ z
+ return T{1,
+ 2,
+ 3}
+ return T{1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ 3}
+ return T{
+ 1,
+ 2,
+ 3,
+ }
+ return T{
+ 1,
+ T{1, 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2, 3},
+ 3,
+ }
+ return T{
+ 1,
+ T{1,
+ 2,
+ 3},
+ 3,
+ }
+ return T{
+ 1,
+ 2,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ },
+ nil
+ return x + y +
+ z
+ return func() {}
+ return func() {
+ _ = 0
+ }, T{
+ 1, 2,
+ }
+ return func() {
+ _ = 0
+ }
+ return func() T {
+ return T {
+ 1, 2,
+ }
+ }
+}
+
+// Formatting of multi-line returns: test cases from issue 1207.
+func F() (*T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ nil
+}
+
+func G() (*T, *T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ &T{
+ X: 3,
+ Y: 4,
+ },
+ nil
+}
+
+func _() interface{} {
+ return &fileStat{
+ name: basename(file.name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSysFromFI(&d),
+ }, nil
+}
+
// Formatting of if-statement headers.
func _() {
if true {}
diff --git a/src/pkg/go/scanner/Makefile b/src/pkg/go/scanner/Makefile
deleted file mode 100644
index 453faac00..000000000
--- a/src/pkg/go/scanner/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=go/scanner
-GOFILES=\
- errors.go\
- scanner.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/scanner/errors.go b/src/pkg/go/scanner/errors.go
index a0927e416..8a75a9650 100644
--- a/src/pkg/go/scanner/errors.go
+++ b/src/pkg/go/scanner/errors.go
@@ -8,48 +8,21 @@ import (
"fmt"
"go/token"
"io"
- "os"
"sort"
)
-// An implementation of an ErrorHandler may be provided to the Scanner.
-// If a syntax error is encountered and a handler was installed, Error
-// is called with a position and an error message. The position points
-// to the beginning of the offending token.
-//
-type ErrorHandler interface {
- Error(pos token.Position, msg string)
-}
-
-// ErrorVector implements the ErrorHandler interface. It maintains a list
-// of errors which can be retrieved with GetErrorList and GetError. The
-// zero value for an ErrorVector is an empty ErrorVector ready to use.
-//
-// A common usage pattern is to embed an ErrorVector alongside a
-// scanner in a data structure that uses the scanner. By passing a
-// reference to an ErrorVector to the scanner's Init call, default
-// error handling is obtained.
-//
-type ErrorVector struct {
- errors []*Error
-}
-
-// Reset resets an ErrorVector to no errors.
-func (h *ErrorVector) Reset() { h.errors = h.errors[:0] }
-
-// ErrorCount returns the number of errors collected.
-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
-// token, and the error condition is described by Msg.
+// In an ErrorList, an error is represented by an *Error.
+// The position Pos, if valid, points to the beginning of
+// the offending token, and the error condition is described
+// by Msg.
//
type Error struct {
Pos token.Position
Msg string
}
-func (e *Error) String() string {
+// Error implements the error interface.
+func (e Error) Error() string {
if e.Pos.Filename != "" || e.Pos.IsValid() {
// don't print "<unknown position>"
// TODO(gri) reconsider the semantics of Position.IsValid
@@ -58,9 +31,19 @@ func (e *Error) String() string {
return e.Msg
}
-// An ErrorList is a (possibly sorted) list of Errors.
+// ErrorList is a list of *Errors.
+// The zero value for an ErrorList is an empty ErrorList ready to use.
+//
type ErrorList []*Error
+// Add adds an Error with given position and error message to an ErrorList.
+func (p *ErrorList) Add(pos token.Position, msg string) {
+ *p = append(*p, &Error{pos, msg})
+}
+
+// Reset resets an ErrorList to no errors.
+func (p *ErrorList) Reset() { *p = (*p)[0:0] }
+
// 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] }
@@ -85,79 +68,54 @@ func (p ErrorList) Less(i, j int) bool {
return false
}
-func (p ErrorList) String() string {
- switch len(p) {
- case 0:
- return "unspecified error"
- case 1:
- return p[0].String()
- }
- return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
-}
-
-// These constants control the construction of the ErrorList
-// returned by GetErrors.
+// Sort sorts an ErrorList. *Error entries are sorted by position,
+// other errors are sorted by error message, and before any *Error
+// entry.
//
-const (
- Raw = iota // leave error list unchanged
- Sorted // sort error list by file, line, and column number
- NoMultiples // sort error list and leave only the first error per line
-)
-
-// GetErrorList returns the list of errors collected by an ErrorVector.
-// The construction of the ErrorList returned is controlled by the mode
-// parameter. If there are no errors, the result is nil.
-//
-func (h *ErrorVector) GetErrorList(mode int) ErrorList {
- if len(h.errors) == 0 {
- return nil
- }
-
- list := make(ErrorList, len(h.errors))
- copy(list, h.errors)
-
- if mode >= Sorted {
- sort.Sort(list)
- }
+func (p ErrorList) Sort() {
+ sort.Sort(p)
+}
- if mode >= NoMultiples {
- var last token.Position // initial last.Line is != any legal error line
- i := 0
- for _, e := range list {
- if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
- last = e.Pos
- list[i] = e
- i++
- }
+// RemoveMultiples sorts an ErrorList and removes all but the first error per line.
+func (p *ErrorList) RemoveMultiples() {
+ sort.Sort(p)
+ var last token.Position // initial last.Line is != any legal error line
+ i := 0
+ for _, e := range *p {
+ if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
+ last = e.Pos
+ (*p)[i] = e
+ i++
}
- list = list[0:i]
}
-
- return list
+ (*p) = (*p)[0:i]
}
-// 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 len(h.errors) == 0 {
- return nil
+// An ErrorList implements the error interface.
+func (p ErrorList) Error() string {
+ switch len(p) {
+ case 0:
+ return "no errors"
+ case 1:
+ return p[0].Error()
}
-
- return h.GetErrorList(mode)
+ return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1)
}
-// ErrorVector implements the ErrorHandler interface.
-func (h *ErrorVector) Error(pos token.Position, msg string) {
- h.errors = append(h.errors, &Error{pos, msg})
+// Err returns an error equivalent to this error list.
+// If the list is empty, Err returns nil.
+func (p ErrorList) Err() error {
+ if len(p) == 0 {
+ return nil
+ }
+ return p
}
// PrintError is a utility function that prints a list of errors to w,
// one error per line, if the err parameter is an ErrorList. Otherwise
// it prints the err string.
//
-func PrintError(w io.Writer, err os.Error) {
+func PrintError(w io.Writer, err error) {
if list, ok := err.(ErrorList); ok {
for _, e := range list {
fmt.Fprintf(w, "%s\n", e)
diff --git a/src/pkg/go/scanner/example_test.go b/src/pkg/go/scanner/example_test.go
new file mode 100644
index 000000000..9004a4ad3
--- /dev/null
+++ b/src/pkg/go/scanner/example_test.go
@@ -0,0 +1,46 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scanner_test
+
+import (
+ "fmt"
+ "go/scanner"
+ "go/token"
+)
+
+func ExampleScanner_Scan() {
+ // src is the input that we want to tokenize.
+ src := []byte("cos(x) + 1i*sin(x) // Euler")
+
+ // Initialize the scanner.
+ var s scanner.Scanner
+ fset := token.NewFileSet() // positions are relative to fset
+ file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
+ s.Init(file, src, nil /* no error handler */, scanner.ScanComments)
+
+ // Repeated calls to Scan yield the token sequence found in the input.
+ for {
+ pos, tok, lit := s.Scan()
+ if tok == token.EOF {
+ break
+ }
+ fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)
+ }
+
+ // output:
+ // 1:1 IDENT "cos"
+ // 1:4 ( ""
+ // 1:5 IDENT "x"
+ // 1:6 ) ""
+ // 1:8 + ""
+ // 1:10 IMAG "1i"
+ // 1:12 * ""
+ // 1:13 IDENT "sin"
+ // 1:16 ( ""
+ // 1:17 IDENT "x"
+ // 1:18 ) ""
+ // 1:20 ; "\n"
+ // 1:20 COMMENT "// Euler"
+}
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 7f3dd2373..da508747a 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -2,21 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package scanner implements a scanner for Go source text. Takes a []byte as
-// source which can then be tokenized through repeated calls to the Scan
-// function. Typical use:
-//
-// var s Scanner
-// fset := token.NewFileSet() // position information is relative to fset
-// file := fset.AddFile(filename, fset.Base(), len(src)) // register file
-// s.Init(file, src, nil /* no error handler */, 0)
-// for {
-// pos, tok, lit := s.Scan()
-// if tok == token.EOF {
-// break
-// }
-// // do something here with pos, tok, and lit
-// }
+// Package scanner implements a scanner for Go source text.
+// It takes a []byte as source which can then be tokenized
+// through repeated calls to the Scan method.
//
package scanner
@@ -27,9 +15,16 @@ import (
"path/filepath"
"strconv"
"unicode"
- "utf8"
+ "unicode/utf8"
)
+// An ErrorHandler may be provided to Scanner.Init. If a syntax error is
+// encountered and a handler was installed, the handler is called with a
+// position and an error message. The position points to the beginning of
+// the offending token.
+//
+type ErrorHandler func(pos token.Position, msg string)
+
// 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.
@@ -40,10 +35,10 @@ type Scanner struct {
dir string // directory portion of file.Name()
src []byte // source
err ErrorHandler // error reporting; or nil
- mode uint // scanning mode
+ mode Mode // scanning mode
// scanning state
- ch int // current character
+ ch rune // current character
offset int // character offset
rdOffset int // reading offset (position after current character)
lineOffset int // current line offset
@@ -53,94 +48,95 @@ type Scanner struct {
ErrorCount int // number of errors encountered
}
-// Read the next Unicode char into S.ch.
-// S.ch < 0 means end-of-file.
+// Read the next Unicode char into s.ch.
+// s.ch < 0 means end-of-file.
//
-func (S *Scanner) next() {
- if S.rdOffset < len(S.src) {
- S.offset = S.rdOffset
- if S.ch == '\n' {
- S.lineOffset = S.offset
- S.file.AddLine(S.offset)
+func (s *Scanner) next() {
+ if s.rdOffset < len(s.src) {
+ s.offset = s.rdOffset
+ if s.ch == '\n' {
+ s.lineOffset = s.offset
+ s.file.AddLine(s.offset)
}
- r, w := int(S.src[S.rdOffset]), 1
+ r, w := rune(s.src[s.rdOffset]), 1
switch {
case r == 0:
- S.error(S.offset, "illegal character NUL")
+ s.error(s.offset, "illegal character NUL")
case r >= 0x80:
// not ASCII
- r, w = utf8.DecodeRune(S.src[S.rdOffset:])
+ r, w = utf8.DecodeRune(s.src[s.rdOffset:])
if r == utf8.RuneError && w == 1 {
- S.error(S.offset, "illegal UTF-8 encoding")
+ s.error(s.offset, "illegal UTF-8 encoding")
}
}
- S.rdOffset += w
- S.ch = r
+ s.rdOffset += w
+ s.ch = r
} else {
- S.offset = len(S.src)
- if S.ch == '\n' {
- S.lineOffset = S.offset
- S.file.AddLine(S.offset)
+ s.offset = len(s.src)
+ if s.ch == '\n' {
+ s.lineOffset = s.offset
+ s.file.AddLine(s.offset)
}
- S.ch = -1 // eof
+ s.ch = -1 // eof
}
}
-// The mode parameter to the Init function is a set of flags (or 0).
+// A mode value is set of flags (or 0).
// They control scanner behavior.
//
+type Mode uint
+
const (
- ScanComments = 1 << iota // return comments as COMMENT tokens
- AllowIllegalChars // do not report an error for illegal chars
- InsertSemis // automatically insert semicolons
+ ScanComments Mode = 1 << iota // return comments as COMMENT tokens
+ dontInsertSemis // do not automatically insert semicolons - for testing only
)
-// Init prepares the scanner S to tokenize the text src by setting the
+// Init prepares the scanner s to tokenize the text src by setting the
// scanner at the beginning of src. The scanner uses the file set file
// for position information and it adds line information for each line.
// It is ok to re-use the same file when re-scanning the same file as
// line information which is already present is ignored. Init causes a
// panic if the file size does not match the src size.
//
-// Calls to Scan will use the error handler err if they encounter a
+// Calls to Scan will invoke the error handler err if they encounter a
// syntax error and err is not nil. Also, for each error encountered,
// the Scanner field ErrorCount is incremented by one. The mode parameter
-// determines how comments, illegal characters, and semicolons are handled.
+// determines how comments are handled.
//
// Note that Init may call err if there is an error in the first character
// of the file.
//
-func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint) {
+func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
// Explicitly initialize all fields since a scanner may be reused.
if file.Size() != len(src) {
- panic("file size does not match src len")
- }
- S.file = file
- S.dir, _ = filepath.Split(file.Name())
- S.src = src
- S.err = err
- S.mode = mode
-
- S.ch = ' '
- S.offset = 0
- S.rdOffset = 0
- S.lineOffset = 0
- S.insertSemi = false
- S.ErrorCount = 0
-
- S.next()
+ panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src)))
+ }
+ s.file = file
+ s.dir, _ = filepath.Split(file.Name())
+ s.src = src
+ s.err = err
+ s.mode = mode
+
+ s.ch = ' '
+ s.offset = 0
+ s.rdOffset = 0
+ s.lineOffset = 0
+ s.insertSemi = false
+ s.ErrorCount = 0
+
+ s.next()
}
-func (S *Scanner) error(offs int, msg string) {
- if S.err != nil {
- S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
+func (s *Scanner) error(offs int, msg string) {
+ if s.err != nil {
+ s.err(s.file.Position(s.file.Pos(offs)), msg)
}
- S.ErrorCount++
+ s.ErrorCount++
}
var prefix = []byte("//line ")
-func (S *Scanner) interpretLineComment(text []byte) {
+func (s *Scanner) interpretLineComment(text []byte) {
if bytes.HasPrefix(text, prefix) {
// get filename and line number, if any
if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
@@ -149,303 +145,335 @@ func (S *Scanner) interpretLineComment(text []byte) {
filename := filepath.Clean(string(text[len(prefix):i]))
if !filepath.IsAbs(filename) {
// make filename relative to current directory
- filename = filepath.Join(S.dir, filename)
+ filename = filepath.Join(s.dir, filename)
}
// update scanner position
- S.file.AddLineInfo(S.lineOffset, filename, line-1) // -1 since comment applies to next line
+ s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
}
}
}
}
-func (S *Scanner) scanComment() {
- // initial '/' already consumed; S.ch == '/' || S.ch == '*'
- offs := S.offset - 1 // position of initial '/'
+func (s *Scanner) scanComment() string {
+ // initial '/' already consumed; s.ch == '/' || s.ch == '*'
+ offs := s.offset - 1 // position of initial '/'
- if S.ch == '/' {
+ if s.ch == '/' {
//-style comment
- S.next()
- for S.ch != '\n' && S.ch >= 0 {
- S.next()
+ s.next()
+ for s.ch != '\n' && s.ch >= 0 {
+ s.next()
}
- if offs == S.lineOffset {
+ if offs == s.lineOffset {
// comment starts at the beginning of the current line
- S.interpretLineComment(S.src[offs:S.offset])
+ s.interpretLineComment(s.src[offs:s.offset])
}
- return
+ goto exit
}
/*-style comment */
- S.next()
- for S.ch >= 0 {
- ch := S.ch
- S.next()
- if ch == '*' && S.ch == '/' {
- S.next()
- return
+ s.next()
+ for s.ch >= 0 {
+ ch := s.ch
+ s.next()
+ if ch == '*' && s.ch == '/' {
+ s.next()
+ goto exit
}
}
- S.error(offs, "comment not terminated")
+ s.error(offs, "comment not terminated")
+
+exit:
+ return string(s.src[offs:s.offset])
}
-func (S *Scanner) findLineEnd() bool {
+func (s *Scanner) findLineEnd() bool {
// initial '/' already consumed
defer func(offs int) {
// reset scanner state to where it was upon calling findLineEnd
- S.ch = '/'
- S.offset = offs
- S.rdOffset = offs + 1
- S.next() // consume initial '/' again
- }(S.offset - 1)
+ s.ch = '/'
+ s.offset = offs
+ s.rdOffset = offs + 1
+ s.next() // consume initial '/' again
+ }(s.offset - 1)
// read ahead until a newline, EOF, or non-comment token is found
- for S.ch == '/' || S.ch == '*' {
- if S.ch == '/' {
+ for s.ch == '/' || s.ch == '*' {
+ if s.ch == '/' {
//-style comment always contains a newline
return true
}
/*-style comment: look for newline */
- S.next()
- for S.ch >= 0 {
- ch := S.ch
+ s.next()
+ for s.ch >= 0 {
+ ch := s.ch
if ch == '\n' {
return true
}
- S.next()
- if ch == '*' && S.ch == '/' {
- S.next()
+ s.next()
+ if ch == '*' && s.ch == '/' {
+ s.next()
break
}
}
- S.skipWhitespace() // S.insertSemi is set
- if S.ch < 0 || S.ch == '\n' {
+ s.skipWhitespace() // s.insertSemi is set
+ if s.ch < 0 || s.ch == '\n' {
return true
}
- if S.ch != '/' {
+ if s.ch != '/' {
// non-comment token
return false
}
- S.next() // consume '/'
+ s.next() // consume '/'
}
return false
}
-func isLetter(ch int) bool {
+func isLetter(ch rune) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
}
-func isDigit(ch int) bool {
+func isDigit(ch rune) bool {
return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
}
-func (S *Scanner) scanIdentifier() token.Token {
- offs := S.offset
- for isLetter(S.ch) || isDigit(S.ch) {
- S.next()
+func (s *Scanner) scanIdentifier() string {
+ offs := s.offset
+ for isLetter(s.ch) || isDigit(s.ch) {
+ s.next()
}
- return token.Lookup(S.src[offs:S.offset])
+ return string(s.src[offs:s.offset])
}
-func digitVal(ch int) int {
+func digitVal(ch rune) int {
switch {
case '0' <= ch && ch <= '9':
- return ch - '0'
+ return int(ch - '0')
case 'a' <= ch && ch <= 'f':
- return ch - 'a' + 10
+ return int(ch - 'a' + 10)
case 'A' <= ch && ch <= 'F':
- return ch - 'A' + 10
+ return int(ch - 'A' + 10)
}
return 16 // larger than any legal digit val
}
-func (S *Scanner) scanMantissa(base int) {
- for digitVal(S.ch) < base {
- S.next()
+func (s *Scanner) scanMantissa(base int) {
+ for digitVal(s.ch) < base {
+ s.next()
}
}
-func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
- // digitVal(S.ch) < 10
+func (s *Scanner) scanNumber(seenDecimalPoint bool) (token.Token, string) {
+ // digitVal(s.ch) < 10
+ offs := s.offset
tok := token.INT
if seenDecimalPoint {
+ offs--
tok = token.FLOAT
- S.scanMantissa(10)
+ s.scanMantissa(10)
goto exponent
}
- if S.ch == '0' {
+ if s.ch == '0' {
// int or float
- offs := S.offset
- S.next()
- if S.ch == 'x' || S.ch == 'X' {
+ offs := s.offset
+ s.next()
+ if s.ch == 'x' || s.ch == 'X' {
// hexadecimal int
- S.next()
- S.scanMantissa(16)
- if S.offset-offs <= 2 {
+ s.next()
+ s.scanMantissa(16)
+ if s.offset-offs <= 2 {
// only scanned "0x" or "0X"
- S.error(offs, "illegal hexadecimal number")
+ s.error(offs, "illegal hexadecimal number")
}
} else {
// octal int or float
seenDecimalDigit := false
- S.scanMantissa(8)
- if S.ch == '8' || S.ch == '9' {
+ s.scanMantissa(8)
+ if s.ch == '8' || s.ch == '9' {
// illegal octal int or float
seenDecimalDigit = true
- S.scanMantissa(10)
+ s.scanMantissa(10)
}
- if S.ch == '.' || S.ch == 'e' || S.ch == 'E' || S.ch == 'i' {
+ if s.ch == '.' || s.ch == 'e' || s.ch == 'E' || s.ch == 'i' {
goto fraction
}
// octal int
if seenDecimalDigit {
- S.error(offs, "illegal octal number")
+ s.error(offs, "illegal octal number")
}
}
goto exit
}
// decimal int or float
- S.scanMantissa(10)
+ s.scanMantissa(10)
fraction:
- if S.ch == '.' {
+ if s.ch == '.' {
tok = token.FLOAT
- S.next()
- S.scanMantissa(10)
+ s.next()
+ s.scanMantissa(10)
}
exponent:
- if S.ch == 'e' || S.ch == 'E' {
+ if s.ch == 'e' || s.ch == 'E' {
tok = token.FLOAT
- S.next()
- if S.ch == '-' || S.ch == '+' {
- S.next()
+ s.next()
+ if s.ch == '-' || s.ch == '+' {
+ s.next()
}
- S.scanMantissa(10)
+ s.scanMantissa(10)
}
- if S.ch == 'i' {
+ if s.ch == 'i' {
tok = token.IMAG
- S.next()
+ s.next()
}
exit:
- return tok
+ return tok, string(s.src[offs:s.offset])
}
-func (S *Scanner) scanEscape(quote int) {
- offs := S.offset
+func (s *Scanner) scanEscape(quote rune) {
+ offs := s.offset
var i, base, max uint32
- switch S.ch {
+ switch s.ch {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
- S.next()
+ s.next()
return
case '0', '1', '2', '3', '4', '5', '6', '7':
i, base, max = 3, 8, 255
case 'x':
- S.next()
+ s.next()
i, base, max = 2, 16, 255
case 'u':
- S.next()
+ s.next()
i, base, max = 4, 16, unicode.MaxRune
case 'U':
- S.next()
+ s.next()
i, base, max = 8, 16, unicode.MaxRune
default:
- S.next() // always make progress
- S.error(offs, "unknown escape sequence")
+ s.next() // always make progress
+ s.error(offs, "unknown escape sequence")
return
}
var x uint32
- for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
- d := uint32(digitVal(S.ch))
+ for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+ d := uint32(digitVal(s.ch))
if d >= base {
- S.error(S.offset, "illegal character in escape sequence")
+ s.error(s.offset, "illegal character in escape sequence")
break
}
x = x*base + d
- S.next()
+ s.next()
}
// in case of an error, consume remaining chars
- for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
- S.next()
+ for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+ s.next()
}
if x > max || 0xd800 <= x && x < 0xe000 {
- S.error(offs, "escape sequence is invalid Unicode code point")
+ s.error(offs, "escape sequence is invalid Unicode code point")
}
}
-func (S *Scanner) scanChar() {
+func (s *Scanner) scanChar() string {
// '\'' opening already consumed
- offs := S.offset - 1
+ offs := s.offset - 1
n := 0
- for S.ch != '\'' {
- ch := S.ch
+ for s.ch != '\'' {
+ ch := s.ch
n++
- S.next()
+ s.next()
if ch == '\n' || ch < 0 {
- S.error(offs, "character literal not terminated")
+ s.error(offs, "character literal not terminated")
n = 1
break
}
if ch == '\\' {
- S.scanEscape('\'')
+ s.scanEscape('\'')
}
}
- S.next()
+ s.next()
if n != 1 {
- S.error(offs, "illegal character literal")
+ s.error(offs, "illegal character literal")
}
+
+ return string(s.src[offs:s.offset])
}
-func (S *Scanner) scanString() {
+func (s *Scanner) scanString() string {
// '"' opening already consumed
- offs := S.offset - 1
+ offs := s.offset - 1
- for S.ch != '"' {
- ch := S.ch
- S.next()
+ for s.ch != '"' {
+ ch := s.ch
+ s.next()
if ch == '\n' || ch < 0 {
- S.error(offs, "string not terminated")
+ s.error(offs, "string not terminated")
break
}
if ch == '\\' {
- S.scanEscape('"')
+ s.scanEscape('"')
}
}
- S.next()
+ s.next()
+
+ return string(s.src[offs:s.offset])
}
-func (S *Scanner) scanRawString() {
- // '`' opening already consumed
- offs := S.offset - 1
+func stripCR(b []byte) []byte {
+ c := make([]byte, len(b))
+ i := 0
+ for _, ch := range b {
+ if ch != '\r' {
+ c[i] = ch
+ i++
+ }
+ }
+ return c[:i]
+}
- for S.ch != '`' {
- ch := S.ch
- S.next()
+func (s *Scanner) scanRawString() string {
+ // '`' opening already consumed
+ offs := s.offset - 1
+
+ hasCR := false
+ for s.ch != '`' {
+ ch := s.ch
+ s.next()
+ if ch == '\r' {
+ hasCR = true
+ }
if ch < 0 {
- S.error(offs, "string not terminated")
+ s.error(offs, "string not terminated")
break
}
}
- S.next()
+ s.next()
+
+ lit := s.src[offs:s.offset]
+ if hasCR {
+ lit = stripCR(lit)
+ }
+
+ return string(lit)
}
-func (S *Scanner) skipWhitespace() {
- for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
- S.next()
+func (s *Scanner) skipWhitespace() {
+ for s.ch == ' ' || s.ch == '\t' || s.ch == '\n' && !s.insertSemi || s.ch == '\r' {
+ s.next()
}
}
@@ -455,35 +483,35 @@ func (S *Scanner) skipWhitespace() {
// respectively. Otherwise, the result is tok0 if there was no other
// matching character, or tok2 if the matching character was ch2.
-func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
- if S.ch == '=' {
- S.next()
+func (s *Scanner) switch2(tok0, tok1 token.Token) token.Token {
+ if s.ch == '=' {
+ s.next()
return tok1
}
return tok0
}
-func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
- if S.ch == '=' {
- S.next()
+func (s *Scanner) switch3(tok0, tok1 token.Token, ch2 rune, tok2 token.Token) token.Token {
+ if s.ch == '=' {
+ s.next()
return tok1
}
- if S.ch == ch2 {
- S.next()
+ if s.ch == ch2 {
+ s.next()
return tok2
}
return tok0
}
-func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
- if S.ch == '=' {
- S.next()
+func (s *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Token) token.Token {
+ if s.ch == '=' {
+ s.next()
return tok1
}
- if S.ch == ch2 {
- S.next()
- if S.ch == '=' {
- S.next()
+ if s.ch == ch2 {
+ s.next()
+ if s.ch == '=' {
+ s.next()
return tok3
}
return tok2
@@ -491,15 +519,24 @@ 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.
+// Scan scans the next token and returns the token position, the token,
+// and its literal string if applicable. The source end is indicated by
+// token.EOF.
+//
+// If the returned token is a literal (token.IDENT, token.INT, token.FLOAT,
+// token.IMAG, token.CHAR, token.STRING) or token.COMMENT, the literal string
+// has the corresponding value.
//
// If the returned token is token.SEMICOLON, the corresponding
// literal string is ";" if the semicolon was present in the source,
// and "\n" if the semicolon was inserted because of a newline or
// at EOF.
//
+// If the returned token is token.ILLEGAL, the literal string is the
+// offending character.
+//
+// In all other cases, Scan returns an empty literal string.
+//
// For more tolerant parsing, Scan will return a valid token if
// possible even if a syntax error was encountered. Thus, even
// if the resulting token sequence contains no illegal tokens,
@@ -511,63 +548,63 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
// set with Init. Token positions are relative to that file
// and thus relative to the file set.
//
-func (S *Scanner) Scan() (token.Pos, token.Token, string) {
+func (s *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) {
scanAgain:
- S.skipWhitespace()
+ s.skipWhitespace()
// current token start
- insertSemi := false
- offs := S.offset
- tok := token.ILLEGAL
+ pos = s.file.Pos(s.offset)
// determine token value
- switch ch := S.ch; {
+ insertSemi := false
+ switch ch := s.ch; {
case isLetter(ch):
- tok = S.scanIdentifier()
+ lit = s.scanIdentifier()
+ tok = token.Lookup(lit)
switch tok {
case token.IDENT, token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN:
insertSemi = true
}
case digitVal(ch) < 10:
insertSemi = true
- tok = S.scanNumber(false)
+ tok, lit = s.scanNumber(false)
default:
- S.next() // always make progress
+ s.next() // always make progress
switch ch {
case -1:
- if S.insertSemi {
- S.insertSemi = false // EOF consumed
- return S.file.Pos(offs), token.SEMICOLON, "\n"
+ if s.insertSemi {
+ s.insertSemi = false // EOF consumed
+ return pos, token.SEMICOLON, "\n"
}
tok = token.EOF
case '\n':
- // we only reach here if S.insertSemi was
+ // we only reach here if s.insertSemi was
// set in the first place and exited early
- // from S.skipWhitespace()
- S.insertSemi = false // newline consumed
- return S.file.Pos(offs), token.SEMICOLON, "\n"
+ // from s.skipWhitespace()
+ s.insertSemi = false // newline consumed
+ return pos, token.SEMICOLON, "\n"
case '"':
insertSemi = true
tok = token.STRING
- S.scanString()
+ lit = s.scanString()
case '\'':
insertSemi = true
tok = token.CHAR
- S.scanChar()
+ lit = s.scanChar()
case '`':
insertSemi = true
tok = token.STRING
- S.scanRawString()
+ lit = s.scanRawString()
case ':':
- tok = S.switch2(token.COLON, token.DEFINE)
+ tok = s.switch2(token.COLON, token.DEFINE)
case '.':
- if digitVal(S.ch) < 10 {
+ if digitVal(s.ch) < 10 {
insertSemi = true
- tok = S.scanNumber(true)
- } else if S.ch == '.' {
- S.next()
- if S.ch == '.' {
- S.next()
+ tok, lit = s.scanNumber(true)
+ } else if s.ch == '.' {
+ s.next()
+ if s.ch == '.' {
+ s.next()
tok = token.ELLIPSIS
}
} else {
@@ -577,6 +614,7 @@ scanAgain:
tok = token.COMMA
case ';':
tok = token.SEMICOLON
+ lit = ";"
case '(':
tok = token.LPAREN
case ')':
@@ -593,78 +631,74 @@ scanAgain:
insertSemi = true
tok = token.RBRACE
case '+':
- tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
+ tok = s.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
if tok == token.INC {
insertSemi = true
}
case '-':
- tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
+ tok = s.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
if tok == token.DEC {
insertSemi = true
}
case '*':
- tok = S.switch2(token.MUL, token.MUL_ASSIGN)
+ tok = s.switch2(token.MUL, token.MUL_ASSIGN)
case '/':
- if S.ch == '/' || S.ch == '*' {
+ if s.ch == '/' || s.ch == '*' {
// comment
- if S.insertSemi && S.findLineEnd() {
+ if s.insertSemi && s.findLineEnd() {
// reset position to the beginning of the comment
- S.ch = '/'
- S.offset = offs
- S.rdOffset = offs + 1
- S.insertSemi = false // newline consumed
- return S.file.Pos(offs), token.SEMICOLON, "\n"
+ s.ch = '/'
+ s.offset = s.file.Offset(pos)
+ s.rdOffset = s.offset + 1
+ s.insertSemi = false // newline consumed
+ return pos, token.SEMICOLON, "\n"
}
- S.scanComment()
- if S.mode&ScanComments == 0 {
+ lit = s.scanComment()
+ if s.mode&ScanComments == 0 {
// skip comment
- S.insertSemi = false // newline consumed
+ s.insertSemi = false // newline consumed
goto scanAgain
}
tok = token.COMMENT
} else {
- tok = S.switch2(token.QUO, token.QUO_ASSIGN)
+ tok = s.switch2(token.QUO, token.QUO_ASSIGN)
}
case '%':
- tok = S.switch2(token.REM, token.REM_ASSIGN)
+ tok = s.switch2(token.REM, token.REM_ASSIGN)
case '^':
- tok = S.switch2(token.XOR, token.XOR_ASSIGN)
+ tok = s.switch2(token.XOR, token.XOR_ASSIGN)
case '<':
- if S.ch == '-' {
- S.next()
+ if s.ch == '-' {
+ s.next()
tok = token.ARROW
} else {
- tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
+ tok = s.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
}
case '>':
- tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
+ tok = s.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
case '=':
- tok = S.switch2(token.ASSIGN, token.EQL)
+ tok = s.switch2(token.ASSIGN, token.EQL)
case '!':
- tok = S.switch2(token.NOT, token.NEQ)
+ tok = s.switch2(token.NOT, token.NEQ)
case '&':
- if S.ch == '^' {
- S.next()
- tok = S.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
+ if s.ch == '^' {
+ s.next()
+ tok = s.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
} else {
- tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
+ tok = s.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
}
case '|':
- tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
+ tok = s.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
- if S.mode&AllowIllegalChars == 0 {
- S.error(offs, fmt.Sprintf("illegal character %#U", ch))
- }
- insertSemi = S.insertSemi // preserve insertSemi info
+ s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
+ insertSemi = s.insertSemi // preserve insertSemi info
+ tok = token.ILLEGAL
+ lit = string(ch)
}
}
-
- if S.mode&InsertSemis != 0 {
- S.insertSemi = insertSemi
+ if s.mode&dontInsertSemis == 0 {
+ s.insertSemi = insertSemi
}
- // TODO(gri): The scanner API should change such that the literal string
- // is only valid if an actual literal was scanned. This will
- // permit a more efficient implementation.
- return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
+ return
}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index eb9e1cb81..06223e23b 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -83,6 +83,8 @@ var tokens = [...]elt{
"`",
literal,
},
+ {token.STRING, "`\r`", literal},
+ {token.STRING, "`foo\r\nbar`", literal},
// Operators and delimiters
{token.ADD, "+", operator},
@@ -175,13 +177,14 @@ var tokens = [...]elt{
const whitespace = " \t \n\n\n" // to separate tokens
-type testErrorHandler struct {
- t *testing.T
-}
-
-func (h *testErrorHandler) Error(pos token.Position, msg string) {
- h.t.Errorf("Error() called (msg = %s)", msg)
-}
+var source = func() []byte {
+ var src []byte
+ for _, t := range tokens {
+ src = append(src, t.lit...)
+ src = append(src, whitespace...)
+ }
+ return src
+}()
func newlineCount(s string) int {
n := 0
@@ -212,20 +215,31 @@ 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
- var src string
- for _, e := range tokens {
- src += e.lit + whitespace
- }
- src_linecount := newlineCount(src)
+ src_linecount := newlineCount(string(source))
whitespace_linecount := newlineCount(whitespace)
+ // error handler
+ eh := func(_ token.Position, msg string) {
+ t.Errorf("error handler called (msg = %s)", msg)
+ }
+
// verify scan
var s Scanner
- s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &testErrorHandler{t}, ScanComments)
+ s.Init(fset.AddFile("", fset.Base(), len(source)), source, eh, ScanComments|dontInsertSemis)
index := 0
- epos := token.Position{"", 0, 1, 1} // expected position
+ // epos is the expected position
+ epos := token.Position{
+ Filename: "",
+ Offset: 0,
+ Line: 1,
+ Column: 1,
+ }
for {
pos, tok, lit := s.Scan()
+ if lit == "" {
+ // no literal value for non-literal tokens
+ lit = tok.String()
+ }
e := elt{token.EOF, "", special}
if index < len(tokens) {
e = tokens[index]
@@ -237,10 +251,18 @@ func TestScan(t *testing.T) {
}
checkPos(t, lit, pos, epos)
if tok != e.tok {
- t.Errorf("bad token for %q: got %s, expected %s", lit, tok.String(), e.tok.String())
+ t.Errorf("bad token for %q: got %s, expected %s", lit, tok, e.tok)
}
- if e.tok.IsLiteral() && lit != e.lit {
- t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+ if e.tok.IsLiteral() {
+ // no CRs in raw string literals
+ elit := e.lit
+ if elit[0] == '`' {
+ elit = string(stripCR([]byte(elit)))
+ epos.Offset += len(e.lit) - len(lit) // correct position
+ }
+ if lit != elit {
+ t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, elit)
+ }
}
if tokenclass(tok) != e.class {
t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
@@ -262,7 +284,7 @@ func TestScan(t *testing.T) {
}
}
-func checkSemi(t *testing.T, line string, mode uint) {
+func checkSemi(t *testing.T, line string, mode Mode) {
var S Scanner
file := fset.AddFile("TestSemis", fset.Base(), len(line))
S.Init(file, []byte(line), nil, mode)
@@ -286,7 +308,7 @@ func checkSemi(t *testing.T, line string, mode uint) {
}
checkPos(t, line, pos, semiPos)
} else {
- t.Errorf("bad token for %q: got %s, expected ;", line, tok.String())
+ t.Errorf("bad token for %q: got %s, expected ;", line, tok)
}
} else if tok == token.SEMICOLON {
t.Errorf("bad token for %q: got ;, expected no ;", line)
@@ -420,14 +442,14 @@ var lines = []string{
func TestSemis(t *testing.T) {
for _, line := range lines {
- checkSemi(t, line, AllowIllegalChars|InsertSemis)
- checkSemi(t, line, AllowIllegalChars|InsertSemis|ScanComments)
+ checkSemi(t, line, 0)
+ checkSemi(t, line, ScanComments)
// if the input ended in newlines, the input must tokenize the
// same with or without those newlines
for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
- checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis)
- checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis|ScanComments)
+ checkSemi(t, line[0:i], 0)
+ checkSemi(t, line[0:i], ScanComments)
}
}
}
@@ -482,11 +504,16 @@ func TestLineComments(t *testing.T) {
// verify scan
var S Scanner
file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
- S.Init(file, []byte(src), nil, 0)
+ S.Init(file, []byte(src), nil, dontInsertSemis)
for _, s := range segs {
p, _, lit := S.Scan()
pos := file.Position(p)
- checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+ checkPos(t, lit, p, token.Position{
+ Filename: s.filename,
+ Offset: pos.Offset,
+ Line: s.line,
+ Column: pos.Column,
+ })
}
if S.ErrorCount != 0 {
@@ -501,7 +528,7 @@ func TestInit(t *testing.T) {
// 1st init
src1 := "if true { }"
f1 := fset.AddFile("src1", fset.Base(), len(src1))
- s.Init(f1, []byte(src1), nil, 0)
+ s.Init(f1, []byte(src1), nil, dontInsertSemis)
if f1.Size() != len(src1) {
t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1))
}
@@ -509,40 +536,19 @@ func TestInit(t *testing.T) {
s.Scan() // true
_, tok, _ := s.Scan() // {
if tok != token.LBRACE {
- t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE)
+ t.Errorf("bad token: got %s, expected %s", tok, token.LBRACE)
}
// 2nd init
src2 := "go true { ]"
f2 := fset.AddFile("src2", fset.Base(), len(src2))
- s.Init(f2, []byte(src2), nil, 0)
+ s.Init(f2, []byte(src2), nil, dontInsertSemis)
if f2.Size() != len(src2) {
t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2))
}
_, tok, _ = s.Scan() // go
if tok != token.GO {
- t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO)
- }
-
- if s.ErrorCount != 0 {
- t.Errorf("found %d errors", s.ErrorCount)
- }
-}
-
-func TestIllegalChars(t *testing.T) {
- var s Scanner
-
- const src = "*?*$*@*"
- file := fset.AddFile("", fset.Base(), len(src))
- s.Init(file, []byte(src), &testErrorHandler{t}, AllowIllegalChars)
- for offs, ch := range src {
- pos, tok, lit := s.Scan()
- if poffs := file.Offset(pos); poffs != offs {
- t.Errorf("bad position for %s: got %d, expected %d", lit, poffs, offs)
- }
- if tok == token.ILLEGAL && lit != string(ch) {
- t.Errorf("bad token: got %s, expected %s", lit, string(ch))
- }
+ t.Errorf("bad token: got %s, expected %s", tok, token.GO)
}
if s.ErrorCount != 0 {
@@ -560,36 +566,37 @@ func TestStdErrorHander(t *testing.T) {
"//line File1:1\n" +
"@ @ @" // original file, line 1 again
- v := new(ErrorVector)
+ var list ErrorList
+ eh := func(pos token.Position, msg string) { list.Add(pos, msg) }
+
var s Scanner
- s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), v, 0)
+ s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), eh, dontInsertSemis)
for {
if _, tok, _ := s.Scan(); tok == token.EOF {
break
}
}
- list := v.GetErrorList(Raw)
+ if len(list) != s.ErrorCount {
+ t.Errorf("found %d errors, expected %d", len(list), s.ErrorCount)
+ }
+
if len(list) != 9 {
t.Errorf("found %d raw errors, expected 9", len(list))
PrintError(os.Stderr, list)
}
- list = v.GetErrorList(Sorted)
+ list.Sort()
if len(list) != 9 {
t.Errorf("found %d sorted errors, expected 9", len(list))
PrintError(os.Stderr, list)
}
- list = v.GetErrorList(NoMultiples)
+ list.RemoveMultiples()
if len(list) != 4 {
t.Errorf("found %d one-per-line errors, expected 4", len(list))
PrintError(os.Stderr, list)
}
-
- if v.ErrorCount() != s.ErrorCount {
- t.Errorf("found %d errors, expected %d", v.ErrorCount(), s.ErrorCount)
- }
}
type errorCollector struct {
@@ -598,16 +605,15 @@ type errorCollector struct {
pos token.Position // last error position encountered
}
-func (h *errorCollector) Error(pos token.Position, msg string) {
- h.cnt++
- h.msg = msg
- h.pos = pos
-}
-
func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
var s Scanner
var h errorCollector
- s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &h, ScanComments)
+ eh := func(pos token.Position, msg string) {
+ h.cnt++
+ h.msg = msg
+ h.pos = pos
+ }
+ s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), eh, ScanComments|dontInsertSemis)
_, tok0, _ := s.Scan()
_, tok1, _ := s.Scan()
if tok0 != tok {
@@ -670,3 +676,20 @@ func TestScanErrors(t *testing.T) {
checkError(t, e.src, e.tok, e.pos, e.err)
}
}
+
+func BenchmarkScan(b *testing.B) {
+ b.StopTimer()
+ fset := token.NewFileSet()
+ file := fset.AddFile("", fset.Base(), len(source))
+ var s Scanner
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ s.Init(file, source, nil, ScanComments)
+ for {
+ _, tok, _ := s.Scan()
+ if tok == token.EOF {
+ break
+ }
+ }
+ }
+}
diff --git a/src/pkg/go/token/Makefile b/src/pkg/go/token/Makefile
deleted file mode 100644
index 4a4e64dc8..000000000
--- a/src/pkg/go/token/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=go/token
-GOFILES=\
- position.go\
- token.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/token/position.go b/src/pkg/go/token/position.go
index c559e19f8..647d1b770 100644
--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -12,6 +12,9 @@ import (
"sync"
)
+// -----------------------------------------------------------------------------
+// Positions
+
// Position describes an arbitrary source position
// including the file, line, and column location.
// A Position is valid if the line number is > 0.
@@ -81,82 +84,8 @@ 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
- }
- if i := searchFiles(s.files, int(p)); i >= 0 {
- f := s.files[i]
- // f.base <= int(p) by definition of searchFiles
- if int(p) <= f.base+f.size {
- s.last = f
- return f
- }
- }
- return nil
-}
-
-// File returns the file which contains the position p.
-// If no such file is found (for instance for p == NoPos),
-// the result is nil.
-//
-func (s *FileSet) File(p Pos) (f *File) {
- if p != NoPos {
- s.mutex.RLock()
- f = s.file(p)
- s.mutex.RUnlock()
- }
- return
-}
-
-func (f *File) position(p Pos) (pos Position) {
- offset := int(p) - f.base
- pos.Offset = offset
- pos.Filename, pos.Line, pos.Column = f.info(offset)
- return
-}
-
-// Position converts a Pos in the fileset into a general Position.
-func (s *FileSet) Position(p Pos) (pos Position) {
- if p != NoPos {
- // TODO(gri) consider optimizing the case where p
- // is in the last file added, or perhaps
- // looked at - will eliminate one level
- // of search
- s.mutex.RLock()
- if f := s.file(p); f != nil {
- pos = f.position(p)
- }
- s.mutex.RUnlock()
- }
- return
-}
-
-type lineInfo struct {
- offset int
- filename string
- line int
-}
-
-// AddLineInfo adds alternative file and line number information for
-// a given file offset. The offset must be larger than the offset for
-// the previously added alternative line info and smaller than the
-// file size; otherwise the information is ignored.
-//
-// AddLineInfo is typically used to register alternative position
-// information for //line filename:line comments in source files.
-//
-func (f *File) AddLineInfo(offset int, filename string, line int) {
- f.set.mutex.Lock()
- if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset < f.size {
- f.infos = append(f.infos, lineInfo{offset, filename, line})
- }
- f.set.mutex.Unlock()
-}
+// -----------------------------------------------------------------------------
+// File
// A File is a handle for a file belonging to a FileSet.
// A File has a name, size, and line offset table.
@@ -251,6 +180,32 @@ func (f *File) SetLinesForContent(content []byte) {
f.set.mutex.Unlock()
}
+// A lineInfo object describes alternative file and line number
+// information (such as provided via a //line comment in a .go
+// file) for a given file offset.
+type lineInfo struct {
+ // fields are exported to make them accessible to gob
+ 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
+// file size; otherwise the information is ignored.
+//
+// AddLineInfo is typically used to register alternative position
+// information for //line filename:line comments in source files.
+//
+func (f *File) AddLineInfo(offset int, filename string, line int) {
+ f.set.mutex.Lock()
+ if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size {
+ f.infos = append(f.infos, lineInfo{offset, filename, line})
+ }
+ f.set.mutex.Unlock()
+}
+
// Pos returns the Pos value for the given file offset;
// the offset must be <= f.Size().
// f.Pos(f.Offset(p)) == p.
@@ -281,43 +236,8 @@ 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.
-//
-func (f *File) Position(p Pos) (pos Position) {
- if p != NoPos {
- if int(p) < f.base || int(p) > f.base+f.size {
- panic("illegal Pos value")
- }
- pos = f.position(p)
- }
- return
-}
-
-func searchInts(a []int, x int) int {
- // This function body is a manually inlined version of:
- //
- // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
- //
- // With better compiler optimizations, this may not be needed in the
- // future, but at the moment this change improves the go/printer
- // benchmark performance by ~30%. This has a direct impact on the
- // speed of gofmt and thus seems worthwhile (2011-04-29).
- i, j := 0, len(a)
- for i < j {
- h := i + (j-i)/2 // avoid overflow when computing h
- // i ≤ h < j
- if a[h] <= x {
- i = h + 1
- } else {
- j = h
- }
- }
- 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
+ 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.
@@ -330,15 +250,38 @@ func (f *File) info(offset int) (filename string, line, column int) {
// almost no files have extra line infos
if i := searchLineInfos(f.infos, offset); i >= 0 {
alt := &f.infos[i]
- filename = alt.filename
- if i := searchInts(f.lines, alt.offset); i >= 0 {
- line += alt.line - i - 1
+ filename = alt.Filename
+ if i := searchInts(f.lines, alt.Offset); i >= 0 {
+ line += alt.Line - i - 1
}
}
}
return
}
+func (f *File) position(p Pos) (pos Position) {
+ offset := int(p) - f.base
+ pos.Offset = offset
+ pos.Filename, pos.Line, pos.Column = f.info(offset)
+ return
+}
+
+// Position returns the Position value for the given file position p;
+// p must be a Pos value in that file or NoPos.
+//
+func (f *File) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ if int(p) < f.base || int(p) > f.base+f.size {
+ panic("illegal Pos value")
+ }
+ pos = f.position(p)
+ }
+ return
+}
+
+// -----------------------------------------------------------------------------
+// FileSet
+
// A FileSet represents a set of source files.
// Methods of file sets are synchronized; multiple goroutines
// may invoke them concurrently.
@@ -402,23 +345,91 @@ 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)
- go func() {
- for i := 0; ; i++ {
- var f *File
- s.mutex.RLock()
- if i < len(s.files) {
- f = s.files[i]
- }
- s.mutex.RUnlock()
- if f == nil {
- break
- }
- ch <- f
+// Iterate calls f for the files in the file set in the order they were added
+// until f returns false.
+//
+func (s *FileSet) Iterate(f func(*File) bool) {
+ for i := 0; ; i++ {
+ var file *File
+ s.mutex.RLock()
+ if i < len(s.files) {
+ file = s.files[i]
}
- close(ch)
- }()
- return ch
+ s.mutex.RUnlock()
+ if file == nil || !f(file) {
+ break
+ }
+ }
+}
+
+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 {
+ // common case: p is in last file
+ if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
+ return f
+ }
+ // p is not in last file - search all files
+ if i := searchFiles(s.files, int(p)); i >= 0 {
+ f := s.files[i]
+ // f.base <= int(p) by definition of searchFiles
+ if int(p) <= f.base+f.size {
+ s.last = f
+ return f
+ }
+ }
+ return nil
+}
+
+// File returns the file that contains the position p.
+// If no such file is found (for instance for p == NoPos),
+// the result is nil.
+//
+func (s *FileSet) File(p Pos) (f *File) {
+ if p != NoPos {
+ s.mutex.RLock()
+ f = s.file(p)
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+// Position converts a Pos in the fileset into a general Position.
+func (s *FileSet) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ s.mutex.RLock()
+ if f := s.file(p); f != nil {
+ pos = f.position(p)
+ }
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+// -----------------------------------------------------------------------------
+// Helper functions
+
+func searchInts(a []int, x int) int {
+ // This function body is a manually inlined version of:
+ //
+ // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
+ //
+ // With better compiler optimizations, this may not be needed in the
+ // future, but at the moment this change improves the go/printer
+ // benchmark performance by ~30%. This has a direct impact on the
+ // speed of gofmt and thus seems worthwhile (2011-04-29).
+ // TODO(gri): Remove this when compilers have caught up.
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2 // avoid overflow when computing h
+ // i ≤ h < j
+ if a[h] <= x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i - 1
}
diff --git a/src/pkg/go/token/position_test.go b/src/pkg/go/token/position_test.go
index 30bec5991..160107df4 100644
--- a/src/pkg/go/token/position_test.go
+++ b/src/pkg/go/token/position_test.go
@@ -167,12 +167,13 @@ func TestFiles(t *testing.T) {
for i, test := range tests {
fset.AddFile(test.filename, fset.Base(), test.size)
j := 0
- for g := range fset.Files() {
- if g.Name() != tests[j].filename {
- t.Errorf("expected filename = %s; got %s", tests[j].filename, g.Name())
+ fset.Iterate(func(f *File) bool {
+ if f.Name() != tests[j].filename {
+ t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name())
}
j++
- }
+ return true
+ })
if j != i+1 {
t.Errorf("expected %d files; got %d", i+1, j)
}
diff --git a/src/pkg/go/token/serialize.go b/src/pkg/go/token/serialize.go
new file mode 100644
index 000000000..4adc8f9e3
--- /dev/null
+++ b/src/pkg/go/token/serialize.go
@@ -0,0 +1,56 @@
+// 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 token
+
+type serializedFile struct {
+ // fields correspond 1:1 to fields with same (lower-case) name in File
+ Name string
+ Base int
+ Size int
+ Lines []int
+ Infos []lineInfo
+}
+
+type serializedFileSet struct {
+ Base int
+ Files []serializedFile
+}
+
+// Read calls decode to deserialize a file set into s; s must not be nil.
+func (s *FileSet) Read(decode func(interface{}) error) error {
+ var ss serializedFileSet
+ if err := decode(&ss); err != nil {
+ return err
+ }
+
+ s.mutex.Lock()
+ s.base = ss.Base
+ files := make([]*File, len(ss.Files))
+ for i := 0; i < len(ss.Files); i++ {
+ f := &ss.Files[i]
+ files[i] = &File{s, f.Name, f.Base, f.Size, f.Lines, f.Infos}
+ }
+ s.files = files
+ s.last = nil
+ s.mutex.Unlock()
+
+ return nil
+}
+
+// Write calls encode to serialize the file set s.
+func (s *FileSet) Write(encode func(interface{}) error) error {
+ var ss serializedFileSet
+
+ s.mutex.Lock()
+ ss.Base = s.base
+ files := make([]serializedFile, len(s.files))
+ for i, f := range s.files {
+ files[i] = serializedFile{f.name, f.base, f.size, f.lines, f.infos}
+ }
+ ss.Files = files
+ s.mutex.Unlock()
+
+ return encode(ss)
+}
diff --git a/src/pkg/go/token/serialize_test.go b/src/pkg/go/token/serialize_test.go
new file mode 100644
index 000000000..4e925adb6
--- /dev/null
+++ b/src/pkg/go/token/serialize_test.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 token
+
+import (
+ "bytes"
+ "encoding/gob"
+ "fmt"
+ "testing"
+)
+
+// equal returns nil if p and q describe the same file set;
+// otherwise it returns an error describing the discrepancy.
+func equal(p, q *FileSet) error {
+ if p == q {
+ // avoid deadlock if p == q
+ return nil
+ }
+
+ // not strictly needed for the test
+ p.mutex.Lock()
+ q.mutex.Lock()
+ defer q.mutex.Unlock()
+ defer p.mutex.Unlock()
+
+ if p.base != q.base {
+ return fmt.Errorf("different bases: %d != %d", p.base, q.base)
+ }
+
+ if len(p.files) != len(q.files) {
+ return fmt.Errorf("different number of files: %d != %d", len(p.files), len(q.files))
+ }
+
+ for i, f := range p.files {
+ g := q.files[i]
+ if f.set != p {
+ return fmt.Errorf("wrong fileset for %q", f.name)
+ }
+ if g.set != q {
+ return fmt.Errorf("wrong fileset for %q", g.name)
+ }
+ if f.name != g.name {
+ return fmt.Errorf("different filenames: %q != %q", f.name, g.name)
+ }
+ if f.base != g.base {
+ return fmt.Errorf("different base for %q: %d != %d", f.name, f.base, g.base)
+ }
+ if f.size != g.size {
+ return fmt.Errorf("different size for %q: %d != %d", f.name, f.size, g.size)
+ }
+ for j, l := range f.lines {
+ m := g.lines[j]
+ if l != m {
+ return fmt.Errorf("different offsets for %q", f.name)
+ }
+ }
+ for j, l := range f.infos {
+ m := g.infos[j]
+ if l.Offset != m.Offset || l.Filename != m.Filename || l.Line != m.Line {
+ return fmt.Errorf("different infos for %q", f.name)
+ }
+ }
+ }
+
+ // we don't care about .last - it's just a cache
+ return nil
+}
+
+func checkSerialize(t *testing.T, p *FileSet) {
+ var buf bytes.Buffer
+ encode := func(x interface{}) error {
+ return gob.NewEncoder(&buf).Encode(x)
+ }
+ if err := p.Write(encode); err != nil {
+ t.Errorf("writing fileset failed: %s", err)
+ return
+ }
+ q := NewFileSet()
+ decode := func(x interface{}) error {
+ return gob.NewDecoder(&buf).Decode(x)
+ }
+ if err := q.Read(decode); err != nil {
+ t.Errorf("reading fileset failed: %s", err)
+ return
+ }
+ if err := equal(p, q); err != nil {
+ t.Errorf("filesets not identical: %s", err)
+ }
+}
+
+func TestSerialization(t *testing.T) {
+ p := NewFileSet()
+ checkSerialize(t, p)
+ // add some files
+ for i := 0; i < 10; i++ {
+ f := p.AddFile(fmt.Sprintf("file%d", i), p.Base()+i, i*100)
+ checkSerialize(t, p)
+ // add some lines and alternative file infos
+ line := 1000
+ for offs := 0; offs < f.Size(); offs += 40 + i {
+ f.AddLine(offs)
+ if offs%7 == 0 {
+ f.AddLineInfo(offs, fmt.Sprintf("file%d", offs), line)
+ line += 33
+ }
+ }
+ checkSerialize(t, p)
+ }
+}
diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go
index 557374052..84b6314d5 100644
--- a/src/pkg/go/token/token.go
+++ b/src/pkg/go/token/token.go
@@ -283,10 +283,8 @@ func init() {
// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
-func Lookup(ident []byte) Token {
- // TODO Maps with []byte key are illegal because []byte does not
- // support == . Should find a more efficient solution eventually.
- if tok, is_keyword := keywords[string(ident)]; is_keyword {
+func Lookup(ident string) Token {
+ if tok, is_keyword := keywords[ident]; is_keyword {
return tok
}
return IDENT
@@ -295,16 +293,16 @@ func Lookup(ident []byte) Token {
// Predicates
// IsLiteral returns true for tokens corresponding to identifiers
-// and basic type literals; returns false otherwise.
+// and basic type literals; it returns false otherwise.
//
func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end }
// IsOperator returns true for tokens corresponding to operators and
-// delimiters; returns false otherwise.
+// delimiters; it returns false otherwise.
//
func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end }
// IsKeyword returns true for tokens corresponding to keywords;
-// returns false otherwise.
+// it returns false otherwise.
//
func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
diff --git a/src/pkg/go/typechecker/Makefile b/src/pkg/go/typechecker/Makefile
deleted file mode 100644
index 83af3ef4e..000000000
--- a/src/pkg/go/typechecker/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=go/typechecker
-GOFILES=\
- scope.go\
- type.go\
- typechecker.go\
- universe.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/typechecker/scope.go b/src/pkg/go/typechecker/scope.go
deleted file mode 100644
index d73d1a450..000000000
--- a/src/pkg/go/typechecker/scope.go
+++ /dev/null
@@ -1,69 +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.
-
-// DEPRECATED FILE - WILL GO AWAY EVENTUALLY.
-//
-// Scope handling is now done in go/parser.
-// The functionality here is only present to
-// keep the typechecker running for now.
-
-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.
-func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
- obj := ast.NewObj(kind, name.Name)
- obj.Decl = decl
- //obj.N = n
- name.Obj = obj
- if name.Name != "_" {
- if alt := scope.Insert(obj); alt != nil {
- tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
- }
- }
- 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) {
- for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
- obj = s.Lookup(name.Name)
- }
- if obj == nil {
- tc.Errorf(name.Pos(), "%s not declared", name.Name)
- obj = ast.NewObj(ast.Bad, name.Name)
- }
- name.Obj = obj
- return
-}
-
-// findField returns the object with the given name if visible in the type's scope.
-// If no such object is found, an error is reported and a bad object is returned instead.
-func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
- // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
- obj = typ.Scope.Lookup(name.Name)
- if obj == nil {
- tc.Errorf(name.Pos(), "%s not declared", name.Name)
- obj = ast.NewObj(ast.Bad, name.Name)
- }
- return
-}
diff --git a/src/pkg/go/typechecker/testdata/test0.src b/src/pkg/go/typechecker/testdata/test0.src
deleted file mode 100644
index 4e317f214..000000000
--- a/src/pkg/go/typechecker/testdata/test0.src
+++ /dev/null
@@ -1,94 +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.
-
-// type declarations
-
-package P0
-
-type (
- B bool
- I int32
- A [10]P
- T struct {
- x, y P
- }
- P *T
- R *R
- F func(A) I
- Y interface {
- f(A) I
- }
- S []P
- M map[I]F
- C chan<- I
-)
-
-type (
- a/* ERROR "illegal cycle" */ a
- a/* ERROR "already declared" */ int
-
- b/* ERROR "illegal cycle" */ c
- c d
- d e
- e b /* ERROR "not a type" */
-
- t *t
-
- U V
- V W
- W *U
-
- P1 *S2
- P2 P1
-
- S1 struct {
- a, b, c int
- u, v, a/* ERROR "already declared" */ float
- }
- S2/* ERROR "illegal cycle" */ struct {
- x S2
- }
-
- L1 []L1
- L2 []int
-
- A1 [10]int
- A2/* ERROR "illegal cycle" */ [10]A2
- A3/* ERROR "illegal cycle" */ [10]struct {
- x A4
- }
- A4 [10]A3
-
- F1 func()
- F2 func(x, y, z float)
- F3 func(x, y, x /* ERROR "already declared" */ float)
- F4 func() (x, y, x /* ERROR "already declared" */ float)
- F5 func(x int) (x /* ERROR "already declared" */ float)
-
- I1 interface{}
- I2 interface {
- m1()
- }
- I3 interface {
- m1()
- m1 /* ERROR "already declared" */ ()
- }
- I4 interface {
- m1(x, y, x /* ERROR "already declared" */ float)
- m2() (x, y, x /* ERROR "already declared" */ float)
- m3(x int) (x /* ERROR "already declared" */ float)
- }
- I5 interface {
- m1(I5)
- }
-
- C1 chan int
- C2 <-chan int
- C3 chan<- C3
-
- M1 map[Last]string
- M2 map[string]M2
-
- Last int
-)
diff --git a/src/pkg/go/typechecker/testdata/test1.src b/src/pkg/go/typechecker/testdata/test1.src
deleted file mode 100644
index b5531fb9f..000000000
--- a/src/pkg/go/typechecker/testdata/test1.src
+++ /dev/null
@@ -1,13 +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.
-
-// const and var declarations
-
-package P1
-
-const (
- c1 = 0
- c2 int = 0
- c3, c4 = 0
-)
diff --git a/src/pkg/go/typechecker/testdata/test3.src b/src/pkg/go/typechecker/testdata/test3.src
deleted file mode 100644
index 2e1a9fa8f..000000000
--- a/src/pkg/go/typechecker/testdata/test3.src
+++ /dev/null
@@ -1,41 +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 P3
-
-// function and method signatures
-
-func _() {}
-func _() {}
-func _(x, x /* ERROR "already declared" */ int) {}
-
-func f() {}
-func f /* ERROR "already declared" */ () {}
-
-func (*foo /* ERROR "invalid receiver" */ ) m() {}
-func (bar /* ERROR "not a type" */ ) m() {}
-
-func f1(x, _, _ int) (_, _ float) {}
-func f2(x, y, x /* ERROR "already declared" */ int) {}
-func f3(x, y int) (a, b, x /* ERROR "already declared" */ int) {}
-
-func (x *T) m1() {}
-func (x *T) m1 /* ERROR "already declared" */ () {}
-func (x T) m1 /* ERROR "already declared" */ () {}
-func (T) m1 /* ERROR "already declared" */ () {}
-
-func (x *T) m2(u, x /* ERROR "already declared" */ int) {}
-func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
-// The following are disabled for now because the typechecker
-// in in the process of being rewritten and cannot handle them
-// at the moment
-//func (T) _(x, x /* "already declared" */ int) {}
-//func (T) _() (x, x /* "already declared" */ int) {}
-
-//func (PT) _() {}
-
-var bar int
-
-type T struct{}
-type PT (T)
diff --git a/src/pkg/go/typechecker/testdata/test4.src b/src/pkg/go/typechecker/testdata/test4.src
deleted file mode 100644
index 94d3558f9..000000000
--- a/src/pkg/go/typechecker/testdata/test4.src
+++ /dev/null
@@ -1,11 +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.
-
-// Constant declarations
-
-package P4
-
-const (
- c0 = 0
-)
diff --git a/src/pkg/go/typechecker/type.go b/src/pkg/go/typechecker/type.go
deleted file mode 100644
index 1b88eb54b..000000000
--- a/src/pkg/go/typechecker/type.go
+++ /dev/null
@@ -1,118 +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 typechecker
-
-import "go/ast"
-
-// A Type represents a Go type.
-type Type struct {
- Form Form
- Obj *ast.Object // corresponding type name, or nil
- Scope *ast.Scope // fields and methods, always present
- N uint // basic type id, array length, number of function results, or channel direction
- Key, Elt *Type // map key and array, pointer, slice, map or channel element
- Params *ast.Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
- 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
-
-// The list of possible type forms.
-const (
- BadType Form = iota // for error handling
- Unresolved // type not fully setup
- Basic
- Array
- Struct
- Pointer
- Function
- Method
- Interface
- Slice
- Map
- Channel
- Tuple
-)
-
-var formStrings = [...]string{
- BadType: "badType",
- Unresolved: "unresolved",
- Basic: "basic",
- Array: "array",
- Struct: "struct",
- Pointer: "pointer",
- Function: "function",
- Method: "method",
- Interface: "interface",
- Slice: "slice",
- Map: "map",
- Channel: "channel",
- Tuple: "tuple",
-}
-
-func (form Form) String() string { return formStrings[form] }
-
-// The list of basic type id's.
-const (
- Bool = iota
- Byte
- Uint
- Int
- Float
- Complex
- Uintptr
- String
-
- Uint8
- Uint16
- Uint32
- Uint64
-
- Int8
- Int16
- Int32
- Int64
-
- Float32
- Float64
-
- Complex64
- Complex128
-
- // TODO(gri) ideal types are missing
-)
-
-var BasicTypes = map[uint]string{
- Bool: "bool",
- Byte: "byte",
- Uint: "uint",
- Int: "int",
- Float: "float",
- Complex: "complex",
- Uintptr: "uintptr",
- String: "string",
-
- Uint8: "uint8",
- Uint16: "uint16",
- Uint32: "uint32",
- Uint64: "uint64",
-
- Int8: "int8",
- Int16: "int16",
- Int32: "int32",
- Int64: "int64",
-
- Float32: "float32",
- Float64: "float64",
-
- Complex64: "complex64",
- Complex128: "complex128",
-}
diff --git a/src/pkg/go/typechecker/typechecker.go b/src/pkg/go/typechecker/typechecker.go
deleted file mode 100644
index 24480165b..000000000
--- a/src/pkg/go/typechecker/typechecker.go
+++ /dev/null
@@ -1,468 +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.
-
-// DEPRECATED PACKAGE - SEE go/types INSTEAD.
-// This package implements typechecking of a Go AST.
-// The result of the typecheck is an augmented AST
-// with object and type information for each identifier.
-//
-package typechecker
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "go/scanner"
- "os"
-)
-
-// TODO(gri) don't report errors for objects/types that are marked as bad.
-
-
-const debug = true // set for debugging output
-
-// An importer takes an import path and returns the data describing the
-// respective package's exported interface. The data format is TBD.
-//
-type Importer func(path string) ([]byte, os.Error)
-
-// CheckPackage typechecks a package and augments the AST by setting
-// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
-// importer is provided, it is used to handle imports, otherwise they
-// are ignored (likely leading to typechecking errors).
-//
-// If errors are reported, the AST may be incompletely augmented (fields
-// may be nil) or contain incomplete object, type, or scope information.
-//
-func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.Error {
- var tc typechecker
- tc.fset = fset
- tc.importer = importer
- tc.checkPackage(pkg)
- return tc.GetError(scanner.Sorted)
-}
-
-// CheckFile typechecks a single file, but otherwise behaves like
-// CheckPackage. If the complete package consists of more than just
-// one file, the file may not typecheck without errors.
-//
-func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
- // create a single-file dummy package
- pkg := &ast.Package{file.Name.Name, nil, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
- return CheckPackage(fset, pkg, importer)
-}
-
-// ----------------------------------------------------------------------------
-// Typechecker state
-
-type typechecker struct {
- fset *token.FileSet
- scanner.ErrorVector
- importer Importer
- globals []*ast.Object // list of global objects
- topScope *ast.Scope // current top-most scope
- cyclemap map[*ast.Object]bool // for cycle detection
- iota int // current value of iota
-}
-
-func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
- tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
-}
-
-func assert(pred bool) {
- if !pred {
- panic("internal error")
- }
-}
-
-/*
-Typechecking is done in several phases:
-
-phase 1: declare all global objects; also collect all function and method declarations
- - all objects have kind, name, decl fields; the decl field permits
- quick lookup of an object's declaration
- - constant objects have an iota value
- - type objects have unresolved types with empty scopes, all others have nil types
- - report global double declarations
-
-phase 2: bind methods to their receiver base types
- - receiver base types must be declared in the package, thus for
- each method a corresponding (unresolved) type must exist
- - report method double declarations and errors with base types
-
-phase 3: resolve all global objects
- - sequentially iterate through all objects in the global scope
- - resolve types for all unresolved types and assign types to
- all attached methods
- - assign types to all other objects, possibly by evaluating
- constant and initializer expressions
- - resolution may recurse; a cyclemap is used to detect cycles
- - report global typing errors
-
-phase 4: sequentially typecheck function and method bodies
- - all global objects are declared and have types and values;
- all methods have types
- - sequentially process statements in each body; any object
- referred to must be fully defined at this point
- - report local typing errors
-*/
-
-func (tc *typechecker) checkPackage(pkg *ast.Package) {
- // setup package scope
- tc.topScope = Universe
- tc.openScope()
- defer tc.closeScope()
-
- // TODO(gri) there's no file scope at the moment since we ignore imports
-
- // phase 1: declare all global objects; also collect all function and method declarations
- var funcs []*ast.FuncDecl
- for _, file := range pkg.Files {
- for _, decl := range file.Decls {
- tc.declGlobal(decl)
- if f, isFunc := decl.(*ast.FuncDecl); isFunc {
- funcs = append(funcs, f)
- }
- }
- }
-
- // phase 2: bind methods to their receiver base types
- for _, m := range funcs {
- if m.Recv != nil {
- tc.bindMethod(m)
- }
- }
-
- // phase 3: resolve all global objects
- tc.cyclemap = make(map[*ast.Object]bool)
- for _, obj := range tc.globals {
- tc.resolve(obj)
- }
- assert(len(tc.cyclemap) == 0)
-
- // 4: sequentially typecheck function and method bodies
- for _, f := range funcs {
- ftype, _ := f.Name.Obj.Type.(*Type)
- tc.checkBlock(f.Body.List, ftype)
- }
-
- pkg.Scope = tc.topScope
-}
-
-func (tc *typechecker) declGlobal(global ast.Decl) {
- switch d := global.(type) {
- case *ast.BadDecl:
- // ignore
-
- case *ast.GenDecl:
- iota := 0
- var prev *ast.ValueSpec
- for _, spec := range d.Specs {
- switch s := spec.(type) {
- case *ast.ImportSpec:
- // TODO(gri) imports go into file scope
- case *ast.ValueSpec:
- switch d.Tok {
- case token.CONST:
- if s.Values == nil {
- // create a new spec with type and values from the previous one
- if prev != nil {
- s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
- } else {
- // TODO(gri) this should probably go into the const decl code
- tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
- }
- }
- for _, name := range s.Names {
- tc.globals = append(tc.globals, tc.decl(ast.Con, name, s, iota))
- }
- case token.VAR:
- for _, name := range s.Names {
- tc.globals = append(tc.globals, tc.decl(ast.Var, name, s, 0))
- }
- default:
- panic("unreachable")
- }
- prev = s
- iota++
- case *ast.TypeSpec:
- obj := tc.decl(ast.Typ, s.Name, s, 0)
- tc.globals = append(tc.globals, obj)
- // give all type objects an unresolved type so
- // that we can collect methods in the type scope
- typ := NewType(Unresolved)
- obj.Type = typ
- typ.Obj = obj
- default:
- panic("unreachable")
- }
- }
-
- case *ast.FuncDecl:
- if d.Recv == nil {
- tc.globals = append(tc.globals, tc.decl(ast.Fun, d.Name, d, 0))
- }
-
- default:
- panic("unreachable")
- }
-}
-
-// If x is of the form *T, deref returns T, otherwise it returns x.
-func deref(x ast.Expr) ast.Expr {
- if p, isPtr := x.(*ast.StarExpr); isPtr {
- x = p.X
- }
- return x
-}
-
-func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
- // a method is declared in the receiver base type's scope
- var scope *ast.Scope
- base := deref(method.Recv.List[0].Type)
- if name, isIdent := base.(*ast.Ident); isIdent {
- // if base is not an *ast.Ident, we had a syntax
- // error and the parser reported an error already
- obj := tc.topScope.Lookup(name.Name)
- if obj == nil {
- tc.Errorf(name.Pos(), "invalid receiver: %s is not declared in this package", name.Name)
- } else if obj.Kind != ast.Typ {
- tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
- } else {
- typ := obj.Type.(*Type)
- assert(typ.Form == Unresolved)
- scope = typ.Scope
- }
- }
- if scope == nil {
- // no receiver type found; use a dummy scope
- // (we still want to type-check the method
- // body, so make sure there is a name object
- // and type)
- // TODO(gri) should we record the scope so
- // that we don't lose the receiver for type-
- // checking of the method body?
- scope = ast.NewScope(nil)
- }
- tc.declInScope(scope, ast.Fun, method.Name, method, 0)
-}
-
-func (tc *typechecker) resolve(obj *ast.Object) {
- // check for declaration cycles
- if tc.cyclemap[obj] {
- tc.Errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
- obj.Kind = ast.Bad
- return
- }
- tc.cyclemap[obj] = true
- defer func() {
- tc.cyclemap[obj] = false, false
- }()
-
- // resolve non-type objects
- typ, _ := obj.Type.(*Type)
- if typ == nil {
- switch obj.Kind {
- case ast.Bad:
- // ignore
-
- case ast.Con:
- tc.declConst(obj)
-
- case ast.Var:
- tc.declVar(obj)
- obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
-
- case ast.Fun:
- obj.Type = NewType(Function)
- t := obj.Decl.(*ast.FuncDecl).Type
- tc.declSignature(obj.Type.(*Type), nil, t.Params, t.Results)
-
- default:
- // type objects have non-nil types when resolve is called
- if debug {
- fmt.Printf("kind = %s\n", obj.Kind)
- }
- panic("unreachable")
- }
- return
- }
-
- // resolve type objects
- if typ.Form == Unresolved {
- tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
-
- // provide types for all methods
- for _, obj := range typ.Scope.Objects {
- if obj.Kind == ast.Fun {
- assert(obj.Type == nil)
- obj.Type = NewType(Method)
- f := obj.Decl.(*ast.FuncDecl)
- t := f.Type
- tc.declSignature(obj.Type.(*Type), f.Recv, t.Params, t.Results)
- }
- }
- }
-}
-
-func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
- tc.openScope()
- defer tc.closeScope()
-
- // inject function/method parameters into block scope, if any
- if ftype != nil {
- for _, par := range ftype.Params.Objects {
- if par.Name != "_" {
- alt := tc.topScope.Insert(par)
- assert(alt == nil) // ftype has no double declarations
- }
- }
- }
-
- for _, stmt := range body {
- tc.checkStmt(stmt)
- }
-}
-
-// ----------------------------------------------------------------------------
-// Types
-
-// unparen removes parentheses around x, if any.
-func unparen(x ast.Expr) ast.Expr {
- if ux, hasParens := x.(*ast.ParenExpr); hasParens {
- return unparen(ux.X)
- }
- return x
-}
-
-func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
- if fields != nil {
- for _, f := range fields.List {
- typ := tc.typeFor(nil, f.Type, ref)
- for _, name := range f.Names {
- fld := tc.declInScope(scope, ast.Var, name, f, 0)
- fld.Type = typ
- n++
- }
- }
- }
- return n
-}
-
-func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
- assert((typ.Form == Method) == (recv != nil))
- typ.Params = ast.NewScope(nil)
- tc.declFields(typ.Params, recv, true)
- tc.declFields(typ.Params, params, true)
- typ.N = tc.declFields(typ.Params, results, true)
-}
-
-func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
- x = unparen(x)
-
- // type name
- if t, isIdent := x.(*ast.Ident); isIdent {
- obj := tc.find(t)
-
- if obj.Kind != ast.Typ {
- tc.Errorf(t.Pos(), "%s is not a type", t.Name)
- if def == nil {
- typ = NewType(BadType)
- } else {
- typ = def
- typ.Form = BadType
- }
- typ.Expr = x
- return
- }
-
- if !ref {
- tc.resolve(obj) // check for cycles even if type resolved
- }
- typ = obj.Type.(*Type)
-
- if def != nil {
- // new type declaration: copy type structure
- def.Form = typ.Form
- def.N = typ.N
- def.Key, def.Elt = typ.Key, typ.Elt
- def.Params = typ.Params
- def.Expr = x
- typ = def
- }
- return
- }
-
- // type literal
- typ = def
- if typ == nil {
- typ = NewType(BadType)
- }
- typ.Expr = x
-
- switch t := x.(type) {
- case *ast.SelectorExpr:
- if debug {
- fmt.Println("qualified identifier unimplemented")
- }
- typ.Form = BadType
-
- case *ast.StarExpr:
- typ.Form = Pointer
- typ.Elt = tc.typeFor(nil, t.X, true)
-
- case *ast.ArrayType:
- if t.Len != nil {
- typ.Form = Array
- // TODO(gri) compute the real length
- // (this may call resolve recursively)
- (*typ).N = 42
- } else {
- typ.Form = Slice
- }
- typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
-
- case *ast.StructType:
- typ.Form = Struct
- tc.declFields(typ.Scope, t.Fields, false)
-
- case *ast.FuncType:
- typ.Form = Function
- tc.declSignature(typ, nil, t.Params, t.Results)
-
- case *ast.InterfaceType:
- typ.Form = Interface
- tc.declFields(typ.Scope, t.Methods, true)
-
- case *ast.MapType:
- typ.Form = Map
- typ.Key = tc.typeFor(nil, t.Key, true)
- typ.Elt = tc.typeFor(nil, t.Value, true)
-
- case *ast.ChanType:
- typ.Form = Channel
- typ.N = uint(t.Dir)
- typ.Elt = tc.typeFor(nil, t.Value, true)
-
- default:
- if debug {
- fmt.Printf("x is %T\n", x)
- }
- panic("unreachable")
- }
-
- return
-}
-
-// ----------------------------------------------------------------------------
-// TODO(gri) implement these place holders
-
-func (tc *typechecker) declConst(*ast.Object) {
-}
-
-func (tc *typechecker) declVar(*ast.Object) {
-}
-
-func (tc *typechecker) checkStmt(ast.Stmt) {
-}
diff --git a/src/pkg/go/typechecker/typechecker_test.go b/src/pkg/go/typechecker/typechecker_test.go
deleted file mode 100644
index 4bad4499a..000000000
--- a/src/pkg/go/typechecker/typechecker_test.go
+++ /dev/null
@@ -1,163 +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.
-
-// This file implements a simple typechecker test harness. Packages found
-// in the testDir directory are typechecked. Error messages reported by
-// the typechecker are compared against the error messages expected for
-// the test files.
-//
-// Expected errors are indicated in the test files by putting a comment
-// of the form /* ERROR "rx" */ immediately following an offending token.
-// The harness will verify that an error matching the regular expression
-// rx is reported at that source position. Consecutive comments may be
-// used to indicate multiple errors for the same token position.
-//
-// For instance, the following test file indicates that a "not declared"
-// error should be reported for the undeclared variable x:
-//
-// package P0
-// func f() {
-// _ = x /* ERROR "not declared" */ + 1
-// }
-//
-// If the -pkg flag is set, only packages with package names matching
-// the regular expression provided via the flag value are tested.
-
-package typechecker
-
-import (
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/scanner"
- "go/token"
- "io/ioutil"
- "os"
- "regexp"
- "sort"
- "strings"
- "testing"
-)
-
-const testDir = "./testdata" // location of test packages
-
-var fset = token.NewFileSet()
-
-var (
- pkgPat = flag.String("pkg", ".*", "regular expression to select test packages by package name")
- trace = flag.Bool("trace", false, "print package names")
-)
-
-// ERROR comments must be of the form /* ERROR "rx" */ and rx is
-// a regular expression that matches the expected error message.
-var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
-
-// expectedErrors collects the regular expressions of ERROR comments
-// found in the package files of pkg and returns them in sorted order
-// (by filename and position).
-func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
- // scan all package files
- for filename := range pkg.Files {
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- t.Fatalf("expectedErrors(%s): %v", pkg.Name, err)
- }
-
- var s scanner.Scanner
- file := fset.AddFile(filename, fset.Base(), len(src))
- s.Init(file, src, nil, scanner.ScanComments)
- var prev token.Pos // position of last non-comment token
- loop:
- for {
- pos, tok, lit := s.Scan()
- switch tok {
- case token.EOF:
- break loop
- case token.COMMENT:
- s := errRx.FindStringSubmatch(lit)
- if len(s) == 2 {
- list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
- }
- default:
- prev = pos
- }
- }
- }
- sort.Sort(list) // multiple files may not be sorted
- return
-}
-
-func testFilter(f *os.FileInfo) bool {
- return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
-}
-
-func checkError(t *testing.T, expected, found *scanner.Error) {
- rx, err := regexp.Compile(expected.Msg)
- if err != nil {
- t.Errorf("%s: %v", expected.Pos, err)
- return
- }
-
- match := rx.MatchString(found.Msg)
-
- if expected.Pos.Offset != found.Pos.Offset {
- if match {
- t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
- } else {
- t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
- return
- }
- }
-
- if !match {
- t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
- }
-}
-
-func TestTypeCheck(t *testing.T) {
- flag.Parse()
- pkgRx, err := regexp.Compile(*pkgPat)
- if err != nil {
- t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
- }
-
- pkgs, err := parser.ParseDir(fset, testDir, testFilter, 0)
- if err != nil {
- scanner.PrintError(os.Stderr, err)
- t.Fatalf("packages in %s contain syntax errors", testDir)
- }
-
- for _, pkg := range pkgs {
- if !pkgRx.MatchString(pkg.Name) {
- continue // only test selected packages
- }
-
- if *trace {
- fmt.Println(pkg.Name)
- }
-
- xlist := expectedErrors(t, pkg)
- err := CheckPackage(fset, pkg, nil)
- if err != nil {
- if elist, ok := err.(scanner.ErrorList); ok {
- // verify that errors match
- for i := 0; i < len(xlist) && i < len(elist); i++ {
- checkError(t, xlist[i], elist[i])
- }
- // the correct number or errors must have been found
- if len(xlist) != len(elist) {
- fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
- scanner.PrintError(os.Stderr, elist)
- fmt.Fprintln(os.Stderr)
- t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
- }
- } else {
- t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
- }
- } else if len(xlist) > 0 {
- t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
- }
- }
-}
diff --git a/src/pkg/go/typechecker/universe.go b/src/pkg/go/typechecker/universe.go
deleted file mode 100644
index 81c14a05e..000000000
--- a/src/pkg/go/typechecker/universe.go
+++ /dev/null
@@ -1,36 +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 typechecker
-
-import "go/ast"
-
-// TODO(gri) should this be in package ast?
-
-// The Universe scope contains all predeclared identifiers.
-var Universe *ast.Scope
-
-func def(obj *ast.Object) {
- alt := Universe.Insert(obj)
- if alt != nil {
- panic("object declared twice")
- }
-}
-
-func init() {
- Universe = ast.NewScope(nil)
-
- // basic types
- for n, name := range BasicTypes {
- typ := NewType(Basic)
- typ.N = n
- obj := ast.NewObj(ast.Typ, name)
- obj.Type = typ
- typ.Obj = obj
- def(obj)
- }
-
- // built-in functions
- // TODO(gri) implement this
-}
diff --git a/src/pkg/go/types/Makefile b/src/pkg/go/types/Makefile
deleted file mode 100644
index 4ca707c73..000000000
--- a/src/pkg/go/types/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=go/types
-GOFILES=\
- check.go\
- const.go\
- exportdata.go\
- gcimporter.go\
- types.go\
- universe.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/go/types/check.go b/src/pkg/go/types/check.go
deleted file mode 100644
index 87e3e93da..000000000
--- a/src/pkg/go/types/check.go
+++ /dev/null
@@ -1,226 +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.
-
-// 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/src/pkg/go/types/check_test.go b/src/pkg/go/types/check_test.go
deleted file mode 100644
index 8be653fcb..000000000
--- a/src/pkg/go/types/check_test.go
+++ /dev/null
@@ -1,215 +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.
-
-// 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/src/pkg/go/types/const.go b/src/pkg/go/types/const.go
deleted file mode 100644
index 1ef95d9f9..000000000
--- a/src/pkg/go/types/const.go
+++ /dev/null
@@ -1,332 +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.
-
-// This file implements operations on ideal constants.
-
-package types
-
-import (
- "big"
- "go/token"
- "strconv"
-)
-
-// TODO(gri) Consider changing the API so Const is an interface
-// and operations on consts don't have to type switch.
-
-// A Const implements an ideal constant Value.
-// The zero value z for a Const is not a valid constant value.
-type Const struct {
- // representation of constant values:
- // ideal bool -> bool
- // ideal int -> *big.Int
- // ideal float -> *big.Rat
- // ideal complex -> cmplx
- // ideal string -> string
- 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 {
- switch tok {
- case token.INT:
- var x big.Int
- _, ok := x.SetString(lit, 0)
- assert(ok)
- return Const{&x}
- case token.FLOAT:
- var y big.Rat
- _, ok := y.SetString(lit)
- assert(ok)
- return Const{&y}
- case token.IMAG:
- assert(lit[len(lit)-1] == 'i')
- var im big.Rat
- _, ok := im.SetString(lit[0 : len(lit)-1])
- assert(ok)
- return Const{cmplx{big.NewRat(0, 1), &im}}
- case token.CHAR:
- assert(lit[0] == '\'' && lit[len(lit)-1] == '\'')
- code, _, _, err := strconv.UnquoteChar(lit[1:len(lit)-1], '\'')
- assert(err == nil)
- return Const{big.NewInt(int64(code))}
- case token.STRING:
- s, err := strconv.Unquote(lit)
- assert(err == nil)
- return Const{s}
- }
- 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
-// the results are invalid.
-func (x Const) Match(y Const) (u, v Const) {
- switch a := x.val.(type) {
- case bool:
- if _, ok := y.val.(bool); ok {
- u, v = x, y
- }
- case *big.Int:
- switch y.val.(type) {
- case *big.Int:
- u, v = x, y
- case *big.Rat:
- var z big.Rat
- z.SetInt(a)
- u, v = Const{&z}, y
- case cmplx:
- var z big.Rat
- z.SetInt(a)
- u, v = Const{cmplx{&z, big.NewRat(0, 1)}}, y
- }
- case *big.Rat:
- switch y.val.(type) {
- case *big.Int:
- v, u = y.Match(x)
- case *big.Rat:
- u, v = x, y
- case cmplx:
- u, v = Const{cmplx{a, big.NewRat(0, 0)}}, y
- }
- case cmplx:
- switch y.val.(type) {
- case *big.Int, *big.Rat:
- v, u = y.Match(x)
- case cmplx:
- u, v = x, y
- }
- case string:
- if _, ok := y.val.(string); ok {
- u, v = x, y
- }
- default:
- panic("unreachable")
- }
- 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.
-func (x Const) Convert(typ *Type) Const {
- // TODO(gri) implement this
- switch x := x.val.(type) {
- case bool:
- case *big.Int:
- case *big.Rat:
- case cmplx:
- case string:
- }
- return x
-}
-
-func (x Const) String() string {
- switch x := x.val.(type) {
- case bool:
- if x {
- return "true"
- }
- return "false"
- case *big.Int:
- return x.String()
- case *big.Rat:
- return x.FloatString(10) // 10 digits of precision after decimal point seems fine
- case cmplx:
- // TODO(gri) don't print 0 components
- return x.re.FloatString(10) + " + " + x.im.FloatString(10) + "i"
- case string:
- return x
- }
- 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) {
- case bool:
- z = binaryBoolOp(x, op, y.val.(bool))
- case *big.Int:
- z = binaryIntOp(x, op, y.val.(*big.Int))
- case *big.Rat:
- z = binaryFloatOp(x, op, y.val.(*big.Rat))
- case cmplx:
- z = binaryCmplxOp(x, op, y.val.(cmplx))
- case string:
- z = binaryStringOp(x, op, y.val.(string))
- default:
- panic("unreachable")
- }
- return Const{z}
-}
-
-func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
- switch op {
- case token.EQL:
- return x == y
- case token.NEQ:
- return x != y
- }
- panic("unreachable")
-}
-
-func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
- var z big.Int
- switch op {
- case token.ADD:
- return z.Add(x, y)
- case token.SUB:
- return z.Sub(x, y)
- case token.MUL:
- return z.Mul(x, y)
- case token.QUO:
- return z.Quo(x, y)
- case token.REM:
- return z.Rem(x, y)
- case token.AND:
- return z.And(x, y)
- case token.OR:
- return z.Or(x, y)
- case token.XOR:
- return z.Xor(x, y)
- case token.AND_NOT:
- return z.AndNot(x, y)
- case token.SHL:
- panic("unimplemented")
- case token.SHR:
- panic("unimplemented")
- case token.EQL:
- return x.Cmp(y) == 0
- case token.NEQ:
- return x.Cmp(y) != 0
- case token.LSS:
- return x.Cmp(y) < 0
- case token.LEQ:
- return x.Cmp(y) <= 0
- case token.GTR:
- return x.Cmp(y) > 0
- case token.GEQ:
- return x.Cmp(y) >= 0
- }
- panic("unreachable")
-}
-
-func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
- var z big.Rat
- switch op {
- case token.ADD:
- return z.Add(x, y)
- case token.SUB:
- return z.Sub(x, y)
- case token.MUL:
- return z.Mul(x, y)
- case token.QUO:
- return z.Quo(x, y)
- case token.EQL:
- return x.Cmp(y) == 0
- case token.NEQ:
- return x.Cmp(y) != 0
- case token.LSS:
- return x.Cmp(y) < 0
- case token.LEQ:
- return x.Cmp(y) <= 0
- case token.GTR:
- return x.Cmp(y) > 0
- case token.GEQ:
- return x.Cmp(y) >= 0
- }
- panic("unreachable")
-}
-
-func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
- a, b := x.re, x.im
- c, d := y.re, y.im
- switch op {
- case token.ADD:
- // (a+c) + i(b+d)
- var re, im big.Rat
- re.Add(a, c)
- im.Add(b, d)
- return cmplx{&re, &im}
- case token.SUB:
- // (a-c) + i(b-d)
- var re, im big.Rat
- re.Sub(a, c)
- im.Sub(b, d)
- return cmplx{&re, &im}
- case token.MUL:
- // (ac-bd) + i(bc+ad)
- var ac, bd, bc, ad big.Rat
- ac.Mul(a, c)
- bd.Mul(b, d)
- bc.Mul(b, c)
- ad.Mul(a, d)
- var re, im big.Rat
- re.Sub(&ac, &bd)
- im.Add(&bc, &ad)
- return cmplx{&re, &im}
- case token.QUO:
- // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
- var ac, bd, bc, ad, s big.Rat
- ac.Mul(a, c)
- bd.Mul(b, d)
- bc.Mul(b, c)
- ad.Mul(a, d)
- s.Add(c.Mul(c, c), d.Mul(d, d))
- var re, im big.Rat
- re.Add(&ac, &bd)
- re.Quo(&re, &s)
- im.Sub(&bc, &ad)
- im.Quo(&im, &s)
- return cmplx{&re, &im}
- case token.EQL:
- return a.Cmp(c) == 0 && b.Cmp(d) == 0
- case token.NEQ:
- return a.Cmp(c) != 0 || b.Cmp(d) != 0
- }
- panic("unreachable")
-}
-
-func binaryStringOp(x string, op token.Token, y string) interface{} {
- switch op {
- case token.ADD:
- return x + y
- case token.EQL:
- return x == y
- case token.NEQ:
- return x != y
- case token.LSS:
- return x < y
- case token.LEQ:
- return x <= y
- case token.GTR:
- return x > y
- case token.GEQ:
- return x >= y
- }
- panic("unreachable")
-}
diff --git a/src/pkg/go/types/exportdata.go b/src/pkg/go/types/exportdata.go
deleted file mode 100644
index 383520320..000000000
--- a/src/pkg/go/types/exportdata.go
+++ /dev/null
@@ -1,132 +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.
-
-// This file implements ExportData.
-
-package types
-
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "strconv"
- "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)
- _, err = io.ReadFull(buf, hdr)
- if err != nil {
- return
- }
- if trace {
- fmt.Printf("header: %s", hdr)
- }
- 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.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.
-//
-func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
- file, err := os.Open(filename)
- if err != nil {
- return
- }
-
- defer func() {
- if err != nil {
- file.Close()
- // Add file name to error.
- err = fmt.Errorf("reading export data: %s: %v", filename, err)
- }
- }()
-
- buf := bufio.NewReader(file)
-
- // Read first line to make sure this is an object file.
- line, err := buf.ReadSlice('\n')
- if err != nil {
- return
- }
- if string(line) == "!<arch>\n" {
- // Archive file. Scan to __.PKGDEF, which should
- // be second archive entry.
- var name string
- var size int
-
- // First entry should be __.SYMDEF.
- // Read and discard.
- if name, size, err = readGopackHeader(buf); err != nil {
- return
- }
- if name != "__.SYMDEF" {
- err = os.NewError("go archive does not begin with __.SYMDEF")
- return
- }
- const block = 4096
- tmp := make([]byte, block)
- for size > 0 {
- n := size
- if n > block {
- n = block
- }
- _, err = io.ReadFull(buf, tmp[:n])
- if err != nil {
- return
- }
- size -= n
- }
-
- // Second entry should be __.PKGDEF.
- if name, size, err = readGopackHeader(buf); err != nil {
- return
- }
- if name != "__.PKGDEF" {
- err = os.NewError("go archive is missing __.PKGDEF")
- return
- }
-
- // Read first line of __.PKGDEF data, so that line
- // is once again the first line of the input.
- line, err = buf.ReadSlice('\n')
- if err != nil {
- return
- }
- }
-
- // 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.NewError("not a go object file")
- return
- }
-
- // Skip over object header to export data.
- // Begins after first line with $$.
- for line[0] != '$' {
- line, err = buf.ReadSlice('\n')
- if err != nil {
- return
- }
- }
-
- rc = &dataReader{buf, file}
- return
-}
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
deleted file mode 100644
index 6ab1806b6..000000000
--- a/src/pkg/go/types/gcimporter.go
+++ /dev/null
@@ -1,799 +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.
-
-// This file implements an ast.Importer for gc generated object files.
-// TODO(gri) Eventually move this into a separate package outside types.
-
-package types
-
-import (
- "big"
- "fmt"
- "go/ast"
- "go/token"
- "io"
- "os"
- "path/filepath"
- "runtime"
- "scanner"
- "strconv"
-)
-
-const trace = false // set to true for debugging
-
-var (
- pkgRoot = filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH)
- 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) {
- if len(path) == 0 {
- return
- }
-
- id = path
- var noext string
- switch path[0] {
- default:
- // "x" -> "$GOROOT/pkg/$GOOS_$GOARCH/x.ext", "x"
- noext = filepath.Join(pkgRoot, path)
-
- case '.':
- // "./x" -> "/this/directory/x.ext", "/this/directory/x"
- cwd, err := os.Getwd()
- if err != nil {
- return
- }
- noext = filepath.Join(cwd, path)
- id = noext
-
- case '/':
- // "/x" -> "/x.ext", "/x"
- noext = path
- }
-
- // try extensions
- for _, ext := range pkgExts {
- filename = noext + ext
- if f, err := os.Stat(filename); err == nil && f.IsRegular() {
- return
- }
- }
-
- filename = "" // not found
- 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
- imports map[string]*ast.Object // package id -> package object
-}
-
-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
- p.scanner.Whitespace = 1<<'\t' | 1<<' '
- p.scanner.Filename = filename // for good error messages
- p.next()
- p.id = id
- p.imports = imports
-}
-
-func (p *gcParser) next() {
- p.tok = p.scanner.Scan()
- switch p.tok {
- case scanner.Ident, scanner.Int, scanner.String:
- p.lit = p.scanner.TokenText()
- default:
- p.lit = ""
- }
- if trace {
- fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
- }
-}
-
-// GcImporter implements the ast.Importer signature.
-func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
- if path == "unsafe" {
- return Unsafe, nil
- }
-
- defer func() {
- if r := recover(); r != nil {
- err = r.(importError) // will re-panic if r is not an importError
- if trace {
- panic(err) // force a stack trace
- }
- }
- }()
-
- filename, id := findPkg(path)
- if filename == "" {
- 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
- }
- defer buf.Close()
-
- if trace {
- fmt.Printf("importing %s (%s)\n", id, filename)
- }
-
- var p gcParser
- p.init(filename, id, buf, imports)
- pkg = p.parseExport()
- return
-}
-
-// ----------------------------------------------------------------------------
-// Error handling
-
-// Internal errors are boxed as importErrors.
-type importError struct {
- pos scanner.Position
- 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.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 {
- p.errorf("expected %q, got %q (%q)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
- }
- p.next()
- return lit
-}
-
-func (p *gcParser) expectSpecial(tok string) {
- sep := 'x' // not white space
- i := 0
- for i < len(tok) && p.tok == int(tok[i]) && sep > ' ' {
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- i++
- }
- if i < len(tok) {
- p.errorf("expected %q, got %q", tok, tok[0:i])
- }
-}
-
-func (p *gcParser) expectKeyword(keyword string) {
- lit := p.expect(scanner.Ident)
- if lit != keyword {
- p.errorf("expected keyword %s, got %q", keyword, lit)
- }
-}
-
-// ----------------------------------------------------------------------------
-// Import declarations
-
-// ImportPath = string_lit .
-//
-func (p *gcParser) parsePkgId() *ast.Object {
- id, err := strconv.Unquote(p.expect(scanner.String))
- if err != nil {
- p.error(err)
- }
-
- 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
- }
-
- 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 {
- ident := ""
- if p.tok != scanner.Int {
- sep := 'x' // not white space
- for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
- ident += p.lit
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- }
- }
- if ident == "" {
- p.expect(scanner.Ident) // use expect() for error handling
- }
- return ident
-}
-
-// ExportedName = ImportPath "." dotIdentifier .
-//
-func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
- 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)
- return obj
- }
- }
-
- // any other object must be a newly declared object -
- // create it and insert it into the package scope
- obj := ast.NewObj(kind, name)
- if scope.Insert(obj) != nil {
- p.errorf("already declared: %s", obj.Name)
- }
-
- // a new type object is a named type and may be referred
- // to before the underlying type is known - set it up
- if kind == ast.Typ {
- obj.Type = &Name{Obj: obj}
- }
-
- return obj
-}
-
-// ----------------------------------------------------------------------------
-// Types
-
-// BasicType = identifier .
-//
-func (p *gcParser) parseBasicType() Type {
- obj := Universe.Lookup(p.expect(scanner.Ident))
- if obj == nil || obj.Kind != ast.Typ {
- p.errorf("not a basic type: %s", obj.Name)
- }
- return obj.Type.(Type)
-}
-
-// ArrayType = "[" int_lit "]" Type .
-//
-func (p *gcParser) parseArrayType() Type {
- // "[" already consumed and lookahead known not to be "]"
- lit := p.expect(scanner.Int)
- p.expect(']')
- elt := p.parseType()
- n, err := strconv.Atoui64(lit)
- if err != nil {
- p.error(err)
- }
- return &Array{Len: n, Elt: elt}
-}
-
-// MapType = "map" "[" Type "]" Type .
-//
-func (p *gcParser) parseMapType() Type {
- p.expectKeyword("map")
- p.expect('[')
- key := p.parseType()
- p.expect(']')
- elt := p.parseType()
- return &Map{Key: key, Elt: elt}
-}
-
-// Name = identifier | "?" .
-//
-func (p *gcParser) parseName() (name string) {
- switch p.tok {
- case scanner.Ident:
- name = p.lit
- p.next()
- case '?':
- // anonymous
- p.next()
- default:
- p.error("name expected")
- }
- return
-}
-
-// Field = Name Type [ ":" string_lit ] .
-//
-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
- if _, ok := Deref(ftyp).(*Name); !ok {
- p.errorf("anonymous field expected")
- }
- }
- if p.tok == ':' {
- p.next()
- tag = p.expect(scanner.String)
- }
- fld = ast.NewObj(ast.Var, name)
- fld.Type = ftyp
- 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('{')
- if p.tok != '}' {
- parseField()
- for p.tok == ';' {
- p.next()
- parseField()
- }
- }
- p.expect('}')
-
- return &Struct{Fields: fields, Tags: tags}
-}
-
-// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
-//
-func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
- name := p.parseName()
- if name == "" {
- name = "_" // cannot access unnamed identifiers
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- isVariadic = true
- }
- ptyp := p.parseType()
- // ignore argument tag
- if p.tok == ':' {
- p.next()
- p.expect(scanner.String)
- }
- par = ast.NewObj(ast.Var, name)
- par.Type = ptyp
- return
-}
-
-// Parameters = "(" [ ParameterList ] ")" .
-// ParameterList = { Parameter "," } Parameter .
-//
-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 != ')' {
- parseParameter()
- for p.tok == ',' {
- p.next()
- parseParameter()
- }
- }
- p.expect(')')
-
- return
-}
-
-// Signature = Parameters [ Result ] .
-// Result = Type | Parameters .
-//
-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()
- results = []*ast.Object{result}
- case '(':
- // named or multiple result(s)
- var variadic bool
- results, variadic = p.parseParameters()
- if variadic {
- p.error("... not permitted on result type")
- }
- }
-
- return &Func{Params: params, Results: results, IsVariadic: isVariadic}
-}
-
-// MethodSpec = identifier Signature .
-//
-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()
- }
- 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('{')
- if p.tok != '}' {
- parseMethod()
- for p.tok == ';' {
- p.next()
- parseMethod()
- }
- }
- p.expect('}')
-
- methods.Sort()
- return &Interface{Methods: methods}
-}
-
-// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
-//
-func (p *gcParser) parseChanType() Type {
- dir := ast.SEND | ast.RECV
- if p.tok == scanner.Ident {
- p.expectKeyword("chan")
- if p.tok == '<' {
- p.expectSpecial("<-")
- dir = ast.SEND
- }
- } else {
- p.expectSpecial("<-")
- p.expectKeyword("chan")
- dir = ast.RECV
- }
- elt := p.parseType()
- return &Chan{Dir: dir, Elt: elt}
-}
-
-// Type =
-// BasicType | TypeName | ArrayType | SliceType | StructType |
-// PointerType | FuncType | InterfaceType | MapType | ChanType |
-// "(" Type ")" .
-// BasicType = ident .
-// TypeName = ExportedName .
-// SliceType = "[" "]" Type .
-// PointerType = "*" Type .
-// FuncType = "func" Signature .
-//
-func (p *gcParser) parseType() Type {
- switch p.tok {
- case scanner.Ident:
- switch p.lit {
- default:
- return p.parseBasicType()
- case "struct":
- return p.parseStructType()
- case "func":
- // FuncType
- p.next()
- return p.parseSignature()
- case "interface":
- return p.parseInterfaceType()
- case "map":
- return p.parseMapType()
- case "chan":
- return p.parseChanType()
- }
- case scanner.String:
- // TypeName
- return p.parseExportedName(ast.Typ).Type.(Type)
- case '[':
- p.next() // look ahead
- if p.tok == ']' {
- // SliceType
- p.next()
- return &Slice{Elt: p.parseType()}
- }
- return p.parseArrayType()
- case '*':
- // PointerType
- p.next()
- return &Pointer{Base: p.parseType()}
- case '<':
- return p.parseChanType()
- case '(':
- // "(" Type ")"
- p.next()
- typ := p.parseType()
- p.expect(')')
- return typ
- }
- p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
- return nil
-}
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-// ImportDecl = "import" identifier string_lit .
-//
-func (p *gcParser) parseImportDecl() {
- p.expectKeyword("import")
- // 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.
- 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) {
- switch p.tok {
- case '-':
- p.next()
- sign = "-"
- case '+':
- p.next()
- }
- val = p.expect(scanner.Int)
- return
-}
-
-// number = int_lit [ "p" int_lit ] .
-//
-func (p *gcParser) parseNumber() Const {
- // mantissa
- sign, val := p.parseInt()
- mant, ok := new(big.Int).SetString(sign+val, 10)
- assert(ok)
-
- if p.lit == "p" {
- // exponent (base 2)
- p.next()
- sign, val = p.parseInt()
- exp, err := strconv.Atoui(val)
- if err != nil {
- p.error(err)
- }
- if sign == "-" {
- denom := big.NewInt(1)
- denom.Lsh(denom, exp)
- return Const{new(big.Rat).SetFrac(mant, denom)}
- }
- if exp > 0 {
- mant.Lsh(mant, exp)
- }
- return Const{new(big.Rat).SetInt(mant)}
- }
-
- return Const{mant}
-}
-
-// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
-// Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
-// bool_lit = "true" | "false" .
-// complex_lit = "(" float_lit "+" float_lit ")" .
-// string_lit = `"` { unicode_char } `"` .
-//
-func (p *gcParser) parseConstDecl() {
- p.expectKeyword("const")
- obj := p.parseExportedName(ast.Con)
- var x Const
- var typ Type
- if p.tok != '=' {
- obj.Type = p.parseType()
- }
- p.expect('=')
- switch p.tok {
- case scanner.Ident:
- // bool_lit
- if p.lit != "true" && p.lit != "false" {
- p.error("expected true or false")
- }
- x = Const{p.lit == "true"}
- typ = Bool.Underlying
- p.next()
- case '-', scanner.Int:
- // int_lit
- x = p.parseNumber()
- typ = Int.Underlying
- if _, ok := x.val.(*big.Rat); ok {
- typ = Float64.Underlying
- }
- case '(':
- // complex_lit
- p.next()
- re := p.parseNumber()
- p.expect('+')
- im := p.parseNumber()
- p.expect(')')
- x = Const{cmplx{re.val.(*big.Rat), im.val.(*big.Rat)}}
- typ = Complex128.Underlying
- case scanner.String:
- // string_lit
- x = MakeConst(token.STRING, p.lit)
- p.next()
- typ = String.Underlying
- default:
- p.error("expected literal")
- }
- if obj.Type == nil {
- obj.Type = typ
- }
- 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()
-
- if name := obj.Type.(*Name); name.Underlying == nil {
- assert(Underlying(typ) == typ)
- name.Underlying = typ
- }
-}
-
-// VarDecl = "var" ExportedName Type .
-//
-func (p *gcParser) parseVarDecl() {
- p.expectKeyword("var")
- obj := p.parseExportedName(ast.Var)
- obj.Type = p.parseType()
-}
-
-// FuncDecl = "func" ExportedName Signature .
-//
-func (p *gcParser) parseFuncDecl() {
- // "func" already consumed
- obj := p.parseExportedName(ast.Fun)
- obj.Type = p.parseSignature()
-}
-
-// MethodDecl = "func" Receiver identifier Signature .
-// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
-//
-func (p *gcParser) parseMethodDecl() {
- // "func" already consumed
- p.expect('(')
- p.parseParameter() // receiver
- p.expect(')')
- p.expect(scanner.Ident)
- p.parseSignature()
-}
-
-// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
-//
-func (p *gcParser) parseDecl() {
- switch p.lit {
- case "import":
- p.parseImportDecl()
- case "const":
- p.parseConstDecl()
- case "type":
- p.parseTypeDecl()
- case "var":
- p.parseVarDecl()
- case "func":
- p.next() // look ahead
- if p.tok == '(' {
- p.parseMethodDecl()
- } else {
- p.parseFuncDecl()
- }
- }
- p.expect('\n')
-}
-
-// ----------------------------------------------------------------------------
-// Export
-
-// Export = "PackageClause { Decl } "$$" .
-// PackageClause = "package" identifier [ "safe" ] "\n" .
-//
-func (p *gcParser) parseExport() *ast.Object {
- p.expectKeyword("package")
- name := p.expect(scanner.Ident)
- if p.tok != '\n' {
- // A package is safe if it was compiled with the -u flag,
- // which disables the unsafe package.
- // TODO(gri) remember "safe" package
- p.expectKeyword("safe")
- }
- 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()
- }
-
- if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
- // don't call next()/expect() since reading past the
- // export data may cause scanner errors (e.g. NUL chars)
- p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
- }
-
- if n := p.scanner.ErrorCount; n != 0 {
- p.errorf("expected no scanner errors, got %d", n)
- }
-
- return pkg
-}
diff --git a/src/pkg/go/types/gcimporter_test.go b/src/pkg/go/types/gcimporter_test.go
deleted file mode 100644
index ec87f5d51..000000000
--- a/src/pkg/go/types/gcimporter_test.go
+++ /dev/null
@@ -1,101 +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 types
-
-import (
- "exec"
- "go/ast"
- "io/ioutil"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
- "time"
-)
-
-var gcName, gcPath string // compiler name and path
-
-func init() {
- // determine compiler
- switch runtime.GOARCH {
- case "386":
- gcName = "8g"
- case "amd64":
- gcName = "6g"
- case "arm":
- gcName = "5g"
- default:
- gcName = "unknown-GOARCH-compiler"
- gcPath = gcName
- return
- }
- gcPath, _ = exec.LookPath(gcName)
-}
-
-func compile(t *testing.T, dirname, filename string) {
- 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
- }
- 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(imports, path)
- if err != nil {
- t.Errorf("testPath(%s): %s", path, err)
- return false
- }
- return true
-}
-
-const maxTime = 3e9 // maximum allotted testing time in ns
-
-func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
- dirname := filepath.Join(pkgRoot, dir)
- list, err := ioutil.ReadDir(dirname)
- if err != nil {
- t.Errorf("testDir(%s): %s", dirname, err)
- }
- for _, f := range list {
- if time.Nanoseconds() >= endTime {
- t.Log("testing time used up")
- return
- }
- switch {
- case f.IsRegular():
- // try extensions
- for _, ext := range pkgExts {
- if strings.HasSuffix(f.Name, ext) {
- name := f.Name[0 : len(f.Name)-len(ext)] // remove extension
- if testPath(t, filepath.Join(dir, name)) {
- nimports++
- }
- }
- }
- case f.IsDirectory():
- nimports += testDir(t, filepath.Join(dir, f.Name), endTime)
- }
- }
- return
-}
-
-func TestGcImport(t *testing.T) {
- compile(t, "testdata", "exports.go")
-
- nimports := 0
- if testPath(t, "./testdata/exports") {
- nimports++
- }
- nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages
- t.Logf("tested %d imports", nimports)
-}
diff --git a/src/pkg/go/types/testdata/exports.go b/src/pkg/go/types/testdata/exports.go
deleted file mode 100644
index ed63bf9ad..000000000
--- a/src/pkg/go/types/testdata/exports.go
+++ /dev/null
@@ -1,84 +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.
-
-// This file is used to generate an object file which
-// serves as test file for gcimporter_test.go.
-
-package exports
-
-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`
-)
-
-type (
- T1 int
- T2 [10]int
- T3 []int
- T4 *int
- T5 chan int
- T6a chan<- int
- T6b chan (<-chan int)
- T6c chan<- (chan int)
- T7 <-chan *ast.File
- T8 struct{}
- T9 struct {
- a int
- b, c float32
- d []string `go:"tag"`
- }
- T10 struct {
- T8
- T9
- _ *T10
- }
- T11 map[int]string
- T12 interface{}
- T13 interface {
- m1()
- m2(int) float32
- }
- T14 interface {
- T12
- T13
- m3(x ...struct{}) []T9
- }
- T15 func()
- T16 func(int)
- T17 func(x int)
- T18 func() float32
- T19 func() (x float32)
- T20 func(...interface{})
- T21 struct{ next *T21 }
- T22 struct{ link *T23 }
- T23 struct{ link *T22 }
- T24 *T24
- T25 *T26
- T26 *T27
- T27 *T25
- 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/src/pkg/go/types/testdata/test0.src b/src/pkg/go/types/testdata/test0.src
deleted file mode 100644
index 84a1abe27..000000000
--- a/src/pkg/go/types/testdata/test0.src
+++ /dev/null
@@ -1,154 +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.
-
-// type declarations
-
-package test0
-
-import "unsafe"
-
-const pi = 3.1415
-
-type (
- N undeclared /* ERROR "undeclared" */
- B bool
- I int32
- A [10]P
- T struct {
- x, y P
- }
- P *T
- R (*R)
- F func(A) I
- Y interface {
- f(A) I
- }
- S [](((P)))
- M map[I]F
- C chan<- I
-)
-
-
-type (
- p1 pi /* ERROR "not a package" */ .foo
- p2 unsafe.Pointer
-)
-
-
-type (
- Pi pi /* ERROR "not a type" */
-
- a /* DISABLED "illegal cycle" */ a
- a /* ERROR "redeclared" */ int
-
- // where the cycle error appears depends on the
- // order in which declarations are processed
- // (which depends on the order in which a map
- // is iterated through)
- b c
- c /* DISABLED "illegal cycle" */ d
- d e
- e b
-
- t *t
-
- U V
- V *W
- W U
-
- P1 *S2
- P2 P1
-
- S0 struct {
- }
- S1 struct {
- a, b, c int
- u, v, a /* ERROR "redeclared" */ float32
- }
- S2 struct {
- U // anonymous field
- // TODO(gri) recognize double-declaration below
- // U /* ERROR "redeclared" */ int
- }
- S3 struct {
- x S2
- }
- S4/* DISABLED "illegal cycle" */ struct {
- S4
- }
- S5 struct {
- S6
- }
- S6 /* DISABLED "illegal cycle" */ struct {
- field S7
- }
- S7 struct {
- S5
- }
-
- L1 []L1
- L2 []int
-
- A1 [10]int
- A2 /* DISABLED "illegal cycle" */ [10]A2
- A3 /* DISABLED "illegal cycle" */ [10]struct {
- x A4
- }
- A4 [10]A3
-
- F1 func()
- F2 func(x, y, z float32)
- F3 func(x, y, x /* ERROR "redeclared" */ float32)
- F4 func() (x, y, x /* ERROR "redeclared" */ float32)
- F5 func(x int) (x /* ERROR "redeclared" */ float32)
- F6 func(x ...int)
-
- I1 interface{}
- I2 interface {
- m1()
- }
- I3 interface {
- m1()
- m1 /* ERROR "redeclared" */ ()
- }
- I4 interface {
- m1(x, y, x /* ERROR "redeclared" */ float32)
- m2() (x, y, x /* ERROR "redeclared" */ float32)
- m3(x int) (x /* ERROR "redeclared" */ float32)
- }
- I5 interface {
- m1(I5)
- }
- I6 interface {
- S0 /* ERROR "non-interface" */
- }
- I7 interface {
- I1
- I1
- }
- I8 /* DISABLED "illegal cycle" */ interface {
- I8
- }
- I9 /* DISABLED "illegal cycle" */ interface {
- I10
- }
- I10 interface {
- I11
- }
- I11 interface {
- I9
- }
-
- C1 chan int
- C2 <-chan int
- C3 chan<- C3
- C4 chan C5
- C5 chan C6
- C6 chan C4
-
- M1 map[Last]string
- M2 map[string]M2
-
- Last int
-)
diff --git a/src/pkg/go/types/types.go b/src/pkg/go/types/types.go
deleted file mode 100644
index 3aa896892..000000000
--- a/src/pkg/go/types/types.go
+++ /dev/null
@@ -1,255 +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 UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
-// Package types declares the types used to represent Go types.
-//
-package types
-
-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 {
- ImplementsType
- // TODO(gri) need a field specifying the exact basic type
-}
-
-// An Array represents an array type [Len]Elt.
-type Array struct {
- ImplementsType
- Len uint64
- 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
- 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
- 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
- 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
- Dir ast.ChanDir
- Elt Type
-}
-
-// A Name represents a named type as declared in a type declaration.
-type Name struct {
- ImplementsType
- Underlying Type // nil if not fully declared
- Obj *ast.Object // corresponding declared object
- // 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 {
- if typ, ok := typ.(*Pointer); ok {
- return typ.Base
- }
- 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 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/src/pkg/go/types/universe.go b/src/pkg/go/types/universe.go
deleted file mode 100644
index 6ae88e5f9..000000000
--- a/src/pkg/go/types/universe.go
+++ /dev/null
@@ -1,108 +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.
-
-// FILE UNDER CONSTRUCTION. ANY AND ALL PARTS MAY CHANGE.
-// This file implements the universe and unsafe package scopes.
-
-package types
-
-import "go/ast"
-
-var (
- 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 {
- panic("types internal error: double declaration")
- }
- return obj
-}
-
-func defType(name string) *Name {
- obj := define(ast.Typ, name)
- typ := &Name{Underlying: &Basic{}, Obj: obj}
- obj.Type = typ
- 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,
- Float64,
- Complex128,
- String *Name
-)
-
-func init() {
- scope = ast.NewScope(nil)
- Universe = scope
-
- Bool = defType("bool")
- defType("byte") // TODO(gri) should be an alias for uint8
- defType("complex64")
- Complex128 = defType("complex128")
- defType("float32")
- Float64 = defType("float64")
- defType("int8")
- defType("int16")
- defType("int32")
- defType("int64")
- String = defType("string")
- defType("uint8")
- defType("uint16")
- defType("uint32")
- defType("uint64")
- Int = defType("int")
- defType("uint")
- defType("uintptr")
-
- defConst("true")
- defConst("false")
- defConst("iota")
- defConst("nil")
-
- defFun("append")
- defFun("cap")
- defFun("close")
- defFun("complex")
- defFun("copy")
- defFun("imag")
- defFun("len")
- defFun("make")
- defFun("new")
- defFun("panic")
- defFun("print")
- defFun("println")
- defFun("real")
- defFun("recover")
-
- scope = ast.NewScope(nil)
- Unsafe = ast.NewObj(ast.Pkg, "unsafe")
- Unsafe.Data = scope
-
- defType("Pointer")
-
- defFun("Alignof")
- defFun("New")
- defFun("NewArray")
- defFun("Offsetof")
- defFun("Reflect")
- defFun("Sizeof")
- defFun("Typeof")
- defFun("Unreflect")
-}
diff --git a/src/pkg/gob/Makefile b/src/pkg/gob/Makefile
deleted file mode 100644
index 68007c189..000000000
--- a/src/pkg/gob/Makefile
+++ /dev/null
@@ -1,25 +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.
-
-include ../../Make.inc
-
-TARG=gob
-GOFILES=\
- decode.go\
- decoder.go\
- doc.go\
- encode.go\
- encoder.go\
- error.go\
- type.go\
-
-include ../../Make.pkg
-
-# Help for debugging. Requires adding debug.go to the gob package as well.
-
-dump: dump.$O
- $(LD) -o dump $<
-
-dump.$O: dump.go
- $(GC) $<
diff --git a/src/pkg/hash/Makefile b/src/pkg/hash/Makefile
deleted file mode 100644
index 56071cb33..000000000
--- a/src/pkg/hash/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=hash
-GOFILES=\
- hash.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/hash/adler32/Makefile b/src/pkg/hash/adler32/Makefile
deleted file mode 100644
index 38ce537ba..000000000
--- a/src/pkg/hash/adler32/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=hash/adler32
-GOFILES=\
- adler32.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/hash/adler32/adler32.go b/src/pkg/hash/adler32/adler32.go
index 84943d9ae..64fe68c44 100644
--- a/src/pkg/hash/adler32/adler32.go
+++ b/src/pkg/hash/adler32/adler32.go
@@ -11,10 +11,7 @@
// significant-byte first (network) order.
package adler32
-import (
- "hash"
- "os"
-)
+import "hash"
const (
mod = 65521
@@ -41,6 +38,8 @@ func New() hash.Hash32 {
func (d *digest) Size() int { return Size }
+func (d *digest) BlockSize() int { return 1 }
+
// Add p to the running checksum a, b.
func update(a, b uint32, p []byte) (aa, bb uint32) {
for _, pi := range p {
@@ -67,21 +66,20 @@ func finish(a, b uint32) uint32 {
return b<<16 | a
}
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
+func (d *digest) Write(p []byte) (nn int, err error) {
d.a, d.b = update(d.a, d.b, p)
return len(p), nil
}
func (d *digest) Sum32() uint32 { return finish(d.a, d.b) }
-func (d *digest) Sum() []byte {
- p := make([]byte, 4)
+func (d *digest) Sum(in []byte) []byte {
s := d.Sum32()
- p[0] = byte(s >> 24)
- p[1] = byte(s >> 16)
- p[2] = byte(s >> 8)
- p[3] = byte(s)
- return p
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
+ return in
}
// Checksum returns the Adler-32 checksum of data.
diff --git a/src/pkg/hash/crc32/Makefile b/src/pkg/hash/crc32/Makefile
deleted file mode 100644
index af8a64cf2..000000000
--- a/src/pkg/hash/crc32/Makefile
+++ /dev/null
@@ -1,20 +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.
-
-include ../../../Make.inc
-
-TARG=hash/crc32
-
-ifeq ($(GOARCH), amd64)
- ARCH_GOFILES=crc32_amd64.go
- OFILES=crc32_amd64.6
-else
- ARCH_GOFILES=crc32_generic.go
-endif
-
-GOFILES=\
- crc32.go\
- $(ARCH_GOFILES)
-
-include ../../../Make.pkg
diff --git a/src/pkg/hash/crc32/crc32.go b/src/pkg/hash/crc32/crc32.go
index 0245b1ee8..236d77872 100644
--- a/src/pkg/hash/crc32/crc32.go
+++ b/src/pkg/hash/crc32/crc32.go
@@ -9,7 +9,6 @@ package crc32
import (
"hash"
- "os"
"sync"
)
@@ -95,6 +94,8 @@ func NewIEEE() hash.Hash32 { return New(IEEETable) }
func (d *digest) Size() int { return Size }
+func (d *digest) BlockSize() int { return 1 }
+
func (d *digest) Reset() { d.crc = 0 }
func update(crc uint32, tab *Table, p []byte) uint32 {
@@ -113,21 +114,20 @@ func Update(crc uint32, tab *Table, p []byte) uint32 {
return update(crc, tab, p)
}
-func (d *digest) Write(p []byte) (n int, err os.Error) {
+func (d *digest) Write(p []byte) (n int, err error) {
d.crc = Update(d.crc, d.tab, p)
return len(p), nil
}
func (d *digest) Sum32() uint32 { return d.crc }
-func (d *digest) Sum() []byte {
- p := make([]byte, 4)
+func (d *digest) Sum(in []byte) []byte {
s := d.Sum32()
- p[0] = byte(s >> 24)
- p[1] = byte(s >> 16)
- p[2] = byte(s >> 8)
- p[3] = byte(s)
- return p
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
+ return in
}
// Checksum returns the CRC-32 checksum of data
diff --git a/src/pkg/hash/crc32/crc32_generic.go b/src/pkg/hash/crc32/crc32_generic.go
index 27aabd903..c3fdcd685 100644
--- a/src/pkg/hash/crc32/crc32_generic.go
+++ b/src/pkg/hash/crc32/crc32_generic.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.
+// +build 386 arm
+
package crc32
// The file contains the generic version of updateCastagnoli which just calls
diff --git a/src/pkg/hash/crc64/Makefile b/src/pkg/hash/crc64/Makefile
deleted file mode 100644
index 5f6c3de69..000000000
--- a/src/pkg/hash/crc64/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=hash/crc64
-GOFILES=\
- crc64.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/hash/crc64/crc64.go b/src/pkg/hash/crc64/crc64.go
index ae37e781c..5b64390f3 100644
--- a/src/pkg/hash/crc64/crc64.go
+++ b/src/pkg/hash/crc64/crc64.go
@@ -7,10 +7,7 @@
// information.
package crc64
-import (
- "hash"
- "os"
-)
+import "hash"
// The size of a CRC-64 checksum in bytes.
const Size = 8
@@ -56,6 +53,8 @@ func New(tab *Table) hash.Hash64 { return &digest{0, tab} }
func (d *digest) Size() int { return Size }
+func (d *digest) BlockSize() int { return 1 }
+
func (d *digest) Reset() { d.crc = 0 }
func update(crc uint64, tab *Table, p []byte) uint64 {
@@ -71,25 +70,24 @@ func Update(crc uint64, tab *Table, p []byte) uint64 {
return update(crc, tab, p)
}
-func (d *digest) Write(p []byte) (n int, err os.Error) {
+func (d *digest) Write(p []byte) (n int, err error) {
d.crc = update(d.crc, d.tab, p)
return len(p), nil
}
func (d *digest) Sum64() uint64 { return d.crc }
-func (d *digest) Sum() []byte {
- p := make([]byte, 8)
+func (d *digest) Sum(in []byte) []byte {
s := d.Sum64()
- p[0] = byte(s >> 56)
- p[1] = byte(s >> 48)
- p[2] = byte(s >> 40)
- p[3] = byte(s >> 32)
- p[4] = byte(s >> 24)
- p[5] = byte(s >> 16)
- p[6] = byte(s >> 8)
- p[7] = byte(s)
- return p
+ in = append(in, byte(s>>56))
+ in = append(in, byte(s>>48))
+ in = append(in, byte(s>>40))
+ in = append(in, byte(s>>32))
+ in = append(in, byte(s>>24))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s))
+ return in
}
// Checksum returns the CRC-64 checksum of data
diff --git a/src/pkg/hash/fnv/Makefile b/src/pkg/hash/fnv/Makefile
deleted file mode 100644
index 4c8a4ecf0..000000000
--- a/src/pkg/hash/fnv/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=hash/fnv
-GOFILES=\
- fnv.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
index 3ff7d7c75..ea5019818 100644
--- a/src/pkg/hash/fnv/fnv.go
+++ b/src/pkg/hash/fnv/fnv.go
@@ -8,9 +8,7 @@
package fnv
import (
- "encoding/binary"
"hash"
- "os"
)
type (
@@ -61,7 +59,7 @@ func (s *sum32a) Sum32() uint32 { return uint32(*s) }
func (s *sum64) Sum64() uint64 { return uint64(*s) }
func (s *sum64a) Sum64() uint64 { return uint64(*s) }
-func (s *sum32) Write(data []byte) (int, os.Error) {
+func (s *sum32) Write(data []byte) (int, error) {
hash := *s
for _, c := range data {
hash *= prime32
@@ -71,7 +69,7 @@ func (s *sum32) Write(data []byte) (int, os.Error) {
return len(data), nil
}
-func (s *sum32a) Write(data []byte) (int, os.Error) {
+func (s *sum32a) Write(data []byte) (int, error) {
hash := *s
for _, c := range data {
hash ^= sum32a(c)
@@ -81,7 +79,7 @@ func (s *sum32a) Write(data []byte) (int, os.Error) {
return len(data), nil
}
-func (s *sum64) Write(data []byte) (int, os.Error) {
+func (s *sum64) Write(data []byte) (int, error) {
hash := *s
for _, c := range data {
hash *= prime64
@@ -91,7 +89,7 @@ func (s *sum64) Write(data []byte) (int, os.Error) {
return len(data), nil
}
-func (s *sum64a) Write(data []byte) (int, os.Error) {
+func (s *sum64a) Write(data []byte) (int, error) {
hash := *s
for _, c := range data {
hash ^= sum64a(c)
@@ -106,26 +104,51 @@ func (s *sum32a) Size() int { return 4 }
func (s *sum64) Size() int { return 8 }
func (s *sum64a) Size() int { return 8 }
-func (s *sum32) Sum() []byte {
- a := make([]byte, 4)
- binary.BigEndian.PutUint32(a, uint32(*s))
- return a
+func (s *sum32) BlockSize() int { return 1 }
+func (s *sum32a) BlockSize() int { return 1 }
+func (s *sum64) BlockSize() int { return 1 }
+func (s *sum64a) BlockSize() int { return 1 }
+
+func (s *sum32) Sum(in []byte) []byte {
+ v := uint32(*s)
+ in = append(in, byte(v>>24))
+ in = append(in, byte(v>>16))
+ in = append(in, byte(v>>8))
+ in = append(in, byte(v))
+ return in
}
-func (s *sum32a) Sum() []byte {
- a := make([]byte, 4)
- binary.BigEndian.PutUint32(a, uint32(*s))
- return a
+func (s *sum32a) Sum(in []byte) []byte {
+ v := uint32(*s)
+ in = append(in, byte(v>>24))
+ in = append(in, byte(v>>16))
+ in = append(in, byte(v>>8))
+ in = append(in, byte(v))
+ return in
}
-func (s *sum64) Sum() []byte {
- a := make([]byte, 8)
- binary.BigEndian.PutUint64(a, uint64(*s))
- return a
+func (s *sum64) Sum(in []byte) []byte {
+ v := uint64(*s)
+ in = append(in, byte(v>>56))
+ in = append(in, byte(v>>48))
+ in = append(in, byte(v>>40))
+ in = append(in, byte(v>>32))
+ in = append(in, byte(v>>24))
+ in = append(in, byte(v>>16))
+ in = append(in, byte(v>>8))
+ in = append(in, byte(v))
+ return in
}
-func (s *sum64a) Sum() []byte {
- a := make([]byte, 8)
- binary.BigEndian.PutUint64(a, uint64(*s))
- return a
+func (s *sum64a) Sum(in []byte) []byte {
+ v := uint64(*s)
+ in = append(in, byte(v>>56))
+ in = append(in, byte(v>>48))
+ in = append(in, byte(v>>40))
+ in = append(in, byte(v>>32))
+ in = append(in, byte(v>>24))
+ in = append(in, byte(v>>16))
+ in = append(in, byte(v>>8))
+ in = append(in, byte(v))
+ return in
}
diff --git a/src/pkg/hash/fnv/fnv_test.go b/src/pkg/hash/fnv/fnv_test.go
index 429230c80..17454deda 100644
--- a/src/pkg/hash/fnv/fnv_test.go
+++ b/src/pkg/hash/fnv/fnv_test.go
@@ -72,7 +72,7 @@ func testGolden(t *testing.T, hash hash.Hash, gold []golden) {
if done != len(g.text) {
t.Fatalf("wrote only %d out of %d bytes", done, len(g.text))
}
- if actual := hash.Sum(); !bytes.Equal(g.sum, actual) {
+ if actual := hash.Sum(nil); !bytes.Equal(g.sum, actual) {
t.Errorf("hash(%q) = 0x%x want 0x%x", g.text, actual, g.sum)
}
}
@@ -97,26 +97,26 @@ func TestIntegrity64a(t *testing.T) {
func testIntegrity(t *testing.T, h hash.Hash) {
data := []byte{'1', '2', 3, 4, 5}
h.Write(data)
- sum := h.Sum()
+ sum := h.Sum(nil)
if size := h.Size(); size != len(sum) {
t.Fatalf("Size()=%d but len(Sum())=%d", size, len(sum))
}
- if a := h.Sum(); !bytes.Equal(sum, a) {
+ if a := h.Sum(nil); !bytes.Equal(sum, a) {
t.Fatalf("first Sum()=0x%x, second Sum()=0x%x", sum, a)
}
h.Reset()
h.Write(data)
- if a := h.Sum(); !bytes.Equal(sum, a) {
+ if a := h.Sum(nil); !bytes.Equal(sum, a) {
t.Fatalf("Sum()=0x%x, but after Reset() Sum()=0x%x", sum, a)
}
h.Reset()
h.Write(data[:2])
h.Write(data[2:])
- if a := h.Sum(); !bytes.Equal(sum, a) {
+ if a := h.Sum(nil); !bytes.Equal(sum, a) {
t.Fatalf("Sum()=0x%x, but with partial writes, Sum()=0x%x", sum, a)
}
@@ -162,6 +162,6 @@ func benchmark(b *testing.B, h hash.Hash) {
for todo := b.N; todo != 0; todo-- {
h.Reset()
h.Write(data)
- h.Sum()
+ h.Sum(nil)
}
}
diff --git a/src/pkg/hash/hash.go b/src/pkg/hash/hash.go
index 3536c0b6a..aa895cf98 100644
--- a/src/pkg/hash/hash.go
+++ b/src/pkg/hash/hash.go
@@ -13,15 +13,21 @@ type Hash interface {
// It never returns an error.
io.Writer
- // Sum returns the current hash, without changing the
- // underlying hash state.
- Sum() []byte
+ // Sum appends the current hash to b and returns the resulting slice.
+ // It does not change the underlying hash state.
+ Sum(b []byte) []byte
// Reset resets the hash to one with zero bytes written.
Reset()
// Size returns the number of bytes Sum will return.
Size() int
+
+ // BlockSize returns the hash's underlying block size.
+ // The Write method must be able to accept any amount
+ // of data, but it may operate more efficiently if all writes
+ // are a multiple of the block size.
+ BlockSize() int
}
// Hash32 is the common interface implemented by all 32-bit hash functions.
diff --git a/src/pkg/html/Makefile b/src/pkg/html/Makefile
deleted file mode 100644
index 28dc1a3f5..000000000
--- a/src/pkg/html/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=html
-GOFILES=\
- const.go\
- doc.go\
- entity.go\
- escape.go\
- node.go\
- parse.go\
- token.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/html/const.go b/src/pkg/html/const.go
deleted file mode 100644
index 9078d2601..000000000
--- a/src/pkg/html/const.go
+++ /dev/null
@@ -1,90 +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 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/src/pkg/html/doc.go b/src/pkg/html/doc.go
deleted file mode 100644
index 5bc063086..000000000
--- a/src/pkg/html/doc.go
+++ /dev/null
@@ -1,110 +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 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.
-
- z := html.NewTokenizer(r)
-
-Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
-which parses the next token and returns its type, or an error:
-
- for {
- tt := z.Next()
- if tt == html.ErrorToken {
- // ...
- return ...
- }
- // Process the current token.
- }
-
-There are two APIs for retrieving the current token. The high-level API is to
-call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
-allow optionally calling Raw after Next but before Token, Text, TagName, or
-TagAttr. In EBNF notation, the valid call sequence per token is:
-
- Next {Raw} [ Token | Text | TagName {TagAttr} ]
-
-Token returns an independent data structure that completely describes a token.
-Entities (such as "&lt;") are unescaped, tag names and attribute keys are
-lower-cased, and attributes are collected into a []Attribute. For example:
-
- for {
- if z.Next() == html.ErrorToken {
- // Returning os.EOF indicates success.
- return z.Error()
- }
- emitToken(z.Token())
- }
-
-The low-level API performs fewer allocations and copies, but the contents of
-the []byte values returned by Text, TagName and TagAttr may change on the next
-call to Next. For example, to extract an HTML page's anchor text:
-
- depth := 0
- for {
- tt := z.Next()
- switch tt {
- case ErrorToken:
- return z.Error()
- case TextToken:
- if depth > 0 {
- // emitBytes should copy the []byte it receives,
- // if it doesn't process it immediately.
- emitBytes(z.Text())
- }
- case StartTagToken, EndTagToken:
- tn, _ := z.TagName()
- if len(tn) == 1 && tn[0] == 'a' {
- if tt == StartTag {
- depth++
- } else {
- depth--
- }
- }
- }
- }
-
-A Tokenizer typically skips over HTML comments. To return comment tokens, set
-Tokenizer.ReturnComments to true before looping over calls to Next.
-
-Parsing is done by calling Parse with an io.Reader, which returns the root of
-the parse tree (the document element) as a *Node. It is the caller's
-responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
-example, to process each anchor node in depth-first order:
-
- doc, err := html.Parse(r)
- if err != nil {
- // ...
- }
- var f func(*html.Node)
- f = func(n *html.Node) {
- if n.Type == html.ElementNode && n.Data == "a" {
- // Do something with n...
- }
- for _, c := range n.Child {
- f(c)
- }
- }
- f(doc)
-
-The relevant specifications include:
-http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
-http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
-*/
-package html
-
-// The tokenization algorithm implemented by this package is not a line-by-line
-// transliteration of the relatively verbose state-machine in the WHATWG
-// specification. A more direct approach is used instead, where the program
-// counter implies the state, such as whether it is tokenizing a tag or a text
-// node. Specification compliance is verified by checking expected and actual
-// outputs over a test suite rather than aiming for algorithmic fidelity.
-
-// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
-// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/src/pkg/html/entity.go b/src/pkg/html/entity.go
index 21263e22d..bd8307523 100644
--- a/src/pkg/html/entity.go
+++ b/src/pkg/html/entity.go
@@ -13,7 +13,7 @@ const longestEntityWithoutSemicolon = 6
//
// Note that the HTML5 list is larger than the HTML4 list at
// http://www.w3.org/TR/html4/sgml/entities.html
-var entity = map[string]int{
+var entity = map[string]rune{
"AElig;": '\U000000C6',
"AMP;": '\U00000026',
"Aacute;": '\U000000C1',
@@ -2155,7 +2155,7 @@ var entity = map[string]int{
}
// HTML entities that are two unicode codepoints.
-var entity2 = map[string][2]int{
+var entity2 = map[string][2]rune{
// TODO(nigeltao): Handle replacements that are wider than their names.
// "nLt;": {'\u226A', '\u20D2'},
// "nGt;": {'\u226B', '\u20D2'},
diff --git a/src/pkg/html/entity_test.go b/src/pkg/html/entity_test.go
index 2cf49d61d..b53f866fa 100644
--- a/src/pkg/html/entity_test.go
+++ b/src/pkg/html/entity_test.go
@@ -6,7 +6,7 @@ package html
import (
"testing"
- "utf8"
+ "unicode/utf8"
)
func TestEntityLength(t *testing.T) {
diff --git a/src/pkg/html/escape.go b/src/pkg/html/escape.go
index 0de97c5ac..fee771a57 100644
--- a/src/pkg/html/escape.go
+++ b/src/pkg/html/escape.go
@@ -2,18 +2,23 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Package html provides functions for escaping and unescaping HTML text.
package html
import (
"bytes"
"strings"
- "utf8"
+ "unicode/utf8"
)
+type writer interface {
+ WriteString(string) (int, error)
+}
+
// These replacements permit compatibility with old numeric entities that
// assumed Windows-1252 encoding.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
-var replacementTable = [...]int{
+var replacementTable = [...]rune{
'\u20AC', // First entry is what 0x80 should be replaced with.
'\u0081',
'\u201A',
@@ -78,23 +83,23 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
i++
}
- x := 0
+ x := '\x00'
for i < len(s) {
c = s[i]
i++
if hex {
if '0' <= c && c <= '9' {
- x = 16*x + int(c) - '0'
+ x = 16*x + rune(c) - '0'
continue
} else if 'a' <= c && c <= 'f' {
- x = 16*x + int(c) - 'a' + 10
+ x = 16*x + rune(c) - 'a' + 10
continue
} else if 'A' <= c && c <= 'F' {
- x = 16*x + int(c) - 'A' + 10
+ x = 16*x + rune(c) - 'A' + 10
continue
}
} else if '0' <= c && c <= '9' {
- x = 10*x + int(c) - '0'
+ x = 10*x + rune(c) - '0'
continue
}
if c != ';' {
@@ -182,12 +187,24 @@ func unescape(b []byte) []byte {
return b
}
+// lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
+func lower(b []byte) []byte {
+ for i, c := range b {
+ if 'A' <= c && c <= 'Z' {
+ b[i] = c + 'a' - 'A'
+ }
+ }
+ return b
+}
+
const escapedChars = `&'<>"`
-func escape(buf *bytes.Buffer, s string) {
+func escape(w writer, s string) error {
i := strings.IndexAny(s, escapedChars)
for i != -1 {
- buf.WriteString(s[0:i])
+ if _, err := w.WriteString(s[:i]); err != nil {
+ return err
+ }
var esc string
switch s[i] {
case '&':
@@ -204,10 +221,13 @@ func escape(buf *bytes.Buffer, s string) {
panic("unrecognized escape character")
}
s = s[i+1:]
- buf.WriteString(esc)
+ if _, err := w.WriteString(esc); err != nil {
+ return err
+ }
i = strings.IndexAny(s, escapedChars)
}
- buf.WriteString(s)
+ _, err := w.WriteString(s)
+ return err
}
// EscapeString escapes special characters like "<" to become "&lt;". It
@@ -218,8 +238,8 @@ func EscapeString(s string) string {
if strings.IndexAny(s, escapedChars) == -1 {
return s
}
- buf := bytes.NewBuffer(nil)
- escape(buf, s)
+ var buf bytes.Buffer
+ escape(&buf, s)
return buf.String()
}
diff --git a/src/pkg/html/node.go b/src/pkg/html/node.go
deleted file mode 100644
index 4ecfd6ca2..000000000
--- a/src/pkg/html/node.go
+++ /dev/null
@@ -1,147 +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 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/src/pkg/html/parse.go b/src/pkg/html/parse.go
deleted file mode 100644
index 519ebe587..000000000
--- a/src/pkg/html/parse.go
+++ /dev/null
@@ -1,800 +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 html
-
-import (
- "io"
- "os"
-)
-
-// A parser implements the HTML5 parsing algorithm:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
-type parser struct {
- // tokenizer provides the tokens for the parser.
- tokenizer *Tokenizer
- // tok is the most recently read token.
- tok Token
- // Self-closing tags like <hr/> are re-interpreted as a two-token sequence:
- // <hr> followed by </hr>. hasSelfClosingToken is true if we have just read
- // the synthetic start tag and the next one due is the matching end tag.
- hasSelfClosingToken bool
- // doc is the document root element.
- doc *Node
- // The stack of open elements (section 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 11.2.3.5).
- scripting, framesetOK bool
-}
-
-func (p *parser) top() *Node {
- if n := p.oe.top(); n != nil {
- return n
- }
- return p.doc
-}
-
-// 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"}
- buttonScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "button"}
- tableScopeStopTags = []string{"html", "table"}
-)
-
-// popUntil pops the stack of open elements at the highest element whose tag
-// is in matchTags, provided there is no higher element in stopTags. It returns
-// whether or not there was such an element. If there was not, popUntil leaves
-// the stack unchanged.
-//
-// For example, if the stack was:
-// ["html", "body", "font", "table", "b", "i", "u"]
-// then popUntil([]string{"html, "table"}, "font") would return false, but
-// popUntil([]string{"html, "table"}, "i") would return true and the resultant
-// stack would be:
-// ["html", "body", "font", "table", "b"]
-//
-// If an element's tag is in both stopTags and matchTags, then the stack will
-// be popped and the function returns true (provided, of course, there was no
-// higher element in the stack that was also in stopTags). For example,
-// popUntil([]string{"html, "table"}, "table") would return true and leave:
-// ["html", "body", "font"]
-func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
- for i := len(p.oe) - 1; i >= 0; i-- {
- tag := p.oe[i].Data
- for _, t := range matchTags {
- if t == tag {
- p.oe = p.oe[:i]
- return true
- }
- }
- for _, t := range stopTags {
- if t == tag {
- return false
- }
- }
- }
- return false
-}
-
-// addChild adds a child node n to the top element, and pushes n onto the stack
-// of open elements if it is an element node.
-func (p *parser) addChild(n *Node) {
- p.top().Add(n)
- if n.Type == ElementNode {
- p.oe = append(p.oe, n)
- }
-}
-
-// 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: 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,
- })
-}
-
-// addElement calls addChild with an element node.
-func (p *parser) addElement(tag string, attr []Attribute) {
- p.addChild(&Node{
- Type: ElementNode,
- Data: tag,
- Attr: attr,
- })
-}
-
-// Section 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 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() {
- 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
-// be the synthesized end tag implied by a self-closing tag.
-func (p *parser) read() os.Error {
- if p.hasSelfClosingToken {
- p.hasSelfClosingToken = false
- p.tok.Type = EndTagToken
- p.tok.Attr = nil
- return nil
- }
- p.tokenizer.Next()
- p.tok = p.tokenizer.Token()
- switch p.tok.Type {
- case ErrorToken:
- return p.tokenizer.Error()
- case SelfClosingTagToken:
- p.hasSelfClosingToken = true
- p.tok.Type = StartTagToken
- }
- return nil
-}
-
-// Section 11.2.4.
-func (p *parser) acknowledgeSelfClosingTag() {
- p.hasSelfClosingToken = false
-}
-
-// 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
-// the token was consumed.
-type insertionMode func(*parser) (insertionMode, bool)
-
-// useTheRulesFor runs the delegate insertionMode over p, returning the actual
-// insertionMode unless the delegate caused a state transition.
-// Section 11.2.3.1, "using the rules for".
-func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
- im, consumed := delegate(p)
- if im != delegate {
- return im, consumed
- }
- return actual, consumed
-}
-
-// Section 11.2.5.4.1.
-func initialIM(p *parser) (insertionMode, bool) {
- 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 11.2.5.4.2.
-func beforeHTMLIM(p *parser) (insertionMode, bool) {
- var (
- add bool
- attr []Attribute
- implied bool
- )
- switch p.tok.Type {
- case ErrorToken:
- implied = true
- case TextToken:
- // TODO: distinguish whitespace text from others.
- implied = true
- case StartTagToken:
- if p.tok.Data == "html" {
- add = true
- attr = p.tok.Attr
- } else {
- implied = true
- }
- case EndTagToken:
- switch p.tok.Data {
- case "head", "body", "html", "br":
- implied = true
- default:
- // Ignore the token.
- }
- }
- if add || implied {
- p.addElement("html", attr)
- }
- return beforeHeadIM, !implied
-}
-
-// Section 11.2.5.4.3.
-func beforeHeadIM(p *parser) (insertionMode, bool) {
- var (
- add bool
- attr []Attribute
- implied bool
- )
- switch p.tok.Type {
- case ErrorToken:
- implied = true
- case TextToken:
- // TODO: distinguish whitespace text from others.
- implied = true
- case StartTagToken:
- switch p.tok.Data {
- case "head":
- add = true
- attr = p.tok.Attr
- case "html":
- return useTheRulesFor(p, beforeHeadIM, inBodyIM)
- default:
- implied = true
- }
- case EndTagToken:
- switch p.tok.Data {
- case "head", "body", "html", "br":
- implied = true
- default:
- // Ignore the token.
- }
- }
- if add || implied {
- p.addElement("head", attr)
- }
- return inHeadIM, !implied
-}
-
-// Section 11.2.5.4.4.
-func inHeadIM(p *parser) (insertionMode, bool) {
- var (
- pop bool
- implied bool
- )
- switch p.tok.Type {
- case ErrorToken, TextToken:
- implied = true
- case StartTagToken:
- switch p.tok.Data {
- case "meta":
- // TODO.
- case "script":
- // TODO.
- default:
- implied = true
- }
- case EndTagToken:
- if p.tok.Data == "head" {
- pop = true
- }
- // TODO.
- }
- if pop || implied {
- n := p.oe.pop()
- if n.Data != "head" {
- panic("html: bad parser state")
- }
- return afterHeadIM, !implied
- }
- return inHeadIM, !implied
-}
-
-// Section 11.2.5.4.6.
-func afterHeadIM(p *parser) (insertionMode, bool) {
- var (
- add bool
- attr []Attribute
- framesetOK bool
- implied bool
- )
- switch p.tok.Type {
- case ErrorToken, TextToken:
- implied = true
- framesetOK = true
- case StartTagToken:
- switch p.tok.Data {
- case "html":
- // TODO.
- case "body":
- add = true
- attr = p.tok.Attr
- framesetOK = false
- case "frameset":
- // TODO.
- case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title":
- // TODO.
- case "head":
- // TODO.
- default:
- implied = true
- framesetOK = true
- }
- case EndTagToken:
- // TODO.
- }
- if add || implied {
- p.addElement("body", attr)
- p.framesetOK = framesetOK
- }
- return inBodyIM, !implied
-}
-
-// Section 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 11.2.3.2.
- n := p.top()
- if n.Type == ElementNode && n.Data == "p" {
- endP = true
- } else {
- p.addElement(p.tok.Data, p.tok.Attr)
- }
- case "h1", "h2", "h3", "h4", "h5", "h6":
- // TODO: auto-insert </p> if necessary.
- switch n := p.top(); n.Data {
- case "h1", "h2", "h3", "h4", "h5", "h6":
- p.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.oe.pop()
- p.acknowledgeSelfClosingTag()
- p.framesetOK = false
- case "table":
- // TODO: auto-insert </p> if necessary, depending on quirks mode.
- p.addElement(p.tok.Data, p.tok.Attr)
- p.framesetOK = false
- return inTableIM, true
- case "hr":
- // TODO: auto-insert </p> if necessary.
- p.addElement(p.tok.Data, p.tok.Attr)
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- p.framesetOK = false
- default:
- // TODO.
- p.addElement(p.tok.Data, p.tok.Attr)
- }
- case EndTagToken:
- switch p.tok.Data {
- case "body":
- // TODO: autoclose the stack of open elements.
- return afterBodyIM, true
- case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u":
- p.inBodyEndTagFormatting(p.tok.Data)
- default:
- // TODO: any other end tag
- if p.tok.Data == p.top().Data {
- p.oe.pop()
- }
- }
- }
- if endP {
- // TODO: do the proper algorithm.
- n := p.oe.pop()
- if n.Type != ElementNode || n.Data != "p" {
- panic("unreachable")
- }
- }
- return inBodyIM, !endP
-}
-
-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
- data string
- attr []Attribute
- consumed bool
- )
- switch p.tok.Type {
- case ErrorToken:
- // Stop parsing.
- return nil, true
- case TextToken:
- // TODO.
- case StartTagToken:
- switch p.tok.Data {
- case "tbody", "tfoot", "thead":
- add = true
- data = p.tok.Data
- attr = p.tok.Attr
- consumed = true
- case "td", "th", "tr":
- add = true
- data = "tbody"
- default:
- // TODO.
- }
- case EndTagToken:
- switch p.tok.Data {
- case "table":
- if p.popUntil(tableScopeStopTags, "table") {
- // TODO: "reset the insertion mode appropriately" as per 11.2.3.1.
- return inBodyIM, false
- }
- // Ignore the token.
- return inTableIM, true
- case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
- // Ignore the token.
- return inTableIM, true
- }
- }
- if add {
- // TODO: clear the stack back to a table context.
- p.addElement(data, attr)
- return inTableBodyIM, consumed
- }
- // TODO: return useTheRulesFor(inTableIM, inBodyIM, p) unless etc. etc. foster parenting.
- return inTableIM, true
-}
-
-// Section 11.2.5.4.13.
-func inTableBodyIM(p *parser) (insertionMode, bool) {
- var (
- add bool
- data string
- attr []Attribute
- consumed bool
- )
- switch p.tok.Type {
- case ErrorToken:
- // TODO.
- case TextToken:
- // TODO.
- case StartTagToken:
- switch p.tok.Data {
- case "tr":
- add = true
- data = p.tok.Data
- attr = p.tok.Attr
- consumed = true
- case "td", "th":
- add = true
- data = "tr"
- consumed = false
- default:
- // TODO.
- }
- case EndTagToken:
- switch p.tok.Data {
- case "table":
- if p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
- return inTableIM, false
- }
- // Ignore the token.
- return inTableBodyIM, true
- case "body", "caption", "col", "colgroup", "html", "td", "th", "tr":
- // Ignore the token.
- return inTableBodyIM, true
- }
- }
- if add {
- // TODO: clear the stack back to a table body context.
- p.addElement(data, attr)
- return inRowIM, consumed
- }
- return useTheRulesFor(p, inTableBodyIM, inTableIM)
-}
-
-// Section 11.2.5.4.14.
-func inRowIM(p *parser) (insertionMode, bool) {
- switch p.tok.Type {
- case ErrorToken:
- // TODO.
- case TextToken:
- // TODO.
- case StartTagToken:
- switch p.tok.Data {
- case "td", "th":
- // TODO: clear the stack back to a table row context.
- p.addElement(p.tok.Data, p.tok.Attr)
- p.afe = append(p.afe, &scopeMarker)
- return inCellIM, true
- default:
- // TODO.
- }
- case EndTagToken:
- switch p.tok.Data {
- case "tr":
- // TODO.
- case "table":
- if p.popUntil(tableScopeStopTags, "tr") {
- return inTableBodyIM, false
- }
- // Ignore the token.
- return inRowIM, true
- case "tbody", "tfoot", "thead":
- // TODO.
- case "body", "caption", "col", "colgroup", "html", "td", "th":
- // Ignore the token.
- return inRowIM, true
- default:
- // TODO.
- }
- }
- return useTheRulesFor(p, inRowIM, inTableIM)
-}
-
-// Section 11.2.5.4.15.
-func inCellIM(p *parser) (insertionMode, bool) {
- var (
- closeTheCellAndReprocess bool
- )
- switch p.tok.Type {
- case StartTagToken:
- switch p.tok.Data {
- case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr":
- // TODO: check for "td" or "th" in table scope.
- closeTheCellAndReprocess = true
- }
- case EndTagToken:
- switch p.tok.Data {
- case "td", "th":
- // TODO.
- case "body", "caption", "col", "colgroup", "html":
- // TODO.
- case "table", "tbody", "tfoot", "thead", "tr":
- // TODO: check for matching element in table scope.
- closeTheCellAndReprocess = true
- }
- }
- if closeTheCellAndReprocess {
- if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
- p.clearActiveFormattingElements()
- return inRowIM, false
- }
- }
- return useTheRulesFor(p, inCellIM, inBodyIM)
-}
-
-// Section 11.2.5.4.18.
-func afterBodyIM(p *parser) (insertionMode, bool) {
- switch p.tok.Type {
- case ErrorToken:
- // TODO.
- case TextToken:
- // TODO.
- case StartTagToken:
- // TODO.
- case EndTagToken:
- switch p.tok.Data {
- case "html":
- // TODO: autoclose the stack of open elements.
- return afterAfterBodyIM, true
- default:
- // TODO.
- }
- }
- return afterBodyIM, true
-}
-
-// Section 11.2.5.4.21.
-func afterAfterBodyIM(p *parser) (insertionMode, bool) {
- switch p.tok.Type {
- case ErrorToken:
- // Stop parsing.
- return nil, true
- case TextToken:
- // TODO.
- case StartTagToken:
- if p.tok.Data == "html" {
- return useTheRulesFor(p, afterAfterBodyIM, inBodyIM)
- }
- }
- return inBodyIM, false
-}
-
-// Parse returns the parse tree for the HTML from the given Reader.
-// The input is assumed to be UTF-8 encoded.
-func Parse(r io.Reader) (*Node, os.Error) {
- p := &parser{
- tokenizer: NewTokenizer(r),
- doc: &Node{
- Type: DocumentNode,
- },
- scripting: true,
- framesetOK: true,
- }
- // Iterate until EOF. Any other error will cause an early return.
- im, consumed := initialIM, true
- for {
- if consumed {
- if err := p.read(); err != nil {
- if err == os.EOF {
- break
- }
- return nil, err
- }
- }
- im, consumed = im(p)
- }
- // Loop until the final token (the ErrorToken signifying EOF) is consumed.
- for {
- if im, consumed = im(p); consumed {
- break
- }
- }
- return p.doc, nil
-}
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
deleted file mode 100644
index 7d918d250..000000000
--- a/src/pkg/html/parse_test.go
+++ /dev/null
@@ -1,156 +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 html
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "testing"
-)
-
-func pipeErr(err os.Error) io.Reader {
- pr, pw := io.Pipe()
- pw.CloseWithError(err)
- return pr
-}
-
-func readDat(filename string, c chan io.Reader) {
- f, err := os.Open("testdata/webkit/" + filename)
- if err != nil {
- c <- pipeErr(err)
- return
- }
- defer f.Close()
-
- // Loop through the lines of the file. Each line beginning with "#" denotes
- // a new section, which is returned as a separate io.Reader.
- r := bufio.NewReader(f)
- var pw *io.PipeWriter
- for {
- line, err := r.ReadSlice('\n')
- if err != nil {
- if pw != nil {
- pw.CloseWithError(err)
- pw = nil
- } else {
- c <- pipeErr(err)
- }
- return
- }
- if len(line) == 0 {
- continue
- }
- if line[0] == '#' {
- if pw != nil {
- pw.Close()
- }
- var pr *io.PipeReader
- pr, pw = io.Pipe()
- c <- pr
- continue
- }
- if line[0] != '|' {
- // Strip the trailing '\n'.
- line = line[:len(line)-1]
- }
- if pw != nil {
- if _, err := pw.Write(line); err != nil {
- pw.CloseWithError(err)
- pw = nil
- }
- }
- }
-}
-
-func dumpLevel(w io.Writer, n *Node, level int) os.Error {
- io.WriteString(w, "| ")
- for i := 0; i < level; i++ {
- io.WriteString(w, " ")
- }
- switch n.Type {
- case ErrorNode:
- return os.NewError("unexpected ErrorNode")
- case DocumentNode:
- return os.NewError("unexpected DocumentNode")
- case ElementNode:
- fmt.Fprintf(w, "<%s>", EscapeString(n.Data))
- case TextNode:
- fmt.Fprintf(w, "%q", EscapeString(n.Data))
- case CommentNode:
- return os.NewError("COMMENT")
- case DoctypeNode:
- fmt.Fprintf(w, "<!DOCTYPE %s>", EscapeString(n.Data))
- case scopeMarkerNode:
- return os.NewError("unexpected scopeMarkerNode")
- default:
- return os.NewError("unknown node type")
- }
- io.WriteString(w, "\n")
- for _, c := range n.Child {
- if err := dumpLevel(w, c, level+1); err != nil {
- return err
- }
- }
- return nil
-}
-
-func dump(n *Node) (string, os.Error) {
- if n == nil || len(n.Child) == 0 {
- return "", nil
- }
- b := bytes.NewBuffer(nil)
- for _, child := range n.Child {
- if err := dumpLevel(b, child, 0); err != nil {
- return "", err
- }
- }
- return b.String(), nil
-}
-
-func TestParser(t *testing.T) {
- // TODO(nigeltao): Process all the .dat files, not just the first one.
- filenames := []string{
- "tests1.dat",
- }
- for _, filename := range filenames {
- rc := make(chan io.Reader)
- go readDat(filename, rc)
- // TODO(nigeltao): Process all test cases, not just a subset.
- for i := 0; i < 25; i++ {
- // Parse the #data section.
- b, err := ioutil.ReadAll(<-rc)
- if err != nil {
- t.Fatal(err)
- }
- text := string(b)
- doc, err := Parse(strings.NewReader(text))
- if err != nil {
- t.Fatal(err)
- }
- actual, err := dump(doc)
- if err != nil {
- t.Fatal(err)
- }
- // Skip the #error section.
- if _, err := io.Copy(ioutil.Discard, <-rc); err != nil {
- t.Fatal(err)
- }
- // Compare the parsed tree to the #document section.
- b, err = ioutil.ReadAll(<-rc)
- if err != nil {
- t.Fatal(err)
- }
- expected := string(b)
- if actual != expected {
- t.Errorf("%s test #%d %q, actual vs expected:\n----\n%s----\n%s----", filename, i, text, actual, expected)
- }
- }
- }
-}
diff --git a/src/pkg/html/template/attr.go b/src/pkg/html/template/attr.go
new file mode 100644
index 000000000..3ea02880d
--- /dev/null
+++ b/src/pkg/html/template/attr.go
@@ -0,0 +1,175 @@
+// 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 (
+ "strings"
+)
+
+// attrTypeMap[n] describes the value of the given attribute.
+// If an attribute affects (or can mask) the encoding or interpretation of
+// other content, or affects the contents, idempotency, or credentials of a
+// network message, then the value in this map is contentTypeUnsafe.
+// This map is derived from HTML5, specifically
+// http://www.w3.org/TR/html5/Overview.html#attributes-1
+// as well as "%URI"-typed attributes from
+// http://www.w3.org/TR/html4/index/attributes.html
+var attrTypeMap = map[string]contentType{
+ "accept": contentTypePlain,
+ "accept-charset": contentTypeUnsafe,
+ "action": contentTypeURL,
+ "alt": contentTypePlain,
+ "archive": contentTypeURL,
+ "async": contentTypeUnsafe,
+ "autocomplete": contentTypePlain,
+ "autofocus": contentTypePlain,
+ "autoplay": contentTypePlain,
+ "background": contentTypeURL,
+ "border": contentTypePlain,
+ "checked": contentTypePlain,
+ "cite": contentTypeURL,
+ "challenge": contentTypeUnsafe,
+ "charset": contentTypeUnsafe,
+ "class": contentTypePlain,
+ "classid": contentTypeURL,
+ "codebase": contentTypeURL,
+ "cols": contentTypePlain,
+ "colspan": contentTypePlain,
+ "content": contentTypeUnsafe,
+ "contenteditable": contentTypePlain,
+ "contextmenu": contentTypePlain,
+ "controls": contentTypePlain,
+ "coords": contentTypePlain,
+ "crossorigin": contentTypeUnsafe,
+ "data": contentTypeURL,
+ "datetime": contentTypePlain,
+ "default": contentTypePlain,
+ "defer": contentTypeUnsafe,
+ "dir": contentTypePlain,
+ "dirname": contentTypePlain,
+ "disabled": contentTypePlain,
+ "draggable": contentTypePlain,
+ "dropzone": contentTypePlain,
+ "enctype": contentTypeUnsafe,
+ "for": contentTypePlain,
+ "form": contentTypeUnsafe,
+ "formaction": contentTypeURL,
+ "formenctype": contentTypeUnsafe,
+ "formmethod": contentTypeUnsafe,
+ "formnovalidate": contentTypeUnsafe,
+ "formtarget": contentTypePlain,
+ "headers": contentTypePlain,
+ "height": contentTypePlain,
+ "hidden": contentTypePlain,
+ "high": contentTypePlain,
+ "href": contentTypeURL,
+ "hreflang": contentTypePlain,
+ "http-equiv": contentTypeUnsafe,
+ "icon": contentTypeURL,
+ "id": contentTypePlain,
+ "ismap": contentTypePlain,
+ "keytype": contentTypeUnsafe,
+ "kind": contentTypePlain,
+ "label": contentTypePlain,
+ "lang": contentTypePlain,
+ "language": contentTypeUnsafe,
+ "list": contentTypePlain,
+ "longdesc": contentTypeURL,
+ "loop": contentTypePlain,
+ "low": contentTypePlain,
+ "manifest": contentTypeURL,
+ "max": contentTypePlain,
+ "maxlength": contentTypePlain,
+ "media": contentTypePlain,
+ "mediagroup": contentTypePlain,
+ "method": contentTypeUnsafe,
+ "min": contentTypePlain,
+ "multiple": contentTypePlain,
+ "name": contentTypePlain,
+ "novalidate": contentTypeUnsafe,
+ // Skip handler names from
+ // http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects
+ // since we have special handling in attrType.
+ "open": contentTypePlain,
+ "optimum": contentTypePlain,
+ "pattern": contentTypeUnsafe,
+ "placeholder": contentTypePlain,
+ "poster": contentTypeURL,
+ "profile": contentTypeURL,
+ "preload": contentTypePlain,
+ "pubdate": contentTypePlain,
+ "radiogroup": contentTypePlain,
+ "readonly": contentTypePlain,
+ "rel": contentTypeUnsafe,
+ "required": contentTypePlain,
+ "reversed": contentTypePlain,
+ "rows": contentTypePlain,
+ "rowspan": contentTypePlain,
+ "sandbox": contentTypeUnsafe,
+ "spellcheck": contentTypePlain,
+ "scope": contentTypePlain,
+ "scoped": contentTypePlain,
+ "seamless": contentTypePlain,
+ "selected": contentTypePlain,
+ "shape": contentTypePlain,
+ "size": contentTypePlain,
+ "sizes": contentTypePlain,
+ "span": contentTypePlain,
+ "src": contentTypeURL,
+ "srcdoc": contentTypeHTML,
+ "srclang": contentTypePlain,
+ "start": contentTypePlain,
+ "step": contentTypePlain,
+ "style": contentTypeCSS,
+ "tabindex": contentTypePlain,
+ "target": contentTypePlain,
+ "title": contentTypePlain,
+ "type": contentTypeUnsafe,
+ "usemap": contentTypeURL,
+ "value": contentTypeUnsafe,
+ "width": contentTypePlain,
+ "wrap": contentTypePlain,
+ "xmlns": contentTypeURL,
+}
+
+// attrType returns a conservative (upper-bound on authority) guess at the
+// type of the named attribute.
+func attrType(name string) contentType {
+ name = strings.ToLower(name)
+ if strings.HasPrefix(name, "data-") {
+ // Strip data- so that custom attribute heuristics below are
+ // widely applied.
+ // Treat data-action as URL below.
+ name = name[5:]
+ } else if colon := strings.IndexRune(name, ':'); colon != -1 {
+ if name[:colon] == "xmlns" {
+ return contentTypeURL
+ }
+ // Treat svg:href and xlink:href as href below.
+ name = name[colon+1:]
+ }
+ if t, ok := attrTypeMap[name]; ok {
+ return t
+ }
+ // Treat partial event handler names as script.
+ if strings.HasPrefix(name, "on") {
+ return contentTypeJS
+ }
+
+ // Heuristics to prevent "javascript:..." injection in custom
+ // data attributes and custom attributes like g:tweetUrl.
+ // http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes:
+ // "Custom data attributes are intended to store custom data
+ // private to the page or application, for which there are no
+ // more appropriate attributes or elements."
+ // Developers seem to store URL content in data URLs that start
+ // or end with "URI" or "URL".
+ if strings.Contains(name, "src") ||
+ strings.Contains(name, "uri") ||
+ strings.Contains(name, "url") {
+ return contentTypeURL
+ }
+ return contentTypePlain
+}
diff --git a/src/pkg/html/template/clone_test.go b/src/pkg/html/template/clone_test.go
new file mode 100644
index 000000000..2663cddc2
--- /dev/null
+++ b/src/pkg/html/template/clone_test.go
@@ -0,0 +1,148 @@
+// 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"
+ "testing"
+ "text/template/parse"
+)
+
+func TestAddParseTree(t *testing.T) {
+ root := Must(New("root").Parse(`{{define "a"}} {{.}} {{template "b"}} {{.}} "></a>{{end}}`))
+ tree, err := parse.Parse("t", `{{define "b"}}<a href="{{end}}`, "", "", nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ added := Must(root.AddParseTree("b", tree["b"]))
+ b := new(bytes.Buffer)
+ err = added.ExecuteTemplate(b, "a", "1>0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` 1&gt;0 <a href=" 1%3e0 "></a>`; got != want {
+ t.Errorf("got %q want %q", got, want)
+ }
+}
+
+func TestClone(t *testing.T) {
+ // The {{.}} will be executed with data "<i>*/" in different contexts.
+ // In the t0 template, it will be in a text context.
+ // In the t1 template, it will be in a URL context.
+ // In the t2 template, it will be in a JavaScript context.
+ // In the t3 template, it will be in a CSS context.
+ const tmpl = `{{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}`
+ b := new(bytes.Buffer)
+
+ // Create an incomplete template t0.
+ t0 := Must(New("t0").Parse(tmpl))
+
+ // Clone t0 as t1.
+ t1 := Must(t0.Clone())
+ Must(t1.Parse(`{{define "lhs"}} <a href=" {{end}}`))
+ Must(t1.Parse(`{{define "rhs"}} "></a> {{end}}`))
+
+ // Execute t1.
+ b.Reset()
+ if err := t1.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <a href=" %3ci%3e*/ "></a> `; got != want {
+ t.Errorf("t1: got %q want %q", got, want)
+ }
+
+ // Clone t0 as t2.
+ t2 := Must(t0.Clone())
+ Must(t2.Parse(`{{define "lhs"}} <p onclick="javascript: {{end}}`))
+ Must(t2.Parse(`{{define "rhs"}} "></p> {{end}}`))
+
+ // Execute t2.
+ b.Reset()
+ if err := t2.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <p onclick="javascript: &#34;\u003ci\u003e*/&#34; "></p> `; got != want {
+ t.Errorf("t2: got %q want %q", got, want)
+ }
+
+ // Clone t0 as t3, but do not execute t3 yet.
+ t3 := Must(t0.Clone())
+ Must(t3.Parse(`{{define "lhs"}} <style> {{end}}`))
+ Must(t3.Parse(`{{define "rhs"}} </style> {{end}}`))
+
+ // Complete t0.
+ Must(t0.Parse(`{{define "lhs"}} ( {{end}}`))
+ Must(t0.Parse(`{{define "rhs"}} ) {{end}}`))
+
+ // Clone t0 as t4. Redefining the "lhs" template should fail.
+ t4 := Must(t0.Clone())
+ if _, err := t4.Parse(`{{define "lhs"}} FAIL {{end}}`); err == nil {
+ t.Error(`redefine "lhs": got nil err want non-nil`)
+ }
+
+ // Execute t0.
+ b.Reset()
+ if err := t0.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` ( &lt;i&gt;*/ ) `; got != want {
+ t.Errorf("t0: got %q want %q", got, want)
+ }
+
+ // Clone t0. This should fail, as t0 has already executed.
+ if _, err := t0.Clone(); err == nil {
+ t.Error(`t0.Clone(): got nil err want non-nil`)
+ }
+
+ // Similarly, cloning sub-templates should fail.
+ if _, err := t0.Lookup("a").Clone(); err == nil {
+ t.Error(`t0.Lookup("a").Clone(): got nil err want non-nil`)
+ }
+ if _, err := t0.Lookup("lhs").Clone(); err == nil {
+ t.Error(`t0.Lookup("lhs").Clone(): got nil err want non-nil`)
+ }
+
+ // Execute t3.
+ b.Reset()
+ if err := t3.ExecuteTemplate(b, "a", "<i>*/"); err != nil {
+ t.Fatal(err)
+ }
+ if got, want := b.String(), ` <style> ZgotmplZ </style> `; got != want {
+ t.Errorf("t3: got %q want %q", got, want)
+ }
+}
+
+func TestTemplates(t *testing.T) {
+ names := []string{"t0", "a", "lhs", "rhs"}
+ // Some template definitions borrowed from TestClone.
+ const tmpl = `
+ {{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}
+ {{define "lhs"}} <a href=" {{end}}
+ {{define "rhs"}} "></a> {{end}}`
+ t0 := Must(New("t0").Parse(tmpl))
+ templates := t0.Templates()
+ if len(templates) != len(names) {
+ t.Errorf("expected %d templates; got %d", len(names), len(templates))
+ }
+ for _, name := range names {
+ found := false
+ for _, tmpl := range templates {
+ if name == tmpl.text.Name() {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Error("could not find template", name)
+ }
+ }
+}
+
+// This used to crash; http://golang.org/issue/3281
+func TestCloneCrash(t *testing.T) {
+ t1 := New("all")
+ Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
+ t1.Clone()
+}
diff --git a/src/pkg/html/template/content.go b/src/pkg/html/template/content.go
new file mode 100644
index 000000000..c1bd2e494
--- /dev/null
+++ b/src/pkg/html/template/content.go
@@ -0,0 +1,129 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// Strings of content from a trusted source.
+type (
+ // CSS encapsulates known safe content that matches any of:
+ // 1. The CSS3 stylesheet production, such as `p { color: purple }`.
+ // 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
+ // 3. CSS3 declaration productions, such as `color: red; margin: 2px`.
+ // 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
+ // See http://www.w3.org/TR/css3-syntax/#style
+ CSS string
+
+ // HTML encapsulates a known safe HTML document fragment.
+ // It should not be used for HTML from a third-party, or HTML with
+ // unclosed tags or comments. The outputs of a sound HTML sanitizer
+ // and a template escaped by this package are fine for use with HTML.
+ HTML string
+
+ // HTMLAttr encapsulates an HTML attribute from a trusted source,
+ // for example, ` dir="ltr"`.
+ HTMLAttr string
+
+ // JS encapsulates a known safe EcmaScript5 Expression, for example,
+ // `(x + y * z())`.
+ // Template authors are responsible for ensuring that typed expressions
+ // do not break the intended precedence and that there is no
+ // statement/expression ambiguity as when passing an expression like
+ // "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
+ // valid Program with a very different meaning.
+ JS string
+
+ // JSStr encapsulates a sequence of characters meant to be embedded
+ // between quotes in a JavaScript expression.
+ // The string must match a series of StringCharacters:
+ // StringCharacter :: SourceCharacter but not `\` or LineTerminator
+ // | EscapeSequence
+ // Note that LineContinuations are not allowed.
+ // JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
+ JSStr string
+
+ // URL encapsulates a known safe URL as defined in RFC 3896.
+ // A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`
+ // from a trusted source should go in the page, but by default dynamic
+ // `javascript:` URLs are filtered out since they are a frequently
+ // exploited injection vector.
+ URL string
+)
+
+type contentType uint8
+
+const (
+ contentTypePlain contentType = iota
+ contentTypeCSS
+ contentTypeHTML
+ contentTypeHTMLAttr
+ contentTypeJS
+ contentTypeJSStr
+ contentTypeURL
+ // contentTypeUnsafe is used in attr.go for values that affect how
+ // embedded content and network messages are formed, vetted,
+ // or interpreted; or which credentials network messages carry.
+ contentTypeUnsafe
+)
+
+// indirect returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil).
+func indirect(a interface{}) interface{} {
+ if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
+ // Avoid creating a reflect.Value if it's not a pointer.
+ return a
+ }
+ v := reflect.ValueOf(a)
+ for v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
+var (
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+// indirectToStringerOrError returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
+// or error,
+func indirectToStringerOrError(a interface{}) interface{} {
+ v := reflect.ValueOf(a)
+ for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
+// stringify converts its arguments to a string and the type of the content.
+// All pointers are dereferenced, as in the text/template package.
+func stringify(args ...interface{}) (string, contentType) {
+ if len(args) == 1 {
+ switch s := indirect(args[0]).(type) {
+ case string:
+ return s, contentTypePlain
+ case CSS:
+ return string(s), contentTypeCSS
+ case HTML:
+ return string(s), contentTypeHTML
+ case HTMLAttr:
+ return string(s), contentTypeHTMLAttr
+ case JS:
+ return string(s), contentTypeJS
+ case JSStr:
+ return string(s), contentTypeJSStr
+ case URL:
+ return string(s), contentTypeURL
+ }
+ }
+ for i, arg := range args {
+ args[i] = indirectToStringerOrError(arg)
+ }
+ return fmt.Sprint(args...), contentTypePlain
+}
diff --git a/src/pkg/html/template/content_test.go b/src/pkg/html/template/content_test.go
new file mode 100644
index 000000000..3c32e5e89
--- /dev/null
+++ b/src/pkg/html/template/content_test.go
@@ -0,0 +1,261 @@
+// 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"
+ "strings"
+ "testing"
+)
+
+func TestTypedContent(t *testing.T) {
+ data := []interface{}{
+ `<b> "foo%" O'Reilly &bar;`,
+ CSS(`a[href =~ "//example.com"]#foo`),
+ HTML(`Hello, <b>World</b> &amp;tc!`),
+ HTMLAttr(` dir="ltr"`),
+ JS(`c && alert("Hello, World!");`),
+ JSStr(`Hello, World & O'Reilly\x21`),
+ URL(`greeting=H%69&addressee=(World)`),
+ }
+
+ // For each content sensitive escaper, see how it does on
+ // each of the typed strings above.
+ tests := []struct {
+ // A template containing a single {{.}}.
+ input string
+ want []string
+ }{
+ {
+ `<style>{{.}} { color: blue }</style>`,
+ []string{
+ `ZgotmplZ`,
+ // Allowed but not escaped.
+ `a[href =~ "//example.com"]#foo`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ },
+ },
+ {
+ `<div style="{{.}}">`,
+ []string{
+ `ZgotmplZ`,
+ // Allowed and HTML escaped.
+ `a[href =~ &#34;//example.com&#34;]#foo`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ },
+ },
+ {
+ `{{.}}`,
+ []string{
+ `&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
+ `a[href =~ &#34;//example.com&#34;]#foo`,
+ // Not escaped.
+ `Hello, <b>World</b> &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ `Hello, World &amp; O&#39;Reilly\x21`,
+ `greeting=H%69&amp;addressee=(World)`,
+ },
+ },
+ {
+ `<a{{.}}>`,
+ []string{
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ // Allowed and HTML escaped.
+ ` dir="ltr"`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ `ZgotmplZ`,
+ },
+ },
+ {
+ `<a title={{.}}>`,
+ []string{
+ `&lt;b&gt;&#32;&#34;foo%&#34;&#32;O&#39;Reilly&#32;&amp;bar;`,
+ `a[href&#32;&#61;~&#32;&#34;//example.com&#34;]#foo`,
+ // Tags stripped, spaces escaped, entity not re-escaped.
+ `Hello,&#32;World&#32;&amp;tc!`,
+ `&#32;dir&#61;&#34;ltr&#34;`,
+ `c&#32;&amp;&amp;&#32;alert(&#34;Hello,&#32;World!&#34;);`,
+ `Hello,&#32;World&#32;&amp;&#32;O&#39;Reilly\x21`,
+ `greeting&#61;H%69&amp;addressee&#61;(World)`,
+ },
+ },
+ {
+ `<a title='{{.}}'>`,
+ []string{
+ `&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
+ `a[href =~ &#34;//example.com&#34;]#foo`,
+ // Tags stripped, entity not re-escaped.
+ `Hello, World &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ `Hello, World &amp; O&#39;Reilly\x21`,
+ `greeting=H%69&amp;addressee=(World)`,
+ },
+ },
+ {
+ `<textarea>{{.}}</textarea>`,
+ []string{
+ `&lt;b&gt; &#34;foo%&#34; O&#39;Reilly &amp;bar;`,
+ `a[href =~ &#34;//example.com&#34;]#foo`,
+ // Angle brackets escaped to prevent injection of close tags, entity not re-escaped.
+ `Hello, &lt;b&gt;World&lt;/b&gt; &amp;tc!`,
+ ` dir=&#34;ltr&#34;`,
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ `Hello, World &amp; O&#39;Reilly\x21`,
+ `greeting=H%69&amp;addressee=(World)`,
+ },
+ },
+ {
+ `<script>alert({{.}})</script>`,
+ []string{
+ `"\u003cb\u003e \"foo%\" O'Reilly &bar;"`,
+ `"a[href =~ \"//example.com\"]#foo"`,
+ `"Hello, \u003cb\u003eWorld\u003c/b\u003e &amp;tc!"`,
+ `" dir=\"ltr\""`,
+ // Not escaped.
+ `c && alert("Hello, World!");`,
+ // Escape sequence not over-escaped.
+ `"Hello, World & O'Reilly\x21"`,
+ `"greeting=H%69&addressee=(World)"`,
+ },
+ },
+ {
+ `<button onclick="alert({{.}})">`,
+ []string{
+ `&#34;\u003cb\u003e \&#34;foo%\&#34; O&#39;Reilly &amp;bar;&#34;`,
+ `&#34;a[href =~ \&#34;//example.com\&#34;]#foo&#34;`,
+ `&#34;Hello, \u003cb\u003eWorld\u003c/b\u003e &amp;amp;tc!&#34;`,
+ `&#34; dir=\&#34;ltr\&#34;&#34;`,
+ // Not JS escaped but HTML escaped.
+ `c &amp;&amp; alert(&#34;Hello, World!&#34;);`,
+ // Escape sequence not over-escaped.
+ `&#34;Hello, World &amp; O&#39;Reilly\x21&#34;`,
+ `&#34;greeting=H%69&amp;addressee=(World)&#34;`,
+ },
+ },
+ {
+ `<script>alert("{{.}}")</script>`,
+ []string{
+ `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+ `a[href =~ \x22\/\/example.com\x22]#foo`,
+ `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+ ` dir=\x22ltr\x22`,
+ `c \x26\x26 alert(\x22Hello, World!\x22);`,
+ // Escape sequence not over-escaped.
+ `Hello, World \x26 O\x27Reilly\x21`,
+ `greeting=H%69\x26addressee=(World)`,
+ },
+ },
+ {
+ `<button onclick='alert("{{.}}")'>`,
+ []string{
+ `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+ `a[href =~ \x22\/\/example.com\x22]#foo`,
+ `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+ ` dir=\x22ltr\x22`,
+ `c \x26\x26 alert(\x22Hello, World!\x22);`,
+ // Escape sequence not over-escaped.
+ `Hello, World \x26 O\x27Reilly\x21`,
+ `greeting=H%69\x26addressee=(World)`,
+ },
+ },
+ {
+ `<a href="?q={{.}}">`,
+ []string{
+ `%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
+ `a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
+ `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
+ `%20dir%3d%22ltr%22`,
+ `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
+ `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
+ // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is done.
+ `greeting=H%69&amp;addressee=%28World%29`,
+ },
+ },
+ {
+ `<style>body { background: url('?img={{.}}') }</style>`,
+ []string{
+ `%3cb%3e%20%22foo%25%22%20O%27Reilly%20%26bar%3b`,
+ `a%5bhref%20%3d~%20%22%2f%2fexample.com%22%5d%23foo`,
+ `Hello%2c%20%3cb%3eWorld%3c%2fb%3e%20%26amp%3btc%21`,
+ `%20dir%3d%22ltr%22`,
+ `c%20%26%26%20alert%28%22Hello%2c%20World%21%22%29%3b`,
+ `Hello%2c%20World%20%26%20O%27Reilly%5cx21`,
+ // Quotes and parens are escaped but %69 is not over-escaped. HTML escaping is not done.
+ `greeting=H%69&addressee=%28World%29`,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ tmpl := Must(New("x").Parse(test.input))
+ pre := strings.Index(test.input, "{{.}}")
+ post := len(test.input) - (pre + 5)
+ var b bytes.Buffer
+ for i, x := range data {
+ b.Reset()
+ if err := tmpl.Execute(&b, x); err != nil {
+ t.Errorf("%q with %v: %s", test.input, x, err)
+ continue
+ }
+ if want, got := test.want[i], b.String()[pre:b.Len()-post]; want != got {
+ t.Errorf("%q with %v:\nwant\n\t%q,\ngot\n\t%q\n", test.input, x, want, got)
+ continue
+ }
+ }
+ }
+}
+
+// Test that we print using the String method. Was issue 3073.
+type stringer struct {
+ v int
+}
+
+func (s *stringer) String() string {
+ return fmt.Sprintf("string=%d", s.v)
+}
+
+type errorer struct {
+ v int
+}
+
+func (s *errorer) Error() string {
+ return fmt.Sprintf("error=%d", s.v)
+}
+
+func TestStringer(t *testing.T) {
+ s := &stringer{3}
+ b := new(bytes.Buffer)
+ tmpl := Must(New("x").Parse("{{.}}"))
+ if err := tmpl.Execute(b, s); err != nil {
+ t.Fatal(err)
+ }
+ var expect = "string=3"
+ if b.String() != expect {
+ t.Errorf("expected %q got %q", expect, b.String())
+ }
+ e := &errorer{7}
+ b.Reset()
+ if err := tmpl.Execute(b, e); err != nil {
+ t.Fatal(err)
+ }
+ expect = "error=7"
+ if b.String() != expect {
+ t.Errorf("expected %q got %q", expect, b.String())
+ }
+}
diff --git a/src/pkg/html/template/context.go b/src/pkg/html/template/context.go
new file mode 100644
index 000000000..7202221b8
--- /dev/null
+++ b/src/pkg/html/template/context.go
@@ -0,0 +1,339 @@
+// 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"
+)
+
+// 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
+ urlPart urlPart
+ jsCtx jsCtx
+ attr attr
+ element element
+ err *Error
+}
+
+func (c context) String() string {
+ return fmt.Sprintf("{%v %v %v %v %v %v %v}", c.state, c.delim, c.urlPart, c.jsCtx, c.attr, c.element, c.err)
+}
+
+// eq returns whether two contexts are equal.
+func (c context) eq(d context) bool {
+ return c.state == d.state &&
+ c.delim == d.delim &&
+ c.urlPart == d.urlPart &&
+ c.jsCtx == d.jsCtx &&
+ c.attr == d.attr &&
+ c.element == d.element &&
+ c.err == d.err
+}
+
+// mangle produces an identifier that includes a suffix that distinguishes it
+// from template names mangled with different contexts.
+func (c context) mangle(templateName string) string {
+ // The mangled name for the default context is the input templateName.
+ if c.state == stateText {
+ return templateName
+ }
+ s := templateName + "$htmltemplate_" + c.state.String()
+ if c.delim != 0 {
+ s += "_" + c.delim.String()
+ }
+ if c.urlPart != 0 {
+ s += "_" + c.urlPart.String()
+ }
+ if c.jsCtx != 0 {
+ s += "_" + c.jsCtx.String()
+ }
+ if c.attr != 0 {
+ s += "_" + c.attr.String()
+ }
+ if c.element != 0 {
+ s += "_" + c.element.String()
+ }
+ return s
+}
+
+// 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 (
+ // stateText 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.
+ stateText state = iota
+ // stateTag occurs before an HTML attribute or the end of a tag.
+ stateTag
+ // stateAttrName occurs inside an attribute name.
+ // It occurs between the ^'s in ` ^name^ = value`.
+ stateAttrName
+ // stateAfterName occurs after an attr name has ended but before any
+ // equals sign. It occurs between the ^'s in ` name^ ^= value`.
+ stateAfterName
+ // stateBeforeValue occurs after the equals sign but before the value.
+ // It occurs between the ^'s in ` name =^ ^value`.
+ stateBeforeValue
+ // stateHTMLCmt occurs inside an <!-- HTML comment -->.
+ stateHTMLCmt
+ // stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
+ // as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
+ stateRCDATA
+ // stateAttr occurs inside an HTML attribute whose content is text.
+ stateAttr
+ // stateURL occurs inside an HTML attribute whose content is a URL.
+ stateURL
+ // stateJS occurs inside an event handler or script element.
+ stateJS
+ // stateJSDqStr occurs inside a JavaScript double quoted string.
+ stateJSDqStr
+ // stateJSSqStr occurs inside a JavaScript single quoted string.
+ stateJSSqStr
+ // stateJSRegexp occurs inside a JavaScript regexp literal.
+ stateJSRegexp
+ // stateJSBlockCmt occurs inside a JavaScript /* block comment */.
+ stateJSBlockCmt
+ // stateJSLineCmt occurs inside a JavaScript // line comment.
+ stateJSLineCmt
+ // stateCSS occurs inside a <style> element or style attribute.
+ stateCSS
+ // stateCSSDqStr occurs inside a CSS double quoted string.
+ stateCSSDqStr
+ // stateCSSSqStr occurs inside a CSS single quoted string.
+ stateCSSSqStr
+ // stateCSSDqURL occurs inside a CSS double quoted url("...").
+ stateCSSDqURL
+ // stateCSSSqURL occurs inside a CSS single quoted url('...').
+ stateCSSSqURL
+ // stateCSSURL occurs inside a CSS unquoted url(...).
+ stateCSSURL
+ // stateCSSBlockCmt occurs inside a CSS /* block comment */.
+ stateCSSBlockCmt
+ // stateCSSLineCmt occurs inside a CSS // line comment.
+ stateCSSLineCmt
+ // stateError is an infectious error state outside any valid
+ // HTML/CSS/JS construct.
+ stateError
+)
+
+var stateNames = [...]string{
+ stateText: "stateText",
+ stateTag: "stateTag",
+ stateAttrName: "stateAttrName",
+ stateAfterName: "stateAfterName",
+ stateBeforeValue: "stateBeforeValue",
+ stateHTMLCmt: "stateHTMLCmt",
+ stateRCDATA: "stateRCDATA",
+ stateAttr: "stateAttr",
+ stateURL: "stateURL",
+ stateJS: "stateJS",
+ stateJSDqStr: "stateJSDqStr",
+ stateJSSqStr: "stateJSSqStr",
+ stateJSRegexp: "stateJSRegexp",
+ stateJSBlockCmt: "stateJSBlockCmt",
+ stateJSLineCmt: "stateJSLineCmt",
+ stateCSS: "stateCSS",
+ stateCSSDqStr: "stateCSSDqStr",
+ stateCSSSqStr: "stateCSSSqStr",
+ stateCSSDqURL: "stateCSSDqURL",
+ stateCSSSqURL: "stateCSSSqURL",
+ stateCSSURL: "stateCSSURL",
+ stateCSSBlockCmt: "stateCSSBlockCmt",
+ stateCSSLineCmt: "stateCSSLineCmt",
+ stateError: "stateError",
+}
+
+func (s state) String() string {
+ if int(s) < len(stateNames) {
+ return stateNames[s]
+ }
+ return fmt.Sprintf("illegal state %d", int(s))
+}
+
+// isComment is true for any state that contains content meant for template
+// authors & maintainers, not for end-users or machines.
+func isComment(s state) bool {
+ switch s {
+ case stateHTMLCmt, stateJSBlockCmt, stateJSLineCmt, stateCSSBlockCmt, stateCSSLineCmt:
+ return true
+ }
+ return false
+}
+
+// isInTag return whether s occurs solely inside an HTML tag.
+func isInTag(s state) bool {
+ switch s {
+ case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr:
+ return true
+ }
+ return false
+}
+
+// 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 int(d) < len(delimNames) {
+ return delimNames[d]
+ }
+ return fmt.Sprintf("illegal delim %d", int(d))
+}
+
+// urlPart identifies a part in an RFC 3986 hierarchical URL to allow different
+// encoding strategies.
+type urlPart uint8
+
+const (
+ // urlPartNone occurs when not in a URL, or possibly at the start:
+ // ^ in "^http://auth/path?k=v#frag".
+ urlPartNone urlPart = iota
+ // urlPartPreQuery occurs in the scheme, authority, or path; between the
+ // ^s in "h^ttp://auth/path^?k=v#frag".
+ urlPartPreQuery
+ // urlPartQueryOrFrag occurs in the query portion between the ^s in
+ // "http://auth/path?^k=v#frag^".
+ urlPartQueryOrFrag
+ // urlPartUnknown occurs due to joining of contexts both before and
+ // after the query separator.
+ urlPartUnknown
+)
+
+var urlPartNames = [...]string{
+ urlPartNone: "urlPartNone",
+ urlPartPreQuery: "urlPartPreQuery",
+ urlPartQueryOrFrag: "urlPartQueryOrFrag",
+ urlPartUnknown: "urlPartUnknown",
+}
+
+func (u urlPart) String() string {
+ if int(u) < len(urlPartNames) {
+ return urlPartNames[u]
+ }
+ return fmt.Sprintf("illegal urlPart %d", int(u))
+}
+
+// jsCtx determines whether a '/' starts a regular expression literal or a
+// division operator.
+type jsCtx uint8
+
+const (
+ // jsCtxRegexp occurs where a '/' would start a regexp literal.
+ jsCtxRegexp jsCtx = iota
+ // jsCtxDivOp occurs where a '/' would start a division operator.
+ jsCtxDivOp
+ // jsCtxUnknown occurs where a '/' is ambiguous due to context joining.
+ jsCtxUnknown
+)
+
+func (c jsCtx) String() string {
+ switch c {
+ case jsCtxRegexp:
+ return "jsCtxRegexp"
+ case jsCtxDivOp:
+ return "jsCtxDivOp"
+ case jsCtxUnknown:
+ return "jsCtxUnknown"
+ }
+ return fmt.Sprintf("illegal jsCtx %d", int(c))
+}
+
+// element identifies the HTML element when inside a start tag or special body.
+// Certain HTML element (for example <script> and <style>) have bodies that are
+// treated differently from stateText so the element type is necessary to
+// transition into the correct context at the end of a tag and to identify the
+// end delimiter for the body.
+type element uint8
+
+const (
+ // elementNone occurs outside a special tag or special element body.
+ elementNone element = iota
+ // elementScript corresponds to the raw text <script> element.
+ elementScript
+ // elementStyle corresponds to the raw text <style> element.
+ elementStyle
+ // elementTextarea corresponds to the RCDATA <textarea> element.
+ elementTextarea
+ // elementTitle corresponds to the RCDATA <title> element.
+ elementTitle
+)
+
+var elementNames = [...]string{
+ elementNone: "elementNone",
+ elementScript: "elementScript",
+ elementStyle: "elementStyle",
+ elementTextarea: "elementTextarea",
+ elementTitle: "elementTitle",
+}
+
+func (e element) String() string {
+ if int(e) < len(elementNames) {
+ return elementNames[e]
+ }
+ return fmt.Sprintf("illegal element %d", int(e))
+}
+
+// attr identifies the most recent HTML attribute when inside a start tag.
+type attr uint8
+
+const (
+ // attrNone corresponds to a normal attribute or no attribute.
+ attrNone attr = iota
+ // attrScript corresponds to an event handler attribute.
+ attrScript
+ // attrStyle corresponds to the style attribute whose value is CSS.
+ attrStyle
+ // attrURL corresponds to an attribute whose value is a URL.
+ attrURL
+)
+
+var attrNames = [...]string{
+ attrNone: "attrNone",
+ attrScript: "attrScript",
+ attrStyle: "attrStyle",
+ attrURL: "attrURL",
+}
+
+func (a attr) String() string {
+ if int(a) < len(attrNames) {
+ return attrNames[a]
+ }
+ return fmt.Sprintf("illegal attr %d", int(a))
+}
diff --git a/src/pkg/html/template/css.go b/src/pkg/html/template/css.go
new file mode 100644
index 000000000..3bcd98498
--- /dev/null
+++ b/src/pkg/html/template/css.go
@@ -0,0 +1,268 @@
+// 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"
+ "unicode"
+ "unicode/utf8"
+)
+
+// endsWithCSSKeyword returns whether b ends with an ident that
+// case-insensitively matches the lower-case kw.
+func endsWithCSSKeyword(b []byte, kw string) bool {
+ i := len(b) - len(kw)
+ if i < 0 {
+ // Too short.
+ return false
+ }
+ if i != 0 {
+ r, _ := utf8.DecodeLastRune(b[:i])
+ if isCSSNmchar(r) {
+ // Too long.
+ return false
+ }
+ }
+ // Many CSS keywords, such as "!important" can have characters encoded,
+ // but the URI production does not allow that according to
+ // http://www.w3.org/TR/css3-syntax/#TOK-URI
+ // This does not attempt to recognize encoded keywords. For example,
+ // given "\75\72\6c" and "url" this return false.
+ return string(bytes.ToLower(b[i:])) == kw
+}
+
+// isCSSNmchar returns whether rune is allowed anywhere in a CSS identifier.
+func isCSSNmchar(r rune) bool {
+ // Based on the CSS3 nmchar production but ignores multi-rune escape
+ // sequences.
+ // http://www.w3.org/TR/css3-syntax/#SUBTOK-nmchar
+ return 'a' <= r && r <= 'z' ||
+ 'A' <= r && r <= 'Z' ||
+ '0' <= r && r <= '9' ||
+ r == '-' ||
+ r == '_' ||
+ // Non-ASCII cases below.
+ 0x80 <= r && r <= 0xd7ff ||
+ 0xe000 <= r && r <= 0xfffd ||
+ 0x10000 <= r && r <= 0x10ffff
+}
+
+// decodeCSS decodes CSS3 escapes given a sequence of stringchars.
+// If there is no change, it returns the input, otherwise it returns a slice
+// backed by a new array.
+// http://www.w3.org/TR/css3-syntax/#SUBTOK-stringchar defines stringchar.
+func decodeCSS(s []byte) []byte {
+ i := bytes.IndexByte(s, '\\')
+ if i == -1 {
+ return s
+ }
+ // The UTF-8 sequence for a codepoint is never longer than 1 + the
+ // number hex digits need to represent that codepoint, so len(s) is an
+ // upper bound on the output length.
+ b := make([]byte, 0, len(s))
+ for len(s) != 0 {
+ i := bytes.IndexByte(s, '\\')
+ if i == -1 {
+ i = len(s)
+ }
+ b, s = append(b, s[:i]...), s[i:]
+ if len(s) < 2 {
+ break
+ }
+ // http://www.w3.org/TR/css3-syntax/#SUBTOK-escape
+ // escape ::= unicode | '\' [#x20-#x7E#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
+ if isHex(s[1]) {
+ // http://www.w3.org/TR/css3-syntax/#SUBTOK-unicode
+ // unicode ::= '\' [0-9a-fA-F]{1,6} wc?
+ j := 2
+ for j < len(s) && j < 7 && isHex(s[j]) {
+ j++
+ }
+ r := hexDecode(s[1:j])
+ if r > unicode.MaxRune {
+ r, j = r/16, j-1
+ }
+ n := utf8.EncodeRune(b[len(b):cap(b)], r)
+ // The optional space at the end allows a hex
+ // sequence to be followed by a literal hex.
+ // string(decodeCSS([]byte(`\A B`))) == "\nB"
+ b, s = b[:len(b)+n], skipCSSSpace(s[j:])
+ } else {
+ // `\\` decodes to `\` and `\"` to `"`.
+ _, n := utf8.DecodeRune(s[1:])
+ b, s = append(b, s[1:1+n]...), s[1+n:]
+ }
+ }
+ return b
+}
+
+// isHex returns whether the given character is a hex digit.
+func isHex(c byte) bool {
+ return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'
+}
+
+// hexDecode decodes a short hex digit sequence: "10" -> 16.
+func hexDecode(s []byte) rune {
+ n := '\x00'
+ for _, c := range s {
+ n <<= 4
+ switch {
+ case '0' <= c && c <= '9':
+ n |= rune(c - '0')
+ case 'a' <= c && c <= 'f':
+ n |= rune(c-'a') + 10
+ case 'A' <= c && c <= 'F':
+ n |= rune(c-'A') + 10
+ default:
+ panic(fmt.Sprintf("Bad hex digit in %q", s))
+ }
+ }
+ return n
+}
+
+// skipCSSSpace returns a suffix of c, skipping over a single space.
+func skipCSSSpace(c []byte) []byte {
+ if len(c) == 0 {
+ return c
+ }
+ // wc ::= #x9 | #xA | #xC | #xD | #x20
+ switch c[0] {
+ case '\t', '\n', '\f', ' ':
+ return c[1:]
+ case '\r':
+ // This differs from CSS3's wc production because it contains a
+ // probable spec error whereby wc contains all the single byte
+ // sequences in nl (newline) but not CRLF.
+ if len(c) >= 2 && c[1] == '\n' {
+ return c[2:]
+ }
+ return c[1:]
+ }
+ return c
+}
+
+// isCSSSpace returns whether b is a CSS space char as defined in wc.
+func isCSSSpace(b byte) bool {
+ switch b {
+ case '\t', '\n', '\f', '\r', ' ':
+ return true
+ }
+ return false
+}
+
+// cssEscaper escapes HTML and CSS special characters using \<hex>+ escapes.
+func cssEscaper(args ...interface{}) string {
+ s, _ := stringify(args...)
+ var b bytes.Buffer
+ written := 0
+ for i, r := range s {
+ var repl string
+ switch r {
+ case 0:
+ repl = `\0`
+ case '\t':
+ repl = `\9`
+ case '\n':
+ repl = `\a`
+ case '\f':
+ repl = `\c`
+ case '\r':
+ repl = `\d`
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ case '"':
+ repl = `\22`
+ case '&':
+ repl = `\26`
+ case '\'':
+ repl = `\27`
+ case '(':
+ repl = `\28`
+ case ')':
+ repl = `\29`
+ case '+':
+ repl = `\2b`
+ case '/':
+ repl = `\2f`
+ case ':':
+ repl = `\3a`
+ case ';':
+ repl = `\3b`
+ case '<':
+ repl = `\3c`
+ case '>':
+ repl = `\3e`
+ case '\\':
+ repl = `\\`
+ case '{':
+ repl = `\7b`
+ case '}':
+ repl = `\7d`
+ default:
+ continue
+ }
+ b.WriteString(s[written:i])
+ b.WriteString(repl)
+ written = i + utf8.RuneLen(r)
+ if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) {
+ b.WriteByte(' ')
+ }
+ }
+ if written == 0 {
+ return s
+ }
+ b.WriteString(s[written:])
+ return b.String()
+}
+
+var expressionBytes = []byte("expression")
+var mozBindingBytes = []byte("mozbinding")
+
+// cssValueFilter allows innocuous CSS values in the output including CSS
+// quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values
+// (inherit, blue), and colors (#888).
+// It filters out unsafe values, such as those that affect token boundaries,
+// and anything that might execute scripts.
+func cssValueFilter(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeCSS {
+ return s
+ }
+ b, id := decodeCSS([]byte(s)), make([]byte, 0, 64)
+
+ // CSS3 error handling is specified as honoring string boundaries per
+ // http://www.w3.org/TR/css3-syntax/#error-handling :
+ // Malformed declarations. User agents must handle unexpected
+ // tokens encountered while parsing a declaration by reading until
+ // the end of the declaration, while observing the rules for
+ // matching pairs of (), [], {}, "", and '', and correctly handling
+ // escapes. For example, a malformed declaration may be missing a
+ // property, colon (:) or value.
+ // So we need to make sure that values do not have mismatched bracket
+ // or quote characters to prevent the browser from restarting parsing
+ // inside a string that might embed JavaScript source.
+ for i, c := range b {
+ switch c {
+ case 0, '"', '\'', '(', ')', '/', ';', '@', '[', '\\', ']', '`', '{', '}':
+ return filterFailsafe
+ case '-':
+ // Disallow <!-- or -->.
+ // -- should not appear in valid identifiers.
+ if i != 0 && b[i-1] == '-' {
+ return filterFailsafe
+ }
+ default:
+ if c < 0x80 && isCSSNmchar(rune(c)) {
+ id = append(id, c)
+ }
+ }
+ }
+ id = bytes.ToLower(id)
+ if bytes.Index(id, expressionBytes) != -1 || bytes.Index(id, mozBindingBytes) != -1 {
+ return filterFailsafe
+ }
+ return string(b)
+}
diff --git a/src/pkg/html/template/css_test.go b/src/pkg/html/template/css_test.go
new file mode 100644
index 000000000..a735638b0
--- /dev/null
+++ b/src/pkg/html/template/css_test.go
@@ -0,0 +1,281 @@
+// 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 (
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func TestEndsWithCSSKeyword(t *testing.T) {
+ tests := []struct {
+ css, kw string
+ want bool
+ }{
+ {"", "url", false},
+ {"url", "url", true},
+ {"URL", "url", true},
+ {"Url", "url", true},
+ {"url", "important", false},
+ {"important", "important", true},
+ {"image-url", "url", false},
+ {"imageurl", "url", false},
+ {"image url", "url", true},
+ }
+ for _, test := range tests {
+ got := endsWithCSSKeyword([]byte(test.css), test.kw)
+ if got != test.want {
+ t.Errorf("want %t but got %t for css=%v, kw=%v", test.want, got, test.css, test.kw)
+ }
+ }
+}
+
+func TestIsCSSNmchar(t *testing.T) {
+ tests := []struct {
+ rune rune
+ want bool
+ }{
+ {0, false},
+ {'0', true},
+ {'9', true},
+ {'A', true},
+ {'Z', true},
+ {'a', true},
+ {'z', true},
+ {'_', true},
+ {'-', true},
+ {':', false},
+ {';', false},
+ {' ', false},
+ {0x7f, false},
+ {0x80, true},
+ {0x1234, true},
+ {0xd800, false},
+ {0xdc00, false},
+ {0xfffe, false},
+ {0x10000, true},
+ {0x110000, false},
+ }
+ for _, test := range tests {
+ got := isCSSNmchar(test.rune)
+ if got != test.want {
+ t.Errorf("%q: want %t but got %t", string(test.rune), test.want, got)
+ }
+ }
+}
+
+func TestDecodeCSS(t *testing.T) {
+ tests := []struct {
+ css, want string
+ }{
+ {``, ``},
+ {`foo`, `foo`},
+ {`foo\`, `foo`},
+ {`foo\\`, `foo\`},
+ {`\`, ``},
+ {`\A`, "\n"},
+ {`\a`, "\n"},
+ {`\0a`, "\n"},
+ {`\00000a`, "\n"},
+ {`\000000a`, "\u0000a"},
+ {`\1234 5`, "\u1234" + "5"},
+ {`\1234\20 5`, "\u1234" + " 5"},
+ {`\1234\A 5`, "\u1234" + "\n5"},
+ {"\\1234\t5", "\u1234" + "5"},
+ {"\\1234\n5", "\u1234" + "5"},
+ {"\\1234\r\n5", "\u1234" + "5"},
+ {`\12345`, "\U00012345"},
+ {`\\`, `\`},
+ {`\\ `, `\ `},
+ {`\"`, `"`},
+ {`\'`, `'`},
+ {`\.`, `.`},
+ {`\. .`, `. .`},
+ {
+ `The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e fox jumps\2028over the \3c canine class=\22lazy\22 \3e dog\3c/canine\3e`,
+ "The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>",
+ },
+ }
+ for _, test := range tests {
+ got1 := string(decodeCSS([]byte(test.css)))
+ if got1 != test.want {
+ t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.css, test.want, got1)
+ }
+ recoded := cssEscaper(got1)
+ if got2 := string(decodeCSS([]byte(recoded))); got2 != test.want {
+ t.Errorf("%q: escape & decode not dual for %q", test.css, recoded)
+ }
+ }
+}
+
+func TestHexDecode(t *testing.T) {
+ for i := 0; i < 0x200000; i += 101 /* coprime with 16 */ {
+ s := strconv.FormatInt(int64(i), 16)
+ if got := int(hexDecode([]byte(s))); got != i {
+ t.Errorf("%s: want %d but got %d", s, i, got)
+ }
+ s = strings.ToUpper(s)
+ if got := int(hexDecode([]byte(s))); got != i {
+ t.Errorf("%s: want %d but got %d", s, i, got)
+ }
+ }
+}
+
+func TestSkipCSSSpace(t *testing.T) {
+ tests := []struct {
+ css, want string
+ }{
+ {"", ""},
+ {"foo", "foo"},
+ {"\n", ""},
+ {"\r\n", ""},
+ {"\r", ""},
+ {"\t", ""},
+ {" ", ""},
+ {"\f", ""},
+ {" foo", "foo"},
+ {" foo", " foo"},
+ {`\20`, `\20`},
+ }
+ for _, test := range tests {
+ got := string(skipCSSSpace([]byte(test.css)))
+ if got != test.want {
+ t.Errorf("%q: want %q but got %q", test.css, test.want, got)
+ }
+ }
+}
+
+func TestCSSEscaper(t *testing.T) {
+ input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !"#$%&'()*+,-./` +
+ `0123456789:;<=>?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+
+ want := ("\\0\x01\x02\x03\x04\x05\x06\x07" +
+ "\x08\\9 \\a\x0b\\c \\d\x0E\x0F" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17" +
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !\22#$%\26\27\28\29*\2b,-.\2f ` +
+ `0123456789\3a\3b\3c=\3e?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\\]^_` +
+ "`abcdefghijklmno" +
+ `pqrstuvwxyz\7b|\7d~` + "\u007f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+
+ got := cssEscaper(input)
+ if got != want {
+ t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
+ }
+
+ got = string(decodeCSS([]byte(got)))
+ if input != got {
+ t.Errorf("decode: want\n\t%q\nbut got\n\t%q", input, got)
+ }
+}
+
+func TestCSSValueFilter(t *testing.T) {
+ tests := []struct {
+ css, want string
+ }{
+ {"", ""},
+ {"foo", "foo"},
+ {"0", "0"},
+ {"0px", "0px"},
+ {"-5px", "-5px"},
+ {"1.25in", "1.25in"},
+ {"+.33em", "+.33em"},
+ {"100%", "100%"},
+ {"12.5%", "12.5%"},
+ {".foo", ".foo"},
+ {"#bar", "#bar"},
+ {"corner-radius", "corner-radius"},
+ {"-moz-corner-radius", "-moz-corner-radius"},
+ {"#000", "#000"},
+ {"#48f", "#48f"},
+ {"#123456", "#123456"},
+ {"U+00-FF, U+980-9FF", "U+00-FF, U+980-9FF"},
+ {"color: red", "color: red"},
+ {"<!--", "ZgotmplZ"},
+ {"-->", "ZgotmplZ"},
+ {"<![CDATA[", "ZgotmplZ"},
+ {"]]>", "ZgotmplZ"},
+ {"</style", "ZgotmplZ"},
+ {`"`, "ZgotmplZ"},
+ {`'`, "ZgotmplZ"},
+ {"`", "ZgotmplZ"},
+ {"\x00", "ZgotmplZ"},
+ {"/* foo */", "ZgotmplZ"},
+ {"//", "ZgotmplZ"},
+ {"[href=~", "ZgotmplZ"},
+ {"expression(alert(1337))", "ZgotmplZ"},
+ {"-expression(alert(1337))", "ZgotmplZ"},
+ {"expression", "ZgotmplZ"},
+ {"Expression", "ZgotmplZ"},
+ {"EXPRESSION", "ZgotmplZ"},
+ {"-moz-binding", "ZgotmplZ"},
+ {"-expr\x00ession(alert(1337))", "ZgotmplZ"},
+ {`-expr\0ession(alert(1337))`, "ZgotmplZ"},
+ {`-express\69on(alert(1337))`, "ZgotmplZ"},
+ {`-express\69 on(alert(1337))`, "ZgotmplZ"},
+ {`-exp\72 ession(alert(1337))`, "ZgotmplZ"},
+ {`-exp\52 ession(alert(1337))`, "ZgotmplZ"},
+ {`-exp\000052 ession(alert(1337))`, "ZgotmplZ"},
+ {`-expre\0000073sion`, "-expre\x073sion"},
+ {`@import url evil.css`, "ZgotmplZ"},
+ }
+ for _, test := range tests {
+ got := cssValueFilter(test.css)
+ if got != test.want {
+ t.Errorf("%q: want %q but got %q", test.css, test.want, got)
+ }
+ }
+}
+
+func BenchmarkCSSEscaper(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ cssEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
+
+func BenchmarkCSSEscaperNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ cssEscaper("The quick, brown fox jumps over the lazy dog.")
+ }
+}
+
+func BenchmarkDecodeCSS(b *testing.B) {
+ s := []byte(`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e fox jumps\2028over the \3c canine class=\22lazy\22 \3edog\3c/canine\3e`)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ decodeCSS(s)
+ }
+}
+
+func BenchmarkDecodeCSSNoSpecials(b *testing.B) {
+ s := []byte("The quick, brown fox jumps over the lazy dog.")
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ decodeCSS(s)
+ }
+}
+
+func BenchmarkCSSValueFilter(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ cssValueFilter(` e\78preS\0Sio/**/n(alert(1337))`)
+ }
+}
+
+func BenchmarkCSSValueFilterOk(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ cssValueFilter(`Times New Roman`)
+ }
+}
diff --git a/src/pkg/html/template/doc.go b/src/pkg/html/template/doc.go
new file mode 100644
index 000000000..f470facfd
--- /dev/null
+++ b/src/pkg/html/template/doc.go
@@ -0,0 +1,191 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package template (html/template) implements data-driven templates for
+generating HTML output safe against code injection. It provides the
+same interface as package text/template and should be used instead of
+text/template whenever the output is HTML.
+
+The documentation here focuses on the security features of the package.
+For information about how to program the templates themselves, see the
+documentation for text/template.
+
+Introduction
+
+This package wraps package text/template so you can share its template API
+to parse and execute HTML templates safely.
+
+ tmpl, err := template.New("name").Parse(...)
+ // Error checking elided
+ err = tmpl.Execute(out, data)
+
+If successful, tmpl will now be injection-safe. Otherwise, err is an error
+defined in the docs for ErrorCode.
+
+HTML templates treat data values as plain text which should be encoded so they
+can be safely embedded in an HTML document. The escaping is contextual, so
+actions can appear within JavaScript, CSS, and URI contexts.
+
+The security model used by this package assumes that template authors are
+trusted, while Execute's data parameter is not. More details are
+provided below.
+
+Example
+
+ import "text/template"
+ ...
+ t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+ err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
+
+produces
+
+ Hello, <script>alert('you have been pwned')</script>!
+
+but the contextual autoescaping in html/template
+
+ import "html/template"
+ ...
+ t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+ err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
+
+produces safe, escaped HTML output
+
+ Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
+
+
+Contexts
+
+This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing
+functions to each simple action pipeline, so given the excerpt
+
+ <a href="/search?q={{.}}">{{.}}</a>
+
+At parse time each {{.}} is overwritten to add escaping functions as necessary.
+In this case it becomes
+
+ <a href="/search?q={{. | urlquery}}">{{. | html}}</a>
+
+
+Errors
+
+See the documentation of ErrorCode for details.
+
+
+A fuller picture
+
+The rest of this package comment may be skipped on first reading; it includes
+details necessary to understand escaping contexts and error messages. Most users
+will not need to understand these details.
+
+
+Contexts
+
+Assuming {{.}} is `O'Reilly: How are <i>you</i>?`, the table below shows
+how {{.}} appears when used in the context to the left.
+
+ Context {{.}} After
+ {{.}} O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?
+ <a title='{{.}}'> O&#39;Reilly: How are you?
+ <a href="/{{.}}"> O&#39;Reilly: How are %3ci%3eyou%3c/i%3e?
+ <a href="?q={{.}}"> O&#39;Reilly%3a%20How%20are%3ci%3e...%3f
+ <a onx='f("{{.}}")'> O\x27Reilly: How are \x3ci\x3eyou...?
+ <a onx='f({{.}})'> "O\x27Reilly: How are \x3ci\x3eyou...?"
+ <a onx='pattern = /{{.}}/;'> O\x27Reilly: How are \x3ci\x3eyou...\x3f
+
+If used in an unsafe context, then the value might be filtered out:
+
+ Context {{.}} After
+ <a href="{{.}}"> #ZgotmplZ
+
+since "O'Reilly:" is not an allowed protocol like "http:".
+
+
+If {{.}} is the innocuous word, `left`, then it can appear more widely,
+
+ Context {{.}} After
+ {{.}} left
+ <a title='{{.}}'> left
+ <a href='{{.}}'> left
+ <a href='/{{.}}'> left
+ <a href='?dir={{.}}'> left
+ <a style="border-{{.}}: 4px"> left
+ <a style="align: {{.}}"> left
+ <a style="background: '{{.}}'> left
+ <a style="background: url('{{.}}')> left
+ <style>p.{{.}} {color:red}</style> left
+
+Non-string values can be used in JavaScript contexts.
+If {{.}} is
+
+ []struct{A,B string}{ "foo", "bar" }
+
+in the escaped template
+
+ <script>var pair = {{.}};</script>
+
+then the template output is
+
+ <script>var pair = {"A": "foo", "B": "bar"};</script>
+
+See package json to understand how non-string content is marshalled for
+embedding in JavaScript contexts.
+
+
+Typed Strings
+
+By default, this package assumes that all pipelines produce a plain text string.
+It adds escaping pipeline stages necessary to correctly and safely embed that
+plain text string in the appropriate context.
+
+When a data value is not plain text, you can make sure it is not over-escaped
+by marking it with its type.
+
+Types HTML, JS, URL, and others from content.go can carry safe content that is
+exempted from escaping.
+
+The template
+
+ Hello, {{.}}!
+
+can be invoked with
+
+ tmpl.Execute(out, HTML(`<b>World</b>`))
+
+to produce
+
+ Hello, <b>World</b>!
+
+instead of the
+
+ Hello, &lt;b&gt;World&lt;b&gt;!
+
+that would have been produced if {{.}} was a regular string.
+
+
+Security Model
+
+http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
+
+This package assumes that template authors are trusted, that Execute's data
+parameter is not, and seeks to preserve the properties below in the face
+of untrusted data:
+
+Structure Preservation Property:
+"... when a template author writes an HTML tag in a safe templating language,
+the browser will interpret the corresponding portion of the output as a tag
+regardless of the values of untrusted data, and similarly for other structures
+such as attribute boundaries and JS and CSS string boundaries."
+
+Code Effect Property:
+"... only code specified by the template author should run as a result of
+injecting the template output into a page and all code specified by the
+template author should run as a result of the same."
+
+Least Surprise Property:
+"A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who
+knows that contextual autoescaping happens should be able to look at a {{.}}
+and correctly infer what sanitization happens."
+*/
+package template
diff --git a/src/pkg/html/template/error.go b/src/pkg/html/template/error.go
new file mode 100644
index 000000000..dcac74896
--- /dev/null
+++ b/src/pkg/html/template/error.go
@@ -0,0 +1,197 @@
+// 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"
+)
+
+// Error describes a problem encountered during template Escaping.
+type Error struct {
+ // ErrorCode describes the kind of error.
+ ErrorCode ErrorCode
+ // Name is the name of the template in which the error was encountered.
+ Name string
+ // Line is the line number of the error in the template source or 0.
+ Line int
+ // Description is a human-readable description of the problem.
+ Description string
+}
+
+// ErrorCode is a code for a kind of error.
+type ErrorCode int
+
+// We define codes for each error that manifests while escaping templates, but
+// escaped templates may also fail at runtime.
+//
+// Output: "ZgotmplZ"
+// Example:
+// <img src="{{.X}}">
+// where {{.X}} evaluates to `javascript:...`
+// Discussion:
+// "ZgotmplZ" is a special value that indicates that unsafe content reached a
+// CSS or URL context at runtime. The output of the example will be
+// <img src="#ZgotmplZ">
+// If the data comes from a trusted source, use content types to exempt it
+// from filtering: URL(`javascript:...`).
+const (
+ // OK indicates the lack of an error.
+ OK ErrorCode = iota
+
+ // ErrAmbigContext: "... appears in an ambiguous URL context"
+ // Example:
+ // <a href="
+ // {{if .C}}
+ // /path/
+ // {{else}}
+ // /search?q=
+ // {{end}}
+ // {{.X}}
+ // ">
+ // Discussion:
+ // {{.X}} is in an ambiguous URL context since, depending on {{.C}},
+ // it may be either a URL suffix or a query parameter.
+ // Moving {{.X}} into the condition removes the ambiguity:
+ // <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}">
+ ErrAmbigContext
+
+ // ErrBadHTML: "expected space, attr name, or end of tag, but got ...",
+ // "... in unquoted attr", "... in attribute name"
+ // Example:
+ // <a href = /search?q=foo>
+ // <href=foo>
+ // <form na<e=...>
+ // <option selected<
+ // Discussion:
+ // This is often due to a typo in an HTML element, but some runes
+ // are banned in tag names, attribute names, and unquoted attribute
+ // values because they can tickle parser ambiguities.
+ // Quoting all attributes is the best policy.
+ ErrBadHTML
+
+ // ErrBranchEnd: "{{if}} branches end in different contexts"
+ // Example:
+ // {{if .C}}<a href="{{end}}{{.X}}
+ // Discussion:
+ // Package html/template statically examines each path through an
+ // {{if}}, {{range}}, or {{with}} to escape any following pipelines.
+ // The example is ambiguous since {{.X}} might be an HTML text node,
+ // or a URL prefix in an HTML attribute. The context of {{.X}} is
+ // used to figure out how to escape it, but that context depends on
+ // the run-time value of {{.C}} which is not statically known.
+ //
+ // The problem is usually something like missing quotes or angle
+ // brackets, or can be avoided by refactoring to put the two contexts
+ // into different branches of an if, range or with. If the problem
+ // is in a {{range}} over a collection that should never be empty,
+ // adding a dummy {{else}} can help.
+ ErrBranchEnd
+
+ // ErrEndContext: "... ends in a non-text context: ..."
+ // Examples:
+ // <div
+ // <div title="no close quote>
+ // <script>f()
+ // Discussion:
+ // Executed templates should produce a DocumentFragment of HTML.
+ // Templates that end without closing tags will trigger this error.
+ // Templates that should not be used in an HTML context or that
+ // produce incomplete Fragments should not be executed directly.
+ //
+ // {{define "main"}} <script>{{template "helper"}}</script> {{end}}
+ // {{define "helper"}} document.write(' <div title=" ') {{end}}
+ //
+ // "helper" does not produce a valid document fragment, so should
+ // not be Executed directly.
+ ErrEndContext
+
+ // ErrNoSuchTemplate: "no such template ..."
+ // Examples:
+ // {{define "main"}}<div {{template "attrs"}}>{{end}}
+ // {{define "attrs"}}href="{{.URL}}"{{end}}
+ // Discussion:
+ // Package html/template looks through template calls to compute the
+ // context.
+ // Here the {{.URL}} in "attrs" must be treated as a URL when called
+ // from "main", but you will get this error if "attrs" is not defined
+ // when "main" is parsed.
+ ErrNoSuchTemplate
+
+ // ErrOutputContext: "cannot compute output context for template ..."
+ // Examples:
+ // {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
+ // Discussion:
+ // A recursive template does not end in the same context in which it
+ // starts, and a reliable output context cannot be computed.
+ // Look for typos in the named template.
+ // If the template should not be called in the named start context,
+ // look for calls to that template in unexpected contexts.
+ // Maybe refactor recursive templates to not be recursive.
+ ErrOutputContext
+
+ // ErrPartialCharset: "unfinished JS regexp charset in ..."
+ // Example:
+ // <script>var pattern = /foo[{{.Chars}}]/</script>
+ // Discussion:
+ // Package html/template does not support interpolation into regular
+ // expression literal character sets.
+ ErrPartialCharset
+
+ // ErrPartialEscape: "unfinished escape sequence in ..."
+ // Example:
+ // <script>alert("\{{.X}}")</script>
+ // Discussion:
+ // Package html/template does not support actions following a
+ // backslash.
+ // This is usually an error and there are better solutions; for
+ // example
+ // <script>alert("{{.X}}")</script>
+ // should work, and if {{.X}} is a partial escape sequence such as
+ // "xA0", mark the whole sequence as safe content: JSStr(`\xA0`)
+ ErrPartialEscape
+
+ // ErrRangeLoopReentry: "on range loop re-entry: ..."
+ // Example:
+ // <script>var x = [{{range .}}'{{.}},{{end}}]</script>
+ // Discussion:
+ // If an iteration through a range would cause it to end in a
+ // different context than an earlier pass, there is no single context.
+ // In the example, there is missing a quote, so it is not clear
+ // whether {{.}} is meant to be inside a JS string or in a JS value
+ // context. The second iteration would produce something like
+ //
+ // <script>var x = ['firstValue,'secondValue]</script>
+ ErrRangeLoopReentry
+
+ // ErrSlashAmbig: '/' could start a division or regexp.
+ // Example:
+ // <script>
+ // {{if .C}}var x = 1{{end}}
+ // /-{{.N}}/i.test(x) ? doThis : doThat();
+ // </script>
+ // Discussion:
+ // The example above could produce `var x = 1/-2/i.test(s)...`
+ // in which the first '/' is a mathematical division operator or it
+ // could produce `/-2/i.test(s)` in which the first '/' starts a
+ // regexp literal.
+ // Look for missing semicolons inside branches, and maybe add
+ // parentheses to make it clear which interpretation you intend.
+ ErrSlashAmbig
+)
+
+func (e *Error) Error() string {
+ if e.Line != 0 {
+ return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
+ } else if e.Name != "" {
+ return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
+ }
+ return "html/template: " + e.Description
+}
+
+// errorf creates an error given a format string f and args.
+// The template Name still needs to be supplied.
+func errorf(k ErrorCode, line int, f string, args ...interface{}) *Error {
+ return &Error{k, "", line, fmt.Sprintf(f, args...)}
+}
diff --git a/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go
new file mode 100644
index 000000000..5f0e28e8c
--- /dev/null
+++ b/src/pkg/html/template/escape.go
@@ -0,0 +1,795 @@
+// 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"
+ "html"
+ "io"
+ "text/template"
+ "text/template/parse"
+)
+
+// escapeTemplates rewrites the named templates, which must be
+// associated with t, to guarantee that the output of any of the named
+// templates is properly escaped. Names should include the names of
+// all templates that might be Executed but need not include helper
+// templates. If no error is returned, then the named templates have
+// been modified. Otherwise the named templates have been rendered
+// unusable.
+func escapeTemplates(tmpl *Template, names ...string) error {
+ e := newEscaper(tmpl)
+ for _, name := range names {
+ c, _ := e.escapeTree(context{}, name, 0)
+ var err error
+ if c.err != nil {
+ err, c.err.Name = c.err, name
+ } else if c.state != stateText {
+ err = &Error{ErrEndContext, name, 0, fmt.Sprintf("ends in a non-text context: %v", c)}
+ }
+ if err != nil {
+ // Prevent execution of unsafe templates.
+ for _, name := range names {
+ if t := tmpl.set[name]; t != nil {
+ t.text.Tree = nil
+ }
+ }
+ return err
+ }
+ tmpl.escaped = true
+ }
+ e.commit()
+ return nil
+}
+
+// funcMap maps command names to functions that render their inputs safe.
+var funcMap = template.FuncMap{
+ "html_template_attrescaper": attrEscaper,
+ "html_template_commentescaper": commentEscaper,
+ "html_template_cssescaper": cssEscaper,
+ "html_template_cssvaluefilter": cssValueFilter,
+ "html_template_htmlnamefilter": htmlNameFilter,
+ "html_template_htmlescaper": htmlEscaper,
+ "html_template_jsregexpescaper": jsRegexpEscaper,
+ "html_template_jsstrescaper": jsStrEscaper,
+ "html_template_jsvalescaper": jsValEscaper,
+ "html_template_nospaceescaper": htmlNospaceEscaper,
+ "html_template_rcdataescaper": rcdataEscaper,
+ "html_template_urlescaper": urlEscaper,
+ "html_template_urlfilter": urlFilter,
+ "html_template_urlnormalizer": urlNormalizer,
+}
+
+// equivEscapers matches contextual escapers to equivalent template builtins.
+var equivEscapers = map[string]string{
+ "html_template_attrescaper": "html",
+ "html_template_htmlescaper": "html",
+ "html_template_nospaceescaper": "html",
+ "html_template_rcdataescaper": "html",
+ "html_template_urlescaper": "urlquery",
+ "html_template_urlnormalizer": "urlquery",
+}
+
+// escaper collects type inferences about templates and changes needed to make
+// templates injection safe.
+type escaper struct {
+ tmpl *Template
+ // output[templateName] is the output context for a templateName that
+ // has been mangled to include its input context.
+ output map[string]context
+ // derived[c.mangle(name)] maps to a template derived from the template
+ // named name templateName for the start context c.
+ derived map[string]*template.Template
+ // called[templateName] is a set of called mangled template names.
+ called map[string]bool
+ // xxxNodeEdits are the accumulated edits to apply during commit.
+ // Such edits are not applied immediately in case a template set
+ // executes a given template in different escaping contexts.
+ actionNodeEdits map[*parse.ActionNode][]string
+ templateNodeEdits map[*parse.TemplateNode]string
+ textNodeEdits map[*parse.TextNode][]byte
+}
+
+// newEscaper creates a blank escaper for the given set.
+func newEscaper(t *Template) *escaper {
+ return &escaper{
+ t,
+ map[string]context{},
+ map[string]*template.Template{},
+ map[string]bool{},
+ map[*parse.ActionNode][]string{},
+ map[*parse.TemplateNode]string{},
+ map[*parse.TextNode][]byte{},
+ }
+}
+
+// filterFailsafe is an innocuous word that is emitted in place of unsafe values
+// by sanitizer functions. It is not a keyword in any programming language,
+// contains no special characters, is not empty, and when it appears in output
+// it is distinct enough that a developer can find the source of the problem
+// via a search engine.
+const filterFailsafe = "ZgotmplZ"
+
+// escape escapes a template node.
+func (e *escaper) escape(c context, n parse.Node) context {
+ switch n := n.(type) {
+ case *parse.ActionNode:
+ return e.escapeAction(c, n)
+ case *parse.IfNode:
+ return e.escapeBranch(c, &n.BranchNode, "if")
+ case *parse.ListNode:
+ return e.escapeList(c, n)
+ case *parse.RangeNode:
+ return e.escapeBranch(c, &n.BranchNode, "range")
+ case *parse.TemplateNode:
+ return e.escapeTemplate(c, n)
+ case *parse.TextNode:
+ return e.escapeText(c, n)
+ case *parse.WithNode:
+ return e.escapeBranch(c, &n.BranchNode, "with")
+ }
+ panic("escaping " + n.String() + " is unimplemented")
+}
+
+// escapeAction escapes an action template node.
+func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
+ if len(n.Pipe.Decl) != 0 {
+ // A local variable assignment, not an interpolation.
+ return c
+ }
+ c = nudge(c)
+ s := make([]string, 0, 3)
+ switch c.state {
+ case stateError:
+ return c
+ case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:
+ switch c.urlPart {
+ case urlPartNone:
+ s = append(s, "html_template_urlfilter")
+ fallthrough
+ case urlPartPreQuery:
+ switch c.state {
+ case stateCSSDqStr, stateCSSSqStr:
+ s = append(s, "html_template_cssescaper")
+ default:
+ s = append(s, "html_template_urlnormalizer")
+ }
+ case urlPartQueryOrFrag:
+ s = append(s, "html_template_urlescaper")
+ case urlPartUnknown:
+ return context{
+ state: stateError,
+ err: errorf(ErrAmbigContext, n.Line, "%s appears in an ambiguous URL context", n),
+ }
+ default:
+ panic(c.urlPart.String())
+ }
+ case stateJS:
+ s = append(s, "html_template_jsvalescaper")
+ // A slash after a value starts a div operator.
+ c.jsCtx = jsCtxDivOp
+ case stateJSDqStr, stateJSSqStr:
+ s = append(s, "html_template_jsstrescaper")
+ case stateJSRegexp:
+ s = append(s, "html_template_jsregexpescaper")
+ case stateCSS:
+ s = append(s, "html_template_cssvaluefilter")
+ case stateText:
+ s = append(s, "html_template_htmlescaper")
+ case stateRCDATA:
+ s = append(s, "html_template_rcdataescaper")
+ case stateAttr:
+ // Handled below in delim check.
+ case stateAttrName, stateTag:
+ c.state = stateAttrName
+ s = append(s, "html_template_htmlnamefilter")
+ default:
+ if isComment(c.state) {
+ s = append(s, "html_template_commentescaper")
+ } else {
+ panic("unexpected state " + c.state.String())
+ }
+ }
+ switch c.delim {
+ case delimNone:
+ // No extra-escaping needed for raw text content.
+ case delimSpaceOrTagEnd:
+ s = append(s, "html_template_nospaceescaper")
+ default:
+ s = append(s, "html_template_attrescaper")
+ }
+ e.editActionNode(n, s)
+ return c
+}
+
+// ensurePipelineContains ensures that the pipeline has commands with
+// the identifiers in s in order.
+// If the pipeline already has some of the sanitizers, do not interfere.
+// For example, if p is (.X | html) and s is ["escapeJSVal", "html"] then it
+// has one matching, "html", and one to insert, "escapeJSVal", to produce
+// (.X | escapeJSVal | html).
+func ensurePipelineContains(p *parse.PipeNode, s []string) {
+ if len(s) == 0 {
+ return
+ }
+ n := len(p.Cmds)
+ // Find the identifiers at the end of the command chain.
+ idents := p.Cmds
+ for i := n - 1; i >= 0; i-- {
+ if cmd := p.Cmds[i]; len(cmd.Args) != 0 {
+ if id, ok := cmd.Args[0].(*parse.IdentifierNode); ok {
+ if id.Ident == "noescape" {
+ return
+ }
+ continue
+ }
+ }
+ idents = p.Cmds[i+1:]
+ }
+ dups := 0
+ for _, id := range idents {
+ if escFnsEq(s[dups], (id.Args[0].(*parse.IdentifierNode)).Ident) {
+ dups++
+ if dups == len(s) {
+ return
+ }
+ }
+ }
+ newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)
+ copy(newCmds, p.Cmds)
+ // Merge existing identifier commands with the sanitizers needed.
+ for _, id := range idents {
+ i := indexOfStr((id.Args[0].(*parse.IdentifierNode)).Ident, s, escFnsEq)
+ if i != -1 {
+ for _, name := range s[:i] {
+ newCmds = appendCmd(newCmds, newIdentCmd(name))
+ }
+ s = s[i+1:]
+ }
+ newCmds = appendCmd(newCmds, id)
+ }
+ // Create any remaining sanitizers.
+ for _, name := range s {
+ newCmds = appendCmd(newCmds, newIdentCmd(name))
+ }
+ p.Cmds = newCmds
+}
+
+// redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
+// for all x.
+var redundantFuncs = map[string]map[string]bool{
+ "html_template_commentescaper": {
+ "html_template_attrescaper": true,
+ "html_template_nospaceescaper": true,
+ "html_template_htmlescaper": true,
+ },
+ "html_template_cssescaper": {
+ "html_template_attrescaper": true,
+ },
+ "html_template_jsregexpescaper": {
+ "html_template_attrescaper": true,
+ },
+ "html_template_jsstrescaper": {
+ "html_template_attrescaper": true,
+ },
+ "html_template_urlescaper": {
+ "html_template_urlnormalizer": true,
+ },
+}
+
+// appendCmd appends the given command to the end of the command pipeline
+// unless it is redundant with the last command.
+func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {
+ if n := len(cmds); n != 0 {
+ last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode)
+ next, _ := cmd.Args[0].(*parse.IdentifierNode)
+ if ok && redundantFuncs[last.Ident][next.Ident] {
+ return cmds
+ }
+ }
+ return append(cmds, cmd)
+}
+
+// indexOfStr is the first i such that eq(s, strs[i]) or -1 if s was not found.
+func indexOfStr(s string, strs []string, eq func(a, b string) bool) int {
+ for i, t := range strs {
+ if eq(s, t) {
+ return i
+ }
+ }
+ return -1
+}
+
+// escFnsEq returns whether the two escaping functions are equivalent.
+func escFnsEq(a, b string) bool {
+ if e := equivEscapers[a]; e != "" {
+ a = e
+ }
+ if e := equivEscapers[b]; e != "" {
+ b = e
+ }
+ return a == b
+}
+
+// newIdentCmd produces a command containing a single identifier node.
+func newIdentCmd(identifier string) *parse.CommandNode {
+ return &parse.CommandNode{
+ NodeType: parse.NodeCommand,
+ Args: []parse.Node{parse.NewIdentifier(identifier)},
+ }
+}
+
+// nudge returns the context that would result from following empty string
+// transitions from the input context.
+// For example, parsing:
+// `<a href=`
+// will end in context{stateBeforeValue, attrURL}, but parsing one extra rune:
+// `<a href=x`
+// will end in context{stateURL, delimSpaceOrTagEnd, ...}.
+// There are two transitions that happen when the 'x' is seen:
+// (1) Transition from a before-value state to a start-of-value state without
+// consuming any character.
+// (2) Consume 'x' and transition past the first value character.
+// In this case, nudging produces the context after (1) happens.
+func nudge(c context) context {
+ switch c.state {
+ case stateTag:
+ // In `<foo {{.}}`, the action should emit an attribute.
+ c.state = stateAttrName
+ case stateBeforeValue:
+ // In `<foo bar={{.}}`, the action is an undelimited value.
+ c.state, c.delim, c.attr = attrStartStates[c.attr], delimSpaceOrTagEnd, attrNone
+ case stateAfterName:
+ // In `<foo bar {{.}}`, the action is an attribute name.
+ c.state, c.attr = stateAttrName, attrNone
+ }
+ return c
+}
+
+// join joins the two contexts of a branch template node. The result is an
+// error context if either of the input contexts are error contexts, or if the
+// the input contexts differ.
+func join(a, b context, line int, nodeName string) context {
+ if a.state == stateError {
+ return a
+ }
+ if b.state == stateError {
+ return b
+ }
+ if a.eq(b) {
+ return a
+ }
+
+ c := a
+ c.urlPart = b.urlPart
+ if c.eq(b) {
+ // The contexts differ only by urlPart.
+ c.urlPart = urlPartUnknown
+ return c
+ }
+
+ c = a
+ c.jsCtx = b.jsCtx
+ if c.eq(b) {
+ // The contexts differ only by jsCtx.
+ c.jsCtx = jsCtxUnknown
+ return c
+ }
+
+ // Allow a nudged context to join with an unnudged one.
+ // This means that
+ // <p title={{if .C}}{{.}}{{end}}
+ // ends in an unquoted value state even though the else branch
+ // ends in stateBeforeValue.
+ if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) {
+ if e := join(c, d, line, nodeName); e.state != stateError {
+ return e
+ }
+ }
+
+ return context{
+ state: stateError,
+ err: errorf(ErrBranchEnd, line, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b),
+ }
+}
+
+// escapeBranch escapes a branch template node: "if", "range" and "with".
+func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context {
+ c0 := e.escapeList(c, n.List)
+ if nodeName == "range" && c0.state != stateError {
+ // The "true" branch of a "range" node can execute multiple times.
+ // We check that executing n.List once results in the same context
+ // as executing n.List twice.
+ c1, _ := e.escapeListConditionally(c0, n.List, nil)
+ c0 = join(c0, c1, n.Line, nodeName)
+ if c0.state == stateError {
+ // Make clear that this is a problem on loop re-entry
+ // since developers tend to overlook that branch when
+ // debugging templates.
+ c0.err.Line = n.Line
+ c0.err.Description = "on range loop re-entry: " + c0.err.Description
+ return c0
+ }
+ }
+ c1 := e.escapeList(c, n.ElseList)
+ return join(c0, c1, n.Line, nodeName)
+}
+
+// escapeList escapes a list template node.
+func (e *escaper) escapeList(c context, n *parse.ListNode) context {
+ if n == nil {
+ return c
+ }
+ for _, m := range n.Nodes {
+ c = e.escape(c, m)
+ }
+ return c
+}
+
+// escapeListConditionally escapes a list node but only preserves edits and
+// inferences in e if the inferences and output context satisfy filter.
+// It returns the best guess at an output context, and the result of the filter
+// which is the same as whether e was updated.
+func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) {
+ e1 := newEscaper(e.tmpl)
+ // Make type inferences available to f.
+ for k, v := range e.output {
+ e1.output[k] = v
+ }
+ c = e1.escapeList(c, n)
+ ok := filter != nil && filter(e1, c)
+ if ok {
+ // Copy inferences and edits from e1 back into e.
+ for k, v := range e1.output {
+ e.output[k] = v
+ }
+ for k, v := range e1.derived {
+ e.derived[k] = v
+ }
+ for k, v := range e1.called {
+ e.called[k] = v
+ }
+ for k, v := range e1.actionNodeEdits {
+ e.editActionNode(k, v)
+ }
+ for k, v := range e1.templateNodeEdits {
+ e.editTemplateNode(k, v)
+ }
+ for k, v := range e1.textNodeEdits {
+ e.editTextNode(k, v)
+ }
+ }
+ return c, ok
+}
+
+// escapeTemplate escapes a {{template}} call node.
+func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context {
+ c, name := e.escapeTree(c, n.Name, n.Line)
+ if name != n.Name {
+ e.editTemplateNode(n, name)
+ }
+ return c
+}
+
+// escapeTree escapes the named template starting in the given context as
+// necessary and returns its output context.
+func (e *escaper) escapeTree(c context, name string, line int) (context, string) {
+ // Mangle the template name with the input context to produce a reliable
+ // identifier.
+ dname := c.mangle(name)
+ e.called[dname] = true
+ if out, ok := e.output[dname]; ok {
+ // Already escaped.
+ return out, dname
+ }
+ t := e.template(name)
+ if t == nil {
+ // Two cases: The template exists but is empty, or has never been mentioned at
+ // all. Distinguish the cases in the error messages.
+ if e.tmpl.set[name] != nil {
+ return context{
+ state: stateError,
+ err: errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name),
+ }, dname
+ }
+ return context{
+ state: stateError,
+ err: errorf(ErrNoSuchTemplate, line, "no such template %q", name),
+ }, dname
+ }
+ if dname != name {
+ // Use any template derived during an earlier call to escapeTemplate
+ // with different top level templates, or clone if necessary.
+ dt := e.template(dname)
+ if dt == nil {
+ dt = template.New(dname)
+ dt.Tree = &parse.Tree{Name: dname, Root: t.Root.CopyList()}
+ e.derived[dname] = dt
+ }
+ t = dt
+ }
+ return e.computeOutCtx(c, t), dname
+}
+
+// computeOutCtx takes a template and its start context and computes the output
+// context while storing any inferences in e.
+func (e *escaper) computeOutCtx(c context, t *template.Template) context {
+ // Propagate context over the body.
+ c1, ok := e.escapeTemplateBody(c, t)
+ if !ok {
+ // Look for a fixed point by assuming c1 as the output context.
+ if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 {
+ c1, ok = c2, true
+ }
+ // Use c1 as the error context if neither assumption worked.
+ }
+ if !ok && c1.state != stateError {
+ return context{
+ state: stateError,
+ // TODO: Find the first node with a line in t.text.Tree.Root
+ err: errorf(ErrOutputContext, 0, "cannot compute output context for template %s", t.Name()),
+ }
+ }
+ return c1
+}
+
+// escapeTemplateBody escapes the given template assuming the given output
+// context, and returns the best guess at the output context and whether the
+// assumption was correct.
+func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) {
+ filter := func(e1 *escaper, c1 context) bool {
+ if c1.state == stateError {
+ // Do not update the input escaper, e.
+ return false
+ }
+ if !e1.called[t.Name()] {
+ // If t is not recursively called, then c1 is an
+ // accurate output context.
+ return true
+ }
+ // c1 is accurate if it matches our assumed output context.
+ return c.eq(c1)
+ }
+ // We need to assume an output context so that recursive template calls
+ // take the fast path out of escapeTree instead of infinitely recursing.
+ // Naively assuming that the input context is the same as the output
+ // works >90% of the time.
+ e.output[t.Name()] = c
+ return e.escapeListConditionally(c, t.Tree.Root, filter)
+}
+
+// delimEnds maps each delim to a string of characters that terminate it.
+var delimEnds = [...]string{
+ delimDoubleQuote: `"`,
+ delimSingleQuote: "'",
+ // Determined empirically by running the below in various browsers.
+ // var div = document.createElement("DIV");
+ // for (var i = 0; i < 0x10000; ++i) {
+ // div.innerHTML = "<span title=x" + String.fromCharCode(i) + "-bar>";
+ // if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0)
+ // document.write("<p>U+" + i.toString(16));
+ // }
+ delimSpaceOrTagEnd: " \t\n\f\r>",
+}
+
+var doctypeBytes = []byte("<!DOCTYPE")
+
+// escapeText escapes a text template node.
+func (e *escaper) escapeText(c context, n *parse.TextNode) context {
+ s, written, i, b := n.Text, 0, 0, new(bytes.Buffer)
+ for i != len(s) {
+ c1, nread := contextAfterText(c, s[i:])
+ i1 := i + nread
+ if c.state == stateText || c.state == stateRCDATA {
+ end := i1
+ if c1.state != c.state {
+ for j := end - 1; j >= i; j-- {
+ if s[j] == '<' {
+ end = j
+ break
+ }
+ }
+ }
+ for j := i; j < end; j++ {
+ if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) {
+ b.Write(s[written:j])
+ b.WriteString("&lt;")
+ written = j + 1
+ }
+ }
+ } else if isComment(c.state) && c.delim == delimNone {
+ switch c.state {
+ case stateJSBlockCmt:
+ // http://es5.github.com/#x7.4:
+ // "Comments behave like white space and are
+ // discarded except that, if a MultiLineComment
+ // contains a line terminator character, then
+ // the entire comment is considered to be a
+ // LineTerminator for purposes of parsing by
+ // the syntactic grammar."
+ if bytes.IndexAny(s[written:i1], "\n\r\u2028\u2029") != -1 {
+ b.WriteByte('\n')
+ } else {
+ b.WriteByte(' ')
+ }
+ case stateCSSBlockCmt:
+ b.WriteByte(' ')
+ }
+ written = i1
+ }
+ if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone {
+ // Preserve the portion between written and the comment start.
+ cs := i1 - 2
+ if c1.state == stateHTMLCmt {
+ // "<!--" instead of "/*" or "//"
+ cs -= 2
+ }
+ b.Write(s[written:cs])
+ written = i1
+ }
+ if i == i1 && c.state == c1.state {
+ panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:]))
+ }
+ c, i = c1, i1
+ }
+
+ if written != 0 && c.state != stateError {
+ if !isComment(c.state) || c.delim != delimNone {
+ b.Write(n.Text[written:])
+ }
+ e.editTextNode(n, b.Bytes())
+ }
+ return c
+}
+
+// contextAfterText starts in context c, consumes some tokens from the front of
+// s, then returns the context after those tokens and the unprocessed suffix.
+func contextAfterText(c context, s []byte) (context, int) {
+ if c.delim == delimNone {
+ c1, i := tSpecialTagEnd(c, s)
+ if i == 0 {
+ // A special end tag (`</script>`) has been seen and
+ // all content preceding it has been consumed.
+ return c1, 0
+ }
+ // Consider all content up to any end tag.
+ return transitionFunc[c.state](c, s[:i])
+ }
+
+ i := bytes.IndexAny(s, delimEnds[c.delim])
+ if i == -1 {
+ i = len(s)
+ }
+ if c.delim == delimSpaceOrTagEnd {
+ // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
+ // lists the runes below as error characters.
+ // Error out because HTML parsers may differ on whether
+ // "<a id= onclick=f(" ends inside id's or onclick's value,
+ // "<a class=`foo " ends inside a value,
+ // "<a style=font:'Arial'" needs open-quote fixup.
+ // IE treats '`' as a quotation character.
+ if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 {
+ return context{
+ state: stateError,
+ err: errorf(ErrBadHTML, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),
+ }, len(s)
+ }
+ }
+ if i == len(s) {
+ // Remain inside the attribute.
+ // Decode the value so non-HTML rules can easily handle
+ // <button onclick="alert(&quot;Hi!&quot;)">
+ // without having to entity decode token boundaries.
+ for u := []byte(html.UnescapeString(string(s))); len(u) != 0; {
+ c1, i1 := transitionFunc[c.state](c, u)
+ c, u = c1, u[i1:]
+ }
+ return c, len(s)
+ }
+ if c.delim != delimSpaceOrTagEnd {
+ // Consume any quote.
+ i++
+ }
+ // On exiting an attribute, we discard all state information
+ // except the state and element.
+ return context{state: stateTag, element: c.element}, i
+}
+
+// editActionNode records a change to an action pipeline for later commit.
+func (e *escaper) editActionNode(n *parse.ActionNode, cmds []string) {
+ if _, ok := e.actionNodeEdits[n]; ok {
+ panic(fmt.Sprintf("node %s shared between templates", n))
+ }
+ e.actionNodeEdits[n] = cmds
+}
+
+// editTemplateNode records a change to a {{template}} callee for later commit.
+func (e *escaper) editTemplateNode(n *parse.TemplateNode, callee string) {
+ if _, ok := e.templateNodeEdits[n]; ok {
+ panic(fmt.Sprintf("node %s shared between templates", n))
+ }
+ e.templateNodeEdits[n] = callee
+}
+
+// editTextNode records a change to a text node for later commit.
+func (e *escaper) editTextNode(n *parse.TextNode, text []byte) {
+ if _, ok := e.textNodeEdits[n]; ok {
+ panic(fmt.Sprintf("node %s shared between templates", n))
+ }
+ e.textNodeEdits[n] = text
+}
+
+// commit applies changes to actions and template calls needed to contextually
+// autoescape content and adds any derived templates to the set.
+func (e *escaper) commit() {
+ for name := range e.output {
+ e.template(name).Funcs(funcMap)
+ }
+ for _, t := range e.derived {
+ if _, err := e.tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil {
+ panic("error adding derived template")
+ }
+ }
+ for n, s := range e.actionNodeEdits {
+ ensurePipelineContains(n.Pipe, s)
+ }
+ for n, name := range e.templateNodeEdits {
+ n.Name = name
+ }
+ for n, s := range e.textNodeEdits {
+ n.Text = s
+ }
+}
+
+// template returns the named template given a mangled template name.
+func (e *escaper) template(name string) *template.Template {
+ t := e.tmpl.text.Lookup(name)
+ if t == nil {
+ t = e.derived[name]
+ }
+ return t
+}
+
+// Forwarding functions so that clients need only import this package
+// to reach the general escaping functions of text/template.
+
+// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
+func HTMLEscape(w io.Writer, b []byte) {
+ template.HTMLEscape(w, b)
+}
+
+// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
+func HTMLEscapeString(s string) string {
+ return template.HTMLEscapeString(s)
+}
+
+// HTMLEscaper returns the escaped HTML equivalent of the textual
+// representation of its arguments.
+func HTMLEscaper(args ...interface{}) string {
+ return template.HTMLEscaper(args...)
+}
+
+// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+func JSEscape(w io.Writer, b []byte) {
+ template.JSEscape(w, b)
+}
+
+// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
+func JSEscapeString(s string) string {
+ return template.JSEscapeString(s)
+}
+
+// JSEscaper returns the escaped JavaScript equivalent of the textual
+// representation of its arguments.
+func JSEscaper(args ...interface{}) string {
+ return template.JSEscaper(args...)
+}
+
+// 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 {
+ return template.URLQueryEscaper(args...)
+}
diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go
new file mode 100644
index 000000000..ce12c1795
--- /dev/null
+++ b/src/pkg/html/template/escape_test.go
@@ -0,0 +1,1657 @@
+// 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"
+ "encoding/json"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+ "text/template"
+ "text/template/parse"
+)
+
+type badMarshaler struct{}
+
+func (x *badMarshaler) MarshalJSON() ([]byte, error) {
+ // Keys in valid JSON must be double quoted as must all strings.
+ return []byte("{ foo: 'not quite valid JSON' }"), nil
+}
+
+type goodMarshaler struct{}
+
+func (x *goodMarshaler) MarshalJSON() ([]byte, error) {
+ return []byte(`{ "<foo>": "O'Reilly" }`), nil
+}
+
+func TestEscape(t *testing.T) {
+ data := struct {
+ F, T bool
+ C, G, H string
+ A, E []string
+ B, M json.Marshaler
+ N int
+ Z *int
+ W HTML
+ }{
+ F: false,
+ T: true,
+ C: "<Cincinatti>",
+ G: "<Goodbye>",
+ H: "<Hello>",
+ A: []string{"<a>", "<b>"},
+ E: []string{},
+ N: 42,
+ B: &badMarshaler{},
+ M: &goodMarshaler{},
+ Z: nil,
+ W: HTML(`&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`),
+ }
+ pdata := &data
+
+ tests := []struct {
+ name string
+ input string
+ output string
+ }{
+ {
+ "if",
+ "{{if .T}}Hello{{end}}, {{.C}}!",
+ "Hello, &lt;Cincinatti&gt;!",
+ },
+ {
+ "else",
+ "{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!",
+ "&lt;Goodbye&gt;!",
+ },
+ {
+ "overescaping1",
+ "Hello, {{.C | html}}!",
+ "Hello, &lt;Cincinatti&gt;!",
+ },
+ {
+ "overescaping2",
+ "Hello, {{html .C}}!",
+ "Hello, &lt;Cincinatti&gt;!",
+ },
+ {
+ "overescaping3",
+ "{{with .C}}{{$msg := .}}Hello, {{$msg}}!{{end}}",
+ "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="/search?q={{"'a<b'"}}">`,
+ `<a href="/search?q=%27a%3cb%27">`,
+ },
+ {
+ "multipleAttrs",
+ "<a b=1 c={{.H}}>",
+ "<a b=1 c=&lt;Hello&gt;>",
+ },
+ {
+ "urlStartRel",
+ `<a href='{{"/foo/bar?a=b&c=d"}}'>`,
+ `<a href='/foo/bar?a=b&amp;c=d'>`,
+ },
+ {
+ "urlStartAbsOk",
+ `<a href='{{"http://example.com/foo/bar?a=b&c=d"}}'>`,
+ `<a href='http://example.com/foo/bar?a=b&amp;c=d'>`,
+ },
+ {
+ "protocolRelativeURLStart",
+ `<a href='{{"//example.com:8000/foo/bar?a=b&c=d"}}'>`,
+ `<a href='//example.com:8000/foo/bar?a=b&amp;c=d'>`,
+ },
+ {
+ "pathRelativeURLStart",
+ `<a href="{{"/javascript:80/foo/bar"}}">`,
+ `<a href="/javascript:80/foo/bar">`,
+ },
+ {
+ "dangerousURLStart",
+ `<a href='{{"javascript:alert(%22pwned%22)"}}'>`,
+ `<a href='#ZgotmplZ'>`,
+ },
+ {
+ "dangerousURLStart2",
+ `<a href=' {{"javascript:alert(%22pwned%22)"}}'>`,
+ `<a href=' #ZgotmplZ'>`,
+ },
+ {
+ "nonHierURL",
+ `<a href={{"mailto:Muhammed \"The Greatest\" Ali <m.ali@example.com>"}}>`,
+ `<a href=mailto:Muhammed%20%22The%20Greatest%22%20Ali%20%3cm.ali@example.com%3e>`,
+ },
+ {
+ "urlPath",
+ `<a href='http://{{"javascript:80"}}/foo'>`,
+ `<a href='http://javascript:80/foo'>`,
+ },
+ {
+ "urlQuery",
+ `<a href='/search?q={{.H}}'>`,
+ `<a href='/search?q=%3cHello%3e'>`,
+ },
+ {
+ "urlFragment",
+ `<a href='/faq#{{.H}}'>`,
+ `<a href='/faq#%3cHello%3e'>`,
+ },
+ {
+ "urlBranch",
+ `<a href="{{if .F}}/foo?a=b{{else}}/bar{{end}}">`,
+ `<a href="/bar">`,
+ },
+ {
+ "urlBranchConflictMoot",
+ `<a href="{{if .T}}/foo?a={{else}}/bar#{{end}}{{.C}}">`,
+ `<a href="/foo?a=%3cCincinatti%3e">`,
+ },
+ {
+ "jsStrValue",
+ "<button onclick='alert({{.H}})'>",
+ `<button onclick='alert(&#34;\u003cHello\u003e&#34;)'>`,
+ },
+ {
+ "jsNumericValue",
+ "<button onclick='alert({{.N}})'>",
+ `<button onclick='alert( 42 )'>`,
+ },
+ {
+ "jsBoolValue",
+ "<button onclick='alert({{.T}})'>",
+ `<button onclick='alert( true )'>`,
+ },
+ {
+ "jsNilValue",
+ "<button onclick='alert(typeof{{.Z}})'>",
+ `<button onclick='alert(typeof null )'>`,
+ },
+ {
+ "jsObjValue",
+ "<button onclick='alert({{.A}})'>",
+ `<button onclick='alert([&#34;\u003ca\u003e&#34;,&#34;\u003cb\u003e&#34;])'>`,
+ },
+ {
+ "jsObjValueScript",
+ "<script>alert({{.A}})</script>",
+ `<script>alert(["\u003ca\u003e","\u003cb\u003e"])</script>`,
+ },
+ {
+ "jsObjValueNotOverEscaped",
+ "<button onclick='alert({{.A | html}})'>",
+ `<button onclick='alert([&#34;\u003ca\u003e&#34;,&#34;\u003cb\u003e&#34;])'>`,
+ },
+ {
+ "jsStr",
+ "<button onclick='alert(&quot;{{.H}}&quot;)'>",
+ `<button onclick='alert(&quot;\x3cHello\x3e&quot;)'>`,
+ },
+ {
+ "badMarshaler",
+ `<button onclick='alert(1/{{.B}}in numbers)'>`,
+ `<button onclick='alert(1/ /* json: error calling MarshalJSON for type *template.badMarshaler: invalid character &#39;f&#39; looking for beginning of object key string */null in numbers)'>`,
+ },
+ {
+ "jsMarshaler",
+ `<button onclick='alert({{.M}})'>`,
+ `<button onclick='alert({&#34;\u003cfoo\u003e&#34;:&#34;O&#39;Reilly&#34;})'>`,
+ },
+ {
+ "jsStrNotUnderEscaped",
+ "<button onclick='alert({{.C | urlquery}})'>",
+ // URL escaped, then quoted for JS.
+ `<button onclick='alert(&#34;%3CCincinatti%3E&#34;)'>`,
+ },
+ {
+ "jsRe",
+ `<button onclick='alert(/{{"foo+bar"}}/.test(""))'>`,
+ `<button onclick='alert(/foo\x2bbar/.test(""))'>`,
+ },
+ {
+ "jsReBlank",
+ `<script>alert(/{{""}}/.test(""));</script>`,
+ `<script>alert(/(?:)/.test(""));</script>`,
+ },
+ {
+ "jsReAmbigOk",
+ `<script>{{if true}}var x = 1{{end}}</script>`,
+ // The {if} ends in an ambiguous jsCtx but there is
+ // no slash following so we shouldn't care.
+ `<script>var x = 1</script>`,
+ },
+ {
+ "styleBidiKeywordPassed",
+ `<p style="dir: {{"ltr"}}">`,
+ `<p style="dir: ltr">`,
+ },
+ {
+ "styleBidiPropNamePassed",
+ `<p style="border-{{"left"}}: 0; border-{{"right"}}: 1in">`,
+ `<p style="border-left: 0; border-right: 1in">`,
+ },
+ {
+ "styleExpressionBlocked",
+ `<p style="width: {{"expression(alert(1337))"}}">`,
+ `<p style="width: ZgotmplZ">`,
+ },
+ {
+ "styleTagSelectorPassed",
+ `<style>{{"p"}} { color: pink }</style>`,
+ `<style>p { color: pink }</style>`,
+ },
+ {
+ "styleIDPassed",
+ `<style>p{{"#my-ID"}} { font: Arial }</style>`,
+ `<style>p#my-ID { font: Arial }</style>`,
+ },
+ {
+ "styleClassPassed",
+ `<style>p{{".my_class"}} { font: Arial }</style>`,
+ `<style>p.my_class { font: Arial }</style>`,
+ },
+ {
+ "styleQuantityPassed",
+ `<a style="left: {{"2em"}}; top: {{0}}">`,
+ `<a style="left: 2em; top: 0">`,
+ },
+ {
+ "stylePctPassed",
+ `<table style=width:{{"100%"}}>`,
+ `<table style=width:100%>`,
+ },
+ {
+ "styleColorPassed",
+ `<p style="color: {{"#8ff"}}; background: {{"#000"}}">`,
+ `<p style="color: #8ff; background: #000">`,
+ },
+ {
+ "styleObfuscatedExpressionBlocked",
+ `<p style="width: {{" e\\78preS\x00Sio/**/n(alert(1337))"}}">`,
+ `<p style="width: ZgotmplZ">`,
+ },
+ {
+ "styleMozBindingBlocked",
+ `<p style="{{"-moz-binding(alert(1337))"}}: ...">`,
+ `<p style="ZgotmplZ: ...">`,
+ },
+ {
+ "styleObfuscatedMozBindingBlocked",
+ `<p style="{{" -mo\\7a-B\x00I/**/nding(alert(1337))"}}: ...">`,
+ `<p style="ZgotmplZ: ...">`,
+ },
+ {
+ "styleFontNameString",
+ `<p style='font-family: "{{"Times New Roman"}}"'>`,
+ `<p style='font-family: "Times New Roman"'>`,
+ },
+ {
+ "styleFontNameString",
+ `<p style='font-family: "{{"Times New Roman"}}", "{{"sans-serif"}}"'>`,
+ `<p style='font-family: "Times New Roman", "sans-serif"'>`,
+ },
+ {
+ "styleFontNameUnquoted",
+ `<p style='font-family: {{"Times New Roman"}}'>`,
+ `<p style='font-family: Times New Roman'>`,
+ },
+ {
+ "styleURLQueryEncoded",
+ `<p style="background: url(/img?name={{"O'Reilly Animal(1)<2>.png"}})">`,
+ `<p style="background: url(/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png)">`,
+ },
+ {
+ "styleQuotedURLQueryEncoded",
+ `<p style="background: url('/img?name={{"O'Reilly Animal(1)<2>.png"}}')">`,
+ `<p style="background: url('/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png')">`,
+ },
+ {
+ "styleStrQueryEncoded",
+ `<p style="background: '/img?name={{"O'Reilly Animal(1)<2>.png"}}'">`,
+ `<p style="background: '/img?name=O%27Reilly%20Animal%281%29%3c2%3e.png'">`,
+ },
+ {
+ "styleURLBadProtocolBlocked",
+ `<a style="background: url('{{"javascript:alert(1337)"}}')">`,
+ `<a style="background: url('#ZgotmplZ')">`,
+ },
+ {
+ "styleStrBadProtocolBlocked",
+ `<a style="background: '{{"vbscript:alert(1337)"}}'">`,
+ `<a style="background: '#ZgotmplZ'">`,
+ },
+ {
+ "styleStrEncodedProtocolEncoded",
+ `<a style="background: '{{"javascript\\3a alert(1337)"}}'">`,
+ // The CSS string 'javascript\\3a alert(1337)' does not contains a colon.
+ `<a style="background: 'javascript\\3a alert\28 1337\29 '">`,
+ },
+ {
+ "styleURLGoodProtocolPassed",
+ `<a style="background: url('{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}')">`,
+ `<a style="background: url('http://oreilly.com/O%27Reilly%20Animals%281%29%3c2%3e;%7b%7d.html')">`,
+ },
+ {
+ "styleStrGoodProtocolPassed",
+ `<a style="background: '{{"http://oreilly.com/O'Reilly Animals(1)<2>;{}.html"}}'">`,
+ `<a style="background: 'http\3a\2f\2foreilly.com\2fO\27Reilly Animals\28 1\29\3c 2\3e\3b\7b\7d.html'">`,
+ },
+ {
+ "styleURLEncodedForHTMLInAttr",
+ `<a style="background: url('{{"/search?img=foo&size=icon"}}')">`,
+ `<a style="background: url('/search?img=foo&amp;size=icon')">`,
+ },
+ {
+ "styleURLNotEncodedForHTMLInCdata",
+ `<style>body { background: url('{{"/search?img=foo&size=icon"}}') }</style>`,
+ `<style>body { background: url('/search?img=foo&size=icon') }</style>`,
+ },
+ {
+ "styleURLMixedCase",
+ `<p style="background: URL(#{{.H}})">`,
+ `<p style="background: URL(#%3cHello%3e)">`,
+ },
+ {
+ "stylePropertyPairPassed",
+ `<a style='{{"color: red"}}'>`,
+ `<a style='color: red'>`,
+ },
+ {
+ "styleStrSpecialsEncoded",
+ `<a style="font-family: '{{"/**/'\";:// \\"}}', &quot;{{"/**/'\";:// \\"}}&quot;">`,
+ `<a style="font-family: '\2f**\2f\27\22\3b\3a\2f\2f \\', &quot;\2f**\2f\27\22\3b\3a\2f\2f \\&quot;">`,
+ },
+ {
+ "styleURLSpecialsEncoded",
+ `<a style="border-image: url({{"/**/'\";:// \\"}}), url(&quot;{{"/**/'\";:// \\"}}&quot;), url('{{"/**/'\";:// \\"}}'), 'http://www.example.com/?q={{"/**/'\";:// \\"}}''">`,
+ `<a style="border-image: url(/**/%27%22;://%20%5c), url(&quot;/**/%27%22;://%20%5c&quot;), url('/**/%27%22;://%20%5c'), 'http://www.example.com/?q=%2f%2a%2a%2f%27%22%3b%3a%2f%2f%20%5c''">`,
+ },
+ {
+ "HTML comment",
+ "<b>Hello, <!-- name of world -->{{.C}}</b>",
+ "<b>Hello, &lt;Cincinatti&gt;</b>",
+ },
+ {
+ "HTML comment not first < in text node.",
+ "<<!-- -->!--",
+ "&lt;!--",
+ },
+ {
+ "HTML normalization 1",
+ "a < b",
+ "a &lt; b",
+ },
+ {
+ "HTML normalization 2",
+ "a << b",
+ "a &lt;&lt; b",
+ },
+ {
+ "HTML normalization 3",
+ "a<<!-- --><!-- -->b",
+ "a&lt;b",
+ },
+ {
+ "HTML doctype not normalized",
+ "<!DOCTYPE html>Hello, World!",
+ "<!DOCTYPE html>Hello, World!",
+ },
+ {
+ "HTML doctype not case-insensitive",
+ "<!doCtYPE htMl>Hello, World!",
+ "<!doCtYPE htMl>Hello, World!",
+ },
+ {
+ "No doctype injection",
+ `<!{{"DOCTYPE"}}`,
+ "&lt;!DOCTYPE",
+ },
+ {
+ "Split HTML comment",
+ "<b>Hello, <!-- name of {{if .T}}city -->{{.C}}{{else}}world -->{{.W}}{{end}}</b>",
+ "<b>Hello, &lt;Cincinatti&gt;</b>",
+ },
+ {
+ "JS line comment",
+ "<script>for (;;) { if (c()) break// foo not a label\n" +
+ "foo({{.T}});}</script>",
+ "<script>for (;;) { if (c()) break\n" +
+ "foo( true );}</script>",
+ },
+ {
+ "JS multiline block comment",
+ "<script>for (;;) { if (c()) break/* foo not a label\n" +
+ " */foo({{.T}});}</script>",
+ // Newline separates break from call. If newline
+ // removed, then break will consume label leaving
+ // code invalid.
+ "<script>for (;;) { if (c()) break\n" +
+ "foo( true );}</script>",
+ },
+ {
+ "JS single-line block comment",
+ "<script>for (;;) {\n" +
+ "if (c()) break/* foo a label */foo;" +
+ "x({{.T}});}</script>",
+ // Newline separates break from call. If newline
+ // removed, then break will consume label leaving
+ // code invalid.
+ "<script>for (;;) {\n" +
+ "if (c()) break foo;" +
+ "x( true );}</script>",
+ },
+ {
+ "JS block comment flush with mathematical division",
+ "<script>var a/*b*//c\nd</script>",
+ "<script>var a /c\nd</script>",
+ },
+ {
+ "JS mixed comments",
+ "<script>var a/*b*///c\nd</script>",
+ "<script>var a \nd</script>",
+ },
+ {
+ "CSS comments",
+ "<style>p// paragraph\n" +
+ `{border: 1px/* color */{{"#00f"}}}</style>`,
+ "<style>p\n" +
+ "{border: 1px #00f}</style>",
+ },
+ {
+ "JS attr block comment",
+ `<a onclick="f(&quot;&quot;); /* alert({{.H}}) */">`,
+ // Attribute comment tests should pass if the comments
+ // are successfully elided.
+ `<a onclick="f(&quot;&quot;); /* alert() */">`,
+ },
+ {
+ "JS attr line comment",
+ `<a onclick="// alert({{.G}})">`,
+ `<a onclick="// alert()">`,
+ },
+ {
+ "CSS attr block comment",
+ `<a style="/* color: {{.H}} */">`,
+ `<a style="/* color: */">`,
+ },
+ {
+ "CSS attr line comment",
+ `<a style="// color: {{.G}}">`,
+ `<a style="// color: ">`,
+ },
+ {
+ "HTML substitution commented out",
+ "<p><!-- {{.H}} --></p>",
+ "<p></p>",
+ },
+ {
+ "Comment ends flush with start",
+ "<!--{{.}}--><script>/*{{.}}*///{{.}}\n</script><style>/*{{.}}*///{{.}}\n</style><a onclick='/*{{.}}*///{{.}}' style='/*{{.}}*///{{.}}'>",
+ "<script> \n</script><style> \n</style><a onclick='/**///' style='/**///'>",
+ },
+ {
+ "typed HTML in text",
+ `{{.W}}`,
+ `&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`,
+ },
+ {
+ "typed HTML in attribute",
+ `<div title="{{.W}}">`,
+ `<div title="&iexcl;Hello, O&#39;World!">`,
+ },
+ {
+ "typed HTML in script",
+ `<button onclick="alert({{.W}})">`,
+ `<button onclick="alert(&#34;&amp;iexcl;\u003cb class=\&#34;foo\&#34;\u003eHello\u003c/b\u003e, \u003ctextarea\u003eO&#39;World\u003c/textarea\u003e!&#34;)">`,
+ },
+ {
+ "typed HTML in RCDATA",
+ `<textarea>{{.W}}</textarea>`,
+ `<textarea>&iexcl;&lt;b class=&#34;foo&#34;&gt;Hello&lt;/b&gt;, &lt;textarea&gt;O&#39;World&lt;/textarea&gt;!</textarea>`,
+ },
+ {
+ "range in textarea",
+ "<textarea>{{range .A}}{{.}}{{end}}</textarea>",
+ "<textarea>&lt;a&gt;&lt;b&gt;</textarea>",
+ },
+ {
+ "auditable exemption from escaping",
+ "{{range .A}}{{. | noescape}}{{end}}",
+ "<a><b>",
+ },
+ {
+ "No tag injection",
+ `{{"10$"}}<{{"script src,evil.org/pwnd.js"}}...`,
+ `10$&lt;script src,evil.org/pwnd.js...`,
+ },
+ {
+ "No comment injection",
+ `<{{"!--"}}`,
+ `&lt;!--`,
+ },
+ {
+ "No RCDATA end tag injection",
+ `<textarea><{{"/textarea "}}...</textarea>`,
+ `<textarea>&lt;/textarea ...</textarea>`,
+ },
+ {
+ "optional attrs",
+ `<img class="{{"iconClass"}}"` +
+ `{{if .T}} id="{{"<iconId>"}}"{{end}}` +
+ // Double quotes inside if/else.
+ ` src=` +
+ `{{if .T}}"?{{"<iconPath>"}}"` +
+ `{{else}}"images/cleardot.gif"{{end}}` +
+ // Missing space before title, but it is not a
+ // part of the src attribute.
+ `{{if .T}}title="{{"<title>"}}"{{end}}` +
+ // Quotes outside if/else.
+ ` alt="` +
+ `{{if .T}}{{"<alt>"}}` +
+ `{{else}}{{if .F}}{{"<title>"}}{{end}}` +
+ `{{end}}"` +
+ `>`,
+ `<img class="iconClass" id="&lt;iconId&gt;" src="?%3ciconPath%3e"title="&lt;title&gt;" alt="&lt;alt&gt;">`,
+ },
+ {
+ "conditional valueless attr name",
+ `<input{{if .T}} checked{{end}} name=n>`,
+ `<input checked name=n>`,
+ },
+ {
+ "conditional dynamic valueless attr name 1",
+ `<input{{if .T}} {{"checked"}}{{end}} name=n>`,
+ `<input checked name=n>`,
+ },
+ {
+ "conditional dynamic valueless attr name 2",
+ `<input {{if .T}}{{"checked"}} {{end}}name=n>`,
+ `<input checked name=n>`,
+ },
+ {
+ "dynamic attribute name",
+ `<img on{{"load"}}="alert({{"loaded"}})">`,
+ // Treated as JS since quotes are inserted.
+ `<img onload="alert(&#34;loaded&#34;)">`,
+ },
+ {
+ "bad dynamic attribute name 1",
+ // Allow checked, selected, disabled, but not JS or
+ // CSS attributes.
+ `<input {{"onchange"}}="{{"doEvil()"}}">`,
+ `<input ZgotmplZ="doEvil()">`,
+ },
+ {
+ "bad dynamic attribute name 2",
+ `<div {{"sTyle"}}="{{"color: expression(alert(1337))"}}">`,
+ `<div ZgotmplZ="color: expression(alert(1337))">`,
+ },
+ {
+ "bad dynamic attribute name 3",
+ // Allow title or alt, but not a URL.
+ `<img {{"src"}}="{{"javascript:doEvil()"}}">`,
+ `<img ZgotmplZ="javascript:doEvil()">`,
+ },
+ {
+ "bad dynamic attribute name 4",
+ // Structure preservation requires values to associate
+ // with a consistent attribute.
+ `<input checked {{""}}="Whose value am I?">`,
+ `<input checked ZgotmplZ="Whose value am I?">`,
+ },
+ {
+ "dynamic element name",
+ `<h{{3}}><table><t{{"head"}}>...</h{{3}}>`,
+ `<h3><table><thead>...</h3>`,
+ },
+ {
+ "bad dynamic element name",
+ // Dynamic element names are typically used to switch
+ // between (thead, tfoot, tbody), (ul, ol), (th, td),
+ // and other replaceable sets.
+ // We do not currently easily support (ul, ol).
+ // If we do change to support that, this test should
+ // catch failures to filter out special tag names which
+ // would violate the structure preservation property --
+ // if any special tag name could be substituted, then
+ // the content could be raw text/RCDATA for some inputs
+ // and regular HTML content for others.
+ `<{{"script"}}>{{"doEvil()"}}</{{"script"}}>`,
+ `&lt;script>doEvil()&lt;/script>`,
+ },
+ }
+
+ for _, test := range tests {
+ tmpl := New(test.name)
+ // TODO: Move noescape into template/func.go
+ tmpl.Funcs(FuncMap{
+ "noescape": func(a ...interface{}) string {
+ return fmt.Sprint(a...)
+ },
+ })
+ tmpl = Must(tmpl.Parse(test.input))
+ b := new(bytes.Buffer)
+ if err := tmpl.Execute(b, data); err != nil {
+ t.Errorf("%s: template execution failed: %s", test.name, err)
+ continue
+ }
+ if w, g := test.output, b.String(); w != g {
+ t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g)
+ continue
+ }
+ b.Reset()
+ if err := tmpl.Execute(b, pdata); err != nil {
+ t.Errorf("%s: template execution failed for pointer: %s", test.name, err)
+ continue
+ }
+ if w, g := test.output, b.String(); w != g {
+ t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g)
+ continue
+ }
+ }
+}
+
+func TestEscapeSet(t *testing.T) {
+ type dataItem struct {
+ Children []*dataItem
+ X string
+ }
+
+ data := dataItem{
+ Children: []*dataItem{
+ {X: "foo"},
+ {X: "<bar>"},
+ {
+ Children: []*dataItem{
+ {X: "baz"},
+ },
+ },
+ },
+ }
+
+ tests := []struct {
+ inputs map[string]string
+ want string
+ }{
+ // The trivial set.
+ {
+ map[string]string{
+ "main": ``,
+ },
+ ``,
+ },
+ // A template called in the start context.
+ {
+ map[string]string{
+ "main": `Hello, {{template "helper"}}!`,
+ // Not a valid top level HTML template.
+ // "<b" is not a full tag.
+ "helper": `{{"<World>"}}`,
+ },
+ `Hello, &lt;World&gt;!`,
+ },
+ // A template called in a context other than the start.
+ {
+ map[string]string{
+ "main": `<a onclick='a = {{template "helper"}};'>`,
+ // Not a valid top level HTML template.
+ // "<b" is not a full tag.
+ "helper": `{{"<a>"}}<b`,
+ },
+ `<a onclick='a = &#34;\u003ca\u003e&#34;<b;'>`,
+ },
+ // A recursive template that ends in its start context.
+ {
+ map[string]string{
+ "main": `{{range .Children}}{{template "main" .}}{{else}}{{.X}} {{end}}`,
+ },
+ `foo &lt;bar&gt; baz `,
+ },
+ // A recursive helper template that ends in its start context.
+ {
+ map[string]string{
+ "main": `{{template "helper" .}}`,
+ "helper": `{{if .Children}}<ul>{{range .Children}}<li>{{template "main" .}}</li>{{end}}</ul>{{else}}{{.X}}{{end}}`,
+ },
+ `<ul><li>foo</li><li>&lt;bar&gt;</li><li><ul><li>baz</li></ul></li></ul>`,
+ },
+ // Co-recursive templates that end in its start context.
+ {
+ map[string]string{
+ "main": `<blockquote>{{range .Children}}{{template "helper" .}}{{end}}</blockquote>`,
+ "helper": `{{if .Children}}{{template "main" .}}{{else}}{{.X}}<br>{{end}}`,
+ },
+ `<blockquote>foo<br>&lt;bar&gt;<br><blockquote>baz<br></blockquote></blockquote>`,
+ },
+ // A template that is called in two different contexts.
+ {
+ map[string]string{
+ "main": `<button onclick="title='{{template "helper"}}'; ...">{{template "helper"}}</button>`,
+ "helper": `{{11}} of {{"<100>"}}`,
+ },
+ `<button onclick="title='11 of \x3c100\x3e'; ...">11 of &lt;100&gt;</button>`,
+ },
+ // A non-recursive template that ends in a different context.
+ // helper starts in jsCtxRegexp and ends in jsCtxDivOp.
+ {
+ map[string]string{
+ "main": `<script>var x={{template "helper"}}/{{"42"}};</script>`,
+ "helper": "{{126}}",
+ },
+ `<script>var x= 126 /"42";</script>`,
+ },
+ // A recursive template that ends in a similar context.
+ {
+ map[string]string{
+ "main": `<script>var x=[{{template "countdown" 4}}];</script>`,
+ "countdown": `{{.}}{{if .}},{{template "countdown" . | pred}}{{end}}`,
+ },
+ `<script>var x=[ 4 , 3 , 2 , 1 , 0 ];</script>`,
+ },
+ // A recursive template that ends in a different context.
+ /*
+ {
+ map[string]string{
+ "main": `<a href="/foo{{template "helper" .}}">`,
+ "helper": `{{if .Children}}{{range .Children}}{{template "helper" .}}{{end}}{{else}}?x={{.X}}{{end}}`,
+ },
+ `<a href="/foo?x=foo?x=%3cbar%3e?x=baz">`,
+ },
+ */
+ }
+
+ // pred is a template function that returns the predecessor of a
+ // natural number for testing recursive templates.
+ fns := FuncMap{"pred": func(a ...interface{}) (interface{}, error) {
+ if len(a) == 1 {
+ if i, _ := a[0].(int); i > 0 {
+ return i - 1, nil
+ }
+ }
+ return nil, fmt.Errorf("undefined pred(%v)", a)
+ }}
+
+ for _, test := range tests {
+ source := ""
+ for name, body := range test.inputs {
+ source += fmt.Sprintf("{{define %q}}%s{{end}} ", name, body)
+ }
+ tmpl, err := New("root").Funcs(fns).Parse(source)
+ if err != nil {
+ t.Errorf("error parsing %q: %v", source, err)
+ continue
+ }
+ var b bytes.Buffer
+
+ if err := tmpl.ExecuteTemplate(&b, "main", data); err != nil {
+ t.Errorf("%q executing %v", err.Error(), tmpl.Lookup("main"))
+ continue
+ }
+ if got := b.String(); test.want != got {
+ t.Errorf("want\n\t%q\ngot\n\t%q", test.want, got)
+ }
+ }
+
+}
+
+func TestErrors(t *testing.T) {
+ tests := []struct {
+ input string
+ err string
+ }{
+ // Non-error cases.
+ {
+ "{{if .Cond}}<a>{{else}}<b>{{end}}",
+ "",
+ },
+ {
+ "{{if .Cond}}<a>{{end}}",
+ "",
+ },
+ {
+ "{{if .Cond}}{{else}}<b>{{end}}",
+ "",
+ },
+ {
+ "{{with .Cond}}<div>{{end}}",
+ "",
+ },
+ {
+ "{{range .Items}}<a>{{end}}",
+ "",
+ },
+ {
+ "<a href='/foo?{{range .Items}}&{{.K}}={{.V}}{{end}}'>",
+ "",
+ },
+ // Error cases.
+ {
+ "{{if .Cond}}<a{{end}}",
+ "z:1: {{if}} branches",
+ },
+ {
+ "{{if .Cond}}\n{{else}}\n<a{{end}}",
+ "z:1: {{if}} branches",
+ },
+ {
+ // Missing quote in the else branch.
+ `{{if .Cond}}<a href="foo">{{else}}<a href="bar>{{end}}`,
+ "z:1: {{if}} branches",
+ },
+ {
+ // Different kind of attribute: href implies a URL.
+ "<a {{if .Cond}}href='{{else}}title='{{end}}{{.X}}'>",
+ "z:1: {{if}} branches",
+ },
+ {
+ "\n{{with .X}}<a{{end}}",
+ "z:2: {{with}} branches",
+ },
+ {
+ "\n{{with .X}}<a>{{else}}<a{{end}}",
+ "z:2: {{with}} branches",
+ },
+ {
+ "{{range .Items}}<a{{end}}",
+ `z:1: on range loop re-entry: "<" in attribute name: "<a"`,
+ },
+ {
+ "\n{{range .Items}} x='<a{{end}}",
+ "z:2: on range loop re-entry: {{range}} branches",
+ },
+ {
+ "<a b=1 c={{.H}}",
+ "z: ends in a non-text context: {stateAttr delimSpaceOrTagEnd",
+ },
+ {
+ "<script>foo();",
+ "z: ends in a non-text context: {stateJS",
+ },
+ {
+ `<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`,
+ "z:1: {{.H}} appears in an ambiguous URL context",
+ },
+ {
+ `<a onclick="alert('Hello \`,
+ `unfinished escape sequence in JS string: "Hello \\"`,
+ },
+ {
+ `<a onclick='alert("Hello\, World\`,
+ `unfinished escape sequence in JS string: "Hello\\, World\\"`,
+ },
+ {
+ `<a onclick='alert(/x+\`,
+ `unfinished escape sequence in JS string: "x+\\"`,
+ },
+ {
+ `<a onclick="/foo[\]/`,
+ `unfinished JS regexp charset: "foo[\\]/"`,
+ },
+ {
+ // It is ambiguous whether 1.5 should be 1\.5 or 1.5.
+ // Either `var x = 1/- 1.5 /i.test(x)`
+ // where `i.test(x)` is a method call of reference i,
+ // or `/-1\.5/i.test(x)` which is a method call on a
+ // case insensitive regular expression.
+ `<script>{{if false}}var x = 1{{end}}/-{{"1.5"}}/i.test(x)</script>`,
+ `'/' could start a division or regexp: "/-"`,
+ },
+ {
+ `{{template "foo"}}`,
+ "z:1: no such template \"foo\"",
+ },
+ {
+ `<div{{template "y"}}>` +
+ // Illegal starting in stateTag but not in stateText.
+ `{{define "y"}} foo<b{{end}}`,
+ `"<" in attribute name: " foo<b"`,
+ },
+ {
+ `<script>reverseList = [{{template "t"}}]</script>` +
+ // Missing " after recursive call.
+ `{{define "t"}}{{if .Tail}}{{template "t" .Tail}}{{end}}{{.Head}}",{{end}}`,
+ `: cannot compute output context for template t$htmltemplate_stateJS_elementScript`,
+ },
+ {
+ `<input type=button value=onclick=>`,
+ `html/template:z: "=" in unquoted attr: "onclick="`,
+ },
+ {
+ `<input type=button value= onclick=>`,
+ `html/template:z: "=" in unquoted attr: "onclick="`,
+ },
+ {
+ `<input type=button value= 1+1=2>`,
+ `html/template:z: "=" in unquoted attr: "1+1=2"`,
+ },
+ {
+ "<a class=`foo>",
+ "html/template:z: \"`\" in unquoted attr: \"`foo\"",
+ },
+ {
+ `<a style=font:'Arial'>`,
+ `html/template:z: "'" in unquoted attr: "font:'Arial'"`,
+ },
+ {
+ `<a=foo>`,
+ `: expected space, attr name, or end of tag, but got "=foo>"`,
+ },
+ }
+
+ for _, test := range tests {
+ buf := new(bytes.Buffer)
+ tmpl, err := New("z").Parse(test.input)
+ if err != nil {
+ t.Errorf("input=%q: unexpected parse error %s\n", test.input, err)
+ continue
+ }
+ err = tmpl.Execute(buf, nil)
+ var got string
+ if err != nil {
+ got = err.Error()
+ }
+ if test.err == "" {
+ if got != "" {
+ t.Errorf("input=%q: unexpected error %q", test.input, got)
+ }
+ continue
+ }
+ if strings.Index(got, test.err) == -1 {
+ t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err)
+ continue
+ }
+ }
+}
+
+func TestEscapeText(t *testing.T) {
+ tests := []struct {
+ input string
+ output context
+ }{
+ {
+ ``,
+ context{},
+ },
+ {
+ `Hello, World!`,
+ context{},
+ },
+ {
+ // An orphaned "<" is OK.
+ `I <3 Ponies!`,
+ context{},
+ },
+ {
+ `<a`,
+ context{state: stateTag},
+ },
+ {
+ `<a `,
+ context{state: stateTag},
+ },
+ {
+ `<a>`,
+ context{state: stateText},
+ },
+ {
+ `<a href`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a on`,
+ context{state: stateAttrName, attr: attrScript},
+ },
+ {
+ `<a href `,
+ context{state: stateAfterName, attr: attrURL},
+ },
+ {
+ `<a style = `,
+ context{state: stateBeforeValue, attr: attrStyle},
+ },
+ {
+ `<a href=`,
+ context{state: stateBeforeValue, attr: attrURL},
+ },
+ {
+ `<a href=x`,
+ context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href=x `,
+ context{state: stateTag},
+ },
+ {
+ `<a href=>`,
+ context{state: stateText},
+ },
+ {
+ `<a href=x>`,
+ context{state: stateText},
+ },
+ {
+ `<a href ='`,
+ context{state: stateURL, delim: delimSingleQuote},
+ },
+ {
+ `<a href=''`,
+ context{state: stateTag},
+ },
+ {
+ `<a href= "`,
+ context{state: stateURL, delim: delimDoubleQuote},
+ },
+ {
+ `<a href=""`,
+ context{state: stateTag},
+ },
+ {
+ `<a title="`,
+ context{state: stateAttr, delim: delimDoubleQuote},
+ },
+ {
+ `<a HREF='http:`,
+ context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a Href='/`,
+ context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href='"`,
+ context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href="'`,
+ context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href='&apos;`,
+ context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href="&quot;`,
+ context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href="&#34;`,
+ context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a href=&quot;`,
+ context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery},
+ },
+ {
+ `<img alt="1">`,
+ context{state: stateText},
+ },
+ {
+ `<img alt="1>"`,
+ context{state: stateTag},
+ },
+ {
+ `<img alt="1>">`,
+ context{state: stateText},
+ },
+ {
+ `<input checked type="checkbox"`,
+ context{state: stateTag},
+ },
+ {
+ `<a onclick="`,
+ context{state: stateJS, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="//foo`,
+ context{state: stateJSLineCmt, delim: delimDoubleQuote},
+ },
+ {
+ "<a onclick='//\n",
+ context{state: stateJS, delim: delimSingleQuote},
+ },
+ {
+ "<a onclick='//\r\n",
+ context{state: stateJS, delim: delimSingleQuote},
+ },
+ {
+ "<a onclick='//\u2028",
+ context{state: stateJS, delim: delimSingleQuote},
+ },
+ {
+ `<a onclick="/*`,
+ context{state: stateJSBlockCmt, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/*/`,
+ context{state: stateJSBlockCmt, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/**/`,
+ context{state: stateJS, delim: delimDoubleQuote},
+ },
+ {
+ `<a onkeypress="&quot;`,
+ context{state: stateJSDqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick='&quot;foo&quot;`,
+ context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<a onclick=&#39;foo&#39;`,
+ context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<a onclick=&#39;foo`,
+ context{state: stateJSSqStr, delim: delimSpaceOrTagEnd},
+ },
+ {
+ `<a onclick="&quot;foo'`,
+ context{state: stateJSDqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="'foo&quot;`,
+ context{state: stateJSSqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<A ONCLICK="'`,
+ context{state: stateJSSqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/`,
+ context{state: stateJSRegexp, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="'foo'`,
+ context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<a onclick="'foo\'`,
+ context{state: stateJSSqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="'foo\'`,
+ context{state: stateJSSqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/foo/`,
+ context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<script>/foo/ /=`,
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ `<a onclick="1 /foo`,
+ context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<a onclick="1 /*c*/ /foo`,
+ context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<a onclick="/foo[/]`,
+ context{state: stateJSRegexp, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/foo\/`,
+ context{state: stateJSRegexp, delim: delimDoubleQuote},
+ },
+ {
+ `<a onclick="/foo/`,
+ context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp},
+ },
+ {
+ `<input checked style="`,
+ context{state: stateCSS, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="//`,
+ context{state: stateCSSLineCmt, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="//</script>`,
+ context{state: stateCSSLineCmt, delim: delimDoubleQuote},
+ },
+ {
+ "<a style='//\n",
+ context{state: stateCSS, delim: delimSingleQuote},
+ },
+ {
+ "<a style='//\r",
+ context{state: stateCSS, delim: delimSingleQuote},
+ },
+ {
+ `<a style="/*`,
+ context{state: stateCSSBlockCmt, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="/*/`,
+ context{state: stateCSSBlockCmt, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="/**/`,
+ context{state: stateCSS, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: '`,
+ context{state: stateCSSSqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: &quot;`,
+ context{state: stateCSSDqStr, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: '/foo?img=`,
+ context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag},
+ },
+ {
+ `<a style="background: '/`,
+ context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url(&#x22;/`,
+ context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url('/`,
+ context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url('/)`,
+ context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url('/ `,
+ context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url(/`,
+ context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery},
+ },
+ {
+ `<a style="background: url( `,
+ context{state: stateCSSURL, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: url( /image?name=`,
+ context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag},
+ },
+ {
+ `<a style="background: url(x)`,
+ context{state: stateCSS, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: url('x'`,
+ context{state: stateCSS, delim: delimDoubleQuote},
+ },
+ {
+ `<a style="background: url( x `,
+ context{state: stateCSS, delim: delimDoubleQuote},
+ },
+ {
+ `<!-- foo`,
+ context{state: stateHTMLCmt},
+ },
+ {
+ `<!-->`,
+ context{state: stateHTMLCmt},
+ },
+ {
+ `<!--->`,
+ context{state: stateHTMLCmt},
+ },
+ {
+ `<!-- foo -->`,
+ context{state: stateText},
+ },
+ {
+ `<script`,
+ context{state: stateTag, element: elementScript},
+ },
+ {
+ `<script `,
+ context{state: stateTag, element: elementScript},
+ },
+ {
+ `<script src="foo.js" `,
+ context{state: stateTag, element: elementScript},
+ },
+ {
+ `<script src='foo.js' `,
+ context{state: stateTag, element: elementScript},
+ },
+ {
+ `<script type=text/javascript `,
+ context{state: stateTag, element: elementScript},
+ },
+ {
+ `<script>foo`,
+ context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
+ },
+ {
+ `<script>foo</script>`,
+ context{state: stateText},
+ },
+ {
+ `<script>foo</script><!--`,
+ context{state: stateHTMLCmt},
+ },
+ {
+ `<script>document.write("<p>foo</p>");`,
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ `<script>document.write("<p>foo<\/script>");`,
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ `<script>document.write("<script>alert(1)</script>");`,
+ context{state: stateText},
+ },
+ {
+ `<Script>`,
+ context{state: stateJS, element: elementScript},
+ },
+ {
+ `<SCRIPT>foo`,
+ context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
+ },
+ {
+ `<textarea>value`,
+ context{state: stateRCDATA, element: elementTextarea},
+ },
+ {
+ `<textarea>value</TEXTAREA>`,
+ context{state: stateText},
+ },
+ {
+ `<textarea name=html><b`,
+ context{state: stateRCDATA, element: elementTextarea},
+ },
+ {
+ `<title>value`,
+ context{state: stateRCDATA, element: elementTitle},
+ },
+ {
+ `<style>value`,
+ context{state: stateCSS, element: elementStyle},
+ },
+ {
+ `<a xlink:href`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a xmlns`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a xmlns:foo`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a xmlnsxyz`,
+ context{state: stateAttrName},
+ },
+ {
+ `<a data-url`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a data-iconUri`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a data-urlItem`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a g:`,
+ context{state: stateAttrName},
+ },
+ {
+ `<a g:url`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a g:iconUri`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a g:urlItem`,
+ context{state: stateAttrName, attr: attrURL},
+ },
+ {
+ `<a g:value`,
+ context{state: stateAttrName},
+ },
+ {
+ `<a svg:style='`,
+ context{state: stateCSS, delim: delimSingleQuote},
+ },
+ {
+ `<svg:font-face`,
+ context{state: stateTag},
+ },
+ {
+ `<svg:a svg:onclick="`,
+ context{state: stateJS, delim: delimDoubleQuote},
+ },
+ }
+
+ for _, test := range tests {
+ b, e := []byte(test.input), newEscaper(nil)
+ c := e.escapeText(context{}, &parse.TextNode{NodeType: parse.NodeText, Text: b})
+ if !test.output.eq(c) {
+ t.Errorf("input %q: want context\n\t%v\ngot\n\t%v", test.input, test.output, c)
+ continue
+ }
+ if test.input != string(b) {
+ t.Errorf("input %q: text node was modified: want %q got %q", test.input, test.input, b)
+ continue
+ }
+ }
+}
+
+func TestEnsurePipelineContains(t *testing.T) {
+ tests := []struct {
+ input, output string
+ ids []string
+ }{
+ {
+ "{{.X}}",
+ ".X",
+ []string{},
+ },
+ {
+ "{{.X | html}}",
+ ".X | html",
+ []string{},
+ },
+ {
+ "{{.X}}",
+ ".X | html",
+ []string{"html"},
+ },
+ {
+ "{{.X | html}}",
+ ".X | html | urlquery",
+ []string{"urlquery"},
+ },
+ {
+ "{{.X | html | urlquery}}",
+ ".X | html | urlquery",
+ []string{"urlquery"},
+ },
+ {
+ "{{.X | html | urlquery}}",
+ ".X | html | urlquery",
+ []string{"html", "urlquery"},
+ },
+ {
+ "{{.X | html | urlquery}}",
+ ".X | html | urlquery",
+ []string{"html"},
+ },
+ {
+ "{{.X | urlquery}}",
+ ".X | html | urlquery",
+ []string{"html", "urlquery"},
+ },
+ {
+ "{{.X | html | print}}",
+ ".X | urlquery | html | print",
+ []string{"urlquery", "html"},
+ },
+ }
+ for i, test := range tests {
+ tmpl := template.Must(template.New("test").Parse(test.input))
+ action, ok := (tmpl.Tree.Root.Nodes[0].(*parse.ActionNode))
+ if !ok {
+ t.Errorf("#%d: First node is not an action: %s", i, test.input)
+ continue
+ }
+ pipe := action.Pipe
+ ensurePipelineContains(pipe, test.ids)
+ got := pipe.String()
+ if got != test.output {
+ t.Errorf("#%d: %s, %v: want\n\t%s\ngot\n\t%s", i, test.input, test.ids, test.output, got)
+ }
+ }
+}
+
+func TestEscapeErrorsNotIgnorable(t *testing.T) {
+ var b bytes.Buffer
+ tmpl, _ := New("dangerous").Parse("<a")
+ err := tmpl.Execute(&b, nil)
+ if err == nil {
+ t.Errorf("Expected error")
+ } else if b.Len() != 0 {
+ t.Errorf("Emitted output despite escaping failure")
+ }
+}
+
+func TestEscapeSetErrorsNotIgnorable(t *testing.T) {
+ var b bytes.Buffer
+ tmpl, err := New("root").Parse(`{{define "t"}}<a{{end}}`)
+ if err != nil {
+ t.Errorf("failed to parse set: %q", err)
+ }
+ err = tmpl.ExecuteTemplate(&b, "t", nil)
+ if err == nil {
+ t.Errorf("Expected error")
+ } else if b.Len() != 0 {
+ t.Errorf("Emitted output despite escaping failure")
+ }
+}
+
+func TestRedundantFuncs(t *testing.T) {
+ inputs := []interface{}{
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !"#$%&'()*+,-./` +
+ `0123456789:;<=>?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\ufdec\ufffd\uffff\U0001D11E" +
+ "&amp;%22\\",
+ CSS(`a[href =~ "//example.com"]#foo`),
+ HTML(`Hello, <b>World</b> &amp;tc!`),
+ HTMLAttr(` dir="ltr"`),
+ JS(`c && alert("Hello, World!");`),
+ JSStr(`Hello, World & O'Reilly\x21`),
+ URL(`greeting=H%69&addressee=(World)`),
+ }
+
+ for n0, m := range redundantFuncs {
+ f0 := funcMap[n0].(func(...interface{}) string)
+ for n1 := range m {
+ f1 := funcMap[n1].(func(...interface{}) string)
+ for _, input := range inputs {
+ want := f0(input)
+ if got := f1(want); want != got {
+ t.Errorf("%s %s with %T %q: want\n\t%q,\ngot\n\t%q", n0, n1, input, input, want, got)
+ }
+ }
+ }
+ }
+}
+
+func TestIndirectPrint(t *testing.T) {
+ a := 3
+ ap := &a
+ b := "hello"
+ bp := &b
+ bpp := &bp
+ tmpl := Must(New("t").Parse(`{{.}}`))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, ap)
+ if err != nil {
+ t.Errorf("Unexpected error: %s", err)
+ } else if buf.String() != "3" {
+ t.Errorf(`Expected "3"; got %q`, buf.String())
+ }
+ buf.Reset()
+ err = tmpl.Execute(&buf, bpp)
+ if err != nil {
+ t.Errorf("Unexpected error: %s", err)
+ } else if buf.String() != "hello" {
+ t.Errorf(`Expected "hello"; got %q`, buf.String())
+ }
+}
+
+// This is a test for issue 3272.
+func TestEmptyTemplate(t *testing.T) {
+ page := Must(New("page").ParseFiles(os.DevNull))
+ if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil {
+ t.Fatal("expected error")
+ }
+}
+
+func BenchmarkEscapedExecute(b *testing.B) {
+ tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
+ var buf bytes.Buffer
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tmpl.Execute(&buf, "foo & 'bar' & baz")
+ buf.Reset()
+ }
+}
diff --git a/src/pkg/html/template/html.go b/src/pkg/html/template/html.go
new file mode 100644
index 000000000..36c88e23e
--- /dev/null
+++ b/src/pkg/html/template/html.go
@@ -0,0 +1,257 @@
+// 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"
+ "strings"
+ "unicode/utf8"
+)
+
+// htmlNospaceEscaper escapes for inclusion in unquoted attribute values.
+func htmlNospaceEscaper(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeHTML {
+ return htmlReplacer(stripTags(s), htmlNospaceNormReplacementTable, false)
+ }
+ return htmlReplacer(s, htmlNospaceReplacementTable, false)
+}
+
+// attrEscaper escapes for inclusion in quoted attribute values.
+func attrEscaper(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeHTML {
+ return htmlReplacer(stripTags(s), htmlNormReplacementTable, true)
+ }
+ return htmlReplacer(s, htmlReplacementTable, true)
+}
+
+// rcdataEscaper escapes for inclusion in an RCDATA element body.
+func rcdataEscaper(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeHTML {
+ return htmlReplacer(s, htmlNormReplacementTable, true)
+ }
+ return htmlReplacer(s, htmlReplacementTable, true)
+}
+
+// htmlEscaper escapes for inclusion in HTML text.
+func htmlEscaper(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeHTML {
+ return s
+ }
+ return htmlReplacer(s, htmlReplacementTable, true)
+}
+
+// htmlReplacementTable contains the runes that need to be escaped
+// inside a quoted attribute value or in a text node.
+var htmlReplacementTable = []string{
+ // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state: "
+ // U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT
+ // CHARACTER character to the current attribute's value.
+ // "
+ // and similarly
+ // http://www.w3.org/TR/html5/tokenization.html#before-attribute-value-state
+ 0: "\uFFFD",
+ '"': "&#34;",
+ '&': "&amp;",
+ '\'': "&#39;",
+ '+': "&#43;",
+ '<': "&lt;",
+ '>': "&gt;",
+}
+
+// htmlNormReplacementTable is like htmlReplacementTable but without '&' to
+// avoid over-encoding existing entities.
+var htmlNormReplacementTable = []string{
+ 0: "\uFFFD",
+ '"': "&#34;",
+ '\'': "&#39;",
+ '+': "&#43;",
+ '<': "&lt;",
+ '>': "&gt;",
+}
+
+// htmlNospaceReplacementTable contains the runes that need to be escaped
+// inside an unquoted attribute value.
+// The set of runes escaped is the union of the HTML specials and
+// those determined by running the JS below in browsers:
+// <div id=d></div>
+// <script>(function () {
+// var a = [], d = document.getElementById("d"), i, c, s;
+// for (i = 0; i < 0x10000; ++i) {
+// c = String.fromCharCode(i);
+// d.innerHTML = "<span title=" + c + "lt" + c + "></span>"
+// s = d.getElementsByTagName("SPAN")[0];
+// if (!s || s.title !== c + "lt" + c) { a.push(i.toString(16)); }
+// }
+// document.write(a.join(", "));
+// })()</script>
+var htmlNospaceReplacementTable = []string{
+ 0: "&#xfffd;",
+ '\t': "&#9;",
+ '\n': "&#10;",
+ '\v': "&#11;",
+ '\f': "&#12;",
+ '\r': "&#13;",
+ ' ': "&#32;",
+ '"': "&#34;",
+ '&': "&amp;",
+ '\'': "&#39;",
+ '+': "&#43;",
+ '<': "&lt;",
+ '=': "&#61;",
+ '>': "&gt;",
+ // A parse error in the attribute value (unquoted) and
+ // before attribute value states.
+ // Treated as a quoting character by IE.
+ '`': "&#96;",
+}
+
+// htmlNospaceNormReplacementTable is like htmlNospaceReplacementTable but
+// without '&' to avoid over-encoding existing entities.
+var htmlNospaceNormReplacementTable = []string{
+ 0: "&#xfffd;",
+ '\t': "&#9;",
+ '\n': "&#10;",
+ '\v': "&#11;",
+ '\f': "&#12;",
+ '\r': "&#13;",
+ ' ': "&#32;",
+ '"': "&#34;",
+ '\'': "&#39;",
+ '+': "&#43;",
+ '<': "&lt;",
+ '=': "&#61;",
+ '>': "&gt;",
+ // A parse error in the attribute value (unquoted) and
+ // before attribute value states.
+ // Treated as a quoting character by IE.
+ '`': "&#96;",
+}
+
+// htmlReplacer returns s with runes replaced according to replacementTable
+// and when badRunes is true, certain bad runes are allowed through unescaped.
+func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
+ written, b := 0, new(bytes.Buffer)
+ for i, r := range s {
+ if int(r) < len(replacementTable) {
+ if repl := replacementTable[r]; len(repl) != 0 {
+ b.WriteString(s[written:i])
+ b.WriteString(repl)
+ // Valid as long as replacementTable doesn't
+ // include anything above 0x7f.
+ written = i + utf8.RuneLen(r)
+ }
+ } else if badRunes {
+ // No-op.
+ // IE does not allow these ranges in unquoted attrs.
+ } else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff {
+ fmt.Fprintf(b, "%s&#x%x;", s[written:i], r)
+ written = i + utf8.RuneLen(r)
+ }
+ }
+ if written == 0 {
+ return s
+ }
+ b.WriteString(s[written:])
+ return b.String()
+}
+
+// stripTags takes a snippet of HTML and returns only the text content.
+// For example, `<b>&iexcl;Hi!</b> <script>...</script>` -> `&iexcl;Hi! `.
+func stripTags(html string) string {
+ var b bytes.Buffer
+ s, c, i, allText := []byte(html), context{}, 0, true
+ // Using the transition funcs helps us avoid mangling
+ // `<div title="1>2">` or `I <3 Ponies!`.
+ for i != len(s) {
+ if c.delim == delimNone {
+ st := c.state
+ // Use RCDATA instead of parsing into JS or CSS styles.
+ if c.element != elementNone && !isInTag(st) {
+ st = stateRCDATA
+ }
+ d, nread := transitionFunc[st](c, s[i:])
+ i1 := i + nread
+ if c.state == stateText || c.state == stateRCDATA {
+ // Emit text up to the start of the tag or comment.
+ j := i1
+ if d.state != c.state {
+ for j1 := j - 1; j1 >= i; j1-- {
+ if s[j1] == '<' {
+ j = j1
+ break
+ }
+ }
+ }
+ b.Write(s[i:j])
+ } else {
+ allText = false
+ }
+ c, i = d, i1
+ continue
+ }
+ i1 := i + bytes.IndexAny(s[i:], delimEnds[c.delim])
+ if i1 < i {
+ break
+ }
+ if c.delim != delimSpaceOrTagEnd {
+ // Consume any quote.
+ i1++
+ }
+ c, i = context{state: stateTag, element: c.element}, i1
+ }
+ if allText {
+ return html
+ } else if c.state == stateText || c.state == stateRCDATA {
+ b.Write(s[i:])
+ }
+ return b.String()
+}
+
+// htmlNameFilter accepts valid parts of an HTML attribute or tag name or
+// a known-safe HTML attribute.
+func htmlNameFilter(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeHTMLAttr {
+ return s
+ }
+ if len(s) == 0 {
+ // Avoid violation of structure preservation.
+ // <input checked {{.K}}={{.V}}>.
+ // Without this, if .K is empty then .V is the value of
+ // checked, but otherwise .V is the value of the attribute
+ // named .K.
+ return filterFailsafe
+ }
+ s = strings.ToLower(s)
+ if t := attrType(s); t != contentTypePlain {
+ // TODO: Split attr and element name part filters so we can whitelist
+ // attributes.
+ return filterFailsafe
+ }
+ for _, r := range s {
+ switch {
+ case '0' <= r && r <= '9':
+ case 'a' <= r && r <= 'z':
+ default:
+ return filterFailsafe
+ }
+ }
+ return s
+}
+
+// commentEscaper returns the empty string regardless of input.
+// Comment content does not correspond to any parsed structure or
+// human-readable content, so the simplest and most secure policy is to drop
+// content interpolated into comments.
+// This approach is equally valid whether or not static comment content is
+// removed from the template.
+func commentEscaper(args ...interface{}) string {
+ return ""
+}
diff --git a/src/pkg/html/template/html_test.go b/src/pkg/html/template/html_test.go
new file mode 100644
index 000000000..b9b970387
--- /dev/null
+++ b/src/pkg/html/template/html_test.go
@@ -0,0 +1,94 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "html"
+ "strings"
+ "testing"
+)
+
+func TestHTMLNospaceEscaper(t *testing.T) {
+ input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !"#$%&'()*+,-./` +
+ `0123456789:;<=>?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E")
+
+ want := ("&#xfffd;\x01\x02\x03\x04\x05\x06\x07" +
+ "\x08&#9;&#10;&#11;&#12;&#13;\x0E\x0F" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17" +
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ `&#32;!&#34;#$%&amp;&#39;()*&#43;,-./` +
+ `0123456789:;&lt;&#61;&gt;?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ `&#96;abcdefghijklmno` +
+ `pqrstuvwxyz{|}~` + "\u007f" +
+ "\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E")
+
+ got := htmlNospaceEscaper(input)
+ if got != want {
+ t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
+ }
+
+ got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1)
+ if want != got {
+ t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got)
+ }
+}
+
+func TestStripTags(t *testing.T) {
+ tests := []struct {
+ input, want string
+ }{
+ {"", ""},
+ {"Hello, World!", "Hello, World!"},
+ {"foo&amp;bar", "foo&amp;bar"},
+ {`Hello <a href="www.example.com/">World</a>!`, "Hello World!"},
+ {"Foo <textarea>Bar</textarea> Baz", "Foo Bar Baz"},
+ {"Foo <!-- Bar --> Baz", "Foo Baz"},
+ {"<", "<"},
+ {"foo < bar", "foo < bar"},
+ {`Foo<script type="text/javascript">alert(1337)</script>Bar`, "FooBar"},
+ {`Foo<div title="1>2">Bar`, "FooBar"},
+ {`I <3 Ponies!`, `I <3 Ponies!`},
+ {`<script>foo()</script>`, ``},
+ }
+
+ for _, test := range tests {
+ if got := stripTags(test.input); got != test.want {
+ t.Errorf("%q: want %q, got %q", test.input, test.want, got)
+ }
+ }
+}
+
+func BenchmarkHTMLNospaceEscaper(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ htmlNospaceEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
+
+func BenchmarkHTMLNospaceEscaperNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ htmlNospaceEscaper("The_quick,_brown_fox_jumps_over_the_lazy_dog.")
+ }
+}
+
+func BenchmarkStripTags(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ stripTags("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
+
+func BenchmarkStripTagsNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ stripTags("The quick, brown fox jumps over the lazy dog.")
+ }
+}
diff --git a/src/pkg/html/template/js.go b/src/pkg/html/template/js.go
new file mode 100644
index 000000000..a895a50aa
--- /dev/null
+++ b/src/pkg/html/template/js.go
@@ -0,0 +1,362 @@
+// 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"
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "strings"
+ "unicode/utf8"
+)
+
+// nextJSCtx returns the context that determines whether a slash after the
+// given run of tokens tokens starts a regular expression instead of a division
+// operator: / or /=.
+//
+// This assumes that the token run does not include any string tokens, comment
+// tokens, regular expression literal tokens, or division operators.
+//
+// This fails on some valid but nonsensical JavaScript programs like
+// "x = ++/foo/i" which is quite different than "x++/foo/i", but is not known to
+// fail on any known useful programs. It is based on the draft
+// JavaScript 2.0 lexical grammar and requires one token of lookbehind:
+// http://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html
+func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
+ s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029")
+ if len(s) == 0 {
+ return preceding
+ }
+
+ // All cases below are in the single-byte UTF-8 group.
+ switch c, n := s[len(s)-1], len(s); c {
+ case '+', '-':
+ // ++ and -- are not regexp preceders, but + and - are whether
+ // they are used as infix or prefix operators.
+ start := n - 1
+ // Count the number of adjacent dashes or pluses.
+ for start > 0 && s[start-1] == c {
+ start--
+ }
+ if (n-start)&1 == 1 {
+ // Reached for trailing minus signs since "---" is the
+ // same as "-- -".
+ return jsCtxRegexp
+ }
+ return jsCtxDivOp
+ case '.':
+ // Handle "42."
+ if n != 1 && '0' <= s[n-2] && s[n-2] <= '9' {
+ return jsCtxDivOp
+ }
+ return jsCtxRegexp
+ // Suffixes for all punctuators from section 7.7 of the language spec
+ // that only end binary operators not handled above.
+ case ',', '<', '>', '=', '*', '%', '&', '|', '^', '?':
+ return jsCtxRegexp
+ // Suffixes for all punctuators from section 7.7 of the language spec
+ // that are prefix operators not handled above.
+ case '!', '~':
+ return jsCtxRegexp
+ // Matches all the punctuators from section 7.7 of the language spec
+ // that are open brackets not handled above.
+ case '(', '[':
+ return jsCtxRegexp
+ // Matches all the punctuators from section 7.7 of the language spec
+ // that precede expression starts.
+ case ':', ';', '{':
+ return jsCtxRegexp
+ // CAVEAT: the close punctuators ('}', ']', ')') precede div ops and
+ // are handled in the default except for '}' which can precede a
+ // division op as in
+ // ({ valueOf: function () { return 42 } } / 2
+ // which is valid, but, in practice, developers don't divide object
+ // literals, so our heuristic works well for code like
+ // function () { ... } /foo/.test(x) && sideEffect();
+ // The ')' punctuator can precede a regular expression as in
+ // if (b) /foo/.test(x) && ...
+ // but this is much less likely than
+ // (a + b) / c
+ case '}':
+ return jsCtxRegexp
+ default:
+ // Look for an IdentifierName and see if it is a keyword that
+ // can precede a regular expression.
+ j := n
+ for j > 0 && isJSIdentPart(rune(s[j-1])) {
+ j--
+ }
+ if regexpPrecederKeywords[string(s[j:])] {
+ return jsCtxRegexp
+ }
+ }
+ // Otherwise is a punctuator not listed above, or
+ // a string which precedes a div op, or an identifier
+ // which precedes a div op.
+ return jsCtxDivOp
+}
+
+// regexPrecederKeywords is a set of reserved JS keywords that can precede a
+// regular expression in JS source.
+var regexpPrecederKeywords = map[string]bool{
+ "break": true,
+ "case": true,
+ "continue": true,
+ "delete": true,
+ "do": true,
+ "else": true,
+ "finally": true,
+ "in": true,
+ "instanceof": true,
+ "return": true,
+ "throw": true,
+ "try": true,
+ "typeof": true,
+ "void": true,
+}
+
+var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
+
+// indirectToJSONMarshaler returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil) or an implementation of json.Marshal.
+func indirectToJSONMarshaler(a interface{}) interface{} {
+ v := reflect.ValueOf(a)
+ for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
+// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
+// neither side-effects nor free variables outside (NaN, Infinity).
+func jsValEscaper(args ...interface{}) string {
+ var a interface{}
+ if len(args) == 1 {
+ a = indirectToJSONMarshaler(args[0])
+ switch t := a.(type) {
+ case JS:
+ return string(t)
+ case JSStr:
+ // TODO: normalize quotes.
+ return `"` + string(t) + `"`
+ case json.Marshaler:
+ // Do not treat as a Stringer.
+ case fmt.Stringer:
+ a = t.String()
+ }
+ } else {
+ for i, arg := range args {
+ args[i] = indirectToJSONMarshaler(arg)
+ }
+ a = fmt.Sprint(args...)
+ }
+ // TODO: detect cycles before calling Marshal which loops infinitely on
+ // cyclic data. This may be an unacceptable DoS risk.
+
+ b, err := json.Marshal(a)
+ if err != nil {
+ // Put a space before comment so that if it is flush against
+ // a division operator it is not turned into a line comment:
+ // x/{{y}}
+ // turning into
+ // x//* error marshalling y:
+ // second line of error message */null
+ return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1))
+ }
+
+ // TODO: maybe post-process output to prevent it from containing
+ // "<!--", "-->", "<![CDATA[", "]]>", or "</script"
+ // in case custom marshallers produce output containing those.
+
+ // TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
+ if len(b) == 0 {
+ // In, `x=y/{{.}}*z` a json.Marshaler that produces "" should
+ // not cause the output `x=y/*z`.
+ return " null "
+ }
+ first, _ := utf8.DecodeRune(b)
+ last, _ := utf8.DecodeLastRune(b)
+ var buf bytes.Buffer
+ // Prevent IdentifierNames and NumericLiterals from running into
+ // keywords: in, instanceof, typeof, void
+ pad := isJSIdentPart(first) || isJSIdentPart(last)
+ if pad {
+ buf.WriteByte(' ')
+ }
+ written := 0
+ // Make sure that json.Marshal escapes codepoints U+2028 & U+2029
+ // so it falls within the subset of JSON which is valid JS.
+ for i := 0; i < len(b); {
+ rune, n := utf8.DecodeRune(b[i:])
+ repl := ""
+ if rune == 0x2028 {
+ repl = `\u2028`
+ } else if rune == 0x2029 {
+ repl = `\u2029`
+ }
+ if repl != "" {
+ buf.Write(b[written:i])
+ buf.WriteString(repl)
+ written = i + n
+ }
+ i += n
+ }
+ if buf.Len() != 0 {
+ buf.Write(b[written:])
+ if pad {
+ buf.WriteByte(' ')
+ }
+ b = buf.Bytes()
+ }
+ return string(b)
+}
+
+// jsStrEscaper produces a string that can be included between quotes in
+// JavaScript source, in JavaScript embedded in an HTML5 <script> element,
+// or in an HTML5 event handler attribute such as onclick.
+func jsStrEscaper(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeJSStr {
+ return replace(s, jsStrNormReplacementTable)
+ }
+ return replace(s, jsStrReplacementTable)
+}
+
+// jsRegexpEscaper behaves like jsStrEscaper but escapes regular expression
+// specials so the result is treated literally when included in a regular
+// expression literal. /foo{{.X}}bar/ matches the string "foo" followed by
+// the literal text of {{.X}} followed by the string "bar".
+func jsRegexpEscaper(args ...interface{}) string {
+ s, _ := stringify(args...)
+ s = replace(s, jsRegexpReplacementTable)
+ if s == "" {
+ // /{{.X}}/ should not produce a line comment when .X == "".
+ return "(?:)"
+ }
+ return s
+}
+
+// replace replaces each rune r of s with replacementTable[r], provided that
+// r < len(replacementTable). If replacementTable[r] is the empty string then
+// no replacement is made.
+// It also replaces runes U+2028 and U+2029 with the raw strings `\u2028` and
+// `\u2029`.
+func replace(s string, replacementTable []string) string {
+ var b bytes.Buffer
+ written := 0
+ for i, r := range s {
+ var repl string
+ switch {
+ case int(r) < len(replacementTable) && replacementTable[r] != "":
+ repl = replacementTable[r]
+ case r == '\u2028':
+ repl = `\u2028`
+ case r == '\u2029':
+ repl = `\u2029`
+ default:
+ continue
+ }
+ b.WriteString(s[written:i])
+ b.WriteString(repl)
+ written = i + utf8.RuneLen(r)
+ }
+ if written == 0 {
+ return s
+ }
+ b.WriteString(s[written:])
+ return b.String()
+}
+
+var jsStrReplacementTable = []string{
+ 0: `\0`,
+ '\t': `\t`,
+ '\n': `\n`,
+ '\v': `\x0b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ '"': `\x22`,
+ '&': `\x26`,
+ '\'': `\x27`,
+ '+': `\x2b`,
+ '/': `\/`,
+ '<': `\x3c`,
+ '>': `\x3e`,
+ '\\': `\\`,
+}
+
+// jsStrNormReplacementTable is like jsStrReplacementTable but does not
+// overencode existing escapes since this table has no entry for `\`.
+var jsStrNormReplacementTable = []string{
+ 0: `\0`,
+ '\t': `\t`,
+ '\n': `\n`,
+ '\v': `\x0b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ '"': `\x22`,
+ '&': `\x26`,
+ '\'': `\x27`,
+ '+': `\x2b`,
+ '/': `\/`,
+ '<': `\x3c`,
+ '>': `\x3e`,
+}
+
+var jsRegexpReplacementTable = []string{
+ 0: `\0`,
+ '\t': `\t`,
+ '\n': `\n`,
+ '\v': `\x0b`, // "\v" == "v" on IE 6.
+ '\f': `\f`,
+ '\r': `\r`,
+ // Encode HTML specials as hex so the output can be embedded
+ // in HTML attributes without further encoding.
+ '"': `\x22`,
+ '$': `\$`,
+ '&': `\x26`,
+ '\'': `\x27`,
+ '(': `\(`,
+ ')': `\)`,
+ '*': `\*`,
+ '+': `\x2b`,
+ '-': `\-`,
+ '.': `\.`,
+ '/': `\/`,
+ '<': `\x3c`,
+ '>': `\x3e`,
+ '?': `\?`,
+ '[': `\[`,
+ '\\': `\\`,
+ ']': `\]`,
+ '^': `\^`,
+ '{': `\{`,
+ '|': `\|`,
+ '}': `\}`,
+}
+
+// isJSIdentPart returns whether the given rune is a JS identifier part.
+// It does not handle all the non-Latin letters, joiners, and combining marks,
+// but it does handle every codepoint that can occur in a numeric literal or
+// a keyword.
+func isJSIdentPart(r rune) bool {
+ switch {
+ case r == '$':
+ return true
+ case '0' <= r && r <= '9':
+ return true
+ case 'A' <= r && r <= 'Z':
+ return true
+ case r == '_':
+ return true
+ case 'a' <= r && r <= 'z':
+ return true
+ }
+ return false
+}
diff --git a/src/pkg/html/template/js_test.go b/src/pkg/html/template/js_test.go
new file mode 100644
index 000000000..311e1d2c4
--- /dev/null
+++ b/src/pkg/html/template/js_test.go
@@ -0,0 +1,401 @@
+// 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"
+ "math"
+ "strings"
+ "testing"
+)
+
+func TestNextJsCtx(t *testing.T) {
+ tests := []struct {
+ jsCtx jsCtx
+ s string
+ }{
+ // Statement terminators precede regexps.
+ {jsCtxRegexp, ";"},
+ // This is not airtight.
+ // ({ valueOf: function () { return 1 } } / 2)
+ // is valid JavaScript but in practice, devs do not do this.
+ // A block followed by a statement starting with a RegExp is
+ // much more common:
+ // while (x) {...} /foo/.test(x) || panic()
+ {jsCtxRegexp, "}"},
+ // But member, call, grouping, and array expression terminators
+ // precede div ops.
+ {jsCtxDivOp, ")"},
+ {jsCtxDivOp, "]"},
+ // At the start of a primary expression, array, or expression
+ // statement, expect a regexp.
+ {jsCtxRegexp, "("},
+ {jsCtxRegexp, "["},
+ {jsCtxRegexp, "{"},
+ // Assignment operators precede regexps as do all exclusively
+ // prefix and binary operators.
+ {jsCtxRegexp, "="},
+ {jsCtxRegexp, "+="},
+ {jsCtxRegexp, "*="},
+ {jsCtxRegexp, "*"},
+ {jsCtxRegexp, "!"},
+ // Whether the + or - is infix or prefix, it cannot precede a
+ // div op.
+ {jsCtxRegexp, "+"},
+ {jsCtxRegexp, "-"},
+ // An incr/decr op precedes a div operator.
+ // This is not airtight. In (g = ++/h/i) a regexp follows a
+ // pre-increment operator, but in practice devs do not try to
+ // increment or decrement regular expressions.
+ // (g++/h/i) where ++ is a postfix operator on g is much more
+ // common.
+ {jsCtxDivOp, "--"},
+ {jsCtxDivOp, "++"},
+ {jsCtxDivOp, "x--"},
+ // When we have many dashes or pluses, then they are grouped
+ // left to right.
+ {jsCtxRegexp, "x---"}, // A postfix -- then a -.
+ // return followed by a slash returns the regexp literal or the
+ // slash starts a regexp literal in an expression statement that
+ // is dead code.
+ {jsCtxRegexp, "return"},
+ {jsCtxRegexp, "return "},
+ {jsCtxRegexp, "return\t"},
+ {jsCtxRegexp, "return\n"},
+ {jsCtxRegexp, "return\u2028"},
+ // Identifiers can be divided and cannot validly be preceded by
+ // a regular expressions. Semicolon insertion cannot happen
+ // between an identifier and a regular expression on a new line
+ // because the one token lookahead for semicolon insertion has
+ // to conclude that it could be a div binary op and treat it as
+ // such.
+ {jsCtxDivOp, "x"},
+ {jsCtxDivOp, "x "},
+ {jsCtxDivOp, "x\t"},
+ {jsCtxDivOp, "x\n"},
+ {jsCtxDivOp, "x\u2028"},
+ {jsCtxDivOp, "preturn"},
+ // Numbers precede div ops.
+ {jsCtxDivOp, "0"},
+ // Dots that are part of a number are div preceders.
+ {jsCtxDivOp, "0."},
+ }
+
+ for _, test := range tests {
+ if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx {
+ t.Errorf("want %s got %q", test.jsCtx, test.s)
+ }
+ if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx {
+ t.Errorf("want %s got %q", test.jsCtx, test.s)
+ }
+ }
+
+ if nextJSCtx([]byte(" "), jsCtxRegexp) != jsCtxRegexp {
+ t.Error("Blank tokens")
+ }
+
+ if nextJSCtx([]byte(" "), jsCtxDivOp) != jsCtxDivOp {
+ t.Error("Blank tokens")
+ }
+}
+
+func TestJSValEscaper(t *testing.T) {
+ tests := []struct {
+ x interface{}
+ js string
+ }{
+ {int(42), " 42 "},
+ {uint(42), " 42 "},
+ {int16(42), " 42 "},
+ {uint16(42), " 42 "},
+ {int32(-42), " -42 "},
+ {uint32(42), " 42 "},
+ {int16(-42), " -42 "},
+ {uint16(42), " 42 "},
+ {int64(-42), " -42 "},
+ {uint64(42), " 42 "},
+ {uint64(1) << 53, " 9007199254740992 "},
+ // ulp(1 << 53) > 1 so this loses precision in JS
+ // but it is still a representable integer literal.
+ {uint64(1)<<53 + 1, " 9007199254740993 "},
+ {float32(1.0), " 1 "},
+ {float32(-1.0), " -1 "},
+ {float32(0.5), " 0.5 "},
+ {float32(-0.5), " -0.5 "},
+ {float32(1.0) / float32(256), " 0.00390625 "},
+ {float32(0), " 0 "},
+ {math.Copysign(0, -1), " -0 "},
+ {float64(1.0), " 1 "},
+ {float64(-1.0), " -1 "},
+ {float64(0.5), " 0.5 "},
+ {float64(-0.5), " -0.5 "},
+ {float64(0), " 0 "},
+ {math.Copysign(0, -1), " -0 "},
+ {"", `""`},
+ {"foo", `"foo"`},
+ // Newlines.
+ {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
+ // "\v" == "v" on IE 6 so use "\x0b" instead.
+ {"\t\x0b", `"\u0009\u000b"`},
+ {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
+ {[]interface{}{}, "[]"},
+ {[]interface{}{42, "foo", nil}, `[42,"foo",null]`},
+ {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
+ {"<!--", `"\u003c!--"`},
+ {"-->", `"--\u003e"`},
+ {"<![CDATA[", `"\u003c![CDATA["`},
+ {"]]>", `"]]\u003e"`},
+ {"</script", `"\u003c/script"`},
+ {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
+ }
+
+ for _, test := range tests {
+ if js := jsValEscaper(test.x); js != test.js {
+ t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
+ }
+ // Make sure that escaping corner cases are not broken
+ // by nesting.
+ a := []interface{}{test.x}
+ want := "[" + strings.TrimSpace(test.js) + "]"
+ if js := jsValEscaper(a); js != want {
+ t.Errorf("%+v: want\n\t%q\ngot\n\t%q", a, want, js)
+ }
+ }
+}
+
+func TestJSStrEscaper(t *testing.T) {
+ tests := []struct {
+ x interface{}
+ esc string
+ }{
+ {"", ``},
+ {"foo", `foo`},
+ {"\u0000", `\0`},
+ {"\t", `\t`},
+ {"\n", `\n`},
+ {"\r", `\r`},
+ {"\u2028", `\u2028`},
+ {"\u2029", `\u2029`},
+ {"\\", `\\`},
+ {"\\n", `\\n`},
+ {"foo\r\nbar", `foo\r\nbar`},
+ // Preserve attribute boundaries.
+ {`"`, `\x22`},
+ {`'`, `\x27`},
+ // Allow embedding in HTML without further escaping.
+ {`&amp;`, `\x26amp;`},
+ // Prevent breaking out of text node and element boundaries.
+ {"</script>", `\x3c\/script\x3e`},
+ {"<![CDATA[", `\x3c![CDATA[`},
+ {"]]>", `]]\x3e`},
+ // http://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span
+ // "The text in style, script, title, and textarea elements
+ // must not have an escaping text span start that is not
+ // followed by an escaping text span end."
+ // Furthermore, spoofing an escaping text span end could lead
+ // to different interpretation of a </script> sequence otherwise
+ // masked by the escaping text span, and spoofing a start could
+ // allow regular text content to be interpreted as script
+ // allowing script execution via a combination of a JS string
+ // injection followed by an HTML text injection.
+ {"<!--", `\x3c!--`},
+ {"-->", `--\x3e`},
+ // From http://code.google.com/p/doctype/wiki/ArticleUtf7
+ {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
+ `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`,
+ },
+ // Invalid UTF-8 sequence
+ {"foo\xA0bar", "foo\xA0bar"},
+ // Invalid unicode scalar value.
+ {"foo\xed\xa0\x80bar", "foo\xed\xa0\x80bar"},
+ }
+
+ for _, test := range tests {
+ esc := jsStrEscaper(test.x)
+ if esc != test.esc {
+ t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
+ }
+ }
+}
+
+func TestJSRegexpEscaper(t *testing.T) {
+ tests := []struct {
+ x interface{}
+ esc string
+ }{
+ {"", `(?:)`},
+ {"foo", `foo`},
+ {"\u0000", `\0`},
+ {"\t", `\t`},
+ {"\n", `\n`},
+ {"\r", `\r`},
+ {"\u2028", `\u2028`},
+ {"\u2029", `\u2029`},
+ {"\\", `\\`},
+ {"\\n", `\\n`},
+ {"foo\r\nbar", `foo\r\nbar`},
+ // Preserve attribute boundaries.
+ {`"`, `\x22`},
+ {`'`, `\x27`},
+ // Allow embedding in HTML without further escaping.
+ {`&amp;`, `\x26amp;`},
+ // Prevent breaking out of text node and element boundaries.
+ {"</script>", `\x3c\/script\x3e`},
+ {"<![CDATA[", `\x3c!\[CDATA\[`},
+ {"]]>", `\]\]\x3e`},
+ // Escaping text spans.
+ {"<!--", `\x3c!\-\-`},
+ {"-->", `\-\-\x3e`},
+ {"*", `\*`},
+ {"+", `\x2b`},
+ {"?", `\?`},
+ {"[](){}", `\[\]\(\)\{\}`},
+ {"$foo|x.y", `\$foo\|x\.y`},
+ {"x^y", `x\^y`},
+ }
+
+ for _, test := range tests {
+ esc := jsRegexpEscaper(test.x)
+ if esc != test.esc {
+ t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
+ }
+ }
+}
+
+func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
+ input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !"#$%&'()*+,-./` +
+ `0123456789:;<=>?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+
+ tests := []struct {
+ name string
+ escaper func(...interface{}) string
+ escaped string
+ }{
+ {
+ "jsStrEscaper",
+ jsStrEscaper,
+ "\\0\x01\x02\x03\x04\x05\x06\x07" +
+ "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17" +
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !\x22#$%\x26\x27()*\x2b,-.\/` +
+ `0123456789:;\x3c=\x3e?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
+ },
+ {
+ "jsRegexpEscaper",
+ jsRegexpEscaper,
+ "\\0\x01\x02\x03\x04\x05\x06\x07" +
+ "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17" +
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` +
+ `0123456789:;\x3c=\x3e\?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ\[\\\]\^_` +
+ "`abcdefghijklmno" +
+ `pqrstuvwxyz\{\|\}~` + "\u007f" +
+ "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
+ },
+ }
+
+ for _, test := range tests {
+ if s := test.escaper(input); s != test.escaped {
+ t.Errorf("%s once: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
+ continue
+ }
+
+ // Escape it rune by rune to make sure that any
+ // fast-path checking does not break escaping.
+ var buf bytes.Buffer
+ for _, c := range input {
+ buf.WriteString(test.escaper(string(c)))
+ }
+
+ if s := buf.String(); s != test.escaped {
+ t.Errorf("%s rune-wise: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
+ continue
+ }
+ }
+}
+
+func BenchmarkJSValEscaperWithNum(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsValEscaper(3.141592654)
+ }
+}
+
+func BenchmarkJSValEscaperWithStr(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsValEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
+
+func BenchmarkJSValEscaperWithStrNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsValEscaper("The quick, brown fox jumps over the lazy dog")
+ }
+}
+
+func BenchmarkJSValEscaperWithObj(b *testing.B) {
+ o := struct {
+ S string
+ N int
+ }{
+ "The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>\u2028",
+ 42,
+ }
+ for i := 0; i < b.N; i++ {
+ jsValEscaper(o)
+ }
+}
+
+func BenchmarkJSValEscaperWithObjNoSpecials(b *testing.B) {
+ o := struct {
+ S string
+ N int
+ }{
+ "The quick, brown fox jumps over the lazy dog",
+ 42,
+ }
+ for i := 0; i < b.N; i++ {
+ jsValEscaper(o)
+ }
+}
+
+func BenchmarkJSStrEscaperNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsStrEscaper("The quick, brown fox jumps over the lazy dog.")
+ }
+}
+
+func BenchmarkJSStrEscaper(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsStrEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
+
+func BenchmarkJSRegexpEscaperNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsRegexpEscaper("The quick, brown fox jumps over the lazy dog")
+ }
+}
+
+func BenchmarkJSRegexpEscaper(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ jsRegexpEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
+ }
+}
diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
new file mode 100644
index 000000000..edac7335c
--- /dev/null
+++ b/src/pkg/html/template/template.go
@@ -0,0 +1,359 @@
+// 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"
+ "io/ioutil"
+ "path/filepath"
+ "sync"
+ "text/template"
+ "text/template/parse"
+)
+
+// Template is a specialized template.Template that produces a safe HTML
+// document fragment.
+type Template struct {
+ escaped bool
+ // We could embed the text/template field, but it's safer not to because
+ // we need to keep our version of the name space and the underlying
+ // template's in sync.
+ text *template.Template
+ *nameSpace // common to all associated templates
+}
+
+// nameSpace is the data structure shared by all templates in an association.
+type nameSpace struct {
+ mu sync.Mutex
+ set map[string]*Template
+}
+
+// Templates returns a slice of the templates associated with t, including t
+// itself.
+func (t *Template) Templates() []*Template {
+ ns := t.nameSpace
+ ns.mu.Lock()
+ defer ns.mu.Unlock()
+ // Return a slice so we don't expose the map.
+ m := make([]*Template, 0, len(ns.set))
+ for _, v := range ns.set {
+ m = append(m, v)
+ }
+ return m
+}
+
+// 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 error) {
+ t.nameSpace.mu.Lock()
+ if !t.escaped {
+ if err = escapeTemplates(t, t.Name()); err != nil {
+ t.escaped = true
+ }
+ }
+ t.nameSpace.mu.Unlock()
+ if err != nil {
+ return
+ }
+ return t.text.Execute(wr, data)
+}
+
+// ExecuteTemplate applies the template associated with t that has the given
+// name to the specified data object and writes the output to wr.
+func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
+ tmpl, err := t.lookupAndEscapeTemplate(name)
+ if err != nil {
+ return err
+ }
+ return tmpl.text.Execute(wr, data)
+}
+
+// lookupAndEscapeTemplate guarantees that the template with the given name
+// is escaped, or returns an error if it cannot be. It returns the named
+// template.
+func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ tmpl = t.set[name]
+ if tmpl == nil {
+ return nil, fmt.Errorf("html/template: %q is undefined", name)
+ }
+ if tmpl.text.Tree == nil || tmpl.text.Root == nil {
+ return nil, fmt.Errorf("html/template: %q is an incomplete template", name)
+ }
+ if t.text.Lookup(name) == nil {
+ panic("html/template internal error: template escaping out of sync")
+ }
+ if tmpl != nil && !tmpl.escaped {
+ err = escapeTemplates(tmpl, name)
+ }
+ return tmpl, err
+}
+
+// Parse parses a string into a template. Nested template definitions
+// will be associated with the top-level template t. Parse may be
+// called multiple times to parse definitions of templates to associate
+// with t. It is an error if a resulting template is non-empty (contains
+// content other than template definitions) and would replace a
+// non-empty template with the same name. (In multiple calls to Parse
+// with the same receiver template, only one call can contain text
+// other than space, comments, and template definitions.)
+func (t *Template) Parse(src string) (*Template, error) {
+ t.nameSpace.mu.Lock()
+ t.escaped = false
+ t.nameSpace.mu.Unlock()
+ ret, err := t.text.Parse(src)
+ if err != nil {
+ return nil, err
+ }
+ // In general, all the named templates might have changed underfoot.
+ // Regardless, some new ones may have been defined.
+ // The template.Template set has been updated; update ours.
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ for _, v := range ret.Templates() {
+ name := v.Name()
+ tmpl := t.set[name]
+ if tmpl == nil {
+ tmpl = t.new(name)
+ }
+ tmpl.escaped = false
+ tmpl.text = v
+ }
+ return t, nil
+}
+
+// AddParseTree creates a new template with the name and parse tree
+// and associates it with t.
+//
+// It returns an error if t has already been executed.
+func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.escaped {
+ return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name())
+ }
+ text, err := t.text.AddParseTree(name, tree)
+ if err != nil {
+ return nil, err
+ }
+ ret := &Template{
+ false,
+ text,
+ t.nameSpace,
+ }
+ t.set[name] = ret
+ return ret, nil
+}
+
+// Clone returns a duplicate of the template, including all associated
+// templates. The actual representation is not copied, but the name space of
+// associated templates is, so further calls to Parse in the copy will add
+// templates to the copy but not to the original. Clone can be used to prepare
+// common templates and use them with variant definitions for other templates
+// by adding the variants after the clone is made.
+//
+// It returns an error if t has already been executed.
+func (t *Template) Clone() (*Template, error) {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.escaped {
+ return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
+ }
+ textClone, err := t.text.Clone()
+ if err != nil {
+ return nil, err
+ }
+ ret := &Template{
+ false,
+ textClone,
+ &nameSpace{
+ set: make(map[string]*Template),
+ },
+ }
+ for _, x := range textClone.Templates() {
+ name := x.Name()
+ src := t.set[name]
+ if src == nil || src.escaped {
+ return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
+ }
+ if x.Tree != nil {
+ x.Tree = &parse.Tree{
+ Name: x.Tree.Name,
+ Root: x.Tree.Root.CopyList(),
+ }
+ }
+ ret.set[name] = &Template{
+ false,
+ x,
+ ret.nameSpace,
+ }
+ }
+ return ret, nil
+}
+
+// New allocates a new HTML template with the given name.
+func New(name string) *Template {
+ tmpl := &Template{
+ false,
+ template.New(name),
+ &nameSpace{
+ set: make(map[string]*Template),
+ },
+ }
+ tmpl.set[name] = tmpl
+ return tmpl
+}
+
+// New allocates a new HTML template associated with the given one
+// and with the same delimiters. The association, which is transitive,
+// allows one template to invoke another with a {{template}} action.
+func (t *Template) New(name string) *Template {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ return t.new(name)
+}
+
+// new is the implementation of New, without the lock.
+func (t *Template) new(name string) *Template {
+ tmpl := &Template{
+ false,
+ t.text.New(name),
+ t.nameSpace,
+ }
+ tmpl.set[name] = tmpl
+ return tmpl
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+ return t.text.Name()
+}
+
+// FuncMap is the type of the map defining the mapping from names to
+// functions. Each function must have either a single return value, or two
+// return values of which the second has type error. In that case, if the
+// second (error) argument evaluates to non-nil during execution, execution
+// terminates and Execute returns that error. FuncMap has the same base type
+// as template.FuncMap, copied here so clients need not import "text/template".
+type FuncMap map[string]interface{}
+
+// Funcs adds the elements of the argument map to the template's function map.
+// It panics if a value in the map is not a function with appropriate return
+// type. However, it is legal to overwrite elements of the map. The return
+// value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+ t.text.Funcs(template.FuncMap(funcMap))
+ return t
+}
+
+// Delims sets the action delimiters to the specified strings, to be used in
+// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
+// definitions will inherit the settings. An empty delimiter stands for the
+// corresponding default: {{ or }}.
+// The return value is the template, so calls can be chained.
+func (t *Template) Delims(left, right string) *Template {
+ t.text.Delims(left, right)
+ return t
+}
+
+// Lookup returns the template with the given name that is associated with t,
+// or nil if there is no such template.
+func (t *Template) Lookup(name string) *Template {
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ return t.set[name]
+}
+
+// Must panics if err is non-nil in the same way as template.Must.
+func Must(t *Template, err error) *Template {
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// ParseFiles creates a new Template and parses the template definitions from
+// the named files. The returned template's name will have the (base) name and
+// (parsed) contents of the first file. There must be at least one file.
+// If an error occurs, parsing stops and the returned *Template is nil.
+func ParseFiles(filenames ...string) (*Template, error) {
+ return parseFiles(nil, filenames...)
+}
+
+// ParseFiles parses the named files and associates the resulting templates with
+// t. If an error occurs, parsing stops and the returned template is nil;
+// otherwise it is t. There must be at least one file.
+func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
+ return parseFiles(t, filenames...)
+}
+
+// parseFiles is the helper for the method and function. If the argument
+// template is nil, it is created from the first file.
+func parseFiles(t *Template, filenames ...string) (*Template, error) {
+ if len(filenames) == 0 {
+ // Not really a problem, but be consistent.
+ return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
+ }
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ s := string(b)
+ name := filepath.Base(filename)
+ // First template becomes return value if not already defined,
+ // and we use that one for subsequent New calls to associate
+ // all the templates together. Also, if this file has the same name
+ // as t, this file becomes the contents of t, so
+ // t, err := New(name).Funcs(xxx).ParseFiles(name)
+ // works. Otherwise we create a new template associated with t.
+ var tmpl *Template
+ if t == nil {
+ t = New(name)
+ }
+ if name == t.Name() {
+ tmpl = t
+ } else {
+ tmpl = t.New(name)
+ }
+ _, err = tmpl.Parse(s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return t, nil
+}
+
+// ParseGlob creates a new Template and parses the template definitions from the
+// files identified by the pattern, which must match at least one file. The
+// returned template will have the (base) name and (parsed) contents of the
+// first file matched by the pattern. ParseGlob is equivalent to calling
+// ParseFiles with the list of files matched by the pattern.
+func ParseGlob(pattern string) (*Template, error) {
+ return parseGlob(nil, pattern)
+}
+
+// ParseGlob parses the template definitions in the files identified by the
+// pattern and associates the resulting templates with t. The pattern is
+// processed by filepath.Glob and must match at least one file. ParseGlob is
+// equivalent to calling t.ParseFiles with the list of files matched by the
+// pattern.
+func (t *Template) ParseGlob(pattern string) (*Template, error) {
+ return parseGlob(t, pattern)
+}
+
+// parseGlob is the implementation of the function and method ParseGlob.
+func parseGlob(t *Template, pattern string) (*Template, error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ if len(filenames) == 0 {
+ return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern)
+ }
+ return parseFiles(t, filenames...)
+}
diff --git a/src/pkg/html/template/transition.go b/src/pkg/html/template/transition.go
new file mode 100644
index 000000000..96a4f6678
--- /dev/null
+++ b/src/pkg/html/template/transition.go
@@ -0,0 +1,553 @@
+// 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"
+ "strings"
+)
+
+// transitionFunc is the array of context transition functions for text nodes.
+// A transition function takes a context and template text input, and returns
+// the updated context and the number of bytes consumed from the front of the
+// input.
+var transitionFunc = [...]func(context, []byte) (context, int){
+ stateText: tText,
+ stateTag: tTag,
+ stateAttrName: tAttrName,
+ stateAfterName: tAfterName,
+ stateBeforeValue: tBeforeValue,
+ stateHTMLCmt: tHTMLCmt,
+ stateRCDATA: tSpecialTagEnd,
+ stateAttr: tAttr,
+ stateURL: tURL,
+ stateJS: tJS,
+ stateJSDqStr: tJSDelimited,
+ stateJSSqStr: tJSDelimited,
+ stateJSRegexp: tJSDelimited,
+ stateJSBlockCmt: tBlockCmt,
+ stateJSLineCmt: tLineCmt,
+ stateCSS: tCSS,
+ stateCSSDqStr: tCSSStr,
+ stateCSSSqStr: tCSSStr,
+ stateCSSDqURL: tCSSStr,
+ stateCSSSqURL: tCSSStr,
+ stateCSSURL: tCSSStr,
+ stateCSSBlockCmt: tBlockCmt,
+ stateCSSLineCmt: tLineCmt,
+ stateError: tError,
+}
+
+var commentStart = []byte("<!--")
+var commentEnd = []byte("-->")
+
+// tText is the context transition function for the text state.
+func tText(c context, s []byte) (context, int) {
+ k := 0
+ for {
+ i := k + bytes.IndexByte(s[k:], '<')
+ if i < k || i+1 == len(s) {
+ return c, len(s)
+ } else if i+4 <= len(s) && bytes.Equal(commentStart, s[i:i+4]) {
+ return context{state: stateHTMLCmt}, i + 4
+ }
+ i++
+ end := false
+ if s[i] == '/' {
+ if i+1 == len(s) {
+ return c, len(s)
+ }
+ end, i = true, i+1
+ }
+ j, e := eatTagName(s, i)
+ if j != i {
+ if end {
+ e = elementNone
+ }
+ // We've found an HTML tag.
+ return context{state: stateTag, element: e}, j
+ }
+ k = j
+ }
+ panic("unreachable")
+}
+
+var elementContentType = [...]state{
+ elementNone: stateText,
+ elementScript: stateJS,
+ elementStyle: stateCSS,
+ elementTextarea: stateRCDATA,
+ elementTitle: stateRCDATA,
+}
+
+// tTag is the context transition function for the tag state.
+func tTag(c context, s []byte) (context, int) {
+ // Find the attribute name.
+ i := eatWhiteSpace(s, 0)
+ if i == len(s) {
+ return c, len(s)
+ }
+ if s[i] == '>' {
+ return context{
+ state: elementContentType[c.element],
+ element: c.element,
+ }, i + 1
+ }
+ j, err := eatAttrName(s, i)
+ if err != nil {
+ return context{state: stateError, err: err}, len(s)
+ }
+ state, attr := stateTag, attrNone
+ if i == j {
+ return context{
+ state: stateError,
+ err: errorf(ErrBadHTML, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
+ }, len(s)
+ }
+ switch attrType(string(s[i:j])) {
+ case contentTypeURL:
+ attr = attrURL
+ case contentTypeCSS:
+ attr = attrStyle
+ case contentTypeJS:
+ attr = attrScript
+ }
+ if j == len(s) {
+ state = stateAttrName
+ } else {
+ state = stateAfterName
+ }
+ return context{state: state, element: c.element, attr: attr}, j
+}
+
+// tAttrName is the context transition function for stateAttrName.
+func tAttrName(c context, s []byte) (context, int) {
+ i, err := eatAttrName(s, 0)
+ if err != nil {
+ return context{state: stateError, err: err}, len(s)
+ } else if i != len(s) {
+ c.state = stateAfterName
+ }
+ return c, i
+}
+
+// tAfterName is the context transition function for stateAfterName.
+func tAfterName(c context, s []byte) (context, int) {
+ // Look for the start of the value.
+ i := eatWhiteSpace(s, 0)
+ if i == len(s) {
+ return c, len(s)
+ } else if s[i] != '=' {
+ // Occurs due to tag ending '>', and valueless attribute.
+ c.state = stateTag
+ return c, i
+ }
+ c.state = stateBeforeValue
+ // Consume the "=".
+ return c, i + 1
+}
+
+var attrStartStates = [...]state{
+ attrNone: stateAttr,
+ attrScript: stateJS,
+ attrStyle: stateCSS,
+ attrURL: stateURL,
+}
+
+// tBeforeValue is the context transition function for stateBeforeValue.
+func tBeforeValue(c context, s []byte) (context, int) {
+ i := eatWhiteSpace(s, 0)
+ if i == len(s) {
+ return c, len(s)
+ }
+ // Find the attribute delimiter.
+ delim := delimSpaceOrTagEnd
+ switch s[i] {
+ case '\'':
+ delim, i = delimSingleQuote, i+1
+ case '"':
+ delim, i = delimDoubleQuote, i+1
+ }
+ c.state, c.delim, c.attr = attrStartStates[c.attr], delim, attrNone
+ return c, i
+}
+
+// tHTMLCmt is the context transition function for stateHTMLCmt.
+func tHTMLCmt(c context, s []byte) (context, int) {
+ if i := bytes.Index(s, commentEnd); i != -1 {
+ return context{}, i + 3
+ }
+ return c, len(s)
+}
+
+// specialTagEndMarkers maps element types to the character sequence that
+// case-insensitively signals the end of the special tag body.
+var specialTagEndMarkers = [...]string{
+ elementScript: "</script",
+ elementStyle: "</style",
+ elementTextarea: "</textarea",
+ elementTitle: "</title",
+}
+
+// tSpecialTagEnd is the context transition function for raw text and RCDATA
+// element states.
+func tSpecialTagEnd(c context, s []byte) (context, int) {
+ if c.element != elementNone {
+ if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 {
+ return context{}, i
+ }
+ }
+ return c, len(s)
+}
+
+// tAttr is the context transition function for the attribute state.
+func tAttr(c context, s []byte) (context, int) {
+ return c, len(s)
+}
+
+// tURL is the context transition function for the URL state.
+func tURL(c context, s []byte) (context, int) {
+ if bytes.IndexAny(s, "#?") >= 0 {
+ c.urlPart = urlPartQueryOrFrag
+ } else if len(s) != eatWhiteSpace(s, 0) && c.urlPart == urlPartNone {
+ // HTML5 uses "Valid URL potentially surrounded by spaces" for
+ // attrs: http://www.w3.org/TR/html5/index.html#attributes-1
+ c.urlPart = urlPartPreQuery
+ }
+ return c, len(s)
+}
+
+// tJS is the context transition function for the JS state.
+func tJS(c context, s []byte) (context, int) {
+ i := bytes.IndexAny(s, `"'/`)
+ if i == -1 {
+ // Entire input is non string, comment, regexp tokens.
+ c.jsCtx = nextJSCtx(s, c.jsCtx)
+ return c, len(s)
+ }
+ c.jsCtx = nextJSCtx(s[:i], c.jsCtx)
+ switch s[i] {
+ case '"':
+ c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp
+ case '\'':
+ c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp
+ case '/':
+ switch {
+ case i+1 < len(s) && s[i+1] == '/':
+ c.state, i = stateJSLineCmt, i+1
+ case i+1 < len(s) && s[i+1] == '*':
+ c.state, i = stateJSBlockCmt, i+1
+ case c.jsCtx == jsCtxRegexp:
+ c.state = stateJSRegexp
+ case c.jsCtx == jsCtxDivOp:
+ c.jsCtx = jsCtxRegexp
+ default:
+ return context{
+ state: stateError,
+ err: errorf(ErrSlashAmbig, 0, "'/' could start a division or regexp: %.32q", s[i:]),
+ }, len(s)
+ }
+ default:
+ panic("unreachable")
+ }
+ return c, i + 1
+}
+
+// tJSDelimited is the context transition function for the JS string and regexp
+// states.
+func tJSDelimited(c context, s []byte) (context, int) {
+ specials := `\"`
+ switch c.state {
+ case stateJSSqStr:
+ specials = `\'`
+ case stateJSRegexp:
+ specials = `\/[]`
+ }
+
+ k, inCharset := 0, false
+ for {
+ i := k + bytes.IndexAny(s[k:], specials)
+ if i < k {
+ break
+ }
+ switch s[i] {
+ case '\\':
+ i++
+ if i == len(s) {
+ return context{
+ state: stateError,
+ err: errorf(ErrPartialEscape, 0, "unfinished escape sequence in JS string: %q", s),
+ }, len(s)
+ }
+ case '[':
+ inCharset = true
+ case ']':
+ inCharset = false
+ default:
+ // end delimiter
+ if !inCharset {
+ c.state, c.jsCtx = stateJS, jsCtxDivOp
+ return c, i + 1
+ }
+ }
+ k = i + 1
+ }
+
+ if inCharset {
+ // This can be fixed by making context richer if interpolation
+ // into charsets is desired.
+ return context{
+ state: stateError,
+ err: errorf(ErrPartialCharset, 0, "unfinished JS regexp charset: %q", s),
+ }, len(s)
+ }
+
+ return c, len(s)
+}
+
+var blockCommentEnd = []byte("*/")
+
+// tBlockCmt is the context transition function for /*comment*/ states.
+func tBlockCmt(c context, s []byte) (context, int) {
+ i := bytes.Index(s, blockCommentEnd)
+ if i == -1 {
+ return c, len(s)
+ }
+ switch c.state {
+ case stateJSBlockCmt:
+ c.state = stateJS
+ case stateCSSBlockCmt:
+ c.state = stateCSS
+ default:
+ panic(c.state.String())
+ }
+ return c, i + 2
+}
+
+// tLineCmt is the context transition function for //comment states.
+func tLineCmt(c context, s []byte) (context, int) {
+ var lineTerminators string
+ var endState state
+ switch c.state {
+ case stateJSLineCmt:
+ lineTerminators, endState = "\n\r\u2028\u2029", stateJS
+ case stateCSSLineCmt:
+ lineTerminators, endState = "\n\f\r", stateCSS
+ // Line comments are not part of any published CSS standard but
+ // are supported by the 4 major browsers.
+ // This defines line comments as
+ // LINECOMMENT ::= "//" [^\n\f\d]*
+ // since http://www.w3.org/TR/css3-syntax/#SUBTOK-nl defines
+ // newlines:
+ // nl ::= #xA | #xD #xA | #xD | #xC
+ default:
+ panic(c.state.String())
+ }
+
+ i := bytes.IndexAny(s, lineTerminators)
+ if i == -1 {
+ return c, len(s)
+ }
+ c.state = endState
+ // Per section 7.4 of EcmaScript 5 : http://es5.github.com/#x7.4
+ // "However, the LineTerminator at the end of the line is not
+ // considered to be part of the single-line comment; it is
+ // recognized separately by the lexical grammar and becomes part
+ // of the stream of input elements for the syntactic grammar."
+ return c, i
+}
+
+// tCSS is the context transition function for the CSS state.
+func tCSS(c context, s []byte) (context, int) {
+ // CSS quoted strings are almost never used except for:
+ // (1) URLs as in background: "/foo.png"
+ // (2) Multiword font-names as in font-family: "Times New Roman"
+ // (3) List separators in content values as in inline-lists:
+ // <style>
+ // ul.inlineList { list-style: none; padding:0 }
+ // ul.inlineList > li { display: inline }
+ // ul.inlineList > li:before { content: ", " }
+ // ul.inlineList > li:first-child:before { content: "" }
+ // </style>
+ // <ul class=inlineList><li>One<li>Two<li>Three</ul>
+ // (4) Attribute value selectors as in a[href="http://example.com/"]
+ //
+ // We conservatively treat all strings as URLs, but make some
+ // allowances to avoid confusion.
+ //
+ // In (1), our conservative assumption is justified.
+ // In (2), valid font names do not contain ':', '?', or '#', so our
+ // conservative assumption is fine since we will never transition past
+ // urlPartPreQuery.
+ // In (3), our protocol heuristic should not be tripped, and there
+ // should not be non-space content after a '?' or '#', so as long as
+ // we only %-encode RFC 3986 reserved characters we are ok.
+ // In (4), we should URL escape for URL attributes, and for others we
+ // have the attribute name available if our conservative assumption
+ // proves problematic for real code.
+
+ k := 0
+ for {
+ i := k + bytes.IndexAny(s[k:], `("'/`)
+ if i < k {
+ return c, len(s)
+ }
+ switch s[i] {
+ case '(':
+ // Look for url to the left.
+ p := bytes.TrimRight(s[:i], "\t\n\f\r ")
+ if endsWithCSSKeyword(p, "url") {
+ j := len(s) - len(bytes.TrimLeft(s[i+1:], "\t\n\f\r "))
+ switch {
+ case j != len(s) && s[j] == '"':
+ c.state, j = stateCSSDqURL, j+1
+ case j != len(s) && s[j] == '\'':
+ c.state, j = stateCSSSqURL, j+1
+ default:
+ c.state = stateCSSURL
+ }
+ return c, j
+ }
+ case '/':
+ if i+1 < len(s) {
+ switch s[i+1] {
+ case '/':
+ c.state = stateCSSLineCmt
+ return c, i + 2
+ case '*':
+ c.state = stateCSSBlockCmt
+ return c, i + 2
+ }
+ }
+ case '"':
+ c.state = stateCSSDqStr
+ return c, i + 1
+ case '\'':
+ c.state = stateCSSSqStr
+ return c, i + 1
+ }
+ k = i + 1
+ }
+ panic("unreachable")
+}
+
+// tCSSStr is the context transition function for the CSS string and URL states.
+func tCSSStr(c context, s []byte) (context, int) {
+ var endAndEsc string
+ switch c.state {
+ case stateCSSDqStr, stateCSSDqURL:
+ endAndEsc = `\"`
+ case stateCSSSqStr, stateCSSSqURL:
+ endAndEsc = `\'`
+ case stateCSSURL:
+ // Unquoted URLs end with a newline or close parenthesis.
+ // The below includes the wc (whitespace character) and nl.
+ endAndEsc = "\\\t\n\f\r )"
+ default:
+ panic(c.state.String())
+ }
+
+ k := 0
+ for {
+ i := k + bytes.IndexAny(s[k:], endAndEsc)
+ if i < k {
+ c, nread := tURL(c, decodeCSS(s[k:]))
+ return c, k + nread
+ }
+ if s[i] == '\\' {
+ i++
+ if i == len(s) {
+ return context{
+ state: stateError,
+ err: errorf(ErrPartialEscape, 0, "unfinished escape sequence in CSS string: %q", s),
+ }, len(s)
+ }
+ } else {
+ c.state = stateCSS
+ return c, i + 1
+ }
+ c, _ = tURL(c, decodeCSS(s[:i+1]))
+ k = i + 1
+ }
+ panic("unreachable")
+}
+
+// tError is the context transition function for the error state.
+func tError(c context, s []byte) (context, int) {
+ return c, len(s)
+}
+
+// eatAttrName returns the largest j such that s[i:j] is an attribute name.
+// It returns an error if s[i:] does not look like it begins with an
+// attribute name, such as encountering a quote mark without a preceding
+// equals sign.
+func eatAttrName(s []byte, i int) (int, *Error) {
+ for j := i; j < len(s); j++ {
+ switch s[j] {
+ case ' ', '\t', '\n', '\f', '\r', '=', '>':
+ return j, nil
+ case '\'', '"', '<':
+ // These result in a parse warning in HTML5 and are
+ // indicative of serious problems if seen in an attr
+ // name in a template.
+ return -1, errorf(ErrBadHTML, 0, "%q in attribute name: %.32q", s[j:j+1], s)
+ default:
+ // No-op.
+ }
+ }
+ return len(s), nil
+}
+
+var elementNameMap = map[string]element{
+ "script": elementScript,
+ "style": elementStyle,
+ "textarea": elementTextarea,
+ "title": elementTitle,
+}
+
+// asciiAlpha returns whether c is an ASCII letter.
+func asciiAlpha(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+// asciiAlphaNum returns whether c is an ASCII letter or digit.
+func asciiAlphaNum(c byte) bool {
+ return asciiAlpha(c) || '0' <= c && c <= '9'
+}
+
+// eatTagName returns the largest j such that s[i:j] is a tag name and the tag type.
+func eatTagName(s []byte, i int) (int, element) {
+ if i == len(s) || !asciiAlpha(s[i]) {
+ return i, elementNone
+ }
+ j := i + 1
+ for j < len(s) {
+ x := s[j]
+ if asciiAlphaNum(x) {
+ j++
+ continue
+ }
+ // Allow "x-y" or "x:y" but not "x-", "-y", or "x--y".
+ if (x == ':' || x == '-') && j+1 < len(s) && asciiAlphaNum(s[j+1]) {
+ j += 2
+ continue
+ }
+ break
+ }
+ return j, elementNameMap[strings.ToLower(string(s[i:j]))]
+}
+
+// eatWhiteSpace returns the largest j such that s[i:j] is white space.
+func eatWhiteSpace(s []byte, i int) int {
+ for j := i; j < len(s); j++ {
+ switch s[j] {
+ case ' ', '\t', '\n', '\f', '\r':
+ // No-op.
+ default:
+ return j
+ }
+ }
+ return len(s)
+}
diff --git a/src/pkg/html/template/url.go b/src/pkg/html/template/url.go
new file mode 100644
index 000000000..454c791ec
--- /dev/null
+++ b/src/pkg/html/template/url.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 template
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// urlFilter returns its input unless it contains an unsafe protocol in which
+// case it defangs the entire URL.
+func urlFilter(args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeURL {
+ return s
+ }
+ if i := strings.IndexRune(s, ':'); i >= 0 && strings.IndexRune(s[:i], '/') < 0 {
+ protocol := strings.ToLower(s[:i])
+ if protocol != "http" && protocol != "https" && protocol != "mailto" {
+ return "#" + filterFailsafe
+ }
+ }
+ return s
+}
+
+// urlEscaper produces an output that can be embedded in a URL query.
+// The output can be embedded in an HTML attribute without further escaping.
+func urlEscaper(args ...interface{}) string {
+ return urlProcessor(false, args...)
+}
+
+// urlEscaper normalizes URL content so it can be embedded in a quote-delimited
+// string or parenthesis delimited url(...).
+// The normalizer does not encode all HTML specials. Specifically, it does not
+// encode '&' so correct embedding in an HTML attribute requires escaping of
+// '&' to '&amp;'.
+func urlNormalizer(args ...interface{}) string {
+ return urlProcessor(true, args...)
+}
+
+// urlProcessor normalizes (when norm is true) or escapes its input to produce
+// a valid hierarchical or opaque URL part.
+func urlProcessor(norm bool, args ...interface{}) string {
+ s, t := stringify(args...)
+ if t == contentTypeURL {
+ norm = true
+ }
+ var b bytes.Buffer
+ written := 0
+ // The byte loop below assumes that all URLs use UTF-8 as the
+ // content-encoding. This is similar to the URI to IRI encoding scheme
+ // defined in section 3.1 of RFC 3987, and behaves the same as the
+ // EcmaScript builtin encodeURIComponent.
+ // It should not cause any misencoding of URLs in pages with
+ // Content-type: text/html;charset=UTF-8.
+ for i, n := 0, len(s); i < n; i++ {
+ c := s[i]
+ switch c {
+ // Single quote and parens are sub-delims in RFC 3986, but we
+ // escape them so the output can be embedded in in single
+ // quoted attributes and unquoted CSS url(...) constructs.
+ // Single quotes are reserved in URLs, but are only used in
+ // the obsolete "mark" rule in an appendix in RFC 3986
+ // so can be safely encoded.
+ case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']':
+ if norm {
+ continue
+ }
+ // Unreserved according to RFC 3986 sec 2.3
+ // "For consistency, percent-encoded octets in the ranges of
+ // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D),
+ // period (%2E), underscore (%5F), or tilde (%7E) should not be
+ // created by URI producers
+ case '-', '.', '_', '~':
+ continue
+ case '%':
+ // When normalizing do not re-encode valid escapes.
+ if norm && i+2 < len(s) && isHex(s[i+1]) && isHex(s[i+2]) {
+ continue
+ }
+ default:
+ // Unreserved according to RFC 3986 sec 2.3
+ if 'a' <= c && c <= 'z' {
+ continue
+ }
+ if 'A' <= c && c <= 'Z' {
+ continue
+ }
+ if '0' <= c && c <= '9' {
+ continue
+ }
+ }
+ b.WriteString(s[written:i])
+ fmt.Fprintf(&b, "%%%02x", c)
+ written = i + 1
+ }
+ if written == 0 {
+ return s
+ }
+ b.WriteString(s[written:])
+ return b.String()
+}
diff --git a/src/pkg/html/template/url_test.go b/src/pkg/html/template/url_test.go
new file mode 100644
index 000000000..5182e9d79
--- /dev/null
+++ b/src/pkg/html/template/url_test.go
@@ -0,0 +1,112 @@
+// 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 (
+ "testing"
+)
+
+func TestURLNormalizer(t *testing.T) {
+ tests := []struct {
+ url, want string
+ }{
+ {"", ""},
+ {
+ "http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
+ "http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
+ },
+ {" ", "%20"},
+ {"%7c", "%7c"},
+ {"%7C", "%7C"},
+ {"%2", "%252"},
+ {"%", "%25"},
+ {"%z", "%25z"},
+ {"/foo|bar/%5c\u1234", "/foo%7cbar/%5c%e1%88%b4"},
+ }
+ for _, test := range tests {
+ if got := urlNormalizer(test.url); test.want != got {
+ t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.url, test.want, got)
+ }
+ if test.want != urlNormalizer(test.want) {
+ t.Errorf("not idempotent: %q", test.want)
+ }
+ }
+}
+
+func TestURLFilters(t *testing.T) {
+ input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
+ ` !"#$%&'()*+,-./` +
+ `0123456789:;<=>?` +
+ `@ABCDEFGHIJKLMNO` +
+ `PQRSTUVWXYZ[\]^_` +
+ "`abcdefghijklmno" +
+ "pqrstuvwxyz{|}~\x7f" +
+ "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
+
+ tests := []struct {
+ name string
+ escaper func(...interface{}) string
+ escaped string
+ }{
+ {
+ "urlEscaper",
+ urlEscaper,
+ "%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
+ "%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
+ "%20%21%22%23%24%25%26%27%28%29%2a%2b%2c-.%2f" +
+ "0123456789%3a%3b%3c%3d%3e%3f" +
+ "%40ABCDEFGHIJKLMNO" +
+ "PQRSTUVWXYZ%5b%5c%5d%5e_" +
+ "%60abcdefghijklmno" +
+ "pqrstuvwxyz%7b%7c%7d~%7f" +
+ "%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
+ },
+ {
+ "urlNormalizer",
+ urlNormalizer,
+ "%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
+ "%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
+ "%20!%22#$%25&%27%28%29*+,-./" +
+ "0123456789:;%3c=%3e?" +
+ "@ABCDEFGHIJKLMNO" +
+ "PQRSTUVWXYZ[%5c]%5e_" +
+ "%60abcdefghijklmno" +
+ "pqrstuvwxyz%7b%7c%7d~%7f" +
+ "%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
+ },
+ }
+
+ for _, test := range tests {
+ if s := test.escaper(input); s != test.escaped {
+ t.Errorf("%s: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
+ continue
+ }
+ }
+}
+
+func BenchmarkURLEscaper(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ urlEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
+ }
+}
+
+func BenchmarkURLEscaperNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ urlEscaper("TheQuickBrownFoxJumpsOverTheLazyDog.")
+ }
+}
+
+func BenchmarkURLNormalizer(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ urlNormalizer("The quick brown fox jumps over the lazy dog.\n")
+ }
+}
+
+func BenchmarkURLNormalizerNoSpecials(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ urlNormalizer("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
+ }
+}
diff --git a/src/pkg/html/testdata/webkit/README b/src/pkg/html/testdata/webkit/README
deleted file mode 100644
index 9b4c2d8be..000000000
--- a/src/pkg/html/testdata/webkit/README
+++ /dev/null
@@ -1,28 +0,0 @@
-The *.dat files in this directory are copied from The WebKit Open Source
-Project, specifically $WEBKITROOT/LayoutTests/html5lib/resources.
-WebKit is licensed under a BSD style license.
-http://webkit.org/coding/bsd-license.html says:
-
-Copyright (C) 2009 Apple Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/src/pkg/html/testdata/webkit/adoption01.dat b/src/pkg/html/testdata/webkit/adoption01.dat
deleted file mode 100644
index 787e1b01e..000000000
--- a/src/pkg/html/testdata/webkit/adoption01.dat
+++ /dev/null
@@ -1,194 +0,0 @@
-#data
-<a><p></a></p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <p>
-| <a>
-
-#data
-<a>1<p>2</a>3</p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <p>
-| <a>
-| "2"
-| "3"
-
-#data
-<a>1<button>2</a>3</button>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <button>
-| <a>
-| "2"
-| "3"
-
-#data
-<a>1<b>2</a>3</b>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <b>
-| "2"
-| <b>
-| "3"
-
-#data
-<a>1<div>2<div>3</a>4</div>5</div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <div>
-| <a>
-| "2"
-| <div>
-| <a>
-| "3"
-| "4"
-| "5"
-
-#data
-<table><a>1<p>2</a>3</p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <p>
-| <a>
-| "2"
-| "3"
-| <table>
-
-#data
-<b><b><a><p></a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <b>
-| <a>
-| <p>
-| <a>
-
-#data
-<b><a><b><p></a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <a>
-| <b>
-| <b>
-| <p>
-| <a>
-
-#data
-<a><b><b><p></a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <b>
-| <b>
-| <b>
-| <p>
-| <a>
-
-#data
-<p>1<s id="A">2<b id="B">3</p>4</s>5</b>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| "1"
-| <s>
-| id="A"
-| "2"
-| <b>
-| id="B"
-| "3"
-| <s>
-| id="A"
-| <b>
-| id="B"
-| "4"
-| <b>
-| id="B"
-| "5"
-
-#data
-<table><a>1<td>2</td>3</table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| "1"
-| <a>
-| "3"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "2"
-
-#data
-<table>A<td>B</td>C</table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "AC"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "B"
-
-#data
-<a><svg><tr><input></a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <svg svg>
-| <svg tr>
-| <svg input>
diff --git a/src/pkg/html/testdata/webkit/adoption02.dat b/src/pkg/html/testdata/webkit/adoption02.dat
deleted file mode 100644
index d18151b44..000000000
--- a/src/pkg/html/testdata/webkit/adoption02.dat
+++ /dev/null
@@ -1,31 +0,0 @@
-#data
-<b>1<i>2<p>3</b>4
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "1"
-| <i>
-| "2"
-| <i>
-| <p>
-| <b>
-| "3"
-| "4"
-
-#data
-<a><div><style></style><address><a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <div>
-| <a>
-| <style>
-| <address>
-| <a>
-| <a>
diff --git a/src/pkg/html/testdata/webkit/comments01.dat b/src/pkg/html/testdata/webkit/comments01.dat
deleted file mode 100644
index 44f187683..000000000
--- a/src/pkg/html/testdata/webkit/comments01.dat
+++ /dev/null
@@ -1,135 +0,0 @@
-#data
-FOO<!-- BAR -->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -->
-| "BAZ"
-
-#data
-FOO<!-- BAR --!>BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -->
-| "BAZ"
-
-#data
-FOO<!-- BAR -- >BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -- >BAZ -->
-
-#data
-FOO<!-- BAR -- <QUX> -- MUX -->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -- <QUX> -- MUX -->
-| "BAZ"
-
-#data
-FOO<!-- BAR -- <QUX> -- MUX --!>BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -- <QUX> -- MUX -->
-| "BAZ"
-
-#data
-FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- BAR -- <QUX> -- MUX -- >BAZ -->
-
-#data
-FOO<!---->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- -->
-| "BAZ"
-
-#data
-FOO<!--->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- -->
-| "BAZ"
-
-#data
-FOO<!-->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- -->
-| "BAZ"
-
-#data
-<?xml version="1.0">Hi
-#errors
-#document
-| <!-- ?xml version="1.0" -->
-| <html>
-| <head>
-| <body>
-| "Hi"
-
-#data
-<?xml version="1.0">
-#errors
-#document
-| <!-- ?xml version="1.0" -->
-| <html>
-| <head>
-| <body>
-
-#data
-<?xml version
-#errors
-#document
-| <!-- ?xml version -->
-| <html>
-| <head>
-| <body>
-
-#data
-FOO<!----->BAZ
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <!-- - -->
-| "BAZ"
diff --git a/src/pkg/html/testdata/webkit/doctype01.dat b/src/pkg/html/testdata/webkit/doctype01.dat
deleted file mode 100644
index ae457328a..000000000
--- a/src/pkg/html/testdata/webkit/doctype01.dat
+++ /dev/null
@@ -1,370 +0,0 @@
-#data
-<!DOCTYPE html>Hello
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!dOctYpE HtMl>Hello
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPEhtml>Hello
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE>Hello
-#errors
-#document
-| <!DOCTYPE >
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE >Hello
-#errors
-#document
-| <!DOCTYPE >
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato >Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato taco>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato taco "ddd>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato sYstEM>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato sYstEM >Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato sYstEM ggg>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato SYSTEM taco >Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato SYSTEM 'taco"'>Hello
-#errors
-#document
-| <!DOCTYPE potato "" "taco"">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato SYSTEM "taco">Hello
-#errors
-#document
-| <!DOCTYPE potato "" "taco">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato SYSTEM "tai'co">Hello
-#errors
-#document
-| <!DOCTYPE potato "" "tai'co">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato SYSTEMtaco "ddd">Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato grass SYSTEM taco>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato pUbLIc>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato pUbLIc >Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato pUbLIcgoof>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato PUBLIC goof>Hello
-#errors
-#document
-| <!DOCTYPE potato>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato PUBLIC "go'of">Hello
-#errors
-#document
-| <!DOCTYPE potato "go'of" "">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato PUBLIC 'go'of'>Hello
-#errors
-#document
-| <!DOCTYPE potato "go" "">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
-#errors
-#document
-| <!DOCTYPE potato "go:hh of" "">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
-#errors
-#document
-| <!DOCTYPE potato "W3C-//dfdf" "">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">Hello
-#errors
-#document
-| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE ...>Hello
-#errors
-#document
-| <!DOCTYPE ...>
-| <html>
-| <head>
-| <body>
-| "Hello"
-
-#data
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-#errors
-#document
-| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
-#errors
-#document
-| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE root-element [SYSTEM OR PUBLIC FPI] "uri" [
-<!-- internal declarations -->
-]>
-#errors
-#document
-| <!DOCTYPE root-element>
-| <html>
-| <head>
-| <body>
-| "]>"
-
-#data
-<!DOCTYPE html PUBLIC
- "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
- "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
-#errors
-#document
-| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
-#errors
-#document
-| <!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/src/pkg/html/testdata/webkit/entities01.dat b/src/pkg/html/testdata/webkit/entities01.dat
deleted file mode 100644
index c8073b781..000000000
--- a/src/pkg/html/testdata/webkit/entities01.dat
+++ /dev/null
@@ -1,603 +0,0 @@
-#data
-FOO&gt;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO>BAR"
-
-#data
-FOO&gtBAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO>BAR"
-
-#data
-FOO&gt BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO> BAR"
-
-#data
-FOO&gt;;;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO>;;BAR"
-
-#data
-I'm &notit; I tell you
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "I'm ¬it; I tell you"
-
-#data
-I'm &notin; I tell you
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "I'm ∉ I tell you"
-
-#data
-FOO& BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO& BAR"
-
-#data
-FOO&<BAR>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&"
-| <bar>
-
-#data
-FOO&&&&gt;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&&&>BAR"
-
-#data
-FOO&#41;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO)BAR"
-
-#data
-FOO&#x41;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOABAR"
-
-#data
-FOO&#X41;BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOABAR"
-
-#data
-FOO&#BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&#BAR"
-
-#data
-FOO&#ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&#ZOO"
-
-#data
-FOO&#xBAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOºR"
-
-#data
-FOO&#xZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&#xZOO"
-
-#data
-FOO&#XZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO&#XZOO"
-
-#data
-FOO&#41BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO)BAR"
-
-#data
-FOO&#x41BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO䆺R"
-
-#data
-FOO&#x41ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOAZOO"
-
-#data
-FOO&#x0000;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#x0078;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOxZOO"
-
-#data
-FOO&#x0079;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOyZOO"
-
-#data
-FOO&#x0080;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO€ZOO"
-
-#data
-FOO&#x0081;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x0082;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO‚ZOO"
-
-#data
-FOO&#x0083;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOƒZOO"
-
-#data
-FOO&#x0084;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO„ZOO"
-
-#data
-FOO&#x0085;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO…ZOO"
-
-#data
-FOO&#x0086;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO†ZOO"
-
-#data
-FOO&#x0087;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO‡ZOO"
-
-#data
-FOO&#x0088;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOˆZOO"
-
-#data
-FOO&#x0089;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO‰ZOO"
-
-#data
-FOO&#x008A;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOŠZOO"
-
-#data
-FOO&#x008B;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO‹ZOO"
-
-#data
-FOO&#x008C;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOŒZOO"
-
-#data
-FOO&#x008D;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x008E;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOŽZOO"
-
-#data
-FOO&#x008F;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x0090;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x0091;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO‘ZOO"
-
-#data
-FOO&#x0092;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO’ZOO"
-
-#data
-FOO&#x0093;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO“ZOO"
-
-#data
-FOO&#x0094;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO”ZOO"
-
-#data
-FOO&#x0095;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO•ZOO"
-
-#data
-FOO&#x0096;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO–ZOO"
-
-#data
-FOO&#x0097;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO—ZOO"
-
-#data
-FOO&#x0098;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO˜ZOO"
-
-#data
-FOO&#x0099;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO™ZOO"
-
-#data
-FOO&#x009A;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOšZOO"
-
-#data
-FOO&#x009B;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO›ZOO"
-
-#data
-FOO&#x009C;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOœZOO"
-
-#data
-FOO&#x009D;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x009E;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOžZOO"
-
-#data
-FOO&#x009F;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOŸZOO"
-
-#data
-FOO&#x00A0;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO ZOO"
-
-#data
-FOO&#xD7FF;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO퟿ZOO"
-
-#data
-FOO&#xD800;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#xD801;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#xDFFE;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#xDFFF;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#xE000;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOOZOO"
-
-#data
-FOO&#x10FFFE;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO􏿾ZOO"
-
-#data
-FOO&#x1087D4;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO􈟔ZOO"
-
-#data
-FOO&#x10FFFF;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO􏿿ZOO"
-
-#data
-FOO&#x110000;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
-
-#data
-FOO&#xFFFFFF;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO�ZOO"
diff --git a/src/pkg/html/testdata/webkit/entities02.dat b/src/pkg/html/testdata/webkit/entities02.dat
deleted file mode 100644
index e2fb42a07..000000000
--- a/src/pkg/html/testdata/webkit/entities02.dat
+++ /dev/null
@@ -1,249 +0,0 @@
-#data
-<div bar="ZZ&gt;YY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ>YY"
-
-#data
-<div bar="ZZ&"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&"
-
-#data
-<div bar='ZZ&'></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&"
-
-#data
-<div bar=ZZ&></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&"
-
-#data
-<div bar="ZZ&gt=YY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&gt=YY"
-
-#data
-<div bar="ZZ&gt0YY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&gt0YY"
-
-#data
-<div bar="ZZ&gt9YY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&gt9YY"
-
-#data
-<div bar="ZZ&gtaYY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&gtaYY"
-
-#data
-<div bar="ZZ&gtZYY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ&gtZYY"
-
-#data
-<div bar="ZZ&gt YY"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ> YY"
-
-#data
-<div bar="ZZ&gt"></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ>"
-
-#data
-<div bar='ZZ&gt'></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ>"
-
-#data
-<div bar=ZZ&gt></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| bar="ZZ>"
-
-#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/src/pkg/html/testdata/webkit/html5test-com.dat b/src/pkg/html/testdata/webkit/html5test-com.dat
deleted file mode 100644
index d7cb71db0..000000000
--- a/src/pkg/html/testdata/webkit/html5test-com.dat
+++ /dev/null
@@ -1,246 +0,0 @@
-#data
-<div<div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div<div>
-
-#data
-<div foo<bar=''>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| foo<bar=""
-
-#data
-<div foo=`bar`>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| foo="`bar`"
-
-#data
-<div \"foo=''>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| \"foo=""
-
-#data
-<a href='\nbar'></a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| href="\nbar"
-
-#data
-<!DOCTYPE html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-&lang;&rang;
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "⟨⟩"
-
-#data
-&apos;
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "'"
-
-#data
-&ImaginaryI;
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "ⅈ"
-
-#data
-&Kopf;
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "𝕂"
-
-#data
-&notinva;
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "∉"
-
-#data
-<?import namespace="foo" implementation="#bar">
-#errors
-#document
-| <!-- ?import namespace="foo" implementation="#bar" -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!--foo--bar-->
-#errors
-#document
-| <!-- foo--bar -->
-| <html>
-| <head>
-| <body>
-
-#data
-<![CDATA[x]]>
-#errors
-#document
-| <!-- [CDATA[x]] -->
-| <html>
-| <head>
-| <body>
-
-#data
-<textarea><!--</textarea>--></textarea>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "<!--"
-| "-->"
-
-#data
-<textarea><!--</textarea>-->
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "<!--"
-| "-->"
-
-#data
-<style><!--</style>--></style>
-#errors
-#document
-| <html>
-| <head>
-| <style>
-| "<!--"
-| <body>
-| "-->"
-
-#data
-<style><!--</style>-->
-#errors
-#document
-| <html>
-| <head>
-| <style>
-| "<!--"
-| <body>
-| "-->"
-
-#data
-<ul><li>A </li> <li>B</li></ul>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <ul>
-| <li>
-| "A "
-| " "
-| <li>
-| "B"
-
-#data
-<table><form><input type=hidden><input></form><div></div></table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <input>
-| <div>
-| <table>
-| <form>
-| <input>
-| type="hidden"
-
-#data
-<i>A<b>B<p></i>C</b>D
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <i>
-| "A"
-| <b>
-| "B"
-| <b>
-| <p>
-| <b>
-| <i>
-| "C"
-| "D"
-
-#data
-<div></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-
-#data
-<svg></svg>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-
-#data
-<math></math>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
diff --git a/src/pkg/html/testdata/webkit/inbody01.dat b/src/pkg/html/testdata/webkit/inbody01.dat
deleted file mode 100644
index 3f2bd374c..000000000
--- a/src/pkg/html/testdata/webkit/inbody01.dat
+++ /dev/null
@@ -1,43 +0,0 @@
-#data
-<button>1</foo>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <button>
-| "1"
-
-#data
-<foo>1<p>2</foo>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| "1"
-| <p>
-| "2"
-
-#data
-<dd>1</foo>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <dd>
-| "1"
-
-#data
-<foo>1<dd>2</foo>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| "1"
-| <dd>
-| "2"
diff --git a/src/pkg/html/testdata/webkit/isindex.dat b/src/pkg/html/testdata/webkit/isindex.dat
deleted file mode 100644
index 88325ffe6..000000000
--- a/src/pkg/html/testdata/webkit/isindex.dat
+++ /dev/null
@@ -1,40 +0,0 @@
-#data
-<isindex>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <form>
-| <hr>
-| <label>
-| "This is a searchable index. Enter search keywords: "
-| <input>
-| name="isindex"
-| <hr>
-
-#data
-<isindex name="A" action="B" prompt="C" foo="D">
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <form>
-| action="B"
-| <hr>
-| <label>
-| "C"
-| <input>
-| foo="D"
-| name="isindex"
-| <hr>
-
-#data
-<form><isindex>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <form>
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
deleted file mode 100644
index a5ebb1eb2..000000000
--- a/src/pkg/html/testdata/webkit/pending-spec-changes-plain-text-unsafe.dat
+++ /dev/null
Binary files differ
diff --git a/src/pkg/html/testdata/webkit/pending-spec-changes.dat b/src/pkg/html/testdata/webkit/pending-spec-changes.dat
deleted file mode 100644
index e00ee85d3..000000000
--- a/src/pkg/html/testdata/webkit/pending-spec-changes.dat
+++ /dev/null
@@ -1,28 +0,0 @@
-#data
-<input type="hidden"><frameset>
-#errors
-21: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-31: “frameset” start tag seen.
-31: End of file seen and there were open elements.
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><table><caption><svg>foo</table>bar
-#errors
-47: End tag “table” did not match the name of the current open element (“svg”).
-47: “table” closed but “caption” was still open.
-47: End tag “table” seen, but there were open elements.
-36: Unclosed element “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <svg svg>
-| "foo"
-| "bar"
diff --git a/src/pkg/html/testdata/webkit/plain-text-unsafe.dat b/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
deleted file mode 100644
index 2f40e83ba..000000000
--- a/src/pkg/html/testdata/webkit/plain-text-unsafe.dat
+++ /dev/null
@@ -1,8 +0,0 @@
-#data
-FOO&#x000D;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO ZOO"
diff --git a/src/pkg/html/testdata/webkit/scriptdata01.dat b/src/pkg/html/testdata/webkit/scriptdata01.dat
deleted file mode 100644
index 76b67f4ba..000000000
--- a/src/pkg/html/testdata/webkit/scriptdata01.dat
+++ /dev/null
@@ -1,308 +0,0 @@
-#data
-FOO<script>'Hello'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'Hello'"
-| "BAR"
-
-#data
-FOO<script></script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "BAR"
-
-#data
-FOO<script></script >BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "BAR"
-
-#data
-FOO<script></script/>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "BAR"
-
-#data
-FOO<script></script/ >BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "BAR"
-
-#data
-FOO<script type="text/plain"></scriptx>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "</scriptx>BAR"
-
-#data
-FOO<script></script foo=">" dd>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "BAR"
-
-#data
-FOO<script>'<'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<'"
-| "BAR"
-
-#data
-FOO<script>'<!'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!'"
-| "BAR"
-
-#data
-FOO<script>'<!-'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-'"
-| "BAR"
-
-#data
-FOO<script>'<!--'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!--'"
-| "BAR"
-
-#data
-FOO<script>'<!---'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!---'"
-| "BAR"
-
-#data
-FOO<script>'<!-->'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-->'"
-| "BAR"
-
-#data
-FOO<script>'<!-->'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-->'"
-| "BAR"
-
-#data
-FOO<script>'<!-- potato'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-- potato'"
-| "BAR"
-
-#data
-FOO<script>'<!-- <sCrIpt'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-- <sCrIpt'"
-| "BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt>'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt>'</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt> -'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt> -'</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt> --'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt> --'</script>BAR"
-
-#data
-FOO<script>'<!-- <sCrIpt> -->'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| "'<!-- <sCrIpt> -->'"
-| "BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt> --!>'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt> --!>'</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt> -- >'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt> -- >'</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt '</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt '</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt/'</script>BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt\'</script>BAR
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt\'"
-| "BAR"
-
-#data
-FOO<script type="text/plain">'<!-- <sCrIpt/'</script>BAR</script>QUX
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO"
-| <script>
-| type="text/plain"
-| "'<!-- <sCrIpt/'</script>BAR"
-| "QUX"
diff --git a/src/pkg/html/testdata/webkit/scripted/adoption01.dat b/src/pkg/html/testdata/webkit/scripted/adoption01.dat
deleted file mode 100644
index 4e08d0e84..000000000
--- a/src/pkg/html/testdata/webkit/scripted/adoption01.dat
+++ /dev/null
@@ -1,15 +0,0 @@
-#data
-<p><b id="A"><script>document.getElementById("A").id = "B"</script></p>TEXT</b>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| id="B"
-| <script>
-| "document.getElementById("A").id = "B""
-| <b>
-| id="A"
-| "TEXT"
diff --git a/src/pkg/html/testdata/webkit/scripted/webkit01.dat b/src/pkg/html/testdata/webkit/scripted/webkit01.dat
deleted file mode 100644
index ef4a41ca0..000000000
--- a/src/pkg/html/testdata/webkit/scripted/webkit01.dat
+++ /dev/null
@@ -1,28 +0,0 @@
-#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"
diff --git a/src/pkg/html/testdata/webkit/tables01.dat b/src/pkg/html/testdata/webkit/tables01.dat
deleted file mode 100644
index 88ef1fe2e..000000000
--- a/src/pkg/html/testdata/webkit/tables01.dat
+++ /dev/null
@@ -1,197 +0,0 @@
-#data
-<table><th>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <th>
-
-#data
-<table><td>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><col foo='bar'>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <colgroup>
-| <col>
-| foo="bar"
-
-#data
-<table><colgroup></html>foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "foo"
-| <table>
-| <colgroup>
-
-#data
-<table></table><p>foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <p>
-| "foo"
-
-#data
-<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr><td>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><select><option>3</select></table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| "3"
-| <table>
-
-#data
-<table><select><table></table></select></table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <table>
-| <table>
-
-#data
-<table><select></table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <table>
-
-#data
-<table><select><option>A<tr><td>B</td></tr></table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| "A"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "B"
-
-#data
-<table><td></body></caption></col></colgroup></html>foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "foo"
-
-#data
-<table><td>A</table>B
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "A"
-| "B"
-
-#data
-<table><tr><caption>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <caption>
-
-#data
-<table><tr></body></caption></col></colgroup></html></td></th><td>foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "foo"
-
-#data
-<table><td><tr>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <tr>
-
-#data
-<table><td><button><td>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <button>
-| <td>
diff --git a/src/pkg/html/testdata/webkit/tests1.dat b/src/pkg/html/testdata/webkit/tests1.dat
deleted file mode 100644
index cbf8bdda6..000000000
--- a/src/pkg/html/testdata/webkit/tests1.dat
+++ /dev/null
@@ -1,1952 +0,0 @@
-#data
-Test
-#errors
-Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "Test"
-
-#data
-<p>One<p>Two
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| "One"
-| <p>
-| "Two"
-
-#data
-Line1<br>Line2<br>Line3<br>Line4
-#errors
-Line: 1 Col: 5 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "Line1"
-| <br>
-| "Line2"
-| <br>
-| "Line3"
-| <br>
-| "Line4"
-
-#data
-<html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<head>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<body>
-#errors
-Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head></head>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head></head><body>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head></head><body></body>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head><body></body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head></body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-Line: 1 Col: 19 Unexpected end tag (body).
-Line: 1 Col: 26 Unexpected end tag (html).
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><head><body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<html><body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<head></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end tag (html). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-</head>
-#errors
-Line: 1 Col: 7 Unexpected end tag (head). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-</body>
-#errors
-Line: 1 Col: 7 Unexpected end tag (body). Expected DOCTYPE.
-Line: 1 Col: 7 Unexpected end tag (body) after the (implied) root element.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-</html>
-#errors
-Line: 1 Col: 7 Unexpected end tag (html). Expected DOCTYPE.
-Line: 1 Col: 7 Unexpected end tag (html) after the (implied) root element.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<b><table><td><i></table>
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <i>
-
-#data
-<b><table><td></b><i></table>X
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 30 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <i>
-| "X"
-
-#data
-<h1>Hello<h2>World
-#errors
-4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-13: Heading cannot be a child of another heading.
-18: End of file seen and there were open elements.
-#document
-| <html>
-| <head>
-| <body>
-| <h1>
-| "Hello"
-| <h2>
-| "World"
-
-#data
-<a><p>X<a>Y</a>Z</p></a>
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 10 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 10 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <p>
-| <a>
-| "X"
-| <a>
-| "Y"
-| "Z"
-
-#data
-<b><button>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.
-#document
-| <html>
-| <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
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end tag (p). Ignored.
-Line: 1 Col: 24 Unexpected end tag (p). Ignored.
-Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
-Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| <div>
-| <b>
-| <marquee>
-| <p>
-| "X"
-
-#data
-<script><div></script></div><title><p></title><p><p>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 28 Unexpected end tag (div). Ignored.
-#document
-| <html>
-| <head>
-| <script>
-| "<div>"
-| <title>
-| "<p>"
-| <body>
-| <p>
-| <p>
-
-#data
-<!--><div>--<!-->
-#errors
-Line: 1 Col: 5 Incorrect comment.
-Line: 1 Col: 10 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 17 Incorrect comment.
-Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
-#document
-| <!-- -->
-| <html>
-| <head>
-| <body>
-| <div>
-| "--"
-| <!-- -->
-
-#data
-<p><hr></p>
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end tag (p). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <hr>
-| <p>
-
-#data
-<select><b><option><select><option></b></select>X
-#errors
-Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
-Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
-Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 48 Unexpected end tag (select). Ignored.
-Line: 1 Col: 49 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| <option>
-| "X"
-
-#data
-<a><table><td><a><table></table><a></tr><a></table><b>X</b>C<a>Y
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 63 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 64 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <a>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <a>
-| <table>
-| <a>
-| <a>
-| <b>
-| "X"
-| "C"
-| <a>
-| "Y"
-
-#data
-<a X>0<b>1<a Y>2
-#errors
-Line: 1 Col: 5 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 15 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| x=""
-| "0"
-| <b>
-| "1"
-| <b>
-| <a>
-| y=""
-| "2"
-
-#data
-<!-----><font><div>hello<table>excite!<b>me!<th><i>please!</tr><!--X-->
-#errors
-Line: 1 Col: 7 Unexpected '-' after '--' found in comment.
-Line: 1 Col: 14 Unexpected start tag (font). Expected DOCTYPE.
-Line: 1 Col: 38 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 41 Unexpected start tag (b) in table context caused voodoo mode.
-Line: 1 Col: 48 Unexpected implied end tag (b) in the table phase.
-Line: 1 Col: 48 Unexpected table cell start tag (th) in the table body phase.
-Line: 1 Col: 63 Got table cell end tag (th) while required end tags are missing.
-Line: 1 Col: 71 Unexpected end of file. Expected table content.
-#document
-| <!-- - -->
-| <html>
-| <head>
-| <body>
-| <font>
-| <div>
-| "helloexcite!"
-| <b>
-| "me!"
-| <table>
-| <tbody>
-| <tr>
-| <th>
-| <i>
-| "please!"
-| <!-- X -->
-
-#data
-<!DOCTYPE html><li>hello<li>world<ul>how<li>do</ul>you</body><!--do-->
-#errors
-Line: 1 Col: 61 Unexpected end tag (li). Missing end tag (body).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <li>
-| "hello"
-| <li>
-| "world"
-| <ul>
-| "how"
-| <li>
-| "do"
-| "you"
-| <!-- do -->
-
-#data
-<!DOCTYPE html>A<option>B<optgroup>C<select>D</option>E
-#errors
-Line: 1 Col: 54 Unexpected end tag (option) in the select phase. Ignored.
-Line: 1 Col: 55 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "A"
-| <option>
-| "B"
-| <optgroup>
-| "C"
-| <select>
-| "DE"
-
-#data
-<
-#errors
-Line: 1 Col: 1 Expected tag name. Got something else instead
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "<"
-
-#data
-<#
-#errors
-Line: 1 Col: 1 Expected tag name. Got something else instead
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "<#"
-
-#data
-</
-#errors
-Line: 1 Col: 2 Expected closing tag. Unexpected end of file.
-Line: 1 Col: 2 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "</"
-
-#data
-</#
-#errors
-Line: 1 Col: 2 Expected closing tag. Unexpected character '#' found.
-Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- # -->
-| <html>
-| <head>
-| <body>
-
-#data
-<?
-#errors
-Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
-Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- ? -->
-| <html>
-| <head>
-| <body>
-
-#data
-<?#
-#errors
-Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
-Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- ?# -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!
-#errors
-Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
-Line: 1 Col: 2 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!#
-#errors
-Line: 1 Col: 3 Expected '--' or 'DOCTYPE'. Not found.
-Line: 1 Col: 3 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- # -->
-| <html>
-| <head>
-| <body>
-
-#data
-<?COMMENT?>
-#errors
-Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
-Line: 1 Col: 11 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- ?COMMENT? -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!COMMENT>
-#errors
-Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
-Line: 1 Col: 10 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- COMMENT -->
-| <html>
-| <head>
-| <body>
-
-#data
-</ COMMENT >
-#errors
-Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
-Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- COMMENT -->
-| <html>
-| <head>
-| <body>
-
-#data
-<?COM--MENT?>
-#errors
-Line: 1 Col: 1 Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)
-Line: 1 Col: 13 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- ?COM--MENT? -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!COM--MENT>
-#errors
-Line: 1 Col: 2 Expected '--' or 'DOCTYPE'. Not found.
-Line: 1 Col: 12 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- COM--MENT -->
-| <html>
-| <head>
-| <body>
-
-#data
-</ COM--MENT >
-#errors
-Line: 1 Col: 2 Expected closing tag. Unexpected character ' ' found.
-Line: 1 Col: 14 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- COM--MENT -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><style> EOF
-#errors
-Line: 1 Col: 26 Unexpected end of file. Expected end tag (style).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| " EOF"
-| <body>
-
-#data
-<!DOCTYPE html><script> <!-- </script> --> </script> EOF
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| " <!-- "
-| " "
-| <body>
-| "--> EOF"
-
-#data
-<b><p></b>TEST
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 10 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <p>
-| <b>
-| "TEST"
-
-#data
-<p id=a><b><p id=b></b>TEST
-#errors
-Line: 1 Col: 8 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 19 Unexpected end tag (p). Ignored.
-Line: 1 Col: 23 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| id="a"
-| <b>
-| <p>
-| id="b"
-| "TEST"
-
-#data
-<b id=a><p><b id=b></p></b>TEST
-#errors
-Line: 1 Col: 8 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end tag (p). Ignored.
-Line: 1 Col: 27 End tag (b) violates step 1, paragraph 2 of the adoption agency algorithm.
-Line: 1 Col: 31 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| id="a"
-| <p>
-| <b>
-| id="b"
-| "TEST"
-
-#data
-<!DOCTYPE html><title>U-test</title><body><div><p>Test<u></p></div></body>
-#errors
-Line: 1 Col: 61 Unexpected end tag (p). Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "U-test"
-| <body>
-| <div>
-| <p>
-| "Test"
-| <u>
-
-#data
-<!DOCTYPE html><font><table></font></table></font>
-#errors
-Line: 1 Col: 35 Unexpected end tag (font) in table context caused voodoo mode.
-Line: 1 Col: 35 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <font>
-| <table>
-
-#data
-<font><p>hello<b>cruel</font>world
-#errors
-Line: 1 Col: 6 Unexpected start tag (font). Expected DOCTYPE.
-Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 29 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <font>
-| <p>
-| <font>
-| "hello"
-| <b>
-| "cruel"
-| <b>
-| "world"
-
-#data
-<b>Test</i>Test
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 11 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "TestTest"
-
-#data
-<b>A<cite>B<div>C
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "A"
-| <cite>
-| "B"
-| <div>
-| "C"
-
-#data
-<b>A<cite>B<div>C</cite>D
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 24 Unexpected end tag (cite). Ignored.
-Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "A"
-| <cite>
-| "B"
-| <div>
-| "CD"
-
-#data
-<b>A<cite>B<div>C</b>D
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 21 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "A"
-| <cite>
-| "B"
-| <div>
-| <b>
-| "C"
-| "D"
-
-#data
-
-#errors
-Line: 1 Col: 0 Unexpected End of file. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<DIV>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 5 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-
-#data
-<DIV> abc
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 9 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc"
-
-#data
-<DIV> abc <B>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-
-#data
-<DIV> abc <B> def
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 17 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def"
-
-#data
-<DIV> abc <B> def <I>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-
-#data
-<DIV> abc <B> def <I> ghi
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi"
-
-#data
-<DIV> abc <B> def <I> ghi <P>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <p>
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <p>
-| " jkl"
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 38 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <b>
-| " jkl "
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B> mno
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <b>
-| " jkl "
-| " mno"
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <i>
-| <b>
-| " jkl "
-| " mno "
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <i>
-| <b>
-| " jkl "
-| " mno "
-| " pqr"
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P>
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <i>
-| <b>
-| " jkl "
-| " mno "
-| " pqr "
-
-#data
-<DIV> abc <B> def <I> ghi <P> jkl </B> mno </I> pqr </P> stu
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 38 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 47 End tag (i) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 60 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| " abc "
-| <b>
-| " def "
-| <i>
-| " ghi "
-| <i>
-| <p>
-| <i>
-| <b>
-| " jkl "
-| " mno "
-| " pqr "
-| " stu"
-
-#data
-<test attribute---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------->
-#errors
-Line: 1 Col: 1040 Unexpected start tag (test). Expected DOCTYPE.
-Line: 1 Col: 1040 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <test>
-| attribute----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------=""
-
-#data
-<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe
-#errors
-Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 39 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 39 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 39 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 45 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
-
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| href="blah"
-| "aba"
-| <a>
-| href="foo"
-| "br"
-| <a>
-| href="foo"
-| "x"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <a>
-| href="foo"
-| "aoe"
-
-#data
-<a href="blah">aba<table><tr><td><a href="foo">br</td></tr>x</table>aoe
-#errors
-Line: 1 Col: 15 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 60 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| href="blah"
-| "abax"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <a>
-| href="foo"
-| "br"
-| "aoe"
-
-#data
-<table><a href="blah">aba<tr><td><a href="foo">br</td></tr>x</table>aoe
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 29 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 54 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 68 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 71 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| href="blah"
-| "aba"
-| <a>
-| href="blah"
-| "x"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <a>
-| href="foo"
-| "br"
-| <a>
-| href="blah"
-| "aoe"
-
-#data
-<a href=a>aa<marquee>aa<a href=b>bb</marquee>aa
-#errors
-Line: 1 Col: 10 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 45 End tag (marquee) seen too early. Expected other end tag.
-Line: 1 Col: 47 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| href="a"
-| "aa"
-| <marquee>
-| "aa"
-| <a>
-| href="b"
-| "bb"
-| "aa"
-
-#data
-<wbr><strike><code></strike><code><strike></code>
-#errors
-Line: 1 Col: 5 Unexpected start tag (wbr). Expected DOCTYPE.
-Line: 1 Col: 28 End tag (strike) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 49 Unexpected end tag (code). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <wbr>
-| <strike>
-| <code>
-| <code>
-| <code>
-| <strike>
-
-#data
-<!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.
-#document
-| <html>
-| <head>
-| <title>
-| "<meta>"
-| <link>
-| <title>
-| "<meta>"
-| <body>
-
-#data
-<style><!--</style><meta><script>--><link></script>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 51 Unexpected end of file. Expected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| "<!--"
-| <meta>
-| <script>
-| "--><link>"
-| <body>
-
-#data
-<head><meta></head><link>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 25 Unexpected start tag (link) that can be in head. Moved.
-#document
-| <html>
-| <head>
-| <meta>
-| <link>
-| <body>
-
-#data
-<table><tr><tr><td><td><span><th><span>X</table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 33 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 48 Got table cell end tag (th) while required end tags are missing.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <tr>
-| <td>
-| <td>
-| <span>
-| <th>
-| <span>
-| "X"
-
-#data
-<body><body><base><link><meta><title><p></title><body><p></body>
-#errors
-Line: 1 Col: 6 Unexpected start tag (body). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected start tag (body).
-Line: 1 Col: 54 Unexpected start tag (body).
-Line: 1 Col: 64 Unexpected end tag (p). Missing end tag (body).
-#document
-| <html>
-| <head>
-| <body>
-| <base>
-| <link>
-| <meta>
-| <title>
-| "<p>"
-| <p>
-
-#data
-<textarea><p></textarea>
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "<p>"
-
-#data
-<p><image></p>
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 10 Unexpected start tag (image). Treated as img.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <img>
-
-#data
-<a><table><a></table><p><a><div><a>
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 13 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 13 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 21 Unexpected end tag (table). Expected end tag (a).
-Line: 1 Col: 27 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 27 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
-Line: 1 Col: 32 Unexpected end tag (p). Ignored.
-Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 35 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
-Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <a>
-| <table>
-| <p>
-| <a>
-| <div>
-| <a>
-
-#data
-<head></p><meta><p>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 10 Unexpected end tag (p). Ignored.
-#document
-| <html>
-| <head>
-| <meta>
-| <body>
-| <p>
-
-#data
-<head></html><meta><p>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 19 Unexpected start tag (meta).
-#document
-| <html>
-| <head>
-| <body>
-| <meta>
-| <p>
-
-#data
-<b><table><td><i></table>
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 25 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <i>
-
-#data
-<b><table><td></b><i></table>
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 18 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 29 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <i>
-
-#data
-<h1><h2>
-#errors
-4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-8: Heading cannot be a child of another heading.
-8: End of file seen and there were open elements.
-#document
-| <html>
-| <head>
-| <body>
-| <h1>
-| <h2>
-
-#data
-<a><p><a></a></p></a>
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 9 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 9 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 21 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <p>
-| <a>
-| <a>
-
-#data
-<b><button></b></button></b>
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <button>
-| <b>
-
-#data
-<p><b><div><marquee></p></b></div>
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end tag (p). Ignored.
-Line: 1 Col: 24 Unexpected end tag (p). Ignored.
-Line: 1 Col: 28 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 34 End tag (div) seen too early. Expected other end tag.
-Line: 1 Col: 34 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| <div>
-| <b>
-| <marquee>
-| <p>
-
-#data
-<script></script></div><title></title><p><p>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end tag (div). Ignored.
-#document
-| <html>
-| <head>
-| <script>
-| <title>
-| <body>
-| <p>
-| <p>
-
-#data
-<p><hr></p>
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end tag (p). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <hr>
-| <p>
-
-#data
-<select><b><option><select><option></b></select>
-#errors
-Line: 1 Col: 8 Unexpected start tag (select). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected start tag token (b) in the select phase. Ignored.
-Line: 1 Col: 27 Unexpected select start tag in the select phase treated as select end tag.
-Line: 1 Col: 39 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 48 Unexpected end tag (select). Ignored.
-Line: 1 Col: 48 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| <option>
-
-#data
-<html><head><title></title><body></body></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <title>
-| <body>
-
-#data
-<a><table><td><a><table></table><a></tr><a></table><a>
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 35 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 40 Got table cell end tag (td) while required end tags are missing.
-Line: 1 Col: 43 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 43 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 43 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 51 Unexpected implied end tag (a) in the table phase.
-Line: 1 Col: 54 Unexpected start tag (a) implies end tag (a).
-Line: 1 Col: 54 End tag (a) violates step 1, paragraph 2 of the adoption agency algorithm.
-Line: 1 Col: 54 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <a>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <a>
-| <table>
-| <a>
-| <a>
-
-#data
-<ul><li></li><div><li></div><li><li><div><li><address><li><b><em></b><li></ul>
-#errors
-Line: 1 Col: 4 Unexpected start tag (ul). Expected DOCTYPE.
-Line: 1 Col: 45 Missing end tag (div, li).
-Line: 1 Col: 58 Missing end tag (address, li).
-Line: 1 Col: 69 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-#document
-| <html>
-| <head>
-| <body>
-| <ul>
-| <li>
-| <div>
-| <li>
-| <li>
-| <li>
-| <div>
-| <li>
-| <address>
-| <li>
-| <b>
-| <em>
-| <li>
-
-#data
-<ul><li><ul></li><li>a</li></ul></li></ul>
-#errors
-XXX: fix me
-#document
-| <html>
-| <head>
-| <body>
-| <ul>
-| <li>
-| <ul>
-| <li>
-| "a"
-
-#data
-<frameset><frame><frameset><frame></frameset><noframes></noframes></frameset>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <frameset>
-| <frame>
-| <frameset>
-| <frame>
-| <noframes>
-
-#data
-<h1><table><td><h3></table><h3></h1>
-#errors
-4: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-15: “td” start tag in table body.
-27: Unclosed elements.
-31: Heading cannot be a child of another heading.
-36: End tag “h1” seen but there were unclosed elements.
-#document
-| <html>
-| <head>
-| <body>
-| <h1>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <h3>
-| <h3>
-
-#data
-<table><colgroup><col><colgroup><col><col><col><colgroup><col><col><thead><tr><td></table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <colgroup>
-| <col>
-| <colgroup>
-| <col>
-| <col>
-| <col>
-| <colgroup>
-| <col>
-| <col>
-| <thead>
-| <tr>
-| <td>
-
-#data
-<table><col><tbody><col><tr><col><td><col></table><col>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 37 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 55 Unexpected start tag col. Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <colgroup>
-| <col>
-| <tbody>
-| <colgroup>
-| <col>
-| <tbody>
-| <tr>
-| <colgroup>
-| <col>
-| <tbody>
-| <tr>
-| <td>
-| <colgroup>
-| <col>
-
-#data
-<table><colgroup><tbody><colgroup><tr><colgroup><td><colgroup></table><colgroup>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 52 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 80 Unexpected start tag colgroup. Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <colgroup>
-| <tbody>
-| <colgroup>
-| <tbody>
-| <tr>
-| <colgroup>
-| <tbody>
-| <tr>
-| <td>
-| <colgroup>
-
-#data
-</strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
-#errors
-Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
-Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
-Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
-Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
-Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
-Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
-Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
-Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
-Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
-Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
-Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
-Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
-Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
-Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
-Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
-Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
-Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
-Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
-Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
-Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
-Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
-Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
-Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
-Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 140 This element (img) has no end tag.
-Line: 1 Col: 148 Unexpected end tag (title). Ignored.
-Line: 1 Col: 155 Unexpected end tag (span). Ignored.
-Line: 1 Col: 163 Unexpected end tag (style). Ignored.
-Line: 1 Col: 172 Unexpected end tag (script). Ignored.
-Line: 1 Col: 180 Unexpected end tag (table). Ignored.
-Line: 1 Col: 185 Unexpected end tag (th). Ignored.
-Line: 1 Col: 190 Unexpected end tag (td). Ignored.
-Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
-Line: 1 Col: 203 This element (frame) has no end tag.
-Line: 1 Col: 210 This element (area) has no end tag.
-Line: 1 Col: 217 Unexpected end tag (link). Ignored.
-Line: 1 Col: 225 This element (param) has no end tag.
-Line: 1 Col: 230 This element (hr) has no end tag.
-Line: 1 Col: 238 This element (input) has no end tag.
-Line: 1 Col: 244 Unexpected end tag (col). Ignored.
-Line: 1 Col: 251 Unexpected end tag (base). Ignored.
-Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
-Line: 1 Col: 269 This element (basefont) has no end tag.
-Line: 1 Col: 279 This element (bgsound) has no end tag.
-Line: 1 Col: 287 This element (embed) has no end tag.
-Line: 1 Col: 296 This element (spacer) has no end tag.
-Line: 1 Col: 300 Unexpected end tag (p). Ignored.
-Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
-Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
-Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
-Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
-Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
-Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
-Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
-Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
-Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
-Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
-Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
-Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
-Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
-Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
-Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
-Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
-Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 460 This element (wbr) has no end tag.
-Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
-Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
-Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
-Line: 1 Col: 513 Unexpected end tag (html). Ignored.
-Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
-Line: 1 Col: 520 Unexpected end tag (head). Ignored.
-Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
-Line: 1 Col: 537 This element (image) has no end tag.
-Line: 1 Col: 547 This element (isindex) has no end tag.
-Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
-Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
-Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
-Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
-Line: 1 Col: 599 Unexpected end tag (option). Ignored.
-Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
-Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <br>
-| <p>
-
-#data
-<table><tr></strong></b></em></i></u></strike></s></blink></tt></pre></big></small></font></select></h1></h2></h3></h4></h5></h6></body></br></a></img></title></span></style></script></table></th></td></tr></frame></area></link></param></hr></input></col></base></meta></basefont></bgsound></embed></spacer></p></dd></dt></caption></colgroup></tbody></tfoot></thead></address></blockquote></center></dir></div></dl></fieldset></listing></menu></ol></ul></li></nobr></wbr></form></button></marquee></object></html></frameset></head></iframe></image></isindex></noembed></noframes></noscript></optgroup></option></plaintext></textarea>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode.
-Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode.
-Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode.
-Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode.
-Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode.
-Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode.
-Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode.
-Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode.
-Line: 1 Col: 58 Unexpected end tag (blink). Ignored.
-Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode.
-Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode.
-Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag.
-Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode.
-Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode.
-Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode.
-Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode.
-Line: 1 Col: 99 Unexpected end tag (select). Ignored.
-Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode.
-Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag.
-Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode.
-Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag.
-Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode.
-Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag.
-Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode.
-Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag.
-Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode.
-Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag.
-Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode.
-Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag.
-Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored.
-Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode.
-Line: 1 Col: 141 Unexpected end tag (br). Treated as br element.
-Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode.
-Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode.
-Line: 1 Col: 151 This element (img) has no end tag.
-Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode.
-Line: 1 Col: 159 Unexpected end tag (title). Ignored.
-Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode.
-Line: 1 Col: 166 Unexpected end tag (span). Ignored.
-Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode.
-Line: 1 Col: 174 Unexpected end tag (style). Ignored.
-Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode.
-Line: 1 Col: 183 Unexpected end tag (script). Ignored.
-Line: 1 Col: 196 Unexpected end tag (th). Ignored.
-Line: 1 Col: 201 Unexpected end tag (td). Ignored.
-Line: 1 Col: 206 Unexpected end tag (tr). Ignored.
-Line: 1 Col: 214 This element (frame) has no end tag.
-Line: 1 Col: 221 This element (area) has no end tag.
-Line: 1 Col: 228 Unexpected end tag (link). Ignored.
-Line: 1 Col: 236 This element (param) has no end tag.
-Line: 1 Col: 241 This element (hr) has no end tag.
-Line: 1 Col: 249 This element (input) has no end tag.
-Line: 1 Col: 255 Unexpected end tag (col). Ignored.
-Line: 1 Col: 262 Unexpected end tag (base). Ignored.
-Line: 1 Col: 269 Unexpected end tag (meta). Ignored.
-Line: 1 Col: 280 This element (basefont) has no end tag.
-Line: 1 Col: 290 This element (bgsound) has no end tag.
-Line: 1 Col: 298 This element (embed) has no end tag.
-Line: 1 Col: 307 This element (spacer) has no end tag.
-Line: 1 Col: 311 Unexpected end tag (p). Ignored.
-Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag.
-Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag.
-Line: 1 Col: 331 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored.
-Line: 1 Col: 350 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 366 Unexpected end tag (thead). Ignored.
-Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag.
-Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag.
-Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag.
-Line: 1 Col: 404 Unexpected end tag (dir). Ignored.
-Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag.
-Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag.
-Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag.
-Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag.
-Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag.
-Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag.
-Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag.
-Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag.
-Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
-Line: 1 Col: 471 This element (wbr) has no end tag.
-Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag.
-Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag.
-Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag.
-Line: 1 Col: 524 Unexpected end tag (html). Ignored.
-Line: 1 Col: 524 Unexpected end tag (frameset). Ignored.
-Line: 1 Col: 531 Unexpected end tag (head). Ignored.
-Line: 1 Col: 540 Unexpected end tag (iframe). Ignored.
-Line: 1 Col: 548 This element (image) has no end tag.
-Line: 1 Col: 558 This element (isindex) has no end tag.
-Line: 1 Col: 568 Unexpected end tag (noembed). Ignored.
-Line: 1 Col: 579 Unexpected end tag (noframes). Ignored.
-Line: 1 Col: 590 Unexpected end tag (noscript). Ignored.
-Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored.
-Line: 1 Col: 610 Unexpected end tag (option). Ignored.
-Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored.
-Line: 1 Col: 633 Unexpected end tag (textarea). Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| <br>
-| <table>
-| <tbody>
-| <tr>
-| <p>
-
-#data
-<frameset>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 1 Col: 10 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <frameset>
diff --git a/src/pkg/html/testdata/webkit/tests10.dat b/src/pkg/html/testdata/webkit/tests10.dat
deleted file mode 100644
index 4f8df86f2..000000000
--- a/src/pkg/html/testdata/webkit/tests10.dat
+++ /dev/null
@@ -1,799 +0,0 @@
-#data
-<!DOCTYPE html><svg></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <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
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-
-#data
-<!DOCTYPE html><body><select><svg></svg></select>
-#errors
-35: Stray “svg” start tag.
-42: Stray end tag “svg”
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!DOCTYPE html><body><select><option><svg></svg></option></select>
-#errors
-43: Stray “svg” start tag.
-50: Stray end tag “svg”
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-
-#data
-<!DOCTYPE html><body><table><svg></svg></table>
-#errors
-34: Start tag “svg” seen in “table”.
-41: Stray end tag “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <table>
-
-#data
-<!DOCTYPE html><body><table><svg><g>foo</g></svg></table>
-#errors
-34: Start tag “svg” seen in “table”.
-46: Stray end tag “g”.
-53: Stray end tag “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <table>
-
-#data
-<!DOCTYPE html><body><table><svg><g>foo</g><g>bar</g></svg></table>
-#errors
-34: Start tag “svg” seen in “table”.
-46: Stray end tag “g”.
-58: Stray end tag “g”.
-65: Stray end tag “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <table>
-
-#data
-<!DOCTYPE html><body><table><tbody><svg><g>foo</g><g>bar</g></svg></tbody></table>
-#errors
-41: Start tag “svg” seen in “table”.
-53: Stray end tag “g”.
-65: Stray end tag “g”.
-72: Stray end tag “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <table>
-| <tbody>
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><svg><g>foo</g><g>bar</g></svg></tr></tbody></table>
-#errors
-45: Start tag “svg” seen in “table”.
-57: Stray end tag “g”.
-69: Stray end tag “g”.
-76: Stray end tag “svg”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg></td></tr></tbody></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><td><svg><g>foo</g><g>bar</g></svg><p>baz</td></tr></tbody></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g></svg><p>baz</caption></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
-#errors
-70: HTML start tag “p” in a foreign namespace context.
-81: “table” closed but “caption” was still open.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><caption><svg><g>foo</g><g>bar</g>baz</table><p>quux
-#errors
-78: “table” closed but “caption” was still open.
-78: Unclosed elements on stack.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| "baz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><colgroup><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
-#errors
-44: Start tag “svg” seen in “table”.
-56: Stray end tag “g”.
-68: Stray end tag “g”.
-71: HTML start tag “p” in a foreign namespace context.
-71: Start tag “p” seen in “table”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-| <table>
-| <colgroup>
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><tr><td><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
-#errors
-50: Stray “svg” start tag.
-54: Stray “g” start tag.
-62: Stray end tag “g”
-66: Stray “g” start tag.
-74: Stray end tag “g”
-77: Stray “p” start tag.
-88: “table” end tag with “select” open.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <select>
-| "foobarbaz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><select><svg><g>foo</g><g>bar</g><p>baz</table><p>quux
-#errors
-36: Start tag “select” seen in “table”.
-42: Stray “svg” start tag.
-46: Stray “g” start tag.
-54: Stray end tag “g”
-58: Stray “g” start tag.
-66: Stray end tag “g”
-69: Stray “p” start tag.
-80: “table” end tag with “select” open.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| "foobarbaz"
-| <table>
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body></body></html><svg><g>foo</g><g>bar</g><p>baz
-#errors
-41: Stray “svg” start tag.
-68: HTML start tag “p” in a foreign namespace context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body></body><svg><g>foo</g><g>bar</g><p>baz
-#errors
-34: Stray “svg” start tag.
-61: HTML start tag “p” in a foreign namespace context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg g>
-| "foo"
-| <svg g>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><frameset><svg><g></g><g></g><p><span>
-#errors
-31: Stray “svg” start tag.
-35: Stray “g” start tag.
-40: Stray end tag “g”
-44: Stray “g” start tag.
-49: Stray end tag “g”
-52: Stray “p” start tag.
-58: Stray “span” start tag.
-58: End of file seen and there were open elements.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><frameset></frameset><svg><g></g><g></g><p><span>
-#errors
-42: Stray “svg” start tag.
-46: Stray “g” start tag.
-51: Stray end tag “g”
-55: Stray “g” start tag.
-60: Stray end tag “g”
-63: Stray “p” start tag.
-69: Stray “span” start tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><body xlink:href=foo><svg xlink:href=foo></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| <svg svg>
-| xlink href="foo"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo></g></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <svg svg>
-| <svg g>
-| xlink href="foo"
-| xml lang="en"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo /></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <svg svg>
-| <svg g>
-| xlink href="foo"
-| xml lang="en"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><svg><g xml:lang=en xlink:href=foo />bar</svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <svg svg>
-| <svg g>
-| xlink href="foo"
-| xml lang="en"
-| "bar"
-
-#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/src/pkg/html/testdata/webkit/tests11.dat b/src/pkg/html/testdata/webkit/tests11.dat
deleted file mode 100644
index 638cde479..000000000
--- a/src/pkg/html/testdata/webkit/tests11.dat
+++ /dev/null
@@ -1,482 +0,0 @@
-#data
-<!DOCTYPE html><body><svg attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| attributeName=""
-| attributeType=""
-| baseFrequency=""
-| baseProfile=""
-| calcMode=""
-| clipPathUnits=""
-| contentScriptType=""
-| contentStyleType=""
-| diffuseConstant=""
-| edgeMode=""
-| externalResourcesRequired=""
-| filterRes=""
-| filterUnits=""
-| glyphRef=""
-| gradientTransform=""
-| gradientUnits=""
-| kernelMatrix=""
-| kernelUnitLength=""
-| keyPoints=""
-| keySplines=""
-| keyTimes=""
-| lengthAdjust=""
-| limitingConeAngle=""
-| markerHeight=""
-| markerUnits=""
-| markerWidth=""
-| maskContentUnits=""
-| maskUnits=""
-| numOctaves=""
-| pathLength=""
-| patternContentUnits=""
-| patternTransform=""
-| patternUnits=""
-| pointsAtX=""
-| pointsAtY=""
-| pointsAtZ=""
-| preserveAlpha=""
-| preserveAspectRatio=""
-| primitiveUnits=""
-| refX=""
-| refY=""
-| repeatCount=""
-| repeatDur=""
-| requiredExtensions=""
-| requiredFeatures=""
-| specularConstant=""
-| specularExponent=""
-| spreadMethod=""
-| startOffset=""
-| stdDeviation=""
-| stitchTiles=""
-| surfaceScale=""
-| systemLanguage=""
-| tableValues=""
-| targetX=""
-| targetY=""
-| textLength=""
-| viewBox=""
-| viewTarget=""
-| xChannelSelector=""
-| yChannelSelector=""
-| zoomAndPan=""
-
-#data
-<!DOCTYPE html><BODY><SVG ATTRIBUTENAME='' ATTRIBUTETYPE='' BASEFREQUENCY='' BASEPROFILE='' CALCMODE='' CLIPPATHUNITS='' CONTENTSCRIPTTYPE='' CONTENTSTYLETYPE='' DIFFUSECONSTANT='' EDGEMODE='' EXTERNALRESOURCESREQUIRED='' FILTERRES='' FILTERUNITS='' GLYPHREF='' GRADIENTTRANSFORM='' GRADIENTUNITS='' KERNELMATRIX='' KERNELUNITLENGTH='' KEYPOINTS='' KEYSPLINES='' KEYTIMES='' LENGTHADJUST='' LIMITINGCONEANGLE='' MARKERHEIGHT='' MARKERUNITS='' MARKERWIDTH='' MASKCONTENTUNITS='' MASKUNITS='' NUMOCTAVES='' PATHLENGTH='' PATTERNCONTENTUNITS='' PATTERNTRANSFORM='' PATTERNUNITS='' POINTSATX='' POINTSATY='' POINTSATZ='' PRESERVEALPHA='' PRESERVEASPECTRATIO='' PRIMITIVEUNITS='' REFX='' REFY='' REPEATCOUNT='' REPEATDUR='' REQUIREDEXTENSIONS='' REQUIREDFEATURES='' SPECULARCONSTANT='' SPECULAREXPONENT='' SPREADMETHOD='' STARTOFFSET='' STDDEVIATION='' STITCHTILES='' SURFACESCALE='' SYSTEMLANGUAGE='' TABLEVALUES='' TARGETX='' TARGETY='' TEXTLENGTH='' VIEWBOX='' VIEWTARGET='' XCHANNELSELECTOR='' YCHANNELSELECTOR='' ZOOMANDPAN=''></SVG>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| attributeName=""
-| attributeType=""
-| baseFrequency=""
-| baseProfile=""
-| calcMode=""
-| clipPathUnits=""
-| contentScriptType=""
-| contentStyleType=""
-| diffuseConstant=""
-| edgeMode=""
-| externalResourcesRequired=""
-| filterRes=""
-| filterUnits=""
-| glyphRef=""
-| gradientTransform=""
-| gradientUnits=""
-| kernelMatrix=""
-| kernelUnitLength=""
-| keyPoints=""
-| keySplines=""
-| keyTimes=""
-| lengthAdjust=""
-| limitingConeAngle=""
-| markerHeight=""
-| markerUnits=""
-| markerWidth=""
-| maskContentUnits=""
-| maskUnits=""
-| numOctaves=""
-| pathLength=""
-| patternContentUnits=""
-| patternTransform=""
-| patternUnits=""
-| pointsAtX=""
-| pointsAtY=""
-| pointsAtZ=""
-| preserveAlpha=""
-| preserveAspectRatio=""
-| primitiveUnits=""
-| refX=""
-| refY=""
-| repeatCount=""
-| repeatDur=""
-| requiredExtensions=""
-| requiredFeatures=""
-| specularConstant=""
-| specularExponent=""
-| spreadMethod=""
-| startOffset=""
-| stdDeviation=""
-| stitchTiles=""
-| surfaceScale=""
-| systemLanguage=""
-| tableValues=""
-| targetX=""
-| targetY=""
-| textLength=""
-| viewBox=""
-| viewTarget=""
-| xChannelSelector=""
-| yChannelSelector=""
-| zoomAndPan=""
-
-#data
-<!DOCTYPE html><body><svg attributename='' attributetype='' basefrequency='' baseprofile='' calcmode='' clippathunits='' contentscripttype='' contentstyletype='' diffuseconstant='' edgemode='' externalresourcesrequired='' filterres='' filterunits='' glyphref='' gradienttransform='' gradientunits='' kernelmatrix='' kernelunitlength='' keypoints='' keysplines='' keytimes='' lengthadjust='' limitingconeangle='' markerheight='' markerunits='' markerwidth='' maskcontentunits='' maskunits='' numoctaves='' pathlength='' patterncontentunits='' patterntransform='' patternunits='' pointsatx='' pointsaty='' pointsatz='' preservealpha='' preserveaspectratio='' primitiveunits='' refx='' refy='' repeatcount='' repeatdur='' requiredextensions='' requiredfeatures='' specularconstant='' specularexponent='' spreadmethod='' startoffset='' stddeviation='' stitchtiles='' surfacescale='' systemlanguage='' tablevalues='' targetx='' targety='' textlength='' viewbox='' viewtarget='' xchannelselector='' ychannelselector='' zoomandpan=''></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| attributeName=""
-| attributeType=""
-| baseFrequency=""
-| baseProfile=""
-| calcMode=""
-| clipPathUnits=""
-| contentScriptType=""
-| contentStyleType=""
-| diffuseConstant=""
-| edgeMode=""
-| externalResourcesRequired=""
-| filterRes=""
-| filterUnits=""
-| glyphRef=""
-| gradientTransform=""
-| gradientUnits=""
-| kernelMatrix=""
-| kernelUnitLength=""
-| keyPoints=""
-| keySplines=""
-| keyTimes=""
-| lengthAdjust=""
-| limitingConeAngle=""
-| markerHeight=""
-| markerUnits=""
-| markerWidth=""
-| maskContentUnits=""
-| maskUnits=""
-| numOctaves=""
-| pathLength=""
-| patternContentUnits=""
-| patternTransform=""
-| patternUnits=""
-| pointsAtX=""
-| pointsAtY=""
-| pointsAtZ=""
-| preserveAlpha=""
-| preserveAspectRatio=""
-| primitiveUnits=""
-| refX=""
-| refY=""
-| repeatCount=""
-| repeatDur=""
-| requiredExtensions=""
-| requiredFeatures=""
-| specularConstant=""
-| specularExponent=""
-| spreadMethod=""
-| startOffset=""
-| stdDeviation=""
-| stitchTiles=""
-| surfaceScale=""
-| systemLanguage=""
-| tableValues=""
-| targetX=""
-| targetY=""
-| textLength=""
-| viewBox=""
-| viewTarget=""
-| xChannelSelector=""
-| yChannelSelector=""
-| zoomAndPan=""
-
-#data
-<!DOCTYPE html><body><math attributeName='' attributeType='' baseFrequency='' baseProfile='' calcMode='' clipPathUnits='' contentScriptType='' contentStyleType='' diffuseConstant='' edgeMode='' externalResourcesRequired='' filterRes='' filterUnits='' glyphRef='' gradientTransform='' gradientUnits='' kernelMatrix='' kernelUnitLength='' keyPoints='' keySplines='' keyTimes='' lengthAdjust='' limitingConeAngle='' markerHeight='' markerUnits='' markerWidth='' maskContentUnits='' maskUnits='' numOctaves='' pathLength='' patternContentUnits='' patternTransform='' patternUnits='' pointsAtX='' pointsAtY='' pointsAtZ='' preserveAlpha='' preserveAspectRatio='' primitiveUnits='' refX='' refY='' repeatCount='' repeatDur='' requiredExtensions='' requiredFeatures='' specularConstant='' specularExponent='' spreadMethod='' startOffset='' stdDeviation='' stitchTiles='' surfaceScale='' systemLanguage='' tableValues='' targetX='' targetY='' textLength='' viewBox='' viewTarget='' xChannelSelector='' yChannelSelector='' zoomAndPan=''></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| attributename=""
-| attributetype=""
-| basefrequency=""
-| baseprofile=""
-| calcmode=""
-| clippathunits=""
-| contentscripttype=""
-| contentstyletype=""
-| diffuseconstant=""
-| edgemode=""
-| externalresourcesrequired=""
-| filterres=""
-| filterunits=""
-| glyphref=""
-| gradienttransform=""
-| gradientunits=""
-| kernelmatrix=""
-| kernelunitlength=""
-| keypoints=""
-| keysplines=""
-| keytimes=""
-| lengthadjust=""
-| limitingconeangle=""
-| markerheight=""
-| markerunits=""
-| markerwidth=""
-| maskcontentunits=""
-| maskunits=""
-| numoctaves=""
-| pathlength=""
-| patterncontentunits=""
-| patterntransform=""
-| patternunits=""
-| pointsatx=""
-| pointsaty=""
-| pointsatz=""
-| preservealpha=""
-| preserveaspectratio=""
-| primitiveunits=""
-| refx=""
-| refy=""
-| repeatcount=""
-| repeatdur=""
-| requiredextensions=""
-| requiredfeatures=""
-| specularconstant=""
-| specularexponent=""
-| spreadmethod=""
-| startoffset=""
-| stddeviation=""
-| stitchtiles=""
-| surfacescale=""
-| systemlanguage=""
-| tablevalues=""
-| targetx=""
-| targety=""
-| textlength=""
-| viewbox=""
-| viewtarget=""
-| xchannelselector=""
-| ychannelselector=""
-| zoomandpan=""
-
-#data
-<!DOCTYPE html><body><svg><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg altGlyph>
-| <svg altGlyphDef>
-| <svg altGlyphItem>
-| <svg animateColor>
-| <svg animateMotion>
-| <svg animateTransform>
-| <svg clipPath>
-| <svg feBlend>
-| <svg feColorMatrix>
-| <svg feComponentTransfer>
-| <svg feComposite>
-| <svg feConvolveMatrix>
-| <svg feDiffuseLighting>
-| <svg feDisplacementMap>
-| <svg feDistantLight>
-| <svg feFlood>
-| <svg feFuncA>
-| <svg feFuncB>
-| <svg feFuncG>
-| <svg feFuncR>
-| <svg feGaussianBlur>
-| <svg feImage>
-| <svg feMerge>
-| <svg feMergeNode>
-| <svg feMorphology>
-| <svg feOffset>
-| <svg fePointLight>
-| <svg feSpecularLighting>
-| <svg feSpotLight>
-| <svg feTile>
-| <svg feTurbulence>
-| <svg foreignObject>
-| <svg glyphRef>
-| <svg linearGradient>
-| <svg radialGradient>
-| <svg textPath>
-
-#data
-<!DOCTYPE html><body><svg><altglyph /><altglyphdef /><altglyphitem /><animatecolor /><animatemotion /><animatetransform /><clippath /><feblend /><fecolormatrix /><fecomponenttransfer /><fecomposite /><feconvolvematrix /><fediffuselighting /><fedisplacementmap /><fedistantlight /><feflood /><fefunca /><fefuncb /><fefuncg /><fefuncr /><fegaussianblur /><feimage /><femerge /><femergenode /><femorphology /><feoffset /><fepointlight /><fespecularlighting /><fespotlight /><fetile /><feturbulence /><foreignobject /><glyphref /><lineargradient /><radialgradient /><textpath /></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg altGlyph>
-| <svg altGlyphDef>
-| <svg altGlyphItem>
-| <svg animateColor>
-| <svg animateMotion>
-| <svg animateTransform>
-| <svg clipPath>
-| <svg feBlend>
-| <svg feColorMatrix>
-| <svg feComponentTransfer>
-| <svg feComposite>
-| <svg feConvolveMatrix>
-| <svg feDiffuseLighting>
-| <svg feDisplacementMap>
-| <svg feDistantLight>
-| <svg feFlood>
-| <svg feFuncA>
-| <svg feFuncB>
-| <svg feFuncG>
-| <svg feFuncR>
-| <svg feGaussianBlur>
-| <svg feImage>
-| <svg feMerge>
-| <svg feMergeNode>
-| <svg feMorphology>
-| <svg feOffset>
-| <svg fePointLight>
-| <svg feSpecularLighting>
-| <svg feSpotLight>
-| <svg feTile>
-| <svg feTurbulence>
-| <svg foreignObject>
-| <svg glyphRef>
-| <svg linearGradient>
-| <svg radialGradient>
-| <svg textPath>
-
-#data
-<!DOCTYPE html><BODY><SVG><ALTGLYPH /><ALTGLYPHDEF /><ALTGLYPHITEM /><ANIMATECOLOR /><ANIMATEMOTION /><ANIMATETRANSFORM /><CLIPPATH /><FEBLEND /><FECOLORMATRIX /><FECOMPONENTTRANSFER /><FECOMPOSITE /><FECONVOLVEMATRIX /><FEDIFFUSELIGHTING /><FEDISPLACEMENTMAP /><FEDISTANTLIGHT /><FEFLOOD /><FEFUNCA /><FEFUNCB /><FEFUNCG /><FEFUNCR /><FEGAUSSIANBLUR /><FEIMAGE /><FEMERGE /><FEMERGENODE /><FEMORPHOLOGY /><FEOFFSET /><FEPOINTLIGHT /><FESPECULARLIGHTING /><FESPOTLIGHT /><FETILE /><FETURBULENCE /><FOREIGNOBJECT /><GLYPHREF /><LINEARGRADIENT /><RADIALGRADIENT /><TEXTPATH /></SVG>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg altGlyph>
-| <svg altGlyphDef>
-| <svg altGlyphItem>
-| <svg animateColor>
-| <svg animateMotion>
-| <svg animateTransform>
-| <svg clipPath>
-| <svg feBlend>
-| <svg feColorMatrix>
-| <svg feComponentTransfer>
-| <svg feComposite>
-| <svg feConvolveMatrix>
-| <svg feDiffuseLighting>
-| <svg feDisplacementMap>
-| <svg feDistantLight>
-| <svg feFlood>
-| <svg feFuncA>
-| <svg feFuncB>
-| <svg feFuncG>
-| <svg feFuncR>
-| <svg feGaussianBlur>
-| <svg feImage>
-| <svg feMerge>
-| <svg feMergeNode>
-| <svg feMorphology>
-| <svg feOffset>
-| <svg fePointLight>
-| <svg feSpecularLighting>
-| <svg feSpotLight>
-| <svg feTile>
-| <svg feTurbulence>
-| <svg foreignObject>
-| <svg glyphRef>
-| <svg linearGradient>
-| <svg radialGradient>
-| <svg textPath>
-
-#data
-<!DOCTYPE html><body><math><altGlyph /><altGlyphDef /><altGlyphItem /><animateColor /><animateMotion /><animateTransform /><clipPath /><feBlend /><feColorMatrix /><feComponentTransfer /><feComposite /><feConvolveMatrix /><feDiffuseLighting /><feDisplacementMap /><feDistantLight /><feFlood /><feFuncA /><feFuncB /><feFuncG /><feFuncR /><feGaussianBlur /><feImage /><feMerge /><feMergeNode /><feMorphology /><feOffset /><fePointLight /><feSpecularLighting /><feSpotLight /><feTile /><feTurbulence /><foreignObject /><glyphRef /><linearGradient /><radialGradient /><textPath /></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math altglyph>
-| <math altglyphdef>
-| <math altglyphitem>
-| <math animatecolor>
-| <math animatemotion>
-| <math animatetransform>
-| <math clippath>
-| <math feblend>
-| <math fecolormatrix>
-| <math fecomponenttransfer>
-| <math fecomposite>
-| <math feconvolvematrix>
-| <math fediffuselighting>
-| <math fedisplacementmap>
-| <math fedistantlight>
-| <math feflood>
-| <math fefunca>
-| <math fefuncb>
-| <math fefuncg>
-| <math fefuncr>
-| <math fegaussianblur>
-| <math feimage>
-| <math femerge>
-| <math femergenode>
-| <math femorphology>
-| <math feoffset>
-| <math fepointlight>
-| <math fespecularlighting>
-| <math fespotlight>
-| <math fetile>
-| <math feturbulence>
-| <math foreignobject>
-| <math glyphref>
-| <math lineargradient>
-| <math radialgradient>
-| <math textpath>
-
-#data
-<!DOCTYPE html><body><svg><solidColor /></svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg solidcolor>
diff --git a/src/pkg/html/testdata/webkit/tests12.dat b/src/pkg/html/testdata/webkit/tests12.dat
deleted file mode 100644
index 63107d277..000000000
--- a/src/pkg/html/testdata/webkit/tests12.dat
+++ /dev/null
@@ -1,62 +0,0 @@
-#data
-<!DOCTYPE html><body><p>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| "foo"
-| <math math>
-| <math mtext>
-| <i>
-| "baz"
-| <math annotation-xml>
-| <svg svg>
-| <svg desc>
-| <b>
-| "eggs"
-| <svg g>
-| <svg foreignObject>
-| <p>
-| "spam"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <img>
-| <svg g>
-| "quux"
-| "bar"
-
-#data
-<!DOCTYPE html><body>foo<math><mtext><i>baz</i></mtext><annotation-xml><svg><desc><b>eggs</b></desc><g><foreignObject><P>spam<TABLE><tr><td><img></td></table></foreignObject></g><g>quux</g></svg></annotation-xml></math>bar
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "foo"
-| <math math>
-| <math mtext>
-| <i>
-| "baz"
-| <math annotation-xml>
-| <svg svg>
-| <svg desc>
-| <b>
-| "eggs"
-| <svg g>
-| <svg foreignObject>
-| <p>
-| "spam"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <img>
-| <svg g>
-| "quux"
-| "bar"
diff --git a/src/pkg/html/testdata/webkit/tests14.dat b/src/pkg/html/testdata/webkit/tests14.dat
deleted file mode 100644
index b8713f885..000000000
--- a/src/pkg/html/testdata/webkit/tests14.dat
+++ /dev/null
@@ -1,74 +0,0 @@
-#data
-<!DOCTYPE html><html><body><xyz:abc></xyz:abc>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <xyz:abc>
-
-#data
-<!DOCTYPE html><html><body><xyz:abc></xyz:abc><span></span>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <xyz:abc>
-| <span>
-
-#data
-<!DOCTYPE html><html><html abc:def=gh><xyz:abc></xyz:abc>
-#errors
-15: Unexpected start tag html
-#document
-| <!DOCTYPE html>
-| <html>
-| abc:def="gh"
-| <head>
-| <body>
-| <xyz:abc>
-
-#data
-<!DOCTYPE html><html xml:lang=bar><html xml:lang=foo>
-#errors
-15: Unexpected start tag html
-#document
-| <!DOCTYPE html>
-| <html>
-| xml:lang="bar"
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><html 123=456>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| 123="456"
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><html 123=456><html 789=012>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| 123="456"
-| 789="012"
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><html><body 789=012>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| 789="012"
diff --git a/src/pkg/html/testdata/webkit/tests15.dat b/src/pkg/html/testdata/webkit/tests15.dat
deleted file mode 100644
index 6ce1c0d16..000000000
--- a/src/pkg/html/testdata/webkit/tests15.dat
+++ /dev/null
@@ -1,208 +0,0 @@
-#data
-<!DOCTYPE html><p><b><i><u></p> <p>X
-#errors
-Line: 1 Col: 31 Unexpected end tag (p). Ignored.
-Line: 1 Col: 36 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| <i>
-| <u>
-| <b>
-| <i>
-| <u>
-| " "
-| <p>
-| "X"
-
-#data
-<p><b><i><u></p>
-<p>X
-#errors
-Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected end tag (p). Ignored.
-Line: 2 Col: 4 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| <i>
-| <u>
-| <b>
-| <i>
-| <u>
-| "
-"
-| <p>
-| "X"
-
-#data
-<!doctype html></html> <head>
-#errors
-Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " "
-
-#data
-<!doctype html></body><meta>
-#errors
-Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <meta>
-
-#data
-<html></html><!-- foo -->
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element.
-#document
-| <html>
-| <head>
-| <body>
-| <!-- foo -->
-
-#data
-<!doctype html></body><title>X</title>
-#errors
-Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <title>
-| "X"
-
-#data
-<!doctype html><table> X<meta></table>
-#errors
-Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " X"
-| <meta>
-| <table>
-
-#data
-<!doctype html><table> x</table>
-#errors
-Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " x"
-| <table>
-
-#data
-<!doctype html><table> x </table>
-#errors
-Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " x "
-| <table>
-
-#data
-<!doctype html><table><tr> x</table>
-#errors
-Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " x"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><table>X<style> <tr>x </style> </table>
-#errors
-Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-| <table>
-| <style>
-| " <tr>x "
-| " "
-
-#data
-<!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div>
-#errors
-Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode.
-Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <div>
-| <a>
-| "foo"
-| <table>
-| " "
-| <tbody>
-| <tr>
-| <td>
-| "bar"
-| " "
-
-#data
-<frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes>
-#errors
-6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-13: Stray start tag “frame”.
-21: Stray end tag “frame”.
-29: Stray end tag “frame”.
-39: “frameset” start tag after “body” already open.
-105: End of file seen inside an [R]CDATA element.
-105: End of file seen and there were open elements.
-XXX: These errors are wrong, please fix me!
-#document
-| <html>
-| <head>
-| <frameset>
-| <frame>
-| <frameset>
-| <frame>
-| <noframes>
-| "</frameset><noframes>"
-
-#data
-<!DOCTYPE html><object></html>
-#errors
-1: Expected closing tag. Unexpected end of file
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <object>
diff --git a/src/pkg/html/testdata/webkit/tests16.dat b/src/pkg/html/testdata/webkit/tests16.dat
deleted file mode 100644
index 937dba9f4..000000000
--- a/src/pkg/html/testdata/webkit/tests16.dat
+++ /dev/null
@@ -1,2277 +0,0 @@
-#data
-<!doctype html><script>
-#errors
-Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<!doctype html><script>a
-#errors
-Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "a"
-| <body>
-
-#data
-<!doctype html><script><
-#errors
-Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<"
-| <body>
-
-#data
-<!doctype html><script></
-#errors
-Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</"
-| <body>
-
-#data
-<!doctype html><script></S
-#errors
-Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</S"
-| <body>
-
-#data
-<!doctype html><script></SC
-#errors
-Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</SC"
-| <body>
-
-#data
-<!doctype html><script></SCR
-#errors
-Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</SCR"
-| <body>
-
-#data
-<!doctype html><script></SCRI
-#errors
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</SCRI"
-| <body>
-
-#data
-<!doctype html><script></SCRIP
-#errors
-Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</SCRIP"
-| <body>
-
-#data
-<!doctype html><script></SCRIPT
-#errors
-Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</SCRIPT"
-| <body>
-
-#data
-<!doctype html><script></SCRIPT
-#errors
-Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<!doctype html><script></s
-#errors
-Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</s"
-| <body>
-
-#data
-<!doctype html><script></sc
-#errors
-Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</sc"
-| <body>
-
-#data
-<!doctype html><script></scr
-#errors
-Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</scr"
-| <body>
-
-#data
-<!doctype html><script></scri
-#errors
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</scri"
-| <body>
-
-#data
-<!doctype html><script></scrip
-#errors
-Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</scrip"
-| <body>
-
-#data
-<!doctype html><script></script
-#errors
-Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "</script"
-| <body>
-
-#data
-<!doctype html><script></script
-#errors
-Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<!doctype html><script><!
-#errors
-Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!"
-| <body>
-
-#data
-<!doctype html><script><!a
-#errors
-Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!a"
-| <body>
-
-#data
-<!doctype html><script><!-
-#errors
-Line: 1 Col: 26 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!-"
-| <body>
-
-#data
-<!doctype html><script><!-a
-#errors
-Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!-a"
-| <body>
-
-#data
-<!doctype html><script><!--
-#errors
-Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--"
-| <body>
-
-#data
-<!doctype html><script><!--a
-#errors
-Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--a"
-| <body>
-
-#data
-<!doctype html><script><!--<
-#errors
-Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<"
-| <body>
-
-#data
-<!doctype html><script><!--<a
-#errors
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<a"
-| <body>
-
-#data
-<!doctype html><script><!--</
-#errors
-Line: 1 Col: 27 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--</"
-| <body>
-
-#data
-<!doctype html><script><!--</script
-#errors
-Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--</script"
-| <body>
-
-#data
-<!doctype html><script><!--</script
-#errors
-Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--"
-| <body>
-
-#data
-<!doctype html><script><!--<s
-#errors
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<s"
-| <body>
-
-#data
-<!doctype html><script><!--<script
-#errors
-Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script"
-| <body>
-
-#data
-<!doctype html><script><!--<script
-#errors
-Line: 1 Col: 35 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script "
-| <body>
-
-#data
-<!doctype html><script><!--<script <
-#errors
-Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script <"
-| <body>
-
-#data
-<!doctype html><script><!--<script <a
-#errors
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script <a"
-| <body>
-
-#data
-<!doctype html><script><!--<script </
-#errors
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </"
-| <body>
-
-#data
-<!doctype html><script><!--<script </s
-#errors
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </s"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script
-#errors
-Line: 1 Col: 43 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script"
-| <body>
-
-#data
-<!doctype html><script><!--<script </scripta
-#errors
-Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </scripta"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script
-#errors
-Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<!doctype html><script><!--<script </script>
-#errors
-Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script>"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script/
-#errors
-Line: 1 Col: 44 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script/"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script <
-#errors
-Line: 1 Col: 45 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script <"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script <a
-#errors
-Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script <a"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script </
-#errors
-Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script </"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script </script
-#errors
-Line: 1 Col: 52 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script </script"
-| <body>
-
-#data
-<!doctype html><script><!--<script </script </script
-#errors
-Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<!doctype html><script><!--<script </script </script/
-#errors
-Line: 1 Col: 53 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<!doctype html><script><!--<script </script </script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<!doctype html><script><!--<script -
-#errors
-Line: 1 Col: 36 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -"
-| <body>
-
-#data
-<!doctype html><script><!--<script -a
-#errors
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -a"
-| <body>
-
-#data
-<!doctype html><script><!--<script -<
-#errors
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -<"
-| <body>
-
-#data
-<!doctype html><script><!--<script --
-#errors
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --"
-| <body>
-
-#data
-<!doctype html><script><!--<script --a
-#errors
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --a"
-| <body>
-
-#data
-<!doctype html><script><!--<script --<
-#errors
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --<"
-| <body>
-
-#data
-<!doctype html><script><!--<script -->
-#errors
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<!doctype html><script><!--<script --><
-#errors
-Line: 1 Col: 39 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --><"
-| <body>
-
-#data
-<!doctype html><script><!--<script --></
-#errors
-Line: 1 Col: 40 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --></"
-| <body>
-
-#data
-<!doctype html><script><!--<script --></script
-#errors
-Line: 1 Col: 46 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script --></script"
-| <body>
-
-#data
-<!doctype html><script><!--<script --></script
-#errors
-Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<!doctype html><script><!--<script --></script/
-#errors
-Line: 1 Col: 47 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<!doctype html><script><!--<script --></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<!doctype html><script><!--<script><\/script>--></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script><\/script>-->"
-| <body>
-
-#data
-<!doctype html><script><!--<script></scr'+'ipt>--></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></scr'+'ipt>-->"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script>--><!--</script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>--><!--"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script>-- ></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>-- >"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script>- -></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>- ->"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script>- - ></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>- - >"
-| <body>
-
-#data
-<!doctype html><script><!--<script></script><script></script>-></script>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>->"
-| <body>
-
-#data
-<!doctype html><script><!--<script>--!></script>X
-#errors
-Line: 1 Col: 49 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script>--!></script>X"
-| <body>
-
-#data
-<!doctype html><script><!--<scr'+'ipt></script>--></script>
-#errors
-Line: 1 Col: 59 Unexpected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<scr'+'ipt>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><script><!--<script></scr'+'ipt></script>X
-#errors
-Line: 1 Col: 57 Unexpected end of file. Expected end tag (script).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "<!--<script></scr'+'ipt></script>X"
-| <body>
-
-#data
-<!doctype html><style><!--<style></style>--></style>
-#errors
-Line: 1 Col: 52 Unexpected end tag (style).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--<style>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><style><!--</style>X
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--"
-| <body>
-| "X"
-
-#data
-<!doctype html><style><!--...</style>...--></style>
-#errors
-Line: 1 Col: 51 Unexpected end tag (style).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--..."
-| <body>
-| "...-->"
-
-#data
-<!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
-| <body>
-| "X"
-
-#data
-<!doctype html><style><!--...<style><!--...--!></style>--></style>
-#errors
-Line: 1 Col: 66 Unexpected end tag (style).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--...<style><!--...--!>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><style><!--...</style><!-- --><style>@import ...</style>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "<!--..."
-| <!-- -->
-| <style>
-| "@import ..."
-| <body>
-
-#data
-<!doctype html><style>...<style><!--...</style><!-- --></style>
-#errors
-Line: 1 Col: 63 Unexpected end tag (style).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "...<style><!--..."
-| <!-- -->
-| <body>
-
-#data
-<!doctype html><style>...<!--[if IE]><style>...</style>X
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <style>
-| "...<!--[if IE]><style>..."
-| <body>
-| "X"
-
-#data
-<!doctype html><title><!--<title></title>--></title>
-#errors
-Line: 1 Col: 52 Unexpected end tag (title).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "<!--<title>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><title>&lt;/title></title>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "</title>"
-| <body>
-
-#data
-<!doctype html><title>foo/title><link></head><body>X
-#errors
-Line: 1 Col: 52 Unexpected end of file. Expected end tag (title).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "foo/title><link></head><body>X"
-| <body>
-
-#data
-<!doctype html><noscript><!--<noscript></noscript>--></noscript>
-#errors
-Line: 1 Col: 64 Unexpected end tag (noscript).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <noscript>
-| "<!--<noscript>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><noscript><!--</noscript>X<noscript>--></noscript>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <noscript>
-| "<!--"
-| <body>
-| "X"
-| <noscript>
-| "-->"
-
-#data
-<!doctype html><noscript><iframe></noscript>X
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <noscript>
-| "<iframe>"
-| <body>
-| "X"
-
-#data
-<!doctype html><noframes><!--<noframes></noframes>--></noframes>
-#errors
-Line: 1 Col: 64 Unexpected end tag (noframes).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <noframes>
-| "<!--<noframes>"
-| <body>
-| "-->"
-
-#data
-<!doctype html><noframes><body><script><!--...</script></body></noframes></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <noframes>
-| "<body><script><!--...</script></body>"
-| <body>
-
-#data
-<!doctype html><textarea><!--<textarea></textarea>--></textarea>
-#errors
-Line: 1 Col: 64 Unexpected end tag (textarea).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "<!--<textarea>"
-| "-->"
-
-#data
-<!doctype html><textarea>&lt;/textarea></textarea>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "</textarea>"
-
-#data
-<!doctype html><iframe><!--<iframe></iframe>--></iframe>
-#errors
-Line: 1 Col: 56 Unexpected end tag (iframe).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <iframe>
-| "<!--<iframe>"
-| "-->"
-
-#data
-<!doctype html><iframe>...<!--X->...<!--/X->...</iframe>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <iframe>
-| "...<!--X->...<!--/X->..."
-
-#data
-<!doctype html><xmp><!--<xmp></xmp>--></xmp>
-#errors
-Line: 1 Col: 44 Unexpected end tag (xmp).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <xmp>
-| "<!--<xmp>"
-| "-->"
-
-#data
-<!doctype html><noembed><!--<noembed></noembed>--></noembed>
-#errors
-Line: 1 Col: 60 Unexpected end tag (noembed).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <noembed>
-| "<!--<noembed>"
-| "-->"
-
-#data
-<script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 8 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<script>a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "a"
-| <body>
-
-#data
-<script><
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 9 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<"
-| <body>
-
-#data
-<script></
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</"
-| <body>
-
-#data
-<script></S
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</S"
-| <body>
-
-#data
-<script></SC
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</SC"
-| <body>
-
-#data
-<script></SCR
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</SCR"
-| <body>
-
-#data
-<script></SCRI
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</SCRI"
-| <body>
-
-#data
-<script></SCRIP
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</SCRIP"
-| <body>
-
-#data
-<script></SCRIPT
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</SCRIPT"
-| <body>
-
-#data
-<script></SCRIPT
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<script></s
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</s"
-| <body>
-
-#data
-<script></sc
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</sc"
-| <body>
-
-#data
-<script></scr
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</scr"
-| <body>
-
-#data
-<script></scri
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</scri"
-| <body>
-
-#data
-<script></scrip
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 15 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</scrip"
-| <body>
-
-#data
-<script></script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</script"
-| <body>
-
-#data
-<script></script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 17 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<script><!
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 10 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!"
-| <body>
-
-#data
-<script><!a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!a"
-| <body>
-
-#data
-<script><!-
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!-"
-| <body>
-
-#data
-<script><!-a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!-a"
-| <body>
-
-#data
-<script><!--
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--"
-| <body>
-
-#data
-<script><!--a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--a"
-| <body>
-
-#data
-<script><!--<
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<"
-| <body>
-
-#data
-<script><!--<a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<a"
-| <body>
-
-#data
-<script><!--</
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--</"
-| <body>
-
-#data
-<script><!--</script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--</script"
-| <body>
-
-#data
-<script><!--</script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--"
-| <body>
-
-#data
-<script><!--<s
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<s"
-| <body>
-
-#data
-<script><!--<script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 19 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script"
-| <body>
-
-#data
-<script><!--<script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script "
-| <body>
-
-#data
-<script><!--<script <
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script <"
-| <body>
-
-#data
-<script><!--<script <a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script <a"
-| <body>
-
-#data
-<script><!--<script </
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </"
-| <body>
-
-#data
-<script><!--<script </s
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </s"
-| <body>
-
-#data
-<script><!--<script </script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 28 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script"
-| <body>
-
-#data
-<script><!--<script </scripta
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </scripta"
-| <body>
-
-#data
-<script><!--<script </script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<script><!--<script </script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script>"
-| <body>
-
-#data
-<script><!--<script </script/
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 29 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script/"
-| <body>
-
-#data
-<script><!--<script </script <
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 30 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script <"
-| <body>
-
-#data
-<script><!--<script </script <a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script <a"
-| <body>
-
-#data
-<script><!--<script </script </
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script </"
-| <body>
-
-#data
-<script><!--<script </script </script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script </script"
-| <body>
-
-#data
-<script><!--<script </script </script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<script><!--<script </script </script/
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 38 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<script><!--<script </script </script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script </script "
-| <body>
-
-#data
-<script><!--<script -
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 21 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -"
-| <body>
-
-#data
-<script><!--<script -a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -a"
-| <body>
-
-#data
-<script><!--<script --
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script --"
-| <body>
-
-#data
-<script><!--<script --a
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script --a"
-| <body>
-
-#data
-<script><!--<script -->
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<script><!--<script --><
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 24 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script --><"
-| <body>
-
-#data
-<script><!--<script --></
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 25 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script --></"
-| <body>
-
-#data
-<script><!--<script --></script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 31 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script --></script"
-| <body>
-
-#data
-<script><!--<script --></script
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<script><!--<script --></script/
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 32 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<script><!--<script --></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script -->"
-| <body>
-
-#data
-<script><!--<script><\/script>--></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script><\/script>-->"
-| <body>
-
-#data
-<script><!--<script></scr'+'ipt>--></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></scr'+'ipt>-->"
-| <body>
-
-#data
-<script><!--<script></script><script></script></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>"
-| <body>
-
-#data
-<script><!--<script></script><script></script>--><!--</script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>--><!--"
-| <body>
-
-#data
-<script><!--<script></script><script></script>-- ></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>-- >"
-| <body>
-
-#data
-<script><!--<script></script><script></script>- -></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>- ->"
-| <body>
-
-#data
-<script><!--<script></script><script></script>- - ></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>- - >"
-| <body>
-
-#data
-<script><!--<script></script><script></script>-></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></script><script></script>->"
-| <body>
-
-#data
-<script><!--<script>--!></script>X
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 34 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script>--!></script>X"
-| <body>
-
-#data
-<script><!--<scr'+'ipt></script>--></script>
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 44 Unexpected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<scr'+'ipt>"
-| <body>
-| "-->"
-
-#data
-<script><!--<script></scr'+'ipt></script>X
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 42 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "<!--<script></scr'+'ipt></script>X"
-| <body>
-
-#data
-<style><!--<style></style>--></style>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 37 Unexpected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| "<!--<style>"
-| <body>
-| "-->"
-
-#data
-<style><!--</style>X
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| "<!--"
-| <body>
-| "X"
-
-#data
-<style><!--...</style>...--></style>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 36 Unexpected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| "<!--..."
-| <body>
-| "...-->"
-
-#data
-<style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>"
-| <body>
-| "X"
-
-#data
-<style><!--...<style><!--...--!></style>--></style>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 51 Unexpected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| "<!--...<style><!--...--!>"
-| <body>
-| "-->"
-
-#data
-<style><!--...</style><!-- --><style>@import ...</style>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| "<!--..."
-| <!-- -->
-| <style>
-| "@import ..."
-| <body>
-
-#data
-<style>...<style><!--...</style><!-- --></style>
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 48 Unexpected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| "...<style><!--..."
-| <!-- -->
-| <body>
-
-#data
-<style>...<!--[if IE]><style>...</style>X
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| "...<!--[if IE]><style>..."
-| <body>
-| "X"
-
-#data
-<title><!--<title></title>--></title>
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-Line: 1 Col: 37 Unexpected end tag (title).
-#document
-| <html>
-| <head>
-| <title>
-| "<!--<title>"
-| <body>
-| "-->"
-
-#data
-<title>&lt;/title></title>
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <title>
-| "</title>"
-| <body>
-
-#data
-<title>foo/title><link></head><body>X
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-Line: 1 Col: 37 Unexpected end of file. Expected end tag (title).
-#document
-| <html>
-| <head>
-| <title>
-| "foo/title><link></head><body>X"
-| <body>
-
-#data
-<noscript><!--<noscript></noscript>--></noscript>
-#errors
-Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
-Line: 1 Col: 49 Unexpected end tag (noscript).
-#document
-| <html>
-| <head>
-| <noscript>
-| "<!--<noscript>"
-| <body>
-| "-->"
-
-#data
-<noscript><!--</noscript>X<noscript>--></noscript>
-#errors
-Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <noscript>
-| "<!--"
-| <body>
-| "X"
-| <noscript>
-| "-->"
-
-#data
-<noscript><iframe></noscript>X
-#errors
-Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <noscript>
-| "<iframe>"
-| <body>
-| "X"
-
-#data
-<noframes><!--<noframes></noframes>--></noframes>
-#errors
-Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
-Line: 1 Col: 49 Unexpected end tag (noframes).
-#document
-| <html>
-| <head>
-| <noframes>
-| "<!--<noframes>"
-| <body>
-| "-->"
-
-#data
-<noframes><body><script><!--...</script></body></noframes></html>
-#errors
-Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <noframes>
-| "<body><script><!--...</script></body>"
-| <body>
-
-#data
-<textarea><!--<textarea></textarea>--></textarea>
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-Line: 1 Col: 49 Unexpected end tag (textarea).
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "<!--<textarea>"
-| "-->"
-
-#data
-<textarea>&lt;/textarea></textarea>
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "</textarea>"
-
-#data
-<iframe><!--<iframe></iframe>--></iframe>
-#errors
-Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
-Line: 1 Col: 41 Unexpected end tag (iframe).
-#document
-| <html>
-| <head>
-| <body>
-| <iframe>
-| "<!--<iframe>"
-| "-->"
-
-#data
-<iframe>...<!--X->...<!--/X->...</iframe>
-#errors
-Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <iframe>
-| "...<!--X->...<!--/X->..."
-
-#data
-<xmp><!--<xmp></xmp>--></xmp>
-#errors
-Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
-Line: 1 Col: 29 Unexpected end tag (xmp).
-#document
-| <html>
-| <head>
-| <body>
-| <xmp>
-| "<!--<xmp>"
-| "-->"
-
-#data
-<noembed><!--<noembed></noembed>--></noembed>
-#errors
-Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE.
-Line: 1 Col: 45 Unexpected end tag (noembed).
-#document
-| <html>
-| <head>
-| <body>
-| <noembed>
-| "<!--<noembed>"
-| "-->"
-
-#data
-<!doctype html><table>
-
-#errors
-Line 2 Col 0 Unexpected end of file. Expected table content.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| "
-"
-
-#data
-<!doctype html><table><td><span><font></span><span>
-#errors
-Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase.
-Line 1 Col 45 Unexpected end tag (span).
-Line 1 Col 51 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <span>
-| <font>
-| <font>
-| <span>
-
-#data
-<!doctype html><form><table></form><form></table></form>
-#errors
-35: Stray end tag “form”.
-41: Start tag “form” seen in “table”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <table>
-| <form>
diff --git a/src/pkg/html/testdata/webkit/tests17.dat b/src/pkg/html/testdata/webkit/tests17.dat
deleted file mode 100644
index 7b555f888..000000000
--- a/src/pkg/html/testdata/webkit/tests17.dat
+++ /dev/null
@@ -1,153 +0,0 @@
-#data
-<!doctype html><table><tbody><select><tr>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><table><tr><select><td>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<!doctype html><table><tr><td><select><td>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <select>
-| <td>
-
-#data
-<!doctype html><table><tr><th><select><td>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <th>
-| <select>
-| <td>
-
-#data
-<!doctype html><table><caption><select><tr>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <select>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><select><tr>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><td>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><th>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><tbody>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><thead>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><tfoot>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><select><caption>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><table><tr></table>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| "a"
diff --git a/src/pkg/html/testdata/webkit/tests18.dat b/src/pkg/html/testdata/webkit/tests18.dat
deleted file mode 100644
index 680e1f068..000000000
--- a/src/pkg/html/testdata/webkit/tests18.dat
+++ /dev/null
@@ -1,269 +0,0 @@
-#data
-<!doctype html><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-
-#data
-<!doctype html><table><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-| <table>
-
-#data
-<!doctype html><table><tbody><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-| <table>
-| <tbody>
-
-#data
-<!doctype html><table><tbody><tr><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><table><tbody><tr><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><table><td><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <plaintext>
-| "</plaintext>"
-
-#data
-<!doctype html><table><caption><plaintext></plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <plaintext>
-| "</plaintext>"
-
-#data
-<!doctype html><table><tr><style></script></style>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "abc"
-| <table>
-| <tbody>
-| <tr>
-| <style>
-| "</script>"
-
-#data
-<!doctype html><table><tr><script></style></script>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "abc"
-| <table>
-| <tbody>
-| <tr>
-| <script>
-| "</style>"
-
-#data
-<!doctype html><table><caption><style></script></style>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <style>
-| "</script>"
-| "abc"
-
-#data
-<!doctype html><table><td><style></script></style>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <style>
-| "</script>"
-| "abc"
-
-#data
-<!doctype html><select><script></style></script>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <script>
-| "</style>"
-| "abc"
-
-#data
-<!doctype html><table><select><script></style></script>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <script>
-| "</style>"
-| "abc"
-| <table>
-
-#data
-<!doctype html><table><tr><select><script></style></script>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <script>
-| "</style>"
-| "abc"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><frameset></frameset><noframes>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <noframes>
-| "abc"
-
-#data
-<!doctype html><frameset></frameset><noframes>abc</noframes><!--abc-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <noframes>
-| "abc"
-| <!-- abc -->
-
-#data
-<!doctype html><frameset></frameset></html><noframes>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <noframes>
-| "abc"
-
-#data
-<!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <noframes>
-| "abc"
-| <!-- abc -->
-
-#data
-<!doctype html><table><tr></tbody><tfoot>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <tfoot>
-
-#data
-<!doctype html><table><td><svg></svg>abc<td>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <svg svg>
-| "abc"
-| <td>
diff --git a/src/pkg/html/testdata/webkit/tests19.dat b/src/pkg/html/testdata/webkit/tests19.dat
deleted file mode 100644
index 06222f5b9..000000000
--- a/src/pkg/html/testdata/webkit/tests19.dat
+++ /dev/null
@@ -1,1220 +0,0 @@
-#data
-<!doctype html><math><mn DefinitionUrl="foo">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mn>
-| definitionURL="foo"
-
-#data
-<!doctype html><html></p><!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <!-- foo -->
-| <head>
-| <body>
-
-#data
-<!doctype html><head></head></p><!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <!-- foo -->
-| <body>
-
-#data
-<!doctype html><body><p><pre>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <pre>
-
-#data
-<!doctype html><body><p><listing>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <listing>
-
-#data
-<!doctype html><p><plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <plaintext>
-
-#data
-<!doctype html><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <h1>
-
-#data
-<!doctype html><form><isindex>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-
-#data
-<!doctype html><isindex action="POST">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| action="POST"
-| <hr>
-| <label>
-| "This is a searchable index. Enter search keywords: "
-| <input>
-| name="isindex"
-| <hr>
-
-#data
-<!doctype html><isindex prompt="this is isindex">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <hr>
-| <label>
-| "this is isindex"
-| <input>
-| name="isindex"
-| <hr>
-
-#data
-<!doctype html><isindex type="hidden">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <hr>
-| <label>
-| "This is a searchable index. Enter search keywords: "
-| <input>
-| name="isindex"
-| type="hidden"
-| <hr>
-
-#data
-<!doctype html><isindex name="foo">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <hr>
-| <label>
-| "This is a searchable index. Enter search keywords: "
-| <input>
-| name="isindex"
-| <hr>
-
-#data
-<!doctype html><ruby><p><rp>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <p>
-| <rp>
-
-#data
-<!doctype html><ruby><div><span><rp>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <div>
-| <span>
-| <rp>
-
-#data
-<!doctype html><ruby><div><p><rp>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <div>
-| <p>
-| <rp>
-
-#data
-<!doctype html><ruby><p><rt>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <p>
-| <rt>
-
-#data
-<!doctype html><ruby><div><span><rt>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <div>
-| <span>
-| <rt>
-
-#data
-<!doctype html><ruby><div><p><rt>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ruby>
-| <div>
-| <p>
-| <rt>
-
-#data
-<!doctype html><math/><foo>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <foo>
-
-#data
-<!doctype html><svg/><foo>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <foo>
-
-#data
-<!doctype html><div></body><!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <div>
-| <!-- foo -->
-
-#data
-<!doctype html><h1><div><h3><span></h1>foo
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <h1>
-| <div>
-| <h3>
-| <span>
-| "foo"
-
-#data
-<!doctype html><p></h3>foo
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| "foo"
-
-#data
-<!doctype html><h3><li>abc</h2>foo
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <h3>
-| <li>
-| "abc"
-| "foo"
-
-#data
-<!doctype html><table>abc<!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "abc"
-| <table>
-| <!-- foo -->
-
-#data
-<!doctype html><table> <!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| " "
-| <!-- foo -->
-
-#data
-<!doctype html><table> b <!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| " b "
-| <table>
-| <!-- foo -->
-
-#data
-<!doctype html><select><option><option>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| <option>
-
-#data
-<!doctype html><select><option></optgroup>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-
-#data
-<!doctype html><select><option></optgroup>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-
-#data
-<!doctype html><p><math><mi><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math mi>
-| <p>
-| <h1>
-
-#data
-<!doctype html><p><math><mo><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math mo>
-| <p>
-| <h1>
-
-#data
-<!doctype html><p><math><mn><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math mn>
-| <p>
-| <h1>
-
-#data
-<!doctype html><p><math><ms><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math ms>
-| <p>
-| <h1>
-
-#data
-<!doctype html><p><math><mtext><p><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math mtext>
-| <p>
-| <h1>
-
-#data
-<!doctype html><frameset></noframes>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!doctype html><html c=d><body></html><html a=b>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| a="b"
-| c="d"
-| <head>
-| <body>
-
-#data
-<!doctype html><html c=d><frameset></frameset></html><html a=b>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| a="b"
-| c="d"
-| <head>
-| <frameset>
-
-#data
-<!doctype html><html><frameset></frameset></html><!--foo-->
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <!-- foo -->
-
-#data
-<!doctype html><html><frameset></frameset></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| " "
-
-#data
-<!doctype html><html><frameset></frameset></html>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!doctype html><html><frameset></frameset></html><p>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!doctype html><html><frameset></frameset></html></p>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<html><frameset></frameset></html><!doctype html>
-#errors
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!doctype html><body><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<!doctype html><p><frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<!doctype html><p>a<frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| "a"
-
-#data
-<!doctype html><p> <frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<!doctype html><pre><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-
-#data
-<!doctype html><listing><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <listing>
-
-#data
-<!doctype html><li><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <li>
-
-#data
-<!doctype html><dd><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <dd>
-
-#data
-<!doctype html><dt><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <dt>
-
-#data
-<!doctype html><button><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <button>
-
-#data
-<!doctype html><applet><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <applet>
-
-#data
-<!doctype html><marquee><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <marquee>
-
-#data
-<!doctype html><object><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <object>
-
-#data
-<!doctype html><table><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-
-#data
-<!doctype html><area><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <area>
-
-#data
-<!doctype html><basefont><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <basefont>
-| <frameset>
-
-#data
-<!doctype html><bgsound><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <bgsound>
-| <frameset>
-
-#data
-<!doctype html><br><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <br>
-
-#data
-<!doctype html><embed><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <embed>
-
-#data
-<!doctype html><img><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <img>
-
-#data
-<!doctype html><input><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <input>
-
-#data
-<!doctype html><keygen><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <keygen>
-
-#data
-<!doctype html><wbr><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <wbr>
-
-#data
-<!doctype html><hr><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <hr>
-
-#data
-<!doctype html><textarea></textarea><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-
-#data
-<!doctype html><xmp></xmp><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <xmp>
-
-#data
-<!doctype html><iframe></iframe><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <iframe>
-
-#data
-<!doctype html><select></select><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!doctype html><svg></svg><frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<!doctype html><math></math><frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<!doctype html><svg><foreignObject><div> <frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<!doctype html><svg>a</svg><frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "a"
-
-#data
-<!doctype html><svg> </svg><frameset><frame>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-| <frame>
-
-#data
-<html>aaa<frameset></frameset>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "aaa"
-
-#data
-<html> a <frameset></frameset>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "a "
-
-#data
-<!doctype html><div><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!doctype html><div><body><frameset>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <div>
-
-#data
-<!doctype html><p><math></p>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| "a"
-
-#data
-<!doctype html><p><math><mn><span></p>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <math math>
-| <math mn>
-| <span>
-| <p>
-| "a"
-
-#data
-<!doctype html><math></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-
-#data
-<!doctype html><meta charset="ascii">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <meta>
-| charset="ascii"
-| <body>
-
-#data
-<!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <meta>
-| content="text/html;charset=ascii"
-| http-equiv="content-type"
-| <body>
-
-#data
-<!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8">
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -->
-| <meta>
-| charset="utf8"
-| <body>
-
-#data
-<!doctype html><html a=b><head></head><html c=d>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| a="b"
-| c="d"
-| <head>
-| <body>
-
-#data
-<!doctype html><image/>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <img>
-
-#data
-<!doctype html>a<i>b<table>c<b>d</i>e</b>f
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "a"
-| <i>
-| "bc"
-| <b>
-| "de"
-| "f"
-| <table>
-
-#data
-<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <i>
-| "a"
-| <b>
-| "b"
-| <b>
-| <div>
-| <b>
-| <i>
-| "c"
-| <a>
-| "d"
-| <a>
-| "e"
-| <a>
-| "f"
-| <table>
-
-#data
-<!doctype html><i>a<b>b<div>c<a>d</i>e</b>f
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <i>
-| "a"
-| <b>
-| "b"
-| <b>
-| <div>
-| <b>
-| <i>
-| "c"
-| <a>
-| "d"
-| <a>
-| "e"
-| <a>
-| "f"
-
-#data
-<!doctype html><table><i>a<b>b<div>c</i>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <i>
-| "a"
-| <b>
-| "b"
-| <b>
-| <div>
-| <i>
-| "c"
-| <table>
-
-#data
-<!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <i>
-| "a"
-| <b>
-| "b"
-| <b>
-| <div>
-| <b>
-| <i>
-| "c"
-| <a>
-| "d"
-| <a>
-| "e"
-| <a>
-| "f"
-| <table>
-
-#data
-<!doctype html><table><i>a<div>b<tr>c<b>d</i>e
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <i>
-| "a"
-| <div>
-| "b"
-| <i>
-| "c"
-| <b>
-| "d"
-| <b>
-| "e"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><table><td><table><i>a<div>b<b>c</i>d
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <i>
-| "a"
-| <div>
-| <i>
-| "b"
-| <b>
-| "c"
-| <b>
-| "d"
-| <table>
-
-#data
-<!doctype html><body><bgsound>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <bgsound>
-
-#data
-<!doctype html><body><basefont>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <basefont>
-
-#data
-<!doctype html><a><b></a><basefont>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <basefont>
-
-#data
-<!doctype html><a><b></a><bgsound>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <bgsound>
-
-#data
-<!doctype html><figcaption><article></figcaption>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <figcaption>
-| <article>
-| "a"
-
-#data
-<!doctype html><summary><article></summary>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <summary>
-| <article>
-| "a"
-
-#data
-<!doctype html><p><a><plaintext>b
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <a>
-| <plaintext>
-| <a>
-| "b"
diff --git a/src/pkg/html/testdata/webkit/tests2.dat b/src/pkg/html/testdata/webkit/tests2.dat
deleted file mode 100644
index 60d859221..000000000
--- a/src/pkg/html/testdata/webkit/tests2.dat
+++ /dev/null
@@ -1,763 +0,0 @@
-#data
-<!DOCTYPE html>Test
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "Test"
-
-#data
-<textarea>test</div>test
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-Line: 1 Col: 24 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "test</div>test"
-
-#data
-<table><td>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 11 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><td>test</tbody></table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "test"
-
-#data
-<frame>test
-#errors
-Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE.
-Line: 1 Col: 7 Unexpected start tag frame. Ignored.
-#document
-| <html>
-| <head>
-| <body>
-| "test"
-
-#data
-<!DOCTYPE html><frameset>test
-#errors
-Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored.
-Line: 1 Col: 29 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><frameset><!DOCTYPE html>
-#errors
-Line: 1 Col: 40 Unexpected DOCTYPE. Ignored.
-Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><font><p><b>test</font>
-#errors
-Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <font>
-| <p>
-| <font>
-| <b>
-| "test"
-
-#data
-<!DOCTYPE html><dt><div><dd>
-#errors
-Line: 1 Col: 28 Missing end tag (div, dt).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <dt>
-| <div>
-| <dd>
-
-#data
-<script></x
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-Line: 1 Col: 11 Unexpected end of file. Expected end tag (script).
-#document
-| <html>
-| <head>
-| <script>
-| "</x"
-| <body>
-
-#data
-<table><plaintext><td>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode.
-Line: 1 Col: 22 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "<td>"
-| <table>
-
-#data
-<plaintext></plaintext>
-#errors
-Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE.
-Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <plaintext>
-| "</plaintext>"
-
-#data
-<!DOCTYPE html><table><tr>TEST
-#errors
-Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 30 Unexpected end of file. Expected table content.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "TEST"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4>
-#errors
-Line: 1 Col: 37 Unexpected start tag (body).
-Line: 1 Col: 53 Unexpected start tag (body).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| t1="1"
-| t2="2"
-| t3="3"
-| t4="4"
-
-#data
-</b test
-#errors
-Line: 1 Col: 8 Unexpected end of file in attribute name.
-Line: 1 Col: 8 End tag contains unexpected attributes.
-Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE.
-Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html></b test<b &=&amp>X
-#errors
-Line: 1 Col: 32 Named entity didn't end with ';'.
-Line: 1 Col: 33 End tag contains unexpected attributes.
-Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-
-#data
-<!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-Line: 1 Col: 54 Unexpected end of file in the tag name.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| type="text/x-foobar;baz"
-| "X</SCRipt"
-| <body>
-
-#data
-&
-#errors
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&"
-
-#data
-&#
-#errors
-Line: 1 Col: 1 Numeric entity expected. Got end of file instead.
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&#"
-
-#data
-&#X
-#errors
-Line: 1 Col: 3 Numeric entity expected but none found.
-Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&#X"
-
-#data
-&#x
-#errors
-Line: 1 Col: 3 Numeric entity expected but none found.
-Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&#x"
-
-#data
-&#45
-#errors
-Line: 1 Col: 4 Numeric entity didn't end with ';'.
-Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "-"
-
-#data
-&x-test
-#errors
-Line: 1 Col: 1 Named entity expected. Got none.
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&x-test"
-
-#data
-<!doctypehtml><p><li>
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <li>
-
-#data
-<!doctypehtml><p><dt>
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <dt>
-
-#data
-<!doctypehtml><p><dd>
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <dd>
-
-#data
-<!doctypehtml><p><form>
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <form>
-
-#data
-<!DOCTYPE html><p></P>X
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| "X"
-
-#data
-&AMP
-#errors
-Line: 1 Col: 4 Named entity didn't end with ';'.
-Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&"
-
-#data
-&AMp;
-#errors
-Line: 1 Col: 1 Named entity expected. Got none.
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "&AMp;"
-
-#data
-<!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY>
-#errors
-Line: 1 Col: 110 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly>
-
-#data
-<!DOCTYPE html>X</body>X
-#errors
-Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "XX"
-
-#data
-<!DOCTYPE html><!-- X
-#errors
-Line: 1 Col: 21 Unexpected end of file in comment.
-#document
-| <!DOCTYPE html>
-| <!-- X -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><table><caption>test TEST</caption><td>test
-#errors
-Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| "test TEST"
-| <tbody>
-| <tr>
-| <td>
-| "test"
-
-#data
-<!DOCTYPE html><select><option><optgroup>
-#errors
-Line: 1 Col: 41 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-| <optgroup>
-
-#data
-<!DOCTYPE html><select><optgroup><option></optgroup><option><select><option>
-#errors
-Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag.
-Line: 1 Col: 76 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <optgroup>
-| <option>
-| <option>
-| <option>
-
-#data
-<!DOCTYPE html><select><optgroup><option><optgroup>
-#errors
-Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <optgroup>
-| <option>
-| <optgroup>
-
-#data
-<!DOCTYPE html><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
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <font>
-| <input>
-| <input>
-
-#data
-<!DOCTYPE html><!-- XXX - XXX -->
-#errors
-#document
-| <!DOCTYPE html>
-| <!-- XXX - XXX -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><!-- XXX - XXX
-#errors
-Line: 1 Col: 29 Unexpected end of file in comment (-)
-#document
-| <!DOCTYPE html>
-| <!-- XXX - XXX -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><!-- XXX - XXX - XXX -->
-#errors
-#document
-| <!DOCTYPE html>
-| <!-- XXX - XXX - XXX -->
-| <html>
-| <head>
-| <body>
-
-#data
-<isindex test=x name=x>
-#errors
-Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
-#document
-| <html>
-| <head>
-| <body>
-| <form>
-| <hr>
-| <label>
-| "This is a searchable index. Enter search keywords: "
-| <input>
-| name="isindex"
-| test="x"
-| <hr>
-
-#data
-test
-test
-#errors
-Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "test
-test"
-
-#data
-<!DOCTYPE html><body><title>test</body></title>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <title>
-| "test</body>"
-
-#data
-<!DOCTYPE html><body><title>X</title><meta name=z><link rel=foo><style>
-x { content:"</style" } </style>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <title>
-| "X"
-| <meta>
-| name="z"
-| <link>
-| rel="foo"
-| <style>
-| "
-x { content:"</style" } "
-
-#data
-<!DOCTYPE html><select><optgroup></optgroup></select>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <optgroup>
-
-#data
-
-
-#errors
-Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html> <html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><script>
-</script> <title>x</title> </head>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <script>
-| "
-"
-| " "
-| <title>
-| "x"
-| " "
-| <body>
-
-#data
-<!DOCTYPE html><html><body><html id=x>
-#errors
-Line: 1 Col: 38 html needs to be the first start tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| id="x"
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html>X</body><html id="x">
-#errors
-Line: 1 Col: 36 Unexpected start tag token (html) in the after body phase.
-Line: 1 Col: 36 html needs to be the first start tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| id="x"
-| <head>
-| <body>
-| "X"
-
-#data
-<!DOCTYPE html><head><html id=x>
-#errors
-Line: 1 Col: 32 html needs to be the first start tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| id="x"
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html>X</html>X
-#errors
-Line: 1 Col: 24 Unexpected non-space characters in the after body phase.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "XX"
-
-#data
-<!DOCTYPE html>X</html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X "
-
-#data
-<!DOCTYPE html>X</html><p>X
-#errors
-Line: 1 Col: 26 Unexpected start tag (p).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-| <p>
-| "X"
-
-#data
-<!DOCTYPE html>X<p/x/y/z>
-#errors
-Line: 1 Col: 19 Expected a > after the /.
-Line: 1 Col: 21 Solidus (/) incorrectly placed in tag.
-Line: 1 Col: 23 Solidus (/) incorrectly placed in tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-| <p>
-| x=""
-| y=""
-| z=""
-
-#data
-<!DOCTYPE html><!--x--
-#errors
-Line: 1 Col: 22 Unexpected end of file in comment (--).
-#document
-| <!DOCTYPE html>
-| <!-- x -->
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE html><table><tr><td></p></table>
-#errors
-Line: 1 Col: 34 Unexpected end tag (p). Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <p>
-
-#data
-<!DOCTYPE <!DOCTYPE HTML>><!--<!--x-->-->
-#errors
-Line: 1 Col: 20 Expected space or '>'. Got ''
-Line: 1 Col: 25 Erroneous DOCTYPE.
-Line: 1 Col: 35 Unexpected character in comment found.
-#document
-| <!DOCTYPE <!doctype>
-| <html>
-| <head>
-| <body>
-| ">"
-| <!-- <!--x -->
-| "-->"
-
-#data
-<!doctype html><div><form></form><div></div></div>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <div>
-| <form>
-| <div>
diff --git a/src/pkg/html/testdata/webkit/tests20.dat b/src/pkg/html/testdata/webkit/tests20.dat
deleted file mode 100644
index 6bd825608..000000000
--- a/src/pkg/html/testdata/webkit/tests20.dat
+++ /dev/null
@@ -1,455 +0,0 @@
-#data
-<!doctype html><p><button><button>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <button>
-
-#data
-<!doctype html><p><button><address>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <address>
-
-#data
-<!doctype html><p><button><blockquote>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <blockquote>
-
-#data
-<!doctype html><p><button><menu>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <menu>
-
-#data
-<!doctype html><p><button><p>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <p>
-
-#data
-<!doctype html><p><button><ul>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <ul>
-
-#data
-<!doctype html><p><button><h1>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <h1>
-
-#data
-<!doctype html><p><button><h6>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <h6>
-
-#data
-<!doctype html><p><button><listing>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <listing>
-
-#data
-<!doctype html><p><button><pre>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <pre>
-
-#data
-<!doctype html><p><button><form>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <form>
-
-#data
-<!doctype html><p><button><li>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <li>
-
-#data
-<!doctype html><p><button><dd>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <dd>
-
-#data
-<!doctype html><p><button><dt>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <dt>
-
-#data
-<!doctype html><p><button><plaintext>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <plaintext>
-
-#data
-<!doctype html><p><button><table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <table>
-
-#data
-<!doctype html><p><button><hr>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <hr>
-
-#data
-<!doctype html><p><button><xmp>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <xmp>
-
-#data
-<!doctype html><p><button></p>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <button>
-| <p>
-
-#data
-<!doctype html><address><button></address>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <address>
-| <button>
-| "a"
-
-#data
-<!doctype html><address><button></address>a
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <address>
-| <button>
-| "a"
-
-#data
-<p><table></p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <p>
-| <table>
-
-#data
-<!doctype html><svg>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-
-#data
-<!doctype html><p><figcaption>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <figcaption>
-
-#data
-<!doctype html><p><summary>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <summary>
-
-#data
-<!doctype html><form><table><form>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <table>
-
-#data
-<!doctype html><table><form><form>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <form>
-
-#data
-<!doctype html><table><form></table><form>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <form>
-
-#data
-<!doctype html><svg><foreignObject><p>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg foreignObject>
-| <p>
-
-#data
-<!doctype html><svg><title>abc
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg title>
-| "abc"
-
-#data
-<option><span><option>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <option>
-| <span>
-| <option>
-
-#data
-<option><option>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <option>
-| <option>
-
-#data
-<math><annotation-xml><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| <div>
-
-#data
-<math><annotation-xml encoding="application/svg+xml"><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding="application/svg+xml"
-| <div>
-
-#data
-<math><annotation-xml encoding="application/xhtml+xml"><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding="application/xhtml+xml"
-| <div>
-
-#data
-<math><annotation-xml encoding="aPPlication/xhtmL+xMl"><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding="aPPlication/xhtmL+xMl"
-| <div>
-
-#data
-<math><annotation-xml encoding="text/html"><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding="text/html"
-| <div>
-
-#data
-<math><annotation-xml encoding="Text/htmL"><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding="Text/htmL"
-| <div>
-
-#data
-<math><annotation-xml encoding=" text/html "><div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math annotation-xml>
-| encoding=" text/html "
-| <div>
diff --git a/src/pkg/html/testdata/webkit/tests21.dat b/src/pkg/html/testdata/webkit/tests21.dat
deleted file mode 100644
index 1260ec03e..000000000
--- a/src/pkg/html/testdata/webkit/tests21.dat
+++ /dev/null
@@ -1,221 +0,0 @@
-#data
-<svg><![CDATA[foo]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "foo"
-
-#data
-<math><![CDATA[foo]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <math math>
-| "foo"
-
-#data
-<div><![CDATA[foo]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| <!-- [CDATA[foo]] -->
-
-#data
-<svg><![CDATA[foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "foo"
-
-#data
-<svg><![CDATA[foo
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "foo"
-
-#data
-<svg><![CDATA[
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-
-#data
-<svg><![CDATA[]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-
-#data
-<svg><![CDATA[]] >]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "]] >"
-
-#data
-<svg><![CDATA[]] >]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "]] >"
-
-#data
-<svg><![CDATA[]]
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "]]"
-
-#data
-<svg><![CDATA[]
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "]"
-
-#data
-<svg><![CDATA[]>a
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "]>a"
-
-#data
-<svg><foreignObject><div><![CDATA[foo]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| <svg foreignObject>
-| <div>
-| <!-- [CDATA[foo]] -->
-
-#data
-<svg><![CDATA[<svg>]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>"
-
-#data
-<svg><![CDATA[</svg>a]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "</svg>a"
-
-#data
-<svg><![CDATA[<svg>a
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>a"
-
-#data
-<svg><![CDATA[</svg>a
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "</svg>a"
-
-#data
-<svg><![CDATA[<svg>]]><path>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>"
-| <svg path>
-
-#data
-<svg><![CDATA[<svg>]]></path>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>"
-
-#data
-<svg><![CDATA[<svg>]]><!--path-->
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>"
-| <!-- path -->
-
-#data
-<svg><![CDATA[<svg>]]>path
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<svg>path"
-
-#data
-<svg><![CDATA[<!--svg-->]]>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <svg svg>
-| "<!--svg-->"
diff --git a/src/pkg/html/testdata/webkit/tests22.dat b/src/pkg/html/testdata/webkit/tests22.dat
deleted file mode 100644
index aab27b2e9..000000000
--- a/src/pkg/html/testdata/webkit/tests22.dat
+++ /dev/null
@@ -1,157 +0,0 @@
-#data
-<a><b><big><em><strong><div>X</a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <big>
-| <em>
-| <strong>
-| <big>
-| <em>
-| <strong>
-| <div>
-| <a>
-| "X"
-
-#data
-<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8>A</a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <b>
-| <div>
-| id="1"
-| <a>
-| <div>
-| id="2"
-| <a>
-| <div>
-| id="3"
-| <a>
-| <div>
-| id="4"
-| <a>
-| <div>
-| id="5"
-| <a>
-| <div>
-| id="6"
-| <a>
-| <div>
-| id="7"
-| <a>
-| <div>
-| id="8"
-| <a>
-| "A"
-
-#data
-<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9>A</a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <b>
-| <div>
-| id="1"
-| <a>
-| <div>
-| id="2"
-| <a>
-| <div>
-| id="3"
-| <a>
-| <div>
-| id="4"
-| <a>
-| <div>
-| id="5"
-| <a>
-| <div>
-| id="6"
-| <a>
-| <div>
-| id="7"
-| <a>
-| <div>
-| id="8"
-| <a>
-| <div>
-| id="9"
-| "A"
-
-#data
-<a><b><div id=1><div id=2><div id=3><div id=4><div id=5><div id=6><div id=7><div id=8><div id=9><div id=10>A</a>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <b>
-| <b>
-| <div>
-| id="1"
-| <a>
-| <div>
-| id="2"
-| <a>
-| <div>
-| id="3"
-| <a>
-| <div>
-| id="4"
-| <a>
-| <div>
-| id="5"
-| <a>
-| <div>
-| id="6"
-| <a>
-| <div>
-| id="7"
-| <a>
-| <div>
-| id="8"
-| <a>
-| <div>
-| id="9"
-| <div>
-| id="10"
-| "A"
-
-#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>
-| <div>
-| <b>
-| "X"
-| "TEST"
diff --git a/src/pkg/html/testdata/webkit/tests23.dat b/src/pkg/html/testdata/webkit/tests23.dat
deleted file mode 100644
index 34d2a73f1..000000000
--- a/src/pkg/html/testdata/webkit/tests23.dat
+++ /dev/null
@@ -1,155 +0,0 @@
-#data
-<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
-#errors
-3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-116: Unclosed elements.
-117: End of file seen and there were open elements.
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <font>
-| size="4"
-| <font>
-| color="red"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| color="red"
-| <p>
-| <font>
-| color="red"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| color="red"
-| "X"
-
-#data
-<p><font size=4><font size=4><font size=4><font size=4><p>X
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <p>
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| "X"
-
-#data
-<p><font size=4><font size=4><font size=4><font size="5"><font size=4><p>X
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="5"
-| <font>
-| size="4"
-| <p>
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="5"
-| <font>
-| size="4"
-| "X"
-
-#data
-<p><font size=4 id=a><font size=4 id=b><font size=4><font size=4><p>X
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <font>
-| id="a"
-| size="4"
-| <font>
-| id="b"
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| <p>
-| <font>
-| id="a"
-| size="4"
-| <font>
-| id="b"
-| size="4"
-| <font>
-| size="4"
-| <font>
-| size="4"
-| "X"
-
-#data
-<p><b id=a><b id=a><b id=a><b><object><b id=a><b id=a>X</object><p>Y
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <b>
-| id="a"
-| <b>
-| id="a"
-| <b>
-| id="a"
-| <b>
-| <object>
-| <b>
-| id="a"
-| <b>
-| id="a"
-| "X"
-| <p>
-| <b>
-| id="a"
-| <b>
-| id="a"
-| <b>
-| id="a"
-| <b>
-| "Y"
diff --git a/src/pkg/html/testdata/webkit/tests24.dat b/src/pkg/html/testdata/webkit/tests24.dat
deleted file mode 100644
index f6dc7eb48..000000000
--- a/src/pkg/html/testdata/webkit/tests24.dat
+++ /dev/null
@@ -1,79 +0,0 @@
-#data
-<!DOCTYPE html>&NotEqualTilde;
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "≂̸"
-
-#data
-<!DOCTYPE html>&NotEqualTilde;A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "≂̸A"
-
-#data
-<!DOCTYPE html>&ThickSpace;
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "  "
-
-#data
-<!DOCTYPE html>&ThickSpace;A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "  A"
-
-#data
-<!DOCTYPE html>&NotSubset;
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "⊂⃒"
-
-#data
-<!DOCTYPE html>&NotSubset;A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "⊂⃒A"
-
-#data
-<!DOCTYPE html>&Gopf;
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "𝔾"
-
-#data
-<!DOCTYPE html>&Gopf;A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "𝔾A"
diff --git a/src/pkg/html/testdata/webkit/tests25.dat b/src/pkg/html/testdata/webkit/tests25.dat
deleted file mode 100644
index 00de7295b..000000000
--- a/src/pkg/html/testdata/webkit/tests25.dat
+++ /dev/null
@@ -1,219 +0,0 @@
-#data
-<!DOCTYPE html><body><foo>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <foo>
-| "A"
-
-#data
-<!DOCTYPE html><body><area>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <area>
-| "A"
-
-#data
-<!DOCTYPE html><body><base>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <base>
-| "A"
-
-#data
-<!DOCTYPE html><body><basefont>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <basefont>
-| "A"
-
-#data
-<!DOCTYPE html><body><bgsound>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <bgsound>
-| "A"
-
-#data
-<!DOCTYPE html><body><br>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <br>
-| "A"
-
-#data
-<!DOCTYPE html><body><col>A
-#errors
-26: Stray start tag “col”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "A"
-
-#data
-<!DOCTYPE html><body><command>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <command>
-| "A"
-
-#data
-<!DOCTYPE html><body><embed>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <embed>
-| "A"
-
-#data
-<!DOCTYPE html><body><frame>A
-#errors
-26: Stray start tag “frame”.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "A"
-
-#data
-<!DOCTYPE html><body><hr>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <hr>
-| "A"
-
-#data
-<!DOCTYPE html><body><img>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <img>
-| "A"
-
-#data
-<!DOCTYPE html><body><input>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <input>
-| "A"
-
-#data
-<!DOCTYPE html><body><keygen>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <keygen>
-| "A"
-
-#data
-<!DOCTYPE html><body><link>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <link>
-| "A"
-
-#data
-<!DOCTYPE html><body><meta>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <meta>
-| "A"
-
-#data
-<!DOCTYPE html><body><param>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <param>
-| "A"
-
-#data
-<!DOCTYPE html><body><source>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <source>
-| "A"
-
-#data
-<!DOCTYPE html><body><track>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <track>
-| "A"
-
-#data
-<!DOCTYPE html><body><wbr>A
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <wbr>
-| "A"
diff --git a/src/pkg/html/testdata/webkit/tests26.dat b/src/pkg/html/testdata/webkit/tests26.dat
deleted file mode 100644
index da128e779..000000000
--- a/src/pkg/html/testdata/webkit/tests26.dat
+++ /dev/null
@@ -1,195 +0,0 @@
-#data
-<!DOCTYPE html><body><a href='#1'><nobr>1<nobr></a><br><a href='#2'><nobr>2<nobr></a><br><a href='#3'><nobr>3<nobr></a>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <a>
-| href="#1"
-| <nobr>
-| "1"
-| <nobr>
-| <nobr>
-| <br>
-| <a>
-| href="#2"
-| <a>
-| href="#2"
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| <br>
-| <a>
-| href="#3"
-| <a>
-| href="#3"
-| <nobr>
-| "3"
-| <nobr>
-
-#data
-<!DOCTYPE html><body><b><nobr>1<nobr></b><i><nobr>2<nobr></i>3
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <nobr>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| "3"
-
-#data
-<!DOCTYPE html><body><b><nobr>1<table><nobr></b><i><nobr>2<nobr></i>3
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| "3"
-| <table>
-
-#data
-<!DOCTYPE html><body><b><nobr>1<table><tr><td><nobr></b><i><nobr>2<nobr></i>3
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| "3"
-
-#data
-<!DOCTYPE html><body><b><nobr>1<div><nobr></b><i><nobr>2<nobr></i>3
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <div>
-| <b>
-| <nobr>
-| <nobr>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| "3"
-
-#data
-<!DOCTYPE html><body><b><nobr>1<nobr></b><div><i><nobr>2<nobr></i>3
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <nobr>
-| <div>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
-| <nobr>
-| <nobr>
-| "3"
-
-#data
-<!DOCTYPE html><body><b><nobr>1<nobr><ins></b><i><nobr>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <nobr>
-| <ins>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-
-#data
-<!DOCTYPE html><body><b><nobr>1<ins><nobr></b><i>2
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| <nobr>
-| "1"
-| <ins>
-| <nobr>
-| <nobr>
-| <i>
-| "2"
-
-#data
-<!DOCTYPE html><body><b>1<nobr></b><i><nobr>2</i>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <b>
-| "1"
-| <nobr>
-| <nobr>
-| <i>
-| <i>
-| <nobr>
-| "2"
diff --git a/src/pkg/html/testdata/webkit/tests3.dat b/src/pkg/html/testdata/webkit/tests3.dat
deleted file mode 100644
index 38dc501be..000000000
--- a/src/pkg/html/testdata/webkit/tests3.dat
+++ /dev/null
@@ -1,305 +0,0 @@
-#data
-<head></head><style></style>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected start tag (style) that can be in head. Moved.
-#document
-| <html>
-| <head>
-| <style>
-| <body>
-
-#data
-<head></head><script></script>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved.
-#document
-| <html>
-| <head>
-| <script>
-| <body>
-
-#data
-<head></head><!-- --><style></style><!-- --><script></script>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved.
-#document
-| <html>
-| <head>
-| <style>
-| <script>
-| <!-- -->
-| <!-- -->
-| <body>
-
-#data
-<head></head><!-- -->x<style></style><!-- --><script></script>
-#errors
-Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <!-- -->
-| <body>
-| "x"
-| <style>
-| <!-- -->
-| <script>
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>
-</pre></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>
-foo</pre></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "foo"
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>
-
-foo</pre></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "
-foo"
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>
-foo
-</pre></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "foo
-"
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>x</pre><span>
-</span></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "x"
-| <span>
-| "
-"
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>x
-y</pre></body></html>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "x
-y"
-
-#data
-<!DOCTYPE html><html><head></head><body><pre>x<div>
-y</pre></body></html>
-#errors
-Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <pre>
-| "x"
-| <div>
-| "
-y"
-
-#data
-<!DOCTYPE html><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.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <meta>
-| <body>
-
-#data
-<!DOCTYPE html><HTML><HEAD><head></HEAD></HTML>
-#errors
-Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<textarea>foo<span>bar</span><i>baz
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-Line: 1 Col: 35 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "foo<span>bar</span><i>baz"
-
-#data
-<title>foo<span>bar</em><i>baz
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-Line: 1 Col: 30 Unexpected end of file. Expected end tag (title).
-#document
-| <html>
-| <head>
-| <title>
-| "foo<span>bar</em><i>baz"
-| <body>
-
-#data
-<!DOCTYPE html><textarea>
-</textarea>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-
-#data
-<!DOCTYPE html><textarea>
-foo</textarea>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "foo"
-
-#data
-<!DOCTYPE html><textarea>
-
-foo</textarea>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <textarea>
-| "
-foo"
-
-#data
-<!DOCTYPE html><html><head></head><body><ul><li><div><p><li></ul></body></html>
-#errors
-Line: 1 Col: 60 Missing end tag (div, li).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <ul>
-| <li>
-| <div>
-| <p>
-| <li>
-
-#data
-<!doctype html><nobr><nobr><nobr>
-#errors
-Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
-Line: 1 Col: 33 Unexpected start tag (nobr) implies end tag (nobr).
-Line: 1 Col: 33 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <nobr>
-| <nobr>
-| <nobr>
-
-#data
-<!doctype html><nobr><nobr></nobr><nobr>
-#errors
-Line: 1 Col: 27 Unexpected start tag (nobr) implies end tag (nobr).
-Line: 1 Col: 40 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <nobr>
-| <nobr>
-| <nobr>
-
-#data
-<!doctype html><html><body><p><table></table></body></html>
-#errors
-Not known
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <table>
-
-#data
-<p><table></table>
-#errors
-Not known
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <table>
diff --git a/src/pkg/html/testdata/webkit/tests4.dat b/src/pkg/html/testdata/webkit/tests4.dat
deleted file mode 100644
index 3c506326d..000000000
--- a/src/pkg/html/testdata/webkit/tests4.dat
+++ /dev/null
@@ -1,59 +0,0 @@
-#data
-direct div content
-#errors
-#document-fragment
-div
-#document
-| "direct div content"
-
-#data
-direct textarea content
-#errors
-#document-fragment
-textarea
-#document
-| "direct textarea content"
-
-#data
-textarea content with <em>pseudo</em> <foo>markup
-#errors
-#document-fragment
-textarea
-#document
-| "textarea content with <em>pseudo</em> <foo>markup"
-
-#data
-this is &#x0043;DATA inside a <style> element
-#errors
-#document-fragment
-style
-#document
-| "this is &#x0043;DATA inside a <style> element"
-
-#data
-</plaintext>
-#errors
-#document-fragment
-plaintext
-#document
-| "</plaintext>"
-
-#data
-setting html's innerHTML
-#errors
-Line: 1 Col: 24 Unexpected EOF in inner html mode.
-#document-fragment
-html
-#document
-| <head>
-| <body>
-| "setting html's innerHTML"
-
-#data
-<title>setting head's innerHTML</title>
-#errors
-#document-fragment
-head
-#document
-| <title>
-| "setting head's innerHTML"
diff --git a/src/pkg/html/testdata/webkit/tests5.dat b/src/pkg/html/testdata/webkit/tests5.dat
deleted file mode 100644
index d7b5128a4..000000000
--- a/src/pkg/html/testdata/webkit/tests5.dat
+++ /dev/null
@@ -1,191 +0,0 @@
-#data
-<style> <!-- </style>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end of file. Expected end tag (style).
-#document
-| <html>
-| <head>
-| <style>
-| " <!-- "
-| <body>
-| "x"
-
-#data
-<style> <!-- </style> --> </style>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| " <!-- "
-| " "
-| <body>
-| "--> x"
-
-#data
-<style> <!--> </style>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| " <!--> "
-| <body>
-| "x"
-
-#data
-<style> <!---> </style>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| " <!---> "
-| <body>
-| "x"
-
-#data
-<iframe> <!---> </iframe>x
-#errors
-Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <iframe>
-| " <!---> "
-| "x"
-
-#data
-<iframe> <!--- </iframe>->x</iframe> --> </iframe>x
-#errors
-Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <iframe>
-| " <!--- "
-| "->x --> x"
-
-#data
-<script> <!-- </script> --> </script>x
-#errors
-Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <script>
-| " <!-- "
-| " "
-| <body>
-| "--> x"
-
-#data
-<title> <!-- </title> --> </title>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <title>
-| " <!-- "
-| " "
-| <body>
-| "--> x"
-
-#data
-<textarea> <!--- </textarea>->x</textarea> --> </textarea>x
-#errors
-Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <textarea>
-| " <!--- "
-| "->x --> x"
-
-#data
-<style> <!</-- </style>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <style>
-| " <!</-- "
-| <body>
-| "x"
-
-#data
-<p><xmp></xmp>
-#errors
-XXX: Unknown
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <xmp>
-
-#data
-<xmp> <!-- > --> </xmp>
-#errors
-Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <xmp>
-| " <!-- > --> "
-
-#data
-<title>&amp;</title>
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <title>
-| "&"
-| <body>
-
-#data
-<title><!--&amp;--></title>
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <title>
-| "<!--&-->"
-| <body>
-
-#data
-<title><!--</title>
-#errors
-Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
-Line: 1 Col: 19 Unexpected end of file. Expected end tag (title).
-#document
-| <html>
-| <head>
-| <title>
-| "<!--"
-| <body>
-
-#data
-<noscript><!--</noscript>--></noscript>
-#errors
-Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <noscript>
-| "<!--"
-| <body>
-| "-->"
diff --git a/src/pkg/html/testdata/webkit/tests6.dat b/src/pkg/html/testdata/webkit/tests6.dat
deleted file mode 100644
index f28ece4fb..000000000
--- a/src/pkg/html/testdata/webkit/tests6.dat
+++ /dev/null
@@ -1,663 +0,0 @@
-#data
-<!doctype html></head> <head>
-#errors
-Line: 1 Col: 29 Unexpected start tag head. Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| " "
-| <body>
-
-#data
-<!doctype html><form><div></form><div>
-#errors
-33: End tag "form" seen but there were unclosed elements.
-38: End of file seen and there were open elements.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <form>
-| <div>
-| <div>
-
-#data
-<!doctype html><title>&amp;</title>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "&"
-| <body>
-
-#data
-<!doctype html><title><!--&amp;--></title>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "<!--&-->"
-| <body>
-
-#data
-<!doctype>
-#errors
-Line: 1 Col: 9 No space after literal string 'DOCTYPE'.
-Line: 1 Col: 10 Unexpected > character. Expected DOCTYPE name.
-Line: 1 Col: 10 Erroneous DOCTYPE.
-#document
-| <!DOCTYPE >
-| <html>
-| <head>
-| <body>
-
-#data
-<!---x
-#errors
-Line: 1 Col: 6 Unexpected end of file in comment.
-Line: 1 Col: 6 Unexpected End of file. Expected DOCTYPE.
-#document
-| <!-- -x -->
-| <html>
-| <head>
-| <body>
-
-#data
-<body>
-<div>
-#errors
-Line: 1 Col: 6 Unexpected start tag (body).
-Line: 2 Col: 5 Expected closing tag. Unexpected end of file.
-#document-fragment
-div
-#document
-| "
-"
-| <div>
-
-#data
-<frameset></frameset>
-foo
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 2 Col: 3 Unexpected non-space characters in the after frameset phase. Ignored.
-#document
-| <html>
-| <head>
-| <frameset>
-| "
-"
-
-#data
-<frameset></frameset>
-<noframes>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 2 Col: 10 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <frameset>
-| "
-"
-| <noframes>
-
-#data
-<frameset></frameset>
-<div>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 2 Col: 5 Unexpected start tag (div) in the after frameset phase. Ignored.
-#document
-| <html>
-| <head>
-| <frameset>
-| "
-"
-
-#data
-<frameset></frameset>
-</html>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <frameset>
-| "
-"
-
-#data
-<frameset></frameset>
-</div>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 2 Col: 6 Unexpected end tag (div) in the after frameset phase. Ignored.
-#document
-| <html>
-| <head>
-| <frameset>
-| "
-"
-
-#data
-<form><form>
-#errors
-Line: 1 Col: 6 Unexpected start tag (form). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected start tag (form).
-Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <form>
-
-#data
-<button><button>
-#errors
-Line: 1 Col: 8 Unexpected start tag (button). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected start tag (button) implies end tag (button).
-Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <button>
-| <button>
-
-#data
-<table><tr><td></th>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end tag (th). Ignored.
-Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><caption><td>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end tag (td). Ignored.
-Line: 1 Col: 20 Unexpected table cell start tag (td) in the table body phase.
-Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><caption><div>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 21 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <div>
-
-#data
-</caption><div>
-#errors
-Line: 1 Col: 10 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
-#document-fragment
-caption
-#document
-| <div>
-
-#data
-<table><caption><div></caption>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 31 Unexpected end tag (caption). Missing end tag (div).
-Line: 1 Col: 31 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <div>
-
-#data
-<table><caption></table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 24 Unexpected end table tag in caption. Generates implied end caption.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-
-#data
-</table><div>
-#errors
-Line: 1 Col: 8 Unexpected end table tag in caption. Generates implied end caption.
-Line: 1 Col: 8 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 13 Expected closing tag. Unexpected end of file.
-#document-fragment
-caption
-#document
-| <div>
-
-#data
-<table><caption></body></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 23 Unexpected end tag (body). Ignored.
-Line: 1 Col: 29 Unexpected end tag (col). Ignored.
-Line: 1 Col: 40 Unexpected end tag (colgroup). Ignored.
-Line: 1 Col: 47 Unexpected end tag (html). Ignored.
-Line: 1 Col: 55 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 60 Unexpected end tag (td). Ignored.
-Line: 1 Col: 68 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 73 Unexpected end tag (th). Ignored.
-Line: 1 Col: 81 Unexpected end tag (thead). Ignored.
-Line: 1 Col: 86 Unexpected end tag (tr). Ignored.
-Line: 1 Col: 86 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-
-#data
-<table><caption><div></div>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 27 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <div>
-
-#data
-<table><tr><td></body></caption></col></colgroup></html>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end tag (body). Ignored.
-Line: 1 Col: 32 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 38 Unexpected end tag (col). Ignored.
-Line: 1 Col: 49 Unexpected end tag (colgroup). Ignored.
-Line: 1 Col: 56 Unexpected end tag (html). Ignored.
-Line: 1 Col: 56 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-</table></tbody></tfoot></thead></tr><div>
-#errors
-Line: 1 Col: 8 Unexpected end tag (table). Ignored.
-Line: 1 Col: 16 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 24 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 32 Unexpected end tag (thead). Ignored.
-Line: 1 Col: 37 Unexpected end tag (tr). Ignored.
-Line: 1 Col: 42 Expected closing tag. Unexpected end of file.
-#document-fragment
-td
-#document
-| <div>
-
-#data
-<table><colgroup>foo
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 20 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| "foo"
-| <table>
-| <colgroup>
-
-#data
-foo<col>
-#errors
-Line: 1 Col: 3 Unexpected end tag (colgroup). Ignored.
-#document-fragment
-colgroup
-#document
-| <col>
-
-#data
-<table><colgroup></col>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 23 This element (col) has no end tag.
-Line: 1 Col: 23 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <colgroup>
-
-#data
-<frameset><div>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 1 Col: 15 Unexpected start tag token (div) in the frameset phase. Ignored.
-Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-</frameset><frame>
-#errors
-Line: 1 Col: 11 Unexpected end tag token (frameset) in the frameset phase (innerHTML).
-#document-fragment
-frameset
-#document
-| <frame>
-
-#data
-<frameset></div>
-#errors
-Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected end tag token (div) in the frameset phase. Ignored.
-Line: 1 Col: 16 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-</body><div>
-#errors
-Line: 1 Col: 7 Unexpected end tag (body). Ignored.
-Line: 1 Col: 12 Expected closing tag. Unexpected end of file.
-#document-fragment
-body
-#document
-| <div>
-
-#data
-<table><tr><div>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
-Line: 1 Col: 16 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| <table>
-| <tbody>
-| <tr>
-
-#data
-</tr><td>
-#errors
-Line: 1 Col: 5 Unexpected end tag (tr). Ignored.
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-</tbody></tfoot></thead><td>
-#errors
-Line: 1 Col: 8 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 16 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 24 Unexpected end tag (thead). Ignored.
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<table><tr><div><td>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 16 Unexpected start tag (div) in table context caused voodoo mode.
-Line: 1 Col: 20 Unexpected implied end tag (div) in the table row phase.
-Line: 1 Col: 20 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<caption><col><colgroup><tbody><tfoot><thead><tr>
-#errors
-Line: 1 Col: 9 Unexpected start tag (caption).
-Line: 1 Col: 14 Unexpected start tag (col).
-Line: 1 Col: 24 Unexpected start tag (colgroup).
-Line: 1 Col: 31 Unexpected start tag (tbody).
-Line: 1 Col: 38 Unexpected start tag (tfoot).
-Line: 1 Col: 45 Unexpected start tag (thead).
-Line: 1 Col: 49 Unexpected end of file. Expected table content.
-#document-fragment
-tbody
-#document
-| <tr>
-
-#data
-<table><tbody></thead>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 22 Unexpected end tag (thead) in the table body phase. Ignored.
-Line: 1 Col: 22 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-
-#data
-</table><tr>
-#errors
-Line: 1 Col: 8 Unexpected end tag (table). Ignored.
-Line: 1 Col: 12 Unexpected end of file. Expected table content.
-#document-fragment
-tbody
-#document
-| <tr>
-
-#data
-<table><tbody></body></caption></col></colgroup></html></td></th></tr>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 21 Unexpected end tag (body) in the table body phase. Ignored.
-Line: 1 Col: 31 Unexpected end tag (caption) in the table body phase. Ignored.
-Line: 1 Col: 37 Unexpected end tag (col) in the table body phase. Ignored.
-Line: 1 Col: 48 Unexpected end tag (colgroup) in the table body phase. Ignored.
-Line: 1 Col: 55 Unexpected end tag (html) in the table body phase. Ignored.
-Line: 1 Col: 60 Unexpected end tag (td) in the table body phase. Ignored.
-Line: 1 Col: 65 Unexpected end tag (th) in the table body phase. Ignored.
-Line: 1 Col: 70 Unexpected end tag (tr) in the table body phase. Ignored.
-Line: 1 Col: 70 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-
-#data
-<table><tbody></div>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 20 Unexpected end tag (div) in table context caused voodoo mode.
-Line: 1 Col: 20 End tag (div) seen too early. Expected other end tag.
-Line: 1 Col: 20 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-
-#data
-<table><table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected start tag (table) implies end tag (table).
-Line: 1 Col: 14 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <table>
-
-#data
-<table></body></caption></col></colgroup></html></tbody></td></tfoot></th></thead></tr>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 14 Unexpected end tag (body). Ignored.
-Line: 1 Col: 24 Unexpected end tag (caption). Ignored.
-Line: 1 Col: 30 Unexpected end tag (col). Ignored.
-Line: 1 Col: 41 Unexpected end tag (colgroup). Ignored.
-Line: 1 Col: 48 Unexpected end tag (html). Ignored.
-Line: 1 Col: 56 Unexpected end tag (tbody). Ignored.
-Line: 1 Col: 61 Unexpected end tag (td). Ignored.
-Line: 1 Col: 69 Unexpected end tag (tfoot). Ignored.
-Line: 1 Col: 74 Unexpected end tag (th). Ignored.
-Line: 1 Col: 82 Unexpected end tag (thead). Ignored.
-Line: 1 Col: 87 Unexpected end tag (tr). Ignored.
-Line: 1 Col: 87 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-
-#data
-</table><tr>
-#errors
-Line: 1 Col: 8 Unexpected end tag (table). Ignored.
-Line: 1 Col: 12 Unexpected end of file. Expected table content.
-#document-fragment
-table
-#document
-| <tbody>
-| <tr>
-
-#data
-<body></body></html>
-#errors
-Line: 1 Col: 20 Unexpected html end tag in inner html mode.
-Line: 1 Col: 20 Unexpected EOF in inner html mode.
-#document-fragment
-html
-#document
-| <head>
-| <body>
-
-#data
-<html><frameset></frameset></html>
-#errors
-Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <frameset>
-| " "
-
-#data
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html></html>
-#errors
-Line: 1 Col: 50 Erroneous DOCTYPE.
-Line: 1 Col: 63 Unexpected end tag (html) after the (implied) root element.
-#document
-| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "">
-| <html>
-| <head>
-| <body>
-
-#data
-<param><frameset></frameset>
-#errors
-Line: 1 Col: 7 Unexpected start tag (param). Expected DOCTYPE.
-Line: 1 Col: 17 Unexpected start tag (frameset).
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-<source><frameset></frameset>
-#errors
-Line: 1 Col: 7 Unexpected start tag (source). Expected DOCTYPE.
-Line: 1 Col: 17 Unexpected start tag (frameset).
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-<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>”.
-17: Stray “frameset” start tag.
-17: “frameset” start tag seen.
-#document
-| <html>
-| <head>
-| <frameset>
-
-#data
-</body><frameset></frameset>
-#errors
-7: End tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
-17: Stray “frameset” start tag.
-17: “frameset” start tag seen.
-#document
-| <html>
-| <head>
-| <frameset>
diff --git a/src/pkg/html/testdata/webkit/tests7.dat b/src/pkg/html/testdata/webkit/tests7.dat
deleted file mode 100644
index f5193c660..000000000
--- a/src/pkg/html/testdata/webkit/tests7.dat
+++ /dev/null
@@ -1,390 +0,0 @@
-#data
-<!doctype html><body><title>X</title>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <title>
-| "X"
-
-#data
-<!doctype html><table><title>X</title></table>
-#errors
-Line: 1 Col: 29 Unexpected start tag (title) in table context caused voodoo mode.
-Line: 1 Col: 38 Unexpected end tag (title) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <title>
-| "X"
-| <table>
-
-#data
-<!doctype html><head></head><title>X</title>
-#errors
-Line: 1 Col: 35 Unexpected start tag (title) that can be in head. Moved.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "X"
-| <body>
-
-#data
-<!doctype html></head><title>X</title>
-#errors
-Line: 1 Col: 29 Unexpected start tag (title) that can be in head. Moved.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <title>
-| "X"
-| <body>
-
-#data
-<!doctype html><table><meta></table>
-#errors
-Line: 1 Col: 28 Unexpected start tag (meta) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <meta>
-| <table>
-
-#data
-<!doctype html><table>X<tr><td><table> <meta></table></table>
-#errors
-Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 45 Unexpected start tag (meta) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <meta>
-| <table>
-| " "
-
-#data
-<!doctype html><html> <head>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<!doctype html> <head>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<!doctype html><table><style> <tr>x </style> </table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <style>
-| " <tr>x "
-| " "
-
-#data
-<!doctype html><table><TBODY><script> <tr>x </script> </table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <script>
-| " <tr>x "
-| " "
-
-#data
-<!doctype html><p><applet><p>X</p></applet>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <p>
-| <applet>
-| <p>
-| "X"
-
-#data
-<!doctype html><listing>
-X</listing>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <listing>
-| "X"
-
-#data
-<!doctype html><select><input>X
-#errors
-Line: 1 Col: 30 Unexpected input start tag in the select phase.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <input>
-| "X"
-
-#data
-<!doctype html><select><select>X
-#errors
-Line: 1 Col: 31 Unexpected select start tag in the select phase treated as select end tag.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| "X"
-
-#data
-<!doctype html><table><input type=hidDEN></table>
-#errors
-Line: 1 Col: 41 Unexpected input with type hidden in table context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <input>
-| type="hidDEN"
-
-#data
-<!doctype html><table>X<input type=hidDEN></table>
-#errors
-Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| "X"
-| <table>
-| <input>
-| type="hidDEN"
-
-#data
-<!doctype html><table> <input type=hidDEN></table>
-#errors
-Line: 1 Col: 43 Unexpected input with type hidden in table context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| " "
-| <input>
-| type="hidDEN"
-
-#data
-<!doctype html><table> <input type='hidDEN'></table>
-#errors
-Line: 1 Col: 45 Unexpected input with type hidden in table context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| " "
-| <input>
-| type="hidDEN"
-
-#data
-<!doctype html><table><input type=" hidden"><input type=hidDEN></table>
-#errors
-Line: 1 Col: 44 Unexpected start tag (input) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <input>
-| type=" hidden"
-| <table>
-| <input>
-| type="hidDEN"
-
-#data
-<!doctype html><table><select>X<tr>
-#errors
-Line: 1 Col: 30 Unexpected start tag (select) in table context caused voodoo mode.
-Line: 1 Col: 35 Unexpected table element start tag (trs) in the select in table phase.
-Line: 1 Col: 35 Unexpected end of file. Expected table content.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| "X"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!doctype html><select>X</select>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| "X"
-
-#data
-<!DOCTYPE hTmL><html></html>
-#errors
-Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<!DOCTYPE HTML><html></html>
-#errors
-Line: 1 Col: 28 Unexpected end tag (html) after the (implied) root element.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-
-#data
-<body>X</body></body>
-#errors
-Line: 1 Col: 21 Unexpected end tag token (body) in the after body phase.
-Line: 1 Col: 21 Unexpected EOF in inner html mode.
-#document-fragment
-html
-#document
-| <head>
-| <body>
-| "X"
-
-#data
-<div><p>a</x> b
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 13 Unexpected end tag (x). Ignored.
-Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| <p>
-| "a b"
-
-#data
-<table><tr><td><code></code> </table>
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <code>
-| " "
-
-#data
-<table><b><tr><td>aaa</td></tr>bbb</table>ccc
-#errors
-XXX: Fix me
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <b>
-| "bbb"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "aaa"
-| <b>
-| "ccc"
-
-#data
-A<table><tr> B</tr> B</table>
-#errors
-XXX: Fix me
-#document
-| <html>
-| <head>
-| <body>
-| "A B B"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-A<table><tr> B</tr> </em>C</table>
-#errors
-XXX: Fix me
-#document
-| <html>
-| <head>
-| <body>
-| "A BC"
-| <table>
-| <tbody>
-| <tr>
-| " "
-
-#data
-<select><keygen>
-#errors
-Not known
-#document
-| <html>
-| <head>
-| <body>
-| <select>
-| <keygen>
diff --git a/src/pkg/html/testdata/webkit/tests8.dat b/src/pkg/html/testdata/webkit/tests8.dat
deleted file mode 100644
index 90e6c919e..000000000
--- a/src/pkg/html/testdata/webkit/tests8.dat
+++ /dev/null
@@ -1,148 +0,0 @@
-#data
-<div>
-<div></div>
-</span>x
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 3 Col: 7 Unexpected end tag (span). Ignored.
-Line: 3 Col: 8 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "
-"
-| <div>
-| "
-x"
-
-#data
-<div>x<div></div>
-</span>x
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 2 Col: 7 Unexpected end tag (span). Ignored.
-Line: 2 Col: 8 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "x"
-| <div>
-| "
-x"
-
-#data
-<div>x<div></div>x</span>x
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 25 Unexpected end tag (span). Ignored.
-Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "x"
-| <div>
-| "xx"
-
-#data
-<div>x<div></div>y</span>z
-#errors
-Line: 1 Col: 5 Unexpected start tag (div). Expected DOCTYPE.
-Line: 1 Col: 25 Unexpected end tag (span). Ignored.
-Line: 1 Col: 26 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "x"
-| <div>
-| "yz"
-
-#data
-<table><div>x<div></div>x</span>x
-#errors
-Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE.
-Line: 1 Col: 12 Unexpected start tag (div) in table context caused voodoo mode.
-Line: 1 Col: 18 Unexpected start tag (div) in table context caused voodoo mode.
-Line: 1 Col: 24 Unexpected end tag (div) in table context caused voodoo mode.
-Line: 1 Col: 32 Unexpected end tag (span) in table context caused voodoo mode.
-Line: 1 Col: 32 Unexpected end tag (span). Ignored.
-Line: 1 Col: 33 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "x"
-| <div>
-| "xx"
-| <table>
-
-#data
-x<table>x
-#errors
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-Line: 1 Col: 9 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 9 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| "xx"
-| <table>
-
-#data
-x<table><table>x
-#errors
-Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE.
-Line: 1 Col: 15 Unexpected start tag (table) implies end tag (table).
-Line: 1 Col: 16 Unexpected non-space characters in table context caused voodoo mode.
-Line: 1 Col: 16 Unexpected end of file. Expected table content.
-#document
-| <html>
-| <head>
-| <body>
-| "x"
-| <table>
-| "x"
-| <table>
-
-#data
-<b>a<div></div><div></b>y
-#errors
-Line: 1 Col: 3 Unexpected start tag (b). Expected DOCTYPE.
-Line: 1 Col: 24 End tag (b) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 25 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| "a"
-| <div>
-| <div>
-| <b>
-| "y"
-
-#data
-<a><div><p></a>
-#errors
-Line: 1 Col: 3 Unexpected start tag (a). Expected DOCTYPE.
-Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 15 End tag (a) violates step 1, paragraph 3 of the adoption agency algorithm.
-Line: 1 Col: 15 Expected closing tag. Unexpected end of file.
-#document
-| <html>
-| <head>
-| <body>
-| <a>
-| <div>
-| <a>
-| <p>
-| <a>
diff --git a/src/pkg/html/testdata/webkit/tests9.dat b/src/pkg/html/testdata/webkit/tests9.dat
deleted file mode 100644
index 554e27aec..000000000
--- a/src/pkg/html/testdata/webkit/tests9.dat
+++ /dev/null
@@ -1,457 +0,0 @@
-#data
-<!DOCTYPE html><math></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-
-#data
-<!DOCTYPE html><body><math></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-
-#data
-<!DOCTYPE html><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.
-Line: 1 Col: 42 Unexpected end tag (math) in the select phase. Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-
-#data
-<!DOCTYPE html><body><select><option><math></math></option></select>
-#errors
-Line: 1 Col: 43 Unexpected start tag token (math) in the select phase. Ignored.
-Line: 1 Col: 50 Unexpected end tag (math) in the select phase. Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| <option>
-
-#data
-<!DOCTYPE html><body><table><math></math></table>
-#errors
-Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 41 Unexpected end tag (math) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <table>
-
-#data
-<!DOCTYPE html><body><table><math><mi>foo</mi></math></table>
-#errors
-Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 53 Unexpected end tag (math) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <table>
-
-#data
-<!DOCTYPE html><body><table><math><mi>foo</mi><mi>bar</mi></math></table>
-#errors
-Line: 1 Col: 34 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 46 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 58 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 65 Unexpected end tag (math) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <table>
-
-#data
-<!DOCTYPE html><body><table><tbody><math><mi>foo</mi><mi>bar</mi></math></tbody></table>
-#errors
-Line: 1 Col: 41 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 53 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 65 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 72 Unexpected end tag (math) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <table>
-| <tbody>
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><math><mi>foo</mi><mi>bar</mi></math></tr></tbody></table>
-#errors
-Line: 1 Col: 45 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 57 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 69 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 76 Unexpected end tag (math) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math></td></tr></tbody></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-
-#data
-<!DOCTYPE html><body><table><tbody><tr><td><math><mi>foo</mi><mi>bar</mi></math><p>baz</td></tr></tbody></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi></math><p>baz</caption></table>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
-#errors
-Line: 1 Col: 70 HTML start tag "p" in a foreign namespace context.
-Line: 1 Col: 81 Unexpected end table tag in caption. Generates implied end caption.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><caption><math><mi>foo</mi><mi>bar</mi>baz</table><p>quux
-#errors
-Line: 1 Col: 78 Unexpected end table tag in caption. Generates implied end caption.
-Line: 1 Col: 78 Unexpected end tag (caption). Missing end tag (math).
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <caption>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| "baz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><colgroup><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
-#errors
-Line: 1 Col: 44 Unexpected start tag (math) in table context caused voodoo mode.
-Line: 1 Col: 56 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 68 Unexpected end tag (mi) in table context caused voodoo mode.
-Line: 1 Col: 71 HTML start tag "p" in a foreign namespace context.
-Line: 1 Col: 71 Unexpected start tag (p) in table context caused voodoo mode.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-| <table>
-| <colgroup>
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><tr><td><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
-#errors
-Line: 1 Col: 50 Unexpected start tag token (math) in the select phase. Ignored.
-Line: 1 Col: 54 Unexpected start tag token (mi) in the select phase. Ignored.
-Line: 1 Col: 62 Unexpected end tag (mi) in the select phase. Ignored.
-Line: 1 Col: 66 Unexpected start tag token (mi) in the select phase. Ignored.
-Line: 1 Col: 74 Unexpected end tag (mi) in the select phase. Ignored.
-Line: 1 Col: 77 Unexpected start tag token (p) in the select phase. Ignored.
-Line: 1 Col: 88 Unexpected table element end tag (tables) in the select in table phase.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <select>
-| "foobarbaz"
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body><table><select><math><mi>foo</mi><mi>bar</mi><p>baz</table><p>quux
-#errors
-Line: 1 Col: 36 Unexpected start tag (select) in table context caused voodoo mode.
-Line: 1 Col: 42 Unexpected start tag token (math) in the select phase. Ignored.
-Line: 1 Col: 46 Unexpected start tag token (mi) in the select phase. Ignored.
-Line: 1 Col: 54 Unexpected end tag (mi) in the select phase. Ignored.
-Line: 1 Col: 58 Unexpected start tag token (mi) in the select phase. Ignored.
-Line: 1 Col: 66 Unexpected end tag (mi) in the select phase. Ignored.
-Line: 1 Col: 69 Unexpected start tag token (p) in the select phase. Ignored.
-Line: 1 Col: 80 Unexpected table element end tag (tables) in the select in table phase.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <select>
-| "foobarbaz"
-| <table>
-| <p>
-| "quux"
-
-#data
-<!DOCTYPE html><body></body></html><math><mi>foo</mi><mi>bar</mi><p>baz
-#errors
-Line: 1 Col: 41 Unexpected start tag (math).
-Line: 1 Col: 68 HTML start tag "p" in a foreign namespace context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><body></body><math><mi>foo</mi><mi>bar</mi><p>baz
-#errors
-Line: 1 Col: 34 Unexpected start tag token (math) in the after body phase.
-Line: 1 Col: 61 HTML start tag "p" in a foreign namespace context.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| <math math>
-| <math mi>
-| "foo"
-| <math mi>
-| "bar"
-| <p>
-| "baz"
-
-#data
-<!DOCTYPE html><frameset><math><mi></mi><mi></mi><p><span>
-#errors
-Line: 1 Col: 31 Unexpected start tag token (math) in the frameset phase. Ignored.
-Line: 1 Col: 35 Unexpected start tag token (mi) in the frameset phase. Ignored.
-Line: 1 Col: 40 Unexpected end tag token (mi) in the frameset phase. Ignored.
-Line: 1 Col: 44 Unexpected start tag token (mi) in the frameset phase. Ignored.
-Line: 1 Col: 49 Unexpected end tag token (mi) in the frameset phase. Ignored.
-Line: 1 Col: 52 Unexpected start tag token (p) in the frameset phase. Ignored.
-Line: 1 Col: 58 Unexpected start tag token (span) in the frameset phase. Ignored.
-Line: 1 Col: 58 Expected closing tag. Unexpected end of file.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><frameset></frameset><math><mi></mi><mi></mi><p><span>
-#errors
-Line: 1 Col: 42 Unexpected start tag (math) in the after frameset phase. Ignored.
-Line: 1 Col: 46 Unexpected start tag (mi) in the after frameset phase. Ignored.
-Line: 1 Col: 51 Unexpected end tag (mi) in the after frameset phase. Ignored.
-Line: 1 Col: 55 Unexpected start tag (mi) in the after frameset phase. Ignored.
-Line: 1 Col: 60 Unexpected end tag (mi) in the after frameset phase. Ignored.
-Line: 1 Col: 63 Unexpected start tag (p) in the after frameset phase. Ignored.
-Line: 1 Col: 69 Unexpected start tag (span) in the after frameset phase. Ignored.
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <frameset>
-
-#data
-<!DOCTYPE html><body xlink:href=foo><math xlink:href=foo></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| <math math>
-| xlink href="foo"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo></mi></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <math math>
-| <math mi>
-| xlink href="foo"
-| xml lang="en"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo /></math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <math math>
-| <math mi>
-| xlink href="foo"
-| xml lang="en"
-
-#data
-<!DOCTYPE html><body xlink:href=foo xml:lang=en><math><mi xml:lang=en xlink:href=foo />bar</math>
-#errors
-#document
-| <!DOCTYPE html>
-| <html>
-| <head>
-| <body>
-| xlink:href="foo"
-| xml:lang="en"
-| <math math>
-| <math mi>
-| xlink href="foo"
-| xml lang="en"
-| "bar"
diff --git a/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat b/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
deleted file mode 100644
index 052fac7d5..000000000
--- a/src/pkg/html/testdata/webkit/tests_innerHTML_1.dat
+++ /dev/null
@@ -1,733 +0,0 @@
-#data
-<body><span>
-#errors
-#document-fragment
-body
-#document
-| <span>
-
-#data
-<span><body>
-#errors
-#document-fragment
-body
-#document
-| <span>
-
-#data
-<span><body>
-#errors
-#document-fragment
-div
-#document
-| <span>
-
-#data
-<body><span>
-#errors
-#document-fragment
-html
-#document
-| <head>
-| <body>
-| <span>
-
-#data
-<frameset><span>
-#errors
-#document-fragment
-body
-#document
-| <span>
-
-#data
-<span><frameset>
-#errors
-#document-fragment
-body
-#document
-| <span>
-
-#data
-<span><frameset>
-#errors
-#document-fragment
-div
-#document
-| <span>
-
-#data
-<frameset><span>
-#errors
-#document-fragment
-html
-#document
-| <head>
-| <frameset>
-
-#data
-<table><tr>
-#errors
-#document-fragment
-table
-#document
-| <tbody>
-| <tr>
-
-#data
-</table><tr>
-#errors
-#document-fragment
-table
-#document
-| <tbody>
-| <tr>
-
-#data
-<a>
-#errors
-#document-fragment
-table
-#document
-| <a>
-
-#data
-<a>
-#errors
-#document-fragment
-table
-#document
-| <a>
-
-#data
-<a><caption>a
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <caption>
-| "a"
-
-#data
-<a><colgroup><col>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <colgroup>
-| <col>
-
-#data
-<a><tbody><tr>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <tbody>
-| <tr>
-
-#data
-<a><tfoot><tr>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <tfoot>
-| <tr>
-
-#data
-<a><thead><tr>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <thead>
-| <tr>
-
-#data
-<a><tr>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <tbody>
-| <tr>
-
-#data
-<a><th>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <tbody>
-| <tr>
-| <th>
-
-#data
-<a><td>
-#errors
-#document-fragment
-table
-#document
-| <a>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table></table><tbody>
-#errors
-#document-fragment
-caption
-#document
-| <table>
-
-#data
-</table><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-
-#data
-<span></table>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-
-#data
-</caption><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-
-#data
-<span></caption><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><caption><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><col><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><colgroup><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><html><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><tbody><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><td><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><tfoot><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><thead><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><th><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span><tr><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-<span></table><span>
-#errors
-#document-fragment
-caption
-#document
-| <span>
-| <span>
-
-#data
-</colgroup><col>
-#errors
-#document-fragment
-colgroup
-#document
-| <col>
-
-#data
-<a><col>
-#errors
-#document-fragment
-colgroup
-#document
-| <col>
-
-#data
-<caption><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<col><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<colgroup><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<tbody><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<tfoot><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<thead><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-</table><a>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-
-#data
-<a><tr>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-| <tr>
-
-#data
-<a><td>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-| <tr>
-| <td>
-
-#data
-<a><td>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-| <tr>
-| <td>
-
-#data
-<a><td>
-#errors
-#document-fragment
-tbody
-#document
-| <a>
-| <tr>
-| <td>
-
-#data
-<td><table><tbody><a><tr>
-#errors
-#document-fragment
-tbody
-#document
-| <tr>
-| <td>
-| <a>
-| <table>
-| <tbody>
-| <tr>
-
-#data
-</tr><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<td><table><a><tr></tr><tr>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-| <a>
-| <table>
-| <tbody>
-| <tr>
-| <tr>
-
-#data
-<caption><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<col><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<colgroup><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<tbody><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<tfoot><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<thead><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<tr><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-</table><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-
-#data
-<td><table></table><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-| <table>
-| <td>
-
-#data
-<td><table></table><td>
-#errors
-#document-fragment
-tr
-#document
-| <td>
-| <table>
-| <td>
-
-#data
-<caption><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<col><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<colgroup><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<tbody><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<tfoot><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<th><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<thead><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<tr><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</table><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</tbody><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</td><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</tfoot><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</thead><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</th><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-</tr><a>
-#errors
-#document-fragment
-td
-#document
-| <a>
-
-#data
-<table><td><td>
-#errors
-#document-fragment
-td
-#document
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| <td>
-
-#data
-</select><option>
-#errors
-#document-fragment
-select
-#document
-| <option>
-
-#data
-<input><option>
-#errors
-#document-fragment
-select
-#document
-| <option>
-
-#data
-<keygen><option>
-#errors
-#document-fragment
-select
-#document
-| <option>
-
-#data
-<textarea><option>
-#errors
-#document-fragment
-select
-#document
-| <option>
-
-#data
-</html><!--abc-->
-#errors
-#document-fragment
-html
-#document
-| <head>
-| <body>
-| <!-- abc -->
-
-#data
-</frameset><frame>
-#errors
-#document-fragment
-frameset
-#document
-| <frame>
diff --git a/src/pkg/html/testdata/webkit/tricky01.dat b/src/pkg/html/testdata/webkit/tricky01.dat
deleted file mode 100644
index 084199244..000000000
--- a/src/pkg/html/testdata/webkit/tricky01.dat
+++ /dev/null
@@ -1,261 +0,0 @@
-#data
-<b><p>Bold </b> Not bold</p>
-Also not bold.
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <b>
-| <p>
-| <b>
-| "Bold "
-| " Not bold"
-| "
-Also not bold."
-
-#data
-<html>
-<font color=red><i>Italic and Red<p>Italic and Red </font> Just italic.</p> Italic only.</i> Plain
-<p>I should not be red. <font color=red>Red. <i>Italic and red.</p>
-<p>Italic and red. </i> Red.</font> I should not be red.</p>
-<b>Bold <i>Bold and italic</b> Only Italic </i> Plain
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <font>
-| color="red"
-| <i>
-| "Italic and Red"
-| <i>
-| <p>
-| <font>
-| color="red"
-| "Italic and Red "
-| " Just italic."
-| " Italic only."
-| " Plain
-"
-| <p>
-| "I should not be red. "
-| <font>
-| color="red"
-| "Red. "
-| <i>
-| "Italic and red."
-| <font>
-| color="red"
-| <i>
-| "
-"
-| <p>
-| <font>
-| color="red"
-| <i>
-| "Italic and red. "
-| " Red."
-| " I should not be red."
-| "
-"
-| <b>
-| "Bold "
-| <i>
-| "Bold and italic"
-| <i>
-| " Only Italic "
-| " Plain"
-
-#data
-<html><body>
-<p><font size="7">First paragraph.</p>
-<p>Second paragraph.</p></font>
-<b><p><i>Bold and Italic</b> Italic</p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "
-"
-| <p>
-| <font>
-| size="7"
-| "First paragraph."
-| <font>
-| size="7"
-| "
-"
-| <p>
-| "Second paragraph."
-| "
-"
-| <b>
-| <p>
-| <b>
-| <i>
-| "Bold and Italic"
-| <i>
-| " Italic"
-
-#data
-<html>
-<dl>
-<dt><b>Boo
-<dd>Goo?
-</dl>
-</html>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <dl>
-| "
-"
-| <dt>
-| <b>
-| "Boo
-"
-| <dd>
-| <b>
-| "Goo?
-"
-| <b>
-| "
-"
-
-#data
-<html><body>
-<label><a><div>Hello<div>World</div></a></label>
-</body></html>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "
-"
-| <label>
-| <a>
-| <div>
-| <a>
-| "Hello"
-| <div>
-| "World"
-| "
-"
-
-#data
-<table><center> <font>a</center> <img> <tr><td> </td> </tr> </table>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <center>
-| " "
-| <font>
-| "a"
-| <font>
-| <img>
-| " "
-| <table>
-| " "
-| <tbody>
-| <tr>
-| <td>
-| " "
-| " "
-| " "
-
-#data
-<table><tr><p><a><p>You should see this text.
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| <a>
-| <p>
-| <a>
-| "You should see this text."
-| <table>
-| <tbody>
-| <tr>
-
-#data
-<TABLE>
-<TR>
-<CENTER><CENTER><TD></TD></TR><TR>
-<FONT>
-<TABLE><tr></tr></TABLE>
-</P>
-<a></font><font></a>
-This page contains an insanely badly-nested tag sequence.
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <center>
-| <center>
-| <font>
-| "
-"
-| <table>
-| "
-"
-| <tbody>
-| <tr>
-| "
-"
-| <td>
-| <tr>
-| "
-"
-| <table>
-| <tbody>
-| <tr>
-| <font>
-| "
-"
-| <p>
-| "
-"
-| <a>
-| <a>
-| <font>
-| <font>
-| "
-This page contains an insanely badly-nested tag sequence."
-
-#data
-<html>
-<body>
-<b><nobr><div>This text is in a div inside a nobr</nobr>More text that should not be in the nobr, i.e., the
-nobr should have closed the div inside it implicitly. </b><pre>A pre tag outside everything else.</pre>
-</body>
-</html>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "
-"
-| <b>
-| <nobr>
-| <div>
-| <b>
-| <nobr>
-| "This text is in a div inside a nobr"
-| "More text that should not be in the nobr, i.e., the
-nobr should have closed the div inside it implicitly. "
-| <pre>
-| "A pre tag outside everything else."
-| "
-
-"
diff --git a/src/pkg/html/testdata/webkit/webkit01.dat b/src/pkg/html/testdata/webkit/webkit01.dat
deleted file mode 100644
index 4101b216e..000000000
--- a/src/pkg/html/testdata/webkit/webkit01.dat
+++ /dev/null
@@ -1,609 +0,0 @@
-#data
-Test
-#errors
-Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE.
-#document
-| <html>
-| <head>
-| <body>
-| "Test"
-
-#data
-<div></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-
-#data
-<div>Test</div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "Test"
-
-#data
-<di
-#errors
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<div>Hello</div>
-<script>
-console.log("PASS");
-</script>
-<div>Bye</div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "Hello"
-| "
-"
-| <script>
-| "
-console.log("PASS");
-"
-| "
-"
-| <div>
-| "Bye"
-
-#data
-<div foo="bar">Hello</div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| foo="bar"
-| "Hello"
-
-#data
-<div>Hello</div>
-<script>
-console.log("FOO<span>BAR</span>BAZ");
-</script>
-<div>Bye</div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| "Hello"
-| "
-"
-| <script>
-| "
-console.log("FOO<span>BAR</span>BAZ");
-"
-| "
-"
-| <div>
-| "Bye"
-
-#data
-<foo bar="baz"></foo><potato quack="duck"></potato>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| bar="baz"
-| <potato>
-| quack="duck"
-
-#data
-<foo bar="baz"><potato quack="duck"></potato></foo>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| bar="baz"
-| <potato>
-| quack="duck"
-
-#data
-<foo></foo bar="baz"><potato></potato quack="duck">
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| <potato>
-
-#data
-</ tttt>
-#errors
-#document
-| <!-- tttt -->
-| <html>
-| <head>
-| <body>
-
-#data
-<div FOO ><img><img></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| foo=""
-| <img>
-| <img>
-
-#data
-<p>Test</p<p>Test2</p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| "TestTest2"
-
-#data
-<rdar://problem/6869687>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <rdar:>
-| 6869687=""
-| problem=""
-
-#data
-<A>test< /A>
-#errors
-#document
-| <html>
-| <head>
-| <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/src/pkg/html/testdata/webkit/webkit02.dat b/src/pkg/html/testdata/webkit/webkit02.dat
deleted file mode 100644
index 2218f4298..000000000
--- a/src/pkg/html/testdata/webkit/webkit02.dat
+++ /dev/null
@@ -1,104 +0,0 @@
-#data
-<foo bar=qux/>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <foo>
-| bar="qux/"
-
-#data
-<p id="status"><noscript><strong>A</strong></noscript><span>B</span></p>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <p>
-| id="status"
-| <noscript>
-| "<strong>A</strong>"
-| <span>
-| "B"
-
-#data
-<div><sarcasm><div></div></sarcasm></div>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <div>
-| <sarcasm>
-| <div>
-
-#data
-<html><body><img src="" border="0" alt="><div>A</div></body></html>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-
-#data
-<table><td></tbody>A
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "A"
-| <table>
-| <tbody>
-| <tr>
-| <td>
-
-#data
-<table><td></thead>A
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "A"
-
-#data
-<table><td></tfoot>A
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <tbody>
-| <tr>
-| <td>
-| "A"
-
-#data
-<table><thead><td></tbody>A
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <table>
-| <thead>
-| <tr>
-| <td>
-| "A"
-
-#data
-<legend>test</legend>
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| <legend>
-| "test"
diff --git a/src/pkg/html/token.go b/src/pkg/html/token.go
deleted file mode 100644
index d266b3a30..000000000
--- a/src/pkg/html/token.go
+++ /dev/null
@@ -1,575 +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 html
-
-import (
- "bytes"
- "io"
- "os"
- "strconv"
-)
-
-// A TokenType is the type of a Token.
-type TokenType int
-
-const (
- // ErrorToken means that an error occurred during tokenization.
- ErrorToken TokenType = iota
- // TextToken means a text node.
- TextToken
- // A StartTagToken looks like <a>.
- StartTagToken
- // An EndTagToken looks like </a>.
- EndTagToken
- // A SelfClosingTagToken tag looks like <br/>.
- SelfClosingTagToken
- // A CommentToken looks like <!--x-->.
- CommentToken
- // A DoctypeToken looks like <!DOCTYPE x>
- DoctypeToken
-)
-
-// String returns a string representation of the TokenType.
-func (t TokenType) String() string {
- switch t {
- case ErrorToken:
- return "Error"
- case TextToken:
- return "Text"
- case StartTagToken:
- return "StartTag"
- case EndTagToken:
- return "EndTag"
- case SelfClosingTagToken:
- return "SelfClosingTag"
- case CommentToken:
- return "Comment"
- case DoctypeToken:
- return "Doctype"
- }
- return "Invalid(" + strconv.Itoa(int(t)) + ")"
-}
-
-// An Attribute is an attribute key-value pair. Key is alphabetic (and hence
-// does not contain escapable characters like '&', '<' or '>'), and Val is
-// unescaped (it looks like "a<b" rather than "a&lt;b").
-type Attribute struct {
- Key, Val string
-}
-
-// A Token consists of a TokenType and some Data (tag name for start and end
-// tags, content for text, 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
- Attr []Attribute
-}
-
-// tagString returns a string representation of a tag Token's Data and Attr.
-func (t Token) tagString() string {
- if len(t.Attr) == 0 {
- return t.Data
- }
- buf := bytes.NewBuffer(nil)
- buf.WriteString(t.Data)
- for _, a := range t.Attr {
- buf.WriteByte(' ')
- buf.WriteString(a.Key)
- buf.WriteString(`="`)
- escape(buf, a.Val)
- buf.WriteByte('"')
- }
- return buf.String()
-}
-
-// String returns a string representation of the Token.
-func (t Token) String() string {
- switch t.Type {
- case ErrorToken:
- return ""
- case TextToken:
- return EscapeString(t.Data)
- case StartTagToken:
- return "<" + t.tagString() + ">"
- case EndTagToken:
- return "</" + t.tagString() + ">"
- case SelfClosingTagToken:
- return "<" + t.tagString() + "/>"
- case CommentToken:
- return "<!--" + EscapeString(t.Data) + "-->"
- case DoctypeToken:
- return "<!DOCTYPE " + EscapeString(t.Data) + ">"
- }
- return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
-}
-
-// A Tokenizer returns a stream of HTML Tokens.
-type Tokenizer struct {
- // If ReturnComments is set, Next returns comment tokens;
- // otherwise it skips over comments (default).
- ReturnComments bool
-
- // r is the source of the HTML text.
- r io.Reader
- // 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.
- p0, p1 int
- buf []byte
-}
-
-// Error returns the error associated with the most recent ErrorToken token.
-// This is typically os.EOF, meaning the end of tokenization.
-func (z *Tokenizer) Error() os.Error {
- if z.tt != ErrorToken {
- return nil
- }
- return z.err
-}
-
-// Raw returns the unmodified text of the current token. Calling Next, Token,
-// Text, TagName or TagAttr may change the contents of the returned slice.
-func (z *Tokenizer) Raw() []byte {
- return z.buf[z.p0:z.p1]
-}
-
-// readByte returns the next byte from the input stream, doing a buffered read
-// from z.r into z.buf if necessary. z.buf[z.p0:z.p1] remains a contiguous byte
-// slice that holds all the bytes read so far for the current token.
-// 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
- // z.p1 - z.p0 is more than half the capacity of z.buf, then we
- // allocate a new buffer before the copy.
- c := cap(z.buf)
- d := z.p1 - z.p0
- var buf1 []byte
- if 2*d > c {
- buf1 = make([]byte, d, 2*c)
- } else {
- buf1 = z.buf[:d]
- }
- copy(buf1, z.buf[z.p0:z.p1])
- 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 {
- z.err = err
- return 0
- }
- z.buf = buf1[:d+n]
- }
- x := z.buf[z.p1]
- z.p1++
- return x
-}
-
-// 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 := z.readByte()
- if z.err != nil {
- return
- }
- switch c {
- case x:
- return
- case '\\':
- z.readByte()
- if z.err != nil {
- return
- }
- }
- }
-}
-
-// 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 := z.readByte()
- if z.err != nil {
- return
- }
- switch c {
- case '-':
- dashCount++
- case '>':
- if dashCount >= 2 {
- z.tt = CommentToken
- return
- }
- dashCount = 0
- default:
- dashCount = 0
- }
- }
-}
-
-// 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 == '/':
- 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':
- z.tt = StartTagToken
- case c == '!':
- z.nextMarkupDeclaration()
- return
- case c == '?':
- z.tt, z.err = ErrorToken, os.NewError("html: TODO: implement XML processing instructions")
- return
- default:
- z.tt, z.err = ErrorToken, os.NewError("html: TODO: handle malformed tags")
- return
- }
- for {
- c := z.readByte()
- if z.err != nil {
- return
- }
- switch c {
- case '"', '\'':
- z.readTo(c)
- if z.err != nil {
- return
- }
- case '>':
- if z.buf[z.p1-2] == '/' && z.tt == StartTagToken {
- z.tt = SelfClosingTagToken
- }
- return
- }
- }
-}
-
-// nextText reads all text up until an '<'.
-// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 1 <= z.p1.
-func (z *Tokenizer) nextText() {
- for {
- c := z.readByte()
- if z.err != nil {
- return
- }
- if c == '<' {
- z.p1--
- return
- }
- }
-}
-
-// Next scans the next token and returns its type.
-func (z *Tokenizer) Next() TokenType {
- for {
- if z.err != nil {
- z.tt = ErrorToken
- return z.tt
- }
- z.p0 = z.p1
- c := z.readByte()
- if z.err != nil {
- z.tt = ErrorToken
- return z.tt
- }
- // 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
- }
- panic("unreachable")
-}
-
-// trim returns the largest j such that z.buf[i:j] contains only white space,
-// or only white space plus the final ">" or "/>" of the raw data.
-func (z *Tokenizer) trim(i int) int {
- k := z.p1
- for ; i < k; i++ {
- switch z.buf[i] {
- case ' ', '\n', '\t', '\f':
- continue
- case '>':
- if i == k-1 {
- return k
- }
- case '/':
- if i == k-2 {
- return k
- }
- }
- return i
- }
- return k
-}
-
-// 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 'A' <= c && c <= 'Z':
- z.buf[i] = c + 'a' - 'A'
- case c > ' ' && c < 0x7f:
- // No-op.
- default:
- break loop
- }
- }
- return z.buf[i0:i], z.trim(i)
-}
-
-// 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:
- i0 = z.p0
- i1 = z.p1
- case CommentToken:
- // 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
- 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
-}
-
-// TagName returns the lower-cased name of a tag token (the `img` out of
-// `<IMG SRC="foo">`) and whether the tag has attributes.
-// The contents of the returned slice may change on the next call to Next.
-func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
- i := z.p0 + 1
- if i >= z.p1 {
- z.p0 = z.p1
- return nil, false
- }
- if z.buf[i] == '/' {
- i++
- }
- name, z.p0 = z.tagName(i)
- hasAttr = z.p0 != z.p1
- return
-}
-
-// TagAttr returns the lower-cased key and unescaped value of the next unparsed
-// attribute for the current tag token and whether there are more attributes.
-// The contents of the returned slices may change on the next call to Next.
-func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
- 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.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 quote.
- dst, src := i, i
-loop:
- for src < z.p1 {
- c := z.buf[src]
- switch c {
- case closeQuote:
- src++
- break loop
- case '&':
- dst, src = unescapeEntity(z.buf, dst, src, true)
- case '\\':
- if src == z.p1 {
- z.buf[dst] = '\\'
- dst++
- } else {
- z.buf[dst] = z.buf[src+1]
- dst, src = dst+1, src+2
- }
- default:
- z.buf[dst] = c
- dst, src = dst+1, src+1
- }
- }
- val, z.p0 = z.buf[i:dst], z.trim(src)
- moreAttr = z.p0 != z.p1
- return
-}
-
-// Token returns the next Token. The result's Data and Attr values remain valid
-// after subsequent Next calls.
-func (z *Tokenizer) Token() Token {
- t := Token{Type: z.tt}
- switch z.tt {
- case TextToken, CommentToken, DoctypeToken:
- t.Data = string(z.Text())
- case StartTagToken, EndTagToken, SelfClosingTagToken:
- var attr []Attribute
- name, moreAttr := z.TagName()
- for moreAttr {
- var key, val []byte
- key, val, moreAttr = z.TagAttr()
- attr = append(attr, Attribute{string(key), string(val)})
- }
- t.Data = string(name)
- t.Attr = attr
- }
- return t
-}
-
-// NewTokenizer returns a new HTML Tokenizer for the given Reader.
-// The input is assumed to be UTF-8 encoded.
-func NewTokenizer(r io.Reader) *Tokenizer {
- return &Tokenizer{
- r: r,
- buf: make([]byte, 0, 4096),
- }
-}
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
deleted file mode 100644
index 0a0beb201..000000000
--- a/src/pkg/html/token_test.go
+++ /dev/null
@@ -1,340 +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 html
-
-import (
- "bytes"
- "os"
- "strings"
- "testing"
-)
-
-type tokenTest struct {
- // A short description of the test case.
- desc string
- // The HTML to parse.
- html string
- // The string representations of the expected tokens, joined by '$'.
- golden string
-}
-
-var tokenTests = []tokenTest{
- // A single text node. The tokenizer should not break text nodes on whitespace,
- // nor should it normalize whitespace within a text node.
- {
- "text",
- "foo bar",
- "foo bar",
- },
- // An entity.
- {
- "entity",
- "one &lt; two",
- "one &lt; two",
- },
- // A start, self-closing and end tag. The tokenizer does not care if the start
- // and end tokens don't match; that is the job of the parser.
- {
- "tags",
- "<a>b<c/>d</e>",
- "<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",
- "abc<b><!-- skipme --></b>def",
- "abc$<b>$</b>$def",
- },
- {
- "comment1",
- "a<!-->z",
- "a$z",
- },
- {
- "comment2",
- "a<!--->z",
- "a$z",
- },
- {
- "comment3",
- "a<!--x>-->z",
- "a$z",
- },
- {
- "comment4",
- "a<!--x->-->z",
- "a$z",
- },
- {
- "comment5",
- "a<!>z",
- "a$&lt;!&gt;z",
- },
- {
- "comment6",
- "a<!->z",
- "a$&lt;!-&gt;z",
- },
- {
- "comment7",
- "a<!---<>z",
- "a$&lt;!---&lt;&gt;z",
- },
- {
- "comment8",
- "a<!--z",
- "a$&lt;!--z",
- },
- // An attribute with a backslash.
- {
- "backslash",
- `<p id="a\"b">`,
- `<p id="a&quot;b">`,
- },
- // Entities, tag name and attribute key lower-casing, and whitespace
- // normalization within a tag.
- {
- "tricky",
- "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
- `<p id="a&quot;B" foo="bar">$<em>$te&lt;&amp;;xt$</em>$</p>`,
- },
- // 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, "$") {
- if z.Next() == ErrorToken {
- t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
- continue loop
- }
- actual := z.Token().String()
- if s != actual {
- t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual)
- continue loop
- }
- }
- z.Next()
- if z.Error() != os.EOF {
- t.Errorf("%s: want EOF got %q", tt.desc, z.Token().String())
- }
- }
-}
-
-type unescapeTest struct {
- // A short description of the test case.
- desc string
- // The HTML text.
- html string
- // The unescaped text.
- unescaped string
-}
-
-var unescapeTests = []unescapeTest{
- // Handle no entities.
- {
- "copy",
- "A\ttext\nstring",
- "A\ttext\nstring",
- },
- // Handle simple named entities.
- {
- "simple",
- "&amp; &gt; &lt;",
- "& > <",
- },
- // Handle hitting the end of the string.
- {
- "stringEnd",
- "&amp &amp",
- "& &",
- },
- // Handle entities with two codepoints.
- {
- "multiCodepoint",
- "text &gesl; blah",
- "text \u22db\ufe00 blah",
- },
- // Handle decimal numeric entities.
- {
- "decimalEntity",
- "Delta = &#916; ",
- "Delta = Δ ",
- },
- // Handle hexadecimal numeric entities.
- {
- "hexadecimalEntity",
- "Lambda = &#x3bb; = &#X3Bb ",
- "Lambda = λ = λ ",
- },
- // Handle numeric early termination.
- {
- "numericEnds",
- "&# &#x &#128;43 &copy = &#169f = &#xa9",
- "&# &#x €43 © = ©f = ©",
- },
- // Handle numeric ISO-8859-1 entity replacements.
- {
- "numericReplacements",
- "Footnote&#x87;",
- "Footnote‡",
- },
-}
-
-func TestUnescape(t *testing.T) {
- for _, tt := range unescapeTests {
- unescaped := UnescapeString(tt.html)
- if unescaped != tt.unescaped {
- t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped)
- }
- }
-}
-
-func TestUnescapeEscape(t *testing.T) {
- ss := []string{
- ``,
- `abc def`,
- `a & b`,
- `a&amp;b`,
- `a &amp b`,
- `&quot;`,
- `"`,
- `"<&>"`,
- `&quot;&lt;&amp;&gt;&quot;`,
- `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
- }
- for _, s := range ss {
- if s != UnescapeString(EscapeString(s)) {
- t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s)
- }
- }
-}
-
-func TestBufAPI(t *testing.T) {
- s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
- z := NewTokenizer(bytes.NewBuffer([]byte(s)))
- result := bytes.NewBuffer(nil)
- depth := 0
-loop:
- for {
- tt := z.Next()
- switch tt {
- case ErrorToken:
- if z.Error() != os.EOF {
- t.Error(z.Error())
- }
- break loop
- case TextToken:
- if depth > 0 {
- result.Write(z.Text())
- }
- case StartTagToken, EndTagToken:
- tn, _ := z.TagName()
- if len(tn) == 1 && tn[0] == 'a' {
- if tt == StartTagToken {
- depth++
- } else {
- depth--
- }
- }
- }
- }
- u := "14567"
- v := string(result.Bytes())
- if u != v {
- t.Errorf("TestBufAPI: want %q got %q", u, v)
- }
-}
diff --git a/src/pkg/http/Makefile b/src/pkg/http/Makefile
deleted file mode 100644
index df4ab9510..000000000
--- a/src/pkg/http/Makefile
+++ /dev/null
@@ -1,26 +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.
-
-include ../../Make.inc
-
-TARG=http
-GOFILES=\
- chunked.go\
- client.go\
- cookie.go\
- dump.go\
- fs.go\
- header.go\
- lex.go\
- persist.go\
- request.go\
- response.go\
- reverseproxy.go\
- server.go\
- sniff.go\
- status.go\
- transfer.go\
- transport.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/http/cgi/Makefile b/src/pkg/http/cgi/Makefile
deleted file mode 100644
index 19b1039c2..000000000
--- a/src/pkg/http/cgi/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=http/cgi
-GOFILES=\
- child.go\
- host.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/http/chunked.go b/src/pkg/http/chunked.go
deleted file mode 100644
index 6c23e691f..000000000
--- a/src/pkg/http/chunked.go
+++ /dev/null
@@ -1,77 +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 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
-// 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 underlying Wire writer.
-type chunkedWriter struct {
- Wire io.Writer
-}
-
-// Write the contents of data as one chunk to Wire.
-// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
-// a bug since it does not check for success of io.WriteString
-func (cw *chunkedWriter) Write(data []byte) (n int, err os.Error) {
-
- // Don't send 0-length data. It looks like EOF for chunked encoding.
- if len(data) == 0 {
- return 0, nil
- }
-
- head := strconv.Itob(len(data), 16) + "\r\n"
-
- if _, err = io.WriteString(cw.Wire, head); err != nil {
- return 0, err
- }
- if n, err = cw.Wire.Write(data); err != nil {
- return
- }
- if n != len(data) {
- err = io.ErrShortWrite
- return
- }
- _, err = io.WriteString(cw.Wire, "\r\n")
-
- return
-}
-
-func (cw *chunkedWriter) Close() os.Error {
- _, err := io.WriteString(cw.Wire, "0\r\n")
- return err
-}
-
-// 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/src/pkg/http/dump.go b/src/pkg/http/dump.go
deleted file mode 100644
index 358980f7c..000000000
--- a/src/pkg/http/dump.go
+++ /dev/null
@@ -1,78 +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 http
-
-import (
- "bytes"
- "io"
- "io/ioutil"
- "os"
-)
-
-// One of the copies, say from b to r2, could be avoided by using a more
-// elaborate trick where the other copy is made during Request/Response.Write.
-// This would complicate things too much, given that these functions are for
-// debugging only.
-func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err os.Error) {
- var buf bytes.Buffer
- if _, err = buf.ReadFrom(b); err != nil {
- return nil, nil, err
- }
- if err = b.Close(); err != nil {
- return nil, nil, err
- }
- return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
-}
-
-// DumpRequest returns the wire representation of req,
-// optionally including the request body, for debugging.
-// DumpRequest is semantically a no-op, but in order to
-// dump the body, it reads the body data into memory and
-// changes req.Body to refer to the in-memory copy.
-// The documentation for Request.Write details which fields
-// of req are used.
-func DumpRequest(req *Request, body bool) (dump []byte, err os.Error) {
- var b bytes.Buffer
- save := req.Body
- if !body || req.Body == nil {
- req.Body = nil
- } else {
- save, req.Body, err = drainBody(req.Body)
- if err != nil {
- return
- }
- }
- err = req.Write(&b)
- req.Body = save
- if err != nil {
- return
- }
- dump = b.Bytes()
- return
-}
-
-// DumpResponse is like DumpRequest but dumps a response.
-func DumpResponse(resp *Response, body bool) (dump []byte, err os.Error) {
- var b bytes.Buffer
- save := resp.Body
- savecl := resp.ContentLength
- if !body || resp.Body == nil {
- resp.Body = nil
- resp.ContentLength = 0
- } else {
- save, resp.Body, err = drainBody(resp.Body)
- if err != nil {
- return
- }
- }
- err = resp.Write(&b)
- resp.Body = save
- resp.ContentLength = savecl
- if err != nil {
- return
- }
- dump = b.Bytes()
- return
-}
diff --git a/src/pkg/http/fcgi/Makefile b/src/pkg/http/fcgi/Makefile
deleted file mode 100644
index bc01cdea9..000000000
--- a/src/pkg/http/fcgi/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=http/fcgi
-GOFILES=\
- child.go\
- fcgi.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/http/httptest/Makefile b/src/pkg/http/httptest/Makefile
deleted file mode 100644
index eb35d8aec..000000000
--- a/src/pkg/http/httptest/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=http/httptest
-GOFILES=\
- recorder.go\
- server.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/http/reverseproxy_test.go b/src/pkg/http/reverseproxy_test.go
deleted file mode 100644
index 8078c8d10..000000000
--- a/src/pkg/http/reverseproxy_test.go
+++ /dev/null
@@ -1,66 +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.
-
-// Reverse proxy tests.
-
-package http_test
-
-import (
- . "http"
- "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 := url.Parse(backend.URL)
- if err != nil {
- t.Fatal(err)
- }
- proxyHandler := NewSingleHostReverseProxy(backendURL)
- frontend := httptest.NewServer(proxyHandler)
- defer frontend.Close()
-
- getReq, _ := NewRequest("GET", frontend.URL, nil)
- getReq.Host = "some-name"
- res, err := DefaultClient.Do(getReq)
- if err != nil {
- t.Fatalf("Get: %v", err)
- }
- if g, e := res.StatusCode, backendStatus; g != e {
- t.Errorf("got res.StatusCode %d; expected %d", g, e)
- }
- 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/src/pkg/http/spdy/Makefile b/src/pkg/http/spdy/Makefile
deleted file mode 100644
index 3bec220c4..000000000
--- a/src/pkg/http/spdy/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=http/spdy
-GOFILES=\
- read.go\
- types.go\
- write.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/http/spdy/read.go b/src/pkg/http/spdy/read.go
deleted file mode 100644
index c6b6ab3af..000000000
--- a/src/pkg/http/spdy/read.go
+++ /dev/null
@@ -1,313 +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 (
- "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/src/pkg/http/spdy/spdy_test.go b/src/pkg/http/spdy/spdy_test.go
deleted file mode 100644
index cb91e0286..000000000
--- a/src/pkg/http/spdy/spdy_test.go
+++ /dev/null
@@ -1,497 +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"
- "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/src/pkg/http/spdy/types.go b/src/pkg/http/spdy/types.go
deleted file mode 100644
index 41cafb174..000000000
--- a/src/pkg/http/spdy/types.go
+++ /dev/null
@@ -1,370 +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"
- "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/src/pkg/http/spdy/write.go b/src/pkg/http/spdy/write.go
deleted file mode 100644
index 7d40bbe9f..000000000
--- a/src/pkg/http/spdy/write.go
+++ /dev/null
@@ -1,286 +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 (
- "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/src/pkg/image/Makefile b/src/pkg/image/Makefile
deleted file mode 100644
index 739ad804b..000000000
--- a/src/pkg/image/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../Make.inc
-
-TARG=image
-GOFILES=\
- color.go\
- format.go\
- geom.go\
- image.go\
- names.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/image/bmp/Makefile b/src/pkg/image/bmp/Makefile
deleted file mode 100644
index 56635f7ce..000000000
--- a/src/pkg/image/bmp/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=image/bmp
-GOFILES=\
- reader.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/bmp/reader.go b/src/pkg/image/bmp/reader.go
deleted file mode 100644
index 357da1dac..000000000
--- a/src/pkg/image/bmp/reader.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package bmp implements a BMP image decoder.
-//
-// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
-package bmp
-
-import (
- "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/src/pkg/image/color.go b/src/pkg/image/color.go
deleted file mode 100644
index 501a882f0..000000000
--- a/src/pkg/image/color.go
+++ /dev/null
@@ -1,251 +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 image
-
-// 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)
-}
-
-// RGBAColor represents a traditional 32-bit alpha-premultiplied color,
-// having 8 bits for each of red, green, blue and alpha.
-type RGBAColor struct {
- R, G, B, A uint8
-}
-
-func (c RGBAColor) RGBA() (r, g, b, a uint32) {
- r = uint32(c.R)
- r |= r << 8
- g = uint32(c.G)
- g |= g << 8
- b = uint32(c.B)
- b |= b << 8
- a = uint32(c.A)
- a |= a << 8
- return
-}
-
-// RGBA64Color represents a 64-bit alpha-premultiplied color,
-// having 16 bits for each of red, green, blue and alpha.
-type RGBA64Color struct {
- R, G, B, A uint16
-}
-
-func (c RGBA64Color) RGBA() (r, g, b, a uint32) {
- return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
-}
-
-// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
-type NRGBAColor struct {
- R, G, B, A uint8
-}
-
-func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
- r = uint32(c.R)
- r |= r << 8
- r *= uint32(c.A)
- r /= 0xff
- g = uint32(c.G)
- g |= g << 8
- g *= uint32(c.A)
- g /= 0xff
- b = uint32(c.B)
- b |= b << 8
- b *= uint32(c.A)
- b /= 0xff
- a = uint32(c.A)
- a |= a << 8
- return
-}
-
-// NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
-// having 16 bits for each of red, green, blue and alpha.
-type NRGBA64Color struct {
- R, G, B, A uint16
-}
-
-func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
- r = uint32(c.R)
- r *= uint32(c.A)
- r /= 0xffff
- g = uint32(c.G)
- g *= uint32(c.A)
- g /= 0xffff
- b = uint32(c.B)
- b *= uint32(c.A)
- b /= 0xffff
- a = uint32(c.A)
- return
-}
-
-// AlphaColor represents an 8-bit alpha.
-type AlphaColor struct {
- A uint8
-}
-
-func (c AlphaColor) RGBA() (r, g, b, a uint32) {
- a = uint32(c.A)
- a |= a << 8
- return a, a, a, a
-}
-
-// Alpha16Color represents a 16-bit alpha.
-type Alpha16Color struct {
- A uint16
-}
-
-func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
- a = uint32(c.A)
- return a, a, a, a
-}
-
-// GrayColor represents an 8-bit grayscale color.
-type GrayColor struct {
- Y uint8
-}
-
-func (c GrayColor) RGBA() (r, g, b, a uint32) {
- y := uint32(c.Y)
- y |= y << 8
- return y, y, y, 0xffff
-}
-
-// Gray16Color represents a 16-bit grayscale color.
-type Gray16Color struct {
- Y uint16
-}
-
-func (c Gray16Color) RGBA() (r, g, b, a uint32) {
- y := uint32(c.Y)
- return y, y, y, 0xffff
-}
-
-// ColorModel can convert foreign Colors, with a possible loss of precision,
-// to a Color from its own color model.
-type ColorModel interface {
- Convert(c Color) Color
-}
-
-// The ColorModelFunc type is an adapter to allow the use of an ordinary
-// color conversion function as a ColorModel. If f is such a function,
-// ColorModelFunc(f) is a ColorModel object that invokes f to implement
-// the conversion.
-type ColorModelFunc func(Color) Color
-
-func (f ColorModelFunc) Convert(c Color) Color {
- return f(c)
-}
-
-func toRGBAColor(c Color) Color {
- if _, ok := c.(RGBAColor); ok {
- return c
- }
- r, g, b, a := c.RGBA()
- return RGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
-}
-
-func toRGBA64Color(c Color) Color {
- if _, ok := c.(RGBA64Color); ok {
- return c
- }
- r, g, b, a := c.RGBA()
- return RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
-}
-
-func toNRGBAColor(c Color) Color {
- if _, ok := c.(NRGBAColor); ok {
- return c
- }
- r, g, b, a := c.RGBA()
- if a == 0xffff {
- return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
- }
- if a == 0 {
- return NRGBAColor{0, 0, 0, 0}
- }
- // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
- r = (r * 0xffff) / a
- g = (g * 0xffff) / a
- b = (b * 0xffff) / a
- return NRGBAColor{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
-}
-
-func toNRGBA64Color(c Color) Color {
- if _, ok := c.(NRGBA64Color); ok {
- return c
- }
- r, g, b, a := c.RGBA()
- if a == 0xffff {
- return NRGBA64Color{uint16(r), uint16(g), uint16(b), 0xffff}
- }
- if a == 0 {
- return NRGBA64Color{0, 0, 0, 0}
- }
- // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
- r = (r * 0xffff) / a
- g = (g * 0xffff) / a
- b = (b * 0xffff) / a
- return NRGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}
-}
-
-func toAlphaColor(c Color) Color {
- if _, ok := c.(AlphaColor); ok {
- return c
- }
- _, _, _, a := c.RGBA()
- return AlphaColor{uint8(a >> 8)}
-}
-
-func toAlpha16Color(c Color) Color {
- if _, ok := c.(Alpha16Color); ok {
- return c
- }
- _, _, _, a := c.RGBA()
- return Alpha16Color{uint16(a)}
-}
-
-func toGrayColor(c Color) Color {
- if _, ok := c.(GrayColor); ok {
- return c
- }
- r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
- return GrayColor{uint8(y >> 8)}
-}
-
-func toGray16Color(c Color) Color {
- if _, ok := c.(Gray16Color); ok {
- return c
- }
- r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
- return Gray16Color{uint16(y)}
-}
-
-// The ColorModel associated with RGBAColor.
-var RGBAColorModel ColorModel = ColorModelFunc(toRGBAColor)
-
-// The ColorModel associated with RGBA64Color.
-var RGBA64ColorModel ColorModel = ColorModelFunc(toRGBA64Color)
-
-// The ColorModel associated with NRGBAColor.
-var NRGBAColorModel ColorModel = ColorModelFunc(toNRGBAColor)
-
-// The ColorModel associated with NRGBA64Color.
-var NRGBA64ColorModel ColorModel = ColorModelFunc(toNRGBA64Color)
-
-// The ColorModel associated with AlphaColor.
-var AlphaColorModel ColorModel = ColorModelFunc(toAlphaColor)
-
-// The ColorModel associated with Alpha16Color.
-var Alpha16ColorModel ColorModel = ColorModelFunc(toAlpha16Color)
-
-// The ColorModel associated with GrayColor.
-var GrayColorModel ColorModel = ColorModelFunc(toGrayColor)
-
-// The ColorModel associated with Gray16Color.
-var Gray16ColorModel ColorModel = ColorModelFunc(toGray16Color)
diff --git a/src/pkg/image/color/color.go b/src/pkg/image/color/color.go
new file mode 100644
index 000000000..29a7b8a40
--- /dev/null
+++ b/src/pkg/image/color/color.go
@@ -0,0 +1,303 @@
+// 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 color implements a basic color library.
+package color
+
+// Color can convert itself to alpha-premultiplied 16-bits per channel RGBA.
+// The conversion may be lossy.
+type Color interface {
+ // RGBA returns the alpha-premultiplied red, green, blue and alpha values
+ // for the color. 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.
+ RGBA() (r, g, b, a uint32)
+}
+
+// RGBA represents a traditional 32-bit alpha-premultiplied color,
+// having 8 bits for each of red, green, blue and alpha.
+type RGBA struct {
+ R, G, B, A uint8
+}
+
+func (c RGBA) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ g = uint32(c.G)
+ g |= g << 8
+ b = uint32(c.B)
+ b |= b << 8
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// RGBA64 represents a 64-bit alpha-premultiplied color,
+// having 16 bits for each of red, green, blue and alpha.
+type RGBA64 struct {
+ R, G, B, A uint16
+}
+
+func (c RGBA64) RGBA() (r, g, b, a uint32) {
+ return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
+}
+
+// NRGBA represents a non-alpha-premultiplied 32-bit color.
+type NRGBA struct {
+ R, G, B, A uint8
+}
+
+func (c NRGBA) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r |= r << 8
+ r *= uint32(c.A)
+ r /= 0xff
+ g = uint32(c.G)
+ g |= g << 8
+ g *= uint32(c.A)
+ g /= 0xff
+ b = uint32(c.B)
+ b |= b << 8
+ b *= uint32(c.A)
+ b /= 0xff
+ a = uint32(c.A)
+ a |= a << 8
+ return
+}
+
+// NRGBA64 represents a non-alpha-premultiplied 64-bit color,
+// having 16 bits for each of red, green, blue and alpha.
+type NRGBA64 struct {
+ R, G, B, A uint16
+}
+
+func (c NRGBA64) RGBA() (r, g, b, a uint32) {
+ r = uint32(c.R)
+ r *= uint32(c.A)
+ r /= 0xffff
+ g = uint32(c.G)
+ g *= uint32(c.A)
+ g /= 0xffff
+ b = uint32(c.B)
+ b *= uint32(c.A)
+ b /= 0xffff
+ a = uint32(c.A)
+ return
+}
+
+// Alpha represents an 8-bit alpha color.
+type Alpha struct {
+ A uint8
+}
+
+func (c Alpha) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ a |= a << 8
+ return a, a, a, a
+}
+
+// Alpha16 represents a 16-bit alpha color.
+type Alpha16 struct {
+ A uint16
+}
+
+func (c Alpha16) RGBA() (r, g, b, a uint32) {
+ a = uint32(c.A)
+ return a, a, a, a
+}
+
+// Gray represents an 8-bit grayscale color.
+type Gray struct {
+ Y uint8
+}
+
+func (c Gray) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ y |= y << 8
+ return y, y, y, 0xffff
+}
+
+// Gray16 represents a 16-bit grayscale color.
+type Gray16 struct {
+ Y uint16
+}
+
+func (c Gray16) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ return y, y, y, 0xffff
+}
+
+// Model can convert any Color to one from its own color model. The conversion
+// may be lossy.
+type Model interface {
+ Convert(c Color) Color
+}
+
+// ModelFunc returns a Model that invokes f to implement the conversion.
+func ModelFunc(f func(Color) Color) Model {
+ // Note: using *modelFunc as the implementation
+ // means that callers can still use comparisons
+ // like m == RGBAModel. This is not possible if
+ // we use the func value directly, because funcs
+ // are no longer comparable.
+ return &modelFunc{f}
+}
+
+type modelFunc struct {
+ f func(Color) Color
+}
+
+func (m *modelFunc) Convert(c Color) Color {
+ return m.f(c)
+}
+
+// Models for the standard color types.
+var (
+ RGBAModel Model = ModelFunc(rgbaModel)
+ RGBA64Model Model = ModelFunc(rgba64Model)
+ NRGBAModel Model = ModelFunc(nrgbaModel)
+ NRGBA64Model Model = ModelFunc(nrgba64Model)
+ AlphaModel Model = ModelFunc(alphaModel)
+ Alpha16Model Model = ModelFunc(alpha16Model)
+ GrayModel Model = ModelFunc(grayModel)
+ Gray16Model Model = ModelFunc(gray16Model)
+)
+
+func rgbaModel(c Color) Color {
+ if _, ok := c.(RGBA); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func rgba64Model(c Color) Color {
+ if _, ok := c.(RGBA64); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func nrgbaModel(c Color) Color {
+ if _, ok := c.(NRGBA); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
+ }
+ if a == 0 {
+ return NRGBA{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}
+
+func nrgba64Model(c Color) Color {
+ if _, ok := c.(NRGBA64); ok {
+ return c
+ }
+ r, g, b, a := c.RGBA()
+ if a == 0xffff {
+ return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff}
+ }
+ if a == 0 {
+ return NRGBA64{0, 0, 0, 0}
+ }
+ // Since Color.RGBA returns a alpha-premultiplied color, we should have r <= a && g <= a && b <= a.
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
+}
+
+func alphaModel(c Color) Color {
+ if _, ok := c.(Alpha); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return Alpha{uint8(a >> 8)}
+}
+
+func alpha16Model(c Color) Color {
+ if _, ok := c.(Alpha16); ok {
+ return c
+ }
+ _, _, _, a := c.RGBA()
+ return Alpha16{uint16(a)}
+}
+
+func grayModel(c Color) Color {
+ if _, ok := c.(Gray); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return Gray{uint8(y >> 8)}
+}
+
+func gray16Model(c Color) Color {
+ if _, ok := c.(Gray16); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y := (299*r + 587*g + 114*b + 500) / 1000
+ return Gray16{uint16(y)}
+}
+
+// Palette is a palette of colors.
+type Palette []Color
+
+func diff(a, b uint32) uint32 {
+ if a > b {
+ return a - b
+ }
+ return b - a
+}
+
+// Convert returns the palette color closest to c in Euclidean R,G,B space.
+func (p Palette) 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 Palette) 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
+ ret, bestSSD := 0, uint32(1<<32-1)
+ for i, v := range p {
+ vr, vg, vb, _ := v.RGBA()
+ vr >>= 1
+ vg >>= 1
+ vb >>= 1
+ dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
+ ssd := (dr * dr) + (dg * dg) + (db * db)
+ if ssd < bestSSD {
+ if ssd == 0 {
+ return i
+ }
+ ret, bestSSD = i, ssd
+ }
+ }
+ return ret
+}
+
+// Standard colors.
+var (
+ Black = Gray16{0}
+ White = Gray16{0xffff}
+ Transparent = Alpha16{0}
+ Opaque = Alpha16{0xffff}
+)
diff --git a/src/pkg/image/color/ycbcr.go b/src/pkg/image/color/ycbcr.go
new file mode 100644
index 000000000..4c2f29ea0
--- /dev/null
+++ b/src/pkg/image/color/ycbcr.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 color
+
+// RGBToYCbCr converts an RGB triple to a Y'CbCr triple.
+func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // Y' = 0.2990*R + 0.5870*G + 0.1140*B
+ // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
+ // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ r1 := int(r)
+ g1 := int(g)
+ b1 := int(b)
+ yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
+ cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
+ if yy < 0 {
+ yy = 0
+ } else if yy > 255 {
+ yy = 255
+ }
+ if cb < 0 {
+ cb = 0
+ } else if cb > 255 {
+ cb = 255
+ }
+ if cr < 0 {
+ cr = 0
+ } else if cr > 255 {
+ cr = 255
+ }
+ return uint8(yy), uint8(cb), uint8(cr)
+}
+
+// YCbCrToRGB converts a Y'CbCr triple to an RGB triple.
+func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
+ // The JFIF specification says:
+ // R = Y' + 1.40200*(Cr-128)
+ // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
+ // B = Y' + 1.77200*(Cb-128)
+ // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+ yy1 := int(y)<<16 + 1<<15
+ cb1 := int(cb) - 128
+ cr1 := int(cr) - 128
+ r := (yy1 + 91881*cr1) >> 16
+ g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+ b := (yy1 + 116130*cb1) >> 16
+ if r < 0 {
+ r = 0
+ } else if r > 255 {
+ r = 255
+ }
+ if g < 0 {
+ g = 0
+ } else if g > 255 {
+ g = 255
+ }
+ if b < 0 {
+ b = 0
+ } else if b > 255 {
+ b = 255
+ }
+ return uint8(r), uint8(g), uint8(b)
+}
+
+// YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for
+// one luma and two chroma components.
+//
+// JPEG, VP8, the MPEG family and other codecs use this color model. Such
+// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
+// speaking, the term YUV applies only to analog video signals, and Y' (luma)
+// is Y (luminance) after applying gamma correction.
+//
+// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
+// different formulae for converting between the two. This package follows
+// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+type YCbCr struct {
+ Y, Cb, Cr uint8
+}
+
+func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
+ r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+ return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+}
+
+// YCbCrModel is the Model for Y'CbCr colors.
+var YCbCrModel Model = ModelFunc(yCbCrModel)
+
+func yCbCrModel(c Color) Color {
+ if _, ok := c.(YCbCr); ok {
+ return c
+ }
+ r, g, b, _ := c.RGBA()
+ y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ return YCbCr{y, u, v}
+}
diff --git a/src/pkg/image/ycbcr/ycbcr_test.go b/src/pkg/image/color/ycbcr_test.go
index 2e60a6f61..92a0e6ff1 100644
--- a/src/pkg/image/ycbcr/ycbcr_test.go
+++ b/src/pkg/image/color/ycbcr_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 ycbcr
+package color
import (
"testing"
diff --git a/src/pkg/image/decode_example_test.go b/src/pkg/image/decode_example_test.go
new file mode 100644
index 000000000..aa5a841c0
--- /dev/null
+++ b/src/pkg/image/decode_example_test.go
@@ -0,0 +1,79 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This example demonstrates decoding a JPEG image and examining its pixels.
+package image_test
+
+import (
+ "fmt"
+ "image"
+ "log"
+ "os"
+
+ // Package image/jpeg is not used explicitly in the code below,
+ // but is imported for its initialization side-effect, which allows
+ // image.Decode to understand JPEG formatted images. Uncomment these
+ // two lines to also understand GIF and PNG images:
+ // _ "image/gif"
+ // _ "image/png"
+ _ "image/jpeg"
+)
+
+func Example() {
+ // Open the file.
+ file, err := os.Open("testdata/video-001.jpeg")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer file.Close()
+
+ // Decode the image.
+ m, _, err := image.Decode(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ bounds := m.Bounds()
+
+ // Calculate a 16-bin histogram for m's red, green, blue and alpha components.
+ //
+ // An image's bounds do not necessarily start at (0, 0), so the two loops start
+ // at bounds.Min.Y and bounds.Min.X. Looping over Y first and X second is more
+ // likely to result in better memory access patterns than X first and Y second.
+ var histogram [16][4]int
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ r, g, b, a := m.At(x, y).RGBA()
+ // A color's RGBA method returns values in the range [0, 65535].
+ // Shifting by 12 reduces this to the range [0, 15].
+ histogram[r>>12][0]++
+ histogram[g>>12][1]++
+ histogram[b>>12][2]++
+ histogram[a>>12][3]++
+ }
+ }
+
+ // Print the results.
+ fmt.Printf("%-14s %6s %6s %6s %6s\n", "bin", "red", "green", "blue", "alpha")
+ for i, x := range histogram {
+ fmt.Printf("0x%04x-0x%04x: %6d %6d %6d %6d\n", i<<12, (i+1)<<12-1, x[0], x[1], x[2], x[3])
+ }
+ // Output:
+ // bin red green blue alpha
+ // 0x0000-0x0fff: 471 819 7596 0
+ // 0x1000-0x1fff: 576 2892 726 0
+ // 0x2000-0x2fff: 1038 2330 943 0
+ // 0x3000-0x3fff: 883 2321 1014 0
+ // 0x4000-0x4fff: 501 1295 525 0
+ // 0x5000-0x5fff: 302 962 242 0
+ // 0x6000-0x6fff: 219 358 150 0
+ // 0x7000-0x7fff: 352 281 192 0
+ // 0x8000-0x8fff: 3688 216 246 0
+ // 0x9000-0x9fff: 2277 237 283 0
+ // 0xa000-0xafff: 971 254 357 0
+ // 0xb000-0xbfff: 317 306 429 0
+ // 0xc000-0xcfff: 203 402 401 0
+ // 0xd000-0xdfff: 256 394 241 0
+ // 0xe000-0xefff: 378 343 173 0
+ // 0xf000-0xffff: 3018 2040 1932 15450
+}
diff --git a/src/pkg/image/decode_test.go b/src/pkg/image/decode_test.go
index 540d5eda5..d65986724 100644
--- a/src/pkg/image/decode_test.go
+++ b/src/pkg/image/decode_test.go
@@ -7,14 +7,13 @@ package image_test
import (
"bufio"
"image"
+ "image/color"
"os"
"testing"
- _ "image/bmp"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
- _ "image/tiff"
)
type imageTest struct {
@@ -24,7 +23,7 @@ type imageTest struct {
}
var imageTests = []imageTest{
- {"testdata/video-001.png", "testdata/video-001.bmp", 0},
+ {"testdata/video-001.png", "testdata/video-001.png", 0},
// GIF images are restricted to a 256-color palette and the conversion
// to GIF loses significant image quality.
{"testdata/video-001.png", "testdata/video-001.gif", 64 << 8},
@@ -32,15 +31,12 @@ var imageTests = []imageTest{
{"testdata/video-001.png", "testdata/video-001.5bpp.gif", 128 << 8},
// JPEG is a lossy format and hence needs a non-zero tolerance.
{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
- {"testdata/video-001.png", "testdata/video-001.png", 0},
- {"testdata/video-001.png", "testdata/video-001.tiff", 0},
-
- // Test grayscale images.
+ // Grayscale images.
{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
}
-func decode(filename string) (image.Image, string, os.Error) {
+func decode(filename string) (image.Image, string, error) {
f, err := os.Open(filename)
if err != nil {
return nil, "", err
@@ -49,7 +45,7 @@ func decode(filename string) (image.Image, string, os.Error) {
return image.Decode(bufio.NewReader(f))
}
-func decodeConfig(filename string) (image.Config, string, os.Error) {
+func decodeConfig(filename string) (image.Config, string, error) {
f, err := os.Open(filename)
if err != nil {
return image.Config{}, "", err
@@ -66,7 +62,7 @@ func delta(u0, u1 uint32) int {
return d
}
-func withinTolerance(c0, c1 image.Color, tolerance int) bool {
+func withinTolerance(c0, c1 color.Color, tolerance int) bool {
r0, g0, b0, a0 := c0.RGBA()
r1, g1, b1, a1 := c1.RGBA()
r := delta(r0, r1)
@@ -82,7 +78,7 @@ loop:
for _, it := range imageTests {
g := golden[it.goldenFilename]
if g == nil {
- var err os.Error
+ var err error
g, _, err = decode(it.goldenFilename)
if err != nil {
t.Errorf("%s: %v", it.goldenFilename, err)
diff --git a/src/pkg/image/draw/Makefile b/src/pkg/image/draw/Makefile
deleted file mode 100644
index 2ba6e7b51..000000000
--- a/src/pkg/image/draw/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=image/draw
-GOFILES=\
- draw.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/draw/bench_test.go b/src/pkg/image/draw/bench_test.go
index a99b40814..cc62e25f1 100644
--- a/src/pkg/image/draw/bench_test.go
+++ b/src/pkg/image/draw/bench_test.go
@@ -6,7 +6,7 @@ package draw
import (
"image"
- "image/ycbcr"
+ "image/color"
"testing"
)
@@ -18,16 +18,16 @@ const (
// 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) {
+func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
b.StopTimer()
var dst Image
switch dcm {
- case image.RGBAColorModel:
- dst1 := image.NewRGBA(dstw, dsth)
+ case color.RGBAModel:
+ dst1 := image.NewRGBA(image.Rect(0, 0, dstw, dsth))
for y := 0; y < dsth; y++ {
for x := 0; x < dstw; x++ {
- dst1.SetRGBA(x, y, image.RGBAColor{
+ dst1.SetRGBA(x, y, color.RGBA{
uint8(5 * x % 0x100),
uint8(7 * y % 0x100),
uint8((7*x + 5*y) % 0x100),
@@ -36,11 +36,11 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
}
}
dst = dst1
- case image.RGBA64ColorModel:
- dst1 := image.NewRGBA64(dstw, dsth)
+ case color.RGBA64Model:
+ dst1 := image.NewRGBA64(image.Rect(0, 0, dstw, dsth))
for y := 0; y < dsth; y++ {
for x := 0; x < dstw; x++ {
- dst1.SetRGBA64(x, y, image.RGBA64Color{
+ dst1.SetRGBA64(x, y, color.RGBA64{
uint16(53 * x % 0x10000),
uint16(59 * y % 0x10000),
uint16((59*x + 53*y) % 0x10000),
@@ -50,18 +50,18 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
}
dst = dst1
default:
- panic("unreachable")
+ b.Fatal("unknown destination color model", dcm)
}
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)
+ src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
+ case color.RGBAModel:
+ src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
for x := 0; x < srcw; x++ {
- src1.SetRGBA(x, y, image.RGBAColor{
+ src1.SetRGBA(x, y, color.RGBA{
uint8(13 * x % 0x80),
uint8(11 * y % 0x80),
uint8((11*x + 13*y) % 0x80),
@@ -70,11 +70,11 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
}
}
src = src1
- case image.RGBA64ColorModel:
- src1 := image.NewRGBA64(srcw, srch)
+ case color.RGBA64Model:
+ src1 := image.NewRGBA64(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
for x := 0; x < srcw; x++ {
- src1.SetRGBA64(x, y, image.RGBA64Color{
+ src1.SetRGBA64(x, y, color.RGBA64{
uint16(103 * x % 0x8000),
uint16(101 * y % 0x8000),
uint16((101*x + 103*y) % 0x8000),
@@ -83,11 +83,11 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
}
}
src = src1
- case image.NRGBAColorModel:
- src1 := image.NewNRGBA(srcw, srch)
+ case color.NRGBAModel:
+ src1 := image.NewNRGBA(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
for x := 0; x < srcw; x++ {
- src1.SetNRGBA(x, y, image.NRGBAColor{
+ src1.SetNRGBA(x, y, color.NRGBA{
uint8(13 * x % 0x100),
uint8(11 * y % 0x100),
uint8((11*x + 13*y) % 0x100),
@@ -96,7 +96,7 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
}
}
src = src1
- case ycbcr.YCbCrColorModel:
+ case color.YCbCrModel:
yy := make([]uint8, srcw*srch)
cb := make([]uint8, srcw*srch)
cr := make([]uint8, srcw*srch)
@@ -105,38 +105,38 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
cb[i] = uint8(5 * i % 0x100)
cr[i] = uint8(7 * i % 0x100)
}
- src = &ycbcr.YCbCr{
+ src = &image.YCbCr{
Y: yy,
Cb: cb,
Cr: cr,
YStride: srcw,
CStride: srcw,
- SubsampleRatio: ycbcr.SubsampleRatio444,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
Rect: image.Rect(0, 0, srcw, srch),
}
default:
- panic("unreachable")
+ b.Fatal("unknown source color model", scm)
}
var mask image.Image
switch mcm {
case nil:
// No-op.
- case image.AlphaColorModel:
- mask1 := image.NewAlpha(srcw, srch)
+ case color.AlphaModel:
+ mask1 := image.NewAlpha(image.Rect(0, 0, 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})
+ mask1.SetAlpha(x, y, color.Alpha{a})
}
}
}
mask = mask1
default:
- panic("unreachable")
+ b.Fatal("unknown mask color model", mcm)
}
b.StartTimer()
@@ -145,62 +145,62 @@ func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
x := 3 * i % (dstw - srcw)
y := 7 * i % (dsth - srch)
- DrawMask(dst, dst.Bounds().Add(image.Point{x, y}), src, image.ZP, mask, image.ZP, op)
+ DrawMask(dst, dst.Bounds().Add(image.Pt(x, y)), src, image.ZP, mask, image.ZP, op)
}
}
// The BenchmarkFoo functions exercise a drawFoo fast-path function in draw.go.
func BenchmarkFillOver(b *testing.B) {
- bench(b, image.RGBAColorModel, nil, nil, Over)
+ bench(b, color.RGBAModel, nil, nil, Over)
}
func BenchmarkFillSrc(b *testing.B) {
- bench(b, image.RGBAColorModel, nil, nil, Src)
+ bench(b, color.RGBAModel, nil, nil, Src)
}
func BenchmarkCopyOver(b *testing.B) {
- bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Over)
+ bench(b, color.RGBAModel, color.RGBAModel, nil, Over)
}
func BenchmarkCopySrc(b *testing.B) {
- bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Src)
+ bench(b, color.RGBAModel, color.RGBAModel, nil, Src)
}
func BenchmarkNRGBAOver(b *testing.B) {
- bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Over)
+ bench(b, color.RGBAModel, color.NRGBAModel, nil, Over)
}
func BenchmarkNRGBASrc(b *testing.B) {
- bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Src)
+ bench(b, color.RGBAModel, color.NRGBAModel, nil, Src)
}
func BenchmarkYCbCr(b *testing.B) {
- bench(b, image.RGBAColorModel, ycbcr.YCbCrColorModel, nil, Over)
+ bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
}
func BenchmarkGlyphOver(b *testing.B) {
- bench(b, image.RGBAColorModel, nil, image.AlphaColorModel, Over)
+ bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
}
func BenchmarkRGBA(b *testing.B) {
- bench(b, image.RGBAColorModel, image.RGBA64ColorModel, nil, Src)
+ bench(b, color.RGBAModel, color.RGBA64Model, nil, Src)
}
// The BenchmarkGenericFoo functions exercise the generic, slow-path code.
func BenchmarkGenericOver(b *testing.B) {
- bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Over)
+ bench(b, color.RGBA64Model, color.RGBA64Model, nil, Over)
}
func BenchmarkGenericMaskOver(b *testing.B) {
- bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Over)
+ bench(b, color.RGBA64Model, color.RGBA64Model, color.AlphaModel, Over)
}
func BenchmarkGenericSrc(b *testing.B) {
- bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Src)
+ bench(b, color.RGBA64Model, color.RGBA64Model, nil, Src)
}
func BenchmarkGenericMaskSrc(b *testing.B) {
- bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Src)
+ bench(b, color.RGBA64Model, color.RGBA64Model, color.AlphaModel, Src)
}
diff --git a/src/pkg/image/draw/clip_test.go b/src/pkg/image/draw/clip_test.go
index db40d82f5..65381f72f 100644
--- a/src/pkg/image/draw/clip_test.go
+++ b/src/pkg/image/draw/clip_test.go
@@ -143,9 +143,9 @@ var clipTests = []clipTest{
}
func TestClip(t *testing.T) {
- dst0 := image.NewRGBA(100, 100)
- src0 := image.NewRGBA(100, 100)
- mask0 := image.NewRGBA(100, 100)
+ dst0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
+ src0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
+ mask0 := image.NewRGBA(image.Rect(0, 0, 100, 100))
for _, c := range clipTests {
dst := dst0.SubImage(c.dr).(*image.RGBA)
src := src0.SubImage(c.sr).(*image.RGBA)
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
index 5171e03b1..bef325c0c 100644
--- a/src/pkg/image/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -5,12 +5,12 @@
// Package draw provides image composition functions.
//
// See "The Go image/draw package" for an introduction to this package:
-// http://blog.golang.org/2011/09/go-imagedraw-package.html
+// http://golang.org/doc/articles/image_draw.html
package draw
import (
"image"
- "image/ycbcr"
+ "image/color"
)
// m is the maximum color value returned by image.Color.RGBA.
@@ -26,12 +26,10 @@ const (
Src
)
-var zeroColor image.Color = image.AlphaColor{0}
-
// A draw.Image is an image.Image with a Set method to change a single pixel.
type Image interface {
image.Image
- Set(x, y int, c image.Color)
+ Set(x, y int, c color.Color)
}
// Draw calls DrawMask with a nil mask.
@@ -73,7 +71,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if op == Over {
if mask == nil {
switch src0 := src.(type) {
- case *image.ColorImage:
+ case *image.Uniform:
drawFillOver(dst0, r, src0)
return
case *image.RGBA:
@@ -82,13 +80,13 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
case *image.NRGBA:
drawNRGBAOver(dst0, r, src0, sp)
return
- case *ycbcr.YCbCr:
+ case *image.YCbCr:
drawYCbCr(dst0, r, src0, sp)
return
}
} else if mask0, ok := mask.(*image.Alpha); ok {
switch src0 := src.(type) {
- case *image.ColorImage:
+ case *image.Uniform:
drawGlyphOver(dst0, r, src0, mask0, mp)
return
}
@@ -96,7 +94,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
} else {
if mask == nil {
switch src0 := src.(type) {
- case *image.ColorImage:
+ case *image.Uniform:
drawFillSrc(dst0, r, src0)
return
case *image.RGBA:
@@ -105,7 +103,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
case *image.NRGBA:
drawNRGBASrc(dst0, r, src0, sp)
return
- case *ycbcr.YCbCr:
+ case *image.YCbCr:
drawYCbCr(dst0, r, src0, sp)
return
}
@@ -125,7 +123,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
}
}
- var out *image.RGBA64Color
+ var out *color.RGBA64
sy := sp.Y + y0 - r.Min.Y
my := mp.Y + y0 - r.Min.Y
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
@@ -141,14 +139,14 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if op == Over {
// No-op.
} else {
- dst.Set(x, y, zeroColor)
+ dst.Set(x, y, color.Transparent)
}
case ma == m && op == Src:
dst.Set(x, y, src.At(sx, sy))
default:
sr, sg, sb, sa := src.At(sx, sy).RGBA()
if out == nil {
- out = new(image.RGBA64Color)
+ out = new(color.RGBA64)
}
if op == Over {
dr, dg, db, da := dst.At(x, y).RGBA()
@@ -169,11 +167,11 @@ 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) {
+func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
sr, sg, sb, sa := src.RGBA()
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
- i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i0 := dst.PixOffset(r.Min.X, r.Min.Y)
i1 := i0 + r.Dx()*4
for y := r.Min.Y; y != r.Max.Y; y++ {
for i := i0; i < i1; i += 4 {
@@ -192,12 +190,12 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
}
}
-func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
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
+ i0 := dst.PixOffset(r.Min.X, r.Min.Y)
i1 := i0 + r.Dx()*4
for i := i0; i < i1; i += 4 {
dst.Pix[i+0] = uint8(sr >> 8)
@@ -215,8 +213,8 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
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
+ d0 := dst.PixOffset(r.Min.X, r.Min.Y)
+ s0 := src.PixOffset(sp.X, sp.Y)
var (
ddelta, sdelta int
i0, i1, idelta int
@@ -263,8 +261,8 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
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
+ d0 := dst.PixOffset(r.Min.X, r.Min.Y)
+ s0 := src.PixOffset(sp.X, sp.Y)
var ddelta, sdelta int
if r.Min.Y <= sp.Y {
ddelta = dst.Stride
@@ -347,41 +345,36 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
}
}
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
- // A YCbCr image is always fully opaque, and so if the mask is implicitly nil
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
+ // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
// (i.e. fully opaque) then the op is effectively always Src.
- var (
- yy, cb, cr 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:
+ case image.YCbCrSubsampleRatio422:
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)
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+ ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ ci := ciBase + sx/2
+ rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
dpix[x+3] = 255
}
}
- case ycbcr.SubsampleRatio420:
+ case image.YCbCrSubsampleRatio420:
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)
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+ ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+ for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+ ci := ciBase + sx/2
+ rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
@@ -392,11 +385,10 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
// Default to 4:4:4 subsampling.
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)
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+ ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+ for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+ rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
dpix[x+0] = rr
dpix[x+1] = gg
dpix[x+2] = bb
@@ -406,10 +398,10 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
}
}
-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
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
+ i0 := dst.PixOffset(r.Min.X, r.Min.Y)
i1 := i0 + r.Dx()*4
- mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+ mi0 := mask.PixOffset(mp.X, mp.Y)
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 {
@@ -453,7 +445,7 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
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
+ i0 := dst.PixOffset(x0, y0)
di := dx * 4
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
diff --git a/src/pkg/image/draw/draw_test.go b/src/pkg/image/draw/draw_test.go
index 55435cc27..1db75b3e3 100644
--- a/src/pkg/image/draw/draw_test.go
+++ b/src/pkg/image/draw/draw_test.go
@@ -6,62 +6,62 @@ package draw
import (
"image"
- "image/ycbcr"
+ "image/color"
"testing"
)
-func eq(c0, c1 image.Color) bool {
+func eq(c0, c1 color.Color) bool {
r0, g0, b0, a0 := c0.RGBA()
r1, g1, b1, a1 := c1.RGBA()
return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
}
func fillBlue(alpha int) image.Image {
- return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
+ return image.NewUniform(color.RGBA{0, 0, uint8(alpha), uint8(alpha)})
}
func fillAlpha(alpha int) image.Image {
- return image.NewColorImage(image.AlphaColor{uint8(alpha)})
+ return image.NewUniform(color.Alpha{uint8(alpha)})
}
func vgradGreen(alpha int) image.Image {
- m := image.NewRGBA(16, 16)
+ m := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
- m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)})
+ m.Set(x, y, color.RGBA{0, uint8(y * alpha / 15), 0, uint8(alpha)})
}
}
return m
}
func vgradAlpha(alpha int) image.Image {
- m := image.NewAlpha(16, 16)
+ m := image.NewAlpha(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
- m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)})
+ m.Set(x, y, color.Alpha{uint8(y * alpha / 15)})
}
}
return m
}
func vgradGreenNRGBA(alpha int) image.Image {
- m := image.NewNRGBA(16, 16)
+ m := image.NewNRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
- m.Set(x, y, image.RGBAColor{0, uint8(y * 0x11), 0, uint8(alpha)})
+ m.Set(x, y, color.RGBA{0, uint8(y * 0x11), 0, uint8(alpha)})
}
}
return m
}
func vgradCr() image.Image {
- m := &ycbcr.YCbCr{
+ m := &image.YCbCr{
Y: make([]byte, 16*16),
Cb: make([]byte, 16*16),
Cr: make([]byte, 16*16),
YStride: 16,
CStride: 16,
- SubsampleRatio: ycbcr.SubsampleRatio444,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
Rect: image.Rect(0, 0, 16, 16),
}
for y := 0; y < 16; y++ {
@@ -73,20 +73,20 @@ func vgradCr() image.Image {
}
func hgradRed(alpha int) Image {
- m := image.NewRGBA(16, 16)
+ m := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
- m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
+ m.Set(x, y, color.RGBA{uint8(x * alpha / 15), 0, 0, uint8(alpha)})
}
}
return m
}
func gradYellow(alpha int) Image {
- m := image.NewRGBA(16, 16)
+ m := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
- m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+ m.Set(x, y, color.RGBA{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
}
}
return m
@@ -97,61 +97,61 @@ type drawTest struct {
src image.Image
mask image.Image
op Op
- expected image.Color
+ expected color.Color
}
var drawTests = []drawTest{
// Uniform mask (0% opaque).
- {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
- {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+ {"nop", vgradGreen(255), fillAlpha(0), Over, color.RGBA{136, 0, 0, 255}},
+ {"clear", vgradGreen(255), fillAlpha(0), Src, color.RGBA{0, 0, 0, 0}},
// Uniform mask (100%, 75%, nil) and uniform source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 90, 90}.
- {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
- {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
- {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
- {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
- {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
- {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fill", fillBlue(90), fillAlpha(255), Over, color.RGBA{88, 0, 90, 255}},
+ {"fillSrc", fillBlue(90), fillAlpha(255), Src, color.RGBA{0, 0, 90, 90}},
+ {"fillAlpha", fillBlue(90), fillAlpha(192), Over, color.RGBA{100, 0, 68, 255}},
+ {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, color.RGBA{0, 0, 68, 68}},
+ {"fillNil", fillBlue(90), nil, Over, color.RGBA{88, 0, 90, 255}},
+ {"fillNilSrc", fillBlue(90), nil, Src, color.RGBA{0, 0, 90, 90}},
// Uniform mask (100%, 75%, nil) and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 48, 0, 90}.
- {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
- {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
- {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
- {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
- {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
- {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copy", vgradGreen(90), fillAlpha(255), Over, color.RGBA{88, 48, 0, 255}},
+ {"copySrc", vgradGreen(90), fillAlpha(255), Src, color.RGBA{0, 48, 0, 90}},
+ {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, color.RGBA{100, 36, 0, 255}},
+ {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, color.RGBA{0, 36, 0, 68}},
+ {"copyNil", vgradGreen(90), nil, Over, color.RGBA{88, 48, 0, 255}},
+ {"copyNilSrc", vgradGreen(90), nil, Src, color.RGBA{0, 48, 0, 90}},
// Uniform mask (100%, 75%, nil) and variable NRGBA source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 136, 0, 90} in NRGBA-space, which is {0, 48, 0, 90} in RGBA-space.
// The result pixel is different than in the "copy*" test cases because of rounding errors.
- {"nrgba", vgradGreenNRGBA(90), fillAlpha(255), Over, image.RGBAColor{88, 46, 0, 255}},
- {"nrgbaSrc", vgradGreenNRGBA(90), fillAlpha(255), Src, image.RGBAColor{0, 46, 0, 90}},
- {"nrgbaAlpha", vgradGreenNRGBA(90), fillAlpha(192), Over, image.RGBAColor{100, 34, 0, 255}},
- {"nrgbaAlphaSrc", vgradGreenNRGBA(90), fillAlpha(192), Src, image.RGBAColor{0, 34, 0, 68}},
- {"nrgbaNil", vgradGreenNRGBA(90), nil, Over, image.RGBAColor{88, 46, 0, 255}},
- {"nrgbaNilSrc", vgradGreenNRGBA(90), nil, Src, image.RGBAColor{0, 46, 0, 90}},
+ {"nrgba", vgradGreenNRGBA(90), fillAlpha(255), Over, color.RGBA{88, 46, 0, 255}},
+ {"nrgbaSrc", vgradGreenNRGBA(90), fillAlpha(255), Src, color.RGBA{0, 46, 0, 90}},
+ {"nrgbaAlpha", vgradGreenNRGBA(90), fillAlpha(192), Over, color.RGBA{100, 34, 0, 255}},
+ {"nrgbaAlphaSrc", vgradGreenNRGBA(90), fillAlpha(192), Src, color.RGBA{0, 34, 0, 68}},
+ {"nrgbaNil", vgradGreenNRGBA(90), nil, Over, color.RGBA{88, 46, 0, 255}},
+ {"nrgbaNilSrc", vgradGreenNRGBA(90), nil, Src, color.RGBA{0, 46, 0, 90}},
// Uniform mask (100%, 75%, nil) and variable YCbCr source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 136} in YCbCr-space, which is {11, 38, 0, 255} in RGB-space.
- {"ycbcr", vgradCr(), fillAlpha(255), Over, image.RGBAColor{11, 38, 0, 255}},
- {"ycbcrSrc", vgradCr(), fillAlpha(255), Src, image.RGBAColor{11, 38, 0, 255}},
- {"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, image.RGBAColor{42, 28, 0, 255}},
- {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, image.RGBAColor{8, 28, 0, 192}},
- {"ycbcrNil", vgradCr(), nil, Over, image.RGBAColor{11, 38, 0, 255}},
- {"ycbcrNilSrc", vgradCr(), nil, Src, image.RGBAColor{11, 38, 0, 255}},
+ {"ycbcr", vgradCr(), fillAlpha(255), Over, color.RGBA{11, 38, 0, 255}},
+ {"ycbcrSrc", vgradCr(), fillAlpha(255), Src, color.RGBA{11, 38, 0, 255}},
+ {"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, color.RGBA{42, 28, 0, 255}},
+ {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
+ {"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
+ {"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
// Variable mask and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 255, 255}.
// The mask pixel's alpha is 102, or 40%.
- {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
- {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+ {"generic", fillBlue(255), vgradAlpha(192), Over, color.RGBA{81, 0, 102, 255}},
+ {"genericSrc", fillBlue(255), vgradAlpha(192), Src, color.RGBA{0, 0, 102, 102}},
}
func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) image.Image {
@@ -163,20 +163,20 @@ func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Po
if mask != nil {
mb = mask.Bounds()
}
- golden := image.NewRGBA(b.Max.X, b.Max.Y)
+ golden := image.NewRGBA(image.Rect(0, 0, b.Max.X, b.Max.Y))
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)) {
+ if !(image.Pt(x, y).In(b)) {
continue
}
sx := x + sp.X - r.Min.X
- if !(image.Point{sx, sy}.In(sb)) {
+ if !(image.Pt(sx, sy).In(sb)) {
continue
}
mx := x + mp.X - r.Min.X
- if !(image.Point{mx, my}.In(mb)) {
+ if !(image.Pt(mx, my).In(mb)) {
continue
}
@@ -191,7 +191,7 @@ func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Po
_, _, _, ma = mask.At(mx, my).RGBA()
}
a := M - (sa * ma / M)
- golden.Set(x, y, image.RGBA64Color{
+ golden.Set(x, y, color.RGBA64{
uint16((dr*a + sr*ma) / M),
uint16((dg*a + sg*ma) / M),
uint16((db*a + sb*ma) / M),
@@ -281,15 +281,15 @@ func TestDrawOverlap(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})
+ a := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ b := image.NewRGBA(image.Rect(0, 0, 2, 2))
+ b.Set(0, 0, color.RGBA{0, 0, 0, 5})
+ b.Set(1, 0, color.RGBA{0, 0, 5, 5})
+ b.Set(0, 1, color.RGBA{0, 5, 0, 5})
+ b.Set(1, 1, color.RGBA{5, 0, 0, 5})
Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1), Over)
- if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
- t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ if !eq(color.RGBA{5, 0, 0, 5}, a.At(0, 0)) {
+ t.Errorf("non-zero src pt: want %v got %v", color.RGBA{5, 0, 0, 5}, a.At(0, 0))
}
}
@@ -310,10 +310,10 @@ func TestFill(t *testing.T) {
image.Rect(20, 20, 29, 29),
}
for _, r := range rr {
- m := image.NewRGBA(40, 30).SubImage(r).(*image.RGBA)
+ m := image.NewRGBA(image.Rect(0, 0, 40, 30)).SubImage(r).(*image.RGBA)
b := m.Bounds()
- c := image.RGBAColor{11, 0, 0, 255}
- src := &image.ColorImage{c}
+ c := color.RGBA{11, 0, 0, 255}
+ src := &image.Uniform{C: c}
check := func(desc string) {
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
@@ -332,22 +332,22 @@ func TestFill(t *testing.T) {
}
check("pixel")
// Draw 1 row at a time.
- c = image.RGBAColor{0, 22, 0, 255}
- src = &image.ColorImage{c}
+ c = color.RGBA{0, 22, 0, 255}
+ src = &image.Uniform{C: c}
for y := b.Min.Y; y < b.Max.Y; y++ {
DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
}
check("row")
// Draw 1 column at a time.
- c = image.RGBAColor{0, 0, 33, 255}
- src = &image.ColorImage{c}
+ c = color.RGBA{0, 0, 33, 255}
+ src = &image.Uniform{C: c}
for x := b.Min.X; x < b.Max.X; x++ {
DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
}
check("column")
// Draw the whole image at once.
- c = image.RGBAColor{44, 55, 66, 77}
- src = &image.ColorImage{c}
+ c = color.RGBA{44, 55, 66, 77}
+ src = &image.Uniform{C: c}
DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)
check("whole")
}
diff --git a/src/pkg/image/format.go b/src/pkg/image/format.go
index b4859325e..f93d356b0 100644
--- a/src/pkg/image/format.go
+++ b/src/pkg/image/format.go
@@ -6,18 +6,18 @@ package image
import (
"bufio"
+ "errors"
"io"
- "os"
)
-// An UnknownFormatErr indicates that decoding encountered an unknown format.
-var UnknownFormatErr = os.NewError("image: unknown format")
+// ErrFormat indicates that decoding encountered an unknown format.
+var ErrFormat = errors.New("image: unknown format")
// A format holds an image format's name, magic header and how to decode it.
type format struct {
name, magic string
- decode func(io.Reader) (Image, os.Error)
- decodeConfig func(io.Reader) (Config, os.Error)
+ decode func(io.Reader) (Image, error)
+ decodeConfig func(io.Reader) (Config, error)
}
// Formats is the list of registered formats.
@@ -29,14 +29,14 @@ var formats []format
// string can contain "?" wildcards that each match any one byte.
// Decode is the function that decodes the encoded image.
// DecodeConfig is the function that decodes just its configuration.
-func RegisterFormat(name, magic string, decode func(io.Reader) (Image, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) {
+func RegisterFormat(name, magic string, decode func(io.Reader) (Image, error), decodeConfig func(io.Reader) (Config, error)) {
formats = append(formats, format{name, magic, decode, decodeConfig})
}
// A reader is an io.Reader that can also peek ahead.
type reader interface {
io.Reader
- Peek(int) ([]byte, os.Error)
+ Peek(int) ([]byte, error)
}
// AsReader converts an io.Reader to a reader.
@@ -75,11 +75,11 @@ func sniff(r reader) format {
// The string returned is the format name used during format registration.
// Format registration is typically done by the init method of the codec-
// specific package.
-func Decode(r io.Reader) (Image, string, os.Error) {
+func Decode(r io.Reader) (Image, string, error) {
rr := asReader(r)
f := sniff(rr)
if f.decode == nil {
- return nil, "", UnknownFormatErr
+ return nil, "", ErrFormat
}
m, err := f.decode(rr)
return m, f.name, err
@@ -89,11 +89,11 @@ func Decode(r io.Reader) (Image, string, os.Error) {
// been encoded in a registered format. The string returned is the format name
// used during format registration. Format registration is typically done by
// the init method of the codec-specific package.
-func DecodeConfig(r io.Reader) (Config, string, os.Error) {
+func DecodeConfig(r io.Reader) (Config, string, error) {
rr := asReader(r)
f := sniff(rr)
if f.decodeConfig == nil {
- return Config{}, "", UnknownFormatErr
+ return Config{}, "", ErrFormat
}
c, err := f.decodeConfig(rr)
return c, f.name, err
diff --git a/src/pkg/image/geom.go b/src/pkg/image/geom.go
index 667aee625..e12348331 100644
--- a/src/pkg/image/geom.go
+++ b/src/pkg/image/geom.go
@@ -112,7 +112,7 @@ func (r Rectangle) Add(p Point) Rectangle {
}
}
-// Add returns the rectangle r translated by -p.
+// Sub returns the rectangle r translated by -p.
func (r Rectangle) Sub(p Point) Rectangle {
return Rectangle{
Point{r.Min.X - p.X, r.Min.Y - p.Y},
diff --git a/src/pkg/image/gif/Makefile b/src/pkg/image/gif/Makefile
deleted file mode 100644
index e89a71361..000000000
--- a/src/pkg/image/gif/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=image/gif
-GOFILES=\
- reader.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index e39b79746..8b36948d6 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -10,10 +10,11 @@ package gif
import (
"bufio"
"compress/lzw"
+ "errors"
"fmt"
"image"
+ "image/color"
"io"
- "os"
)
// If the io.Reader does not also have ReadByte, then decode will introduce its own buffering.
@@ -76,7 +77,7 @@ type decoder struct {
// Computed.
pixelSize uint
- globalColorMap image.PalettedColorModel
+ globalColorMap color.Palette
// Used when decoding.
delay []int
@@ -96,7 +97,7 @@ type blockReader struct {
tmp [256]byte
}
-func (b *blockReader) Read(p []byte) (int, os.Error) {
+func (b *blockReader) Read(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}
@@ -106,7 +107,7 @@ func (b *blockReader) Read(p []byte) (int, os.Error) {
return 0, err
}
if blockLen == 0 {
- return 0, os.EOF
+ return 0, io.EOF
}
b.slice = b.tmp[0:blockLen]
if _, err = io.ReadFull(b.r, b.slice); err != nil {
@@ -119,7 +120,7 @@ func (b *blockReader) Read(p []byte) (int, os.Error) {
}
// decode reads a GIF image from r and stores the result in d.
-func (d *decoder) decode(r io.Reader, configOnly bool) os.Error {
+func (d *decoder) decode(r io.Reader, configOnly bool) error {
// Add buffering if r does not provide ReadByte.
if rr, ok := r.(reader); ok {
d.r = rr
@@ -145,7 +146,7 @@ Loop:
for err == nil {
var c byte
c, err = d.r.ReadByte()
- if err == os.EOF {
+ if err == io.EOF {
break
}
switch c {
@@ -188,7 +189,7 @@ Loop:
return err
}
if c != 0 {
- return os.NewError("gif: extra data after image")
+ return errors.New("gif: extra data after image")
}
// Undo the interlacing if necessary.
@@ -216,7 +217,7 @@ Loop:
return nil
}
-func (d *decoder) readHeaderAndScreenDescriptor() os.Error {
+func (d *decoder) readHeaderAndScreenDescriptor() error {
_, err := io.ReadFull(d.r, d.tmp[0:13])
if err != nil {
return err
@@ -235,7 +236,7 @@ func (d *decoder) readHeaderAndScreenDescriptor() os.Error {
return nil
}
-func (d *decoder) readColorMap() (image.PalettedColorModel, os.Error) {
+func (d *decoder) readColorMap() (color.Palette, error) {
if d.pixelSize > 8 {
return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
}
@@ -248,16 +249,16 @@ func (d *decoder) readColorMap() (image.PalettedColorModel, os.Error) {
if err != nil {
return nil, fmt.Errorf("gif: short read on color map: %s", err)
}
- colorMap := make(image.PalettedColorModel, numColors)
+ colorMap := make(color.Palette, numColors)
j := 0
for i := range colorMap {
- colorMap[i] = image.RGBAColor{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+ colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
j += 3
}
return colorMap, nil
}
-func (d *decoder) readExtension() os.Error {
+func (d *decoder) readExtension() error {
extension, err := d.r.ReadByte()
if err != nil {
return err
@@ -306,7 +307,7 @@ func (d *decoder) readExtension() os.Error {
panic("unreachable")
}
-func (d *decoder) readGraphicControl() os.Error {
+func (d *decoder) readGraphicControl() error {
if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
@@ -319,13 +320,13 @@ func (d *decoder) readGraphicControl() os.Error {
return nil
}
-func (d *decoder) setTransparency(colorMap image.PalettedColorModel) {
+func (d *decoder) setTransparency(colorMap color.Palette) {
if int(d.transparentIndex) < len(colorMap) {
- colorMap[d.transparentIndex] = image.RGBAColor{}
+ colorMap[d.transparentIndex] = color.RGBA{}
}
}
-func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) {
+func (d *decoder) newImageFromDescriptor() (*image.Paletted, 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)
}
@@ -334,13 +335,10 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) {
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]
- 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
+ return image.NewPaletted(image.Rect(left, top, left+width, top+height), nil), nil
}
-func (d *decoder) readBlock() (int, os.Error) {
+func (d *decoder) readBlock() (int, error) {
n, err := d.r.ReadByte()
if n == 0 || err != nil {
return 0, err
@@ -381,7 +379,7 @@ func uninterlace(m *image.Paletted) {
// Decode reads a GIF image from r and returns the first embedded
// image as an image.Image.
-func Decode(r io.Reader) (image.Image, os.Error) {
+func Decode(r io.Reader) (image.Image, error) {
var d decoder
if err := d.decode(r, false); err != nil {
return nil, err
@@ -398,7 +396,7 @@ type GIF struct {
// DecodeAll reads a GIF image from r and returns the sequential frames
// and timing information.
-func DecodeAll(r io.Reader) (*GIF, os.Error) {
+func DecodeAll(r io.Reader) (*GIF, error) {
var d decoder
if err := d.decode(r, false); err != nil {
return nil, err
@@ -413,12 +411,16 @@ func DecodeAll(r io.Reader) (*GIF, os.Error) {
// 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) {
+func DecodeConfig(r io.Reader) (image.Config, error) {
var d decoder
if err := d.decode(r, true); err != nil {
return image.Config{}, err
}
- return image.Config{d.globalColorMap, d.width, d.height}, nil
+ return image.Config{
+ ColorModel: d.globalColorMap,
+ Width: d.width,
+ Height: d.height,
+ }, nil
}
func init() {
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index 7c7a4b7a7..03ac60606 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -4,30 +4,59 @@
// Package image implements a basic 2-D image library.
//
-// See "The Go image package" for an introduction to this package:
-// http://blog.golang.org/2011/09/go-image-package.html
+// The fundamental interface is called Image. An Image contains colors, which
+// are described in the image/color package.
+//
+// Values of the Image interface are created either by calling functions such
+// as NewRGBA and NewPaletted, or by calling Decode on an io.Reader containing
+// image data in a format such as GIF, JPEG or PNG. Decoding any particular
+// image format requires the prior registration of a decoder function.
+// Registration is typically automatic as a side effect of initializing that
+// format's package so that, to decode a PNG image, it suffices to have
+// import _ "image/png"
+// in a program's main package. The _ means to import a package purely for its
+// initialization side effects.
+//
+// See "The Go image package" for more details:
+// http://golang.org/doc/articles/image_package.html
package image
+import (
+ "image/color"
+)
+
// Config holds an image's color model and dimensions.
type Config struct {
- ColorModel ColorModel
+ ColorModel color.Model
Width, Height int
}
-// Image is a finite rectangular grid of Colors drawn from a ColorModel.
+// Image is a finite rectangular grid of color.Color values taken from a color
+// model.
type Image interface {
- // ColorModel returns the Image's ColorModel.
- ColorModel() ColorModel
+ // ColorModel returns the Image's color model.
+ ColorModel() color.Model
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
- At(x, y int) Color
+ At(x, y int) color.Color
+}
+
+// PalettedImage is an image whose colors may come from a limited palette.
+// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
+// then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
+// color model is not a PalettedColorModel, then ColorIndexAt's behavior is
+// undefined.
+type PalettedImage interface {
+ // ColorIndexAt returns the palette index of the pixel at (x, y).
+ ColorIndexAt(x, y int) uint8
+ Image
}
-// RGBA is an in-memory image of RGBAColor values.
+// RGBA is an in-memory image whose At method returns color.RGBA values.
type RGBA struct {
// Pix holds the image's pixels, in R, G, B, A order. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
@@ -38,35 +67,41 @@ type RGBA struct {
Rect Rectangle
}
-func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
+func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
func (p *RGBA) Bounds() Rectangle { return p.Rect }
-func (p *RGBA) At(x, y int) Color {
+func (p *RGBA) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return RGBAColor{}
+ return color.RGBA{}
}
- 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]}
+ i := p.PixOffset(x, y)
+ return color.RGBA{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) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGBA) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func (p *RGBA) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
- c1 := toRGBAColor(c).(RGBAColor)
+ i := p.PixOffset(x, y)
+ c1 := color.RGBAModel.Convert(c).(color.RGBA)
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) {
+func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ i := p.PixOffset(x, y)
p.Pix[i+0] = c.R
p.Pix[i+1] = c.G
p.Pix[i+2] = c.B
@@ -83,7 +118,7 @@ func (p *RGBA) SubImage(r Rectangle) Image {
if r.Empty() {
return &RGBA{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &RGBA{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -109,13 +144,14 @@ func (p *RGBA) Opaque() bool {
return true
}
-// NewRGBA returns a new RGBA with the given width and height.
-func NewRGBA(w, h int) *RGBA {
+// NewRGBA returns a new RGBA with the given bounds.
+func NewRGBA(r Rectangle) *RGBA {
+ w, h := r.Dx(), r.Dy()
buf := make([]uint8, 4*w*h)
- return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
+ return &RGBA{buf, 4 * w, r}
}
-// RGBA64 is an in-memory image of RGBA64Color values.
+// RGBA64 is an in-memory image whose At method returns color.RGBA64 values.
type RGBA64 struct {
// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
@@ -126,16 +162,16 @@ type RGBA64 struct {
Rect Rectangle
}
-func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
+func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
func (p *RGBA64) Bounds() Rectangle { return p.Rect }
-func (p *RGBA64) At(x, y int) Color {
+func (p *RGBA64) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return RGBA64Color{}
+ return color.RGBA64{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
- return RGBA64Color{
+ i := p.PixOffset(x, y)
+ return color.RGBA64{
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]),
@@ -143,12 +179,18 @@ func (p *RGBA64) At(x, y int) Color {
}
}
-func (p *RGBA64) Set(x, y int, c Color) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *RGBA64) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+}
+
+func (p *RGBA64) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
- c1 := toRGBA64Color(c).(RGBA64Color)
+ i := p.PixOffset(x, y)
+ c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
p.Pix[i+0] = uint8(c1.R >> 8)
p.Pix[i+1] = uint8(c1.R)
p.Pix[i+2] = uint8(c1.G >> 8)
@@ -159,11 +201,11 @@ func (p *RGBA64) Set(x, y int, c Color) {
p.Pix[i+7] = uint8(c1.A)
}
-func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
+func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.R >> 8)
p.Pix[i+1] = uint8(c.R)
p.Pix[i+2] = uint8(c.G >> 8)
@@ -184,7 +226,7 @@ func (p *RGBA64) SubImage(r Rectangle) Image {
if r.Empty() {
return &RGBA64{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &RGBA64{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -210,13 +252,14 @@ func (p *RGBA64) Opaque() bool {
return true
}
-// NewRGBA64 returns a new RGBA64 with the given width and height.
-func NewRGBA64(w, h int) *RGBA64 {
+// NewRGBA64 returns a new RGBA64 with the given bounds.
+func NewRGBA64(r Rectangle) *RGBA64 {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 8*w*h)
- return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
+ return &RGBA64{pix, 8 * w, r}
}
-// NRGBA is an in-memory image of NRGBAColor values.
+// NRGBA is an in-memory image whose At method returns color.NRGBA values.
type NRGBA struct {
// Pix holds the image's pixels, in R, G, B, A order. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
@@ -227,35 +270,41 @@ type NRGBA struct {
Rect Rectangle
}
-func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
+func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
func (p *NRGBA) Bounds() Rectangle { return p.Rect }
-func (p *NRGBA) At(x, y int) Color {
+func (p *NRGBA) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return NRGBAColor{}
+ return color.NRGBA{}
}
- 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]}
+ i := p.PixOffset(x, y)
+ return color.NRGBA{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) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *NRGBA) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func (p *NRGBA) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
- c1 := toNRGBAColor(c).(NRGBAColor)
+ i := p.PixOffset(x, y)
+ c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
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) {
+func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ i := p.PixOffset(x, y)
p.Pix[i+0] = c.R
p.Pix[i+1] = c.G
p.Pix[i+2] = c.B
@@ -272,7 +321,7 @@ func (p *NRGBA) SubImage(r Rectangle) Image {
if r.Empty() {
return &NRGBA{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &NRGBA{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -298,13 +347,14 @@ func (p *NRGBA) Opaque() bool {
return true
}
-// NewNRGBA returns a new NRGBA with the given width and height.
-func NewNRGBA(w, h int) *NRGBA {
+// NewNRGBA returns a new NRGBA with the given bounds.
+func NewNRGBA(r Rectangle) *NRGBA {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 4*w*h)
- return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
+ return &NRGBA{pix, 4 * w, r}
}
-// NRGBA64 is an in-memory image of NRGBA64Color values.
+// NRGBA64 is an in-memory image whose At method returns color.NRGBA64 values.
type NRGBA64 struct {
// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
@@ -315,16 +365,16 @@ type NRGBA64 struct {
Rect Rectangle
}
-func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
+func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
-func (p *NRGBA64) At(x, y int) Color {
+func (p *NRGBA64) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return NRGBA64Color{}
+ return color.NRGBA64{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
- return NRGBA64Color{
+ i := p.PixOffset(x, y)
+ return color.NRGBA64{
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]),
@@ -332,12 +382,18 @@ func (p *NRGBA64) At(x, y int) Color {
}
}
-func (p *NRGBA64) Set(x, y int, c Color) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *NRGBA64) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+}
+
+func (p *NRGBA64) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
- c1 := toNRGBA64Color(c).(NRGBA64Color)
+ i := p.PixOffset(x, y)
+ c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
p.Pix[i+0] = uint8(c1.R >> 8)
p.Pix[i+1] = uint8(c1.R)
p.Pix[i+2] = uint8(c1.G >> 8)
@@ -348,11 +404,11 @@ func (p *NRGBA64) Set(x, y int, c Color) {
p.Pix[i+7] = uint8(c1.A)
}
-func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
+func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.R >> 8)
p.Pix[i+1] = uint8(c.R)
p.Pix[i+2] = uint8(c.G >> 8)
@@ -373,7 +429,7 @@ func (p *NRGBA64) SubImage(r Rectangle) Image {
if r.Empty() {
return &NRGBA64{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &NRGBA64{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -399,13 +455,14 @@ func (p *NRGBA64) Opaque() bool {
return true
}
-// NewNRGBA64 returns a new NRGBA64 with the given width and height.
-func NewNRGBA64(w, h int) *NRGBA64 {
+// NewNRGBA64 returns a new NRGBA64 with the given bounds.
+func NewNRGBA64(r Rectangle) *NRGBA64 {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 8*w*h)
- return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
+ return &NRGBA64{pix, 8 * w, r}
}
-// Alpha is an in-memory image of AlphaColor values.
+// Alpha is an in-memory image whose At method returns color.Alpha values.
type Alpha struct {
// Pix holds the image's pixels, as alpha values. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
@@ -416,31 +473,37 @@ type Alpha struct {
Rect Rectangle
}
-func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
+func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
func (p *Alpha) Bounds() Rectangle { return p.Rect }
-func (p *Alpha) At(x, y int) Color {
+func (p *Alpha) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return AlphaColor{}
+ return color.Alpha{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return AlphaColor{p.Pix[i]}
+ i := p.PixOffset(x, y)
+ return color.Alpha{p.Pix[i]}
}
-func (p *Alpha) Set(x, y int, c Color) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Alpha) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
+func (p *Alpha) Set(x, y int, c color.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] = toAlphaColor(c).(AlphaColor).A
+ i := p.PixOffset(x, y)
+ p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
}
-func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
+func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
p.Pix[i] = c.A
}
@@ -454,7 +517,7 @@ func (p *Alpha) SubImage(r Rectangle) Image {
if r.Empty() {
return &Alpha{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &Alpha{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -480,13 +543,14 @@ func (p *Alpha) Opaque() bool {
return true
}
-// NewAlpha returns a new Alpha with the given width and height.
-func NewAlpha(w, h int) *Alpha {
+// NewAlpha returns a new Alpha with the given bounds.
+func NewAlpha(r Rectangle) *Alpha {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 1*w*h)
- return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
+ return &Alpha{pix, 1 * w, r}
}
-// Alpha16 is an in-memory image of Alpha16Color values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
type Alpha16 struct {
// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -497,33 +561,39 @@ type Alpha16 struct {
Rect Rectangle
}
-func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
+func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
func (p *Alpha16) Bounds() Rectangle { return p.Rect }
-func (p *Alpha16) At(x, y int) Color {
+func (p *Alpha16) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return Alpha16Color{}
+ return color.Alpha16{}
}
- 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])}
+ i := p.PixOffset(x, y)
+ return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Alpha16) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}
-func (p *Alpha16) Set(x, y int, c Color) {
+func (p *Alpha16) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
- c1 := toAlpha16Color(c).(Alpha16Color)
+ i := p.PixOffset(x, y)
+ c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
p.Pix[i+0] = uint8(c1.A >> 8)
p.Pix[i+1] = uint8(c1.A)
}
-func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
+func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.A >> 8)
p.Pix[i+1] = uint8(c.A)
}
@@ -538,7 +608,7 @@ func (p *Alpha16) SubImage(r Rectangle) Image {
if r.Empty() {
return &Alpha16{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &Alpha16{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -564,13 +634,14 @@ func (p *Alpha16) Opaque() bool {
return true
}
-// NewAlpha16 returns a new Alpha16 with the given width and height.
-func NewAlpha16(w, h int) *Alpha16 {
+// NewAlpha16 returns a new Alpha16 with the given bounds.
+func NewAlpha16(r Rectangle) *Alpha16 {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 2*w*h)
- return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
+ return &Alpha16{pix, 2 * w, r}
}
-// Gray is an in-memory image of GrayColor values.
+// Gray is an in-memory image whose At method returns color.Gray values.
type Gray struct {
// Pix holds the image's pixels, as gray values. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
@@ -581,31 +652,37 @@ type Gray struct {
Rect Rectangle
}
-func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
+func (p *Gray) ColorModel() color.Model { return color.GrayModel }
func (p *Gray) Bounds() Rectangle { return p.Rect }
-func (p *Gray) At(x, y int) Color {
+func (p *Gray) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return GrayColor{}
+ return color.Gray{}
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
- return GrayColor{p.Pix[i]}
+ i := p.PixOffset(x, y)
+ return color.Gray{p.Pix[i]}
}
-func (p *Gray) Set(x, y int, c Color) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Gray) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
+func (p *Gray) Set(x, y int, c color.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] = toGrayColor(c).(GrayColor).Y
+ i := p.PixOffset(x, y)
+ p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
}
-func (p *Gray) SetGray(x, y int, c GrayColor) {
+func (p *Gray) SetGray(x, y int, c color.Gray) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
p.Pix[i] = c.Y
}
@@ -619,7 +696,7 @@ func (p *Gray) SubImage(r Rectangle) Image {
if r.Empty() {
return &Gray{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &Gray{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -632,13 +709,14 @@ func (p *Gray) Opaque() bool {
return true
}
-// NewGray returns a new Gray with the given width and height.
-func NewGray(w, h int) *Gray {
+// NewGray returns a new Gray with the given bounds.
+func NewGray(r Rectangle) *Gray {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 1*w*h)
- return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
+ return &Gray{pix, 1 * w, r}
}
-// Gray16 is an in-memory image of Gray16Color values.
+// Gray16 is an in-memory image whose At method returns color.Gray16 values.
type Gray16 struct {
// Pix holds the image's pixels, as gray values in big-endian format. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -649,33 +727,39 @@ type Gray16 struct {
Rect Rectangle
}
-func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
+func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
func (p *Gray16) Bounds() Rectangle { return p.Rect }
-func (p *Gray16) At(x, y int) Color {
+func (p *Gray16) At(x, y int) color.Color {
if !(Point{x, y}.In(p.Rect)) {
- return Gray16Color{}
+ return color.Gray16{}
}
- 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])}
+ i := p.PixOffset(x, y)
+ return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Gray16) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
}
-func (p *Gray16) Set(x, y int, c Color) {
+func (p *Gray16) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
- c1 := toGray16Color(c).(Gray16Color)
+ i := p.PixOffset(x, y)
+ c1 := color.Gray16Model.Convert(c).(color.Gray16)
p.Pix[i+0] = uint8(c1.Y >> 8)
p.Pix[i+1] = uint8(c1.Y)
}
-func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
+func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.Y >> 8)
p.Pix[i+1] = uint8(c.Y)
}
@@ -690,7 +774,7 @@ func (p *Gray16) SubImage(r Rectangle) Image {
if r.Empty() {
return &Gray16{}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &Gray16{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -703,51 +787,11 @@ func (p *Gray16) Opaque() bool {
return true
}
-// NewGray16 returns a new Gray16 with the given width and height.
-func NewGray16(w, h int) *Gray16 {
+// NewGray16 returns a new Gray16 with the given bounds.
+func NewGray16(r Rectangle) *Gray16 {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 2*w*h)
- return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
-}
-
-// A PalettedColorModel represents a fixed palette of at most 256 colors.
-type PalettedColorModel []Color
-
-func diff(a, b uint32) uint32 {
- if a > b {
- return a - b
- }
- return b - a
-}
-
-// Convert returns the palette color closest to c in Euclidean R,G,B space.
-func (p PalettedColorModel) Convert(c Color) Color {
- if len(p) == 0 {
- return nil
- }
- 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
- ret, bestSSD := 0, uint32(1<<32-1)
- for i, v := range p {
- vr, vg, vb, _ := v.RGBA()
- vr >>= 1
- vg >>= 1
- vb >>= 1
- dr, dg, db := diff(cr, vr), diff(cg, vg), diff(cb, vb)
- ssd := (dr * dr) + (dg * dg) + (db * db)
- if ssd < bestSSD {
- ret, bestSSD = i, ssd
- }
- }
- return ret
+ return &Gray16{pix, 2 * w, r}
}
// Paletted is an in-memory image of uint8 indices into a given palette.
@@ -760,29 +804,35 @@ type Paletted struct {
// Rect is the image's bounds.
Rect Rectangle
// Palette is the image's palette.
- Palette PalettedColorModel
+ Palette color.Palette
}
-func (p *Paletted) ColorModel() ColorModel { return p.Palette }
+func (p *Paletted) ColorModel() color.Model { return p.Palette }
func (p *Paletted) Bounds() Rectangle { return p.Rect }
-func (p *Paletted) At(x, y int) Color {
+func (p *Paletted) At(x, y int) color.Color {
if len(p.Palette) == 0 {
return nil
}
if !(Point{x, y}.In(p.Rect)) {
return p.Palette[0]
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
return p.Palette[p.Pix[i]]
}
-func (p *Paletted) Set(x, y int, c Color) {
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *Paletted) PixOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
+}
+
+func (p *Paletted) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
p.Pix[i] = uint8(p.Palette.Index(c))
}
@@ -790,7 +840,7 @@ func (p *Paletted) ColorIndexAt(x, y int) uint8 {
if !(Point{x, y}.In(p.Rect)) {
return 0
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
return p.Pix[i]
}
@@ -798,7 +848,7 @@ func (p *Paletted) SetColorIndex(x, y int, index uint8) {
if !(Point{x, y}.In(p.Rect)) {
return
}
- i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ i := p.PixOffset(x, y)
p.Pix[i] = index
}
@@ -814,7 +864,7 @@ func (p *Paletted) SubImage(r Rectangle) Image {
Palette: p.Palette,
}
}
- i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ i := p.PixOffset(r.Min.X, r.Min.Y)
return &Paletted{
Pix: p.Pix[i:],
Stride: p.Stride,
@@ -847,7 +897,8 @@ 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 {
+func NewPaletted(r Rectangle, p color.Palette) *Paletted {
+ w, h := r.Dx(), r.Dy()
pix := make([]uint8, 1*w*h)
- return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
+ return &Paletted{pix, 1 * w, r, p}
}
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index a368e71e6..799c1a7a1 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -5,17 +5,18 @@
package image
import (
+ "image/color"
"testing"
)
type image interface {
Image
Opaque() bool
- Set(int, int, Color)
+ Set(int, int, color.Color)
SubImage(Rectangle) Image
}
-func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
+func cmp(t *testing.T, cm color.Model, c0, c1 color.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
@@ -23,15 +24,15 @@ func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
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{
+ NewRGBA(Rect(0, 0, 10, 10)),
+ NewRGBA64(Rect(0, 0, 10, 10)),
+ NewNRGBA(Rect(0, 0, 10, 10)),
+ NewNRGBA64(Rect(0, 0, 10, 10)),
+ NewAlpha(Rect(0, 0, 10, 10)),
+ NewAlpha16(Rect(0, 0, 10, 10)),
+ NewGray(Rect(0, 0, 10, 10)),
+ NewGray16(Rect(0, 0, 10, 10)),
+ NewPaletted(Rect(0, 0, 10, 10), color.Palette{
Transparent,
Opaque,
}),
@@ -81,14 +82,14 @@ func TestImage(t *testing.T) {
}
func Test16BitsPerColorChannel(t *testing.T) {
- testColorModel := []ColorModel{
- RGBA64ColorModel,
- NRGBA64ColorModel,
- Alpha16ColorModel,
- Gray16ColorModel,
+ testColorModel := []color.Model{
+ color.RGBA64Model,
+ color.NRGBA64Model,
+ color.Alpha16Model,
+ color.Gray16Model,
}
for _, cm := range testColorModel {
- c := cm.Convert(RGBA64Color{0x1234, 0x1234, 0x1234, 0x1234}) // Premultiplied alpha.
+ c := cm.Convert(color.RGBA64{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)
@@ -96,13 +97,13 @@ func Test16BitsPerColorChannel(t *testing.T) {
}
}
testImage := []image{
- NewRGBA64(10, 10),
- NewNRGBA64(10, 10),
- NewAlpha16(10, 10),
- NewGray16(10, 10),
+ NewRGBA64(Rect(0, 0, 10, 10)),
+ NewNRGBA64(Rect(0, 0, 10, 10)),
+ NewAlpha16(Rect(0, 0, 10, 10)),
+ NewGray16(Rect(0, 0, 10, 10)),
}
for _, m := range testImage {
- m.Set(1, 2, NRGBA64Color{0xffff, 0xffff, 0xffff, 0x1357}) // Non-premultiplied alpha.
+ m.Set(1, 2, color.NRGBA64{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)
diff --git a/src/pkg/image/jpeg/Makefile b/src/pkg/image/jpeg/Makefile
deleted file mode 100644
index d9d830f2f..000000000
--- a/src/pkg/image/jpeg/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../../Make.inc
-
-TARG=image/jpeg
-GOFILES=\
- fdct.go\
- huffman.go\
- idct.go\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/jpeg/huffman.go b/src/pkg/image/jpeg/huffman.go
index 0d03a7317..d2382490f 100644
--- a/src/pkg/image/jpeg/huffman.go
+++ b/src/pkg/image/jpeg/huffman.go
@@ -4,10 +4,7 @@
package jpeg
-import (
- "io"
- "os"
-)
+import "io"
// Each code is at most 16 bits long.
const maxCodeLength = 16
@@ -36,7 +33,7 @@ type huffman struct {
}
// Reads bytes from the io.Reader to ensure that bits.n is at least n.
-func (d *decoder) ensureNBits(n int) os.Error {
+func (d *decoder) ensureNBits(n int) error {
for d.b.n < n {
c, err := d.r.ReadByte()
if err != nil {
@@ -64,7 +61,7 @@ func (d *decoder) ensureNBits(n int) os.Error {
}
// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
-func (d *decoder) receiveExtend(t uint8) (int, os.Error) {
+func (d *decoder) receiveExtend(t uint8) (int, error) {
err := d.ensureNBits(int(t))
if err != nil {
return 0, err
@@ -81,7 +78,7 @@ func (d *decoder) receiveExtend(t uint8) (int, os.Error) {
// Processes a Define Huffman Table marker, and initializes a huffman struct from its contents.
// Specified in section B.2.4.2.
-func (d *decoder) processDHT(n int) os.Error {
+func (d *decoder) processDHT(n int) error {
for n > 0 {
if n < 17 {
return FormatError("DHT has wrong length")
@@ -167,7 +164,7 @@ func (d *decoder) processDHT(n int) os.Error {
// Returns the next Huffman-coded value from the bit stream, decoded according to h.
// TODO(nigeltao): This decoding algorithm is simple, but slow. A lookahead table, instead of always
// peeling off only 1 bit at at time, ought to be faster.
-func (d *decoder) decodeHuffman(h *huffman) (uint8, os.Error) {
+func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
if h.length == 0 {
return 0, FormatError("uninitialized Huffman table")
}
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
index 3f22c5271..d9adf6e58 100644
--- a/src/pkg/image/jpeg/reader.go
+++ b/src/pkg/image/jpeg/reader.go
@@ -10,9 +10,8 @@ package jpeg
import (
"bufio"
"image"
- "image/ycbcr"
+ "image/color"
"io"
- "os"
)
// TODO(nigeltao): fix up the doc comment style so that sentences start with
@@ -21,12 +20,12 @@ import (
// A FormatError reports that the input is not a valid JPEG.
type FormatError string
-func (e FormatError) String() string { return "invalid JPEG format: " + string(e) }
+func (e FormatError) Error() string { return "invalid JPEG format: " + string(e) }
// An UnsupportedError reports that the input uses a valid but unimplemented JPEG feature.
type UnsupportedError string
-func (e UnsupportedError) String() string { return "unsupported JPEG feature: " + string(e) }
+func (e UnsupportedError) Error() string { return "unsupported JPEG feature: " + string(e) }
// Component specification, specified in section B.2.2.
type component struct {
@@ -90,14 +89,14 @@ var unzig = [blockSize]int{
// If the passed in io.Reader does not also have ReadByte, then Decode will introduce its own buffering.
type Reader interface {
io.Reader
- ReadByte() (c byte, err os.Error)
+ ReadByte() (c byte, err error)
}
type decoder struct {
r Reader
width, height int
img1 *image.Gray
- img3 *ycbcr.YCbCr
+ img3 *image.YCbCr
ri int // Restart Interval.
nComp int
comp [nColorComponent]component
@@ -108,7 +107,7 @@ type decoder struct {
}
// Reads and ignores the next n bytes.
-func (d *decoder) ignore(n int) os.Error {
+func (d *decoder) ignore(n int) error {
for n > 0 {
m := len(d.tmp)
if m > n {
@@ -124,7 +123,7 @@ func (d *decoder) ignore(n int) os.Error {
}
// Specified in section B.2.2.
-func (d *decoder) processSOF(n int) os.Error {
+func (d *decoder) processSOF(n int) error {
switch n {
case 6 + 3*nGrayComponent:
d.nComp = nGrayComponent
@@ -171,7 +170,7 @@ func (d *decoder) processSOF(n int) os.Error {
}
// Specified in section B.2.4.1.
-func (d *decoder) processDQT(n int) os.Error {
+func (d *decoder) processDQT(n int) error {
const qtLength = 1 + blockSize
for ; n >= qtLength; n -= qtLength {
_, err := io.ReadFull(d.r, d.tmp[0:qtLength])
@@ -199,36 +198,27 @@ func (d *decoder) processDQT(n int) os.Error {
// 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)
+ m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
return
}
- var subsampleRatio ycbcr.SubsampleRatio
- n := h0 * v0
- switch n {
+ var subsampleRatio image.YCbCrSubsampleRatio
+ switch h0 * v0 {
case 1:
- subsampleRatio = ycbcr.SubsampleRatio444
+ subsampleRatio = image.YCbCrSubsampleRatio444
case 2:
- subsampleRatio = ycbcr.SubsampleRatio422
+ subsampleRatio = image.YCbCrSubsampleRatio422
case 4:
- subsampleRatio = ycbcr.SubsampleRatio420
+ subsampleRatio = image.YCbCrSubsampleRatio420
default:
panic("unreachable")
}
- 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),
- }
+ m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
+ d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
}
// Specified in section B.2.3.
-func (d *decoder) processSOS(n int) os.Error {
+func (d *decoder) processSOS(n int) error {
if d.nComp == 0 {
return FormatError("missing SOF marker")
}
@@ -361,7 +351,7 @@ func (d *decoder) processSOS(n int) os.Error {
}
// Specified in section B.2.4.4.
-func (d *decoder) processDRI(n int) os.Error {
+func (d *decoder) processDRI(n int) error {
if n != 2 {
return FormatError("DRI has wrong length")
}
@@ -374,7 +364,7 @@ func (d *decoder) processDRI(n int) os.Error {
}
// decode reads a JPEG image from r and returns it as an image.Image.
-func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
+func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
if rr, ok := r.(Reader); ok {
d.r = rr
} else {
@@ -450,23 +440,31 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
}
// Decode reads a JPEG image from r and returns it as an image.Image.
-func Decode(r io.Reader) (image.Image, os.Error) {
+func Decode(r io.Reader) (image.Image, error) {
var d decoder
return d.decode(r, false)
}
// DecodeConfig returns the color model and dimensions of a JPEG image without
// decoding the entire image.
-func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+func DecodeConfig(r io.Reader) (image.Config, error) {
var d decoder
if _, err := d.decode(r, true); err != nil {
return image.Config{}, err
}
switch d.nComp {
case nGrayComponent:
- return image.Config{image.GrayColorModel, d.width, d.height}, nil
+ return image.Config{
+ ColorModel: color.GrayModel,
+ Width: d.width,
+ Height: d.height,
+ }, nil
case nColorComponent:
- return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
+ return image.Config{
+ ColorModel: color.YCbCrModel,
+ Width: d.width,
+ Height: d.height,
+ }, nil
}
return image.Config{}, FormatError("missing SOF marker")
}
diff --git a/src/pkg/image/jpeg/writer.go b/src/pkg/image/jpeg/writer.go
index 2bb6df5dd..3322c09fe 100644
--- a/src/pkg/image/jpeg/writer.go
+++ b/src/pkg/image/jpeg/writer.go
@@ -6,10 +6,10 @@ package jpeg
import (
"bufio"
+ "errors"
"image"
- "image/ycbcr"
+ "image/color"
"io"
- "os"
)
// min returns the minimum of two integers.
@@ -207,9 +207,9 @@ func init() {
// writer is a buffered writer.
type writer interface {
- Flush() os.Error
- Write([]byte) (int, os.Error)
- WriteByte(byte) os.Error
+ Flush() error
+ Write([]byte) (int, error)
+ WriteByte(byte) error
}
// encoder encodes an image to the JPEG format.
@@ -217,7 +217,7 @@ type encoder struct {
// w is the writer to write to. err is the first error encountered during
// writing. All attempted writes after the first error become no-ops.
w writer
- err os.Error
+ err error
// buf is a scratch buffer.
buf [16]byte
// bits and nBits are accumulated bits to write to w.
@@ -379,7 +379,7 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
for j := 0; j < 8; j++ {
for i := 0; i < 8; i++ {
r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
- yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
yBlock[8*j+i] = int(yy)
cbBlock[8*j+i] = int(cb)
crBlock[8*j+i] = int(cr)
@@ -404,7 +404,7 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
sx = xmax
}
pix := m.Pix[offset+sx*4:]
- yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
+ yy, cb, cr := color.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)
@@ -458,7 +458,7 @@ func (e *encoder) writeSOS(m image.Image) {
for i := 0; i < 4; i++ {
xOff := (i & 1) * 8
yOff := (i & 2) * 4
- p := image.Point{x + xOff, y + yOff}
+ p := image.Pt(x+xOff, y+yOff)
if rgba != nil {
rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
} else {
@@ -487,10 +487,10 @@ type Options struct {
// Encode writes the Image m to w in JPEG 4:2:0 baseline format with the given
// options. Default parameters are used if a nil *Options is passed.
-func Encode(w io.Writer, m image.Image, o *Options) os.Error {
+func Encode(w io.Writer, m image.Image, o *Options) error {
b := m.Bounds()
if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 {
- return os.NewError("jpeg: image is too large to encode")
+ return errors.New("jpeg: image is too large to encode")
}
var e encoder
if ww, ok := w.(writer); ok {
diff --git a/src/pkg/image/jpeg/writer_test.go b/src/pkg/image/jpeg/writer_test.go
index 7aec70f01..b8e8fa34e 100644
--- a/src/pkg/image/jpeg/writer_test.go
+++ b/src/pkg/image/jpeg/writer_test.go
@@ -7,9 +7,10 @@ package jpeg
import (
"bytes"
"image"
+ "image/color"
"image/png"
"io/ioutil"
- "rand"
+ "math/rand"
"os"
"testing"
)
@@ -35,7 +36,7 @@ func delta(u0, u1 uint32) int64 {
return d
}
-func readPng(filename string) (image.Image, os.Error) {
+func readPng(filename string) (image.Image, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
@@ -53,14 +54,14 @@ func TestWriter(t *testing.T) {
continue
}
// Encode that image as JPEG.
- buf := bytes.NewBuffer(nil)
- err = Encode(buf, m0, &Options{Quality: tc.quality})
+ var buf bytes.Buffer
+ err = Encode(&buf, m0, &Options{Quality: tc.quality})
if err != nil {
t.Error(tc.filename, err)
continue
}
// Decode that JPEG.
- m1, err := Decode(buf)
+ m1, err := Decode(&buf)
if err != nil {
t.Error(tc.filename, err)
continue
@@ -90,13 +91,13 @@ func TestWriter(t *testing.T) {
func BenchmarkEncodeRGBOpaque(b *testing.B) {
b.StopTimer()
- img := image.NewRGBA(640, 480)
+ img := image.NewRGBA(image.Rect(0, 0, 640, 480))
// Set all pixels to 0xFF alpha to force opaque mode.
bo := img.Bounds()
rnd := rand.New(rand.NewSource(123))
for y := bo.Min.Y; y < bo.Max.Y; y++ {
for x := bo.Min.X; x < bo.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{
+ img.Set(x, y, color.RGBA{
uint8(rnd.Intn(256)),
uint8(rnd.Intn(256)),
uint8(rnd.Intn(256)),
@@ -104,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
}
}
if !img.Opaque() {
- panic("expected image to be opaque")
+ b.Fatal("expected image to be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
diff --git a/src/pkg/image/names.go b/src/pkg/image/names.go
index c309684ce..55f634c17 100644
--- a/src/pkg/image/names.go
+++ b/src/pkg/image/names.go
@@ -4,64 +4,49 @@
package image
+import (
+ "image/color"
+)
+
var (
- // Black is an opaque black ColorImage.
- Black = NewColorImage(Gray16Color{0})
- // White is an opaque white ColorImage.
- White = NewColorImage(Gray16Color{0xffff})
- // Transparent is a fully transparent ColorImage.
- Transparent = NewColorImage(Alpha16Color{0})
- // Opaque is a fully opaque ColorImage.
- Opaque = NewColorImage(Alpha16Color{0xffff})
+ // Black is an opaque black uniform image.
+ Black = NewUniform(color.Black)
+ // White is an opaque white uniform image.
+ White = NewUniform(color.White)
+ // Transparent is a fully transparent uniform image.
+ Transparent = NewUniform(color.Transparent)
+ // Opaque is a fully opaque uniform image.
+ Opaque = NewUniform(color.Opaque)
)
-// A ColorImage is an infinite-sized Image of uniform Color.
-// It implements both the Color and Image interfaces.
-type ColorImage struct {
- C Color
+// Uniform is an infinite-sized Image of uniform color.
+// It implements the color.Color, color.ColorModel, and Image interfaces.
+type Uniform struct {
+ C color.Color
}
-func (c *ColorImage) RGBA() (r, g, b, a uint32) {
+func (c *Uniform) RGBA() (r, g, b, a uint32) {
return c.C.RGBA()
}
-func (c *ColorImage) ColorModel() ColorModel {
- return ColorModelFunc(func(Color) Color { return c.C })
+func (c *Uniform) ColorModel() color.Model {
+ return c
+}
+
+func (c *Uniform) Convert(color.Color) color.Color {
+ return c.C
}
-func (c *ColorImage) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+func (c *Uniform) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
-func (c *ColorImage) At(x, y int) Color { return c.C }
+func (c *Uniform) At(x, y int) color.Color { return c.C }
// Opaque scans the entire image and returns whether or not it is fully opaque.
-func (c *ColorImage) Opaque() bool {
+func (c *Uniform) Opaque() bool {
_, _, _, a := c.C.RGBA()
return a == 0xffff
}
-func NewColorImage(c Color) *ColorImage {
- return &ColorImage{c}
-}
-
-// A Tiled is an infinite-sized Image that repeats another Image in both
-// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
-// points {x+p.X, y+p.Y} within i's Bounds.
-type Tiled struct {
- I Image
- Offset Point
-}
-
-func (t *Tiled) ColorModel() ColorModel {
- return t.I.ColorModel()
-}
-
-func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
-
-func (t *Tiled) At(x, y int) Color {
- p := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())
- return t.I.At(p.X, p.Y)
-}
-
-func NewTiled(i Image, offset Point) *Tiled {
- return &Tiled{i, offset}
+func NewUniform(c color.Color) *Uniform {
+ return &Uniform{c}
}
diff --git a/src/pkg/image/png/Makefile b/src/pkg/image/png/Makefile
deleted file mode 100644
index 4101f77e1..000000000
--- a/src/pkg/image/png/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=image/png
-GOFILES=\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index 8c76afa72..fe07d60a9 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -4,17 +4,18 @@
// Package png implements a PNG image decoder and encoder.
//
-// The PNG specification is at http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
+// The PNG specification is at http://www.w3.org/TR/PNG/.
package png
import (
"compress/zlib"
+ "encoding/binary"
"fmt"
"hash"
"hash/crc32"
"image"
+ "image/color"
"io"
- "os"
)
// Color type, as per the PNG spec.
@@ -61,6 +62,7 @@ const (
// chunks must appear in that order. There may be multiple IDAT chunks, and
// IDAT chunks must be sequential (i.e. they may not have any other chunks
// between them).
+// http://www.w3.org/TR/PNG/#5ChunkOrdering
const (
dsStart = iota
dsSeenIHDR
@@ -71,45 +73,30 @@ const (
const pngHeader = "\x89PNG\r\n\x1a\n"
-type imgOrErr struct {
- img image.Image
- err os.Error
-}
-
type decoder struct {
+ r io.Reader
+ img image.Image
+ crc hash.Hash32
width, height int
depth int
- palette image.PalettedColorModel
+ palette color.Palette
cb int
stage int
- idatWriter io.WriteCloser
- idatDone chan imgOrErr
+ idatLength uint32
tmp [3 * 256]byte
}
// A FormatError reports that the input is not a valid PNG.
type FormatError string
-func (e FormatError) String() string { return "png: invalid format: " + string(e) }
+func (e FormatError) Error() string { return "png: invalid format: " + string(e) }
var chunkOrderError = FormatError("chunk out of order")
-// An IDATDecodingError wraps an inner error (such as a ZLIB decoding error) encountered while processing an IDAT chunk.
-type IDATDecodingError struct {
- Err os.Error
-}
-
-func (e IDATDecodingError) String() string { return "png: IDAT decoding error: " + e.Err.String() }
-
// An UnsupportedError reports that the input uses a valid but unimplemented PNG feature.
type UnsupportedError string
-func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
-
-// Big-endian.
-func parseUint32(b []uint8) uint32 {
- return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
-}
+func (e UnsupportedError) Error() string { return "png: unsupported feature: " + string(e) }
func abs(x int) int {
if x < 0 {
@@ -125,20 +112,19 @@ func min(a, b int) int {
return b
}
-func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+func (d *decoder) parseIHDR(length uint32) error {
if length != 13 {
return FormatError("bad IHDR length")
}
- _, err := io.ReadFull(r, d.tmp[0:13])
- if err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:13]); err != nil {
return err
}
- crc.Write(d.tmp[0:13])
+ d.crc.Write(d.tmp[:13])
if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
return UnsupportedError("compression, filter or interlace method")
}
- w := int32(parseUint32(d.tmp[0:4]))
- h := int32(parseUint32(d.tmp[4:8]))
+ w := int32(binary.BigEndian.Uint32(d.tmp[0:4]))
+ h := int32(binary.BigEndian.Uint32(d.tmp[4:8]))
if w < 0 || h < 0 {
return FormatError("negative dimension")
}
@@ -199,24 +185,24 @@ func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
}
d.width, d.height = int(w), int(h)
- return nil
+ return d.verifyChecksum()
}
-func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+func (d *decoder) parsePLTE(length uint32) error {
np := int(length / 3) // The number of palette entries.
if length%3 != 0 || np <= 0 || np > 256 || np > 1<<uint(d.depth) {
return FormatError("bad PLTE length")
}
- n, err := io.ReadFull(r, d.tmp[0:3*np])
+ n, err := io.ReadFull(d.r, d.tmp[:3*np])
if err != nil {
return err
}
- crc.Write(d.tmp[0:n])
+ d.crc.Write(d.tmp[:n])
switch d.cb {
case cbP1, cbP2, cbP4, cbP8:
- d.palette = image.PalettedColorModel(make([]image.Color, np))
+ d.palette = color.Palette(make([]color.Color, np))
for i := 0; i < np; i++ {
- d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
+ d.palette[i] = color.RGBA{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
}
case cbTC8, cbTCA8, cbTC16, cbTCA16:
// As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
@@ -224,18 +210,18 @@ func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Erro
default:
return FormatError("PLTE, color type mismatch")
}
- return nil
+ return d.verifyChecksum()
}
-func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Error {
+func (d *decoder) parsetRNS(length uint32) error {
if length > 256 {
return FormatError("bad tRNS length")
}
- n, err := io.ReadFull(r, d.tmp[0:length])
+ n, err := io.ReadFull(d.r, d.tmp[:length])
if err != nil {
return err
}
- crc.Write(d.tmp[0:n])
+ d.crc.Write(d.tmp[:n])
switch d.cb {
case cbG8, cbG16:
return UnsupportedError("grayscale transparency")
@@ -246,13 +232,13 @@ func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Erro
return FormatError("bad tRNS length")
}
for i := 0; i < n; i++ {
- rgba := d.palette[i].(image.RGBAColor)
- d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
+ rgba := d.palette[i].(color.RGBA)
+ d.palette[i] = color.RGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
case cbGA8, cbGA16, cbTCA8, cbTCA16:
return FormatError("tRNS, color type mismatch")
}
- return nil
+ return d.verifyChecksum()
}
// The Paeth filter function, as per the PNG specification.
@@ -269,8 +255,46 @@ func paeth(a, b, c uint8) uint8 {
return c
}
-func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
- r, err := zlib.NewReader(idat)
+// Read presents one or more IDAT chunks as one continuous stream (minus the
+// intermediate chunk headers and footers). If the PNG data looked like:
+// ... len0 IDAT xxx crc0 len1 IDAT yy crc1 len2 IEND crc2
+// then this reader presents xxxyy. For well-formed PNG data, the decoder state
+// immediately before the first Read call is that d.r is positioned between the
+// first IDAT and xxx, and the decoder state immediately after the last Read
+// call is that d.r is positioned between yy and crc1.
+func (d *decoder) Read(p []byte) (int, error) {
+ if len(p) == 0 {
+ return 0, nil
+ }
+ for d.idatLength == 0 {
+ // We have exhausted an IDAT chunk. Verify the checksum of that chunk.
+ if err := d.verifyChecksum(); err != nil {
+ return 0, err
+ }
+ // Read the length and chunk type of the next chunk, and check that
+ // it is an IDAT chunk.
+ if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil {
+ return 0, err
+ }
+ d.idatLength = binary.BigEndian.Uint32(d.tmp[:4])
+ if string(d.tmp[4:8]) != "IDAT" {
+ return 0, FormatError("not enough pixel data")
+ }
+ d.crc.Reset()
+ d.crc.Write(d.tmp[4:8])
+ }
+ if int(d.idatLength) < 0 {
+ return 0, UnsupportedError("IDAT chunk length overflow")
+ }
+ n, err := d.r.Read(p[:min(len(p), int(d.idatLength))])
+ d.crc.Write(p[:n])
+ d.idatLength -= uint32(n)
+ return n, err
+}
+
+// decode decodes the IDAT data into an image.
+func (d *decoder) decode() (image.Image, error) {
+ r, err := zlib.NewReader(d)
if err != nil {
return nil, err
}
@@ -290,40 +314,40 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
bitsPerPixel = d.depth
- gray = image.NewGray(d.width, d.height)
+ gray = image.NewGray(image.Rect(0, 0, d.width, d.height))
img = gray
case cbGA8:
bitsPerPixel = 16
- nrgba = image.NewNRGBA(d.width, d.height)
+ nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height))
img = nrgba
case cbTC8:
bitsPerPixel = 24
- rgba = image.NewRGBA(d.width, d.height)
+ rgba = image.NewRGBA(image.Rect(0, 0, d.width, d.height))
img = rgba
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
- paletted = image.NewPaletted(d.width, d.height, d.palette)
+ paletted = image.NewPaletted(image.Rect(0, 0, d.width, d.height), d.palette)
img = paletted
maxPalette = uint8(len(d.palette) - 1)
case cbTCA8:
bitsPerPixel = 32
- nrgba = image.NewNRGBA(d.width, d.height)
+ nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height))
img = nrgba
case cbG16:
bitsPerPixel = 16
- gray16 = image.NewGray16(d.width, d.height)
+ gray16 = image.NewGray16(image.Rect(0, 0, d.width, d.height))
img = gray16
case cbGA16:
bitsPerPixel = 32
- nrgba64 = image.NewNRGBA64(d.width, d.height)
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height))
img = nrgba64
case cbTC16:
bitsPerPixel = 48
- rgba64 = image.NewRGBA64(d.width, d.height)
+ rgba64 = image.NewRGBA64(image.Rect(0, 0, d.width, d.height))
img = rgba64
case cbTCA16:
bitsPerPixel = 64
- nrgba64 = image.NewNRGBA64(d.width, d.height)
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, d.width, d.height))
img = nrgba64
}
bytesPerPixel := (bitsPerPixel + 7) / 8
@@ -378,7 +402,7 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 8 {
b := cdat[x/8]
for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
- gray.SetGray(x+x2, y, image.GrayColor{(b >> 7) * 0xff})
+ gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
b <<= 1
}
}
@@ -386,7 +410,7 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 4 {
b := cdat[x/4]
for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
- gray.SetGray(x+x2, y, image.GrayColor{(b >> 6) * 0x55})
+ gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
b <<= 2
}
}
@@ -394,22 +418,22 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
for x := 0; x < d.width; x += 2 {
b := cdat[x/2]
for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
- gray.SetGray(x+x2, y, image.GrayColor{(b >> 4) * 0x11})
+ gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
b <<= 4
}
}
case cbG8:
for x := 0; x < d.width; x++ {
- gray.SetGray(x, y, image.GrayColor{cdat[x]})
+ gray.SetGray(x, y, color.Gray{cdat[x]})
}
case cbGA8:
for x := 0; x < d.width; x++ {
ycol := cdat[2*x+0]
- nrgba.SetNRGBA(x, y, image.NRGBAColor{ycol, ycol, ycol, cdat[2*x+1]})
+ nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
for x := 0; x < d.width; x++ {
- rgba.SetRGBA(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
+ rgba.SetRGBA(x, y, color.RGBA{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
}
case cbP1:
for x := 0; x < d.width; x += 8 {
@@ -456,25 +480,25 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
}
case cbTCA8:
for x := 0; x < d.width; x++ {
- nrgba.SetNRGBA(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
+ nrgba.SetNRGBA(x, y, color.NRGBA{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
}
case cbG16:
for x := 0; x < d.width; x++ {
ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.SetGray16(x, y, image.Gray16Color{ycol})
+ gray16.SetGray16(x, y, color.Gray16{ycol})
}
case cbGA16:
for x := 0; x < d.width; x++ {
ycol := uint16(cdat[4*x+0])<<8 | uint16(cdat[4*x+1])
acol := uint16(cdat[4*x+2])<<8 | uint16(cdat[4*x+3])
- nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{ycol, ycol, ycol, acol})
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
for x := 0; x < d.width; x++ {
rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.SetRGBA64(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+ rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
}
case cbTCA16:
for x := 0; x < d.width; x++ {
@@ -482,150 +506,113 @@ func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
- nrgba64.SetNRGBA64(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
}
}
// The current row for y is the previous row for y+1.
pr, cr = cr, pr
}
- return img, nil
-}
-func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
- // There may be more than one IDAT chunk, but their contents must be
- // treated as if it was one continuous stream (to the zlib decoder).
- // We bring up an io.Pipe and write the IDAT chunks into the pipe as
- // we see them, and decode the stream in a separate go-routine, which
- // signals its completion (successful or not) via a channel.
- if d.idatWriter == nil {
- pr, pw := io.Pipe()
- d.idatWriter = pw
- d.idatDone = make(chan imgOrErr)
- go func() {
- img, err := d.idatReader(pr)
- if err == os.EOF {
- err = FormatError("too little IDAT")
- }
- pr.CloseWithError(FormatError("too much IDAT"))
- d.idatDone <- imgOrErr{img, err}
- }()
+ // Check for EOF, to verify the zlib checksum.
+ n, err := r.Read(pr[:1])
+ if err != io.EOF {
+ return nil, FormatError(err.Error())
}
- var buf [4096]byte
- for length > 0 {
- n, err1 := r.Read(buf[0:min(len(buf), int(length))])
- // We delay checking err1. It is possible to get n bytes and an error,
- // but if the n bytes themselves contain a FormatError, for example, we
- // want to report that error, and not the one that made the Read stop.
- n, err2 := d.idatWriter.Write(buf[0:n])
- if err2 != nil {
- return err2
- }
- if err1 != nil {
- return err1
- }
- crc.Write(buf[0:n])
- length -= uint32(n)
+ if n != 0 || d.idatLength != 0 {
+ return nil, FormatError("too much pixel data")
}
- return nil
-}
-func (d *decoder) parseIEND(r io.Reader, crc hash.Hash32, length uint32) os.Error {
- if length != 0 {
- return FormatError("bad IEND length")
- }
- return nil
+ return img, nil
}
-func (d *decoder) parseChunk(r io.Reader) os.Error {
- // Read the length.
- n, err := io.ReadFull(r, d.tmp[0:4])
- if err == os.EOF {
- return io.ErrUnexpectedEOF
- }
+func (d *decoder) parseIDAT(length uint32) (err error) {
+ d.idatLength = length
+ d.img, err = d.decode()
if err != nil {
return err
}
- length := parseUint32(d.tmp[0:4])
+ return d.verifyChecksum()
+}
- // Read the chunk type.
- n, err = io.ReadFull(r, d.tmp[0:4])
- if err == os.EOF {
- return io.ErrUnexpectedEOF
+func (d *decoder) parseIEND(length uint32) error {
+ if length != 0 {
+ return FormatError("bad IEND length")
}
+ return d.verifyChecksum()
+}
+
+func (d *decoder) parseChunk() error {
+ // Read the length and chunk type.
+ n, err := io.ReadFull(d.r, d.tmp[:8])
if err != nil {
return err
}
- crc := crc32.NewIEEE()
- crc.Write(d.tmp[0:4])
+ length := binary.BigEndian.Uint32(d.tmp[:4])
+ d.crc.Reset()
+ d.crc.Write(d.tmp[4:8])
// Read the chunk data.
- switch string(d.tmp[0:4]) {
+ switch string(d.tmp[4:8]) {
case "IHDR":
if d.stage != dsStart {
return chunkOrderError
}
d.stage = dsSeenIHDR
- err = d.parseIHDR(r, crc, length)
+ return d.parseIHDR(length)
case "PLTE":
if d.stage != dsSeenIHDR {
return chunkOrderError
}
d.stage = dsSeenPLTE
- err = d.parsePLTE(r, crc, length)
+ return d.parsePLTE(length)
case "tRNS":
if d.stage != dsSeenPLTE {
return chunkOrderError
}
- err = d.parsetRNS(r, crc, length)
+ return d.parsetRNS(length)
case "IDAT":
if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
return chunkOrderError
}
d.stage = dsSeenIDAT
- err = d.parseIDAT(r, crc, length)
+ return d.parseIDAT(length)
case "IEND":
if d.stage != dsSeenIDAT {
return chunkOrderError
}
d.stage = dsSeenIEND
- err = d.parseIEND(r, crc, length)
- default:
- // Ignore this chunk (of a known length).
- var ignored [4096]byte
- for length > 0 {
- n, err = io.ReadFull(r, ignored[0:min(len(ignored), int(length))])
- if err != nil {
- return err
- }
- crc.Write(ignored[0:n])
- length -= uint32(n)
- }
+ return d.parseIEND(length)
}
- if err != nil {
- return err
+ // Ignore this chunk (of a known length).
+ var ignored [4096]byte
+ for length > 0 {
+ n, err = io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(ignored[:n])
+ length -= uint32(n)
}
+ return d.verifyChecksum()
+}
- // Read the checksum.
- n, err = io.ReadFull(r, d.tmp[0:4])
- if err == os.EOF {
- return io.ErrUnexpectedEOF
- }
- if err != nil {
+func (d *decoder) verifyChecksum() error {
+ if _, err := io.ReadFull(d.r, d.tmp[:4]); err != nil {
return err
}
- if parseUint32(d.tmp[0:4]) != crc.Sum32() {
+ if binary.BigEndian.Uint32(d.tmp[:4]) != d.crc.Sum32() {
return FormatError("invalid checksum")
}
return nil
}
-func (d *decoder) checkHeader(r io.Reader) os.Error {
- _, err := io.ReadFull(r, d.tmp[0:8])
+func (d *decoder) checkHeader() error {
+ _, err := io.ReadFull(d.r, d.tmp[:len(pngHeader)])
if err != nil {
return err
}
- if string(d.tmp[0:8]) != pngHeader {
+ if string(d.tmp[:len(pngHeader)]) != pngHeader {
return FormatError("not a PNG file")
}
return nil
@@ -633,43 +620,46 @@ func (d *decoder) checkHeader(r io.Reader) os.Error {
// Decode reads a PNG image from r and returns it as an image.Image.
// The type of Image returned depends on the PNG contents.
-func Decode(r io.Reader) (image.Image, os.Error) {
- var d decoder
- err := d.checkHeader(r)
- if err != nil {
+func Decode(r io.Reader) (image.Image, error) {
+ d := &decoder{
+ r: r,
+ crc: crc32.NewIEEE(),
+ }
+ if err := d.checkHeader(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return nil, err
}
for d.stage != dsSeenIEND {
- err = d.parseChunk(r)
- if err != nil {
- break
- }
- }
- var img image.Image
- if d.idatWriter != nil {
- d.idatWriter.Close()
- ie := <-d.idatDone
- if err == nil {
- img, err = ie.img, ie.err
+ if err := d.parseChunk(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
}
}
- if err != nil {
- return nil, err
- }
- return img, nil
+ return d.img, nil
}
// DecodeConfig returns the color model and dimensions of a PNG image without
// decoding the entire image.
-func DecodeConfig(r io.Reader) (image.Config, os.Error) {
- var d decoder
- err := d.checkHeader(r)
- if err != nil {
+func DecodeConfig(r io.Reader) (image.Config, error) {
+ d := &decoder{
+ r: r,
+ crc: crc32.NewIEEE(),
+ }
+ if err := d.checkHeader(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return image.Config{}, err
}
for {
- err = d.parseChunk(r)
- if err != nil {
+ if err := d.parseChunk(); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
return image.Config{}, err
}
if d.stage == dsSeenIHDR && d.cb != cbP8 {
@@ -679,28 +669,32 @@ func DecodeConfig(r io.Reader) (image.Config, os.Error) {
break
}
}
- var cm image.ColorModel
+ var cm color.Model
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
- cm = image.GrayColorModel
+ cm = color.GrayModel
case cbGA8:
- cm = image.NRGBAColorModel
+ cm = color.NRGBAModel
case cbTC8:
- cm = image.RGBAColorModel
+ cm = color.RGBAModel
case cbP1, cbP2, cbP4, cbP8:
cm = d.palette
case cbTCA8:
- cm = image.NRGBAColorModel
+ cm = color.NRGBAModel
case cbG16:
- cm = image.Gray16ColorModel
+ cm = color.Gray16Model
case cbGA16:
- cm = image.NRGBA64ColorModel
+ cm = color.NRGBA64Model
case cbTC16:
- cm = image.RGBA64ColorModel
+ cm = color.RGBA64Model
case cbTCA16:
- cm = image.NRGBA64ColorModel
+ cm = color.NRGBA64Model
}
- return image.Config{cm, d.width, d.height}, nil
+ return image.Config{
+ ColorModel: cm,
+ Width: d.width,
+ Height: d.height,
+ }, nil
}
func init() {
diff --git a/src/pkg/image/png/reader_test.go b/src/pkg/image/png/reader_test.go
index bcc1a3db4..24c4ea448 100644
--- a/src/pkg/image/png/reader_test.go
+++ b/src/pkg/image/png/reader_test.go
@@ -8,8 +8,10 @@ import (
"bufio"
"fmt"
"image"
+ "image/color"
"io"
"os"
+ "strings"
"testing"
)
@@ -41,7 +43,7 @@ var filenamesShort = []string{
"basn6a16",
}
-func readPng(filename string) (image.Image, os.Error) {
+func readPNG(filename string) (image.Image, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
@@ -57,12 +59,12 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
cm := png.ColorModel()
var bitdepth int
switch cm {
- case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel:
+ case color.RGBAModel, color.NRGBAModel, color.AlphaModel, color.GrayModel:
bitdepth = 8
default:
bitdepth = 16
}
- cpm, _ := cm.(image.PalettedColorModel)
+ cpm, _ := cm.(color.Palette)
var paletted *image.Paletted
if cpm != nil {
switch {
@@ -82,11 +84,11 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
switch {
- case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel:
+ case cm == color.RGBAModel, cm == color.RGBA64Model:
io.WriteString(w, " using color;\n")
- case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel:
+ case cm == color.NRGBAModel, cm == color.NRGBA64Model:
io.WriteString(w, " using color alpha;\n")
- case cm == image.GrayColorModel, cm == image.Gray16ColorModel:
+ case cm == color.GrayModel, cm == color.Gray16Model:
io.WriteString(w, " using grayscale;\n")
case cpm != nil:
io.WriteString(w, " using color palette;\n")
@@ -129,34 +131,34 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
io.WriteString(w, "IMAGE {\n pixels hex\n")
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
switch {
- case cm == image.GrayColorModel:
+ case cm == color.GrayModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- gray := png.At(x, y).(image.GrayColor)
+ gray := png.At(x, y).(color.Gray)
fmt.Fprintf(w, "%02x", gray.Y)
}
- case cm == image.Gray16ColorModel:
+ case cm == color.Gray16Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- gray16 := png.At(x, y).(image.Gray16Color)
+ gray16 := png.At(x, y).(color.Gray16)
fmt.Fprintf(w, "%04x ", gray16.Y)
}
- case cm == image.RGBAColorModel:
+ case cm == color.RGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- rgba := png.At(x, y).(image.RGBAColor)
+ rgba := png.At(x, y).(color.RGBA)
fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
}
- case cm == image.RGBA64ColorModel:
+ case cm == color.RGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- rgba64 := png.At(x, y).(image.RGBA64Color)
+ rgba64 := png.At(x, y).(color.RGBA64)
fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
}
- case cm == image.NRGBAColorModel:
+ case cm == color.NRGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- nrgba := png.At(x, y).(image.NRGBAColor)
+ nrgba := png.At(x, y).(color.NRGBA)
fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
}
- case cm == image.NRGBA64ColorModel:
+ case cm == color.NRGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
- nrgba64 := png.At(x, y).(image.NRGBA64Color)
+ nrgba64 := png.At(x, y).(color.NRGBA64)
fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
}
case cpm != nil:
@@ -183,7 +185,7 @@ func TestReader(t *testing.T) {
}
for _, fn := range names {
// Read the .png file.
- img, err := readPng("testdata/pngsuite/" + fn + ".png")
+ img, err := readPNG("testdata/pngsuite/" + fn + ".png")
if err != nil {
t.Error(fn, err)
continue
@@ -192,7 +194,7 @@ func TestReader(t *testing.T) {
if fn == "basn4a16" {
// basn4a16.sng is gray + alpha but sng() will produce true color + alpha
// so we just check a single random pixel.
- c := img.At(2, 1).(image.NRGBA64Color)
+ c := img.At(2, 1).(color.NRGBA64)
if c.R != 0x11a7 || c.G != 0x11a7 || c.B != 0x11a7 || c.A != 0x1085 {
t.Error(fn, fmt.Errorf("wrong pixel value at (2, 1): %x", c))
}
@@ -221,7 +223,7 @@ func TestReader(t *testing.T) {
for {
ps, perr := pb.ReadString('\n')
ss, serr := sb.ReadString('\n')
- if perr == os.EOF && serr == os.EOF {
+ if perr == io.EOF && serr == io.EOF {
break
}
if perr != nil {
@@ -239,3 +241,29 @@ func TestReader(t *testing.T) {
}
}
}
+
+var readerErrors = []struct {
+ file string
+ err string
+}{
+ {"invalid-zlib.png", "zlib: invalid checksum"},
+ {"invalid-crc32.png", "invalid checksum"},
+ {"invalid-noend.png", "unexpected EOF"},
+ {"invalid-trunc.png", "unexpected EOF"},
+}
+
+func TestReaderError(t *testing.T) {
+ for _, tt := range readerErrors {
+ img, err := readPNG("testdata/" + tt.file)
+ if err == nil {
+ t.Errorf("decoding %s: missing error", tt.file)
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Errorf("decoding %s: %s, want %s", tt.file, err, tt.err)
+ }
+ if img != nil {
+ t.Errorf("decoding %s: have image + error", tt.file)
+ }
+ }
+}
diff --git a/src/pkg/image/png/testdata/invalid-crc32.png b/src/pkg/image/png/testdata/invalid-crc32.png
new file mode 100644
index 000000000..e5be4086c
--- /dev/null
+++ b/src/pkg/image/png/testdata/invalid-crc32.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/invalid-noend.png b/src/pkg/image/png/testdata/invalid-noend.png
new file mode 100644
index 000000000..9137270d9
--- /dev/null
+++ b/src/pkg/image/png/testdata/invalid-noend.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/invalid-trunc.png b/src/pkg/image/png/testdata/invalid-trunc.png
new file mode 100644
index 000000000..d0748cf65
--- /dev/null
+++ b/src/pkg/image/png/testdata/invalid-trunc.png
Binary files differ
diff --git a/src/pkg/image/png/testdata/invalid-zlib.png b/src/pkg/image/png/testdata/invalid-zlib.png
new file mode 100644
index 000000000..c6d051cae
--- /dev/null
+++ b/src/pkg/image/png/testdata/invalid-zlib.png
Binary files differ
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index 55ca97e06..57c03792b 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -9,8 +9,8 @@ import (
"compress/zlib"
"hash/crc32"
"image"
+ "image/color"
"io"
- "os"
"strconv"
)
@@ -18,7 +18,7 @@ type encoder struct {
w io.Writer
m image.Image
cb int
- err os.Error
+ err error
header [8]byte
footer [4]byte
tmp [3 * 256]byte
@@ -125,7 +125,7 @@ func (e *encoder) writeIHDR() {
e.writeChunk(e.tmp[0:13], "IHDR")
}
-func (e *encoder) writePLTE(p image.PalettedColorModel) {
+func (e *encoder) writePLTE(p color.Palette) {
if len(p) < 1 || len(p) > 256 {
e.err = FormatError("bad palette length: " + strconv.Itoa(len(p)))
return
@@ -139,7 +139,7 @@ func (e *encoder) writePLTE(p image.PalettedColorModel) {
e.writeChunk(e.tmp[0:3*len(p)], "PLTE")
}
-func (e *encoder) maybeWritetRNS(p image.PalettedColorModel) {
+func (e *encoder) maybeWritetRNS(p color.Palette) {
last := -1
for i, c := range p {
_, _, _, a := c.RGBA()
@@ -160,11 +160,7 @@ func (e *encoder) maybeWritetRNS(p image.PalettedColorModel) {
//
// This method should only be called from writeIDATs (via writeImage).
// No other code should treat an encoder as an io.Writer.
-//
-// Note that, because the zlib Reader may involve an io.Pipe, e.Write calls may
-// occur on a separate go-routine than the e.writeIDATs call, and care should be
-// taken that e's state (such as its tmp buffer) is not modified concurrently.
-func (e *encoder) Write(b []byte) (int, os.Error) {
+func (e *encoder) Write(b []byte) (int, error) {
e.writeChunk(b, "IDAT")
if e.err != nil {
return 0, e.err
@@ -266,11 +262,8 @@ func filter(cr *[nFilter][]byte, pr []byte, bpp int) int {
return filter
}
-func writeImage(w io.Writer, m image.Image, cb int) os.Error {
- zw, err := zlib.NewWriter(w)
- if err != nil {
- return err
- }
+func writeImage(w io.Writer, m image.Image, cb int) error {
+ zw := zlib.NewWriter(w)
defer zw.Close()
bpp := 0 // Bytes per pixel.
@@ -310,7 +303,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
switch cb {
case cbG8:
for x := b.Min.X; x < b.Max.X; x++ {
- c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor)
+ c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
cr[0][i] = c.Y
i++
}
@@ -336,13 +329,20 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
}
}
case cbP8:
- paletted := m.(*image.Paletted)
- offset := (y - b.Min.Y) * paletted.Stride
- copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
+ if p, _ := m.(*image.Paletted); p != nil {
+ offset := (y - b.Min.Y) * p.Stride
+ copy(cr[0][1:], p.Pix[offset:offset+b.Dx()])
+ } else {
+ pi := m.(image.PalettedImage)
+ for x := b.Min.X; x < b.Max.X; x++ {
+ cr[0][i] = pi.ColorIndexAt(x, y)
+ i += 1
+ }
+ }
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)
+ c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
cr[0][i+0] = c.R
cr[0][i+1] = c.G
cr[0][i+2] = c.B
@@ -351,7 +351,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
}
case cbG16:
for x := b.Min.X; x < b.Max.X; x++ {
- c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color)
+ c := color.Gray16Model.Convert(m.At(x, y)).(color.Gray16)
cr[0][i+0] = uint8(c.Y >> 8)
cr[0][i+1] = uint8(c.Y)
i += 2
@@ -371,7 +371,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
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)
+ c := color.NRGBA64Model.Convert(m.At(x, y)).(color.NRGBA64)
cr[0][i+0] = uint8(c.R >> 8)
cr[0][i+1] = uint8(c.R)
cr[0][i+2] = uint8(c.G >> 8)
@@ -388,8 +388,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
f := filter(&cr, pr, bpp)
// Write the compressed bytes.
- _, err = zw.Write(cr[f])
- if err != nil {
+ if _, err := zw.Write(cr[f]); err != nil {
return err
}
@@ -405,10 +404,7 @@ func (e *encoder) writeIDATs() {
return
}
var bw *bufio.Writer
- bw, e.err = bufio.NewWriterSize(e, 1<<15)
- if e.err != nil {
- return
- }
+ bw = bufio.NewWriterSize(e, 1<<15)
e.err = writeImage(bw, e.m, e.cb)
if e.err != nil {
return
@@ -420,28 +416,33 @@ func (e *encoder) writeIEND() { e.writeChunk(e.tmp[0:0], "IEND") }
// Encode writes the Image m to w in PNG format. Any Image may be encoded, but
// images that are not image.NRGBA might be encoded lossily.
-func Encode(w io.Writer, m image.Image) os.Error {
+func Encode(w io.Writer, m image.Image) error {
// Obviously, negative widths and heights are invalid. Furthermore, the PNG
// spec section 11.2.2 says that zero is invalid. Excessively large images are
// also rejected.
mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
- return FormatError("invalid image size: " + strconv.Itoa64(mw) + "x" + strconv.Itoa64(mw))
+ return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mw, 10))
}
var e encoder
e.w = w
e.m = m
- pal, _ := m.(*image.Paletted)
+
+ var pal color.Palette
+ // cbP8 encoding needs PalettedImage's ColorIndexAt method.
+ if _, ok := m.(image.PalettedImage); ok {
+ pal, _ = m.ColorModel().(color.Palette)
+ }
if pal != nil {
e.cb = cbP8
} else {
switch m.ColorModel() {
- case image.GrayColorModel:
+ case color.GrayModel:
e.cb = cbG8
- case image.Gray16ColorModel:
+ case color.Gray16Model:
e.cb = cbG16
- case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel:
+ case color.RGBAModel, color.NRGBAModel, color.AlphaModel:
if opaque(m) {
e.cb = cbTC8
} else {
@@ -459,8 +460,8 @@ func Encode(w io.Writer, m image.Image) os.Error {
_, e.err = io.WriteString(w, pngHeader)
e.writeIHDR()
if pal != nil {
- e.writePLTE(pal.Palette)
- e.maybeWritetRNS(pal.Palette)
+ e.writePLTE(pal)
+ e.maybeWritetRNS(pal)
}
e.writeIDATs()
e.writeIEND()
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
index 1599791b3..644c4fb44 100644
--- a/src/pkg/image/png/writer_test.go
+++ b/src/pkg/image/png/writer_test.go
@@ -8,12 +8,12 @@ import (
"bytes"
"fmt"
"image"
+ "image/color"
"io/ioutil"
- "os"
"testing"
)
-func diff(m0, m1 image.Image) os.Error {
+func diff(m0, m1 image.Image) error {
b0, b1 := m0.Bounds(), m1.Bounds()
if !b0.Size().Eq(b1.Size()) {
return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
@@ -34,13 +34,13 @@ func diff(m0, m1 image.Image) os.Error {
return nil
}
-func encodeDecode(m image.Image) (image.Image, os.Error) {
- b := bytes.NewBuffer(nil)
- err := Encode(b, m)
+func encodeDecode(m image.Image) (image.Image, error) {
+ var b bytes.Buffer
+ err := Encode(&b, m)
if err != nil {
return nil, err
}
- m, err = Decode(b)
+ m, err = Decode(&b)
if err != nil {
return nil, err
}
@@ -56,13 +56,13 @@ func TestWriter(t *testing.T) {
for _, fn := range names {
qfn := "testdata/pngsuite/" + fn + ".png"
// Read the image.
- m0, err := readPng(qfn)
+ m0, err := readPNG(qfn)
if err != nil {
t.Error(fn, err)
continue
}
// Read the image again, encode it, and decode it.
- m1, err := readPng(qfn)
+ m1, err := readPNG(qfn)
if err != nil {
t.Error(fn, err)
return
@@ -82,10 +82,10 @@ func TestWriter(t *testing.T) {
}
func TestSubImage(t *testing.T) {
- m0 := image.NewRGBA(256, 256)
+ m0 := image.NewRGBA(image.Rect(0, 0, 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.Set(x, y, color.RGBA{uint8(x), uint8(y), 0, 255})
}
}
m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA)
@@ -103,11 +103,10 @@ func TestSubImage(t *testing.T) {
func BenchmarkEncodePaletted(b *testing.B) {
b.StopTimer()
- img := image.NewPaletted(640, 480,
- []image.Color{
- image.RGBAColor{0, 0, 0, 255},
- image.RGBAColor{255, 255, 255, 255},
- })
+ img := image.NewPaletted(image.Rect(0, 0, 640, 480), color.Palette{
+ color.RGBA{0, 0, 0, 255},
+ color.RGBA{255, 255, 255, 255},
+ })
b.SetBytes(640 * 480 * 1)
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -117,16 +116,16 @@ func BenchmarkEncodePaletted(b *testing.B) {
func BenchmarkEncodeRGBOpaque(b *testing.B) {
b.StopTimer()
- img := image.NewRGBA(640, 480)
+ img := image.NewRGBA(image.Rect(0, 0, 640, 480))
// Set all pixels to 0xFF alpha to force opaque mode.
bo := img.Bounds()
for y := bo.Min.Y; y < bo.Max.Y; y++ {
for x := bo.Min.X; x < bo.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{0, 0, 0, 255})
+ img.Set(x, y, color.RGBA{0, 0, 0, 255})
}
}
if !img.Opaque() {
- panic("expected image to be opaque")
+ b.Fatal("expected image to be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
@@ -137,9 +136,9 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
func BenchmarkEncodeRGBA(b *testing.B) {
b.StopTimer()
- img := image.NewRGBA(640, 480)
+ img := image.NewRGBA(image.Rect(0, 0, 640, 480))
if img.Opaque() {
- panic("expected image to not be opaque")
+ b.Fatal("expected image to not be opaque")
}
b.SetBytes(640 * 480 * 4)
b.StartTimer()
diff --git a/src/pkg/image/testdata/video-001.bmp b/src/pkg/image/testdata/video-001.bmp
deleted file mode 100644
index ca3dd42a7..000000000
--- a/src/pkg/image/testdata/video-001.bmp
+++ /dev/null
Binary files differ
diff --git a/src/pkg/image/testdata/video-001.tiff b/src/pkg/image/testdata/video-001.tiff
deleted file mode 100644
index 0dd6cd931..000000000
--- a/src/pkg/image/testdata/video-001.tiff
+++ /dev/null
Binary files differ
diff --git a/src/pkg/image/tiff/Makefile b/src/pkg/image/tiff/Makefile
deleted file mode 100644
index 1a001afb9..000000000
--- a/src/pkg/image/tiff/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=image/tiff
-GOFILES=\
- buffer.go\
- consts.go\
- reader.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/tiff/buffer.go b/src/pkg/image/tiff/buffer.go
deleted file mode 100644
index 7c0714225..000000000
--- a/src/pkg/image/tiff/buffer.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tiff
-
-import (
- "io"
- "os"
-)
-
-// buffer buffers an io.Reader to satisfy io.ReaderAt.
-type buffer struct {
- r io.Reader
- buf []byte
-}
-
-func (b *buffer) ReadAt(p []byte, off int64) (int, os.Error) {
- o := int(off)
- end := o + len(p)
- if int64(end) != off+int64(len(p)) {
- return 0, os.EINVAL
- }
-
- m := len(b.buf)
- if end > m {
- if end > cap(b.buf) {
- newcap := 1024
- for newcap < end {
- newcap *= 2
- }
- newbuf := make([]byte, end, newcap)
- copy(newbuf, b.buf)
- b.buf = newbuf
- } else {
- b.buf = b.buf[:end]
- }
- if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
- end = m + n
- b.buf = b.buf[:end]
- return copy(p, b.buf[o:end]), err
- }
- }
-
- return copy(p, b.buf[o:end]), nil
-}
-
-// newReaderAt converts an io.Reader into an io.ReaderAt.
-func newReaderAt(r io.Reader) io.ReaderAt {
- if ra, ok := r.(io.ReaderAt); ok {
- return ra
- }
- return &buffer{
- r: r,
- buf: make([]byte, 0, 1024),
- }
-}
diff --git a/src/pkg/image/tiff/buffer_test.go b/src/pkg/image/tiff/buffer_test.go
deleted file mode 100644
index 4f3e68e83..000000000
--- a/src/pkg/image/tiff/buffer_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tiff
-
-import (
- "os"
- "strings"
- "testing"
-)
-
-var readAtTests = []struct {
- n int
- off int64
- s string
- err os.Error
-}{
- {2, 0, "ab", nil},
- {6, 0, "abcdef", nil},
- {3, 3, "def", nil},
- {3, 5, "f", os.EOF},
- {3, 6, "", os.EOF},
-}
-
-func TestReadAt(t *testing.T) {
- r := newReaderAt(strings.NewReader("abcdef"))
- b := make([]byte, 10)
- for _, test := range readAtTests {
- n, err := r.ReadAt(b[:test.n], test.off)
- s := string(b[:n])
- if s != test.s || err != test.err {
- t.Errorf("buffer.ReadAt(<%v bytes>, %v): got %v, %q; want %v, %q", test.n, test.off, err, s, test.err, test.s)
- }
- }
-}
diff --git a/src/pkg/image/tiff/consts.go b/src/pkg/image/tiff/consts.go
deleted file mode 100644
index 169ba2772..000000000
--- a/src/pkg/image/tiff/consts.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tiff
-
-// A tiff image file contains one or more images. The metadata
-// of each image is contained in an Image File Directory (IFD),
-// which contains entries of 12 bytes each and is described
-// on page 14-16 of the specification. An IFD entry consists of
-//
-// - a tag, which describes the signification of the entry,
-// - the data type and length of the entry,
-// - the data itself or a pointer to it if it is more than 4 bytes.
-//
-// The presence of a length means that each IFD is effectively an array.
-
-const (
- leHeader = "II\x2A\x00" // Header for little-endian files.
- beHeader = "MM\x00\x2A" // Header for big-endian files.
-
- ifdLen = 12 // Length of an IFD entry in bytes.
-)
-
-// Data types (p. 14-16 of the spec).
-const (
- dtByte = 1
- dtASCII = 2
- dtShort = 3
- dtLong = 4
- dtRational = 5
-)
-
-// The length of one instance of each data type in bytes.
-var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
-
-// Tags (see p. 28-41 of the spec).
-const (
- tImageWidth = 256
- tImageLength = 257
- tBitsPerSample = 258
- tCompression = 259
- tPhotometricInterpretation = 262
-
- tStripOffsets = 273
- tSamplesPerPixel = 277
- tRowsPerStrip = 278
- tStripByteCounts = 279
-
- tXResolution = 282
- tYResolution = 283
- tResolutionUnit = 296
-
- tPredictor = 317
- tColorMap = 320
- tExtraSamples = 338
- tSampleFormat = 339
-)
-
-// Compression types (defined in various places in the spec and supplements).
-const (
- cNone = 1
- cCCITT = 2
- cG3 = 3 // Group 3 Fax.
- cG4 = 4 // Group 4 Fax.
- cLZW = 5
- cJPEGOld = 6 // Superseded by cJPEG.
- cJPEG = 7
- cDeflate = 8 // zlib compression.
- cPackBits = 32773
- cDeflateOld = 32946 // Superseded by cDeflate.
-)
-
-// Photometric interpretation values (see p. 37 of the spec).
-const (
- pWhiteIsZero = 0
- pBlackIsZero = 1
- pRGB = 2
- pPaletted = 3
- pTransMask = 4 // transparency mask
- pCMYK = 5
- pYCbCr = 6
- pCIELab = 8
-)
-
-// Values for the tPredictor tag (page 64-65 of the spec).
-const (
- prNone = 1
- prHorizontal = 2
-)
-
-// imageMode represents the mode of the image.
-type imageMode int
-
-const (
- mBilevel imageMode = iota
- mPaletted
- mGray
- mGrayInvert
- mRGB
- mRGBA
- mNRGBA
-)
diff --git a/src/pkg/image/tiff/reader.go b/src/pkg/image/tiff/reader.go
deleted file mode 100644
index f5652667a..000000000
--- a/src/pkg/image/tiff/reader.go
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package tiff implements a TIFF image decoder.
-//
-// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
-package tiff
-
-import (
- "compress/lzw"
- "compress/zlib"
- "encoding/binary"
- "image"
- "io"
- "io/ioutil"
- "os"
-)
-
-// A FormatError reports that the input is not a valid TIFF image.
-type FormatError string
-
-func (e FormatError) String() string {
- return "tiff: invalid format: " + string(e)
-}
-
-// An UnsupportedError reports that the input uses a valid but
-// unimplemented feature.
-type UnsupportedError string
-
-func (e UnsupportedError) String() string {
- return "tiff: unsupported feature: " + string(e)
-}
-
-// An InternalError reports that an internal error was encountered.
-type InternalError string
-
-func (e InternalError) String() string {
- return "tiff: internal error: " + string(e)
-}
-
-type decoder struct {
- r io.ReaderAt
- byteOrder binary.ByteOrder
- config image.Config
- mode imageMode
- features map[int][]uint
- palette []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,
-// or 0 if the tag does not exist.
-func (d *decoder) firstVal(tag int) uint {
- f := d.features[tag]
- if len(f) == 0 {
- return 0
- }
- return f[0]
-}
-
-// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
-// or Long type, and returns the decoded uint values.
-func (d *decoder) ifdUint(p []byte) (u []uint, err os.Error) {
- var raw []byte
- datatype := d.byteOrder.Uint16(p[2:4])
- count := d.byteOrder.Uint32(p[4:8])
- if datalen := lengths[datatype] * count; datalen > 4 {
- // The IFD contains a pointer to the real value.
- raw = make([]byte, datalen)
- _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12])))
- } else {
- raw = p[8 : 8+datalen]
- }
- if err != nil {
- return nil, err
- }
-
- u = make([]uint, count)
- switch datatype {
- case dtByte:
- for i := uint32(0); i < count; i++ {
- u[i] = uint(raw[i])
- }
- case dtShort:
- for i := uint32(0); i < count; i++ {
- u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
- }
- case dtLong:
- for i := uint32(0); i < count; i++ {
- u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
- }
- default:
- return nil, UnsupportedError("data type")
- }
- return u, nil
-}
-
-// parseIFD decides whether the the IFD entry in p is "interesting" and
-// stows away the data in the decoder.
-func (d *decoder) parseIFD(p []byte) os.Error {
- tag := d.byteOrder.Uint16(p[0:2])
- switch tag {
- case tBitsPerSample,
- tExtraSamples,
- tPhotometricInterpretation,
- tCompression,
- tPredictor,
- tStripOffsets,
- tStripByteCounts,
- tRowsPerStrip,
- tImageLength,
- tImageWidth:
- val, err := d.ifdUint(p)
- if err != nil {
- return err
- }
- d.features[int(tag)] = val
- case tColorMap:
- val, err := d.ifdUint(p)
- if err != nil {
- return err
- }
- numcolors := len(val) / 3
- if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
- return FormatError("bad ColorMap length")
- }
- d.palette = make([]image.Color, numcolors)
- for i := 0; i < numcolors; i++ {
- d.palette[i] = image.RGBA64Color{
- uint16(val[i]),
- uint16(val[i+numcolors]),
- uint16(val[i+2*numcolors]),
- 0xffff,
- }
- }
- case tSampleFormat:
- // Page 27 of the spec: If the SampleFormat is present and
- // the value is not 1 [= unsigned integer data], a Baseline
- // TIFF reader that cannot handle the SampleFormat value
- // must terminate the import process gracefully.
- val, err := d.ifdUint(p)
- if err != nil {
- return err
- }
- for _, v := range val {
- if v != 1 {
- return UnsupportedError("sample format")
- }
- }
- }
- return nil
-}
-
-// readBits reads n bits from the internal buffer starting at the current offset.
-func (d *decoder) readBits(n uint) uint32 {
- for d.nbits < n {
- d.v <<= 8
- d.v |= uint32(d.buf[d.off])
- d.off++
- d.nbits += 8
- }
- d.nbits -= n
- rv := d.v >> d.nbits
- d.v &^= rv << d.nbits
- return rv
-}
-
-// flushBits discards the unread bits in the buffer used by readBits.
-// It is used at the end of a line.
-func (d *decoder) flushBits() {
- d.v = 0
- d.nbits = 0
-}
-
-// decode decodes the raw data of an image.
-// It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
-func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
- spp := len(d.features[tBitsPerSample]) // samples per pixel
- d.off = 0
- width := dst.Bounds().Dx()
-
- // Apply horizontal predictor if necessary.
- // In this case, p contains the color difference to the preceding pixel.
- // See page 64-65 of the spec.
- if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
- for y := ymin; y < ymax; y++ {
- d.off += spp
- for x := 0; x < (width-1)*spp; x++ {
- d.buf[d.off] += d.buf[d.off-spp]
- d.off++
- }
- }
- d.off = 0
- }
-
- switch d.mode {
- case mGray, mGrayInvert:
- img := dst.(*image.Gray)
- bpp := d.firstVal(tBitsPerSample)
- max := uint32((1 << bpp) - 1)
- for y := ymin; y < ymax; y++ {
- for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- v := uint8(d.readBits(bpp) * 0xff / max)
- if d.mode == mGrayInvert {
- v = 0xff - v
- }
- img.SetGray(x, y, 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, 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.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.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.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
- }
- }
- }
-
- return nil
-}
-
-func newDecoder(r io.Reader) (*decoder, os.Error) {
- d := &decoder{
- r: newReaderAt(r),
- features: make(map[int][]uint),
- }
-
- p := make([]byte, 8)
- if _, err := d.r.ReadAt(p, 0); err != nil {
- return nil, err
- }
- switch string(p[0:4]) {
- case leHeader:
- d.byteOrder = binary.LittleEndian
- case beHeader:
- d.byteOrder = binary.BigEndian
- default:
- return nil, FormatError("malformed header")
- }
-
- ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
-
- // The first two bytes contain the number of entries (12 bytes each).
- if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
- return nil, err
- }
- numItems := int(d.byteOrder.Uint16(p[0:2]))
-
- // All IFD entries are read in one chunk.
- p = make([]byte, ifdLen*numItems)
- if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil {
- return nil, err
- }
-
- for i := 0; i < len(p); i += ifdLen {
- if err := d.parseIFD(p[i : i+ifdLen]); err != nil {
- return nil, err
- }
- }
-
- d.config.Width = int(d.firstVal(tImageWidth))
- d.config.Height = int(d.firstVal(tImageLength))
-
- if _, ok := d.features[tBitsPerSample]; !ok {
- return nil, FormatError("BitsPerSample tag missing")
- }
-
- // Determine the image mode.
- switch d.firstVal(tPhotometricInterpretation) {
- case pRGB:
- for _, b := range d.features[tBitsPerSample] {
- if b != 8 {
- return nil, UnsupportedError("non-8-bit RGB image")
- }
- }
- d.config.ColorModel = image.RGBAColorModel
- // RGB images normally have 3 samples per pixel.
- // If there are more, ExtraSamples (p. 31-32 of the spec)
- // gives their meaning (usually an alpha channel).
- switch len(d.features[tBitsPerSample]) {
- case 3:
- d.mode = mRGB
- case 4:
- switch d.firstVal(tExtraSamples) {
- case 1:
- d.mode = mRGBA
- case 2:
- d.mode = mNRGBA
- d.config.ColorModel = image.NRGBAColorModel
- default:
- // The extra sample is discarded.
- d.mode = mRGB
- }
- default:
- return nil, FormatError("wrong number of samples for RGB")
- }
- case pPaletted:
- d.mode = mPaletted
- d.config.ColorModel = image.PalettedColorModel(d.palette)
- case pWhiteIsZero:
- d.mode = mGrayInvert
- d.config.ColorModel = image.GrayColorModel
- case pBlackIsZero:
- d.mode = mGray
- d.config.ColorModel = image.GrayColorModel
- default:
- return nil, UnsupportedError("color model")
- }
-
- return d, nil
-}
-
-// DecodeConfig returns the color model and dimensions of a TIFF image without
-// decoding the entire image.
-func DecodeConfig(r io.Reader) (image.Config, os.Error) {
- d, err := newDecoder(r)
- if err != nil {
- return image.Config{}, err
- }
- return d.config, nil
-}
-
-// Decode reads a TIFF image from r and returns it as an image.Image.
-// The type of Image returned depends on the contents of the TIFF.
-func Decode(r io.Reader) (img image.Image, err os.Error) {
- d, err := newDecoder(r)
- if err != nil {
- return
- }
-
- // Check if we have the right number of strips, offsets and counts.
- rps := int(d.firstVal(tRowsPerStrip))
- if rps == 0 {
- // Assume only one strip.
- rps = d.config.Height
- }
- numStrips := (d.config.Height + rps - 1) / rps
- if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
- return nil, FormatError("inconsistent header")
- }
-
- switch d.mode {
- case mGray, mGrayInvert:
- img = image.NewGray(d.config.Width, d.config.Height)
- case mPaletted:
- img = image.NewPaletted(d.config.Width, d.config.Height, d.palette)
- case mNRGBA:
- img = image.NewNRGBA(d.config.Width, d.config.Height)
- case mRGB, mRGBA:
- img = image.NewRGBA(d.config.Width, d.config.Height)
- }
-
- for i := 0; i < numStrips; i++ {
- ymin := i * rps
- // The last strip may be shorter.
- if i == numStrips-1 && d.config.Height%rps != 0 {
- rps = d.config.Height % rps
- }
- offset := int64(d.features[tStripOffsets][i])
- n := int64(d.features[tStripByteCounts][i])
- switch d.firstVal(tCompression) {
- case cNone:
- // TODO(bsiegert): Avoid copy if r is a tiff.buffer.
- d.buf = make([]byte, n)
- _, err = d.r.ReadAt(d.buf, offset)
- case cLZW:
- r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
- d.buf, err = ioutil.ReadAll(r)
- r.Close()
- case cDeflate, cDeflateOld:
- r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
- if err != nil {
- return nil, err
- }
- d.buf, err = ioutil.ReadAll(r)
- r.Close()
- default:
- err = UnsupportedError("compression")
- }
- if err != nil {
- return
- }
- err = d.decode(img, ymin, ymin+rps)
- }
- return
-}
-
-func init() {
- image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
- image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
-}
diff --git a/src/pkg/image/tiff/reader_test.go b/src/pkg/image/tiff/reader_test.go
deleted file mode 100644
index f2122c440..000000000
--- a/src/pkg/image/tiff/reader_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tiff
-
-import (
- "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/src/pkg/image/tiff/testdata/no_rps.tiff b/src/pkg/image/tiff/testdata/no_rps.tiff
deleted file mode 100644
index 3280cf8e3..000000000
--- a/src/pkg/image/tiff/testdata/no_rps.tiff
+++ /dev/null
Binary files differ
diff --git a/src/pkg/image/ycbcr.go b/src/pkg/image/ycbcr.go
new file mode 100644
index 000000000..c1a0b666f
--- /dev/null
+++ b/src/pkg/image/ycbcr.go
@@ -0,0 +1,144 @@
+// 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
+
+import (
+ "image/color"
+)
+
+// YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
+type YCbCrSubsampleRatio int
+
+const (
+ YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
+ YCbCrSubsampleRatio422
+ YCbCrSubsampleRatio420
+)
+
+func (s YCbCrSubsampleRatio) String() string {
+ switch s {
+ case YCbCrSubsampleRatio444:
+ return "YCbCrSubsampleRatio444"
+ case YCbCrSubsampleRatio422:
+ return "YCbCrSubsampleRatio422"
+ case YCbCrSubsampleRatio420:
+ return "YCbCrSubsampleRatio420"
+ }
+ return "YCbCrSubsampleRatioUnknown"
+}
+
+// YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
+// pixel, but each Cb and Cr sample can span one or more pixels.
+// YStride is the Y slice index delta between vertically adjacent pixels.
+// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
+// that map to separate chroma samples.
+// It is not an absolute requirement, but YStride and len(Y) are typically
+// multiples of 8, and:
+// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
+// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
+// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
+type YCbCr struct {
+ Y, Cb, Cr []uint8
+ YStride int
+ CStride int
+ SubsampleRatio YCbCrSubsampleRatio
+ Rect Rectangle
+}
+
+func (p *YCbCr) ColorModel() color.Model {
+ return color.YCbCrModel
+}
+
+func (p *YCbCr) Bounds() Rectangle {
+ return p.Rect
+}
+
+func (p *YCbCr) At(x, y int) color.Color {
+ if !(Point{x, y}.In(p.Rect)) {
+ return color.YCbCr{}
+ }
+ yi := p.YOffset(x, y)
+ ci := p.COffset(x, y)
+ return color.YCbCr{
+ p.Y[yi],
+ p.Cb[ci],
+ p.Cr[ci],
+ }
+}
+
+// YOffset returns the index of the first element of Y that corresponds to
+// the pixel at (x, y).
+func (p *YCbCr) YOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X)
+}
+
+// COffset returns the index of the first element of Cb or Cr that corresponds
+// to the pixel at (x, y).
+func (p *YCbCr) COffset(x, y int) int {
+ switch p.SubsampleRatio {
+ case YCbCrSubsampleRatio422:
+ return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2)
+ case YCbCrSubsampleRatio420:
+ return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
+ }
+ // Default to 4:4:4 subsampling.
+ return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
+}
+
+// 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 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 &YCbCr{
+ SubsampleRatio: p.SubsampleRatio,
+ }
+ }
+ yi := p.YOffset(r.Min.X, r.Min.Y)
+ ci := p.COffset(r.Min.X, r.Min.Y)
+ return &YCbCr{
+ Y: p.Y[yi:],
+ Cb: p.Cb[ci:],
+ Cr: p.Cr[ci:],
+ SubsampleRatio: p.SubsampleRatio,
+ YStride: p.YStride,
+ CStride: p.CStride,
+ Rect: r,
+ }
+}
+
+func (p *YCbCr) Opaque() bool {
+ return true
+}
+
+// NewYCbCr returns a new YCbCr with the given bounds and subsample ratio.
+func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
+ w, h, cw, ch := r.Dx(), r.Dy(), 0, 0
+ switch subsampleRatio {
+ case YCbCrSubsampleRatio422:
+ cw = (r.Max.X+1)/2 - r.Min.X/2
+ ch = h
+ case YCbCrSubsampleRatio420:
+ cw = (r.Max.X+1)/2 - r.Min.X/2
+ ch = (r.Max.Y+1)/2 - r.Min.Y/2
+ default:
+ // Default to 4:4:4 subsampling.
+ cw = w
+ ch = h
+ }
+ b := make([]byte, w*h+2*cw*ch)
+ return &YCbCr{
+ Y: b[:w*h],
+ Cb: b[w*h+0*cw*ch : w*h+1*cw*ch],
+ Cr: b[w*h+1*cw*ch : w*h+2*cw*ch],
+ SubsampleRatio: subsampleRatio,
+ YStride: w,
+ CStride: cw,
+ Rect: r,
+ }
+}
diff --git a/src/pkg/image/ycbcr/Makefile b/src/pkg/image/ycbcr/Makefile
deleted file mode 100644
index a9c4c1367..000000000
--- a/src/pkg/image/ycbcr/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=image/ycbcr
-GOFILES=\
- ycbcr.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/image/ycbcr/ycbcr.go b/src/pkg/image/ycbcr/ycbcr.go
deleted file mode 100644
index f2de3d6fb..000000000
--- a/src/pkg/image/ycbcr/ycbcr.go
+++ /dev/null
@@ -1,183 +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 ycbcr provides images from the Y'CbCr color model.
-//
-// JPEG, VP8, the MPEG family and other codecs use this color model. Such
-// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
-// speaking, the term YUV applies only to analog video signals.
-//
-// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
-// different formulae for converting between the two. This package follows
-// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
-package ycbcr
-
-import (
- "image"
-)
-
-// RGBToYCbCr converts an RGB triple to a YCbCr triple. All components lie
-// within the range [0, 255].
-func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
- // The JFIF specification says:
- // Y' = 0.2990*R + 0.5870*G + 0.1140*B
- // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
- // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
- // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- r1 := int(r)
- g1 := int(g)
- b1 := int(b)
- yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
- cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
- cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
- if yy < 0 {
- yy = 0
- } else if yy > 255 {
- yy = 255
- }
- if cb < 0 {
- cb = 0
- } else if cb > 255 {
- cb = 255
- }
- if cr < 0 {
- cr = 0
- } else if cr > 255 {
- cr = 255
- }
- return uint8(yy), uint8(cb), uint8(cr)
-}
-
-// YCbCrToRGB converts a YCbCr triple to an RGB triple. All components lie
-// within the range [0, 255].
-func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
- // The JFIF specification says:
- // R = Y' + 1.40200*(Cr-128)
- // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
- // B = Y' + 1.77200*(Cb-128)
- // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
- yy1 := int(y)<<16 + 1<<15
- cb1 := int(cb) - 128
- cr1 := int(cr) - 128
- r := (yy1 + 91881*cr1) >> 16
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
- b := (yy1 + 116130*cb1) >> 16
- if r < 0 {
- r = 0
- } else if r > 255 {
- r = 255
- }
- if g < 0 {
- g = 0
- } else if g > 255 {
- g = 255
- }
- if b < 0 {
- b = 0
- } else if b > 255 {
- b = 255
- }
- return uint8(r), uint8(g), uint8(b)
-}
-
-// YCbCrColor represents a fully opaque 24-bit Y'CbCr color, having 8 bits for
-// each of one luma and two chroma components.
-type YCbCrColor struct {
- Y, Cb, Cr uint8
-}
-
-func (c YCbCrColor) RGBA() (uint32, uint32, uint32, uint32) {
- r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
- return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
-}
-
-func toYCbCrColor(c image.Color) image.Color {
- if _, ok := c.(YCbCrColor); ok {
- return c
- }
- r, g, b, _ := c.RGBA()
- y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
- return YCbCrColor{y, u, v}
-}
-
-// YCbCrColorModel is the color model for YCbCrColor.
-var YCbCrColorModel image.ColorModel = image.ColorModelFunc(toYCbCrColor)
-
-// SubsampleRatio is the chroma subsample ratio used in a YCbCr image.
-type SubsampleRatio int
-
-const (
- SubsampleRatio444 SubsampleRatio = iota
- SubsampleRatio422
- SubsampleRatio420
-)
-
-// YCbCr is an in-memory image of YCbCr colors. There is one Y sample per pixel,
-// but each Cb and Cr sample can span one or more pixels.
-// YStride is the Y slice index delta between vertically adjacent pixels.
-// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
-// that map to separate chroma samples.
-// It is not an absolute requirement, but YStride and len(Y) are typically
-// multiples of 8, and:
-// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
-// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
-// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
-type YCbCr struct {
- Y []uint8
- Cb []uint8
- Cr []uint8
- YStride int
- CStride int
- SubsampleRatio SubsampleRatio
- Rect image.Rectangle
-}
-
-func (p *YCbCr) ColorModel() image.ColorModel {
- return YCbCrColorModel
-}
-
-func (p *YCbCr) Bounds() image.Rectangle {
- return p.Rect
-}
-
-func (p *YCbCr) At(x, y int) image.Color {
- if !(image.Point{x, y}.In(p.Rect)) {
- return YCbCrColor{}
- }
- switch p.SubsampleRatio {
- case SubsampleRatio422:
- i := x / 2
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[y*p.CStride+i],
- p.Cr[y*p.CStride+i],
- }
- case SubsampleRatio420:
- i, j := x/2, y/2
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[j*p.CStride+i],
- p.Cr[j*p.CStride+i],
- }
- }
- // Default to 4:4:4 subsampling.
- return YCbCrColor{
- p.Y[y*p.YStride+x],
- p.Cb[y*p.CStride+x],
- p.Cr[y*p.CStride+x],
- }
-}
-
-// 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/src/pkg/image/ycbcr_test.go b/src/pkg/image/ycbcr_test.go
new file mode 100644
index 000000000..5fa95be3e
--- /dev/null
+++ b/src/pkg/image/ycbcr_test.go
@@ -0,0 +1,106 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "image/color"
+ "testing"
+)
+
+func TestYCbCr(t *testing.T) {
+ rects := []Rectangle{
+ Rect(0, 0, 16, 16),
+ Rect(1, 0, 16, 16),
+ Rect(0, 1, 16, 16),
+ Rect(1, 1, 16, 16),
+ Rect(1, 1, 15, 16),
+ Rect(1, 1, 16, 15),
+ Rect(1, 1, 15, 15),
+ Rect(2, 3, 14, 15),
+ Rect(7, 0, 7, 16),
+ Rect(0, 8, 16, 8),
+ Rect(0, 0, 10, 11),
+ Rect(5, 6, 16, 16),
+ Rect(7, 7, 8, 8),
+ Rect(7, 8, 8, 9),
+ Rect(8, 7, 9, 8),
+ Rect(8, 8, 9, 9),
+ Rect(7, 7, 17, 17),
+ Rect(8, 8, 17, 17),
+ Rect(9, 9, 17, 17),
+ Rect(10, 10, 17, 17),
+ }
+ subsampleRatios := []YCbCrSubsampleRatio{
+ YCbCrSubsampleRatio444,
+ YCbCrSubsampleRatio422,
+ YCbCrSubsampleRatio420,
+ }
+ deltas := []Point{
+ Pt(0, 0),
+ Pt(1000, 1001),
+ Pt(5001, -400),
+ Pt(-701, -801),
+ }
+ for _, r := range rects {
+ for _, subsampleRatio := range subsampleRatios {
+ for _, delta := range deltas {
+ testYCbCr(t, r, subsampleRatio, delta)
+ }
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, delta Point) {
+ // Create a YCbCr image m, whose bounds are r translated by (delta.X, delta.Y).
+ r1 := r.Add(delta)
+ m := NewYCbCr(r1, subsampleRatio)
+
+ // Test that the image buffer is reasonably small even if (delta.X, delta.Y) is far from the origin.
+ if len(m.Y) > 100*100 {
+ t.Errorf("r=%v, subsampleRatio=%v, delta=%v: image buffer is too large",
+ r, subsampleRatio, delta)
+ return
+ }
+
+ // Initialize m's pixels. For 422 and 420 subsampling, some of the Cb and Cr elements
+ // will be set multiple times. That's OK. We just want to avoid a uniform image.
+ for y := r1.Min.Y; y < r1.Max.Y; y++ {
+ for x := r1.Min.X; x < r1.Max.X; x++ {
+ yi := m.YOffset(x, y)
+ ci := m.COffset(x, y)
+ m.Y[yi] = uint8(16*y + x)
+ m.Cb[ci] = uint8(y + 16*x)
+ m.Cr[ci] = uint8(y + 16*x)
+ }
+ }
+
+ // Make various sub-images of m.
+ for y0 := delta.Y + 3; y0 < delta.Y+7; y0++ {
+ for y1 := delta.Y + 8; y1 < delta.Y+13; y1++ {
+ for x0 := delta.X + 3; x0 < delta.X+7; x0++ {
+ for x1 := delta.X + 8; x1 < delta.X+13; x1++ {
+ subRect := Rect(x0, y0, x1, y1)
+ sub := m.SubImage(subRect).(*YCbCr)
+
+ // For each point in the sub-image's bounds, check that m.At(x, y) equals sub.At(x, y).
+ for y := sub.Rect.Min.Y; y < sub.Rect.Max.Y; y++ {
+ for x := sub.Rect.Min.X; x < sub.Rect.Max.X; x++ {
+ color0 := m.At(x, y).(color.YCbCr)
+ color1 := sub.At(x, y).(color.YCbCr)
+ if color0 != color1 {
+ t.Errorf("r=%v, subsampleRatio=%v, delta=%v, x=%d, y=%d, color0=%v, color1=%v",
+ r, subsampleRatio, delta, x, y, color0, color1)
+ return
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/pkg/index/suffixarray/Makefile b/src/pkg/index/suffixarray/Makefile
deleted file mode 100644
index 297c4279f..000000000
--- a/src/pkg/index/suffixarray/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=index/suffixarray
-GOFILES=\
- qsufsort.go\
- suffixarray.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/index/suffixarray/qsufsort.go b/src/pkg/index/suffixarray/qsufsort.go
index 30c110442..9c36a98f8 100644
--- a/src/pkg/index/suffixarray/qsufsort.go
+++ b/src/pkg/index/suffixarray/qsufsort.go
@@ -11,7 +11,7 @@
// Consecutive groups of suffixes in sa are labeled as sorted groups or
// unsorted groups. For a given pass of the sorter, all suffixes are ordered
// up to their first h characters, and sa is h-ordered. Suffixes in their
-// final positions and unambiguouly sorted in h-order are in a sorted group.
+// final positions and unambiguously sorted in h-order are in a sorted group.
// Consecutive groups of suffixes with identical first h characters are an
// unsorted group. In each pass of the algorithm, unsorted groups are sorted
// according to the group number of their following suffix.
@@ -37,7 +37,7 @@ func qsufsort(data []byte) []int {
inv := initGroups(sa, data)
// the index starts 1-ordered
- sufSortable := &suffixSortable{sa, inv, 1}
+ sufSortable := &suffixSortable{sa: sa, inv: inv, h: 1}
for sa[0] > -len(sa) { // until all suffixes are one big sorted group
// The suffixes are h-ordered, make them 2*h-ordered
@@ -78,7 +78,7 @@ func sortedByFirstByte(data []byte) []int {
for _, b := range data {
count[b]++
}
- // make count[b] equal index of first occurence of b in sorted array
+ // make count[b] equal index of first occurrence of b in sorted array
sum := 0
for b := range count {
count[b], sum = sum, count[b]+sum
@@ -135,6 +135,7 @@ type suffixSortable struct {
sa []int
inv []int
h int
+ buf []int // common scratch space
}
func (x *suffixSortable) Len() int { return len(x.sa) }
@@ -142,7 +143,7 @@ func (x *suffixSortable) Less(i, j int) bool { return x.inv[x.sa[i]+x.h] < x.inv
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)
+ bounds := x.buf[0:0]
group := x.inv[x.sa[0]+x.h]
for i := 1; i < len(x.sa); i++ {
if g := x.inv[x.sa[i]+x.h]; g > group {
@@ -151,6 +152,7 @@ func (x *suffixSortable) updateGroups(offset int) {
}
}
bounds = append(bounds, len(x.sa))
+ x.buf = bounds
// update the group numberings after all new groups are determined
prev := 0
diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go
index 82e98d2ef..c59ae6eef 100644
--- a/src/pkg/index/suffixarray/suffixarray.go
+++ b/src/pkg/index/suffixarray/suffixarray.go
@@ -18,6 +18,8 @@ package suffixarray
import (
"bytes"
+ "encoding/binary"
+ "io"
"regexp"
"sort"
)
@@ -25,7 +27,7 @@ import (
// Index implements a suffix array for fast substring search.
type Index struct {
data []byte
- sa []int // suffix array for data
+ sa []int // suffix array for data; len(sa) == len(data)
}
// New creates a new Index for data.
@@ -34,6 +36,129 @@ func New(data []byte) *Index {
return &Index{data, qsufsort(data)}
}
+// writeInt writes an int x to w using buf to buffer the write.
+func writeInt(w io.Writer, buf []byte, x int) error {
+ binary.PutVarint(buf, int64(x))
+ _, err := w.Write(buf[0:binary.MaxVarintLen64])
+ return err
+}
+
+// readInt reads an int x from r using buf to buffer the read and returns x.
+func readInt(r io.Reader, buf []byte) (int, error) {
+ _, err := io.ReadFull(r, buf[0:binary.MaxVarintLen64]) // ok to continue with error
+ x, _ := binary.Varint(buf)
+ return int(x), err
+}
+
+// writeSlice writes data[:n] to w and returns n.
+// It uses buf to buffer the write.
+func writeSlice(w io.Writer, buf []byte, data []int) (n int, err error) {
+ // encode as many elements as fit into buf
+ p := binary.MaxVarintLen64
+ for ; n < len(data) && p+binary.MaxVarintLen64 <= len(buf); n++ {
+ p += binary.PutUvarint(buf[p:], uint64(data[n]))
+ }
+
+ // update buffer size
+ binary.PutVarint(buf, int64(p))
+
+ // write buffer
+ _, err = w.Write(buf[0:p])
+ return
+}
+
+// readSlice reads data[:n] from r and returns n.
+// It uses buf to buffer the read.
+func readSlice(r io.Reader, buf []byte, data []int) (n int, err error) {
+ // read buffer size
+ var size int
+ size, err = readInt(r, buf)
+ if err != nil {
+ return
+ }
+
+ // read buffer w/o the size
+ if _, err = io.ReadFull(r, buf[binary.MaxVarintLen64:size]); err != nil {
+ return
+ }
+
+ // decode as many elements as present in buf
+ for p := binary.MaxVarintLen64; p < size; n++ {
+ x, w := binary.Uvarint(buf[p:])
+ data[n] = int(x)
+ p += w
+ }
+
+ return
+}
+
+const bufSize = 16 << 10 // reasonable for BenchmarkSaveRestore
+
+// Read reads the index from r into x; x must not be nil.
+func (x *Index) Read(r io.Reader) error {
+ // buffer for all reads
+ buf := make([]byte, bufSize)
+
+ // read length
+ n, err := readInt(r, buf)
+ if err != nil {
+ return err
+ }
+
+ // allocate space
+ if 2*n < cap(x.data) || cap(x.data) < n {
+ // new data is significantly smaller or larger then
+ // existing buffers - allocate new ones
+ x.data = make([]byte, n)
+ x.sa = make([]int, n)
+ } else {
+ // re-use existing buffers
+ x.data = x.data[0:n]
+ x.sa = x.sa[0:n]
+ }
+
+ // read data
+ if _, err := io.ReadFull(r, x.data); err != nil {
+ return err
+ }
+
+ // read index
+ for sa := x.sa; len(sa) > 0; {
+ n, err := readSlice(r, buf, sa)
+ if err != nil {
+ return err
+ }
+ sa = sa[n:]
+ }
+ return nil
+}
+
+// Write writes the index x to w.
+func (x *Index) Write(w io.Writer) error {
+ // buffer for all writes
+ buf := make([]byte, bufSize)
+
+ // write length
+ if err := writeInt(w, buf, len(x.data)); err != nil {
+ return err
+ }
+
+ // write data
+ if _, err := w.Write(x.data); err != nil {
+ return err
+ }
+
+ // write index
+ for sa := x.sa; len(sa) > 0; {
+ n, err := writeSlice(w, buf, sa)
+ if err != nil {
+ return err
+ }
+ sa = sa[n:]
+ }
+ return nil
+}
+
// Bytes returns the data over which the index was created.
// It must not be modified.
//
@@ -65,9 +190,10 @@ func (x *Index) lookupAll(s []byte) []int {
func (x *Index) Lookup(s []byte, n int) (result []int) {
if len(s) > 0 && n != 0 {
matches := x.lookupAll(s)
- if len(matches) < n || n < 0 {
+ if n < 0 || len(matches) < n {
n = len(matches)
}
+ // 0 <= n <= len(matches)
if n > 0 {
result = make([]int, n)
copy(result, matches)
diff --git a/src/pkg/index/suffixarray/suffixarray_test.go b/src/pkg/index/suffixarray/suffixarray_test.go
index 023748500..df3e449d3 100644
--- a/src/pkg/index/suffixarray/suffixarray_test.go
+++ b/src/pkg/index/suffixarray/suffixarray_test.go
@@ -6,6 +6,7 @@ package suffixarray
import (
"bytes"
+ "math/rand"
"regexp"
"sort"
"strings"
@@ -213,14 +214,44 @@ 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)
+ t.Errorf("failed testConstruction %s", tc.name)
}
}
+func equal(x, y *Index) bool {
+ if !bytes.Equal(x.data, y.data) {
+ return false
+ }
+ for i, j := range x.sa {
+ if j != y.sa[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// returns the serialized index size
+func testSaveRestore(t *testing.T, tc *testCase, x *Index) int {
+ var buf bytes.Buffer
+ if err := x.Write(&buf); err != nil {
+ t.Errorf("failed writing index %s (%s)", tc.name, err)
+ }
+ size := buf.Len()
+ var y Index
+ if err := y.Read(&buf); err != nil {
+ t.Errorf("failed reading index %s (%s)", tc.name, err)
+ }
+ if !equal(x, &y) {
+ t.Errorf("restored index doesn't match saved index %s", tc.name)
+ }
+ return size
+}
+
func TestIndex(t *testing.T) {
for _, tc := range testCases {
x := New([]byte(tc.source))
testConstruction(t, &tc, x)
+ testSaveRestore(t, &tc, x)
testLookups(t, &tc, x, 0)
testLookups(t, &tc, x, 1)
testLookups(t, &tc, x, 10)
@@ -228,3 +259,46 @@ func TestIndex(t *testing.T) {
testLookups(t, &tc, x, -1)
}
}
+
+// Of all possible inputs, the random bytes have the least amount of substring
+// repetition, and the repeated bytes have the most. For most algorithms,
+// the running time of every input will be between these two.
+func benchmarkNew(b *testing.B, random bool) {
+ b.StopTimer()
+ data := make([]byte, 1e6)
+ if random {
+ for i := range data {
+ data[i] = byte(rand.Intn(256))
+ }
+ }
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ New(data)
+ }
+}
+
+func BenchmarkNewIndexRandom(b *testing.B) {
+ benchmarkNew(b, true)
+}
+func BenchmarkNewIndexRepeat(b *testing.B) {
+ benchmarkNew(b, false)
+}
+
+func BenchmarkSaveRestore(b *testing.B) {
+ b.StopTimer()
+ r := rand.New(rand.NewSource(0x5a77a1)) // guarantee always same sequence
+ data := make([]byte, 10<<20) // 10MB of data to index
+ for i := range data {
+ data[i] = byte(r.Intn(256))
+ }
+ x := New(data)
+ size := testSaveRestore(nil, nil, x) // verify correctness
+ buf := bytes.NewBuffer(make([]byte, size)) // avoid growing
+ b.SetBytes(int64(size))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ x.Write(buf)
+ var y Index
+ y.Read(buf)
+ }
+}
diff --git a/src/pkg/io/Makefile b/src/pkg/io/Makefile
deleted file mode 100644
index 9786002f0..000000000
--- a/src/pkg/io/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=io
-GOFILES=\
- io.go\
- multi.go\
- pipe.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index b879fe5b7..54bf159eb 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -6,27 +6,33 @@
// Its primary job is to wrap existing implementations of such primitives,
// such as those in package os, into shared public interfaces that
// abstract the functionality, plus some other related primitives.
+//
+// Because these interfaces and primitives wrap lower-level operations with
+// various implementations, unless otherwise informed clients should not
+// assume they are safe for parallel execution.
package io
-import "os"
-
-// Error represents an unexpected I/O behavior.
-type Error struct {
- ErrorString string
-}
-
-func (err *Error) String() string { return err.ErrorString }
+import (
+ "errors"
+)
// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
-var ErrShortWrite os.Error = &Error{"short write"}
+var ErrShortWrite = errors.New("short write")
// ErrShortBuffer means that a read required a longer buffer than was provided.
-var ErrShortBuffer os.Error = &Error{"short buffer"}
+var ErrShortBuffer = errors.New("short buffer")
+
+// EOF is the error returned by Read when no more input is available.
+// Functions should return EOF only to signal a graceful end of input.
+// If the EOF occurs unexpectedly in a structured data stream,
+// the appropriate error is either ErrUnexpectedEOF or some other error
+// giving more detail.
+var EOF = errors.New("EOF")
-// ErrUnexpectedEOF means that os.EOF was encountered in the
+// ErrUnexpectedEOF means that EOF was encountered in the
// middle of reading a fixed-size block or data structure.
-var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
+var ErrUnexpectedEOF = errors.New("unexpected EOF")
// Reader is the interface that wraps the basic Read method.
//
@@ -42,15 +48,15 @@ var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
// 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.
+// return either err == EOF or err == nil. The next Read should
+// return 0, 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)
+ Read(p []byte) (n int, err error)
}
// Writer is the interface that wraps the basic Write method.
@@ -60,12 +66,12 @@ type Reader interface {
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
type Writer interface {
- Write(p []byte) (n int, err os.Error)
+ Write(p []byte) (n int, err error)
}
// Closer is the interface that wraps the basic Close method.
type Closer interface {
- Close() os.Error
+ Close() error
}
// Seeker is the interface that wraps the basic Seek method.
@@ -76,7 +82,7 @@ type Closer interface {
// relative to the end. Seek returns the new offset and an Error, if
// any.
type Seeker interface {
- Seek(offset int64, whence int) (ret int64, err os.Error)
+ Seek(offset int64, whence int) (ret int64, err error)
}
// ReadWriter is the interface that groups the basic Read and Write methods.
@@ -125,12 +131,12 @@ type ReadWriteSeeker interface {
// ReaderFrom is the interface that wraps the ReadFrom method.
type ReaderFrom interface {
- ReadFrom(r Reader) (n int64, err os.Error)
+ ReadFrom(r Reader) (n int64, err error)
}
// WriterTo is the interface that wraps the WriteTo method.
type WriterTo interface {
- WriteTo(w Writer) (n int64, err os.Error)
+ WriteTo(w Writer) (n int64, err error)
}
// ReaderAt is the interface that wraps the basic ReadAt method.
@@ -149,13 +155,16 @@ type WriterTo interface {
// In this respect ReadAt is different from Read.
//
// 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.
+// input source, ReadAt may return either err == EOF or err == nil.
//
// If ReadAt is reading from an input source with a seek offset,
// ReadAt should not affect nor be affected by the underlying
// seek offset.
+//
+// Clients of ReadAt can execute parallel ReadAt calls on the
+// same input source.
type ReaderAt interface {
- ReadAt(p []byte, off int64) (n int, err os.Error)
+ ReadAt(p []byte, off int64) (n int, err error)
}
// WriterAt is the interface that wraps the basic WriteAt method.
@@ -164,8 +173,15 @@ type ReaderAt interface {
// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
+//
+// If WriteAt is writing to a destination with a seek offset,
+// WriteAt should not affect nor be affected by the underlying
+// seek offset.
+//
+// Clients of WriteAt can execute parallel WriteAt calls on the same
+// destination if the ranges do not overlap.
type WriterAt interface {
- WriteAt(p []byte, off int64) (n int, err os.Error)
+ WriteAt(p []byte, off int64) (n int, err error)
}
// ByteReader is the interface that wraps the ReadByte method.
@@ -173,7 +189,7 @@ type WriterAt interface {
// ReadByte reads and returns the next byte from the input.
// If no byte is available, err will be set.
type ByteReader interface {
- ReadByte() (c byte, err os.Error)
+ ReadByte() (c byte, err error)
}
// ByteScanner is the interface that adds the UnreadByte method to the
@@ -185,7 +201,7 @@ type ByteReader interface {
// call to ReadByte.
type ByteScanner interface {
ByteReader
- UnreadByte() os.Error
+ UnreadByte() error
}
// RuneReader is the interface that wraps the ReadRune method.
@@ -194,7 +210,7 @@ type ByteScanner interface {
// and returns the rune and its size in bytes. If no character is
// available, err will be set.
type RuneReader interface {
- ReadRune() (rune int, size int, err os.Error)
+ ReadRune() (r rune, size int, err error)
}
// RuneScanner is the interface that adds the UnreadRune method to the
@@ -206,16 +222,17 @@ type RuneReader interface {
// call to ReadRune.
type RuneScanner interface {
RuneReader
- UnreadRune() os.Error
+ UnreadRune() error
}
// stringWriter is the interface that wraps the WriteString method.
type stringWriter interface {
- WriteString(s string) (n int, err os.Error)
+ WriteString(s string) (n int, err 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 w already implements a WriteString method, it is invoked directly.
+func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(stringWriter); ok {
return sw.WriteString(s)
}
@@ -224,11 +241,11 @@ func WriteString(w Writer, s string) (n int, err os.Error) {
// ReadAtLeast reads from r into buf until it has read at least min bytes.
// It returns the number of bytes copied and an error if fewer bytes were read.
-// The error is os.EOF only if no bytes were read.
+// The error is EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
-func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
+func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error) {
if len(buf) < min {
return 0, ErrShortBuffer
}
@@ -237,7 +254,7 @@ func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
nn, err = r.Read(buf[n:])
n += nn
}
- if err == os.EOF {
+ if err == EOF {
if n >= min {
err = nil
} else if n > 0 {
@@ -249,29 +266,29 @@ func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
// ReadFull reads exactly len(buf) bytes from r into buf.
// It returns the number of bytes copied and an error if fewer bytes were read.
-// The error is os.EOF only if no bytes were read.
+// The error is EOF only if no bytes were read.
// If an EOF happens after reading some but not all the bytes,
// ReadFull returns ErrUnexpectedEOF.
-func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
+func ReadFull(r Reader, buf []byte) (n int, err error) {
return ReadAtLeast(r, buf, len(buf))
}
-// Copyn copies n bytes (or until an error) from src to dst.
+// CopyN copies n bytes (or until an error) from src to dst.
// 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.
+// (including EOF), so can CopyN.
//
// If dst implements the ReaderFrom interface,
-// the copy is implemented by calling dst.ReadFrom(src).
-func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
+// the copy is implemented using it.
+func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
// If the writer has a ReadFrom method, use it to do the copy.
// Avoids a buffer allocation and a copy.
if rt, ok := dst.(ReaderFrom); ok {
written, err = rt.ReadFrom(LimitReader(src, n))
if written < n && err == nil {
// rt stopped early; must have been EOF.
- err = os.EOF
+ err = EOF
}
return
}
@@ -308,7 +325,7 @@ func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
// on src or an error occurs. It returns the number of bytes
// copied and the first error encountered while copying, if any.
//
-// A successful Copy returns err == nil, not err == os.EOF.
+// A successful Copy returns err == nil, not err == 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.
//
@@ -316,7 +333,7 @@ func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
// the copy is implemented by calling dst.ReadFrom(src).
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
-func Copy(dst Writer, src Reader) (written int64, err os.Error) {
+func Copy(dst Writer, src Reader) (written int64, err error) {
// If the writer has a ReadFrom method, use it to do the copy.
// Avoids an allocation and a copy.
if rt, ok := dst.(ReaderFrom); ok {
@@ -343,7 +360,7 @@ func Copy(dst Writer, src Reader) (written int64, err os.Error) {
break
}
}
- if er == os.EOF {
+ if er == EOF {
break
}
if er != nil {
@@ -355,7 +372,7 @@ 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.
+// but stops with EOF after n bytes.
// The underlying implementation is a *LimitedReader.
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
@@ -367,9 +384,9 @@ type LimitedReader struct {
N int64 // max bytes remaining
}
-func (l *LimitedReader) Read(p []byte) (n int, err os.Error) {
+func (l *LimitedReader) Read(p []byte) (n int, err error) {
if l.N <= 0 {
- return 0, os.EOF
+ return 0, EOF
}
if int64(len(p)) > l.N {
p = p[0:l.N]
@@ -380,7 +397,7 @@ func (l *LimitedReader) Read(p []byte) (n int, err os.Error) {
}
// NewSectionReader returns a SectionReader that reads from r
-// starting at offset off and stops with os.EOF after n bytes.
+// starting at offset off and stops with EOF after n bytes.
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader {
return &SectionReader{r, off, off, off + n}
}
@@ -394,9 +411,9 @@ type SectionReader struct {
limit int64
}
-func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
+func (s *SectionReader) Read(p []byte) (n int, err error) {
if s.off >= s.limit {
- return 0, os.EOF
+ return 0, EOF
}
if max := s.limit - s.off; int64(len(p)) > max {
p = p[0:max]
@@ -406,10 +423,13 @@ func (s *SectionReader) Read(p []byte) (n int, err os.Error) {
return
}
-func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error) {
+var errWhence = errors.New("Seek: invalid whence")
+var errOffset = errors.New("Seek: invalid offset")
+
+func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err error) {
switch whence {
default:
- return 0, os.EINVAL
+ return 0, errWhence
case 0:
offset += s.base
case 1:
@@ -418,15 +438,15 @@ func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error)
offset += s.limit
}
if offset < s.base || offset > s.limit {
- return 0, os.EINVAL
+ return 0, errOffset
}
s.off = offset
return offset - s.base, nil
}
-func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
+func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error) {
if off < 0 || off >= s.limit-s.base {
- return 0, os.EOF
+ return 0, EOF
}
off += s.base
if max := s.limit - off; int64(len(p)) > max {
@@ -437,3 +457,27 @@ func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err os.Error) {
// Size returns the size of the section in bytes.
func (s *SectionReader) Size() int64 { return s.limit - s.base }
+
+// TeeReader returns a Reader that writes to w what it reads from r.
+// All reads from r performed through it are matched with
+// corresponding writes to w. There is no internal buffering -
+// the write must complete before the read completes.
+// Any error encountered while writing is reported as a read error.
+func TeeReader(r Reader, w Writer) Reader {
+ return &teeReader{r, w}
+}
+
+type teeReader struct {
+ r Reader
+ w Writer
+}
+
+func (t *teeReader) Read(p []byte) (n int, err error) {
+ n, err = t.r.Read(p)
+ if n > 0 {
+ if n, err := t.w.Write(p[:n]); err != nil {
+ return n, err
+ }
+ }
+ return
+}
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
index bc4f354af..1e671b59b 100644
--- a/src/pkg/io/io_test.go
+++ b/src/pkg/io/io_test.go
@@ -7,7 +7,6 @@ package io_test
import (
"bytes"
. "io"
- "os"
"strings"
"testing"
)
@@ -19,7 +18,7 @@ type Buffer struct {
WriterTo // conflicts with and hides bytes.Buffer's WriterTo.
}
-// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and Copyn.
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN.
func TestCopy(t *testing.T) {
rb := new(Buffer)
@@ -51,33 +50,33 @@ func TestCopyWriteTo(t *testing.T) {
}
}
-func TestCopyn(t *testing.T) {
+func TestCopyN(t *testing.T) {
rb := new(Buffer)
wb := new(Buffer)
rb.WriteString("hello, world.")
- Copyn(wb, rb, 5)
+ CopyN(wb, rb, 5)
if wb.String() != "hello" {
- t.Errorf("Copyn did not work properly")
+ t.Errorf("CopyN did not work properly")
}
}
-func TestCopynReadFrom(t *testing.T) {
+func TestCopyNReadFrom(t *testing.T) {
rb := new(Buffer)
wb := new(bytes.Buffer) // implements ReadFrom.
rb.WriteString("hello")
- Copyn(wb, rb, 5)
+ CopyN(wb, rb, 5)
if wb.String() != "hello" {
- t.Errorf("Copyn did not work properly")
+ t.Errorf("CopyN did not work properly")
}
}
-func TestCopynWriteTo(t *testing.T) {
+func TestCopyNWriteTo(t *testing.T) {
rb := new(bytes.Buffer) // implements WriteTo.
wb := new(Buffer)
rb.WriteString("hello, world.")
- Copyn(wb, rb, 5)
+ CopyN(wb, rb, 5)
if wb.String() != "hello" {
- t.Errorf("Copyn did not work properly")
+ t.Errorf("CopyN did not work properly")
}
}
@@ -85,34 +84,34 @@ type noReadFrom struct {
w Writer
}
-func (w *noReadFrom) Write(p []byte) (n int, err os.Error) {
+func (w *noReadFrom) Write(p []byte) (n int, err error) {
return w.w.Write(p)
}
-func TestCopynEOF(t *testing.T) {
+func TestCopyNEOF(t *testing.T) {
// Test that EOF behavior is the same regardless of whether
- // argument to Copyn has ReadFrom.
+ // argument to CopyN has ReadFrom.
b := new(bytes.Buffer)
- n, err := Copyn(&noReadFrom{b}, strings.NewReader("foo"), 3)
+ n, err := CopyN(&noReadFrom{b}, strings.NewReader("foo"), 3)
if n != 3 || err != nil {
- t.Errorf("Copyn(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err)
+ t.Errorf("CopyN(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err)
}
- n, err = Copyn(&noReadFrom{b}, strings.NewReader("foo"), 4)
- if n != 3 || err != os.EOF {
- t.Errorf("Copyn(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err)
+ n, err = CopyN(&noReadFrom{b}, strings.NewReader("foo"), 4)
+ if n != 3 || err != EOF {
+ t.Errorf("CopyN(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err)
}
- n, err = Copyn(b, strings.NewReader("foo"), 3) // b has read from
+ n, err = CopyN(b, strings.NewReader("foo"), 3) // b has read from
if n != 3 || err != nil {
- t.Errorf("Copyn(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err)
+ t.Errorf("CopyN(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err)
}
- n, err = Copyn(b, strings.NewReader("foo"), 4) // b has read from
- if n != 3 || err != os.EOF {
- t.Errorf("Copyn(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err)
+ n, err = CopyN(b, strings.NewReader("foo"), 4) // b has read from
+ if n != 3 || err != EOF {
+ t.Errorf("CopyN(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err)
}
}
@@ -121,16 +120,16 @@ func TestReadAtLeast(t *testing.T) {
testReadAtLeast(t, &rb)
}
-// A version of bytes.Buffer that returns n > 0, os.EOF on Read
+// A version of bytes.Buffer that returns n > 0, EOF on Read
// when the input is exhausted.
type dataAndEOFBuffer struct {
bytes.Buffer
}
-func (r *dataAndEOFBuffer) Read(p []byte) (n int, err os.Error) {
+func (r *dataAndEOFBuffer) Read(p []byte) (n int, err error) {
n, err = r.Buffer.Read(p)
if n > 0 && r.Buffer.Len() == 0 && err == nil {
- err = os.EOF
+ err = EOF
}
return
}
@@ -162,7 +161,7 @@ func testReadAtLeast(t *testing.T, rb ReadWriter) {
t.Errorf("expected to have read 2 bytes, got %v", n)
}
n, err = ReadAtLeast(rb, buf, 2)
- if err != os.EOF {
+ if err != EOF {
t.Errorf("expected EOF, got %v", err)
}
if n != 0 {
@@ -177,3 +176,30 @@ func testReadAtLeast(t *testing.T, rb ReadWriter) {
t.Errorf("expected to have read 1 bytes, got %v", n)
}
}
+
+func TestTeeReader(t *testing.T) {
+ src := []byte("hello, world")
+ dst := make([]byte, len(src))
+ rb := bytes.NewBuffer(src)
+ wb := new(bytes.Buffer)
+ r := TeeReader(rb, wb)
+ if n, err := ReadFull(r, dst); err != nil || n != len(src) {
+ t.Fatalf("ReadFull(r, dst) = %d, %v; want %d, nil", n, err, len(src))
+ }
+ if !bytes.Equal(dst, src) {
+ t.Errorf("bytes read = %q want %q", dst, src)
+ }
+ if !bytes.Equal(wb.Bytes(), src) {
+ t.Errorf("bytes written = %q want %q", wb.Bytes(), src)
+ }
+ if n, err := r.Read(dst); n != 0 || err != EOF {
+ t.Errorf("r.Read at EOF = %d, %v want 0, EOF", n, err)
+ }
+ rb = bytes.NewBuffer(src)
+ pr, pw := Pipe()
+ pr.Close()
+ r = TeeReader(rb, pw)
+ if n, err := ReadFull(r, dst); n != 0 || err != ErrClosedPipe {
+ t.Errorf("closed tee: ReadFull(r, dst) = %d, %v; want 0, EPIPE", n, err)
+ }
+}
diff --git a/src/pkg/io/ioutil/Makefile b/src/pkg/io/ioutil/Makefile
deleted file mode 100644
index d406d4b7d..000000000
--- a/src/pkg/io/ioutil/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../../Make.inc
-
-TARG=io/ioutil
-GOFILES=\
- ioutil.go\
- tempfile.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index fffa1320f..f072b8c75 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -14,19 +14,38 @@ import (
// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
-func readAll(r io.Reader, capacity int64) ([]byte, os.Error) {
+func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
- _, err := buf.ReadFrom(r)
+ // If the buffer overflows, we will get bytes.ErrTooLarge.
+ // Return that as an error. Any other panic remains.
+ defer func() {
+ e := recover()
+ if e == nil {
+ return
+ }
+ if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
+ err = panicErr
+ } else {
+ panic(e)
+ }
+ }()
+ _, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
// ReadAll reads from r until an error or EOF and returns the data it read.
-func ReadAll(r io.Reader) ([]byte, os.Error) {
+// A successful call returns err == nil, not err == EOF. Because ReadAll is
+// defined to read from src until EOF, it does not treat an EOF from Read
+// as an error to be reported.
+func ReadAll(r io.Reader) ([]byte, error) {
return readAll(r, bytes.MinRead)
}
// ReadFile reads the file named by filename and returns the contents.
-func ReadFile(filename string) ([]byte, os.Error) {
+// A successful call returns err == nil, not err == EOF. Because ReadFile
+// reads the whole file, it does not treat an EOF from Read as an error
+// to be reported.
+func ReadFile(filename string) ([]byte, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
@@ -34,10 +53,13 @@ func ReadFile(filename string) ([]byte, os.Error) {
defer f.Close()
// It's a good but not certain bet that FileInfo will tell us exactly how much to
// read, so let's try it but be prepared for the answer to be wrong.
- fi, err := f.Stat()
var n int64
- if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
- n = fi.Size
+
+ if fi, err := f.Stat(); err == nil {
+ // Don't preallocate a huge buffer, just in case.
+ if size := fi.Size(); size < 1e9 {
+ n = size
+ }
}
// As initial capacity for readAll, use n + a little extra in case Size is zero,
// and to avoid another allocation after Read has filled the buffer. The readAll
@@ -50,7 +72,7 @@ func ReadFile(filename string) ([]byte, os.Error) {
// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm;
// otherwise WriteFile truncates it before writing.
-func WriteFile(filename string, data []byte, perm uint32) os.Error {
+func WriteFile(filename string, data []byte, perm os.FileMode) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
@@ -63,16 +85,16 @@ func WriteFile(filename string, data []byte, perm uint32) os.Error {
return err
}
-// A fileInfoList implements sort.Interface.
-type fileInfoList []*os.FileInfo
+// byName implements sort.Interface.
+type byName []os.FileInfo
-func (f fileInfoList) Len() int { return len(f) }
-func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
-func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+func (f byName) Len() int { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
// ReadDir reads the directory named by dirname and returns
// a list of sorted directory entries.
-func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
+func ReadDir(dirname string) ([]os.FileInfo, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
@@ -82,19 +104,15 @@ func ReadDir(dirname string) ([]*os.FileInfo, os.Error) {
if err != nil {
return nil, err
}
- fi := make(fileInfoList, len(list))
- for i := range list {
- fi[i] = &list[i]
- }
- sort.Sort(fi)
- return fi, nil
+ sort.Sort(byName(list))
+ return list, nil
}
type nopCloser struct {
io.Reader
}
-func (nopCloser) Close() os.Error { return nil }
+func (nopCloser) Close() error { return nil }
// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
@@ -104,19 +122,23 @@ func NopCloser(r io.Reader) io.ReadCloser {
type devNull int
-func (devNull) Write(p []byte) (int, os.Error) {
+// devNull implements ReaderFrom as an optimization so io.Copy to
+// ioutil.Discard can avoid doing unnecessary work.
+var _ io.ReaderFrom = devNull(0)
+
+func (devNull) Write(p []byte) (int, error) {
return len(p), nil
}
var blackHole = make([]byte, 8192)
-func (devNull) ReadFrom(r io.Reader) (n int64, err os.Error) {
+func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
readSize := 0
for {
readSize, err = r.Read(blackHole)
n += int64(readSize)
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
return n, nil
}
return
diff --git a/src/pkg/io/ioutil/ioutil_test.go b/src/pkg/io/ioutil/ioutil_test.go
index 55e4b2c2b..d9c43bead 100644
--- a/src/pkg/io/ioutil/ioutil_test.go
+++ b/src/pkg/io/ioutil/ioutil_test.go
@@ -15,8 +15,8 @@ func checkSize(t *testing.T, path string, size int64) {
if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
}
- if dir.Size != size {
- t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+ if dir.Size() != size {
+ t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size)
}
}
@@ -37,7 +37,11 @@ func TestReadFile(t *testing.T) {
}
func TestWriteFile(t *testing.T) {
- filename := "_test/rumpelstilzchen"
+ f, err := TempFile("", "ioutil-test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ filename := f.Name()
data := "Programming today is a race between software engineers striving to " +
"build bigger and better idiot-proof programs, and the Universe trying " +
"to produce bigger and better idiots. So far, the Universe is winning."
@@ -56,6 +60,7 @@ func TestWriteFile(t *testing.T) {
}
// cleanup
+ f.Close()
os.Remove(filename) // ignore error
}
@@ -66,26 +71,26 @@ func TestReadDir(t *testing.T) {
t.Fatalf("ReadDir %s: error expected, none found", dirname)
}
- dirname = "."
+ dirname = ".."
list, err := ReadDir(dirname)
if err != nil {
t.Fatalf("ReadDir %s: %v", dirname, err)
}
- foundTest := false
- foundTestDir := false
+ foundFile := false
+ foundSubDir := false
for _, dir := range list {
switch {
- case dir.IsRegular() && dir.Name == "ioutil_test.go":
- foundTest = true
- case dir.IsDirectory() && dir.Name == "_test":
- foundTestDir = true
+ case !dir.IsDir() && dir.Name() == "io_test.go":
+ foundFile = true
+ case dir.IsDir() && dir.Name() == "ioutil":
+ foundSubDir = true
}
}
- if !foundTest {
- t.Fatalf("ReadDir %s: test file not found", dirname)
+ if !foundFile {
+ t.Fatalf("ReadDir %s: io_test.go file not found", dirname)
}
- if !foundTestDir {
- t.Fatalf("ReadDir %s: _test directory not found", dirname)
+ if !foundSubDir {
+ t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
}
}
diff --git a/src/pkg/io/ioutil/tempfile.go b/src/pkg/io/ioutil/tempfile.go
index 8e681bdc3..42d2e6758 100644
--- a/src/pkg/io/ioutil/tempfile.go
+++ b/src/pkg/io/ioutil/tempfile.go
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "time"
)
// Random number state, accessed without lock; racy but harmless.
@@ -17,8 +18,7 @@ import (
var rand uint32
func reseed() uint32 {
- sec, nsec, _ := os.Time()
- return uint32(sec*1e9 + nsec + int64(os.Getpid()))
+ return uint32(time.Now().UnixNano() + int64(os.Getpid()))
}
func nextSuffix() string {
@@ -40,7 +40,7 @@ func nextSuffix() string {
// will not choose the same file. The caller can use f.Name()
// to find the name of the file. It is the caller's responsibility to
// remove the file when no longer needed.
-func TempFile(dir, prefix string) (f *os.File, err os.Error) {
+func TempFile(dir, prefix string) (f *os.File, err error) {
if dir == "" {
dir = os.TempDir()
}
@@ -49,7 +49,7 @@ func TempFile(dir, prefix string) (f *os.File, err os.Error) {
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextSuffix())
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
- if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+ if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
@@ -67,7 +67,7 @@ func TempFile(dir, prefix string) (f *os.File, err os.Error) {
// Multiple programs calling TempDir simultaneously
// will not choose the same directory. It is the caller's responsibility
// to remove the directory when no longer needed.
-func TempDir(dir, prefix string) (name string, err os.Error) {
+func TempDir(dir, prefix string) (name string, err error) {
if dir == "" {
dir = os.TempDir()
}
@@ -76,7 +76,7 @@ func TempDir(dir, prefix string) (name string, err os.Error) {
for i := 0; i < 10000; i++ {
try := filepath.Join(dir, prefix+nextSuffix())
err = os.Mkdir(try, 0700)
- if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST {
+ if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go
index d702d46c7..2c7e816cf 100644
--- a/src/pkg/io/multi.go
+++ b/src/pkg/io/multi.go
@@ -4,17 +4,15 @@
package io
-import "os"
-
type multiReader struct {
readers []Reader
}
-func (mr *multiReader) Read(p []byte) (n int, err os.Error) {
+func (mr *multiReader) Read(p []byte) (n int, err error) {
for len(mr.readers) > 0 {
n, err = mr.readers[0].Read(p)
- if n > 0 || err != os.EOF {
- if err == os.EOF {
+ if n > 0 || err != EOF {
+ if err == EOF {
// Don't return EOF yet. There may be more bytes
// in the remaining readers.
err = nil
@@ -23,12 +21,12 @@ func (mr *multiReader) Read(p []byte) (n int, err os.Error) {
}
mr.readers = mr.readers[1:]
}
- return 0, os.EOF
+ return 0, EOF
}
// MultiReader returns a Reader that's the logical concatenation of
// the provided input readers. They're read sequentially. Once all
-// inputs are drained, Read will return os.EOF.
+// inputs are drained, Read will return EOF.
func MultiReader(readers ...Reader) Reader {
return &multiReader{readers}
}
@@ -37,7 +35,7 @@ type multiWriter struct {
writers []Writer
}
-func (t *multiWriter) Write(p []byte) (n int, err os.Error) {
+func (t *multiWriter) Write(p []byte) (n int, err error) {
for _, w := range t.writers {
n, err = w.Write(p)
if err != nil {
diff --git a/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go
index 1b3589dde..eb717f7bc 100644
--- a/src/pkg/io/multi_test.go
+++ b/src/pkg/io/multi_test.go
@@ -5,11 +5,10 @@
package io_test
import (
- . "io"
"bytes"
"crypto/sha1"
"fmt"
- "os"
+ . "io"
"strings"
"testing"
)
@@ -26,7 +25,7 @@ func TestMultiReader(t *testing.T) {
buf = make([]byte, 20)
tests()
}
- expectRead := func(size int, expected string, eerr os.Error) {
+ expectRead := func(size int, expected string, eerr error) {
nread++
n, gerr := mr.Read(buf[0:size])
if n != len(expected) {
@@ -48,13 +47,13 @@ func TestMultiReader(t *testing.T) {
expectRead(2, "fo", nil)
expectRead(5, "o ", nil)
expectRead(5, "bar", nil)
- expectRead(5, "", os.EOF)
+ expectRead(5, "", EOF)
})
withFooBar(func() {
expectRead(4, "foo ", nil)
expectRead(1, "b", nil)
expectRead(3, "ar", nil)
- expectRead(1, "", os.EOF)
+ expectRead(1, "", EOF)
})
withFooBar(func() {
expectRead(5, "foo ", nil)
@@ -78,7 +77,7 @@ func TestMultiWriter(t *testing.T) {
t.Errorf("unexpected error: %v", err)
}
- sha1hex := fmt.Sprintf("%x", sha1.Sum())
+ sha1hex := fmt.Sprintf("%x", sha1.Sum(nil))
if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
t.Error("incorrect sha1 value")
}
diff --git a/src/pkg/io/pipe.go b/src/pkg/io/pipe.go
index 00be8efa2..f3f0f1757 100644
--- a/src/pkg/io/pipe.go
+++ b/src/pkg/io/pipe.go
@@ -8,13 +8,16 @@
package io
import (
- "os"
+ "errors"
"sync"
)
+// ErrClosedPipe is the error used for read or write operations on a closed pipe.
+var ErrClosedPipe = errors.New("io: read/write on closed pipe")
+
type pipeResult struct {
n int
- err os.Error
+ err error
}
// A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
@@ -25,11 +28,11 @@ type pipe struct {
data []byte // data remaining in pending write
rwait sync.Cond // waiting reader
wwait sync.Cond // waiting writer
- rerr os.Error // if reader closed, error to give writes
- werr os.Error // if writer closed, error to give reads
+ rerr error // if reader closed, error to give writes
+ werr error // if writer closed, error to give reads
}
-func (p *pipe) read(b []byte) (n int, err os.Error) {
+func (p *pipe) read(b []byte) (n int, err error) {
// One reader at a time.
p.rl.Lock()
defer p.rl.Unlock()
@@ -38,7 +41,7 @@ func (p *pipe) read(b []byte) (n int, err os.Error) {
defer p.l.Unlock()
for {
if p.rerr != nil {
- return 0, os.EINVAL
+ return 0, ErrClosedPipe
}
if p.data != nil {
break
@@ -59,7 +62,7 @@ func (p *pipe) read(b []byte) (n int, err os.Error) {
var zero [0]byte
-func (p *pipe) write(b []byte) (n int, err os.Error) {
+func (p *pipe) write(b []byte) (n int, err error) {
// pipe uses nil to mean not available
if b == nil {
b = zero[:]
@@ -82,7 +85,7 @@ func (p *pipe) write(b []byte) (n int, err os.Error) {
break
}
if p.werr != nil {
- err = os.EINVAL
+ err = ErrClosedPipe
}
p.wwait.Wait()
}
@@ -91,9 +94,9 @@ func (p *pipe) write(b []byte) (n int, err os.Error) {
return
}
-func (p *pipe) rclose(err os.Error) {
+func (p *pipe) rclose(err error) {
if err == nil {
- err = os.EPIPE
+ err = ErrClosedPipe
}
p.l.Lock()
defer p.l.Unlock()
@@ -102,9 +105,9 @@ func (p *pipe) rclose(err os.Error) {
p.wwait.Signal()
}
-func (p *pipe) wclose(err os.Error) {
+func (p *pipe) wclose(err error) {
if err == nil {
- err = os.EOF
+ err = EOF
}
p.l.Lock()
defer p.l.Unlock()
@@ -122,20 +125,20 @@ type PipeReader struct {
// it reads data from the pipe, blocking until a writer
// arrives or the write end is closed.
// If the write end is closed with an error, that error is
-// returned as err; otherwise err is os.EOF.
-func (r *PipeReader) Read(data []byte) (n int, err os.Error) {
+// returned as err; otherwise err is EOF.
+func (r *PipeReader) Read(data []byte) (n int, err error) {
return r.p.read(data)
}
// Close closes the reader; subsequent writes to the
-// write half of the pipe will return the error os.EPIPE.
-func (r *PipeReader) Close() os.Error {
+// write half of the pipe will return the error ErrClosedPipe.
+func (r *PipeReader) Close() error {
return r.CloseWithError(nil)
}
// CloseWithError closes the reader; subsequent writes
// to the write half of the pipe will return the error err.
-func (r *PipeReader) CloseWithError(err os.Error) os.Error {
+func (r *PipeReader) CloseWithError(err error) error {
r.p.rclose(err)
return nil
}
@@ -149,20 +152,20 @@ type PipeWriter struct {
// it writes data to the pipe, blocking until readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
-// returned as err; otherwise err is os.EPIPE.
-func (w *PipeWriter) Write(data []byte) (n int, err os.Error) {
+// returned as err; otherwise err is ErrClosedPipe.
+func (w *PipeWriter) Write(data []byte) (n int, err error) {
return w.p.write(data)
}
// Close closes the writer; subsequent reads from the
-// read half of the pipe will return no bytes and os.EOF.
-func (w *PipeWriter) Close() os.Error {
+// read half of the pipe will return no bytes and EOF.
+func (w *PipeWriter) Close() error {
return w.CloseWithError(nil)
}
// CloseWithError closes the writer; subsequent reads from the
// read half of the pipe will return no bytes and the error err.
-func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
+func (w *PipeWriter) CloseWithError(err error) error {
w.p.wclose(err)
return nil
}
@@ -172,6 +175,10 @@ func (w *PipeWriter) CloseWithError(err os.Error) os.Error {
// with code expecting an io.Writer.
// Reads on one end are matched with writes on the other,
// copying data directly between the two; there is no internal buffering.
+// It is safe to call Read and Write in parallel with each other or with
+// Close. Close will complete once pending I/O is done. Parallel calls to
+// Read, and parallel calls to Write, are also safe:
+// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := new(pipe)
p.rwait.L = &p.l
diff --git a/src/pkg/io/pipe_test.go b/src/pkg/io/pipe_test.go
index bd4b94f0a..7718151b0 100644
--- a/src/pkg/io/pipe_test.go
+++ b/src/pkg/io/pipe_test.go
@@ -7,7 +7,6 @@ package io_test
import (
"fmt"
. "io"
- "os"
"testing"
"time"
)
@@ -44,7 +43,7 @@ func reader(t *testing.T, r Reader, c chan int) {
var buf = make([]byte, 64)
for {
n, err := r.Read(buf)
- if err == os.EOF {
+ if err == EOF {
c <- 0
break
}
@@ -84,7 +83,7 @@ func TestPipe2(t *testing.T) {
type pipeReturn struct {
n int
- err os.Error
+ err error
}
// Test a large write that requires multiple reads to satisfy.
@@ -106,7 +105,7 @@ func TestPipe3(t *testing.T) {
tot := 0
for n := 1; n <= 256; n *= 2 {
nn, err := r.Read(rdat[tot : tot+n])
- if err != nil && err != os.EOF {
+ if err != nil && err != EOF {
t.Fatalf("read: %v", err)
}
@@ -116,7 +115,7 @@ func TestPipe3(t *testing.T) {
expect = 1
} else if n == 256 {
expect = 0
- if err != os.EOF {
+ if err != EOF {
t.Fatalf("read at end: %v", err)
}
}
@@ -142,13 +141,13 @@ func TestPipe3(t *testing.T) {
// Test read after/before writer close.
type closer interface {
- CloseWithError(os.Error) os.Error
- Close() os.Error
+ CloseWithError(error) error
+ Close() error
}
type pipeTest struct {
async bool
- err os.Error
+ err error
closeWithError bool
}
@@ -166,8 +165,8 @@ var pipeTests = []pipeTest{
}
func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
- time.Sleep(1e6) // 1 ms
- var err os.Error
+ time.Sleep(1 * time.Millisecond)
+ var err error
if tt.closeWithError {
err = cl.CloseWithError(tt.err)
} else {
@@ -193,7 +192,7 @@ func TestPipeReadClose(t *testing.T) {
<-c
want := tt.err
if want == nil {
- want = os.EOF
+ want = EOF
}
if err != want {
t.Errorf("read from closed pipe: %v want %v", err, want)
@@ -214,8 +213,8 @@ func TestPipeReadClose2(t *testing.T) {
go delayClose(t, r, c, pipeTest{})
n, err := r.Read(make([]byte, 64))
<-c
- if n != 0 || err != os.EINVAL {
- t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, os.EINVAL)
+ if n != 0 || err != ErrClosedPipe {
+ t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
}
}
@@ -234,7 +233,7 @@ func TestPipeWriteClose(t *testing.T) {
<-c
expect := tt.err
if expect == nil {
- expect = os.EPIPE
+ expect = ErrClosedPipe
}
if err != expect {
t.Errorf("write on closed pipe: %v want %v", err, expect)
diff --git a/src/pkg/json/Makefile b/src/pkg/json/Makefile
deleted file mode 100644
index 28ed62bc4..000000000
--- a/src/pkg/json/Makefile
+++ /dev/null
@@ -1,16 +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.
-
-include ../../Make.inc
-
-TARG=json
-GOFILES=\
- decode.go\
- encode.go\
- indent.go\
- scanner.go\
- stream.go\
- tags.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/json/encode_test.go b/src/pkg/json/encode_test.go
deleted file mode 100644
index 012e9f143..000000000
--- a/src/pkg/json/encode_test.go
+++ /dev/null
@@ -1,82 +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 json
-
-import (
- "bytes"
- "reflect"
- "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)
- }
-}
-
-type StringTag struct {
- BoolStr bool `json:",string"`
- IntStr int64 `json:",string"`
- StrStr string `json:",string"`
-}
-
-var stringTagExpected = `{
- "BoolStr": "true",
- "IntStr": "42",
- "StrStr": "\"xzbit\""
-}`
-
-func TestStringTag(t *testing.T) {
- var s StringTag
- s.BoolStr = true
- s.IntStr = 42
- s.StrStr = "xzbit"
- got, err := MarshalIndent(&s, "", " ")
- if err != nil {
- t.Fatal(err)
- }
- if got := string(got); got != stringTagExpected {
- t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
- }
-
- // Verify that it round-trips.
- var s2 StringTag
- err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
- if err != nil {
- t.Fatalf("Decode: %v", err)
- }
- if !reflect.DeepEqual(s, s2) {
- t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
- }
-}
diff --git a/src/pkg/log/Makefile b/src/pkg/log/Makefile
deleted file mode 100644
index da72216af..000000000
--- a/src/pkg/log/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=log
-GOFILES=\
- log.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go
index ec097434b..1d7f209d1 100644
--- a/src/pkg/log/log.go
+++ b/src/pkg/log/log.go
@@ -13,13 +13,12 @@
package log
import (
- "bytes"
"fmt"
"io"
- "runtime"
"os"
- "time"
+ "runtime"
"sync"
+ "time"
)
// These flags define which text to prefix to each log entry generated by the Logger.
@@ -28,7 +27,7 @@ const (
// order they appear (the order listed here) or the format they present (as
// described in the comments). A colon appears after these items:
// 2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
- Ldate = 1 << iota // the date: 2009/0123
+ Ldate = 1 << iota // the date: 2009/01/23
Ltime // the time: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
@@ -41,11 +40,11 @@ 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
- out io.Writer // destination for output
- buf bytes.Buffer // for accumulating text to write
+ mu sync.Mutex // ensures atomic writes; protects the following fields
+ prefix string // prefix to write at beginning of each line
+ flag int // properties
+ out io.Writer // destination for output
+ buf []byte // for accumulating text to write
}
// New creates a new Logger. The out variable sets the
@@ -60,10 +59,10 @@ var std = New(os.Stderr, "", LstdFlags)
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
-func itoa(buf *bytes.Buffer, i int, wid int) {
+func itoa(buf *[]byte, i int, wid int) {
var u uint = uint(i)
if u == 0 && wid <= 1 {
- buf.WriteByte('0')
+ *buf = append(*buf, '0')
return
}
@@ -75,37 +74,33 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
wid--
b[bp] = byte(u%10) + '0'
}
-
- // avoid slicing b to avoid an allocation.
- for bp < len(b) {
- buf.WriteByte(b[bp])
- bp++
- }
+ *buf = append(*buf, b[bp:]...)
}
-func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
- buf.WriteString(l.prefix)
+func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
+ *buf = append(*buf, l.prefix...)
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
- t := time.SecondsToLocalTime(ns / 1e9)
if l.flag&Ldate != 0 {
- itoa(buf, int(t.Year), 4)
- buf.WriteByte('/')
- itoa(buf, int(t.Month), 2)
- buf.WriteByte('/')
- itoa(buf, int(t.Day), 2)
- buf.WriteByte(' ')
+ year, month, day := t.Date()
+ itoa(buf, year, 4)
+ *buf = append(*buf, '/')
+ itoa(buf, int(month), 2)
+ *buf = append(*buf, '/')
+ itoa(buf, day, 2)
+ *buf = append(*buf, ' ')
}
if l.flag&(Ltime|Lmicroseconds) != 0 {
- itoa(buf, int(t.Hour), 2)
- buf.WriteByte(':')
- itoa(buf, int(t.Minute), 2)
- buf.WriteByte(':')
- itoa(buf, int(t.Second), 2)
+ hour, min, sec := t.Clock()
+ itoa(buf, hour, 2)
+ *buf = append(*buf, ':')
+ itoa(buf, min, 2)
+ *buf = append(*buf, ':')
+ itoa(buf, sec, 2)
if l.flag&Lmicroseconds != 0 {
- buf.WriteByte('.')
- itoa(buf, int(ns%1e9)/1e3, 6)
+ *buf = append(*buf, '.')
+ itoa(buf, t.Nanosecond()/1e3, 6)
}
- buf.WriteByte(' ')
+ *buf = append(*buf, ' ')
}
}
if l.flag&(Lshortfile|Llongfile) != 0 {
@@ -119,10 +114,10 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
}
file = short
}
- buf.WriteString(file)
- buf.WriteByte(':')
+ *buf = append(*buf, file...)
+ *buf = append(*buf, ':')
itoa(buf, line, -1)
- buf.WriteString(": ")
+ *buf = append(*buf, ": "...)
}
}
@@ -132,8 +127,8 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
// already a newline. Calldepth is used to recover the PC and is
// provided for generality, although at the moment on all pre-defined
// paths it will be 2.
-func (l *Logger) Output(calldepth int, s string) os.Error {
- now := time.Nanoseconds() // get this early.
+func (l *Logger) Output(calldepth int, s string) error {
+ now := time.Now() // get this early.
var file string
var line int
l.mu.Lock()
@@ -149,13 +144,13 @@ func (l *Logger) Output(calldepth int, s string) os.Error {
}
l.mu.Lock()
}
- l.buf.Reset()
+ l.buf = l.buf[:0]
l.formatHeader(&l.buf, now, file, line)
- l.buf.WriteString(s)
+ l.buf = append(l.buf, s...)
if len(s) > 0 && s[len(s)-1] != '\n' {
- l.buf.WriteByte('\n')
+ l.buf = append(l.buf, '\n')
}
- _, err := l.out.Write(l.buf.Bytes())
+ _, err := l.out.Write(l.buf)
return err
}
diff --git a/src/pkg/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index 693337212..f53310cb0 100644
--- a/src/pkg/syslog/syslog.go
+++ b/src/pkg/log/syslog/syslog.go
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !windows,!plan9
+
// Package syslog provides a simple interface to the system log service. It
// can send messages to the syslog daemon using UNIX domain sockets, UDP, or
// TCP connections.
package syslog
import (
+ "errors"
"fmt"
"log"
"net"
@@ -37,9 +40,9 @@ type Writer struct {
}
type serverConn interface {
- writeBytes(p Priority, prefix string, b []byte) (int, os.Error)
- writeString(p Priority, prefix string, s string) (int, os.Error)
- close() os.Error
+ writeBytes(p Priority, prefix string, b []byte) (int, error)
+ writeString(p Priority, prefix string, s string) (int, error)
+ close() error
}
type netConn struct {
@@ -49,7 +52,7 @@ type netConn struct {
// New establishes a new connection to the system log daemon.
// Each write to the returned writer sends a log message with
// the given priority and prefix.
-func New(priority Priority, prefix string) (w *Writer, err os.Error) {
+func New(priority Priority, prefix string) (w *Writer, err error) {
return Dial("", "", priority, prefix)
}
@@ -57,7 +60,7 @@ func New(priority Priority, prefix string) (w *Writer, err os.Error) {
// to address raddr on the network net.
// Each write to the returned writer sends a log message with
// the given priority and prefix.
-func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err os.Error) {
+func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, err error) {
if prefix == "" {
prefix = os.Args[0]
}
@@ -73,77 +76,95 @@ func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, e
}
// Write sends a log message to the syslog daemon.
-func (w *Writer) Write(b []byte) (int, os.Error) {
+func (w *Writer) Write(b []byte) (int, error) {
if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
- return 0, os.EINVAL
+ return 0, errors.New("log/syslog: invalid priority")
}
return w.conn.writeBytes(w.priority, w.prefix, b)
}
-func (w *Writer) writeString(p Priority, s string) (int, os.Error) {
+func (w *Writer) writeString(p Priority, s string) (int, error) {
return w.conn.writeString(p, w.prefix, s)
}
-func (w *Writer) Close() os.Error { return w.conn.close() }
+func (w *Writer) Close() error { return w.conn.close() }
// Emerg logs a message using the LOG_EMERG priority.
-func (w *Writer) Emerg(m string) (err os.Error) {
+func (w *Writer) Emerg(m string) (err error) {
_, err = w.writeString(LOG_EMERG, m)
return err
}
+
+// Alert logs a message using the LOG_ALERT priority.
+func (w *Writer) Alert(m string) (err error) {
+ _, err = w.writeString(LOG_ALERT, m)
+ return err
+}
+
// Crit logs a message using the LOG_CRIT priority.
-func (w *Writer) Crit(m string) (err os.Error) {
+func (w *Writer) Crit(m string) (err error) {
_, err = w.writeString(LOG_CRIT, m)
return err
}
-// ERR logs a message using the LOG_ERR priority.
-func (w *Writer) Err(m string) (err os.Error) {
+
+// Err logs a message using the LOG_ERR priority.
+func (w *Writer) Err(m string) (err error) {
_, err = w.writeString(LOG_ERR, m)
return err
}
// Warning logs a message using the LOG_WARNING priority.
-func (w *Writer) Warning(m string) (err os.Error) {
+func (w *Writer) Warning(m string) (err error) {
_, err = w.writeString(LOG_WARNING, m)
return err
}
// Notice logs a message using the LOG_NOTICE priority.
-func (w *Writer) Notice(m string) (err os.Error) {
+func (w *Writer) Notice(m string) (err error) {
_, err = w.writeString(LOG_NOTICE, m)
return err
}
+
// Info logs a message using the LOG_INFO priority.
-func (w *Writer) Info(m string) (err os.Error) {
+func (w *Writer) Info(m string) (err error) {
_, err = w.writeString(LOG_INFO, m)
return err
}
+
// Debug logs a message using the LOG_DEBUG priority.
-func (w *Writer) Debug(m string) (err os.Error) {
+func (w *Writer) Debug(m string) (err error) {
_, err = w.writeString(LOG_DEBUG, m)
return err
}
-func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, os.Error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
+func (n netConn) writeBytes(p Priority, prefix string, b []byte) (int, error) {
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, b)
+ if err != nil {
+ return 0, err
+ }
+ return len(b), nil
}
-func (n netConn) writeString(p Priority, prefix string, s string) (int, os.Error) {
- return fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
+func (n netConn) writeString(p Priority, prefix string, s string) (int, error) {
+ _, err := fmt.Fprintf(n.conn, "<%d>%s: %s\n", p, prefix, s)
+ if err != nil {
+ return 0, err
+ }
+ return len(s), nil
}
-func (n netConn) close() os.Error {
+func (n netConn) close() error {
return n.conn.Close()
}
-// NewLogger provides an object that implements the full log.Logger interface,
-// but sends messages to Syslog instead; flag is passed as is to Logger;
-// priority will be used for all messages sent using this interface.
-// All messages are logged with priority p.
-func NewLogger(p Priority, flag int) *log.Logger {
+// NewLogger creates a log.Logger whose output is written to
+// the system log service with the specified priority. The logFlag
+// argument is the flag set passed through to log.New to create
+// the Logger.
+func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
s, err := New(p, "")
if err != nil {
- return nil
+ return nil, err
}
- return log.New(s, "", flag)
+ return log.New(s, "", logFlag), nil
}
diff --git a/src/pkg/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 5c0b3e0c4..0fd623905 100644
--- a/src/pkg/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.go
@@ -1,6 +1,9 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+
+// +build !windows,!plan9
+
package syslog
import (
@@ -8,6 +11,7 @@ import (
"log"
"net"
"testing"
+ "time"
)
var serverAddr string
@@ -31,7 +35,7 @@ func startServer(done chan<- string) {
log.Fatalf("net.ListenPacket failed udp :0 %v", e)
}
serverAddr = c.LocalAddr().String()
- c.SetReadTimeout(100e6) // 100ms
+ c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
go runSyslog(c, done)
}
@@ -60,9 +64,9 @@ func TestNewLogger(t *testing.T) {
if skipNetTest(t) {
return
}
- f := NewLogger(LOG_INFO, 0)
+ f, err := NewLogger(LOG_INFO, 0)
if f == nil {
- t.Error("NewLogger() failed")
+ t.Error(err)
}
}
diff --git a/src/pkg/syslog/syslog_unix.go b/src/pkg/log/syslog/syslog_unix.go
index b1516715b..46a164dd5 100644
--- a/src/pkg/syslog/syslog_unix.go
+++ b/src/pkg/log/syslog/syslog_unix.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.
+// +build !windows,!plan9
+
package syslog
import (
+ "errors"
"net"
- "os"
)
// unixSyslog opens a connection to the syslog daemon running on the
// local machine using a Unix domain socket.
-func unixSyslog() (conn serverConn, err os.Error) {
+func unixSyslog() (conn serverConn, err error) {
logTypes := []string{"unixgram", "unix"}
logPaths := []string{"/dev/log", "/var/run/syslog"}
var raddr string
@@ -27,5 +29,5 @@ func unixSyslog() (conn serverConn, err os.Error) {
}
}
}
- return nil, os.NewError("Unix syslog delivery error")
+ return nil, errors.New("Unix syslog delivery error")
}
diff --git a/src/pkg/log/syslog/syslog_windows.go b/src/pkg/log/syslog/syslog_windows.go
new file mode 100644
index 000000000..8d99e2e59
--- /dev/null
+++ b/src/pkg/log/syslog/syslog_windows.go
@@ -0,0 +1,8 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syslog provides a simple interface to the system log service.
+package syslog
+
+// BUG(brainman): This package is not implemented on Windows yet.
diff --git a/src/pkg/mail/Makefile b/src/pkg/mail/Makefile
deleted file mode 100644
index e4de5428e..000000000
--- a/src/pkg/mail/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=mail
-GOFILES=\
- message.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile
deleted file mode 100644
index 8e8e74ae4..000000000
--- a/src/pkg/math/Makefile
+++ /dev/null
@@ -1,102 +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.
-
-include ../../Make.inc
-
-TARG=math
-
-OFILES_arm=\
- sqrt_arm.$O\
-
-OFILES_amd64=\
- exp_amd64.$O\
- fabs_amd64.$O\
- fdim_amd64.$O\
- hypot_amd64.$O\
- log_amd64.$O\
- sincos_amd64.$O\
- sqrt_amd64.$O\
-
-OFILES_386=\
- asin_386.$O\
- atan_386.$O\
- atan2_386.$O\
- exp_386.$O\
- exp2_386.$O\
- expm1_386.$O\
- fabs_386.$O\
- floor_386.$O\
- frexp_386.$O\
- fmod_386.$O\
- hypot_386.$O\
- ldexp_386.$O\
- log_386.$O\
- log10_386.$O\
- log1p_386.$O\
- modf_386.$O\
- remainder_386.$O\
- sin_386.$O\
- sincos_386.$O\
- sqrt_386.$O\
- tan_386.$O\
-
-OFILES=\
- $(OFILES_$(GOARCH))
-
-ALLGOFILES=\
- acosh.go\
- asin.go\
- asinh.go\
- atan.go\
- atanh.go\
- atan2.go\
- bits.go\
- cbrt.go\
- const.go\
- copysign.go\
- erf.go\
- exp.go\
- exp_port.go\
- exp2.go\
- expm1.go\
- fabs.go\
- fdim.go\
- floor.go\
- fmod.go\
- frexp.go\
- gamma.go\
- hypot.go\
- hypot_port.go\
- j0.go\
- j1.go\
- jn.go\
- lgamma.go\
- ldexp.go\
- log.go\
- log10.go\
- log1p.go\
- logb.go\
- modf.go\
- nextafter.go\
- pow.go\
- pow10.go\
- remainder.go\
- signbit.go\
- sin.go\
- sincos.go\
- sinh.go\
- sqrt.go\
- sqrt_port.go\
- tan.go\
- tanh.go\
- unsafe.go\
-
-NOGOFILES=\
- $(subst _$(GOARCH).$O,.go,$(OFILES_$(GOARCH)))
-
-GOFILES=\
- $(filter-out $(NOGOFILES),$(ALLGOFILES))\
- $(subst .go,_decl.go,$(NOGOFILES))\
-
-include ../../Make.pkg
diff --git a/src/pkg/math/fabs.go b/src/pkg/math/abs.go
index 343123126..bc41a6d6b 100644
--- a/src/pkg/math/fabs.go
+++ b/src/pkg/math/abs.go
@@ -4,18 +4,19 @@
package math
-// Fabs returns the absolute value of x.
+// Abs returns the absolute value of x.
//
// Special cases are:
-// Fabs(+Inf) = +Inf
-// Fabs(-Inf) = +Inf
-// Fabs(NaN) = NaN
-func Fabs(x float64) float64 {
+// Abs(±Inf) = +Inf
+// Abs(NaN) = NaN
+func Abs(x float64) float64
+
+func abs(x float64) float64 {
switch {
case x < 0:
return -x
case x == 0:
- return 0 // return correctly fabs(-0)
+ return 0 // return correctly abs(-0)
}
return x
}
diff --git a/src/pkg/math/fabs_386.s b/src/pkg/math/abs_386.s
index 55de4e6b8..889e80181 100644
--- a/src/pkg/math/fabs_386.s
+++ b/src/pkg/math/abs_386.s
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// func Fabs(x float64) float64
-TEXT ·Fabs(SB),7,$0
+// func Abs(x float64) float64
+TEXT ·Abs(SB),7,$0
FMOVD x+0(FP), F0 // F0=x
FABS // F0=|x|
FMOVDP F0, r+8(FP)
diff --git a/src/pkg/math/fabs_amd64.s b/src/pkg/math/abs_amd64.s
index 8a9aedbd7..32b78539a 100644
--- a/src/pkg/math/fabs_amd64.s
+++ b/src/pkg/math/abs_amd64.s
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// func Fabs(x float64) float64
-TEXT ·Fabs(SB),7,$0
+// func Abs(x float64) float64
+TEXT ·Abs(SB),7,$0
MOVQ $(1<<63), BX
MOVQ BX, X0 // movsd $(-0.0), x0
MOVSD x+0(FP), X1
diff --git a/src/pkg/go/build/cgotest/cgotest.h b/src/pkg/math/abs_arm.s
index 9c73643b6..23f6a2a2d 100644
--- a/src/pkg/go/build/cgotest/cgotest.h
+++ b/src/pkg/math/abs_arm.s
@@ -2,4 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-extern int Add(int, int, int *);
+TEXT ·Abs(SB),7,$0
+ B ·abs(SB)
diff --git a/src/pkg/math/acosh.go b/src/pkg/math/acosh.go
index 7e8740b89..c6c8645e1 100644
--- a/src/pkg/math/acosh.go
+++ b/src/pkg/math/acosh.go
@@ -36,6 +36,7 @@ package math
// Acosh(x) calculates the inverse hyperbolic cosine of x.
//
// Special cases are:
+// Acosh(+Inf) = +Inf
// Acosh(x) = NaN if x < 1
// Acosh(NaN) = NaN
func Acosh(x float64) float64 {
@@ -43,11 +44,9 @@ func Acosh(x float64) float64 {
Ln2 = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
Large = 1 << 28 // 2**28
)
- // TODO(rsc): Remove manual inlining of IsNaN
- // when compiler does it for us
// first case is special case
switch {
- case x < 1 || x != x: // x < 1 || IsNaN(x):
+ case x < 1 || IsNaN(x):
return NaN()
case x == 1:
return 0
diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go
index d2a7d411e..ed66a42fb 100644
--- a/src/pkg/math/all_test.go
+++ b/src/pkg/math/all_test.go
@@ -7,7 +7,6 @@ package math_test
import (
"fmt"
. "math"
- "runtime"
"testing"
)
@@ -23,6 +22,7 @@ var vf = []float64{
1.8253080916808550e+00,
-8.6859247685756013e+00,
}
+
// The expected results below were computed by the high precision calculators
// at http://keisan.casio.com/. More exact input values (array vf[], above)
// were obtained by printing them with "%.26f". The answers were calculated
@@ -160,6 +160,20 @@ var cos = []float64{
-2.517729313893103197176091e-01,
-7.39241351595676573201918e-01,
}
+
+// Results for 100000 * Pi + vf[i]
+var cosLarge = []float64{
+ 2.634752141185559426744e-01,
+ 1.14855126055543100712e-01,
+ 9.61912973266488928113e-01,
+ 2.9381411499556122552e-01,
+ -9.777138189880161924641e-01,
+ -9.76930413445147608049e-01,
+ 4.940088097314976789841e-01,
+ -9.15658690217517835002e-01,
+ -2.51772931436786954751e-01,
+ -7.3924135157173099849e-01,
+}
var cosh = []float64{
7.2668796942212842775517446e+01,
1.1479413465659254502011135e+03,
@@ -502,6 +516,20 @@ var sin = []float64{
9.6778633541687993721617774e-01,
-6.734405869050344734943028e-01,
}
+
+// Results for 100000 * Pi + vf[i]
+var sinLarge = []float64{
+ -9.646661658548936063912e-01,
+ 9.933822527198506903752e-01,
+ -2.7335587036246899796e-01,
+ 9.55862576853689321268e-01,
+ -2.099421066862688873691e-01,
+ 2.13557878070308981163e-01,
+ -8.694568970959221300497e-01,
+ 4.01956668098863248917e-01,
+ 9.67786335404528727927e-01,
+ -6.7344058693131973066e-01,
+}
var sinh = []float64{
7.2661916084208532301448439e+01,
1.1479409110035194500526446e+03,
@@ -538,6 +566,20 @@ var tan = []float64{
-3.843885560201130679995041e+00,
9.10988793377685105753416e-01,
}
+
+// Results for 100000 * Pi + vf[i]
+var tanLarge = []float64{
+ -3.66131656475596512705e+00,
+ 8.6490023287202547927e+00,
+ -2.841794195104782406e-01,
+ 3.2532901861033120983e+00,
+ 2.14727564046880001365e-01,
+ -2.18600910700688062874e-01,
+ -1.760002817699722747043e+00,
+ -4.38980891453536115952e-01,
+ -3.84388555942723509071e+00,
+ 9.1098879344275101051e-01,
+}
var tanh = []float64{
9.9990531206936338549262119e-01,
9.9999962057085294197613294e-01,
@@ -920,6 +962,75 @@ var fabsSC = []float64{
NaN(),
}
+var vffdimSC = [][2]float64{
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {Inf(1), Inf(-1)},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), Copysign(0, -1)},
+ {NaN(), 0},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
+}
+var fdimSC = []float64{
+ NaN(),
+ 0,
+ NaN(),
+ 0,
+ 0,
+ 0,
+ 0,
+ Inf(1),
+ NaN(),
+ NaN(),
+ NaN(),
+ NaN(),
+ NaN(),
+ NaN(),
+ NaN(),
+}
+var fmaxSC = []float64{
+ Inf(-1),
+ Inf(1),
+ NaN(),
+ Copysign(0, -1),
+ 0,
+ 0,
+ 0,
+ Inf(1),
+ Inf(1),
+ Inf(1),
+ NaN(),
+ NaN(),
+ NaN(),
+ Inf(1),
+ NaN(),
+}
+var fminSC = []float64{
+ Inf(-1),
+ Inf(-1),
+ Inf(-1),
+ Copysign(0, -1),
+ Copysign(0, -1),
+ Copysign(0, -1),
+ 0,
+ Inf(-1),
+ Inf(1),
+ NaN(),
+ Inf(-1),
+ NaN(),
+ NaN(),
+ NaN(),
+ NaN(),
+}
+
var vffmodSC = [][2]float64{
{Inf(-1), Inf(-1)},
{Inf(-1), -Pi},
@@ -1221,12 +1332,26 @@ var modfSC = [][2]float64{
}
var vfnextafterSC = [][2]float64{
+ {0, 0},
+ {0, Copysign(0, -1)},
+ {0, -1},
{0, NaN()},
+ {Copysign(0, -1), 1},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), -1},
{NaN(), 0},
{NaN(), NaN()},
}
var nextafterSC = []float64{
+ 0,
+ 0,
+ -4.9406564584124654418e-324, // Float64frombits(0x8000000000000001)
NaN(),
+ 4.9406564584124654418e-324, // Float64frombits(0x0000000000000001)
+ Copysign(0, -1),
+ Copysign(0, -1),
+ -4.9406564584124654418e-324, // Float64frombits(0x8000000000000001)
NaN(),
NaN(),
}
@@ -1359,6 +1484,20 @@ var powSC = []float64{
NaN(), // pow(NaN, NaN)
}
+var vfpow10SC = []int{
+ MinInt32,
+ MaxInt32,
+ -325,
+ 309,
+}
+
+var pow10SC = []float64{
+ 0, // pow10(MinInt32)
+ Inf(1), // pow10(MaxInt32)
+ 0, // pow10(-325)
+ Inf(1), // pow10(309)
+}
+
var vfsignbitSC = []float64{
Inf(-1),
Copysign(0, -1),
@@ -1570,7 +1709,7 @@ func TestAcos(t *testing.T) {
func TestAcosh(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := 1 + Fabs(vf[i])
+ a := 1 + Abs(vf[i])
if f := Acosh(a); !veryclose(acosh[i], f) {
t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
}
@@ -1695,7 +1834,7 @@ func TestCopysign(t *testing.T) {
func TestCos(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Cos(vf[i]); !close(cos[i], f) {
+ if f := Cos(vf[i]); !veryclose(cos[i], f) {
t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
}
}
@@ -1804,23 +1943,28 @@ func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
}
}
-func TestFabs(t *testing.T) {
+func TestAbs(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Fabs(vf[i]); fabs[i] != f {
- t.Errorf("Fabs(%g) = %g, want %g", vf[i], f, fabs[i])
+ if f := Abs(vf[i]); fabs[i] != f {
+ t.Errorf("Abs(%g) = %g, want %g", vf[i], f, fabs[i])
}
}
for i := 0; i < len(vffabsSC); i++ {
- if f := Fabs(vffabsSC[i]); !alike(fabsSC[i], f) {
- t.Errorf("Fabs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
+ if f := Abs(vffabsSC[i]); !alike(fabsSC[i], f) {
+ t.Errorf("Abs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
}
}
}
-func TestFdim(t *testing.T) {
+func TestDim(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Fdim(vf[i], 0); fdim[i] != f {
- t.Errorf("Fdim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
+ if f := Dim(vf[i], 0); fdim[i] != f {
+ t.Errorf("Dim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
+ }
+ }
+ for i := 0; i < len(vffdimSC); i++ {
+ if f := Dim(vffdimSC[i][0], vffdimSC[i][1]); !alike(fdimSC[i], f) {
+ t.Errorf("Dim(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fdimSC[i])
}
}
}
@@ -1838,31 +1982,41 @@ func TestFloor(t *testing.T) {
}
}
-func TestFmax(t *testing.T) {
+func TestMax(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Fmax(vf[i], ceil[i]); ceil[i] != f {
- t.Errorf("Fmax(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
+ if f := Max(vf[i], ceil[i]); ceil[i] != f {
+ t.Errorf("Max(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
+ }
+ }
+ for i := 0; i < len(vffdimSC); i++ {
+ if f := Max(vffdimSC[i][0], vffdimSC[i][1]); !alike(fmaxSC[i], f) {
+ t.Errorf("Max(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fmaxSC[i])
}
}
}
-func TestFmin(t *testing.T) {
+func TestMin(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Fmin(vf[i], floor[i]); floor[i] != f {
- t.Errorf("Fmin(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
+ if f := Min(vf[i], floor[i]); floor[i] != f {
+ t.Errorf("Min(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
+ }
+ }
+ for i := 0; i < len(vffdimSC); i++ {
+ if f := Min(vffdimSC[i][0], vffdimSC[i][1]); !alike(fminSC[i], f) {
+ t.Errorf("Min(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fminSC[i])
}
}
}
-func TestFmod(t *testing.T) {
+func TestMod(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Fmod(10, vf[i]); fmod[i] != f {
- t.Errorf("Fmod(10, %g) = %g, want %g", vf[i], f, fmod[i])
+ if f := Mod(10, vf[i]); fmod[i] != f {
+ t.Errorf("Mod(10, %g) = %g, want %g", vf[i], f, fmod[i])
}
}
for i := 0; i < len(vffmodSC); i++ {
- if f := Fmod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
- t.Errorf("Fmod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ if f := Mod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
+ t.Errorf("Mod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
}
}
}
@@ -1900,7 +2054,7 @@ func TestGamma(t *testing.T) {
func TestHypot(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(1e200 * tanh[i] * Sqrt(2))
+ a := Abs(1e200 * tanh[i] * Sqrt(2))
if f := Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
t.Errorf("Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
}
@@ -1912,6 +2066,20 @@ func TestHypot(t *testing.T) {
}
}
+func TestHypotGo(t *testing.T) {
+ for i := 0; i < len(vf); i++ {
+ a := Abs(1e200 * tanh[i] * Sqrt(2))
+ if f := HypotGo(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
+ t.Errorf("HypotGo(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
+ }
+ }
+ for i := 0; i < len(vfhypotSC); i++ {
+ if f := HypotGo(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) {
+ t.Errorf("HypotGo(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
+ }
+ }
+}
+
func TestIlogb(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := frexp[i].i - 1 // adjust because fr in the interval [½, 1)
@@ -2019,7 +2187,7 @@ func TestLgamma(t *testing.T) {
func TestLog(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Log(a); log[i] != f {
t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
}
@@ -2046,15 +2214,15 @@ func TestLogb(t *testing.T) {
}
}
for i := 0; i < len(vffrexpBC); i++ {
- if e := Logb(vffrexpBC[i]); !alike(logbBC[i], e) {
- t.Errorf("Ilogb(%g) = %g, want %g", vffrexpBC[i], e, logbBC[i])
+ if f := Logb(vffrexpBC[i]); !alike(logbBC[i], f) {
+ t.Errorf("Logb(%g) = %g, want %g", vffrexpBC[i], f, logbBC[i])
}
}
}
func TestLog10(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Log10(a); !veryclose(log10[i], f) {
t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
}
@@ -2089,7 +2257,7 @@ func TestLog1p(t *testing.T) {
func TestLog2(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Log2(a); !veryclose(log2[i], f) {
t.Errorf("Log2(%g) = %g, want %g", a, f, log2[i])
}
@@ -2123,7 +2291,7 @@ func TestNextafter(t *testing.T) {
t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
}
}
- for i := 0; i < len(vfmodfSC); i++ {
+ for i := 0; i < len(vfnextafterSC); i++ {
if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
}
@@ -2143,6 +2311,14 @@ func TestPow(t *testing.T) {
}
}
+func TestPow10(t *testing.T) {
+ for i := 0; i < len(vfpow10SC); i++ {
+ if f := Pow10(vfpow10SC[i]); !alike(pow10SC[i], f) {
+ t.Errorf("Pow10(%d) = %g, want %g", vfpow10SC[i], f, pow10SC[i])
+ }
+ }
+}
+
func TestRemainder(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Remainder(10, vf[i]); remainder[i] != f {
@@ -2170,7 +2346,7 @@ func TestSignbit(t *testing.T) {
}
func TestSin(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Sin(vf[i]); !close(sin[i], f) {
+ if f := Sin(vf[i]); !veryclose(sin[i], f) {
t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
}
}
@@ -2183,7 +2359,7 @@ func TestSin(t *testing.T) {
func TestSincos(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if s, c := Sincos(vf[i]); !close(sin[i], s) || !close(cos[i], c) {
+ if s, c := Sincos(vf[i]); !veryclose(sin[i], s) || !veryclose(cos[i], c) {
t.Errorf("Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i])
}
}
@@ -2204,11 +2380,11 @@ func TestSinh(t *testing.T) {
func TestSqrt(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := SqrtGo(a); sqrt[i] != f {
t.Errorf("SqrtGo(%g) = %g, want %g", a, f, sqrt[i])
}
- a = Fabs(vf[i])
+ a = Abs(vf[i])
if f := Sqrt(a); sqrt[i] != f {
t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
}
@@ -2225,7 +2401,7 @@ func TestSqrt(t *testing.T) {
func TestTan(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if f := Tan(vf[i]); !close(tan[i], f) {
+ if f := Tan(vf[i]); !veryclose(tan[i], f) {
t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
}
}
@@ -2235,16 +2411,6 @@ func TestTan(t *testing.T) {
t.Errorf("Tan(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
}
}
-
- // Make sure portable Tan(Pi/2) doesn't panic (it used to).
- // The portable implementation returns NaN.
- // Assembly implementations might not,
- // because Pi/2 is not exactly representable.
- if runtime.GOARCH != "386" {
- if f := Tan(Pi / 2); !alike(f, NaN()) {
- t.Errorf("Tan(%g) = %g, want %g", Pi/2, f, NaN())
- }
- }
}
func TestTanh(t *testing.T) {
@@ -2275,7 +2441,7 @@ func TestTrunc(t *testing.T) {
func TestY0(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Y0(a); !close(y0[i], f) {
t.Errorf("Y0(%g) = %g, want %g", a, f, y0[i])
}
@@ -2289,7 +2455,7 @@ func TestY0(t *testing.T) {
func TestY1(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Y1(a); !soclose(y1[i], f, 2e-14) {
t.Errorf("Y1(%g) = %g, want %g", a, f, y1[i])
}
@@ -2303,7 +2469,7 @@ func TestY1(t *testing.T) {
func TestYn(t *testing.T) {
for i := 0; i < len(vf); i++ {
- a := Fabs(vf[i])
+ a := Abs(vf[i])
if f := Yn(2, a); !close(y2[i], f) {
t.Errorf("Yn(2, %g) = %g, want %g", a, f, y2[i])
}
@@ -2322,13 +2488,15 @@ func TestYn(t *testing.T) {
}
// Check that math functions of high angle values
-// return similar results to low angle values
+// return accurate results. [Since (vf[i] + large) - large != vf[i],
+// testing for Trig(vf[i] + large) == Trig(vf[i]), where large is
+// a multiple of 2*Pi, is misleading.]
func TestLargeCos(t *testing.T) {
large := float64(100000 * Pi)
for i := 0; i < len(vf); i++ {
- f1 := Cos(vf[i])
+ f1 := cosLarge[i]
f2 := Cos(vf[i] + large)
- if !kindaclose(f1, f2) {
+ if !close(f1, f2) {
t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
@@ -2337,9 +2505,9 @@ func TestLargeCos(t *testing.T) {
func TestLargeSin(t *testing.T) {
large := float64(100000 * Pi)
for i := 0; i < len(vf); i++ {
- f1 := Sin(vf[i])
+ f1 := sinLarge[i]
f2 := Sin(vf[i] + large)
- if !kindaclose(f1, f2) {
+ if !close(f1, f2) {
t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
@@ -2348,9 +2516,9 @@ func TestLargeSin(t *testing.T) {
func TestLargeSincos(t *testing.T) {
large := float64(100000 * Pi)
for i := 0; i < len(vf); i++ {
- f1, g1 := Sincos(vf[i])
+ f1, g1 := sinLarge[i], cosLarge[i]
f2, g2 := Sincos(vf[i] + large)
- if !kindaclose(f1, f2) || !kindaclose(g1, g2) {
+ if !close(f1, f2) || !close(g1, g2) {
t.Errorf("Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1)
}
}
@@ -2359,16 +2527,16 @@ func TestLargeSincos(t *testing.T) {
func TestLargeTan(t *testing.T) {
large := float64(100000 * Pi)
for i := 0; i < len(vf); i++ {
- f1 := Tan(vf[i])
+ f1 := tanLarge[i]
f2 := Tan(vf[i] + large)
- if !kindaclose(f1, f2) {
+ if !close(f1, f2) {
t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
}
// Check that math constants are accepted by compiler
-// and have right value (assumes strconv.Atof works).
+// and have right value (assumes strconv.ParseFloat works).
// http://code.google.com/p/go/issues/detail?id=201
type floatTest struct {
@@ -2509,15 +2677,15 @@ func BenchmarkExp2Go(b *testing.B) {
}
}
-func BenchmarkFabs(b *testing.B) {
+func BenchmarkAbs(b *testing.B) {
for i := 0; i < b.N; i++ {
- Fabs(.5)
+ Abs(.5)
}
}
-func BenchmarkFdim(b *testing.B) {
+func BenchmarkDim(b *testing.B) {
for i := 0; i < b.N; i++ {
- Fdim(10, 3)
+ Dim(10, 3)
}
}
@@ -2527,21 +2695,21 @@ func BenchmarkFloor(b *testing.B) {
}
}
-func BenchmarkFmax(b *testing.B) {
+func BenchmarkMax(b *testing.B) {
for i := 0; i < b.N; i++ {
- Fmax(10, 3)
+ Max(10, 3)
}
}
-func BenchmarkFmin(b *testing.B) {
+func BenchmarkMin(b *testing.B) {
for i := 0; i < b.N; i++ {
- Fmin(10, 3)
+ Min(10, 3)
}
}
-func BenchmarkFmod(b *testing.B) {
+func BenchmarkMod(b *testing.B) {
for i := 0; i < b.N; i++ {
- Fmod(10, 3)
+ Mod(10, 3)
}
}
@@ -2659,6 +2827,18 @@ func BenchmarkPowFrac(b *testing.B) {
}
}
+func BenchmarkPow10Pos(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow10(300)
+ }
+}
+
+func BenchmarkPow10Neg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pow10(-300)
+ }
+}
+
func BenchmarkRemainder(b *testing.B) {
for i := 0; i < b.N; i++ {
Remainder(10, 3)
diff --git a/src/pkg/math/asin.go b/src/pkg/math/asin.go
index 0a0b0a11c..00bf61ee4 100644
--- a/src/pkg/math/asin.go
+++ b/src/pkg/math/asin.go
@@ -16,7 +16,9 @@ package math
// Special cases are:
// Asin(±0) = ±0
// Asin(x) = NaN if x < -1 or x > 1
-func Asin(x float64) float64 {
+func Asin(x float64) float64
+
+func asin(x float64) float64 {
if x == 0 {
return x // special case
}
@@ -46,4 +48,8 @@ func Asin(x float64) float64 {
//
// Special case is:
// Acos(x) = NaN if x < -1 or x > 1
-func Acos(x float64) float64 { return Pi/2 - Asin(x) }
+func Acos(x float64) float64
+
+func acos(x float64) float64 {
+ return Pi/2 - Asin(x)
+}
diff --git a/src/pkg/math/asin_amd64.s b/src/pkg/math/asin_amd64.s
new file mode 100644
index 000000000..42151f1e9
--- /dev/null
+++ b/src/pkg/math/asin_amd64.s
@@ -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.
+
+TEXT ·Asin(SB),7,$0
+ JMP ·asin(SB)
+
+TEXT ·Acos(SB),7,$0
+ JMP ·acos(SB)
diff --git a/src/pkg/math/asin_arm.s b/src/pkg/math/asin_arm.s
new file mode 100644
index 000000000..d27213fad
--- /dev/null
+++ b/src/pkg/math/asin_arm.s
@@ -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.
+
+TEXT ·Asin(SB),7,$0
+ B ·asin(SB)
+
+TEXT ·Acos(SB),7,$0
+ B ·acos(SB)
diff --git a/src/pkg/math/asin_decl.go b/src/pkg/math/asin_decl.go
deleted file mode 100644
index 63a55dce9..000000000
--- a/src/pkg/math/asin_decl.go
+++ /dev/null
@@ -1,8 +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 math
-
-func Acos(x float64) float64
-func Asin(x float64) float64
diff --git a/src/pkg/math/asinh.go b/src/pkg/math/asinh.go
index c1cad563c..0defbb9be 100644
--- a/src/pkg/math/asinh.go
+++ b/src/pkg/math/asinh.go
@@ -33,8 +33,8 @@ package math
// Asinh(x) calculates the inverse hyperbolic sine of x.
//
// Special cases are:
-// Asinh(+Inf) = +Inf
-// Asinh(-Inf) = -Inf
+// Asinh(±0) = ±0
+// Asinh(±Inf) = ±Inf
// Asinh(NaN) = NaN
func Asinh(x float64) float64 {
const (
@@ -42,10 +42,8 @@ func Asinh(x float64) float64 {
NearZero = 1.0 / (1 << 28) // 2**-28
Large = 1 << 28 // 2**28
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
- if x != x || x > MaxFloat64 || x < -MaxFloat64 { // IsNaN(x) || IsInf(x, 0)
+ if IsNaN(x) || IsInf(x, 0) {
return x
}
sign := false
diff --git a/src/pkg/math/atan.go b/src/pkg/math/atan.go
index 9d4ec2f72..d424a2be4 100644
--- a/src/pkg/math/atan.go
+++ b/src/pkg/math/atan.go
@@ -51,7 +51,9 @@ func satan(arg float64) float64 {
// Special cases are:
// Atan(±0) = ±0
// Atan(±Inf) = ±Pi/2
-func Atan(x float64) float64 {
+func Atan(x float64) float64
+
+func atan(x float64) float64 {
if x == 0 {
return x
}
diff --git a/src/pkg/math/atan2.go b/src/pkg/math/atan2.go
index 49d4bdd71..d84b332c9 100644
--- a/src/pkg/math/atan2.go
+++ b/src/pkg/math/atan2.go
@@ -26,12 +26,12 @@ package math
// Atan2(y<0, -Inf) = -Pi
// Atan2(+Inf, x) = +Pi/2
// Atan2(-Inf, x) = -Pi/2
-func Atan2(y, x float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
+func Atan2(y, x float64) float64
+
+func atan2(y, x float64) float64 {
// special cases
switch {
- case y != y || x != x: // IsNaN(y) || IsNaN(x):
+ case IsNaN(y) || IsNaN(x):
return NaN()
case y == 0:
if x >= 0 && !Signbit(x) {
@@ -40,22 +40,22 @@ func Atan2(y, x float64) float64 {
return Copysign(Pi, y)
case x == 0:
return Copysign(Pi/2, y)
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
- if x > MaxFloat64 { // IsInf(x, 1) {
+ case IsInf(x, 0):
+ if IsInf(x, 1) {
switch {
- case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ case IsInf(y, 0):
return Copysign(Pi/4, y)
default:
return Copysign(0, y)
}
}
switch {
- case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+ case IsInf(y, 0):
return Copysign(3*Pi/4, y)
default:
return Copysign(Pi, y)
}
- case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0):
+ case IsInf(y, 0):
return Copysign(Pi/2, y)
}
diff --git a/src/pkg/math/atan2_386.s b/src/pkg/math/atan2_386.s
index 9a664926a..9a664926a 100755..100644
--- a/src/pkg/math/atan2_386.s
+++ b/src/pkg/math/atan2_386.s
diff --git a/src/pkg/go/build/cgotest/cgotest.c b/src/pkg/math/atan2_amd64.s
index b13acb227..1c5b038c2 100644
--- a/src/pkg/go/build/cgotest/cgotest.c
+++ b/src/pkg/math/atan2_amd64.s
@@ -2,8 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-int
-Add(int x, int y, int *sum)
-{
- sum = x+y;
-}
+TEXT ·Atan2(SB),7,$0
+ JMP ·atan2(SB)
diff --git a/src/pkg/math/atan2_arm.s b/src/pkg/math/atan2_arm.s
new file mode 100644
index 000000000..c2edafae1
--- /dev/null
+++ b/src/pkg/math/atan2_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Atan2(SB),7,$0
+ B ·atan2(SB)
diff --git a/src/pkg/math/atan2_decl.go b/src/pkg/math/atan2_decl.go
deleted file mode 100755
index 3932ed6e4..000000000
--- a/src/pkg/math/atan2_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Atan2(y, x float64) float64
diff --git a/src/pkg/math/atan_amd64.s b/src/pkg/math/atan_amd64.s
new file mode 100644
index 000000000..206072b93
--- /dev/null
+++ b/src/pkg/math/atan_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Atan(SB),7,$0
+ JMP ·atan(SB)
diff --git a/src/pkg/math/atan_arm.s b/src/pkg/math/atan_arm.s
new file mode 100644
index 000000000..ed492ab46
--- /dev/null
+++ b/src/pkg/math/atan_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Atan(SB),7,$0
+ B ·atan(SB)
diff --git a/src/pkg/math/atanh.go b/src/pkg/math/atanh.go
index ed38fcac6..5b5d46855 100644
--- a/src/pkg/math/atanh.go
+++ b/src/pkg/math/atanh.go
@@ -39,17 +39,16 @@ package math
// Atanh(x) calculates the inverse hyperbolic tangent of x.
//
// Special cases are:
-// Atanh(x) = NaN if x < -1 or x > 1
// Atanh(1) = +Inf
+// Atanh(±0) = ±0
// Atanh(-1) = -Inf
+// Atanh(x) = NaN if x < -1 or x > 1
// Atanh(NaN) = NaN
func Atanh(x float64) float64 {
const NearZero = 1.0 / (1 << 28) // 2**-28
- // TODO(rsc): Remove manual inlining of IsNaN
- // when compiler does it for us
// special cases
switch {
- case x < -1 || x > 1 || x != x: // x < -1 || x > 1 || IsNaN(x):
+ case x < -1 || x > 1 || IsNaN(x):
return NaN()
case x == 1:
return Inf(1)
diff --git a/src/pkg/big/arith.go b/src/pkg/math/big/arith.go
index 0a02a4ef5..f316806d7 100644
--- a/src/pkg/big/arith.go
+++ b/src/pkg/math/big/arith.go
@@ -8,8 +8,7 @@
package big
-// TODO(gri) Decide if Word needs to remain exported.
-
+// A Word represents a single digit of a multi-precision unsigned integer.
type Word uintptr
const (
@@ -79,11 +78,23 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
}
// Length of x in bits.
-func bitLen(x Word) (n int) {
- for ; x >= 0x100; x >>= 8 {
+func bitLen_g(x Word) (n int) {
+ for ; x >= 0x8000; x >>= 16 {
+ n += 16
+ }
+ if x >= 0x80 {
+ x >>= 8
n += 8
}
- for ; x > 0; x >>= 1 {
+ if x >= 0x8 {
+ x >>= 4
+ n += 4
+ }
+ if x >= 0x2 {
+ x >>= 2
+ n += 2
+ }
+ if x >= 0x1 {
n++
}
return
diff --git a/src/pkg/big/arith_386.s b/src/pkg/math/big/arith_386.s
index 07c07b02c..f1262c651 100644
--- a/src/pkg/big/arith_386.s
+++ b/src/pkg/math/big/arith_386.s
@@ -245,7 +245,7 @@ E6: CMPL BX, $0 // i < 0
RET
-// divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
+// func divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
TEXT ·divWVW(SB),7,$0
MOVL z+0(FP), DI
MOVL xn+12(FP), DX // r = xn
@@ -263,3 +263,14 @@ E7: SUBL $1, BX // i--
MOVL DX, r+32(FP)
RET
+
+// func bitLen(x Word) (n int)
+TEXT ·bitLen(SB),7,$0
+ BSRL x+0(FP), AX
+ JZ Z1
+ INCL AX
+ MOVL AX, n+4(FP)
+ RET
+
+Z1: MOVL $0, n+4(FP)
+ RET
diff --git a/src/pkg/big/arith_amd64.s b/src/pkg/math/big/arith_amd64.s
index 89b65f38a..54f647322 100644
--- a/src/pkg/big/arith_amd64.s
+++ b/src/pkg/math/big/arith_amd64.s
@@ -243,7 +243,7 @@ E6: CMPQ BX, R11 // i < n
RET
-// divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
+// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
TEXT ·divWVW(SB),7,$0
MOVQ z+0(FP), R10
MOVQ xn+16(FP), DX // r = xn
@@ -261,3 +261,14 @@ E7: SUBL $1, BX // i--
MOVQ DX, r+48(FP)
RET
+
+// func bitLen(x Word) (n int)
+TEXT ·bitLen(SB),7,$0
+ BSRQ x+0(FP), AX
+ JZ Z1
+ INCL AX
+ MOVL AX, n+8(FP)
+ RET
+
+Z1: MOVL $0, n+8(FP)
+ RET
diff --git a/src/pkg/big/arith_arm.s b/src/pkg/math/big/arith_arm.s
index 60abe6eaa..dbf3360b5 100644
--- a/src/pkg/big/arith_arm.s
+++ b/src/pkg/math/big/arith_arm.s
@@ -290,7 +290,7 @@ E9:
RET
-// divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
+// func divWVW(z* Word, xn Word, x []Word, y Word) (r Word)
TEXT ·divWVW(SB),7,$0
// ARM has no multiword division, so use portable code.
B ·divWVW_g(SB)
@@ -310,3 +310,12 @@ TEXT ·mulWW(SB),7,$0
MOVW R4, z1+8(FP)
MOVW R3, z0+12(FP)
RET
+
+// func bitLen(x Word) (n int)
+TEXT ·bitLen(SB),7,$0
+ MOVW x+0(FP), R0
+ WORD $0xe16f0f10 // CLZ R0, R0 (count leading zeros)
+ MOVW $32, R1
+ SUB.S R0, R1
+ MOVW R1, n+4(FP)
+ RET
diff --git a/src/pkg/big/arith_decl.go b/src/pkg/math/big/arith_decl.go
index 95fcd8b94..068cc8d93 100644
--- a/src/pkg/big/arith_decl.go
+++ b/src/pkg/math/big/arith_decl.go
@@ -16,3 +16,4 @@ 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)
+func bitLen(x Word) (n int)
diff --git a/src/pkg/big/arith_test.go b/src/pkg/math/big/arith_test.go
index b6c56c39e..c7e3d284c 100644
--- a/src/pkg/big/arith_test.go
+++ b/src/pkg/math/big/arith_test.go
@@ -333,3 +333,40 @@ func TestMulAddWWW(t *testing.T) {
}
}
}
+
+func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
+ for i := 0; i <= _W; i++ {
+ x := Word(1) << uint(i-1) // i == 0 => x == 0
+ n := f(x)
+ if n != i {
+ t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
+ }
+ }
+}
+
+func TestWordBitLen(t *testing.T) {
+ testWordBitLen(t, "bitLen", bitLen)
+ testWordBitLen(t, "bitLen_g", bitLen_g)
+}
+
+// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
+func benchmarkBitLenN(b *testing.B, nbits uint) {
+ testword := Word((uint64(1) << nbits) - 1)
+ for i := 0; i < b.N; i++ {
+ bitLen(testword)
+ }
+}
+
+// Individual bitLen tests. Numbers chosen to examine both sides
+// of powers-of-two boundaries.
+func BenchmarkBitLen0(b *testing.B) { benchmarkBitLenN(b, 0) }
+func BenchmarkBitLen1(b *testing.B) { benchmarkBitLenN(b, 1) }
+func BenchmarkBitLen2(b *testing.B) { benchmarkBitLenN(b, 2) }
+func BenchmarkBitLen3(b *testing.B) { benchmarkBitLenN(b, 3) }
+func BenchmarkBitLen4(b *testing.B) { benchmarkBitLenN(b, 4) }
+func BenchmarkBitLen5(b *testing.B) { benchmarkBitLenN(b, 5) }
+func BenchmarkBitLen8(b *testing.B) { benchmarkBitLenN(b, 8) }
+func BenchmarkBitLen9(b *testing.B) { benchmarkBitLenN(b, 9) }
+func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
+func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
+func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
diff --git a/src/pkg/big/calibrate_test.go b/src/pkg/math/big/calibrate_test.go
index 1cd93b105..efe1837bb 100644
--- a/src/pkg/big/calibrate_test.go
+++ b/src/pkg/math/big/calibrate_test.go
@@ -8,7 +8,7 @@
// results are somewhat fragile; use repeated runs to get
// a clear picture.
-// Usage: gotest -calibrate
+// Usage: go test -run=TestCalibrate -calibrate
package big
@@ -22,14 +22,14 @@ import (
var calibrate = flag.Bool("calibrate", false, "run calibration test")
// measure returns the time to run f
-func measure(f func()) int64 {
+func measure(f func()) time.Duration {
const N = 100
- start := time.Nanoseconds()
+ start := time.Now()
for i := N; i > 0; i-- {
f()
}
- stop := time.Nanoseconds()
- return (stop - start) / N
+ stop := time.Now()
+ return stop.Sub(start) / N
}
func computeThresholds() {
@@ -46,7 +46,7 @@ func computeThresholds() {
th1 := -1
th2 := -1
- var deltaOld int64
+ var deltaOld time.Duration
for count := -1; count != 0; count-- {
// determine Tk, the work load execution time using Karatsuba multiplication
karatsubaThreshold = n // enable karatsuba
diff --git a/src/pkg/math/big/example_test.go b/src/pkg/math/big/example_test.go
new file mode 100644
index 000000000..078be47f9
--- /dev/null
+++ b/src/pkg/math/big/example_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big_test
+
+import (
+ "fmt"
+ "log"
+ "math/big"
+)
+
+func ExampleRat_SetString() {
+ r := new(big.Rat)
+ r.SetString("355/113")
+ fmt.Println(r.FloatString(3))
+ // Output: 3.142
+}
+
+func ExampleInt_SetString() {
+ i := new(big.Int)
+ i.SetString("644", 8) // octal
+ fmt.Println(i)
+ // Output: 420
+}
+
+func ExampleRat_Scan() {
+ // The Scan function is rarely used directly;
+ // the fmt package recognizes it as an implementation of fmt.Scanner.
+ r := new(big.Rat)
+ _, err := fmt.Sscan("1.5000", r)
+ if err != nil {
+ log.Println("error scanning value:", err)
+ } else {
+ fmt.Println(r)
+ }
+ // Output: 3/2
+}
+
+func ExampleInt_Scan() {
+ // The Scan function is rarely used directly;
+ // the fmt package recognizes it as an implementation of fmt.Scanner.
+ i := new(big.Int)
+ _, err := fmt.Sscan("18446744073709551617", i)
+ if err != nil {
+ log.Println("error scanning value:", err)
+ } else {
+ fmt.Println(i)
+ }
+ // Output: 18446744073709551617
+}
diff --git a/src/pkg/big/hilbert_test.go b/src/pkg/math/big/hilbert_test.go
index 1a84341b3..1a84341b3 100644
--- a/src/pkg/big/hilbert_test.go
+++ b/src/pkg/math/big/hilbert_test.go
diff --git a/src/pkg/big/int.go b/src/pkg/math/big/int.go
index 701b69715..cd2cd0e2d 100755..100644
--- a/src/pkg/big/int.go
+++ b/src/pkg/math/big/int.go
@@ -7,10 +7,10 @@
package big
import (
+ "errors"
"fmt"
"io"
- "os"
- "rand"
+ "math/rand"
"strings"
)
@@ -58,22 +58,44 @@ func NewInt(x int64) *Int {
// Set sets z to x and returns z.
func (z *Int) Set(x *Int) *Int {
- z.abs = z.abs.set(x.abs)
- z.neg = x.neg
+ if z != x {
+ z.abs = z.abs.set(x.abs)
+ z.neg = x.neg
+ }
+ return z
+}
+
+// Bits provides raw (unchecked but fast) access to x by returning its
+// absolute value as a little-endian Word slice. The result and x share
+// the same underlying array.
+// Bits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (x *Int) Bits() []Word {
+ return x.abs
+}
+
+// SetBits provides raw (unchecked but fast) access to z by setting its
+// value to abs, interpreted as a little-endian Word slice, and returning
+// z. The result and abs share the same underlying array.
+// SetBits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (z *Int) SetBits(abs []Word) *Int {
+ z.abs = nat(abs).norm()
+ z.neg = false
return z
}
// Abs sets z to |x| (the absolute value of x) and returns z.
func (z *Int) Abs(x *Int) *Int {
- z.abs = z.abs.set(x.abs)
+ z.Set(x)
z.neg = false
return z
}
// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
- z.abs = z.abs.set(x.abs)
- z.neg = len(z.abs) > 0 && !x.neg // 0 has no sign
+ z.Set(x)
+ z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
return z
}
@@ -163,7 +185,7 @@ func (z *Int) Binomial(n, k int64) *Int {
// 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.
+// Quo implements truncated division (like Go); see QuoRem for more details.
func (z *Int) Quo(x, y *Int) *Int {
z.abs, _ = z.abs.div(nil, x.abs, y.abs)
z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
@@ -172,7 +194,7 @@ func (z *Int) Quo(x, y *Int) *Int {
// 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.
+// Rem implements truncated modulus (like Go); see QuoRem for more details.
func (z *Int) Rem(x, y *Int) *Int {
_, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
@@ -189,6 +211,7 @@ func (z *Int) Rem(x, y *Int) *Int {
// r = x - y*q
//
// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+// See DivMod for Euclidean division and modulus (unlike Go).
//
func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
@@ -198,7 +221,7 @@ func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
// 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.
+// Div implements Euclidean division (unlike Go); see DivMod for more details.
func (z *Int) Div(x, y *Int) *Int {
y_neg := y.neg // z may be an alias for y
var r Int
@@ -215,7 +238,7 @@ func (z *Int) Div(x, y *Int) *Int {
// 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.
+// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
func (z *Int) Mod(x, y *Int) *Int {
y0 := y // save y
if z == y || alias(z.abs, y.abs) {
@@ -246,6 +269,7 @@ func (z *Int) Mod(x, y *Int) *Int {
// div and mod''. ACM Transactions on Programming Languages and
// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
// ACM press.)
+// See QuoRem for T-division and modulus (like Go).
//
func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
y0 := y // save y
@@ -300,7 +324,7 @@ func (x *Int) String() string {
return x.abs.decimalString()
}
-func charset(ch int) string {
+func charset(ch rune) string {
switch ch {
case 'b':
return lowercaseDigits[0:2]
@@ -337,7 +361,7 @@ func writeMultiple(s fmt.State, text string, count int) {
// output field width, space or zero padding, and left or
// right justification.
//
-func (x *Int) Format(s fmt.State, ch int) {
+func (x *Int) Format(s fmt.State, ch rune) {
cs := charset(ch)
// special cases
@@ -422,19 +446,19 @@ func (x *Int) Format(s fmt.State, ch int) {
// 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.
+// error case, the value of z is undefined but the returned value is nil. 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) {
+func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, error) {
// determine sign
ch, _, err := r.ReadRune()
if err != nil {
- return z, 0, err
+ return nil, 0, err
}
neg := false
switch ch {
@@ -448,7 +472,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
// determine mantissa
z.abs, base, err = z.abs.scan(r, base)
if err != nil {
- return z, base, err
+ return nil, base, err
}
z.neg = len(z.abs) > 0 && neg // 0 has no sign
@@ -458,7 +482,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
// 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 {
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
s.SkipSpace() // skip leading space characters
base := 0
switch ch {
@@ -473,7 +497,7 @@ func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
case 's', 'v':
// let scan determine the base
default:
- return os.NewError("Int.Scan: invalid verb")
+ return errors.New("Int.Scan: invalid verb")
}
_, _, err := z.scan(s, base)
return err
@@ -497,7 +521,7 @@ func (x *Int) Int64() int64 {
// 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.
+// the value of z is undefined but the returned value is nil.
//
// 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
@@ -508,10 +532,13 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
r := strings.NewReader(s)
_, _, err := z.scan(r, base)
if err != nil {
- return z, false
+ return nil, false
}
_, _, err = r.ReadRune()
- return z, err == os.EOF // err == os.EOF => scan consumed all of s
+ if err != io.EOF {
+ return nil, false
+ }
+ return z, true // err == io.EOF => scan consumed all of s
}
// SetBytes interprets buf as the bytes of a big-endian unsigned
@@ -523,18 +550,18 @@ func (z *Int) SetBytes(buf []byte) *Int {
}
// Bytes returns the absolute value of z as a big-endian byte slice.
-func (z *Int) Bytes() []byte {
- buf := make([]byte, len(z.abs)*_S)
- return buf[z.abs.bytes(buf):]
+func (x *Int) Bytes() []byte {
+ buf := make([]byte, len(x.abs)*_S)
+ return buf[x.abs.bytes(buf):]
}
// BitLen returns the length of the absolute value of z in bits.
// The bit length of 0 is 0.
-func (z *Int) BitLen() int {
- return z.abs.bitLen()
+func (x *Int) BitLen() int {
+ return x.abs.bitLen()
}
-// Exp sets z = x**y mod m. If m is nil, z = x**y.
+// Exp sets z = x**y mod m and returns z. If m is nil, z = x**y.
// See Knuth, volume 2, section 4.6.3.
func (z *Int) Exp(x, y, m *Int) *Int {
if y.neg || len(y.abs) == 0 {
@@ -554,20 +581,20 @@ func (z *Int) Exp(x, y, m *Int) *Int {
return z
}
-// GcdInt sets d to the greatest common divisor of a and b, which must be
-// positive numbers.
-// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
-// If either a or b is not positive, GcdInt sets d = x = y = 0.
-func GcdInt(d, x, y, a, b *Int) {
+// GCD sets z to the greatest common divisor of a and b, which must be
+// positive numbers, and returns z.
+// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
+// If either a or b is not positive, GCD sets z = x = y = 0.
+func (z *Int) GCD(x, y, a, b *Int) *Int {
if a.neg || b.neg {
- d.SetInt64(0)
+ z.SetInt64(0)
if x != nil {
x.SetInt64(0)
}
if y != nil {
y.SetInt64(0)
}
- return
+ return z
}
A := new(Int).Set(a)
@@ -609,14 +636,15 @@ func GcdInt(d, x, y, a, b *Int) {
*y = *lastY
}
- *d = *A
+ *z = *A
+ return z
}
-// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
-// If it returns true, z is prime with probability 1 - 1/4^n.
-// If it returns false, z is not prime.
-func ProbablyPrime(z *Int, n int) bool {
- return !z.neg && z.abs.probablyPrime(n)
+// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If it returns true, x is prime with probability 1 - 1/4^n.
+// If it returns false, x is not prime.
+func (x *Int) ProbablyPrime(n int) bool {
+ return !x.neg && x.abs.probablyPrime(n)
}
// Rand sets z to a pseudo-random number in [0, n) and returns z.
@@ -634,7 +662,7 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
// p is a prime) and returns z.
func (z *Int) ModInverse(g, p *Int) *Int {
var d Int
- GcdInt(&d, z, nil, g, p)
+ d.GCD(z, nil, g, p)
// x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
// that modulo p results in g*x = 1, therefore x is the inverse element.
if z.neg {
@@ -666,21 +694,21 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
return z
}
-// Bit returns the value of the i'th bit of z. That is, it
-// returns (z>>i)&1. The bit index i must be >= 0.
-func (z *Int) Bit(i int) uint {
+// Bit returns the value of the i'th bit of x. That is, it
+// returns (x>>i)&1. The bit index i must be >= 0.
+func (x *Int) Bit(i int) uint {
if i < 0 {
panic("negative bit index")
}
- if z.neg {
- t := nat{}.sub(z.abs, natOne)
+ if x.neg {
+ t := nat(nil).sub(x.abs, natOne)
return t.bit(uint(i)) ^ 1
}
- return z.abs.bit(uint(i))
+ return x.abs.bit(uint(i))
}
-// SetBit sets the i'th bit of z to bit and returns z.
+// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
// 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.
@@ -705,8 +733,8 @@ func (z *Int) And(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -724,7 +752,7 @@ func (z *Int) And(x, y *Int) *Int {
}
// x & (-y) == x & ^(y-1) == x &^ (y-1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.andNot(x.abs, y1)
z.neg = false
return z
@@ -735,8 +763,8 @@ func (z *Int) AndNot(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.andNot(y1, x1)
z.neg = false
return z
@@ -750,14 +778,14 @@ func (z *Int) AndNot(x, y *Int) *Int {
if x.neg {
// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
- x1 := nat{}.sub(x.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
z.neg = true // z cannot be zero if x is negative and y is positive
return z
}
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- y1 := nat{}.add(y.abs, natOne)
+ y1 := nat(nil).add(y.abs, natOne)
z.abs = z.abs.and(x.abs, y1)
z.neg = false
return z
@@ -768,8 +796,8 @@ func (z *Int) Or(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -787,7 +815,7 @@ func (z *Int) Or(x, y *Int) *Int {
}
// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
z.neg = true // z cannot be zero if one of x or y is negative
return z
@@ -798,8 +826,8 @@ func (z *Int) Xor(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.xor(x1, y1)
z.neg = false
return z
@@ -817,7 +845,7 @@ func (z *Int) Xor(x, y *Int) *Int {
}
// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
z.neg = true // z cannot be zero if only one of x or y is negative
return z
@@ -842,11 +870,11 @@ func (z *Int) Not(x *Int) *Int {
const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
-func (z *Int) GobEncode() ([]byte, os.Error) {
- buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
- i := z.abs.bytes(buf) - 1 // i >= 0
+func (x *Int) GobEncode() ([]byte, error) {
+ buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+ i := x.abs.bytes(buf) - 1 // i >= 0
b := intGobVersion << 1 // make space for sign bit
- if z.neg {
+ if x.neg {
b |= 1
}
buf[i] = b
@@ -854,13 +882,13 @@ func (z *Int) GobEncode() ([]byte, os.Error) {
}
// GobDecode implements the gob.GobDecoder interface.
-func (z *Int) GobDecode(buf []byte) os.Error {
+func (z *Int) GobDecode(buf []byte) error {
if len(buf) == 0 {
- return os.NewError("Int.GobDecode: no data")
+ return errors.New("Int.GobDecode: no data")
}
b := buf[0]
if b>>1 != intGobVersion {
- return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+ return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
}
z.neg = b&1 != 0
z.abs = z.abs.setBytes(buf[1:])
diff --git a/src/pkg/big/int_test.go b/src/pkg/math/big/int_test.go
index 03446d6ae..9700a9b5a 100755..100644
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/math/big/int_test.go
@@ -6,9 +6,10 @@ package big
import (
"bytes"
+ "encoding/gob"
"encoding/hex"
"fmt"
- "gob"
+ "math/rand"
"testing"
"testing/quick"
)
@@ -301,6 +302,9 @@ func TestGetString(t *testing.T) {
func TestSetString(t *testing.T) {
tmp := new(Int)
for i, test := range stringTests {
+ // initialize to a non-zero value so that issues with parsing
+ // 0 are detected
+ tmp.SetInt64(1234567890)
n1, ok1 := new(Int).SetString(test.in, test.base)
n2, ok2 := tmp.SetString(test.in, test.base)
expected := NewInt(test.val)
@@ -308,7 +312,16 @@ func TestSetString(t *testing.T) {
t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
continue
}
- if !ok1 || !ok2 {
+ if !ok1 {
+ if n1 != nil {
+ t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+ }
+ continue
+ }
+ if !ok2 {
+ if n2 != nil {
+ t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+ }
continue
}
@@ -524,7 +537,7 @@ func TestScan(t *testing.T) {
buf.Reset()
buf.WriteString(test.input)
if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
- t.Errorf("#%d error: %s", i, err.String())
+ t.Errorf("#%d error: %s", i, err)
}
if x.String() != test.output {
t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
@@ -811,7 +824,7 @@ func checkGcd(aBytes, bBytes []byte) bool {
y := new(Int)
d := new(Int)
- GcdInt(d, x, y, a, b)
+ d.GCD(x, y, a, b)
x.Mul(x, a)
y.Mul(y, b)
x.Add(x, y)
@@ -839,7 +852,7 @@ func TestGcd(t *testing.T) {
expectedY := NewInt(test.y)
expectedD := NewInt(test.d)
- GcdInt(d, x, y, a, b)
+ d.GCD(x, y, a, b)
if expectedX.Cmp(x) != 0 ||
expectedY.Cmp(y) != 0 ||
@@ -890,14 +903,14 @@ func TestProbablyPrime(t *testing.T) {
}
for i, s := range primes {
p, _ := new(Int).SetString(s, 10)
- if !ProbablyPrime(p, nreps) {
+ if !p.ProbablyPrime(nreps) {
t.Errorf("#%d prime found to be non-prime (%s)", i, s)
}
}
for i, s := range composites {
c, _ := new(Int).SetString(s, 10)
- if ProbablyPrime(c, nreps) {
+ if c.ProbablyPrime(nreps) {
t.Errorf("#%d composite found to be prime (%s)", i, s)
}
if testing.Short() {
@@ -1230,10 +1243,14 @@ func TestBitSet(t *testing.T) {
x.SetString(test.x, 0)
b := x.Bit(test.i)
if b != test.b {
-
- t.Errorf("#%d want %v got %v", i, test.b, b)
+ t.Errorf("#%d got %v want %v", i, b, test.b)
}
}
+ z := NewInt(1)
+ z.SetBit(NewInt(0), 2, 1)
+ if z.Cmp(NewInt(4)) != 0 {
+ t.Errorf("destination leaked into result; got %s want 4", z)
+ }
}
func BenchmarkBitset(b *testing.B) {
@@ -1389,3 +1406,9 @@ func TestIntGobEncoding(t *testing.T) {
}
}
}
+
+func TestIssue2607(t *testing.T) {
+ // This code sequence used to hang.
+ n := NewInt(10)
+ n.Rand(rand.New(rand.NewSource(9)), n)
+}
diff --git a/src/pkg/big/nat.go b/src/pkg/math/big/nat.go
index be3aff29d..0bc6572b9 100755..100644
--- a/src/pkg/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -8,9 +8,15 @@
// - Int signed integers
// - Rat rational numbers
//
-// All methods on Int take the result as the receiver; if it is one
-// of the operands it may be overwritten (and its memory reused).
-// To enable chaining of operations, the result is also returned.
+// Methods are typically of the form:
+//
+// func (z *Int) Op(x, y *Int) *Int (similar for *Rat)
+//
+// and implement operations z = x Op y with the result as receiver; if it
+// is one of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned. Methods
+// returning a result other than *Int or *Rat take one of the operands as
+// the receiver.
//
package big
@@ -19,9 +25,11 @@ package big
// and rationals.
import (
+ "errors"
"io"
- "os"
- "rand"
+ "math"
+ "math/rand"
+ "sync"
)
// An unsigned integer x of the form
@@ -35,7 +43,7 @@ import (
// During arithmetic operations, denormalized values may occur but are
// always normalized before returning the final result. The normalized
// representation of 0 is the empty or nil slice (length = 0).
-
+//
type nat []Word
var (
@@ -589,16 +597,15 @@ func (x nat) bitLen() int {
// MaxBase is the largest number base accepted for string conversions.
const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
-
-func hexValue(ch int) Word {
- d := MaxBase + 1 // illegal base
+func hexValue(ch rune) Word {
+ d := int(MaxBase + 1) // illegal base
switch {
case '0' <= ch && ch <= '9':
- d = ch - '0'
+ d = int(ch - '0')
case 'a' <= ch && ch <= 'z':
- d = ch - 'a' + 10
+ d = int(ch - 'a' + 10)
case 'A' <= ch && ch <= 'Z':
- d = ch - 'A' + 10
+ d = int(ch - 'A' + 10)
}
return Word(d)
}
@@ -614,10 +621,10 @@ func hexValue(ch int) Word {
// ``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(r io.RuneScanner, base int) (nat, int, os.Error) {
+func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) {
// reject illegal bases
if base < 0 || base == 1 || MaxBase < base {
- return z, 0, os.NewError("illegal number base")
+ return z, 0, errors.New("illegal number base")
}
// one char look-ahead
@@ -645,8 +652,8 @@ func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
return z, 0, err
}
}
- case os.EOF:
- return z, 10, nil
+ case io.EOF:
+ return z.make(0), 10, nil
default:
return z, 10, err
}
@@ -677,7 +684,7 @@ func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
}
if ch, _, err = r.ReadRune(); err != nil {
- if err != os.EOF {
+ if err != io.EOF {
return z, int(b), err
}
break
@@ -694,7 +701,7 @@ func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
return z, 10, nil
case base != 0 || b != 8:
// there was neither a mantissa digit nor the octal prefix 0
- return z, int(b), os.NewError("syntax error scanning number")
+ return z, int(b), errors.New("syntax error scanning number")
}
return z.norm(), int(b), nil
@@ -714,23 +721,23 @@ func (x nat) decimalString() string {
// 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.
+// by len(charset), which must be >= 2 and <= 256.
func (x nat) string(charset string) string {
b := Word(len(charset))
// special cases
switch {
- case b < 2 || b > 256:
+ case b < 2 || MaxBase > 256:
panic("illegal base")
case len(x) == 0:
return string(charset[0])
}
// allocate buffer for conversion
- i := x.bitLen()/log2(b) + 1 // +1: round up
+ i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
s := make([]byte, i)
- // special case: power of two bases can avoid divisions completely
+ // convert power of two and non power of two bases separately
if b == b&-b {
// shift is base-b digit size in bits
shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
@@ -773,64 +780,201 @@ func (x nat) string(charset string) string {
nbits -= shift
}
- return string(s[i:])
+ } else {
+ // determine "big base"; i.e., the largest possible value bb
+ // that is a power of base b and still fits into a Word
+ // (as in 10^19 for 19 decimal digits in a 64bit Word)
+ bb := b // big base is b**ndigits
+ ndigits := 1 // number of base b digits
+ for max := Word(_M / b); bb <= max; bb *= b {
+ ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M
+ }
+
+ // construct table of successive squares of bb*leafSize to use in subdivisions
+ // result (table != nil) <=> (len(x) > leafSize > 0)
+ table := divisors(len(x), b, ndigits, bb)
+
+ // preserve x, create local copy for use by convertWords
+ q := nat(nil).set(x)
+
+ // convert q to string s in base b
+ q.convertWords(s, charset, b, ndigits, bb, table)
+
+ // strip leading zeros
+ // (x != 0; thus s must contain at least one non-zero digit
+ // and the loop will terminate)
+ i = 0
+ for zero := charset[0]; s[i] == zero; {
+ i++
+ }
}
- // general case: extract groups of digits by multiprecision division
+ return string(s[i:])
+}
- // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits
- bb := Word(1)
- ndigits := 0
- for max := Word(_M / b); bb <= max; bb *= b {
- ndigits++
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word divison.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+ // split larger blocks recursively
+ if table != nil {
+ // len(q) > leafSize > 0
+ var r nat
+ index := len(table) - 1
+ for len(q) > leafSize {
+ // find divisor close to sqrt(q) if possible, but in any case < q
+ maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length
+ minLength := maxLength >> 1 // ~= log2 sqrt(q)
+ for index > 0 && table[index-1].nbits > minLength {
+ index-- // desired
+ }
+ if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+ index--
+ if index < 0 {
+ panic("internal inconsistency")
+ }
+ }
+
+ // split q into the two digit number (q'*bbb + r) to form independent subblocks
+ q, r = q.div(r, q, table[index].bbb)
+
+ // convert subblocks and collect results in s[:h] and s[h:]
+ h := len(s) - table[index].ndigits
+ r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+ s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+ }
}
- // preserve x, create local copy for use in repeated divisions
- q := nat(nil).set(x)
+ // having split any large blocks now process the remaining (small) block iteratively
+ i := len(s)
var r Word
-
- // convert
- if b == 10 { // hard-coding for 10 here speeds this up by 1.25x
+ if b == 10 {
+ // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
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
- }
+ q, r = q.divW(q, bb)
+ for j := 0; j < ndigits && i > 0; j++ {
+ i--
+ // avoid % computation since r%10 == r - int(r/10)*10;
+ // this appears to be faster for BenchmarkString10000Base10
+ // and smaller strings (but a bit slower for larger ones)
+ t := r / 10
+ s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+ r = t
}
}
} else {
for len(q) > 0 {
- // extract least significant group of digits
- q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
- if len(q) == 0 {
- // 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
+ // extract least significant, base bb "digit"
+ q, r = q.divW(q, bb)
+ for j := 0; j < ndigits && i > 0; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ }
+ }
+
+ // prepend high-order zeroes
+ zero := charset[0]
+ for i > 0 { // while need more leading zeroes
+ i--
+ s[i] = zero
+ }
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+ bbb nat // divisor
+ nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+ ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 [64]divisor // cached divisors for base 10
+var cacheLock sync.Mutex // protects cacheBase10
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+ return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+ // only compute table when recursive conversion is enabled and x is large
+ if leafSize == 0 || m <= leafSize {
+ return nil
+ }
+
+ // determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+ k := 1
+ for words := leafSize; words < m>>1 && k < len(cacheBase10); words <<= 1 {
+ k++
+ }
+
+ // create new table of divisors or extend and reuse existing table as appropriate
+ var table []divisor
+ var cached bool
+ switch b {
+ case 10:
+ table = cacheBase10[0:k] // reuse old table for this conversion
+ cached = true
+ default:
+ table = make([]divisor, k) // new table for this conversion
+ }
+
+ // extend table
+ if table[k-1].ndigits == 0 {
+ if cached {
+ cacheLock.Lock() // begin critical section
+ }
+
+ // add new entries as needed
+ var larger nat
+ for i := 0; i < k; i++ {
+ if table[i].ndigits == 0 {
+ if i == 0 {
+ table[i].bbb = nat(nil).expWW(bb, Word(leafSize))
+ table[i].ndigits = ndigits * leafSize
+ } else {
+ table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+ table[i].ndigits = 2 * table[i-1].ndigits
}
- } else {
- for j := 0; j < ndigits; j++ {
- i--
- s[i] = charset[r%b]
- r /= b
+
+ // optimization: exploit aggregated extra bits in macro blocks
+ larger = nat(nil).set(table[i].bbb)
+ for mulAddVWW(larger, larger, b, 0) == 0 {
+ table[i].bbb = table[i].bbb.set(larger)
+ table[i].ndigits++
}
+
+ table[i].nbits = table[i].bbb.bitLen()
}
}
+
+ if cached {
+ cacheLock.Unlock() // end critical section
+ }
}
- return string(s[i:])
+ return table
}
const deBruijn32 = 0x077CB531
@@ -920,9 +1064,11 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
return z.norm()
case 1:
if j >= n {
- n = j + 1
+ z = z.make(j + 1)
+ z[n:].clear()
+ } else {
+ z = z.make(n)
}
- z = z.make(n)
copy(z, x)
z[j] |= m
// no need to normalize
@@ -1049,12 +1195,16 @@ func (x nat) powersOfTwoDecompose() (q nat, k int) {
// 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 {
+ if alias(z, limit) {
+ z = nil // z is an alias for limit - cannot reuse
+ }
+ z = z.make(len(limit))
+
bitLengthOfMSW := uint(n % _W)
if bitLengthOfMSW == 0 {
bitLengthOfMSW = _W
}
mask := Word((1 << bitLengthOfMSW) - 1)
- z = z.make(len(limit))
for {
for i := range z {
@@ -1141,7 +1291,7 @@ func (z nat) expNN(x, y, m nat) nat {
}
}
- return z
+ return z.norm()
}
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
diff --git a/src/pkg/big/nat_test.go b/src/pkg/math/big/nat_test.go
index 71d086087..7f3f76dc3 100755..100644
--- a/src/pkg/big/nat_test.go
+++ b/src/pkg/math/big/nat_test.go
@@ -5,8 +5,7 @@
package big
import (
- "fmt"
- "os"
+ "io"
"strings"
"testing"
)
@@ -16,9 +15,9 @@ var cmpTests = []struct {
r int
}{
{nil, nil, 0},
- {nil, nat{}, 0},
- {nat{}, nil, 0},
- {nat{}, nat{}, 0},
+ {nil, nat(nil), 0},
+ {nat(nil), nil, 0},
+ {nat(nil), nat(nil), 0},
{nat{0}, nat{0}, 0},
{nat{0}, nat{1}, -1},
{nat{1}, nat{0}, 1},
@@ -231,7 +230,7 @@ var natScanTests = []struct {
x nat // expected nat
b int // expected base
ok bool // expected success
- next int // next character (or 0, if at EOF)
+ next rune // next character (or 0, if at EOF)
}{
// error: illegal base
{base: -1},
@@ -288,7 +287,7 @@ func TestScanBase(t *testing.T) {
t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
}
next, _, err := r.ReadRune()
- if err == os.EOF {
+ if err == io.EOF {
next = 0
err = nil
}
@@ -370,157 +369,152 @@ func BenchmarkScanPi(b *testing.B) {
}
}
-const (
- // 314**271
- // base 2: 2249 digits
- // base 8: 751 digits
- // base 10: 678 digits
- // base 16: 563 digits
- shortBase = 314
- shortExponent = 271
-
- // 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 BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
-func BenchmarkScanMedium10(b *testing.B) {
- ScanHelper(b, 10, mediumBase, mediumExponent)
-}
-
-func BenchmarkScanMedium16(b *testing.B) {
- ScanHelper(b, 16, mediumBase, mediumExponent)
-}
+func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
-func BenchmarkScanLong2(b *testing.B) {
- ScanHelper(b, 2, longBase, longExponent)
-}
+func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
-func BenchmarkScanLong8(b *testing.B) {
- ScanHelper(b, 8, longBase, longExponent)
-}
-
-func BenchmarkScanLong10(b *testing.B) {
- ScanHelper(b, 10, longBase, longExponent)
-}
+func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
-func BenchmarkScanLong16(b *testing.B) {
- ScanHelper(b, 16, longBase, longExponent)
-}
-
-func ScanHelper(b *testing.B, base int, xv, yv Word) {
+func ScanHelper(b *testing.B, base int, x, y Word) {
b.StopTimer()
- var x, y, z nat
- x = x.setWord(xv)
- y = y.setWord(yv)
- z = z.expNN(x, y, nil)
+ var z nat
+ z = z.expWW(x, y)
var s string
s = z.string(lowercaseDigits[0:base])
if t := toString(z, lowercaseDigits[0:base]); t != s {
- panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+ b.Fatalf("scanning: got %s; want %s", s, t)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
- x.scan(strings.NewReader(s), base)
+ z.scan(strings.NewReader(s), base)
}
}
-func BenchmarkStringShort2(b *testing.B) {
- StringHelper(b, 2, shortBase, shortExponent)
-}
-
-func BenchmarkStringShort8(b *testing.B) {
- StringHelper(b, 8, shortBase, shortExponent)
-}
+func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
-func BenchmarkStringShort10(b *testing.B) {
- StringHelper(b, 10, shortBase, shortExponent)
-}
+func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
-func BenchmarkStringShort16(b *testing.B) {
- StringHelper(b, 16, shortBase, shortExponent)
-}
+func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
-func BenchmarkStringMedium2(b *testing.B) {
- StringHelper(b, 2, mediumBase, mediumExponent)
-}
+func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
-func BenchmarkStringMedium8(b *testing.B) {
- StringHelper(b, 8, mediumBase, mediumExponent)
-}
+func StringHelper(b *testing.B, base int, x, y Word) {
+ b.StopTimer()
+ var z nat
+ z = z.expWW(x, y)
+ z.string(lowercaseDigits[0:base]) // warm divisor cache
+ b.StartTimer()
-func BenchmarkStringMedium10(b *testing.B) {
- StringHelper(b, 10, mediumBase, mediumExponent)
+ for i := 0; i < b.N; i++ {
+ _ = z.string(lowercaseDigits[0:base])
+ }
}
-func BenchmarkStringMedium16(b *testing.B) {
- StringHelper(b, 16, mediumBase, mediumExponent)
-}
+func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+ b.StopTimer()
+ originalLeafSize := leafSize
+ resetTable(cacheBase10[:])
+ leafSize = size
+ b.StartTimer()
-func BenchmarkStringLong2(b *testing.B) {
- StringHelper(b, 2, longBase, longExponent)
-}
+ for d := 1; d <= 10000; d *= 10 {
+ b.StopTimer()
+ var z nat
+ z = z.expWW(base, Word(d)) // build target number
+ _ = z.string(lowercaseDigits[0:base]) // warm divisor cache
+ b.StartTimer()
-func BenchmarkStringLong8(b *testing.B) {
- StringHelper(b, 8, longBase, longExponent)
-}
+ for i := 0; i < b.N; i++ {
+ _ = z.string(lowercaseDigits[0:base])
+ }
+ }
-func BenchmarkStringLong10(b *testing.B) {
- StringHelper(b, 10, longBase, longExponent)
+ b.StopTimer()
+ resetTable(cacheBase10[:])
+ leafSize = originalLeafSize
+ b.StartTimer()
}
-func BenchmarkStringLong16(b *testing.B) {
- StringHelper(b, 16, longBase, longExponent)
+func resetTable(table []divisor) {
+ if table != nil && table[0].bbb != nil {
+ for i := 0; i < len(table); i++ {
+ table[i].bbb = nil
+ table[i].nbits = 0
+ table[i].ndigits = 0
+ }
+ }
}
-func 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 TestStringPowers(t *testing.T) {
+ var b, p Word
+ for b = 2; b <= 16; b++ {
+ for p = 0; p <= 512; p++ {
+ x := nat(nil).expWW(b, p)
+ xs := x.string(lowercaseDigits[0:b])
+ xs2 := toString(x, lowercaseDigits[0:b])
+ if xs != xs2 {
+ t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+ }
+ }
+ if b >= 3 && testing.Short() {
+ break
+ }
}
}
diff --git a/src/pkg/big/rat.go b/src/pkg/math/big/rat.go
index 327b9bd9c..7bd83fc0f 100644
--- a/src/pkg/big/rat.go
+++ b/src/pkg/math/big/rat.go
@@ -8,16 +8,16 @@ package big
import (
"encoding/binary"
+ "errors"
"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.
+// A Rat represents a quotient a/b of arbitrary precision.
+// The zero value for a Rat represents the value 0.
type Rat struct {
a Int
- b nat
+ b nat // len(b) == 0 acts like b == 1
}
// NewRat creates a new Rat with numerator a and denominator b.
@@ -27,15 +27,25 @@ func NewRat(a, b int64) *Rat {
// SetFrac sets z to a/b and returns z.
func (z *Rat) SetFrac(a, b *Int) *Rat {
- z.a.Set(a)
z.a.neg = a.neg != b.neg
- z.b = z.b.set(b.abs)
+ babs := b.abs
+ if len(babs) == 0 {
+ panic("division by zero")
+ }
+ if &z.a == b || alias(z.a.abs, babs) {
+ babs = nat(nil).set(babs) // make a copy
+ }
+ z.a.abs = z.a.abs.set(a.abs)
+ z.b = z.b.set(babs)
return z.norm()
}
// SetFrac64 sets z to a/b and returns z.
func (z *Rat) SetFrac64(a, b int64) *Rat {
z.a.SetInt64(a)
+ if b == 0 {
+ panic("division by zero")
+ }
if b < 0 {
b = -b
z.a.neg = !z.a.neg
@@ -47,14 +57,55 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
// SetInt sets z to x (by making a copy of x) and returns z.
func (z *Rat) SetInt(x *Int) *Rat {
z.a.Set(x)
- z.b = z.b.setWord(1)
+ z.b = z.b.make(0)
return z
}
// SetInt64 sets z to x and returns z.
func (z *Rat) SetInt64(x int64) *Rat {
z.a.SetInt64(x)
- z.b = z.b.setWord(1)
+ z.b = z.b.make(0)
+ return z
+}
+
+// Set sets z to x (by making a copy of x) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+ if z != x {
+ z.a.Set(&x.a)
+ z.b = z.b.set(x.b)
+ }
+ return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+ z.Set(x)
+ z.a.neg = false
+ return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+ z.Set(x)
+ z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
+ return z
+}
+
+// Inv sets z to 1/x and returns z.
+func (z *Rat) Inv(x *Rat) *Rat {
+ if len(x.a.abs) == 0 {
+ panic("division by zero")
+ }
+ z.Set(x)
+ a := z.b
+ if len(a) == 0 {
+ a = a.setWord(1) // materialize numerator
+ }
+ b := z.a.abs
+ if b.cmp(natOne) == 0 {
+ b = b.make(0) // normalize denominator
+ }
+ z.a.abs, z.b = a, b // sign doesn't change
return z
}
@@ -70,21 +121,24 @@ func (x *Rat) Sign() int {
// IsInt returns true if the denominator of x is 1.
func (x *Rat) IsInt() bool {
- return len(x.b) == 1 && x.b[0] == 1
+ return len(x.b) == 0 || x.b.cmp(natOne) == 0
}
-// Num returns the numerator of z; it may be <= 0.
-// The result is a reference to z's numerator; it
-// may change if a new value is assigned to z.
-func (z *Rat) Num() *Int {
- return &z.a
+// Num returns the numerator of x; it may be <= 0.
+// The result is a reference to x's numerator; it
+// may change if a new value is assigned to x.
+func (x *Rat) Num() *Int {
+ return &x.a
}
-// 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}
+// Denom returns the denominator of x; it is always > 0.
+// The result is a reference to x's denominator; it
+// may change if a new value is assigned to x.
+func (x *Rat) Denom() *Int {
+ if len(x.b) == 0 {
+ return &Int{abs: nat{1}}
+ }
+ return &Int{abs: x.b}
}
func gcd(x, y nat) nat {
@@ -102,24 +156,47 @@ func gcd(x, y nat) nat {
}
func (z *Rat) norm() *Rat {
- f := gcd(z.a.abs, z.b)
- if len(z.a.abs) == 0 {
- // z == 0
- z.a.neg = false // normalize sign
- z.b = z.b.setWord(1)
- return z
- }
- if f.cmp(natOne) != 0 {
- z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f)
- z.b, _ = z.b.div(nil, z.b, f)
+ switch {
+ case len(z.a.abs) == 0:
+ // z == 0 - normalize sign and denominator
+ z.a.neg = false
+ z.b = z.b.make(0)
+ case len(z.b) == 0:
+ // z is normalized int - nothing to do
+ case z.b.cmp(natOne) == 0:
+ // z is int - normalize denominator
+ z.b = z.b.make(0)
+ default:
+ if f := gcd(z.a.abs, z.b); f.cmp(natOne) != 0 {
+ z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f)
+ z.b, _ = z.b.div(nil, z.b, f)
+ }
}
return z
}
-func mulNat(x *Int, y nat) *Int {
+// mulDenom sets z to the denominator product x*y (by taking into
+// account that 0 values for x or y must be interpreted as 1) and
+// returns z.
+func mulDenom(z, x, y nat) nat {
+ switch {
+ case len(x) == 0:
+ return z.set(y)
+ case len(y) == 0:
+ return z.set(x)
+ }
+ return z.mul(x, y)
+}
+
+// scaleDenom computes x*f.
+// If f == 0 (zero value of denominator), the result is (a copy of) x.
+func scaleDenom(x *Int, f nat) *Int {
var z Int
- z.abs = z.abs.mul(x.abs, y)
- z.neg = len(z.abs) > 0 && x.neg
+ if len(f) == 0 {
+ return z.Set(x)
+ }
+ z.abs = z.abs.mul(x.abs, f)
+ z.neg = x.neg
return &z
}
@@ -129,39 +206,32 @@ func mulNat(x *Int, y nat) *Int {
// 0 if x == y
// +1 if x > y
//
-func (x *Rat) Cmp(y *Rat) (r int) {
- return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b))
-}
-
-// Abs sets z to |x| (the absolute value of x) and returns z.
-func (z *Rat) Abs(x *Rat) *Rat {
- z.a.Abs(&x.a)
- z.b = z.b.set(x.b)
- return z
+func (x *Rat) Cmp(y *Rat) int {
+ return scaleDenom(&x.a, y.b).Cmp(scaleDenom(&y.a, x.b))
}
// Add sets z to the sum x+y and returns z.
func (z *Rat) Add(x, y *Rat) *Rat {
- a1 := mulNat(&x.a, y.b)
- a2 := mulNat(&y.a, x.b)
+ a1 := scaleDenom(&x.a, y.b)
+ a2 := scaleDenom(&y.a, x.b)
z.a.Add(a1, a2)
- z.b = z.b.mul(x.b, y.b)
+ z.b = mulDenom(z.b, x.b, y.b)
return z.norm()
}
// Sub sets z to the difference x-y and returns z.
func (z *Rat) Sub(x, y *Rat) *Rat {
- a1 := mulNat(&x.a, y.b)
- a2 := mulNat(&y.a, x.b)
+ a1 := scaleDenom(&x.a, y.b)
+ a2 := scaleDenom(&y.a, x.b)
z.a.Sub(a1, a2)
- z.b = z.b.mul(x.b, y.b)
+ z.b = mulDenom(z.b, x.b, y.b)
return z.norm()
}
// Mul sets z to the product x*y and returns z.
func (z *Rat) Mul(x, y *Rat) *Rat {
z.a.Mul(&x.a, &y.a)
- z.b = z.b.mul(x.b, y.b)
+ z.b = mulDenom(z.b, x.b, y.b)
return z.norm()
}
@@ -171,67 +241,53 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
if len(y.a.abs) == 0 {
panic("division by zero")
}
- a := mulNat(&x.a, y.b)
- b := mulNat(&y.a, x.b)
+ a := scaleDenom(&x.a, y.b)
+ b := scaleDenom(&y.a, x.b)
z.a.abs = a.abs
z.b = b.abs
z.a.neg = a.neg != b.neg
return z.norm()
}
-// Neg sets z to -x (by making a copy of x if necessary) and returns z.
-func (z *Rat) Neg(x *Rat) *Rat {
- z.a.Neg(&x.a)
- z.b = z.b.set(x.b)
- return z
-}
-
-// Set sets z to x (by making a copy of x if necessary) and returns z.
-func (z *Rat) Set(x *Rat) *Rat {
- z.a.Set(&x.a)
- z.b = z.b.set(x.b)
- return z
-}
-
-func ratTok(ch int) bool {
+func ratTok(ch rune) 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 {
+func (z *Rat) Scan(s fmt.ScanState, ch rune) 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")
+ return errors.New("Rat.Scan: invalid verb")
}
if _, ok := z.SetString(string(tok)); !ok {
- return os.NewError("Rat.Scan: invalid syntax")
+ return errors.New("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
-// optionally followed by an exponent. If the operation failed, the value of z
-// is undefined.
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
- return z, false
+ return nil, false
}
// check for a quotient
sep := strings.Index(s, "/")
if sep >= 0 {
if _, ok := z.a.SetString(s[0:sep], 10); !ok {
- return z, false
+ return nil, false
}
s = s[sep+1:]
- var err os.Error
+ var err error
if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil {
- return z, false
+ return nil, false
}
return z.norm(), true
}
@@ -244,10 +300,10 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if e >= 0 {
if e < sep {
// The E must come after the decimal point.
- return z, false
+ return nil, false
}
if _, ok := exp.SetString(s[e+1:], 10); !ok {
- return z, false
+ return nil, false
}
s = s[0:e]
}
@@ -257,67 +313,72 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
}
if _, ok := z.a.SetString(s, 10); !ok {
- return z, false
+ return nil, false
}
- powTen := nat{}.expNN(natTen, exp.abs, nil)
+ powTen := nat(nil).expNN(natTen, exp.abs, nil)
if exp.neg {
z.b = powTen
z.norm()
} else {
z.a.abs = z.a.abs.mul(z.a.abs, powTen)
- z.b = z.b.setWord(1)
+ z.b = z.b.make(0)
}
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.decimalString()
+func (x *Rat) String() string {
+ s := "/1"
+ if len(x.b) != 0 {
+ s = "/" + x.b.decimalString()
+ }
+ return x.a.String() + s
}
// RatString returns a string representation of z in the form "a/b" if b != 1,
// and in the form "a" if b == 1.
-func (z *Rat) RatString() string {
- if z.IsInt() {
- return z.a.String()
+func (x *Rat) RatString() string {
+ if x.IsInt() {
+ return x.a.String()
}
- return z.String()
+ return x.String()
}
// FloatString returns a string representation of z in decimal form with prec
// digits of precision after the decimal point and the last digit rounded.
-func (z *Rat) FloatString(prec int) string {
- if z.IsInt() {
- s := z.a.String()
+func (x *Rat) FloatString(prec int) string {
+ if x.IsInt() {
+ s := x.a.String()
if prec > 0 {
s += "." + strings.Repeat("0", prec)
}
return s
}
+ // x.b != 0
- q, r := nat{}.div(nat{}, z.a.abs, z.b)
+ q, r := nat(nil).div(nat(nil), x.a.abs, x.b)
p := natOne
if prec > 0 {
- p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil)
+ p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
}
r = r.mul(r, p)
- r, r2 := r.div(nat{}, r, z.b)
+ r, r2 := r.div(nat(nil), r, x.b)
// see if we need to round up
r2 = r2.add(r2, r2)
- if z.b.cmp(r2) <= 0 {
+ if x.b.cmp(r2) <= 0 {
r = r.add(r, natOne)
if r.cmp(p) >= 0 {
- q = nat{}.add(q, natOne)
- r = nat{}.sub(r, p)
+ q = nat(nil).add(q, natOne)
+ r = nat(nil).sub(r, p)
}
}
s := q.decimalString()
- if z.a.neg {
+ if x.a.neg {
s = "-" + s
}
@@ -334,19 +395,19 @@ func (z *Rat) FloatString(prec int) string {
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])
+func (x *Rat) GobEncode() ([]byte, error) {
+ buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+ i := x.b.bytes(buf)
+ j := x.a.abs.bytes(buf[0:i])
n := i - j
if int(uint32(n)) != n {
// this should never happen
- return nil, os.NewError("Rat.GobEncode: numerator too large")
+ return nil, errors.New("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 {
+ if x.a.neg {
b |= 1
}
buf[j] = b
@@ -354,13 +415,13 @@ func (z *Rat) GobEncode() ([]byte, os.Error) {
}
// GobDecode implements the gob.GobDecoder interface.
-func (z *Rat) GobDecode(buf []byte) os.Error {
+func (z *Rat) GobDecode(buf []byte) error {
if len(buf) == 0 {
- return os.NewError("Rat.GobDecode: no data")
+ return errors.New("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))
+ return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
}
const j = 1 + 4
i := j + binary.BigEndian.Uint32(buf[j-4:j])
diff --git a/src/pkg/big/rat_test.go b/src/pkg/math/big/rat_test.go
index dbc5bb6cc..f7f31ae1a 100644
--- a/src/pkg/big/rat_test.go
+++ b/src/pkg/math/big/rat_test.go
@@ -6,11 +6,51 @@ package big
import (
"bytes"
+ "encoding/gob"
"fmt"
- "gob"
"testing"
)
+func TestZeroRat(t *testing.T) {
+ var x, y, z Rat
+ y.SetFrac64(0, 42)
+
+ if x.Cmp(&y) != 0 {
+ t.Errorf("x and y should be both equal and zero")
+ }
+
+ if s := x.String(); s != "0/1" {
+ t.Errorf("got x = %s, want 0/1", s)
+ }
+
+ if s := x.RatString(); s != "0" {
+ t.Errorf("got x = %s, want 0", s)
+ }
+
+ z.Add(&x, &y)
+ if s := z.RatString(); s != "0" {
+ t.Errorf("got x+y = %s, want 0", s)
+ }
+
+ z.Sub(&x, &y)
+ if s := z.RatString(); s != "0" {
+ t.Errorf("got x-y = %s, want 0", s)
+ }
+
+ z.Mul(&x, &y)
+ if s := z.RatString(); s != "0" {
+ t.Errorf("got x*y = %s, want 0", s)
+ }
+
+ // check for division by zero
+ defer func() {
+ if s := recover(); s == nil || s.(string) != "division by zero" {
+ panic(s)
+ }
+ }()
+ z.Quo(&x, &y)
+}
+
var setStringTests = []struct {
in, out string
ok bool
@@ -50,8 +90,14 @@ func TestRatSetString(t *testing.T) {
for i, test := range setStringTests {
x, ok := new(Rat).SetString(test.in)
- if ok != test.ok || ok && x.RatString() != test.out {
- t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ if ok {
+ if !test.ok {
+ t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+ } else if x.RatString() != test.out {
+ t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+ }
+ } else if x != nil {
+ t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
}
}
}
@@ -66,7 +112,7 @@ func TestRatScan(t *testing.T) {
_, err := fmt.Fscanf(&buf, "%v", x)
if err == nil != test.ok {
if test.ok {
- t.Errorf("#%d error: %s", i, err.String())
+ t.Errorf("#%d error: %s", i, err)
} else {
t.Errorf("#%d expected error", i)
}
@@ -113,8 +159,10 @@ func TestFloatString(t *testing.T) {
func TestRatSign(t *testing.T) {
zero := NewRat(0, 1)
for _, a := range setStringTests {
- var x Rat
- x.SetString(a.in)
+ x, ok := new(Rat).SetString(a.in)
+ if !ok {
+ continue
+ }
s := x.Sign()
e := x.Cmp(zero)
if s != e {
@@ -153,29 +201,65 @@ func TestRatCmp(t *testing.T) {
func TestIsInt(t *testing.T) {
one := NewInt(1)
for _, a := range setStringTests {
- var x Rat
- x.SetString(a.in)
+ x, ok := new(Rat).SetString(a.in)
+ if !ok {
+ continue
+ }
i := x.IsInt()
e := x.Denom().Cmp(one) == 0
if i != e {
- t.Errorf("got %v; want %v for z = %v", i, e, &x)
+ t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
}
}
}
func TestRatAbs(t *testing.T) {
- zero := NewRat(0, 1)
+ zero := new(Rat)
for _, a := range setStringTests {
- var z Rat
- z.SetString(a.in)
- var e Rat
- e.Set(&z)
+ x, ok := new(Rat).SetString(a.in)
+ if !ok {
+ continue
+ }
+ e := new(Rat).Set(x)
if e.Cmp(zero) < 0 {
- e.Sub(zero, &e)
+ e.Sub(zero, e)
+ }
+ z := new(Rat).Abs(x)
+ if z.Cmp(e) != 0 {
+ t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
}
- z.Abs(&z)
- if z.Cmp(&e) != 0 {
- t.Errorf("got z = %v; want %v", &z, &e)
+ }
+}
+
+func TestRatNeg(t *testing.T) {
+ zero := new(Rat)
+ for _, a := range setStringTests {
+ x, ok := new(Rat).SetString(a.in)
+ if !ok {
+ continue
+ }
+ e := new(Rat).Sub(zero, x)
+ z := new(Rat).Neg(x)
+ if z.Cmp(e) != 0 {
+ t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
+ }
+ }
+}
+
+func TestRatInv(t *testing.T) {
+ zero := new(Rat)
+ for _, a := range setStringTests {
+ x, ok := new(Rat).SetString(a.in)
+ if !ok {
+ continue
+ }
+ if x.Cmp(zero) == 0 {
+ continue // avoid division by zero
+ }
+ e := new(Rat).SetFrac(x.Denom(), x.Num())
+ z := new(Rat).Inv(x)
+ if z.Cmp(e) != 0 {
+ t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
}
}
}
@@ -186,10 +270,10 @@ type ratBinArg struct {
}
func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
- x, _ := NewRat(0, 1).SetString(a.x)
- y, _ := NewRat(0, 1).SetString(a.y)
- z, _ := NewRat(0, 1).SetString(a.z)
- out := f(NewRat(0, 1), x, y)
+ x, _ := new(Rat).SetString(a.x)
+ y, _ := new(Rat).SetString(a.y)
+ z, _ := new(Rat).SetString(a.z)
+ out := f(new(Rat), x, y)
if out.Cmp(z) != 0 {
t.Errorf("%s #%d got %s want %s", name, i, out, z)
@@ -330,3 +414,43 @@ func TestRatGobEncoding(t *testing.T) {
}
}
}
+
+func TestIssue2379(t *testing.T) {
+ // 1) no aliasing
+ q := NewRat(3, 2)
+ x := new(Rat)
+ x.SetFrac(NewInt(3), NewInt(2))
+ if x.Cmp(q) != 0 {
+ t.Errorf("1) got %s want %s", x, q)
+ }
+
+ // 2) aliasing of numerator
+ x = NewRat(2, 3)
+ x.SetFrac(NewInt(3), x.Num())
+ if x.Cmp(q) != 0 {
+ t.Errorf("2) got %s want %s", x, q)
+ }
+
+ // 3) aliasing of denominator
+ x = NewRat(2, 3)
+ x.SetFrac(x.Denom(), NewInt(2))
+ if x.Cmp(q) != 0 {
+ t.Errorf("3) got %s want %s", x, q)
+ }
+
+ // 4) aliasing of numerator and denominator
+ x = NewRat(2, 3)
+ x.SetFrac(x.Denom(), x.Num())
+ if x.Cmp(q) != 0 {
+ t.Errorf("4) got %s want %s", x, q)
+ }
+
+ // 5) numerator and denominator are the same
+ q = NewRat(1, 1)
+ x = new(Rat)
+ n := NewInt(7)
+ x.SetFrac(n, n)
+ if x.Cmp(q) != 0 {
+ t.Errorf("5) got %s want %s", x, q)
+ }
+}
diff --git a/src/pkg/math/bits.go b/src/pkg/math/bits.go
index a1dca3ed6..1cf60ce7d 100644
--- a/src/pkg/math/bits.go
+++ b/src/pkg/math/bits.go
@@ -52,7 +52,7 @@ func IsInf(f float64, sign int) bool {
// satisfying x == y × 2**exp. It assumes x is finite and non-zero.
func normalize(x float64) (y float64, exp int) {
const SmallestNormal = 2.2250738585072014e-308 // 2**-1022
- if Fabs(x) < SmallestNormal {
+ if Abs(x) < SmallestNormal {
return x * (1 << 52), -52
}
return x, 0
diff --git a/src/pkg/math/cbrt.go b/src/pkg/math/cbrt.go
index d2b7e910b..8c43f0afb 100644
--- a/src/pkg/math/cbrt.go
+++ b/src/pkg/math/cbrt.go
@@ -33,11 +33,9 @@ func Cbrt(x float64) float64 {
C3 = 6.46502159e-02
C4 = 1.412333954e-01
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x == 0 || x != x || x < -MaxFloat64 || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 0):
+ case x == 0 || IsNaN(x) || IsInf(x, 0):
return x
}
sign := false
@@ -45,22 +43,21 @@ func Cbrt(x float64) float64 {
x = -x
sign = true
}
- // Reduce argument
- f, e := Frexp(x)
+ // Reduce argument and estimate cube root
+ f, e := Frexp(x) // 0.5 <= f < 1.0
m := e % 3
if m > 0 {
m -= 3
e -= m // e is multiple of 3
}
- f = Ldexp(f, m) // 0.125 <= f < 1.0
-
- // Estimate cube root
switch m {
case 0: // 0.5 <= f < 1.0
f = A1*f + A2 - A3/(A4+f)
- case -1: // 0.25 <= f < 0.5
+ case -1:
+ f *= 0.5 // 0.25 <= f < 0.5
f = B1*f + B2 - B3/(B4+f)
- default: // 0.125 <= f < 0.25
+ default: // m == -2
+ f *= 0.25 // 0.125 <= f < 0.25
f = C1*f + C2 - C3/(C4+f)
}
y := Ldexp(f, e/3) // e/3 = exponent of cube root
diff --git a/src/pkg/cmath/abs.go b/src/pkg/math/cmplx/abs.go
index f3199cad5..f3cd1073e 100644
--- a/src/pkg/cmath/abs.go
+++ b/src/pkg/math/cmplx/abs.go
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package cmath provides basic constants and mathematical functions for
+// Package cmplx provides basic constants and mathematical functions for
// complex numbers.
-package cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/asin.go b/src/pkg/math/cmplx/asin.go
index d6a3ca480..61880a257 100644
--- a/src/pkg/cmath/asin.go
+++ b/src/pkg/math/cmplx/asin.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 cmath
+package cmplx
import "math"
@@ -50,7 +50,7 @@ import "math"
// Asin returns the inverse sine of x.
func Asin(x complex128) complex128 {
if imag(x) == 0 {
- if math.Fabs(real(x)) > 1 {
+ if math.Abs(real(x)) > 1 {
return complex(math.Pi/2, 0) // DOMAIN error
}
return complex(math.Asin(real(x)), 0)
@@ -67,7 +67,7 @@ func Asin(x complex128) complex128 {
func Asinh(x complex128) complex128 {
// TODO check range
if imag(x) == 0 {
- if math.Fabs(real(x)) > 1 {
+ if math.Abs(real(x)) > 1 {
return complex(math.Pi/2, 0) // DOMAIN error
}
return complex(math.Asinh(real(x)), 0)
diff --git a/src/pkg/cmath/cmath_test.go b/src/pkg/math/cmplx/cmath_test.go
index 6a595b0a6..610ca8ceb 100644
--- a/src/pkg/cmath/cmath_test.go
+++ b/src/pkg/math/cmplx/cmath_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 cmath
+package cmplx
import (
"math"
diff --git a/src/pkg/cmath/conj.go b/src/pkg/math/cmplx/conj.go
index 776b57da7..34a4277c1 100644
--- a/src/pkg/cmath/conj.go
+++ b/src/pkg/math/cmplx/conj.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 cmath
+package cmplx
// Conj returns the complex conjugate of x.
func Conj(x complex128) complex128 { return complex(real(x), -imag(x)) }
diff --git a/src/pkg/cmath/exp.go b/src/pkg/math/cmplx/exp.go
index 64c1ef409..485ed2c78 100644
--- a/src/pkg/cmath/exp.go
+++ b/src/pkg/math/cmplx/exp.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/isinf.go b/src/pkg/math/cmplx/isinf.go
index f23d2dea7..d5a65b44b 100644
--- a/src/pkg/cmath/isinf.go
+++ b/src/pkg/math/cmplx/isinf.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/isnan.go b/src/pkg/math/cmplx/isnan.go
index 2063bb835..05d0cce63 100644
--- a/src/pkg/cmath/isnan.go
+++ b/src/pkg/math/cmplx/isnan.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/log.go b/src/pkg/math/cmplx/log.go
index 8e6964fee..881a064d8 100644
--- a/src/pkg/cmath/log.go
+++ b/src/pkg/math/cmplx/log.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/phase.go b/src/pkg/math/cmplx/phase.go
index 2d67aa34c..03cece8a5 100644
--- a/src/pkg/cmath/phase.go
+++ b/src/pkg/math/cmplx/phase.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/polar.go b/src/pkg/math/cmplx/polar.go
index 033676acc..9b192bc62 100644
--- a/src/pkg/cmath/polar.go
+++ b/src/pkg/math/cmplx/polar.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 cmath
+package cmplx
// Polar returns the absolute value r and phase θ of x,
// such that x = r * e**θi.
diff --git a/src/pkg/cmath/pow.go b/src/pkg/math/cmplx/pow.go
index 68e1207c6..4dbc58398 100644
--- a/src/pkg/cmath/pow.go
+++ b/src/pkg/math/cmplx/pow.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/rect.go b/src/pkg/math/cmplx/rect.go
index b955f0bf7..bf94d787e 100644
--- a/src/pkg/cmath/rect.go
+++ b/src/pkg/math/cmplx/rect.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 cmath
+package cmplx
import "math"
diff --git a/src/pkg/cmath/sin.go b/src/pkg/math/cmplx/sin.go
index 8900ecdde..2c57536ed 100644
--- a/src/pkg/cmath/sin.go
+++ b/src/pkg/math/cmplx/sin.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 cmath
+package cmplx
import "math"
@@ -122,7 +122,7 @@ func Cosh(x complex128) complex128 {
// calculate sinh and cosh
func sinhcosh(x float64) (sh, ch float64) {
- if math.Fabs(x) <= 0.5 {
+ if math.Abs(x) <= 0.5 {
return math.Sinh(x), math.Cosh(x)
}
e := math.Exp(x)
diff --git a/src/pkg/cmath/sqrt.go b/src/pkg/math/cmplx/sqrt.go
index e77a9b9df..179b5396a 100644
--- a/src/pkg/cmath/sqrt.go
+++ b/src/pkg/math/cmplx/sqrt.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 cmath
+package cmplx
import "math"
@@ -76,7 +76,7 @@ func Sqrt(x complex128) complex128 {
b := imag(x)
var scale float64
// Rescale to avoid internal overflow or underflow.
- if math.Fabs(a) > 4 || math.Fabs(b) > 4 {
+ if math.Abs(a) > 4 || math.Abs(b) > 4 {
a *= 0.25
b *= 0.25
scale = 2
@@ -89,11 +89,11 @@ func Sqrt(x complex128) complex128 {
var t float64
if a > 0 {
t = math.Sqrt(0.5*r + 0.5*a)
- r = scale * math.Fabs((0.5*b)/t)
+ r = scale * math.Abs((0.5*b)/t)
t *= scale
} else {
r = math.Sqrt(0.5*r - 0.5*a)
- t = scale * math.Fabs((0.5*b)/r)
+ t = scale * math.Abs((0.5*b)/r)
r *= scale
}
if b < 0 {
diff --git a/src/pkg/cmath/tan.go b/src/pkg/math/cmplx/tan.go
index 94b517521..9485315d8 100644
--- a/src/pkg/cmath/tan.go
+++ b/src/pkg/math/cmplx/tan.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 cmath
+package cmplx
import "math"
@@ -58,7 +58,7 @@ import "math"
// Tan returns the tangent of x.
func Tan(x complex128) complex128 {
d := math.Cos(2*real(x)) + math.Cosh(2*imag(x))
- if math.Fabs(d) < 0.25 {
+ if math.Abs(d) < 0.25 {
d = tanSeries(x)
}
if d == 0 {
@@ -109,8 +109,8 @@ func reducePi(x float64) float64 {
// Taylor series expansion for cosh(2y) - cos(2x)
func tanSeries(z complex128) float64 {
const MACHEP = 1.0 / (1 << 53)
- x := math.Fabs(2 * real(z))
- y := math.Fabs(2 * imag(z))
+ x := math.Abs(2 * real(z))
+ y := math.Abs(2 * imag(z))
x = reducePi(x)
x = x * x
y = y * y
@@ -139,7 +139,7 @@ func tanSeries(z complex128) float64 {
t = y2 - x2
t /= f
d += t
- if math.Fabs(t/d) <= MACHEP {
+ if math.Abs(t/d) <= MACHEP {
break
}
}
@@ -174,7 +174,7 @@ func tanSeries(z complex128) float64 {
// Cot returns the cotangent of x.
func Cot(x complex128) complex128 {
d := math.Cosh(2*imag(x)) - math.Cos(2*real(x))
- if math.Fabs(d) < 0.25 {
+ if math.Abs(d) < 0.25 {
d = tanSeries(x)
}
if d == 0 {
diff --git a/src/pkg/math/const.go b/src/pkg/math/const.go
index a108d3e29..f1247c383 100644
--- a/src/pkg/math/const.go
+++ b/src/pkg/math/const.go
@@ -6,7 +6,7 @@
package math
// Mathematical constants.
-// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx
+// Reference: http://oeis.org/Axxxxxx
const (
E = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
@@ -27,11 +27,11 @@ const (
// Max is the largest finite value representable by the type.
// SmallestNonzero is the smallest positive, non-zero value representable by the type.
const (
- MaxFloat32 = 3.40282346638528859811704183484516925440e+38 /* 2**127 * (2**24 - 1) / 2**23 */
- SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 /* 1 / 2**(127 - 1 + 23) */
+ MaxFloat32 = 3.40282346638528859811704183484516925440e+38 // 2**127 * (2**24 - 1) / 2**23
+ SmallestNonzeroFloat32 = 1.401298464324817070923729583289916131280e-45 // 1 / 2**(127 - 1 + 23)
- MaxFloat64 = 1.797693134862315708145274237317043567981e+308 /* 2**1023 * (2**53 - 1) / 2**52 */
- SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 /* 1 / 2**(1023 - 1 + 52) */
+ MaxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+ SmallestNonzeroFloat64 = 4.940656458412465441765687928682213723651e-324 // 1 / 2**(1023 - 1 + 52)
)
// Integer limit values.
@@ -49,5 +49,3 @@ const (
MaxUint32 = 1<<32 - 1
MaxUint64 = 1<<64 - 1
)
-
-// BUG(rsc): The manual should define the special cases for all of these functions.
diff --git a/src/pkg/math/dim.go b/src/pkg/math/dim.go
new file mode 100644
index 000000000..1c634d415
--- /dev/null
+++ b/src/pkg/math/dim.go
@@ -0,0 +1,72 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Dim returns the maximum of x-y or 0.
+//
+// Special cases are:
+// Dim(+Inf, +Inf) = NaN
+// Dim(-Inf, -Inf) = NaN
+// Dim(x, NaN) = Dim(NaN, x) = NaN
+func Dim(x, y float64) float64
+
+func dim(x, y float64) float64 {
+ return max(x-y, 0)
+}
+
+// Max returns the larger of x or y.
+//
+// Special cases are:
+// Max(x, +Inf) = Max(+Inf, x) = +Inf
+// Max(x, NaN) = Max(NaN, x) = NaN
+// Max(+0, ±0) = Max(±0, +0) = +0
+// Max(-0, -0) = -0
+func Max(x, y float64) float64
+
+func max(x, y float64) float64 {
+ // special cases
+ switch {
+ case IsInf(x, 1) || IsInf(y, 1):
+ return Inf(1)
+ case IsNaN(x) || IsNaN(y):
+ return NaN()
+ case x == 0 && x == y:
+ if Signbit(x) {
+ return y
+ }
+ return x
+ }
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// Min returns the smaller of x or y.
+//
+// Special cases are:
+// Min(x, -Inf) = Min(-Inf, x) = -Inf
+// Min(x, NaN) = Min(NaN, x) = NaN
+// Min(-0, ±0) = Min(±0, -0) = -0
+func Min(x, y float64) float64
+
+func min(x, y float64) float64 {
+ // special cases
+ switch {
+ case IsInf(x, -1) || IsInf(y, -1):
+ return Inf(-1)
+ case IsNaN(x) || IsNaN(y):
+ return NaN()
+ case x == 0 && x == y:
+ if Signbit(x) {
+ return x
+ }
+ return y
+ }
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/src/pkg/math/dim_386.s b/src/pkg/math/dim_386.s
new file mode 100644
index 000000000..6a31c7540
--- /dev/null
+++ b/src/pkg/math/dim_386.s
@@ -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.
+
+TEXT ·Dim(SB),7,$0
+ JMP ·dim(SB)
+
+TEXT ·Max(SB),7,$0
+ JMP ·max(SB)
+
+TEXT ·Min(SB),7,$0
+ JMP ·min(SB)
diff --git a/src/pkg/math/dim_amd64.s b/src/pkg/math/dim_amd64.s
new file mode 100644
index 000000000..c867db553
--- /dev/null
+++ b/src/pkg/math/dim_amd64.s
@@ -0,0 +1,142 @@
+// 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.
+
+#define PosInf 0x7FF0000000000000
+#define NaN 0x7FF0000000000001
+#define NegInf 0xFFF0000000000000
+
+// func Dim(x, y float64) float64
+TEXT ·Dim(SB),7,$0
+ // (+Inf, +Inf) special case
+ MOVQ x+0(FP), BX
+ MOVQ y+8(FP), CX
+ MOVQ $PosInf, AX
+ CMPQ AX, BX
+ JNE dim2
+ CMPQ AX, CX
+ JEQ bothInf
+dim2: // (-Inf, -Inf) special case
+ MOVQ $NegInf, AX
+ CMPQ AX, BX
+ JNE dim3
+ CMPQ AX, CX
+ JEQ bothInf
+dim3: // (NaN, x) or (x, NaN)
+ MOVQ $~(1<<63), DX
+ MOVQ $NaN, AX
+ ANDQ DX, BX // x = |x|
+ CMPQ AX, BX
+ JLE isDimNaN
+ ANDQ DX, CX // y = |y|
+ CMPQ AX, CX
+ JLE isDimNaN
+
+ MOVSD x+0(FP), X0
+ SUBSD y+8(FP), X0
+ MOVSD $(0.0), X1
+ MAXSD X1, X0
+ MOVSD X0, r+16(FP)
+ RET
+bothInf: // Dim(-Inf, -Inf) or Dim(+Inf, +Inf)
+ MOVQ $NaN, AX
+isDimNaN:
+ MOVQ AX, r+16(FP)
+ RET
+
+// func ·Max(x, y float64) float64
+TEXT ·Max(SB),7,$0
+ // +Inf special cases
+ MOVQ $PosInf, AX
+ MOVQ x+0(FP), R8
+ CMPQ AX, R8
+ JEQ isPosInf
+ MOVQ y+8(FP), R9
+ CMPQ AX, R9
+ JEQ isPosInf
+ // NaN special cases
+ MOVQ $~(1<<63), DX // bit mask
+ MOVQ $NaN, AX
+ MOVQ R8, BX
+ ANDQ DX, BX // x = |x|
+ CMPQ AX, BX
+ JLE isMaxNaN
+ MOVQ R9, CX
+ ANDQ DX, CX // y = |y|
+ CMPQ AX, CX
+ JLE isMaxNaN
+ // ±0 special cases
+ ORQ CX, BX
+ JEQ isMaxZero
+
+ MOVQ R8, X0
+ MOVQ R9, X1
+ MAXSD X1, X0
+ MOVSD X0, r+16(FP)
+ RET
+isMaxNaN: // return NaN
+isPosInf: // return +Inf
+ MOVQ AX, r+16(FP)
+ RET
+isMaxZero:
+ MOVQ $(1<<63), AX // -0.0
+ CMPQ AX, R8
+ JEQ +3(PC)
+ MOVQ R8, r+16(FP) // return 0
+ RET
+ MOVQ R9, r+16(FP) // return other 0
+ RET
+
+/*
+ MOVQ $0, AX
+ CMPQ AX, R8
+ JNE +3(PC)
+ MOVQ R8, r+16(FP) // return 0
+ RET
+ MOVQ R9, r+16(FP) // return other 0
+ RET
+*/
+
+// func Min(x, y float64) float64
+TEXT ·Min(SB),7,$0
+ // -Inf special cases
+ MOVQ $NegInf, AX
+ MOVQ x+0(FP), R8
+ CMPQ AX, R8
+ JEQ isNegInf
+ MOVQ y+8(FP), R9
+ CMPQ AX, R9
+ JEQ isNegInf
+ // NaN special cases
+ MOVQ $~(1<<63), DX
+ MOVQ $NaN, AX
+ MOVQ R8, BX
+ ANDQ DX, BX // x = |x|
+ CMPQ AX, BX
+ JLE isMinNaN
+ MOVQ R9, CX
+ ANDQ DX, CX // y = |y|
+ CMPQ AX, CX
+ JLE isMinNaN
+ // ±0 special cases
+ ORQ CX, BX
+ JEQ isMinZero
+
+ MOVQ R8, X0
+ MOVQ R9, X1
+ MINSD X1, X0
+ MOVSD X0, r+16(FP)
+ RET
+isMinNaN: // return NaN
+isNegInf: // return -Inf
+ MOVQ AX, r+16(FP)
+ RET
+isMinZero:
+ MOVQ $(1<<63), AX // -0.0
+ CMPQ AX, R8
+ JEQ +3(PC)
+ MOVQ R9, r+16(FP) // return other 0
+ RET
+ MOVQ R8, r+16(FP) // return -0
+ RET
+
diff --git a/src/pkg/go/build/cmdtest/main.go b/src/pkg/math/dim_arm.s
index bed4f485a..304fa78cd 100644
--- a/src/pkg/go/build/cmdtest/main.go
+++ b/src/pkg/math/dim_arm.s
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package main
+TEXT ·Dim(SB),7,$0
+ B ·dim(SB)
-import "go/build/pkgtest"
+TEXT ·Min(SB),7,$0
+ B ·min(SB)
-func main() {
- pkgtest.Foo()
- print(int(pkgtest.Sqrt(9)))
-}
+TEXT ·Max(SB),7,$0
+ B ·max(SB)
diff --git a/src/pkg/math/erf.go b/src/pkg/math/erf.go
index 6d3d9b7c5..c6f32bdbe 100644
--- a/src/pkg/math/erf.go
+++ b/src/pkg/math/erf.go
@@ -191,14 +191,12 @@ func Erf(x float64) float64 {
Small = 1.0 / (1 << 28) // 2**-28
)
// special cases
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
switch {
- case x != x: // IsNaN(x):
+ case IsNaN(x):
return NaN()
- case x > MaxFloat64: // IsInf(x, 1):
+ case IsInf(x, 1):
return 1
- case x < -MaxFloat64: // IsInf(x, -1):
+ case IsInf(x, -1):
return -1
}
sign := false
@@ -250,7 +248,7 @@ func Erf(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
}
- z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign {
return r/x - 1
@@ -267,14 +265,12 @@ func Erf(x float64) float64 {
func Erfc(x float64) float64 {
const Tiny = 1.0 / (1 << 56) // 2**-56
// special cases
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
switch {
- case x != x: // IsNaN(x):
+ case IsNaN(x):
return NaN()
- case x > MaxFloat64: // IsInf(x, 1):
+ case IsInf(x, 1):
return 0
- case x < -MaxFloat64: // IsInf(x, -1):
+ case IsInf(x, -1):
return 2
}
sign := false
@@ -325,7 +321,7 @@ func Erfc(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
}
- z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign {
return 2 - r/x
diff --git a/src/pkg/math/exp.go b/src/pkg/math/exp.go
index c519c2cb6..f31585fa7 100644
--- a/src/pkg/math/exp.go
+++ b/src/pkg/math/exp.go
@@ -11,4 +11,181 @@ package math
// Exp(NaN) = NaN
// Very large values overflow to 0 or +Inf.
// Very small values underflow to 1.
-func Exp(x float64) float64 { return expGo(x) }
+func Exp(x float64) float64
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// exp(x)
+// Returns the exponential of x.
+//
+// Method
+// 1. Argument reduction:
+// Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+// Given x, find r and integer k such that
+//
+// x = k*ln2 + r, |r| <= 0.5*ln2.
+//
+// Here r will be represented as r = hi-lo for better
+// accuracy.
+//
+// 2. Approximation of exp(r) by a special rational function on
+// the interval [0,0.34658]:
+// Write
+// R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+// We use a special Remes algorithm on [0,0.34658] to generate
+// a polynomial of degree 5 to approximate R. The maximum error
+// of this polynomial approximation is bounded by 2**-59. In
+// other words,
+// R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+// (where z=r*r, and the values of P1 to P5 are listed below)
+// and
+// | 5 | -59
+// | 2.0+P1*z+...+P5*z - R(z) | <= 2
+// | |
+// The computation of exp(r) thus becomes
+// 2*r
+// exp(r) = 1 + -------
+// R - r
+// r*R1(r)
+// = 1 + r + ----------- (for better accuracy)
+// 2 - R1(r)
+// where
+// 2 4 10
+// R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+//
+// 3. Scale back to obtain exp(x):
+// From step 1, we have
+// exp(x) = 2**k * exp(r)
+//
+// Special cases:
+// exp(INF) is INF, exp(NaN) is NaN;
+// exp(-INF) is 0, and
+// for finite argument, only exp(0)=1 is exact.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Misc. info.
+// For IEEE double
+// if x > 7.09782712893383973096e+02 then exp(x) overflow
+// if x < -7.45133219101941108420e+02 then exp(x) underflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+func exp(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+ Log2e = 1.44269504088896338700e+00
+
+ Overflow = 7.09782712893383973096e+02
+ Underflow = -7.45133219101941108420e+02
+ NearZero = 1.0 / (1 << 28) // 2**-28
+ )
+
+ // special cases
+ switch {
+ case IsNaN(x) || IsInf(x, 1):
+ return x
+ case IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ case -NearZero < x && x < NearZero:
+ return 1 + x
+ }
+
+ // reduce; computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x < 0:
+ k = int(Log2e*x - 0.5)
+ case x > 0:
+ k = int(Log2e*x + 0.5)
+ }
+ hi := x - float64(k)*Ln2Hi
+ lo := float64(k) * Ln2Lo
+
+ // compute
+ return expmulti(hi, lo, k)
+}
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func Exp2(x float64) float64
+
+func exp2(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+
+ Overflow = 1.0239999999999999e+03
+ Underflow = -1.0740e+03
+ )
+
+ // special cases
+ switch {
+ case IsNaN(x) || IsInf(x, 1):
+ return x
+ case IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ }
+
+ // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2.
+ // computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x > 0:
+ k = int(x + 0.5)
+ case x < 0:
+ k = int(x - 0.5)
+ }
+ t := x - float64(k)
+ hi := t * Ln2Hi
+ lo := -t * Ln2Lo
+
+ // compute
+ return expmulti(hi, lo, k)
+}
+
+// exp1 returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2.
+func expmulti(hi, lo float64, k int) float64 {
+ const (
+ P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */
+ P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */
+ P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */
+ P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */
+ P5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */
+ )
+
+ r := hi - lo
+ t := r * r
+ c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
+ y := 1 - ((lo - (r*c)/(2-c)) - hi)
+ // TODO(rsc): make sure Ldexp can handle boundary k
+ return Ldexp(y, k)
+}
diff --git a/src/pkg/math/exp2.go b/src/pkg/math/exp2.go
deleted file mode 100644
index 1cface9d3..000000000
--- a/src/pkg/math/exp2.go
+++ /dev/null
@@ -1,10 +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 math
-
-// Exp2 returns 2**x, the base-2 exponential of x.
-//
-// Special cases are the same as Exp.
-func Exp2(x float64) float64 { return exp2Go(x) }
diff --git a/src/pkg/math/exp2_amd64.s b/src/pkg/math/exp2_amd64.s
new file mode 100644
index 000000000..7bb44f78a
--- /dev/null
+++ b/src/pkg/math/exp2_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Exp2(SB),7,$0
+ JMP ·exp2(SB)
diff --git a/src/pkg/math/exp2_arm.s b/src/pkg/math/exp2_arm.s
new file mode 100644
index 000000000..41b63bfaf
--- /dev/null
+++ b/src/pkg/math/exp2_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Exp2(SB),7,$0
+ B ·exp2(SB)
diff --git a/src/pkg/math/exp2_decl.go b/src/pkg/math/exp2_decl.go
deleted file mode 100644
index cff741174..000000000
--- a/src/pkg/math/exp2_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Exp2(x float64) float64
diff --git a/src/pkg/math/exp_arm.s b/src/pkg/math/exp_arm.s
new file mode 100644
index 000000000..a95fa9342
--- /dev/null
+++ b/src/pkg/math/exp_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Exp(SB),7,$0
+ B ·exp(SB)
diff --git a/src/pkg/math/exp_port.go b/src/pkg/math/exp_port.go
deleted file mode 100644
index 618c31a5d..000000000
--- a/src/pkg/math/exp_port.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 math
-
-// The original C code, the long comment, and the constants
-// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
-// and came with this notice. The go code is a simplified
-// version of the original C.
-//
-// ====================================================
-// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
-//
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
-//
-//
-// exp(x)
-// Returns the exponential of x.
-//
-// Method
-// 1. Argument reduction:
-// Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
-// Given x, find r and integer k such that
-//
-// x = k*ln2 + r, |r| <= 0.5*ln2.
-//
-// Here r will be represented as r = hi-lo for better
-// accuracy.
-//
-// 2. Approximation of exp(r) by a special rational function on
-// the interval [0,0.34658]:
-// Write
-// R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
-// We use a special Remes algorithm on [0,0.34658] to generate
-// a polynomial of degree 5 to approximate R. The maximum error
-// of this polynomial approximation is bounded by 2**-59. In
-// other words,
-// R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
-// (where z=r*r, and the values of P1 to P5 are listed below)
-// and
-// | 5 | -59
-// | 2.0+P1*z+...+P5*z - R(z) | <= 2
-// | |
-// The computation of exp(r) thus becomes
-// 2*r
-// exp(r) = 1 + -------
-// R - r
-// r*R1(r)
-// = 1 + r + ----------- (for better accuracy)
-// 2 - R1(r)
-// where
-// 2 4 10
-// R1(r) = r - (P1*r + P2*r + ... + P5*r ).
-//
-// 3. Scale back to obtain exp(x):
-// From step 1, we have
-// exp(x) = 2**k * exp(r)
-//
-// Special cases:
-// exp(INF) is INF, exp(NaN) is NaN;
-// exp(-INF) is 0, and
-// for finite argument, only exp(0)=1 is exact.
-//
-// Accuracy:
-// according to an error analysis, the error is always less than
-// 1 ulp (unit in the last place).
-//
-// Misc. info.
-// For IEEE double
-// if x > 7.09782712893383973096e+02 then exp(x) overflow
-// if x < -7.45133219101941108420e+02 then exp(x) underflow
-//
-// Constants:
-// The hexadecimal values are the intended ones for the following
-// constants. The decimal values may be used, provided that the
-// compiler will convert from decimal to binary accurately enough
-// to produce the hexadecimal values shown.
-
-// Exp returns e**x, the base-e exponential of x.
-//
-// Special cases are:
-// Exp(+Inf) = +Inf
-// Exp(NaN) = NaN
-// Very large values overflow to 0 or +Inf.
-// Very small values underflow to 1.
-func expGo(x float64) float64 {
- const (
- Ln2Hi = 6.93147180369123816490e-01
- Ln2Lo = 1.90821492927058770002e-10
- Log2e = 1.44269504088896338700e+00
-
- Overflow = 7.09782712893383973096e+02
- Underflow = -7.45133219101941108420e+02
- NearZero = 1.0 / (1 << 28) // 2**-28
- )
-
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
- // special cases
- switch {
- case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
- return x
- case x < -MaxFloat64: // IsInf(x, -1):
- return 0
- case x > Overflow:
- return Inf(1)
- case x < Underflow:
- return 0
- case -NearZero < x && x < NearZero:
- return 1 + x
- }
-
- // reduce; computed as r = hi - lo for extra precision.
- var k int
- switch {
- case x < 0:
- k = int(Log2e*x - 0.5)
- case x > 0:
- k = int(Log2e*x + 0.5)
- }
- hi := x - float64(k)*Ln2Hi
- lo := float64(k) * Ln2Lo
-
- // compute
- return exp(hi, lo, k)
-}
-
-// Exp2 returns 2**x, the base-2 exponential of x.
-//
-// Special cases are the same as Exp.
-func exp2Go(x float64) float64 {
- const (
- Ln2Hi = 6.93147180369123816490e-01
- Ln2Lo = 1.90821492927058770002e-10
-
- Overflow = 1.0239999999999999e+03
- Underflow = -1.0740e+03
- )
-
- // TODO: remove manual inlining of IsNaN and IsInf
- // when compiler does it for us
- // special cases
- switch {
- case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
- return x
- case x < -MaxFloat64: // IsInf(x, -1):
- return 0
- case x > Overflow:
- return Inf(1)
- case x < Underflow:
- return 0
- }
-
- // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2.
- // computed as r = hi - lo for extra precision.
- var k int
- switch {
- case x > 0:
- k = int(x + 0.5)
- case x < 0:
- k = int(x - 0.5)
- }
- t := x - float64(k)
- hi := t * Ln2Hi
- lo := -t * Ln2Lo
-
- // compute
- return exp(hi, lo, k)
-}
-
-// exp returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2.
-func exp(hi, lo float64, k int) float64 {
- const (
- P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */
- P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */
- P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */
- P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */
- P5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */
- )
-
- r := hi - lo
- t := r * r
- c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
- y := 1 - ((lo - (r*c)/(2-c)) - hi)
- // TODO(rsc): make sure Ldexp can handle boundary k
- return Ldexp(y, k)
-}
diff --git a/src/pkg/math/exp_test.go b/src/pkg/math/exp_test.go
deleted file mode 100644
index 7381fd5ad..000000000
--- a/src/pkg/math/exp_test.go
+++ /dev/null
@@ -1,10 +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 math
-
-// Make expGo and exp2Go available for testing.
-
-func ExpGo(x float64) float64 { return expGo(x) }
-func Exp2Go(x float64) float64 { return exp2Go(x) }
diff --git a/src/pkg/math/expm1.go b/src/pkg/math/expm1.go
index e9f833140..8f56e15cc 100644
--- a/src/pkg/math/expm1.go
+++ b/src/pkg/math/expm1.go
@@ -121,7 +121,9 @@ package math
// Expm1(-Inf) = -1
// Expm1(NaN) = NaN
// Very large values overflow to -1 or +Inf.
-func Expm1(x float64) float64 {
+func Expm1(x float64) float64
+
+func expm1(x float64) float64 {
const (
Othreshold = 7.09782712893383973096e+02 // 0x40862E42FEFA39EF
Ln2X56 = 3.88162421113569373274e+01 // 0x4043687a9f1af2b1
@@ -140,12 +142,10 @@ func Expm1(x float64) float64 {
)
// special cases
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
switch {
- case x > MaxFloat64 || x != x: // IsInf(x, 1) || IsNaN(x):
+ case IsInf(x, 1) || IsNaN(x):
return x
- case x < -MaxFloat64: // IsInf(x, -1):
+ case IsInf(x, -1):
return -1
}
diff --git a/src/pkg/math/expm1_amd64.s b/src/pkg/math/expm1_amd64.s
new file mode 100644
index 000000000..a3b09e2f6
--- /dev/null
+++ b/src/pkg/math/expm1_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Expm1(SB),7,$0
+ JMP ·expm1(SB)
diff --git a/src/pkg/math/expm1_arm.s b/src/pkg/math/expm1_arm.s
new file mode 100644
index 000000000..e4e40441b
--- /dev/null
+++ b/src/pkg/math/expm1_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Expm1(SB),7,$0
+ B ·expm1(SB)
diff --git a/src/pkg/math/expm1_decl.go b/src/pkg/math/expm1_decl.go
deleted file mode 100644
index 4dab70bc9..000000000
--- a/src/pkg/math/expm1_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Expm1(x float64) float64
diff --git a/src/pkg/math/export_test.go b/src/pkg/math/export_test.go
new file mode 100644
index 000000000..02992d70e
--- /dev/null
+++ b/src/pkg/math/export_test.go
@@ -0,0 +1,11 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Export internal functions for testing.
+var ExpGo = exp
+var Exp2Go = exp2
+var HypotGo = hypot
+var SqrtGo = sqrt
diff --git a/src/pkg/math/fabs_decl.go b/src/pkg/math/fabs_decl.go
deleted file mode 100644
index 9071f49d8..000000000
--- a/src/pkg/math/fabs_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Fabs(x float64) float64
diff --git a/src/pkg/math/fdim.go b/src/pkg/math/fdim.go
deleted file mode 100644
index 18993137a..000000000
--- a/src/pkg/math/fdim.go
+++ /dev/null
@@ -1,29 +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 math
-
-// Fdim returns the maximum of x-y or 0.
-func Fdim(x, y float64) float64 {
- if x > y {
- return x - y
- }
- return 0
-}
-
-// Fmax returns the larger of x or y.
-func Fmax(x, y float64) float64 {
- if x > y {
- return x
- }
- return y
-}
-
-// Fmin returns the smaller of x or y.
-func Fmin(x, y float64) float64 {
- if x < y {
- return x
- }
- return y
-}
diff --git a/src/pkg/math/fdim_amd64.s b/src/pkg/math/fdim_amd64.s
deleted file mode 100644
index 1f45ef8b9..000000000
--- a/src/pkg/math/fdim_amd64.s
+++ /dev/null
@@ -1,26 +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.
-
-// func Fdim(x, y float64) float64
-TEXT ·Fdim(SB),7,$0
- MOVSD x+0(FP), X0
- SUBSD y+8(FP), X0
- MOVSD $(0.0), X1
- MAXSD X1, X0
- MOVSD X0, r+16(FP)
- RET
-
-// func Fmax(x, y float64) float64
-TEXT ·Fmax(SB),7,$0
- MOVSD x+0(FP), X0
- MAXSD y+8(FP), X0
- MOVSD X0, r+16(FP)
- RET
-
-// func Fmin(x, y float64) float64
-TEXT ·Fmin(SB),7,$0
- MOVSD x+0(FP), X0
- MINSD y+8(FP), X0
- MOVSD X0, r+16(FP)
- RET
diff --git a/src/pkg/math/fdim_decl.go b/src/pkg/math/fdim_decl.go
deleted file mode 100644
index 88dea3de4..000000000
--- a/src/pkg/math/fdim_decl.go
+++ /dev/null
@@ -1,9 +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 math
-
-func Fdim(x, y float64) float64
-func Fmax(x, y float64) float64
-func Fmin(x, y float64) float64
diff --git a/src/pkg/math/floor.go b/src/pkg/math/floor.go
index babbf645f..9d30629c5 100644
--- a/src/pkg/math/floor.go
+++ b/src/pkg/math/floor.go
@@ -7,13 +7,13 @@ package math
// Floor returns the greatest integer value less than or equal to x.
//
// Special cases are:
-// Floor(+Inf) = +Inf
-// Floor(-Inf) = -Inf
+// Floor(±0) = ±0
+// Floor(±Inf) = ±Inf
// Floor(NaN) = NaN
-func Floor(x float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
- if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+func Floor(x float64) float64
+
+func floor(x float64) float64 {
+ if x == 0 || IsNaN(x) || IsInf(x, 0) {
return x
}
if x < 0 {
@@ -30,21 +30,25 @@ func Floor(x float64) float64 {
// Ceil returns the least integer value greater than or equal to x.
//
// Special cases are:
-// Ceil(+Inf) = +Inf
-// Ceil(-Inf) = -Inf
+// Ceil(±0) = ±0
+// Ceil(±Inf) = ±Inf
// Ceil(NaN) = NaN
-func Ceil(x float64) float64 { return -Floor(-x) }
+func Ceil(x float64) float64
+
+func ceil(x float64) float64 {
+ return -Floor(-x)
+}
// Trunc returns the integer value of x.
//
// Special cases are:
-// Trunc(+Inf) = +Inf
-// Trunc(-Inf) = -Inf
+// Trunc(±0) = ±0
+// Trunc(±Inf) = ±Inf
// Trunc(NaN) = NaN
-func Trunc(x float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
- if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+func Trunc(x float64) float64
+
+func trunc(x float64) float64 {
+ if x == 0 || IsNaN(x) || IsInf(x, 0) {
return x
}
d, _ := Modf(x)
diff --git a/src/pkg/math/floor_amd64.s b/src/pkg/math/floor_amd64.s
new file mode 100644
index 000000000..9fc49a56f
--- /dev/null
+++ b/src/pkg/math/floor_amd64.s
@@ -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.
+
+TEXT ·Floor(SB),7,$0
+ JMP ·floor(SB)
+
+TEXT ·Ceil(SB),7,$0
+ JMP ·ceil(SB)
+
+TEXT ·Trunc(SB),7,$0
+ JMP ·trunc(SB)
diff --git a/src/pkg/math/floor_arm.s b/src/pkg/math/floor_arm.s
new file mode 100644
index 000000000..e3ae53f52
--- /dev/null
+++ b/src/pkg/math/floor_arm.s
@@ -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.
+
+TEXT ·Floor(SB),7,$0
+ B ·floor(SB)
+
+TEXT ·Ceil(SB),7,$0
+ B ·ceil(SB)
+
+TEXT ·Trunc(SB),7,$0
+ B ·trunc(SB)
diff --git a/src/pkg/math/floor_decl.go b/src/pkg/math/floor_decl.go
deleted file mode 100644
index 7da420179..000000000
--- a/src/pkg/math/floor_decl.go
+++ /dev/null
@@ -1,9 +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 math
-
-func Ceil(x float64) float64
-func Floor(x float64) float64
-func Trunc(x float64) float64
diff --git a/src/pkg/math/fmod_decl.go b/src/pkg/math/fmod_decl.go
deleted file mode 100644
index 8d97cdf4a..000000000
--- a/src/pkg/math/fmod_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Fmod(x, y float64) float64
diff --git a/src/pkg/math/frexp.go b/src/pkg/math/frexp.go
index 867b78f36..0e26feb66 100644
--- a/src/pkg/math/frexp.go
+++ b/src/pkg/math/frexp.go
@@ -13,14 +13,14 @@ package math
// Frexp(±0) = ±0, 0
// Frexp(±Inf) = ±Inf, 0
// Frexp(NaN) = NaN, 0
-func Frexp(f float64) (frac float64, exp int) {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
+func Frexp(f float64) (frac float64, exp int)
+
+func frexp(f float64) (frac float64, exp int) {
// special cases
switch {
case f == 0:
return f, 0 // correctly return -0
- case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
+ case IsInf(f, 0) || IsNaN(f):
return f, 0
}
f, exp = normalize(f)
diff --git a/src/pkg/math/frexp_amd64.s b/src/pkg/math/frexp_amd64.s
new file mode 100644
index 000000000..bc52b79ab
--- /dev/null
+++ b/src/pkg/math/frexp_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Frexp(SB),7,$0
+ JMP ·frexp(SB)
diff --git a/src/pkg/math/frexp_arm.s b/src/pkg/math/frexp_arm.s
new file mode 100644
index 000000000..cfd5d0b52
--- /dev/null
+++ b/src/pkg/math/frexp_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Frexp(SB),7,$0
+ B ·frexp(SB)
diff --git a/src/pkg/math/frexp_decl.go b/src/pkg/math/frexp_decl.go
deleted file mode 100644
index b36bf2eb7..000000000
--- a/src/pkg/math/frexp_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Frexp(x float64) (f float64, e int)
diff --git a/src/pkg/math/gamma.go b/src/pkg/math/gamma.go
index 73ca0e53a..7c6f421ba 100644
--- a/src/pkg/math/gamma.go
+++ b/src/pkg/math/gamma.go
@@ -63,7 +63,7 @@ package math
// Stephen L. Moshier
// moshier@na-net.ornl.gov
-var _P = []float64{
+var _gamP = [...]float64{
1.60119522476751861407e-04,
1.19135147006586384913e-03,
1.04213797561761569935e-02,
@@ -72,7 +72,7 @@ var _P = []float64{
4.94214826801497100753e-01,
9.99999999999999996796e-01,
}
-var _Q = []float64{
+var _gamQ = [...]float64{
-2.31581873324120129819e-05,
5.39605580493303397842e-04,
-4.45641913851797240494e-03,
@@ -82,7 +82,7 @@ var _Q = []float64{
7.14304917030273074085e-02,
1.00000000000000000320e+00,
}
-var _S = []float64{
+var _gamS = [...]float64{
7.87311395793093628397e-04,
-2.29549961613378126380e-04,
-2.68132617805781232825e-03,
@@ -98,7 +98,7 @@ func stirling(x float64) float64 {
MaxStirling = 143.01608
)
w := 1 / x
- w = 1 + w*((((_S[0]*w+_S[1])*w+_S[2])*w+_S[3])*w+_S[4])
+ w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
y := Exp(x)
if x > MaxStirling { // avoid Pow() overflow
v := Pow(x, 0.5*x-0.25)
@@ -113,21 +113,20 @@ func stirling(x float64) float64 {
// Gamma(x) returns the Gamma function of x.
//
// Special cases are:
-// Gamma(Inf) = Inf
-// Gamma(-Inf) = -Inf
+// Gamma(±Inf) = ±Inf
// Gamma(NaN) = NaN
// Large values overflow to +Inf.
-// Negative integer values equal ±Inf.
+// Zero and negative integer arguments return ±Inf.
func Gamma(x float64) float64 {
const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
// special cases
switch {
- case x < -MaxFloat64 || x != x: // IsInf(x, -1) || IsNaN(x):
+ case IsInf(x, -1) || IsNaN(x):
return x
case x < -170.5674972726612 || x > 171.61447887182298:
return Inf(1)
}
- q := Fabs(x)
+ q := Abs(x)
p := Floor(q)
if q > 33 {
if x >= 0 {
@@ -146,7 +145,7 @@ func Gamma(x float64) float64 {
if z == 0 {
return Inf(signgam)
}
- z = Pi / (Fabs(z) * stirling(q))
+ z = Pi / (Abs(z) * stirling(q))
return float64(signgam) * z
}
@@ -176,8 +175,8 @@ func Gamma(x float64) float64 {
}
x = x - 2
- p = (((((x*_P[0]+_P[1])*x+_P[2])*x+_P[3])*x+_P[4])*x+_P[5])*x + _P[6]
- q = ((((((x*_Q[0]+_Q[1])*x+_Q[2])*x+_Q[3])*x+_Q[4])*x+_Q[5])*x+_Q[6])*x + _Q[7]
+ p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
+ q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
return z * p / q
small:
diff --git a/src/pkg/math/hypot.go b/src/pkg/math/hypot.go
index ecd115d9e..df4d3eb70 100644
--- a/src/pkg/math/hypot.go
+++ b/src/pkg/math/hypot.go
@@ -14,14 +14,14 @@ package math
// Special cases are:
// Hypot(p, q) = +Inf if p or q is infinite
// Hypot(p, q) = NaN if p or q is NaN
-func Hypot(p, q float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
+func Hypot(p, q float64) float64
+
+func hypot(p, q float64) float64 {
// special cases
switch {
- case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+ case IsInf(p, 0) || IsInf(q, 0):
return Inf(1)
- case p != p || q != q: // IsNaN(p) || IsNaN(q):
+ case IsNaN(p) || IsNaN(q):
return NaN()
}
if p < 0 {
diff --git a/src/pkg/math/hypot_arm.s b/src/pkg/math/hypot_arm.s
new file mode 100644
index 000000000..2c599fd55
--- /dev/null
+++ b/src/pkg/math/hypot_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Hypot(SB),7,$0
+ B ·hypot(SB)
diff --git a/src/pkg/math/hypot_decl.go b/src/pkg/math/hypot_decl.go
deleted file mode 100644
index 72603c5d5..000000000
--- a/src/pkg/math/hypot_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Hypot(x, y float64) float64
diff --git a/src/pkg/math/hypot_port.go b/src/pkg/math/hypot_port.go
deleted file mode 100644
index 27f335ba2..000000000
--- a/src/pkg/math/hypot_port.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2009-2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package math
-
-/*
- Hypot -- sqrt(p*p + q*q), but overflows only if the result does.
- See:
- Cleve Moler and Donald Morrison,
- Replacing Square Roots by Pythagorean Sums
- IBM Journal of Research and Development,
- Vol. 27, Number 6, pp. 577-581, Nov. 1983
-*/
-
-// Hypot computes Sqrt(p*p + q*q), taking care to avoid
-// unnecessary overflow and underflow.
-//
-// Special cases are:
-// Hypot(p, q) = +Inf if p or q is infinite
-// Hypot(p, q) = NaN if p or q is NaN
-func hypotGo(p, q float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
- // special cases
- switch {
- case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
- return Inf(1)
- case p != p || q != q: // IsNaN(p) || IsNaN(q):
- return NaN()
- }
- if p < 0 {
- p = -p
- }
- if q < 0 {
- q = -q
- }
-
- if p < q {
- p, q = q, p
- }
-
- if p == 0 {
- return 0
- }
-
- pfac := p
- q = q / p
- r := q
- p = 1
- for {
- r = r * r
- s := r + 4
- if s == 4 {
- return p * pfac
- }
- r = r / s
- p = p + 2*r*p
- q = q * r
- r = q / p
- }
- panic("unreachable")
-}
diff --git a/src/pkg/math/hypot_test.go b/src/pkg/math/hypot_test.go
deleted file mode 100644
index 85ce1d404..000000000
--- a/src/pkg/math/hypot_test.go
+++ /dev/null
@@ -1,9 +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 math
-
-// Make hypotGo available for testing.
-
-func HypotGo(x, y float64) float64 { return hypotGo(x, y) }
diff --git a/src/pkg/math/j0.go b/src/pkg/math/j0.go
index 5aaf4ab9c..c20a9b22a 100644
--- a/src/pkg/math/j0.go
+++ b/src/pkg/math/j0.go
@@ -89,13 +89,11 @@ func J0(x float64) float64 {
S03 = 5.13546550207318111446e-07 // 0x3EA13B54CE84D5A9
S04 = 1.16614003333790000205e-09 // 0x3E1408BCF4745D8F
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x != x: // IsNaN(x)
+ case IsNaN(x):
return x
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
return 0
case x == 0:
return 1
@@ -171,13 +169,11 @@ func Y0(x float64) float64 {
V03 = 2.59150851840457805467e-07 // 0x3E91642D7FF202FD
V04 = 4.41110311332675467403e-10 // 0x3DFE50183BD6D9EF
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x < 0 || x != x: // x < 0 || IsNaN(x):
+ case x < 0 || IsNaN(x):
return NaN()
- case x > MaxFloat64: // IsInf(x, 1):
+ case IsInf(x, 1):
return 0
case x == 0:
return Inf(-1)
diff --git a/src/pkg/math/j1.go b/src/pkg/math/j1.go
index 278162e9d..7ac186b72 100644
--- a/src/pkg/math/j1.go
+++ b/src/pkg/math/j1.go
@@ -86,13 +86,11 @@ func J1(x float64) float64 {
S04 = 5.04636257076217042715e-09 // 0x3E35AC88C97DFF2C
S05 = 1.23542274426137913908e-11 // 0x3DAB2ACFCFB97ED8
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x != x: // IsNaN(x)
+ case IsNaN(x):
return x
- case x < -MaxFloat64 || x > MaxFloat64 || x == 0: // IsInf(x, 0) || x == 0:
+ case IsInf(x, 0) || x == 0:
return 0
}
@@ -168,13 +166,11 @@ func Y1(x float64) float64 {
V03 = 6.22741452364621501295e-09 // 0x3E3ABF1D5BA69A86
V04 = 1.66559246207992079114e-11 // 0x3DB25039DACA772A
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x < 0 || x != x: // x < 0 || IsNaN(x):
+ case x < 0 || IsNaN(x):
return NaN()
- case x > MaxFloat64: // IsInf(x, 1):
+ case IsInf(x, 1):
return 0
case x == 0:
return Inf(-1)
diff --git a/src/pkg/math/jn.go b/src/pkg/math/jn.go
index 9024af3c2..a7909eb24 100644
--- a/src/pkg/math/jn.go
+++ b/src/pkg/math/jn.go
@@ -55,13 +55,11 @@ func Jn(n int, x float64) float64 {
TwoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000
Two302 = 1 << 302 // 2**302 0x52D0000000000000
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x != x: // IsNaN(x)
+ case IsNaN(x):
return x
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
return 0
}
// J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x)
@@ -197,7 +195,7 @@ func Jn(n int, x float64) float64 {
tmp := float64(n)
v := 2 / x
- tmp = tmp * Log(Fabs(v*tmp))
+ tmp = tmp * Log(Abs(v*tmp))
if tmp < 7.09782712893383973096e+02 {
for i := n - 1; i > 0; i-- {
di := float64(i + i)
@@ -236,13 +234,11 @@ func Jn(n int, x float64) float64 {
// Y1(n, NaN) = NaN
func Yn(n int, x float64) float64 {
const Two302 = 1 << 302 // 2**302 0x52D0000000000000
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x < 0 || x != x: // x < 0 || IsNaN(x):
+ case x < 0 || IsNaN(x):
return NaN()
- case x > MaxFloat64: // IsInf(x, 1)
+ case IsInf(x, 1):
return 0
}
@@ -299,7 +295,7 @@ func Yn(n int, x float64) float64 {
a := Y0(x)
b = Y1(x)
// quit if b is -inf
- for i := 1; i < n && b >= -MaxFloat64; i++ { // for i := 1; i < n && !IsInf(b, -1); i++ {
+ for i := 1; i < n && !IsInf(b, -1); i++ {
a, b = b, (float64(i+i)/x)*b-a
}
}
diff --git a/src/pkg/math/ldexp.go b/src/pkg/math/ldexp.go
index 96c95cad4..b5d2a5e7e 100644
--- a/src/pkg/math/ldexp.go
+++ b/src/pkg/math/ldexp.go
@@ -11,14 +11,14 @@ package math
// Ldexp(±0, exp) = ±0
// Ldexp(±Inf, exp) = ±Inf
// Ldexp(NaN, exp) = NaN
-func Ldexp(frac float64, exp int) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
+func Ldexp(frac float64, exp int) float64
+
+func ldexp(frac float64, exp int) float64 {
// special cases
switch {
case frac == 0:
return frac // correctly return -0
- case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac):
+ case IsInf(frac, 0) || IsNaN(frac):
return frac
}
frac, e := normalize(frac)
diff --git a/src/pkg/math/ldexp_amd64.s b/src/pkg/math/ldexp_amd64.s
new file mode 100644
index 000000000..a8d458322
--- /dev/null
+++ b/src/pkg/math/ldexp_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Ldexp(SB),7,$0
+ JMP ·ldexp(SB)
diff --git a/src/pkg/math/ldexp_arm.s b/src/pkg/math/ldexp_arm.s
new file mode 100644
index 000000000..3c42f515e
--- /dev/null
+++ b/src/pkg/math/ldexp_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Ldexp(SB),7,$0
+ B ·ldexp(SB)
diff --git a/src/pkg/math/ldexp_decl.go b/src/pkg/math/ldexp_decl.go
deleted file mode 100644
index 40e11e7a1..000000000
--- a/src/pkg/math/ldexp_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Ldexp(f float64, e int) float64
diff --git a/src/pkg/math/lgamma.go b/src/pkg/math/lgamma.go
index dc30f468f..6a02c412d 100644
--- a/src/pkg/math/lgamma.go
+++ b/src/pkg/math/lgamma.go
@@ -88,6 +88,81 @@ package math
//
//
+var _lgamA = [...]float64{
+ 7.72156649015328655494e-02, // 0x3FB3C467E37DB0C8
+ 3.22467033424113591611e-01, // 0x3FD4A34CC4A60FAD
+ 6.73523010531292681824e-02, // 0x3FB13E001A5562A7
+ 2.05808084325167332806e-02, // 0x3F951322AC92547B
+ 7.38555086081402883957e-03, // 0x3F7E404FB68FEFE8
+ 2.89051383673415629091e-03, // 0x3F67ADD8CCB7926B
+ 1.19270763183362067845e-03, // 0x3F538A94116F3F5D
+ 5.10069792153511336608e-04, // 0x3F40B6C689B99C00
+ 2.20862790713908385557e-04, // 0x3F2CF2ECED10E54D
+ 1.08011567247583939954e-04, // 0x3F1C5088987DFB07
+ 2.52144565451257326939e-05, // 0x3EFA7074428CFA52
+ 4.48640949618915160150e-05, // 0x3F07858E90A45837
+}
+var _lgamR = [...]float64{
+ 1.0, // placeholder
+ 1.39200533467621045958e+00, // 0x3FF645A762C4AB74
+ 7.21935547567138069525e-01, // 0x3FE71A1893D3DCDC
+ 1.71933865632803078993e-01, // 0x3FC601EDCCFBDF27
+ 1.86459191715652901344e-02, // 0x3F9317EA742ED475
+ 7.77942496381893596434e-04, // 0x3F497DDACA41A95B
+ 7.32668430744625636189e-06, // 0x3EDEBAF7A5B38140
+}
+var _lgamS = [...]float64{
+ -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8
+ 2.14982415960608852501e-01, // 0x3FCB848B36E20878
+ 3.25778796408930981787e-01, // 0x3FD4D98F4F139F59
+ 1.46350472652464452805e-01, // 0x3FC2BB9CBEE5F2F7
+ 2.66422703033638609560e-02, // 0x3F9B481C7E939961
+ 1.84028451407337715652e-03, // 0x3F5E26B67368F239
+ 3.19475326584100867617e-05, // 0x3F00BFECDD17E945
+}
+var _lgamT = [...]float64{
+ 4.83836122723810047042e-01, // 0x3FDEF72BC8EE38A2
+ -1.47587722994593911752e-01, // 0xBFC2E4278DC6C509
+ 6.46249402391333854778e-02, // 0x3FB08B4294D5419B
+ -3.27885410759859649565e-02, // 0xBFA0C9A8DF35B713
+ 1.79706750811820387126e-02, // 0x3F9266E7970AF9EC
+ -1.03142241298341437450e-02, // 0xBF851F9FBA91EC6A
+ 6.10053870246291332635e-03, // 0x3F78FCE0E370E344
+ -3.68452016781138256760e-03, // 0xBF6E2EFFB3E914D7
+ 2.25964780900612472250e-03, // 0x3F6282D32E15C915
+ -1.40346469989232843813e-03, // 0xBF56FE8EBF2D1AF1
+ 8.81081882437654011382e-04, // 0x3F4CDF0CEF61A8E9
+ -5.38595305356740546715e-04, // 0xBF41A6109C73E0EC
+ 3.15632070903625950361e-04, // 0x3F34AF6D6C0EBBF7
+ -3.12754168375120860518e-04, // 0xBF347F24ECC38C38
+ 3.35529192635519073543e-04, // 0x3F35FD3EE8C2D3F4
+}
+var _lgamU = [...]float64{
+ -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8
+ 6.32827064025093366517e-01, // 0x3FE4401E8B005DFF
+ 1.45492250137234768737e+00, // 0x3FF7475CD119BD6F
+ 9.77717527963372745603e-01, // 0x3FEF497644EA8450
+ 2.28963728064692451092e-01, // 0x3FCD4EAEF6010924
+ 1.33810918536787660377e-02, // 0x3F8B678BBF2BAB09
+}
+var _lgamV = [...]float64{
+ 1.0,
+ 2.45597793713041134822e+00, // 0x4003A5D7C2BD619C
+ 2.12848976379893395361e+00, // 0x40010725A42B18F5
+ 7.69285150456672783825e-01, // 0x3FE89DFBE45050AF
+ 1.04222645593369134254e-01, // 0x3FBAAE55D6537C88
+ 3.21709242282423911810e-03, // 0x3F6A5ABB57D0CF61
+}
+var _lgamW = [...]float64{
+ 4.18938533204672725052e-01, // 0x3FDACFE390C97D69
+ 8.33333333333329678849e-02, // 0x3FB555555555553B
+ -2.77777777728775536470e-03, // 0xBF66C16C16B02E5C
+ 7.93650558643019558500e-04, // 0x3F4A019F98CF38B6
+ -5.95187557450339963135e-04, // 0xBF4380CB8C0FE741
+ 8.36339918996282139126e-04, // 0x3F4B67BA4CDAD5D1
+ -1.63092934096575273989e-03, // 0xBF5AB89D0B9E43E4
+}
+
// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x).
//
// Special cases are:
@@ -103,78 +178,18 @@ func Lgamma(x float64) (lgamma float64, sign int) {
Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
Two58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17
Tiny = 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22
- A0 = 7.72156649015328655494e-02 // 0x3FB3C467E37DB0C8
- A1 = 3.22467033424113591611e-01 // 0x3FD4A34CC4A60FAD
- A2 = 6.73523010531292681824e-02 // 0x3FB13E001A5562A7
- A3 = 2.05808084325167332806e-02 // 0x3F951322AC92547B
- A4 = 7.38555086081402883957e-03 // 0x3F7E404FB68FEFE8
- A5 = 2.89051383673415629091e-03 // 0x3F67ADD8CCB7926B
- A6 = 1.19270763183362067845e-03 // 0x3F538A94116F3F5D
- A7 = 5.10069792153511336608e-04 // 0x3F40B6C689B99C00
- A8 = 2.20862790713908385557e-04 // 0x3F2CF2ECED10E54D
- A9 = 1.08011567247583939954e-04 // 0x3F1C5088987DFB07
- A10 = 2.52144565451257326939e-05 // 0x3EFA7074428CFA52
- A11 = 4.48640949618915160150e-05 // 0x3F07858E90A45837
Tc = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F
Tf = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42
// Tt = -(tail of Tf)
- Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
- T0 = 4.83836122723810047042e-01 // 0x3FDEF72BC8EE38A2
- T1 = -1.47587722994593911752e-01 // 0xBFC2E4278DC6C509
- T2 = 6.46249402391333854778e-02 // 0x3FB08B4294D5419B
- T3 = -3.27885410759859649565e-02 // 0xBFA0C9A8DF35B713
- T4 = 1.79706750811820387126e-02 // 0x3F9266E7970AF9EC
- T5 = -1.03142241298341437450e-02 // 0xBF851F9FBA91EC6A
- T6 = 6.10053870246291332635e-03 // 0x3F78FCE0E370E344
- T7 = -3.68452016781138256760e-03 // 0xBF6E2EFFB3E914D7
- T8 = 2.25964780900612472250e-03 // 0x3F6282D32E15C915
- T9 = -1.40346469989232843813e-03 // 0xBF56FE8EBF2D1AF1
- T10 = 8.81081882437654011382e-04 // 0x3F4CDF0CEF61A8E9
- T11 = -5.38595305356740546715e-04 // 0xBF41A6109C73E0EC
- T12 = 3.15632070903625950361e-04 // 0x3F34AF6D6C0EBBF7
- T13 = -3.12754168375120860518e-04 // 0xBF347F24ECC38C38
- T14 = 3.35529192635519073543e-04 // 0x3F35FD3EE8C2D3F4
- U0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
- U1 = 6.32827064025093366517e-01 // 0x3FE4401E8B005DFF
- U2 = 1.45492250137234768737e+00 // 0x3FF7475CD119BD6F
- U3 = 9.77717527963372745603e-01 // 0x3FEF497644EA8450
- U4 = 2.28963728064692451092e-01 // 0x3FCD4EAEF6010924
- U5 = 1.33810918536787660377e-02 // 0x3F8B678BBF2BAB09
- V1 = 2.45597793713041134822e+00 // 0x4003A5D7C2BD619C
- V2 = 2.12848976379893395361e+00 // 0x40010725A42B18F5
- V3 = 7.69285150456672783825e-01 // 0x3FE89DFBE45050AF
- V4 = 1.04222645593369134254e-01 // 0x3FBAAE55D6537C88
- V5 = 3.21709242282423911810e-03 // 0x3F6A5ABB57D0CF61
- S0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
- S1 = 2.14982415960608852501e-01 // 0x3FCB848B36E20878
- S2 = 3.25778796408930981787e-01 // 0x3FD4D98F4F139F59
- S3 = 1.46350472652464452805e-01 // 0x3FC2BB9CBEE5F2F7
- S4 = 2.66422703033638609560e-02 // 0x3F9B481C7E939961
- S5 = 1.84028451407337715652e-03 // 0x3F5E26B67368F239
- S6 = 3.19475326584100867617e-05 // 0x3F00BFECDD17E945
- R1 = 1.39200533467621045958e+00 // 0x3FF645A762C4AB74
- R2 = 7.21935547567138069525e-01 // 0x3FE71A1893D3DCDC
- R3 = 1.71933865632803078993e-01 // 0x3FC601EDCCFBDF27
- R4 = 1.86459191715652901344e-02 // 0x3F9317EA742ED475
- R5 = 7.77942496381893596434e-04 // 0x3F497DDACA41A95B
- R6 = 7.32668430744625636189e-06 // 0x3EDEBAF7A5B38140
- W0 = 4.18938533204672725052e-01 // 0x3FDACFE390C97D69
- W1 = 8.33333333333329678849e-02 // 0x3FB555555555553B
- W2 = -2.77777777728775536470e-03 // 0xBF66C16C16B02E5C
- W3 = 7.93650558643019558500e-04 // 0x3F4A019F98CF38B6
- W4 = -5.95187557450339963135e-04 // 0xBF4380CB8C0FE741
- W5 = 8.36339918996282139126e-04 // 0x3F4B67BA4CDAD5D1
- W6 = -1.63092934096575273989e-03 // 0xBF5AB89D0B9E43E4
+ Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
sign = 1
switch {
- case x != x: // IsNaN(x):
+ case IsNaN(x):
lgamma = x
return
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
lgamma = x
return
case x == 0:
@@ -206,7 +221,7 @@ func Lgamma(x float64) (lgamma float64, sign int) {
lgamma = Inf(1) // -integer
return
}
- nadj = Log(Pi / Fabs(t*x))
+ nadj = Log(Pi / Abs(t*x))
if t < 0 {
sign = -1
}
@@ -249,28 +264,28 @@ func Lgamma(x float64) (lgamma float64, sign int) {
switch i {
case 0:
z := y * y
- p1 := A0 + z*(A2+z*(A4+z*(A6+z*(A8+z*A10))))
- p2 := z * (A1 + z*(A3+z*(A5+z*(A7+z*(A9+z*A11)))))
+ p1 := _lgamA[0] + z*(_lgamA[2]+z*(_lgamA[4]+z*(_lgamA[6]+z*(_lgamA[8]+z*_lgamA[10]))))
+ p2 := z * (_lgamA[1] + z*(+_lgamA[3]+z*(_lgamA[5]+z*(_lgamA[7]+z*(_lgamA[9]+z*_lgamA[11])))))
p := y*p1 + p2
lgamma += (p - 0.5*y)
case 1:
z := y * y
w := z * y
- p1 := T0 + w*(T3+w*(T6+w*(T9+w*T12))) // parallel comp
- p2 := T1 + w*(T4+w*(T7+w*(T10+w*T13)))
- p3 := T2 + w*(T5+w*(T8+w*(T11+w*T14)))
+ p1 := _lgamT[0] + w*(_lgamT[3]+w*(_lgamT[6]+w*(_lgamT[9]+w*_lgamT[12]))) // parallel comp
+ p2 := _lgamT[1] + w*(_lgamT[4]+w*(_lgamT[7]+w*(_lgamT[10]+w*_lgamT[13])))
+ p3 := _lgamT[2] + w*(_lgamT[5]+w*(_lgamT[8]+w*(_lgamT[11]+w*_lgamT[14])))
p := z*p1 - (Tt - w*(p2+y*p3))
lgamma += (Tf + p)
case 2:
- p1 := y * (U0 + y*(U1+y*(U2+y*(U3+y*(U4+y*U5)))))
- p2 := 1 + y*(V1+y*(V2+y*(V3+y*(V4+y*V5))))
+ p1 := y * (_lgamU[0] + y*(_lgamU[1]+y*(_lgamU[2]+y*(_lgamU[3]+y*(_lgamU[4]+y*_lgamU[5])))))
+ p2 := 1 + y*(_lgamV[1]+y*(_lgamV[2]+y*(_lgamV[3]+y*(_lgamV[4]+y*_lgamV[5]))))
lgamma += (-0.5*y + p1/p2)
}
case x < 8: // 2 <= x < 8
i := int(x)
y := x - float64(i)
- p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
- q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
+ p := y * (_lgamS[0] + y*(_lgamS[1]+y*(_lgamS[2]+y*(_lgamS[3]+y*(_lgamS[4]+y*(_lgamS[5]+y*_lgamS[6]))))))
+ q := 1 + y*(_lgamR[1]+y*(_lgamR[2]+y*(_lgamR[3]+y*(_lgamR[4]+y*(_lgamR[5]+y*_lgamR[6])))))
lgamma = 0.5*y + p/q
z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s)
switch i {
@@ -294,7 +309,7 @@ func Lgamma(x float64) (lgamma float64, sign int) {
t := Log(x)
z := 1 / x
y := z * z
- w := W0 + z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6)))))
+ w := _lgamW[0] + z*(_lgamW[1]+y*(_lgamW[2]+y*(_lgamW[3]+y*(_lgamW[4]+y*(_lgamW[5]+y*_lgamW[6])))))
lgamma = (x-0.5)*(t-1) + w
default: // 2**58 <= x <= Inf
lgamma = x * (Log(x) - 1)
@@ -319,7 +334,7 @@ func sinPi(x float64) float64 {
z := Floor(x)
var n int
if z != x { // inexact
- x = Fmod(x, 2)
+ x = Mod(x, 2)
n = int(x * 4)
} else {
if x >= Two53 { // x must be even
diff --git a/src/pkg/math/log.go b/src/pkg/math/log.go
index a786c8ce3..818f00a73 100644
--- a/src/pkg/math/log.go
+++ b/src/pkg/math/log.go
@@ -77,7 +77,9 @@ package math
// Log(0) = -Inf
// Log(x < 0) = NaN
// Log(NaN) = NaN
-func Log(x float64) float64 {
+func Log(x float64) float64
+
+func log(x float64) float64 {
const (
Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
@@ -90,11 +92,9 @@ func Log(x float64) float64 {
L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ case IsNaN(x) || IsInf(x, 1):
return x
case x < 0:
return NaN()
diff --git a/src/pkg/math/log10.go b/src/pkg/math/log10.go
index 6d18baae2..67c163a49 100644
--- a/src/pkg/math/log10.go
+++ b/src/pkg/math/log10.go
@@ -6,8 +6,16 @@ package math
// Log10 returns the decimal logarithm of x.
// The special cases are the same as for Log.
-func Log10(x float64) float64 { return Log(x) * (1 / Ln10) }
+func Log10(x float64) float64
+
+func log10(x float64) float64 {
+ return Log(x) * (1 / Ln10)
+}
// Log2 returns the binary logarithm of x.
// The special cases are the same as for Log.
-func Log2(x float64) float64 { return Log(x) * (1 / Ln2) }
+func Log2(x float64) float64
+
+func log2(x float64) float64 {
+ return Log(x) * (1 / Ln2)
+}
diff --git a/src/pkg/math/log10_amd64.s b/src/pkg/math/log10_amd64.s
new file mode 100644
index 000000000..86a3b0577
--- /dev/null
+++ b/src/pkg/math/log10_amd64.s
@@ -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.
+
+TEXT ·Log10(SB),7,$0
+ JMP ·log10(SB)
+
+TEXT ·Log2(SB),7,$0
+ JMP ·log2(SB)
diff --git a/src/pkg/math/log10_arm.s b/src/pkg/math/log10_arm.s
new file mode 100644
index 000000000..619b0fe1e
--- /dev/null
+++ b/src/pkg/math/log10_arm.s
@@ -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.
+
+TEXT ·Log10(SB),7,$0
+ B ·log10(SB)
+
+TEXT ·Log2(SB),7,$0
+ B ·log2(SB)
diff --git a/src/pkg/math/log10_decl.go b/src/pkg/math/log10_decl.go
deleted file mode 100644
index 5aec94e1c..000000000
--- a/src/pkg/math/log10_decl.go
+++ /dev/null
@@ -1,8 +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 math
-
-func Log10(x float64) float64
-func Log2(x float64) float64
diff --git a/src/pkg/math/log1p.go b/src/pkg/math/log1p.go
index c25d73b66..12b98684c 100644
--- a/src/pkg/math/log1p.go
+++ b/src/pkg/math/log1p.go
@@ -44,7 +44,7 @@ package math
// 2 4 6 8 10 12 14
// R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
// (the values of Lp1 to Lp7 are listed in the program)
-// a-0.2929nd
+// and
// | 2 14 | -58.45
// | Lp1*s +...+Lp7*s - R(z) | <= 2
// | |
@@ -88,10 +88,13 @@ package math
//
// Special cases are:
// Log1p(+Inf) = +Inf
+// Log1p(±0) = ±0
// Log1p(-1) = -Inf
// Log1p(x < -1) = NaN
// Log1p(NaN) = NaN
-func Log1p(x float64) float64 {
+func Log1p(x float64) float64
+
+func log1p(x float64) float64 {
const (
Sqrt2M1 = 4.142135623730950488017e-01 // Sqrt(2)-1 = 0x3fda827999fcef34
Sqrt2HalfM1 = -2.928932188134524755992e-01 // Sqrt(2)/2-1 = 0xbfd2bec333018866
@@ -110,14 +113,12 @@ func Log1p(x float64) float64 {
)
// special cases
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
switch {
- case x < -1 || x != x: // x < -1 || IsNaN(x): // includes -Inf
+ case x < -1 || IsNaN(x): // includes -Inf
return NaN()
case x == -1:
return Inf(-1)
- case x > MaxFloat64: // IsInf(x, 1):
+ case IsInf(x, 1):
return Inf(1)
}
diff --git a/src/pkg/math/log1p_amd64.s b/src/pkg/math/log1p_amd64.s
new file mode 100644
index 000000000..65c93adad
--- /dev/null
+++ b/src/pkg/math/log1p_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Log1p(SB),7,$0
+ JMP ·log1p(SB)
diff --git a/src/pkg/math/log1p_arm.s b/src/pkg/math/log1p_arm.s
new file mode 100644
index 000000000..0e599aaff
--- /dev/null
+++ b/src/pkg/math/log1p_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Log1p(SB),7,$0
+ B ·log1p(SB)
diff --git a/src/pkg/math/log1p_decl.go b/src/pkg/math/log1p_decl.go
deleted file mode 100644
index 84b6030fb..000000000
--- a/src/pkg/math/log1p_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Log1p(x float64) float64
diff --git a/src/pkg/math/log_arm.s b/src/pkg/math/log_arm.s
new file mode 100644
index 000000000..3dce1e9d4
--- /dev/null
+++ b/src/pkg/math/log_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Log(SB),7,$0
+ B ·log(SB)
diff --git a/src/pkg/math/log_decl.go b/src/pkg/math/log_decl.go
deleted file mode 100644
index deda305dd..000000000
--- a/src/pkg/math/log_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Log(x float64) float64
diff --git a/src/pkg/math/logb.go b/src/pkg/math/logb.go
index 072281ddf..d32f9f100 100644
--- a/src/pkg/math/logb.go
+++ b/src/pkg/math/logb.go
@@ -11,15 +11,13 @@ package math
// Logb(0) = -Inf
// Logb(NaN) = NaN
func Logb(x float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
case x == 0:
return Inf(-1)
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
return Inf(1)
- case x != x: // IsNaN(x):
+ case IsNaN(x):
return x
}
return float64(ilogb(x))
@@ -32,15 +30,13 @@ func Logb(x float64) float64 {
// Ilogb(0) = MinInt32
// Ilogb(NaN) = MaxInt32
func Ilogb(x float64) int {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
case x == 0:
return MinInt32
- case x != x: // IsNaN(x):
+ case IsNaN(x):
return MaxInt32
- case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
return MaxInt32
}
return ilogb(x)
diff --git a/src/pkg/math/fmod.go b/src/pkg/math/mod.go
index 75c614629..e1a414e5f 100644
--- a/src/pkg/math/fmod.go
+++ b/src/pkg/math/mod.go
@@ -8,17 +8,20 @@ package math
Floating-point mod function.
*/
-// Fmod returns the floating-point remainder of x/y.
+// Mod returns the floating-point remainder of x/y.
// The magnitude of the result is less than y and its
// sign agrees with that of x.
//
// Special cases are:
-// if x is not finite, Fmod returns NaN
-// if y is 0 or NaN, Fmod returns NaN
-func Fmod(x, y float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us.
- if y == 0 || x > MaxFloat64 || x < -MaxFloat64 || x != x || y != y { // y == 0 || IsInf(x, 0) || IsNaN(x) || IsNan(y)
+// Mod(±Inf, y) = NaN
+// Mod(NaN, y) = NaN
+// Mod(x, 0) = NaN
+// Mod(x, ±Inf) = x
+// Mod(x, NaN) = NaN
+func Mod(x, y float64) float64
+
+func mod(x, y float64) float64 {
+ if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) {
return NaN()
}
if y < 0 {
diff --git a/src/pkg/math/fmod_386.s b/src/pkg/math/mod_386.s
index eb37bef40..6b9c28d4f 100644
--- a/src/pkg/math/fmod_386.s
+++ b/src/pkg/math/mod_386.s
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// func Fmod(x, y float64) float64
-TEXT ·Fmod(SB),7,$0
+// func Mod(x, y float64) float64
+TEXT ·Mod(SB),7,$0
FMOVD y+8(FP), F0 // F0=y
FMOVD x+0(FP), F0 // F0=x, F1=y
FPREM // F0=reduced_x, F1=y
diff --git a/src/pkg/math/mod_amd64.s b/src/pkg/math/mod_amd64.s
new file mode 100644
index 000000000..33b86be40
--- /dev/null
+++ b/src/pkg/math/mod_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Mod(SB),7,$0
+ JMP ·mod(SB)
diff --git a/src/pkg/math/mod_arm.s b/src/pkg/math/mod_arm.s
new file mode 100644
index 000000000..47c564bf1
--- /dev/null
+++ b/src/pkg/math/mod_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Mod(SB),7,$0
+ B ·mod(SB)
diff --git a/src/pkg/math/modf.go b/src/pkg/math/modf.go
index 315174b70..1e8376a93 100644
--- a/src/pkg/math/modf.go
+++ b/src/pkg/math/modf.go
@@ -8,10 +8,11 @@ package math
// that sum to f. Both values have the same sign as f.
//
// Special cases are:
-// Modf(+Inf) = +Inf, NaN
-// Modf(-Inf) = -Inf, NaN
+// Modf(±Inf) = ±Inf, NaN
// Modf(NaN) = NaN, NaN
-func Modf(f float64) (int float64, frac float64) {
+func Modf(f float64) (int float64, frac float64)
+
+func modf(f float64) (int float64, frac float64) {
if f < 1 {
if f < 0 {
int, frac = Modf(-f)
diff --git a/src/pkg/math/modf_amd64.s b/src/pkg/math/modf_amd64.s
new file mode 100644
index 000000000..2a6d7ea04
--- /dev/null
+++ b/src/pkg/math/modf_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Modf(SB),7,$0
+ JMP ·modf(SB)
diff --git a/src/pkg/math/modf_arm.s b/src/pkg/math/modf_arm.s
new file mode 100644
index 000000000..6cef18734
--- /dev/null
+++ b/src/pkg/math/modf_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Modf(SB),7,$0
+ B ·modf(SB)
diff --git a/src/pkg/math/modf_decl.go b/src/pkg/math/modf_decl.go
deleted file mode 100644
index 7add2af95..000000000
--- a/src/pkg/math/modf_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Modf(f float64) (int float64, frac float64)
diff --git a/src/pkg/math/nextafter.go b/src/pkg/math/nextafter.go
index 86114340c..7c4b5bcdf 100644
--- a/src/pkg/math/nextafter.go
+++ b/src/pkg/math/nextafter.go
@@ -8,13 +8,11 @@ package math
// If x == y, then x is returned.
//
// Special cases are:
-// Nextafter(NaN, y) = NaN
-// Nextafter(x, NaN) = NaN
+// Nextafter(NaN, y) = NaN
+// Nextafter(x, NaN) = NaN
func Nextafter(x, y float64) (r float64) {
- // TODO(rsc): Remove manual inlining of IsNaN
- // when compiler does it for us
switch {
- case x != x || y != y: // IsNaN(x) || IsNaN(y): // special case
+ case IsNaN(x) || IsNaN(y): // special case
r = NaN()
case x == y:
r = x
@@ -25,5 +23,5 @@ func Nextafter(x, y float64) (r float64) {
default:
r = Float64frombits(Float64bits(x) - 1)
}
- return r
+ return
}
diff --git a/src/pkg/math/pow.go b/src/pkg/math/pow.go
index 06b107401..77af25648 100644
--- a/src/pkg/math/pow.go
+++ b/src/pkg/math/pow.go
@@ -36,8 +36,6 @@ func isOddInt(x float64) bool {
// Pow(-Inf, y) = Pow(-0, -y)
// Pow(x, y) = NaN for finite x < 0 and finite non-integer y
func Pow(x, y float64) float64 {
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
switch {
case y == 0 || x == 1:
return 1
@@ -47,7 +45,7 @@ func Pow(x, y float64) float64 {
return Sqrt(x)
case y == -0.5:
return 1 / Sqrt(x)
- case x != x || y != y: // IsNaN(x) || IsNaN(y):
+ case IsNaN(x) || IsNaN(y):
return NaN()
case x == 0:
switch {
@@ -62,16 +60,16 @@ func Pow(x, y float64) float64 {
}
return 0
}
- case y > MaxFloat64 || y < -MaxFloat64: // IsInf(y, 0):
+ case IsInf(y, 0):
switch {
case x == -1:
return 1
- case (Fabs(x) < 1) == IsInf(y, 1):
+ case (Abs(x) < 1) == IsInf(y, 1):
return 0
default:
return Inf(1)
}
- case x > MaxFloat64 || x < -MaxFloat64: // IsInf(x, 0):
+ case IsInf(x, 0):
if IsInf(x, -1) {
return Pow(1/x, -y) // Pow(-0, -y)
}
diff --git a/src/pkg/math/pow10.go b/src/pkg/math/pow10.go
index bda2e824e..f5ad28bb4 100644
--- a/src/pkg/math/pow10.go
+++ b/src/pkg/math/pow10.go
@@ -9,7 +9,17 @@ package math
var pow10tab [70]float64
// Pow10 returns 10**e, the base-10 exponential of e.
+//
+// Special cases are:
+// Pow10(e) = +Inf for e > 309
+// Pow10(e) = 0 for e < -324
func Pow10(e int) float64 {
+ if e <= -325 {
+ return 0
+ } else if e > 309 {
+ return Inf(1)
+ }
+
if e < 0 {
return 1 / Pow10(-e)
}
diff --git a/src/pkg/rand/exp.go b/src/pkg/math/rand/exp.go
index 85da49521..85da49521 100644
--- a/src/pkg/rand/exp.go
+++ b/src/pkg/math/rand/exp.go
diff --git a/src/pkg/rand/normal.go b/src/pkg/math/rand/normal.go
index 9ab46db9f..9ab46db9f 100644
--- a/src/pkg/rand/normal.go
+++ b/src/pkg/math/rand/normal.go
diff --git a/src/pkg/rand/rand.go b/src/pkg/math/rand/rand.go
index 459aed1db..94f84a85f 100644
--- a/src/pkg/rand/rand.go
+++ b/src/pkg/math/rand/rand.go
@@ -49,9 +49,10 @@ func (r *Rand) Int() int {
}
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Int63n(n int64) int64 {
if n <= 0 {
- return 0
+ panic("invalid argument to Int63n")
}
max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
v := r.Int63()
@@ -62,9 +63,10 @@ func (r *Rand) Int63n(n int64) int64 {
}
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Int31n(n int32) int32 {
if n <= 0 {
- return 0
+ panic("invalid argument to Int31n")
}
max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
v := r.Int31()
@@ -75,7 +77,11 @@ func (r *Rand) Int31n(n int32) int32 {
}
// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func (r *Rand) Intn(n int) int {
+ if n <= 0 {
+ panic("invalid argument to Intn")
+ }
if n <= 1<<31-1 {
return int(r.Int31n(int32(n)))
}
@@ -107,7 +113,9 @@ func (r *Rand) Perm(n int) []int {
var globalRand = New(&lockedSource{src: NewSource(1)})
-// Seed uses the provided seed value to initialize the generator to a deterministic state.
+// Seed uses the provided seed value to initialize the generator to a
+// deterministic state. If Seed is not called, the generator behaves as
+// if seeded by Seed(1).
func Seed(seed int64) { globalRand.Seed(seed) }
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
@@ -123,12 +131,15 @@ func Int31() int32 { return globalRand.Int31() }
func Int() int { return globalRand.Int() }
// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Int63n(n int64) int64 { return globalRand.Int63n(n) }
// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Int31n(n int32) int32 { return globalRand.Int31n(n) }
// Intn returns, as an int, a non-negative pseudo-random number in [0,n).
+// It panics if n <= 0.
func Intn(n int) int { return globalRand.Intn(n) }
// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
diff --git a/src/pkg/rand/rand_test.go b/src/pkg/math/rand/rand_test.go
index 3ebc1141d..bbd44e3f8 100644
--- a/src/pkg/rand/rand_test.go
+++ b/src/pkg/math/rand/rand_test.go
@@ -5,9 +5,9 @@
package rand
import (
- "math"
+ "errors"
"fmt"
- "os"
+ "math"
"testing"
)
@@ -30,27 +30,27 @@ func max(a, b float64) float64 {
}
func nearEqual(a, b, closeEnough, maxError float64) bool {
- absDiff := math.Fabs(a - b)
+ absDiff := math.Abs(a - b)
if absDiff < closeEnough { // Necessary when one value is zero and one value is close to zero.
return true
}
- return absDiff/max(math.Fabs(a), math.Fabs(b)) < maxError
+ return absDiff/max(math.Abs(a), math.Abs(b)) < maxError
}
var testSeeds = []int64{1, 1754801282, 1698661970, 1550503961}
// checkSimilarDistribution returns success if the mean and stddev of the
// two statsResults are similar.
-func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Error {
+func (this *statsResults) checkSimilarDistribution(expected *statsResults) error {
if !nearEqual(this.mean, expected.mean, expected.closeEnough, expected.maxError) {
s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", this.mean, expected.mean, expected.closeEnough, expected.maxError)
fmt.Println(s)
- return os.NewError(s)
+ return errors.New(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.NewError(s)
+ return errors.New(s)
}
return nil
}
@@ -74,7 +74,7 @@ func checkSampleDistribution(t *testing.T, samples []float64, expected *statsRes
actual := getStatsResults(samples)
err := actual.checkSimilarDistribution(expected)
if err != nil {
- t.Errorf(err.String())
+ t.Errorf(err.Error())
}
}
@@ -131,10 +131,19 @@ func TestStandardNormalValues(t *testing.T) {
}
func TestNonStandardNormalValues(t *testing.T) {
- for sd := 0.5; sd < 1000; sd *= 2 {
- for m := 0.5; m < 1000; m *= 2 {
+ sdmax := 1000.0
+ mmax := 1000.0
+ if testing.Short() {
+ sdmax = 5
+ mmax = 5
+ }
+ for sd := 0.5; sd < sdmax; sd *= 2 {
+ for m := 0.5; m < mmax; m *= 2 {
for _, seed := range testSeeds {
testNormalDistribution(t, numTestSamples, m, sd, seed)
+ if testing.Short() {
+ break
+ }
}
}
}
@@ -185,6 +194,9 @@ func TestNonStandardExponentialValues(t *testing.T) {
for rate := 0.05; rate < 10; rate *= 2 {
for _, seed := range testSeeds {
testExponentialDistribution(t, numTestSamples, rate, seed)
+ if testing.Short() {
+ break
+ }
}
}
}
diff --git a/src/pkg/rand/rng.go b/src/pkg/math/rand/rng.go
index 947c49f0f..947c49f0f 100644
--- a/src/pkg/rand/rng.go
+++ b/src/pkg/math/rand/rng.go
diff --git a/src/pkg/rand/zipf.go b/src/pkg/math/rand/zipf.go
index 38e8ec516..38e8ec516 100644
--- a/src/pkg/rand/zipf.go
+++ b/src/pkg/math/rand/zipf.go
diff --git a/src/pkg/math/remainder.go b/src/pkg/math/remainder.go
index be8724c7f..41efd7908 100644
--- a/src/pkg/math/remainder.go
+++ b/src/pkg/math/remainder.go
@@ -24,28 +24,28 @@ package math
// precision arithmetic, where [x/y] is the (infinite bit)
// integer nearest x/y (in half way cases, choose the even one).
// Method :
-// Based on fmod() returning x - [x/y]chopped * y exactly.
+// Based on Mod() returning x - [x/y]chopped * y exactly.
// Remainder returns the IEEE 754 floating-point remainder of x/y.
//
// Special cases are:
-// Remainder(x, NaN) = NaN
+// Remainder(±Inf, y) = NaN
// Remainder(NaN, y) = NaN
-// Remainder(Inf, y) = NaN
// Remainder(x, 0) = NaN
-// Remainder(x, Inf) = x
-func Remainder(x, y float64) float64 {
+// Remainder(x, ±Inf) = x
+// Remainder(x, NaN) = NaN
+func Remainder(x, y float64) float64
+
+func remainder(x, y float64) float64 {
const (
Tiny = 4.45014771701440276618e-308 // 0x0020000000000000
HalfMax = MaxFloat64 / 2
)
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
// special cases
switch {
- case x != x || y != y || x < -MaxFloat64 || x > MaxFloat64 || y == 0: // IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
+ case IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
return NaN()
- case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y):
+ case IsInf(y, 0):
return x
}
sign := false
@@ -60,7 +60,7 @@ func Remainder(x, y float64) float64 {
return 0
}
if y <= HalfMax {
- x = Fmod(x, y+y) // now x < 2y
+ x = Mod(x, y+y) // now x < 2y
}
if y < Tiny {
if x+x > y {
diff --git a/src/pkg/math/remainder_amd64.s b/src/pkg/math/remainder_amd64.s
new file mode 100644
index 000000000..f04bd3de7
--- /dev/null
+++ b/src/pkg/math/remainder_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Remainder(SB),7,$0
+ JMP ·remainder(SB)
diff --git a/src/pkg/math/remainder_arm.s b/src/pkg/math/remainder_arm.s
new file mode 100644
index 000000000..642af6a85
--- /dev/null
+++ b/src/pkg/math/remainder_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Remainder(SB),7,$0
+ B ·remainder(SB)
diff --git a/src/pkg/math/remainder_decl.go b/src/pkg/math/remainder_decl.go
deleted file mode 100644
index 1407d9a6a..000000000
--- a/src/pkg/math/remainder_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Remainder(x, y float64) float64
diff --git a/src/pkg/math/sin.go b/src/pkg/math/sin.go
index 8a2edd7e5..8beb8bbe3 100644
--- a/src/pkg/math/sin.go
+++ b/src/pkg/math/sin.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,60 +6,219 @@ package math
/*
Floating-point sine and cosine.
-
- Coefficients are #5077 from Hart & Cheney. (18.80D)
*/
-func sinus(x float64, quad int) float64 {
+// The original C code, the long comment, and the constants
+// below were from http://netlib.sandia.gov/cephes/cmath/sin.c,
+// available from http://www.netlib.org/cephes/cmath.tgz.
+// The go code is a simplified version of the original C.
+//
+// sin.c
+//
+// Circular sine
+//
+// SYNOPSIS:
+//
+// double x, y, sin();
+// y = sin( x );
+//
+// DESCRIPTION:
+//
+// Range reduction is into intervals of pi/4. The reduction error is nearly
+// eliminated by contriving an extended precision modular arithmetic.
+//
+// Two polynomial approximating functions are employed.
+// Between 0 and pi/4 the sine is approximated by
+// x + x**3 P(x**2).
+// Between pi/4 and pi/2 the cosine is represented as
+// 1 - x**2 Q(x**2).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC 0, 10 150000 3.0e-17 7.8e-18
+// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
+//
+// Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss
+// is not gradual, but jumps suddenly to about 1 part in 10e7. Results may
+// be meaningless for x > 2**49 = 5.6e14.
+//
+// cos.c
+//
+// Circular cosine
+//
+// SYNOPSIS:
+//
+// double x, y, cos();
+// y = cos( x );
+//
+// DESCRIPTION:
+//
+// Range reduction is into intervals of pi/4. The reduction error is nearly
+// eliminated by contriving an extended precision modular arithmetic.
+//
+// Two polynomial approximating functions are employed.
+// Between 0 and pi/4 the cosine is approximated by
+// 1 - x**2 Q(x**2).
+// Between pi/4 and pi/2 the sine is represented as
+// x + x**3 P(x**2).
+//
+// ACCURACY:
+//
+// Relative error:
+// arithmetic domain # trials peak rms
+// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
+// DEC 0,+1.07e9 17000 3.0e-17 7.2e-18
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// sin coefficients
+var _sin = [...]float64{
+ 1.58962301576546568060E-10, // 0x3de5d8fd1fd19ccd
+ -2.50507477628578072866E-8, // 0xbe5ae5e5a9291f5d
+ 2.75573136213857245213E-6, // 0x3ec71de3567d48a1
+ -1.98412698295895385996E-4, // 0xbf2a01a019bfdf03
+ 8.33333333332211858878E-3, // 0x3f8111111110f7d0
+ -1.66666666666666307295E-1, // 0xbfc5555555555548
+}
+
+// cos coefficients
+var _cos = [...]float64{
+ -1.13585365213876817300E-11, // 0xbda8fa49a0861a9b
+ 2.08757008419747316778E-9, // 0x3e21ee9d7b4e3f05
+ -2.75573141792967388112E-7, // 0xbe927e4f7eac4bc6
+ 2.48015872888517045348E-5, // 0x3efa01a019c844f5
+ -1.38888888888730564116E-3, // 0xbf56c16c16c14f91
+ 4.16666666666665929218E-2, // 0x3fa555555555554b
+}
+
+// Cos returns the cosine of x.
+//
+// Special cases are:
+// Cos(±Inf) = NaN
+// Cos(NaN) = NaN
+func Cos(x float64) float64
+
+func cos(x float64) float64 {
const (
- P0 = .1357884097877375669092680e8
- P1 = -.4942908100902844161158627e7
- P2 = .4401030535375266501944918e6
- P3 = -.1384727249982452873054457e5
- P4 = .1459688406665768722226959e3
- Q0 = .8644558652922534429915149e7
- Q1 = .4081792252343299749395779e6
- Q2 = .9463096101538208180571257e4
- Q3 = .1326534908786136358911494e3
+ PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts
+ PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000,
+ PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170,
+ M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi
)
+ // special cases
+ switch {
+ case IsNaN(x) || IsInf(x, 0):
+ return NaN()
+ }
+
+ // make argument positive
+ sign := false
if x < 0 {
x = -x
- quad = quad + 2
}
- x = x * (2 / Pi) /* underflow? */
- var y float64
- if x > 32764 {
- var e float64
- e, y = Modf(x)
- e = e + float64(quad)
- f, _ := Modf(0.25 * e)
- quad = int(e - 4*f)
- } else {
- k := int32(x)
- y = x - float64(k)
- quad = (quad + int(k)) & 3
+
+ j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
+ y := float64(j) // integer part of x/(Pi/4), as float
+
+ // map zeros to origin
+ if j&1 == 1 {
+ j += 1
+ y += 1
+ }
+ j &= 7 // octant modulo 2Pi radians (360 degrees)
+ if j > 3 {
+ j -= 4
+ sign = !sign
+ }
+ if j > 1 {
+ sign = !sign
}
- if quad&1 != 0 {
- y = 1 - y
+ z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
+ zz := z * z
+ if j == 1 || j == 2 {
+ y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
+ } else {
+ y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
}
- if quad > 1 {
+ if sign {
y = -y
}
-
- yy := y * y
- temp1 := ((((P4*yy+P3)*yy+P2)*yy+P1)*yy + P0) * y
- temp2 := ((((yy+Q3)*yy+Q2)*yy+Q1)*yy + Q0)
- return temp1 / temp2
+ return y
}
-// Cos returns the cosine of x.
-func Cos(x float64) float64 {
+// Sin returns the sine of x.
+//
+// Special cases are:
+// Sin(±0) = ±0
+// Sin(±Inf) = NaN
+// Sin(NaN) = NaN
+func Sin(x float64) float64
+
+func sin(x float64) float64 {
+ const (
+ PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts
+ PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000,
+ PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170,
+ M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi
+ )
+ // special cases
+ switch {
+ case x == 0 || IsNaN(x):
+ return x // return ±0 || NaN()
+ case IsInf(x, 0):
+ return NaN()
+ }
+
+ // make argument positive but save the sign
+ sign := false
if x < 0 {
x = -x
+ sign = true
}
- return sinus(x, 1)
-}
-// Sin returns the sine of x.
-func Sin(x float64) float64 { return sinus(x, 0) }
+ j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
+ y := float64(j) // integer part of x/(Pi/4), as float
+
+ // map zeros to origin
+ if j&1 == 1 {
+ j += 1
+ y += 1
+ }
+ j &= 7 // octant modulo 2Pi radians (360 degrees)
+ // reflect in x axis
+ if j > 3 {
+ sign = !sign
+ j -= 4
+ }
+
+ z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
+ zz := z * z
+ if j == 1 || j == 2 {
+ y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
+ } else {
+ y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
+ }
+ if sign {
+ y = -y
+ }
+ return y
+}
diff --git a/src/pkg/math/atan_decl.go b/src/pkg/math/sin_amd64.s
index 14d3fc014..c9c99e5b3 100644
--- a/src/pkg/math/atan_decl.go
+++ b/src/pkg/math/sin_amd64.s
@@ -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 math
+TEXT ·Sin(SB),7,$0
+ JMP ·sin(SB)
-func Atan(x float64) float64
+TEXT ·Cos(SB),7,$0
+ JMP ·cos(SB)
diff --git a/src/pkg/math/exp_decl.go b/src/pkg/math/sin_arm.s
index dc8404c4f..9447ca2eb 100644
--- a/src/pkg/math/exp_decl.go
+++ b/src/pkg/math/sin_arm.s
@@ -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 math
+TEXT ·Sin(SB),7,$0
+ B ·sin(SB)
-func Exp(x float64) float64
+TEXT ·Cos(SB),7,$0
+ B ·cos(SB)
diff --git a/src/pkg/math/sin_decl.go b/src/pkg/math/sin_decl.go
deleted file mode 100644
index fc37b032c..000000000
--- a/src/pkg/math/sin_decl.go
+++ /dev/null
@@ -1,8 +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 math
-
-func Cos(x float64) float64
-func Sin(x float64) float64
diff --git a/src/pkg/math/sincos.go b/src/pkg/math/sincos.go
index 4c1576bea..730042920 100644
--- a/src/pkg/math/sincos.go
+++ b/src/pkg/math/sincos.go
@@ -4,10 +4,66 @@
package math
+// Coefficients _sin[] and _cos[] are found in pkg/math/sin.go.
+
// Sincos(x) returns Sin(x), Cos(x).
//
-// Special conditions are:
-// Sincos(+Inf) = NaN, NaN
-// Sincos(-Inf) = NaN, NaN
+// Special cases are:
+// Sincos(±0) = ±0, 1
+// Sincos(±Inf) = NaN, NaN
// Sincos(NaN) = NaN, NaN
-func Sincos(x float64) (sin, cos float64) { return Sin(x), Cos(x) }
+func Sincos(x float64) (sin, cos float64)
+
+func sincos(x float64) (sin, cos float64) {
+ const (
+ PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts
+ PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000,
+ PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170,
+ M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi
+ )
+ // special cases
+ switch {
+ case x == 0:
+ return x, 1 // return ±0.0, 1.0
+ case IsNaN(x) || IsInf(x, 0):
+ return NaN(), NaN()
+ }
+
+ // make argument positive
+ sinSign, cosSign := false, false
+ if x < 0 {
+ x = -x
+ sinSign = true
+ }
+
+ j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
+ y := float64(j) // integer part of x/(Pi/4), as float
+
+ if j&1 == 1 { // map zeros to origin
+ j += 1
+ y += 1
+ }
+ j &= 7 // octant modulo 2Pi radians (360 degrees)
+ if j > 3 { // reflect in x axis
+ j -= 4
+ sinSign, cosSign = !sinSign, !cosSign
+ }
+ if j > 1 {
+ cosSign = !cosSign
+ }
+
+ z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
+ zz := z * z
+ cos = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
+ sin = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
+ if j == 1 || j == 2 {
+ sin, cos = cos, sin
+ }
+ if cosSign {
+ cos = -cos
+ }
+ if sinSign {
+ sin = -sin
+ }
+ return
+}
diff --git a/src/pkg/math/sincos_arm.s b/src/pkg/math/sincos_arm.s
new file mode 100644
index 000000000..3e2b0e4e0
--- /dev/null
+++ b/src/pkg/math/sincos_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Sincos(SB),7,$0
+ B ·sincos(SB)
diff --git a/src/pkg/math/sincos_decl.go b/src/pkg/math/sincos_decl.go
deleted file mode 100644
index 0b4054469..000000000
--- a/src/pkg/math/sincos_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Sincos(x float64) (sin, cos float64)
diff --git a/src/pkg/math/sinh.go b/src/pkg/math/sinh.go
index eaf28a51c..139b911fe 100644
--- a/src/pkg/math/sinh.go
+++ b/src/pkg/math/sinh.go
@@ -17,6 +17,11 @@ package math
*/
// Sinh returns the hyperbolic sine of x.
+//
+// Special cases are:
+// Sinh(±0) = ±0
+// Sinh(±Inf) = ±Inf
+// Sinh(NaN) = NaN
func Sinh(x float64) float64 {
// The coefficients are #2029 from Hart & Cheney. (20.36D)
const (
@@ -56,6 +61,11 @@ func Sinh(x float64) float64 {
}
// Cosh returns the hyperbolic cosine of x.
+//
+// Special cases are:
+// Cosh(±0) = 1
+// Cosh(±Inf) = +Inf
+// Cosh(NaN) = NaN
func Cosh(x float64) float64 {
if x < 0 {
x = -x
diff --git a/src/pkg/math/sqrt.go b/src/pkg/math/sqrt.go
index ff5cc91e0..21336df2a 100644
--- a/src/pkg/math/sqrt.go
+++ b/src/pkg/math/sqrt.go
@@ -11,4 +11,140 @@ package math
// Sqrt(±0) = ±0
// Sqrt(x < 0) = NaN
// Sqrt(NaN) = NaN
-func Sqrt(x float64) float64 { return sqrtGo(x) }
+func Sqrt(x float64) float64
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+// -----------------------------------------
+// | Use the hardware sqrt if you have one |
+// -----------------------------------------
+// Method:
+// Bit by bit method using integer arithmetic. (Slow, but portable)
+// 1. Normalization
+// Scale x to y in [1,4) with even powers of 2:
+// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
+// sqrt(x) = 2**k * sqrt(y)
+// 2. Bit by bit computation
+// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
+// i 0
+// i+1 2
+// s = 2*q , and y = 2 * ( y - q ). (1)
+// i i i i
+//
+// To compute q from q , one checks whether
+// i+1 i
+//
+// -(i+1) 2
+// (q + 2 ) <= y. (2)
+// i
+// -(i+1)
+// If (2) is false, then q = q ; otherwise q = q + 2 .
+// i+1 i i+1 i
+//
+// With some algebraic manipulation, it is not difficult to see
+// that (2) is equivalent to
+// -(i+1)
+// s + 2 <= y (3)
+// i i
+//
+// The advantage of (3) is that s and y can be computed by
+// i i
+// the following recurrence formula:
+// if (3) is false
+//
+// s = s , y = y ; (4)
+// i+1 i i+1 i
+//
+// otherwise,
+// -i -(i+1)
+// s = s + 2 , y = y - s - 2 (5)
+// i+1 i i+1 i i
+//
+// One may easily use induction to prove (4) and (5).
+// Note. Since the left hand side of (3) contain only i+2 bits,
+// it does not necessary to do a full (53-bit) comparison
+// in (3).
+// 3. Final rounding
+// After generating the 53 bits result, we compute one more bit.
+// Together with the remainder, we can decide whether the
+// result is exact, bigger than 1/2ulp, or less than 1/2ulp
+// (it will never equal to 1/2ulp).
+// The rounding mode can be detected by checking whether
+// huge + tiny is equal to huge, and whether huge - tiny is
+// equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes: Rounding mode detection omitted. The constants "mask", "shift",
+// and "bias" are found in src/pkg/math/bits.go
+
+// Sqrt returns the square root of x.
+//
+// Special cases are:
+// Sqrt(+Inf) = +Inf
+// Sqrt(±0) = ±0
+// Sqrt(x < 0) = NaN
+// Sqrt(NaN) = NaN
+func sqrt(x float64) float64 {
+ // special cases
+ switch {
+ case x == 0 || IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < 0:
+ return NaN()
+ }
+ ix := Float64bits(x)
+ // normalize x
+ exp := int((ix >> shift) & mask)
+ if exp == 0 { // subnormal x
+ for ix&1<<shift == 0 {
+ ix <<= 1
+ exp--
+ }
+ exp++
+ }
+ exp -= bias // unbias exponent
+ ix &^= mask << shift
+ ix |= 1 << shift
+ if exp&1 == 1 { // odd exp, double x to make it even
+ ix <<= 1
+ }
+ exp >>= 1 // exp = exp/2, exponent of square root
+ // generate sqrt(x) bit by bit
+ ix <<= 1
+ var q, s uint64 // q = sqrt(x)
+ r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+ for r != 0 {
+ t := s + r
+ if t <= ix {
+ s = t + r
+ ix -= t
+ q += r
+ }
+ ix <<= 1
+ r >>= 1
+ }
+ // final rounding
+ if ix != 0 { // remainder, result not exact
+ q += q & 1 // round according to extra bit
+ }
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+ return Float64frombits(ix)
+}
+
+func sqrtC(f float64, r *float64) {
+ *r = sqrt(f)
+}
diff --git a/src/pkg/math/sqrt_decl.go b/src/pkg/math/sqrt_decl.go
deleted file mode 100644
index e50774645..000000000
--- a/src/pkg/math/sqrt_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Sqrt(x float64) float64
diff --git a/src/pkg/math/sqrt_port.go b/src/pkg/math/sqrt_port.go
deleted file mode 100644
index 148239bcf..000000000
--- a/src/pkg/math/sqrt_port.go
+++ /dev/null
@@ -1,147 +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 math
-
-/*
- Floating-point square root.
-*/
-
-// The original C code and the long comment below are
-// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
-// came with this notice. The go code is a simplified
-// version of the original C.
-//
-// ====================================================
-// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
-//
-// Developed at SunPro, a Sun Microsystems, Inc. business.
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
-//
-// __ieee754_sqrt(x)
-// Return correctly rounded sqrt.
-// -----------------------------------------
-// | Use the hardware sqrt if you have one |
-// -----------------------------------------
-// Method:
-// Bit by bit method using integer arithmetic. (Slow, but portable)
-// 1. Normalization
-// Scale x to y in [1,4) with even powers of 2:
-// find an integer k such that 1 <= (y=x*2**(2k)) < 4, then
-// sqrt(x) = 2**k * sqrt(y)
-// 2. Bit by bit computation
-// Let q = sqrt(y) truncated to i bit after binary point (q = 1),
-// i 0
-// i+1 2
-// s = 2*q , and y = 2 * ( y - q ). (1)
-// i i i i
-//
-// To compute q from q , one checks whether
-// i+1 i
-//
-// -(i+1) 2
-// (q + 2 ) <= y. (2)
-// i
-// -(i+1)
-// If (2) is false, then q = q ; otherwise q = q + 2 .
-// i+1 i i+1 i
-//
-// With some algebraic manipulation, it is not difficult to see
-// that (2) is equivalent to
-// -(i+1)
-// s + 2 <= y (3)
-// i i
-//
-// The advantage of (3) is that s and y can be computed by
-// i i
-// the following recurrence formula:
-// if (3) is false
-//
-// s = s , y = y ; (4)
-// i+1 i i+1 i
-//
-// otherwise,
-// -i -(i+1)
-// s = s + 2 , y = y - s - 2 (5)
-// i+1 i i+1 i i
-//
-// One may easily use induction to prove (4) and (5).
-// Note. Since the left hand side of (3) contain only i+2 bits,
-// it does not necessary to do a full (53-bit) comparison
-// in (3).
-// 3. Final rounding
-// After generating the 53 bits result, we compute one more bit.
-// Together with the remainder, we can decide whether the
-// result is exact, bigger than 1/2ulp, or less than 1/2ulp
-// (it will never equal to 1/2ulp).
-// The rounding mode can be detected by checking whether
-// huge + tiny is equal to huge, and whether huge - tiny is
-// equal to huge for some floating point number "huge" and "tiny".
-//
-//
-// Notes: Rounding mode detection omitted. The constants "mask", "shift",
-// and "bias" are found in src/pkg/math/bits.go
-
-// Sqrt returns the square root of x.
-//
-// Special cases are:
-// Sqrt(+Inf) = +Inf
-// Sqrt(±0) = ±0
-// Sqrt(x < 0) = NaN
-// Sqrt(NaN) = NaN
-func sqrtGo(x float64) float64 {
- // special cases
- // TODO(rsc): Remove manual inlining of IsNaN, IsInf
- // when compiler does it for us
- switch {
- case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
- return x
- case x < 0:
- return NaN()
- }
- ix := Float64bits(x)
- // normalize x
- exp := int((ix >> shift) & mask)
- if exp == 0 { // subnormal x
- for ix&1<<shift == 0 {
- ix <<= 1
- exp--
- }
- exp++
- }
- exp -= bias // unbias exponent
- ix &^= mask << shift
- ix |= 1 << shift
- if exp&1 == 1 { // odd exp, double x to make it even
- ix <<= 1
- }
- exp >>= 1 // exp = exp/2, exponent of square root
- // generate sqrt(x) bit by bit
- ix <<= 1
- var q, s uint64 // q = sqrt(x)
- r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
- for r != 0 {
- t := s + r
- if t <= ix {
- s = t + r
- ix -= t
- q += r
- }
- ix <<= 1
- r >>= 1
- }
- // final rounding
- if ix != 0 { // remainder, result not exact
- q += q & 1 // round according to extra bit
- }
- ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
- return Float64frombits(ix)
-}
-
-func sqrtGoC(f float64, r *float64) {
- *r = sqrtGo(f)
-}
diff --git a/src/pkg/math/sqrt_test.go b/src/pkg/math/sqrt_test.go
deleted file mode 100644
index 84cbc169e..000000000
--- a/src/pkg/math/sqrt_test.go
+++ /dev/null
@@ -1,9 +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 math
-
-// Make sqrtGo available for testing.
-
-func SqrtGo(x float64) float64 { return sqrtGo(x) }
diff --git a/src/pkg/math/tan.go b/src/pkg/math/tan.go
index 6d7a60ba6..b2f29cc3b 100644
--- a/src/pkg/math/tan.go
+++ b/src/pkg/math/tan.go
@@ -1,64 +1,130 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package math
/*
- Floating point tangent.
+ Floating-point tangent.
*/
+// The original C code, the long comment, and the constants
+// below were from http://netlib.sandia.gov/cephes/cmath/sin.c,
+// available from http://www.netlib.org/cephes/cmath.tgz.
+// The go code is a simplified version of the original C.
+//
+// tan.c
+//
+// Circular tangent
+//
+// SYNOPSIS:
+//
+// double x, y, tan();
+// y = tan( x );
+//
+// DESCRIPTION:
+//
+// Returns the circular tangent of the radian argument x.
+//
+// Range reduction is modulo pi/4. A rational function
+// x + x**3 P(x**2)/Q(x**2)
+// is employed in the basic interval [0, pi/4].
+//
+// ACCURACY:
+// Relative error:
+// arithmetic domain # trials peak rms
+// DEC +-1.07e9 44000 4.1e-17 1.0e-17
+// IEEE +-1.07e9 30000 2.9e-16 8.1e-17
+//
+// Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss
+// is not gradual, but jumps suddenly to about 1 part in 10e7. Results may
+// be meaningless for x > 2**49 = 5.6e14.
+// [Accuracy loss statement from sin.go comments.]
+//
+// Cephes Math Library Release 2.8: June, 2000
+// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
+//
+// The readme file at http://netlib.sandia.gov/cephes/ says:
+// Some software in this archive may be from the book _Methods and
+// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
+// International, 1989) or from the Cephes Mathematical Library, a
+// commercial product. In either event, it is copyrighted by the author.
+// What you see here may be used freely but it comes with no support or
+// guarantee.
+//
+// The two known misprints in the book are repaired here in the
+// source listings for the gamma function and the incomplete beta
+// integral.
+//
+// Stephen L. Moshier
+// moshier@na-net.ornl.gov
+
+// tan coefficients
+var _tanP = [...]float64{
+ -1.30936939181383777646E4, // 0xc0c992d8d24f3f38
+ 1.15351664838587416140E6, // 0x413199eca5fc9ddd
+ -1.79565251976484877988E7, // 0xc1711fead3299176
+}
+var _tanQ = [...]float64{
+ 1.00000000000000000000E0,
+ 1.36812963470692954678E4, //0x40cab8a5eeb36572
+ -1.32089234440210967447E6, //0xc13427bc582abc96
+ 2.50083801823357915839E7, //0x4177d98fc2ead8ef
+ -5.38695755929454629881E7, //0xc189afe03cbe5a31
+}
+
// Tan returns the tangent of x.
-func Tan(x float64) float64 {
- // Coefficients are #4285 from Hart & Cheney. (19.74D)
+//
+// Special cases are:
+// Tan(±0) = ±0
+// Tan(±Inf) = NaN
+// Tan(NaN) = NaN
+func Tan(x float64) float64
+
+func tan(x float64) float64 {
const (
- P0 = -.1306820264754825668269611177e+5
- P1 = .1055970901714953193602353981e+4
- P2 = -.1550685653483266376941705728e+2
- P3 = .3422554387241003435328470489e-1
- P4 = .3386638642677172096076369e-4
- Q0 = -.1663895238947119001851464661e+5
- Q1 = .4765751362916483698926655581e+4
- Q2 = -.1555033164031709966900124574e+3
+ PI4A = 7.85398125648498535156E-1 // 0x3fe921fb40000000, Pi/4 split into three parts
+ PI4B = 3.77489470793079817668E-8 // 0x3e64442d00000000,
+ PI4C = 2.69515142907905952645E-15 // 0x3ce8469898cc5170,
+ M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi
)
+ // special cases
+ switch {
+ case x == 0 || IsNaN(x):
+ return x // return ±0 || NaN()
+ case IsInf(x, 0):
+ return NaN()
+ }
- flag := false
+ // make argument positive but save the sign
sign := false
if x < 0 {
x = -x
sign = true
}
- x = x * (4 / Pi) /* overflow? */
- var e float64
- e, x = Modf(x)
- i := int32(e)
- switch i & 3 {
- case 1:
- x = 1 - x
- flag = true
+ j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
+ y := float64(j) // integer part of x/(Pi/4), as float
- case 2:
- sign = !sign
- flag = true
-
- case 3:
- x = 1 - x
- sign = !sign
+ /* map zeros and singularities to origin */
+ if j&1 == 1 {
+ j += 1
+ y += 1
}
- xsq := x * x
- temp := ((((P4*xsq+P3)*xsq+P2)*xsq+P1)*xsq + P0) * x
- temp = temp / (((xsq+Q2)*xsq+Q1)*xsq + Q0)
+ z := ((x - y*PI4A) - y*PI4B) - y*PI4C
+ zz := z * z
- if flag {
- if temp == 0 {
- return NaN()
- }
- temp = 1 / temp
+ if zz > 1e-14 {
+ y = z + z*(zz*(((_tanP[0]*zz)+_tanP[1])*zz+_tanP[2])/((((zz+_tanQ[1])*zz+_tanQ[2])*zz+_tanQ[3])*zz+_tanQ[4]))
+ } else {
+ y = z
+ }
+ if j&2 == 2 {
+ y = -1 / y
}
if sign {
- temp = -temp
+ y = -y
}
- return temp
+ return y
}
diff --git a/src/pkg/math/tan_amd64.s b/src/pkg/math/tan_amd64.s
new file mode 100644
index 000000000..823ceb254
--- /dev/null
+++ b/src/pkg/math/tan_amd64.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Tan(SB),7,$0
+ JMP ·tan(SB)
diff --git a/src/pkg/math/tan_arm.s b/src/pkg/math/tan_arm.s
new file mode 100644
index 000000000..4be35c38b
--- /dev/null
+++ b/src/pkg/math/tan_arm.s
@@ -0,0 +1,6 @@
+// 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.
+
+TEXT ·Tan(SB),7,$0
+ B ·tan(SB)
diff --git a/src/pkg/math/tan_decl.go b/src/pkg/math/tan_decl.go
deleted file mode 100644
index 2796b3501..000000000
--- a/src/pkg/math/tan_decl.go
+++ /dev/null
@@ -1,7 +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 math
-
-func Tan(x float64) float64
diff --git a/src/pkg/math/tanh.go b/src/pkg/math/tanh.go
index f4a8a5a4d..03a641b4d 100644
--- a/src/pkg/math/tanh.go
+++ b/src/pkg/math/tanh.go
@@ -12,6 +12,11 @@ package math
*/
// Tanh computes the hyperbolic tangent of x.
+//
+// Special cases are:
+// Tanh(±0) = ±0
+// Tanh(±Inf) = ±1
+// Tanh(NaN) = NaN
func Tanh(x float64) float64 {
if x < 0 {
x = -x
diff --git a/src/pkg/mime/Makefile b/src/pkg/mime/Makefile
deleted file mode 100644
index 901ed6f8e..000000000
--- a/src/pkg/mime/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=mime
-GOFILES=\
- grammar.go\
- mediatype.go\
- type.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/mime/grammar.go b/src/pkg/mime/grammar.go
index 6e319ff8b..83cc41134 100644
--- a/src/pkg/mime/grammar.go
+++ b/src/pkg/mime/grammar.go
@@ -10,27 +10,36 @@ import (
// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
// 1521 and RFC 2045.
-func isTSpecial(rune int) bool {
- return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
+func isTSpecial(r rune) bool {
+ return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1
}
-// IsTokenChar returns true if rune is in 'token' as defined by RFC
+// isTokenChar returns true if rune is in 'token' as defined by RFC
// 1521 and RFC 2045.
-func IsTokenChar(rune int) bool {
+func isTokenChar(r rune) bool {
// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
// or tspecials>
- return rune > 0x20 && rune < 0x7f && !isTSpecial(rune)
+ return r > 0x20 && r < 0x7f && !isTSpecial(r)
}
-// IsQText returns true if rune is in 'qtext' as defined by RFC 822.
-func IsQText(rune int) bool {
+// isToken returns true if s is a 'token' as as defined by RFC 1521
+// and RFC 2045.
+func isToken(s string) bool {
+ if s == "" {
+ return false
+ }
+ return strings.IndexFunc(s, isNotTokenChar) < 0
+}
+
+// isQText returns true if rune is in 'qtext' as defined by RFC 822.
+func isQText(r int) bool {
// CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
// qtext = <any CHAR excepting <">, ; => may be folded
// "\" & CR, and including
// linear-white-space>
- switch rune {
+ switch r {
case '"', '\\', '\r':
return false
}
- return rune < 0x80
+ return r < 0x80
}
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index 40c735c5b..9398dece1 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -6,46 +6,100 @@ package mime
import (
"bytes"
+ "errors"
"fmt"
- "os"
"strings"
"unicode"
)
-func validMediaTypeOrDisposition(s string) bool {
+// FormatMediaType serializes mediatype t and the parameters
+// param as a media type conforming to RFC 2045 and RFC 2616.
+// The type and parameter names are written in lower-case.
+// When any of the arguments result in a standard violation then
+// FormatMediaType returns the empty string.
+func FormatMediaType(t string, param map[string]string) string {
+ slash := strings.Index(t, "/")
+ if slash == -1 {
+ return ""
+ }
+ major, sub := t[:slash], t[slash+1:]
+ if !isToken(major) || !isToken(sub) {
+ return ""
+ }
+ var b bytes.Buffer
+ b.WriteString(strings.ToLower(major))
+ b.WriteByte('/')
+ b.WriteString(strings.ToLower(sub))
+
+ for attribute, value := range param {
+ b.WriteByte(';')
+ b.WriteByte(' ')
+ if !isToken(attribute) {
+ return ""
+ }
+ b.WriteString(strings.ToLower(attribute))
+ b.WriteByte('=')
+ if isToken(value) {
+ b.WriteString(value)
+ continue
+ }
+
+ b.WriteByte('"')
+ offset := 0
+ for index, character := range value {
+ if character == '"' || character == '\r' {
+ b.WriteString(value[offset:index])
+ offset = index
+ b.WriteByte('\\')
+ }
+ if character&0x80 != 0 {
+ return ""
+ }
+ }
+ b.WriteString(value[offset:])
+ b.WriteByte('"')
+ }
+ return b.String()
+}
+
+func checkMediaTypeDisposition(s string) error {
typ, rest := consumeToken(s)
if typ == "" {
- return false
+ return errors.New("mime: no media type")
}
if rest == "" {
- return true
+ return nil
}
if !strings.HasPrefix(rest, "/") {
- return false
+ return errors.New("mime: expected slash after first token")
}
subtype, rest := consumeToken(rest[1:])
if subtype == "" {
- return false
+ return errors.New("mime: expected token after slash")
}
- return rest == ""
+ if rest != "" {
+ return errors.New("mime: unexpected content after media subtype")
+ }
+ return nil
}
// ParseMediaType parses a media type value and any optional
// 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
+// to lowercase and trimmed of white space and a non-nil map.
+// The returned 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) {
+func ParseMediaType(v string) (mediatype string, params map[string]string, err error) {
i := strings.Index(v, ";")
if i == -1 {
i = len(v)
}
mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
- if !validMediaTypeOrDisposition(mediatype) {
- return "", nil
+
+ err = checkMediaTypeDisposition(mediatype)
+ if err != nil {
+ return
}
params = make(map[string]string)
@@ -69,7 +123,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string) {
return
}
// Parse error.
- return "", nil
+ return "", nil, errors.New("mime: invalid media parameter")
}
pmap := params
@@ -86,7 +140,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string) {
}
if _, exists := pmap[key]; exists {
// Duplicate parameter name is bogus.
- return "", nil
+ return "", nil, errors.New("mime: duplicate parameter name")
}
pmap[key] = value
v = rest
@@ -150,8 +204,8 @@ func decode2231Enc(v string) string {
return encv
}
-func isNotTokenChar(rune int) bool {
- return !IsTokenChar(rune)
+func isNotTokenChar(r rune) bool {
+ return !isTokenChar(r)
}
// consumeToken consumes a token from the beginning of provided
@@ -179,24 +233,25 @@ func consumeValue(v string) (value, rest string) {
return consumeToken(v)
}
- leadQuote := int(v[0])
+ leadQuote := rune(v[0])
// parse a quoted-string
rest = v[1:] // consume the leading quote
buffer := new(bytes.Buffer)
- var idx, rune int
+ var idx int
+ var r rune
var nextIsLiteral bool
- for idx, rune = range rest {
+ for idx, r = range rest {
switch {
case nextIsLiteral:
- buffer.WriteRune(rune)
+ buffer.WriteRune(r)
nextIsLiteral = false
- case rune == leadQuote:
+ case r == leadQuote:
return buffer.String(), rest[idx+1:]
- case rune == '\\':
+ case r == '\\':
nextIsLiteral = true
- case rune != '\r' && rune != '\n':
- buffer.WriteRune(rune)
+ case r != '\r' && r != '\n':
+ buffer.WriteRune(r)
default:
return "", v
}
@@ -231,7 +286,7 @@ func consumeMediaParam(v string) (param, value, rest string) {
return param, value, rest
}
-func percentHexUnescape(s string) (string, os.Error) {
+func percentHexUnescape(s string) (string, error) {
// Count %, check that they're well-formed.
percents := 0
for i := 0; i < len(s); {
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
index 93264bd09..64ab29134 100644
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/mime/mediatype_test.go
@@ -219,7 +219,14 @@ func TestParseMediaType(t *testing.T) {
m("firstname", "Брэд", "lastname", "Фицпатрик")},
}
for _, test := range tests {
- mt, params := ParseMediaType(test.in)
+ mt, params, err := ParseMediaType(test.in)
+ if err != nil {
+ if test.t != "" {
+ t.Errorf("for input %q, unexpected error: %v", test.in, err)
+ continue
+ }
+ continue
+ }
if g, e := mt, test.t; g != e {
t.Errorf("for input %q, expected type %q, got %q",
test.in, e, g)
@@ -238,11 +245,32 @@ func TestParseMediaType(t *testing.T) {
}
func TestParseMediaTypeBogus(t *testing.T) {
- mt, params := ParseMediaType("bogus ;=========")
- if mt != "" {
- t.Error("expected empty type")
+ mt, params, err := ParseMediaType("bogus ;=========")
+ if err == nil {
+ t.Fatalf("expected an error parsing invalid media type; got type %q, params %#v", mt, params)
+ }
+ if err.Error() != "mime: invalid media parameter" {
+ t.Errorf("expected invalid media parameter; got error %q", err)
}
- if params != nil {
- t.Error("expected nil params")
+}
+
+type formatTest struct {
+ typ string
+ params map[string]string
+ want string
+}
+
+var formatTests = []formatTest{
+ {"noslash", nil, ""},
+ {"foo/BAR", nil, "foo/bar"},
+ {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"},
+}
+
+func TestFormatMediaType(t *testing.T) {
+ for i, tt := range formatTests {
+ got := FormatMediaType(tt.typ, tt.params)
+ if got != tt.want {
+ t.Errorf("%d. FormatMediaType(%q, %v) = %q; want %q", i, tt.typ, tt.params, got, tt.want)
+ }
}
}
diff --git a/src/pkg/mime/mime_test.go b/src/pkg/mime/mime_test.go
deleted file mode 100644
index 17e610443..000000000
--- a/src/pkg/mime/mime_test.go
+++ /dev/null
@@ -1,27 +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.
-
-// Tests for type.go
-
-package mime
-
-import "testing"
-
-var typeTests = map[string]string{
- ".t1": "application/test",
- ".t2": "text/test; charset=utf-8",
- ".png": "image/png",
-}
-
-func TestType(t *testing.T) {
- typeFiles = []string{"test.types"}
-
- for ext, want := range typeTests {
- val := TypeByExtension(ext)
- if val != want {
- t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
- }
-
- }
-}
diff --git a/src/pkg/mime/multipart/Makefile b/src/pkg/mime/multipart/Makefile
deleted file mode 100644
index de1a439f2..000000000
--- a/src/pkg/mime/multipart/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=mime/multipart
-GOFILES=\
- formdata.go\
- multipart.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/mime/multipart/formdata.go b/src/pkg/mime/multipart/formdata.go
index 91404d6f4..eee53fc8d 100644
--- a/src/pkg/mime/multipart/formdata.go
+++ b/src/pkg/mime/multipart/formdata.go
@@ -6,6 +6,7 @@ package multipart
import (
"bytes"
+ "errors"
"io"
"io/ioutil"
"net/textproto"
@@ -19,7 +20,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 *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
+func (r *Reader) ReadForm(maxMemory int64) (f *Form, err error) {
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
defer func() {
if err != nil {
@@ -30,7 +31,7 @@ func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
maxValueBytes := int64(10 << 20) // 10 MB is a lot of text.
for {
p, err := r.NextPart()
- if err == os.EOF {
+ if err == io.EOF {
break
}
if err != nil {
@@ -47,13 +48,13 @@ func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
if filename == "" {
// value, store as string in memory
- n, err := io.Copyn(&b, p, maxValueBytes)
- if err != nil && err != os.EOF {
+ n, err := io.CopyN(&b, p, maxValueBytes)
+ if err != nil && err != io.EOF {
return nil, err
}
maxValueBytes -= n
if maxValueBytes == 0 {
- return nil, os.NewError("multipart: message too large")
+ return nil, errors.New("multipart: message too large")
}
form.Value[name] = append(form.Value[name], b.String())
continue
@@ -64,8 +65,8 @@ func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
Filename: filename,
Header: p.Header,
}
- n, err := io.Copyn(&b, p, maxMemory+1)
- if err != nil && err != os.EOF {
+ n, err := io.CopyN(&b, p, maxMemory+1)
+ if err != nil && err != io.EOF {
return nil, err
}
if n > maxMemory {
@@ -102,8 +103,8 @@ type Form struct {
}
// RemoveAll removes any temporary files associated with a Form.
-func (f *Form) RemoveAll() os.Error {
- var err os.Error
+func (f *Form) RemoveAll() error {
+ var err error
for _, fhs := range f.File {
for _, fh := range fhs {
if fh.tmpfile != "" {
@@ -127,9 +128,9 @@ type FileHeader struct {
}
// Open opens and returns the FileHeader's associated File.
-func (fh *FileHeader) Open() (File, os.Error) {
+func (fh *FileHeader) Open() (File, error) {
if b := fh.content; b != nil {
- r := io.NewSectionReader(sliceReaderAt(b), 0, int64(len(b)))
+ r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b)))
return sectionReadCloser{r}, nil
}
return os.Open(fh.tmpfile)
@@ -151,16 +152,6 @@ type sectionReadCloser struct {
*io.SectionReader
}
-func (rc sectionReadCloser) Close() os.Error {
+func (rc sectionReadCloser) Close() error {
return nil
}
-
-type sliceReaderAt []byte
-
-func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
- if int(off) >= len(r) || off < 0 {
- return 0, os.EINVAL
- }
- n := copy(b, r[int(off):])
- return n, nil
-}
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 2533bd337..d733130ab 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -20,7 +20,6 @@ import (
"io/ioutil"
"mime"
"net/textproto"
- "os"
)
// TODO(bradfitz): inline these once the compiler can inline them in
@@ -69,8 +68,9 @@ func (p *Part) FileName() string {
func (p *Part) parseContentDisposition() {
v := p.Header.Get("Content-Disposition")
- p.disposition, p.dispositionParams = mime.ParseMediaType(v)
- if p.dispositionParams == nil {
+ var err error
+ p.disposition, p.dispositionParams, err = mime.ParseMediaType(v)
+ if err != nil {
p.dispositionParams = emptyParams
}
}
@@ -89,7 +89,7 @@ func NewReader(reader io.Reader, boundary string) *Reader {
}
}
-func newPart(mr *Reader) (*Part, os.Error) {
+func newPart(mr *Reader) (*Part, error) {
bp := &Part{
Header: make(map[string][]string),
mr: mr,
@@ -101,7 +101,7 @@ func newPart(mr *Reader) (*Part, os.Error) {
return bp, nil
}
-func (bp *Part) populateHeaders() os.Error {
+func (bp *Part) populateHeaders() error {
r := textproto.NewReader(bp.mr.bufReader)
header, err := r.ReadMIMEHeader()
if err == nil {
@@ -112,14 +112,14 @@ func (bp *Part) populateHeaders() os.Error {
// Read reads the body of a part, after its headers and before the
// next part (if any) begins.
-func (bp *Part) Read(p []byte) (n int, err os.Error) {
- if bp.buffer.Len() >= len(p) {
+func (p *Part) Read(d []byte) (n int, err error) {
+ if p.buffer.Len() >= len(d) {
// Internal buffer of unconsumed data is large enough for
// the read request. No need to parse more at the moment.
- return bp.buffer.Read(p)
+ return p.buffer.Read(d)
}
- peek, err := bp.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
- unexpectedEof := err == os.EOF
+ peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
+ unexpectedEof := err == io.EOF
if err != nil && !unexpectedEof {
return 0, fmt.Errorf("multipart: Part Read: %v", err)
}
@@ -133,10 +133,10 @@ func (bp *Part) Read(p []byte) (n int, err os.Error) {
// string.
nCopy := 0
foundBoundary := false
- if idx := bytes.Index(peek, bp.mr.nlDashBoundary); idx != -1 {
+ if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
nCopy = idx
foundBoundary = true
- } else if safeCount := len(peek) - len(bp.mr.nlDashBoundary); safeCount > 0 {
+ } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
nCopy = safeCount
} else if unexpectedEof {
// If we've run out of peek buffer and the boundary
@@ -145,12 +145,12 @@ func (bp *Part) Read(p []byte) (n int, err os.Error) {
return 0, io.ErrUnexpectedEOF
}
if nCopy > 0 {
- if _, err := io.Copyn(bp.buffer, bp.mr.bufReader, int64(nCopy)); err != nil {
+ if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
return 0, err
}
}
- n, err = bp.buffer.Read(p)
- if err == os.EOF && !foundBoundary {
+ n, err = p.buffer.Read(d)
+ if err == io.EOF && !foundBoundary {
// If the boundary hasn't been reached there's more to
// read, so don't pass through an EOF from the buffer
err = nil
@@ -158,8 +158,8 @@ func (bp *Part) Read(p []byte) (n int, err os.Error) {
return
}
-func (bp *Part) Close() os.Error {
- io.Copy(ioutil.Discard, bp)
+func (p *Part) Close() error {
+ io.Copy(ioutil.Discard, p)
return nil
}
@@ -176,39 +176,39 @@ type Reader struct {
}
// 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()
+// When there are no more parts, the error io.EOF is returned.
+func (r *Reader) NextPart() (*Part, error) {
+ if r.currentPart != nil {
+ r.currentPart.Close()
}
expectNewPart := false
for {
- line, err := mr.bufReader.ReadSlice('\n')
+ line, err := r.bufReader.ReadSlice('\n')
if err != nil {
return nil, fmt.Errorf("multipart: NextPart: %v", err)
}
- if mr.isBoundaryDelimiterLine(line) {
- mr.partsRead++
- bp, err := newPart(mr)
+ if r.isBoundaryDelimiterLine(line) {
+ r.partsRead++
+ bp, err := newPart(r)
if err != nil {
return nil, err
}
- mr.currentPart = bp
+ r.currentPart = bp
return bp, nil
}
- if hasPrefixThenNewline(line, mr.dashBoundaryDash) {
+ if hasPrefixThenNewline(line, r.dashBoundaryDash) {
// Expected EOF
- return nil, os.EOF
+ return nil, io.EOF
}
if expectNewPart {
return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
}
- if mr.partsRead == 0 {
+ if r.partsRead == 0 {
// skip line
continue
}
@@ -217,7 +217,7 @@ func (mr *Reader) NextPart() (*Part, os.Error) {
// body of the previous part and the boundary line we
// now expect will follow. (either a new part or the
// end boundary)
- if bytes.Equal(line, mr.nl) {
+ if bytes.Equal(line, r.nl) {
expectNewPart = true
continue
}
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
index 38079e53a..89ff5e489 100644
--- a/src/pkg/mime/multipart/multipart_test.go
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -6,11 +6,10 @@ package multipart
import (
"bytes"
+ "encoding/json"
"fmt"
"io"
"io/ioutil"
- "json"
- "os"
"strings"
"testing"
)
@@ -214,8 +213,8 @@ func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
if part != nil {
t.Error("Didn't expect a fifth part.")
}
- if err != os.EOF {
- t.Errorf("On fifth part expected os.EOF; got %v", err)
+ if err != io.EOF {
+ t.Errorf("On fifth part expected io.EOF; got %v", err)
}
}
@@ -259,8 +258,8 @@ func TestVariousTextLineEndings(t *testing.T) {
if part != nil {
t.Errorf("Unexpected part in test %d", testNum)
}
- if err != os.EOF {
- t.Errorf("On test %d expected os.EOF; got %v", testNum, err)
+ if err != io.EOF {
+ t.Errorf("On test %d expected io.EOF; got %v", testNum, err)
}
}
@@ -273,11 +272,11 @@ type maliciousReader struct {
const maxReadThreshold = 1 << 20
-func (mr *maliciousReader) Read(b []byte) (n int, err os.Error) {
+func (mr *maliciousReader) Read(b []byte) (n int, err error) {
mr.n += len(b)
if mr.n >= maxReadThreshold {
mr.t.Fatal("too much was read")
- return 0, os.EOF
+ return 0, io.EOF
}
return len(b), nil
}
@@ -346,7 +345,7 @@ type slowReader struct {
r io.Reader
}
-func (s *slowReader) Read(p []byte) (int, os.Error) {
+func (s *slowReader) Read(p []byte) (int, error) {
if len(p) == 0 {
return s.r.Read(p)
}
diff --git a/src/pkg/mime/multipart/writer.go b/src/pkg/mime/multipart/writer.go
index 97a8897b2..ec70be492 100644
--- a/src/pkg/mime/multipart/writer.go
+++ b/src/pkg/mime/multipart/writer.go
@@ -7,10 +7,10 @@ package multipart
import (
"bytes"
"crypto/rand"
+ "errors"
"fmt"
"io"
"net/textproto"
- "os"
"strings"
)
@@ -54,7 +54,7 @@ func randomBoundary() string {
// 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) {
+func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
if w.lastpart != nil {
if err := w.lastpart.close(); err != nil {
return nil, err
@@ -85,15 +85,15 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, os.Error) {
return p, nil
}
+var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
+
func escapeQuotes(s string) string {
- s = strings.Replace(s, "\\", "\\\\", -1)
- s = strings.Replace(s, "\"", "\\\"", -1)
- return s
+ return quoteEscaper.Replace(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) {
+func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
@@ -104,7 +104,7 @@ func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, os.Error
// CreateFormField calls CreatePart with a header using the
// given field name.
-func (w *Writer) CreateFormField(fieldname string) (io.Writer, os.Error) {
+func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname)))
@@ -112,7 +112,7 @@ func (w *Writer) CreateFormField(fieldname string) (io.Writer, os.Error) {
}
// WriteField calls CreateFormField and then writes the given value.
-func (w *Writer) WriteField(fieldname, value string) os.Error {
+func (w *Writer) WriteField(fieldname, value string) error {
p, err := w.CreateFormField(fieldname)
if err != nil {
return err
@@ -123,7 +123,7 @@ func (w *Writer) WriteField(fieldname, value string) os.Error {
// Close finishes the multipart message and writes the trailing
// boundary end line to the output.
-func (w *Writer) Close() os.Error {
+func (w *Writer) Close() error {
if w.lastpart != nil {
if err := w.lastpart.close(); err != nil {
return err
@@ -137,17 +137,17 @@ func (w *Writer) Close() os.Error {
type part struct {
mw *Writer
closed bool
- we os.Error // last error that occurred writing
+ we error // last error that occurred writing
}
-func (p *part) close() os.Error {
+func (p *part) close() error {
p.closed = true
return p.we
}
-func (p *part) Write(d []byte) (n int, err os.Error) {
+func (p *part) Write(d []byte) (n int, err error) {
if p.closed {
- return 0, os.NewError("multipart: can't write to finished part")
+ return 0, errors.New("multipart: can't write to finished part")
}
n, err = p.mw.w.Write(d)
if err != nil {
diff --git a/src/pkg/mime/type.go b/src/pkg/mime/type.go
index 8ecfe9a37..00cff263b 100644
--- a/src/pkg/mime/type.go
+++ b/src/pkg/mime/type.go
@@ -6,18 +6,11 @@
package mime
import (
- "bufio"
- "os"
+ "fmt"
"strings"
"sync"
)
-var typeFiles = []string{
- "/etc/mime.types",
- "/etc/apache2/mime.types",
- "/etc/apache/mime.types",
-}
-
var mimeTypes = map[string]string{
".css": "text/css; charset=utf-8",
".gif": "image/gif",
@@ -32,55 +25,23 @@ var mimeTypes = map[string]string{
var mimeLock sync.RWMutex
-func loadMimeFile(filename string) {
- f, err := os.Open(filename)
- if err != nil {
- return
- }
-
- reader := bufio.NewReader(f)
- for {
- line, err := reader.ReadString('\n')
- if err != nil {
- f.Close()
- return
- }
- fields := strings.Fields(line)
- if len(fields) <= 1 || fields[0][0] == '#' {
- continue
- }
- typename := fields[0]
- if strings.HasPrefix(typename, "text/") {
- typename += "; charset=utf-8"
- }
- for _, ext := range fields[1:] {
- if ext[0] == '#' {
- break
- }
- mimeTypes["."+ext] = typename
- }
- }
-}
-
-func initMime() {
- for _, filename := range typeFiles {
- loadMimeFile(filename)
- }
-}
-
var once sync.Once
// TypeByExtension returns the MIME type associated with the file extension ext.
// The extension ext should begin with a leading dot, as in ".html".
// When ext has no associated type, TypeByExtension returns "".
//
-// The built-in table is small but is is augmented by the local
+// The built-in table is small but on unix it is augmented by the local
// system's mime.types file(s) if available under one or more of these
// names:
//
// /etc/mime.types
// /etc/apache2/mime.types
// /etc/apache/mime.types
+//
+// Windows system mime types are extracted from registry.
+//
+// Text types have the charset parameter set to "utf-8" by default.
func TypeByExtension(ext string) string {
once.Do(initMime)
mimeLock.RLock()
@@ -92,13 +53,25 @@ func TypeByExtension(ext string) string {
// AddExtensionType sets the MIME type associated with
// the extension ext to typ. The extension should begin with
// a leading dot, as in ".html".
-func AddExtensionType(ext, typ string) os.Error {
+func AddExtensionType(ext, typ string) error {
+ if ext == "" || ext[0] != '.' {
+ return fmt.Errorf(`mime: extension "%s" misses dot`, ext)
+ }
once.Do(initMime)
- if len(ext) < 1 || ext[0] != '.' {
- return os.EINVAL
+ return setExtensionType(ext, typ)
+}
+
+func setExtensionType(extension, mimeType string) error {
+ _, param, err := ParseMediaType(mimeType)
+ if err != nil {
+ return err
+ }
+ if strings.HasPrefix(mimeType, "text/") && param["charset"] == "" {
+ param["charset"] = "utf-8"
+ mimeType = FormatMediaType(mimeType, param)
}
mimeLock.Lock()
- mimeTypes[ext] = typ
+ mimeTypes[extension] = mimeType
mimeLock.Unlock()
return nil
}
diff --git a/src/pkg/mime/type_test.go b/src/pkg/mime/type_test.go
new file mode 100644
index 000000000..07e1cd5da
--- /dev/null
+++ b/src/pkg/mime/type_test.go
@@ -0,0 +1,29 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import "testing"
+
+var typeTests = initMimeForTests()
+
+func TestTypeByExtension(t *testing.T) {
+ for ext, want := range typeTests {
+ val := TypeByExtension(ext)
+ if val != want {
+ t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
+ }
+
+ }
+}
+
+func TestCustomExtension(t *testing.T) {
+ custom := "text/xml; charset=iso-8859-1"
+ if error := AddExtensionType(".xml", custom); error != nil {
+ t.Fatalf("error %s for AddExtension(%s)", error, custom)
+ }
+ if registered := TypeByExtension(".xml"); registered != custom {
+ t.Fatalf("registered %s instead of %s", registered, custom)
+ }
+}
diff --git a/src/pkg/mime/type_unix.go b/src/pkg/mime/type_unix.go
new file mode 100644
index 000000000..2dab1eac7
--- /dev/null
+++ b/src/pkg/mime/type_unix.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd plan9
+
+package mime
+
+import (
+ "bufio"
+ "os"
+ "strings"
+)
+
+var typeFiles = []string{
+ "/etc/mime.types",
+ "/etc/apache2/mime.types",
+ "/etc/apache/mime.types",
+}
+
+func loadMimeFile(filename string) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+
+ reader := bufio.NewReader(f)
+ for {
+ line, err := reader.ReadString('\n')
+ if err != nil {
+ f.Close()
+ return
+ }
+ fields := strings.Fields(line)
+ if len(fields) <= 1 || fields[0][0] == '#' {
+ continue
+ }
+ mimeType := fields[0]
+ for _, ext := range fields[1:] {
+ if ext[0] == '#' {
+ break
+ }
+ setExtensionType("."+ext, mimeType)
+ }
+ }
+}
+
+func initMime() {
+ for _, filename := range typeFiles {
+ loadMimeFile(filename)
+ }
+}
+
+func initMimeForTests() map[string]string {
+ typeFiles = []string{"test.types"}
+ return map[string]string{
+ ".t1": "application/test",
+ ".t2": "text/test; charset=utf-8",
+ ".png": "image/png",
+ }
+}
diff --git a/src/pkg/mime/type_windows.go b/src/pkg/mime/type_windows.go
new file mode 100644
index 000000000..bc388893b
--- /dev/null
+++ b/src/pkg/mime/type_windows.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func initMime() {
+ var root syscall.Handle
+ if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`),
+ 0, syscall.KEY_READ, &root) != nil {
+ return
+ }
+ defer syscall.RegCloseKey(root)
+ var count uint32
+ if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil {
+ return
+ }
+ var buf [1 << 10]uint16
+ for i := uint32(0); i < count; i++ {
+ n := uint32(len(buf))
+ if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != nil {
+ continue
+ }
+ ext := syscall.UTF16ToString(buf[:])
+ if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
+ continue
+ }
+ var h syscall.Handle
+ if syscall.RegOpenKeyEx(
+ syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`+ext),
+ 0, syscall.KEY_READ, &h) != nil {
+ continue
+ }
+ var typ uint32
+ n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
+ if syscall.RegQueryValueEx(
+ h, syscall.StringToUTF16Ptr("Content Type"),
+ nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
+ syscall.RegCloseKey(h)
+ continue
+ }
+ syscall.RegCloseKey(h)
+ if typ != syscall.REG_SZ { // null terminated strings only
+ continue
+ }
+ mimeType := syscall.UTF16ToString(buf[:])
+ setExtensionType(ext, mimeType)
+ }
+}
+
+func initMimeForTests() map[string]string {
+ return map[string]string{
+ ".bmp": "image/bmp",
+ ".png": "image/png",
+ }
+}
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
deleted file mode 100644
index eba9e26d9..000000000
--- a/src/pkg/net/Makefile
+++ /dev/null
@@ -1,157 +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.
-
-include ../../Make.inc
-
-TARG=net
-GOFILES=\
- dial.go\
- dnsclient.go\
- dnsmsg.go\
- hosts.go\
- interface.go\
- ip.go\
- iprawsock.go\
- ipsock.go\
- net.go\
- parse.go\
- pipe.go\
- tcpsock.go\
- udpsock.go\
- unixsock.go\
-
-GOFILES_freebsd=\
- dnsclient_unix.go\
- dnsconfig.go\
- fd.go\
- fd_$(GOOS).go\
- file.go\
- interface_bsd.go\
- interface_freebsd.go\
- iprawsock_posix.go\
- ipsock_posix.go\
- lookup_unix.go\
- newpollserver.go\
- port.go\
- sendfile_stub.go\
- sock.go\
- sock_bsd.go\
- tcpsock_posix.go\
- udpsock_posix.go\
- unixsock_posix.go\
-
-ifeq ($(CGO_ENABLED),1)
-CGOFILES_freebsd=\
- cgo_bsd.go\
- cgo_unix.go
-else
-GOFILES_freebsd+=cgo_stub.go
-endif
-
-GOFILES_darwin=\
- dnsclient_unix.go\
- dnsconfig.go\
- fd.go\
- fd_$(GOOS).go\
- file.go\
- interface_bsd.go\
- interface_darwin.go\
- iprawsock_posix.go\
- ipsock_posix.go\
- lookup_unix.go\
- newpollserver.go\
- port.go\
- sendfile_stub.go\
- sock.go\
- sock_bsd.go\
- tcpsock_posix.go\
- udpsock_posix.go\
- unixsock_posix.go\
-
-ifeq ($(CGO_ENABLED),1)
-CGOFILES_darwin=\
- cgo_bsd.go\
- cgo_unix.go
-else
-GOFILES_darwin+=cgo_stub.go
-endif
-
-GOFILES_linux=\
- dnsclient_unix.go\
- dnsconfig.go\
- fd.go\
- fd_$(GOOS).go\
- file.go\
- interface_linux.go\
- iprawsock_posix.go\
- ipsock_posix.go\
- lookup_unix.go\
- newpollserver.go\
- port.go\
- sendfile_linux.go\
- sock.go\
- sock_linux.go\
- tcpsock_posix.go\
- udpsock_posix.go\
- unixsock_posix.go\
-
-ifeq ($(CGO_ENABLED),1)
-CGOFILES_linux=\
- cgo_linux.go\
- cgo_unix.go
-else
-GOFILES_linux+=cgo_stub.go
-endif
-
-GOFILES_openbsd=\
- dnsclient_unix.go\
- dnsconfig.go\
- fd.go\
- fd_$(GOOS).go\
- file.go\
- interface_bsd.go\
- interface_openbsd.go\
- iprawsock_posix.go\
- ipsock_posix.go\
- lookup_unix.go\
- newpollserver.go\
- port.go\
- sendfile_stub.go\
- sock.go\
- sock_bsd.go\
- tcpsock_posix.go\
- udpsock_posix.go\
- unixsock_posix.go\
- cgo_stub.go\
-
-GOFILES_plan9=\
- file_plan9.go\
- interface_stub.go\
- iprawsock_plan9.go\
- ipsock_plan9.go\
- lookup_plan9.go\
- tcpsock_plan9.go\
- udpsock_plan9.go\
- unixsock_plan9.go\
-
-GOFILES_windows=\
- fd_$(GOOS).go\
- file_windows.go\
- interface_windows.go\
- iprawsock_posix.go\
- ipsock_posix.go\
- lookup_windows.go\
- sendfile_windows.go\
- sock.go\
- sock_windows.go\
- tcpsock_posix.go\
- udpsock_posix.go\
- unixsock_posix.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-ifneq ($(CGOFILES_$(GOOS)),)
-CGOFILES+=$(CGOFILES_$(GOOS))
-endif
-
-include ../../Make.pkg
diff --git a/src/pkg/net/cgo_bsd.go b/src/pkg/net/cgo_bsd.go
index 4984df4a2..63750f7a3 100644
--- a/src/pkg/net/cgo_bsd.go
+++ b/src/pkg/net/cgo_bsd.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.
+// +build darwin freebsd
+
package net
/*
diff --git a/src/pkg/net/cgo_stub.go b/src/pkg/net/cgo_stub.go
index c6277cb65..52e57d740 100644
--- a/src/pkg/net/cgo_stub.go
+++ b/src/pkg/net/cgo_stub.go
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !cgo
+
// Stub cgo routines for systems that do not use cgo to do network lookups.
package net
-import "os"
-
-func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
+func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
return nil, nil, false
}
-func cgoLookupPort(network, service string) (port int, err os.Error, completed bool) {
+func cgoLookupPort(network, service string) (port int, err error, completed bool) {
return 0, nil, false
}
-func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
+func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
return nil, nil, false
}
-func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) {
+func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
return "", nil, false
}
diff --git a/src/pkg/net/cgo_unix.go b/src/pkg/net/cgo_unix.go
index a3711d601..36a3f3d34 100644
--- a/src/pkg/net/cgo_unix.go
+++ b/src/pkg/net/cgo_unix.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.
+// +build darwin freebsd linux
+
package net
/*
@@ -16,12 +18,11 @@ package net
import "C"
import (
- "os"
"syscall"
"unsafe"
)
-func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
+func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
ip, err, completed := cgoLookupIP(name)
for _, p := range ip {
addrs = append(addrs, p.String())
@@ -29,7 +30,7 @@ func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
return
}
-func cgoLookupPort(net, service string) (port int, err os.Error, completed bool) {
+func cgoLookupPort(net, service string) (port int, err error, completed bool) {
var res *C.struct_addrinfo
var hints C.struct_addrinfo
@@ -76,7 +77,7 @@ func cgoLookupPort(net, service string) (port int, err os.Error, completed bool)
return 0, &AddrError{"unknown port", net + "/" + service}, true
}
-func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err os.Error, completed bool) {
+func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) {
var res *C.struct_addrinfo
var hints C.struct_addrinfo
@@ -96,11 +97,11 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err os.Error, comp
if gerrno == C.EAI_NONAME {
str = noSuchHost
} else if gerrno == C.EAI_SYSTEM {
- str = err.String()
+ str = err.Error()
} else {
str = C.GoString(C.gai_strerror(gerrno))
}
- return nil, "", &DNSError{Error: str, Name: name}, true
+ return nil, "", &DNSError{Err: str, Name: name}, true
}
defer C.freeaddrinfo(res)
if res != nil {
@@ -131,12 +132,12 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err os.Error, comp
return addrs, cname, nil, true
}
-func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
+func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
addrs, _, err, completed = cgoLookupIPCNAME(name)
return
}
-func cgoLookupCNAME(name string) (cname string, err os.Error, completed bool) {
+func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
_, cname, err, completed = cgoLookupIPCNAME(name)
return
}
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 10c67dcc4..10ca5faf7 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -4,26 +4,63 @@
package net
-import "os"
+import (
+ "time"
+)
-func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
- if addr == "" {
- return nil, &OpError{op, net, nil, errMissingAddress}
+func parseDialNetwork(net string) (afnet string, proto int, err error) {
+ i := last(net, ':')
+ if i < 0 { // no colon
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ case "udp", "udp4", "udp6":
+ case "unix", "unixgram", "unixpacket":
+ default:
+ return "", 0, UnknownNetworkError(net)
+ }
+ return net, 0, nil
}
- 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)
+ afnet = net[:i]
+ switch afnet {
case "ip", "ip4", "ip6":
- a, err = ResolveIPAddr(net, addr)
- default:
- err = UnknownNetworkError(net)
+ protostr := net[i+1:]
+ proto, i, ok := dtoi(protostr, 0)
+ if !ok || i != len(protostr) {
+ proto, err = lookupProtocol(protostr)
+ if err != nil {
+ return "", 0, err
+ }
+ }
+ return afnet, proto, nil
}
+ return "", 0, UnknownNetworkError(net)
+}
+
+func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) {
+ afnet, _, err = parseDialNetwork(net)
if err != nil {
- return nil, &OpError{op, net + " " + addr, nil, err}
+ return "", nil, &OpError{op, net, nil, err}
+ }
+ if op == "dial" && addr == "" {
+ return "", nil, &OpError{op, net, nil, errMissingAddress}
+ }
+ switch afnet {
+ case "tcp", "tcp4", "tcp6":
+ if addr != "" {
+ a, err = ResolveTCPAddr(afnet, addr)
+ }
+ case "udp", "udp4", "udp6":
+ if addr != "" {
+ a, err = ResolveUDPAddr(afnet, addr)
+ }
+ case "ip", "ip4", "ip6":
+ if addr != "" {
+ a, err = ResolveIPAddr(afnet, addr)
+ }
+ case "unix", "unixgram", "unixpacket":
+ if addr != "" {
+ a, err = ResolveUnixAddr(afnet, addr)
+ }
}
return
}
@@ -32,122 +69,160 @@ func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
-// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixgram".
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixpacket".
//
-// For IP networks, addresses have the form host:port. If host is
-// a literal IPv6 address, it must be enclosed in square brackets.
-// The functions JoinHostPort and SplitHostPort manipulate
-// addresses in this form.
+// For TCP and UDP networks, addresses have the form host:port.
+// If host is a literal IPv6 address, it must be enclosed
+// in square brackets. The functions JoinHostPort and SplitHostPort
+// manipulate addresses in this form.
//
// Examples:
// Dial("tcp", "12.34.56.78:80")
// Dial("tcp", "google.com:80")
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
//
-func Dial(net, addr string) (c Conn, err os.Error) {
- addri, err := resolveNetAddr("dial", net, addr)
+// For IP networks, addr must be "ip", "ip4" or "ip6" followed
+// by a colon and a protocol number or name.
+//
+// Examples:
+// Dial("ip4:1", "127.0.0.1")
+// Dial("ip6:ospf", "::1")
+//
+func Dial(net, addr string) (Conn, error) {
+ _, addri, err := resolveNetAddr("dial", net, addr)
if err != nil {
return nil, err
}
+ return dialAddr(net, addr, addri)
+}
+
+func dialAddr(net, addr string, addri Addr) (c Conn, err 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)
case *IPAddr:
c, err = DialIP(net, nil, ra)
+ case *UnixAddr:
+ c, err = DialUnix(net, nil, ra)
default:
- err = UnknownNetworkError(net)
+ err = &OpError{"dial", net + " " + addr, nil, UnknownNetworkError(net)}
}
if err != nil {
- return nil, &OpError{"dial", net + " " + addr, nil, err}
+ return nil, err
}
return
}
+// DialTimeout acts like Dial but takes a timeout.
+// The timeout includes name resolution, if required.
+func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
+ // TODO(bradfitz): the timeout should be pushed down into the
+ // net package's event loop, so on timeout to dead hosts we
+ // don't have a goroutine sticking around for the default of
+ // ~3 minutes.
+ t := time.NewTimer(timeout)
+ defer t.Stop()
+ type pair struct {
+ Conn
+ error
+ }
+ ch := make(chan pair, 1)
+ resolvedAddr := make(chan Addr, 1)
+ go func() {
+ _, addri, err := resolveNetAddr("dial", net, addr)
+ if err != nil {
+ ch <- pair{nil, err}
+ return
+ }
+ resolvedAddr <- addri // in case we need it for OpError
+ c, err := dialAddr(net, addr, addri)
+ ch <- pair{c, err}
+ }()
+ select {
+ case <-t.C:
+ // Try to use the real Addr in our OpError, if we resolved it
+ // before the timeout. Otherwise we just use stringAddr.
+ var addri Addr
+ select {
+ case a := <-resolvedAddr:
+ addri = a
+ default:
+ addri = &stringAddr{net, addr}
+ }
+ err := &OpError{
+ Op: "dial",
+ Net: net,
+ Addr: addri,
+ Err: &timeoutError{},
+ }
+ return nil, err
+ case p := <-ch:
+ return p.Conn, p.error
+ }
+ panic("unreachable")
+}
+
+type stringAddr struct {
+ net, addr string
+}
+
+func (a stringAddr) Network() string { return a.net }
+func (a stringAddr) String() string { return a.addr }
+
// Listen announces on the local network address laddr.
-// The network string net must be a stream-oriented
-// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
-func Listen(net, laddr string) (l Listener, err os.Error) {
- switch net {
+// The network string net must be a stream-oriented network:
+// "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
+func Listen(net, laddr string) (Listener, error) {
+ afnet, a, err := resolveNetAddr("listen", net, laddr)
+ if err != nil {
+ return nil, err
+ }
+ switch afnet {
case "tcp", "tcp4", "tcp6":
var la *TCPAddr
- if laddr != "" {
- if la, err = ResolveTCPAddr(net, laddr); err != nil {
- return nil, err
- }
- }
- l, err := ListenTCP(net, la)
- if err != nil {
- return nil, err
+ if a != nil {
+ la = a.(*TCPAddr)
}
- return l, nil
+ return ListenTCP(net, la)
case "unix", "unixpacket":
var la *UnixAddr
- if laddr != "" {
- if la, err = ResolveUnixAddr(net, laddr); err != nil {
- return nil, err
- }
- }
- l, err := ListenUnix(net, la)
- if err != nil {
- return nil, err
+ if a != nil {
+ la = a.(*UnixAddr)
}
- return l, nil
+ return ListenUnix(net, la)
}
return nil, UnknownNetworkError(net)
}
// ListenPacket announces on the local network address laddr.
// The network string net must be a packet-oriented network:
-// "udp", "udp4", "udp6", or "unixgram".
-func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
- switch net {
+// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
+func ListenPacket(net, addr string) (PacketConn, error) {
+ afnet, a, err := resolveNetAddr("listen", net, addr)
+ if err != nil {
+ return nil, err
+ }
+ switch afnet {
case "udp", "udp4", "udp6":
var la *UDPAddr
- if laddr != "" {
- if la, err = ResolveUDPAddr(net, laddr); err != nil {
- return nil, err
- }
+ if a != nil {
+ la = a.(*UDPAddr)
}
- c, err := ListenUDP(net, la)
- if err != nil {
- return nil, err
+ return ListenUDP(net, la)
+ case "ip", "ip4", "ip6":
+ var la *IPAddr
+ if a != nil {
+ la = a.(*IPAddr)
}
- return c, nil
+ return ListenIP(net, la)
case "unixgram":
var la *UnixAddr
- if laddr != "" {
- if la, err = ResolveUnixAddr(net, laddr); err != nil {
- return nil, err
- }
- }
- c, err := DialUnix(net, la, nil)
- if err != nil {
- return nil, err
- }
- return c, nil
- }
-
- 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(rawnet, laddr); err != nil {
- return nil, err
- }
- }
- c, err := ListenIP(net, la)
- if err != nil {
- return nil, err
- }
- return c, nil
+ if a != nil {
+ la = a.(*UnixAddr)
}
+ return DialUnix(net, la, nil)
}
-
return nil, UnknownNetworkError(net)
}
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
new file mode 100644
index 000000000..7212087fe
--- /dev/null
+++ b/src/pkg/net/dial_test.go
@@ -0,0 +1,224 @@
+// 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 (
+ "flag"
+ "fmt"
+ "regexp"
+ "runtime"
+ "testing"
+ "time"
+)
+
+func newLocalListener(t *testing.T) Listener {
+ ln, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ errc := make(chan error)
+
+ numConns := listenerBacklog + 10
+
+ // TODO(bradfitz): It's hard to test this in a portable
+ // way. This is unfortunate, but works for now.
+ switch runtime.GOOS {
+ case "linux":
+ // The kernel will start accepting TCP connections before userspace
+ // gets a chance to not accept them, so fire off a bunch to fill up
+ // the kernel's backlog. Then we test we get a failure after that.
+ for i := 0; i < numConns; i++ {
+ go func() {
+ _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
+ errc <- err
+ }()
+ }
+ case "darwin", "windows":
+ // At least OS X 10.7 seems to accept any number of
+ // connections, ignoring listen's backlog, so resort
+ // to connecting to a hopefully-dead 127/8 address.
+ // Same for windows.
+ //
+ // Use an IANA reserved port (49151) instead of 80, because
+ // on our 386 builder, this Dial succeeds, connecting
+ // to an IIS web server somewhere. The data center
+ // or VM or firewall must be stealing the TCP connection.
+ //
+ // IANA Service Name and Transport Protocol Port Number Registry
+ // <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
+ go func() {
+ c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
+ if err == nil {
+ err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
+ c.Close()
+ }
+ errc <- err
+ }()
+ default:
+ // TODO(bradfitz):
+ // OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
+ // by default. FreeBSD likely works, but is untested.
+ // TODO(rsc):
+ // The timeout never happens on Windows. Why? Issue 3016.
+ t.Logf("skipping test on %q; untested.", runtime.GOOS)
+ return
+ }
+
+ connected := 0
+ for {
+ select {
+ case <-time.After(15 * time.Second):
+ t.Fatal("too slow")
+ case err := <-errc:
+ if err == nil {
+ connected++
+ if connected == numConns {
+ t.Fatal("all connections connected; expected some to time out")
+ }
+ } else {
+ terr, ok := err.(timeout)
+ if !ok {
+ t.Fatalf("got error %q; want error with timeout interface", err)
+ }
+ if !terr.Timeout() {
+ t.Fatalf("got error %q; not a timeout", err)
+ }
+ // Pass. We saw a timeout error.
+ return
+ }
+ }
+ }
+}
+
+func TestSelfConnect(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // TODO(brainman): do not know why it hangs.
+ t.Logf("skipping known-broken test on windows")
+ return
+ }
+ // Test that Dial does not honor self-connects.
+ // See the comment in DialTCP.
+
+ // Find a port that would be used as a local address.
+ l, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ c, err := Dial("tcp", l.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ addr := c.LocalAddr().String()
+ c.Close()
+ l.Close()
+
+ // Try to connect to that address repeatedly.
+ n := 100000
+ if testing.Short() {
+ n = 1000
+ }
+ switch runtime.GOOS {
+ case "darwin", "freebsd", "openbsd", "windows":
+ // Non-Linux systems take a long time to figure
+ // out that there is nothing listening on localhost.
+ n = 100
+ }
+ for i := 0; i < n; i++ {
+ c, err := Dial("tcp", addr)
+ if err == nil {
+ c.Close()
+ t.Errorf("#%d: Dial %q succeeded", i, addr)
+ }
+ }
+}
+
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+
+type DialErrorTest struct {
+ Net string
+ Raddr string
+ Pattern string
+}
+
+var dialErrorTests = []DialErrorTest{
+ {
+ "datakit", "mh/astro/r70",
+ "dial datakit mh/astro/r70: unknown network datakit",
+ },
+ {
+ "tcp", "127.0.0.1:☺",
+ "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+ },
+ {
+ "tcp", "no-such-name.google.com.:80",
+ "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name.no-such-top-level-domain.:80",
+ "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+ },
+ {
+ "tcp", "no-such-name:80",
+ `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+ },
+ {
+ "tcp", "mh/astro/r70:http",
+ "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+ },
+ {
+ "unix", "/etc/file-not-found",
+ "dial unix /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unix", "/etc/",
+ "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+ {
+ "unixpacket", "/etc/file-not-found",
+ "dial unixpacket /etc/file-not-found: no such file or directory",
+ },
+ {
+ "unixpacket", "/etc/",
+ "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+ },
+}
+
+var duplicateErrorPattern = `dial (.*) dial (.*)`
+
+func TestDialError(t *testing.T) {
+ if !*runErrorTest {
+ t.Logf("test disabled; use -run_error_test to enable")
+ return
+ }
+ for i, tt := range dialErrorTests {
+ c, err := Dial(tt.Net, tt.Raddr)
+ if c != nil {
+ c.Close()
+ }
+ if err == nil {
+ t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+ continue
+ }
+ s := err.Error()
+ match, _ := regexp.MatchString(tt.Pattern, s)
+ if !match {
+ t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+ }
+ match, _ = regexp.MatchString(duplicateErrorPattern, s)
+ if match {
+ t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
+ }
+ }
+}
diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
index 9ad1770da..03c449972 100644
--- a/src/pkg/net/dialgoogle_test.go
+++ b/src/pkg/net/dialgoogle_test.go
@@ -14,12 +14,12 @@ import (
)
// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
-var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
// fd is already connected to the destination, port 80.
// Run an HTTP request to fetch the appropriate page.
func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
- req := []byte("GET /intl/en/privacy/ HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+ req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
n, err := fd.Write(req)
buf := make([]byte, 1000)
@@ -42,9 +42,8 @@ func doDial(t *testing.T, network, addr string) {
}
func TestLookupCNAME(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
cname, err := LookupCNAME("www.google.com")
@@ -67,9 +66,8 @@ var googleaddrsipv4 = []string{
}
func TestDialGoogleIPv4(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
@@ -124,13 +122,12 @@ var googleaddrsipv6 = []string{
}
func TestDialGoogleIPv6(t *testing.T) {
- if testing.Short() {
- // Don't use external network.
- t.Logf("skipping external network test during -short")
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
return
}
// Only run tcp6 if the kernel will take it.
- if !*ipv6 || !supportsIPv6 {
+ if !*testIPv6 || !supportsIPv6 {
return
}
diff --git a/src/pkg/net/dict/Makefile b/src/pkg/net/dict/Makefile
deleted file mode 100644
index eaa9e6531..000000000
--- a/src/pkg/net/dict/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-include ../../../Make.inc
-
-TARG=net/dict
-GOFILES=\
- dict.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/net/dict/dict.go b/src/pkg/net/dict/dict.go
deleted file mode 100644
index b146ea212..000000000
--- a/src/pkg/net/dict/dict.go
+++ /dev/null
@@ -1,211 +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 dict implements the Dictionary Server Protocol
-// as defined in RFC 2229.
-package dict
-
-import (
- "net/textproto"
- "os"
- "strconv"
- "strings"
-)
-
-// A Client represents a client connection to a dictionary server.
-type Client struct {
- text *textproto.Conn
-}
-
-// Dial returns a new client connected to a dictionary server at
-// addr on the given network.
-func Dial(network, addr string) (*Client, os.Error) {
- text, err := textproto.Dial(network, addr)
- if err != nil {
- return nil, err
- }
- _, _, err = text.ReadCodeLine(220)
- if err != nil {
- text.Close()
- return nil, err
- }
- return &Client{text: text}, nil
-}
-
-// Close closes the connection to the dictionary server.
-func (c *Client) Close() os.Error {
- return c.text.Close()
-}
-
-// A Dict represents a dictionary available on the server.
-type Dict struct {
- Name string // short name of dictionary
- Desc string // long description
-}
-
-// Dicts returns a list of the dictionaries available on the server.
-func (c *Client) Dicts() ([]Dict, os.Error) {
- id, err := c.text.Cmd("SHOW DB")
- if err != nil {
- return nil, err
- }
-
- c.text.StartResponse(id)
- defer c.text.EndResponse(id)
-
- _, _, err = c.text.ReadCodeLine(110)
- if err != nil {
- return nil, err
- }
- lines, err := c.text.ReadDotLines()
- if err != nil {
- return nil, err
- }
- _, _, err = c.text.ReadCodeLine(250)
-
- dicts := make([]Dict, len(lines))
- for i := range dicts {
- d := &dicts[i]
- a, _ := fields(lines[i])
- if len(a) < 2 {
- return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
- }
- d.Name = a[0]
- d.Desc = a[1]
- }
- return dicts, err
-}
-
-// A Defn represents a definition.
-type Defn struct {
- Dict Dict // Dict where definition was found
- Word string // Word being defined
- Text []byte // Definition text, typically multiple lines
-}
-
-// Define requests the definition of the given word.
-// The argument dict names the dictionary to use,
-// the Name field of a Dict returned by Dicts.
-//
-// The special dictionary name "*" means to look in all the
-// server's dictionaries.
-// The special dictionary name "!" means to look in all the
-// server's dictionaries in turn, stopping after finding the word
-// in one of them.
-func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
- id, err := c.text.Cmd("DEFINE %s %q", dict, word)
- if err != nil {
- return nil, err
- }
-
- c.text.StartResponse(id)
- defer c.text.EndResponse(id)
-
- _, line, err := c.text.ReadCodeLine(150)
- if err != nil {
- return nil, err
- }
- a, _ := fields(line)
- if len(a) < 1 {
- return nil, textproto.ProtocolError("malformed response: " + line)
- }
- n, err := strconv.Atoi(a[0])
- if err != nil {
- return nil, textproto.ProtocolError("invalid definition count: " + a[0])
- }
- def := make([]*Defn, n)
- for i := 0; i < n; i++ {
- _, line, err = c.text.ReadCodeLine(151)
- if err != nil {
- return nil, err
- }
- a, _ := fields(line)
- if len(a) < 3 {
- // skip it, to keep protocol in sync
- i--
- n--
- def = def[0:n]
- continue
- }
- d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
- d.Text, err = c.text.ReadDotBytes()
- if err != nil {
- return nil, err
- }
- def[i] = d
- }
- _, _, err = c.text.ReadCodeLine(250)
- return def, err
-}
-
-// Fields returns the fields in s.
-// Fields are space separated unquoted words
-// or quoted with single or double quote.
-func fields(s string) ([]string, os.Error) {
- var v []string
- i := 0
- for {
- for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
- i++
- }
- if i >= len(s) {
- break
- }
- if s[i] == '"' || s[i] == '\'' {
- q := s[i]
- // quoted string
- var j int
- for j = i + 1; ; j++ {
- if j >= len(s) {
- return nil, textproto.ProtocolError("malformed quoted string")
- }
- if s[j] == '\\' {
- j++
- continue
- }
- if s[j] == q {
- j++
- break
- }
- }
- v = append(v, unquote(s[i+1:j-1]))
- i = j
- } else {
- // atom
- var j int
- for j = i; j < len(s); j++ {
- if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
- break
- }
- }
- v = append(v, s[i:j])
- i = j
- }
- if i < len(s) {
- c := s[i]
- if c != ' ' && c != '\t' {
- return nil, textproto.ProtocolError("quotes not on word boundaries")
- }
- }
- }
- return v, nil
-}
-
-func unquote(s string) string {
- if strings.Index(s, "\\") < 0 {
- return s
- }
- b := []byte(s)
- w := 0
- for r := 0; r < len(b); r++ {
- c := b[r]
- if c == '\\' {
- r++
- c = b[r]
- }
- b[w] = c
- w++
- }
- return string(b[0:w])
-}
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index 93c04f6b5..e69cb3188 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -5,22 +5,19 @@
package net
import (
- "bytes"
- "fmt"
- "os"
- "rand"
+ "math/rand"
"sort"
)
// DNSError represents a DNS lookup error.
type DNSError struct {
- Error string // description of the error
+ Err string // description of the error
Name string // name looked for
Server string // server used
IsTimeout bool
}
-func (e *DNSError) String() string {
+func (e *DNSError) Error() string {
if e == nil {
return "<nil>"
}
@@ -28,7 +25,7 @@ func (e *DNSError) String() string {
if e.Server != "" {
s += " on " + e.Server
}
- s += ": " + e.Error
+ s += ": " + e.Err
return s
}
@@ -40,42 +37,44 @@ const noSuchHost = "no such host"
// 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) {
+func reverseaddr(addr string) (arpa string, err error) {
ip := ParseIP(addr)
if ip == nil {
- return "", &DNSError{Error: "unrecognized address", Name: addr}
+ return "", &DNSError{Err: "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
+ return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
+ itoa(int(ip[12])) + ".in-addr.arpa.", nil
}
// Must be IPv6
- var buf bytes.Buffer
+ buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
// 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('.')
+ v := ip[i]
+ buf = append(buf, hexDigit[v&0xF])
+ buf = append(buf, '.')
+ buf = append(buf, hexDigit[v>>4])
+ buf = append(buf, '.')
}
// Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
+ buf = append(buf, "ip6.arpa."...)
+ return string(buf), 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) {
+func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err error) {
addrs = make([]dnsRR, 0, len(dns.answer))
if dns.rcode == dnsRcodeNameError && dns.recursion_available {
- return "", nil, &DNSError{Error: noSuchHost, Name: name}
+ return "", nil, &DNSError{Err: noSuchHost, Name: name}
}
if dns.rcode != dnsRcodeSuccess {
// None of the error codes make sense
// for the query we sent. If we didn't get
// a name error and we didn't get success,
// the server is behaving incorrectly.
- return "", nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
+ return "", nil, &DNSError{Err: "server misbehaving", Name: name, Server: server}
}
// Look for the name.
@@ -107,12 +106,12 @@ Cname:
}
}
if len(addrs) == 0 {
- return "", nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
+ return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server}
}
return name, addrs, nil
}
- return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
+ return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server}
}
func isDomainName(s string) bool {
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index f407b1778..18c39360e 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.
@@ -15,27 +17,26 @@
package net
import (
- "os"
- "rand"
+ "math/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) {
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error) {
if len(name) >= 256 {
- return nil, &DNSError{Error: "name too long", Name: name}
+ return nil, &DNSError{Err: "name too long", Name: name}
}
out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+ out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
out.question = []dnsQuestion{
{name, qtype, dnsClassINET},
}
out.recursion_desired = true
msg, ok := out.Pack()
if !ok {
- return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+ return nil, &DNSError{Err: "internal error - cannot pack message", Name: name}
}
for attempt := 0; attempt < cfg.attempts; attempt++ {
@@ -44,7 +45,11 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
return nil, err
}
- c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+ if cfg.timeout == 0 {
+ c.SetReadDeadline(time.Time{})
+ } else {
+ c.SetReadDeadline(time.Now().Add(time.Duration(cfg.timeout) * time.Second))
+ }
buf := make([]byte, 2000) // More than enough.
n, err = c.Read(buf)
@@ -65,14 +70,14 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
if a := c.RemoteAddr(); a != nil {
server = a.String()
}
- return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+ return nil, &DNSError{Err: "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) {
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Error: "no DNS servers", Name: name}
+ return "", nil, &DNSError{Err: "no DNS servers", Name: name}
}
for i := 0; i < len(cfg.servers); i++ {
// Calling Dial here is scary -- we have to be sure
@@ -94,7 +99,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
continue
}
cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Error == noSuchHost {
+ if err == nil || err.(*DNSError).Err == noSuchHost {
break
}
}
@@ -113,7 +118,7 @@ func convertRR_A(records []dnsRR) []IP {
func convertRR_AAAA(records []dnsRR) []IP {
addrs := make([]IP, len(records))
for i, rr := range records {
- a := make(IP, 16)
+ a := make(IP, IPv6len)
copy(a, rr.(*dnsRR_AAAA).AAAA[:])
addrs[i] = a
}
@@ -121,15 +126,15 @@ func convertRR_AAAA(records []dnsRR) []IP {
}
var cfg *dnsConfig
-var dnserr os.Error
+var dnserr error
func loadConfig() { cfg, dnserr = dnsReadConfig() }
var onceLoadConfig sync.Once
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
if !isDomainName(name) {
- return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+ return name, nil, &DNSError{Err: "invalid domain name", Name: name}
}
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
@@ -184,7 +189,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
// 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) {
+func goLookupHost(name string) (addrs []string, err error) {
// Use entries from /etc/hosts if they match.
addrs = lookupStaticHost(name)
if len(addrs) > 0 {
@@ -212,7 +217,19 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
// 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) {
+func goLookupIP(name string) (addrs []IP, err error) {
+ // Use entries from /etc/hosts if possible.
+ haddrs := lookupStaticHost(name)
+ if len(haddrs) > 0 {
+ for _, haddr := range haddrs {
+ if ip := ParseIP(haddr); ip != nil {
+ addrs = append(addrs, ip)
+ }
+ }
+ if len(addrs) > 0 {
+ return
+ }
+ }
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
@@ -246,7 +263,7 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
// 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) {
+func goLookupCNAME(name string) (cname string, err error) {
onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
diff --git a/src/pkg/net/dnsconfig.go b/src/pkg/net/dnsconfig.go
index 54e334342..bb46cc900 100644
--- a/src/pkg/net/dnsconfig.go
+++ b/src/pkg/net/dnsconfig.go
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
// Read system DNS config from /etc/resolv.conf
package net
-import "os"
-
type dnsConfig struct {
servers []string // servers to use
search []string // suffixes to append to local name
@@ -17,24 +17,11 @@ type dnsConfig struct {
rotate bool // round robin among servers
}
-var dnsconfigError os.Error
-
-type DNSConfigError struct {
- Error os.Error
-}
-
-func (e *DNSConfigError) String() string {
- return "error reading DNS config: " + e.Error.String()
-}
-
-func (e *DNSConfigError) Timeout() bool { return false }
-func (e *DNSConfigError) Temporary() bool { return false }
-
// See resolv.conf(5) on a Linux machine.
// TODO(rsc): Supposed to call uname() and chop the beginning
// of the host name to get the default search domain.
// We assume it's in resolv.conf anyway.
-func dnsReadConfig() (*dnsConfig, os.Error) {
+func dnsReadConfig() (*dnsConfig, error) {
file, err := open("/etc/resolv.conf")
if err != nil {
return nil, &DNSConfigError{err}
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 7595aa2ab..b6ebe1173 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -4,14 +4,13 @@
// DNS packet assembly. See RFC 1035.
//
-// This is intended to support name resolution during net.Dial.
+// This is intended to support name resolution during Dial.
// It doesn't have to be blazing fast.
//
-// Rather than write the usual handful of routines to pack and
-// unpack every message that can appear on the wire, we use
-// reflection to write a generic pack/unpack for structs and then
-// use it. Thus, if in the future we need to define new message
-// structs, no new pack/unpack/printing code needs to be written.
+// Each message structure has a Walk method that is used by
+// a generic pack/unpack routine. Thus, if in the future we need
+// to define new message structs, no new pack/unpack/printing code
+// needs to be written.
//
// The first half of this file defines the DNS message formats.
// The second half implements the conversion to and from wire format.
@@ -23,12 +22,6 @@
package net
-import (
- "fmt"
- "os"
- "reflect"
-)
-
// Packet formats
// Wire constants.
@@ -75,6 +68,20 @@ const (
dnsRcodeRefused = 5
)
+// A dnsStruct describes how to iterate over its fields to emulate
+// reflective marshalling.
+type dnsStruct interface {
+ // Walk iterates over fields of a structure and calls f
+ // with a reference to that field, the name of the field
+ // and a tag ("", "domain", "ipv4", "ipv6") specifying
+ // particular encodings. Possible concrete types
+ // for v are *uint16, *uint32, *string, or []byte, and
+ // *int, *bool in the case of dnsMsgHdr.
+ // Whenever f returns false, Walk must stop and return
+ // false, and otherwise return true.
+ Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool)
+}
+
// The wire format for the DNS packet header.
type dnsHeader struct {
Id uint16
@@ -82,6 +89,15 @@ type dnsHeader struct {
Qdcount, Ancount, Nscount, Arcount uint16
}
+func (h *dnsHeader) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Id, "Id", "") &&
+ f(&h.Bits, "Bits", "") &&
+ f(&h.Qdcount, "Qdcount", "") &&
+ f(&h.Ancount, "Ancount", "") &&
+ f(&h.Nscount, "Nscount", "") &&
+ f(&h.Arcount, "Arcount", "")
+}
+
const (
// dnsHeader.Bits
_QR = 1 << 15 // query/response (response=1)
@@ -98,6 +114,12 @@ type dnsQuestion struct {
Qclass uint16
}
+func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&q.Name, "Name", "domain") &&
+ f(&q.Qtype, "Qtype", "") &&
+ f(&q.Qclass, "Qclass", "")
+}
+
// DNS responses (resource records).
// There are many types of messages,
// but they all share the same header.
@@ -113,7 +135,16 @@ func (h *dnsRR_Header) Header() *dnsRR_Header {
return h
}
+func (h *dnsRR_Header) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Name, "Name", "domain") &&
+ f(&h.Rrtype, "Rrtype", "") &&
+ f(&h.Class, "Class", "") &&
+ f(&h.Ttl, "Ttl", "") &&
+ f(&h.Rdlength, "Rdlength", "")
+}
+
type dnsRR interface {
+ dnsStruct
Header() *dnsRR_Header
}
@@ -128,6 +159,10 @@ func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
+}
+
type dnsRR_HINFO struct {
Hdr dnsRR_Header
Cpu string
@@ -138,6 +173,10 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
+}
+
type dnsRR_MB struct {
Hdr dnsRR_Header
Mb string `net:"domain-name"`
@@ -147,6 +186,10 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
+}
+
type dnsRR_MG struct {
Hdr dnsRR_Header
Mg string `net:"domain-name"`
@@ -156,6 +199,10 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
+}
+
type dnsRR_MINFO struct {
Hdr dnsRR_Header
Rmail string `net:"domain-name"`
@@ -166,6 +213,10 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
+}
+
type dnsRR_MR struct {
Hdr dnsRR_Header
Mr string `net:"domain-name"`
@@ -175,6 +226,10 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
+}
+
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
@@ -185,6 +240,10 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
+}
+
type dnsRR_NS struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -194,6 +253,10 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
+}
+
type dnsRR_PTR struct {
Hdr dnsRR_Header
Ptr string `net:"domain-name"`
@@ -203,6 +266,10 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
+}
+
type dnsRR_SOA struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -218,6 +285,17 @@ func (rr *dnsRR_SOA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Ns, "Ns", "domain") &&
+ f(&rr.Mbox, "Mbox", "domain") &&
+ f(&rr.Serial, "Serial", "") &&
+ f(&rr.Refresh, "Refresh", "") &&
+ f(&rr.Retry, "Retry", "") &&
+ f(&rr.Expire, "Expire", "") &&
+ f(&rr.Minttl, "Minttl", "")
+}
+
type dnsRR_TXT struct {
Hdr dnsRR_Header
Txt string // not domain name
@@ -227,6 +305,10 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
+}
+
type dnsRR_SRV struct {
Hdr dnsRR_Header
Priority uint16
@@ -239,6 +321,14 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Priority, "Priority", "") &&
+ f(&rr.Weight, "Weight", "") &&
+ f(&rr.Port, "Port", "") &&
+ f(&rr.Target, "Target", "domain")
+}
+
type dnsRR_A struct {
Hdr dnsRR_Header
A uint32 `net:"ipv4"`
@@ -248,6 +338,10 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
+}
+
type dnsRR_AAAA struct {
Hdr dnsRR_Header
AAAA [16]byte `net:"ipv6"`
@@ -257,6 +351,10 @@ func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
+}
+
// Packing and unpacking.
//
// All the packers and unpackers take a (msg []byte, off int)
@@ -386,134 +484,107 @@ Loop:
return s, off1, true
}
-// TODO(rsc): Move into generic library?
-// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
-// [n]byte, and other (often anonymous) structs.
-func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// packStruct packs a structure into msg at specified offset off, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = packStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
+ i := *fv
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- i := fv.Uint()
msg[off] = byte(i >> 8)
msg[off+1] = byte(i)
off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- i := fv.Uint()
+ case *uint32:
+ i := *fv
msg[off] = byte(i >> 24)
msg[off+1] = byte(i >> 16)
msg[off+2] = byte(i >> 8)
msg[off+3] = byte(i)
off += 4
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
+ copy(msg[off:off+n], fv)
off += n
- case reflect.String:
- // There are multiple string encodings.
- // The tag distinguishes ordinary strings from domain names.
- s := fv.String()
- switch f.Tag {
+ case *string:
+ s := *fv
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
off, ok = packDomainName(s, msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
// Counted string: 1 byte length.
if len(s) > 255 || off+1+len(s) > len(msg) {
- return len(msg), false
+ return false
}
msg[off] = byte(len(s))
off++
off += copy(msg[off:], s)
}
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func structValue(any interface{}) reflect.Value {
- return reflect.ValueOf(any).Elem()
-}
-
-func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = packStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// TODO(rsc): Move into generic library?
-// Unpack a reflect.StructValue from msg.
-// Same restrictions as packStructValue.
-func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// unpackStruct decodes msg[off:] into the given structure, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = unpackStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint16(msg[off])<<8 | uint16(msg[off+1])
- fv.SetUint(uint64(i))
+ *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
off += 2
- case reflect.Uint32:
+ case *uint32:
if off+4 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
- fv.SetUint(uint64(i))
+ *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
+ uint32(msg[off+2])<<8 | uint32(msg[off+3])
off += 4
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
+ copy(fv, msg[off:off+n])
off += n
- case reflect.String:
+ case *string:
var s string
- switch f.Tag {
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
s, off, ok = unpackDomainName(msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
- return len(msg), false
+ return false
}
n := int(msg[off])
off++
@@ -524,51 +595,77 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += n
s = string(b)
}
- fv.SetString(s)
+ *fv = s
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = unpackStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// Generic struct printer.
-// Doesn't care about the string tag `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 {
+// Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
+// as IP addresses.
+func printStruct(any dnsStruct) string {
s := "{"
- for i := 0; i < val.NumField(); i++ {
- if i > 0 {
+ i := 0
+ any.Walk(func(val interface{}, name, tag string) bool {
+ i++
+ if i > 1 {
s += ", "
}
- f := val.Type().Field(i)
- if !f.Anonymous {
- s += f.Name + "="
- }
- 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 == `net:"ipv4"` {
- i := fv.Uint()
+ s += name + "="
+ switch tag {
+ case "ipv4":
+ i := val.(uint32)
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
- i := fv.Interface().([]byte)
+ case "ipv6":
+ i := val.([]byte)
s += IP(i).String()
- } else {
- s += fmt.Sprint(fval.Interface())
+ default:
+ var i int64
+ switch v := val.(type) {
+ default:
+ // can't really happen.
+ s += "<unknown type>"
+ return true
+ case *string:
+ s += *v
+ return true
+ case []byte:
+ s += string(v)
+ return true
+ case *bool:
+ if *v {
+ s += "true"
+ } else {
+ s += "false"
+ }
+ return true
+ case *int:
+ i = int64(*v)
+ case *uint:
+ i = int64(*v)
+ case *uint8:
+ i = int64(*v)
+ case *uint16:
+ i = int64(*v)
+ case *uint32:
+ i = int64(*v)
+ case *uint64:
+ i = int64(*v)
+ case *uintptr:
+ i = int64(*v)
+ }
+ s += itoa(int(i))
}
- }
+ return true
+ })
s += "}"
return s
}
-func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
-
// Resource record packer.
func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
var off1 int
@@ -627,6 +724,17 @@ type dnsMsgHdr struct {
rcode int
}
+func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.id, "id", "") &&
+ f(&h.response, "response", "") &&
+ f(&h.opcode, "opcode", "") &&
+ f(&h.authoritative, "authoritative", "") &&
+ f(&h.truncated, "truncated", "") &&
+ f(&h.recursion_desired, "recursion_desired", "") &&
+ f(&h.recursion_available, "recursion_available", "") &&
+ f(&h.rcode, "rcode", "")
+}
+
type dnsMsg struct {
dnsMsgHdr
question []dnsQuestion
diff --git a/src/pkg/net/dnsmsg_test.go b/src/pkg/net/dnsmsg_test.go
index 06152a01a..c39dbdb04 100644
--- a/src/pkg/net/dnsmsg_test.go
+++ b/src/pkg/net/dnsmsg_test.go
@@ -6,6 +6,7 @@ package net
import (
"encoding/hex"
+ "reflect"
"testing"
)
@@ -19,6 +20,7 @@ func TestDNSParseSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -38,6 +40,16 @@ func TestDNSParseSRVReply(t *testing.T) {
t.Errorf("len(addrs) = %d; want %d", g, e)
t.Logf("addrs = %#v", addrs)
}
+ // repack and unpack.
+ data2, ok := msg.Pack()
+ msg2 := new(dnsMsg)
+ msg2.Unpack(data2)
+ switch {
+ case !ok:
+ t.Errorf("failed to repack message")
+ case !reflect.DeepEqual(msg, msg2):
+ t.Errorf("repacked message differs from original")
+ }
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
@@ -50,6 +62,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
diff --git a/src/pkg/net/doc.go b/src/pkg/net/doc.go
new file mode 100644
index 000000000..3a44e528e
--- /dev/null
+++ b/src/pkg/net/doc.go
@@ -0,0 +1,59 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+// 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 error) {
+ return lookupHost(host)
+}
+
+// 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 error) {
+ return lookupIP(host)
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err error) {
+ return lookupPort(network, service)
+}
+
+// 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 error) {
+ return lookupCNAME(name)
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name. The proto is "tcp" or "udp".
+// The returned records are sorted by priority and randomized
+// by weight within a priority.
+//
+// LookupSRV constructs the DNS name to look up following RFC 2782.
+// That is, it looks up _service._proto.name. To accommodate services
+// publishing SRV records under non-standard names, if both service
+// and proto are empty strings, LookupSRV looks up name directly.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+ return lookupSRV(service, proto, name)
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err error) {
+ return lookupMX(name)
+}
+
+// LookupTXT returns the DNS TXT records for the given domain name.
+func LookupTXT(name string) (txt []string, err error) {
+ return lookupTXT(name)
+}
+
+// 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 error) {
+ return lookupAddr(addr)
+}
diff --git a/src/pkg/net/example_test.go b/src/pkg/net/example_test.go
new file mode 100644
index 000000000..1a1c2edfe
--- /dev/null
+++ b/src/pkg/net/example_test.go
@@ -0,0 +1,35 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net_test
+
+import (
+ "io"
+ "log"
+ "net"
+)
+
+func ExampleListener() {
+ // Listen on TCP port 2000 on all interfaces.
+ l, err := net.Listen("tcp", ":2000")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for {
+ // Wait for a connection.
+ conn, err := l.Accept()
+ if err != nil {
+ log.Fatal(err)
+ }
+ // Handle the connection in a new goroutine.
+ // The loop then returns to accepting, so that
+ // multiple connections may be served concurrently.
+ go func(c net.Conn) {
+ // Echo all incoming data.
+ io.Copy(c, c)
+ // Shut down the connection.
+ c.Close()
+ }(conn)
+ }
+}
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index 707dccaa4..76c953b9b 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package net
import (
+ "errors"
"io"
"os"
"sync"
@@ -15,39 +18,35 @@ import (
// Network file descriptor.
type netFD struct {
// locking/lifetime of sysfd
- sysmu sync.Mutex
- sysref int
+ sysmu sync.Mutex
+ sysref int
+
+ // must lock both sysmu and pollserver to write
+ // can lock either to read
closing bool
// immutable until Close
- sysfd int
- family int
- proto int
- sysfile *os.File
- cr chan bool
- cw chan bool
- net string
- laddr Addr
- raddr Addr
+ sysfd int
+ family int
+ sotype int
+ isConnected bool
+ sysfile *os.File
+ cr chan error
+ cw chan error
+ net string
+ laddr Addr
+ raddr Addr
// owned by client
- rdeadline_delta int64
- rdeadline int64
- rio sync.Mutex
- wdeadline_delta int64
- wdeadline int64
- wio sync.Mutex
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
// owned by fd wait server
ncr, ncw int
}
-type InvalidConnError struct{}
-
-func (e *InvalidConnError) String() string { return "invalid net.Conn" }
-func (e *InvalidConnError) Temporary() bool { return false }
-func (e *InvalidConnError) Timeout() bool { return false }
-
// A pollServer helps FDs determine when to retry a non-blocking
// read or write after they get EAGAIN. When an FD needs to wait,
// send the fd on s.cr (for a read) or s.cw (for a write) to pass the
@@ -91,20 +90,15 @@ type pollServer struct {
deadline int64 // next deadline (nsec since 1970)
}
-func (s *pollServer) AddFD(fd *netFD, mode int) {
+func (s *pollServer) AddFD(fd *netFD, mode int) error {
+ s.Lock()
intfd := fd.sysfd
- if intfd < 0 {
+ if intfd < 0 || fd.closing {
// fd closed underfoot
- if mode == 'r' {
- fd.cr <- true
- } else {
- fd.cw <- true
- }
- return
+ s.Unlock()
+ return errClosing
}
- s.Lock()
-
var t int64
key := intfd << 1
if mode == 'r' {
@@ -124,17 +118,33 @@ func (s *pollServer) AddFD(fd *netFD, mode int) {
wake, err := s.poll.AddFD(intfd, mode, false)
if err != nil {
- panic("pollServer AddFD " + err.String())
+ panic("pollServer AddFD " + err.Error())
}
if wake {
doWakeup = true
}
-
s.Unlock()
if doWakeup {
s.Wakeup()
}
+ return nil
+}
+
+// Evict evicts fd from the pending list, unblocking
+// any I/O running on fd. The caller must have locked
+// pollserver.
+func (s *pollServer) Evict(fd *netFD) {
+ if s.pending[fd.sysfd<<1] == fd {
+ s.WakeFD(fd, 'r', errClosing)
+ s.poll.DelFD(fd.sysfd, 'r')
+ delete(s.pending, fd.sysfd<<1)
+ }
+ if s.pending[fd.sysfd<<1|1] == fd {
+ s.WakeFD(fd, 'w', errClosing)
+ s.poll.DelFD(fd.sysfd, 'w')
+ delete(s.pending, fd.sysfd<<1|1)
+ }
}
var wakeupbuf [1]byte
@@ -150,26 +160,26 @@ func (s *pollServer) LookupFD(fd int, mode int) *netFD {
if !ok {
return nil
}
- s.pending[key] = nil, false
+ delete(s.pending, key)
return netfd
}
-func (s *pollServer) WakeFD(fd *netFD, mode int) {
+func (s *pollServer) WakeFD(fd *netFD, mode int, err error) {
if mode == 'r' {
for fd.ncr > 0 {
fd.ncr--
- fd.cr <- true
+ fd.cr <- err
}
} else {
for fd.ncw > 0 {
fd.ncw--
- fd.cw <- true
+ fd.cw <- err
}
}
}
func (s *pollServer) Now() int64 {
- return time.Nanoseconds()
+ return time.Now().UnixNano()
}
func (s *pollServer) CheckDeadlines() {
@@ -193,7 +203,7 @@ func (s *pollServer) CheckDeadlines() {
}
if t > 0 {
if t <= now {
- s.pending[key] = nil, false
+ delete(s.pending, key)
if mode == 'r' {
s.poll.DelFD(fd.sysfd, mode)
fd.rdeadline = -1
@@ -201,7 +211,7 @@ func (s *pollServer) CheckDeadlines() {
s.poll.DelFD(fd.sysfd, mode)
fd.wdeadline = -1
}
- s.WakeFD(fd, mode)
+ s.WakeFD(fd, mode, nil)
} else if next_deadline == 0 || t < next_deadline {
next_deadline = t
}
@@ -225,7 +235,7 @@ func (s *pollServer) Run() {
}
fd, mode, err := s.poll.WaitFD(s, t)
if err != nil {
- print("pollServer WaitFD: ", err.String(), "\n")
+ print("pollServer WaitFD: ", err.Error(), "\n")
return
}
if fd < 0 {
@@ -233,7 +243,7 @@ func (s *pollServer) Run() {
s.CheckDeadlines()
continue
}
- if fd == s.pr.Fd() {
+ if fd == int(s.pr.Fd()) {
// Drain our wakeup pipe (we could loop here,
// but it's unlikely that there are more than
// len(scratch) wakeup calls).
@@ -242,22 +252,30 @@ func (s *pollServer) Run() {
} else {
netfd := s.LookupFD(fd, mode)
if netfd == nil {
- print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
+ // This can happen because the WaitFD runs without
+ // holding s's lock, so there might be a pending wakeup
+ // for an fd that has been evicted. No harm done.
continue
}
- s.WakeFD(netfd, mode)
+ s.WakeFD(netfd, mode, nil)
}
}
}
-func (s *pollServer) WaitRead(fd *netFD) {
- s.AddFD(fd, 'r')
- <-fd.cr
+func (s *pollServer) WaitRead(fd *netFD) error {
+ err := s.AddFD(fd, 'r')
+ if err == nil {
+ err = <-fd.cr
+ }
+ return err
}
-func (s *pollServer) WaitWrite(fd *netFD) {
- s.AddFD(fd, 'w')
- <-fd.cw
+func (s *pollServer) WaitWrite(fd *netFD) error {
+ err := s.AddFD(fd, 'w')
+ if err == nil {
+ err = <-fd.cw
+ }
+ return err
}
// Network FD methods.
@@ -269,25 +287,25 @@ var onceStartServer sync.Once
func startServer() {
p, err := newPollServer()
if err != nil {
- print("Start pollServer: ", err.String(), "\n")
+ print("Start pollServer: ", err.Error(), "\n")
}
pollserver = p
}
-func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
+func newFD(fd, family, sotype int, net string) (*netFD, error) {
onceStartServer.Do(startServer)
- if e := syscall.SetNonblock(fd, true); e != 0 {
- return nil, os.Errno(e)
+ if err := syscall.SetNonblock(fd, true); err != nil {
+ return nil, err
}
- f = &netFD{
+ netfd := &netFD{
sysfd: fd,
family: family,
- proto: proto,
+ sotype: sotype,
net: net,
}
- f.cr = make(chan bool, 1)
- f.cw = make(chan bool, 1)
- return f, nil
+ netfd.cr = make(chan error, 1)
+ netfd.cw = make(chan error, 1)
+ return netfd, nil
}
func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -300,43 +318,58 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
if raddr != nil {
rs = raddr.String()
}
- fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
+ fd.sysfile = os.NewFile(uintptr(fd.sysfd), fd.net+":"+ls+"->"+rs)
}
-func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
- e := syscall.Connect(fd.sysfd, ra)
- if e == syscall.EINPROGRESS {
- var errno int
- pollserver.WaitWrite(fd)
- e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
- if errno != 0 {
- return os.NewSyscallError("getsockopt", errno)
+func (fd *netFD) connect(ra syscall.Sockaddr) error {
+ err := syscall.Connect(fd.sysfd, ra)
+ if err == syscall.EINPROGRESS {
+ if err = pollserver.WaitWrite(fd); err != nil {
+ return err
+ }
+ var e int
+ e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
+ return os.NewSyscallError("getsockopt", err)
+ }
+ if e != 0 {
+ err = syscall.Errno(e)
}
}
- if e != 0 {
- return os.Errno(e)
- }
- return nil
+ return err
}
+var errClosing = errors.New("use of closed network connection")
+
// Add a reference to this fd.
-func (fd *netFD) incref() {
+// If closing==true, pollserver must be locked; mark the fd as closing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref(closing bool) error {
+ if fd == nil {
+ return errClosing
+ }
fd.sysmu.Lock()
+ if fd.closing {
+ fd.sysmu.Unlock()
+ return errClosing
+ }
fd.sysref++
+ if closing {
+ fd.closing = true
+ }
fd.sysmu.Unlock()
+ return nil
}
// Remove a reference to this FD and close if we've been asked to do so (and
// there are no references left.
func (fd *netFD) decref() {
+ if fd == nil {
+ return
+ }
fd.sysmu.Lock()
fd.sysref--
- if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
- // In case the user has set linger, switch to blocking mode so
- // the close blocks. As long as this doesn't happen often, we
- // can handle the extra OS processes. Otherwise we'll need to
- // use the pollserver for Close too. Sigh.
- syscall.SetNonblock(fd.sysfd, false)
+ if fd.closing && fd.sysref == 0 && fd.sysfile != nil {
fd.sysfile.Close()
fd.sysfile = nil
fd.sysfd = -1
@@ -344,302 +377,287 @@ func (fd *netFD) decref() {
fd.sysmu.Unlock()
}
-func (fd *netFD) Close() os.Error {
- if fd == nil || fd.sysfile == nil {
- return os.EINVAL
- }
-
- fd.incref()
- syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
- fd.closing = true
+func (fd *netFD) Close() error {
+ pollserver.Lock() // needed for both fd.incref(true) and pollserver.Evict
+ defer pollserver.Unlock()
+ if err := fd.incref(true); err != nil {
+ return err
+ }
+ // Unblock any I/O. Once it all unblocks and returns,
+ // so that it cannot be referring to fd.sysfd anymore,
+ // the final decref will close fd.sysfd. This should happen
+ // fairly quickly, since all the I/O is non-blocking, and any
+ // attempts to block in the pollserver will return errClosing.
+ pollserver.Evict(fd)
fd.decref()
return nil
}
-func (fd *netFD) Read(p []byte) (n int, err os.Error) {
- if fd == nil {
- return 0, os.EINVAL
+func (fd *netFD) shutdown(how int) error {
+ if err := fd.incref(false); err != nil {
+ return err
}
- fd.rio.Lock()
- defer fd.rio.Unlock()
- fd.incref()
defer fd.decref()
- if fd.sysfile == nil {
- return 0, os.EINVAL
+ err := syscall.Shutdown(fd.sysfd, how)
+ if err != nil {
+ return &OpError{"shutdown", fd.net, fd.laddr, err}
}
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
+ return nil
+}
+
+func (fd *netFD) CloseRead() error {
+ return fd.shutdown(syscall.SHUT_RD)
+}
+
+func (fd *netFD) CloseWrite() error {
+ return fd.shutdown(syscall.SHUT_WR)
+}
+
+func (fd *netFD) Read(p []byte) (n int, err error) {
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ if err := fd.incref(false); err != nil {
+ return 0, err
}
- var oserr os.Error
+ defer fd.decref()
for {
- var errno int
- n, errno = syscall.Read(fd.sysfile.Fd(), p)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
+ n, err = syscall.Read(int(fd.sysfd), p)
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.rdeadline >= 0 {
+ if err = pollserver.WaitRead(fd); err == nil {
+ continue
+ }
+ }
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
- } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
- err = os.EOF
+ } else if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM {
+ err = io.EOF
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.raddr, oserr}
+ if err != nil && err != io.EOF {
+ err = &OpError{"read", fd.net, fd.raddr, err}
}
return
}
-func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
- if fd == nil || fd.sysfile == nil {
- return 0, nil, os.EINVAL
- }
+func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
fd.rio.Lock()
defer fd.rio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
+ if err := fd.incref(false); err != nil {
+ return 0, nil, err
}
- var oserr os.Error
+ defer fd.decref()
for {
- var errno int
- n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
+ n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.rdeadline >= 0 {
+ if err = pollserver.WaitRead(fd); err == nil {
+ continue
+ }
+ }
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.laddr, oserr}
+ if err != nil && err != io.EOF {
+ err = &OpError{"read", fd.net, fd.laddr, err}
}
return
}
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
- if fd == nil || fd.sysfile == nil {
- return 0, 0, 0, nil, os.EINVAL
- }
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
fd.rio.Lock()
defer fd.rio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.rdeadline_delta > 0 {
- fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
- } else {
- fd.rdeadline = 0
+ if err := fd.incref(false); err != nil {
+ return 0, 0, 0, nil, err
}
- var oserr os.Error
+ defer fd.decref()
for {
- var errno int
- n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.rdeadline >= 0 {
+ if err = pollserver.WaitRead(fd); err == nil {
+ continue
+ }
+ }
}
- if n == 0 {
- oserr = os.EOF
+ if err == nil && n == 0 {
+ err = io.EOF
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.laddr, oserr}
+ if err != nil && err != io.EOF {
+ err = &OpError{"read", fd.net, fd.laddr, err}
return
}
return
}
-func (fd *netFD) Write(p []byte) (n int, err os.Error) {
- if fd == nil {
- return 0, os.EINVAL
- }
+func (fd *netFD) Write(p []byte) (int, error) {
fd.wio.Lock()
defer fd.wio.Unlock()
- fd.incref()
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
defer fd.decref()
if fd.sysfile == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
- }
- nn := 0
- var oserr os.Error
+ var err error
+ nn := 0
for {
- n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
+ var n int
+ n, err = syscall.Write(int(fd.sysfd), p[nn:])
if n > 0 {
nn += n
}
if nn == len(p) {
break
}
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.wdeadline >= 0 {
+ if err = pollserver.WaitWrite(fd); err == nil {
+ continue
+ }
+ }
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
break
}
if n == 0 {
- oserr = io.ErrUnexpectedEOF
+ err = io.ErrUnexpectedEOF
break
}
}
- if oserr != nil {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ if err != nil {
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return nn, err
}
-func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
- if fd == nil || fd.sysfile == nil {
- return 0, os.EINVAL
- }
+func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
fd.wio.Lock()
defer fd.wio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
+ if err := fd.incref(false); err != nil {
+ return 0, err
}
- var oserr os.Error
+ defer fd.decref()
for {
- errno := syscall.Sendto(fd.sysfd, p, 0, sa)
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ err = syscall.Sendto(fd.sysfd, p, 0, sa)
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.wdeadline >= 0 {
+ if err = pollserver.WaitWrite(fd); err == nil {
+ continue
+ }
+ }
}
break
}
- if oserr == nil {
+ if err == nil {
n = len(p)
} else {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
- if fd == nil || fd.sysfile == nil {
- return 0, 0, os.EINVAL
- }
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
fd.wio.Lock()
defer fd.wio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.wdeadline_delta > 0 {
- fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
- } else {
- fd.wdeadline = 0
+ if err := fd.incref(false); err != nil {
+ return 0, 0, err
}
- var oserr os.Error
+ defer fd.decref()
for {
- var errno int
- errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.wdeadline >= 0 {
+ if err = pollserver.WaitWrite(fd); err == nil {
+ continue
+ }
+ }
}
break
}
- if oserr == nil {
+ if err == nil {
n = len(p)
oobn = len(oob)
} else {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return
}
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
- if fd == nil || fd.sysfile == nil {
- return nil, os.EINVAL
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
}
-
- 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 s int
var rsa syscall.Sockaddr
for {
- if fd.closing {
+ syscall.ForkLock.RLock()
+ s, rsa, err = syscall.Accept(fd.sysfd)
+ if err != nil {
syscall.ForkLock.RUnlock()
- return nil, os.EINVAL
- }
- s, rsa, e = syscall.Accept(fd.sysfd)
- if e != syscall.EAGAIN || fd.rdeadline < 0 {
- break
+ if err == syscall.EAGAIN {
+ err = errTimeout
+ if fd.rdeadline >= 0 {
+ if err = pollserver.WaitRead(fd); err == nil {
+ continue
+ }
+ }
+ } else if err == syscall.ECONNABORTED {
+ // This means that a socket on the listen queue was closed
+ // before we Accept()ed it; it's a silly error, so try again.
+ continue
+ }
+ return nil, &OpError{"accept", fd.net, fd.laddr, err}
}
- syscall.ForkLock.RUnlock()
- pollserver.WaitRead(fd)
- syscall.ForkLock.RLock()
- }
- if e != 0 {
- syscall.ForkLock.RUnlock()
- return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
+ break
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
- if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil {
+ if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
syscall.Close(s)
return nil, err
}
- lsa, _ := syscall.Getsockname(nfd.sysfd)
- nfd.setAddr(toAddr(lsa), toAddr(rsa))
- return nfd, nil
+ lsa, _ := syscall.Getsockname(netfd.sysfd)
+ netfd.setAddr(toAddr(lsa), toAddr(rsa))
+ return netfd, nil
}
-func (fd *netFD) dup() (f *os.File, err os.Error) {
- ns, e := syscall.Dup(fd.sysfd)
- if e != 0 {
- return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
+func (fd *netFD) dup() (f *os.File, err error) {
+ ns, err := syscall.Dup(fd.sysfd)
+ if err != nil {
+ return nil, &OpError{"dup", fd.net, fd.laddr, err}
}
// We want blocking mode for the new fd, hence the double negative.
- if e = syscall.SetNonblock(ns, false); e != 0 {
- return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
+ if err = syscall.SetNonblock(ns, false); err != nil {
+ return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
}
- return os.NewFile(ns, fd.sysfile.Name()), nil
+ return os.NewFile(uintptr(ns), fd.sysfile.Name()), nil
}
-func closesocket(s int) (errno int) {
+func closesocket(s int) error {
return syscall.Close(s)
}
diff --git a/src/pkg/net/fd_darwin.go b/src/pkg/net/fd_darwin.go
index 7e3d549eb..3dd33edc2 100644
--- a/src/pkg/net/fd_darwin.go
+++ b/src/pkg/net/fd_darwin.go
@@ -7,6 +7,7 @@
package net
import (
+ "errors"
"os"
"syscall"
)
@@ -21,17 +22,17 @@ type pollster struct {
kbuf [1]syscall.Kevent_t
}
-func newpollster() (p *pollster, err os.Error) {
+func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
- if p.kq, e = syscall.Kqueue(); e != 0 {
- return nil, os.NewSyscallError("kqueue", e)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
}
+ syscall.CloseOnExec(p.kq)
p.events = p.eventbuf[0:0]
return p, nil
}
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
// pollServer is locked.
var kmode int
@@ -51,15 +52,15 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
}
syscall.SetKevent(ev, fd, kmode, flags)
- n, e := syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
- if e != 0 {
- return false, os.NewSyscallError("kevent", e)
+ n, err := syscall.Kevent(p.kq, p.kbuf[:], p.kbuf[:], nil)
+ if err != nil {
+ return false, os.NewSyscallError("kevent", err)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
- return false, os.NewError("kqueue phase error")
+ return false, errors.New("kqueue phase error")
}
if ev.Data != 0 {
- return false, os.Errno(int(ev.Data))
+ return false, syscall.Errno(ev.Data)
}
return false, nil
}
@@ -81,7 +82,7 @@ func (p *pollster) DelFD(fd int, mode int) {
syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
}
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
var t *syscall.Timespec
for len(p.events) == 0 {
if nsec > 0 {
@@ -92,19 +93,19 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
}
s.Unlock()
- nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[0:], t)
+ n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
s.Lock()
- if e != 0 {
- if e == syscall.EINTR {
+ if err != nil {
+ if err == syscall.EINTR {
continue
}
- return -1, 0, os.NewSyscallError("kevent", e)
+ return -1, 0, os.NewSyscallError("kevent", nil)
}
- if nn == 0 {
+ if n == 0 {
return -1, 0, nil
}
- p.events = p.eventbuf[0:nn]
+ p.events = p.eventbuf[:n]
}
ev := &p.events[0]
p.events = p.events[1:]
@@ -117,4 +118,4 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
return fd, mode, nil
}
-func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_freebsd.go b/src/pkg/net/fd_freebsd.go
index e50883e94..35d84c30e 100644
--- a/src/pkg/net/fd_freebsd.go
+++ b/src/pkg/net/fd_freebsd.go
@@ -21,17 +21,17 @@ type pollster struct {
kbuf [1]syscall.Kevent_t
}
-func newpollster() (p *pollster, err os.Error) {
+func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
- if p.kq, e = syscall.Kqueue(); e != 0 {
- return nil, os.NewSyscallError("kqueue", e)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
}
+ syscall.CloseOnExec(p.kq)
p.events = p.eventbuf[0:0]
return p, nil
}
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
// pollServer is locked.
var kmode int
@@ -49,15 +49,15 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
}
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)
+ n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if err != nil {
+ return false, os.NewSyscallError("kevent", err)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
- return false, os.NewSyscallError("kqueue phase error", e)
+ return false, os.NewSyscallError("kqueue phase error", err)
}
if ev.Data != 0 {
- return false, os.Errno(int(ev.Data))
+ return false, syscall.Errno(int(ev.Data))
}
return false, nil
}
@@ -77,7 +77,7 @@ func (p *pollster) DelFD(fd int, mode int) {
syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
}
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
var t *syscall.Timespec
for len(p.events) == 0 {
if nsec > 0 {
@@ -88,19 +88,19 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
}
s.Unlock()
- nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
s.Lock()
- if e != 0 {
- if e == syscall.EINTR {
+ if err != nil {
+ if err == syscall.EINTR {
continue
}
- return -1, 0, os.NewSyscallError("kevent", e)
+ return -1, 0, os.NewSyscallError("kevent", err)
}
- if nn == 0 {
+ if n == 0 {
return -1, 0, nil
}
- p.events = p.eventbuf[0:nn]
+ p.events = p.eventbuf[:n]
}
ev := &p.events[0]
p.events = p.events[1:]
@@ -113,4 +113,4 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
return fd, mode, nil
}
-func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go
index 70fc344b2..085e42307 100644
--- a/src/pkg/net/fd_linux.go
+++ b/src/pkg/net/fd_linux.go
@@ -33,21 +33,25 @@ type pollster struct {
ctlEvent syscall.EpollEvent
}
-func newpollster() (p *pollster, err os.Error) {
+func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
-
- // The arg to epoll_create is a hint to the kernel
- // about the number of FDs we will care about.
- // We don't know, and since 2.6.8 the kernel ignores it anyhow.
- if p.epfd, e = syscall.EpollCreate(16); e != 0 {
- return nil, os.NewSyscallError("epoll_create", e)
+ if p.epfd, err = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); err != nil {
+ if err != syscall.ENOSYS {
+ return nil, os.NewSyscallError("epoll_create1", err)
+ }
+ // The arg to epoll_create is a hint to the kernel
+ // about the number of FDs we will care about.
+ // We don't know, and since 2.6.8 the kernel ignores it anyhow.
+ if p.epfd, err = syscall.EpollCreate(16); err != nil {
+ return nil, os.NewSyscallError("epoll_create", err)
+ }
+ syscall.CloseOnExec(p.epfd)
}
p.events = make(map[int]uint32)
return p, nil
}
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
// pollServer is locked.
var already bool
@@ -68,8 +72,8 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
} else {
op = syscall.EPOLL_CTL_ADD
}
- if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 {
- return false, os.NewSyscallError("epoll_ctl", e)
+ if err := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); err != nil {
+ return false, os.NewSyscallError("epoll_ctl", err)
}
p.events[fd] = p.ctlEvent.Events
return false, nil
@@ -80,7 +84,8 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
events, already := p.events[fd]
if !already {
- print("Epoll unexpected fd=", fd, "\n")
+ // The fd returned by the kernel may have been
+ // cancelled already; return silently.
return
}
@@ -97,15 +102,15 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
if int32(events)&^syscall.EPOLLONESHOT != 0 {
p.ctlEvent.Fd = int32(fd)
p.ctlEvent.Events = events
- if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
- print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
+ if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); err != nil {
+ print("Epoll modify fd=", fd, ": ", err.Error(), "\n")
}
p.events[fd] = events
} else {
- if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
- print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
+ if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil {
+ print("Epoll delete fd=", fd, ": ", err.Error(), "\n")
}
- p.events[fd] = 0, false
+ delete(p.events, fd)
}
}
@@ -130,7 +135,7 @@ func (p *pollster) DelFD(fd int, mode int) {
}
}
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
for len(p.waitEvents) == 0 {
var msec int = -1
if nsec > 0 {
@@ -138,14 +143,14 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
}
s.Unlock()
- n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
+ n, err := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
s.Lock()
- if e != 0 {
- if e == syscall.EAGAIN || e == syscall.EINTR {
+ if err != nil {
+ if err == syscall.EAGAIN || err == syscall.EINTR {
continue
}
- return -1, 0, os.NewSyscallError("epoll_wait", e)
+ return -1, 0, os.NewSyscallError("epoll_wait", err)
}
if n == 0 {
return -1, 0, nil
@@ -177,6 +182,6 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
return fd, 'r', nil
}
-func (p *pollster) Close() os.Error {
+func (p *pollster) Close() error {
return os.NewSyscallError("close", syscall.Close(p.epfd))
}
diff --git a/src/pkg/net/fd_netbsd.go b/src/pkg/net/fd_netbsd.go
new file mode 100644
index 000000000..35d84c30e
--- /dev/null
+++ b/src/pkg/net/fd_netbsd.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 error) {
+ p = new(pollster)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
+ }
+ syscall.CloseOnExec(p.kq)
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, 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, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if err != nil {
+ return false, os.NewSyscallError("kevent", err)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", err)
+ }
+ if ev.Data != 0 {
+ return false, syscall.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 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()
+ n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if err != nil {
+ if err == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", err)
+ }
+ if n == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[:n]
+ }
+ 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() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_openbsd.go b/src/pkg/net/fd_openbsd.go
index e50883e94..35d84c30e 100644
--- a/src/pkg/net/fd_openbsd.go
+++ b/src/pkg/net/fd_openbsd.go
@@ -21,17 +21,17 @@ type pollster struct {
kbuf [1]syscall.Kevent_t
}
-func newpollster() (p *pollster, err os.Error) {
+func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
- if p.kq, e = syscall.Kqueue(); e != 0 {
- return nil, os.NewSyscallError("kqueue", e)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
}
+ syscall.CloseOnExec(p.kq)
p.events = p.eventbuf[0:0]
return p, nil
}
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
// pollServer is locked.
var kmode int
@@ -49,15 +49,15 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
}
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)
+ n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if err != nil {
+ return false, os.NewSyscallError("kevent", err)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
- return false, os.NewSyscallError("kqueue phase error", e)
+ return false, os.NewSyscallError("kqueue phase error", err)
}
if ev.Data != 0 {
- return false, os.Errno(int(ev.Data))
+ return false, syscall.Errno(int(ev.Data))
}
return false, nil
}
@@ -77,7 +77,7 @@ func (p *pollster) DelFD(fd int, mode int) {
syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
}
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
var t *syscall.Timespec
for len(p.events) == 0 {
if nsec > 0 {
@@ -88,19 +88,19 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
}
s.Unlock()
- nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
s.Lock()
- if e != 0 {
- if e == syscall.EINTR {
+ if err != nil {
+ if err == syscall.EINTR {
continue
}
- return -1, 0, os.NewSyscallError("kevent", e)
+ return -1, 0, os.NewSyscallError("kevent", err)
}
- if nn == 0 {
+ if n == 0 {
return -1, 0, nil
}
- p.events = p.eventbuf[0:nn]
+ p.events = p.eventbuf[:n]
}
ev := &p.events[0]
p.events = p.events[1:]
@@ -113,4 +113,4 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.E
return fd, mode, nil
}
-func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 3757e143d..45f5c2d88 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -5,6 +5,8 @@
package net
import (
+ "errors"
+ "io"
"os"
"runtime"
"sync"
@@ -13,23 +15,17 @@ import (
"unsafe"
)
-type InvalidConnError struct{}
-
-func (e *InvalidConnError) String() string { return "invalid net.Conn" }
-func (e *InvalidConnError) Temporary() bool { return false }
-func (e *InvalidConnError) Timeout() bool { return false }
-
-var initErr os.Error
+var initErr error
func init() {
var d syscall.WSAData
- e := syscall.WSAStartup(uint32(0x101), &d)
- if e != 0 {
+ e := syscall.WSAStartup(uint32(0x202), &d)
+ if e != nil {
initErr = os.NewSyscallError("WSAStartup", e)
}
}
-func closesocket(s syscall.Handle) (errno int) {
+func closesocket(s syscall.Handle) error {
return syscall.Closesocket(s)
}
@@ -37,13 +33,13 @@ func closesocket(s syscall.Handle) (errno int) {
type anOpIface interface {
Op() *anOp
Name() string
- Submit() (errno int)
+ Submit() error
}
// IO completion result parameters.
type ioResult struct {
qty uint32
- err int
+ err error
}
// anOp implements functionality common to all io operations.
@@ -52,15 +48,27 @@ type anOp struct {
// of the struct, as our code rely on it.
o syscall.Overlapped
- resultc chan ioResult // io completion results
- errnoc chan int // io submit / cancel operation errors
+ resultc chan ioResult
+ errnoc chan error
fd *netFD
}
-func (o *anOp) Init(fd *netFD) {
+func (o *anOp) Init(fd *netFD, mode int) {
o.fd = fd
- o.resultc = make(chan ioResult, 1)
- o.errnoc = make(chan int)
+ var i int
+ if mode == 'r' {
+ i = 0
+ } else {
+ i = 1
+ }
+ if fd.resultc[i] == nil {
+ fd.resultc[i] = make(chan ioResult, 1)
+ }
+ o.resultc = fd.resultc[i]
+ if fd.errnoc[i] == nil {
+ fd.errnoc[i] = make(chan error)
+ }
+ o.errnoc = fd.errnoc[i]
}
func (o *anOp) Op() *anOp {
@@ -74,8 +82,8 @@ type bufOp struct {
buf syscall.WSABuf
}
-func (o *bufOp) Init(fd *netFD, buf []byte) {
- o.anOp.Init(fd)
+func (o *bufOp) Init(fd *netFD, buf []byte, mode int) {
+ o.anOp.Init(fd, mode)
o.buf.Len = uint32(len(buf))
if len(buf) == 0 {
o.buf.Buf = nil
@@ -98,14 +106,14 @@ func (s *resultSrv) Run() {
for {
r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
switch {
- case r.err == 0:
+ case r.err == nil:
// Dequeued successfully completed io packet.
- case r.err == syscall.WAIT_TIMEOUT && o == nil:
+ case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil:
// Wait has timed out (should not happen now, but might be used in the future).
panic("GetQueuedCompletionStatus timed out")
case o == nil:
// Failed to dequeue anything -> report the error.
- panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err))
+ panic("GetQueuedCompletionStatus failed " + r.err.Error())
default:
// Dequeued failed io packet.
}
@@ -137,33 +145,41 @@ func (s *ioSrv) ProcessRemoteIO() {
}
// ExecIO executes a single io operation. It either executes it
-// inline, or, if timeouts are employed, passes the request onto
+// inline, or, if a deadline is employed, passes the request onto
// a special goroutine and waits for completion or cancels request.
-func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error) {
- var e int
+// deadline is unix nanos.
+func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
+ var err error
o := oi.Op()
- if deadline_delta > 0 {
+ if deadline != 0 {
// Send request to a special dedicated thread,
// so it can stop the io with CancelIO later.
s.submchan <- oi
- e = <-o.errnoc
+ err = <-o.errnoc
} else {
- e = oi.Submit()
+ err = oi.Submit()
}
- switch e {
- case 0:
+ switch err {
+ case nil:
// IO completed immediately, but we need to get our completion message anyway.
case syscall.ERROR_IO_PENDING:
// IO started, and we have to wait for its completion.
+ err = nil
default:
- return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
+ return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, err}
}
// Wait for our request to complete.
var r ioResult
- if deadline_delta > 0 {
+ if deadline != 0 {
+ dt := deadline - time.Now().UnixNano()
+ if dt < 1 {
+ dt = 1
+ }
+ timer := time.NewTimer(time.Duration(dt) * time.Nanosecond)
+ defer timer.Stop()
select {
case r = <-o.resultc:
- case <-time.After(deadline_delta):
+ case <-timer.C:
s.canchan <- oi
<-o.errnoc
r = <-o.resultc
@@ -174,8 +190,8 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error)
} else {
r = <-o.resultc
}
- if r.err != 0 {
- err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)}
+ if r.err != nil {
+ err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err}
}
return int(r.qty), err
}
@@ -187,10 +203,10 @@ var onceStartServer sync.Once
func startServer() {
resultsrv = new(resultSrv)
- var errno int
- resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
- if errno != 0 {
- panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
+ var err error
+ resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
+ if err != nil {
+ panic("CreateIoCompletionPort: " + err.Error())
}
go resultsrv.Run()
@@ -208,41 +224,42 @@ type netFD struct {
closing bool
// immutable until Close
- sysfd syscall.Handle
- family int
- proto int
- net string
- laddr Addr
- raddr Addr
+ sysfd syscall.Handle
+ family int
+ sotype int
+ isConnected bool
+ net string
+ laddr Addr
+ raddr Addr
+ resultc [2]chan ioResult // read/write completion results
+ errnoc [2]chan error // read/write submit or cancel operation errors
// owned by client
- rdeadline_delta int64
- rdeadline int64
- rio sync.Mutex
- wdeadline_delta int64
- wdeadline int64
- wio sync.Mutex
+ rdeadline int64
+ rio sync.Mutex
+ wdeadline int64
+ wio sync.Mutex
}
-func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
- f = &netFD{
+func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
+ netfd := &netFD{
sysfd: fd,
family: family,
- proto: proto,
+ sotype: sotype,
net: net,
}
- runtime.SetFinalizer(f, (*netFD).Close)
- return f
+ runtime.SetFinalizer(netfd, (*netFD).Close)
+ return netfd
}
-func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) {
+func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
if initErr != nil {
return nil, initErr
}
onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp.
- if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, err := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); err != nil {
+ return nil, err
}
return allocFD(fd, family, proto, net), nil
}
@@ -252,19 +269,31 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
fd.raddr = raddr
}
-func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
- e := syscall.Connect(fd.sysfd, ra)
- if e != 0 {
- return os.Errno(e)
- }
- return nil
+func (fd *netFD) connect(ra syscall.Sockaddr) error {
+ return syscall.Connect(fd.sysfd, ra)
}
+var errClosing = errors.New("use of closed network connection")
+
// Add a reference to this fd.
-func (fd *netFD) incref() {
+// If closing==true, mark the fd as closing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref(closing bool) error {
+ if fd == nil {
+ return errClosing
+ }
fd.sysmu.Lock()
+ if fd.closing {
+ fd.sysmu.Unlock()
+ return errClosing
+ }
fd.sysref++
+ if closing {
+ fd.closing = true
+ }
+ closing = fd.closing
fd.sysmu.Unlock()
+ return nil
}
// Remove a reference to this FD and close if we've been asked to do so (and
@@ -272,7 +301,17 @@ func (fd *netFD) incref() {
func (fd *netFD) decref() {
fd.sysmu.Lock()
fd.sysref--
- if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
+ // NOTE(rsc): On Unix we check fd.sysref == 0 here before closing,
+ // but on Windows we have no way to wake up the blocked I/O other
+ // than closing the socket (or calling Shutdown, which breaks other
+ // programs that might have a reference to the socket). So there is
+ // a small race here that we might close fd.sysfd and then some other
+ // goroutine might start a read of fd.sysfd (having read it before we
+ // write InvalidHandle to it), which might refer to some other file
+ // if the specific handle value gets reused. I think handle values on
+ // Windows are not reused as aggressively as file descriptors on Unix,
+ // so this might be tolerable.
+ if fd.closing && 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
@@ -286,25 +325,40 @@ func (fd *netFD) decref() {
fd.sysmu.Unlock()
}
-func (fd *netFD) Close() os.Error {
- if fd == nil || fd.sysfd == syscall.InvalidHandle {
- return os.EINVAL
+func (fd *netFD) Close() error {
+ if err := fd.incref(true); err != nil {
+ return err
}
-
- fd.incref()
- syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
- fd.closing = true
fd.decref()
return nil
}
+func (fd *netFD) shutdown(how int) error {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
+ return syscall.EINVAL
+ }
+ err := syscall.Shutdown(fd.sysfd, how)
+ if err != nil {
+ return &OpError{"shutdown", fd.net, fd.laddr, err}
+ }
+ return nil
+}
+
+func (fd *netFD) CloseRead() error {
+ return fd.shutdown(syscall.SHUT_RD)
+}
+
+func (fd *netFD) CloseWrite() error {
+ return fd.shutdown(syscall.SHUT_WR)
+}
+
// Read from network.
type readOp struct {
bufOp
}
-func (o *readOp) Submit() (errno int) {
+func (o *readOp) Submit() error {
var d, f uint32
return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
}
@@ -313,24 +367,26 @@ func (o *readOp) Name() string {
return "WSARecv"
}
-func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
+func (fd *netFD) Read(buf []byte) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
fd.rio.Lock()
defer fd.rio.Unlock()
- fd.incref()
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
var o readOp
- o.Init(fd, buf)
- n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ o.Init(fd, buf, 'r')
+ n, err := iosrv.ExecIO(&o, fd.rdeadline)
if err == nil && n == 0 {
- err = os.EOF
+ err = io.EOF
}
- return
+ return n, err
}
// ReadFrom from network.
@@ -341,7 +397,7 @@ type readFromOp struct {
rsan int32
}
-func (o *readFromOp) Submit() (errno int) {
+func (o *readFromOp) Submit() error {
var d, f uint32
return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
}
@@ -350,24 +406,23 @@ func (o *readFromOp) Name() string {
return "WSARecvFrom"
}
-func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error) {
+func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
if fd == nil {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil, nil
}
fd.rio.Lock()
defer fd.rio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.sysfd == syscall.InvalidHandle {
- return 0, nil, os.EINVAL
+ if err := fd.incref(false); err != nil {
+ return 0, nil, err
}
+ defer fd.decref()
var o readFromOp
- o.Init(fd, buf)
+ o.Init(fd, buf, 'r')
o.rsan = int32(unsafe.Sizeof(o.rsa))
- n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ n, err = iosrv.ExecIO(&o, fd.rdeadline)
if err != nil {
return 0, nil, err
}
@@ -381,7 +436,7 @@ type writeOp struct {
bufOp
}
-func (o *writeOp) Submit() (errno int) {
+func (o *writeOp) Submit() error {
var d uint32
return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
}
@@ -390,20 +445,19 @@ func (o *writeOp) Name() string {
return "WSASend"
}
-func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
+func (fd *netFD) Write(buf []byte) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
fd.wio.Lock()
defer fd.wio.Unlock()
- fd.incref()
- defer fd.decref()
- if fd.sysfd == syscall.InvalidHandle {
- return 0, os.EINVAL
+ if err := fd.incref(false); err != nil {
+ return 0, err
}
+ defer fd.decref()
var o writeOp
- o.Init(fd, buf)
- return iosrv.ExecIO(&o, fd.wdeadline_delta)
+ o.Init(fd, buf, 'w')
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// WriteTo to network.
@@ -413,7 +467,7 @@ type writeToOp struct {
sa syscall.Sockaddr
}
-func (o *writeToOp) Submit() (errno int) {
+func (o *writeToOp) Submit() error {
var d uint32
return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
}
@@ -422,24 +476,26 @@ func (o *writeToOp) Name() string {
return "WSASendto"
}
-func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error) {
+func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if fd == nil {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil
}
fd.wio.Lock()
defer fd.wio.Unlock()
- fd.incref()
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
var o writeToOp
- o.Init(fd, buf)
+ o.Init(fd, buf, 'w')
o.sa = sa
- return iosrv.ExecIO(&o, fd.wdeadline_delta)
+ return iosrv.ExecIO(&o, fd.wdeadline)
}
// Accept new network connections.
@@ -450,7 +506,7 @@ type acceptOp struct {
attrs [2]syscall.RawSockaddrAny // space for local and remote address only
}
-func (o *acceptOp) Submit() (errno int) {
+func (o *acceptOp) Submit() error {
var d uint32
l := uint32(unsafe.Sizeof(o.attrs[0]))
return syscall.AcceptEx(o.fd.sysfd, o.newsock,
@@ -461,33 +517,32 @@ func (o *acceptOp) Name() string {
return "AcceptEx"
}
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
- if fd == nil || fd.sysfd == syscall.InvalidHandle {
- return nil, os.EINVAL
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
}
- fd.incref()
defer fd.decref()
// Get new socket.
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, e := syscall.Socket(fd.family, fd.proto, 0)
- if e != 0 {
+ s, err := syscall.Socket(fd.family, fd.sotype, 0)
+ if err != nil {
syscall.ForkLock.RUnlock()
- return nil, os.Errno(e)
+ return nil, err
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
- if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
- return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
+ if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
+ return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
}
// Submit accept request.
var o acceptOp
- o.Init(fd)
+ o.Init(fd, 'r')
o.newsock = s
_, err = iosrv.ExecIO(&o, 0)
if err != nil {
@@ -496,8 +551,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
}
// Inherit properties of the listening socket.
- e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
- if e != 0 {
+ err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
+ if err != nil {
closesocket(s)
return nil, err
}
@@ -511,22 +566,24 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr()
- nfd = allocFD(s, fd.family, fd.proto, fd.net)
- nfd.setAddr(toAddr(lsa), toAddr(rsa))
- return nfd, nil
+ netfd := allocFD(s, fd.family, fd.sotype, fd.net)
+ netfd.setAddr(toAddr(lsa), toAddr(rsa))
+ return netfd, nil
}
// Unimplemented functions.
-func (fd *netFD) dup() (f *os.File, err os.Error) {
+func (fd *netFD) dup() (*os.File, error) {
// TODO: Implement this
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
}
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
- return 0, 0, 0, nil, os.EAFNOSUPPORT
+var errNoSupport = errors.New("address family not supported")
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+ return 0, 0, 0, nil, errNoSupport
}
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
- return 0, 0, os.EAFNOSUPPORT
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+ return 0, 0, errNoSupport
}
diff --git a/src/pkg/net/file.go b/src/pkg/net/file.go
index 0e411a192..c95d16d64 100644
--- a/src/pkg/net/file.go
+++ b/src/pkg/net/file.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.
+// +build darwin freebsd linux netbsd openbsd
+
package net
import (
@@ -9,36 +11,40 @@ import (
"syscall"
)
-func newFileFD(f *os.File) (nfd *netFD, err os.Error) {
- fd, errno := syscall.Dup(f.Fd())
- if errno != 0 {
- return nil, os.NewSyscallError("dup", errno)
+func newFileFD(f *os.File) (*netFD, error) {
+ fd, err := syscall.Dup(int(f.Fd()))
+ if err != nil {
+ return nil, os.NewSyscallError("dup", err)
}
- proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
- if errno != 0 {
- return nil, os.NewSyscallError("getsockopt", errno)
+ proto, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
}
+ family := syscall.AF_UNSPEC
toAddr := sockaddrToTCP
sa, _ := syscall.Getsockname(fd)
switch sa.(type) {
default:
closesocket(fd)
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
case *syscall.SockaddrInet4:
+ family = syscall.AF_INET
if proto == syscall.SOCK_DGRAM {
toAddr = sockaddrToUDP
} else if proto == syscall.SOCK_RAW {
toAddr = sockaddrToIP
}
case *syscall.SockaddrInet6:
+ family = syscall.AF_INET6
if proto == syscall.SOCK_DGRAM {
toAddr = sockaddrToUDP
} else if proto == syscall.SOCK_RAW {
toAddr = sockaddrToIP
}
case *syscall.SockaddrUnix:
+ family = syscall.AF_UNIX
toAddr = sockaddrToUnix
if proto == syscall.SOCK_DGRAM {
toAddr = sockaddrToUnixgram
@@ -50,18 +56,19 @@ func newFileFD(f *os.File) (nfd *netFD, err os.Error) {
sa, _ = syscall.Getpeername(fd)
raddr := toAddr(sa)
- if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil {
+ netfd, err := newFD(fd, family, proto, laddr.Network())
+ if err != nil {
return nil, err
}
- nfd.setAddr(laddr, raddr)
- return nfd, nil
+ netfd.setAddr(laddr, raddr)
+ return netfd, nil
}
// FileConn returns a copy of the network connection corresponding to
// 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) {
+func FileConn(f *os.File) (c Conn, err error) {
fd, err := newFileFD(f)
if err != nil {
return nil, err
@@ -77,14 +84,14 @@ func FileConn(f *os.File) (c Conn, err os.Error) {
return newIPConn(fd), nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
// 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) {
+func FileListener(f *os.File) (l Listener, err error) {
fd, err := newFileFD(f)
if err != nil {
return nil, err
@@ -96,14 +103,14 @@ func FileListener(f *os.File) (l Listener, err os.Error) {
return &UnixListener{fd, laddr.Name}, nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
// 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) {
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
fd, err := newFileFD(f)
if err != nil {
return nil, err
@@ -115,5 +122,5 @@ func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
return newUnixConn(fd), nil
}
fd.Close()
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
diff --git a/src/pkg/net/file_plan9.go b/src/pkg/net/file_plan9.go
index a07e74331..04f7ee040 100644
--- a/src/pkg/net/file_plan9.go
+++ b/src/pkg/net/file_plan9.go
@@ -6,28 +6,29 @@ package net
import (
"os"
+ "syscall"
)
// 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
+func FileConn(f *os.File) (c Conn, err error) {
+ return nil, syscall.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
+func FileListener(f *os.File) (l Listener, err error) {
+ return nil, syscall.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
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
+ return nil, syscall.EPLAN9
}
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index 9a8c2dcbc..95c0b6699 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -8,27 +8,27 @@ import (
"os"
"reflect"
"runtime"
- "syscall"
"testing"
)
type listenerFile interface {
Listener
- File() (f *os.File, err os.Error)
+ File() (f *os.File, err error)
}
type packetConnFile interface {
PacketConn
- File() (f *os.File, err os.Error)
+ File() (f *os.File, err error)
}
type connFile interface {
Conn
- File() (f *os.File, err os.Error)
+ File() (f *os.File, err error)
}
func testFileListener(t *testing.T, net, laddr string) {
- if net == "tcp" {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
laddr += ":0" // any available port
}
l, err := Listen(net, laddr)
@@ -56,24 +56,56 @@ func testFileListener(t *testing.T, net, laddr string) {
}
}
+var fileListenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "tcp", laddr: ""},
+ {net: "tcp", laddr: "0.0.0.0"},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]"},
+ {net: "tcp", laddr: "[::]", ipv6: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: ""},
+ {net: "tcp4", laddr: "0.0.0.0"},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]"},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
+
+ {net: "unix", laddr: "@gotest/net", linux: true},
+ {net: "unixpacket", laddr: "@gotest/net", linux: true},
+}
+
func TestFileListener(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFileListener(t, "tcp", "127.0.0.1")
- testFileListener(t, "tcp", "127.0.0.1")
- 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]")
- }
- if syscall.OS == "linux" {
- testFileListener(t, "unix", "@gotest/net")
- testFileListener(t, "unixpacket", "@gotest/net")
+
+ for _, tt := range fileListenerTests {
+ if skipServerTest(tt.net, "unix", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ if skipServerTest(tt.net, "unixpacket", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFileListener(t, tt.net, tt.laddr)
}
}
-func testFilePacketConn(t *testing.T, pcf packetConnFile) {
+func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
f, err := pcf.File()
if err != nil {
t.Fatalf("File failed: %v", err)
@@ -85,6 +117,11 @@ func testFilePacketConn(t *testing.T, pcf packetConnFile) {
if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
}
+ if listen {
+ if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil {
+ t.Fatalf("WriteTo failed: %v", err)
+ }
+ }
if err := c.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
@@ -94,40 +131,71 @@ func testFilePacketConn(t *testing.T, pcf packetConnFile) {
}
func testFilePacketConnListen(t *testing.T, net, laddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ laddr += ":0" // any available port
+ }
l, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ t.Fatalf("ListenPacket failed: %v", err)
}
- testFilePacketConn(t, l.(packetConnFile))
+ testFilePacketConn(t, l.(packetConnFile), true)
if err := l.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
func testFilePacketConnDial(t *testing.T, net, raddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ raddr += ":12345"
+ }
c, err := Dial(net, raddr)
if err != nil {
t.Fatalf("Dial failed: %v", err)
}
- testFilePacketConn(t, c.(packetConnFile))
+ testFilePacketConn(t, c.(packetConnFile), false)
if err := c.Close(); err != nil {
t.Fatalf("Close failed: %v", err)
}
}
+var filePacketConnTests = []struct {
+ net string
+ addr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "udp", addr: "127.0.0.1"},
+ {net: "udp", addr: "[::ffff:127.0.0.1]"},
+ {net: "udp", addr: "[::1]", ipv6: true},
+
+ {net: "udp4", addr: "127.0.0.1"},
+ {net: "udp4", addr: "[::ffff:127.0.0.1]"},
+
+ {net: "udp6", addr: "[::1]", ipv6: true},
+
+ {net: "unixgram", addr: "@gotest3/net", linux: true},
+}
+
func TestFilePacketConn(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFilePacketConnListen(t, "udp", "127.0.0.1:0")
- testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
- if supportsIPv6 {
- testFilePacketConnListen(t, "udp", "[::1]:0")
- }
- if supportsIPv6 && supportsIPv4map {
- testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
- }
- if syscall.OS == "linux" {
- testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+
+ for _, tt := range filePacketConnTests {
+ if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFilePacketConnListen(t, tt.net, tt.addr)
+ switch tt.addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ default:
+ if tt.net != "unixgram" {
+ testFilePacketConnDial(t, tt.net, tt.addr)
+ }
+ }
}
}
diff --git a/src/pkg/net/file_windows.go b/src/pkg/net/file_windows.go
index 94aa58375..c50c32e21 100644
--- a/src/pkg/net/file_windows.go
+++ b/src/pkg/net/file_windows.go
@@ -9,17 +9,17 @@ import (
"syscall"
)
-func FileConn(f *os.File) (c Conn, err os.Error) {
+func FileConn(f *os.File) (c Conn, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
}
-func FileListener(f *os.File) (l Listener, err os.Error) {
+func FileListener(f *os.File) (l Listener, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
}
-func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
}
diff --git a/src/pkg/net/hosts.go b/src/pkg/net/hosts.go
index d75e9e038..e6674ba34 100644
--- a/src/pkg/net/hosts.go
+++ b/src/pkg/net/hosts.go
@@ -7,11 +7,11 @@
package net
import (
- "os"
"sync"
+ "time"
)
-const cacheMaxAge = int64(300) // 5 minutes.
+const cacheMaxAge = 5 * time.Minute
// hostsPath points to the file with static IP/address entries.
var hostsPath = "/etc/hosts"
@@ -21,14 +21,14 @@ var hosts struct {
sync.Mutex
byName map[string][]string
byAddr map[string][]string
- time int64
+ expire time.Time
path string
}
func readHosts() {
- now, _, _ := os.Time()
+ now := time.Now()
hp := hostsPath
- if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+ if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
hs := make(map[string][]string)
is := make(map[string][]string)
var file *file
@@ -51,7 +51,7 @@ func readHosts() {
}
}
// Update the data cache.
- hosts.time, _, _ = os.Time()
+ hosts.expire = time.Now().Add(cacheMaxAge)
hosts.path = hp
hosts.byName = hs
hosts.byAddr = is
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index 1bd00541c..064e7e432 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -34,7 +34,7 @@ var hosttests = []hostTest{
func TestLookupStaticHost(t *testing.T) {
p := hostsPath
- hostsPath = "hosts_testdata"
+ hostsPath = "testdata/hosts"
for i := 0; i < len(hosttests); i++ {
tt := hosttests[i]
ips := lookupStaticHost(tt.host)
diff --git a/src/pkg/http/cgi/child.go b/src/pkg/net/http/cgi/child.go
index 8d0eca8d5..1ba7bec5f 100644
--- a/src/pkg/http/cgi/child.go
+++ b/src/pkg/net/http/cgi/child.go
@@ -10,22 +10,23 @@ package cgi
import (
"bufio"
"crypto/tls"
+ "errors"
"fmt"
- "http"
"io"
"io/ioutil"
"net"
+ "net/http"
+ "net/url"
"os"
"strconv"
"strings"
- "url"
)
// Request returns the HTTP request as represented in the current
// environment. This assumes the current program is being run
// by a web server in a CGI environment.
// The returned Request's Body is populated, if applicable.
-func Request() (*http.Request, os.Error) {
+func Request() (*http.Request, error) {
r, err := RequestFromMap(envMap(os.Environ()))
if err != nil {
return nil, err
@@ -48,18 +49,18 @@ func envMap(env []string) map[string]string {
// 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) {
+func RequestFromMap(params map[string]string) (*http.Request, error) {
r := new(http.Request)
r.Method = params["REQUEST_METHOD"]
if r.Method == "" {
- return nil, os.NewError("cgi: no REQUEST_METHOD in environment")
+ return nil, errors.New("cgi: no REQUEST_METHOD in environment")
}
r.Proto = params["SERVER_PROTOCOL"]
var ok bool
r.ProtoMajor, r.ProtoMinor, ok = http.ParseHTTPVersion(r.Proto)
if !ok {
- return nil, os.NewError("cgi: invalid SERVER_PROTOCOL version")
+ return nil, errors.New("cgi: invalid SERVER_PROTOCOL version")
}
r.Close = true
@@ -69,9 +70,9 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
r.Host = params["HTTP_HOST"]
if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
- clen, err := strconv.Atoi64(lenstr)
+ clen, err := strconv.ParseInt(lenstr, 10, 64)
if err != nil {
- return nil, os.NewError("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
+ return nil, errors.New("cgi: bad CONTENT_LENGTH in environment: " + lenstr)
}
r.ContentLength = clen
}
@@ -93,20 +94,20 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
if r.Host != "" {
// 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 := url.Parse(r.RawURL)
+ rawurl := "http://" + r.Host + params["REQUEST_URI"]
+ url, err := url.Parse(rawurl)
if err != nil {
- return nil, os.NewError("cgi: failed to parse host and REQUEST_URI into a URL: " + r.RawURL)
+ return nil, errors.New("cgi: failed to parse host and REQUEST_URI into a URL: " + rawurl)
}
r.URL = url
}
// Fallback logic if we don't have a Host header or the URL
// failed to parse
if r.URL == nil {
- r.RawURL = params["REQUEST_URI"]
- url, err := url.Parse(r.RawURL)
+ uriStr := params["REQUEST_URI"]
+ url, err := url.Parse(uriStr)
if err != nil {
- return nil, os.NewError("cgi: failed to parse REQUEST_URI into a URL: " + r.RawURL)
+ return nil, errors.New("cgi: failed to parse REQUEST_URI into a URL: " + uriStr)
}
r.URL = url
}
@@ -129,7 +130,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
// request, if any. If there's no current CGI environment
// an error is returned. The provided handler may be nil to use
// http.DefaultServeMux.
-func Serve(handler http.Handler) os.Error {
+func Serve(handler http.Handler) error {
req, err := Request()
if err != nil {
return err
@@ -143,6 +144,7 @@ func Serve(handler http.Handler) os.Error {
bufw: bufio.NewWriter(os.Stdout),
}
handler.ServeHTTP(rw, req)
+ rw.Write(nil) // make sure a response is sent
if err = rw.bufw.Flush(); err != nil {
return err
}
@@ -164,7 +166,7 @@ func (r *response) Header() http.Header {
return r.header
}
-func (r *response) Write(p []byte) (n int, err os.Error) {
+func (r *response) Write(p []byte) (n int, err error) {
if !r.headerSent {
r.WriteHeader(http.StatusOK)
}
diff --git a/src/pkg/http/cgi/child_test.go b/src/pkg/net/http/cgi/child_test.go
index eee043bc9..ec53ab851 100644
--- a/src/pkg/http/cgi/child_test.go
+++ b/src/pkg/net/http/cgi/child_test.go
@@ -49,9 +49,6 @@ func TestRequest(t *testing.T) {
if g, e := req.Header.Get("Foo-Bar"), "baz"; e != g {
t.Errorf("expected Foo-Bar %q; got %q", e, g)
}
- if g, e := req.RawURL, "http://example.com/path?a=b"; e != g {
- t.Errorf("expected RawURL %q; got %q", e, g)
- }
if g, e := req.URL.String(), "http://example.com/path?a=b"; e != g {
t.Errorf("expected URL %q; got %q", e, g)
}
@@ -81,9 +78,6 @@ func TestRequestWithoutHost(t *testing.T) {
if err != nil {
t.Fatalf("RequestFromMap: %v", err)
}
- if g, e := req.RawURL, "/path?a=b"; e != g {
- t.Errorf("expected RawURL %q; got %q", e, g)
- }
if req.URL == nil {
t.Fatalf("unexpected nil URL")
}
diff --git a/src/pkg/http/cgi/host.go b/src/pkg/net/http/cgi/host.go
index f7de89f99..d27cc4dc9 100644
--- a/src/pkg/http/cgi/host.go
+++ b/src/pkg/net/http/cgi/host.go
@@ -16,12 +16,12 @@ package cgi
import (
"bufio"
- "exec"
"fmt"
- "http"
"io"
"log"
+ "net/http"
"os"
+ "os/exec"
"path/filepath"
"regexp"
"runtime"
@@ -32,13 +32,14 @@ import (
var trailingPort = regexp.MustCompile(`:([0-9]+)$`)
var osDefaultInheritEnv = map[string][]string{
- "darwin": []string{"DYLD_LIBRARY_PATH"},
- "freebsd": []string{"LD_LIBRARY_PATH"},
- "hpux": []string{"LD_LIBRARY_PATH", "SHLIB_PATH"},
- "irix": []string{"LD_LIBRARY_PATH", "LD_LIBRARYN32_PATH", "LD_LIBRARY64_PATH"},
- "linux": []string{"LD_LIBRARY_PATH"},
- "solaris": []string{"LD_LIBRARY_PATH", "LD_LIBRARY_PATH_32", "LD_LIBRARY_PATH_64"},
- "windows": []string{"SystemRoot", "COMSPEC", "PATHEXT", "WINDIR"},
+ "darwin": {"DYLD_LIBRARY_PATH"},
+ "freebsd": {"LD_LIBRARY_PATH"},
+ "hpux": {"LD_LIBRARY_PATH", "SHLIB_PATH"},
+ "irix": {"LD_LIBRARY_PATH", "LD_LIBRARYN32_PATH", "LD_LIBRARY64_PATH"},
+ "linux": {"LD_LIBRARY_PATH"},
+ "openbsd": {"LD_LIBRARY_PATH"},
+ "solaris": {"LD_LIBRARY_PATH", "LD_LIBRARY_PATH_32", "LD_LIBRARY_PATH_64"},
+ "windows": {"SystemRoot", "COMSPEC", "PATHEXT", "WINDIR"},
}
// Handler runs an executable in a subprocess with a CGI environment.
@@ -68,6 +69,31 @@ type Handler struct {
PathLocationHandler http.Handler
}
+// removeLeadingDuplicates remove leading duplicate in environments.
+// It's possible to override environment like following.
+// cgi.Handler{
+// ...
+// Env: []string{"SCRIPT_FILENAME=foo.php"},
+// }
+func removeLeadingDuplicates(env []string) (ret []string) {
+ n := len(env)
+ for i := 0; i < n; i++ {
+ e := env[i]
+ s := strings.SplitN(e, "=", 2)[0]
+ found := false
+ for j := i + 1; j < n; j++ {
+ if s == strings.SplitN(env[j], "=", 2)[0] {
+ found = true
+ break
+ }
+ }
+ if !found {
+ ret = append(ret, e)
+ }
+ }
+ return
+}
+
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
root := h.Root
if root == "" {
@@ -98,7 +124,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
"GATEWAY_INTERFACE=CGI/1.1",
"REQUEST_METHOD=" + req.Method,
"QUERY_STRING=" + req.URL.RawQuery,
- "REQUEST_URI=" + req.URL.RawPath,
+ "REQUEST_URI=" + req.URL.RequestURI(),
"PATH_INFO=" + pathInfo,
"SCRIPT_NAME=" + root,
"SCRIPT_FILENAME=" + h.Path,
@@ -149,6 +175,8 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
+ env = removeLeadingDuplicates(env)
+
var cwd, path string
if h.Dir != "" {
path = h.Path
@@ -160,7 +188,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
cwd = "."
}
- internalError := func(err os.Error) {
+ internalError := func(err error) {
rw.WriteHeader(http.StatusInternalServerError)
h.printf("CGI error: %v", err)
}
@@ -189,7 +217,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
defer cmd.Wait()
defer stdoutRead.Close()
- linebody, _ := bufio.NewReaderSize(stdoutRead, 1024)
+ linebody := bufio.NewReaderSize(stdoutRead, 1024)
headers := make(http.Header)
statusCode := 0
for {
@@ -199,7 +227,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
h.printf("cgi: long header line from subprocess.")
return
}
- if err == os.EOF {
+ if err == io.EOF {
break
}
if err != nil {
@@ -294,7 +322,6 @@ func (h *Handler) handleInternalRedirect(rw http.ResponseWriter, req *http.Reque
newReq := &http.Request{
Method: "GET",
URL: url,
- RawURL: path,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
@@ -306,18 +333,18 @@ func (h *Handler) handleInternalRedirect(rw http.ResponseWriter, req *http.Reque
h.PathLocationHandler.ServeHTTP(rw, newReq)
}
-func upperCaseAndUnderscore(rune int) int {
+func upperCaseAndUnderscore(r rune) rune {
switch {
- case rune >= 'a' && rune <= 'z':
- return rune - ('a' - 'A')
- case rune == '-':
+ case r >= 'a' && r <= 'z':
+ return r - ('a' - 'A')
+ case r == '-':
return '_'
- case rune == '=':
+ case r == '=':
// Maybe not part of the CGI 'spec' but would mess up
// the environment in any case, as Go represents the
// environment as a slice of "key=value" strings.
return '_'
}
// TODO: other transformations in spec or practice?
- return rune
+ return r
}
diff --git a/src/pkg/http/cgi/host_test.go b/src/pkg/net/http/cgi/host_test.go
index 1dc3abdbb..4db3d850c 100644
--- a/src/pkg/http/cgi/host_test.go
+++ b/src/pkg/net/http/cgi/host_test.go
@@ -8,19 +8,20 @@ package cgi
import (
"bufio"
- "exec"
"fmt"
- "http"
- "http/httptest"
"io"
- "os"
"net"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "os/exec"
"path/filepath"
+ "runtime"
"strconv"
"strings"
+ "syscall"
"testing"
"time"
- "runtime"
)
func newRequest(httpreq string) *http.Request {
@@ -40,12 +41,13 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string
// Make a map to hold the test map that the CGI returns.
m := make(map[string]string)
+ m["_body"] = rw.Body.String()
linesRead := 0
readlines:
for {
line, err := rw.Body.ReadString('\n')
switch {
- case err == os.EOF:
+ case err == io.EOF:
break readlines
case err != nil:
t.Fatalf("unexpected error reading from CGI: %v", err)
@@ -355,7 +357,7 @@ func TestCopyError(t *testing.T) {
if err != nil {
return false
}
- return p.Signal(os.UnixSignal(0)) == nil
+ return p.Signal(syscall.Signal(0)) == nil
}
if !childRunning() {
@@ -363,14 +365,13 @@ func TestCopyError(t *testing.T) {
}
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")
- }
+ tries := 0
+ for tries < 25 && childRunning() {
+ time.Sleep(50 * time.Millisecond * time.Duration(tries))
+ tries++
+ }
+ if childRunning() {
+ t.Fatalf("post-conn.Close, expected child to be gone")
}
}
@@ -410,7 +411,7 @@ func TestDirWindows(t *testing.T) {
cgifile, _ := filepath.Abs("testdata/test.cgi")
var perl string
- var err os.Error
+ var err error
perl, err = exec.LookPath("perl")
if err != nil {
return
@@ -447,3 +448,32 @@ func TestDirWindows(t *testing.T) {
}
runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
}
+
+func TestEnvOverride(t *testing.T) {
+ cgifile, _ := filepath.Abs("testdata/test.cgi")
+
+ var perl string
+ var err 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,
+ "REQUEST_URI=/foo/bar"},
+ }
+ expectedMap := map[string]string{
+ "cwd": cwd,
+ "env-SCRIPT_FILENAME": cgifile,
+ "env-REQUEST_URI": "/foo/bar",
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
diff --git a/src/pkg/http/cgi/matryoshka_test.go b/src/pkg/net/http/cgi/matryoshka_test.go
index 3e4a6addf..e1a78c8f6 100644
--- a/src/pkg/http/cgi/matryoshka_test.go
+++ b/src/pkg/net/http/cgi/matryoshka_test.go
@@ -10,7 +10,7 @@ package cgi
import (
"fmt"
- "http"
+ "net/http"
"os"
"testing"
)
@@ -51,6 +51,22 @@ func TestHostingOurselves(t *testing.T) {
}
}
+// Test that a child handler only writing headers works.
+func TestChildOnlyHeaders(t *testing.T) {
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ expectedMap := map[string]string{
+ "_body": "",
+ }
+ replay := runCgiTest(t, h, "GET /test.go?no-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap)
+ if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
+ t.Errorf("got a X-Test-Header of %q; expected %q", got, expected)
+ }
+}
+
// Note: not actually a test.
func TestBeChildCGIProcess(t *testing.T) {
if os.Getenv("REQUEST_METHOD") == "" {
@@ -59,8 +75,11 @@ func TestBeChildCGIProcess(t *testing.T) {
}
Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("X-Test-Header", "X-Test-Value")
- fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
req.ParseForm()
+ if req.FormValue("no-body") == "1" {
+ return
+ }
+ fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
for k, vv := range req.Form {
for _, v := range vv {
fmt.Fprintf(rw, "param-%s=%s\n", k, v)
diff --git a/src/pkg/http/cgi/testdata/test.cgi b/src/pkg/net/http/cgi/testdata/test.cgi
index b46b1330f..b46b1330f 100755
--- a/src/pkg/http/cgi/testdata/test.cgi
+++ b/src/pkg/net/http/cgi/testdata/test.cgi
diff --git a/src/pkg/net/http/chunked.go b/src/pkg/net/http/chunked.go
new file mode 100644
index 000000000..60a478fd8
--- /dev/null
+++ b/src/pkg/net/http/chunked.go
@@ -0,0 +1,170 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The wire protocol for HTTP's "chunked" Transfer-Encoding.
+
+// This code is duplicated in httputil/chunked.go.
+// Please make any changes in both files.
+
+package http
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "io"
+ "strconv"
+)
+
+const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+
+var ErrLineTooLong = errors.New("header line too long")
+
+// newChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.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 io.Reader) io.Reader {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ return &chunkedReader{r: br}
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.ParseUint(line, 16, 64)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ cr.err = io.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ p = bytes.TrimRight(p, " \r\t\n")
+
+ return p, nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// 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 {
+ return &chunkedWriter{w}
+}
+
+// Writing to chunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the underlying Wire chunkedWriter.
+type chunkedWriter struct {
+ Wire io.Writer
+}
+
+// Write the contents of data as one chunk to Wire.
+// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
+// a bug since it does not check for success of io.WriteString
+func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
+
+ // Don't send 0-length data. It looks like EOF for chunked encoding.
+ if len(data) == 0 {
+ return 0, nil
+ }
+
+ head := strconv.FormatInt(int64(len(data)), 16) + "\r\n"
+
+ if _, err = io.WriteString(cw.Wire, head); err != nil {
+ return 0, err
+ }
+ if n, err = cw.Wire.Write(data); err != nil {
+ return
+ }
+ if n != len(data) {
+ err = io.ErrShortWrite
+ return
+ }
+ _, err = io.WriteString(cw.Wire, "\r\n")
+
+ return
+}
+
+func (cw *chunkedWriter) Close() error {
+ _, err := io.WriteString(cw.Wire, "0\r\n")
+ return err
+}
diff --git a/src/pkg/net/http/chunked_test.go b/src/pkg/net/http/chunked_test.go
new file mode 100644
index 000000000..b77ee2ff2
--- /dev/null
+++ b/src/pkg/net/http/chunked_test.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code is duplicated in httputil/chunked_test.go.
+// Please make any changes in both files.
+
+package http
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+func TestChunk(t *testing.T) {
+ var b bytes.Buffer
+
+ w := newChunkedWriter(&b)
+ const chunk1 = "hello, "
+ const chunk2 = "world! 0123456789abcdef"
+ w.Write([]byte(chunk1))
+ w.Write([]byte(chunk2))
+ w.Close()
+
+ if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
+ t.Fatalf("chunk writer wrote %q; want %q", g, e)
+ }
+
+ r := newChunkedReader(&b)
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Logf(`data: "%s"`, data)
+ t.Fatalf("ReadAll from reader: %v", err)
+ }
+ if g, e := string(data), chunk1+chunk2; g != e {
+ t.Errorf("chunk reader read %q; want %q", g, e)
+ }
+}
diff --git a/src/pkg/http/client.go b/src/pkg/net/http/client.go
index 44b3443fc..5d450258b 100644
--- a/src/pkg/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -2,17 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Primitive HTTP client. See RFC 2616.
+// HTTP client. See RFC 2616.
+//
+// This is the high-level Client interface.
+// The low-level implementation is in transport.go.
package http
import (
"encoding/base64"
+ "errors"
"fmt"
"io"
- "os"
+ "net/url"
"strings"
- "url"
)
// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
@@ -21,11 +24,13 @@ import (
// 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
+ // Transport specifies the mechanism by which individual
+ // HTTP requests are made.
+ // If nil, DefaultTransport is used.
+ Transport RoundTripper
+ // CheckRedirect specifies the policy for handling redirects.
// If CheckRedirect is not nil, the client calls it before
// following an HTTP redirect. The arguments req and via
// are the upcoming request and the requests made already,
@@ -34,7 +39,12 @@ type Client struct {
//
// If CheckRedirect is nil, the Client uses its default policy,
// which is to stop after 10 consecutive requests.
- CheckRedirect func(req *Request, via []*Request) os.Error
+ CheckRedirect func(req *Request, via []*Request) error
+
+ // Jar specifies the cookie jar.
+ // If Jar is nil, cookies are not sent in requests and ignored
+ // in responses.
+ Jar CookieJar
}
// DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -56,9 +66,10 @@ type RoundTripper interface {
// higher-level protocol details such as redirects,
// authentication, or cookies.
//
- // RoundTrip may modify the request. The request Headers field is
- // guaranteed to be initialized.
- RoundTrip(req *Request) (resp *Response, err os.Error)
+ // RoundTrip should not modify the request, except for
+ // consuming the Body. The request's URL and Header fields
+ // are guaranteed to be initialized.
+ RoundTrip(*Request) (*Response, error)
}
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
@@ -76,10 +87,15 @@ type readClose struct {
// Do sends an HTTP request and returns an HTTP response, following
// policy (e.g. redirects, cookies, auth) as configured on the client.
//
-// Callers should close resp.Body when done reading from it.
+// A non-nil response always contains a non-nil resp.Body.
+//
+// Callers should close resp.Body when done reading from it. If
+// resp.Body is not closed, the Client's underlying RoundTripper
+// (typically Transport) may not be able to re-use a persistent TCP
+// connection to the server for a subsequent "keep-alive" request.
//
// Generally Get, Post, or PostForm will be used instead of Do.
-func (c *Client) Do(req *Request) (resp *Response, err os.Error) {
+func (c *Client) Do(req *Request) (resp *Response, err error) {
if req.Method == "GET" || req.Method == "HEAD" {
return c.doFollowingRedirects(req)
}
@@ -87,15 +103,23 @@ func (c *Client) Do(req *Request) (resp *Response, err os.Error) {
}
// 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) {
+func send(req *Request, t RoundTripper) (resp *Response, err error) {
if t == nil {
t = DefaultTransport
if t == nil {
- err = os.NewError("no http.Client.Transport or http.DefaultTransport")
+ err = errors.New("http: no Client.Transport or DefaultTransport")
return
}
}
+ if req.URL == nil {
+ return nil, errors.New("http: nil Request.URL")
+ }
+
+ if req.RequestURI != "" {
+ return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
+ }
+
// Most the callers of send (Get, Post, et al) don't need
// Headers, leaving it uninitialized. We guarantee to the
// Transport that this has been initialized, though.
@@ -103,12 +127,8 @@ func send(req *Request, t RoundTripper) (resp *Response, err os.Error) {
req.Header = make(Header)
}
- info := req.URL.RawUserinfo
- if len(info) > 0 {
- if req.Header == nil {
- req.Header = make(Header)
- }
- req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(info)))
+ if u := req.URL.User; u != nil {
+ req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String())))
}
return t.RoundTrip(req)
}
@@ -133,8 +153,8 @@ func shouldRedirect(statusCode int) bool {
//
// Caller should close r.Body when done reading from it.
//
-// Get is a convenience wrapper around DefaultClient.Get.
-func Get(url string) (r *Response, err os.Error) {
+// Get is a wrapper around DefaultClient.Get.
+func Get(url string) (r *Response, err error) {
return DefaultClient.Get(url)
}
@@ -148,7 +168,7 @@ func Get(url string) (r *Response, err os.Error) {
// 307 (Temporary Redirect)
//
// Caller should close r.Body when done reading from it.
-func (c *Client) Get(url string) (r *Response, err os.Error) {
+func (c *Client) Get(url string) (r *Response, err error) {
req, err := NewRequest("GET", url, nil)
if err != nil {
return nil, err
@@ -156,7 +176,7 @@ func (c *Client) Get(url string) (r *Response, err os.Error) {
return c.doFollowingRedirects(req)
}
-func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error) {
+func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
// TODO: if/when we add cookie support, the redirected request shouldn't
// necessarily supply the same cookies as the original.
var base *url.URL
@@ -166,6 +186,15 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
}
var via []*Request
+ if ireq.URL == nil {
+ return nil, errors.New("http: nil Request.URL")
+ }
+
+ jar := c.Jar
+ if jar == nil {
+ jar = blackHoleJar{}
+ }
+
req := ireq
urlStr := "" // next relative or absolute URL to fetch (after first request)
for redirect := 0; ; redirect++ {
@@ -191,14 +220,21 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
}
}
+ for _, cookie := range jar.Cookies(req.URL) {
+ req.AddCookie(cookie)
+ }
urlStr = req.URL.String()
if r, err = send(req, c.Transport); err != nil {
break
}
+ if c := r.Cookies(); len(c) > 0 {
+ jar.SetCookies(req.URL, c)
+ }
+
if shouldRedirect(r.StatusCode) {
r.Body.Close()
if urlStr = r.Header.Get("Location"); urlStr == "" {
- err = os.NewError(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+ err = errors.New(fmt.Sprintf("%d response missing Location header", r.StatusCode))
break
}
base = req.URL
@@ -209,13 +245,17 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
}
method := ireq.Method
- err = &url.Error{method[0:1] + strings.ToLower(method[1:]), urlStr, err}
+ err = &url.Error{
+ Op: method[0:1] + strings.ToLower(method[1:]),
+ URL: urlStr,
+ Err: err,
+ }
return
}
-func defaultCheckRedirect(req *Request, via []*Request) os.Error {
+func defaultCheckRedirect(req *Request, via []*Request) error {
if len(via) >= 10 {
- return os.NewError("stopped after 10 redirects")
+ return errors.New("stopped after 10 redirects")
}
return nil
}
@@ -225,20 +265,24 @@ func defaultCheckRedirect(req *Request, via []*Request) os.Error {
// Caller should close r.Body when done reading from it.
//
// Post is a wrapper around DefaultClient.Post
-func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Error) {
+func Post(url string, bodyType string, body io.Reader) (r *Response, err error) {
return DefaultClient.Post(url, bodyType, body)
}
// Post issues a POST to the specified URL.
//
// 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) {
+func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", bodyType)
- return send(req, c.Transport)
+ r, err = send(req, c.Transport)
+ if err == nil && c.Jar != nil {
+ c.Jar.SetCookies(req.URL, r.Cookies())
+ }
+ return r, err
}
// PostForm issues a POST to the specified URL,
@@ -247,7 +291,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 url.Values) (r *Response, err os.Error) {
+func PostForm(url string, data url.Values) (r *Response, err error) {
return DefaultClient.PostForm(url, data)
}
@@ -255,7 +299,7 @@ func PostForm(url string, data url.Values) (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 url.Values) (r *Response, err os.Error) {
+func (c *Client) PostForm(url string, data url.Values) (r *Response, err error) {
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
@@ -269,7 +313,7 @@ func (c *Client) PostForm(url string, data url.Values) (r *Response, err os.Erro
// 307 (Temporary Redirect)
//
// Head is a wrapper around DefaultClient.Head
-func Head(url string) (r *Response, err os.Error) {
+func Head(url string) (r *Response, err error) {
return DefaultClient.Head(url)
}
@@ -281,7 +325,7 @@ func Head(url string) (r *Response, err os.Error) {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
-func (c *Client) Head(url string) (r *Response, err os.Error) {
+func (c *Client) Head(url string) (r *Response, err error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
diff --git a/src/pkg/http/client_test.go b/src/pkg/net/http/client_test.go
index f22cce50b..e00b62e59 100644
--- a/src/pkg/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -7,17 +7,19 @@
package http_test
import (
+ "crypto/tls"
+ "errors"
"fmt"
- . "http"
- "http/httptest"
"io"
"io/ioutil"
"net"
- "os"
+ . "net/http"
+ "net/http/httptest"
+ "net/url"
"strconv"
"strings"
+ "sync"
"testing"
- "url"
)
var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -25,6 +27,31 @@ var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})
+// pedanticReadAll works like ioutil.ReadAll but additionally
+// verifies that r obeys the documented io.Reader contract.
+func pedanticReadAll(r io.Reader) (b []byte, err error) {
+ var bufa [64]byte
+ buf := bufa[:]
+ for {
+ n, err := r.Read(buf)
+ if n == 0 && err == nil {
+ return nil, fmt.Errorf("Read: n=0 with err=nil")
+ }
+ b = append(b, buf[:n]...)
+ if err == io.EOF {
+ n, err := r.Read(buf)
+ if n != 0 || err != io.EOF {
+ return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err)
+ }
+ return b, nil
+ }
+ if err != nil {
+ return b, err
+ }
+ }
+ panic("unreachable")
+}
+
func TestClient(t *testing.T) {
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
@@ -32,7 +59,7 @@ func TestClient(t *testing.T) {
r, err := Get(ts.URL)
var b []byte
if err == nil {
- b, err = ioutil.ReadAll(r.Body)
+ b, err = pedanticReadAll(r.Body)
r.Body.Close()
}
if err != nil {
@@ -59,9 +86,9 @@ type recordingTransport struct {
req *Request
}
-func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
+func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error) {
t.req = req
- return nil, os.NewError("dummy impl")
+ return nil, errors.New("dummy impl")
}
func TestGetRequestFormat(t *testing.T) {
@@ -132,7 +159,9 @@ func TestPostFormRequestFormat(t *testing.T) {
if tr.req.Close {
t.Error("got Close true, want false")
}
+ // Depending on map iteration, body can be either of these.
expectedBody := "foo=bar&foo=bar2&bar=baz"
+ expectedBody1 := "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)
}
@@ -140,8 +169,8 @@ func TestPostFormRequestFormat(t *testing.T) {
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)
+ if g := string(bodyb); g != expectedBody && g != expectedBody1 {
+ t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1)
}
}
@@ -182,9 +211,9 @@ func TestRedirects(t *testing.T) {
t.Errorf("with default client Do, expected error %q, got %q", e, g)
}
- var checkErr os.Error
+ var checkErr error
var lastVia []*Request
- c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
+ c = &Client{CheckRedirect: func(_ *Request, via []*Request) error {
lastVia = via
return checkErr
}}
@@ -200,7 +229,7 @@ func TestRedirects(t *testing.T) {
t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
}
- checkErr = os.NewError("no redirects allowed")
+ checkErr = errors.New("no redirects allowed")
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 {
@@ -208,6 +237,92 @@ func TestRedirects(t *testing.T) {
}
}
+var expectedCookies = []*Cookie{
+ {Name: "ChocolateChip", Value: "tasty"},
+ {Name: "First", Value: "Hit"},
+ {Name: "Second", Value: "Hit"},
+}
+
+var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
+ for _, cookie := range r.Cookies() {
+ SetCookie(w, cookie)
+ }
+ if r.URL.Path == "/" {
+ SetCookie(w, expectedCookies[1])
+ Redirect(w, r, "/second", StatusMovedPermanently)
+ } else {
+ SetCookie(w, expectedCookies[2])
+ w.Write([]byte("hello"))
+ }
+})
+
+// Just enough correctness for our redirect tests. Uses the URL.Host as the
+// scope of all cookies.
+type TestJar struct {
+ m sync.Mutex
+ perURL map[string][]*Cookie
+}
+
+func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) {
+ j.m.Lock()
+ defer j.m.Unlock()
+ j.perURL[u.Host] = cookies
+}
+
+func (j *TestJar) Cookies(u *url.URL) []*Cookie {
+ j.m.Lock()
+ defer j.m.Unlock()
+ return j.perURL[u.Host]
+}
+
+func TestRedirectCookiesOnRequest(t *testing.T) {
+ var ts *httptest.Server
+ ts = httptest.NewServer(echoCookiesRedirectHandler)
+ defer ts.Close()
+ c := &Client{}
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req.AddCookie(expectedCookies[0])
+ // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands.
+ _ = c
+ // resp, _ := c.Do(req)
+ // matchReturnedCookies(t, expectedCookies, resp.Cookies())
+
+ req, _ = NewRequest("GET", ts.URL, nil)
+ // resp, _ = c.Do(req)
+ // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies())
+}
+
+func TestRedirectCookiesJar(t *testing.T) {
+ var ts *httptest.Server
+ ts = httptest.NewServer(echoCookiesRedirectHandler)
+ defer ts.Close()
+ c := &Client{}
+ c.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
+ u, _ := url.Parse(ts.URL)
+ c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
+ resp, _ := c.Get(ts.URL)
+ matchReturnedCookies(t, expectedCookies, resp.Cookies())
+}
+
+func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
+ t.Logf("Received cookies: %v", given)
+ if len(given) != len(expected) {
+ t.Errorf("Expected %d cookies, got %d", len(expected), len(given))
+ }
+ for _, ec := range expected {
+ foundC := false
+ for _, c := range given {
+ if ec.Name == c.Name && ec.Value == c.Value {
+ foundC = true
+ break
+ }
+ }
+ if !foundC {
+ t.Errorf("Missing cookie %v", ec)
+ }
+ }
+}
+
func TestStreamingGet(t *testing.T) {
say := make(chan string)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -241,7 +356,7 @@ func TestStreamingGet(t *testing.T) {
}
close(say)
_, err = io.ReadFull(res.Body, buf[0:1])
- if err != os.EOF {
+ if err != io.EOF {
t.Fatalf("at end expected EOF, got %v", err)
}
}
@@ -251,7 +366,7 @@ type writeCountingConn struct {
count *int
}
-func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
+func (c *writeCountingConn) Write(p []byte) (int, error) {
*c.count++
return c.Conn.Write(p)
}
@@ -264,7 +379,7 @@ func TestClientWrites(t *testing.T) {
defer ts.Close()
writes := 0
- dialer := func(netz string, addr string) (net.Conn, os.Error) {
+ dialer := func(netz string, addr string) (net.Conn, error) {
c, err := net.Dial(netz, addr)
if err == nil {
c = &writeCountingConn{c, &writes}
@@ -290,3 +405,38 @@ func TestClientWrites(t *testing.T) {
t.Errorf("Post request did %d Write calls, want 1", writes)
}
}
+
+func TestClientInsecureTransport(t *testing.T) {
+ ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Write([]byte("Hello"))
+ }))
+ defer ts.Close()
+
+ // TODO(bradfitz): add tests for skipping hostname checks too?
+ // would require a new cert for testing, and probably
+ // redundant with these tests.
+ for _, insecure := range []bool{true, false} {
+ tr := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: insecure,
+ },
+ }
+ c := &Client{Transport: tr}
+ _, err := c.Get(ts.URL)
+ if (err == nil) != insecure {
+ t.Errorf("insecure=%v: got unexpected err=%v", insecure, err)
+ }
+ }
+}
+
+func TestClientErrorWithRequestURI(t *testing.T) {
+ req, _ := NewRequest("GET", "http://localhost:1234/", nil)
+ req.RequestURI = "/this/field/is/illegal/and/should/error/"
+ _, err := DefaultClient.Do(req)
+ if err == nil {
+ t.Fatalf("expected an error")
+ }
+ if !strings.Contains(err.Error(), "RequestURI") {
+ t.Errorf("wanted error mentioning RequestURI; got error: %v", err)
+ }
+}
diff --git a/src/pkg/http/cookie.go b/src/pkg/net/http/cookie.go
index fe70431bb..2e30bbff1 100644
--- a/src/pkg/http/cookie.go
+++ b/src/pkg/net/http/cookie.go
@@ -96,7 +96,7 @@ func readSetCookies(h Header) []*Cookie {
continue
case "max-age":
secs, err := strconv.Atoi(val)
- if err != nil || secs < 0 || secs != 0 && val[0] == '0' {
+ if err != nil || secs != 0 && val[0] == '0' {
break
}
if secs <= 0 {
@@ -115,7 +115,7 @@ func readSetCookies(h Header) []*Cookie {
break
}
}
- c.Expires = *exptime
+ c.Expires = exptime.UTC()
continue
case "path":
c.Path = val
@@ -146,8 +146,8 @@ func (c *Cookie) String() string {
if len(c.Domain) > 0 {
fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
}
- if len(c.Expires.Zone) > 0 {
- fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
+ if c.Expires.Unix() > 0 {
+ fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
}
if c.MaxAge > 0 {
fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
@@ -207,17 +207,16 @@ func readCookies(h Header, filter string) []*Cookie {
return cookies
}
+var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")
+
func sanitizeName(n string) string {
- n = strings.Replace(n, "\n", "-", -1)
- n = strings.Replace(n, "\r", "-", -1)
- return n
+ return cookieNameSanitizer.Replace(n)
}
+var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")
+
func sanitizeValue(v string) string {
- v = strings.Replace(v, "\n", " ", -1)
- v = strings.Replace(v, "\r", " ", -1)
- v = strings.Replace(v, ";", " ", -1)
- return v
+ return cookieValueSanitizer.Replace(v)
}
func unquoteCookieValue(v string) string {
diff --git a/src/pkg/http/cookie_test.go b/src/pkg/net/http/cookie_test.go
index d7aeda0be..1e9186a05 100644
--- a/src/pkg/http/cookie_test.go
+++ b/src/pkg/net/http/cookie_test.go
@@ -5,9 +5,8 @@
package http
import (
+ "encoding/json"
"fmt"
- "json"
- "os"
"reflect"
"testing"
"time"
@@ -50,7 +49,7 @@ func (ho headerOnlyResponseWriter) Header() Header {
return Header(ho)
}
-func (ho headerOnlyResponseWriter) Write([]byte) (int, os.Error) {
+func (ho headerOnlyResponseWriter) Write([]byte) (int, error) {
panic("NOIMPL")
}
@@ -82,14 +81,14 @@ var addCookieTests = []struct {
"",
},
{
- []*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}},
+ []*Cookie{{Name: "cookie-1", Value: "v$1"}},
"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"},
+ {Name: "cookie-1", Value: "v$1"},
+ {Name: "cookie-2", Value: "v$2"},
+ {Name: "cookie-3", Value: "v$3"},
},
"cookie-1=v$1; cookie-2=v$2; cookie-3=v$3",
},
@@ -114,21 +113,49 @@ var readSetCookiesTests = []struct {
}{
{
Header{"Set-Cookie": {"Cookie-1=v$1"}},
- []*Cookie{&Cookie{Name: "Cookie-1", Value: "v$1", Raw: "Cookie-1=v$1"}},
+ []*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{
+ []*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"},
+ Expires: time.Date(2011, 11, 23, 1, 5, 3, 0, time.UTC),
RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
}},
},
+ {
+ Header{"Set-Cookie": {".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly"}},
+ []*Cookie{{
+ Name: ".ASPXAUTH",
+ Value: "7E3AA",
+ Path: "/",
+ Expires: time.Date(2012, 3, 7, 14, 25, 6, 0, time.UTC),
+ RawExpires: "Wed, 07-Mar-2012 14:25:06 GMT",
+ HttpOnly: true,
+ Raw: ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ }},
+ },
+ {
+ Header{"Set-Cookie": {"ASP.NET_SessionId=foo; path=/; HttpOnly"}},
+ []*Cookie{{
+ Name: "ASP.NET_SessionId",
+ Value: "foo",
+ Path: "/",
+ HttpOnly: true,
+ Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly",
+ }},
+ },
+
+ // TODO(bradfitz): users have reported seeing this in the
+ // wild, but do browsers handle it? RFC 6265 just says "don't
+ // do that" (section 3) and then never mentions header folding
+ // again.
+ // Header{"Set-Cookie": {"ASP.NET_SessionId=foo; path=/; HttpOnly, .ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly"}},
}
func toJSON(v interface{}) string {
@@ -160,30 +187,30 @@ var readCookiesTests = []struct {
Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
"",
[]*Cookie{
- &Cookie{Name: "Cookie-1", Value: "v$1"},
- &Cookie{Name: "c2", Value: "v2"},
+ {Name: "Cookie-1", Value: "v$1"},
+ {Name: "c2", Value: "v2"},
},
},
{
Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
"c2",
[]*Cookie{
- &Cookie{Name: "c2", Value: "v2"},
+ {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"},
+ {Name: "Cookie-1", Value: "v$1"},
+ {Name: "c2", Value: "v2"},
},
},
{
Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
"c2",
[]*Cookie{
- &Cookie{Name: "c2", Value: "v2"},
+ {Name: "c2", Value: "v2"},
},
},
}
diff --git a/src/pkg/net/http/doc.go b/src/pkg/net/http/doc.go
new file mode 100644
index 000000000..b6ae8b87a
--- /dev/null
+++ b/src/pkg/net/http/doc.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 provides HTTP client and server implementations.
+
+Get, Head, Post, and PostForm make HTTP requests:
+
+ resp, err := http.Get("http://example.com/")
+ ...
+ resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
+ ...
+ resp, err := http.PostForm("http://example.com/form",
+ url.Values{"key": {"Value"}, "id": {"123"}})
+
+The client must close the response body when finished with it:
+
+ resp, err := http.Get("http://example.com/")
+ if err != nil {
+ // handle error
+ }
+ defer resp.Body.Close()
+ body, err := ioutil.ReadAll(resp.Body)
+ // ...
+
+For control over HTTP client headers, redirect policy, and other
+settings, create a Client:
+
+ client := &http.Client{
+ CheckRedirect: redirectPolicyFunc,
+ }
+
+ resp, err := client.Get("http://example.com")
+ // ...
+
+ req, err := http.NewRequest("GET", "http://example.com", nil)
+ // ...
+ req.Header.Add("If-None-Match", `W/"wyzzy"`)
+ resp, err := client.Do(req)
+ // ...
+
+For control over proxies, TLS configuration, keep-alives,
+compression, and other settings, create a Transport:
+
+ tr := &http.Transport{
+ TLSClientConfig: &tls.Config{RootCAs: pool},
+ DisableCompression: true,
+ }
+ client := &http.Client{Transport: tr}
+ resp, err := client.Get("https://example.com")
+
+Clients and Transports are safe for concurrent use by multiple
+goroutines and for efficiency should only be created once and re-used.
+
+ListenAndServe starts an HTTP server with a given address and handler.
+The handler is usually nil, which means to use DefaultServeMux.
+Handle and HandleFunc add handlers to DefaultServeMux:
+
+ http.Handle("/foo", fooHandler)
+
+ http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
+ })
+
+ log.Fatal(http.ListenAndServe(":8080", nil))
+
+More control over the server's behavior is available by creating a
+custom Server:
+
+ s := &http.Server{
+ Addr: ":8080",
+ Handler: myHandler,
+ ReadTimeout: 10 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ MaxHeaderBytes: 1 << 20,
+ }
+ log.Fatal(s.ListenAndServe())
+*/
+package http
diff --git a/src/pkg/net/http/example_test.go b/src/pkg/net/http/example_test.go
new file mode 100644
index 000000000..2584afc43
--- /dev/null
+++ b/src/pkg/net/http/example_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+)
+
+func ExampleHijacker() {
+ http.HandleFunc("/hijack", func(w http.ResponseWriter, r *http.Request) {
+ hj, ok := w.(http.Hijacker)
+ if !ok {
+ http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
+ return
+ }
+ conn, bufrw, err := hj.Hijack()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ // Don't forget to close the connection:
+ defer conn.Close()
+ bufrw.WriteString("Now we're speaking raw TCP. Say hi: ")
+ bufrw.Flush()
+ s, err := bufrw.ReadString('\n')
+ if err != nil {
+ log.Printf("error reading string: %v", err)
+ return
+ }
+ fmt.Fprintf(bufrw, "You said: %q\nBye.\n", s)
+ bufrw.Flush()
+ })
+}
+
+func ExampleGet() {
+ res, err := http.Get("http://www.google.com/robots.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ robots, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+ res.Body.Close()
+ fmt.Printf("%s", robots)
+}
diff --git a/src/pkg/http/export_test.go b/src/pkg/net/http/export_test.go
index 3fe658641..13640ca85 100644
--- a/src/pkg/http/export_test.go
+++ b/src/pkg/net/http/export_test.go
@@ -7,6 +7,8 @@
package http
+import "time"
+
func (t *Transport) IdleConnKeysForTesting() (keys []string) {
keys = make([]string, 0)
t.lk.Lock()
@@ -33,8 +35,8 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
return len(conns)
}
-func NewTestTimeoutHandler(handler Handler, ch <-chan int64) Handler {
- f := func() <-chan int64 {
+func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
+ f := func() <-chan time.Time {
return ch
}
return &timeoutHandler{handler, f, ""}
diff --git a/src/pkg/http/fcgi/child.go b/src/pkg/net/http/fcgi/child.go
index 19718824c..c8b9a33c8 100644
--- a/src/pkg/http/fcgi/child.go
+++ b/src/pkg/net/http/fcgi/child.go
@@ -7,11 +7,12 @@ package fcgi
// This file implements FastCGI from the perspective of a child process.
import (
+ "errors"
"fmt"
- "http"
- "http/cgi"
"io"
"net"
+ "net/http"
+ "net/http/cgi"
"os"
"time"
)
@@ -80,7 +81,7 @@ func (r *response) Header() http.Header {
return r.header
}
-func (r *response) Write(data []byte) (int, os.Error) {
+func (r *response) Write(data []byte) (int, error) {
if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
@@ -102,7 +103,7 @@ func (r *response) WriteHeader(code int) {
}
if r.header.Get("Date") == "" {
- r.header.Set("Date", time.UTC().Format(http.TimeFormat))
+ r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
}
fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
@@ -117,95 +118,107 @@ func (r *response) Flush() {
r.w.Flush()
}
-func (r *response) Close() os.Error {
+func (r *response) Close() error {
r.Flush()
return r.w.Close()
}
type child struct {
- conn *conn
- handler http.Handler
+ conn *conn
+ handler http.Handler
+ requests map[uint16]*request // keyed by request ID
}
-func newChild(rwc net.Conn, handler http.Handler) *child {
- return &child{newConn(rwc), handler}
+func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
+ return &child{
+ conn: newConn(rwc),
+ handler: handler,
+ requests: make(map[uint16]*request),
+ }
}
func (c *child) serve() {
- requests := map[uint16]*request{}
defer c.conn.Close()
var rec record
- var br beginRequest
for {
if err := rec.read(c.conn.rwc); err != nil {
return
}
-
- req, ok := requests[rec.h.Id]
- if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
- // The spec says to ignore unknown request IDs.
- continue
- }
- if ok && rec.h.Type == typeBeginRequest {
- // The server is trying to begin a request with the same ID
- // as an in-progress request. This is an error.
+ if err := c.handleRecord(&rec); err != nil {
return
}
+ }
+}
- switch rec.h.Type {
- case typeBeginRequest:
- if err := br.read(rec.content()); err != nil {
- return
- }
- if br.role != roleResponder {
- c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
- break
- }
- requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
- case typeParams:
- // NOTE(eds): Technically a key-value pair can straddle the boundary
- // between two packets. We buffer until we've received all parameters.
- if len(rec.content()) > 0 {
- req.rawParams = append(req.rawParams, rec.content()...)
- break
- }
- req.parseParams()
- case typeStdin:
- content := rec.content()
- if req.pw == nil {
- var body io.ReadCloser
- if len(content) > 0 {
- // body could be an io.LimitReader, but it shouldn't matter
- // as long as both sides are behaving.
- body, req.pw = io.Pipe()
- }
- go c.serveRequest(req, body)
- }
+var errCloseConn = errors.New("fcgi: connection should be closed")
+
+func (c *child) handleRecord(rec *record) error {
+ req, ok := c.requests[rec.h.Id]
+ if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
+ // The spec says to ignore unknown request IDs.
+ return nil
+ }
+ if ok && rec.h.Type == typeBeginRequest {
+ // The server is trying to begin a request with the same ID
+ // as an in-progress request. This is an error.
+ return errors.New("fcgi: received ID that is already in-flight")
+ }
+
+ switch rec.h.Type {
+ case typeBeginRequest:
+ var br beginRequest
+ if err := br.read(rec.content()); err != nil {
+ return err
+ }
+ if br.role != roleResponder {
+ c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
+ return nil
+ }
+ c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ case typeParams:
+ // NOTE(eds): Technically a key-value pair can straddle the boundary
+ // between two packets. We buffer until we've received all parameters.
+ if len(rec.content()) > 0 {
+ req.rawParams = append(req.rawParams, rec.content()...)
+ return nil
+ }
+ req.parseParams()
+ case typeStdin:
+ content := rec.content()
+ if req.pw == nil {
+ var body io.ReadCloser
if len(content) > 0 {
- // TODO(eds): This blocks until the handler reads from the pipe.
- // If the handler takes a long time, it might be a problem.
- req.pw.Write(content)
- } else if req.pw != nil {
- req.pw.Close()
- }
- case typeGetValues:
- values := map[string]string{"FCGI_MPXS_CONNS": "1"}
- c.conn.writePairs(0, typeGetValuesResult, values)
- case typeData:
- // If the filter role is implemented, read the data stream here.
- case typeAbortRequest:
- requests[rec.h.Id] = nil, false
- c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
- if !req.keepConn {
- // connection will close upon return
- return
+ // body could be an io.LimitReader, but it shouldn't matter
+ // as long as both sides are behaving.
+ body, req.pw = io.Pipe()
}
- default:
- b := make([]byte, 8)
- b[0] = rec.h.Type
- c.conn.writeRecord(typeUnknownType, 0, b)
+ go c.serveRequest(req, body)
+ }
+ if len(content) > 0 {
+ // TODO(eds): This blocks until the handler reads from the pipe.
+ // If the handler takes a long time, it might be a problem.
+ req.pw.Write(content)
+ } else if req.pw != nil {
+ req.pw.Close()
+ }
+ case typeGetValues:
+ values := map[string]string{"FCGI_MPXS_CONNS": "1"}
+ c.conn.writePairs(typeGetValuesResult, 0, values)
+ case typeData:
+ // If the filter role is implemented, read the data stream here.
+ case typeAbortRequest:
+ delete(c.requests, rec.h.Id)
+ c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
+ if !req.keepConn {
+ // connection will close upon return
+ return errCloseConn
}
+ default:
+ b := make([]byte, 8)
+ b[0] = byte(rec.h.Type)
+ c.conn.writeRecord(typeUnknownType, 0, b)
}
+ return nil
}
func (c *child) serveRequest(req *request, body io.ReadCloser) {
@@ -214,7 +227,7 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
if err != nil {
// there was an error reading the request
r.WriteHeader(http.StatusInternalServerError)
- c.conn.writeRecord(typeStderr, req.reqId, []byte(err.String()))
+ c.conn.writeRecord(typeStderr, req.reqId, []byte(err.Error()))
} else {
httpReq.Body = body
c.handler.ServeHTTP(r, httpReq)
@@ -230,13 +243,13 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
}
// Serve accepts incoming FastCGI connections on the listener l, creating a new
-// service thread for each. The service threads read requests and then call handler
+// goroutine for each. The goroutine reads requests and then calls handler
// to reply to them.
-// If l is nil, Serve accepts connections on stdin.
+// If l is nil, Serve accepts connections from os.Stdin.
// If handler is nil, http.DefaultServeMux is used.
-func Serve(l net.Listener, handler http.Handler) os.Error {
+func Serve(l net.Listener, handler http.Handler) error {
if l == nil {
- var err os.Error
+ var err error
l, err = net.FileListener(os.Stdin)
if err != nil {
return err
diff --git a/src/pkg/http/fcgi/fcgi.go b/src/pkg/net/http/fcgi/fcgi.go
index 8e2e1cd3c..06bba0488 100644
--- a/src/pkg/http/fcgi/fcgi.go
+++ b/src/pkg/net/http/fcgi/fcgi.go
@@ -14,24 +14,27 @@ import (
"bufio"
"bytes"
"encoding/binary"
+ "errors"
"io"
- "os"
"sync"
)
+// recType is a record type, as defined by
+// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8
+type recType uint8
+
const (
- // Packet Types
- typeBeginRequest = iota + 1
- typeAbortRequest
- typeEndRequest
- typeParams
- typeStdin
- typeStdout
- typeStderr
- typeData
- typeGetValues
- typeGetValuesResult
- typeUnknownType
+ typeBeginRequest recType = 1
+ typeAbortRequest recType = 2
+ typeEndRequest recType = 3
+ typeParams recType = 4
+ typeStdin recType = 5
+ typeStdout recType = 6
+ typeStderr recType = 7
+ typeData recType = 8
+ typeGetValues recType = 9
+ typeGetValuesResult recType = 10
+ typeUnknownType recType = 11
)
// keep the connection between web-server and responder open after request
@@ -59,7 +62,7 @@ const headerLen = 8
type header struct {
Version uint8
- Type uint8
+ Type recType
Id uint16
ContentLength uint16
PaddingLength uint8
@@ -72,9 +75,9 @@ type beginRequest struct {
reserved [5]uint8
}
-func (br *beginRequest) read(content []byte) os.Error {
+func (br *beginRequest) read(content []byte) error {
if len(content) != 8 {
- return os.NewError("fcgi: invalid begin request record")
+ return errors.New("fcgi: invalid begin request record")
}
br.role = binary.BigEndian.Uint16(content)
br.flags = content[2]
@@ -85,7 +88,7 @@ func (br *beginRequest) read(content []byte) os.Error {
// not synchronized because we don't care what the contents are
var pad [maxPad]byte
-func (h *header) init(recType uint8, reqId uint16, contentLength int) {
+func (h *header) init(recType recType, reqId uint16, contentLength int) {
h.Version = 1
h.Type = recType
h.Id = reqId
@@ -107,7 +110,7 @@ func newConn(rwc io.ReadWriteCloser) *conn {
return &conn{rwc: rwc}
}
-func (c *conn) Close() os.Error {
+func (c *conn) Close() error {
c.mutex.Lock()
defer c.mutex.Unlock()
return c.rwc.Close()
@@ -118,12 +121,12 @@ type record struct {
buf [maxWrite + maxPad]byte
}
-func (rec *record) read(r io.Reader) (err os.Error) {
+func (rec *record) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
return err
}
if rec.h.Version != 1 {
- return os.NewError("fcgi: invalid header version")
+ return errors.New("fcgi: invalid header version")
}
n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
if _, err = io.ReadFull(r, rec.buf[:n]); err != nil {
@@ -137,7 +140,7 @@ func (r *record) content() []byte {
}
// writeRecord writes and sends a single record.
-func (c *conn) writeRecord(recType uint8, reqId uint16, b []byte) os.Error {
+func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
c.mutex.Lock()
defer c.mutex.Unlock()
c.buf.Reset()
@@ -155,24 +158,24 @@ func (c *conn) writeRecord(recType uint8, reqId uint16, b []byte) os.Error {
return err
}
-func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) os.Error {
+func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
b := [8]byte{byte(role >> 8), byte(role), flags}
return c.writeRecord(typeBeginRequest, reqId, b[:])
}
-func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) os.Error {
+func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
b := make([]byte, 8)
binary.BigEndian.PutUint32(b, uint32(appStatus))
b[4] = protocolStatus
return c.writeRecord(typeEndRequest, reqId, b)
}
-func (c *conn) writePairs(recType uint8, reqId uint16, pairs map[string]string) os.Error {
+func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error {
w := newWriter(c, recType, reqId)
b := make([]byte, 8)
for k, v := range pairs {
n := encodeSize(b, uint32(len(k)))
- n += encodeSize(b[n:], uint32(len(k)))
+ n += encodeSize(b[n:], uint32(len(v)))
if _, err := w.Write(b[:n]); err != nil {
return err
}
@@ -227,7 +230,7 @@ type bufWriter struct {
*bufio.Writer
}
-func (w *bufWriter) Close() os.Error {
+func (w *bufWriter) Close() error {
if err := w.Writer.Flush(); err != nil {
w.closer.Close()
return err
@@ -235,9 +238,9 @@ func (w *bufWriter) Close() os.Error {
return w.closer.Close()
}
-func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter {
+func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {
s := &streamWriter{c: c, recType: recType, reqId: reqId}
- w, _ := bufio.NewWriterSize(s, maxWrite)
+ w := bufio.NewWriterSize(s, maxWrite)
return &bufWriter{s, w}
}
@@ -245,11 +248,11 @@ func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter {
// It only writes maxWrite bytes at a time.
type streamWriter struct {
c *conn
- recType uint8
+ recType recType
reqId uint16
}
-func (w *streamWriter) Write(p []byte) (int, os.Error) {
+func (w *streamWriter) Write(p []byte) (int, error) {
nn := 0
for len(p) > 0 {
n := len(p)
@@ -265,7 +268,7 @@ func (w *streamWriter) Write(p []byte) (int, os.Error) {
return nn, nil
}
-func (w *streamWriter) Close() os.Error {
+func (w *streamWriter) Close() error {
// send empty record to close the stream
return w.c.writeRecord(w.recType, w.reqId, nil)
}
diff --git a/src/pkg/http/fcgi/fcgi_test.go b/src/pkg/net/http/fcgi/fcgi_test.go
index 16a624329..6c7e1a9ce 100644
--- a/src/pkg/http/fcgi/fcgi_test.go
+++ b/src/pkg/net/http/fcgi/fcgi_test.go
@@ -6,8 +6,8 @@ package fcgi
import (
"bytes"
+ "errors"
"io"
- "os"
"testing"
)
@@ -41,25 +41,25 @@ func TestSize(t *testing.T) {
var streamTests = []struct {
desc string
- recType uint8
+ recType recType
reqId uint16
content []byte
raw []byte
}{
{"single record", typeStdout, 1, nil,
- []byte{1, typeStdout, 0, 1, 0, 0, 0, 0},
+ []byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0},
},
// this data will have to be split into two records
{"two records", typeStdin, 300, make([]byte, 66000),
bytes.Join([][]byte{
// header for the first record
- []byte{1, typeStdin, 0x01, 0x2C, 0xFF, 0xFF, 1, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0},
make([]byte, 65536),
// header for the second
- []byte{1, typeStdin, 0x01, 0x2C, 0x01, 0xD1, 7, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0},
make([]byte, 472),
// header for the empty record
- []byte{1, typeStdin, 0x01, 0x2C, 0, 0, 0, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0},
},
nil),
},
@@ -69,7 +69,7 @@ type nilCloser struct {
io.ReadWriter
}
-func (c *nilCloser) Close() os.Error { return nil }
+func (c *nilCloser) Close() error { return nil }
func TestStreams(t *testing.T) {
var rec record
@@ -112,3 +112,39 @@ outer:
}
}
}
+
+type writeOnlyConn struct {
+ buf []byte
+}
+
+func (c *writeOnlyConn) Write(p []byte) (int, error) {
+ c.buf = append(c.buf, p...)
+ return len(p), nil
+}
+
+func (c *writeOnlyConn) Read(p []byte) (int, error) {
+ return 0, errors.New("conn is write-only")
+}
+
+func (c *writeOnlyConn) Close() error {
+ return nil
+}
+
+func TestGetValues(t *testing.T) {
+ var rec record
+ rec.h.Type = typeGetValues
+
+ wc := new(writeOnlyConn)
+ c := newChild(wc, nil)
+ err := c.handleRecord(&rec)
+ if err != nil {
+ t.Fatalf("handleRecord: %v", err)
+ }
+
+ const want = "\x01\n\x00\x00\x00\x12\x06\x00" +
+ "\x0f\x01FCGI_MPXS_CONNS1" +
+ "\x00\x00\x00\x00\x00\x00\x01\n\x00\x00\x00\x00\x00\x00"
+ if got := string(wc.buf); got != want {
+ t.Errorf(" got: %q\nwant: %q\n", got, want)
+ }
+}
diff --git a/src/pkg/net/http/filetransport.go b/src/pkg/net/http/filetransport.go
new file mode 100644
index 000000000..821787e0c
--- /dev/null
+++ b/src/pkg/net/http/filetransport.go
@@ -0,0 +1,123 @@
+// 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 (
+ "fmt"
+ "io"
+)
+
+// fileTransport implements RoundTripper for the 'file' protocol.
+type fileTransport struct {
+ fh fileHandler
+}
+
+// NewFileTransport returns a new RoundTripper, serving the provided
+// FileSystem. The returned RoundTripper ignores the URL host in its
+// incoming requests, as well as most other properties of the
+// request.
+//
+// The typical use case for NewFileTransport is to register the "file"
+// protocol with a Transport, as in:
+//
+// t := &http.Transport{}
+// t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
+// c := &http.Client{Transport: t}
+// res, err := c.Get("file:///etc/passwd")
+// ...
+func NewFileTransport(fs FileSystem) RoundTripper {
+ return fileTransport{fileHandler{fs}}
+}
+
+func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
+ // We start ServeHTTP in a goroutine, which may take a long
+ // time if the file is large. The newPopulateResponseWriter
+ // call returns a channel which either ServeHTTP or finish()
+ // sends our *Response on, once the *Response itself has been
+ // populated (even if the body itself is still being
+ // written to the res.Body, a pipe)
+ rw, resc := newPopulateResponseWriter()
+ go func() {
+ t.fh.ServeHTTP(rw, req)
+ rw.finish()
+ }()
+ return <-resc, nil
+}
+
+func newPopulateResponseWriter() (*populateResponse, <-chan *Response) {
+ pr, pw := io.Pipe()
+ rw := &populateResponse{
+ ch: make(chan *Response),
+ pw: pw,
+ res: &Response{
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ Header: make(Header),
+ Close: true,
+ Body: pr,
+ },
+ }
+ return rw, rw.ch
+}
+
+// populateResponse is a ResponseWriter that populates the *Response
+// in res, and writes its body to a pipe connected to the response
+// body. Once writes begin or finish() is called, the response is sent
+// on ch.
+type populateResponse struct {
+ res *Response
+ ch chan *Response
+ wroteHeader bool
+ hasContent bool
+ sentResponse bool
+ pw *io.PipeWriter
+}
+
+func (pr *populateResponse) finish() {
+ if !pr.wroteHeader {
+ pr.WriteHeader(500)
+ }
+ if !pr.sentResponse {
+ pr.sendResponse()
+ }
+ pr.pw.Close()
+}
+
+func (pr *populateResponse) sendResponse() {
+ if pr.sentResponse {
+ return
+ }
+ pr.sentResponse = true
+
+ if pr.hasContent {
+ pr.res.ContentLength = -1
+ }
+ pr.ch <- pr.res
+}
+
+func (pr *populateResponse) Header() Header {
+ return pr.res.Header
+}
+
+func (pr *populateResponse) WriteHeader(code int) {
+ if pr.wroteHeader {
+ return
+ }
+ pr.wroteHeader = true
+
+ pr.res.StatusCode = code
+ pr.res.Status = fmt.Sprintf("%d %s", code, StatusText(code))
+}
+
+func (pr *populateResponse) Write(p []byte) (n int, err error) {
+ if !pr.wroteHeader {
+ pr.WriteHeader(StatusOK)
+ }
+ pr.hasContent = true
+ if !pr.sentResponse {
+ pr.sendResponse()
+ }
+ return pr.pw.Write(p)
+}
diff --git a/src/pkg/net/http/filetransport_test.go b/src/pkg/net/http/filetransport_test.go
new file mode 100644
index 000000000..039926b53
--- /dev/null
+++ b/src/pkg/net/http/filetransport_test.go
@@ -0,0 +1,65 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http_test
+
+import (
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func checker(t *testing.T) func(string, error) {
+ return func(call string, err error) {
+ if err == nil {
+ return
+ }
+ t.Fatalf("%s: %v", call, err)
+ }
+}
+
+func TestFileTransport(t *testing.T) {
+ check := checker(t)
+
+ dname, err := ioutil.TempDir("", "")
+ check("TempDir", err)
+ fname := filepath.Join(dname, "foo.txt")
+ err = ioutil.WriteFile(fname, []byte("Bar"), 0644)
+ check("WriteFile", err)
+ defer os.Remove(dname)
+ defer os.Remove(fname)
+
+ tr := &http.Transport{}
+ tr.RegisterProtocol("file", http.NewFileTransport(http.Dir(dname)))
+ c := &http.Client{Transport: tr}
+
+ fooURLs := []string{"file:///foo.txt", "file://../foo.txt"}
+ for _, urlstr := range fooURLs {
+ res, err := c.Get(urlstr)
+ check("Get "+urlstr, err)
+ if res.StatusCode != 200 {
+ t.Errorf("for %s, StatusCode = %d, want 200", urlstr, res.StatusCode)
+ }
+ if res.ContentLength != -1 {
+ t.Errorf("for %s, ContentLength = %d, want -1", urlstr, res.ContentLength)
+ }
+ if res.Body == nil {
+ t.Fatalf("for %s, nil Body", urlstr)
+ }
+ slurp, err := ioutil.ReadAll(res.Body)
+ check("ReadAll "+urlstr, err)
+ if string(slurp) != "Bar" {
+ t.Errorf("for %s, got content %q, want %q", urlstr, string(slurp), "Bar")
+ }
+ }
+
+ const badURL = "file://../no-exist.txt"
+ res, err := c.Get(badURL)
+ check("Get "+badURL, err)
+ if res.StatusCode != 404 {
+ t.Errorf("for %s, StatusCode = %d, want 404", badURL, res.StatusCode)
+ }
+}
diff --git a/src/pkg/http/fs.go b/src/pkg/net/http/fs.go
index 2c7c636fd..f35dd32c3 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/net/http/fs.go
@@ -7,6 +7,7 @@
package http
import (
+ "errors"
"fmt"
"io"
"mime"
@@ -16,18 +17,23 @@ import (
"strconv"
"strings"
"time"
- "utf8"
)
// A Dir implements http.FileSystem using the native file
// system restricted to a specific directory tree.
+//
+// An empty Dir is treated as ".".
type Dir string
-func (d Dir) Open(name string) (File, os.Error) {
+func (d Dir) Open(name string) (File, error) {
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
- return nil, os.NewError("http: invalid character in file path")
+ return nil, errors.New("http: invalid character in file path")
+ }
+ dir := string(d)
+ if dir == "" {
+ dir = "."
}
- f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
+ f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))
if err != nil {
return nil, err
}
@@ -38,43 +44,17 @@ func (d Dir) Open(name string) (File, os.Error) {
// 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)
+ Open(name string) (File, 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 {
- for len(b) > 0 && utf8.FullRune(b) {
- rune, size := utf8.DecodeRune(b)
- if size == 1 && rune == utf8.RuneError {
- // decoding error
- return false
- }
- if 0x7F <= rune && rune <= 0x9F {
- return false
- }
- if rune < ' ' {
- switch rune {
- case '\n', '\r', '\t':
- // okay
- default:
- // binary garbage
- return false
- }
- }
- b = b[size:]
- }
- return true
+ Close() error
+ Stat() (os.FileInfo, error)
+ Readdir(count int) ([]os.FileInfo, error)
+ Read([]byte) (int, error)
+ Seek(offset int64, whence int) (int64, error)
}
func dirList(w ResponseWriter, f File) {
@@ -86,8 +66,8 @@ func dirList(w ResponseWriter, f File) {
break
}
for _, d := range dirs {
- name := d.Name
- if d.IsDirectory() {
+ name := d.Name()
+ if d.IsDir() {
name += "/"
}
// TODO htmlescape
@@ -97,6 +77,126 @@ func dirList(w ResponseWriter, f File) {
fmt.Fprintf(w, "</pre>\n")
}
+// ServeContent replies to the request using the content in the
+// provided ReadSeeker. The main benefit of ServeContent over io.Copy
+// is that it handles Range requests properly, sets the MIME type, and
+// handles If-Modified-Since requests.
+//
+// If the response's Content-Type header is not set, ServeContent
+// first tries to deduce the type from name's file extension and,
+// if that fails, falls back to reading the first block of the content
+// and passing it to DetectContentType.
+// The name is otherwise unused; in particular it can be empty and is
+// never sent in the response.
+//
+// If modtime is not the zero time, ServeContent includes it in a
+// Last-Modified header in the response. If the request includes an
+// If-Modified-Since header, ServeContent uses modtime to decide
+// whether the content needs to be sent at all.
+//
+// The content's Seek method must work: ServeContent uses
+// a seek to the end of the content to determine its size.
+//
+// Note that *os.File implements the io.ReadSeeker interface.
+func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) {
+ size, err := content.Seek(0, os.SEEK_END)
+ if err != nil {
+ Error(w, "seeker can't seek", StatusInternalServerError)
+ return
+ }
+ _, err = content.Seek(0, os.SEEK_SET)
+ if err != nil {
+ Error(w, "seeker can't seek", StatusInternalServerError)
+ return
+ }
+ serveContent(w, req, name, modtime, size, content)
+}
+
+// if name is empty, filename is unknown. (used for mime type, before sniffing)
+// if modtime.IsZero(), modtime is unknown.
+// content must be seeked to the beginning of the file.
+func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, size int64, content io.ReadSeeker) {
+ if checkLastModified(w, r, modtime) {
+ return
+ }
+
+ code := StatusOK
+
+ // If Content-Type isn't set, use the file's extension to find it.
+ if w.Header().Get("Content-Type") == "" {
+ ctype := mime.TypeByExtension(filepath.Ext(name))
+ if ctype == "" {
+ // read a chunk to decide between utf-8 text and binary
+ var buf [1024]byte
+ n, _ := io.ReadFull(content, buf[:])
+ b := buf[:n]
+ ctype = DetectContentType(b)
+ _, err := content.Seek(0, os.SEEK_SET) // rewind to output whole file
+ if err != nil {
+ Error(w, "seeker can't seek", StatusInternalServerError)
+ return
+ }
+ }
+ w.Header().Set("Content-Type", ctype)
+ }
+
+ // handle Content-Range header.
+ // TODO(adg): handle multiple ranges
+ sendSize := size
+ if size >= 0 {
+ ranges, err := parseRange(r.Header.Get("Range"), size)
+ if err == nil && len(ranges) > 1 {
+ err = errors.New("multiple ranges not supported")
+ }
+ if err != nil {
+ Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ if len(ranges) == 1 {
+ ra := ranges[0]
+ if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil {
+ Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ sendSize = ra.length
+ code = StatusPartialContent
+ w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, size))
+ }
+
+ w.Header().Set("Accept-Ranges", "bytes")
+ if w.Header().Get("Content-Encoding") == "" {
+ w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10))
+ }
+ }
+
+ w.WriteHeader(code)
+
+ if r.Method != "HEAD" {
+ if sendSize == -1 {
+ io.Copy(w, content)
+ } else {
+ io.CopyN(w, content, sendSize)
+ }
+ }
+}
+
+// modtime is the modification time of the resource to be served, or IsZero().
+// return value is whether this request is now complete.
+func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
+ if modtime.IsZero() {
+ return false
+ }
+
+ // The Date-Modified header truncates sub-second precision, so
+ // use mtime < t+1s instead of mtime <= t to check for unmodified.
+ if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) {
+ w.WriteHeader(StatusNotModified)
+ return true
+ }
+ w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
+ return false
+}
+
// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
const indexPage = "/index.html"
@@ -128,7 +228,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
// redirect to canonical path: / at end of directory url
// r.URL.Path always begins with /
url := r.URL.Path
- if d.IsDirectory() {
+ if d.IsDir() {
if url[len(url)-1] != '/' {
localRedirect(w, r, path.Base(url)+"/")
return
@@ -141,14 +241,11 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
}
}
- if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
- w.WriteHeader(StatusNotModified)
- return
- }
- w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
-
// use contents of index.html for directory, if present
- if d.IsDirectory() {
+ if d.IsDir() {
+ if checkLastModified(w, r, d.ModTime()) {
+ return
+ }
index := name + indexPage
ff, err := fs.Open(index)
if err == nil {
@@ -162,65 +259,12 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
}
}
- if d.IsDirectory() {
+ if d.IsDir() {
dirList(w, f)
return
}
- // serve file
- size := d.Size
- code := StatusOK
-
- // If Content-Type isn't set, use the file's extension to find it.
- if w.Header().Get("Content-Type") == "" {
- ctype := mime.TypeByExtension(filepath.Ext(name))
- if ctype == "" {
- // read a chunk to decide between utf-8 text and binary
- var buf [1024]byte
- n, _ := io.ReadFull(f, buf[:])
- b := buf[:n]
- if isText(b) {
- ctype = "text/plain; charset=utf-8"
- } else {
- // generic binary
- ctype = "application/octet-stream"
- }
- f.Seek(0, os.SEEK_SET) // rewind to output whole file
- }
- w.Header().Set("Content-Type", ctype)
- }
-
- // handle Content-Range header.
- // TODO(adg): handle multiple ranges
- ranges, err := parseRange(r.Header.Get("Range"), size)
- if err == nil && len(ranges) > 1 {
- err = os.NewError("multiple ranges not supported")
- }
- if err != nil {
- Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
- return
- }
- if len(ranges) == 1 {
- ra := ranges[0]
- if _, err := f.Seek(ra.start, os.SEEK_SET); err != nil {
- Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
- return
- }
- size = ra.length
- code = StatusPartialContent
- w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
- }
-
- w.Header().Set("Accept-Ranges", "bytes")
- if w.Header().Get("Content-Encoding") == "" {
- w.Header().Set("Content-Length", strconv.Itoa64(size))
- }
-
- w.WriteHeader(code)
-
- if r.Method != "HEAD" {
- io.Copyn(w, f, size)
- }
+ serveContent(w, r, d.Name(), d.ModTime(), d.Size(), f)
}
// localRedirect gives a Moved Permanently response.
@@ -269,28 +313,28 @@ type httpRange struct {
}
// parseRange parses a Range header string as per RFC 2616.
-func parseRange(s string, size int64) ([]httpRange, os.Error) {
+func parseRange(s string, size int64) ([]httpRange, error) {
if s == "" {
return nil, nil // header not present
}
const b = "bytes="
if !strings.HasPrefix(s, b) {
- return nil, os.NewError("invalid range")
+ return nil, errors.New("invalid range")
}
var ranges []httpRange
for _, ra := range strings.Split(s[len(b):], ",") {
i := strings.Index(ra, "-")
if i < 0 {
- return nil, os.NewError("invalid range")
+ return nil, errors.New("invalid range")
}
start, end := ra[:i], ra[i+1:]
var r httpRange
if start == "" {
// If no start is specified, end specifies the
// range start relative to the end of the file.
- i, err := strconv.Atoi64(end)
+ i, err := strconv.ParseInt(end, 10, 64)
if err != nil {
- return nil, os.NewError("invalid range")
+ return nil, errors.New("invalid range")
}
if i > size {
i = size
@@ -298,18 +342,18 @@ func parseRange(s string, size int64) ([]httpRange, os.Error) {
r.start = size - i
r.length = size - r.start
} else {
- i, err := strconv.Atoi64(start)
+ i, err := strconv.ParseInt(start, 10, 64)
if err != nil || i > size || i < 0 {
- return nil, os.NewError("invalid range")
+ return nil, errors.New("invalid range")
}
r.start = i
if end == "" {
// If no end is specified, range extends to end of the file.
r.length = size - r.start
} else {
- i, err := strconv.Atoi64(end)
+ i, err := strconv.ParseInt(end, 10, 64)
if err != nil || r.start > i {
- return nil, os.NewError("invalid range")
+ return nil, errors.New("invalid range")
}
if i >= size {
i = size - 1
diff --git a/src/pkg/http/fs_test.go b/src/pkg/net/http/fs_test.go
index bb6d0158b..5aa93ce58 100644
--- a/src/pkg/http/fs_test.go
+++ b/src/pkg/net/http/fs_test.go
@@ -5,15 +5,23 @@
package http_test
import (
+ "bytes"
+ "errors"
"fmt"
- . "http"
- "http/httptest"
+ "io"
"io/ioutil"
+ "net"
+ . "net/http"
+ "net/http/httptest"
+ "net/url"
"os"
+ "os/exec"
"path/filepath"
+ "regexp"
+ "runtime"
"strings"
"testing"
- "url"
+ "time"
)
const (
@@ -40,7 +48,7 @@ func TestServeFile(t *testing.T) {
}))
defer ts.Close()
- var err os.Error
+ var err error
file, err := ioutil.ReadFile(testFile)
if err != nil {
@@ -56,18 +64,18 @@ func TestServeFile(t *testing.T) {
req.Method = "GET"
// straight GET
- _, body := getBody(t, req)
+ _, body := getBody(t, "straight get", req)
if !equal(body, file) {
t.Fatalf("body mismatch: got %q, want %q", body, file)
}
// Range tests
- for _, rt := range ServeFileRangeTests {
+ for i, rt := range ServeFileRangeTests {
req.Header.Set("Range", "bytes="+rt.r)
if rt.r == "" {
req.Header["Range"] = nil
}
- r, body := getBody(t, req)
+ r, body := getBody(t, fmt.Sprintf("test %d", i), req)
if r.StatusCode != rt.code {
t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
}
@@ -113,18 +121,18 @@ func TestFSRedirect(t *testing.T) {
}
type testFileSystem struct {
- open func(name string) (File, os.Error)
+ open func(name string) (File, error)
}
-func (fs *testFileSystem) Open(name string) (File, os.Error) {
+func (fs *testFileSystem) Open(name string) (File, error) {
return fs.open(name)
}
func TestFileServerCleans(t *testing.T) {
ch := make(chan string, 1)
- fs := FileServer(&testFileSystem{func(name string) (File, os.Error) {
+ fs := FileServer(&testFileSystem{func(name string) (File, error) {
ch <- name
- return nil, os.ENOENT
+ return nil, errors.New("file does not exist")
}})
tests := []struct {
reqPath, openArg string
@@ -144,12 +152,19 @@ func TestFileServerCleans(t *testing.T) {
}
}
+func mustRemoveAll(dir string) {
+ err := os.RemoveAll(dir)
+ if err != nil {
+ panic(err)
+ }
+}
+
func TestFileServerImplicitLeadingSlash(t *testing.T) {
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
- defer os.RemoveAll(tempDir)
+ defer mustRemoveAll(tempDir)
if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
@@ -164,6 +179,7 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) {
if err != nil {
t.Fatalf("ReadAll %s: %v", suffix, err)
}
+ res.Body.Close()
return string(b)
}
if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
@@ -190,8 +206,8 @@ func TestDirJoin(t *testing.T) {
if err != nil {
t.Fatalf("stat of %s: %v", name, err)
}
- if gfi.Ino != wfi.Ino {
- t.Errorf("%s got different inode", name)
+ if !os.SameFile(gfi, wfi) {
+ t.Errorf("%s got different file", name)
}
}
test(Dir("/etc/"), "/hosts")
@@ -208,18 +224,31 @@ func TestDirJoin(t *testing.T) {
test(Dir("/etc/hosts"), "../")
}
+func TestEmptyDirOpenCWD(t *testing.T) {
+ test := func(d Dir) {
+ name := "fs_test.go"
+ f, err := d.Open(name)
+ if err != nil {
+ t.Fatalf("open of %s: %v", name, err)
+ }
+ defer f.Close()
+ }
+ test(Dir(""))
+ test(Dir("."))
+ test(Dir("./"))
+}
+
func TestServeFileContentType(t *testing.T) {
const ctype = "icecream/chocolate"
- override := false
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
- if override {
+ if r.FormValue("override") == "1" {
w.Header().Set("Content-Type", ctype)
}
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
- get := func(want string) {
- resp, err := Get(ts.URL)
+ get := func(override, want string) {
+ resp, err := Get(ts.URL + "?override=" + override)
if err != nil {
t.Fatal(err)
}
@@ -227,9 +256,8 @@ func TestServeFileContentType(t *testing.T) {
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
}
}
- get("text/plain; charset=utf-8")
- override = true
- get(ctype)
+ get("0", "text/plain; charset=utf-8")
+ get("1", ctype)
}
func TestServeFileMimeType(t *testing.T) {
@@ -247,6 +275,20 @@ func TestServeFileMimeType(t *testing.T) {
}
}
+func TestServeFileFromCWD(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "fs_test.go")
+ }))
+ defer ts.Close()
+ r, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if r.StatusCode != 200 {
+ t.Fatalf("expected 200 OK, got %s", r.Status)
+ }
+}
+
func TestServeFileWithContentEncoding(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "foo")
@@ -272,7 +314,6 @@ func TestServeIndexHtml(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- defer res.Body.Close()
b, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal("reading Body:", err)
@@ -280,21 +321,150 @@ func TestServeIndexHtml(t *testing.T) {
if s := string(b); s != want {
t.Errorf("for path %q got %q, want %q", path, s, want)
}
+ res.Body.Close()
+ }
+}
+
+func TestServeContent(t *testing.T) {
+ type req struct {
+ name string
+ modtime time.Time
+ content io.ReadSeeker
+ }
+ ch := make(chan req, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ p := <-ch
+ ServeContent(w, r, p.name, p.modtime, p.content)
+ }))
+ defer ts.Close()
+
+ css, err := os.Open("testdata/style.css")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer css.Close()
+
+ ch <- req{"style.css", time.Time{}, css}
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.Header.Get("Content-Type"), "text/css; charset=utf-8"; g != e {
+ t.Errorf("style.css: content type = %q, want %q", g, e)
+ }
+ if g := res.Header.Get("Last-Modified"); g != "" {
+ t.Errorf("want empty Last-Modified; got %q", g)
+ }
+
+ fi, err := css.Stat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ ch <- req{"style.html", fi.ModTime(), css}
+ res, err = Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.Header.Get("Content-Type"), "text/html; charset=utf-8"; g != e {
+ t.Errorf("style.html: content type = %q, want %q", g, e)
+ }
+ if g := res.Header.Get("Last-Modified"); g == "" {
+ t.Errorf("want non-empty last-modified")
}
}
-func getBody(t *testing.T, req Request) (*Response, []byte) {
+// verifies that sendfile is being used on Linux
+func TestLinuxSendfile(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Logf("skipping; linux-only test")
+ return
+ }
+ _, err := exec.LookPath("strace")
+ if err != nil {
+ t.Logf("skipping; strace not found in path")
+ return
+ }
+
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ lnf, err := ln.(*net.TCPListener).File()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ var buf bytes.Buffer
+ child := exec.Command("strace", "-f", os.Args[0], "-test.run=TestLinuxSendfileChild")
+ child.ExtraFiles = append(child.ExtraFiles, lnf)
+ child.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
+ child.Stdout = &buf
+ child.Stderr = &buf
+ err = child.Start()
+ if err != nil {
+ t.Logf("skipping; failed to start straced child: %v", err)
+ return
+ }
+
+ res, err := Get(fmt.Sprintf("http://%s/", ln.Addr()))
+ if err != nil {
+ t.Fatalf("http client error: %v", err)
+ }
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != nil {
+ t.Fatalf("client body read error: %v", err)
+ }
+ res.Body.Close()
+
+ // Force child to exit cleanly.
+ Get(fmt.Sprintf("http://%s/quit", ln.Addr()))
+ child.Wait()
+
+ rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+\)\s*=\s*\d+\s*\n`)
+ rxResume := regexp.MustCompile(`<\.\.\. sendfile(64)? resumed> \)\s*=\s*\d+\s*\n`)
+ out := buf.String()
+ if !rx.MatchString(out) && !rxResume.MatchString(out) {
+ t.Errorf("no sendfile system call found in:\n%s", out)
+ }
+}
+
+func getBody(t *testing.T, testName string, req Request) (*Response, []byte) {
r, err := DefaultClient.Do(&req)
if err != nil {
- t.Fatal(req.URL.String(), "send:", err)
+ t.Fatalf("%s: for URL %q, send error: %v", testName, req.URL.String(), err)
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
- t.Fatal("reading Body:", err)
+ t.Fatalf("%s: for URL %q, reading body: %v", testName, req.URL.String(), err)
}
return r, b
}
+// TestLinuxSendfileChild isn't a real test. It's used as a helper process
+// for TestLinuxSendfile.
+func TestLinuxSendfileChild(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+ fd3 := os.NewFile(3, "ephemeral-port-listener")
+ ln, err := net.FileListener(fd3)
+ if err != nil {
+ panic(err)
+ }
+ mux := NewServeMux()
+ mux.Handle("/", FileServer(Dir("testdata")))
+ mux.HandleFunc("/quit", func(ResponseWriter, *Request) {
+ os.Exit(0)
+ })
+ s := &Server{Handler: mux}
+ err = s.Serve(ln)
+ if err != nil {
+ panic(err)
+ }
+}
+
func equal(a, b []byte) bool {
if len(a) != len(b) {
return false
diff --git a/src/pkg/http/header.go b/src/pkg/net/http/header.go
index 08b077130..b107c312d 100644
--- a/src/pkg/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -8,7 +8,6 @@ import (
"fmt"
"io"
"net/textproto"
- "os"
"sort"
"strings"
)
@@ -31,8 +30,8 @@ func (h Header) Set(key, value string) {
// Get gets the first value associated with the given key.
// If there are no values associated with the key, Get returns "".
-// Get is a convenience method. For more complex queries,
-// access the map directly.
+// To access multiple values of a key, access the map directly
+// with CanonicalHeaderKey.
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
@@ -43,13 +42,15 @@ func (h Header) Del(key string) {
}
// Write writes a header in wire format.
-func (h Header) Write(w io.Writer) os.Error {
+func (h Header) Write(w io.Writer) error {
return h.WriteSubset(w, nil)
}
+var headerNewlineToSpace = strings.NewReplacer("\n", " ", "\r", " ")
+
// WriteSubset writes a header in wire format.
// If exclude is not nil, keys where exclude[key] == true are not written.
-func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
+func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
keys := make([]string, 0, len(h))
for k := range h {
if exclude == nil || !exclude[k] {
@@ -59,8 +60,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
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 = headerNewlineToSpace.Replace(v)
v = strings.TrimSpace(v)
if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
return err
diff --git a/src/pkg/http/header_test.go b/src/pkg/net/http/header_test.go
index ccdee8a97..ccdee8a97 100644
--- a/src/pkg/http/header_test.go
+++ b/src/pkg/net/http/header_test.go
diff --git a/src/pkg/http/httptest/recorder.go b/src/pkg/net/http/httptest/recorder.go
index f2fedefcf..9aa0d510b 100644
--- a/src/pkg/http/httptest/recorder.go
+++ b/src/pkg/net/http/httptest/recorder.go
@@ -7,8 +7,7 @@ package httptest
import (
"bytes"
- "http"
- "os"
+ "net/http"
)
// ResponseRecorder is an implementation of http.ResponseWriter that
@@ -38,7 +37,7 @@ func (rw *ResponseRecorder) Header() http.Header {
}
// Write always succeeds and writes to rw.Body, if not nil.
-func (rw *ResponseRecorder) Write(buf []byte) (int, os.Error) {
+func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
if rw.Body != nil {
rw.Body.Write(buf)
}
diff --git a/src/pkg/http/httptest/server.go b/src/pkg/net/http/httptest/server.go
index 2ec36d04c..57cf0c941 100644
--- a/src/pkg/http/httptest/server.go
+++ b/src/pkg/net/http/httptest/server.go
@@ -7,14 +7,13 @@
package httptest
import (
- "crypto/rand"
"crypto/tls"
"flag"
"fmt"
- "http"
"net"
+ "net/http"
"os"
- "time"
+ "sync"
)
// A Server is an HTTP server listening on a system-chosen port on the
@@ -23,6 +22,14 @@ type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener
TLS *tls.Config // nil if not using using TLS
+
+ // Config may be changed after calling NewUnstartedServer and
+ // before Start or StartTLS.
+ Config *http.Server
+
+ // wg counts the number of outstanding HTTP requests on this server.
+ // Close blocks until all requests are finished.
+ wg sync.WaitGroup
}
// historyListener keeps track of all connections that it's ever
@@ -32,7 +39,7 @@ type historyListener struct {
history []net.Conn
}
-func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
+func (hs *historyListener) Accept() (c net.Conn, err error) {
c, err = hs.Listener.Accept()
if err == nil {
hs.history = append(hs.history, c)
@@ -41,6 +48,13 @@ func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
}
func newLocalListener() net.Listener {
+ if *serve != "" {
+ l, err := net.Listen("tcp", *serve)
+ if err != nil {
+ panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
+ }
+ return l
+ }
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
@@ -52,64 +66,92 @@ func newLocalListener() net.Listener {
// When debugging a particular http server-based test,
// this flag lets you run
-// gotest -run=BrokenTest -httptest.serve=127.0.0.1:8000
+// go test -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)
- 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 := NewUnstartedServer(handler)
+ ts.Start()
+ return ts
+}
+
+// NewUnstartedServer returns a new Server but doesn't start it.
+//
+// After changing its configuration, the caller should call Start or
+// StartTLS.
+//
+// The caller should call Close when finished, to shut it down.
+func NewUnstartedServer(handler http.Handler) *Server {
+ return &Server{
+ Listener: newLocalListener(),
+ Config: &http.Server{Handler: handler},
}
- ts.Listener = &historyListener{l, make([]net.Conn, 0)}
- ts.URL = "http://" + l.Addr().String()
- server := &http.Server{Handler: handler}
- go server.Serve(ts.Listener)
+}
+
+// Start starts a server from NewUnstartedServer.
+func (s *Server) Start() {
+ if s.URL != "" {
+ panic("Server already started")
+ }
+ s.Listener = &historyListener{s.Listener, make([]net.Conn, 0)}
+ s.URL = "http://" + s.Listener.Addr().String()
+ s.wrapHandler()
+ go s.Config.Serve(s.Listener)
if *serve != "" {
- fmt.Println(os.Stderr, "httptest: serving on", ts.URL)
+ fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL)
select {}
}
- return ts
}
-// NewTLSServer starts and returns a new Server using TLS.
-// The caller should call Close when finished, to shut it down.
-func NewTLSServer(handler http.Handler) *Server {
- l := newLocalListener()
- ts := new(Server)
-
+// StartTLS starts TLS on a server from NewUnstartedServer.
+func (s *Server) StartTLS() {
+ if s.URL != "" {
+ panic("Server already started")
+ }
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
if err != nil {
panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
}
- ts.TLS = &tls.Config{
- Rand: rand.Reader,
- Time: time.Seconds,
+ s.TLS = &tls.Config{
NextProtos: []string{"http/1.1"},
Certificates: []tls.Certificate{cert},
}
- tlsListener := tls.NewListener(l, ts.TLS)
+ tlsListener := tls.NewListener(s.Listener, s.TLS)
+
+ s.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
+ s.URL = "https://" + s.Listener.Addr().String()
+ s.wrapHandler()
+ go s.Config.Serve(s.Listener)
+}
+
+func (s *Server) wrapHandler() {
+ h := s.Config.Handler
+ if h == nil {
+ h = http.DefaultServeMux
+ }
+ s.Config.Handler = &waitGroupHandler{
+ s: s,
+ h: h,
+ }
+}
- ts.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
- ts.URL = "https://" + l.Addr().String()
- server := &http.Server{Handler: handler}
- go server.Serve(ts.Listener)
+// NewTLSServer starts and returns a new Server using TLS.
+// The caller should call Close when finished, to shut it down.
+func NewTLSServer(handler http.Handler) *Server {
+ ts := NewUnstartedServer(handler)
+ ts.StartTLS()
return ts
}
-// Close shuts down the server.
+// Close shuts down the server and blocks until all outstanding
+// requests on this server have completed.
func (s *Server) Close() {
s.Listener.Close()
+ s.wg.Wait()
}
// CloseClientConnections closes any currently open HTTP connections
@@ -124,6 +166,20 @@ func (s *Server) CloseClientConnections() {
}
}
+// waitGroupHandler wraps a handler, incrementing and decrementing a
+// sync.WaitGroup on each request, to enable Server.Close to block
+// until outstanding requests are finished.
+type waitGroupHandler struct {
+ s *Server
+ h http.Handler // non-nil
+}
+
+func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ h.s.wg.Add(1)
+ defer h.s.wg.Done() // a defer, in case ServeHTTP below panics
+ h.h.ServeHTTP(w, r)
+}
+
// localhostCert is a PEM-encoded TLS cert with SAN DNS names
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
diff --git a/src/pkg/net/http/httptest/server_test.go b/src/pkg/net/http/httptest/server_test.go
new file mode 100644
index 000000000..500a9f0b8
--- /dev/null
+++ b/src/pkg/net/http/httptest/server_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httptest
+
+import (
+ "io/ioutil"
+ "net/http"
+ "testing"
+)
+
+func TestServer(t *testing.T) {
+ ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("hello"))
+ }))
+ defer ts.Close()
+ res, err := http.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ got, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != "hello" {
+ t.Errorf("got %q, want hello", string(got))
+ }
+}
diff --git a/src/pkg/net/http/httputil/chunked.go b/src/pkg/net/http/httputil/chunked.go
new file mode 100644
index 000000000..29eaf3475
--- /dev/null
+++ b/src/pkg/net/http/httputil/chunked.go
@@ -0,0 +1,172 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The wire protocol for HTTP's "chunked" Transfer-Encoding.
+
+// This code is a duplicate of ../chunked.go with these edits:
+// s/newChunked/NewChunked/g
+// s/package http/package httputil/
+// Please make any changes in both files.
+
+package httputil
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "io"
+ "strconv"
+)
+
+const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+
+var ErrLineTooLong = errors.New("header line too long")
+
+// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.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 io.Reader) io.Reader {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ return &chunkedReader{r: br}
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.ParseUint(line, 16, 64)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ cr.err = io.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ p = bytes.TrimRight(p, " \r\t\n")
+
+ return p, nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// 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 {
+ return &chunkedWriter{w}
+}
+
+// Writing to chunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the underlying Wire chunkedWriter.
+type chunkedWriter struct {
+ Wire io.Writer
+}
+
+// Write the contents of data as one chunk to Wire.
+// NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has
+// a bug since it does not check for success of io.WriteString
+func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
+
+ // Don't send 0-length data. It looks like EOF for chunked encoding.
+ if len(data) == 0 {
+ return 0, nil
+ }
+
+ head := strconv.FormatInt(int64(len(data)), 16) + "\r\n"
+
+ if _, err = io.WriteString(cw.Wire, head); err != nil {
+ return 0, err
+ }
+ if n, err = cw.Wire.Write(data); err != nil {
+ return
+ }
+ if n != len(data) {
+ err = io.ErrShortWrite
+ return
+ }
+ _, err = io.WriteString(cw.Wire, "\r\n")
+
+ return
+}
+
+func (cw *chunkedWriter) Close() error {
+ _, err := io.WriteString(cw.Wire, "0\r\n")
+ return err
+}
diff --git a/src/pkg/net/http/httputil/chunked_test.go b/src/pkg/net/http/httputil/chunked_test.go
new file mode 100644
index 000000000..155a32bdf
--- /dev/null
+++ b/src/pkg/net/http/httputil/chunked_test.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code is a duplicate of ../chunked_test.go with these edits:
+// s/newChunked/NewChunked/g
+// s/package http/package httputil/
+// Please make any changes in both files.
+
+package httputil
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+func TestChunk(t *testing.T) {
+ var b bytes.Buffer
+
+ w := NewChunkedWriter(&b)
+ const chunk1 = "hello, "
+ const chunk2 = "world! 0123456789abcdef"
+ w.Write([]byte(chunk1))
+ w.Write([]byte(chunk2))
+ w.Close()
+
+ if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
+ t.Fatalf("chunk writer wrote %q; want %q", g, e)
+ }
+
+ r := NewChunkedReader(&b)
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Logf(`data: "%s"`, data)
+ t.Fatalf("ReadAll from reader: %v", err)
+ }
+ if g, e := string(data), chunk1+chunk2; g != e {
+ t.Errorf("chunk reader read %q; want %q", g, e)
+ }
+}
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
new file mode 100644
index 000000000..892ef4ede
--- /dev/null
+++ b/src/pkg/net/http/httputil/dump.go
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httputil
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+ "time"
+)
+
+// One of the copies, say from b to r2, could be avoided by using a more
+// elaborate trick where the other copy is made during Request/Response.Write.
+// This would complicate things too much, given that these functions are for
+// debugging only.
+func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
+ var buf bytes.Buffer
+ if _, err = buf.ReadFrom(b); err != nil {
+ return nil, nil, err
+ }
+ if err = b.Close(); err != nil {
+ return nil, nil, err
+ }
+ return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
+}
+
+// dumpConn is a net.Conn which writes to Writer and reads from Reader
+type dumpConn struct {
+ io.Writer
+ io.Reader
+}
+
+func (c *dumpConn) Close() error { return nil }
+func (c *dumpConn) LocalAddr() net.Addr { return nil }
+func (c *dumpConn) RemoteAddr() net.Addr { return nil }
+func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
+func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
+
+// DumpRequestOut is like DumpRequest but includes
+// headers that the standard http.Transport adds,
+// such as User-Agent.
+func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
+ save := req.Body
+ if !body || req.Body == nil {
+ req.Body = nil
+ } else {
+ var err error
+ save, req.Body, err = drainBody(req.Body)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Since we're using the actual Transport code to write the request,
+ // switch to http so the Transport doesn't try to do an SSL
+ // negotiation with our dumpConn and its bytes.Buffer & pipe.
+ // The wire format for https and http are the same, anyway.
+ reqSend := req
+ if req.URL.Scheme == "https" {
+ reqSend = new(http.Request)
+ *reqSend = *req
+ reqSend.URL = new(url.URL)
+ *reqSend.URL = *req.URL
+ reqSend.URL.Scheme = "http"
+ }
+
+ // Use the actual Transport code to record what we would send
+ // on the wire, but not using TCP. Use a Transport with a
+ // customer dialer that returns a fake net.Conn that waits
+ // for the full input (and recording it), and then responds
+ // with a dummy response.
+ var buf bytes.Buffer // records the output
+ pr, pw := io.Pipe()
+ dr := &delegateReader{c: make(chan io.Reader)}
+ // Wait for the request before replying with a dummy response:
+ go func() {
+ http.ReadRequest(bufio.NewReader(pr))
+ dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
+ }()
+
+ t := &http.Transport{
+ Dial: func(net, addr string) (net.Conn, error) {
+ return &dumpConn{io.MultiWriter(pw, &buf), dr}, nil
+ },
+ }
+
+ _, err := t.RoundTrip(reqSend)
+
+ req.Body = save
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+// delegateReader is a reader that delegates to another reader,
+// once it arrives on a channel.
+type delegateReader struct {
+ c chan io.Reader
+ r io.Reader // nil until received from c
+}
+
+func (r *delegateReader) Read(p []byte) (int, error) {
+ if r.r == nil {
+ r.r = <-r.c
+ }
+ return r.r.Read(p)
+}
+
+// Return value if nonempty, def otherwise.
+func valueOrDefault(value, def string) string {
+ if value != "" {
+ return value
+ }
+ return def
+}
+
+var reqWriteExcludeHeaderDump = map[string]bool{
+ "Host": true, // not in Header map anyway
+ "Content-Length": true,
+ "Transfer-Encoding": true,
+ "Trailer": true,
+}
+
+// dumpAsReceived writes req to w in the form as it was received, or
+// at least as accurately as possible from the information retained in
+// the request.
+func dumpAsReceived(req *http.Request, w io.Writer) error {
+ return nil
+}
+
+// DumpRequest returns the as-received wire representation of req,
+// optionally including the request body, for debugging.
+// DumpRequest is semantically a no-op, but in order to
+// dump the body, it reads the body data into memory and
+// changes req.Body to refer to the in-memory copy.
+// The documentation for http.Request.Write details which fields
+// of req are used.
+func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
+ save := req.Body
+ if !body || req.Body == nil {
+ req.Body = nil
+ } else {
+ save, req.Body, err = drainBody(req.Body)
+ if err != nil {
+ return
+ }
+ }
+
+ var b bytes.Buffer
+
+ fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
+ req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor)
+
+ host := req.Host
+ if host == "" && req.URL != nil {
+ host = req.URL.Host
+ }
+ if host != "" {
+ fmt.Fprintf(&b, "Host: %s\r\n", host)
+ }
+
+ chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
+ if len(req.TransferEncoding) > 0 {
+ fmt.Fprintf(&b, "Transfer-Encoding: %s\r\n", strings.Join(req.TransferEncoding, ","))
+ }
+ if req.Close {
+ fmt.Fprintf(&b, "Connection: close\r\n")
+ }
+
+ err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
+ if err != nil {
+ return
+ }
+
+ io.WriteString(&b, "\r\n")
+
+ if req.Body != nil {
+ var dest io.Writer = &b
+ if chunked {
+ dest = NewChunkedWriter(dest)
+ }
+ _, err = io.Copy(dest, req.Body)
+ if chunked {
+ dest.(io.Closer).Close()
+ io.WriteString(&b, "\r\n")
+ }
+ }
+
+ req.Body = save
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
+
+// DumpResponse is like DumpRequest but dumps a response.
+func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
+ var b bytes.Buffer
+ save := resp.Body
+ savecl := resp.ContentLength
+ if !body || resp.Body == nil {
+ resp.Body = nil
+ resp.ContentLength = 0
+ } else {
+ save, resp.Body, err = drainBody(resp.Body)
+ if err != nil {
+ return
+ }
+ }
+ err = resp.Write(&b)
+ resp.Body = save
+ resp.ContentLength = savecl
+ if err != nil {
+ return
+ }
+ dump = b.Bytes()
+ return
+}
diff --git a/src/pkg/net/http/httputil/dump_test.go b/src/pkg/net/http/httputil/dump_test.go
new file mode 100644
index 000000000..5afe9ba74
--- /dev/null
+++ b/src/pkg/net/http/httputil/dump_test.go
@@ -0,0 +1,152 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httputil
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "testing"
+)
+
+type dumpTest struct {
+ Req http.Request
+ Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
+
+ WantDump string
+ WantDumpOut string
+}
+
+var dumpTests = []dumpTest{
+
+ // HTTP/1.1 => chunked coding; body; empty trailer
+ {
+ Req: http.Request{
+ Method: "GET",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/search",
+ },
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ TransferEncoding: []string{"chunked"},
+ },
+
+ Body: []byte("abcdef"),
+
+ WantDump: "GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("abcdef") + chunk(""),
+ },
+
+ // Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
+ // and doesn't add a User-Agent.
+ {
+ Req: http.Request{
+ Method: "GET",
+ URL: mustParseURL("/foo"),
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Header: http.Header{
+ "X-Foo": []string{"X-Bar"},
+ },
+ },
+
+ WantDump: "GET /foo HTTP/1.0\r\n" +
+ "X-Foo: X-Bar\r\n\r\n",
+ },
+
+ {
+ Req: *mustNewRequest("GET", "http://example.com/foo", nil),
+
+ WantDumpOut: "GET /foo HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Accept-Encoding: gzip\r\n\r\n",
+ },
+
+ // Test that an https URL doesn't try to do an SSL negotiation
+ // with a bytes.Buffer and hang with all goroutines not
+ // runnable.
+ {
+ Req: *mustNewRequest("GET", "https://example.com/foo", nil),
+
+ WantDumpOut: "GET /foo HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Accept-Encoding: gzip\r\n\r\n",
+ },
+}
+
+func TestDumpRequest(t *testing.T) {
+ for i, tt := range dumpTests {
+ setBody := func() {
+ if tt.Body == nil {
+ return
+ }
+ switch b := tt.Body.(type) {
+ case []byte:
+ tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ case func() io.ReadCloser:
+ tt.Req.Body = b()
+ }
+ }
+ setBody()
+ if tt.Req.Header == nil {
+ tt.Req.Header = make(http.Header)
+ }
+
+ if tt.WantDump != "" {
+ setBody()
+ dump, err := DumpRequest(&tt.Req, true)
+ if err != nil {
+ t.Errorf("DumpRequest #%d: %s", i, err)
+ continue
+ }
+ if string(dump) != tt.WantDump {
+ t.Errorf("DumpRequest %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDump, string(dump))
+ continue
+ }
+ }
+
+ if tt.WantDumpOut != "" {
+ setBody()
+ dump, err := DumpRequestOut(&tt.Req, true)
+ if err != nil {
+ t.Errorf("DumpRequestOut #%d: %s", i, err)
+ continue
+ }
+ if string(dump) != tt.WantDumpOut {
+ t.Errorf("DumpRequestOut %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantDumpOut, string(dump))
+ continue
+ }
+ }
+ }
+}
+
+func chunk(s string) string {
+ return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
+}
+
+func mustParseURL(s string) *url.URL {
+ u, err := url.Parse(s)
+ if err != nil {
+ panic(fmt.Sprintf("Error parsing URL %q: %v", s, err))
+ }
+ return u
+}
+
+func mustNewRequest(method, url string, body io.Reader) *http.Request {
+ req, err := http.NewRequest(method, url, body)
+ if err != nil {
+ panic(fmt.Sprintf("NewRequest(%q, %q, %p) err = %v", method, url, body, err))
+ }
+ return req
+}
diff --git a/src/pkg/http/persist.go b/src/pkg/net/http/httputil/persist.go
index 78bf9058f..507938aca 100644
--- a/src/pkg/http/persist.go
+++ b/src/pkg/net/http/httputil/persist.go
@@ -2,22 +2,30 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package http
+// Package httputil provides HTTP utility functions, complementing the
+// more common ones in the net/http package.
+package httputil
import (
"bufio"
+ "errors"
"io"
"net"
+ "net/http"
"net/textproto"
- "os"
"sync"
)
var (
- ErrPersistEOF = &ProtocolError{"persistent connection closed"}
- ErrPipeline = &ProtocolError{"pipeline error"}
+ ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
+ ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
+ ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)
+// This is an API usage error - the local side is closed.
+// ErrPersistEOF (above) reports that the remote side is closed.
+var errClosed = errors.New("i/o operation on closed connection")
+
// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// also allows hijacking the underlying connection by calling Hijack
@@ -31,10 +39,10 @@ type ServerConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
r *bufio.Reader
- re, we os.Error // read/write errors
+ re, we error // read/write errors
lastbody io.ReadCloser
nread, nwritten int
- pipereq map[*Request]uint
+ pipereq map[*http.Request]uint
pipe textproto.Pipeline
}
@@ -45,7 +53,7 @@ func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
if r == nil {
r = bufio.NewReader(c)
}
- return &ServerConn{c: c, r: r, pipereq: make(map[*Request]uint)}
+ return &ServerConn{c: c, r: r, pipereq: make(map[*http.Request]uint)}
}
// Hijack detaches the ServerConn and returns the underlying connection as well
@@ -63,7 +71,7 @@ func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
}
// Close calls Hijack and then also closes the underlying connection
-func (sc *ServerConn) Close() os.Error {
+func (sc *ServerConn) Close() error {
c, _ := sc.Hijack()
if c != nil {
return c.Close()
@@ -75,7 +83,7 @@ func (sc *ServerConn) Close() os.Error {
// it is gracefully determined that there are no more requests (e.g. after the
// first request on an HTTP/1.0 connection, or after a Connection:close on a
// HTTP/1.1 connection).
-func (sc *ServerConn) Read() (req *Request, err os.Error) {
+func (sc *ServerConn) Read() (req *http.Request, err error) {
// Ensure ordered execution of Reads and Writes
id := sc.pipe.Next()
@@ -104,7 +112,7 @@ func (sc *ServerConn) Read() (req *Request, err os.Error) {
}
if sc.r == nil { // connection closed by user in the meantime
defer sc.lk.Unlock()
- return nil, os.EBADF
+ return nil, errClosed
}
r := sc.r
lastbody := sc.lastbody
@@ -125,7 +133,7 @@ func (sc *ServerConn) Read() (req *Request, err os.Error) {
}
}
- req, err = ReadRequest(r)
+ req, err = http.ReadRequest(r)
sc.lk.Lock()
defer sc.lk.Unlock()
if err != nil {
@@ -160,12 +168,12 @@ func (sc *ServerConn) Pending() int {
// Write writes resp in response to req. To close the connection gracefully, set the
// Response.Close field to true. Write should be considered operational until
// it returns an error, regardless of any errors returned on the Read side.
-func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
+func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
// Retrieve the pipeline ID of this request/response pair
sc.lk.Lock()
id, ok := sc.pipereq[req]
- sc.pipereq[req] = 0, false
+ delete(sc.pipereq, req)
if !ok {
sc.lk.Unlock()
return ErrPipeline
@@ -183,12 +191,12 @@ func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
}
if sc.c == nil { // connection closed by user in the meantime
defer sc.lk.Unlock()
- return os.EBADF
+ return ErrClosed
}
c := sc.c
if sc.nread <= sc.nwritten {
defer sc.lk.Unlock()
- return os.NewError("persist server pipe count")
+ return errors.New("persist server pipe count")
}
if resp.Close {
// After signaling a keep-alive close, any pipelined unread
@@ -221,13 +229,13 @@ type ClientConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
r *bufio.Reader
- re, we os.Error // read/write errors
+ re, we error // read/write errors
lastbody io.ReadCloser
nread, nwritten int
- pipereq map[*Request]uint
+ pipereq map[*http.Request]uint
pipe textproto.Pipeline
- writeReq func(*Request, io.Writer) os.Error
+ writeReq func(*http.Request, io.Writer) error
}
// NewClientConn returns a new ClientConn reading and writing c. If r is not
@@ -239,8 +247,8 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
return &ClientConn{
c: c,
r: r,
- pipereq: make(map[*Request]uint),
- writeReq: (*Request).Write,
+ pipereq: make(map[*http.Request]uint),
+ writeReq: (*http.Request).Write,
}
}
@@ -248,7 +256,7 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
// using Request's WriteProxy method.
func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
cc := NewClientConn(c, r)
- cc.writeReq = (*Request).WriteProxy
+ cc.writeReq = (*http.Request).WriteProxy
return cc
}
@@ -267,7 +275,7 @@ func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
}
// Close calls Hijack and then also closes the underlying connection
-func (cc *ClientConn) Close() os.Error {
+func (cc *ClientConn) Close() error {
c, _ := cc.Hijack()
if c != nil {
return c.Close()
@@ -280,7 +288,7 @@ func (cc *ClientConn) Close() os.Error {
// keepalive connection is logically closed after this request and the opposing
// server is informed. An ErrUnexpectedEOF indicates the remote closed the
// underlying TCP connection, which is usually considered as graceful close.
-func (cc *ClientConn) Write(req *Request) (err os.Error) {
+func (cc *ClientConn) Write(req *http.Request) (err error) {
// Ensure ordered execution of Writes
id := cc.pipe.Next()
@@ -309,7 +317,7 @@ func (cc *ClientConn) Write(req *Request) (err os.Error) {
}
if cc.c == nil { // connection closed by user in the meantime
defer cc.lk.Unlock()
- return os.EBADF
+ return errClosed
}
c := cc.c
if req.Close {
@@ -343,17 +351,11 @@ 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) (*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) {
+func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
// Retrieve the pipeline ID of this request/response pair
cc.lk.Lock()
id, ok := cc.pipereq[req]
- cc.pipereq[req] = 0, false
+ delete(cc.pipereq, req)
if !ok {
cc.lk.Unlock()
return nil, ErrPipeline
@@ -371,7 +373,7 @@ func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Reque
}
if cc.r == nil { // connection closed by user in the meantime
defer cc.lk.Unlock()
- return nil, os.EBADF
+ return nil, errClosed
}
r := cc.r
lastbody := cc.lastbody
@@ -381,7 +383,7 @@ func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Reque
// 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 {
@@ -392,7 +394,7 @@ func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Reque
}
}
- resp, err = readRes(r, req)
+ resp, err = http.ReadResponse(r, req)
cc.lk.Lock()
defer cc.lk.Unlock()
if err != nil {
@@ -411,7 +413,7 @@ func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Reque
}
// Do is convenience method that writes a request and reads a response.
-func (cc *ClientConn) Do(req *Request) (resp *Response, err os.Error) {
+func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {
err = cc.Write(req)
if err != nil {
return
diff --git a/src/pkg/http/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 3f8bfdc80..9c4bd6e09 100644
--- a/src/pkg/http/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -4,17 +4,17 @@
// HTTP reverse proxy handler
-package http
+package httputil
import (
"io"
"log"
"net"
- "os"
+ "net/http"
+ "net/url"
"strings"
"sync"
"time"
- "url"
)
// ReverseProxy is an HTTP Handler that takes an incoming request and
@@ -25,17 +25,17 @@ type ReverseProxy struct {
// the request into a new request to be sent
// using Transport. Its response is then copied
// back to the original client unmodified.
- Director func(*Request)
+ Director func(*http.Request)
- // The Transport used to perform proxy requests.
- // If nil, DefaultTransport is used.
- Transport RoundTripper
+ // The transport used to perform proxy requests.
+ // If nil, http.DefaultTransport is used.
+ Transport http.RoundTripper
- // FlushInterval specifies the flush interval, in
- // nanoseconds, to flush to the client while
- // coping the response body.
+ // FlushInterval specifies the flush interval
+ // to flush to the client while copying the
+ // response body.
// If zero, no periodic flushing is done.
- FlushInterval int64
+ FlushInterval time.Duration
}
func singleJoiningSlash(a, b string) string {
@@ -55,27 +55,35 @@ func singleJoiningSlash(a, b string) string {
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
- director := func(req *Request) {
+ targetQuery := target.RawQuery
+ director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
- if q := req.URL.RawQuery; q != "" {
- req.URL.RawPath = req.URL.Path + "?" + q
+ if targetQuery == "" || req.URL.RawQuery == "" {
+ req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
- req.URL.RawPath = req.URL.Path
+ req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
- req.URL.RawQuery = target.RawQuery
}
return &ReverseProxy{Director: director}
}
-func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
+func copyHeader(dst, src http.Header) {
+ for k, vv := range src {
+ for _, v := range vv {
+ dst.Add(k, v)
+ }
+ }
+}
+
+func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
- transport = DefaultTransport
+ transport = http.DefaultTransport
}
- outreq := new(Request)
+ outreq := new(http.Request)
*outreq = *req // includes shallow copies of maps, but okay
p.Director(outreq)
@@ -84,6 +92,16 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
outreq.ProtoMinor = 1
outreq.Close = false
+ // Remove the connection header to the backend. We want a
+ // persistent connection, regardless of what the client sent
+ // to us. This is modifying the same underlying map from req
+ // (shallow copied above) so we only copy it if necessary.
+ if outreq.Header.Get("Connection") != "" {
+ outreq.Header = make(http.Header)
+ copyHeader(outreq.Header, req.Header)
+ outreq.Header.Del("Connection")
+ }
+
if clientIp, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
outreq.Header.Set("X-Forwarded-For", clientIp)
}
@@ -91,16 +109,11 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
res, err := transport.RoundTrip(outreq)
if err != nil {
log.Printf("http: proxy error: %v", err)
- rw.WriteHeader(StatusInternalServerError)
+ rw.WriteHeader(http.StatusInternalServerError)
return
}
- hdr := rw.Header()
- for k, vv := range res.Header {
- for _, v := range vv {
- hdr.Add(k, v)
- }
- }
+ copyHeader(rw.Header(), res.Header)
rw.WriteHeader(res.StatusCode)
@@ -117,18 +130,18 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
type writeFlusher interface {
io.Writer
- Flusher
+ http.Flusher
}
type maxLatencyWriter struct {
dst writeFlusher
- latency int64 // nanos
+ latency time.Duration
lk sync.Mutex // protects init of done, as well Write + Flush
done chan bool
}
-func (m *maxLatencyWriter) Write(p []byte) (n int, err os.Error) {
+func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
m.lk.Lock()
defer m.lk.Unlock()
if m.done == nil {
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
new file mode 100644
index 000000000..28e9c90ad
--- /dev/null
+++ b/src/pkg/net/http/httputil/reverseproxy_test.go
@@ -0,0 +1,109 @@
+// 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.
+
+// Reverse proxy tests.
+
+package httputil
+
+import (
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+)
+
+func TestReverseProxy(t *testing.T) {
+ const backendResponse = "I am the backend"
+ const backendStatus = 404
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.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 c := r.Header.Get("Connection"); c != "" {
+ t.Errorf("handler got Connection header value %q", c)
+ }
+ 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")
+ http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
+ w.WriteHeader(backendStatus)
+ w.Write([]byte(backendResponse))
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+ getReq.Host = "some-name"
+ getReq.Header.Set("Connection", "close")
+ getReq.Close = true
+ res, err := http.DefaultClient.Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ if g, e := res.StatusCode, backendStatus; g != e {
+ t.Errorf("got res.StatusCode %d; expected %d", g, e)
+ }
+ 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)
+ }
+}
+
+var proxyQueryTests = []struct {
+ baseSuffix string // suffix to add to backend URL
+ reqSuffix string // suffix to add to frontend's request URL
+ want string // what backend should see for final request URL (without ?)
+}{
+ {"", "", ""},
+ {"?sta=tic", "?us=er", "sta=tic&us=er"},
+ {"", "?us=er", "us=er"},
+ {"?sta=tic", "", "sta=tic"},
+}
+
+func TestReverseProxyQuery(t *testing.T) {
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("X-Got-Query", r.URL.RawQuery)
+ w.Write([]byte("hi"))
+ }))
+ defer backend.Close()
+
+ for i, tt := range proxyQueryTests {
+ backendURL, err := url.Parse(backend.URL + tt.baseSuffix)
+ if err != nil {
+ t.Fatal(err)
+ }
+ frontend := httptest.NewServer(NewSingleHostReverseProxy(backendURL))
+ req, _ := http.NewRequest("GET", frontend.URL+tt.reqSuffix, nil)
+ req.Close = true
+ res, err := http.DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("%d. Get: %v", i, err)
+ }
+ if g, e := res.Header.Get("X-Got-Query"), tt.want; g != e {
+ t.Errorf("%d. got query %q; expected %q", i, g, e)
+ }
+ res.Body.Close()
+ frontend.Close()
+ }
+}
diff --git a/src/pkg/net/http/jar.go b/src/pkg/net/http/jar.go
new file mode 100644
index 000000000..2c2caa251
--- /dev/null
+++ b/src/pkg/net/http/jar.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.
+
+package http
+
+import (
+ "net/url"
+)
+
+// A CookieJar manages storage and use of cookies in HTTP requests.
+//
+// Implementations of CookieJar must be safe for concurrent use by multiple
+// goroutines.
+type CookieJar interface {
+ // SetCookies handles the receipt of the cookies in a reply for the
+ // given URL. It may or may not choose to save the cookies, depending
+ // on the jar's policy and implementation.
+ SetCookies(u *url.URL, cookies []*Cookie)
+
+ // Cookies returns the cookies to send in a request for the given URL.
+ // It is up to the implementation to honor the standard cookie use
+ // restrictions such as in RFC 6265.
+ Cookies(u *url.URL) []*Cookie
+}
+
+type blackHoleJar struct{}
+
+func (blackHoleJar) SetCookies(u *url.URL, cookies []*Cookie) {}
+func (blackHoleJar) Cookies(u *url.URL) []*Cookie { return nil }
diff --git a/src/pkg/http/lex.go b/src/pkg/net/http/lex.go
index 93b67e701..ffb393ccf 100644
--- a/src/pkg/http/lex.go
+++ b/src/pkg/net/http/lex.go
@@ -14,14 +14,6 @@ func isSeparator(c byte) bool {
return false
}
-func isSpace(c byte) bool {
- switch c {
- case ' ', '\t', '\r', '\n':
- return true
- }
- return false
-}
-
func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
func isChar(c byte) bool { return 0 <= c && c <= 127 }
diff --git a/src/pkg/http/lex_test.go b/src/pkg/net/http/lex_test.go
index 5386f7534..5386f7534 100644
--- a/src/pkg/http/lex_test.go
+++ b/src/pkg/net/http/lex_test.go
diff --git a/src/pkg/http/pprof/pprof.go b/src/pkg/net/http/pprof/pprof.go
index 917c7f877..06fcde144 100644
--- a/src/pkg/http/pprof/pprof.go
+++ b/src/pkg/net/http/pprof/pprof.go
@@ -12,15 +12,23 @@
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
-// import _ "http/pprof"
+// import _ "net/http/pprof"
//
// Then use the pprof tool to look at the heap profile:
//
-// pprof http://localhost:6060/debug/pprof/heap
+// go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
-// pprof http://localhost:6060/debug/pprof/profile
+// go tool pprof http://localhost:6060/debug/pprof/profile
+//
+// Or to view all available profiles:
+//
+// go tool pprof http://localhost:6060/debug/pprof/
+//
+// For a study of the facility in action, visit
+//
+// http://blog.golang.org/2011/06/profiling-go-programs.html
//
package pprof
@@ -28,7 +36,10 @@ import (
"bufio"
"bytes"
"fmt"
- "http"
+ "html/template"
+ "io"
+ "log"
+ "net/http"
"os"
"runtime"
"runtime/pprof"
@@ -38,9 +49,9 @@ import (
)
func init() {
+ http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
- http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
}
@@ -52,17 +63,10 @@ func Cmdline(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}
-// Heap responds with the pprof-formatted heap profile.
-// The package initialization registers it as /debug/pprof/heap.
-func Heap(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- pprof.WriteHeapProfile(w)
-}
-
// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
- sec, _ := strconv.Atoi64(r.FormValue("seconds"))
+ sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
if sec == 0 {
sec = 30
}
@@ -79,7 +83,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
return
}
- time.Sleep(sec * 1e9)
+ time.Sleep(time.Duration(sec) * time.Second)
pprof.StopCPUProfile()
}
@@ -110,7 +114,7 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
if err == nil {
word = word[0 : len(word)-1] // trim +
}
- pc, _ := strconv.Btoui64(string(word), 0)
+ pc, _ := strconv.ParseUint(string(word), 0, 64)
if pc != 0 {
f := runtime.FuncForPC(uintptr(pc))
if f != nil {
@@ -121,7 +125,7 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
// Wait until here to check for err; the last
// symbol will have an err because it doesn't end in +.
if err != nil {
- if err != os.EOF {
+ if err != io.EOF {
fmt.Fprintf(&buf, "reading request: %v\n", err)
}
break
@@ -130,3 +134,61 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
w.Write(buf.Bytes())
}
+
+// Handler returns an HTTP handler that serves the named profile.
+func Handler(name string) http.Handler {
+ return handler(name)
+}
+
+type handler string
+
+func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ debug, _ := strconv.Atoi(r.FormValue("debug"))
+ p := pprof.Lookup(string(name))
+ if p == nil {
+ w.WriteHeader(404)
+ fmt.Fprintf(w, "Unknown profile: %s\n", name)
+ return
+ }
+ p.WriteTo(w, debug)
+ return
+}
+
+// Index responds with the pprof-formatted profile named by the request.
+// For example, "/debug/pprof/heap" serves the "heap" profile.
+// Index responds to a request for "/debug/pprof/" with an HTML page
+// listing the available profiles.
+func Index(w http.ResponseWriter, r *http.Request) {
+ if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
+ name := r.URL.Path[len("/debug/pprof/"):]
+ if name != "" {
+ handler(name).ServeHTTP(w, r)
+ return
+ }
+ }
+
+ profiles := pprof.Profiles()
+ if err := indexTmpl.Execute(w, profiles); err != nil {
+ log.Print(err)
+ }
+}
+
+var indexTmpl = template.Must(template.New("index").Parse(`<html>
+<head>
+<title>/debug/pprof/</title>
+</head>
+/debug/pprof/<br>
+<br>
+<body>
+profiles:<br>
+<table>
+{{range .}}
+<tr><td align=right>{{.Count}}<td><a href="/debug/pprof/{{.Name}}?debug=1">{{.Name}}</a>
+{{end}}
+</table>
+<br>
+<a href="/debug/pprof/goroutine?debug=2">full goroutine stack dump</a><br>
+</body>
+</html>
+`))
diff --git a/src/pkg/http/proxy_test.go b/src/pkg/net/http/proxy_test.go
index 9b320b3aa..9b320b3aa 100644
--- a/src/pkg/http/proxy_test.go
+++ b/src/pkg/net/http/proxy_test.go
diff --git a/src/pkg/http/range_test.go b/src/pkg/net/http/range_test.go
index 5274a81fa..5274a81fa 100644
--- a/src/pkg/http/range_test.go
+++ b/src/pkg/net/http/range_test.go
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/net/http/readrequest_test.go
index f6dc99e2e..2e03c658a 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/net/http/readrequest_test.go
@@ -9,19 +9,22 @@ import (
"bytes"
"fmt"
"io"
+ "net/url"
+ "reflect"
"testing"
- "url"
)
type reqTest struct {
- Raw string
- Req *Request
- Body string
- Error string
+ Raw string
+ Req *Request
+ Body string
+ Trailer Header
+ Error string
}
var noError = ""
var noBody = ""
+var noTrailer Header = nil
var reqTests = []reqTest{
// Baseline test; All Request fields included for template use
@@ -40,17 +43,10 @@ var reqTests = []reqTest{
&Request{
Method: "GET",
- RawURL: "http://www.techcrunch.com/",
URL: &url.URL{
- Raw: "http://www.techcrunch.com/",
- Scheme: "http",
- RawPath: "/",
- RawAuthority: "www.techcrunch.com",
- RawUserinfo: "",
- Host: "www.techcrunch.com",
- Path: "/",
- RawQuery: "",
- Fragment: "",
+ Scheme: "http",
+ Host: "www.techcrunch.com",
+ Path: "/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
@@ -68,11 +64,12 @@ var reqTests = []reqTest{
Close: false,
ContentLength: 7,
Host: "www.techcrunch.com",
- Form: url.Values{},
+ RequestURI: "http://www.techcrunch.com/",
},
"abcdef\n",
+ noTrailer,
noError,
},
@@ -83,22 +80,21 @@ var reqTests = []reqTest{
&Request{
Method: "GET",
- RawURL: "/",
URL: &url.URL{
- Raw: "/",
- Path: "/",
- RawPath: "/",
+ Path: "/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Close: false,
ContentLength: 0,
Host: "foo.com",
- Form: url.Values{},
+ RequestURI: "/",
},
noBody,
+ noTrailer,
noError,
},
@@ -110,17 +106,8 @@ var reqTests = []reqTest{
&Request{
Method: "GET",
- RawURL: "//user@host/is/actually/a/path/",
URL: &url.URL{
- Raw: "//user@host/is/actually/a/path/",
- Scheme: "",
- RawPath: "//user@host/is/actually/a/path/",
- RawAuthority: "",
- RawUserinfo: "",
- Host: "",
- Path: "//user@host/is/actually/a/path/",
- RawQuery: "",
- Fragment: "",
+ Path: "//user@host/is/actually/a/path/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
@@ -129,10 +116,11 @@ var reqTests = []reqTest{
Close: false,
ContentLength: 0,
Host: "test",
- Form: url.Values{},
+ RequestURI: "//user@host/is/actually/a/path/",
},
noBody,
+ noTrailer,
noError,
},
@@ -142,6 +130,7 @@ var reqTests = []reqTest{
"Host: test\r\n\r\n",
nil,
noBody,
+ noTrailer,
"parse ../../../../etc/passwd: invalid URI for request",
},
@@ -151,8 +140,113 @@ var reqTests = []reqTest{
"Host: test\r\n\r\n",
nil,
noBody,
+ noTrailer,
"parse : empty url",
},
+
+ // Tests chunked body with trailer:
+ {
+ "POST / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ "3\r\nfoo\r\n" +
+ "3\r\nbar\r\n" +
+ "0\r\n" +
+ "Trailer-Key: Trailer-Value\r\n" +
+ "\r\n",
+ &Request{
+ Method: "POST",
+ URL: &url.URL{
+ Path: "/",
+ },
+ TransferEncoding: []string{"chunked"},
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ ContentLength: -1,
+ Host: "foo.com",
+ RequestURI: "/",
+ },
+
+ "foobar",
+ Header{
+ "Trailer-Key": {"Trailer-Value"},
+ },
+ noError,
+ },
+
+ // CONNECT request with domain name:
+ {
+ "CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
+
+ &Request{
+ Method: "CONNECT",
+ URL: &url.URL{
+ Host: "www.google.com:443",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: false,
+ ContentLength: 0,
+ Host: "www.google.com:443",
+ RequestURI: "www.google.com:443",
+ },
+
+ noBody,
+ noTrailer,
+ noError,
+ },
+
+ // CONNECT request with IP address:
+ {
+ "CONNECT 127.0.0.1:6060 HTTP/1.1\r\n\r\n",
+
+ &Request{
+ Method: "CONNECT",
+ URL: &url.URL{
+ Host: "127.0.0.1:6060",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: false,
+ ContentLength: 0,
+ Host: "127.0.0.1:6060",
+ RequestURI: "127.0.0.1:6060",
+ },
+
+ noBody,
+ noTrailer,
+ noError,
+ },
+
+ // CONNECT request for RPC:
+ {
+ "CONNECT /_goRPC_ HTTP/1.1\r\n\r\n",
+
+ &Request{
+ Method: "CONNECT",
+ URL: &url.URL{
+ Path: "/_goRPC_",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{},
+ Close: false,
+ ContentLength: 0,
+ Host: "",
+ RequestURI: "/_goRPC_",
+ },
+
+ noBody,
+ noTrailer,
+ noError,
+ },
}
func TestReadRequest(t *testing.T) {
@@ -162,8 +256,8 @@ func TestReadRequest(t *testing.T) {
braw.WriteString(tt.Raw)
req, err := ReadRequest(bufio.NewReader(&braw))
if err != nil {
- if err.String() != tt.Error {
- t.Errorf("#%d: error %q, want error %q", i, err.String(), tt.Error)
+ if err.Error() != tt.Error {
+ t.Errorf("#%d: error %q, want error %q", i, err.Error(), tt.Error)
}
continue
}
@@ -172,12 +266,18 @@ func TestReadRequest(t *testing.T) {
diff(t, fmt.Sprintf("#%d Request", i), req, tt.Req)
var bout bytes.Buffer
if rbody != nil {
- io.Copy(&bout, rbody)
+ _, err := io.Copy(&bout, rbody)
+ if err != nil {
+ t.Fatalf("#%d. copying body: %v", i, err)
+ }
rbody.Close()
}
body := bout.String()
if body != tt.Body {
t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
}
+ if !reflect.DeepEqual(tt.Trailer, req.Trailer) {
+ t.Errorf("#%d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
+ }
}
}
diff --git a/src/pkg/http/request.go b/src/pkg/net/http/request.go
index ed41fa45c..f5bc6eb91 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -4,8 +4,6 @@
// HTTP Request reading and parsing.
-// Package http implements parsing of HTTP requests, replies, and URLs and
-// provides an extensible HTTP server and a basic HTTP client.
package http
import (
@@ -13,20 +11,18 @@ import (
"bytes"
"crypto/tls"
"encoding/base64"
+ "errors"
"fmt"
"io"
"io/ioutil"
"mime"
"mime/multipart"
"net/textproto"
- "os"
- "strconv"
+ "net/url"
"strings"
- "url"
)
const (
- maxLineLength = 4096 // assumed <= bufio.defaultBufSize
maxValueLength = 4096
maxHeaderLines = 1024
chunkSize = 4 << 10 // 4 KB chunks
@@ -35,17 +31,16 @@ 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.NewError("http: no such file")
+var ErrMissingFile = errors.New("http: no such file")
// HTTP request parsing errors.
type ProtocolError struct {
ErrorString string
}
-func (err *ProtocolError) String() string { return err.ErrorString }
+func (err *ProtocolError) Error() string { return err.ErrorString }
var (
- ErrLineTooLong = &ProtocolError{"header line too long"}
ErrHeaderTooLong = &ProtocolError{"header too long"}
ErrShortBody = &ProtocolError{"entity body too short"}
ErrNotSupported = &ProtocolError{"feature not supported"}
@@ -60,22 +55,22 @@ type badStringError struct {
str string
}
-func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
+func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
// Headers that Request.Write handles itself and should be skipped.
var reqWriteExcludeHeader = map[string]bool{
- "Host": true,
+ "Host": true, // not in Header map anyway
"User-Agent": true,
"Content-Length": true,
"Transfer-Encoding": true,
"Trailer": true,
}
-// A Request represents a parsed HTTP request header.
+// A Request represents an HTTP request received by a server
+// or to be sent by a client.
type Request struct {
- Method string // GET, POST, PUT, etc.
- RawURL string // The raw URL given in the request.
- URL *url.URL // Parsed URL.
+ Method string // GET, POST, PUT, etc.
+ URL *url.URL
// The protocol version for incoming requests.
// Outgoing requests always use HTTP/1.1.
@@ -109,14 +104,20 @@ type Request struct {
// ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
- // Values >= 0 indicate that the given number of bytes may be read from Body.
+ // Values >= 0 indicate that the given number of bytes may
+ // be read from Body.
+ // For outgoing requests, a value of 0 means unknown if Body is not nil.
ContentLength int64
- // TransferEncoding lists the transfer encodings from outermost to innermost.
- // An empty list denotes the "identity" encoding.
+ // TransferEncoding lists the transfer encodings from outermost to
+ // innermost. An empty list denotes the "identity" encoding.
+ // TransferEncoding can usually be ignored; chunked encoding is
+ // automatically added and removed as necessary when sending and
+ // receiving requests.
TransferEncoding []string
- // Whether to close the connection after replying to this request.
+ // Close indicates whether to close the connection after
+ // replying to this request.
Close bool
// The host on which the URL is sought.
@@ -124,16 +125,23 @@ type Request struct {
// or the host name given in the URL itself.
Host string
- // The parsed form. Only available after ParseForm is called.
+ // Form contains the parsed form data, including both the URL
+ // field's query parameters and the POST or PUT form data.
+ // This field is only available after ParseForm is called.
+ // The HTTP client ignores Form and uses Body instead.
Form url.Values
- // The parsed multipart form, including file uploads.
- // Only available after ParseMultipartForm is called.
+ // MultipartForm is the parsed multipart form, including file uploads.
+ // This field is only available after ParseMultipartForm is called.
+ // The HTTP client ignores MultipartForm and uses Body instead.
MultipartForm *multipart.Form
// Trailer maps trailer keys to values. Like for Header, if the
// response has multiple trailer lines with the same key, they will be
// concatenated, delimited by commas.
+ // For server requests, Trailer is only populated after Body has been
+ // closed or fully consumed.
+ // Trailer support is only partially complete.
Trailer Header
// RemoteAddr allows HTTP servers and other software to record
@@ -142,14 +150,22 @@ type Request struct {
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
+ // This field is ignored by the HTTP client.
RemoteAddr string
+ // RequestURI is the unmodified Request-URI of the
+ // Request-Line (RFC 2616, Section 5.1) as sent by the client
+ // to a server. Usually the URL field should be used instead.
+ // It is an error to set this field in an HTTP client request.
+ RequestURI string
+
// TLS allows HTTP servers and other software to record
// information about the TLS connection on which the request
// was received. This field is not filled in by ReadRequest.
// The HTTP server in this package sets the field for
// TLS-enabled connections before invoking a handler;
// otherwise it leaves the field nil.
+ // This field is ignored by the HTTP client.
TLS *tls.ConnectionState
}
@@ -170,11 +186,11 @@ func (r *Request) Cookies() []*Cookie {
return readCookies(r.Header, "")
}
-var ErrNoCookie = os.NewError("http: named cookied not present")
+var ErrNoCookie = errors.New("http: named cookie 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) {
+func (r *Request) Cookie(name string) (*Cookie, error) {
for _, c := range readCookies(r.Header, name) {
return c, nil
}
@@ -218,24 +234,24 @@ 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, error) {
if r.MultipartForm == multipartByReader {
- return nil, os.NewError("http: MultipartReader called twice")
+ return nil, errors.New("http: MultipartReader called twice")
}
if r.MultipartForm != nil {
- return nil, os.NewError("http: multipart handled by ParseMultipartForm")
+ return nil, errors.New("http: multipart handled by ParseMultipartForm")
}
r.MultipartForm = multipartByReader
return r.multipartReader()
}
-func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
+func (r *Request) multipartReader() (*multipart.Reader, error) {
v := r.Header.Get("Content-Type")
if v == "" {
return nil, ErrNotMultipart
}
- d, params := mime.ParseMediaType(v)
- if d != "multipart/form-data" {
+ d, params, err := mime.ParseMediaType(v)
+ if err != nil || d != "multipart/form-data" {
return nil, ErrNotMultipart
}
boundary, ok := params["boundary"]
@@ -256,9 +272,9 @@ func valueOrDefault(value, def string) string {
const defaultUserAgent = "Go http package"
// Write writes an HTTP/1.1 request -- header and body -- in wire format.
-// This method consults the following fields of req:
+// This method consults the following fields of the request:
// Host
-// RawURL, if non-empty, or else URL
+// URL
// Method (defaults to "GET")
// Header
// ContentLength
@@ -268,44 +284,41 @@ const defaultUserAgent = "Go http package"
// If Body is present, Content-Length is <= 0 and TransferEncoding
// hasn't been set to "identity", Write adds "Transfer-Encoding:
// chunked" to the header. Body is closed after it is sent.
-func (req *Request) Write(w io.Writer) os.Error {
- return req.write(w, false)
+func (r *Request) Write(w io.Writer) error {
+ return r.write(w, false, nil)
}
// WriteProxy is like Write but writes the request in the form
-// expected by an HTTP proxy. It includes the scheme and host
-// name in the URI instead of using a separate Host: header line.
-// If req.RawURL is non-empty, WriteProxy uses it unchanged
-// instead of URL but still omits the Host: header.
-func (req *Request) WriteProxy(w io.Writer) os.Error {
- return req.write(w, true)
+// expected by an HTTP proxy. In particular, WriteProxy writes the
+// initial Request-URI line of the request with an absolute URI, per
+// section 5.1.2 of RFC 2616, including the scheme and host.
+// In either case, WriteProxy also writes a Host header, using
+// either r.Host or r.URL.Host.
+func (r *Request) WriteProxy(w io.Writer) error {
+ return r.write(w, true, nil)
}
-func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
+// extraHeaders may be nil
+func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
host := req.Host
if host == "" {
if req.URL == nil {
- return os.NewError("http: Request.Write on Request with no Host or URL set")
+ return errors.New("http: Request.Write on Request with no Host or URL set")
}
host = req.URL.Host
}
- urlStr := req.RawURL
- if urlStr == "" {
- urlStr = valueOrDefault(req.URL.EncodedPath(), "/")
- if req.URL.RawQuery != "" {
- urlStr += "?" + req.URL.RawQuery
- }
- if usingProxy {
- if urlStr == "" || urlStr[0] != '/' {
- urlStr = "/" + urlStr
- }
- urlStr = req.URL.Scheme + "://" + host + urlStr
- }
+ ruri := req.URL.RequestURI()
+ if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
+ ruri = req.URL.Scheme + "://" + host + ruri
+ } else if req.Method == "CONNECT" && req.URL.Path == "" {
+ // CONNECT requests normally give just the host and port, not a full URL.
+ ruri = host
}
+ // TODO(bradfitz): escape at least newlines in ruri?
bw := bufio.NewWriter(w)
- fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), urlStr)
+ fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
// Header lines
fmt.Fprintf(bw, "Host: %s\r\n", host)
@@ -338,6 +351,13 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
return err
}
+ if extraHeaders != nil {
+ err = extraHeaders.Write(bw)
+ if err != nil {
+ return err
+ }
+ }
+
io.WriteString(bw, "\r\n")
// Write body and trailer
@@ -345,46 +365,8 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
if err != nil {
return err
}
- bw.Flush()
- return nil
-}
-// Read a line of bytes (up to \n) from b.
-// Give up if the line exceeds maxLineLength.
-// The returned bytes are a pointer into storage in
-// the bufio, so they are only valid until the next bufio read.
-func readLineBytes(b *bufio.Reader) (p []byte, err os.Error) {
- if p, err = b.ReadSlice('\n'); err != nil {
- // We always know when EOF is coming.
- // If the caller asked for a line, there should be a line.
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- } else if err == bufio.ErrBufferFull {
- err = ErrLineTooLong
- }
- return nil, err
- }
- if len(p) >= maxLineLength {
- return nil, ErrLineTooLong
- }
-
- // Chop off trailing white space.
- var i int
- for i = len(p); i > 0; i-- {
- if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
- break
- }
- }
- return p[0:i], nil
-}
-
-// readLineBytes, but convert the bytes into a string.
-func readLine(b *bufio.Reader) (s string, err os.Error) {
- p, e := readLineBytes(b)
- if e != nil {
- return "", e
- }
- return string(p), nil
+ return bw.Flush()
}
// Convert decimal at s[i:len(s)] to integer,
@@ -422,67 +404,8 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
return major, minor, true
}
-type chunkedReader struct {
- r *bufio.Reader
- n uint64 // unread bytes in chunk
- err os.Error
-}
-
-func (cr *chunkedReader) beginChunk() {
- // chunk-size CRLF
- var line string
- line, cr.err = readLine(cr.r)
- if cr.err != nil {
- return
- }
- cr.n, cr.err = strconv.Btoui64(line, 16)
- if cr.err != nil {
- return
- }
- if cr.n == 0 {
- // trailer CRLF
- for {
- line, cr.err = readLine(cr.r)
- if cr.err != nil {
- return
- }
- if line == "" {
- break
- }
- }
- cr.err = os.EOF
- }
-}
-
-func (cr *chunkedReader) Read(b []uint8) (n int, err os.Error) {
- if cr.err != nil {
- return 0, cr.err
- }
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
- }
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- b := make([]byte, 2)
- if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
- if b[0] != '\r' || b[1] != '\n' {
- cr.err = os.NewError("malformed chunked encoding")
- }
- }
- }
- return n, cr.err
-}
-
// NewRequest returns a new Request given a method, URL, and optional body.
-func NewRequest(method, urlStr string, body io.Reader) (*Request, os.Error) {
+func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
@@ -524,7 +447,7 @@ func (r *Request) SetBasicAuth(username, password string) {
}
// ReadRequest reads and parses a request from b.
-func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
+func ReadRequest(b *bufio.Reader) (req *Request, err error) {
tp := textproto.NewReader(b)
req = new(Request)
@@ -532,26 +455,48 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
// First line: GET /index.html HTTP/1.0
var s string
if s, err = tp.ReadLine(); err != nil {
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
return nil, err
}
+ defer func() {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ }()
var f []string
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]
+ req.Method, req.RequestURI, req.Proto = f[0], f[1], f[2]
+ rawurl := req.RequestURI
var ok bool
if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
return nil, &badStringError{"malformed HTTP version", req.Proto}
}
- if req.URL, err = url.ParseRequest(req.RawURL); err != nil {
+ // CONNECT requests are used two different ways, and neither uses a full URL:
+ // The standard use is to tunnel HTTPS through an HTTP proxy.
+ // It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is
+ // just the authority section of a URL. This information should go in req.URL.Host.
+ //
+ // The net/rpc package also uses CONNECT, but there the parameter is a path
+ // that starts with a slash. It can be parsed with the regular URL parser,
+ // and the path will end up in req.URL.Path, where it needs to be in order for
+ // RPC to work.
+ justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/")
+ if justAuthority {
+ rawurl = "http://" + rawurl
+ }
+
+ if req.URL, err = url.ParseRequestURI(rawurl); err != nil {
return nil, err
}
+ if justAuthority {
+ // Strip the bogus "http://" back off.
+ req.URL.Scheme = ""
+ }
+
// Subsequent lines: Key: value.
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
@@ -608,27 +553,77 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return req, nil
}
-// ParseForm parses the raw query.
-// For POST requests, it also parses the request body as a form.
+// MaxBytesReader is similar to io.LimitReader but is intended for
+// limiting the size of incoming request bodies. In contrast to
+// io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
+// non-EOF error for a Read beyond the limit, and Closes the
+// underlying reader when its Close method is called.
+//
+// MaxBytesReader prevents clients from accidentally or maliciously
+// sending a large request and wasting server resources.
+func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
+ return &maxBytesReader{w: w, r: r, n: n}
+}
+
+type maxBytesReader struct {
+ w ResponseWriter
+ r io.ReadCloser // underlying reader
+ n int64 // max bytes remaining
+ stopped bool
+}
+
+func (l *maxBytesReader) Read(p []byte) (n int, err error) {
+ if l.n <= 0 {
+ if !l.stopped {
+ l.stopped = true
+ if res, ok := l.w.(*response); ok {
+ res.requestTooLarge()
+ }
+ }
+ return 0, errors.New("http: request body too large")
+ }
+ if int64(len(p)) > l.n {
+ p = p[:l.n]
+ }
+ n, err = l.r.Read(p)
+ l.n -= int64(n)
+ return
+}
+
+func (l *maxBytesReader) Close() error {
+ return l.r.Close()
+}
+
+// ParseForm parses the raw query from the URL.
+//
+// For POST or PUT requests, it also parses the request body as a form.
+// If the request Body's size has not already been limited by MaxBytesReader,
+// the size is capped at 10MB.
+//
// ParseMultipartForm calls ParseForm automatically.
// It is idempotent.
-func (r *Request) ParseForm() (err os.Error) {
+func (r *Request) ParseForm() (err error) {
if r.Form != nil {
return
}
-
if r.URL != nil {
r.Form, err = url.ParseQuery(r.URL.RawQuery)
}
- if r.Method == "POST" {
+ if r.Method == "POST" || r.Method == "PUT" {
if r.Body == nil {
- return os.NewError("missing form body")
+ return errors.New("missing form body")
}
ct := r.Header.Get("Content-Type")
- 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))
+ ct, _, err = mime.ParseMediaType(ct)
+ switch {
+ case ct == "application/x-www-form-urlencoded":
+ var reader io.Reader = r.Body
+ maxFormSize := int64(1<<63 - 1)
+ if _, ok := r.Body.(*maxBytesReader); !ok {
+ maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
+ reader = io.LimitReader(r.Body, maxFormSize+1)
+ }
+ b, e := ioutil.ReadAll(reader)
if e != nil {
if err == nil {
err = e
@@ -636,7 +631,7 @@ func (r *Request) ParseForm() (err os.Error) {
break
}
if int64(len(b)) > maxFormSize {
- return os.NewError("http: POST too large")
+ return errors.New("http: POST too large")
}
var newValues url.Values
newValues, e = url.ParseQuery(string(b))
@@ -652,10 +647,13 @@ func (r *Request) ParseForm() (err os.Error) {
r.Form.Add(k, value)
}
}
- case "multipart/form-data":
- // handled by ParseMultipartForm
- default:
- return &badStringError{"unknown Content-Type", ct}
+ case ct == "multipart/form-data":
+ // handled by ParseMultipartForm (which is calling us, or should be)
+ // TODO(bradfitz): there are too many possible
+ // orders to call too many functions here.
+ // Clean this up and write more tests.
+ // request_test.go contains the start of this,
+ // in TestRequestMultipartCallOrder.
}
}
return err
@@ -667,9 +665,9 @@ func (r *Request) ParseForm() (err os.Error) {
// disk in temporary files.
// ParseMultipartForm calls ParseForm if necessary.
// After one call to ParseMultipartForm, subsequent calls have no effect.
-func (r *Request) ParseMultipartForm(maxMemory int64) os.Error {
+func (r *Request) ParseMultipartForm(maxMemory int64) error {
if r.MultipartForm == multipartByReader {
- return os.NewError("http: multipart handled by MultipartReader")
+ return errors.New("http: multipart handled by MultipartReader")
}
if r.Form == nil {
err := r.ParseForm()
@@ -714,9 +712,9 @@ func (r *Request) FormValue(key string) string {
// FormFile returns the first file for the provided form key.
// FormFile calls ParseMultipartForm and ParseForm if necessary.
-func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, os.Error) {
+func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
if r.MultipartForm == multipartByReader {
- return nil, nil, os.NewError("http: multipart handled by MultipartReader")
+ return nil, nil, errors.New("http: multipart handled by MultipartReader")
}
if r.MultipartForm == nil {
err := r.ParseMultipartForm(defaultMaxMemory)
diff --git a/src/pkg/http/request_test.go b/src/pkg/net/http/request_test.go
index 869cd57b6..6e00b9bfd 100644
--- a/src/pkg/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -5,72 +5,22 @@
package http_test
import (
+ "bufio"
"bytes"
"fmt"
- . "http"
- "http/httptest"
"io"
"io/ioutil"
"mime/multipart"
+ . "net/http"
+ "net/http/httptest"
+ "net/url"
"os"
"reflect"
"regexp"
"strings"
"testing"
- "url"
)
-type stringMultimap map[string][]string
-
-type parseTest struct {
- query string
- out stringMultimap
-}
-
-var parseTests = []parseTest{
- {
- query: "a=1&b=2",
- out: stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
- },
- {
- query: "a=1&a=2&a=banana",
- out: stringMultimap{"a": []string{"1", "2", "banana"}},
- },
- {
- query: "ascii=%3Ckey%3A+0x90%3E",
- out: stringMultimap{"ascii": []string{"<key: 0x90>"}},
- },
-}
-
-func TestParseForm(t *testing.T) {
- for i, test := range parseTests {
- form, err := url.ParseQuery(test.query)
- if err != nil {
- t.Errorf("test %d: Unexpected error: %v", i, err)
- continue
- }
- if len(form) != len(test.out) {
- t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
- }
- for k, evs := range test.out {
- vs, ok := form[k]
- if !ok {
- t.Errorf("test %d: Missing key %q", i, k)
- continue
- }
- if len(vs) != len(evs) {
- t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
- continue
- }
- for j, ev := range evs {
- if v := vs[j]; v != ev {
- t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
- }
- }
- }
- }
-}
-
func TestQuery(t *testing.T) {
req := &Request{Method: "GET"}
req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
@@ -80,12 +30,10 @@ func TestQuery(t *testing.T) {
}
func TestPostQuery(t *testing.T) {
- req := &Request{Method: "POST"}
- 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!"},
- }
- req.Body = ioutil.NopCloser(strings.NewReader("z=post&both=y"))
+ req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x",
+ strings.NewReader("z=post&both=y"))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
if q := req.FormValue("q"); q != "foo" {
t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
}
@@ -99,21 +47,19 @@ func TestPostQuery(t *testing.T) {
type stringMap map[string][]string
type parseContentTypeTest struct {
+ shouldError bool
contentType stringMap
- error bool
}
var parseContentTypeTests = []parseContentTypeTest{
- {contentType: stringMap{"Content-Type": {"text/plain"}}},
- {contentType: stringMap{}}, // Non-existent keys are not placed. The value nil is illegal.
- {contentType: stringMap{"Content-Type": {"text/plain; boundary="}}},
- {
- contentType: stringMap{"Content-Type": {"application/unknown"}},
- error: true,
- },
+ {false, stringMap{"Content-Type": {"text/plain"}}},
+ // Non-existent keys are not placed. The value nil is illegal.
+ {true, stringMap{}},
+ {true, stringMap{"Content-Type": {"text/plain; boundary="}}},
+ {false, stringMap{"Content-Type": {"application/unknown"}}},
}
-func TestPostContentTypeParsing(t *testing.T) {
+func TestParseFormUnknownContentType(t *testing.T) {
for i, test := range parseContentTypeTests {
req := &Request{
Method: "POST",
@@ -121,11 +67,11 @@ func TestPostContentTypeParsing(t *testing.T) {
Body: ioutil.NopCloser(bytes.NewBufferString("body")),
}
err := req.ParseForm()
- if !test.error && err != nil {
- t.Errorf("test %d: Unexpected error: %v", i, err)
- }
- if test.error && err == nil {
+ switch {
+ case err == nil && test.shouldError:
t.Errorf("test %d should have returned error", i)
+ case err != nil && !test.shouldError:
+ t.Errorf("test %d should not have returned error, got %v", i, err)
}
}
}
@@ -232,6 +178,24 @@ func TestRequestMultipartCallOrder(t *testing.T) {
}
}
+var readRequestErrorTests = []struct {
+ in string
+ err error
+}{
+ {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
+ {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
+ {"", io.EOF},
+}
+
+func TestReadRequestErrors(t *testing.T) {
+ for i, tt := range readRequestErrorTests {
+ _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err != tt.err {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
@@ -260,8 +224,8 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
if g, e := req.FormValue("texta"), textaValue; g != e {
t.Errorf("texta value = %q, want %q", g, e)
}
- if g, e := req.FormValue("texta"), textaValue; g != e {
- t.Errorf("texta value = %q, want %q", g, e)
+ if g, e := req.FormValue("textb"), textbValue; g != e {
+ t.Errorf("textb value = %q, want %q", g, e)
}
if g := req.FormValue("missing"); g != "" {
t.Errorf("missing value = %q, want empty string", g)
@@ -272,14 +236,16 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
t.Error(n, " is *os.File, should not be")
}
}
- fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
- assertMem("filea", fd)
- fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+ fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
+ defer fda.Close()
+ assertMem("filea", fda)
+ fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+ defer fdb.Close()
if allMem {
- assertMem("fileb", fd)
+ assertMem("fileb", fdb)
} else {
- if _, ok := fd.(*os.File); !ok {
- t.Errorf("fileb has unexpected underlying type %T", fd)
+ if _, ok := fdb.(*os.File); !ok {
+ t.Errorf("fileb has unexpected underlying type %T", fdb)
}
}
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/net/http/requestwrite_test.go
index 458f0bd7f..fc3186f0c 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -6,38 +6,35 @@ package http
import (
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
- "os"
+ "net/url"
"strings"
"testing"
- "url"
)
type reqWriteTest struct {
- Req Request
- Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
- Raw string
- RawProxy string
+ Req Request
+ Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
+
+ // Any of these three may be empty to skip that test.
+ WantWrite string // Request.Write
+ WantProxy string // Request.WriteProxy
+
+ WantError error // wanted error from Request.Write
}
var reqWriteTests = []reqWriteTest{
// HTTP/1.1 => chunked coding; no body; no trailer
{
- Request{
+ Req: Request{
Method: "GET",
- RawURL: "http://www.techcrunch.com/",
URL: &url.URL{
- Raw: "http://www.techcrunch.com/",
- Scheme: "http",
- RawPath: "http://www.techcrunch.com/",
- RawAuthority: "www.techcrunch.com",
- RawUserinfo: "",
- Host: "www.techcrunch.com",
- Path: "/",
- RawQuery: "",
- Fragment: "",
+ Scheme: "http",
+ Host: "www.techcrunch.com",
+ Path: "/",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
@@ -57,9 +54,7 @@ var reqWriteTests = []reqWriteTest{
Form: map[string][]string{},
},
- nil,
-
- "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ WantWrite: "GET / 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" +
@@ -69,7 +64,7 @@ var reqWriteTests = []reqWriteTest{
"Keep-Alive: 300\r\n" +
"Proxy-Connection: keep-alive\r\n\r\n",
- "GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
+ WantProxy: "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" +
@@ -81,7 +76,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 => chunked coding; body; empty trailer
{
- Request{
+ Req: Request{
Method: "GET",
URL: &url.URL{
Scheme: "http",
@@ -94,15 +89,15 @@ var reqWriteTests = []reqWriteTest{
TransferEncoding: []string{"chunked"},
},
- []byte("abcdef"),
+ Body: []byte("abcdef"),
- "GET /search HTTP/1.1\r\n" +
+ WantWrite: "GET /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
- "GET http://www.google.com/search HTTP/1.1\r\n" +
+ WantProxy: "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" +
@@ -110,7 +105,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 POST => chunked coding; body; empty trailer
{
- Request{
+ Req: Request{
Method: "POST",
URL: &url.URL{
Scheme: "http",
@@ -124,16 +119,16 @@ var reqWriteTests = []reqWriteTest{
TransferEncoding: []string{"chunked"},
},
- []byte("abcdef"),
+ Body: []byte("abcdef"),
- "POST /search HTTP/1.1\r\n" +
+ WantWrite: "POST /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"Connection: close\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
- "POST http://www.google.com/search HTTP/1.1\r\n" +
+ WantProxy: "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" +
@@ -143,7 +138,7 @@ var reqWriteTests = []reqWriteTest{
// HTTP/1.1 POST with Content-Length, no chunking
{
- Request{
+ Req: Request{
Method: "POST",
URL: &url.URL{
Scheme: "http",
@@ -157,9 +152,9 @@ var reqWriteTests = []reqWriteTest{
ContentLength: 6,
},
- []byte("abcdef"),
+ Body: []byte("abcdef"),
- "POST /search HTTP/1.1\r\n" +
+ WantWrite: "POST /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"Connection: close\r\n" +
@@ -167,7 +162,7 @@ var reqWriteTests = []reqWriteTest{
"\r\n" +
"abcdef",
- "POST http://www.google.com/search HTTP/1.1\r\n" +
+ WantProxy: "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" +
@@ -178,9 +173,9 @@ var reqWriteTests = []reqWriteTest{
// HTTP/1.1 POST with Content-Length in headers
{
- Request{
+ Req: Request{
Method: "POST",
- RawURL: "http://example.com/",
+ URL: mustParseURL("http://example.com/"),
Host: "example.com",
Header: Header{
"Content-Length": []string{"10"}, // ignored
@@ -188,16 +183,16 @@ var reqWriteTests = []reqWriteTest{
ContentLength: 6,
},
- []byte("abcdef"),
+ Body: []byte("abcdef"),
- "POST http://example.com/ HTTP/1.1\r\n" +
+ WantWrite: "POST / 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" +
+ WantProxy: "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" +
@@ -207,21 +202,13 @@ var reqWriteTests = []reqWriteTest{
// default to HTTP/1.1
{
- Request{
+ Req: Request{
Method: "GET",
- RawURL: "/search",
+ URL: mustParseURL("/search"),
Host: "www.google.com",
},
- nil,
-
- "GET /search HTTP/1.1\r\n" +
- "Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
- "\r\n",
-
- // Looks weird but RawURL overrides what WriteProxy would choose.
- "GET /search HTTP/1.1\r\n" +
+ WantWrite: "GET /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"\r\n",
@@ -229,53 +216,118 @@ var reqWriteTests = []reqWriteTest{
// Request with a 0 ContentLength and a 0 byte body.
{
- Request{
+ Req: Request{
Method: "POST",
- RawURL: "/",
+ URL: mustParseURL("/"),
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)) },
+ Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
- "POST / HTTP/1.1\r\n" +
+ // RFC 2616 Section 14.13 says Content-Length should be specified
+ // unless body is prohibited by the request method.
+ // Also, nginx expects it for POST and PUT.
+ WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"User-Agent: Go http package\r\n" +
+ "Content-Length: 0\r\n" +
"\r\n",
- "POST / HTTP/1.1\r\n" +
+ WantProxy: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"User-Agent: Go http package\r\n" +
+ "Content-Length: 0\r\n" +
"\r\n",
},
// Request with a 0 ContentLength and a 1 byte body.
{
- Request{
+ Req: Request{
Method: "POST",
- RawURL: "/",
+ URL: mustParseURL("/"),
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)) },
+ Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) },
- "POST / HTTP/1.1\r\n" +
+ WantWrite: "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" +
+ WantProxy: "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(""),
},
+
+ // Request with a ContentLength of 10 but a 5 byte body.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 10, // but we're going to send only 5 bytes
+ },
+ Body: []byte("12345"),
+ WantError: errors.New("http: Request.ContentLength=10 with Body length 5"),
+ },
+
+ // Request with a ContentLength of 4 but an 8 byte body.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 4, // but we're going to try to send 8 bytes
+ },
+ Body: []byte("12345678"),
+ WantError: errors.New("http: Request.ContentLength=4 with Body length 8"),
+ },
+
+ // Request with a 5 ContentLength and nil body.
+ {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 5, // but we'll omit the body
+ },
+ WantError: errors.New("http: Request.ContentLength=5 with nil Body"),
+ },
+
+ // Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
+ // and doesn't add a User-Agent.
+ {
+ Req: Request{
+ Method: "GET",
+ URL: mustParseURL("/foo"),
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Header: Header{
+ "X-Foo": []string{"X-Bar"},
+ },
+ },
+
+ WantWrite: "GET /foo HTTP/1.1\r\n" +
+ "Host: \r\n" +
+ "User-Agent: Go http package\r\n" +
+ "X-Foo: X-Bar\r\n\r\n",
+ },
}
func TestRequestWrite(t *testing.T) {
@@ -283,6 +335,9 @@ func TestRequestWrite(t *testing.T) {
tt := &reqWriteTests[i]
setBody := func() {
+ if tt.Body == nil {
+ return
+ }
switch b := tt.Body.(type) {
case []byte:
tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
@@ -290,37 +345,42 @@ func TestRequestWrite(t *testing.T) {
tt.Req.Body = b()
}
}
- if tt.Body != nil {
- setBody()
- }
+ setBody()
if tt.Req.Header == nil {
tt.Req.Header = make(Header)
}
+
var braw bytes.Buffer
err := tt.Req.Write(&braw)
- if err != nil {
- t.Errorf("error writing #%d: %s", i, err)
+ if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.WantError); g != e {
+ t.Errorf("writing #%d, err = %q, want %q", i, g, e)
continue
}
- sraw := braw.String()
- if sraw != tt.Raw {
- t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, sraw)
+ if err != nil {
continue
}
- if tt.Body != nil {
- setBody()
- }
- var praw bytes.Buffer
- err = tt.Req.WriteProxy(&praw)
- if err != nil {
- t.Errorf("error writing #%d: %s", i, err)
- continue
+ if tt.WantWrite != "" {
+ sraw := braw.String()
+ if sraw != tt.WantWrite {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantWrite, sraw)
+ continue
+ }
}
- sraw = praw.String()
- if sraw != tt.RawProxy {
- t.Errorf("Test Proxy %d, expecting:\n%s\nGot:\n%s\n", i, tt.RawProxy, sraw)
- continue
+
+ if tt.WantProxy != "" {
+ setBody()
+ var praw bytes.Buffer
+ err = tt.Req.WriteProxy(&praw)
+ if err != nil {
+ t.Errorf("WriteProxy #%d: %s", i, err)
+ continue
+ }
+ sraw := praw.String()
+ if sraw != tt.WantProxy {
+ t.Errorf("Test Proxy %d, expecting:\n%s\nGot:\n%s\n", i, tt.WantProxy, sraw)
+ continue
+ }
}
}
}
@@ -330,7 +390,7 @@ type closeChecker struct {
closed bool
}
-func (rc *closeChecker) Close() os.Error {
+func (rc *closeChecker) Close() error {
rc.closed = true
return nil
}
@@ -368,3 +428,11 @@ func TestRequestWriteClosesBody(t *testing.T) {
func chunk(s string) string {
return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
}
+
+func mustParseURL(s string) *url.URL {
+ u, err := url.Parse(s)
+ if err != nil {
+ panic(fmt.Sprintf("Error parsing URL %q: %v", s, err))
+ }
+ return u
+}
diff --git a/src/pkg/http/response.go b/src/pkg/net/http/response.go
index 915327a69..b79022097 100644
--- a/src/pkg/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -8,9 +8,10 @@ package http
import (
"bufio"
+ "errors"
"io"
"net/textproto"
- "os"
+ "net/url"
"strconv"
"strings"
)
@@ -41,6 +42,10 @@ type Response struct {
Header Header
// Body represents the response body.
+ //
+ // The http Client and Transport guarantee that Body is always
+ // non-nil, even on responses without a body or responses with
+ // a zero-lengthed body.
Body io.ReadCloser
// ContentLength records the length of the associated content. The
@@ -73,13 +78,30 @@ func (r *Response) Cookies() []*Cookie {
return readSetCookies(r.Header)
}
+var ErrNoLocation = errors.New("http: no Location header in response")
+
+// Location returns the URL of the response's "Location" header,
+// if present. Relative redirects are resolved relative to
+// the Response's Request. ErrNoLocation is returned if no
+// Location header is present.
+func (r *Response) Location() (*url.URL, error) {
+ lv := r.Header.Get("Location")
+ if lv == "" {
+ return nil, ErrNoLocation
+ }
+ if r.Request != nil && r.Request.URL != nil {
+ return r.Request.URL.Parse(lv)
+ }
+ return url.Parse(lv)
+}
+
// 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) {
+func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err error) {
tp := textproto.NewReader(r)
resp = new(Response)
@@ -90,7 +112,7 @@ func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err os.Error)
// Parse the first line of the response.
line, err := tp.ReadLine()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
@@ -152,7 +174,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
}
// Writes the response (header, body and trailer) in wire format. This method
-// consults the following fields of resp:
+// consults the following fields of the response:
//
// StatusCode
// ProtoMajor
@@ -164,28 +186,28 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
// ContentLength
// Header, values for non-canonical keys will have unpredictable behavior
//
-func (resp *Response) Write(w io.Writer) os.Error {
+func (r *Response) Write(w io.Writer) error {
// RequestMethod should be upper-case
- if resp.Request != nil {
- resp.Request.Method = strings.ToUpper(resp.Request.Method)
+ if r.Request != nil {
+ r.Request.Method = strings.ToUpper(r.Request.Method)
}
// Status line
- text := resp.Status
+ text := r.Status
if text == "" {
var ok bool
- text, ok = statusText[resp.StatusCode]
+ text, ok = statusText[r.StatusCode]
if !ok {
- text = "status code " + strconv.Itoa(resp.StatusCode)
+ text = "status code " + strconv.Itoa(r.StatusCode)
}
}
- io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
- io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
- io.WriteString(w, strconv.Itoa(resp.StatusCode)+" "+text+"\r\n")
+ io.WriteString(w, "HTTP/"+strconv.Itoa(r.ProtoMajor)+".")
+ io.WriteString(w, strconv.Itoa(r.ProtoMinor)+" ")
+ io.WriteString(w, strconv.Itoa(r.StatusCode)+" "+text+"\r\n")
// Process Body,ContentLength,Close,Trailer
- tw, err := newTransferWriter(resp)
+ tw, err := newTransferWriter(r)
if err != nil {
return err
}
@@ -195,7 +217,7 @@ func (resp *Response) Write(w io.Writer) os.Error {
}
// Rest of header
- err = resp.Header.WriteSubset(w, respExcludeHeader)
+ err = r.Header.WriteSubset(w, respExcludeHeader)
if err != nil {
return err
}
diff --git a/src/pkg/http/response_test.go b/src/pkg/net/http/response_test.go
index 1d4a23423..165ec3624 100644
--- a/src/pkg/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -10,9 +10,9 @@ import (
"compress/gzip"
"crypto/rand"
"fmt"
- "os"
"io"
"io/ioutil"
+ "net/url"
"reflect"
"testing"
)
@@ -65,6 +65,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Request: dummyReq("GET"),
Close: true,
ContentLength: -1,
@@ -85,6 +86,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Request: dummyReq("GET"),
Close: false,
ContentLength: 0,
@@ -300,7 +302,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
args = append([]interface{}{test.chunked, test.compressed}, args...)
t.Fatalf("on test chunked=%v, compressed=%v: "+format, args...)
}
- checkErr := func(err os.Error, msg string) {
+ checkErr := func(err error, msg string) {
if err == nil {
return
}
@@ -315,13 +317,11 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
}
var wr io.Writer = &buf
if test.chunked {
- wr = &chunkedWriter{wr}
+ wr = newChunkedWriter(wr)
}
if test.compressed {
buf.WriteString("Content-Encoding: gzip\r\n")
- var err os.Error
- wr, err = gzip.NewWriter(wr)
- checkErr(err, "gzip.NewWriter")
+ wr = gzip.NewWriter(wr)
}
buf.WriteString("\r\n")
@@ -335,7 +335,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
wr.Write(chunk)
}
if test.compressed {
- err := wr.(*gzip.Compressor).Close()
+ err := wr.(*gzip.Writer).Close()
checkErr(err, "compressor close")
}
if test.chunked {
@@ -395,3 +395,52 @@ func diff(t *testing.T, prefix string, have, want interface{}) {
}
}
}
+
+type responseLocationTest struct {
+ location string // Response's Location header or ""
+ requrl string // Response.Request.URL or ""
+ want string
+ wantErr error
+}
+
+var responseLocationTests = []responseLocationTest{
+ {"/foo", "http://bar.com/baz", "http://bar.com/foo", nil},
+ {"http://foo.com/", "http://bar.com/baz", "http://foo.com/", nil},
+ {"", "http://bar.com/baz", "", ErrNoLocation},
+}
+
+func TestLocationResponse(t *testing.T) {
+ for i, tt := range responseLocationTests {
+ res := new(Response)
+ res.Header = make(Header)
+ res.Header.Set("Location", tt.location)
+ if tt.requrl != "" {
+ res.Request = &Request{}
+ var err error
+ res.Request.URL, err = url.Parse(tt.requrl)
+ if err != nil {
+ t.Fatalf("bad test URL %q: %v", tt.requrl, err)
+ }
+ }
+
+ got, err := res.Location()
+ if tt.wantErr != nil {
+ if err == nil {
+ t.Errorf("%d. err=nil; want %q", i, tt.wantErr)
+ continue
+ }
+ if g, e := err.Error(), tt.wantErr.Error(); g != e {
+ t.Errorf("%d. err=%q; want %q", i, g, e)
+ continue
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%d. err=%q", i, err)
+ continue
+ }
+ if g, e := got.String(), tt.want; g != e {
+ t.Errorf("%d. Location=%q; want %q", i, g, e)
+ }
+ }
+}
diff --git a/src/pkg/http/responsewrite_test.go b/src/pkg/net/http/responsewrite_test.go
index f8e63acf4..f8e63acf4 100644
--- a/src/pkg/http/responsewrite_test.go
+++ b/src/pkg/net/http/responsewrite_test.go
diff --git a/src/pkg/http/serve_test.go b/src/pkg/net/http/serve_test.go
index ac0403345..b6a6b4c77 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -9,20 +9,22 @@ package http_test
import (
"bufio"
"bytes"
+ "crypto/tls"
"fmt"
- . "http"
- "http/httptest"
"io"
"io/ioutil"
"log"
- "os"
"net"
+ . "net/http"
+ "net/http/httptest"
+ "net/http/httputil"
+ "net/url"
+ "os"
"reflect"
"strings"
"syscall"
"testing"
"time"
- "url"
)
type dummyAddr string
@@ -30,10 +32,10 @@ type oneConnListener struct {
conn net.Conn
}
-func (l *oneConnListener) Accept() (c net.Conn, err os.Error) {
+func (l *oneConnListener) Accept() (c net.Conn, err error) {
c = l.conn
if c == nil {
- err = os.EOF
+ err = io.EOF
return
}
err = nil
@@ -41,7 +43,7 @@ func (l *oneConnListener) Accept() (c net.Conn, err os.Error) {
return
}
-func (l *oneConnListener) Close() os.Error {
+func (l *oneConnListener) Close() error {
return nil
}
@@ -62,15 +64,15 @@ type testConn struct {
writeBuf bytes.Buffer
}
-func (c *testConn) Read(b []byte) (int, os.Error) {
+func (c *testConn) Read(b []byte) (int, error) {
return c.readBuf.Read(b)
}
-func (c *testConn) Write(b []byte) (int, os.Error) {
+func (c *testConn) Write(b []byte) (int, error) {
return c.writeBuf.Write(b)
}
-func (c *testConn) Close() os.Error {
+func (c *testConn) Close() error {
return nil
}
@@ -82,15 +84,15 @@ func (c *testConn) RemoteAddr() net.Addr {
return dummyAddr("remote-addr")
}
-func (c *testConn) SetTimeout(nsec int64) os.Error {
+func (c *testConn) SetDeadline(t time.Time) error {
return nil
}
-func (c *testConn) SetReadTimeout(nsec int64) os.Error {
+func (c *testConn) SetReadDeadline(t time.Time) error {
return nil
}
-func (c *testConn) SetWriteTimeout(nsec int64) os.Error {
+func (c *testConn) SetWriteDeadline(t time.Time) error {
return nil
}
@@ -107,7 +109,7 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
reqNum := 0
ch := make(chan *Request)
- servech := make(chan os.Error)
+ servech := make(chan error)
listener := &oneConnListener{conn}
handler := func(res ResponseWriter, req *Request) {
reqNum++
@@ -137,7 +139,7 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
req.Method, "POST")
}
- if serveerr := <-servech; serveerr != os.EOF {
+ if serveerr := <-servech; serveerr != io.EOF {
t.Errorf("Serve returned %q; expected EOF", serveerr)
}
}
@@ -180,7 +182,7 @@ func TestHostHandlers(t *testing.T) {
t.Fatal(err)
}
defer conn.Close()
- cc := NewClientConn(conn, nil)
+ cc := httputil.NewClientConn(conn, nil)
for _, vt := range vtests {
var r *Response
var req Request
@@ -243,8 +245,7 @@ func TestServerTimeouts(t *testing.T) {
fmt.Fprintf(res, "req=%d", reqNum)
})
- const second = 1000000000 /* nanos */
- server := &Server{Handler: handler, ReadTimeout: 0.25 * second, WriteTimeout: 0.25 * second}
+ server := &Server{Handler: handler, ReadTimeout: 250 * time.Millisecond, WriteTimeout: 250 * time.Millisecond}
go server.Serve(l)
url := fmt.Sprintf("http://%s/", addr)
@@ -264,19 +265,19 @@ func TestServerTimeouts(t *testing.T) {
}
// Slow client that should timeout.
- t1 := time.Nanoseconds()
+ t1 := time.Now()
conn, err := net.Dial("tcp", addr.String())
if err != nil {
t.Fatalf("Dial: %v", err)
}
buf := make([]byte, 1)
n, err := conn.Read(buf)
- latency := time.Nanoseconds() - t1
- if n != 0 || err != os.EOF {
- t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, os.EOF)
+ latency := time.Now().Sub(t1)
+ if n != 0 || err != io.EOF {
+ t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
}
- if latency < second*0.20 /* fudge from 0.25 above */ {
- t.Errorf("got EOF after %d ns, want >= %d", latency, second*0.20)
+ if latency < 200*time.Millisecond /* fudge from 250 ms above */ {
+ t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
}
// Hit the HTTP server successfully again, verifying that the
@@ -356,18 +357,17 @@ func TestIdentityResponse(t *testing.T) {
if err != nil {
t.Fatalf("error writing: %v", err)
}
- // The next ReadAll will hang for a failing test, so use a Timer instead
- // to fail more traditionally
- timer := time.AfterFunc(2e9, func() {
- t.Fatalf("Timeout expired in ReadAll.")
+
+ // The ReadAll will hang for a failing test, so use a Timer to
+ // fail explicitly.
+ goTimeout(t, 2*time.Second, func() {
+ got, _ := ioutil.ReadAll(conn)
+ expectedSuffix := "\r\n\r\ntoo short"
+ if !strings.HasSuffix(string(got), expectedSuffix) {
+ t.Errorf("Expected output to end with %q; got response body %q",
+ expectedSuffix, string(got))
+ }
})
- defer timer.Stop()
- got, _ := ioutil.ReadAll(conn)
- expectedSuffix := "\r\n\r\ntoo short"
- if !strings.HasSuffix(string(got), expectedSuffix) {
- t.Fatalf("Expected output to end with %q; got response body %q",
- expectedSuffix, string(got))
- }
}
func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
@@ -394,7 +394,7 @@ func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
success := make(chan bool)
go func() {
select {
- case <-time.After(5e9):
+ case <-time.After(5 * time.Second):
t.Fatal("body not closed after 5s")
case <-success:
}
@@ -503,8 +503,9 @@ func Test304Responses(t *testing.T) {
}
// TestHeadResponses verifies that responses to HEAD requests don't
-// declare that they're chunking in their response headers and aren't
-// allowed to produce output.
+// declare that they're chunking in their response headers, aren't
+// allowed to produce output, and don't set a Content-Type since
+// the real type of the body data cannot be inferred.
func TestHeadResponses(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := w.Write([]byte("Ignored body"))
@@ -526,6 +527,10 @@ func TestHeadResponses(t *testing.T) {
if len(res.TransferEncoding) > 0 {
t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
}
+ ct := res.Header.Get("Content-Type")
+ if ct != "" {
+ t.Errorf("expected no Content-Type; got %s", ct)
+ }
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
@@ -535,6 +540,25 @@ func TestHeadResponses(t *testing.T) {
}
}
+func TestTLSHandshakeTimeout(t *testing.T) {
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ ts.Config.ReadTimeout = 250 * time.Millisecond
+ ts.StartTLS()
+ defer ts.Close()
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer conn.Close()
+ goTimeout(t, 10*time.Second, func() {
+ var buf [1]byte
+ n, err := conn.Read(buf[:])
+ if err == nil || n != 0 {
+ t.Errorf("Read = %d, %v; want an error and no bytes", n, err)
+ }
+ })
+}
+
func TestTLSServer(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS != nil {
@@ -545,23 +569,46 @@ func TestTLSServer(t *testing.T) {
}
}))
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)
+
+ // Connect an idle TCP connection to this server before we run
+ // our real tests. This idle connection used to block forever
+ // in the TLS handshake, preventing future connections from
+ // being accepted. It may prevent future accidental blocking
+ // in newConn.
+ idleConn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil {
- t.Fatal(err)
- }
- if res == nil {
- t.Fatalf("got nil Response")
- }
- defer res.Body.Close()
- if res.Header.Get("X-TLS-Set") != "true" {
- t.Errorf("expected X-TLS-Set response header")
- }
- if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
- t.Errorf("expected X-TLS-HandshakeComplete header")
+ t.Fatalf("Dial: %v", err)
}
+ defer idleConn.Close()
+ goTimeout(t, 10*time.Second, func() {
+ if !strings.HasPrefix(ts.URL, "https://") {
+ t.Errorf("expected test TLS server to start with https://, got %q", ts.URL)
+ return
+ }
+ noVerifyTransport := &Transport{
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ },
+ }
+ client := &Client{Transport: noVerifyTransport}
+ res, err := client.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if res == nil {
+ t.Errorf("got nil Response")
+ return
+ }
+ defer res.Body.Close()
+ if res.Header.Get("X-TLS-Set") != "true" {
+ t.Errorf("expected X-TLS-Set response header")
+ return
+ }
+ if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
+ t.Errorf("expected X-TLS-HandshakeComplete header")
+ }
+ })
}
type serverExpectTest struct {
@@ -599,7 +646,7 @@ func TestServerExpect(t *testing.T) {
// Note using r.FormValue("readbody") because for POST
// requests that would read from r.Body, which we only
// conditionally want to do.
- if strings.Contains(r.URL.RawPath, "readbody=true") {
+ if strings.Contains(r.URL.RawQuery, "readbody=true") {
ioutil.ReadAll(r.Body)
w.Write([]byte("Hi"))
} else {
@@ -646,9 +693,11 @@ func TestServerExpect(t *testing.T) {
}
}
-func TestServerConsumesRequestBody(t *testing.T) {
+// Under a ~256KB (maxPostHandlerReadBytes) threshold, the server
+// should consume client request bodies that a handler didn't read.
+func TestServerUnreadRequestBodyLittle(t *testing.T) {
conn := new(testConn)
- body := strings.Repeat("x", 1<<20)
+ body := strings.Repeat("x", 100<<10)
conn.readBuf.Write([]byte(fmt.Sprintf(
"POST / HTTP/1.1\r\n"+
"Host: test\r\n"+
@@ -660,27 +709,62 @@ func TestServerConsumesRequestBody(t *testing.T) {
ls := &oneConnListener{conn}
go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+ defer close(done)
if conn.readBuf.Len() < len(body)/2 {
- t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
+ t.Errorf("on request, read buffer length is %d; expected about 100 KB", conn.readBuf.Len())
}
rw.WriteHeader(200)
if g, e := conn.readBuf.Len(), 0; g != e {
t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e)
}
- done <- true
+ if c := rw.Header().Get("Connection"); c != "" {
+ t.Errorf(`Connection header = %q; want ""`, c)
+ }
+ }))
+ <-done
+}
+
+// Over a ~256KB (maxPostHandlerReadBytes) threshold, the server
+// should ignore client request bodies that a handler didn't read
+// and close the connection.
+func TestServerUnreadRequestBodyLarge(t *testing.T) {
+ conn := new(testConn)
+ body := strings.Repeat("x", 1<<20)
+ conn.readBuf.Write([]byte(fmt.Sprintf(
+ "POST / HTTP/1.1\r\n"+
+ "Host: test\r\n"+
+ "Content-Length: %d\r\n"+
+ "\r\n", len(body))))
+ conn.readBuf.Write([]byte(body))
+
+ done := make(chan bool)
+
+ ls := &oneConnListener{conn}
+ go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+ defer close(done)
+ if conn.readBuf.Len() < len(body)/2 {
+ t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
+ }
+ rw.WriteHeader(200)
+ if conn.readBuf.Len() < len(body)/2 {
+ t.Errorf("post-WriteHeader, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
+ }
+ if c := rw.Header().Get("Connection"); c != "close" {
+ t.Errorf(`Connection header = %q; want "close"`, c)
+ }
}))
<-done
}
func TestTimeoutHandler(t *testing.T) {
sendHi := make(chan bool, 1)
- writeErrors := make(chan os.Error, 1)
+ writeErrors := make(chan error, 1)
sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
<-sendHi
_, werr := w.Write([]byte("hi"))
writeErrors <- werr
})
- timeout := make(chan int64, 1) // write to this to force timeouts
+ timeout := make(chan time.Time, 1) // write to this to force timeouts
ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
defer ts.Close()
@@ -702,7 +786,7 @@ func TestTimeoutHandler(t *testing.T) {
}
// Times out:
- timeout <- 1
+ timeout <- time.Time{}
res, err = Get(ts.URL)
if err != nil {
t.Error(err)
@@ -745,7 +829,7 @@ func TestRedirectMunging(t *testing.T) {
// 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.
+// as the client would then see http.ErrBodyReadAfterClose and not 0, io.EOF.
func TestZeroLengthPostAndResponse(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
all, err := ioutil.ReadAll(r.Body)
@@ -785,6 +869,14 @@ func TestZeroLengthPostAndResponse(t *testing.T) {
}
func TestHandlerPanic(t *testing.T) {
+ testHandlerPanic(t, false)
+}
+
+func TestHandlerPanicWithHijack(t *testing.T) {
+ testHandlerPanic(t, true)
+}
+
+func testHandlerPanic(t *testing.T, withHijack bool) {
// 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:
@@ -805,21 +897,24 @@ func TestHandlerPanic(t *testing.T) {
log.SetOutput(pw)
defer log.SetOutput(os.Stderr)
- ts := httptest.NewServer(HandlerFunc(func(ResponseWriter, *Request) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if withHijack {
+ rwc, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Logf("unexpected error: %v", err)
+ }
+ defer rwc.Close()
+ }
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)
+ done := make(chan bool, 1)
go func() {
- buf := make([]byte, 1024)
+ buf := make([]byte, 4<<10)
_, err := pr.Read(buf)
pr.Close()
if err != nil {
@@ -827,10 +922,16 @@ func TestHandlerPanic(t *testing.T) {
}
done <- true
}()
+
+ _, err := Get(ts.URL)
+ if err == nil {
+ t.Logf("expected an error")
+ }
+
select {
case <-done:
return
- case <-time.After(5e9):
+ case <-time.After(5 * time.Second):
t.Fatal("expected server handler to log an error")
}
}
@@ -891,25 +992,151 @@ func TestRequestLimit(t *testing.T) {
// 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)
+ if res.StatusCode != 413 {
+ t.Fatalf("expected 413 response status; got: %d %s", res.StatusCode, res.Status)
+ }
+}
+
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (n int, err error) {
+ for i := range p {
+ p[i] = byte(b)
+ }
+ return len(p), nil
+}
+
+type countReader struct {
+ r io.Reader
+ n *int64
+}
+
+func (cr countReader) Read(p []byte) (n int, err error) {
+ n, err = cr.r.Read(p)
+ *cr.n += int64(n)
+ return
+}
+
+func TestRequestBodyLimit(t *testing.T) {
+ const limit = 1 << 20
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ r.Body = MaxBytesReader(w, r.Body, limit)
+ n, err := io.Copy(ioutil.Discard, r.Body)
+ if err == nil {
+ t.Errorf("expected error from io.Copy")
+ }
+ if n != limit {
+ t.Errorf("io.Copy = %d, want %d", n, limit)
+ }
+ }))
+ defer ts.Close()
+
+ nWritten := int64(0)
+ req, _ := NewRequest("POST", ts.URL, io.LimitReader(countReader{neverEnding('a'), &nWritten}, limit*200))
+
+ // Send the POST, but don't care it succeeds or not. The
+ // remote side is going to reply and then close the TCP
+ // connection, and HTTP doesn't really define if that's
+ // allowed or not. Some HTTP clients will get the response
+ // and some (like ours, currently) will complain that the
+ // request write failed, without reading the response.
+ //
+ // But that's okay, since what we're really testing is that
+ // the remote side hung up on us before we wrote too much.
+ _, _ = DefaultClient.Do(req)
+
+ if nWritten > limit*100 {
+ t.Errorf("handler restricted the request body to %d bytes, but client managed to write %d",
+ limit, nWritten)
}
}
+// TestClientWriteShutdown tests that if the client shuts down the write
+// side of their TCP connection, the server doesn't send a 400 Bad Request.
+func TestClientWriteShutdown(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ defer ts.Close()
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ err = conn.(*net.TCPConn).CloseWrite()
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ donec := make(chan bool)
+ go func() {
+ defer close(donec)
+ bs, err := ioutil.ReadAll(conn)
+ if err != nil {
+ t.Fatalf("ReadAll: %v", err)
+ }
+ got := string(bs)
+ if got != "" {
+ t.Errorf("read %q from server; want nothing", got)
+ }
+ }()
+ select {
+ case <-donec:
+ case <-time.After(10 * time.Second):
+ t.Fatalf("timeout")
+ }
+}
+
+// Tests that chunked server responses that write 1 byte at a time are
+// buffered before chunk headers are added, not after chunk headers.
+func TestServerBufferedChunking(t *testing.T) {
+ if true {
+ t.Logf("Skipping known broken test; see Issue 2357")
+ return
+ }
+ conn := new(testConn)
+ conn.readBuf.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
+ done := make(chan bool)
+ ls := &oneConnListener{conn}
+ go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+ defer close(done)
+ rw.Header().Set("Content-Type", "text/plain") // prevent sniffing, which buffers
+ rw.Write([]byte{'x'})
+ rw.Write([]byte{'y'})
+ rw.Write([]byte{'z'})
+ }))
+ <-done
+ if !bytes.HasSuffix(conn.writeBuf.Bytes(), []byte("\r\n\r\n3\r\nxyz\r\n0\r\n\r\n")) {
+ t.Errorf("response didn't end with a single 3 byte 'xyz' chunk; got:\n%q",
+ conn.writeBuf.Bytes())
+ }
+}
+
+// goTimeout runs f, failing t if f takes more than ns to complete.
+func goTimeout(t *testing.T, d time.Duration, f func()) {
+ ch := make(chan bool, 2)
+ timer := time.AfterFunc(d, func() {
+ t.Errorf("Timeout expired after %v", d)
+ ch <- true
+ })
+ defer timer.Stop()
+ go func() {
+ defer func() { ch <- true }()
+ f()
+ }()
+ <-ch
+}
+
type errorListener struct {
- errs []os.Error
+ errs []error
}
-func (l *errorListener) Accept() (c net.Conn, err os.Error) {
+func (l *errorListener) Accept() (c net.Conn, err error) {
if len(l.errs) == 0 {
- return nil, os.EOF
+ return nil, io.EOF
}
err = l.errs[0]
l.errs = l.errs[1:]
return
}
-func (l *errorListener) Close() os.Error {
+func (l *errorListener) Close() error {
return nil
}
@@ -921,13 +1148,13 @@ func TestAcceptMaxFds(t *testing.T) {
log.SetOutput(ioutil.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
- ln := &errorListener{[]os.Error{
+ ln := &errorListener{[]error{
&net.OpError{
- Op: "accept",
- Error: os.Errno(syscall.EMFILE),
+ Op: "accept",
+ Err: syscall.EMFILE,
}}}
err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("got error %v, want EOF", err)
}
}
@@ -943,15 +1170,15 @@ func BenchmarkClientServer(b *testing.B) {
for i := 0; i < b.N; i++ {
res, err := Get(ts.URL)
if err != nil {
- panic("Get: " + err.String())
+ b.Fatal("Get:", err)
}
all, err := ioutil.ReadAll(res.Body)
if err != nil {
- panic("ReadAll: " + err.String())
+ b.Fatal("ReadAll:", err)
}
body := string(all)
if body != "Hello world.\n" {
- panic("Got body: " + body)
+ b.Fatal("Got body:", body)
}
}
diff --git a/src/pkg/http/server.go b/src/pkg/net/http/server.go
index b634e27d6..228ac4019 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -12,28 +12,28 @@ package http
import (
"bufio"
"bytes"
- "crypto/rand"
"crypto/tls"
+ "errors"
"fmt"
"io"
+ "io/ioutil"
"log"
"net"
- "os"
+ "net/url"
"path"
"runtime/debug"
"strconv"
"strings"
"sync"
"time"
- "url"
)
// Errors introduced by the HTTP server.
var (
- ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush")
- ErrBodyNotAllowed = os.NewError("http: response status code does not allow body")
- ErrHijacked = os.NewError("Conn has been hijacked")
- ErrContentLength = os.NewError("Conn.Write wrote more than the declared Content-Length")
+ ErrWriteAfterFlush = errors.New("Conn.Write called after Flush")
+ ErrBodyNotAllowed = errors.New("http: response status code does not allow body")
+ ErrHijacked = errors.New("Conn has been hijacked")
+ ErrContentLength = errors.New("Conn.Write wrote more than the declared Content-Length")
)
// Objects implementing the Handler interface can be
@@ -58,8 +58,10 @@ type ResponseWriter interface {
// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
- // before writing the data.
- Write([]byte) (int, os.Error)
+ // before writing the data. If the Header does not contain a
+ // Content-Type line, Write adds a Content-Type set to the result of passing
+ // the initial 512 bytes of written data to DetectContentType.
+ Write([]byte) (int, error)
// WriteHeader sends an HTTP response header with status code.
// If WriteHeader is not called explicitly, the first call to Write
@@ -89,7 +91,7 @@ type Hijacker interface {
// will not do anything else with the connection.
// It becomes the caller's responsibility to manage
// and close the connection.
- Hijack() (net.Conn, *bufio.ReadWriter, os.Error)
+ Hijack() (net.Conn, *bufio.ReadWriter, error)
}
// A conn represents the server side of an HTTP connection.
@@ -122,34 +124,55 @@ type response struct {
// "Connection: keep-alive" response header and a
// Content-Length.
closeAfterReply bool
+
+ // requestBodyLimitHit is set by requestTooLarge when
+ // maxBytesReader hits its max size. It is checked in
+ // WriteHeader, to make sure we don't consume the the
+ // remaining request body to try to advance to the next HTTP
+ // request. Instead, when this is set, we stop doing
+ // subsequent requests on this connection and stop reading
+ // input from it.
+ requestBodyLimitHit bool
+}
+
+// requestTooLarge is called by maxBytesReader when too much input has
+// been read from the client.
+func (w *response) requestTooLarge() {
+ w.closeAfterReply = true
+ w.requestBodyLimitHit = true
+ if !w.wroteHeader {
+ w.Header().Set("Connection", "close")
+ }
}
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 {
+func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
+ // Call WriteHeader before checking w.chunking if it hasn't
+ // been called yet, since WriteHeader is what sets w.chunking.
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
+ if !w.chunking && w.bodyAllowed() && !w.needSniff {
+ w.Flush()
+ if rf, ok := w.conn.rwc.(io.ReaderFrom); ok {
n, err = rf.ReadFrom(src)
- r.written += n
+ w.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)
+ // Use wrapper to hide w.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{w}, src)
}
// noLimit is an effective infinite upper bound for io.LimitedReader
const noLimit int64 = (1 << 63) - 1
// Create new connection from rwc.
-func (srv *Server) newConn(rwc net.Conn) (c *conn, err os.Error) {
+func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
c = new(conn)
c.remoteAddr = rwc.RemoteAddr().String()
c.server = srv
@@ -159,13 +182,6 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err os.Error) {
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()
- }
-
return c, nil
}
@@ -189,9 +205,9 @@ type expectContinueReader struct {
closed bool
}
-func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
+func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
if ecr.closed {
- return 0, os.NewError("http: Read after Close on request Body")
+ return 0, errors.New("http: Read after Close on request Body")
}
if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
ecr.resp.wroteContinue = true
@@ -201,7 +217,7 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
return ecr.readCloser.Read(p)
}
-func (ecr *expectContinueReader) Close() os.Error {
+func (ecr *expectContinueReader) Close() error {
ecr.closed = true
return ecr.readCloser.Close()
}
@@ -212,10 +228,10 @@ 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")
+var errTooLarge = errors.New("http: request too large")
// Read next request from connection.
-func (c *conn) readRequest() (w *response, err os.Error) {
+func (c *conn) readRequest() (w *response, err error) {
if c.hijacked {
return nil, ErrHijacked
}
@@ -245,6 +261,17 @@ func (w *response) Header() Header {
return w.header
}
+// maxPostHandlerReadBytes is the max number of Request.Body bytes not
+// consumed by a handler that the server will read from the client
+// in order to keep a connection alive. If there are more bytes than
+// this then the server to be paranoid instead sends a "Connection:
+// close" response.
+//
+// This number is approximately what a typical machine's TCP buffer
+// size is anyway. (if we have the bytes on the machine, we might as
+// well read them)
+const maxPostHandlerReadBytes = 256 << 10
+
func (w *response) WriteHeader(code int) {
if w.conn.hijacked {
log.Print("http: response.WriteHeader on hijacked connection")
@@ -254,18 +281,54 @@ func (w *response) WriteHeader(code int) {
log.Print("http: multiple response.WriteHeader calls")
return
}
+ w.wroteHeader = true
+ w.status = code
+
+ // Check for a explicit (and valid) Content-Length header.
+ var hasCL bool
+ var contentLength int64
+ if clenStr := w.header.Get("Content-Length"); clenStr != "" {
+ var err error
+ contentLength, err = strconv.ParseInt(clenStr, 10, 64)
+ if err == nil {
+ hasCL = true
+ } else {
+ log.Printf("http: invalid Content-Length of %q sent", clenStr)
+ w.header.Del("Content-Length")
+ }
+ }
+
+ if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) {
+ _, connectionHeaderSet := w.header["Connection"]
+ if !connectionHeaderSet {
+ w.header.Set("Connection", "keep-alive")
+ }
+ } else if !w.req.ProtoAtLeast(1, 1) {
+ // Client did not ask to keep connection alive.
+ w.closeAfterReply = true
+ }
+
+ if w.header.Get("Connection") == "close" {
+ w.closeAfterReply = true
+ }
// Per RFC 2616, we should consume the request body before
- // replying, if the handler hasn't already done so.
- if w.req.ContentLength != 0 {
+ // replying, if the handler hasn't already done so. But we
+ // don't want to do an unbounded amount of reading here for
+ // DoS reasons, so we only try up to a threshold.
+ if w.req.ContentLength != 0 && !w.closeAfterReply {
ecr, isExpecter := w.req.Body.(*expectContinueReader)
if !isExpecter || ecr.resp.wroteContinue {
- w.req.Body.Close()
+ n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
+ if n >= maxPostHandlerReadBytes {
+ w.requestTooLarge()
+ w.header.Set("Connection", "close")
+ } else {
+ w.req.Body.Close()
+ }
}
}
- w.wroteHeader = true
- w.status = code
if code == StatusNotModified {
// Must not have body.
for _, header := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
@@ -279,27 +342,13 @@ func (w *response) WriteHeader(code int) {
}
} else {
// If no content type, apply sniffing algorithm to body.
- if w.header.Get("Content-Type") == "" {
+ if w.header.Get("Content-Type") == "" && w.req.Method != "HEAD" {
w.needSniff = true
}
}
if _, ok := w.header["Date"]; !ok {
- w.Header().Set("Date", time.UTC().Format(TimeFormat))
- }
-
- // Check for a explicit (and valid) Content-Length header.
- var hasCL bool
- var contentLength int64
- if clenStr := w.header.Get("Content-Length"); clenStr != "" {
- var err os.Error
- contentLength, err = strconv.Atoi64(clenStr)
- if err == nil {
- hasCL = true
- } else {
- log.Printf("http: invalid Content-Length of %q sent", clenStr)
- w.header.Del("Content-Length")
- }
+ w.Header().Set("Date", time.Now().UTC().Format(TimeFormat))
}
te := w.header.Get("Transfer-Encoding")
@@ -334,20 +383,6 @@ func (w *response) WriteHeader(code int) {
w.header.Del("Transfer-Encoding") // in case already set
}
- if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) {
- _, connectionHeaderSet := w.header["Connection"]
- if !connectionHeaderSet {
- w.header.Set("Connection", "keep-alive")
- }
- } else if !w.req.ProtoAtLeast(1, 1) {
- // Client did not ask to keep connection alive.
- 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")
@@ -407,7 +442,7 @@ func (w *response) bodyAllowed() bool {
return w.status != StatusNotModified && w.req.Method != "HEAD"
}
-func (w *response) Write(data []byte) (n int, err os.Error) {
+func (w *response) Write(data []byte) (n int, err error) {
if w.conn.hijacked {
log.Print("http: response.Write on hijacked connection")
return 0, ErrHijacked
@@ -433,7 +468,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
// determine the content type. Accumulate the
// initial writes in w.conn.body.
// Cap m so that append won't allocate.
- m := cap(w.conn.body) - len(w.conn.body)
+ m = cap(w.conn.body) - len(w.conn.body)
if m > len(data) {
m = len(data)
}
@@ -472,55 +507,6 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
return m + n, err
}
-// If this is an error reply (4xx or 5xx)
-// and the handler wrote some data explaining the error,
-// some browsers (i.e., Chrome, Internet Explorer)
-// will show their own error instead unless the error is
-// long enough. The minimum lengths used in those
-// browsers are in the 256-512 range.
-// Pad to 1024 bytes.
-func errorKludge(w *response) {
- const min = 1024
-
- // Is this an error?
- if kind := w.status / 100; kind != 4 && kind != 5 {
- return
- }
-
- // Did the handler supply any info? Enough?
- if w.written == 0 || w.written >= min {
- return
- }
-
- // Is it a broken browser?
- var msg string
- switch agent := w.req.UserAgent(); {
- case strings.Contains(agent, "MSIE"):
- msg = "Internet Explorer"
- case strings.Contains(agent, "Chrome/"):
- msg = "Chrome"
- default:
- return
- }
- msg += " would ignore this error page if this text weren't here.\n"
-
- // Is it text? ("Content-Type" is always in the map)
- baseType := strings.SplitN(w.header.Get("Content-Type"), ";", 2)[0]
- switch baseType {
- case "text/html":
- io.WriteString(w, "<!-- ")
- for w.written < min {
- io.WriteString(w, msg)
- }
- io.WriteString(w, " -->")
- case "text/plain":
- io.WriteString(w, "\n")
- for w.written < min {
- io.WriteString(w, msg)
- }
- }
-}
-
func (w *response) finishRequest() {
// If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
// back, we can make this a keep-alive response ...
@@ -536,14 +522,17 @@ func (w *response) finishRequest() {
if w.needSniff {
w.sniff()
}
- errorKludge(w)
if w.chunking {
io.WriteString(w.conn.buf, "0\r\n")
// trailer key/value pairs, followed by blank line
io.WriteString(w.conn.buf, "\r\n")
}
w.conn.buf.Flush()
- w.req.Body.Close()
+ // Close the body, unless we're about to close the whole TCP connection
+ // anyway.
+ if !w.closeAfterReply {
+ w.req.Body.Close()
+ }
if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll()
}
@@ -581,25 +570,43 @@ func (c *conn) serve() {
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())
+
+ if c.rwc != nil { // may be nil if connection hijacked
+ c.rwc.Close()
+ }
}()
+ if tlsConn, ok := c.rwc.(*tls.Conn); ok {
+ if err := tlsConn.Handshake(); err != nil {
+ c.close()
+ return
+ }
+ c.tlsState = new(tls.ConnectionState)
+ *c.tlsState = tlsConn.ConnectionState()
+ }
+
for {
w, err := c.readRequest()
if err != nil {
+ msg := "400 Bad Request"
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")
+ msg = "413 Request Entity Too Large"
+ } else if err == io.EOF {
+ break // Don't reply
+ } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ break // Don't reply
}
+ fmt.Fprintf(c.rwc, "HTTP/1.1 %s\r\n\r\n", msg)
break
}
@@ -660,7 +667,7 @@ func (c *conn) serve() {
// Hijack implements the Hijacker.Hijack method. Our response is both a ResponseWriter
// and a Hijacker.
-func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err os.Error) {
+func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if w.conn.hijacked {
return nil, nil, ErrHijacked
}
@@ -774,13 +781,16 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
}
}
+var htmlReplacer = strings.NewReplacer(
+ "&", "&amp;",
+ "<", "&lt;",
+ ">", "&gt;",
+ `"`, "&quot;",
+ "'", "&apos;",
+)
+
func htmlEscape(s string) string {
- s = strings.Replace(s, "&", "&amp;", -1)
- s = strings.Replace(s, "<", "&lt;", -1)
- s = strings.Replace(s, ">", "&gt;", -1)
- s = strings.Replace(s, "\"", "&quot;", -1)
- s = strings.Replace(s, "'", "&apos;", -1)
- return s
+ return htmlReplacer.Replace(s)
}
// Redirect to a fixed URL
@@ -824,11 +834,17 @@ func RedirectHandler(url string, code int) Handler {
// redirecting any request containing . or .. elements to an
// equivalent .- and ..-free URL.
type ServeMux struct {
- m map[string]Handler
+ mu sync.RWMutex
+ m map[string]muxEntry
+}
+
+type muxEntry struct {
+ explicit bool
+ h Handler
}
// NewServeMux allocates and returns a new ServeMux.
-func NewServeMux() *ServeMux { return &ServeMux{make(map[string]Handler)} }
+func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()
@@ -874,12 +890,28 @@ func (mux *ServeMux) match(path string) Handler {
}
if h == nil || len(k) > n {
n = len(k)
- h = v
+ h = v.h
}
}
return h
}
+// handler returns the handler to use for the request r.
+func (mux *ServeMux) handler(r *Request) Handler {
+ mux.mu.RLock()
+ defer mux.mu.RUnlock()
+
+ // Host-specific pattern takes precedence over generic ones
+ h := mux.match(r.Host + r.URL.Path)
+ if h == nil {
+ h = mux.match(r.URL.Path)
+ }
+ if h == nil {
+ h = NotFoundHandler()
+ }
+ return h
+}
+
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
@@ -889,30 +921,33 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
w.WriteHeader(StatusMovedPermanently)
return
}
- // Host-specific pattern takes precedence over generic ones
- h := mux.match(r.Host + r.URL.Path)
- if h == nil {
- h = mux.match(r.URL.Path)
- }
- if h == nil {
- h = NotFoundHandler()
- }
- h.ServeHTTP(w, r)
+ mux.handler(r).ServeHTTP(w, r)
}
// Handle registers the handler for the given pattern.
+// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
+ mux.mu.Lock()
+ defer mux.mu.Unlock()
+
if pattern == "" {
panic("http: invalid pattern " + pattern)
}
+ if handler == nil {
+ panic("http: nil handler")
+ }
+ if mux.m[pattern].explicit {
+ panic("http: multiple registrations for " + pattern)
+ }
- mux.m[pattern] = handler
+ mux.m[pattern] = muxEntry{explicit: true, h: handler}
// Helpful behavior:
- // If pattern is /tree/, insert permanent redirect for /tree.
+ // If pattern is /tree/, insert an implicit permanent redirect for /tree.
+ // It can be overridden by an explicit registration.
n := len(pattern)
- if n > 0 && pattern[n-1] == '/' {
- mux.m[pattern[0:n-1]] = RedirectHandler(pattern, StatusMovedPermanently)
+ if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {
+ mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(pattern, StatusMovedPermanently)}
}
}
@@ -937,24 +972,25 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
// creating a new service thread for each. The service threads
// read requests and then call handler to reply to them.
// Handler is typically nil, in which case the DefaultServeMux is used.
-func Serve(l net.Listener, handler Handler) os.Error {
+func Serve(l net.Listener, handler Handler) error {
srv := &Server{Handler: handler}
return srv.Serve(l)
}
// 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
- MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
+ Addr string // TCP address to listen on, ":http" if empty
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
+ ReadTimeout time.Duration // maximum duration before timing out read of the request
+ WriteTimeout time.Duration // maximum duration before timing out write of the response
+ MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
+ TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
}
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections. If
// srv.Addr is blank, ":http" is used.
-func (srv *Server) ListenAndServe() os.Error {
+func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == "" {
addr = ":http"
@@ -969,22 +1005,33 @@ func (srv *Server) ListenAndServe() os.Error {
// Serve accepts incoming connections on the Listener l, creating a
// new service thread for each. The service threads read requests and
// then call srv.Handler to reply to them.
-func (srv *Server) Serve(l net.Listener) os.Error {
+func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
+ var tempDelay time.Duration // how long to sleep on accept failure
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
- log.Printf("http: Accept error: %v", e)
+ if tempDelay == 0 {
+ tempDelay = 5 * time.Millisecond
+ } else {
+ tempDelay *= 2
+ }
+ if max := 1 * time.Second; tempDelay > max {
+ tempDelay = max
+ }
+ log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
+ time.Sleep(tempDelay)
continue
}
return e
}
+ tempDelay = 0
if srv.ReadTimeout != 0 {
- rw.SetReadTimeout(srv.ReadTimeout)
+ rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0 {
- rw.SetWriteTimeout(srv.WriteTimeout)
+ rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
c, err := srv.newConn(rw)
if err != nil {
@@ -1005,8 +1052,8 @@ func (srv *Server) Serve(l net.Listener) os.Error {
// package main
//
// import (
-// "http"
// "io"
+// "net/http"
// "log"
// )
//
@@ -1019,10 +1066,10 @@ func (srv *Server) Serve(l net.Listener) os.Error {
// http.HandleFunc("/hello", HelloServer)
// err := http.ListenAndServe(":12345", nil)
// if err != nil {
-// log.Fatal("ListenAndServe: ", err.String())
+// log.Fatal("ListenAndServe: ", err)
// }
// }
-func ListenAndServe(addr string, handler Handler) os.Error {
+func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
@@ -1036,8 +1083,8 @@ func ListenAndServe(addr string, handler Handler) os.Error {
// A trivial example server is:
//
// import (
-// "http"
// "log"
+// "net/http"
// )
//
// func handler(w http.ResponseWriter, req *http.Request) {
@@ -1055,7 +1102,7 @@ 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 {
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServeTLS(certFile, keyFile)
}
@@ -1069,18 +1116,20 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
// of the server's certificate followed by the CA's certificate.
//
// If srv.Addr is blank, ":https" is used.
-func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error {
- addr := s.Addr
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
+ addr := srv.Addr
if addr == "" {
addr = ":https"
}
- config := &tls.Config{
- Rand: rand.Reader,
- Time: time.Seconds,
- NextProtos: []string{"http/1.1"},
+ config := &tls.Config{}
+ if srv.TLSConfig != nil {
+ *config = *srv.TLSConfig
+ }
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
}
- var err os.Error
+ var err error
config.Certificates = make([]tls.Certificate, 1)
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
@@ -1093,7 +1142,7 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error {
}
tlsListener := tls.NewListener(conn, config)
- return s.Serve(tlsListener)
+ return srv.Serve(tlsListener)
}
// TimeoutHandler returns a Handler that runs h with the given time limit.
@@ -1104,20 +1153,20 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error {
// (If msg is empty, a suitable default message will be sent.)
// After such a timeout, writes by h to its ResponseWriter will return
// ErrHandlerTimeout.
-func TimeoutHandler(h Handler, ns int64, msg string) Handler {
- f := func() <-chan int64 {
- return time.After(ns)
+func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
+ f := func() <-chan time.Time {
+ return time.After(dt)
}
return &timeoutHandler{h, f, msg}
}
// ErrHandlerTimeout is returned on ResponseWriter Write calls
// in handlers which have timed out.
-var ErrHandlerTimeout = os.NewError("http: Handler timeout")
+var ErrHandlerTimeout = errors.New("http: Handler timeout")
type timeoutHandler struct {
handler Handler
- timeout func() <-chan int64 // returns channel producing a timeout
+ timeout func() <-chan time.Time // returns channel producing a timeout
body string
}
@@ -1161,7 +1210,7 @@ func (tw *timeoutWriter) Header() Header {
return tw.w.Header()
}
-func (tw *timeoutWriter) Write(p []byte) (int, os.Error) {
+func (tw *timeoutWriter) Write(p []byte) (int, error) {
tw.mu.Lock()
timedOut := tw.timedOut
tw.mu.Unlock()
diff --git a/src/pkg/http/sniff.go b/src/pkg/net/http/sniff.go
index d60868750..68f519b05 100644
--- a/src/pkg/http/sniff.go
+++ b/src/pkg/net/http/sniff.go
@@ -9,15 +9,15 @@ import (
"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.
+// The algorithm uses at most 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.
+// DetectContentType implements the algorithm described
+// at http://mimesniff.spec.whatwg.org/ to determine the
+// Content-Type of the given data. It considers at most the
+// first 512 bytes of data. DetectContentType always returns
+// a valid MIME type: if it cannot determine a more specific one, it
+// returns "application/octet-stream".
func DetectContentType(data []byte) string {
if len(data) > sniffLen {
data = data[:sniffLen]
@@ -38,7 +38,7 @@ func DetectContentType(data []byte) string {
}
func isWS(b byte) bool {
- return bytes.IndexByte([]byte("\t\n\x0C\n "), b) != -1
+ return bytes.IndexByte([]byte("\t\n\x0C\r "), b) != -1
}
type sniffSig interface {
@@ -48,23 +48,23 @@ type sniffSig interface {
// Data matching the table in section 6.
var sniffSignatures = []sniffSig{
- htmlSig([]byte("<!DOCTYPE HTML")),
- htmlSig([]byte("<HTML")),
- htmlSig([]byte("<HEAD")),
- htmlSig([]byte("<SCRIPT")),
- htmlSig([]byte("<IFRAME")),
- htmlSig([]byte("<H1")),
- htmlSig([]byte("<DIV")),
- htmlSig([]byte("<FONT")),
- htmlSig([]byte("<TABLE")),
- htmlSig([]byte("<A")),
- htmlSig([]byte("<STYLE")),
- htmlSig([]byte("<TITLE")),
- htmlSig([]byte("<B")),
- htmlSig([]byte("<BODY")),
- htmlSig([]byte("<BR")),
- htmlSig([]byte("<P")),
- htmlSig([]byte("<!--")),
+ htmlSig("<!DOCTYPE HTML"),
+ htmlSig("<HTML"),
+ htmlSig("<HEAD"),
+ htmlSig("<SCRIPT"),
+ htmlSig("<IFRAME"),
+ htmlSig("<H1"),
+ htmlSig("<DIV"),
+ htmlSig("<FONT"),
+ htmlSig("<TABLE"),
+ htmlSig("<A"),
+ htmlSig("<STYLE"),
+ htmlSig("<TITLE"),
+ htmlSig("<B"),
+ htmlSig("<BODY"),
+ htmlSig("<BR"),
+ htmlSig("<P"),
+ htmlSig("<!--"),
&maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
diff --git a/src/pkg/http/sniff_test.go b/src/pkg/net/http/sniff_test.go
index faf05e405..8ab72ac23 100644
--- a/src/pkg/http/sniff_test.go
+++ b/src/pkg/net/http/sniff_test.go
@@ -6,11 +6,14 @@ package http_test
import (
"bytes"
- . "http"
- "http/httptest"
+ "fmt"
+ "io"
"io/ioutil"
"log"
+ . "net/http"
+ "net/http/httptest"
"strconv"
+ "strings"
"testing"
)
@@ -26,6 +29,7 @@ var sniffTests = []struct {
{"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"},
+ {"HTML document #4 (leading CRLF)", []byte("\r\n<html>..."), "text/html; charset=utf-8"},
{"Plain text", []byte(`This is not HTML. It has ☃ though.`), "text/plain; charset=utf-8"},
@@ -78,3 +82,57 @@ func TestServerContentType(t *testing.T) {
resp.Body.Close()
}
}
+
+func TestContentTypeWithCopy(t *testing.T) {
+ const (
+ input = "\n<html>\n\t<head>\n"
+ expected = "text/html; charset=utf-8"
+ )
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
+ buf := bytes.NewBuffer([]byte(input))
+ n, err := io.Copy(w, buf)
+ if int(n) != len(input) || err != nil {
+ t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ }))
+ defer ts.Close()
+
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ if ct := resp.Header.Get("Content-Type"); ct != expected {
+ t.Errorf("Content-Type = %q, want %q", ct, expected)
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Errorf("reading body: %v", err)
+ } else if !bytes.Equal(data, []byte(input)) {
+ t.Errorf("data is %q, want %q", data, input)
+ }
+ resp.Body.Close()
+}
+
+func TestSniffWriteSize(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ size, _ := strconv.Atoi(r.FormValue("size"))
+ written, err := io.WriteString(w, strings.Repeat("a", size))
+ if err != nil {
+ t.Errorf("write of %d bytes: %v", size, err)
+ return
+ }
+ if written != size {
+ t.Errorf("write of %d bytes wrote %d bytes", size, written)
+ }
+ }))
+ defer ts.Close()
+ for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
+ res, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size))
+ if err != nil {
+ t.Fatalf("size %d: %v", size, err)
+ }
+ res.Body.Close()
+ }
+}
diff --git a/src/pkg/http/status.go b/src/pkg/net/http/status.go
index b6e2d65c6..5af0b77c4 100644
--- a/src/pkg/http/status.go
+++ b/src/pkg/net/http/status.go
@@ -43,6 +43,7 @@ const (
StatusUnsupportedMediaType = 415
StatusRequestedRangeNotSatisfiable = 416
StatusExpectationFailed = 417
+ StatusTeapot = 418
StatusInternalServerError = 500
StatusNotImplemented = 501
@@ -90,6 +91,7 @@ var statusText = map[int]string{
StatusUnsupportedMediaType: "Unsupported Media Type",
StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
StatusExpectationFailed: "Expectation Failed",
+ StatusTeapot: "I'm a teapot",
StatusInternalServerError: "Internal Server Error",
StatusNotImplemented: "Not Implemented",
diff --git a/src/pkg/http/testdata/file b/src/pkg/net/http/testdata/file
index 11f11f9be..11f11f9be 100644
--- a/src/pkg/http/testdata/file
+++ b/src/pkg/net/http/testdata/file
diff --git a/src/pkg/http/testdata/index.html b/src/pkg/net/http/testdata/index.html
index da8e1e93d..da8e1e93d 100644
--- a/src/pkg/http/testdata/index.html
+++ b/src/pkg/net/http/testdata/index.html
diff --git a/src/pkg/http/testdata/style.css b/src/pkg/net/http/testdata/style.css
index 208d16d42..208d16d42 100644
--- a/src/pkg/http/testdata/style.css
+++ b/src/pkg/net/http/testdata/style.css
diff --git a/src/pkg/http/transfer.go b/src/pkg/net/http/transfer.go
index b65d99a6f..3c8fe7f5b 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -5,11 +5,13 @@
package http
import (
- "bytes"
"bufio"
+ "bytes"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
- "os"
+ "net/textproto"
"strconv"
"strings"
)
@@ -18,22 +20,27 @@ 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 {
+ Method string
Body io.Reader
BodyCloser io.Closer
ResponseToHEAD bool
- ContentLength int64
+ ContentLength int64 // -1 means unknown, 0 means exactly none
Close bool
TransferEncoding []string
Trailer Header
}
-func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
+func newTransferWriter(r interface{}) (t *transferWriter, err error) {
t = &transferWriter{}
// Extract relevant fields
atLeastHTTP11 := false
switch rr := r.(type) {
case *Request:
+ if rr.ContentLength != 0 && rr.Body == nil {
+ return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
+ }
+ t.Method = rr.Method
t.Body = rr.Body
t.BodyCloser = rr.Body
t.ContentLength = rr.ContentLength
@@ -64,6 +71,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
}
}
case *Response:
+ t.Method = rr.Request.Method
t.Body = rr.Body
t.BodyCloser = rr.Body
t.ContentLength = rr.ContentLength
@@ -105,7 +113,28 @@ func noBodyExpected(requestMethod string) bool {
return requestMethod == "HEAD"
}
-func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
+func (t *transferWriter) shouldSendContentLength() bool {
+ if chunked(t.TransferEncoding) {
+ return false
+ }
+ if t.ContentLength > 0 {
+ return true
+ }
+ if t.ResponseToHEAD {
+ return true
+ }
+ // Many servers expect a Content-Length for these methods
+ if t.Method == "POST" || t.Method == "PUT" {
+ return true
+ }
+ if t.ContentLength == 0 && isIdentity(t.TransferEncoding) {
+ return true
+ }
+
+ return false
+}
+
+func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
if t.Close {
_, err = io.WriteString(w, "Connection: close\r\n")
if err != nil {
@@ -116,14 +145,14 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
// Write Content-Length and/or Transfer-Encoding whose values are a
// function of the sanitized field triple (Body, ContentLength,
// TransferEncoding)
- if chunked(t.TransferEncoding) {
- _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
+ if t.shouldSendContentLength() {
+ io.WriteString(w, "Content-Length: ")
+ _, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n")
if err != nil {
return
}
- } 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")
+ } else if chunked(t.TransferEncoding) {
+ _, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
if err != nil {
return
}
@@ -153,19 +182,26 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
return
}
-func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
+func (t *transferWriter) WriteBody(w io.Writer) (err error) {
+ var ncopy int64
+
// Write body
if t.Body != nil {
if chunked(t.TransferEncoding) {
- cw := NewChunkedWriter(w)
+ cw := newChunkedWriter(w)
_, err = io.Copy(cw, t.Body)
if err == nil {
err = cw.Close()
}
} else if t.ContentLength == -1 {
- _, err = io.Copy(w, t.Body)
+ ncopy, err = io.Copy(w, t.Body)
} else {
- _, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+ ncopy, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
+ nextra, err := io.Copy(ioutil.Discard, t.Body)
+ if err != nil {
+ return err
+ }
+ ncopy += nextra
}
if err != nil {
return err
@@ -175,6 +211,11 @@ func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
}
}
+ if t.ContentLength != -1 && t.ContentLength != ncopy {
+ return fmt.Errorf("http: Request.ContentLength=%d with Body length %d",
+ t.ContentLength, ncopy)
+ }
+
// TODO(petar): Place trailer writer code here.
if chunked(t.TransferEncoding) {
// Last chunk, empty trailer
@@ -214,7 +255,7 @@ func bodyAllowedForStatus(status int) bool {
}
// msg is *Request or *Response.
-func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
+func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t := &transferReader{}
// Unify input
@@ -279,7 +320,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}
@@ -320,13 +361,13 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
// Sanitize transfer encoding
-func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
+func fixTransferEncoding(requestMethod string, header Header) ([]string, error) {
raw, present := header["Transfer-Encoding"]
if !present {
return nil, nil
}
- header["Transfer-Encoding"] = nil, false
+ delete(header, "Transfer-Encoding")
// Head responses have no bodies, so the transfer encoding
// should be ignored.
@@ -342,7 +383,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
// chunked encoding must always come first.
for _, encoding := range encodings {
encoding = strings.ToLower(strings.TrimSpace(encoding))
- // "identity" encoding is not recored
+ // "identity" encoding is not recorded
if encoding == "identity" {
break
}
@@ -359,7 +400,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
// Chunked encoding trumps Content-Length. See RFC 2616
// Section 4.4. Currently len(te) > 0 implies chunked
// encoding.
- header["Content-Length"] = nil, false
+ delete(header, "Content-Length")
return te, nil
}
@@ -369,7 +410,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(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, os.Error) {
+func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) {
// Logic based on response type or status
if noBodyExpected(requestMethod) {
@@ -391,7 +432,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
// Logic based on Content-Length
cl := strings.TrimSpace(header.Get("Content-Length"))
if cl != "" {
- n, err := strconv.Atoi64(cl)
+ n, err := strconv.ParseInt(cl, 10, 64)
if err != nil || n < 0 {
return -1, &badStringError{"bad Content-Length", cl}
}
@@ -442,7 +483,7 @@ func shouldClose(major, minor int, header Header) bool {
}
// Parse the trailer header
-func fixTrailer(header Header, te []string) (Header, os.Error) {
+func fixTrailer(header Header, te []string) (Header, error) {
raw := header.Get("Trailer")
if raw == "" {
return nil, nil
@@ -478,22 +519,87 @@ type body struct {
r *bufio.Reader // underlying wire-format reader for the trailer
closing bool // is the connection to be closed after reading body?
closed bool
+
+ res *response // response writer for server requests, else nil
}
// ErrBodyReadAfterClose is returned when reading a Request Body after
// the body has been closed. This typically happens when the body is
// read after an HTTP Handler calls WriteHeader or Write on its
// ResponseWriter.
-var ErrBodyReadAfterClose = os.NewError("http: invalid Read on closed request Body")
+var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed request Body")
-func (b *body) Read(p []byte) (n int, err os.Error) {
+func (b *body) Read(p []byte) (n int, err error) {
if b.closed {
return 0, ErrBodyReadAfterClose
}
- return b.Reader.Read(p)
+ n, err = b.Reader.Read(p)
+
+ // Read the final trailer once we hit EOF.
+ if err == io.EOF && b.hdr != nil {
+ if e := b.readTrailer(); e != nil {
+ err = e
+ }
+ b.hdr = nil
+ }
+ return n, err
}
-func (b *body) Close() os.Error {
+var (
+ singleCRLF = []byte("\r\n")
+ doubleCRLF = []byte("\r\n\r\n")
+)
+
+func seeUpcomingDoubleCRLF(r *bufio.Reader) bool {
+ for peekSize := 4; ; peekSize++ {
+ // This loop stops when Peek returns an error,
+ // which it does when r's buffer has been filled.
+ buf, err := r.Peek(peekSize)
+ if bytes.HasSuffix(buf, doubleCRLF) {
+ return true
+ }
+ if err != nil {
+ break
+ }
+ }
+ return false
+}
+
+func (b *body) readTrailer() error {
+ // The common case, since nobody uses trailers.
+ buf, _ := b.r.Peek(2)
+ if bytes.Equal(buf, singleCRLF) {
+ b.r.ReadByte()
+ b.r.ReadByte()
+ return nil
+ }
+
+ // Make sure there's a header terminator coming up, to prevent
+ // a DoS with an unbounded size Trailer. It's not easy to
+ // slip in a LimitReader here, as textproto.NewReader requires
+ // a concrete *bufio.Reader. Also, we can't get all the way
+ // back up to our conn's LimitedReader that *might* be backing
+ // this bufio.Reader. Instead, a hack: we iteratively Peek up
+ // to the bufio.Reader's max size, looking for a double CRLF.
+ // This limits the trailer to the underlying buffer size, typically 4kB.
+ if !seeUpcomingDoubleCRLF(b.r) {
+ return errors.New("http: suspiciously long trailer after chunked body")
+ }
+
+ hdr, err := textproto.NewReader(b.r).ReadMIMEHeader()
+ if err != nil {
+ return err
+ }
+ switch rr := b.hdr.(type) {
+ case *Request:
+ rr.Trailer = Header(hdr)
+ case *Response:
+ rr.Trailer = Header(hdr)
+ }
+ return nil
+}
+
+func (b *body) Close() error {
if b.closed {
return nil
}
@@ -506,15 +612,19 @@ func (b *body) Close() os.Error {
return nil
}
- if _, err := io.Copy(ioutil.Discard, b); err != nil {
- return err
- }
-
- if b.hdr == nil { // not reading trailer
+ // In a server request, don't continue reading from the client
+ // if we've already hit the maximum body size set by the
+ // handler. If this is set, that also means the TCP connection
+ // is about to be closed, so getting to the next HTTP request
+ // in the stream is not necessary.
+ if b.res != nil && b.res.requestBodyLimitHit {
return nil
}
- // TODO(petar): Put trailer reader code here
-
+ // Fully consume the body, which will also lead to us reading
+ // the trailer headers after the body, if present.
+ if _, err := io.Copy(ioutil.Discard, b); err != nil {
+ return err
+ }
return nil
}
diff --git a/src/pkg/http/transport.go b/src/pkg/net/http/transport.go
index 4302ffab1..024975946 100644
--- a/src/pkg/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -2,6 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// HTTP client implementation. See RFC 2616.
+//
+// This is the low-level Transport implementation of RoundTripper.
+// The high-level interface is in client.go.
+
package http
import (
@@ -9,15 +14,16 @@ import (
"compress/gzip"
"crypto/tls"
"encoding/base64"
+ "errors"
"fmt"
"io"
"io/ioutil"
"log"
"net"
+ "net/url"
"os"
"strings"
"sync"
- "url"
)
// DefaultTransport is the default implementation of Transport and is
@@ -47,12 +53,16 @@ type Transport struct {
// 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)
+ Proxy func(*Request) (*url.URL, 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)
+ Dial func(net, addr string) (c net.Conn, err error)
+
+ // TLSClientConfig specifies the TLS configuration to use with
+ // tls.Client. If nil, the default configuration is used.
+ TLSClientConfig *tls.Config
DisableKeepAlives bool
DisableCompression bool
@@ -66,8 +76,10 @@ type Transport struct {
// 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) {
+// An error is returned if the proxy environment is invalid.
+// A nil URL and nil error are returned if no proxy is defined in the
+// environment, or a proxy should not be used for the given request.
+func ProxyFromEnvironment(req *Request) (*url.URL, error) {
proxy := getenvEitherCase("HTTP_PROXY")
if proxy == "" {
return nil, nil
@@ -75,33 +87,48 @@ func ProxyFromEnvironment(req *Request) (*url.URL, os.Error) {
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")
+ proxyURL, err := url.Parse(proxy)
+ if err != nil || proxyURL.Scheme == "" {
+ if u, err := url.Parse("http://" + proxy); err == nil {
+ proxyURL = u
+ err = nil
}
}
+ if err != nil {
+ return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
+ }
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) {
+func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
+ return func(*Request) (*url.URL, error) {
return fixedURL, nil
}
}
+// transportRequest is a wrapper around a *Request that adds
+// optional extra headers to write.
+type transportRequest struct {
+ *Request // original request, not to be mutated
+ extra Header // extra headers to write, or nil
+}
+
+func (tr *transportRequest) extraHeaders() Header {
+ if tr.extra == nil {
+ tr.extra = make(Header)
+ }
+ return tr.extra
+}
+
// RoundTrip implements the RoundTripper interface.
-func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
+func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
if req.URL == nil {
- if req.URL, err = url.Parse(req.RawURL); err != nil {
- return
- }
+ return nil, errors.New("http: nil Request.URL")
+ }
+ if req.Header == nil {
+ return nil, errors.New("http: nil Request.Header")
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
t.lk.Lock()
@@ -115,8 +142,8 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
}
return rt.RoundTrip(req)
}
-
- cm, err := t.connectMethodForRequest(req)
+ treq := &transportRequest{Request: req}
+ cm, err := t.connectMethodForRequest(treq)
if err != nil {
return nil, err
}
@@ -130,7 +157,7 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
return nil, err
}
- return pconn.roundTrip(req)
+ return pconn.roundTrip(treq)
}
// RegisterProtocol registers a new protocol with scheme.
@@ -169,7 +196,7 @@ func (t *Transport) CloseIdleConnections() {
pconn.close()
}
}
- t.idleConn = nil
+ t.idleConn = make(map[string][]*persistConn)
}
//
@@ -183,14 +210,14 @@ func getenvEitherCase(k string) string {
return os.Getenv(strings.ToLower(k))
}
-func (t *Transport) connectMethodForRequest(req *Request) (*connectMethod, os.Error) {
+func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
cm := &connectMethod{
- targetScheme: req.URL.Scheme,
- targetAddr: canonicalAddr(req.URL),
+ targetScheme: treq.URL.Scheme,
+ targetAddr: canonicalAddr(treq.URL),
}
if t.Proxy != nil {
- var err os.Error
- cm.proxyURL, err = t.Proxy(req)
+ var err error
+ cm.proxyURL, err = t.Proxy(treq.Request)
if err != nil {
return nil, err
}
@@ -204,22 +231,25 @@ func (cm *connectMethod) proxyAuth() string {
if cm.proxyURL == nil {
return ""
}
- proxyInfo := cm.proxyURL.RawUserinfo
- if proxyInfo != "" {
- return "Basic " + base64.URLEncoding.EncodeToString([]byte(proxyInfo))
+ if u := cm.proxyURL.User; u != nil {
+ return "Basic " + base64.URLEncoding.EncodeToString([]byte(u.String()))
}
return ""
}
-func (t *Transport) putIdleConn(pconn *persistConn) {
+// putIdleConn adds pconn to the list of idle persistent connections awaiting
+// a new request.
+// If pconn is no longer needed or not in a good state, putIdleConn
+// returns false.
+func (t *Transport) putIdleConn(pconn *persistConn) bool {
t.lk.Lock()
defer t.lk.Unlock()
if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
pconn.close()
- return
+ return false
}
if pconn.isBroken() {
- return
+ return false
}
key := pconn.cacheKey
max := t.MaxIdleConnsPerHost
@@ -228,9 +258,10 @@ func (t *Transport) putIdleConn(pconn *persistConn) {
}
if len(t.idleConn[key]) >= max {
pconn.close()
- return
+ return false
}
t.idleConn[key] = append(t.idleConn[key], pconn)
+ return true
}
func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
@@ -247,7 +278,7 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
}
if len(pconns) == 1 {
pconn = pconns[0]
- t.idleConn[key] = nil, false
+ delete(t.idleConn, key)
} else {
// 2 or more cached connections; pop last
// TODO: queue?
@@ -261,7 +292,7 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
return
}
-func (t *Transport) dial(network, addr string) (c net.Conn, err os.Error) {
+func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
if t.Dial != nil {
return t.Dial(network, addr)
}
@@ -272,7 +303,7 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err os.Error) {
// specified in the connectMethod. This includes doing a proxy CONNECT
// and/or setting up TLS. If this doesn't return an error, the persistConn
// is ready to write requests to.
-func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
+func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
if pc := t.getIdleConn(cm); pc != nil {
return pc, nil
}
@@ -293,25 +324,21 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
conn: conn,
reqch: make(chan requestAndChan, 50),
}
- newClientConnFunc := NewClientConn
switch {
case cm.proxyURL == nil:
// Do nothing.
case cm.targetScheme == "http":
- newClientConnFunc = NewProxyClientConn
+ pconn.isProxy = true
if pa != "" {
- pconn.mutateRequestFunc = func(req *Request) {
- if req.Header == nil {
- req.Header = make(Header)
- }
- req.Header.Set("Proxy-Authorization", pa)
+ pconn.mutateHeaderFunc = func(h Header) {
+ h.Set("Proxy-Authorization", pa)
}
}
case cm.targetScheme == "https":
connectReq := &Request{
Method: "CONNECT",
- RawURL: cm.targetAddr,
+ URL: &url.URL{Opaque: cm.targetAddr},
Host: cm.targetAddr,
Header: make(Header),
}
@@ -332,24 +359,26 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
if resp.StatusCode != 200 {
f := strings.SplitN(resp.Status, " ", 2)
conn.Close()
- return nil, os.NewError(f[1])
+ return nil, errors.New(f[1])
}
}
if cm.targetScheme == "https" {
// Initiate TLS and check remote host name against certificate.
- conn = tls.Client(conn, nil)
+ conn = tls.Client(conn, t.TLSClientConfig)
if err = conn.(*tls.Conn).Handshake(); err != nil {
return nil, err
}
- if err = conn.(*tls.Conn).VerifyHostname(cm.tlsHost()); err != nil {
- return nil, err
+ if t.TLSClientConfig == nil || !t.TLSClientConfig.InsecureSkipVerify {
+ if err = conn.(*tls.Conn).VerifyHostname(cm.tlsHost()); err != nil {
+ return nil, err
+ }
}
pconn.conn = conn
}
pconn.br = bufio.NewReader(pconn.conn)
- pconn.cc = newClientConnFunc(conn, pconn.br)
+ pconn.bw = bufio.NewWriter(pconn.conn)
go pconn.readLoop()
return pconn, nil
}
@@ -445,30 +474,21 @@ func (cm *connectMethod) tlsHost() string {
return h
}
-type readResult struct {
- res *Response // either res or err will be set
- err os.Error
-}
-
-type writeRequest struct {
- // Set by client (in pc.roundTrip)
- req *Request
- resch chan *readResult
-
- // Set by writeLoop if an error writing headers.
- writeErr os.Error
-}
-
// persistConn wraps a connection, usually a persistent one
// (but may be used for non-keep-alive requests as well)
type persistConn struct {
- t *Transport
- cacheKey string // its connectMethod.String()
- conn net.Conn
- cc *ClientConn
- br *bufio.Reader
- reqch chan requestAndChan // written by roundTrip(); read by readLoop()
- mutateRequestFunc func(*Request) // nil or func to modify each outbound request
+ t *Transport
+ cacheKey string // its connectMethod.String()
+ conn net.Conn
+ br *bufio.Reader // from conn
+ bw *bufio.Writer // to conn
+ reqch chan requestAndChan // written by roundTrip(); read by readLoop()
+ isProxy bool
+
+ // mutateHeaderFunc is an optional func to modify extra
+ // headers on each outbound request before it's written. (the
+ // original Request given to RoundTrip is not modified)
+ mutateHeaderFunc func(Header)
lk sync.Mutex // guards numExpectedResponses and broken
numExpectedResponses int
@@ -481,62 +501,67 @@ func (pc *persistConn) isBroken() bool {
return pc.broken
}
-func (pc *persistConn) expectingResponse() bool {
- pc.lk.Lock()
- defer pc.lk.Unlock()
- return pc.numExpectedResponses > 0
+var remoteSideClosedFunc func(error) bool // or nil to use default
+
+func remoteSideClosed(err error) bool {
+ if err == io.EOF {
+ return true
+ }
+ if remoteSideClosedFunc != nil {
+ return remoteSideClosedFunc(err)
+ }
+ return false
}
func (pc *persistConn) readLoop() {
alive := true
+ var lastbody io.ReadCloser // last response body, if any, read on this connection
+
for alive {
pb, err := pc.br.Peek(1)
- if err != nil {
- if (err == os.EOF || err == os.EINVAL) && !pc.expectingResponse() {
- // Remote side closed on us. (We probably hit their
- // max idle timeout)
- pc.close()
- return
+
+ pc.lk.Lock()
+ if pc.numExpectedResponses == 0 {
+ pc.closeLocked()
+ pc.lk.Unlock()
+ if len(pb) > 0 {
+ log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
+ string(pb), err)
}
- }
- if !pc.expectingResponse() {
- log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
- string(pb), err)
- pc.close()
return
}
+ pc.lk.Unlock()
rc := <-pc.reqch
- 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" {
+
+ // Advance past the previous response's body, if the
+ // caller hasn't done so.
+ if lastbody != nil {
+ lastbody.Close() // assumed idempotent
+ lastbody = nil
+ }
+ resp, err := ReadResponse(pc.br, rc.req)
+
+ if err != nil {
+ pc.close()
+ } else {
+ hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
+ if rc.addedGzip && hasBody && resp.Header.Get("Content-Encoding") == "gzip" {
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
resp.ContentLength = -1
- gzReader, err := gzip.NewReader(resp.Body)
- if err != nil {
+ gzReader, zerr := gzip.NewReader(resp.Body)
+ if zerr != nil {
pc.close()
- return nil, err
+ err = zerr
+ } else {
+ resp.Body = &readFirstCloseBoth{&discardOnCloseReadCloser{gzReader}, resp.Body}
}
- 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
- // persistent connections on this again. We
- // hide this error to upstream callers.
- alive = false
- err = nil
- } else if err != nil || rc.req.Close {
+ if err != nil || resp.Close || rc.req.Close {
alive = false
}
@@ -544,9 +569,12 @@ func (pc *persistConn) readLoop() {
var waitForBodyRead chan bool
if alive {
if hasBody {
+ lastbody = resp.Body
waitForBodyRead = make(chan bool)
resp.Body.(*bodyEOFSignal).fn = func() {
- pc.t.putIdleConn(pc)
+ if !pc.t.putIdleConn(pc) {
+ alive = false
+ }
waitForBodyRead <- true
}
} else {
@@ -557,11 +585,11 @@ func (pc *persistConn) readLoop() {
// 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()
+ lastbody = nil
- pc.t.putIdleConn(pc)
+ if !pc.t.putIdleConn(pc) {
+ alive = false
+ }
}
}
@@ -577,7 +605,7 @@ func (pc *persistConn) readLoop() {
type responseAndError struct {
res *Response
- err os.Error
+ err error
}
type requestAndChan struct {
@@ -590,9 +618,9 @@ type requestAndChan struct {
addedGzip bool
}
-func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
- if pc.mutateRequestFunc != nil {
- pc.mutateRequestFunc(req)
+func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
+ if pc.mutateHeaderFunc != nil {
+ pc.mutateHeaderFunc(req.extraHeaders())
}
// Ask for a compressed version if the caller didn't set their
@@ -602,24 +630,25 @@ func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
requestedGzip := false
if !pc.t.DisableCompression && req.Header.Get("Accept-Encoding") == "" {
// Request gzip only, not deflate. Deflate is ambiguous and
- // as universally supported anyway.
+ // not as universally supported anyway.
// See: http://www.gzip.org/zlib/zlib_faq.html#faq38
requestedGzip = true
- req.Header.Set("Accept-Encoding", "gzip")
+ req.extraHeaders().Set("Accept-Encoding", "gzip")
}
pc.lk.Lock()
pc.numExpectedResponses++
pc.lk.Unlock()
- err = pc.cc.Write(req)
+ err = req.Request.write(pc.bw, pc.isProxy, req.extra)
if err != nil {
pc.close()
return
}
+ pc.bw.Flush()
ch := make(chan responseAndError, 1)
- pc.reqch <- requestAndChan{req, ch, requestedGzip}
+ pc.reqch <- requestAndChan{req.Request, ch, requestedGzip}
re := <-ch
pc.lk.Lock()
pc.numExpectedResponses--
@@ -631,10 +660,13 @@ func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
func (pc *persistConn) close() {
pc.lk.Lock()
defer pc.lk.Unlock()
+ pc.closeLocked()
+}
+
+func (pc *persistConn) closeLocked() {
pc.broken = true
- pc.cc.Close()
pc.conn.Close()
- pc.mutateRequestFunc = nil
+ pc.mutateHeaderFunc = nil
}
var portMap = map[string]string{
@@ -665,19 +697,19 @@ type bodyEOFSignal struct {
isClosed bool
}
-func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) {
+func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
n, err = es.body.Read(p)
if es.isClosed && n > 0 {
panic("http: unexpected bodyEOFSignal Read after Close; see issue 1725")
}
- if err == os.EOF && es.fn != nil {
+ if err == io.EOF && es.fn != nil {
es.fn()
es.fn = nil
}
return
}
-func (es *bodyEOFSignal) Close() (err os.Error) {
+func (es *bodyEOFSignal) Close() (err error) {
if es.isClosed {
return nil
}
@@ -695,7 +727,7 @@ type readFirstCloseBoth struct {
io.Closer
}
-func (r *readFirstCloseBoth) Close() os.Error {
+func (r *readFirstCloseBoth) Close() error {
if err := r.ReadCloser.Close(); err != nil {
r.Closer.Close()
return err
@@ -711,7 +743,7 @@ type discardOnCloseReadCloser struct {
io.ReadCloser
}
-func (d *discardOnCloseReadCloser) Close() os.Error {
+func (d *discardOnCloseReadCloser) Close() error {
io.Copy(ioutil.Discard, d.ReadCloser) // ignore errors; likely invalid or already closed
return d.ReadCloser.Close()
}
diff --git a/src/pkg/http/transport_test.go b/src/pkg/net/http/transport_test.go
index eafde7f89..a9e401de5 100644
--- a/src/pkg/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -11,16 +11,17 @@ import (
"compress/gzip"
"crypto/rand"
"fmt"
- . "http"
- "http/httptest"
"io"
"io/ioutil"
+ . "net/http"
+ "net/http/httptest"
+ "net/url"
"os"
+ "runtime"
"strconv"
"strings"
"testing"
"time"
- "url"
)
// TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close
@@ -77,8 +78,8 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
fetch := func(n int) string {
req := new(Request)
- var err os.Error
- req.URL, err = url.Parse(ts.URL + fmt.Sprintf("?close=%v", connectionClose))
+ var err error
+ req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose))
if err != nil {
t.Fatalf("URL parse error: %v", err)
}
@@ -119,7 +120,7 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
fetch := func(n int) string {
req := new(Request)
- var err os.Error
+ var err error
req.URL, err = url.Parse(ts.URL)
if err != nil {
t.Fatalf("URL parse error: %v", err)
@@ -264,7 +265,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
t.Fatalf(format, arg...)
}
t.Logf("retrying shortly after expected error: "+format, arg...)
- time.Sleep(1e9 / int64(retries))
+ time.Sleep(time.Second / time.Duration(retries))
}
for retries >= 0 {
retries--
@@ -293,7 +294,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
// it on most fast machines, causing the next fetch() call to
// succeed quickly. But if we do get errors, fetch() will retry 5
// times with some delays between.
- time.Sleep(25e6)
+ time.Sleep(25 * time.Millisecond)
body3 := fetch(3, 5)
@@ -305,6 +306,62 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
}
}
+// Test for http://golang.org/issue/2616 (appropriate issue number)
+// This fails pretty reliably with GOMAXPROCS=100 or something high.
+func TestStressSurpriseServerCloses(t *testing.T) {
+ if testing.Short() {
+ t.Logf("skipping test in short mode")
+ return
+ }
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Length", "5")
+ w.Header().Set("Content-Type", "text/plain")
+ w.Write([]byte("Hello"))
+ w.(Flusher).Flush()
+ conn, buf, _ := w.(Hijacker).Hijack()
+ buf.Flush()
+ conn.Close()
+ }))
+ defer ts.Close()
+
+ tr := &Transport{DisableKeepAlives: false}
+ c := &Client{Transport: tr}
+
+ // Do a bunch of traffic from different goroutines. Send to activityc
+ // after each request completes, regardless of whether it failed.
+ const (
+ numClients = 50
+ reqsPerClient = 250
+ )
+ activityc := make(chan bool)
+ for i := 0; i < numClients; i++ {
+ go func() {
+ for i := 0; i < reqsPerClient; i++ {
+ res, err := c.Get(ts.URL)
+ if err == nil {
+ // We expect errors since the server is
+ // hanging up on us after telling us to
+ // send more requests, so we don't
+ // actually care what the error is.
+ // But we want to close the body in cases
+ // where we won the race.
+ res.Body.Close()
+ }
+ activityc <- true
+ }
+ }()
+ }
+
+ // Make sure all the request come back, one way or another.
+ for i := 0; i < numClients*reqsPerClient; i++ {
+ select {
+ case <-activityc:
+ case <-time.After(5 * time.Second):
+ t.Fatalf("presumed deadlock; no HTTP client activity seen in awhile")
+ }
+ }
+}
+
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
@@ -362,32 +419,6 @@ func TestTransportHeadChunkedResponse(t *testing.T) {
}
}
-func TestTransportNilURL(t *testing.T) {
- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
- fmt.Fprintf(w, "Hi")
- }))
- defer ts.Close()
-
- req := new(Request)
- req.URL = nil // what we're actually testing
- req.Method = "GET"
- req.RawURL = ts.URL
- req.Proto = "HTTP/1.1"
- req.ProtoMajor = 1
- req.ProtoMinor = 1
- req.Header = make(Header)
-
- tr := &Transport{}
- res, err := tr.RoundTrip(req)
- if err != nil {
- t.Fatalf("unexpected RoundTrip error: %v", err)
- }
- body, err := ioutil.ReadAll(res.Body)
- if g, e := string(body), "Hi"; g != e {
- t.Fatalf("Expected response body of %q; got %q", e, g)
- }
-}
-
var roundTripTests = []struct {
accept string
expectAccept string
@@ -398,7 +429,8 @@ var roundTripTests = []struct {
// Requests with other accept-encoding should pass through unmodified
{"foo", "foo", false},
// Requests with accept-encoding == gzip should be passed through
- {"gzip", "gzip", true}}
+ {"gzip", "gzip", true},
+}
// Test that the modification made to the Request by the RoundTripper is cleaned up
func TestRoundTripGzip(t *testing.T) {
@@ -406,11 +438,12 @@ func TestRoundTripGzip(t *testing.T) {
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)
+ t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q",
+ req.FormValue("testnum"), accept, expect)
}
if accept == "gzip" {
rw.Header().Set("Content-Encoding", "gzip")
- gz, _ := gzip.NewWriter(rw)
+ gz := gzip.NewWriter(rw)
gz.Write([]byte(responseBody))
gz.Close()
} else {
@@ -422,12 +455,18 @@ func TestRoundTripGzip(t *testing.T) {
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)
+ req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil)
+ if test.accept != "" {
+ req.Header.Set("Accept-Encoding", test.accept)
+ }
res, err := DefaultTransport.RoundTrip(req)
var body []byte
if test.compressed {
- gzip, _ := gzip.NewReader(res.Body)
+ gzip, err := gzip.NewReader(res.Body)
+ if err != nil {
+ t.Errorf("%d. gzip NewReader: %v", i, err)
+ continue
+ }
body, err = ioutil.ReadAll(gzip)
res.Body.Close()
} else {
@@ -435,16 +474,16 @@ func TestRoundTripGzip(t *testing.T) {
}
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)
- }
+ continue
+ }
+ 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 (it was mutated, in violation of RoundTrip contract)", 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)
}
}
@@ -471,10 +510,10 @@ func TestTransportGzip(t *testing.T) {
rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
}()
}
- gz, _ := gzip.NewWriter(w)
+ gz := gzip.NewWriter(w)
gz.Write([]byte(testString))
if req.FormValue("body") == "large" {
- io.Copyn(gz, rand.Reader, nRandBytes)
+ io.CopyN(gz, rand.Reader, nRandBytes)
}
gz.Close()
}))
@@ -484,7 +523,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)
}
@@ -504,7 +543,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)
}
@@ -595,9 +634,99 @@ func TestTransportGzipRecursive(t *testing.T) {
}
}
+// tests that persistent goroutine connections shut down when no longer desired.
+func TestTransportPersistConnLeak(t *testing.T) {
+ gotReqCh := make(chan bool)
+ unblockCh := make(chan bool)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ gotReqCh <- true
+ <-unblockCh
+ w.Header().Set("Content-Length", "0")
+ w.WriteHeader(204)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ n0 := runtime.NumGoroutine()
+
+ const numReq = 25
+ didReqCh := make(chan bool)
+ for i := 0; i < numReq; i++ {
+ go func() {
+ res, err := c.Get(ts.URL)
+ didReqCh <- true
+ if err != nil {
+ t.Errorf("client fetch error: %v", err)
+ return
+ }
+ res.Body.Close()
+ }()
+ }
+
+ // Wait for all goroutines to be stuck in the Handler.
+ for i := 0; i < numReq; i++ {
+ <-gotReqCh
+ }
+
+ nhigh := runtime.NumGoroutine()
+
+ // Tell all handlers to unblock and reply.
+ for i := 0; i < numReq; i++ {
+ unblockCh <- true
+ }
+
+ // Wait for all HTTP clients to be done.
+ for i := 0; i < numReq; i++ {
+ <-didReqCh
+ }
+
+ tr.CloseIdleConnections()
+ time.Sleep(100 * time.Millisecond)
+ runtime.GC()
+ runtime.GC() // even more.
+ nfinal := runtime.NumGoroutine()
+
+ growth := nfinal - n0
+
+ // We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
+ // Previously we were leaking one per numReq.
+ t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
+ if int(growth) > 5 {
+ t.Error("too many new goroutines")
+ }
+}
+
+// This used to crash; http://golang.org/issue/3266
+func TestTransportIdleConnCrash(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ unblockCh := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ <-unblockCh
+ tr.CloseIdleConnections()
+ }))
+ defer ts.Close()
+
+ didreq := make(chan bool)
+ go func() {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ } else {
+ res.Body.Close() // returns idle conn
+ }
+ didreq <- true
+ }()
+ unblockCh <- true
+ <-didreq
+}
+
type fooProto struct{}
-func (fooProto) RoundTrip(req *Request) (*Response, os.Error) {
+func (fooProto) RoundTrip(req *Request) (*Response, error) {
res := &Response{
Status: "200 OK",
StatusCode: 200,
@@ -625,6 +754,36 @@ func TestTransportAltProto(t *testing.T) {
}
}
+var proxyFromEnvTests = []struct {
+ env string
+ wanturl string
+ wanterr error
+}{
+ {"127.0.0.1:8080", "http://127.0.0.1:8080", nil},
+ {"http://127.0.0.1:8080", "http://127.0.0.1:8080", nil},
+ {"https://127.0.0.1:8080", "https://127.0.0.1:8080", nil},
+ {"", "<nil>", nil},
+}
+
+func TestProxyFromEnvironment(t *testing.T) {
+ os.Setenv("HTTP_PROXY", "")
+ os.Setenv("http_proxy", "")
+ os.Setenv("NO_PROXY", "")
+ os.Setenv("no_proxy", "")
+ for i, tt := range proxyFromEnvTests {
+ os.Setenv("HTTP_PROXY", tt.env)
+ req, _ := NewRequest("GET", "http://example.com", nil)
+ url, err := ProxyFromEnvironment(req)
+ if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
+ t.Errorf("%d. got error = %q, want %q", i, g, e)
+ continue
+ }
+ if got := fmt.Sprintf("%s", url); got != tt.wanturl {
+ t.Errorf("%d. got URL = %q, want %q", i, url, tt.wanturl)
+ }
+ }
+}
+
// rgz is a gzip quine that uncompresses to itself.
var rgz = []byte{
0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
diff --git a/src/pkg/http/triv.go b/src/pkg/net/http/triv.go
index a8fd99aa4..232d65089 100644
--- a/src/pkg/http/triv.go
+++ b/src/pkg/net/http/triv.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.
+// +build ignore
+
package main
import (
@@ -9,11 +11,13 @@ import (
"expvar"
"flag"
"fmt"
- "http"
"io"
"log"
+ "net/http"
"os"
+ "os/exec"
"strconv"
+ "sync"
)
// hello world, the web server
@@ -26,14 +30,21 @@ func HelloServer(w http.ResponseWriter, req *http.Request) {
// Simple counter server. POSTing to it will set the value.
type Counter struct {
- n int
+ mu sync.Mutex // protects n
+ n int
}
// This makes Counter satisfy the expvar.Var interface, so we can export
// it directly.
-func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
+func (ctr *Counter) String() string {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
+ return fmt.Sprintf("%d", ctr.n)
+}
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
switch req.Method {
case "GET":
ctr.n++
@@ -93,55 +104,36 @@ func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- r, w, err := os.Pipe()
- if err != nil {
- fmt.Fprintf(rw, "pipe: %s\n", err)
- return
- }
- p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
- defer r.Close()
- w.Close()
+ date, err := exec.Command("/bin/date").Output()
if err != nil {
- fmt.Fprintf(rw, "fork/exec: %s\n", err)
- return
- }
- defer p.Release()
- io.Copy(rw, r)
- wait, err := p.Wait(0)
- if err != nil {
- fmt.Fprintf(rw, "wait: %s\n", err)
- return
- }
- if !wait.Exited() || wait.ExitStatus() != 0 {
- fmt.Fprintf(rw, "date: %v\n", wait)
+ http.Error(rw, err.Error(), 500)
return
}
+ rw.Write(date)
}
func Logger(w http.ResponseWriter, req *http.Request) {
- log.Print(req.URL.Raw)
- w.WriteHeader(404)
- w.Write([]byte("oops"))
+ log.Print(req.URL)
+ http.Error(w, "oops", 404)
}
-var webroot = flag.String("root", "/home/rsc", "web root directory")
+var webroot = flag.String("root", os.Getenv("HOME"), "web root directory")
func main() {
flag.Parse()
// The counter is published as a variable directly.
ctr := new(Counter)
- http.Handle("/counter", ctr)
expvar.Publish("counter", ctr)
-
+ http.Handle("/counter", ctr)
http.Handle("/", http.HandlerFunc(Logger))
http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
- http.Handle("/flags", http.HandlerFunc(FlagServer))
- http.Handle("/args", http.HandlerFunc(ArgServer))
- http.Handle("/go/hello", http.HandlerFunc(HelloServer))
http.Handle("/chan", ChanCreate())
- http.Handle("/date", http.HandlerFunc(DateServer))
+ http.HandleFunc("/flags", FlagServer)
+ http.HandleFunc("/args", ArgServer)
+ http.HandleFunc("/go/hello", HelloServer)
+ http.HandleFunc("/date", DateServer)
err := http.ListenAndServe(":12345", nil)
if err != nil {
log.Panicln("ListenAndServe:", err)
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index 8a14cb232..ee23570a9 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -6,26 +6,16 @@
package net
-import (
- "bytes"
- "fmt"
- "os"
+import "errors"
+
+var (
+ errInvalidInterface = errors.New("net: invalid interface")
+ errInvalidInterfaceIndex = errors.New("net: invalid interface index")
+ errInvalidInterfaceName = errors.New("net: invalid interface name")
+ errNoSuchInterface = errors.New("net: no such interface")
+ errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
)
-// 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.
@@ -72,37 +62,37 @@ func (f Flags) String() string {
}
// Addrs returns interface addresses for a specific interface.
-func (ifi *Interface) Addrs() ([]Addr, os.Error) {
+func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil {
- return nil, os.NewError("net: invalid interface")
+ return nil, errInvalidInterface
}
return interfaceAddrTable(ifi.Index)
}
// MulticastAddrs returns multicast, joined group addresses for
// a specific interface.
-func (ifi *Interface) MulticastAddrs() ([]Addr, os.Error) {
+func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil {
- return nil, os.NewError("net: invalid interface")
+ return nil, errInvalidInterface
}
return interfaceMulticastAddrTable(ifi.Index)
}
-// Interfaces returns a list of the systems's network interfaces.
-func Interfaces() ([]Interface, os.Error) {
+// Interfaces returns a list of the system's network interfaces.
+func Interfaces() ([]Interface, error) {
return interfaceTable(0)
}
// InterfaceAddrs returns a list of the system's network interface
// addresses.
-func InterfaceAddrs() ([]Addr, os.Error) {
+func InterfaceAddrs() ([]Addr, error) {
return interfaceAddrTable(0)
}
// InterfaceByIndex returns the interface specified by index.
-func InterfaceByIndex(index int) (*Interface, os.Error) {
+func InterfaceByIndex(index int) (*Interface, error) {
if index <= 0 {
- return nil, os.NewError("net: invalid interface index")
+ return nil, errInvalidInterfaceIndex
}
ift, err := interfaceTable(index)
if err != nil {
@@ -111,13 +101,13 @@ func InterfaceByIndex(index int) (*Interface, os.Error) {
for _, ifi := range ift {
return &ifi, nil
}
- return nil, os.NewError("net: no such interface")
+ return nil, errNoSuchInterface
}
// InterfaceByName returns the interface specified by name.
-func InterfaceByName(name string) (*Interface, os.Error) {
+func InterfaceByName(name string) (*Interface, error) {
if name == "" {
- return nil, os.NewError("net: invalid interface name")
+ return nil, errInvalidInterfaceName
}
ift, err := interfaceTable(0)
if err != nil {
@@ -128,5 +118,5 @@ func InterfaceByName(name string) (*Interface, os.Error) {
return &ifi, nil
}
}
- return nil, os.NewError("net: no such interface")
+ return nil, errNoSuchInterface
}
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
index 2675f94b9..7f090d8d4 100644
--- a/src/pkg/net/interface_bsd.go
+++ b/src/pkg/net/interface_bsd.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.
+// +build darwin freebsd netbsd openbsd
+
// Network interface identification for BSD variants
package net
@@ -13,26 +15,20 @@ import (
)
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otheriwse it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
-func interfaceTable(ifindex int) ([]Interface, 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)
+func interfaceTable(ifindex int) ([]Interface, error) {
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
+ var ift []Interface
for _, m := range msgs {
switch v := m.(type) {
case *syscall.InterfaceMessage:
@@ -45,18 +41,16 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
}
}
}
-
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)
+func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
+ var ift []Interface
for _, s := range sas {
switch v := s.(type) {
case *syscall.SockaddrDatalink:
@@ -78,7 +72,6 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
ift = append(ift, ifi)
}
}
-
return ift, nil
}
@@ -105,24 +98,18 @@ func linkFlags(rawFlags int32) Flags {
// 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)
+func interfaceAddrTable(ifindex int) ([]Addr, error) {
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
+ var ifat []Addr
for _, m := range msgs {
switch v := m.(type) {
case *syscall.InterfaceAddrMessage:
@@ -131,41 +118,46 @@ func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
if err != nil {
return nil, err
}
- ifat = append(ifat, ifa...)
+ 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)
+func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
- for _, s := range sas {
-
+ ifa := &IPNet{}
+ for i, 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())
+ switch i {
+ case 0:
+ ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ case 1:
+ ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ }
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
+ switch i {
+ case 0:
+ ifa.Mask = make(IPMask, IPv6len)
+ copy(ifa.Mask, v.Addr[:])
+ case 1:
+ ifa.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
+ return ifa, nil
}
diff --git a/src/pkg/net/interface_darwin.go b/src/pkg/net/interface_darwin.go
index a7b68ad7f..0b5fb5fb9 100644
--- a/src/pkg/net/interface_darwin.go
+++ b/src/pkg/net/interface_darwin.go
@@ -14,24 +14,18 @@ import (
// 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)
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
+ var ifmat []Addr
for _, m := range msgs {
switch v := m.(type) {
case *syscall.InterfaceMulticastAddrMessage:
@@ -44,18 +38,16 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
}
}
}
-
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)
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
+ var ifmat []Addr
for _, s := range sas {
switch v := s.(type) {
case *syscall.SockaddrInet4:
@@ -75,6 +67,5 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Erro
ifmat = append(ifmat, ifma.toAddr())
}
}
-
return ifmat, nil
}
diff --git a/src/pkg/net/interface_freebsd.go b/src/pkg/net/interface_freebsd.go
index 20f506b08..3cba28fc6 100644
--- a/src/pkg/net/interface_freebsd.go
+++ b/src/pkg/net/interface_freebsd.go
@@ -14,24 +14,18 @@ import (
// 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)
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
+ tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+ if err != nil {
+ return nil, os.NewSyscallError("route rib", err)
}
- msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
- return nil, os.NewSyscallError("route message", e)
+ msgs, err := syscall.ParseRoutingMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("route message", err)
}
+ var ifmat []Addr
for _, m := range msgs {
switch v := m.(type) {
case *syscall.InterfaceMulticastAddrMessage:
@@ -44,18 +38,16 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
}
}
}
-
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)
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, os.NewSyscallError("route sockaddr", err)
}
+ var ifmat []Addr
for _, s := range sas {
switch v := s.(type) {
case *syscall.SockaddrInet4:
@@ -75,6 +67,5 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Erro
ifmat = append(ifmat, ifma.toAddr())
}
}
-
return ifmat, nil
}
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 3d2a0bb9f..825b20227 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -7,33 +7,26 @@
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
+// network interfaces. Otherwise 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)
+func interfaceTable(ifindex int) ([]Interface, error) {
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink rib", err)
}
- msgs, e = syscall.ParseNetlinkMessage(tab)
- if e != 0 {
- return nil, os.NewSyscallError("netlink message", e)
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink message", err)
}
+ var ift []Interface
for _, m := range msgs {
switch m.Header.Type {
case syscall.NLMSG_DONE:
@@ -41,21 +34,20 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
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)
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink routeattr", err)
}
- ifi := newLink(attrs, ifim)
+ ifi := newLink(ifim, attrs)
ift = append(ift, ifi)
}
}
}
-
done:
return ift, nil
}
-func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
@@ -101,49 +93,26 @@ func linkFlags(rawFlags uint32) Flags {
// 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)
+func interfaceAddrTable(ifindex int) ([]Addr, error) {
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
if err != nil {
- return nil, err
+ return nil, os.NewSyscallError("netlink rib", 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)
+ msgs, err := syscall.ParseNetlinkMessage(tab)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink message", err)
}
- ifat6, err = addrTable(msgs6, ifindex)
+
+ ifat, err := addrTable(msgs, ifindex)
if err != nil {
return nil, err
}
-
- return append(ifat4, ifat6...), nil
+ return ifat, nil
}
-func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
+func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
var ifat []Addr
-
for _, m := range msgs {
switch m.Header.Type {
case syscall.NLMSG_DONE:
@@ -151,112 +120,111 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
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)
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+ if err != nil {
+ return nil, os.NewSyscallError("netlink routeattr", err)
}
- ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
}
}
}
-
done:
return ifat, nil
}
-func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
- var ifat []Addr
-
+func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
+ ifa := &IPNet{}
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())
+ ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+ ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
case syscall.AF_INET6:
- ifa := &IPAddr{IP: make(IP, IPv6len)}
+ ifa.IP = make(IP, IPv6len)
copy(ifa.IP, a.Value[:])
- ifat = append(ifat, ifa.toAddr())
+ ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
}
}
}
-
- return ifat
+ return ifa
}
// 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) {
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
+ err error
ifi *Interface
- err os.Error
)
-
if ifindex > 0 {
ifi, err = InterfaceByIndex(ifindex)
if err != nil {
return nil, err
}
}
-
- ifmat4 := parseProcNetIGMP(ifi)
- ifmat6 := parseProcNetIGMP6(ifi)
-
+ ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
+ ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
return append(ifmat4, ifmat6...), nil
}
-func parseProcNetIGMP(ifi *Interface) []Addr {
- var (
- ifmat []Addr
- name string
- )
-
- fd, err := open("/proc/net/igmp")
+func parseProcNetIGMP(path string, ifi *Interface) []Addr {
+ fd, err := open(path)
if err != nil {
return nil
}
defer fd.close()
+ var (
+ ifmat []Addr
+ name string
+ )
fd.readLine() // skip first line
b := make([]byte, IPv4len)
for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
- f := getFields(l)
- switch len(f) {
- case 4:
+ f := splitAtBytes(l, " :\r\t\n")
+ if len(f) < 4 {
+ continue
+ }
+ switch {
+ case l[0] != ' ' && l[0] != '\t': // new interface line
+ name = f[1]
+ case len(f[0]) == 8:
if ifi == nil || name == ifi.Name {
- fmt.Sscanf(f[0], "%08x", &b)
+ for i := 0; i+1 < len(f[0]); i += 2 {
+ b[i/2], _ = xtoi2(f[0][i:i+2], 0)
+ }
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")
+func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
+ fd, err := open(path)
if err != nil {
return nil
}
defer fd.close()
+ var ifmat []Addr
b := make([]byte, IPv6len)
for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
- f := getFields(l)
+ f := splitAtBytes(l, " \r\t\n")
+ if len(f) < 6 {
+ continue
+ }
if ifi == nil || f[1] == ifi.Name {
- fmt.Sscanf(f[2], "%32x", &b)
+ for i := 0; i+1 < len(f[2]); i += 2 {
+ b[i/2], _ = xtoi2(f[2][i:i+2], 0)
+ }
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/src/pkg/net/interface_linux_test.go b/src/pkg/net/interface_linux_test.go
new file mode 100644
index 000000000..f14d1fe06
--- /dev/null
+++ b/src/pkg/net/interface_linux_test.go
@@ -0,0 +1,54 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "testing"
+
+const (
+ numOfTestIPv4MCAddrs = 14
+ numOfTestIPv6MCAddrs = 18
+)
+
+var (
+ igmpInterfaceTable = []Interface{
+ {Name: "lo"},
+ {Name: "eth0"}, {Name: "eth1"}, {Name: "eth2"},
+ {Name: "eth0.100"}, {Name: "eth0.101"}, {Name: "eth0.102"}, {Name: "eth0.103"},
+ {Name: "device1tap2"},
+ }
+ igmp6InterfaceTable = []Interface{
+ {Name: "lo"},
+ {Name: "eth0"}, {Name: "eth1"}, {Name: "eth2"},
+ {Name: "eth0.100"}, {Name: "eth0.101"}, {Name: "eth0.102"}, {Name: "eth0.103"},
+ {Name: "device1tap2"},
+ {Name: "pan0"},
+ }
+)
+
+func TestParseProcNet(t *testing.T) {
+ defer func() {
+ if p := recover(); p != nil {
+ t.Fatalf("panicked")
+ }
+ }()
+
+ var ifmat4 []Addr
+ for _, ifi := range igmpInterfaceTable {
+ ifmat := parseProcNetIGMP("testdata/igmp", &ifi)
+ ifmat4 = append(ifmat4, ifmat...)
+ }
+ if len(ifmat4) != numOfTestIPv4MCAddrs {
+ t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
+ }
+
+ var ifmat6 []Addr
+ for _, ifi := range igmp6InterfaceTable {
+ ifmat := parseProcNetIGMP6("testdata/igmp6", &ifi)
+ ifmat6 = append(ifmat6, ifmat...)
+ }
+ if len(ifmat6) != numOfTestIPv6MCAddrs {
+ t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
+ }
+}
diff --git a/src/pkg/net/interface_netbsd.go b/src/pkg/net/interface_netbsd.go
new file mode 100644
index 000000000..4150e9ad5
--- /dev/null
+++ b/src/pkg/net/interface_netbsd.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.
+
+// Network interface identification for NetBSD
+
+package net
+
+// 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, error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/interface_openbsd.go b/src/pkg/net/interface_openbsd.go
index f18149393..d8adb4676 100644
--- a/src/pkg/net/interface_openbsd.go
+++ b/src/pkg/net/interface_openbsd.go
@@ -6,11 +6,9 @@
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) {
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, nil
}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index 950de6c59..d4d7ce9c7 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -2,29 +2,29 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build plan9
+
// 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
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
-func interfaceTable(ifindex int) ([]Interface, os.Error) {
+func interfaceTable(ifindex int) ([]Interface, 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) {
+func interfaceAddrTable(ifindex int) ([]Addr, 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) {
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, nil
}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
index 0e4089abf..0a33bfdb5 100644
--- a/src/pkg/net/interface_test.go
+++ b/src/pkg/net/interface_test.go
@@ -22,52 +22,75 @@ func sameInterface(i, j *Interface) bool {
func TestInterfaces(t *testing.T) {
ift, err := Interfaces()
if err != nil {
- t.Fatalf("Interfaces() failed: %v", err)
+ 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)
+ t.Fatalf("InterfaceByIndex(%q) failed: %v", ifi.Index, err)
}
if !sameInterface(ifxi, &ifi) {
- t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *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)
+ 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.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, *ifxn, ifi)
}
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())
+ testInterfaceAddrs(t, &ifi)
+ testInterfaceMulticastAddrs(t, &ifi)
}
}
func TestInterfaceAddrs(t *testing.T) {
ifat, err := InterfaceAddrs()
if err != nil {
- t.Fatalf("InterfaceAddrs() failed: %v", err)
+ t.Fatalf("InterfaceAddrs failed: %v", err)
}
t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+ testAddrs(t, ifat)
+}
+
+func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatalf("Interface.Addrs failed: %v", err)
+ }
+ testAddrs(t, ifat)
+}
+
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+ }
+ testMulticastAddrs(t, ifmat)
+}
+func testAddrs(t *testing.T, ifat []Addr) {
for _, ifa := range ifat {
- t.Logf("interface address %q\n", ifa.String())
+ switch ifa.(type) {
+ case *IPAddr, *IPNet:
+ t.Logf("\tinterface address %q\n", ifa.String())
+ default:
+ t.Errorf("\tunexpected type: %T", ifa)
+ }
+ }
+}
+
+func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+ for _, ifma := range ifmat {
+ switch ifma.(type) {
+ case *IPAddr:
+ t.Logf("\tjoined group address %q\n", ifma.String())
+ default:
+ t.Errorf("\tunexpected type: %T", ifma)
+ }
}
}
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
index 7f5169c87..4368b3306 100644
--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -21,52 +21,52 @@ func bytePtrToString(p *uint8) string {
return string(a[:i])
}
-func getAdapterList() (*syscall.IpAdapterInfo, os.Error) {
+func getAdapterList() (*syscall.IpAdapterInfo, error) {
b := make([]byte, 1000)
l := uint32(len(b))
a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
- e := syscall.GetAdaptersInfo(a, &l)
- if e == syscall.ERROR_BUFFER_OVERFLOW {
+ err := syscall.GetAdaptersInfo(a, &l)
+ if err == syscall.ERROR_BUFFER_OVERFLOW {
b = make([]byte, l)
a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
- e = syscall.GetAdaptersInfo(a, &l)
+ err = syscall.GetAdaptersInfo(a, &l)
}
- if e != 0 {
- return nil, os.NewSyscallError("GetAdaptersInfo", e)
+ if err != nil {
+ return nil, os.NewSyscallError("GetAdaptersInfo", err)
}
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)
+func getInterfaceList() ([]syscall.InterfaceInfo, error) {
+ s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+ if err != nil {
+ return nil, os.NewSyscallError("Socket", err)
}
defer syscall.Closesocket(s)
ii := [20]syscall.InterfaceInfo{}
ret := uint32(0)
size := uint32(unsafe.Sizeof(ii))
- e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
- if e != 0 {
- return nil, os.NewSyscallError("WSAIoctl", e)
+ err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ if err != nil {
+ return nil, os.NewSyscallError("WSAIoctl", err)
}
c := ret / uint32(unsafe.Sizeof(ii[0]))
return ii[:c-1], nil
}
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otheriwse it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
-func interfaceTable(ifindex int) ([]Interface, os.Error) {
- ai, e := getAdapterList()
- if e != nil {
- return nil, e
+func interfaceTable(ifindex int) ([]Interface, error) {
+ ai, err := getAdapterList()
+ if err != nil {
+ return nil, err
}
- ii, e := getInterfaceList()
- if e != nil {
- return nil, e
+ ii, err := getInterfaceList()
+ if err != nil {
+ return nil, err
}
var ift []Interface
@@ -77,7 +77,7 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
row := syscall.MibIfRow{Index: index}
e := syscall.GetIfEntry(&row)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("GetIfEntry", e)
}
@@ -129,10 +129,10 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
// 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
+func interfaceAddrTable(ifindex int) ([]Addr, error) {
+ ai, err := getAdapterList()
+ if err != nil {
+ return nil, err
}
var ifat []Addr
@@ -153,6 +153,6 @@ func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
// 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) {
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, nil
}
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
index b0e2c4205..979d7acd5 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -12,8 +12,6 @@
package net
-import "os"
-
// IP address lengths (bytes).
const (
IPv4len = 4
@@ -21,11 +19,8 @@ const (
)
// An IP is a single IP address, an array of bytes.
-// Functions in this package accept either 4-byte (IP v4)
-// or 16-byte (IP v6) arrays as input. Unless otherwise
-// specified, functions in this package always return
-// IP addresses in 16-byte form using the canonical
-// embedding.
+// Functions in this package accept either 4-byte (IPv4)
+// or 16-byte (IPv6) arrays as input.
//
// Note that in this documentation, referring to an
// IP address as an IPv4 address or an IPv6 address
@@ -37,6 +32,12 @@ type IP []byte
// An IP mask is an IP address.
type IPMask []byte
+// An IPNet represents an IP network.
+type IPNet struct {
+ IP IP // network number
+ Mask IPMask // network mask
+}
+
// IPv4 returns the IP address (in 16-byte form) of the
// IPv4 address a.b.c.d.
func IPv4(a, b, c, d byte) IP {
@@ -51,20 +52,42 @@ func IPv4(a, b, c, d byte) IP {
var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
-// IPv4Mask returns the IP mask (in 16-byte form) of the
+// IPv4Mask returns the IP mask (in 4-byte form) of the
// IPv4 mask a.b.c.d.
func IPv4Mask(a, b, c, d byte) IPMask {
- p := make(IPMask, IPv6len)
- for i := 0; i < 12; i++ {
- p[i] = 0xff
- }
- p[12] = a
- p[13] = b
- p[14] = c
- p[15] = d
+ p := make(IPMask, IPv4len)
+ p[0] = a
+ p[1] = b
+ p[2] = c
+ p[3] = d
return p
}
+// CIDRMask returns an IPMask consisting of `ones' 1 bits
+// followed by 0s up to a total length of `bits' bits.
+// For a mask of this form, CIDRMask is the inverse of IPMask.Size.
+func CIDRMask(ones, bits int) IPMask {
+ if bits != 8*IPv4len && bits != 8*IPv6len {
+ return nil
+ }
+ if ones < 0 || ones > bits {
+ return nil
+ }
+ l := bits / 8
+ m := make(IPMask, l)
+ n := uint(ones)
+ for i := 0; i < l; i++ {
+ if n >= 8 {
+ m[i] = 0xff
+ n -= 8
+ continue
+ }
+ m[i] = ^byte(0xff >> n)
+ n = 0
+ }
+ return m
+}
+
// Well-known IPv4 addresses
var (
IPv4bcast = IPv4(255, 255, 255, 255) // broadcast
@@ -213,13 +236,13 @@ func allFF(b []byte) bool {
// Mask returns the result of masking the IP address ip with mask.
func (ip IP) Mask(mask IPMask) IP {
- n := len(ip)
- if len(mask) == 16 && len(ip) == 4 && allFF(mask[:12]) {
+ if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
mask = mask[12:]
}
- if len(mask) == 4 && len(ip) == 16 && bytesEqual(ip[:12], v4InV6Prefix) {
+ if len(mask) == IPv4len && len(ip) == IPv6len && bytesEqual(ip[:12], v4InV6Prefix) {
ip = ip[12:]
}
+ n := len(ip)
if n != len(mask) {
return nil
}
@@ -230,40 +253,6 @@ func (ip IP) Mask(mask IPMask) IP {
return out
}
-// Convert i to decimal string.
-func itod(i uint) string {
- if i == 0 {
- return "0"
- }
-
- // Assemble decimal in reverse order.
- var b [32]byte
- bp := len(b)
- for ; i > 0; i /= 10 {
- bp--
- b[bp] = byte(i%10) + '0'
- }
-
- return string(b[bp:])
-}
-
-// Convert i to hexadecimal string.
-func itox(i uint) string {
- if i == 0 {
- return "0"
- }
-
- // Assemble hexadecimal in reverse order.
- var b [32]byte
- bp := len(b)
- for ; i > 0; i /= 16 {
- bp--
- b[bp] = "0123456789abcdef"[byte(i%16)]
- }
-
- return string(b[bp:])
-}
-
// String returns the string form of the IP address ip.
// If the address is an IPv4 address, the string representation
// is dotted decimal ("74.125.19.99"). Otherwise the representation
@@ -272,11 +261,11 @@ func (ip IP) String() string {
p := ip
if len(ip) == 0 {
- return ""
+ return "<nil>"
}
// If IPv4, use dotted notation.
- if p4 := p.To4(); len(p4) == 4 {
+ if p4 := p.To4(); len(p4) == IPv4len {
return itod(uint(p4[0])) + "." +
itod(uint(p4[1])) + "." +
itod(uint(p4[2])) + "." +
@@ -289,9 +278,9 @@ func (ip IP) String() string {
// Find longest run of zeros.
e0 := -1
e1 := -1
- for i := 0; i < 16; i += 2 {
+ for i := 0; i < IPv6len; i += 2 {
j := i
- for j < 16 && p[j] == 0 && p[j+1] == 0 {
+ for j < IPv6len && p[j] == 0 && p[j+1] == 0 {
j += 2
}
if j > i && j-i > e1-e0 {
@@ -307,17 +296,17 @@ func (ip IP) String() string {
// Print with possible :: in place of run of zeros
var s string
- for i := 0; i < 16; i += 2 {
+ for i := 0; i < IPv6len; i += 2 {
if i == e0 {
s += "::"
i = e1
- if i >= 16 {
+ if i >= IPv6len {
break
}
} else if i > 0 {
s += ":"
}
- s += itox((uint(p[i]) << 8) | uint(p[i+1]))
+ s += itox((uint(p[i])<<8)|uint(p[i+1]), 1)
}
return s
}
@@ -329,10 +318,10 @@ func (ip IP) Equal(x IP) bool {
if len(ip) == len(x) {
return bytesEqual(ip, x)
}
- if len(ip) == 4 && len(x) == 16 {
+ if len(ip) == IPv4len && len(x) == IPv6len {
return bytesEqual(x[0:12], v4InV6Prefix) && bytesEqual(ip, x[12:])
}
- if len(ip) == 16 && len(x) == 4 {
+ if len(ip) == IPv6len && len(x) == IPv4len {
return bytesEqual(ip[0:12], v4InV6Prefix) && bytesEqual(ip[12:], x)
}
return false
@@ -379,27 +368,91 @@ func simpleMaskLength(mask IPMask) int {
return n
}
-// String returns the string representation of mask.
-// If the mask is in the canonical form--ones followed by zeros--the
-// string representation is just the decimal number of ones.
-// If the mask is in a non-canonical form, it is formatted
-// as an IP address.
-func (mask IPMask) String() string {
- switch len(mask) {
- case 4:
- n := simpleMaskLength(mask)
- if n >= 0 {
- return itod(uint(n + (IPv6len-IPv4len)*8))
+// Size returns the number of leading ones and total bits in the mask.
+// If the mask is not in the canonical form--ones followed by zeros--then
+// Size returns 0, 0.
+func (m IPMask) Size() (ones, bits int) {
+ ones, bits = simpleMaskLength(m), len(m)*8
+ if ones == -1 {
+ return 0, 0
+ }
+ return
+}
+
+// String returns the hexadecimal form of m, with no punctuation.
+func (m IPMask) String() string {
+ s := ""
+ for _, b := range m {
+ s += itox(uint(b), 2)
+ }
+ if len(s) == 0 {
+ return "<nil>"
+ }
+ return s
+}
+
+func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
+ if ip = n.IP.To4(); ip == nil {
+ ip = n.IP
+ if len(ip) != IPv6len {
+ return nil, nil
}
- case 16:
- n := simpleMaskLength(mask)
- if n >= 12*8 {
- return itod(uint(n - 12*8))
+ }
+ m = n.Mask
+ switch len(m) {
+ case IPv4len:
+ if len(ip) != IPv4len {
+ return nil, nil
+ }
+ case IPv6len:
+ if len(ip) == IPv4len {
+ m = m[12:]
}
+ default:
+ return nil, nil
}
- return IP(mask).String()
+ return
}
+// Contains reports whether the network includes ip.
+func (n *IPNet) Contains(ip IP) bool {
+ nn, m := networkNumberAndMask(n)
+ if x := ip.To4(); x != nil {
+ ip = x
+ }
+ l := len(ip)
+ if l != len(nn) {
+ return false
+ }
+ for i := 0; i < l; i++ {
+ if nn[i]&m[i] != ip[i]&m[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// String returns the CIDR notation of n like "192.168.100.1/24"
+// or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291.
+// If the mask is not in the canonical form, it returns the
+// string which consists of an IP address, followed by a slash
+// character and a mask expressed as hexadecimal form with no
+// punctuation like "192.168.100.1/c000ff00".
+func (n *IPNet) String() string {
+ nn, m := networkNumberAndMask(n)
+ if nn == nil || m == nil {
+ return "<nil>"
+ }
+ l := simpleMaskLength(m)
+ if l == -1 {
+ return nn.String() + "/" + m.String()
+ }
+ return nn.String() + "/" + itod(uint(l))
+}
+
+// Network returns the address's network name, "ip+net".
+func (n *IPNet) Network() string { return "ip+net" }
+
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
@@ -440,7 +493,7 @@ func parseIPv4(s string) IP {
// * The last 32 bits can be in IPv4 form.
// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4.
func parseIPv6(s string) IP {
- p := make(IP, 16)
+ p := make(IP, IPv6len)
ellipsis := -1 // position of ellipsis in p
i := 0 // index in string s
@@ -482,7 +535,7 @@ func parseIPv6(s string) IP {
p[j+2] = p4[14]
p[j+3] = p4[15]
i = len(s)
- j += 4
+ j += IPv4len
break
}
@@ -542,7 +595,7 @@ type ParseError struct {
Text string
}
-func (e *ParseError) String() string {
+func (e *ParseError) Error() string {
return "invalid " + e.Type + ": " + e.Text
}
@@ -569,46 +622,28 @@ func ParseIP(s string) IP {
}
// ParseCIDR parses s as a CIDR notation IP address and mask,
-// like "192.168.100.1/24", "2001:DB8::/48", as defined in
+// like "192.168.100.1/24" or "2001:DB8::/48", as defined in
// RFC 4632 and RFC 4291.
-func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
+//
+// It returns the IP address and the network implied by the IP
+// and mask. For example, ParseCIDR("192.168.100.1/16") returns
+// the IP address 192.168.100.1 and the network 192.168.0.0/16.
+func ParseCIDR(s string) (IP, *IPNet, error) {
i := byteIndex(s, '/')
if i < 0 {
return nil, nil, &ParseError{"CIDR address", s}
}
ipstr, maskstr := s[:i], s[i+1:]
- iplen := 4
- ip = parseIPv4(ipstr)
+ iplen := IPv4len
+ ip := parseIPv4(ipstr)
if ip == nil {
- iplen = 16
+ iplen = IPv6len
ip = parseIPv6(ipstr)
}
- nn, i, ok := dtoi(maskstr, 0)
- if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*iplen {
+ n, i, ok := dtoi(maskstr, 0)
+ if ip == nil || !ok || i != len(maskstr) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{"CIDR address", s}
}
- n := uint(nn)
- if iplen == 4 {
- v4mask := ^uint32(0xffffffff >> n)
- mask = IPv4Mask(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))
- } else {
- mask = make(IPMask, 16)
- for i := 0; i < 16; i++ {
- if n >= 8 {
- mask[i] = 0xff
- n -= 8
- continue
- }
- mask[i] = ^byte(0xff >> n)
- n = 0
-
- }
- }
- // address must not have any bits not in mask
- for i := range ip {
- if ip[i]&^mask[i] != 0 {
- return nil, nil, &ParseError{"CIDR address", s}
- }
- }
- return ip, mask, nil
+ m := CIDRMask(n, 8*iplen)
+ return ip, &IPNet{ip.Mask(m), m}, nil
}
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index b189b10c4..df647ef73 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/net/ip_test.go
@@ -7,9 +7,8 @@ package net
import (
"bytes"
"reflect"
- "testing"
- "os"
"runtime"
+ "testing"
)
func isEqual(a, b []byte) bool {
@@ -34,12 +33,13 @@ var parseiptests = []struct {
{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+ {"", nil},
}
func TestParseIP(t *testing.T) {
for _, tt := range parseiptests {
if out := ParseIP(tt.in); !isEqual(out, tt.out) {
- t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
+ t.Errorf("ParseIP(%q) = %v, want %v", tt.in, out, tt.out)
}
}
}
@@ -49,60 +49,213 @@ 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},
- "2001:db8::123:12:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
- "2001:db8::1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
- "2001:db8:0:1:0:1:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
- "2001:db8:1:0:1:0:1:0"},
- {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
- "2001::1:0:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
- "2001:db8:0:0:1::"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
- "2001:db8::1:0:0:1"},
- {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
- "2001:db8::a:b:c:d"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "2001:db8::123:12:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0}, "2001:db8:1:0:1:0:1:0"},
+ {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001::1:0:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0}, "2001:db8:0:0:1::"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1:0:0:1"},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD}, "2001:db8::a:b:c:d"},
+ {nil, "<nil>"},
}
func TestIPString(t *testing.T) {
for _, tt := range ipstringtests {
if out := tt.in.String(); out != tt.out {
- t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
+ t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.out)
}
}
}
-var parsecidrtests = []struct {
- in string
- ip IP
+var ipmasktests = []struct {
+ in IP
mask IPMask
- err os.Error
+ out IP
+}{
+ {IPv4(192, 168, 1, 127), IPv4Mask(255, 255, 255, 128), IPv4(192, 168, 1, 0)},
+ {IPv4(192, 168, 1, 127), IPMask(ParseIP("255.255.255.192")), IPv4(192, 168, 1, 64)},
+ {IPv4(192, 168, 1, 127), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0")), IPv4(192, 168, 1, 96)},
+ {IPv4(192, 168, 1, 127), IPv4Mask(255, 0, 255, 0), IPv4(192, 0, 1, 0)},
+ {ParseIP("2001:db8::1"), IPMask(ParseIP("ffff:ff80::")), ParseIP("2001:d80::")},
+ {ParseIP("2001:db8::1"), IPMask(ParseIP("f0f0:0f0f::")), ParseIP("2000:d08::")},
+}
+
+func TestIPMask(t *testing.T) {
+ for _, tt := range ipmasktests {
+ if out := tt.in.Mask(tt.mask); out == nil || !tt.out.Equal(out) {
+ t.Errorf("IP(%v).Mask(%v) = %v, want %v", tt.in, tt.mask, out, tt.out)
+ }
+ }
+}
+
+var ipmaskstringtests = []struct {
+ in IPMask
+ out string
}{
- {"135.104.0.0/32", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255), nil},
- {"0.0.0.0/24", IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
- {"135.104.0.0/24", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
- {"135.104.0.1/32", IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255), nil},
- {"135.104.0.1/24", nil, nil, &ParseError{"CIDR address", "135.104.0.1/24"}},
- {"::1/128", ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")), nil},
- {"abcd:2345::/127", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")), nil},
- {"abcd:2345::/65", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::")), nil},
- {"abcd:2345::/64", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::")), nil},
- {"abcd:2345::/63", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::")), nil},
- {"abcd:2345::/33", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::")), nil},
- {"abcd:2345::/32", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::")), nil},
- {"abcd:2344::/31", ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::")), nil},
- {"abcd:2300::/24", ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::")), nil},
- {"abcd:2345::/24", nil, nil, &ParseError{"CIDR address", "abcd:2345::/24"}},
- {"2001:DB8::/48", ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::")), nil},
+ {IPv4Mask(255, 255, 255, 240), "fffffff0"},
+ {IPv4Mask(255, 0, 128, 0), "ff008000"},
+ {IPMask(ParseIP("ffff:ff80::")), "ffffff80000000000000000000000000"},
+ {IPMask(ParseIP("ef00:ff80::cafe:0")), "ef00ff800000000000000000cafe0000"},
+ {nil, "<nil>"},
+}
+
+func TestIPMaskString(t *testing.T) {
+ for _, tt := range ipmaskstringtests {
+ if out := tt.in.String(); out != tt.out {
+ t.Errorf("IPMask.String(%v) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+}
+
+var parsecidrtests = []struct {
+ in string
+ ip IP
+ net *IPNet
+ err error
+}{
+ {"135.104.0.0/32", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255)}, nil},
+ {"0.0.0.0/24", IPv4(0, 0, 0, 0), &IPNet{IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
+ {"135.104.0.0/24", IPv4(135, 104, 0, 0), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
+ {"135.104.0.1/32", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255)}, nil},
+ {"135.104.0.1/24", IPv4(135, 104, 0, 1), &IPNet{IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0)}, nil},
+ {"::1/128", ParseIP("::1"), &IPNet{ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
+ {"abcd:2345::/127", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
+ {"abcd:2345::/65", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
+ {"abcd:2345::/64", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
+ {"abcd:2345::/63", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
+ {"abcd:2345::/33", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::"))}, nil},
+ {"abcd:2345::/32", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::"))}, nil},
+ {"abcd:2344::/31", ParseIP("abcd:2344::"), &IPNet{ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::"))}, nil},
+ {"abcd:2300::/24", ParseIP("abcd:2300::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
+ {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::"))}, nil},
+ {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+ {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
+ {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
+ {"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
+ {"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
+ {"", nil, nil, &ParseError{"CIDR address", ""}},
}
func TestParseCIDR(t *testing.T) {
for _, tt := range parsecidrtests {
- if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
- t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
+ ip, net, err := ParseCIDR(tt.in)
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ParseCIDR(%q) = %v, %v; want %v, %v", tt.in, ip, net, tt.ip, tt.net)
+ }
+ if err == nil && (!tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !isEqual(net.Mask, tt.net.Mask)) {
+ t.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
+ }
+ }
+}
+
+var ipnetcontainstests = []struct {
+ ip IP
+ net *IPNet
+ ok bool
+}{
+ {IPv4(172, 16, 1, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(12, 32)}, true},
+ {IPv4(172, 24, 0, 1), &IPNet{IPv4(172, 16, 0, 0), CIDRMask(13, 32)}, false},
+ {IPv4(192, 168, 0, 3), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 0, 255, 252)}, true},
+ {IPv4(192, 168, 0, 4), &IPNet{IPv4(192, 168, 0, 0), IPv4Mask(0, 255, 0, 252)}, false},
+ {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), CIDRMask(47, 128)}, true},
+ {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:2::"), CIDRMask(47, 128)}, false},
+ {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("ffff:0:ffff::"))}, true},
+ {ParseIP("2001:db8:1:2::1"), &IPNet{ParseIP("2001:db8:1::"), IPMask(ParseIP("0:0:0:ffff::"))}, false},
+}
+
+func TestIPNetContains(t *testing.T) {
+ for _, tt := range ipnetcontainstests {
+ if ok := tt.net.Contains(tt.ip); ok != tt.ok {
+ t.Errorf("IPNet(%v).Contains(%v) = %v, want %v", tt.net, tt.ip, ok, tt.ok)
+ }
+ }
+}
+
+var ipnetstringtests = []struct {
+ in *IPNet
+ out string
+}{
+ {&IPNet{IPv4(192, 168, 1, 0), CIDRMask(26, 32)}, "192.168.1.0/26"},
+ {&IPNet{IPv4(192, 168, 1, 0), IPv4Mask(255, 0, 255, 0)}, "192.168.1.0/ff00ff00"},
+ {&IPNet{ParseIP("2001:db8::"), CIDRMask(55, 128)}, "2001:db8::/55"},
+ {&IPNet{ParseIP("2001:db8::"), IPMask(ParseIP("8000:f123:0:cafe::"))}, "2001:db8::/8000f1230000cafe0000000000000000"},
+}
+
+func TestIPNetString(t *testing.T) {
+ for _, tt := range ipnetstringtests {
+ if out := tt.in.String(); out != tt.out {
+ t.Errorf("IPNet.String(%v) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+}
+
+var cidrmasktests = []struct {
+ ones int
+ bits int
+ out IPMask
+}{
+ {0, 32, IPv4Mask(0, 0, 0, 0)},
+ {12, 32, IPv4Mask(255, 240, 0, 0)},
+ {24, 32, IPv4Mask(255, 255, 255, 0)},
+ {32, 32, IPv4Mask(255, 255, 255, 255)},
+ {0, 128, IPMask{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {4, 128, IPMask{0xf0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {48, 128, IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {128, 128, IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ {33, 32, nil},
+ {32, 33, nil},
+ {-1, 128, nil},
+ {128, -1, nil},
+}
+
+func TestCIDRMask(t *testing.T) {
+ for _, tt := range cidrmasktests {
+ if out := CIDRMask(tt.ones, tt.bits); !isEqual(out, tt.out) {
+ t.Errorf("CIDRMask(%v, %v) = %v, want %v", tt.ones, tt.bits, out, tt.out)
+ }
+ }
+}
+
+var (
+ v4addr = IP{192, 168, 0, 1}
+ v4mappedv6addr = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 0, 1}
+ v6addr = IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}
+ v4mask = IPMask{255, 255, 255, 0}
+ v4mappedv6mask = IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 255, 255, 255, 0}
+ v6mask = IPMask{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}
+ badaddr = IP{192, 168, 0}
+ badmask = IPMask{255, 255, 0}
+ v4maskzero = IPMask{0, 0, 0, 0}
+)
+
+var networknumberandmasktests = []struct {
+ in IPNet
+ out IPNet
+}{
+ {IPNet{v4addr, v4mask}, IPNet{v4addr, v4mask}},
+ {IPNet{v4addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
+ {IPNet{v4mappedv6addr, v4mappedv6mask}, IPNet{v4addr, v4mask}},
+ {IPNet{v4mappedv6addr, v6mask}, IPNet{v4addr, v4maskzero}},
+ {IPNet{v4addr, v6mask}, IPNet{v4addr, v4maskzero}},
+ {IPNet{v6addr, v6mask}, IPNet{v6addr, v6mask}},
+ {IPNet{v6addr, v4mappedv6mask}, IPNet{v6addr, v4mappedv6mask}},
+ {in: IPNet{v6addr, v4mask}},
+ {in: IPNet{v4addr, badmask}},
+ {in: IPNet{v4mappedv6addr, badmask}},
+ {in: IPNet{v6addr, badmask}},
+ {in: IPNet{badaddr, v4mask}},
+ {in: IPNet{badaddr, v4mappedv6mask}},
+ {in: IPNet{badaddr, v6mask}},
+ {in: IPNet{badaddr, badmask}},
+}
+
+func TestNetworkNumberAndMask(t *testing.T) {
+ for _, tt := range networknumberandmasktests {
+ ip, m := networkNumberAndMask(&tt.in)
+ out := &IPNet{ip, m}
+ if !reflect.DeepEqual(&tt.out, out) {
+ t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out)
}
}
}
@@ -158,10 +311,10 @@ var ipaftests = []struct {
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)
+ 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)
+ t.Errorf("verifying IPv6 address family for %q = %v, want %v", tt.in, af, tt.af6)
}
}
}
@@ -209,7 +362,7 @@ func name(f interface{}) string {
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)
+ t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
}
}
}
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 6894ce656..613620272 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -2,119 +2,205 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO(cw): ListenPacket test, Read() test, ipv6 test &
-// Dial()/Listen() level tests
-
package net
import (
"bytes"
- "flag"
"os"
+ "syscall"
"testing"
+ "time"
)
-const ICMP_ECHO_REQUEST = 8
-const ICMP_ECHO_REPLY = 0
-
-// returns a suitable 'ping request' packet, with id & seq and a
-// payload length of pktlen
-func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
- p := make([]byte, pktlen)
- copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
-
- p[0] = ICMP_ECHO_REQUEST // type
- p[1] = 0 // code
- p[2] = 0 // cksum
- p[3] = 0 // cksum
- p[4] = uint8(id >> 8) // id
- p[5] = uint8(id & 0xff) // id
- p[6] = uint8(seq >> 8) // sequence
- p[7] = uint8(seq & 0xff) // sequence
-
- // calculate icmp checksum
- cklen := len(p)
- s := uint32(0)
- for i := 0; i < (cklen - 1); i += 2 {
- s += uint32(p[i+1])<<8 | uint32(p[i])
- }
- if cklen&1 == 1 {
- s += uint32(p[cklen-1])
- }
- s = (s >> 16) + (s & 0xffff)
- s = s + (s >> 16)
-
- // place checksum back in header; using ^= avoids the
- // assumption the checksum bytes are zero
- p[2] ^= uint8(^s & 0xff)
- p[3] ^= uint8(^s >> 8)
-
- return p
-}
-
-func parsePingReply(p []byte) (id, seq int) {
- id = int(p[4])<<8 | int(p[5])
- seq = int(p[6])<<8 | int(p[7])
- return
+var icmpTests = []struct {
+ net string
+ laddr string
+ raddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+}{
+ {"ip4:icmp", "", "127.0.0.1", false},
+ {"ip6:icmp", "", "::1", true},
}
-var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
-// 127.0.0.1 because this is an IPv4-specific test.
-var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
-
-// test (raw) IP socket using ICMP
func TestICMP(t *testing.T) {
if os.Getuid() != 0 {
t.Logf("test disabled; must be root")
return
}
- var (
- laddr *IPAddr
- err os.Error
- )
- if *srchost != "" {
- laddr, err = ResolveIPAddr("ip4", *srchost)
- if err != nil {
- t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
+ seqnum := 61455
+ for _, tt := range icmpTests {
+ if tt.ipv6 && !supportsIPv6 {
+ continue
}
+ id := os.Getpid() & 0xffff
+ seqnum++
+ echo := newICMPEchoRequest(tt.net, id, seqnum, 128, []byte("Go Go Gadget Ping!!!"))
+ exchangeICMPEcho(t, tt.net, tt.laddr, tt.raddr, echo)
}
+}
- raddr, err := ResolveIPAddr("ip4", *dsthost)
+func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, echo []byte) {
+ c, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
+ t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ return
}
+ c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ defer c.Close()
- c, err := ListenIP("ip4:icmp", laddr)
+ ra, err := ResolveIPAddr(net, raddr)
if err != nil {
- t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
+ t.Errorf("ResolveIPAddr(%q, %q) failed: %v", net, raddr, err)
+ return
}
- sendid := os.Getpid() & 0xffff
- const sendseq = 61455
- const pingpktlen = 128
- sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
+ waitForReady := make(chan bool)
+ go icmpEchoTransponder(t, net, raddr, waitForReady)
+ <-waitForReady
- n, err := c.WriteToIP(sendpkt, raddr)
- if err != nil || n != pingpktlen {
- t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
+ _, err = c.WriteTo(echo, ra)
+ if err != nil {
+ t.Errorf("WriteTo failed: %v", err)
+ return
}
- c.SetTimeout(100e6)
- resp := make([]byte, 1024)
+ reply := make([]byte, 256)
for {
- n, from, err := c.ReadFrom(resp)
+ _, _, err := c.ReadFrom(reply)
if err != nil {
- t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
+ t.Errorf("ReadFrom failed: %v", err)
+ return
}
- if resp[0] != ICMP_ECHO_REPLY {
- continue
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
+ if reply[0] != ICMP4_ECHO_REPLY {
+ continue
+ }
+ case syscall.AF_INET6:
+ if reply[0] != ICMP6_ECHO_REPLY {
+ continue
+ }
}
- rcvid, rcvseq := parsePingReply(resp)
- if rcvid != sendid || rcvseq != sendseq {
- t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
+ xid, xseqnum := parseICMPEchoReply(echo)
+ rid, rseqnum := parseICMPEchoReply(reply)
+ if rid != xid || rseqnum != xseqnum {
+ t.Errorf("ID = %v, Seqnum = %v, want ID = %v, Seqnum = %v", rid, rseqnum, xid, xseqnum)
+ return
}
+ break
+ }
+}
+
+func icmpEchoTransponder(t *testing.T, net, raddr string, waitForReady chan bool) {
+ c, err := Dial(net, raddr)
+ if err != nil {
+ waitForReady <- true
+ t.Errorf("Dial(%q, %q) failed: %v", net, raddr, err)
return
}
- t.Fatalf("saw no ping return")
+ c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+ defer c.Close()
+ waitForReady <- true
+
+ echo := make([]byte, 256)
+ var nr int
+ for {
+ nr, err = c.Read(echo)
+ if err != nil {
+ t.Errorf("Read failed: %v", err)
+ return
+ }
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
+ if echo[0] != ICMP4_ECHO_REQUEST {
+ continue
+ }
+ case syscall.AF_INET6:
+ if echo[0] != ICMP6_ECHO_REQUEST {
+ continue
+ }
+ }
+ break
+ }
+
+ switch c.(*IPConn).fd.family {
+ case syscall.AF_INET:
+ echo[0] = ICMP4_ECHO_REPLY
+ case syscall.AF_INET6:
+ echo[0] = ICMP6_ECHO_REPLY
+ }
+
+ _, err = c.Write(echo[:nr])
+ if err != nil {
+ t.Errorf("Write failed: %v", err)
+ return
+ }
+}
+
+const (
+ ICMP4_ECHO_REQUEST = 8
+ ICMP4_ECHO_REPLY = 0
+ ICMP6_ECHO_REQUEST = 128
+ ICMP6_ECHO_REPLY = 129
+)
+
+func newICMPEchoRequest(net string, id, seqnum, msglen int, filler []byte) []byte {
+ afnet, _, _ := parseDialNetwork(net)
+ switch afnet {
+ case "ip4":
+ return newICMPv4EchoRequest(id, seqnum, msglen, filler)
+ case "ip6":
+ return newICMPv6EchoRequest(id, seqnum, msglen, filler)
+ }
+ return nil
+}
+
+func newICMPv4EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
+ b := newICMPInfoMessage(id, seqnum, msglen, filler)
+ b[0] = ICMP4_ECHO_REQUEST
+
+ // calculate ICMP checksum
+ cklen := len(b)
+ s := uint32(0)
+ for i := 0; i < cklen-1; i += 2 {
+ s += uint32(b[i+1])<<8 | uint32(b[i])
+ }
+ if cklen&1 == 1 {
+ s += uint32(b[cklen-1])
+ }
+ s = (s >> 16) + (s & 0xffff)
+ s = s + (s >> 16)
+ // place checksum back in header; using ^= avoids the
+ // assumption the checksum bytes are zero
+ b[2] ^= uint8(^s & 0xff)
+ b[3] ^= uint8(^s >> 8)
+
+ return b
+}
+
+func newICMPv6EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
+ b := newICMPInfoMessage(id, seqnum, msglen, filler)
+ b[0] = ICMP6_ECHO_REQUEST
+ return b
+}
+
+func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
+ b := make([]byte, msglen)
+ copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
+ b[0] = 0 // type
+ b[1] = 0 // code
+ b[2] = 0 // checksum
+ b[3] = 0 // checksum
+ b[4] = uint8(id >> 8) // identifier
+ b[5] = uint8(id & 0xff) // identifier
+ b[6] = uint8(seqnum >> 8) // sequence number
+ b[7] = uint8(seqnum & 0xff) // sequence number
+ return b
+}
+
+func parseICMPEchoReply(b []byte) (id, seqnum int) {
+ id = int(b[4])<<8 | int(b[5])
+ seqnum = int(b[6])<<8 | int(b[7])
+ return
}
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
index 662b9f57b..b23213ee1 100644
--- a/src/pkg/net/iprawsock.go
+++ b/src/pkg/net/iprawsock.go
@@ -6,10 +6,6 @@
package net
-import (
- "os"
-)
-
// IPAddr represents the address of a IP end point.
type IPAddr struct {
IP IP
@@ -29,7 +25,7 @@ func (a *IPAddr) String() string {
// 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(net, addr string) (*IPAddr, os.Error) {
+func ResolveIPAddr(net, addr string) (*IPAddr, error) {
ip, err := hostToIP(net, addr)
if err != nil {
return nil, err
@@ -38,7 +34,7 @@ func ResolveIPAddr(net, addr string) (*IPAddr, os.Error) {
}
// Convert "host" into IP address.
-func hostToIP(net, host string) (ip IP, err os.Error) {
+func hostToIP(net, host string) (ip IP, err error) {
var addr IP
// Try as an IP address.
addr = ParseIP(host)
diff --git a/src/pkg/net/iprawsock_plan9.go b/src/pkg/net/iprawsock_plan9.go
index 808e17974..43719fc99 100644
--- a/src/pkg/net/iprawsock_plan9.go
+++ b/src/pkg/net/iprawsock_plan9.go
@@ -7,28 +7,44 @@
package net
import (
- "os"
+ "syscall"
+ "time"
)
// IPConn is the implementation of the Conn and PacketConn
// interfaces for IP network connections.
type IPConn bool
+// SetDeadline implements the Conn SetDeadline method.
+func (c *IPConn) SetDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *IPConn) SetReadDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *IPConn) SetWriteDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
// 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
+// Read implements the Conn Read method.
+func (c *IPConn) Read(b []byte) (int, error) {
+ return 0, syscall.EPLAN9
}
-// Write implements the net.Conn Write method.
-func (c *IPConn) Write(b []byte) (n int, err os.Error) {
- return 0, os.EPLAN9
+// Write implements the Conn Write method.
+func (c *IPConn) Write(b []byte) (int, error) {
+ return 0, syscall.EPLAN9
}
// Close closes the IP connection.
-func (c *IPConn) Close() os.Error {
- return os.EPLAN9
+func (c *IPConn) Close() error {
+ return syscall.EPLAN9
}
// LocalAddr returns the local network address.
@@ -41,59 +57,49 @@ 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
-}
+// IP-specific methods.
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
- return os.EPLAN9
+// 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 SetDeadline and
+// SetReadDeadline.
+func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
+ return 0, nil, syscall.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
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
+ return 0, nil, syscall.EPLAN9
}
// 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.
+// see SetDeadline and SetWriteDeadline.
// 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 (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
+ return 0, syscall.EPLAN9
}
-func splitNetProto(netProto string) (net string, proto int, err os.Error) {
- err = os.EPLAN9
- return
+// WriteTo implements the PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
+ return 0, syscall.EPLAN9
}
-// 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
+// DialIP connects to the remote address raddr on the network protocol netProto,
+// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
+func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.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
+func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
+ return nil, syscall.EPLAN9
}
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 4e1151800..6bbe67c3d 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
// (Raw) IP sockets
package net
import (
"os"
- "sync"
"syscall"
+ "time"
)
-var onceReadProtocols sync.Once
-
func sockaddrToIP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
@@ -25,7 +25,7 @@ func sockaddrToIP(sa syscall.Sockaddr) Addr {
}
func (a *IPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
+ if a == nil || len(a.IP) <= IPv4len {
return syscall.AF_INET
}
if a.IP.To4() != nil {
@@ -34,7 +34,14 @@ func (a *IPAddr) family() int {
return syscall.AF_INET6
}
-func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+func (a *IPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
+func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0)
}
@@ -57,24 +64,24 @@ 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
+// Read implements the Conn Read method.
+func (c *IPConn) Read(b []byte) (int, error) {
+ n, _, err := c.ReadFrom(b)
+ return n, err
}
-// Write implements the net.Conn Write method.
-func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+// Write implements the Conn Write method.
+func (c *IPConn) Write(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
// Close closes the IP connection.
-func (c *IPConn) Close() os.Error {
+func (c *IPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -97,44 +104,44 @@ func (c *IPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *IPConn) SetTimeout(nsec int64) os.Error {
+// SetDeadline implements the Conn SetDeadline method.
+func (c *IPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *IPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *IPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
-func (c *IPConn) SetReadBuffer(bytes int) os.Error {
+func (c *IPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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 {
+func (c *IPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -146,19 +153,20 @@ func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
// 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) {
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
+func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
+ var addr *IPAddr
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
+ if len(b) >= IPv4len { // discard ipv4 header
hsize := (int(b[0]) & 0xf) * 4
copy(b, b[hsize:])
n -= hsize
@@ -166,13 +174,13 @@ func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
case *syscall.SockaddrInet6:
addr = &IPAddr{sa.Addr[0:]}
}
- return
+ return n, addr, err
}
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromIP(b)
return n, uaddr.toAddr(), err
@@ -182,81 +190,37 @@ func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
//
// WriteToIP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
- sa, err1 := addr.sockaddr(c.fd.family)
- if err1 != nil {
- return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
+ sa, err := addr.sockaddr(c.fd.family)
+ if err != nil {
+ return 0, &OpError{"write", c.fd.net, addr, err}
}
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) {
+// WriteTo implements the PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*IPAddr)
if !ok {
- return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.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)
+// DialIP connects to the remote address raddr on the network protocol netProto,
+// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
+func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+ net, proto, err := parseDialNetwork(netProto)
if err != nil {
- return
+ return nil, err
}
switch net {
case "ip", "ip4", "ip6":
@@ -264,11 +228,11 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
return nil, UnknownNetworkError(net)
}
if raddr == nil {
- return nil, &OpError{"dial", "ip", nil, errMissingAddress}
+ return nil, &OpError{"dial", netProto, nil, errMissingAddress}
}
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
- if e != nil {
- return nil, e
+ fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if err != nil {
+ return nil, err
}
return newIPConn(fd), nil
}
@@ -277,29 +241,24 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
// 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)
+func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
+ net, proto, err := parseDialNetwork(netProto)
if err != nil {
- return
+ return nil, err
}
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
+ fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "listen", sockaddrToIP)
+ if err != nil {
+ return nil, err
}
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))
-}
+// 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 *IPConn) File() (f *os.File, err error) { return c.fd.dup() }
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 4e2a5622b..bfbce18a4 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -6,14 +6,10 @@
package net
-import (
- "os"
-)
-
var supportsIPv6, supportsIPv4map = probeIPv6Stack()
func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
- if filter == anyaddr {
+ if filter == nil {
// 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
@@ -61,14 +57,14 @@ func ipv6only(x IP) IP {
type InvalidAddrError string
-func (e InvalidAddrError) String() string { return string(e) }
+func (e InvalidAddrError) Error() string { return string(e) }
func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
// 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.
-func SplitHostPort(hostport string) (host, port string, err os.Error) {
+func SplitHostPort(hostport string) (host, port string, err error) {
// The port starts after the last colon.
i := last(hostport, ':')
if i < 0 {
@@ -102,22 +98,18 @@ 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
- )
+func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
host, port, err := SplitHostPort(hostport)
if err != nil {
- goto Error
+ return nil, 0, err
}
+ var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
- filter := anyaddr
+ var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
@@ -125,34 +117,29 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
- addrs, err1 := LookupHost(host)
- if err1 != nil {
- err = err1
- goto Error
+ addrs, err := LookupHost(host)
+ if err != nil {
+ return nil, 0, err
}
addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
- err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
- goto Error
+ return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
}
}
}
- p, i, ok = dtoi(port, 0)
+ p, i, ok := dtoi(port, 0)
if !ok || i != len(port) {
p, err = LookupPort(net, port)
if err != nil {
- goto Error
+ return nil, 0, err
}
}
if p < 0 || p > 0xFFFF {
- err = &AddrError{"invalid port", port}
- goto Error
+ return nil, 0, &AddrError{"invalid port", port}
}
return addr, p, nil
-Error:
- return nil, 0, err
}
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index 9e5da6d38..eab0bf3e8 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -7,7 +7,11 @@
package net
import (
+ "errors"
+ "io"
"os"
+ "syscall"
+ "time"
)
// probeIPv6Stack returns two boolean values. If the first boolean value is
@@ -18,37 +22,26 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}
// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
-func parsePlan9Addr(s string) (ip IP, iport int, err os.Error) {
- var (
- addr IP
- p, i int
- ok bool
- )
- addr = IPv4zero // address contains port only
- i = byteIndex(s, '!')
+func parsePlan9Addr(s string) (ip IP, iport int, err error) {
+ 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
+ return nil, 0, errors.New("net: parsing IP failed")
}
}
- p, _, ok = dtoi(s[i+1:], 0)
+ p, _, ok := dtoi(s[i+1:], 0)
if !ok {
- err = os.NewError("net: parsing port failed")
- goto Error
+ return nil, 0, errors.New("net: parsing port failed")
}
if p < 0 || p > 0xFFFF {
- err = &AddrError{"invalid port", string(p)}
- goto Error
+ return nil, 0, &AddrError{"invalid port", string(p)}
}
return addr, p, nil
-
-Error:
- return nil, 0, err
}
-func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
+func readPlan9Addr(proto, filename string) (addr Addr, err error) {
var buf [128]byte
f, err := os.Open(filename)
@@ -69,7 +62,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
case "udp":
addr = &UDPAddr{ip, port}
default:
- return nil, os.NewError("unknown protocol " + proto)
+ return nil, errors.New("unknown protocol " + proto)
}
return addr, nil
}
@@ -88,10 +81,10 @@ 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) {
+// Read implements the Conn Read method.
+func (c *plan9Conn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -100,17 +93,17 @@ func (c *plan9Conn) Read(b []byte) (n int, err os.Error) {
}
}
n, err = c.data.Read(b)
- if c.proto == "udp" && err == os.EOF {
+ if c.proto == "udp" && err == io.EOF {
n = 0
err = nil
}
return
}
-// Write implements the net.Conn Write method.
-func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
+// Write implements the Conn Write method.
+func (c *plan9Conn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -122,9 +115,9 @@ func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
}
// Close closes the connection.
-func (c *plan9Conn) Close() os.Error {
+func (c *plan9Conn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.ctl.Close()
if err != nil {
@@ -154,31 +147,22 @@ func (c *plan9Conn) RemoteAddr() Addr {
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
+// SetDeadline implements the Conn SetDeadline method.
+func (c *plan9Conn) SetDeadline(t time.Time) error {
+ return syscall.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
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *plan9Conn) SetReadDeadline(t time.Time) error {
+ return syscall.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
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *plan9Conn) SetWriteDeadline(t time.Time) error {
+ return syscall.EPLAN9
}
-func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err os.Error) {
+func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
var (
ip IP
port int
@@ -213,7 +197,7 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
return f, dest, proto, string(buf[:n]), nil
}
-func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err os.Error) {
+func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err error) {
f, dest, proto, name, err := startPlan9(net, raddr)
if err != nil {
return
@@ -239,7 +223,7 @@ type plan9Listener struct {
laddr Addr
}
-func listenPlan9(net string, laddr Addr) (l *plan9Listener, err os.Error) {
+func listenPlan9(net string, laddr Addr) (l *plan9Listener, err error) {
f, dest, proto, name, err := startPlan9(net, laddr)
if err != nil {
return
@@ -265,7 +249,7 @@ 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) {
+func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err error) {
f, err := os.Open(l.dir + "/listen")
if err != nil {
return
@@ -287,7 +271,7 @@ func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err os.Error) {
return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
}
-func (l *plan9Listener) Accept() (c Conn, err os.Error) {
+func (l *plan9Listener) Accept() (c Conn, err error) {
c1, err := l.acceptPlan9()
if err != nil {
return
@@ -295,9 +279,9 @@ func (l *plan9Listener) Accept() (c Conn, err os.Error) {
return c1, nil
}
-func (l *plan9Listener) Close() os.Error {
+func (l *plan9Listener) Close() error {
if l == nil || l.ctl == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return l.ctl.Close()
}
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index 0c522fb7f..ed313195c 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/net/ipsock_posix.go
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
package net
-import (
- "os"
- "syscall"
-)
+import "syscall"
// Should we try to use the IPv4 socket interface if we're
// only dealing with IPv4 sockets? As long as the host system
@@ -34,17 +33,18 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}
for i := range probes {
- s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
- if errno != 0 {
+ s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if err != nil {
continue
}
defer closesocket(s)
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
if err != nil {
continue
}
- errno = syscall.Bind(s, sa)
- if errno != 0 {
+ err = syscall.Bind(s, sa)
+ if err != nil {
continue
}
probes[i].ok = true
@@ -54,75 +54,89 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}
// favoriteAddrFamily returns the appropriate address family to
-// the given net, raddr, laddr and mode. At first it figures
+// the given net, laddr, raddr 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 {
+// and laddr is a wildcard, it assumes that the user wants to
+// make a passive connection with a wildcard address family, both
+// AF_INET and AF_INET6, and a wildcard address like following:
+//
+// 1. A wild-wild listen, "tcp" + ""
+// If the platform supports both IPv6 and IPv6 IPv4-mapping
+// capabilities, we assume that the user want to listen on
+// both IPv4 and IPv6 wildcard address over an AF_INET6
+// socket with IPV6_V6ONLY=0. Otherwise we prefer an IPv4
+// wildcard address listen over an AF_INET socket.
+//
+// 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
+// Same as 1.
+//
+// 3. A wild-ipv6wild listen, "tcp" + "[::]"
+// Almost same as 1 but we prefer an IPv6 wildcard address
+// listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
+// the platform supports IPv6 capability but not IPv6 IPv4-
+// mapping capability.
+//
+// 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
+// We use an IPv4 (AF_INET) wildcard address listen.
+//
+// 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
+// We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
+// listen.
+//
+// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
+// or else returns AF_INET6. It also returns a boolean value what
+// designates IPV6_V6ONLY option.
+//
+// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
+// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
switch net[len(net)-1] {
case '4':
- return syscall.AF_INET
+ return syscall.AF_INET, false
case '6':
- return syscall.AF_INET6
+ return syscall.AF_INET6, true
}
- 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 mode == "listen" && laddr.isWildcard() {
+ if supportsIPv4map {
+ return syscall.AF_INET6, false
}
+ return laddr.family(), false
}
if (laddr == nil || laddr.family() == syscall.AF_INET) &&
(raddr == nil || raddr.family() == syscall.AF_INET) {
- return syscall.AF_INET
+ return syscall.AF_INET, false
}
- return syscall.AF_INET6
+ return syscall.AF_INET6, false
}
-// 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)
+// Internet sockets (TCP, UDP, IP)
-// A sockaddr represents a TCP or UDP network address that can
+// A sockaddr represents a TCP, UDP or IP network address that can
// be converted into a syscall.Sockaddr.
type sockaddr interface {
Addr
- sockaddr(family int) (syscall.Sockaddr, os.Error)
family() int
+ isWildcard() bool
+ sockaddr(family int) (syscall.Sockaddr, error)
}
-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
+func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
var la, ra syscall.Sockaddr
- family := favoriteAddrFamily(net, raddr, laddr, mode)
+ family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
if laddr != nil {
- if la, oserr = laddr.sockaddr(family); oserr != nil {
+ if la, err = laddr.sockaddr(family); err != nil {
goto Error
}
}
if raddr != nil {
- if ra, oserr = raddr.sockaddr(family); oserr != nil {
+ if ra, err = raddr.sockaddr(family); err != nil {
goto Error
}
}
- fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
- if oserr != nil {
+ fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, toAddr)
+ if err != nil {
goto Error
}
return fd, nil
@@ -132,10 +146,10 @@ Error:
if mode == "listen" {
addr = laddr
}
- return nil, &OpError{mode, net, addr, oserr}
+ return nil, &OpError{mode, net, addr, err}
}
-func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
+func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
switch family {
case syscall.AF_INET:
if len(ip) == 0 {
@@ -156,7 +170,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
}
// 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.
+ // which it refuses to do. Rewrite to the IPv6 unspecified address.
if ip.Equal(IPv4zero) {
ip = IPv6zero
}
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index 37d6b8e31..2c698304b 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -5,10 +5,12 @@
package net
import (
+ "errors"
"os"
+ "syscall"
)
-func query(filename, query string, bufSize int) (res []string, err os.Error) {
+func query(filename, query string, bufSize int) (res []string, err error) {
file, err := os.OpenFile(filename, os.O_RDWR, 0)
if err != nil {
return
@@ -34,7 +36,7 @@ func query(filename, query string, bufSize int) (res []string, err os.Error) {
return
}
-func queryCS(net, host, service string) (res []string, err os.Error) {
+func queryCS(net, host, service string) (res []string, err error) {
switch net {
case "tcp4", "tcp6":
net = "tcp"
@@ -47,9 +49,9 @@ func queryCS(net, host, service string) (res []string, err os.Error) {
return query("/net/cs", net+"!"+host+"!"+service, 128)
}
-func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) {
+func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
ips := "*"
- if !ip.IsUnspecified() {
+ if len(ip) != 0 && !ip.IsUnspecified() {
ips = ip.String()
}
lines, err := queryCS(net, ips, itoa(port))
@@ -58,20 +60,23 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) {
}
f := getFields(lines[0])
if len(f) < 2 {
- return "", "", os.NewError("net: bad response from ndb/cs")
+ return "", "", errors.New("net: bad response from ndb/cs")
}
clone, dest = f[0], f[1]
return
}
-func queryDNS(addr string, typ string) (res []string, err os.Error) {
+func queryDNS(addr string, typ string) (res []string, err 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
+func lookupProtocol(name string) (proto int, err error) {
+ // TODO: Implement this
+ return 0, syscall.EPLAN9
+}
+
+func lookupHost(host string) (addrs []string, err error) {
+ // Use /net/cs instead 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 {
@@ -94,9 +99,7 @@ func LookupHost(host string) (addrs []string, err os.Error) {
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) {
+func lookupIP(host string) (ips []IP, err error) {
addrs, err := LookupHost(host)
if err != nil {
return
@@ -109,8 +112,7 @@ func LookupIP(host string) (ips []IP, err os.Error) {
return
}
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
+func lookupPort(network, service string) (port int, err error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
@@ -139,11 +141,7 @@ func LookupPort(network, service string) (port int, err os.Error) {
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) {
+func lookupCNAME(name string) (cname string, err error) {
lines, err := queryDNS(name, "cname")
if err != nil {
return
@@ -153,16 +151,16 @@ func LookupCNAME(name string) (cname string, err os.Error) {
return f[2] + ".", nil
}
}
- return "", os.NewError("net: bad response from ndb/dns")
+ return "", errors.New("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
+func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+ var target string
+ if service == "" && proto == "" {
+ target = name
+ } else {
+ target = "_" + service + "._" + proto + "." + name
+ }
lines, err := queryDNS(target, "srv")
if err != nil {
return
@@ -185,8 +183,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return
}
-// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err os.Error) {
+func lookupMX(name string) (mx []*MX, err error) {
lines, err := queryDNS(name, "mx")
if err != nil {
return
@@ -204,9 +201,20 @@ func LookupMX(name string) (mx []*MX, err os.Error) {
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) {
+func lookupTXT(name string) (txt []string, err error) {
+ lines, err := queryDNS(name, "txt")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ if i := byteIndex(line, '\t'); i >= 0 {
+ txt = append(txt, line[i+1:])
+ }
+ }
+ return
+}
+
+func lookupAddr(addr string) (name []string, err error) {
arpa, err := reverseaddr(addr)
if err != nil {
return
diff --git a/src/pkg/net/lookup_test.go b/src/pkg/net/lookup_test.go
index 995ab03d0..3a61dfb29 100644
--- a/src/pkg/net/lookup_test.go
+++ b/src/pkg/net/lookup_test.go
@@ -8,14 +8,14 @@
package net
import (
- "runtime"
+ "flag"
"testing"
)
-var avoidMacFirewall = runtime.GOOS == "darwin"
+var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
func TestGoogleSRV(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -26,10 +26,19 @@ func TestGoogleSRV(t *testing.T) {
if len(addrs) == 0 {
t.Errorf("no results")
}
+
+ // Non-standard back door.
+ _, addrs, err = LookupSRV("", "", "_xmpp-server._tcp.google.com")
+ if err != nil {
+ t.Errorf("back door failed: %s", err)
+ }
+ if len(addrs) == 0 {
+ t.Errorf("back door no results")
+ }
}
func TestGmailMX(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -42,8 +51,22 @@ func TestGmailMX(t *testing.T) {
}
}
+func TestGmailTXT(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ txt, err := LookupTXT("gmail.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(txt) == 0 || len(txt[0]) == 0 {
+ t.Errorf("no results")
+ }
+}
+
func TestGoogleDNSAddr(t *testing.T) {
- if testing.Short() || avoidMacFirewall {
+ if testing.Short() || !*testExternal {
t.Logf("skipping test to avoid external network")
return
}
@@ -55,3 +78,40 @@ func TestGoogleDNSAddr(t *testing.T) {
t.Errorf("no results")
}
}
+
+var revAddrTests = []struct {
+ Addr string
+ Reverse string
+ ErrPrefix string
+}{
+ {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
+ {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
+ {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
+ {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
+ {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
+ {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
+ {"1.2.3", "", "unrecognized address"},
+ {"1.2.3.4.5", "", "unrecognized address"},
+ {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
+ {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+}
+
+func TestReverseAddress(t *testing.T) {
+ for i, tt := range revAddrTests {
+ a, err := reverseaddr(tt.Addr)
+ if len(tt.ErrPrefix) > 0 && err == nil {
+ t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
+ continue
+ }
+ if len(tt.ErrPrefix) == 0 && err != nil {
+ t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
+ }
+ if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
+ t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
+ }
+ if a != tt.Reverse {
+ t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ }
+ }
+}
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index 8f5e66212..d500a1240 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/net/lookup_unix.go
@@ -2,15 +2,57 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package net
import (
- "os"
+ "errors"
+ "sync"
+)
+
+var (
+ protocols map[string]int
+ onceReadProtocols sync.Once
)
-// 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) {
+// readProtocols loads contents of /etc/protocols into protocols map
+// for quick access.
+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()
+ }
+}
+
+// lookupProtocol looks up IP protocol name in /etc/protocols and
+// returns correspondent protocol number.
+func lookupProtocol(name string) (proto int, err error) {
+ onceReadProtocols.Do(readProtocols)
+ proto, found := protocols[name]
+ if !found {
+ return 0, errors.New("unknown IP protocol specified: " + name)
+ }
+ return
+}
+
+func lookupHost(host string) (addrs []string, err error) {
addrs, err, ok := cgoLookupHost(host)
if !ok {
addrs, err = goLookupHost(host)
@@ -18,9 +60,7 @@ func LookupHost(host string) (addrs []string, err os.Error) {
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) {
+func lookupIP(host string) (addrs []IP, err error) {
addrs, err, ok := cgoLookupIP(host)
if !ok {
addrs, err = goLookupIP(host)
@@ -28,8 +68,7 @@ func LookupIP(host string) (addrs []IP, err os.Error) {
return
}
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
+func lookupPort(network, service string) (port int, err error) {
port, err, ok := cgoLookupPort(network, service)
if !ok {
port, err = goLookupPort(network, service)
@@ -37,11 +76,7 @@ func LookupPort(network, service string) (port int, err os.Error) {
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) {
+func lookupCNAME(name string) (cname string, err error) {
cname, err, ok := cgoLookupCNAME(name)
if !ok {
cname, err = goLookupCNAME(name)
@@ -49,13 +84,13 @@ func LookupCNAME(name string) (cname string, err os.Error) {
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
+func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+ var target string
+ if service == "" && proto == "" {
+ target = name
+ } else {
+ target = "_" + service + "._" + proto + "." + name
+ }
var records []dnsRR
cname, records, err = lookup(target, dnsTypeSRV)
if err != nil {
@@ -70,24 +105,33 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
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)
+func lookupMX(name string) (mx []*MX, err error) {
+ _, records, err := lookup(name, dnsTypeMX)
if err != nil {
return
}
- mx = make([]*MX, len(rr))
- for i := range rr {
- r := rr[i].(*dnsRR_MX)
+ mx = make([]*MX, len(records))
+ for i, rr := range records {
+ r := rr.(*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) {
+func lookupTXT(name string) (txt []string, err error) {
+ _, records, err := lookup(name, dnsTypeTXT)
+ if err != nil {
+ return
+ }
+ txt = make([]string, len(records))
+ for i, r := range records {
+ txt[i] = r.(*dnsRR_TXT).Txt
+ }
+ return
+}
+
+func lookupAddr(addr string) (name []string, err error) {
name = lookupStaticAddr(addr)
if len(name) > 0 {
return
diff --git a/src/pkg/net/lookup_windows.go b/src/pkg/net/lookup_windows.go
index fa3ad7c7f..99783e975 100644
--- a/src/pkg/net/lookup_windows.go
+++ b/src/pkg/net/lookup_windows.go
@@ -5,16 +5,30 @@
package net
import (
- "syscall"
- "unsafe"
"os"
"sync"
+ "syscall"
+ "unsafe"
+)
+
+var (
+ protoentLock sync.Mutex
+ hostentLock sync.Mutex
+ serventLock sync.Mutex
)
-var hostentLock sync.Mutex
-var serventLock sync.Mutex
+// lookupProtocol looks up IP protocol name and returns correspondent protocol number.
+func lookupProtocol(name string) (proto int, err error) {
+ protoentLock.Lock()
+ defer protoentLock.Unlock()
+ p, err := syscall.GetProtoByName(name)
+ if err != nil {
+ return 0, os.NewSyscallError("GetProtoByName", err)
+ }
+ return int(p.Proto), nil
+}
-func LookupHost(name string) (addrs []string, err os.Error) {
+func lookupHost(name string) (addrs []string, err error) {
ips, err := LookupIP(name)
if err != nil {
return
@@ -26,12 +40,12 @@ func LookupHost(name string) (addrs []string, err os.Error) {
return
}
-func LookupIP(name string) (addrs []IP, err os.Error) {
+func lookupIP(name string) (addrs []IP, err error) {
hostentLock.Lock()
defer hostentLock.Unlock()
- h, e := syscall.GetHostByName(name)
- if e != 0 {
- return nil, os.NewSyscallError("GetHostByName", e)
+ h, err := syscall.GetHostByName(name)
+ if err != nil {
+ return nil, os.NewSyscallError("GetHostByName", err)
}
switch h.AddrType {
case syscall.AF_INET:
@@ -47,7 +61,7 @@ func LookupIP(name string) (addrs []IP, err os.Error) {
return addrs, nil
}
-func LookupPort(network, service string) (port int, err os.Error) {
+func lookupPort(network, service string) (port int, err error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
@@ -56,18 +70,18 @@ func LookupPort(network, service string) (port int, err os.Error) {
}
serventLock.Lock()
defer serventLock.Unlock()
- s, e := syscall.GetServByName(service, network)
- if e != 0 {
- return 0, os.NewSyscallError("GetServByName", e)
+ s, err := syscall.GetServByName(service, network)
+ if err != nil {
+ return 0, os.NewSyscallError("GetServByName", err)
}
return int(syscall.Ntohs(s.Port)), nil
}
-func LookupCNAME(name string) (cname string, err os.Error) {
+func lookupCNAME(name string) (cname string, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
- if int(e) != 0 {
- return "", os.NewSyscallError("LookupCNAME", int(e))
+ if e != nil {
+ return "", os.NewSyscallError("LookupCNAME", e)
}
defer syscall.DnsRecordListFree(r, 1)
if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
@@ -77,12 +91,17 @@ func LookupCNAME(name string) (cname string, err os.Error) {
return
}
-func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+ var target string
+ if service == "" && proto == "" {
+ target = name
+ } else {
+ target = "_" + service + "._" + proto + "." + name
+ }
var r *syscall.DNSRecord
- target := "_" + service + "._" + proto + "." + name
e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
- if int(e) != 0 {
- return "", nil, os.NewSyscallError("LookupSRV", int(e))
+ if e != nil {
+ return "", nil, os.NewSyscallError("LookupSRV", e)
}
defer syscall.DnsRecordListFree(r, 1)
addrs = make([]*SRV, 0, 10)
@@ -94,11 +113,11 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return name, addrs, nil
}
-func LookupMX(name string) (mx []*MX, err os.Error) {
+func lookupMX(name string) (mx []*MX, err 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))
+ if e != nil {
+ return nil, os.NewSyscallError("LookupMX", e)
}
defer syscall.DnsRecordListFree(r, 1)
mx = make([]*MX, 0, 10)
@@ -110,15 +129,33 @@ func LookupMX(name string) (mx []*MX, err os.Error) {
return mx, nil
}
-func LookupAddr(addr string) (name []string, err os.Error) {
+func lookupTXT(name string) (txt []string, err error) {
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
+ if e != nil {
+ return nil, os.NewSyscallError("LookupTXT", e)
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ txt = make([]string, 0, 10)
+ if r != nil && r.Type == syscall.DNS_TYPE_TEXT {
+ d := (*syscall.DNSTXTData)(unsafe.Pointer(&r.Data[0]))
+ for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
+ s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
+ txt = append(txt, s)
+ }
+ }
+ return
+}
+
+func lookupAddr(addr string) (name []string, err error) {
arpa, err := reverseaddr(addr)
if err != nil {
return nil, err
}
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))
+ if e != nil {
+ return nil, os.NewSyscallError("LookupAddr", e)
}
defer syscall.DnsRecordListFree(r, 1)
name = make([]string, 0, 10)
diff --git a/src/pkg/net/mac.go b/src/pkg/net/mac.go
new file mode 100644
index 000000000..d616b1f68
--- /dev/null
+++ b/src/pkg/net/mac.go
@@ -0,0 +1,86 @@
+// 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.
+
+// MAC address manipulations
+
+package net
+
+import "errors"
+
+const hexDigit = "0123456789abcdef"
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ if len(a) == 0 {
+ return ""
+ }
+ buf := make([]byte, 0, len(a)*3-1)
+ for i, b := range a {
+ if i > 0 {
+ buf = append(buf, ':')
+ }
+ buf = append(buf, hexDigit[b>>4])
+ buf = append(buf, hexDigit[b&0xF])
+ }
+ return string(buf)
+}
+
+// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
+// following formats:
+// 01:23:45:67:89:ab
+// 01:23:45:67:89:ab:cd:ef
+// 01-23-45-67-89-ab
+// 01-23-45-67-89-ab-cd-ef
+// 0123.4567.89ab
+// 0123.4567.89ab.cdef
+func ParseMAC(s string) (hw HardwareAddr, err error) {
+ if len(s) < 14 {
+ goto error
+ }
+
+ if s[2] == ':' || s[2] == '-' {
+ if (len(s)+1)%3 != 0 {
+ goto error
+ }
+ n := (len(s) + 1) / 3
+ if n != 6 && n != 8 {
+ goto error
+ }
+ hw = make(HardwareAddr, n)
+ for x, i := 0, 0; i < n; i++ {
+ var ok bool
+ if hw[i], ok = xtoi2(s[x:], s[2]); !ok {
+ goto error
+ }
+ x += 3
+ }
+ } else if s[4] == '.' {
+ if (len(s)+1)%5 != 0 {
+ goto error
+ }
+ n := 2 * (len(s) + 1) / 5
+ if n != 6 && n != 8 {
+ goto error
+ }
+ hw = make(HardwareAddr, n)
+ for x, i := 0, 0; i < n; i += 2 {
+ var ok bool
+ if hw[i], ok = xtoi2(s[x:x+2], 0); !ok {
+ goto error
+ }
+ if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok {
+ goto error
+ }
+ x += 5
+ }
+ } else {
+ goto error
+ }
+ return hw, nil
+
+error:
+ return nil, errors.New("invalid MAC address: " + s)
+}
diff --git a/src/pkg/net/mac_test.go b/src/pkg/net/mac_test.go
new file mode 100644
index 000000000..8f9dc6685
--- /dev/null
+++ b/src/pkg/net/mac_test.go
@@ -0,0 +1,66 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var mactests = []struct {
+ in string
+ out HardwareAddr
+ err string
+}{
+ {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""},
+ {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""},
+ {"01.02.03.04.05.06", nil, "invalid MAC address"},
+ {"01:02:03:04:05:06:", nil, "invalid MAC address"},
+ {"x1:02:03:04:05:06", nil, "invalid MAC address"},
+ {"01002:03:04:05:06", nil, "invalid MAC address"},
+ {"01:02003:04:05:06", nil, "invalid MAC address"},
+ {"01:02:03004:05:06", nil, "invalid MAC address"},
+ {"01:02:03:04005:06", nil, "invalid MAC address"},
+ {"01:02:03:04:05006", nil, "invalid MAC address"},
+ {"01-02:03:04:05:06", nil, "invalid MAC address"},
+ {"01:02-03-04-05-06", nil, "invalid MAC address"},
+ {"0123:4567:89AF", nil, "invalid MAC address"},
+ {"0123-4567-89AF", nil, "invalid MAC address"},
+ {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+ {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+ {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
+}
+
+func match(err error, s string) bool {
+ if s == "" {
+ return err == nil
+ }
+ return err != nil && strings.Contains(err.Error(), s)
+}
+
+func TestMACParseString(t *testing.T) {
+ for i, tt := range mactests {
+ out, err := ParseMAC(tt.in)
+ if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
+ t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
+ tt.err)
+ }
+ if tt.err == "" {
+ // Verify that serialization works too, and that it round-trips.
+ s := out.String()
+ out2, err := ParseMAC(s)
+ if err != nil {
+ t.Errorf("%d. ParseMAC(%q) = %v", i, s, err)
+ continue
+ }
+ if !reflect.DeepEqual(out2, out) {
+ t.Errorf("%d. ParseMAC(%q) = %v, want %v", i, s, out2, out)
+ }
+ }
+ }
+}
diff --git a/src/pkg/mail/message.go b/src/pkg/net/mail/message.go
index e227d17d6..0917bbedf 100644
--- a/src/pkg/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -19,12 +19,12 @@ import (
"bufio"
"bytes"
"encoding/base64"
+ "errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/textproto"
- "os"
"strconv"
"strings"
"time"
@@ -48,7 +48,7 @@ type Message struct {
// 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) {
+func ReadMessage(r io.Reader) (msg *Message, err error) {
tp := textproto.NewReader(bufio.NewReader(r))
hdr, err := tp.ReadMIMEHeader()
@@ -89,14 +89,14 @@ func init() {
}
}
-func parseDate(date string) (*time.Time, os.Error) {
+func parseDate(date string) (time.Time, error) {
for _, layout := range dateLayouts {
t, err := time.Parse(layout, date)
if err == nil {
return t, nil
}
}
- return nil, os.NewError("mail: header could not be parsed")
+ return time.Time{}, errors.New("mail: header could not be parsed")
}
// A Header represents the key-value pairs in a mail message header.
@@ -108,19 +108,19 @@ func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
-var ErrHeaderNotPresent = os.NewError("mail: header not in message")
+var ErrHeaderNotPresent = errors.New("mail: header not in message")
// Date parses the Date header field.
-func (h Header) Date() (*time.Time, os.Error) {
+func (h Header) Date() (time.Time, error) {
hdr := h.Get("Date")
if hdr == "" {
- return nil, ErrHeaderNotPresent
+ return time.Time{}, ErrHeaderNotPresent
}
return parseDate(hdr)
}
// AddressList parses the named header field as a list of addresses.
-func (h Header) AddressList(key string) ([]*Address, os.Error) {
+func (h Header) AddressList(key string) ([]*Address, error) {
hdr := h.Get(key)
if hdr == "" {
return nil, ErrHeaderNotPresent
@@ -185,11 +185,11 @@ func (a *Address) String() string {
type addrParser []byte
func newAddrParser(s string) *addrParser {
- p := addrParser([]byte(s))
+ p := addrParser(s)
return &p
}
-func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
+func (p *addrParser) parseAddressList() ([]*Address, error) {
var list []*Address
for {
p.skipSpace()
@@ -204,18 +204,18 @@ func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
break
}
if !p.consume(',') {
- return nil, os.NewError("mail: expected comma")
+ return nil, errors.New("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) {
+func (p *addrParser) parseAddress() (addr *Address, err error) {
debug.Printf("parseAddress: %q", *p)
p.skipSpace()
if p.empty() {
- return nil, os.NewError("mail: no address")
+ return nil, errors.New("mail: no address")
}
// address = name-addr / addr-spec
@@ -246,14 +246,14 @@ func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
// angle-addr = "<" addr-spec ">"
p.skipSpace()
if !p.consume('<') {
- return nil, os.NewError("mail: no angle-addr")
+ return nil, errors.New("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")
+ return nil, errors.New("mail: unclosed angle-addr")
}
debug.Printf("parseAddress: spec=%q", spec)
@@ -264,7 +264,7 @@ func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
}
// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
-func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
+func (p *addrParser) consumeAddrSpec() (spec string, err error) {
debug.Printf("consumeAddrSpec: %q", *p)
orig := *p
@@ -278,7 +278,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
var localPart string
p.skipSpace()
if p.empty() {
- return "", os.NewError("mail: no addr-spec")
+ return "", errors.New("mail: no addr-spec")
}
if p.peek() == '"' {
// quoted-string
@@ -295,14 +295,14 @@ func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
}
if !p.consume('@') {
- return "", os.NewError("mail: missing @ in addr-spec")
+ return "", errors.New("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")
+ return "", errors.New("mail: no domain in addr-spec")
}
// TODO(dsymonds): Handle domain-literal
domain, err = p.consumeAtom(true)
@@ -314,7 +314,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
}
// consumePhrase parses the RFC 5322 phrase at the start of p.
-func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
+func (p *addrParser) consumePhrase() (phrase string, err error) {
debug.Printf("consumePhrase: [%s]", *p)
// phrase = 1*word
var words []string
@@ -323,7 +323,7 @@ func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
var word string
p.skipSpace()
if p.empty() {
- return "", os.NewError("mail: missing phrase")
+ return "", errors.New("mail: missing phrase")
}
if p.peek() == '"' {
// quoted-string
@@ -347,28 +347,28 @@ func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
// Ignore any error if we got at least one word.
if err != nil && len(words) == 0 {
debug.Printf("consumePhrase: hit err: %v", err)
- return "", os.NewError("mail: missing word in phrase")
+ return "", errors.New("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) {
+func (p *addrParser) consumeQuotedString() (qs string, err 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")
+ return "", errors.New("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")
+ return "", errors.New("mail: unclosed quoted-string")
}
qsb = append(qsb, (*p)[i+1])
i += 2
@@ -387,15 +387,14 @@ Loop:
// 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) {
+func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
if !isAtext(p.peek(), false) {
- return "", os.NewError("mail: invalid string")
+ return "", errors.New("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:]
+ atom, *p = string((*p)[:i]), (*p)[i:]
return atom, nil
}
@@ -424,10 +423,10 @@ func (p *addrParser) len() int {
return len(*p)
}
-func decodeRFC2047Word(s string) (string, os.Error) {
+func decodeRFC2047Word(s string) (string, error) {
fields := strings.Split(s, "?")
if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
- return "", os.NewError("mail: address not RFC 2047 encoded")
+ return "", errors.New("mail: address not RFC 2047 encoded")
}
charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
if charset != "iso-8859-1" && charset != "utf-8" {
@@ -454,7 +453,7 @@ func decodeRFC2047Word(s string) (string, os.Error) {
case "iso-8859-1":
b := new(bytes.Buffer)
for _, c := range dec {
- b.WriteRune(int(c))
+ b.WriteRune(rune(c))
}
return b.String(), nil
case "utf-8":
@@ -468,7 +467,7 @@ type qDecoder struct {
scratch [2]byte
}
-func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
+func (qd qDecoder) Read(p []byte) (n int, err error) {
// This method writes at most one byte into p.
if len(p) == 0 {
return 0, nil
@@ -481,7 +480,7 @@ func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
return 0, err
}
- x, err := strconv.Btoi64(string(qd.scratch[:2]), 16)
+ x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64)
if err != nil {
return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
}
diff --git a/src/pkg/mail/message_test.go b/src/pkg/net/mail/message_test.go
index e1bcc89ee..671ff2efa 100644
--- a/src/pkg/mail/message_test.go
+++ b/src/pkg/net/mail/message_test.go
@@ -82,35 +82,18 @@ func headerEq(a, b Header) bool {
func TestDateParsing(t *testing.T) {
tests := []struct {
dateStr string
- exp *time.Time
+ exp time.Time
}{
// RFC 5322, Appendix A.1.1
{
"Fri, 21 Nov 1997 09:55:06 -0600",
- &time.Time{
- Year: 1997,
- Month: 11,
- Day: 21,
- Hour: 9,
- Minute: 55,
- Second: 6,
- Weekday: 5, // Fri
- ZoneOffset: -6 * 60 * 60,
- },
+ time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
},
// RFC5322, Appendix A.6.2
// Obsolete date.
{
"21 Nov 97 09:55:06 GMT",
- &time.Time{
- Year: 1997,
- Month: 11,
- Day: 21,
- Hour: 9,
- Minute: 55,
- Second: 6,
- Zone: "GMT",
- },
+ time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("GMT", 0)),
},
}
for _, test := range tests {
@@ -122,7 +105,7 @@ func TestDateParsing(t *testing.T) {
t.Errorf("Failed parsing %q: %v", test.dateStr, err)
continue
}
- if !reflect.DeepEqual(date, test.exp) {
+ if !date.Equal(test.exp) {
t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
}
}
@@ -136,14 +119,14 @@ func TestAddressParsing(t *testing.T) {
// Bare address
{
`jdoe@machine.example`,
- []*Address{&Address{
+ []*Address{{
Address: "jdoe@machine.example",
}},
},
// RFC 5322, Appendix A.1.1
{
`John Doe <jdoe@machine.example>`,
- []*Address{&Address{
+ []*Address{{
Name: "John Doe",
Address: "jdoe@machine.example",
}},
@@ -151,7 +134,7 @@ func TestAddressParsing(t *testing.T) {
// RFC 5322, Appendix A.1.2
{
`"Joe Q. Public" <john.q.public@example.com>`,
- []*Address{&Address{
+ []*Address{{
Name: "Joe Q. Public",
Address: "john.q.public@example.com",
}},
@@ -159,14 +142,14 @@ func TestAddressParsing(t *testing.T) {
{
`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",
},
@@ -175,10 +158,10 @@ func TestAddressParsing(t *testing.T) {
{
`<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>`,
[]*Address{
- &Address{
+ {
Address: "boss@nil.test",
},
- &Address{
+ {
Name: `Giant; "Big" Box`,
Address: "sysservices@example.net",
},
@@ -191,7 +174,7 @@ func TestAddressParsing(t *testing.T) {
{
`=?iso-8859-1?q?J=F6rg_Doe?= <joerg@example.com>`,
[]*Address{
- &Address{
+ {
Name: `Jörg Doe`,
Address: "joerg@example.com",
},
@@ -201,7 +184,7 @@ func TestAddressParsing(t *testing.T) {
{
`=?utf-8?q?J=C3=B6rg_Doe?= <joerg@example.com>`,
[]*Address{
- &Address{
+ {
Name: `Jörg Doe`,
Address: "joerg@example.com",
},
@@ -211,7 +194,7 @@ func TestAddressParsing(t *testing.T) {
{
`=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
[]*Address{
- &Address{
+ {
Name: `André Pirard`,
Address: "PIRARD@vm1.ulg.ac.be",
},
@@ -221,7 +204,7 @@ func TestAddressParsing(t *testing.T) {
{
`=?ISO-8859-1?B?SvZyZw==?= <joerg@example.com>`,
[]*Address{
- &Address{
+ {
Name: `Jörg`,
Address: "joerg@example.com",
},
@@ -231,7 +214,7 @@ func TestAddressParsing(t *testing.T) {
{
`=?UTF-8?B?SsO2cmc=?= <joerg@example.com>`,
[]*Address{
- &Address{
+ {
Name: `Jörg`,
Address: "joerg@example.com",
},
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index be6dbf2dc..67261b1ee 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -5,69 +5,230 @@
package net
import (
- "flag"
+ "errors"
+ "os"
"runtime"
+ "syscall"
"testing"
)
-var multicast = flag.Bool("multicast", false, "enable multicast tests")
+var multicastListenerTests = []struct {
+ net string
+ gaddr *UDPAddr
+ flags Flags
+ ipv6 bool // test with underlying AF_INET6 socket
+}{
+ // cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
-func TestMulticastJoinAndLeave(t *testing.T) {
- if runtime.GOOS == "windows" {
+ {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+ {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
+ {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
+
+ {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+ {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, 0, false},
+
+ {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, 0, true},
+ {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, 0, true},
+ {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, 0, true},
+ {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, 0, true},
+ {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, 0, true},
+ {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
+ {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, 0, true},
+}
+
+// TestMulticastListener tests both single and double listen to a test
+// listener with same address family, same group address and same port.
+func TestMulticastListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "netbsd", "openbsd", "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
+ case "linux":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+ t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
+ return
+ }
+ }
+
+ for _, tt := range multicastListenerTests {
+ if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
+ continue
+ }
+ ifi, err := availMulticastInterface(t, tt.flags)
+ if err != nil {
+ continue
+ }
+ c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("First ListenMulticastUDP failed: %v", err)
+ }
+ checkMulticastListener(t, err, c1, tt.gaddr)
+ c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("Second ListenMulticastUDP failed: %v", err)
+ }
+ checkMulticastListener(t, err, c2, tt.gaddr)
+ c2.Close()
+ switch c1.fd.family {
+ case syscall.AF_INET:
+ testIPv4MulticastSocketOptions(t, c1.fd, ifi)
+ case syscall.AF_INET6:
+ testIPv6MulticastSocketOptions(t, c1.fd, ifi)
+ }
+ c1.Close()
}
- if !*multicast {
- t.Logf("test disabled; use --multicast to enable")
+}
+
+func TestSimpleMulticastListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
+ case "windows":
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test on windows to avoid firewall")
+ return
+ }
}
- addr := &UDPAddr{
- IP: IPv4zero,
- Port: 0,
+ for _, tt := range multicastListenerTests {
+ if tt.ipv6 {
+ continue
+ }
+ tt.flags = FlagUp | FlagMulticast // for windows testing
+ ifi, err := availMulticastInterface(t, tt.flags)
+ if err != nil {
+ continue
+ }
+ c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("First ListenMulticastUDP failed: %v", err)
+ }
+ checkSimpleMulticastListener(t, err, c1, tt.gaddr)
+ c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
+ if err != nil {
+ t.Fatalf("Second ListenMulticastUDP failed: %v", err)
+ }
+ checkSimpleMulticastListener(t, err, c2, tt.gaddr)
+ c2.Close()
+ c1.Close()
}
- // open a UDPConn
- conn, err := ListenUDP("udp4", addr)
- if err != nil {
- t.Fatal(err)
+}
+
+func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
+ if !multicastRIBContains(t, gaddr.IP) {
+ t.Fatalf("%q not found in RIB", gaddr.String())
+ }
+ if c.LocalAddr().String() != gaddr.String() {
+ t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
}
- defer conn.Close()
+}
- // try to join group
- mcast := IPv4(224, 0, 0, 254)
- err = conn.JoinGroup(mcast)
- if err != nil {
- t.Fatal(err)
+func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
+ if c.LocalAddr().String() != gaddr.String() {
+ t.Fatalf("LocalAddr returns %q, expected %q", c.LocalAddr().String(), gaddr.String())
}
+}
- // try to leave group
- err = conn.LeaveGroup(mcast)
- if err != nil {
- t.Fatal(err)
+func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) {
+ var ifi *Interface
+ if flags != Flags(0) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces failed: %v", err)
+ }
+ for _, x := range ift {
+ if x.Flags&flags == flags {
+ ifi = &x
+ break
+ }
+ }
+ if ifi == nil {
+ return nil, errors.New("an appropriate multicast interface not found")
+ }
}
+ return ifi, nil
}
-func TestJoinFailureWithIPv6Address(t *testing.T) {
- if !*multicast {
- t.Logf("test disabled; use --multicast to enable")
- return
+func multicastRIBContains(t *testing.T, ip IP) bool {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces failed: %v", err)
}
- addr := &UDPAddr{
- IP: IPv4zero,
- Port: 0,
+ for _, ifi := range ift {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("MulticastAddrs failed: %v", err)
+ }
+ for _, ifma := range ifmat {
+ if ifma.(*IPAddr).IP.Equal(ip) {
+ return true
+ }
+ }
}
+ return false
+}
- // open a UDPConn
- conn, err := ListenUDP("udp4", addr)
+func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
+ _, err := ipv4MulticastInterface(fd)
if err != nil {
- t.Fatal(err)
+ t.Fatalf("ipv4MulticastInterface failed: %v", err)
+ }
+ if ifi != nil {
+ err = setIPv4MulticastInterface(fd, ifi)
+ if err != nil {
+ t.Fatalf("setIPv4MulticastInterface failed: %v", err)
+ }
}
- defer conn.Close()
+ _, err = ipv4MulticastTTL(fd)
+ if err != nil {
+ t.Fatalf("ipv4MulticastTTL failed: %v", err)
+ }
+ err = setIPv4MulticastTTL(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv4MulticastTTL failed: %v", err)
+ }
+ _, err = ipv4MulticastLoopback(fd)
+ if err != nil {
+ t.Fatalf("ipv4MulticastLoopback failed: %v", err)
+ }
+ err = setIPv4MulticastLoopback(fd, false)
+ if err != nil {
+ t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
+ }
+}
- // try to join group
- mcast := ParseIP("ff02::1")
- err = conn.JoinGroup(mcast)
- if err == nil {
- t.Fatal("JoinGroup succeeded, should fail")
+func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
+ _, err := ipv6MulticastInterface(fd)
+ if err != nil {
+ t.Fatalf("ipv6MulticastInterface failed: %v", err)
+ }
+ if ifi != nil {
+ err = setIPv6MulticastInterface(fd, ifi)
+ if err != nil {
+ t.Fatalf("setIPv6MulticastInterface failed: %v", err)
+ }
+ }
+ _, err = ipv6MulticastHopLimit(fd)
+ if err != nil {
+ t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
+ }
+ err = setIPv6MulticastHopLimit(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
+ }
+ _, err = ipv6MulticastLoopback(fd)
+ if err != nil {
+ t.Fatalf("ipv6MulticastLoopback failed: %v", err)
+ }
+ err = setIPv6MulticastLoopback(fd, false)
+ if err != nil {
+ t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
}
- t.Logf("%s", err)
}
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 5c84d3434..9ebcdbe99 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -2,14 +2,50 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package net provides a portable interface to Unix networks sockets,
-// including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
+/*
+Package net provides a portable interface for network I/O, including
+TCP/IP, UDP, domain name resolution, and Unix domain sockets.
+
+Although the package provides access to low-level networking
+primitives, most clients will need only the basic interface provided
+by the Dial, Listen, and Accept functions and the associated
+Conn and Listener interfaces. The crypto/tls package uses
+the same interfaces and similar Dial and Listen functions.
+
+The Dial function connects to a server:
+
+ conn, err := net.Dial("tcp", "google.com:80")
+ if err != nil {
+ // handle error
+ }
+ fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
+ status, err := bufio.NewReader(conn).ReadString('\n')
+ // ...
+
+The Listen function creates servers:
+
+ ln, err := net.Listen("tcp", ":8080")
+ if err != nil {
+ // handle error
+ }
+ for {
+ conn, err := ln.Accept()
+ if err != nil {
+ // handle error
+ continue
+ }
+ go handleConnection(conn)
+ }
+*/
package net
// TODO(rsc):
// support for raw ethernet sockets
-import "os"
+import (
+ "errors"
+ "time"
+)
// Addr represents a network end point address.
type Addr interface {
@@ -18,19 +54,22 @@ type Addr interface {
}
// Conn is a generic stream-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
- // Read can be made to time out and return a net.Error with Timeout() == true
- // after a fixed time limit; see SetTimeout and SetReadTimeout.
- Read(b []byte) (n int, err os.Error)
+ // Read can be made to time out and return a Error with Timeout() == true
+ // after a fixed time limit; see SetDeadline and SetReadDeadline.
+ Read(b []byte) (n int, err error)
// Write writes data to the connection.
- // Write can be made to time out and return a net.Error with Timeout() == true
- // after a fixed time limit; see SetTimeout and SetWriteTimeout.
- Write(b []byte) (n int, err os.Error)
+ // Write can be made to time out and return a Error with Timeout() == true
+ // after a fixed time limit; see SetDeadline and SetWriteDeadline.
+ Write(b []byte) (n int, err error)
// Close closes the connection.
- Close() os.Error
+ // Any blocked Read or Write operations will be unblocked and return errors.
+ Close() error
// LocalAddr returns the local network address.
LocalAddr() Addr
@@ -38,31 +77,42 @@ type Conn interface {
// RemoteAddr returns the remote network address.
RemoteAddr() Addr
- // SetTimeout sets the read and write deadlines associated
- // with the connection.
- SetTimeout(nsec int64) os.Error
-
- // SetReadTimeout sets the time (in nanoseconds) that
- // Read will wait for data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
- SetReadTimeout(nsec int64) os.Error
-
- // SetWriteTimeout sets the time (in nanoseconds) that
- // Write will wait to send its data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
+ // SetDeadline sets the read and write deadlines associated
+ // with the connection. It is equivalent to calling both
+ // SetReadDeadline and SetWriteDeadline.
+ //
+ // A deadline is an absolute time after which I/O operations
+ // fail with a timeout (see type Error) instead of
+ // blocking. The deadline applies to all future I/O, not just
+ // the immediately following call to Read or Write.
+ //
+ // An idle timeout can be implemented by repeatedly extending
+ // the deadline after successful Read or Write calls.
+ //
+ // A zero value for t means I/O operations will not time out.
+ SetDeadline(t time.Time) error
+
+ // SetReadDeadline sets the deadline for future Read calls.
+ // A zero value for t means Read will not time out.
+ SetReadDeadline(t time.Time) error
+
+ // SetWriteDeadline sets the deadline for future Write calls.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
- SetWriteTimeout(nsec int64) os.Error
+ // A zero value for t means Write will not time out.
+ SetWriteDeadline(t time.Time) error
}
// An Error represents a network error.
type Error interface {
- os.Error
+ error
Timeout() bool // Is the error a timeout?
Temporary() bool // Is the error temporary?
}
// PacketConn is a generic packet-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
// ReadFrom reads a packet from the connection,
// copying the payload into b. It returns the number of
@@ -70,61 +120,67 @@ type PacketConn interface {
// was on the packet.
// ReadFrom can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
- // see SetTimeout and SetReadTimeout.
- ReadFrom(b []byte) (n int, addr Addr, err os.Error)
+ // see SetDeadline and SetReadDeadline.
+ ReadFrom(b []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload b to addr.
// WriteTo can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
- // see SetTimeout and SetWriteTimeout.
+ // see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
- WriteTo(b []byte, addr Addr) (n int, err os.Error)
+ WriteTo(b []byte, addr Addr) (n int, err error)
// Close closes the connection.
- Close() os.Error
+ // Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
+ Close() error
// LocalAddr returns the local network address.
LocalAddr() Addr
- // SetTimeout sets the read and write deadlines associated
+ // SetDeadline sets the read and write deadlines associated
// with the connection.
- SetTimeout(nsec int64) os.Error
-
- // SetReadTimeout sets the time (in nanoseconds) that
- // Read will wait for data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
- SetReadTimeout(nsec int64) os.Error
-
- // SetWriteTimeout sets the time (in nanoseconds) that
- // Write will wait to send its data before returning an error with Timeout() == true.
- // Setting nsec == 0 (the default) disables the deadline.
+ SetDeadline(t time.Time) error
+
+ // SetReadDeadline sets the deadline for future Read calls.
+ // If the deadline is reached, Read will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Read will not time out.
+ SetReadDeadline(t time.Time) error
+
+ // SetWriteDeadline sets the deadline for future Write calls.
+ // If the deadline is reached, Write will fail with a timeout
+ // (see type Error) instead of blocking.
+ // A zero value for t means Write will not time out.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
- SetWriteTimeout(nsec int64) os.Error
+ SetWriteDeadline(t time.Time) error
}
// A Listener is a generic network listener for stream-oriented protocols.
+//
+// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
- Accept() (c Conn, err os.Error)
+ Accept() (c Conn, err error)
// Close closes the listener.
- Close() os.Error
+ // Any blocked Accept operations will be unblocked and return errors.
+ Close() error
// Addr returns the listener's network address.
Addr() Addr
}
-var errMissingAddress = os.NewError("missing address")
+var errMissingAddress = errors.New("missing address")
type OpError struct {
- Op string
- Net string
- Addr Addr
- Error os.Error
+ Op string
+ Net string
+ Addr Addr
+ Err error
}
-func (e *OpError) String() string {
+func (e *OpError) Error() string {
if e == nil {
return "<nil>"
}
@@ -135,7 +191,7 @@ func (e *OpError) String() string {
if e.Addr != nil {
s += " " + e.Addr.String()
}
- s += ": " + e.Error.String()
+ s += ": " + e.Err.Error()
return s
}
@@ -144,7 +200,7 @@ type temporary interface {
}
func (e *OpError) Temporary() bool {
- t, ok := e.Error.(temporary)
+ t, ok := e.Err.(temporary)
return ok && t.Temporary()
}
@@ -153,20 +209,28 @@ type timeout interface {
}
func (e *OpError) Timeout() bool {
- t, ok := e.Error.(timeout)
+ t, ok := e.Err.(timeout)
return ok && t.Timeout()
}
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var errTimeout error = &timeoutError{}
+
type AddrError struct {
- Error string
- Addr string
+ Err string
+ Addr string
}
-func (e *AddrError) String() string {
+func (e *AddrError) Error() string {
if e == nil {
return "<nil>"
}
- s := e.Error
+ s := e.Err
if e.Addr != "" {
s += " " + e.Addr
}
@@ -183,6 +247,18 @@ func (e *AddrError) Timeout() bool {
type UnknownNetworkError string
-func (e UnknownNetworkError) String() string { return "unknown network " + string(e) }
+func (e UnknownNetworkError) Error() string { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool { return false }
+
+// DNSConfigError represents an error reading the machine's DNS configuration.
+type DNSConfigError struct {
+ Err error
+}
+
+func (e *DNSConfigError) Error() string {
+ return "error reading DNS config: " + e.Err.Error()
+}
+
+func (e *DNSConfigError) Timeout() bool { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 698a84527..fd145e1d7 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -5,117 +5,110 @@
package net
import (
- "flag"
- "regexp"
+ "io"
+ "runtime"
"testing"
+ "time"
)
-var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
-
-type DialErrorTest struct {
- Net string
- Raddr string
- Pattern string
-}
-
-var dialErrorTests = []DialErrorTest{
- {
- "datakit", "mh/astro/r70",
- "dial datakit mh/astro/r70: unknown network datakit",
- },
- {
- "tcp", "127.0.0.1:☺",
- "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
- },
- {
- "tcp", "no-such-name.google.com.:80",
- "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
- },
- {
- "tcp", "no-such-name.no-such-top-level-domain.:80",
- "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
- },
- {
- "tcp", "no-such-name:80",
- `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
- },
- {
- "tcp", "mh/astro/r70:http",
- "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
- },
- {
- "unix", "/etc/file-not-found",
- "dial unix /etc/file-not-found: no such file or directory",
- },
- {
- "unix", "/etc/",
- "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
- },
- {
- "unixpacket", "/etc/file-not-found",
- "dial unixpacket /etc/file-not-found: no such file or directory",
- },
- {
- "unixpacket", "/etc/",
- "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
- },
-}
-
-func TestDialError(t *testing.T) {
- if !*runErrorTest {
- t.Logf("test disabled; use --run_error_test to enable")
+func TestShutdown(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- for i, tt := range dialErrorTests {
- c, e := Dial(tt.Net, tt.Raddr)
- if c != nil {
- c.Close()
+ l, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ if l, err = Listen("tcp6", "[::1]:0"); err != nil {
+ t.Fatalf("ListenTCP on :0: %v", err)
}
- if e == nil {
- t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
- continue
+ }
+
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ t.Fatalf("Accept: %v", err)
}
- s := e.String()
- match, _ := regexp.MatchString(tt.Pattern, s)
- if !match {
- t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+ var buf [10]byte
+ n, err := c.Read(buf[:])
+ if n != 0 || err != io.EOF {
+ t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
}
+ c.Write([]byte("response"))
+ c.Close()
+ }()
+
+ c, err := Dial("tcp", l.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
}
-}
+ defer c.Close()
-var revAddrTests = []struct {
- Addr string
- Reverse string
- ErrPrefix string
-}{
- {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
- {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
- {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
- {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""},
- {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""},
- {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
- {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""},
- {"1.2.3", "", "unrecognized address"},
- {"1.2.3.4.5", "", "unrecognized address"},
- {"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
- {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
+ err = c.(*TCPConn).CloseWrite()
+ if err != nil {
+ t.Fatalf("CloseWrite: %v", err)
+ }
+ var buf [10]byte
+ n, err := c.Read(buf[:])
+ if err != nil {
+ t.Fatalf("client Read: %d, %v", n, err)
+ }
+ got := string(buf[:n])
+ if got != "response" {
+ t.Errorf("read = %q, want \"response\"", got)
+ }
}
-func TestReverseAddress(t *testing.T) {
- for i, tt := range revAddrTests {
- a, e := reverseaddr(tt.Addr)
- if len(tt.ErrPrefix) > 0 && e == nil {
- t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
- continue
- }
- if len(tt.ErrPrefix) == 0 && e != nil {
- t.Errorf("#%d: expected <nil>, got %q (error)", i, e)
- }
- if e != nil && e.(*DNSError).Error != tt.ErrPrefix {
- t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error)
+func TestTCPListenClose(t *testing.T) {
+ l, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+
+ done := make(chan bool, 1)
+ go func() {
+ time.Sleep(100 * time.Millisecond)
+ l.Close()
+ }()
+ go func() {
+ _, err = l.Accept()
+ if err == nil {
+ t.Error("Accept succeeded")
+ } else {
+ t.Logf("Accept timeout error: %s (any error is fine)", err)
}
- if a != tt.Reverse {
- t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
+ done <- true
+ }()
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Fatal("timeout waiting for TCP close")
+ }
+}
+
+func TestUDPListenClose(t *testing.T) {
+ l, err := ListenPacket("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+
+ buf := make([]byte, 1000)
+ done := make(chan bool, 1)
+ go func() {
+ time.Sleep(100 * time.Millisecond)
+ l.Close()
+ }()
+ go func() {
+ _, _, err = l.ReadFrom(buf)
+ if err == nil {
+ t.Error("ReadFrom succeeded")
+ } else {
+ t.Logf("ReadFrom timeout error: %s (any error is fine)", err)
}
+ done <- true
+ }()
+ select {
+ case <-done:
+ case <-time.After(2 * time.Second):
+ t.Fatal("timeout waiting for UDP close")
}
}
diff --git a/src/pkg/net/newpollserver.go b/src/pkg/net/newpollserver.go
index 427208701..d34bb511f 100644
--- a/src/pkg/net/newpollserver.go
+++ b/src/pkg/net/newpollserver.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.
+// +build darwin freebsd linux netbsd openbsd
+
package net
import (
@@ -9,24 +11,23 @@ import (
"syscall"
)
-func newPollServer() (s *pollServer, err os.Error) {
+func newPollServer() (s *pollServer, err error) {
s = new(pollServer)
s.cr = make(chan *netFD, 1)
s.cw = make(chan *netFD, 1)
if s.pr, s.pw, err = os.Pipe(); err != nil {
return nil, err
}
- var e int
- if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+ if err = syscall.SetNonblock(int(s.pr.Fd()), true); err != nil {
goto Errno
}
- if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+ if err = syscall.SetNonblock(int(s.pw.Fd()), true); err != nil {
goto Errno
}
if s.poll, err = newpollster(); err != nil {
goto Error
}
- if _, err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil {
+ if _, err = s.poll.AddFD(int(s.pr.Fd()), 'r', true); err != nil {
s.poll.Close()
goto Error
}
@@ -35,7 +36,11 @@ func newPollServer() (s *pollServer, err os.Error) {
return s, nil
Errno:
- err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+ err = &os.PathError{
+ Op: "setnonblock",
+ Path: s.pr.Name(),
+ Err: err,
+ }
Error:
s.pr.Close()
s.pw.Close()
diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go
index de46830d2..7c87b42f6 100644
--- a/src/pkg/net/parse.go
+++ b/src/pkg/net/parse.go
@@ -54,7 +54,7 @@ func (f *file) readLine() (s string, ok bool) {
if n >= 0 {
f.data = f.data[0 : ln+n]
}
- if err == os.EOF {
+ if err == io.EOF {
f.atEOF = true
}
}
@@ -62,12 +62,12 @@ func (f *file) readLine() (s string, ok bool) {
return
}
-func open(name string) (*file, os.Error) {
+func open(name string) (*file, error) {
fd, err := os.Open(name)
if err != nil {
return nil, err
}
- return &file{fd, make([]byte, 1024)[0:0], false}, nil
+ return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
}
func byteIndex(s string, c byte) int {
@@ -159,6 +159,18 @@ func xtoi(s string, i0 int) (n int, i int, ok bool) {
return n, i, true
}
+// xtoi2 converts the next two hex digits of s into a byte.
+// If s is longer than 2 bytes then the third byte must be e.
+// If the first two bytes of s are not hex digits or the third byte
+// does not match e, false is returned.
+func xtoi2(s string, e byte) (byte, bool) {
+ if len(s) > 2 && s[2] != e {
+ return 0, false
+ }
+ n, ei, ok := xtoi(s[:2], 0)
+ return byte(n), ok && ei == 2
+}
+
// Integer to decimal.
func itoa(i int) string {
var buf [30]byte
@@ -181,6 +193,37 @@ func itoa(i int) string {
return string(buf[n:])
}
+// Convert i to decimal string.
+func itod(i uint) string {
+ if i == 0 {
+ return "0"
+ }
+
+ // Assemble decimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0; i /= 10 {
+ bp--
+ b[bp] = byte(i%10) + '0'
+ }
+
+ return string(b[bp:])
+}
+
+// Convert i to hexadecimal string.
+func itox(i uint, min int) string {
+ // Assemble hexadecimal in reverse order.
+ var b [32]byte
+ bp := len(b)
+ for ; i > 0 || min > 0; i /= 16 {
+ bp--
+ b[bp] = "0123456789abcdef"[byte(i%16)]
+ min--
+ }
+
+ return string(b[bp:])
+}
+
// Number of occurrences of b in s.
func count(s string, b byte) int {
n := 0
diff --git a/src/pkg/net/parse_test.go b/src/pkg/net/parse_test.go
index 8d51eba18..30fda45df 100644
--- a/src/pkg/net/parse_test.go
+++ b/src/pkg/net/parse_test.go
@@ -7,13 +7,15 @@ package net
import (
"bufio"
"os"
- "testing"
"runtime"
+ "testing"
)
func TestReadLine(t *testing.T) {
// /etc/services file does not exist on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
filename := "/etc/services" // a nice big file
diff --git a/src/pkg/net/pipe.go b/src/pkg/net/pipe.go
index c0bbd356b..f1a2eca4e 100644
--- a/src/pkg/net/pipe.go
+++ b/src/pkg/net/pipe.go
@@ -1,8 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package net
import (
+ "errors"
"io"
- "os"
+ "time"
)
// Pipe creates a synchronous, in-memory, full duplex
@@ -32,7 +37,7 @@ func (pipeAddr) String() string {
return "pipe"
}
-func (p *pipe) Close() os.Error {
+func (p *pipe) Close() error {
err := p.PipeReader.Close()
err1 := p.PipeWriter.Close()
if err == nil {
@@ -49,14 +54,14 @@ func (p *pipe) RemoteAddr() Addr {
return pipeAddr(0)
}
-func (p *pipe) SetTimeout(nsec int64) os.Error {
- return os.NewError("net.Pipe does not support timeouts")
+func (p *pipe) SetDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
-func (p *pipe) SetReadTimeout(nsec int64) os.Error {
- return os.NewError("net.Pipe does not support timeouts")
+func (p *pipe) SetReadDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
-func (p *pipe) SetWriteTimeout(nsec int64) os.Error {
- return os.NewError("net.Pipe does not support timeouts")
+func (p *pipe) SetWriteDeadline(t time.Time) error {
+ return errors.New("net.Pipe does not support deadlines")
}
diff --git a/src/pkg/net/pipe_test.go b/src/pkg/net/pipe_test.go
index 7e4c6db44..afe4f2408 100644
--- a/src/pkg/net/pipe_test.go
+++ b/src/pkg/net/pipe_test.go
@@ -7,7 +7,6 @@ package net
import (
"bytes"
"io"
- "os"
"testing"
)
@@ -22,7 +21,7 @@ func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
c <- 0
}
-func checkRead(t *testing.T, r io.Reader, data []byte, wantErr os.Error) {
+func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
buf := make([]byte, len(data)+10)
n, err := r.Read(buf)
if err != wantErr {
@@ -52,6 +51,6 @@ func TestPipe(t *testing.T) {
checkRead(t, srv, []byte("a third line"), nil)
<-c
go srv.Close()
- checkRead(t, cli, nil, os.EOF)
+ checkRead(t, cli, nil, io.EOF)
cli.Close()
}
diff --git a/src/pkg/net/port.go b/src/pkg/net/port.go
index 8f8327a37..16780da11 100644
--- a/src/pkg/net/port.go
+++ b/src/pkg/net/port.go
@@ -2,17 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
// Read system port mappings from /etc/services
package net
-import (
- "os"
- "sync"
-)
+import "sync"
var services map[string]map[string]int
-var servicesError os.Error
+var servicesError error
var onceReadServices sync.Once
func readServices() {
@@ -51,7 +50,7 @@ func readServices() {
}
// goLookupPort is the native Go implementation of LookupPort.
-func goLookupPort(network, service string) (port int, err os.Error) {
+func goLookupPort(network, service string) (port int, err error) {
onceReadServices.Do(readServices)
switch network {
diff --git a/src/pkg/rpc/client.go b/src/pkg/net/rpc/client.go
index 4acfdf6d9..db2da8e44 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/net/rpc/client.go
@@ -6,12 +6,12 @@ package rpc
import (
"bufio"
- "gob"
- "http"
+ "encoding/gob"
+ "errors"
"io"
"log"
"net"
- "os"
+ "net/http"
"sync"
)
@@ -19,25 +19,25 @@ import (
// the remote side of the RPC connection.
type ServerError string
-func (e ServerError) String() string {
+func (e ServerError) Error() string {
return string(e)
}
-var ErrShutdown = os.NewError("connection is shut down")
+var ErrShutdown = errors.New("connection is shut down")
// Call represents an active RPC.
type Call struct {
ServiceMethod string // The name of the service and method to call.
Args interface{} // The argument to the function (*struct).
Reply interface{} // The reply from the function (*struct).
- Error os.Error // After completion, the error status.
- Done chan *Call // Strobes when call is complete; value is the error status.
- seq uint64
+ Error error // After completion, the error status.
+ Done chan *Call // Strobes when call is complete.
}
// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
-// with a single Client.
+// with a single Client, and a Client may be used by
+// multiple goroutines simultaneously.
type Client struct {
mutex sync.Mutex // protects pending, seq, request
sending sync.Mutex
@@ -58,81 +58,90 @@ type Client struct {
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
- WriteRequest(*Request, interface{}) os.Error
- ReadResponseHeader(*Response) os.Error
- ReadResponseBody(interface{}) os.Error
+ WriteRequest(*Request, interface{}) error
+ ReadResponseHeader(*Response) error
+ ReadResponseBody(interface{}) error
- Close() os.Error
+ Close() error
}
-func (client *Client) send(c *Call) {
+func (client *Client) send(call *Call) {
+ client.sending.Lock()
+ defer client.sending.Unlock()
+
// Register this call.
client.mutex.Lock()
if client.shutdown {
- c.Error = ErrShutdown
+ call.Error = ErrShutdown
client.mutex.Unlock()
- c.done()
+ call.done()
return
}
- c.seq = client.seq
+ seq := client.seq
client.seq++
- client.pending[c.seq] = c
+ client.pending[seq] = call
client.mutex.Unlock()
// Encode and send the request.
- client.sending.Lock()
- defer client.sending.Unlock()
- client.request.Seq = c.seq
- client.request.ServiceMethod = c.ServiceMethod
- if err := client.codec.WriteRequest(&client.request, c.Args); err != nil {
- panic("rpc: client encode error: " + err.String())
+ client.request.Seq = seq
+ client.request.ServiceMethod = call.ServiceMethod
+ err := client.codec.WriteRequest(&client.request, call.Args)
+ if err != nil {
+ client.mutex.Lock()
+ delete(client.pending, seq)
+ client.mutex.Unlock()
+ call.Error = err
+ call.done()
}
}
func (client *Client) input() {
- var err os.Error
+ var err error
var response Response
for err == nil {
response = Response{}
err = client.codec.ReadResponseHeader(&response)
if err != nil {
- if err == os.EOF && !client.closing {
+ if err == io.EOF && !client.closing {
err = io.ErrUnexpectedEOF
}
break
}
seq := response.Seq
client.mutex.Lock()
- c := client.pending[seq]
- client.pending[seq] = c, false
+ call := client.pending[seq]
+ delete(client.pending, seq)
client.mutex.Unlock()
if response.Error == "" {
- err = client.codec.ReadResponseBody(c.Reply)
+ err = client.codec.ReadResponseBody(call.Reply)
if err != nil {
- c.Error = os.NewError("reading body " + err.String())
+ call.Error = errors.New("reading body " + err.Error())
}
} else {
// We've got an error response. Give this to the request;
// any subsequent requests will get the ReadResponseBody
// error if there is one.
- c.Error = ServerError(response.Error)
+ call.Error = ServerError(response.Error)
err = client.codec.ReadResponseBody(nil)
if err != nil {
- err = os.NewError("reading error body: " + err.String())
+ err = errors.New("reading error body: " + err.Error())
}
}
- c.done()
+ call.done()
}
// Terminate pending calls.
+ client.sending.Lock()
client.mutex.Lock()
client.shutdown = true
+ closing := client.closing
for _, call := range client.pending {
call.Error = err
call.done()
}
client.mutex.Unlock()
- if err != os.EOF || !client.closing {
+ client.sending.Unlock()
+ if err != io.EOF && !closing {
log.Println("rpc: client protocol error:", err)
}
}
@@ -144,6 +153,7 @@ func (call *Call) done() {
default:
// We don't want to block here. It is the caller's responsibility to make
// sure the channel has enough buffer space. See comment in Go().
+ log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
}
}
@@ -175,7 +185,7 @@ type gobClientCodec struct {
encBuf *bufio.Writer
}
-func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err os.Error) {
+func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
if err = c.enc.Encode(r); err != nil {
return
}
@@ -185,28 +195,28 @@ func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err os.Erro
return c.encBuf.Flush()
}
-func (c *gobClientCodec) ReadResponseHeader(r *Response) os.Error {
+func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
return c.dec.Decode(r)
}
-func (c *gobClientCodec) ReadResponseBody(body interface{}) os.Error {
+func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
return c.dec.Decode(body)
}
-func (c *gobClientCodec) Close() os.Error {
+func (c *gobClientCodec) Close() 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) {
+func DialHTTP(network, address string) (*Client, error) {
return DialHTTPPath(network, address, DefaultRPCPath)
}
// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
-func DialHTTPPath(network, address, path string) (*Client, os.Error) {
- var err os.Error
+func DialHTTPPath(network, address, path string) (*Client, error) {
+ var err error
conn, err := net.Dial(network, address)
if err != nil {
return nil, err
@@ -220,14 +230,19 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) {
return NewClient(conn), nil
}
if err == nil {
- err = os.NewError("unexpected HTTP response: " + resp.Status)
+ err = errors.New("unexpected HTTP response: " + resp.Status)
}
conn.Close()
- return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
+ return nil, &net.OpError{
+ Op: "dial-http",
+ Net: network + " " + address,
+ Addr: nil,
+ Err: err,
+ }
}
// Dial connects to an RPC server at the specified network address.
-func Dial(network, address string) (*Client, os.Error) {
+func Dial(network, address string) (*Client, error) {
conn, err := net.Dial(network, address)
if err != nil {
return nil, err
@@ -235,7 +250,7 @@ func Dial(network, address string) (*Client, os.Error) {
return NewClient(conn), nil
}
-func (client *Client) Close() os.Error {
+func (client *Client) Close() error {
client.mutex.Lock()
if client.shutdown || client.closing {
client.mutex.Unlock()
@@ -251,10 +266,10 @@ func (client *Client) Close() os.Error {
// the same Call object. If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
- c := new(Call)
- c.ServiceMethod = serviceMethod
- c.Args = args
- c.Reply = reply
+ call := new(Call)
+ call.ServiceMethod = serviceMethod
+ call.Args = args
+ call.Reply = reply
if done == nil {
done = make(chan *Call, 10) // buffered.
} else {
@@ -266,21 +281,13 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
log.Panic("rpc: done channel is unbuffered")
}
}
- c.Done = done
- if client.shutdown {
- c.Error = ErrShutdown
- c.done()
- return c
- }
- client.send(c)
- return c
+ call.Done = done
+ client.send(call)
+ return call
}
// Call invokes the named function, waits for it to complete, and returns its error status.
-func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) os.Error {
- if client.shutdown {
- return ErrShutdown
- }
+func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
return call.Error
}
diff --git a/src/pkg/rpc/debug.go b/src/pkg/net/rpc/debug.go
index 7e3e6f6e5..663663fe9 100644
--- a/src/pkg/rpc/debug.go
+++ b/src/pkg/net/rpc/debug.go
@@ -11,9 +11,9 @@ package rpc
import (
"fmt"
- "http"
+ "net/http"
"sort"
- "template"
+ "text/template"
)
const debugText = `<html>
@@ -27,7 +27,7 @@ const debugText = `<html>
<th align=center>Method</th><th align=center>Calls</th>
{{range .Method}}
<tr>
- <td align=left font=fixed>{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) os.Error</td>
+ <td align=left font=fixed>{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) error</td>
<td align=center>{{.Type.NumCalls}}</td>
</tr>
{{end}}
@@ -85,6 +85,6 @@ func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
sort.Sort(services)
err := debug.Execute(w, services)
if err != nil {
- fmt.Fprintln(w, "rpc: error executing template:", err.String())
+ fmt.Fprintln(w, "rpc: error executing template:", err.Error())
}
}
diff --git a/src/pkg/rpc/jsonrpc/all_test.go b/src/pkg/net/rpc/jsonrpc/all_test.go
index c1a9e8ecb..e6c7441f0 100644
--- a/src/pkg/rpc/jsonrpc/all_test.go
+++ b/src/pkg/net/rpc/jsonrpc/all_test.go
@@ -5,11 +5,12 @@
package jsonrpc
import (
+ "encoding/json"
+ "errors"
"fmt"
- "json"
+ "io"
"net"
- "os"
- "rpc"
+ "net/rpc"
"testing"
)
@@ -23,25 +24,25 @@ type Reply struct {
type Arith int
-func (t *Arith) Add(args *Args, reply *Reply) os.Error {
+func (t *Arith) Add(args *Args, reply *Reply) error {
reply.C = args.A + args.B
return nil
}
-func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+func (t *Arith) Mul(args *Args, reply *Reply) error {
reply.C = args.A * args.B
return nil
}
-func (t *Arith) Div(args *Args, reply *Reply) os.Error {
+func (t *Arith) Div(args *Args, reply *Reply) error {
if args.B == 0 {
- return os.NewError("divide by zero")
+ return errors.New("divide by zero")
}
reply.C = args.A / args.B
return nil
}
-func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+func (t *Arith) Error(args *Args, reply *Reply) error {
panic("ERROR")
}
@@ -104,7 +105,7 @@ func TestClient(t *testing.T) {
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())
+ t.Errorf("Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
@@ -114,7 +115,7 @@ func TestClient(t *testing.T) {
reply = new(Reply)
err = client.Call("Arith.Mul", args, reply)
if err != nil {
- t.Errorf("Mul: expected no error but got string %q", err.String())
+ t.Errorf("Mul: expected no error but got string %q", err.Error())
}
if reply.C != args.A*args.B {
t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
@@ -129,7 +130,7 @@ func TestClient(t *testing.T) {
addCall = <-addCall.Done
if addCall.Error != nil {
- t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.Error())
}
if addReply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
@@ -137,7 +138,7 @@ func TestClient(t *testing.T) {
mulCall = <-mulCall.Done
if mulCall.Error != nil {
- t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.Error())
}
if mulReply.C != args.A*args.B {
t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
@@ -150,7 +151,71 @@ func TestClient(t *testing.T) {
// expect an error: zero divide
if err == nil {
t.Error("Div: expected error")
- } else if err.String() != "divide by zero" {
+ } else if err.Error() != "divide by zero" {
t.Error("Div: expected divide by zero error; got", err)
}
}
+
+func TestMalformedInput(t *testing.T) {
+ cli, srv := net.Pipe()
+ go cli.Write([]byte(`{id:1}`)) // invalid json
+ ServeConn(srv) // must return, not loop
+}
+
+func TestUnexpectedError(t *testing.T) {
+ cli, srv := myPipe()
+ go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
+ ServeConn(srv) // must return, not loop
+}
+
+// Copied from package net.
+func myPipe() (*pipe, *pipe) {
+ r1, w1 := io.Pipe()
+ r2, w2 := io.Pipe()
+
+ return &pipe{r1, w2}, &pipe{r2, w1}
+}
+
+type pipe struct {
+ *io.PipeReader
+ *io.PipeWriter
+}
+
+type pipeAddr int
+
+func (pipeAddr) Network() string {
+ return "pipe"
+}
+
+func (pipeAddr) String() string {
+ return "pipe"
+}
+
+func (p *pipe) Close() error {
+ err := p.PipeReader.Close()
+ err1 := p.PipeWriter.Close()
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+func (p *pipe) LocalAddr() net.Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) RemoteAddr() net.Addr {
+ return pipeAddr(0)
+}
+
+func (p *pipe) SetTimeout(nsec int64) error {
+ return errors.New("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetReadTimeout(nsec int64) error {
+ return errors.New("net.Pipe does not support timeouts")
+}
+
+func (p *pipe) SetWriteTimeout(nsec int64) error {
+ return errors.New("net.Pipe does not support timeouts")
+}
diff --git a/src/pkg/rpc/jsonrpc/client.go b/src/pkg/net/rpc/jsonrpc/client.go
index 577d0ce42..3fa8cbf08 100644
--- a/src/pkg/rpc/jsonrpc/client.go
+++ b/src/pkg/net/rpc/jsonrpc/client.go
@@ -7,12 +7,11 @@
package jsonrpc
import (
+ "encoding/json"
"fmt"
"io"
- "json"
"net"
- "os"
- "rpc"
+ "net/rpc"
"sync"
)
@@ -49,7 +48,7 @@ type clientRequest struct {
Id uint64 `json:"id"`
}
-func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
+func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) error {
c.mutex.Lock()
c.pending[r.Seq] = r.ServiceMethod
c.mutex.Unlock()
@@ -71,7 +70,7 @@ func (r *clientResponse) reset() {
r.Error = nil
}
-func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
+func (c *clientCodec) ReadResponseHeader(r *rpc.Response) error {
c.resp.reset()
if err := c.dec.Decode(&c.resp); err != nil {
return err
@@ -79,7 +78,7 @@ func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
c.mutex.Lock()
r.ServiceMethod = c.pending[c.resp.Id]
- c.pending[c.resp.Id] = "", false
+ delete(c.pending, c.resp.Id)
c.mutex.Unlock()
r.Error = ""
@@ -97,14 +96,14 @@ func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
return nil
}
-func (c *clientCodec) ReadResponseBody(x interface{}) os.Error {
+func (c *clientCodec) ReadResponseBody(x interface{}) error {
if x == nil {
return nil
}
return json.Unmarshal(*c.resp.Result, x)
}
-func (c *clientCodec) Close() os.Error {
+func (c *clientCodec) Close() error {
return c.c.Close()
}
@@ -115,7 +114,7 @@ func NewClient(conn io.ReadWriteCloser) *rpc.Client {
}
// Dial connects to a JSON-RPC server at the specified network address.
-func Dial(network, address string) (*rpc.Client, os.Error) {
+func Dial(network, address string) (*rpc.Client, error) {
conn, err := net.Dial(network, address)
if err != nil {
return nil, err
diff --git a/src/pkg/rpc/jsonrpc/server.go b/src/pkg/net/rpc/jsonrpc/server.go
index 9801fdf22..4c54553a7 100644
--- a/src/pkg/rpc/jsonrpc/server.go
+++ b/src/pkg/net/rpc/jsonrpc/server.go
@@ -5,10 +5,10 @@
package jsonrpc
import (
+ "encoding/json"
+ "errors"
"io"
- "json"
- "os"
- "rpc"
+ "net/rpc"
"sync"
)
@@ -64,7 +64,7 @@ type serverResponse struct {
Error interface{} `json:"error"`
}
-func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
+func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error {
c.req.reset()
if err := c.dec.Decode(&c.req); err != nil {
return err
@@ -84,7 +84,7 @@ func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
return nil
}
-func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
+func (c *serverCodec) ReadRequestBody(x interface{}) error {
if x == nil {
return nil
}
@@ -99,15 +99,15 @@ func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
var null = json.RawMessage([]byte("null"))
-func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
+func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
var resp serverResponse
c.mutex.Lock()
b, ok := c.pending[r.Seq]
if !ok {
c.mutex.Unlock()
- return os.NewError("invalid sequence number in response")
+ return errors.New("invalid sequence number in response")
}
- c.pending[r.Seq] = nil, false
+ delete(c.pending, r.Seq)
c.mutex.Unlock()
if b == nil {
@@ -124,7 +124,7 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
return c.enc.Encode(resp)
}
-func (c *serverCodec) Close() os.Error {
+func (c *serverCodec) Close() error {
return c.c.Close()
}
diff --git a/src/pkg/rpc/server.go b/src/pkg/net/rpc/server.go
index 745074428..1680e2f0d 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/net/rpc/server.go
@@ -13,17 +13,23 @@
Only methods that satisfy these criteria will be made available for remote access;
other methods will be ignored:
- - the method name is exported, that is, begins with an upper case letter.
- - the method receiver is exported or local (defined in the package
- registering the service).
- - the method has two arguments, both exported or local types.
+ - the method is exported.
+ - the method has two arguments, both exported (or builtin) types.
- the method's second argument is a pointer.
- - the method has return type os.Error.
+ - the method has return type error.
+
+ In effect, the method must look schematically like
+
+ func (t *T) MethodName(argType T1, replyType *T2) error
+
+ where T, T1 and T2 can be marshaled by encoding/gob.
+ These requirements apply even if a different codec is used.
+ (In future, these requirements may soften for custom codecs.)
The method's first argument represents the arguments provided by the caller; the
second argument represents the result parameters to be returned to the caller.
The method's return value, if non-nil, is passed back as a string that the client
- sees as an os.ErrorString.
+ sees as if created by errors.New.
The server may handle requests on a single connection by calling ServeConn. More
typically it will create a network listener and call Accept or, for an HTTP
@@ -36,10 +42,12 @@
call, a pointer containing the arguments, and a pointer to receive the result
parameters.
- Call waits for the remote call to complete; Go launches the call asynchronously
- and returns a channel that will signal completion.
+ The Call method waits for the remote call to complete while the Go method
+ launches the call asynchronously and signals completion using the Call
+ structure's Done channel.
- Package "gob" is used to transport the data.
+ Unless an explicit codec is set up, package encoding/gob is used to
+ transport the data.
Here is a simple example. A server wishes to export an object of type Arith:
@@ -55,14 +63,14 @@
type Arith int
- func (t *Arith) Multiply(args *Args, reply *int) os.Error {
+ func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
- func (t *Arith) Divide(args *Args, quo *Quotient) os.Error {
+ func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
- return os.ErrorString("divide by zero")
+ return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
@@ -97,7 +105,7 @@
if err != nil {
log.Fatal("arith error:", err)
}
- fmt.Printf("Arith: %d*%d=%d", args.A, args.B, *reply)
+ fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
or
@@ -114,17 +122,17 @@ package rpc
import (
"bufio"
- "gob"
- "http"
- "log"
+ "encoding/gob"
+ "errors"
"io"
+ "log"
"net"
- "os"
+ "net/http"
"reflect"
"strings"
"sync"
"unicode"
- "utf8"
+ "unicode/utf8"
)
const (
@@ -133,10 +141,9 @@ const (
DefaultDebugPath = "/debug/rpc"
)
-// Precompute the reflect type for os.Error. Can't use os.Error directly
+// Precompute the reflect type for error. Can't use error directly
// because Typeof takes an empty interface value. This is annoying.
-var unusedError *os.Error
-var typeOfOsError = reflect.TypeOf(unusedError).Elem()
+var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
type methodType struct {
sync.Mutex // protects counters
@@ -210,22 +217,22 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
// receiver value that satisfy the following conditions:
// - exported method
// - two arguments, both pointers to exported structs
-// - one return value, of type os.Error
+// - one return value, of type error
// It returns an error if the receiver is not an exported type or has no
// suitable methods.
// The client accesses each method using a string of the form "Type.Method",
// where Type is the receiver's concrete type.
-func (server *Server) Register(rcvr interface{}) os.Error {
+func (server *Server) Register(rcvr interface{}) error {
return server.register(rcvr, "", false)
}
// RegisterName is like Register but uses the provided name for the type
// instead of the receiver's concrete type.
-func (server *Server) RegisterName(name string, rcvr interface{}) os.Error {
+func (server *Server) RegisterName(name string, rcvr interface{}) error {
return server.register(rcvr, name, true)
}
-func (server *Server) register(rcvr interface{}, name string, useName bool) os.Error {
+func (server *Server) register(rcvr interface{}, name string, useName bool) error {
server.mu.Lock()
defer server.mu.Unlock()
if server.serviceMap == nil {
@@ -244,10 +251,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
if !isExported(sname) && !useName {
s := "rpc Register: type " + sname + " is not exported"
log.Print(s)
- return os.NewError(s)
+ return errors.New(s)
}
if _, present := server.serviceMap[sname]; present {
- return os.NewError("rpc: service already defined: " + sname)
+ return errors.New("rpc: service already defined: " + sname)
}
s.name = sname
s.method = make(map[string]*methodType)
@@ -257,6 +264,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
method := s.typ.Method(m)
mtype := method.Type
mname := method.Name
+ // Method must be exported.
if method.PkgPath != "" {
continue
}
@@ -268,7 +276,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 !isExportedOrBuiltinType(argType) {
- log.Println(mname, "argument type not exported or local:", argType)
+ log.Println(mname, "argument type not exported:", argType)
continue
}
// Second arg must be a pointer.
@@ -277,17 +285,19 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
log.Println("method", mname, "reply type not a pointer:", replyType)
continue
}
+ // Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
- log.Println("method", mname, "reply type not exported or local:", replyType)
+ log.Println("method", mname, "reply type not exported:", replyType)
continue
}
- // Method needs one out: os.Error.
+ // Method needs one out.
if mtype.NumOut() != 1 {
log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
continue
}
- if returnType := mtype.Out(0); returnType != typeOfOsError {
- log.Println("method", mname, "returns", returnType.String(), "not os.Error")
+ // The return type of the method must be error.
+ if returnType := mtype.Out(0); returnType != typeOfError {
+ log.Println("method", mname, "returns", returnType.String(), "not error")
continue
}
s.method[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
@@ -296,16 +306,16 @@ 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.NewError(s)
+ return errors.New(s)
}
server.serviceMap[s.name] = s
return nil
}
-// A value sent as a placeholder for the response when the server receives an invalid request.
-type InvalidRequest struct{}
-
-var invalidRequest = InvalidRequest{}
+// A value sent as a placeholder for the server's response value when the server
+// receives an invalid request. It is never decoded by the client since the Response
+// contains an error when it is used.
+var invalidRequest = struct{}{}
func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) {
resp := server.getResponse()
@@ -339,11 +349,11 @@ func (s *service) call(server *Server, sending *sync.Mutex, mtype *methodType, r
function := mtype.method.Func
// Invoke the method, providing a new value for the reply.
returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})
- // The return value for the method is an os.Error.
+ // The return value for the method is an error.
errInter := returnValues[0].Interface()
errmsg := ""
if errInter != nil {
- errmsg = errInter.(os.Error).String()
+ errmsg = errInter.(error).Error()
}
server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)
server.freeRequest(req)
@@ -356,15 +366,15 @@ type gobServerCodec struct {
encBuf *bufio.Writer
}
-func (c *gobServerCodec) ReadRequestHeader(r *Request) os.Error {
+func (c *gobServerCodec) ReadRequestHeader(r *Request) error {
return c.dec.Decode(r)
}
-func (c *gobServerCodec) ReadRequestBody(body interface{}) os.Error {
+func (c *gobServerCodec) ReadRequestBody(body interface{}) error {
return c.dec.Decode(body)
}
-func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err os.Error) {
+func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) {
if err = c.enc.Encode(r); err != nil {
return
}
@@ -374,7 +384,7 @@ func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err os.Er
return c.encBuf.Flush()
}
-func (c *gobServerCodec) Close() os.Error {
+func (c *gobServerCodec) Close() error {
return c.rwc.Close()
}
@@ -394,17 +404,17 @@ func (server *Server) ServeConn(conn io.ReadWriteCloser) {
func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
for {
- service, mtype, req, argv, replyv, err := server.readRequest(codec)
+ service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
if err != nil {
- if err != os.EOF {
+ if err != io.EOF {
log.Println("rpc:", err)
}
- if err == os.EOF || err == io.ErrUnexpectedEOF {
+ if !keepReading {
break
}
// send a response if we actually managed to read a header.
if req != nil {
- server.sendResponse(sending, req, invalidRequest, codec, err.String())
+ server.sendResponse(sending, req, invalidRequest, codec, err.Error())
server.freeRequest(req)
}
continue
@@ -416,16 +426,16 @@ func (server *Server) ServeCodec(codec ServerCodec) {
// 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 {
+func (server *Server) ServeRequest(codec ServerCodec) error {
sending := new(sync.Mutex)
- service, mtype, req, argv, replyv, err := server.readRequest(codec)
+ service, mtype, req, argv, replyv, keepReading, err := server.readRequest(codec)
if err != nil {
- if err == os.EOF || err == io.ErrUnexpectedEOF {
+ if !keepReading {
return err
}
// send a response if we actually managed to read a header.
if req != nil {
- server.sendResponse(sending, req, invalidRequest, codec, err.String())
+ server.sendResponse(sending, req, invalidRequest, codec, err.Error())
server.freeRequest(req)
}
return err
@@ -474,10 +484,10 @@ func (server *Server) freeResponse(resp *Response) {
server.respLock.Unlock()
}
-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)
+func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, keepReading bool, err error) {
+ service, mtype, req, keepReading, err = server.readRequestHeader(codec)
if err != nil {
- if err == os.EOF || err == io.ErrUnexpectedEOF {
+ if !keepReading {
return
}
// discard body
@@ -505,22 +515,26 @@ func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *m
return
}
-func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, err os.Error) {
+func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, keepReading bool, err error) {
// Grab the request header.
req = server.getRequest()
err = codec.ReadRequestHeader(req)
if err != nil {
req = nil
- if err == os.EOF || err == io.ErrUnexpectedEOF {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
return
}
- err = os.NewError("rpc: server cannot decode request: " + err.String())
+ err = errors.New("rpc: server cannot decode request: " + err.Error())
return
}
+ // We read the header successfully. If we see an error now,
+ // we can still recover and move on to the next request.
+ keepReading = true
+
serviceMethod := strings.Split(req.ServiceMethod, ".")
if len(serviceMethod) != 2 {
- err = os.NewError("rpc: service/method request ill-formed: " + req.ServiceMethod)
+ err = errors.New("rpc: service/method request ill-formed: " + req.ServiceMethod)
return
}
// Look up the request.
@@ -528,12 +542,12 @@ func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mt
service = server.serviceMap[serviceMethod[0]]
server.mu.Unlock()
if service == nil {
- err = os.NewError("rpc: can't find service " + req.ServiceMethod)
+ err = errors.New("rpc: can't find service " + req.ServiceMethod)
return
}
mtype = service.method[serviceMethod[1]]
if mtype == nil {
- err = os.NewError("rpc: can't find method " + req.ServiceMethod)
+ err = errors.New("rpc: can't find method " + req.ServiceMethod)
}
return
}
@@ -545,18 +559,18 @@ func (server *Server) Accept(lis net.Listener) {
for {
conn, err := lis.Accept()
if err != nil {
- log.Fatal("rpc.Serve: accept:", err.String()) // TODO(r): exit?
+ log.Fatal("rpc.Serve: accept:", err.Error()) // TODO(r): exit?
}
go server.ServeConn(conn)
}
}
// Register publishes the receiver's methods in the DefaultServer.
-func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
+func Register(rcvr interface{}) error { return DefaultServer.Register(rcvr) }
// RegisterName is like Register but uses the provided name for the type
// instead of the receiver's concrete type.
-func RegisterName(name string, rcvr interface{}) os.Error {
+func RegisterName(name string, rcvr interface{}) error {
return DefaultServer.RegisterName(name, rcvr)
}
@@ -568,11 +582,11 @@ func RegisterName(name string, rcvr interface{}) os.Error {
// connection. ReadRequestBody may be called with a nil
// argument to force the body of the request to be read and discarded.
type ServerCodec interface {
- ReadRequestHeader(*Request) os.Error
- ReadRequestBody(interface{}) os.Error
- WriteResponse(*Response, interface{}) os.Error
+ ReadRequestHeader(*Request) error
+ ReadRequestBody(interface{}) error
+ WriteResponse(*Response, interface{}) error
- Close() os.Error
+ Close() error
}
// ServeConn runs the DefaultServer on a single connection.
@@ -592,7 +606,7 @@ func ServeCodec(codec ServerCodec) {
// ServeRequest is like ServeCodec but synchronously serves a single request.
// It does not close the codec upon completion.
-func ServeRequest(codec ServerCodec) os.Error {
+func ServeRequest(codec ServerCodec) error {
return DefaultServer.ServeRequest(codec)
}
@@ -614,7 +628,7 @@ func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
- log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.String())
+ log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error())
return
}
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/net/rpc/server_test.go
index e7bbfbe97..62c7b1e60 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/net/rpc/server_test.go
@@ -5,15 +5,16 @@
package rpc
import (
+ "errors"
"fmt"
- "http/httptest"
"io"
"log"
"net"
- "os"
+ "net/http/httptest"
"runtime"
"strings"
"sync"
+ "sync/atomic"
"testing"
"time"
)
@@ -26,7 +27,6 @@ var (
)
const (
- second = 1e9
newHttpPath = "/foo"
)
@@ -42,35 +42,35 @@ type Arith int
// Some of Arith's methods have value args, some have pointer args. That's deliberate.
-func (t *Arith) Add(args Args, reply *Reply) os.Error {
+func (t *Arith) Add(args Args, reply *Reply) error {
reply.C = args.A + args.B
return nil
}
-func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
+func (t *Arith) Mul(args *Args, reply *Reply) error {
reply.C = args.A * args.B
return nil
}
-func (t *Arith) Div(args Args, reply *Reply) os.Error {
+func (t *Arith) Div(args Args, reply *Reply) error {
if args.B == 0 {
- return os.NewError("divide by zero")
+ return errors.New("divide by zero")
}
reply.C = args.A / args.B
return nil
}
-func (t *Arith) String(args *Args, reply *string) os.Error {
+func (t *Arith) String(args *Args, reply *string) error {
*reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
return nil
}
-func (t *Arith) Scan(args string, reply *Reply) (err os.Error) {
+func (t *Arith) Scan(args string, reply *Reply) (err error) {
_, err = fmt.Sscan(args, &reply.C)
return
}
-func (t *Arith) Error(args *Args, reply *Reply) os.Error {
+func (t *Arith) Error(args *Args, reply *Reply) error {
panic("ERROR")
}
@@ -131,7 +131,7 @@ func testRPC(t *testing.T, addr string) {
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())
+ t.Errorf("Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
@@ -144,7 +144,7 @@ func testRPC(t *testing.T, addr string) {
// expect an error
if err == nil {
t.Error("BadOperation: expected error")
- } else if !strings.HasPrefix(err.String(), "rpc: can't find method ") {
+ } else if !strings.HasPrefix(err.Error(), "rpc: can't find method ") {
t.Errorf("BadOperation: expected can't find method error; got %q", err)
}
@@ -154,7 +154,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Unknown", args, reply)
if err == nil {
t.Error("expected error calling unknown service")
- } else if strings.Index(err.String(), "method") < 0 {
+ } else if strings.Index(err.Error(), "method") < 0 {
t.Error("expected error about method; got", err)
}
@@ -167,7 +167,7 @@ func testRPC(t *testing.T, addr string) {
addCall = <-addCall.Done
if addCall.Error != nil {
- t.Errorf("Add: expected no error but got string %q", addCall.Error.String())
+ t.Errorf("Add: expected no error but got string %q", addCall.Error.Error())
}
if addReply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", addReply.C, args.A+args.B)
@@ -175,7 +175,7 @@ func testRPC(t *testing.T, addr string) {
mulCall = <-mulCall.Done
if mulCall.Error != nil {
- t.Errorf("Mul: expected no error but got string %q", mulCall.Error.String())
+ t.Errorf("Mul: expected no error but got string %q", mulCall.Error.Error())
}
if mulReply.C != args.A*args.B {
t.Errorf("Mul: expected %d got %d", mulReply.C, args.A*args.B)
@@ -188,7 +188,7 @@ func testRPC(t *testing.T, addr string) {
// expect an error: zero divide
if err == nil {
t.Error("Div: expected error")
- } else if err.String() != "divide by zero" {
+ } else if err.Error() != "divide by zero" {
t.Error("Div: expected divide by zero error; got", err)
}
@@ -197,7 +197,7 @@ func testRPC(t *testing.T, addr string) {
err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
if err == nil {
t.Error("expected error calling Arith.Add with wrong arg type")
- } else if strings.Index(err.String(), "type") < 0 {
+ } else if strings.Index(err.Error(), "type") < 0 {
t.Error("expected error about type; got", err)
}
@@ -207,7 +207,7 @@ func testRPC(t *testing.T, addr string) {
reply = new(Reply)
err = client.Call("Arith.Scan", &str, reply)
if err != nil {
- t.Errorf("Scan: expected no error but got string %q", err.String())
+ t.Errorf("Scan: expected no error but got string %q", err.Error())
} else if reply.C != Val {
t.Errorf("Scan: expected %d got %d", Val, reply.C)
}
@@ -217,7 +217,7 @@ func testRPC(t *testing.T, addr string) {
str = ""
err = client.Call("Arith.String", args, &str)
if err != nil {
- t.Errorf("String: expected no error but got string %q", err.String())
+ t.Errorf("String: expected no error but got string %q", err.Error())
}
expect := fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B)
if str != expect {
@@ -228,7 +228,7 @@ func testRPC(t *testing.T, addr string) {
reply = new(Reply)
err = client.Call("Arith.Mul", args, reply)
if err != nil {
- t.Errorf("Mul: expected no error but got string %q", err.String())
+ t.Errorf("Mul: expected no error but got string %q", err.Error())
}
if reply.C != args.A*args.B {
t.Errorf("Mul: expected %d got %d", reply.C, args.A*args.B)
@@ -244,7 +244,7 @@ func TestHTTP(t *testing.T) {
func testHTTPRPC(t *testing.T, path string) {
var client *Client
- var err os.Error
+ var err error
if path == "" {
client, err = DialHTTP("tcp", httpServerAddr)
} else {
@@ -259,7 +259,7 @@ func testHTTPRPC(t *testing.T, path string) {
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())
+ t.Errorf("Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
@@ -273,15 +273,15 @@ type CodecEmulator struct {
serviceMethod string
args *Args
reply *Reply
- err os.Error
+ err error
}
-func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply) os.Error {
+func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply) error {
codec.serviceMethod = serviceMethod
codec.args = args
codec.reply = reply
codec.err = nil
- var serverError os.Error
+ var serverError error
if codec.server == nil {
serverError = ServeRequest(codec)
} else {
@@ -293,13 +293,13 @@ func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply)
return codec.err
}
-func (codec *CodecEmulator) ReadRequestHeader(req *Request) os.Error {
+func (codec *CodecEmulator) ReadRequestHeader(req *Request) error {
req.ServiceMethod = codec.serviceMethod
req.Seq = 0
return nil
}
-func (codec *CodecEmulator) ReadRequestBody(argv interface{}) os.Error {
+func (codec *CodecEmulator) ReadRequestBody(argv interface{}) error {
if codec.args == nil {
return io.ErrUnexpectedEOF
}
@@ -307,15 +307,16 @@ func (codec *CodecEmulator) ReadRequestBody(argv interface{}) os.Error {
return nil
}
-func (codec *CodecEmulator) WriteResponse(resp *Response, reply interface{}) os.Error {
+func (codec *CodecEmulator) WriteResponse(resp *Response, reply interface{}) error {
if resp.Error != "" {
- codec.err = os.NewError(resp.Error)
+ codec.err = errors.New(resp.Error)
+ } else {
+ *codec.reply = *(reply.(*Reply))
}
- *codec.reply = *(reply.(*Reply))
return nil
}
-func (codec *CodecEmulator) Close() os.Error {
+func (codec *CodecEmulator) Close() error {
return nil
}
@@ -333,7 +334,7 @@ func testServeRequest(t *testing.T, server *Server) {
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())
+ t.Errorf("Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
@@ -350,15 +351,15 @@ type ArgNotPublic int
type ReplyNotPublic int
type local struct{}
-func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) os.Error {
+func (t *ReplyNotPointer) ReplyNotPointer(args *Args, reply Reply) error {
return nil
}
-func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) os.Error {
+func (t *ArgNotPublic) ArgNotPublic(args *local, reply *Reply) error {
return nil
}
-func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) os.Error {
+func (t *ReplyNotPublic) ReplyNotPublic(args *Args, reply *local) error {
return nil
}
@@ -380,22 +381,22 @@ func TestRegistrationError(t *testing.T) {
type WriteFailCodec int
-func (WriteFailCodec) WriteRequest(*Request, interface{}) os.Error {
+func (WriteFailCodec) WriteRequest(*Request, interface{}) error {
// the panic caused by this error used to not unlock a lock.
- return os.NewError("fail")
+ return errors.New("fail")
}
-func (WriteFailCodec) ReadResponseHeader(*Response) os.Error {
- time.Sleep(120e9)
+func (WriteFailCodec) ReadResponseHeader(*Response) error {
+ select {}
panic("unreachable")
}
-func (WriteFailCodec) ReadResponseBody(interface{}) os.Error {
- time.Sleep(120e9)
+func (WriteFailCodec) ReadResponseBody(interface{}) error {
+ select {}
panic("unreachable")
}
-func (WriteFailCodec) Close() os.Error {
+func (WriteFailCodec) Close() error {
return nil
}
@@ -411,7 +412,7 @@ func TestSendDeadlock(t *testing.T) {
select {
case <-done:
return
- case <-time.After(5e9):
+ case <-time.After(5 * time.Second):
t.Fatal("deadlock")
}
}
@@ -425,15 +426,15 @@ func testSendDeadlock(client *Client) {
client.Call("Arith.Add", args, reply)
}
-func dialDirect() (*Client, os.Error) {
+func dialDirect() (*Client, error) {
return Dial("tcp", serverAddr)
}
-func dialHTTP() (*Client, os.Error) {
+func dialHTTP() (*Client, error) {
return DialHTTP("tcp", httpServerAddr)
}
-func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
+func countMallocs(dial func() (*Client, error), t *testing.T) uint64 {
once.Do(startServer)
client, err := dial()
if err != nil {
@@ -441,20 +442,21 @@ 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
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ mallocs := 0 - memstats.Mallocs
const count = 100
for i := 0; i < count; i++ {
err := client.Call("Arith.Add", args, reply)
if err != nil {
- t.Errorf("Add: expected no error but got string %q", err.String())
+ t.Errorf("Add: expected no error but got string %q", err.Error())
}
if reply.C != args.A+args.B {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
}
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
+ runtime.ReadMemStats(memstats)
+ mallocs += memstats.Mallocs
return mallocs / count
}
@@ -466,30 +468,116 @@ func TestCountMallocsOverHTTP(t *testing.T) {
fmt.Printf("mallocs per HTTP rpc round trip: %d\n", countMallocs(dialHTTP, t))
}
-func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
+type writeCrasher struct {
+ done chan bool
+}
+
+func (writeCrasher) Close() error {
+ return nil
+}
+
+func (w *writeCrasher) Read(p []byte) (int, error) {
+ <-w.done
+ return 0, io.EOF
+}
+
+func (writeCrasher) Write(p []byte) (int, error) {
+ return 0, errors.New("fake write failure")
+}
+
+func TestClientWriteError(t *testing.T) {
+ w := &writeCrasher{done: make(chan bool)}
+ c := NewClient(w)
+ res := false
+ err := c.Call("foo", 1, &res)
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if err.Error() != "fake write failure" {
+ t.Error("unexpected value of error:", err)
+ }
+ w.done <- true
+}
+
+func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
b.StopTimer()
once.Do(startServer)
client, err := dial()
if err != nil {
- fmt.Println("error dialing", err)
- return
+ b.Fatal("error dialing:", err)
}
// Synchronous calls
args := &Args{7, 8}
- reply := new(Reply)
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N)
+ var wg sync.WaitGroup
+ wg.Add(procs)
b.StartTimer()
- for i := 0; i < b.N; i++ {
- err = client.Call("Arith.Add", args, reply)
- if err != nil {
- fmt.Printf("Add: expected no error but got string %q", err.String())
- break
- }
- if reply.C != args.A+args.B {
- fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B)
- break
- }
+
+ for p := 0; p < procs; p++ {
+ go func() {
+ reply := new(Reply)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ err := client.Call("Arith.Add", args, reply)
+ if err != nil {
+ b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
+ }
+ if reply.C != args.A+args.B {
+ b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
+ }
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
+ const MaxConcurrentCalls = 100
+ b.StopTimer()
+ once.Do(startServer)
+ client, err := dial()
+ if err != nil {
+ b.Fatal("error dialing:", err)
}
+
+ // Asynchronous calls
+ args := &Args{7, 8}
+ procs := 4 * runtime.GOMAXPROCS(-1)
+ send := int32(b.N)
+ recv := int32(b.N)
+ var wg sync.WaitGroup
+ wg.Add(procs)
+ gate := make(chan bool, MaxConcurrentCalls)
+ res := make(chan *Call, MaxConcurrentCalls)
+ b.StartTimer()
+
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&send, -1) >= 0 {
+ gate <- true
+ reply := new(Reply)
+ client.Go("Arith.Add", args, reply, res)
+ }
+ }()
+ go func() {
+ for call := range res {
+ A := call.Args.(*Args).A
+ B := call.Args.(*Args).B
+ C := call.Reply.(*Reply).C
+ if A+B != C {
+ b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
+ }
+ <-gate
+ if atomic.AddInt32(&recv, -1) == 0 {
+ close(res)
+ }
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
}
func BenchmarkEndToEnd(b *testing.B) {
@@ -499,3 +587,11 @@ func BenchmarkEndToEnd(b *testing.B) {
func BenchmarkEndToEndHTTP(b *testing.B) {
benchmarkEndToEnd(dialHTTP, b)
}
+
+func BenchmarkEndToEndAsync(b *testing.B) {
+ benchmarkEndToEndAsync(dialDirect, b)
+}
+
+func BenchmarkEndToEndAsyncHTTP(b *testing.B) {
+ benchmarkEndToEndAsync(dialHTTP, b)
+}
diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go
index 6a5a06c8c..a0d530362 100644
--- a/src/pkg/net/sendfile_linux.go
+++ b/src/pkg/net/sendfile_linux.go
@@ -21,7 +21,7 @@ const maxSendfileSize int = 4 << 20
// non-EOF error.
//
// if handled == false, sendFile performed no work.
-func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
var remain int64 = 1 << 62 // by default, copy until EOF
lr, ok := r.(*io.LimitedReader)
@@ -38,42 +38,36 @@ func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool)
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
+ if err := c.incref(false); err != nil {
+ return 0, err, true
}
+ defer c.decref()
dst := c.sysfd
- src := f.Fd()
+ src := int(f.Fd())
for remain > 0 {
n := maxSendfileSize
if int64(n) > remain {
n = int(remain)
}
- n, errno := syscall.Sendfile(dst, src, nil, n)
+ n, err1 := syscall.Sendfile(dst, src, nil, n)
if n > 0 {
written += int64(n)
remain -= int64(n)
}
- if n == 0 && errno == 0 {
+ if n == 0 && err1 == nil {
break
}
- if errno == syscall.EAGAIN && c.wdeadline >= 0 {
- pollserver.WaitWrite(c)
- continue
+ if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
+ if err1 = pollserver.WaitWrite(c); err1 == nil {
+ continue
+ }
}
- if errno != 0 {
+ if err1 != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile together)
- err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)}
+ err = &OpError{"sendfile", c.net, c.raddr, err1}
break
}
}
diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
index 43e8104e9..ff76ab9cf 100644
--- a/src/pkg/net/sendfile_stub.go
+++ b/src/pkg/net/sendfile_stub.go
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd netbsd openbsd
+
package net
-import (
- "io"
- "os"
-)
+import "io"
-func sendFile(c *netFD, r io.Reader) (n int64, err os.Error, handled bool) {
+func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) {
return 0, nil, false
}
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
index 3772eee24..f5a6d8804 100644
--- a/src/pkg/net/sendfile_windows.go
+++ b/src/pkg/net/sendfile_windows.go
@@ -16,7 +16,7 @@ type sendfileOp struct {
n uint32
}
-func (o *sendfileOp) Submit() (errno int) {
+func (o *sendfileOp) Submit() (err error) {
return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
}
@@ -33,7 +33,7 @@ func (o *sendfileOp) Name() string {
// 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) {
+func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
var n int64 = 0 // by default, copy until EOF
lr, ok := r.(*io.LimitedReader)
@@ -50,13 +50,15 @@ func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool)
c.wio.Lock()
defer c.wio.Unlock()
- c.incref()
+ if err := c.incref(false); err != nil {
+ return 0, err, true
+ }
defer c.decref()
var o sendfileOp
- o.Init(c)
+ o.Init(c, 'w')
o.n = uint32(n)
- o.src = f.Fd()
+ o.src = syscall.Handle(f.Fd())
done, err := iosrv.ExecIO(&o, 0)
if err != nil {
return 0, err, false
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 7d7f7fc01..158b9477d 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -8,236 +8,462 @@ import (
"flag"
"io"
"os"
- "strings"
- "syscall"
- "testing"
"runtime"
+ "testing"
+ "time"
)
-// Do not test empty datagrams by default.
-// It causes unexplained timeouts on some systems,
-// including Snow Leopard. I think that the kernel
-// doesn't quite expect them.
-var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+ switch runtime.GOOS {
+ case "linux":
+ case "plan9", "windows":
+ // "unix" sockets are not supported on Windows and Plan 9.
+ if net == unixsotype {
+ return true
+ }
+ default:
+ if net == unixsotype && linuxonly {
+ return true
+ }
+ }
+ switch addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ if testing.Short() || !*testExternal {
+ return true
+ }
+ }
+ if ipv6 && !supportsIPv6 {
+ return true
+ }
+ if ipv4map && !supportsIPv4map {
+ return true
+ }
+ return false
+}
-func runEcho(fd io.ReadWriter, done chan<- int) {
- var buf [1024]byte
+var streamConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "[::1]", ipv6: true},
- for {
- n, err := fd.Read(buf[0:])
- if err != nil || n == 0 || string(buf[:n]) == "END" {
- break
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "127.0.0.1", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:127.0.0.1]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::1]", cnet: "tcp", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp4", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp6", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+ {snet: "tcp6", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+ {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+}
+
+func TestStreamConnServer(t *testing.T) {
+ for _, tt := range streamConnServerTests {
+ if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "tcp", "tcp4", "tcp6":
+ tt.saddr += ":0"
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "tcp", "tcp4", "tcp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ }
+
+ runStreamConnClient(t, tt.cnet, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
}
- fd.Write(buf[0:n])
}
- done <- 1
}
-func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- l, err := Listen(network, addr)
+var seqpacketConnServerTests = []struct {
+ net string
+ saddr string // server address
+ caddr string // client address
+ empty bool // test with empty data
+}{
+ {net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+ {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+}
+
+func TestSeqpacketConnServer(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range seqpacketConnServerTests {
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ runStreamConnClient(t, tt.net, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+ }
+}
+
+func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ l, err := Listen(net, laddr)
if err != nil {
- t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer l.Close()
listening <- l.Addr().String()
+ echo := func(rw io.ReadWriter, done chan<- int) {
+ buf := make([]byte, 1024)
+ for {
+ n, err := rw.Read(buf[0:])
+ if err != nil || n == 0 || string(buf[:n]) == "END" {
+ break
+ }
+ rw.Write(buf[0:n])
+ }
+ done <- 1
+ }
+
+run:
for {
- fd, err := l.Accept()
+ c, err := l.Accept()
if err != nil {
- break
+ continue run
}
echodone := make(chan int)
- go runEcho(fd, echodone)
- <-echodone // make sure Echo stops
- l.Close()
+ go echo(c, echodone)
+ <-echodone // make sure echo stopped
+ c.Close()
+ break run
}
done <- 1
}
-func connect(t *testing.T, network, addr string, isEmpty bool) {
- var fd Conn
- var err os.Error
- if network == "unixgram" {
- fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
- } else {
- fd, err = Dial(network, addr)
- }
+func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
+ c, err := Dial(net, taddr)
if err != nil {
- t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
}
- fd.SetReadTimeout(1e9) // 1s
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
- var b []byte
+ var wb []byte
if !isEmpty {
- b = []byte("hello, world\n")
+ wb = []byte("StreamConnClient by Dial\n")
}
- var b1 [100]byte
-
- n, err1 := fd.Write(b)
- if n != len(b) {
- t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+ if n, err := c.Write(wb); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
- n, err1 = fd.Read(b1[0:])
- if n != len(b) || err1 != nil {
- t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
// Send explicit ending for unixpacket.
- // Older Linux kernels do stop reads on close.
- if network == "unixpacket" {
- fd.Write([]byte("END"))
+ // Older Linux kernels do not stop reads on close.
+ switch net {
+ case "unixpacket":
+ c.Write([]byte("END"))
}
-
- fd.Close()
}
-func doTest(t *testing.T, network, listenaddr, dialaddr string) {
- 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" || 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" || network == "tcp4" || network == "tcp6" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, false)
- <-done // make sure server stopped
-}
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard. I think that the kernel
+// doesn't quite expect them.
+var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
-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")
- 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")
- }
+var datagramPacketConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ dial bool // test with Dial or DialUnix
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:127.0.0.1]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp4", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
+ {snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", empty: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
+
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
}
-func TestUnixServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func TestDatagramPacketConnServer(t *testing.T) {
+ if !*testDatagram {
return
}
- os.Remove("/tmp/gotest.net")
- doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- if syscall.OS == "linux" {
- doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- // Test abstract unix domain socket, a Linux-ism
- doTest(t, "unix", "@gotest/net", "@gotest/net")
- doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
+
+ for _, tt := range datagramPacketConnServerTests {
+ if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "udp", "udp4", "udp6":
+ tt.saddr += ":0"
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "udp", "udp4", "udp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ tt.caddr += ":0"
+ }
+ if tt.dial {
+ runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ } else {
+ runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ }
+ <-done // tell server to stop
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
}
}
-func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- c, err := ListenPacket(network, addr)
+func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ c, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer c.Close()
listening <- c.LocalAddr().String()
- c.SetReadTimeout(10e6) // 10ms
- var buf [1000]byte
-Run:
+
+ buf := make([]byte, 1024)
+run:
for {
- n, addr, err := c.ReadFrom(buf[0:])
- if e, ok := err.(Error); ok && e.Timeout() {
+ c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
+ n, ra, err := c.ReadFrom(buf[0:])
+ if nerr, ok := err.(Error); ok && nerr.Timeout() {
select {
case done <- 1:
- break Run
+ break run
default:
- continue Run
+ continue run
}
}
if err != nil {
- break
+ break run
}
- if _, err = c.WriteTo(buf[0:n], addr); err != nil {
- t.Fatalf("WriteTo %v: %v", addr, err)
+ if _, err = c.WriteTo(buf[0:n], ra); err != nil {
+ t.Errorf("WriteTo(%v) failed: %v", ra, err)
+ break run
}
}
- c.Close()
done <- 1
}
-func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
- t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr)
- listening := make(chan string)
- done := make(chan int)
- if network == "udp" {
- listenaddr += ":0" // any available port
- }
- go runPacket(t, network, listenaddr, listening, done)
- addr := <-listening // wait for server to start
- if network == "udp" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, isEmpty)
- <-done // tell server to stop
- <-done // wait for stop
-}
+func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var c Conn
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ c, err = Dial(net, taddr)
+ if err != nil {
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ c, err = DialUnix(net, &UnixAddr{laddr, net}, &UnixAddr{taddr, net})
+ if err != nil {
+ t.Errorf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
+ return
+ }
+ }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
-func TestUDPServer(t *testing.T) {
- if !*testUDP {
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramConnClient by Dial\n")
+ }
+ if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
return
}
- for _, isEmpty := range []bool{false, true} {
- doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
- doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
- if 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)
- }
+
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
-func TestUnixDatagramServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var ra Addr
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ ra, err = ResolveUDPAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ ra, err = ResolveUnixAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ }
+ c, err := ListenPacket(net, laddr)
+ if err != nil {
+ t.Errorf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
return
}
- for _, isEmpty := range []bool{false} {
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- if syscall.OS == "linux" {
- // Test abstract unix domain socket, a Linux-ism
- doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
- }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
+
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramPacketConnClient by ListenPacket\n")
+ }
+ if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
+ t.Errorf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
+ return
+ }
+
+ rb := make([]byte, 1024)
+ if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
diff --git a/src/pkg/smtp/auth.go b/src/pkg/net/smtp/auth.go
index dd27f8e93..d401e3c21 100644
--- a/src/pkg/smtp/auth.go
+++ b/src/pkg/net/smtp/auth.go
@@ -5,7 +5,10 @@
package smtp
import (
- "os"
+ "crypto/hmac"
+ "crypto/md5"
+ "errors"
+ "fmt"
)
// Auth is implemented by an SMTP authentication mechanism.
@@ -15,17 +18,17 @@ type Auth interface {
// and optionally data to include in the initial AUTH message
// sent to the server. It can return proto == "" to indicate
// that the authentication should be skipped.
- // If it returns a non-nil os.Error, the SMTP client aborts
+ // If it returns a non-nil error, the SMTP client aborts
// the authentication attempt and closes the connection.
- Start(server *ServerInfo) (proto string, toServer []byte, err os.Error)
+ Start(server *ServerInfo) (proto string, toServer []byte, err error)
// Next continues the authentication. The server has just sent
// the fromServer data. If more is true, the server expects a
// response, which Next should return as toServer; otherwise
// Next should return toServer == nil.
- // If Next returns a non-nil os.Error, the SMTP client aborts
+ // If Next returns a non-nil error, the SMTP client aborts
// the authentication attempt and closes the connection.
- Next(fromServer []byte, more bool) (toServer []byte, err os.Error)
+ Next(fromServer []byte, more bool) (toServer []byte, err error)
}
// ServerInfo records information about an SMTP server.
@@ -49,21 +52,47 @@ func PlainAuth(identity, username, password, host string) Auth {
return &plainAuth{identity, username, password, host}
}
-func (a *plainAuth) Start(server *ServerInfo) (string, []byte, os.Error) {
+func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
if !server.TLS {
- return "", nil, os.NewError("unencrypted connection")
+ return "", nil, errors.New("unencrypted connection")
}
if server.Name != a.host {
- return "", nil, os.NewError("wrong host name")
+ return "", nil, errors.New("wrong host name")
}
resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
return "PLAIN", resp, nil
}
-func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, os.Error) {
+func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
// We've already sent everything.
- return nil, os.NewError("unexpected server challenge")
+ return nil, errors.New("unexpected server challenge")
+ }
+ return nil, nil
+}
+
+type cramMD5Auth struct {
+ username, secret string
+}
+
+// CRAMMD5Auth returns an Auth that implements the CRAM-MD5 authentication
+// mechanism as defined in RFC 2195.
+// The returned Auth uses the given username and secret to authenticate
+// to the server using the challenge-response mechanism.
+func CRAMMD5Auth(username, secret string) Auth {
+ return &cramMD5Auth{username, secret}
+}
+
+func (a *cramMD5Auth) Start(server *ServerInfo) (string, []byte, error) {
+ return "CRAM-MD5", nil, nil
+}
+
+func (a *cramMD5Auth) Next(fromServer []byte, more bool) ([]byte, error) {
+ if more {
+ d := hmac.New(md5.New, []byte(a.secret))
+ d.Write(fromServer)
+ s := make([]byte, 0, d.Size())
+ return []byte(fmt.Sprintf("%s %x", a.username, d.Sum(s))), nil
}
return nil, nil
}
diff --git a/src/pkg/smtp/smtp.go b/src/pkg/net/smtp/smtp.go
index 2d5e86247..59f6449f0 100644
--- a/src/pkg/smtp/smtp.go
+++ b/src/pkg/net/smtp/smtp.go
@@ -14,7 +14,6 @@ import (
"crypto/tls"
"encoding/base64"
"io"
- "os"
"net"
"net/textproto"
"strings"
@@ -38,7 +37,7 @@ type Client struct {
}
// Dial returns a new Client connected to an SMTP server at addr.
-func Dial(addr string) (*Client, os.Error) {
+func Dial(addr string) (*Client, error) {
conn, err := net.Dial("tcp", addr)
if err != nil {
return nil, err
@@ -49,24 +48,23 @@ func Dial(addr string) (*Client, os.Error) {
// NewClient returns a new Client using an existing connection and host as a
// server name to be used when authenticating.
-func NewClient(conn net.Conn, host string) (*Client, os.Error) {
+func NewClient(conn net.Conn, host string) (*Client, error) {
text := textproto.NewConn(conn)
- _, msg, err := text.ReadResponse(220)
+ _, _, err := text.ReadResponse(220)
if err != nil {
text.Close()
return nil, err
}
c := &Client{Text: text, conn: conn, serverName: host}
- if strings.Contains(msg, "ESMTP") {
- err = c.ehlo()
- } else {
+ err = c.ehlo()
+ if err != nil {
err = c.helo()
}
return c, err
}
// cmd is a convenience function that sends a command and returns the response
-func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
+func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, error) {
id, err := c.Text.Cmd(format, args...)
if err != nil {
return 0, "", err
@@ -79,7 +77,7 @@ func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, s
// helo sends the HELO greeting to the server. It should be used only when the
// server does not support ehlo.
-func (c *Client) helo() os.Error {
+func (c *Client) helo() error {
c.ext = nil
_, _, err := c.cmd(250, "HELO localhost")
return err
@@ -87,7 +85,7 @@ func (c *Client) helo() os.Error {
// ehlo sends the EHLO (extended hello) greeting to the server. It
// should be the preferred greeting for servers that support it.
-func (c *Client) ehlo() os.Error {
+func (c *Client) ehlo() error {
_, msg, err := c.cmd(250, "EHLO localhost")
if err != nil {
return err
@@ -114,7 +112,7 @@ func (c *Client) ehlo() os.Error {
// StartTLS sends the STARTTLS command and encrypts all further communication.
// Only servers that advertise the STARTTLS extension support this function.
-func (c *Client) StartTLS(config *tls.Config) os.Error {
+func (c *Client) StartTLS(config *tls.Config) error {
_, _, err := c.cmd(220, "STARTTLS")
if err != nil {
return err
@@ -129,7 +127,7 @@ func (c *Client) StartTLS(config *tls.Config) os.Error {
// If Verify returns nil, the address is valid. A non-nil return
// does not necessarily indicate an invalid address. Many servers
// will not verify addresses for security reasons.
-func (c *Client) Verify(addr string) os.Error {
+func (c *Client) Verify(addr string) error {
_, _, err := c.cmd(250, "VRFY %s", addr)
return err
}
@@ -137,7 +135,7 @@ func (c *Client) Verify(addr string) os.Error {
// Auth authenticates a client using the provided authentication mechanism.
// A failed authentication closes the connection.
// Only servers that advertise the AUTH extension support this function.
-func (c *Client) Auth(a Auth) os.Error {
+func (c *Client) Auth(a Auth) error {
encoding := base64.StdEncoding
mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
if err != nil {
@@ -156,7 +154,7 @@ func (c *Client) Auth(a Auth) os.Error {
// the last message isn't base64 because it isn't a challenge
msg = []byte(msg64)
default:
- err = &textproto.Error{code, msg64}
+ err = &textproto.Error{Code: code, Msg: msg64}
}
resp, err = a.Next(msg, code == 334)
if err != nil {
@@ -179,7 +177,7 @@ func (c *Client) Auth(a Auth) os.Error {
// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
// parameter.
// This initiates a mail transaction and is followed by one or more Rcpt calls.
-func (c *Client) Mail(from string) os.Error {
+func (c *Client) Mail(from string) error {
cmdStr := "MAIL FROM:<%s>"
if c.ext != nil {
if _, ok := c.ext["8BITMIME"]; ok {
@@ -193,7 +191,7 @@ func (c *Client) Mail(from string) os.Error {
// Rcpt issues a RCPT command to the server using the provided email address.
// A call to Rcpt must be preceded by a call to Mail and may be followed by
// a Data call or another Rcpt call.
-func (c *Client) Rcpt(to string) os.Error {
+func (c *Client) Rcpt(to string) error {
_, _, err := c.cmd(25, "RCPT TO:<%s>", to)
return err
}
@@ -203,7 +201,7 @@ type dataCloser struct {
io.WriteCloser
}
-func (d *dataCloser) Close() os.Error {
+func (d *dataCloser) Close() error {
d.WriteCloser.Close()
_, _, err := d.c.Text.ReadResponse(250)
return err
@@ -213,7 +211,7 @@ func (d *dataCloser) Close() os.Error {
// can be used to write the data. The caller should close the writer
// before calling any more methods on c.
// A call to Data must be preceded by one or more calls to Rcpt.
-func (c *Client) Data() (io.WriteCloser, os.Error) {
+func (c *Client) Data() (io.WriteCloser, error) {
_, _, err := c.cmd(354, "DATA")
if err != nil {
return nil, err
@@ -224,7 +222,7 @@ func (c *Client) Data() (io.WriteCloser, os.Error) {
// SendMail connects to the server at addr, switches to TLS if possible,
// authenticates with mechanism a if possible, and then sends an email from
// address from, to addresses to, with message msg.
-func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
+func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
c, err := Dial(addr)
if err != nil {
return err
@@ -279,13 +277,13 @@ func (c *Client) Extension(ext string) (bool, string) {
// Reset sends the RSET command to the server, aborting the current mail
// transaction.
-func (c *Client) Reset() os.Error {
+func (c *Client) Reset() error {
_, _, err := c.cmd(250, "RSET")
return err
}
// Quit sends the QUIT command and closes the connection to the server.
-func (c *Client) Quit() os.Error {
+func (c *Client) Quit() error {
_, _, err := c.cmd(221, "QUIT")
if err != nil {
return err
diff --git a/src/pkg/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index c053557d7..c315d185c 100644
--- a/src/pkg/smtp/smtp_test.go
+++ b/src/pkg/net/smtp/smtp_test.go
@@ -8,10 +8,11 @@ import (
"bufio"
"bytes"
"io"
+ "net"
"net/textproto"
- "os"
"strings"
"testing"
+ "time"
)
type authTest struct {
@@ -24,6 +25,7 @@ type authTest struct {
var authTests = []authTest{
{PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}},
{PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}},
+ {CRAMMD5Auth("user", "pass"), []string{"<123456.1322876914@testserver>"}, "CRAM-MD5", []string{"", "user 287eb355114cf5c471c26a875f1ca4ae"}},
}
func TestAuth(t *testing.T) {
@@ -37,14 +39,14 @@ testLoop:
t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0])
}
if err != nil {
- t.Errorf("#%d error: %s", i, err.String())
+ t.Errorf("#%d error: %s", i, err)
}
for j := range test.challenges {
challenge := []byte(test.challenges[j])
expected := []byte(test.responses[j+1])
resp, err := test.auth.Next(challenge, true)
if err != nil {
- t.Errorf("#%d error: %s", i, err.String())
+ t.Errorf("#%d error: %s", i, err)
continue testLoop
}
if !bytes.Equal(resp, expected) {
@@ -59,9 +61,12 @@ type faker struct {
io.ReadWriter
}
-func (f faker) Close() os.Error {
- return nil
-}
+func (f faker) Close() error { return nil }
+func (f faker) LocalAddr() net.Addr { return nil }
+func (f faker) RemoteAddr() net.Addr { return nil }
+func (f faker) SetDeadline(time.Time) error { return nil }
+func (f faker) SetReadDeadline(time.Time) error { return nil }
+func (f faker) SetWriteDeadline(time.Time) error { return nil }
func TestBasic(t *testing.T) {
basicServer = strings.Join(strings.Split(basicServer, "\n"), "\r\n")
@@ -74,13 +79,13 @@ func TestBasic(t *testing.T) {
c := &Client{Text: textproto.NewConn(fake)}
if err := c.helo(); err != nil {
- t.Fatalf("HELO failed: %s", err.String())
+ t.Fatalf("HELO failed: %s", err)
}
if err := c.ehlo(); err == nil {
t.Fatalf("Expected first EHLO to fail")
}
if err := c.ehlo(); err != nil {
- t.Fatalf("Second EHLO failed: %s", err.String())
+ t.Fatalf("Second EHLO failed: %s", err)
}
if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
@@ -105,14 +110,14 @@ func TestBasic(t *testing.T) {
c.tls = true
c.serverName = "smtp.google.com"
if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil {
- t.Fatalf("AUTH failed: %s", err.String())
+ t.Fatalf("AUTH failed: %s", err)
}
if err := c.Mail("user@gmail.com"); err != nil {
- t.Fatalf("MAIL failed: %s", err.String())
+ t.Fatalf("MAIL failed: %s", err)
}
if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil {
- t.Fatalf("RCPT failed: %s", err.String())
+ t.Fatalf("RCPT failed: %s", err)
}
msg := `From: user@gmail.com
To: golang-nuts@googlegroups.com
@@ -123,17 +128,17 @@ Line 1
Goodbye.`
w, err := c.Data()
if err != nil {
- t.Fatalf("DATA failed: %s", err.String())
+ t.Fatalf("DATA failed: %s", err)
}
if _, err := w.Write([]byte(msg)); err != nil {
- t.Fatalf("Data write failed: %s", err.String())
+ t.Fatalf("Data write failed: %s", err)
}
if err := w.Close(); err != nil {
- t.Fatalf("Bad data response: %s", err.String())
+ t.Fatalf("Bad data response: %s", err)
}
if err := c.Quit(); err != nil {
- t.Fatalf("QUIT failed: %s", err.String())
+ t.Fatalf("QUIT failed: %s", err)
}
bcmdbuf.Flush()
@@ -180,3 +185,87 @@ Goodbye.
.
QUIT
`
+
+func TestNewClient(t *testing.T) {
+ newClientServer = strings.Join(strings.Split(newClientServer, "\n"), "\r\n")
+ newClientClient = strings.Join(strings.Split(newClientClient, "\n"), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ out := func() string {
+ bcmdbuf.Flush()
+ return cmdbuf.String()
+ }
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(newClientServer)), bcmdbuf)
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v\n(after %v)", err, out())
+ }
+ if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
+ t.Fatalf("Expected AUTH supported")
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err)
+ }
+
+ actualcmds := out()
+ if newClientClient != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, newClientClient)
+ }
+}
+
+var newClientServer = `220 hello world
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+221 OK
+`
+
+var newClientClient = `EHLO localhost
+QUIT
+`
+
+func TestNewClient2(t *testing.T) {
+ newClient2Server = strings.Join(strings.Split(newClient2Server, "\n"), "\r\n")
+ newClient2Client = strings.Join(strings.Split(newClient2Client, "\n"), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(newClient2Server)), bcmdbuf)
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v", err)
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err)
+ }
+
+ bcmdbuf.Flush()
+ actualcmds := cmdbuf.String()
+ if newClient2Client != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, newClient2Client)
+ }
+}
+
+var newClient2Server = `220 hello world
+502 EH?
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+221 OK
+`
+
+var newClient2Client = `EHLO localhost
+HELO localhost
+QUIT
+`
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index 821716e43..3ae16054e 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -2,61 +2,72 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
// Sockets
package net
import (
"io"
- "os"
- "reflect"
"syscall"
)
-// Boolean to int.
-func boolint(b bool) int {
- if b {
- return 1
- }
- return 0
-}
+var listenerBacklog = maxListenerBacklog()
// Generic socket creation.
-func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+func socket(net string, f, t, p int, ipv6only bool, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, e := syscall.Socket(f, p, t)
- if e != 0 {
+ s, err := syscall.Socket(f, t, p)
+ if err != nil {
syscall.ForkLock.RUnlock()
- return nil, os.Errno(e)
+ return nil, err
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
- setKernelSpecificSockopt(s, f)
+ err = setDefaultSockopts(s, f, t, ipv6only)
+ if err != nil {
+ closesocket(s)
+ return nil, err
+ }
+ var bla syscall.Sockaddr
if la != nil {
- e = syscall.Bind(s, la)
- if e != 0 {
+ bla, err = listenerSockaddr(s, f, la, toAddr)
+ if err != nil {
+ closesocket(s)
+ return nil, err
+ }
+ err = syscall.Bind(s, bla)
+ if err != nil {
closesocket(s)
- return nil, os.Errno(e)
+ return nil, err
}
}
- if fd, err = newFD(s, f, p, net); err != nil {
+ if fd, err = newFD(s, f, t, net); err != nil {
closesocket(s)
return nil, err
}
if ra != nil {
if err = fd.connect(ra); err != nil {
+ closesocket(s)
fd.Close()
return nil, err
}
+ fd.isConnected = true
}
sa, _ := syscall.Getsockname(s)
- laddr := toAddr(sa)
+ var laddr Addr
+ if la != nil && bla != la {
+ laddr = toAddr(la)
+ } else {
+ laddr = toAddr(sa)
+ }
sa, _ = syscall.Getpeername(s)
raddr := toAddr(sa)
@@ -64,103 +75,13 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
return fd, nil
}
-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 *netFD, level, opt int, nsec int64) os.Error {
- var tv = syscall.NsecToTimeval(nsec)
- 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, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
-}
-
-func setWriteBuffer(fd *netFD, bytes int) os.Error {
- fd.incref()
- defer fd.decref()
- return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
-}
-
-func setReadTimeout(fd *netFD, nsec int64) os.Error {
- fd.rdeadline_delta = nsec
- return nil
-}
-
-func setWriteTimeout(fd *netFD, nsec int64) os.Error {
- fd.wdeadline_delta = nsec
- return nil
-}
-
-func setTimeout(fd *netFD, nsec int64) os.Error {
- if e := setReadTimeout(fd, nsec); e != nil {
- return e
- }
- return setWriteTimeout(fd, nsec)
-}
-
-func setReuseAddr(fd *netFD, reuse bool) os.Error {
- fd.incref()
- defer fd.decref()
- return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
-}
-
-func bindToDevice(fd *netFD, dev string) os.Error {
- // TODO(rsc): call setsockopt with null-terminated string pointer
- return os.EINVAL
-}
-
-func setDontRoute(fd *netFD, dontroute bool) os.Error {
- fd.incref()
- defer fd.decref()
- return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
-}
-
-func setKeepAlive(fd *netFD, keepalive bool) os.Error {
- fd.incref()
- defer fd.decref()
- 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, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
-}
-
-func setLinger(fd *netFD, sec int) os.Error {
- var l syscall.Linger
- if sec >= 0 {
- l.Onoff = 1
- l.Linger = int32(sec)
- } else {
- l.Onoff = 0
- l.Linger = 0
- }
- fd.incref()
- defer fd.decref()
- e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)
- return os.NewSyscallError("setsockopt", e)
-}
-
-type UnknownSocketError struct {
- sa syscall.Sockaddr
-}
-
-func (e *UnknownSocketError) String() string {
- return "unknown socket address type " + reflect.TypeOf(e.sa).String()
-}
-
type writerOnly struct {
io.Writer
}
// 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) {
+func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
// Use wrapper to hide existing r.ReadFrom from io.Copy.
return io.Copy(writerOnly{w}, r)
}
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 5fd52074a..2607b04c7 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.go
@@ -1,31 +1,62 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd netbsd openbsd
+
// Sockets for BSD variants
package net
import (
+ "runtime"
"syscall"
)
-func setKernelSpecificSockopt(s, f int) {
- // Allow reuse of recently-used addresses.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
-
- // Allow reuse of recently-used ports.
- // This option is supported only in descendants of 4.4BSD,
- // to make an effective multicast application and an application
- // that requires quick draw possible.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
-
- // Allow broadcast.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+func maxListenerBacklog() int {
+ var (
+ n uint32
+ err error
+ )
+ switch runtime.GOOS {
+ case "darwin", "freebsd":
+ n, err = syscall.SysctlUint32("kern.ipc.somaxconn")
+ case "netbsd":
+ // NOTE: NetBSD has no somaxconn-like kernel state so far
+ case "openbsd":
+ n, err = syscall.SysctlUint32("kern.somaxconn")
+ }
+ if n == 0 || err != nil {
+ return syscall.SOMAXCONN
+ }
+ return int(n)
+}
- if f == syscall.AF_INET6 {
- // using ip, tcp, udp, etc.
- // allow both protocols even if the OS default is otherwise.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+ a := toAddr(la)
+ if a == nil {
+ return la, nil
+ }
+ switch v := a.(type) {
+ case *TCPAddr, *UnixAddr:
+ err := setDefaultListenerSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ case *UDPAddr:
+ if v.IP.IsMulticast() {
+ err := setDefaultMulticastSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ switch f {
+ case syscall.AF_INET:
+ v.IP = IPv4zero
+ case syscall.AF_INET6:
+ v.IP = IPv6unspecified
+ }
+ return v.sockaddr(f)
+ }
}
+ return la, nil
}
diff --git a/src/pkg/net/sock_linux.go b/src/pkg/net/sock_linux.go
index ec31e803b..e509d9397 100644
--- a/src/pkg/net/sock_linux.go
+++ b/src/pkg/net/sock_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,20 +6,51 @@
package net
-import (
- "syscall"
-)
+import "syscall"
-func setKernelSpecificSockopt(s, f int) {
- // Allow reuse of recently-used addresses.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
-
- // Allow broadcast.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+func maxListenerBacklog() int {
+ fd, err := open("/proc/sys/net/core/somaxconn")
+ if err != nil {
+ return syscall.SOMAXCONN
+ }
+ defer fd.close()
+ l, ok := fd.readLine()
+ if !ok {
+ return syscall.SOMAXCONN
+ }
+ f := getFields(l)
+ n, _, ok := dtoi(f[0], 0)
+ if n == 0 || !ok {
+ return syscall.SOMAXCONN
+ }
+ return n
+}
- if f == syscall.AF_INET6 {
- // using ip, tcp, udp, etc.
- // allow both protocols even if the OS default is otherwise.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+ a := toAddr(la)
+ if a == nil {
+ return la, nil
+ }
+ switch v := a.(type) {
+ case *TCPAddr, *UnixAddr:
+ err := setDefaultListenerSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ case *UDPAddr:
+ if v.IP.IsMulticast() {
+ err := setDefaultMulticastSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ switch f {
+ case syscall.AF_INET:
+ v.IP = IPv4zero
+ case syscall.AF_INET6:
+ v.IP = IPv6unspecified
+ }
+ return v.sockaddr(f)
+ }
}
+ return la, nil
}
diff --git a/src/pkg/net/sock_windows.go b/src/pkg/net/sock_windows.go
index c6dbd0465..cce6181c9 100644
--- a/src/pkg/net/sock_windows.go
+++ b/src/pkg/net/sock_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,20 +6,38 @@
package net
-import (
- "syscall"
-)
+import "syscall"
-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)
-
- // Allow broadcast.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+func maxListenerBacklog() int {
+ // TODO: Implement this
+ return syscall.SOMAXCONN
+}
- if f == syscall.AF_INET6 {
- // using ip, tcp, udp, etc.
- // allow both protocols even if the OS default is otherwise.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+func listenerSockaddr(s syscall.Handle, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+ a := toAddr(la)
+ if a == nil {
+ return la, nil
+ }
+ switch v := a.(type) {
+ case *TCPAddr, *UnixAddr:
+ err := setDefaultListenerSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ case *UDPAddr:
+ if v.IP.IsMulticast() {
+ err := setDefaultMulticastSockopts(s)
+ if err != nil {
+ return nil, err
+ }
+ switch f {
+ case syscall.AF_INET:
+ v.IP = IPv4zero
+ case syscall.AF_INET6:
+ v.IP = IPv6unspecified
+ }
+ return v.sockaddr(f)
+ }
}
+ return la, nil
}
diff --git a/src/pkg/net/sockopt.go b/src/pkg/net/sockopt.go
new file mode 100644
index 000000000..0cd19266f
--- /dev/null
+++ b/src/pkg/net/sockopt.go
@@ -0,0 +1,193 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd windows
+
+// Socket options
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "time"
+)
+
+// Boolean to int.
+func boolint(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+func ipv4AddrToInterface(ip IP) (*Interface, error) {
+ ift, err := Interfaces()
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ for _, ifa := range ifat {
+ switch v := ifa.(type) {
+ case *IPAddr:
+ if ip.Equal(v.IP) {
+ return &ifi, nil
+ }
+ case *IPNet:
+ if ip.Equal(v.IP) {
+ return &ifi, nil
+ }
+ }
+ }
+ }
+ if ip.Equal(IPv4zero) {
+ return nil, nil
+ }
+ return nil, errNoSuchInterface
+}
+
+func interfaceToIPv4Addr(ifi *Interface) (IP, error) {
+ if ifi == nil {
+ return IPv4zero, nil
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ for _, ifa := range ifat {
+ switch v := ifa.(type) {
+ case *IPAddr:
+ if v.IP.To4() != nil {
+ return v.IP, nil
+ }
+ case *IPNet:
+ if v.IP.To4() != nil {
+ return v.IP, nil
+ }
+ }
+ }
+ return nil, errNoSuchInterface
+}
+
+func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error {
+ if ifi == nil {
+ return nil
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ return err
+ }
+ for _, ifa := range ifat {
+ switch v := ifa.(type) {
+ case *IPAddr:
+ if a := v.IP.To4(); a != nil {
+ copy(mreq.Interface[:], a)
+ goto done
+ }
+ case *IPNet:
+ if a := v.IP.To4(); a != nil {
+ copy(mreq.Interface[:], a)
+ goto done
+ }
+ }
+ }
+done:
+ if bytesEqual(mreq.Multiaddr[:], IPv4zero.To4()) {
+ return errNoSuchMulticastInterface
+ }
+ return nil
+}
+
+func setReadBuffer(fd *netFD, bytes int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
+}
+
+func setWriteBuffer(fd *netFD, bytes int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
+}
+
+func setReadDeadline(fd *netFD, t time.Time) error {
+ if t.IsZero() {
+ fd.rdeadline = 0
+ } else {
+ fd.rdeadline = t.UnixNano()
+ }
+ return nil
+}
+
+func setWriteDeadline(fd *netFD, t time.Time) error {
+ if t.IsZero() {
+ fd.wdeadline = 0
+ } else {
+ fd.wdeadline = t.UnixNano()
+ }
+ return nil
+}
+
+func setDeadline(fd *netFD, t time.Time) error {
+ if err := setReadDeadline(fd, t); err != nil {
+ return err
+ }
+ return setWriteDeadline(fd, t)
+}
+
+func setReuseAddr(fd *netFD, reuse bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)))
+}
+
+func setDontRoute(fd *netFD, dontroute bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)))
+}
+
+func setKeepAlive(fd *netFD, keepalive bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
+}
+
+func setNoDelay(fd *netFD, noDelay bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
+}
+
+func setLinger(fd *netFD, sec int) error {
+ var l syscall.Linger
+ if sec >= 0 {
+ l.Onoff = 1
+ l.Linger = int32(sec)
+ } else {
+ l.Onoff = 0
+ l.Linger = 0
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
+}
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
new file mode 100644
index 000000000..fff65f362
--- /dev/null
+++ b/src/pkg/net/sockopt_bsd.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.
+
+// +build darwin freebsd netbsd openbsd
+
+// Socket options for BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
+ switch f {
+ case syscall.AF_INET6:
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
+ }
+ // Allow broadcast.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func setDefaultListenerSockopts(s int) error {
+ // Allow reuse of recently-used addresses.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func setDefaultMulticastSockopts(s int) error {
+ // Allow multicast UDP and raw IP datagram sockets to listen
+ // concurrently across multiple listeners.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ // Allow reuse of recently-used ports.
+ // This option is supported only in descendants of 4.4BSD,
+ // to make an effective multicast application that requires
+ // quick draw possible.
+ err = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockopt_linux.go b/src/pkg/net/sockopt_linux.go
new file mode 100644
index 000000000..0f47538c5
--- /dev/null
+++ b/src/pkg/net/sockopt_linux.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.
+
+// Socket options for Linux
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
+ switch f {
+ case syscall.AF_INET6:
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
+ }
+ // Allow broadcast.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func setDefaultListenerSockopts(s int) error {
+ // Allow reuse of recently-used addresses.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func setDefaultMulticastSockopts(s int) error {
+ // Allow multicast UDP and raw IP datagram sockets to listen
+ // concurrently across multiple listeners.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockopt_windows.go b/src/pkg/net/sockopt_windows.go
new file mode 100644
index 000000000..509b5963b
--- /dev/null
+++ b/src/pkg/net/sockopt_windows.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.
+
+// Socket options for Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func setDefaultSockopts(s syscall.Handle, f, t int, ipv6only bool) error {
+ switch f {
+ case syscall.AF_INET6:
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
+ }
+ // Allow broadcast.
+ syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ return nil
+}
+
+func setDefaultListenerSockopts(s syscall.Handle) error {
+ // Windows will reuse recently-used addresses by default.
+ // SO_REUSEADDR should not be used here, as it allows
+ // a socket to forcibly bind to a port in use by another socket.
+ // This could lead to a non-deterministic behavior, where
+ // connection requests over the port cannot be guaranteed
+ // to be handled by the correct socket.
+ return nil
+}
+
+func setDefaultMulticastSockopts(s syscall.Handle) error {
+ // Allow multicast UDP and raw IP datagram sockets to listen
+ // concurrently across multiple listeners.
+ err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip.go b/src/pkg/net/sockoptip.go
new file mode 100644
index 000000000..1fcad4018
--- /dev/null
+++ b/src/pkg/net/sockoptip.go
@@ -0,0 +1,219 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd windows
+
+// IP-level socket options
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4TOS(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv4TOS(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4TTL(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv4TTL(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+ mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}}
+ if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
+ return err
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+}
+
+func leaveIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+ mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}}
+ if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
+ return err
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
+}
+
+func ipv6HopLimit(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv6HopLimit(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv6MulticastInterface(fd *netFD) (*Interface, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
+ }
+ if v == 0 {
+ return nil, nil
+ }
+ ifi, err := InterfaceByIndex(v)
+ if err != nil {
+ return nil, err
+ }
+ return ifi, nil
+}
+
+func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
+ var v int
+ if ifi != nil {
+ v = ifi.Index
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv6MulticastHopLimit(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv6MulticastHopLimit(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv6MulticastLoopback(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv6MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+ mreq := &syscall.IPv6Mreq{}
+ copy(mreq.Multiaddr[:], ip)
+ if ifi != nil {
+ mreq.Interface = uint32(ifi.Index)
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
+}
+
+func leaveIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+ mreq := &syscall.IPv6Mreq{}
+ copy(mreq.Multiaddr[:], ip)
+ if ifi != nil {
+ mreq.Interface = uint32(ifi.Index)
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq))
+}
diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
new file mode 100644
index 000000000..19e2b142e
--- /dev/null
+++ b/src/pkg/net/sockoptip_bsd.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.
+
+// +build darwin freebsd netbsd openbsd
+
+// IP-level socket options for BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastTTL(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return int(v), nil
+}
+
+func setIPv4MulticastTTL(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv6TrafficClass(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv6TrafficClass(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip_darwin.go b/src/pkg/net/sockoptip_darwin.go
new file mode 100644
index 000000000..52b237c4b
--- /dev/null
+++ b/src/pkg/net/sockoptip_darwin.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.
+
+// IP-level socket options for Darwin
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
+ }
+ defer fd.decref()
+ a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
+ }
+ return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3]))
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ ip, err := interfaceToIPv4Addr(ifi)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ var x [4]byte
+ copy(x[:], ip.To4())
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip_freebsd.go b/src/pkg/net/sockoptip_freebsd.go
new file mode 100644
index 000000000..4a3bc2e82
--- /dev/null
+++ b/src/pkg/net/sockoptip_freebsd.go
@@ -0,0 +1,92 @@
+// 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.
+
+// IP-level socket options for FreeBSD
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
+ }
+ defer fd.decref()
+ mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
+ }
+ if int(mreq.Ifindex) == 0 {
+ return nil, nil
+ }
+ return InterfaceByIndex(int(mreq.Ifindex))
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ var v int32
+ if ifi != nil {
+ v = int32(ifi.Index)
+ }
+ mreq := &syscall.IPMreqn{Ifindex: v}
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip_linux.go b/src/pkg/net/sockoptip_linux.go
new file mode 100644
index 000000000..169718f14
--- /dev/null
+++ b/src/pkg/net/sockoptip_linux.go
@@ -0,0 +1,140 @@
+// 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.
+
+// IP-level socket options for Linux
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
+ }
+ defer fd.decref()
+ mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
+ }
+ if int(mreq.Ifindex) == 0 {
+ return nil, nil
+ }
+ return InterfaceByIndex(int(mreq.Ifindex))
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ var v int32
+ if ifi != nil {
+ v = int32(ifi.Index)
+ }
+ mreq := &syscall.IPMreqn{Ifindex: v}
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastTTL(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
+ if err != nil {
+ return -1, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv4MulticastTTL(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv6TrafficClass(fd *netFD) (int, error) {
+ if err := fd.incref(false); err != nil {
+ return 0, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
+ if err != nil {
+ return 0, os.NewSyscallError("getsockopt", err)
+ }
+ return v, nil
+}
+
+func setIPv6TrafficClass(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip_netbsd.go b/src/pkg/net/sockoptip_netbsd.go
new file mode 100644
index 000000000..446d92aa3
--- /dev/null
+++ b/src/pkg/net/sockoptip_netbsd.go
@@ -0,0 +1,39 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IP-level socket options for NetBSD
+
+package net
+
+import "syscall"
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ // TODO: Implement this
+ return nil, syscall.EAFNOSUPPORT
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EAFNOSUPPORT
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EAFNOSUPPORT
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ // TODO: Implement this
+ return syscall.EAFNOSUPPORT
+}
diff --git a/src/pkg/net/sockoptip_openbsd.go b/src/pkg/net/sockoptip_openbsd.go
new file mode 100644
index 000000000..f3e42f1a9
--- /dev/null
+++ b/src/pkg/net/sockoptip_openbsd.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.
+
+// IP-level socket options for OpenBSD
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ if err := fd.incref(false); err != nil {
+ return nil, err
+ }
+ defer fd.decref()
+ a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
+ if err != nil {
+ return nil, os.NewSyscallError("getsockopt", err)
+ }
+ return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3]))
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ ip, err := interfaceToIPv4Addr(ifi)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ var x [4]byte
+ copy(x[:], ip.To4())
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ if err := fd.incref(false); err != nil {
+ return false, err
+ }
+ defer fd.decref()
+ v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
+ if err != nil {
+ return false, os.NewSyscallError("getsockopt", err)
+ }
+ return v == 1, nil
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
diff --git a/src/pkg/net/sockoptip_windows.go b/src/pkg/net/sockoptip_windows.go
new file mode 100644
index 000000000..b9db3334d
--- /dev/null
+++ b/src/pkg/net/sockoptip_windows.go
@@ -0,0 +1,91 @@
+// 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.
+
+// IP-level socket options for Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
+ // TODO: Implement this
+ return nil, syscall.EWINDOWS
+}
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+ ip, err := interfaceToIPv4Addr(ifi)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ var x [4]byte
+ copy(x[:], ip.To4())
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+}
+
+func ipv4MulticastTTL(fd *netFD) (int, error) {
+ // TODO: Implement this
+ return -1, syscall.EWINDOWS
+}
+
+func setIPv4MulticastTTL(fd *netFD, v int) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+
+}
+
+func ipv4MulticastLoopback(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EWINDOWS
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+
+}
+
+func ipv4ReceiveInterface(fd *netFD) (bool, error) {
+ // TODO: Implement this
+ return false, syscall.EWINDOWS
+}
+
+func setIPv4ReceiveInterface(fd *netFD, v bool) error {
+ // TODO: Implement this
+ return syscall.EWINDOWS
+}
+
+func ipv6TrafficClass(fd *netFD) (int, error) {
+ // TODO: Implement this
+ return 0, syscall.EWINDOWS
+}
+
+func setIPv6TrafficClass(fd *netFD, v int) error {
+ // TODO: Implement this
+ return syscall.EWINDOWS
+}
diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go
index f5c0a2781..47fbf2919 100644
--- a/src/pkg/net/tcpsock.go
+++ b/src/pkg/net/tcpsock.go
@@ -6,10 +6,6 @@
package net
-import (
- "os"
-)
-
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
@@ -31,7 +27,7 @@ func (a *TCPAddr) String() string {
// 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(net, addr string) (*TCPAddr, os.Error) {
+func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
ip, port, err := hostPortToIP(net, addr)
if err != nil {
return nil, err
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index f4f6e9fee..35f56966e 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -7,7 +7,8 @@
package net
import (
- "os"
+ "syscall"
+ "time"
)
// TCPConn is an implementation of the Conn interface
@@ -16,17 +17,50 @@ type TCPConn struct {
plan9Conn
}
+// SetDeadline implements the Conn SetDeadline method.
+func (c *TCPConn) SetDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *TCPConn) SetReadDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *TCPConn) SetWriteDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// CloseRead shuts down the reading side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseRead() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ return syscall.EPLAN9
+}
+
+// CloseWrite shuts down the writing side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseWrite() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ return syscall.EPLAN9
+}
+
// 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) {
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, UnknownNetworkError(net)
}
if raddr == nil {
- return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ return nil, &OpError{"dial", net, nil, errMissingAddress}
}
c1, err := dialPlan9(net, laddr, raddr)
if err != nil {
@@ -46,14 +80,14 @@ type TCPListener struct {
// Net must be "tcp", "tcp4", or "tcp6".
// If laddr has a port of 0, it means to listen on some available port.
// The caller can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, UnknownNetworkError(net)
}
if laddr == nil {
- return nil, &OpError{"listen", "tcp", nil, errMissingAddress}
+ return nil, &OpError{"listen", net, nil, errMissingAddress}
}
l1, err := listenPlan9(net, laddr)
if err != nil {
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 5560301b4..15f8efdd7 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.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.
+// +build darwin freebsd linux netbsd openbsd windows
+
// TCP sockets
package net
@@ -10,20 +12,31 @@ import (
"io"
"os"
"syscall"
+ "time"
)
+// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
+// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic
+// will not be routed to an IPv6 socket - two separate sockets are required
+// if both AFs are to be supported. See inet6(4) on OpenBSD for details.
+
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}
+ default:
+ if sa != nil {
+ // Diagnose when we will turn a non-nil sockaddr into a nil.
+ panic("unexpected type in sockaddrToTCP")
+ }
}
return nil
}
func (a *TCPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
+ if a == nil || len(a.IP) <= IPv4len {
return syscall.AF_INET
}
if a.IP.To4() != nil {
@@ -32,7 +45,14 @@ func (a *TCPAddr) family() int {
return syscall.AF_INET6
}
-func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+func (a *TCPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
+func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
@@ -59,40 +79,58 @@ 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) {
+// Read implements the Conn Read method.
+func (c *TCPConn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
// ReadFrom implements the io.ReaderFrom ReadFrom method.
-func (c *TCPConn) ReadFrom(r io.Reader) (int64, os.Error) {
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, 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) {
+// Write implements the Conn Write method.
+func (c *TCPConn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
// Close closes the TCP connection.
-func (c *TCPConn) Close() os.Error {
+func (c *TCPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
return err
}
+// CloseRead shuts down the reading side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseRead() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ return c.fd.CloseRead()
+}
+
+// CloseWrite shuts down the writing side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseWrite() error {
+ if !c.ok() {
+ return syscall.EINVAL
+ }
+ return c.fd.CloseWrite()
+}
+
// LocalAddr returns the local network address, a *TCPAddr.
func (c *TCPConn) LocalAddr() Addr {
if !c.ok() {
@@ -109,44 +147,44 @@ func (c *TCPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *TCPConn) SetTimeout(nsec int64) os.Error {
+// SetDeadline implements the Conn SetDeadline method.
+func (c *TCPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *TCPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *TCPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
-func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
+func (c *TCPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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 {
+func (c *TCPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -162,18 +200,18 @@ func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
//
// 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 {
+func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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 {
+func (c *TCPConn) SetKeepAlive(keepalive bool) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setKeepAlive(c.fd, keepalive)
}
@@ -182,9 +220,9 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
// 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 {
+func (c *TCPConn) SetNoDelay(noDelay bool) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setNoDelay(c.fd, noDelay)
}
@@ -192,22 +230,63 @@ func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
// 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() }
+func (c *TCPConn) File() (f *os.File, err error) { return c.fd.dup() }
// DialTCP connects to the remote address raddr on the network net,
// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
// as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
if raddr == nil {
- return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ return nil, &OpError{"dial", net, nil, errMissingAddress}
}
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
- if e != nil {
- return nil, e
+
+ fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+
+ // TCP has a rarely used mechanism called a 'simultaneous connection' in
+ // which Dial("tcp", addr1, addr2) run on the machine at addr1 can
+ // connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
+ // at addr2, without either machine executing Listen. If laddr == nil,
+ // it means we want the kernel to pick an appropriate originating local
+ // address. Some Linux kernels cycle blindly through a fixed range of
+ // local ports, regardless of destination port. If a kernel happens to
+ // pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
+ // then the Dial will succeed, having simultaneously connected to itself.
+ // This can only happen when we are letting the kernel pick a port (laddr == nil)
+ // and when there is no listener for the destination address.
+ // It's hard to argue this is anything other than a kernel bug. If we
+ // see this happen, rather than expose the buggy effect to users, we
+ // close the fd and try again. If it happens twice more, we relent and
+ // use the result. See also:
+ // http://golang.org/issue/2690
+ // http://stackoverflow.com/questions/4949858/
+ for i := 0; i < 2 && err == nil && laddr == nil && selfConnect(fd); i++ {
+ fd.Close()
+ fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ }
+
+ if err != nil {
+ return nil, err
}
return newTCPConn(fd), nil
}
+func selfConnect(fd *netFD) bool {
+ // The socket constructor can return an fd with raddr nil under certain
+ // unknown conditions. The errors in the calls there to Getpeername
+ // are discarded, but we can't catch the problem there because those
+ // calls are sometimes legally erroneous with a "socket not connected".
+ // Since this code (selfConnect) is already trying to work around
+ // a problem, we make sure if this happens we recognize trouble and
+ // ask the DialTCP routine to try again.
+ // TODO: try to understand what's really going on.
+ if fd.laddr == nil || fd.raddr == nil {
+ return true
+ }
+ l := fd.laddr.(*TCPAddr)
+ r := fd.raddr.(*TCPAddr)
+ return l.Port == r.Port && l.IP.Equal(r.IP)
+}
+
// TCPListener is a TCP network listener.
// Clients should typically use variables of type Listener
// instead of assuming TCP.
@@ -219,26 +298,26 @@ type TCPListener struct {
// Net must be "tcp", "tcp4", or "tcp6".
// If laddr has a port of 0, it means to listen on some available port.
// The caller can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
if err != nil {
return nil, err
}
- errno := syscall.Listen(fd.sysfd, listenBacklog())
- if errno != 0 {
+ err = syscall.Listen(fd.sysfd, listenerBacklog)
+ if err != nil {
closesocket(fd.sysfd)
- return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+ return nil, &OpError{"listen", net, laddr, err}
}
- l = new(TCPListener)
+ 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) {
+func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) {
if l == nil || l.fd == nil || l.fd.sysfd < 0 {
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
fd, err := l.fd.accept(sockaddrToTCP)
if err != nil {
@@ -249,7 +328,7 @@ func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
// 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) {
+func (l *TCPListener) Accept() (c Conn, err error) {
c1, err := l.AcceptTCP()
if err != nil {
return nil, err
@@ -259,9 +338,9 @@ func (l *TCPListener) Accept() (c Conn, err os.Error) {
// Close stops listening on the TCP address.
// Already Accepted connections are not closed.
-func (l *TCPListener) Close() os.Error {
+func (l *TCPListener) Close() error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
return l.fd.Close()
}
@@ -269,15 +348,16 @@ func (l *TCPListener) Close() os.Error {
// 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 {
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *TCPListener) SetDeadline(t time.Time) error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(l.fd, nsec)
+ return setDeadline(l.fd, t)
}
// 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() }
+func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
diff --git a/src/pkg/net/hosts_testdata b/src/pkg/net/testdata/hosts
index b60176389..b60176389 100644
--- a/src/pkg/net/hosts_testdata
+++ b/src/pkg/net/testdata/hosts
diff --git a/src/pkg/net/testdata/igmp b/src/pkg/net/testdata/igmp
new file mode 100644
index 000000000..5f380a2c7
--- /dev/null
+++ b/src/pkg/net/testdata/igmp
@@ -0,0 +1,24 @@
+Idx Device : Count Querier Group Users Timer Reporter
+1 lo : 1 V3
+ 010000E0 1 0:00000000 0
+2 eth0 : 2 V2
+ FB0000E0 1 0:00000000 1
+ 010000E0 1 0:00000000 0
+3 eth1 : 1 V3
+ 010000E0 1 0:00000000 0
+4 eth2 : 1 V3
+ 010000E0 1 0:00000000 0
+5 eth0.100 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+6 eth0.101 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+7 eth0.102 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+8 eth0.103 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+9 device1tap2: 1 V3
+ 010000E0 1 0:00000000 0
diff --git a/src/pkg/net/testdata/igmp6 b/src/pkg/net/testdata/igmp6
new file mode 100644
index 000000000..6cd5a2d4d
--- /dev/null
+++ b/src/pkg/net/testdata/igmp6
@@ -0,0 +1,18 @@
+1 lo ff020000000000000000000000000001 1 0000000C 0
+2 eth0 ff0200000000000000000001ffac891e 1 00000006 0
+2 eth0 ff020000000000000000000000000001 1 0000000C 0
+3 eth1 ff0200000000000000000001ffac8928 2 00000006 0
+3 eth1 ff020000000000000000000000000001 1 0000000C 0
+4 eth2 ff0200000000000000000001ffac8932 2 00000006 0
+4 eth2 ff020000000000000000000000000001 1 0000000C 0
+5 eth0.100 ff0200000000000000000001ffac891e 1 00000004 0
+5 eth0.100 ff020000000000000000000000000001 1 0000000C 0
+6 pan0 ff020000000000000000000000000001 1 0000000C 0
+7 eth0.101 ff0200000000000000000001ffac891e 1 00000004 0
+7 eth0.101 ff020000000000000000000000000001 1 0000000C 0
+8 eth0.102 ff0200000000000000000001ffac891e 1 00000004 0
+8 eth0.102 ff020000000000000000000000000001 1 0000000C 0
+9 eth0.103 ff0200000000000000000001ffac891e 1 00000004 0
+9 eth0.103 ff020000000000000000000000000001 1 0000000C 0
+10 device1tap2 ff0200000000000000000001ff4cc3a3 1 00000004 0
+10 device1tap2 ff020000000000000000000000000001 1 0000000C 0
diff --git a/src/pkg/net/textproto/Makefile b/src/pkg/net/textproto/Makefile
deleted file mode 100644
index cadf3ab69..000000000
--- a/src/pkg/net/textproto/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=net/textproto
-GOFILES=\
- header.go\
- pipeline.go\
- reader.go\
- textproto.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/net/textproto/header.go b/src/pkg/net/textproto/header.go
index 288deb2ce..7fb32f804 100644
--- a/src/pkg/net/textproto/header.go
+++ b/src/pkg/net/textproto/header.go
@@ -39,5 +39,5 @@ func (h MIMEHeader) Get(key string) string {
// Del deletes the values associated with key.
func (h MIMEHeader) Del(key string) {
- h[CanonicalMIMEHeaderKey(key)] = nil, false
+ delete(h, CanonicalMIMEHeaderKey(key))
}
diff --git a/src/pkg/net/textproto/pipeline.go b/src/pkg/net/textproto/pipeline.go
index 8c25884b3..ca50eddac 100644
--- a/src/pkg/net/textproto/pipeline.go
+++ b/src/pkg/net/textproto/pipeline.go
@@ -108,7 +108,7 @@ func (s *sequencer) End(id uint) {
}
c, ok := s.wait[id]
if ok {
- s.wait[id] = nil, false
+ delete(s.wait, id)
}
s.mu.Unlock()
if ok {
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index ce0ddc73f..125feb3e8 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/net/textproto/reader.go
@@ -9,8 +9,8 @@ import (
"bytes"
"io"
"io/ioutil"
- "os"
"strconv"
+ "strings"
)
// BUG(rsc): To let callers manage exposure to denial of service
@@ -22,6 +22,7 @@ import (
type Reader struct {
R *bufio.Reader
dot *dotReader
+ buf []byte // a re-usable buffer for readContinuedLineSlice
}
// NewReader returns a new Reader reading from r.
@@ -31,13 +32,13 @@ 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) {
+func (r *Reader) ReadLine() (string, error) {
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) {
+func (r *Reader) ReadLineBytes() ([]byte, error) {
line, err := r.readLineSlice()
if line != nil {
buf := make([]byte, len(line))
@@ -47,10 +48,24 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
return line, err
}
-func (r *Reader) readLineSlice() ([]byte, os.Error) {
+func (r *Reader) readLineSlice() ([]byte, error) {
r.closeDot()
- line, _, err := r.R.ReadLine()
- return line, err
+ var line []byte
+ for {
+ l, more, err := r.R.ReadLine()
+ if err != nil {
+ return nil, err
+ }
+ // Avoid the copy if the first call produced a full line.
+ if line == nil && !more {
+ return l, nil
+ }
+ line = append(line, l...)
+ if !more {
+ break
+ }
+ }
+ return line, nil
}
// ReadContinuedLine reads a possibly continued line from r,
@@ -72,7 +87,7 @@ func (r *Reader) readLineSlice() ([]byte, os.Error) {
//
// A line consisting of only white space is never continued.
//
-func (r *Reader) ReadContinuedLine() (string, os.Error) {
+func (r *Reader) ReadContinuedLine() (string, error) {
line, err := r.readContinuedLineSlice()
return string(line), err
}
@@ -93,7 +108,7 @@ func trim(s []byte) []byte {
// ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string.
-func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
line, err := r.readContinuedLineSlice()
if line != nil {
buf := make([]byte, len(line))
@@ -103,85 +118,59 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
return line, err
}
-func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
+func (r *Reader) readContinuedLineSlice() ([]byte, error) {
// Read the first line.
line, err := r.readLineSlice()
if err != nil {
- return line, err
+ return nil, err
}
if len(line) == 0 { // blank line - no continuation
return line, nil
}
- 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 {
- // Delay err until we read the byte next time.
- return line, nil
- }
- if c != ' ' && c != '\t' {
- // Not a continuation.
- r.R.UnreadByte()
- return line, nil
- }
-
- if !copied {
- // The next readLineSlice will invalidate the previous one.
- line = append(make([]byte, 0, len(line)*2), line...)
- }
+ // ReadByte or the next readLineSlice will flush the read buffer;
+ // copy the slice into buf.
+ r.buf = append(r.buf[:0], trim(line)...)
// Read continuation lines.
- for {
- // Consume leading spaces; one already gone.
- for {
- c, err = r.R.ReadByte()
- if err != nil {
- break
- }
- if c != ' ' && c != '\t' {
- r.R.UnreadByte()
- break
- }
- }
- var cont []byte
- cont, err = r.readLineSlice()
- cont = trim(cont)
- line = append(line, ' ')
- line = append(line, cont...)
+ for r.skipSpace() > 0 {
+ line, err := r.readLineSlice()
if err != nil {
break
}
+ r.buf = append(r.buf, ' ')
+ r.buf = append(r.buf, line...)
+ }
+ return r.buf, nil
+}
- // Check for leading space on next line.
- if c, err = r.R.ReadByte(); err != nil {
+// skipSpace skips R over all spaces and returns the number of bytes skipped.
+func (r *Reader) skipSpace() int {
+ n := 0
+ for {
+ c, err := r.R.ReadByte()
+ if err != nil {
+ // Bufio will keep err until next read.
break
}
if c != ' ' && c != '\t' {
r.R.UnreadByte()
break
}
+ n++
}
-
- // Delay error until next call.
- if len(line) > 0 {
- err = nil
- }
- return line, err
+ return n
}
-func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err os.Error) {
+func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) {
line, err := r.ReadLine()
if err != nil {
return
}
+ return parseCodeLine(line, expectCode)
+}
+
+func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) {
if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
err = ProtocolError("short response: " + line)
return
@@ -216,7 +205,7 @@ func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message
//
// An expectCode <= 0 disables the check of the status code.
//
-func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.Error) {
+func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) {
code, continued, message, err := r.readCodeLine(expectCode)
if err == nil && continued {
err = ProtocolError("unexpected multi-line response: " + message)
@@ -224,15 +213,20 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.
return
}
-// ReadResponse reads a multi-line response of the form
+// ReadResponse reads a multi-line response of the form:
+//
// code-message line 1
// code-message line 2
// ...
// code message line n
-// where code is a 3-digit status code. Each line should have the same code.
-// The response is terminated by a line that uses a space between the code and
-// the message line rather than a dash. Each line in message is separated by
-// a newline (\n).
+//
+// where code is a 3-digit status code. The first line starts with the
+// code and a hyphen. The response is terminated by a line that starts
+// with the same code followed by a space. Each line in message is
+// separated by a newline (\n).
+//
+// See page 36 of RFC 959 (http://www.ietf.org/rfc/rfc959.txt) for
+// details.
//
// If the prefix of the status does not match the digits in expectCode,
// ReadResponse returns with err set to &Error{code, message}.
@@ -241,14 +235,21 @@ func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.
//
// An expectCode <= 0 disables the check of the status code.
//
-func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
+func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) {
code, continued, message, err := r.readCodeLine(expectCode)
for err == nil && continued {
+ line, err := r.ReadLine()
+ if err != nil {
+ return 0, "", err
+ }
+
var code2 int
var moreMessage string
- code2, continued, moreMessage, err = r.readCodeLine(expectCode)
- if code != code2 {
- err = ProtocolError("status code mismatch: " + strconv.Itoa(code) + ", " + strconv.Itoa(code2))
+ code2, continued, moreMessage, err = parseCodeLine(line, expectCode)
+ if err != nil || code2 != code {
+ message += "\n" + strings.TrimRight(line, "\r\n")
+ continued = true
+ continue
}
message += "\n" + moreMessage
}
@@ -269,7 +270,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.
//
// The decoded form returned by the Reader's Read method
// rewrites the "\r\n" line endings into the simpler "\n",
-// removes leading dot escapes if present, and stops with error os.EOF
+// removes leading dot escapes if present, and stops with error io.EOF
// after consuming (and discarding) the end-of-sequence line.
func (r *Reader) DotReader() io.Reader {
r.closeDot()
@@ -283,7 +284,7 @@ type dotReader struct {
}
// Read satisfies reads by decoding dot-encoded data read from d.r.
-func (d *dotReader) Read(b []byte) (n int, err os.Error) {
+func (d *dotReader) Read(b []byte) (n int, err error) {
// Run data through a simple state machine to
// elide leading dots, rewrite trailing \r\n into \n,
// and detect ending .\r\n line.
@@ -300,7 +301,7 @@ func (d *dotReader) Read(b []byte) (n int, err os.Error) {
var c byte
c, err = br.ReadByte()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
break
@@ -362,7 +363,7 @@ func (d *dotReader) Read(b []byte) (n int, err os.Error) {
n++
}
if err == nil && d.state == stateEOF {
- err = os.EOF
+ err = io.EOF
}
if err != nil && d.r.dot == d {
d.r.dot = nil
@@ -387,7 +388,7 @@ func (r *Reader) closeDot() {
// ReadDotBytes reads a dot-encoding and returns the decoded data.
//
// See the documentation for the DotReader method for details about dot-encoding.
-func (r *Reader) ReadDotBytes() ([]byte, os.Error) {
+func (r *Reader) ReadDotBytes() ([]byte, error) {
return ioutil.ReadAll(r.DotReader())
}
@@ -395,17 +396,17 @@ func (r *Reader) ReadDotBytes() ([]byte, os.Error) {
// containing the decoded lines, with the final \r\n or \n elided from each.
//
// See the documentation for the DotReader method for details about dot-encoding.
-func (r *Reader) ReadDotLines() ([]string, os.Error) {
+func (r *Reader) ReadDotLines() ([]string, 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 []string
- var err os.Error
+ var err error
for {
var line string
line, err = r.ReadLine()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
break
@@ -443,7 +444,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
// "Long-Key": {"Even Longer Value"},
// }
//
-func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
+func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
m := make(MIMEHeader)
for {
kv, err := r.readContinuedLineSlice()
@@ -453,10 +454,14 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
// Key ends at first colon; must not have spaces.
i := bytes.IndexByte(kv, ':')
- if i < 0 || bytes.IndexByte(kv[0:i], ' ') >= 0 {
+ if i < 0 {
return m, ProtocolError("malformed MIME header line: " + string(kv))
}
- key := CanonicalMIMEHeaderKey(string(kv[0:i]))
+ key := string(kv[0:i])
+ if strings.Index(key, " ") >= 0 {
+ key = strings.TrimRight(key, " ")
+ }
+ key = CanonicalMIMEHeaderKey(key)
// Skip initial spaces in value.
i++ // skip colon
@@ -502,6 +507,11 @@ MustRewrite:
a := []byte(s)
upper := true
for i, v := range a {
+ if v == ' ' {
+ a[i] = '-'
+ upper = true
+ continue
+ }
if upper && 'a' <= v && v <= 'z' {
a[i] = v + 'A' - 'a'
}
diff --git a/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
index 0658e58b8..7c5d16227 100644
--- a/src/pkg/net/textproto/reader_test.go
+++ b/src/pkg/net/textproto/reader_test.go
@@ -7,7 +7,6 @@ package textproto
import (
"bufio"
"io"
- "os"
"reflect"
"strings"
"testing"
@@ -49,7 +48,7 @@ func TestReadLine(t *testing.T) {
t.Fatalf("Line 2: %s, %v", s, err)
}
s, err = r.ReadLine()
- if s != "" || err != os.EOF {
+ if s != "" || err != io.EOF {
t.Fatalf("EOF: %s, %v", s, err)
}
}
@@ -69,7 +68,7 @@ func TestReadContinuedLine(t *testing.T) {
t.Fatalf("Line 3: %s, %v", s, err)
}
s, err = r.ReadContinuedLine()
- if s != "" || err != os.EOF {
+ if s != "" || err != io.EOF {
t.Fatalf("EOF: %s, %v", s, err)
}
}
@@ -92,7 +91,7 @@ func TestReadCodeLine(t *testing.T) {
t.Fatalf("Line 3: wrong error %v\n", err)
}
code, msg, err = r.ReadCodeLine(1)
- if code != 0 || msg != "" || err != os.EOF {
+ if code != 0 || msg != "" || err != io.EOF {
t.Fatalf("EOF: %d, %s, %v", code, msg, err)
}
}
@@ -138,3 +137,105 @@ func TestReadMIMEHeader(t *testing.T) {
t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
}
}
+
+func TestReadMIMEHeaderSingle(t *testing.T) {
+ r := reader("Foo: bar\n\n")
+ m, err := r.ReadMIMEHeader()
+ want := MIMEHeader{"Foo": {"bar"}}
+ if !reflect.DeepEqual(m, want) || err != nil {
+ t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
+ }
+}
+
+func TestLargeReadMIMEHeader(t *testing.T) {
+ data := make([]byte, 16*1024)
+ for i := 0; i < len(data); i++ {
+ data[i] = 'x'
+ }
+ sdata := string(data)
+ r := reader("Cookie: " + sdata + "\r\n\n")
+ m, err := r.ReadMIMEHeader()
+ if err != nil {
+ t.Fatalf("ReadMIMEHeader: %v", err)
+ }
+ cookie := m.Get("Cookie")
+ if cookie != sdata {
+ t.Fatalf("ReadMIMEHeader: %v bytes, want %v bytes", len(cookie), len(sdata))
+ }
+}
+
+// Test that we read slightly-bogus MIME headers seen in the wild,
+// with spaces before colons, and spaces in keys.
+func TestReadMIMEHeaderNonCompliant(t *testing.T) {
+ // Invalid HTTP response header as sent by an Axis security
+ // camera: (this is handled by IE, Firefox, Chrome, curl, etc.)
+ r := reader("Foo: bar\r\n" +
+ "Content-Language: en\r\n" +
+ "SID : 0\r\n" +
+ "Audio Mode : None\r\n" +
+ "Privilege : 127\r\n\r\n")
+ m, err := r.ReadMIMEHeader()
+ want := MIMEHeader{
+ "Foo": {"bar"},
+ "Content-Language": {"en"},
+ "Sid": {"0"},
+ "Audio-Mode": {"None"},
+ "Privilege": {"127"},
+ }
+ if !reflect.DeepEqual(m, want) || err != nil {
+ t.Fatalf("ReadMIMEHeader =\n%v, %v; want:\n%v", m, err, want)
+ }
+}
+
+type readResponseTest struct {
+ in string
+ inCode int
+ wantCode int
+ wantMsg string
+}
+
+var readResponseTests = []readResponseTest{
+ {"230-Anonymous access granted, restrictions apply\n" +
+ "Read the file README.txt,\n" +
+ "230 please",
+ 23,
+ 230,
+ "Anonymous access granted, restrictions apply\nRead the file README.txt,\n please",
+ },
+
+ {"230 Anonymous access granted, restrictions apply\n",
+ 23,
+ 230,
+ "Anonymous access granted, restrictions apply",
+ },
+
+ {"400-A\n400-B\n400 C",
+ 4,
+ 400,
+ "A\nB\nC",
+ },
+
+ {"400-A\r\n400-B\r\n400 C\r\n",
+ 4,
+ 400,
+ "A\nB\nC",
+ },
+}
+
+// See http://www.ietf.org/rfc/rfc959.txt page 36.
+func TestRFC959Lines(t *testing.T) {
+ for i, tt := range readResponseTests {
+ r := reader(tt.in + "\nFOLLOWING DATA")
+ code, msg, err := r.ReadResponse(tt.inCode)
+ if err != nil {
+ t.Errorf("#%d: ReadResponse: %v", i, err)
+ continue
+ }
+ if code != tt.wantCode {
+ t.Errorf("#%d: code=%d, want %d", i, code, tt.wantCode)
+ }
+ if msg != tt.wantMsg {
+ t.Errorf("#%d: msg=%q, want %q", i, msg, tt.wantMsg)
+ }
+ }
+}
diff --git a/src/pkg/net/textproto/textproto.go b/src/pkg/net/textproto/textproto.go
index 9f19b5495..ad5840cf7 100644
--- a/src/pkg/net/textproto/textproto.go
+++ b/src/pkg/net/textproto/textproto.go
@@ -20,6 +20,9 @@
//
// Writer, to write dot-encoded text blocks.
//
+// Conn, a convenient packaging of Reader, Writer, and Pipeline for use
+// with a single network connection.
+//
package textproto
import (
@@ -27,7 +30,6 @@ import (
"fmt"
"io"
"net"
- "os"
)
// An Error represents a numeric error response from a server.
@@ -36,7 +38,7 @@ type Error struct {
Msg string
}
-func (e *Error) String() string {
+func (e *Error) Error() string {
return fmt.Sprintf("%03d %s", e.Code, e.Msg)
}
@@ -44,7 +46,7 @@ func (e *Error) String() string {
// as an invalid response or a hung-up connection.
type ProtocolError string
-func (p ProtocolError) String() string {
+func (p ProtocolError) Error() string {
return string(p)
}
@@ -70,13 +72,13 @@ func NewConn(conn io.ReadWriteCloser) *Conn {
}
// Close closes the connection.
-func (c *Conn) Close() os.Error {
+func (c *Conn) Close() error {
return c.conn.Close()
}
// Dial connects to the given address on the given network using net.Dial
// and then returns a new Conn for the connection.
-func Dial(network, addr string) (*Conn, os.Error) {
+func Dial(network, addr string) (*Conn, error) {
c, err := net.Dial(network, addr)
if err != nil {
return nil, err
@@ -109,7 +111,7 @@ func Dial(network, addr string) (*Conn, os.Error) {
// }
// return c.ReadCodeLine(250)
//
-func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err os.Error) {
+func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err error) {
id = c.Next()
c.StartRequest(id)
err = c.PrintfLine(format, args...)
diff --git a/src/pkg/net/textproto/writer.go b/src/pkg/net/textproto/writer.go
index 4e705f6c3..03e2fd658 100644
--- a/src/pkg/net/textproto/writer.go
+++ b/src/pkg/net/textproto/writer.go
@@ -8,7 +8,6 @@ import (
"bufio"
"fmt"
"io"
- "os"
)
// A Writer implements convenience methods for writing
@@ -27,7 +26,7 @@ var crnl = []byte{'\r', '\n'}
var dotcrnl = []byte{'.', '\r', '\n'}
// PrintfLine writes the formatted output followed by \r\n.
-func (w *Writer) PrintfLine(format string, args ...interface{}) os.Error {
+func (w *Writer) PrintfLine(format string, args ...interface{}) error {
w.closeDot()
fmt.Fprintf(w.W, format, args...)
w.W.Write(crnl)
@@ -64,7 +63,7 @@ const (
wstateData // writing data in middle of line
)
-func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
+func (d *dotWriter) Write(b []byte) (n int, err error) {
bw := d.w.W
for n < len(b) {
c := b[n]
@@ -100,7 +99,7 @@ func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
return
}
-func (d *dotWriter) Close() os.Error {
+func (d *dotWriter) Close() error {
if d.w.dot == d {
d.w.dot = nil
}
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 0dbab5846..672fb7241 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -5,53 +5,117 @@
package net
import (
- "os"
+ "fmt"
+ "runtime"
"testing"
"time"
)
-func testTimeout(t *testing.T, network, addr string, readFrom bool) {
- fd, err := Dial(network, addr)
+func testTimeout(t *testing.T, net, addr string, readFrom bool) {
+ c, err := Dial(net, addr)
if err != nil {
- t.Errorf("dial %s %s failed: %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
return
}
- defer fd.Close()
- t0 := time.Nanoseconds()
- fd.SetReadTimeout(1e8) // 100ms
- var b [100]byte
- var n int
- var err1 os.Error
- if readFrom {
- n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
- } else {
- n, err1 = fd.Read(b[0:])
- }
- t1 := time.Nanoseconds()
+ defer c.Close()
what := "Read"
if readFrom {
what = "ReadFrom"
}
- if n != 0 || err1 == nil || !err1.(Error).Timeout() {
- t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
- }
- if t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
- t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
+
+ errc := make(chan error, 1)
+ go func() {
+ t0 := time.Now()
+ c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+ var b [100]byte
+ var n int
+ var err error
+ if readFrom {
+ n, _, err = c.(PacketConn).ReadFrom(b[0:])
+ } else {
+ n, err = c.Read(b[0:])
+ }
+ t1 := time.Now()
+ if n != 0 || err == nil || !err.(Error).Timeout() {
+ errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
+ return
+ }
+ if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
+ errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
+ return
+ }
+ errc <- nil
+ }()
+ select {
+ case err := <-errc:
+ if err != nil {
+ t.Error(err)
+ }
+ case <-time.After(1 * time.Second):
+ t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
}
}
func TestTimeoutUDP(t *testing.T) {
- testTimeout(t, "udp", "127.0.0.1:53", false)
- testTimeout(t, "udp", "127.0.0.1:53", true)
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ // set up a listener that won't talk back
+ listening := make(chan string)
+ done := make(chan int)
+ go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
+ addr := <-listening
+
+ testTimeout(t, "udp", addr, false)
+ testTimeout(t, "udp", addr, true)
+ <-done
}
func TestTimeoutTCP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
// set up a listener that won't talk back
listening := make(chan string)
done := make(chan int)
- go runServe(t, "tcp", "127.0.0.1:0", listening, done)
+ go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
addr := <-listening
testTimeout(t, "tcp", addr, false)
<-done
}
+
+func TestDeadlineReset(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ ln, err := Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+ tl := ln.(*TCPListener)
+ tl.SetDeadline(time.Now().Add(1 * time.Minute))
+ tl.SetDeadline(time.Time{}) // reset it
+ errc := make(chan error, 1)
+ go func() {
+ _, err := ln.Accept()
+ errc <- err
+ }()
+ select {
+ case <-time.After(50 * time.Millisecond):
+ // Pass.
+ case err := <-errc:
+ // Accept should never return; we never
+ // connected to it.
+ t.Errorf("unexpected return from Accept; err=%v", err)
+ }
+}
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
new file mode 100644
index 000000000..f80d3b5a9
--- /dev/null
+++ b/src/pkg/net/udp_test.go
@@ -0,0 +1,89 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "runtime"
+ "testing"
+)
+
+func TestWriteToUDP(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ l, err := ListenPacket("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+ defer l.Close()
+
+ testWriteToConn(t, l.LocalAddr().String())
+ testWriteToPacketConn(t, l.LocalAddr().String())
+}
+
+func testWriteToConn(t *testing.T, raddr string) {
+ c, err := Dial("udp", raddr)
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c.Close()
+
+ ra, err := ResolveUDPAddr("udp", raddr)
+ if err != nil {
+ t.Fatalf("ResolveUDPAddr failed: %v", err)
+ }
+
+ _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
+ if err == nil {
+ t.Fatal("WriteToUDP should fail")
+ }
+ if err != nil && err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err)
+ }
+
+ _, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra)
+ if err == nil {
+ t.Fatal("WriteTo should fail")
+ }
+ if err != nil && err.(*OpError).Err != ErrWriteToConnected {
+ t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+ }
+
+ _, err = c.Write([]byte("Connection-oriented mode socket"))
+ if err != nil {
+ t.Fatalf("Write failed: %v", err)
+ }
+}
+
+func testWriteToPacketConn(t *testing.T, raddr string) {
+ c, err := ListenPacket("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("ListenPacket failed: %v", err)
+ }
+ defer c.Close()
+
+ ra, err := ResolveUDPAddr("udp", raddr)
+ if err != nil {
+ t.Fatalf("ResolveUDPAddr failed: %v", err)
+ }
+
+ _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra)
+ if err != nil {
+ t.Fatalf("WriteToUDP failed: %v", err)
+ }
+
+ _, err = c.WriteTo([]byte("Connection-less mode socket"), ra)
+ if err != nil {
+ t.Fatalf("WriteTo failed: %v", err)
+ }
+
+ _, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
+ if err == nil {
+ t.Fatal("Write should fail")
+ }
+}
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 3dfa71675..b3520cf09 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -6,10 +6,6 @@
package net
-import (
- "os"
-)
-
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
@@ -31,7 +27,7 @@ func (a *UDPAddr) String() string {
// 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(net, addr string) (*UDPAddr, os.Error) {
+func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
ip, port, err := hostPortToIP(net, addr)
if err != nil {
return nil, err
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index bb7196041..4f298a42f 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -7,7 +7,10 @@
package net
import (
+ "errors"
"os"
+ "syscall"
+ "time"
)
// UDPConn is the implementation of the Conn and PacketConn
@@ -16,6 +19,21 @@ type UDPConn struct {
plan9Conn
}
+// SetDeadline implements the Conn SetDeadline method.
+func (c *UDPConn) SetDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *UDPConn) SetReadDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *UDPConn) SetWriteDeadline(t time.Time) error {
+ return syscall.EPLAN9
+}
+
// UDP-specific methods.
// ReadFromUDP reads a UDP packet from c, copying the payload into b.
@@ -23,10 +41,10 @@ type UDPConn struct {
// 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) {
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -40,7 +58,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
return
}
if m < udpHeaderSize {
- return 0, nil, os.NewError("short read reading UDP header")
+ return 0, nil, errors.New("short read reading UDP header")
}
buf = buf[:m]
@@ -49,10 +67,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
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) {
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
return c.ReadFromUDP(b)
}
@@ -61,11 +79,11 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
//
// WriteToUDP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
if c.data == nil {
c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
@@ -86,14 +104,14 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
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) {
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UDPAddr)
if !ok {
- return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ return 0, &OpError{"write", c.dir, addr, syscall.EINVAL}
}
return c.WriteToUDP(b, a)
}
@@ -101,14 +119,14 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
// 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) {
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
switch net {
case "udp", "udp4", "udp6":
default:
return nil, UnknownNetworkError(net)
}
if raddr == nil {
- return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ return nil, &OpError{"dial", net, nil, errMissingAddress}
}
c1, err := dialPlan9(net, laddr, raddr)
if err != nil {
@@ -149,14 +167,14 @@ func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
// 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) {
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
switch net {
case "udp", "udp4", "udp6":
default:
return nil, UnknownNetworkError(net)
}
if laddr == nil {
- return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ return nil, &OpError{"listen", net, nil, errMissingAddress}
}
l, err := listenPlan9(net, laddr)
if err != nil {
@@ -169,19 +187,10 @@ func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
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
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// addressed to the group address gaddr on ifi, which specifies
+// the interface to join. ListenMulticastUDP uses default
+// multicast interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ return nil, syscall.EPLAN9
}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index d4ea056f3..9e820e1c5 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -2,15 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
// UDP sockets
package net
import (
+ "errors"
"os"
"syscall"
+ "time"
)
+var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
+
func sockaddrToUDP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
@@ -22,7 +28,7 @@ func sockaddrToUDP(sa syscall.Sockaddr) Addr {
}
func (a *UDPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
+ if a == nil || len(a.IP) <= IPv4len {
return syscall.AF_INET
}
if a.IP.To4() != nil {
@@ -31,7 +37,14 @@ func (a *UDPAddr) family() int {
return syscall.AF_INET6
}
-func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+func (a *UDPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
+func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
@@ -54,26 +67,26 @@ 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) {
+// Read implements the Conn Read method.
+func (c *UDPConn) Read(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
-// Write implements the net.Conn Write method.
-func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
+// Write implements the Conn Write method.
+func (c *UDPConn) Write(b []byte) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
// Close closes the UDP connection.
-func (c *UDPConn) Close() os.Error {
+func (c *UDPConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -96,44 +109,44 @@ func (c *UDPConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UDPConn) SetTimeout(nsec int64) os.Error {
+// SetDeadline implements the Conn SetDeadline method.
+func (c *UDPConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *UDPConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *UDPConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
-func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
+func (c *UDPConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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 {
+func (c *UDPConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
return setWriteBuffer(c.fd, bytes)
}
@@ -145,10 +158,10 @@ func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
// 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) {
+// after a fixed time limit; see SetDeadline and SetReadDeadline.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) {
@@ -160,10 +173,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
return
}
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromUDP(b)
return n, uaddr.toAddr(), err
@@ -173,46 +186,54 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
//
// WriteToUDP can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
+ }
+ if c.fd.isConnected {
+ return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
}
- sa, err1 := addr.sockaddr(c.fd.family)
- if err1 != nil {
- return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
+ sa, err := addr.sockaddr(c.fd.family)
+ if err != nil {
+ return 0, &OpError{"write", c.fd.net, addr, err}
}
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) {
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UDPAddr)
if !ok {
- return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
}
return c.WriteToUDP(b, a)
}
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err error) { return c.fd.dup() }
+
// DialUDP connects to the remote address raddr on the network net,
// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
// as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
switch net {
case "udp", "udp4", "udp6":
default:
return nil, UnknownNetworkError(net)
}
if raddr == nil {
- return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ return nil, &OpError{"dial", net, nil, errMissingAddress}
}
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
- if e != nil {
- return nil, e
+ fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if err != nil {
+ return nil, err
}
return newUDPConn(fd), nil
}
@@ -221,74 +242,121 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
// 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) {
+func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
switch net {
case "udp", "udp4", "udp6":
default:
return nil, UnknownNetworkError(net)
}
if laddr == nil {
- return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ return nil, &OpError{"listen", net, nil, errMissingAddress}
}
- fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
- if e != nil {
- return nil, e
+ fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
+ if err != nil {
+ return nil, err
}
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
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// addressed to the group address gaddr on ifi, which specifies
+// the interface to join. ListenMulticastUDP uses default
+// multicast interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
}
- c.fd.incref()
- defer c.fd.decref()
- return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+ if gaddr == nil || gaddr.IP == nil {
+ return nil, &OpError{"listenmulticast", net, nil, errMissingAddress}
+ }
+ fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
+ if err != nil {
+ return nil, err
+ }
+ c := newUDPConn(fd)
+ ip4 := gaddr.IP.To4()
+ if ip4 != nil {
+ err := listenIPv4MulticastUDP(c, ifi, ip4)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ } else {
+ err := listenIPv6MulticastUDP(c, ifi, gaddr.IP)
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+ }
+ return c, nil
}
-// 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
+func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ if ifi != nil {
+ err := setIPv4MulticastInterface(c.fd, ifi)
+ if err != nil {
+ return err
+ }
+ }
+ err := setIPv4MulticastLoopback(c.fd, false)
+ if err != nil {
+ return err
+ }
+ err = joinIPv4GroupUDP(c, ifi, ip)
+ if err != nil {
+ return err
}
- ip := addr.To4()
- if ip == nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ return nil
+}
+
+func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ if ifi != nil {
+ err := setIPv6MulticastInterface(c.fd, ifi)
+ if err != nil {
+ return err
+ }
}
- mreq := &syscall.IPMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ err := setIPv6MulticastLoopback(c.fd, false)
+ if err != nil {
+ return err
}
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+ err = joinIPv6GroupUDP(c, ifi, ip)
if err != nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
+ return 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
+func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ err := joinIPv4Group(c.fd, ifi, ip)
+ if err != nil {
+ return &OpError{"joinipv4group", c.fd.net, &IPAddr{ip}, err}
}
- ip := addr.To4()
- if ip == nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ return nil
+}
+
+func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ err := leaveIPv4Group(c.fd, ifi, ip)
+ if err != nil {
+ return &OpError{"leaveipv4group", c.fd.net, &IPAddr{ip}, err}
}
- mreq := &syscall.IPMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ return nil
+}
+
+func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ err := joinIPv6Group(c.fd, ifi, ip)
+ if err != nil {
+ return &OpError{"joinipv6group", c.fd.net, &IPAddr{ip}, err}
}
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
+ return nil
+}
+
+func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
+ err := leaveIPv6Group(c.fd, ifi, ip)
if err != nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
+ return &OpError{"leaveipv6group", c.fd.net, &IPAddr{ip}, err}
}
return nil
}
diff --git a/src/pkg/net/unicast_test.go b/src/pkg/net/unicast_test.go
new file mode 100644
index 000000000..e5dd013db
--- /dev/null
+++ b/src/pkg/net/unicast_test.go
@@ -0,0 +1,538 @@
+// 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 (
+ "runtime"
+ "syscall"
+ "testing"
+)
+
+var listenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ wildcard bool // test with wildcard address
+}{
+ {net: "tcp", laddr: "", wildcard: true},
+ {net: "tcp", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+ {net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: "", wildcard: true},
+ {net: "tcp4", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true, wildcard: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
+}
+
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 && !supportsIPv6 {
+ continue
+ }
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*TCPListener).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.Close()
+ }
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 && !supportsIPv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*UDPConn).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.Close()
+ }
+}
+
+func TestSimpleTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.Close()
+ }
+}
+
+func TestSimpleUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.Close()
+ }
+}
+
+var dualStackListenerTests = []struct {
+ net1 string // first listener
+ laddr1 string
+ net2 string // second listener
+ laddr2 string
+ wildcard bool // test with wildcard address
+ xerr error // expected error value, nil or other
+}{
+ // Test cases and expected results for the attemping 2nd listen on the same port
+ // 1st listen 2nd listen darwin freebsd linux openbsd
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "" - - - -
+ // "tcp" "" "tcp" "0.0.0.0" - - - -
+ // "tcp" "0.0.0.0" "tcp" "" - - - -
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "" - - - ok
+ // "tcp" "0.0.0.0" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "0.0.0.0" - - - ok
+ // "tcp" "[::ffff:0.0.0.0]" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "[::ffff:0.0.0.0]" - - - ok
+ // ------------------------------------------------------------------------------------
+ // "tcp4" "" "tcp6" "" ok ok ok ok
+ // "tcp6" "" "tcp4" "" ok ok ok ok
+ // "tcp4" "0.0.0.0" "tcp6" "[::]" ok ok ok ok
+ // "tcp6" "[::]" "tcp4" "0.0.0.0" ok ok ok ok
+ // ------------------------------------------------------------------------------------
+ // "tcp" "127.0.0.1" "tcp" "[::1]" ok ok ok ok
+ // "tcp" "[::1]" "tcp" "127.0.0.1" ok ok ok ok
+ // "tcp4" "127.0.0.1" "tcp6" "[::1]" ok ok ok ok
+ // "tcp6" "[::1]" "tcp4" "127.0.0.1" ok ok ok ok
+ //
+ // Platform default configurations:
+ // darwin, kernel version 11.3.0
+ // net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // freebsd, kernel version 8.2
+ // net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+ // linux, kernel version 3.0.0
+ // net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // openbsd, kernel version 5.0
+ // net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
+ {net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
+ {net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
+ {net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
+
+ {net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
+ {net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
+ {net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
+ {net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
+ }
+ }
+ l1, port := usableListenPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := Listen(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ tt.net1 = toudpnet(tt.net1)
+ tt.net2 = toudpnet(tt.net2)
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
+ }
+ }
+ l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := ListenPacket(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPort net=" + net)
+ case "tcp", "tcp4", "tcp6":
+ l, err = Listen(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*TCPListener).Addr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPacketPort net=" + net)
+ case "udp", "udp4", "udp6":
+ l, err = ListenPacket(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*UDPConn).LocalAddr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func differentWildcardAddr(i, j string) bool {
+ if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+ return false
+ }
+ if i == "[::]" && j == "[::]" {
+ return false
+ }
+ return true
+}
+
+func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
+ switch net {
+ case "tcp":
+ fd := l.(*TCPListener).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "tcp4":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "tcp6":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ case "udp":
+ fd := l.(*UDPConn).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "udp4":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "udp6":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if err == nil {
+ l.(*TCPListener).Close()
+ t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
+ }
+ case "udp", "udp4", "udp6":
+ if err == nil {
+ l.(*UDPConn).Close()
+ t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*TCPListener).Close()
+ case "udp", "udp4", "udp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*UDPConn).Close()
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
+ switch a := fd.laddr.(type) {
+ case *TCPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ } else {
+ if fd.family != a.family() {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+ }
+ }
+ case *UDPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ } else {
+ if fd.family != a.family() {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+ }
+ }
+ default:
+ t.Fatalf("Unexpected protocol address type: %T", a)
+ }
+}
+
+func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
+ _, err := ipv4TOS(fd)
+ if err != nil {
+ t.Fatalf("ipv4TOS failed: %v", err)
+ }
+ err = setIPv4TOS(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv4TOS failed: %v", err)
+ }
+ _, err = ipv4TTL(fd)
+ if err != nil {
+ t.Fatalf("ipv4TTL failed: %v", err)
+ }
+ err = setIPv4TTL(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv4TTL failed: %v", err)
+ }
+}
+
+func testIPv6UnicastSocketOptions(t *testing.T, fd *netFD) {
+ _, err := ipv6TrafficClass(fd)
+ if err != nil {
+ t.Fatalf("ipv6TrafficClass failed: %v", err)
+ }
+ err = setIPv6TrafficClass(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv6TrafficClass failed: %v", err)
+ }
+ _, err = ipv6HopLimit(fd)
+ if err != nil {
+ t.Fatalf("ipv6HopLimit failed: %v", err)
+ }
+ err = setIPv6HopLimit(fd, 1)
+ if err != nil {
+ t.Fatalf("setIPv6HopLimit failed: %v", err)
+ }
+}
+
+var prohibitionaryDialArgTests = []struct {
+ net string
+ addr string
+}{
+ {"tcp6", "127.0.0.1"},
+ {"tcp6", "[::ffff:127.0.0.1]"},
+}
+
+func TestProhibitionaryDialArgs(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ // This test requires both IPv6 and IPv6 IPv4-mapping functionality.
+ if !supportsIPv4map || testing.Short() || !*testExternal {
+ return
+ }
+
+ l, port := usableListenPort(t, "tcp", "[::]")
+ defer l.Close()
+
+ for _, tt := range prohibitionaryDialArgTests {
+ c, err := Dial(tt.net, tt.addr+":"+port)
+ if err == nil {
+ c.Close()
+ t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
+ }
+ }
+}
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
index d5040f9a2..ae0956958 100644
--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.go
@@ -6,10 +6,6 @@
package net
-import (
- "os"
-)
-
// UnixAddr represents the address of a Unix domain socket end point.
type UnixAddr struct {
Name string
@@ -38,7 +34,7 @@ func (a *UnixAddr) toAddr() Addr {
// ResolveUnixAddr parses addr as a Unix domain socket address.
// The string net gives the network name, "unix", "unixgram" or
// "unixpacket".
-func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
+func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
switch net {
case "unix":
case "unixpacket":
diff --git a/src/pkg/net/unixsock_plan9.go b/src/pkg/net/unixsock_plan9.go
index 7e212df8a..7b4ae6bd1 100644
--- a/src/pkg/net/unixsock_plan9.go
+++ b/src/pkg/net/unixsock_plan9.go
@@ -7,7 +7,8 @@
package net
import (
- "os"
+ "syscall"
+ "time"
)
// UnixConn is an implementation of the Conn interface
@@ -16,19 +17,19 @@ 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
+// Read implements the Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err error) {
+ return 0, syscall.EPLAN9
}
-// Write implements the net.Conn Write method.
-func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
- return 0, os.EPLAN9
+// Write implements the Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err error) {
+ return 0, syscall.EPLAN9
}
// Close closes the Unix domain connection.
-func (c *UnixConn) Close() os.Error {
- return os.EPLAN9
+func (c *UnixConn) Close() error {
+ return syscall.EPLAN9
}
// LocalAddr returns the local network address, a *UnixAddr.
@@ -44,38 +45,38 @@ 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
+// SetDeadline implements the Conn SetDeadline method.
+func (c *UnixConn) SetDeadline(t time.Time) error {
+ return syscall.EPLAN9
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
- return os.EPLAN9
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *UnixConn) SetReadDeadline(t time.Time) error {
+ return syscall.EPLAN9
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
- return os.EPLAN9
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *UnixConn) SetWriteDeadline(t time.Time) error {
+ return syscall.EPLAN9
}
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
- err = os.EPLAN9
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
+ err = syscall.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
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
+ err = syscall.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
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error) {
+ return nil, syscall.EPLAN9
}
// UnixListener is a Unix domain socket listener.
@@ -85,20 +86,20 @@ 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
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) {
+ return nil, syscall.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
+func (l *UnixListener) Accept() (c Conn, err error) {
+ return nil, syscall.EPLAN9
}
// Close stops listening on the Unix address.
// Already accepted connections are not closed.
-func (l *UnixListener) Close() os.Error {
- return os.EPLAN9
+func (l *UnixListener) Close() error {
+ return syscall.EPLAN9
}
// Addr returns the listener's network address.
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 38c6fe9eb..37a2b1e09 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.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.
+// +build darwin freebsd linux netbsd openbsd windows
+
// Unix domain sockets
package net
@@ -9,19 +11,20 @@ package net
import (
"os"
"syscall"
+ "time"
)
-func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
- var proto int
+func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err error) {
+ var sotype int
switch net {
default:
return nil, UnknownNetworkError(net)
case "unix":
- proto = syscall.SOCK_STREAM
+ sotype = syscall.SOCK_STREAM
case "unixgram":
- proto = syscall.SOCK_DGRAM
+ sotype = syscall.SOCK_DGRAM
case "unixpacket":
- proto = syscall.SOCK_SEQPACKET
+ sotype = syscall.SOCK_SEQPACKET
}
var la, ra syscall.Sockaddr
@@ -35,8 +38,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
}
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}
+ } else if sotype != syscall.SOCK_DGRAM || laddr == nil {
+ return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress}
}
case "listen":
@@ -45,19 +48,19 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
}
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()}}
+ return nil, &OpError{Op: mode, Net: net, Addr: raddr, Err: &AddrError{Err: "unexpected remote address", Addr: raddr.String()}}
}
}
f := sockaddrToUnix
- if proto == syscall.SOCK_DGRAM {
+ if sotype == syscall.SOCK_DGRAM {
f = sockaddrToUnixgram
- } else if proto == syscall.SOCK_SEQPACKET {
+ } else if sotype == syscall.SOCK_SEQPACKET {
f = sockaddrToUnixpacket
}
- fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
- if oserr != nil {
+ fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, f)
+ if err != nil {
goto Error
}
return fd, nil
@@ -67,7 +70,7 @@ Error:
if mode == "listen" {
addr = laddr
}
- return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
+ return nil, &OpError{Op: mode, Net: net, Addr: addr, Err: err}
}
func sockaddrToUnix(sa syscall.Sockaddr) Addr {
@@ -91,8 +94,8 @@ func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
return nil
}
-func protoToNet(proto int) string {
- switch proto {
+func sotypeToNet(sotype int) string {
+ switch sotype {
case syscall.SOCK_STREAM:
return "unix"
case syscall.SOCK_SEQPACKET:
@@ -100,7 +103,7 @@ func protoToNet(proto int) string {
case syscall.SOCK_DGRAM:
return "unixgram"
default:
- panic("protoToNet unknown protocol")
+ panic("sotypeToNet unknown socket type")
}
return ""
}
@@ -117,26 +120,26 @@ 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) {
+// Read implements the Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Read(b)
}
-// Write implements the net.Conn Write method.
-func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+// Write implements the Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
return c.fd.Write(b)
}
// Close closes the Unix domain connection.
-func (c *UnixConn) Close() os.Error {
+func (c *UnixConn) Close() error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
err := c.fd.Close()
c.fd = nil
@@ -162,71 +165,71 @@ func (c *UnixConn) RemoteAddr() Addr {
return c.fd.raddr
}
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+// SetDeadline implements the Conn SetDeadline method.
+func (c *UnixConn) SetDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(c.fd, nsec)
+ return setDeadline(c.fd, t)
}
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+// SetReadDeadline implements the Conn SetReadDeadline method.
+func (c *UnixConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setReadTimeout(c.fd, nsec)
+ return setReadDeadline(c.fd, t)
}
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
+func (c *UnixConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setWriteTimeout(c.fd, nsec)
+ return setWriteDeadline(c.fd, t)
}
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
-func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
+func (c *UnixConn) SetReadBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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 {
+func (c *UnixConn) SetWriteBuffer(bytes int) error {
if !c.ok() {
- return os.EINVAL
+ return syscall.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.
+// It returns the number of bytes copied into b and the source address
+// of 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) {
+// see SetDeadline and SetReadDeadline.
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, sa, err := c.fd.ReadFrom(b)
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
- addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
}
return
}
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
if !c.ok() {
- return 0, nil, os.EINVAL
+ return 0, nil, syscall.EINVAL
}
n, uaddr, err := c.ReadFromUnix(b)
return n, uaddr.toAddr(), err
@@ -236,50 +239,58 @@ func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
//
// WriteToUnix can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
+// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
- if addr.Net != protoToNet(c.fd.proto) {
- return 0, os.EAFNOSUPPORT
+ if addr.Net != sotypeToNet(c.fd.sotype) {
+ return 0, syscall.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) {
+// WriteTo implements the PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
if !c.ok() {
- return 0, os.EINVAL
+ return 0, syscall.EINVAL
}
a, ok := addr.(*UnixAddr)
if !ok {
- return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
+ return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
}
return c.WriteToUnix(b, a)
}
-func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+// ReadMsgUnix reads a packet from c, copying the payload into b
+// and the associated out-of-band data into oob.
+// It returns the number of bytes copied into b, the number of
+// bytes copied into oob, the flags that were set on the packet,
+// and the source address of the packet.
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
if !c.ok() {
- return 0, 0, 0, nil, os.EINVAL
+ return 0, 0, 0, nil, syscall.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)}
+ addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
}
return
}
-func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+// WriteMsgUnix writes a packet to addr via c, copying the payload from b
+// and the associated out-of-band data from oob. It returns the number
+// of payload and out-of-band bytes written.
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if !c.ok() {
- return 0, 0, os.EINVAL
+ return 0, 0, syscall.EINVAL
}
if addr != nil {
- if addr.Net != protoToNet(c.fd.proto) {
- return 0, 0, os.EAFNOSUPPORT
+ if addr.Net != sotypeToNet(c.fd.sotype) {
+ return 0, 0, syscall.EAFNOSUPPORT
}
sa := &syscall.SockaddrUnix{Name: addr.Name}
return c.fd.WriteMsg(b, oob, sa)
@@ -290,15 +301,15 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
// 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() }
+func (c *UnixConn) File() (f *os.File, err error) { return c.fd.dup() }
// DialUnix connects to the remote address raddr on the network net,
// which must be "unix" or "unixgram". If laddr is not nil, it is used
// as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
- fd, e := unixSocket(net, laddr, raddr, "dial")
- if e != nil {
- return nil, e
+func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+ fd, err := unixSocket(net, laddr, raddr, "dial")
+ if err != nil {
+ return nil, err
}
return newUnixConn(fd), nil
}
@@ -313,7 +324,7 @@ type UnixListener struct {
// 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) {
+func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
if net != "unix" && net != "unixgram" && net != "unixpacket" {
return nil, UnknownNetworkError(net)
}
@@ -324,31 +335,31 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
if err != nil {
return nil, err
}
- e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
- if e1 != 0 {
+ err = syscall.Listen(fd.sysfd, listenerBacklog)
+ if err != nil {
closesocket(fd.sysfd)
- return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
+ return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
}
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) {
+func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
if l == nil || l.fd == nil {
- return nil, os.EINVAL
+ return nil, syscall.EINVAL
}
- fd, e := l.fd.accept(sockaddrToUnix)
- if e != nil {
- return nil, e
+ fd, err := l.fd.accept(sockaddrToUnix)
+ if err != nil {
+ return nil, err
}
- c = newUnixConn(fd)
+ c := newUnixConn(fd)
return c, nil
}
// 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) {
+func (l *UnixListener) Accept() (c Conn, err error) {
c1, err := l.AcceptUnix()
if err != nil {
return nil, err
@@ -358,9 +369,9 @@ func (l *UnixListener) Accept() (c Conn, err os.Error) {
// Close stops listening on the Unix address.
// Already accepted connections are not closed.
-func (l *UnixListener) Close() os.Error {
+func (l *UnixListener) Close() error {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
// The operating system doesn't clean up
@@ -384,35 +395,36 @@ func (l *UnixListener) Close() os.Error {
// 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) {
+// SetDeadline sets the deadline associated with the listener.
+// A zero time value disables the deadline.
+func (l *UnixListener) SetDeadline(t time.Time) (err error) {
if l == nil || l.fd == nil {
- return os.EINVAL
+ return syscall.EINVAL
}
- return setTimeout(l.fd, nsec)
+ return setDeadline(l.fd, t)
}
// 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() }
+func (l *UnixListener) File() (f *os.File, err 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) {
+func ListenUnixgram(net string, laddr *UnixAddr) (*UDPConn, error) {
switch net {
case "unixgram":
default:
return nil, UnknownNetworkError(net)
}
if laddr == nil {
- return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
+ return nil, &OpError{"listen", net, nil, errMissingAddress}
}
- fd, e := unixSocket(net, laddr, nil, "listen")
- if e != nil {
- return nil, e
+ fd, err := unixSocket(net, laddr, nil, "listen")
+ if err != nil {
+ return nil, err
}
return newUDPConn(fd), nil
}
diff --git a/src/pkg/net/url/example_test.go b/src/pkg/net/url/example_test.go
new file mode 100644
index 000000000..56c5dc696
--- /dev/null
+++ b/src/pkg/net/url/example_test.go
@@ -0,0 +1,41 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package url_test
+
+import (
+ "fmt"
+ "log"
+ "net/url"
+)
+
+func ExampleValues() {
+ v := url.Values{}
+ v.Set("name", "Ava")
+ v.Add("friend", "Jess")
+ v.Add("friend", "Sarah")
+ v.Add("friend", "Zoe")
+ // v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
+ fmt.Println(v.Get("name"))
+ fmt.Println(v.Get("friend"))
+ fmt.Println(v["friend"])
+ // Output:
+ // Ava
+ // Jess
+ // [Jess Sarah Zoe]
+}
+
+func ExampleURL() {
+ u, err := url.Parse("http://bing.com/search?q=dotnet")
+ if err != nil {
+ log.Fatal(err)
+ }
+ u.Scheme = "https"
+ u.Host = "google.com"
+ q := u.Query()
+ q.Set("q", "golang")
+ u.RawQuery = q.Encode()
+ fmt.Println(u)
+ // Output: https://google.com/search?q=golang
+}
diff --git a/src/pkg/url/url.go b/src/pkg/net/url/url.go
index d07b01611..88ff7ebfe 100644
--- a/src/pkg/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package URL parses URLs and implements query escaping.
+// Package url parses URLs and implements query escaping.
// See RFC 3986.
package url
import (
- "os"
+ "errors"
"strconv"
"strings"
)
// Error reports an error and the operation and URL that caused it.
type Error struct {
- Op string
- URL string
- Error os.Error
+ Op string
+ URL string
+ Err error
}
-func (e *Error) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
+func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
func ishex(c byte) bool {
switch {
@@ -52,12 +52,11 @@ const (
encodeUserPassword
encodeQueryComponent
encodeFragment
- encodeOpaque
)
type EscapeError string
-func (e EscapeError) String() string {
+func (e EscapeError) Error() string {
return "invalid URL escape " + strconv.Quote(string(e))
}
@@ -69,6 +68,7 @@ func shouldEscape(c byte, mode encoding) bool {
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
return false
}
+ // TODO: Update the character sets after RFC 3986.
switch c {
case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark)
return false
@@ -78,12 +78,10 @@ func shouldEscape(c byte, mode encoding) bool {
// the reserved characters to appear unescaped.
switch mode {
case encodePath: // §3.3
- // The RFC allows : @ & = + $ , but saves / ; for assigning
- // meaning to individual path segments. This package
+ // The RFC allows : @ & = + $ but saves / ; , for assigning
+ // meaning to individual path segments. This package
// only manipulates the path as a whole, so we allow those
- // last two as well. Clients that need to distinguish between
- // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath.
- // That leaves only ? to escape.
+ // last two as well. That leaves only ? to escape.
return c == '?'
case encodeUserPassword: // §3.2.2
@@ -99,12 +97,6 @@ func shouldEscape(c byte, mode encoding) bool {
// The RFC text is silent but the grammar allows
// everything, so escape nothing.
return false
-
- case encodeOpaque: // §3 opaque_part
- // The RFC allows opaque_part to use all characters
- // except that the leading / must be escaped.
- // (We implement that case in String.)
- return false
}
}
@@ -115,13 +107,13 @@ func shouldEscape(c byte, mode encoding) bool {
// 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) {
+func QueryUnescape(s string) (string, error) {
return unescape(s, encodeQueryComponent)
}
// 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) {
+func unescape(s string, mode encoding) (string, error) {
// Count %, check that they're well-formed.
n := 0
hasPlus := false
@@ -217,70 +209,79 @@ func escape(s string, mode encoding) string {
return string(t)
}
-// UnescapeUserinfo parses the RawUserinfo field of a URL
-// as the form user or user:password and unescapes and returns
-// the two halves.
+// A URL represents a parsed URL (technically, a URI reference).
+// The general form represented is:
//
-// This functionality should only be used with legacy web sites.
-// RFC 2396 warns that interpreting Userinfo this way
-// ``is NOT RECOMMENDED, because the passing of authentication
-// information in clear text (such as URI) has proven to be a
-// security risk in almost every case where it has been used.''
-func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
- u, p := split(rawUserinfo, ':', true)
- if user, err = unescape(u, encodeUserPassword); err != nil {
- return "", "", err
- }
- if password, err = unescape(p, encodeUserPassword); err != nil {
- return "", "", err
- }
- return
+// scheme://[userinfo@]host/path[?query][#fragment]
+//
+// URLs that do not start with a slash after the scheme are interpreted as:
+//
+// scheme:opaque[?query][#fragment]
+//
+type URL struct {
+ Scheme string
+ Opaque string // encoded opaque data
+ User *Userinfo // username and password information
+ Host string
+ Path string
+ RawQuery string // encoded query values, without '?'
+ Fragment string // fragment for references, without '#'
}
-// EscapeUserinfo combines user and password in the form
-// user:password (or just user if password is empty) and then
-// escapes it for use as the URL.RawUserinfo field.
-//
+// User returns a Userinfo containing the provided username
+// and no password set.
+func User(username string) *Userinfo {
+ return &Userinfo{username, "", false}
+}
+
+// UserPassword returns a Userinfo containing the provided username
+// and password.
// This functionality should only be used with legacy web sites.
// RFC 2396 warns that interpreting Userinfo this way
// ``is NOT RECOMMENDED, because the passing of authentication
// information in clear text (such as URI) has proven to be a
// security risk in almost every case where it has been used.''
-func EscapeUserinfo(user, password string) string {
- raw := escape(user, encodeUserPassword)
- if password != "" {
- raw += ":" + escape(password, encodeUserPassword)
+func UserPassword(username, password string) *Userinfo {
+ return &Userinfo{username, password, true}
+}
+
+// The Userinfo type is an immutable encapsulation of username and
+// password details for a URL. An existing Userinfo value is guaranteed
+// to have a username set (potentially empty, as allowed by RFC 2396),
+// and optionally a password.
+type Userinfo struct {
+ username string
+ password string
+ passwordSet bool
+}
+
+// Username returns the username.
+func (u *Userinfo) Username() string {
+ return u.username
+}
+
+// Password returns the password in case it is set, and whether it is set.
+func (u *Userinfo) Password() (string, bool) {
+ if u.passwordSet {
+ return u.password, true
}
- return raw
+ return "", false
}
-// A URL represents a parsed URL (technically, a URI reference).
-// The general form represented is:
-// scheme://[userinfo@]host/path[?query][#fragment]
-// The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format"
-// (special characters must be hex-escaped if not meant to have special meaning).
-// All other fields are logical values; '+' or '%' represent themselves.
-//
-// The various Raw values are supplied in wire format because
-// clients typically have to split them into pieces before further
-// decoding.
-type URL struct {
- Raw string // the original string
- Scheme string // scheme
- RawAuthority string // [userinfo@]host
- RawUserinfo string // userinfo
- Host string // host
- RawPath string // /path[?query][#fragment]
- Path string // /path
- OpaquePath bool // path is opaque (unrooted when scheme is present)
- RawQuery string // query
- Fragment string // fragment
+// String returns the encoded userinfo information in the standard form
+// of "username[:password]".
+func (u *Userinfo) String() string {
+ s := escape(u.username, encodeUserPassword)
+ if u.passwordSet {
+ s += ":" + escape(u.password, encodeUserPassword)
+ }
+ return s
}
// Maybe rawurl is of the form scheme:path.
// (Scheme must be [a-zA-Z][a-zA-Z0-9+-.]*)
// If so, return scheme, path; else return "", rawurl.
-func getscheme(rawurl string) (scheme, path string, err os.Error) {
+func getscheme(rawurl string) (scheme, path string, err error) {
for i := 0; i < len(rawurl); i++ {
c := rawurl[i]
switch {
@@ -292,7 +293,7 @@ func getscheme(rawurl string) (scheme, path string, err os.Error) {
}
case c == ':':
if i == 0 {
- return "", "", os.NewError("missing protocol scheme")
+ return "", "", errors.New("missing protocol scheme")
}
return rawurl[0:i], rawurl[i+1:], nil
default:
@@ -320,19 +321,28 @@ func split(s string, c byte, cutc bool) (string, string) {
}
// 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 Parse(rawurl string) (url *URL, err os.Error) {
- return parse(rawurl, false)
+func Parse(rawurl string) (url *URL, err error) {
+ // Cut off #frag
+ u, frag := split(rawurl, '#', true)
+ if url, err = parse(u, false); err != nil {
+ return nil, err
+ }
+ if frag == "" {
+ return url, nil
+ }
+ if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ return url, nil
}
-// ParseRequest parses rawurl into a URL structure. It assumes that
-// rawurl was received from an HTTP request, so the rawurl is interpreted
+// ParseRequestURI parses rawurl into a URL structure. It assumes that
+// rawurl was received in 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 ParseRequest(rawurl string) (url *URL, err os.Error) {
+func ParseRequestURI(rawurl string) (url *URL, err error) {
return parse(rawurl, true)
}
@@ -340,144 +350,104 @@ func ParseRequest(rawurl string) (url *URL, err os.Error) {
// 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 parse(rawurl string, viaRequest bool) (url *URL, err os.Error) {
- var (
- leadingSlash bool
- path string
- )
+func parse(rawurl string, viaRequest bool) (url *URL, err error) {
+ var rest string
if rawurl == "" {
- err = os.NewError("empty url")
+ err = errors.New("empty url")
goto Error
}
url = new(URL)
- url.Raw = rawurl
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
- if url.Scheme, path, err = getscheme(rawurl); err != nil {
+ if url.Scheme, rest, err = getscheme(rawurl); err != nil {
goto Error
}
- leadingSlash = strings.HasPrefix(path, "/")
- if url.Scheme != "" && !leadingSlash {
- // RFC 2396:
- // Absolute URI (has scheme) with non-rooted path
- // is uninterpreted. It doesn't even have a ?query.
- // This is the case that handles mailto:name@example.com.
- url.RawPath = path
+ rest, url.RawQuery = split(rest, '?', true)
- if url.Path, err = unescape(path, encodeOpaque); err != nil {
- goto Error
+ if !strings.HasPrefix(rest, "/") {
+ if url.Scheme != "" {
+ // We consider rootless paths per RFC 3986 as opaque.
+ url.Opaque = rest
+ return url, nil
}
- url.OpaquePath = true
- } else {
- if viaRequest && !leadingSlash {
- err = os.NewError("invalid URI for request")
+ if viaRequest {
+ err = errors.New("invalid URI for request")
goto Error
}
+ }
- // Split off query before parsing path further.
- url.RawPath = path
- path, query := split(path, '?', false)
- if len(query) > 1 {
- url.RawQuery = query[1:]
- }
-
- // Maybe path is //authority/path
- if (url.Scheme != "" || !viaRequest) &&
- strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///") {
- url.RawAuthority, path = split(path[2:], '/', false)
- url.RawPath = url.RawPath[2+len(url.RawAuthority):]
- }
-
- // Split authority into userinfo@host.
- // If there's no @, split's default is wrong. Check explicitly.
- var rawHost string
- if strings.Index(url.RawAuthority, "@") < 0 {
- rawHost = url.RawAuthority
- } else {
- url.RawUserinfo, rawHost = split(url.RawAuthority, '@', true)
- }
-
- // We leave RawAuthority only in raw form because clients
- // of common protocols should be using Userinfo and Host
- // instead. Clients that wish to use RawAuthority will have to
- // interpret it themselves: RFC 2396 does not define the meaning.
-
- if strings.Contains(rawHost, "%") {
- // Host cannot contain escaped characters.
- err = os.NewError("hexadecimal escape in host")
+ if (url.Scheme != "" || !viaRequest) && strings.HasPrefix(rest, "//") && !strings.HasPrefix(rest, "///") {
+ var authority string
+ authority, rest = split(rest[2:], '/', false)
+ url.User, url.Host, err = parseAuthority(authority)
+ if err != nil {
goto Error
}
- url.Host = rawHost
-
- if url.Path, err = unescape(path, encodePath); err != nil {
+ if strings.Contains(url.Host, "%") {
+ err = errors.New("hexadecimal escape in host")
goto Error
}
}
+ if url.Path, err = unescape(rest, encodePath); err != nil {
+ goto Error
+ }
return url, nil
Error:
return nil, &Error{"parse", rawurl, err}
-
}
-// 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 = Parse(rawurl); err != nil {
- return nil, err
+func parseAuthority(authority string) (user *Userinfo, host string, err error) {
+ if strings.Index(authority, "@") < 0 {
+ host = authority
+ return
}
- url.Raw += frag
- url.RawPath += frag
- if len(frag) > 1 {
- frag = frag[1:]
- if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
- return nil, &Error{"parse", rawurl, err}
+ userinfo, host := split(authority, '@', true)
+ if strings.Index(userinfo, ":") < 0 {
+ if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
+ return
+ }
+ user = User(userinfo)
+ } else {
+ username, password := split(userinfo, ':', true)
+ if username, err = unescape(username, encodeUserPassword); err != nil {
+ return
+ }
+ if password, err = unescape(password, encodeUserPassword); err != nil {
+ return
}
+ user = UserPassword(username, password)
}
- return url, nil
+ return
}
-// String reassembles url into a valid URL string.
-//
-// There are redundant fields stored in the URL structure:
-// the String method consults Scheme, Path, Host, RawUserinfo,
-// RawQuery, and Fragment, but not Raw, RawPath or RawAuthority.
-func (url *URL) String() string {
+// String reassembles the URL into a valid URL string.
+func (u *URL) String() string {
+ // TODO: Rewrite to use bytes.Buffer
result := ""
- if url.Scheme != "" {
- result += url.Scheme + ":"
- }
- if url.Host != "" || url.RawUserinfo != "" {
- result += "//"
- if url.RawUserinfo != "" {
- // hide the password, if any
- info := url.RawUserinfo
- if i := strings.Index(info, ":"); i >= 0 {
- info = info[0:i] + ":******"
- }
- result += info + "@"
- }
- result += url.Host
+ if u.Scheme != "" {
+ result += u.Scheme + ":"
}
- if url.OpaquePath {
- path := url.Path
- if strings.HasPrefix(path, "/") {
- result += "%2f"
- path = path[1:]
- }
- result += escape(path, encodeOpaque)
+ if u.Opaque != "" {
+ result += u.Opaque
} else {
- result += escape(url.Path, encodePath)
+ if u.Host != "" || u.User != nil {
+ result += "//"
+ if u := u.User; u != nil {
+ result += u.String() + "@"
+ }
+ result += u.Host
+ }
+ result += escape(u.Path, encodePath)
}
- if url.RawQuery != "" {
- result += "?" + url.RawQuery
+ if u.RawQuery != "" {
+ result += "?" + u.RawQuery
}
- if url.Fragment != "" {
- result += "#" + escape(url.Fragment, encodeFragment)
+ if u.Fragment != "" {
+ result += "#" + escape(u.Fragment, encodeFragment)
}
return result
}
@@ -517,7 +487,7 @@ func (v Values) Add(key, value string) {
// Del deletes the values associated with key.
func (v Values) Del(key string) {
- v[key] = nil, false
+ delete(v, key)
}
// ParseQuery parses the URL-encoded query string and returns
@@ -525,27 +495,35 @@ func (v Values) Del(key string) {
// 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) {
+func ParseQuery(query string) (m Values, err 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 {
+func parseQuery(m Values, query string) (err error) {
+ for query != "" {
+ key := query
+ if i := strings.IndexAny(key, "&;"); i >= 0 {
+ key, query = key[:i], key[i+1:]
+ } else {
+ query = ""
+ }
+ if key == "" {
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])
+ value := ""
+ if i := strings.Index(key, "="); i >= 0 {
+ key, value = key[:i], key[i+1:]
+ }
+ key, err1 := QueryUnescape(key)
+ if err1 != nil {
+ err = err1
+ continue
}
- if e != nil {
- err = e
+ value, err1 = QueryUnescape(value)
+ if err1 != nil {
+ err = err1
continue
}
m[key] = append(m[key], value)
@@ -600,19 +578,19 @@ func resolvePath(basepath string, refpath string) string {
}
// IsAbs returns true if the URL is absolute.
-func (url *URL) IsAbs() bool {
- return url.Scheme != ""
+func (u *URL) IsAbs() bool {
+ return u.Scheme != ""
}
-// Parse parses a URL in the context of a base URL. The URL in ref
+// Parse parses a URL in the context of the receiver. The provided URL
// may be relative or absolute. Parse returns nil, err on parse
// failure, otherwise its return value is the same as ResolveReference.
-func (base *URL) Parse(ref string) (*URL, os.Error) {
+func (u *URL) Parse(ref string) (*URL, error) {
refurl, err := Parse(ref)
if err != nil {
return nil, err
}
- return base.ResolveReference(refurl), nil
+ return u.ResolveReference(refurl), nil
}
// ResolveReference resolves a URI reference to an absolute URI from
@@ -621,48 +599,39 @@ func (base *URL) Parse(ref string) (*URL, os.Error) {
// URL instance, even if the returned URL is identical to either the
// base or reference. If ref is an absolute URL, then ResolveReference
// ignores base and returns a copy of ref.
-func (base *URL) ResolveReference(ref *URL) *URL {
- url := new(URL)
- switch {
- case ref.IsAbs():
- *url = *ref
- default:
- // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- *url = *base
- if ref.RawAuthority != "" {
- // The "net_path" case.
- url.RawAuthority = ref.RawAuthority
- url.Host = ref.Host
- url.RawUserinfo = ref.RawUserinfo
- }
- switch {
- case url.OpaquePath:
- url.Path = ref.Path
- url.RawPath = ref.RawPath
- url.RawQuery = ref.RawQuery
- case strings.HasPrefix(ref.Path, "/"):
- // The "abs_path" case.
- url.Path = ref.Path
- url.RawPath = ref.RawPath
- url.RawQuery = ref.RawQuery
- default:
- // The "rel_path" case.
- path := resolvePath(base.Path, ref.Path)
- if !strings.HasPrefix(path, "/") {
- path = "/" + path
- }
- url.Path = path
- url.RawPath = url.Path
- url.RawQuery = ref.RawQuery
- if ref.RawQuery != "" {
- url.RawPath += "?" + url.RawQuery
- }
+func (u *URL) ResolveReference(ref *URL) *URL {
+ if ref.IsAbs() {
+ url := *ref
+ return &url
+ }
+ // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ url := *u
+ url.RawQuery = ref.RawQuery
+ url.Fragment = ref.Fragment
+ if ref.Opaque != "" {
+ url.Opaque = ref.Opaque
+ url.User = nil
+ url.Host = ""
+ url.Path = ""
+ return &url
+ }
+ if ref.Host != "" || ref.User != nil {
+ // The "net_path" case.
+ url.Host = ref.Host
+ url.User = ref.User
+ }
+ if strings.HasPrefix(ref.Path, "/") {
+ // The "abs_path" case.
+ url.Path = ref.Path
+ } else {
+ // The "rel_path" case.
+ path := resolvePath(u.Path, ref.Path)
+ if !strings.HasPrefix(path, "/") {
+ path = "/" + path
}
-
- url.Fragment = ref.Fragment
+ url.Path = path
}
- url.Raw = url.String()
- return url
+ return &url
}
// Query parses RawQuery and returns the corresponding values.
@@ -671,7 +640,18 @@ func (u *URL) Query() Values {
return v
}
-// EncodedPath returns the URL's path in "URL path encoded" form.
-func (u *URL) EncodedPath() string {
- return escape(u.Path, encodePath)
+// RequestURI returns the encoded path?query or opaque?query
+// string that would be used in an HTTP request for u.
+func (u *URL) RequestURI() string {
+ result := u.Opaque
+ if result == "" {
+ result = escape(u.Path, encodePath)
+ if result == "" {
+ result = "/"
+ }
+ }
+ if u.RawQuery != "" {
+ result += "?" + u.RawQuery
+ }
+ return result
}
diff --git a/src/pkg/url/url_test.go b/src/pkg/net/url/url_test.go
index af394d4fb..2d911ed50 100644
--- a/src/pkg/url/url_test.go
+++ b/src/pkg/net/url/url_test.go
@@ -6,16 +6,10 @@ package url
import (
"fmt"
- "os"
"reflect"
"testing"
)
-// TODO(rsc):
-// test Unescape
-// test Escape
-// test Parse
-
type URLTest struct {
in string
out *URL
@@ -27,10 +21,8 @@ var urltests = []URLTest{
{
"http://www.google.com",
&URL{
- Raw: "http://www.google.com",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
+ Scheme: "http",
+ Host: "www.google.com",
},
"",
},
@@ -38,12 +30,9 @@ var urltests = []URLTest{
{
"http://www.google.com/",
&URL{
- Raw: "http://www.google.com/",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
},
"",
},
@@ -51,12 +40,9 @@ var urltests = []URLTest{
{
"http://www.google.com/file%20one%26two",
&URL{
- Raw: "http://www.google.com/file%20one%26two",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/file%20one%26two",
- Path: "/file one&two",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/file one&two",
},
"http://www.google.com/file%20one&two",
},
@@ -64,13 +50,10 @@ var urltests = []URLTest{
{
"ftp://webmaster@www.google.com/",
&URL{
- Raw: "ftp://webmaster@www.google.com/",
- Scheme: "ftp",
- RawAuthority: "webmaster@www.google.com",
- RawUserinfo: "webmaster",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Scheme: "ftp",
+ User: User("webmaster"),
+ Host: "www.google.com",
+ Path: "/",
},
"",
},
@@ -78,13 +61,10 @@ var urltests = []URLTest{
{
"ftp://john%20doe@www.google.com/",
&URL{
- Raw: "ftp://john%20doe@www.google.com/",
- Scheme: "ftp",
- RawAuthority: "john%20doe@www.google.com",
- RawUserinfo: "john%20doe",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Scheme: "ftp",
+ User: User("john doe"),
+ Host: "www.google.com",
+ Path: "/",
},
"ftp://john%20doe@www.google.com/",
},
@@ -92,13 +72,10 @@ var urltests = []URLTest{
{
"http://www.google.com/?q=go+language",
&URL{
- Raw: "http://www.google.com/?q=go+language",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language",
- Path: "/",
- RawQuery: "q=go+language",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
},
"",
},
@@ -106,13 +83,10 @@ var urltests = []URLTest{
{
"http://www.google.com/?q=go%20language",
&URL{
- Raw: "http://www.google.com/?q=go%20language",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go%20language",
- Path: "/",
- RawQuery: "q=go%20language",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go%20language",
},
"",
},
@@ -120,48 +94,39 @@ var urltests = []URLTest{
{
"http://www.google.com/a%20b?q=c+d",
&URL{
- Raw: "http://www.google.com/a%20b?q=c+d",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/a%20b?q=c+d",
- Path: "/a b",
- RawQuery: "q=c+d",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/a b",
+ RawQuery: "q=c+d",
},
"",
},
- // path without leading /, so no query parsing
+ // path without leading /, so no parsing
{
"http:www.google.com/?q=go+language",
&URL{
- Raw: "http:www.google.com/?q=go+language",
- Scheme: "http",
- RawPath: "www.google.com/?q=go+language",
- Path: "www.google.com/?q=go+language",
- OpaquePath: true,
+ Scheme: "http",
+ Opaque: "www.google.com/",
+ RawQuery: "q=go+language",
},
"http:www.google.com/?q=go+language",
},
- // path without leading /, so no query parsing
+ // path without leading /, so no parsing
{
"http:%2f%2fwww.google.com/?q=go+language",
&URL{
- Raw: "http:%2f%2fwww.google.com/?q=go+language",
- Scheme: "http",
- RawPath: "%2f%2fwww.google.com/?q=go+language",
- Path: "//www.google.com/?q=go+language",
- OpaquePath: true,
+ Scheme: "http",
+ Opaque: "%2f%2fwww.google.com/",
+ RawQuery: "q=go+language",
},
- "http:%2f/www.google.com/?q=go+language",
+ "http:%2f%2fwww.google.com/?q=go+language",
},
// non-authority
{
"mailto:/webmaster@golang.org",
&URL{
- Raw: "mailto:/webmaster@golang.org",
- Scheme: "mailto",
- RawPath: "/webmaster@golang.org",
- Path: "/webmaster@golang.org",
+ Scheme: "mailto",
+ Path: "/webmaster@golang.org",
},
"",
},
@@ -169,11 +134,8 @@ var urltests = []URLTest{
{
"mailto:webmaster@golang.org",
&URL{
- Raw: "mailto:webmaster@golang.org",
- Scheme: "mailto",
- RawPath: "webmaster@golang.org",
- Path: "webmaster@golang.org",
- OpaquePath: true,
+ Scheme: "mailto",
+ Opaque: "webmaster@golang.org",
},
"",
},
@@ -181,8 +143,6 @@ var urltests = []URLTest{
{
"/foo?query=http://bad",
&URL{
- Raw: "/foo?query=http://bad",
- RawPath: "/foo?query=http://bad",
Path: "/foo",
RawQuery: "query=http://bad",
},
@@ -192,12 +152,7 @@ var urltests = []URLTest{
{
"//foo",
&URL{
- RawAuthority: "foo",
- Raw: "//foo",
- Host: "foo",
- Scheme: "",
- RawPath: "",
- Path: "",
+ Host: "foo",
},
"",
},
@@ -205,14 +160,10 @@ var urltests = []URLTest{
{
"//user@foo/path?a=b",
&URL{
- Raw: "//user@foo/path?a=b",
- RawAuthority: "user@foo",
- RawUserinfo: "user",
- Scheme: "",
- RawPath: "/path?a=b",
- Path: "/path",
- RawQuery: "a=b",
- Host: "foo",
+ User: User("user"),
+ Host: "foo",
+ Path: "/path",
+ RawQuery: "a=b",
},
"",
},
@@ -224,81 +175,38 @@ var urltests = []URLTest{
{
"///threeslashes",
&URL{
- RawAuthority: "",
- Raw: "///threeslashes",
- Host: "",
- Scheme: "",
- RawPath: "///threeslashes",
- Path: "///threeslashes",
+ Path: "///threeslashes",
},
"",
},
{
"http://user:password@google.com",
&URL{
- Raw: "http://user:password@google.com",
- Scheme: "http",
- RawAuthority: "user:password@google.com",
- RawUserinfo: "user:password",
- Host: "google.com",
- },
- "http://user:******@google.com",
- },
- {
- "http://user:longerpass@google.com",
- &URL{
- Raw: "http://user:longerpass@google.com",
- Scheme: "http",
- RawAuthority: "user:longerpass@google.com",
- RawUserinfo: "user:longerpass",
- Host: "google.com",
- },
- "http://user:******@google.com",
- },
-}
-
-var urlnofragtests = []URLTest{
- {
- "http://www.google.com/?q=go+language#foo",
- &URL{
- Raw: "http://www.google.com/?q=go+language#foo",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo",
- Path: "/",
- RawQuery: "q=go+language#foo",
+ Scheme: "http",
+ User: UserPassword("user", "password"),
+ Host: "google.com",
},
- "",
+ "http://user:password@google.com",
},
-}
-
-var urlfragtests = []URLTest{
{
"http://www.google.com/?q=go+language#foo",
&URL{
- Raw: "http://www.google.com/?q=go+language#foo",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo",
- Path: "/",
- RawQuery: "q=go+language",
- Fragment: "foo",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo",
},
"",
},
{
"http://www.google.com/?q=go+language#foo%26bar",
&URL{
- Raw: "http://www.google.com/?q=go+language#foo%26bar",
- Scheme: "http",
- RawAuthority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo%26bar",
- Path: "/",
- RawQuery: "q=go+language",
- Fragment: "foo&bar",
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo&bar",
},
"http://www.google.com/?q=go+language#foo&bar",
},
@@ -306,12 +214,18 @@ var urlfragtests = []URLTest{
// more useful string for debugging than fmt's struct printer
func ufmt(u *URL) string {
- return fmt.Sprintf("raw=%q, scheme=%q, rawpath=%q, auth=%q, userinfo=%q, host=%q, path=%q, rawq=%q, frag=%q",
- u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo,
- u.Host, u.Path, u.RawQuery, u.Fragment)
+ var user, pass interface{}
+ if u.User != nil {
+ user = u.User.Username()
+ if p, ok := u.User.Password(); ok {
+ pass = p
+ }
+ }
+ return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawq=%q, frag=%q",
+ u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawQuery, u.Fragment)
}
-func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
for _, tt := range tests {
u, err := parse(tt.in)
if err != nil {
@@ -327,12 +241,6 @@ func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, test
func TestParse(t *testing.T) {
DoTest(t, Parse, "Parse", urltests)
- DoTest(t, Parse, "Parse", urlnofragtests)
-}
-
-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 +259,16 @@ var parseRequestUrlTests = []struct {
{"../dir/", false},
}
-func TestParseRequest(t *testing.T) {
+func TestParseRequestURI(t *testing.T) {
for _, test := range parseRequestUrlTests {
- _, err := ParseRequest(test.url)
+ _, err := ParseRequestURI(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 := ParseRequest(pathThatLooksSchemeRelative)
+ url, err := ParseRequestURI(pathThatLooksSchemeRelative)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
@@ -369,18 +277,18 @@ func TestParseRequest(t *testing.T) {
}
}
-func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) {
+func DoTestString(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
for _, tt := range tests {
u, err := parse(tt.in)
if err != nil {
t.Errorf("%s(%q) returned error %s", name, tt.in, err)
continue
}
- s := u.String()
expected := tt.in
if len(tt.roundtrip) > 0 {
expected = tt.roundtrip
}
+ s := u.String()
if s != expected {
t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
}
@@ -389,15 +297,12 @@ func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string
func TestURLString(t *testing.T) {
DoTestString(t, Parse, "Parse", urltests)
- DoTestString(t, Parse, "Parse", urlnofragtests)
- DoTestString(t, ParseWithReference, "ParseWithReference", urltests)
- DoTestString(t, ParseWithReference, "ParseWithReference", urlfragtests)
}
type EscapeTest struct {
in string
out string
- err os.Error
+ err error
}
var unescapeTests = []EscapeTest{
@@ -510,33 +415,11 @@ func TestEscape(t *testing.T) {
}
}
-type UserinfoTest struct {
- User string
- Password string
- Raw string
-}
-
-var userinfoTests = []UserinfoTest{
- {"user", "password", "user:password"},
- {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
- "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"},
-}
-
-func TestEscapeUserinfo(t *testing.T) {
- for _, tt := range userinfoTests {
- if raw := EscapeUserinfo(tt.User, tt.Password); raw != tt.Raw {
- t.Errorf("EscapeUserinfo(%q, %q) = %q, want %q", tt.User, tt.Password, raw, tt.Raw)
- }
- }
-}
-
-func TestUnescapeUserinfo(t *testing.T) {
- for _, tt := range userinfoTests {
- if user, pass, err := UnescapeUserinfo(tt.Raw); user != tt.User || pass != tt.Password || err != nil {
- t.Errorf("UnescapeUserinfo(%q) = %q, %q, %v, want %q, %q, nil", tt.Raw, user, pass, err, tt.User, tt.Password)
- }
- }
-}
+//var userinfoTests = []UserinfoTest{
+// {"user", "password", "user:password"},
+// {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
+// "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"},
+//}
type EncodeQueryTest struct {
m Values
@@ -630,7 +513,58 @@ var resolveReferenceTests = []struct {
func TestResolveReference(t *testing.T) {
mustParse := func(url string) *URL {
- u, err := ParseWithReference(url)
+ u, err := Parse(url)
+ if err != nil {
+ t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ }
+ return u
+ }
+ for _, test := range resolveReferenceTests {
+ base := mustParse(test.base)
+ rel := mustParse(test.rel)
+ url := base.ResolveReference(rel)
+ urlStr := url.String()
+ if urlStr != test.expected {
+ t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr)
+ }
+ }
+
+ // Test that new instances are returned.
+ base := mustParse("http://foo.com/")
+ abs := base.ResolveReference(mustParse("."))
+ if base == abs {
+ t.Errorf("Expected no-op reference to return new URL instance.")
+ }
+ 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 = mustParse("http://foo.com/path/one/")
+ abs, _ = base.Parse("../two")
+ expected := "http://foo.com/path/two"
+ if abs.String() != expected {
+ t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected)
+ }
+ _, err := base.Parse("")
+ if err == nil {
+ t.Errorf("Expected an error from Parse wrapper parsing an empty string.")
+ }
+
+ // Ensure Opaque resets the URL.
+ base = mustParse("scheme://user@foo.com/bar")
+ abs = base.ResolveReference(&URL{Opaque: "opaque"})
+ want := mustParse("scheme:opaque")
+ if *abs != *want {
+ t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", abs, want)
+ }
+}
+
+func TestResolveReferenceOpaque(t *testing.T) {
+ mustParse := func(url string) *URL {
+ u, err := Parse(url)
if err != nil {
t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
}
@@ -696,3 +630,117 @@ func TestQueryValues(t *testing.T) {
t.Errorf("second Get(bar) = %q, want %q", g, e)
}
}
+
+type parseTest struct {
+ query string
+ out Values
+}
+
+var parseTests = []parseTest{
+ {
+ query: "a=1&b=2",
+ out: Values{"a": []string{"1"}, "b": []string{"2"}},
+ },
+ {
+ query: "a=1&a=2&a=banana",
+ out: Values{"a": []string{"1", "2", "banana"}},
+ },
+ {
+ query: "ascii=%3Ckey%3A+0x90%3E",
+ out: Values{"ascii": []string{"<key: 0x90>"}},
+ },
+ {
+ query: "a=1;b=2",
+ out: Values{"a": []string{"1"}, "b": []string{"2"}},
+ },
+ {
+ query: "a=1&a=2;a=banana",
+ out: Values{"a": []string{"1", "2", "banana"}},
+ },
+}
+
+func TestParseQuery(t *testing.T) {
+ for i, test := range parseTests {
+ form, err := ParseQuery(test.query)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ if len(form) != len(test.out) {
+ t.Errorf("test %d: len(form) = %d, want %d", i, len(form), len(test.out))
+ }
+ for k, evs := range test.out {
+ vs, ok := form[k]
+ if !ok {
+ t.Errorf("test %d: Missing key %q", i, k)
+ continue
+ }
+ if len(vs) != len(evs) {
+ t.Errorf("test %d: len(form[%q]) = %d, want %d", i, k, len(vs), len(evs))
+ continue
+ }
+ for j, ev := range evs {
+ if v := vs[j]; v != ev {
+ t.Errorf("test %d: form[%q][%d] = %q, want %q", i, k, j, v, ev)
+ }
+ }
+ }
+ }
+}
+
+type RequestURITest struct {
+ url *URL
+ out string
+}
+
+var requritests = []RequestURITest{
+ {
+ &URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "",
+ },
+ "/",
+ },
+ {
+ &URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "/a b",
+ },
+ "/a%20b",
+ },
+ {
+ &URL{
+ Scheme: "http",
+ Host: "example.com",
+ Path: "/a b",
+ RawQuery: "q=go+language",
+ },
+ "/a%20b?q=go+language",
+ },
+ {
+ &URL{
+ Scheme: "myschema",
+ Opaque: "opaque",
+ },
+ "opaque",
+ },
+ {
+ &URL{
+ Scheme: "myschema",
+ Opaque: "opaque",
+ RawQuery: "q=go+language",
+ },
+ "opaque?q=go+language",
+ },
+}
+
+func TestRequestURI(t *testing.T) {
+ for _, tt := range requritests {
+ s := tt.url.RequestURI()
+ if s != tt.out {
+ t.Errorf("%#v.RequestURI() == %q (expected %q)", tt.url, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/netchan/Makefile b/src/pkg/netchan/Makefile
deleted file mode 100644
index 9b9fdcf59..000000000
--- a/src/pkg/netchan/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=netchan
-GOFILES=\
- common.go\
- export.go\
- import.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/netchan/common.go b/src/pkg/netchan/common.go
deleted file mode 100644
index ac1ca12f5..000000000
--- a/src/pkg/netchan/common.go
+++ /dev/null
@@ -1,336 +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 netchan
-
-import (
- "gob"
- "io"
- "os"
- "reflect"
- "sync"
- "time"
-)
-
-// The direction of a connection from the client's perspective.
-type Dir int
-
-const (
- Recv Dir = iota
- Send
-)
-
-func (dir Dir) String() string {
- switch dir {
- case Recv:
- return "Recv"
- case Send:
- return "Send"
- }
- return "???"
-}
-
-// Payload types
-const (
- payRequest = iota // request structure follows
- payError // error structure follows
- payData // user payload follows
- payAck // acknowledgement; no payload
- payClosed // channel is now closed
- payAckSend // payload has been delivered.
-)
-
-// A header is sent as a prefix to every transmission. It will be followed by
-// a request structure, an error structure, or an arbitrary user payload structure.
-type header struct {
- Id int
- PayloadType int
- SeqNum int64
-}
-
-// Sent with a header once per channel from importer to exporter to report
-// that it wants to bind to a channel with the specified direction for count
-// messages, with space for size buffered values. If count is -1, it means unlimited.
-type request struct {
- Name string
- Count int64
- Size int
- Dir Dir
-}
-
-// Sent with a header to report an error.
-type error struct {
- Error string
-}
-
-// Used to unify management of acknowledgements for import and export.
-type unackedCounter interface {
- unackedCount() int64
- ack() int64
- seq() int64
-}
-
-// A channel and its direction.
-type chanDir struct {
- ch reflect.Value
- dir Dir
-}
-
-// clientSet contains the objects and methods needed for tracking
-// clients of an exporter and draining outstanding messages.
-type clientSet struct {
- mu sync.Mutex // protects access to channel and client maps
- names map[string]*chanDir
- clients map[unackedCounter]bool
-}
-
-// Mutex-protected encoder and decoder pair.
-type encDec struct {
- decLock sync.Mutex
- dec *gob.Decoder
- encLock sync.Mutex
- enc *gob.Encoder
-}
-
-func newEncDec(conn io.ReadWriter) *encDec {
- return &encDec{
- dec: gob.NewDecoder(conn),
- enc: gob.NewEncoder(conn),
- }
-}
-
-// Decode an item from the connection.
-func (ed *encDec) decode(value reflect.Value) os.Error {
- ed.decLock.Lock()
- err := ed.dec.DecodeValue(value)
- if err != nil {
- // TODO: tear down connection?
- }
- ed.decLock.Unlock()
- return err
-}
-
-// Encode a header and payload onto the connection.
-func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) os.Error {
- ed.encLock.Lock()
- hdr.PayloadType = payloadType
- err := ed.enc.Encode(hdr)
- if err == nil {
- if payload != nil {
- err = ed.enc.Encode(payload)
- }
- }
- if err != nil {
- // TODO: tear down connection if there is an error?
- }
- ed.encLock.Unlock()
- return err
-}
-
-// See the comment for Exporter.Drain.
-func (cs *clientSet) drain(timeout int64) os.Error {
- startTime := time.Nanoseconds()
- for {
- pending := false
- cs.mu.Lock()
- // Any messages waiting for a client?
- for _, chDir := range cs.names {
- if chDir.ch.Len() > 0 {
- pending = true
- }
- }
- // Any unacknowledged messages?
- for client := range cs.clients {
- n := client.unackedCount()
- if n > 0 { // Check for > rather than != just to be safe.
- pending = true
- break
- }
- }
- cs.mu.Unlock()
- if !pending {
- break
- }
- if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.NewError("timeout")
- }
- time.Sleep(100 * 1e6) // 100 milliseconds
- }
- return nil
-}
-
-// See the comment for Exporter.Sync.
-func (cs *clientSet) sync(timeout int64) os.Error {
- startTime := time.Nanoseconds()
- // seq remembers the clients and their seqNum at point of entry.
- seq := make(map[unackedCounter]int64)
- for client := range cs.clients {
- seq[client] = client.seq()
- }
- for {
- pending := false
- cs.mu.Lock()
- // Any unacknowledged messages? Look only at clients that existed
- // when we started and are still in this client set.
- for client := range seq {
- if _, ok := cs.clients[client]; ok {
- if client.ack() < seq[client] {
- pending = true
- break
- }
- }
- }
- cs.mu.Unlock()
- if !pending {
- break
- }
- if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.NewError("timeout")
- }
- time.Sleep(100 * 1e6) // 100 milliseconds
- }
- return nil
-}
-
-// A netChan represents a channel imported or exported
-// on a single connection. Flow is controlled by the receiving
-// side by sending payAckSend messages when values
-// are delivered into the local channel.
-type netChan struct {
- *chanDir
- name string
- id int
- size int // buffer size of channel.
- closed bool
-
- // sender-specific state
- ackCh chan bool // buffered with space for all the acks we need
- space int // available space.
-
- // receiver-specific state
- sendCh chan reflect.Value // buffered channel of values received from other end.
- ed *encDec // so that we can send acks.
- count int64 // number of values still to receive.
-}
-
-// Create a new netChan with the given name (only used for
-// messages), id, direction, buffer size, and count.
-// The connection to the other side is represented by ed.
-func newNetChan(name string, id int, ch *chanDir, ed *encDec, size int, count int64) *netChan {
- c := &netChan{chanDir: ch, name: name, id: id, size: size, ed: ed, count: count}
- if c.dir == Send {
- c.ackCh = make(chan bool, size)
- c.space = size
- }
- return c
-}
-
-// Close the channel.
-func (nch *netChan) close() {
- if nch.closed {
- return
- }
- if nch.dir == Recv {
- if nch.sendCh != nil {
- // If the sender goroutine is active, close the channel to it.
- // It will close nch.ch when it can.
- close(nch.sendCh)
- } else {
- nch.ch.Close()
- }
- } else {
- nch.ch.Close()
- close(nch.ackCh)
- }
- nch.closed = true
-}
-
-// Send message from remote side to local receiver.
-func (nch *netChan) send(val reflect.Value) {
- if nch.dir != Recv {
- panic("send on wrong direction of channel")
- }
- if nch.sendCh == nil {
- // If possible, do local send directly and ack immediately.
- if nch.ch.TrySend(val) {
- nch.sendAck()
- return
- }
- // Start sender goroutine to manage delayed delivery of values.
- nch.sendCh = make(chan reflect.Value, nch.size)
- go nch.sender()
- }
- select {
- case nch.sendCh <- val:
- // ok
- default:
- // TODO: should this be more resilient?
- panic("netchan: remote sender sent more values than allowed")
- }
-}
-
-// sendAck sends an acknowledgment that a message has left
-// the channel's buffer. If the messages remaining to be sent
-// will fit in the channel's buffer, then we don't
-// need to send an ack.
-func (nch *netChan) sendAck() {
- if nch.count < 0 || nch.count > int64(nch.size) {
- nch.ed.encode(&header{Id: nch.id}, payAckSend, nil)
- }
- if nch.count > 0 {
- nch.count--
- }
-}
-
-// The sender process forwards items from the sending queue
-// to the destination channel, acknowledging each item.
-func (nch *netChan) sender() {
- if nch.dir != Recv {
- panic("sender on wrong direction of channel")
- }
- // When Exporter.Hangup is called, the underlying channel is closed,
- // and so we may get a "too many operations on closed channel" error
- // if there are outstanding messages in sendCh.
- // Make sure that this doesn't panic the whole program.
- defer func() {
- if r := recover(); r != nil {
- // TODO check that r is "too many operations", otherwise re-panic.
- }
- }()
- for v := range nch.sendCh {
- nch.ch.Send(v)
- nch.sendAck()
- }
- nch.ch.Close()
-}
-
-// Receive value from local side for sending to remote side.
-func (nch *netChan) recv() (val reflect.Value, ok bool) {
- if nch.dir != Send {
- panic("recv on wrong direction of channel")
- }
-
- if nch.space == 0 {
- // Wait for buffer space.
- <-nch.ackCh
- nch.space++
- }
- nch.space--
- return nch.ch.Recv()
-}
-
-// acked is called when the remote side indicates that
-// a value has been delivered.
-func (nch *netChan) acked() {
- if nch.dir != Send {
- panic("recv on wrong direction of channel")
- }
- select {
- case nch.ackCh <- true:
- // ok
- default:
- // TODO: should this be more resilient?
- panic("netchan: remote receiver sent too many acks")
- }
-}
diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go
deleted file mode 100644
index 7df736515..000000000
--- a/src/pkg/netchan/export.go
+++ /dev/null
@@ -1,400 +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 netchan implements type-safe networked channels:
- it allows the two ends of a channel to appear on different
- computers connected by a network. It does this by transporting
- data sent to a channel on one machine so it can be recovered
- by a receive of a channel of the same type on the other.
-
- An exporter publishes a set of channels by name. An importer
- connects to the exporting machine and imports the channels
- by name. After importing the channels, the two machines can
- use the channels in the usual way.
-
- Networked channels are not synchronized; they always behave
- as if they are buffered channels of at least one element.
-*/
-package netchan
-
-// BUG: can't use range clause to receive when using ImportNValues to limit the count.
-
-import (
- "log"
- "io"
- "net"
- "os"
- "reflect"
- "strconv"
- "sync"
-)
-
-// Export
-
-// expLog is a logging convenience function. The first argument must be a string.
-func expLog(args ...interface{}) {
- args[0] = "netchan export: " + args[0].(string)
- log.Print(args...)
-}
-
-// An Exporter allows a set of channels to be published on a single
-// network port. A single machine may have multiple Exporters
-// but they must use different ports.
-type Exporter struct {
- *clientSet
-}
-
-type expClient struct {
- *encDec
- exp *Exporter
- chans map[int]*netChan // channels in use by client
- mu sync.Mutex // protects remaining fields
- errored bool // client has been sent an error
- seqNum int64 // sequences messages sent to client; has value of highest sent
- ackNum int64 // highest sequence number acknowledged
- seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
-}
-
-func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
- client := new(expClient)
- client.exp = exp
- client.encDec = newEncDec(conn)
- client.seqNum = 0
- client.ackNum = 0
- client.chans = make(map[int]*netChan)
- return client
-}
-
-func (client *expClient) sendError(hdr *header, err string) {
- error := &error{err}
- expLog("sending error to client:", error.Error)
- client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
- client.mu.Lock()
- client.errored = true
- client.mu.Unlock()
-}
-
-func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
- exp := client.exp
- exp.mu.Lock()
- ech, ok := exp.names[name]
- exp.mu.Unlock()
- if !ok {
- client.sendError(hdr, "no such channel: "+name)
- return nil
- }
- if ech.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+name)
- return nil
- }
- nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
- client.chans[hdr.Id] = nch
- return nch
-}
-
-func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
- nch := client.chans[hdr.Id]
- if nch == nil {
- return nil
- }
- if nch.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+nch.name)
- }
- return nch
-}
-
-// The function run manages sends and receives for a single client. For each
-// (client Recv) request, this will launch a serveRecv goroutine to deliver
-// the data for that channel, while (client Send) requests are handled as
-// data arrives from the client.
-func (client *expClient) run() {
- hdr := new(header)
- hdrValue := reflect.ValueOf(hdr)
- req := new(request)
- reqValue := reflect.ValueOf(req)
- error := new(error)
- for {
- *hdr = header{}
- if err := client.decode(hdrValue); err != nil {
- if err != os.EOF {
- expLog("error decoding client header:", err)
- }
- break
- }
- switch hdr.PayloadType {
- case payRequest:
- *req = request{}
- if err := client.decode(reqValue); err != nil {
- expLog("error decoding client request:", err)
- break
- }
- if req.Size < 1 {
- panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
- }
- switch req.Dir {
- case Recv:
- // look up channel before calling serveRecv to
- // avoid a lock around client.chans.
- if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
- go client.serveRecv(nch, *hdr, req.Count)
- }
- case Send:
- client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
- // The actual sends will have payload type payData.
- // TODO: manage the count?
- default:
- error.Error = "request: can't handle channel direction"
- expLog(error.Error, req.Dir)
- client.encode(hdr, payError, error)
- }
- case payData:
- client.serveSend(*hdr)
- case payClosed:
- client.serveClosed(*hdr)
- case payAck:
- client.mu.Lock()
- if client.ackNum != hdr.SeqNum-1 {
- // Since the sequence number is incremented and the message is sent
- // in a single instance of locking client.mu, the messages are guaranteed
- // to be sent in order. Therefore receipt of acknowledgement N means
- // all messages <=N have been seen by the recipient. We check anyway.
- expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
- }
- if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
- client.ackNum = hdr.SeqNum
- }
- client.mu.Unlock()
- case payAckSend:
- if nch := client.getChan(hdr, Send); nch != nil {
- nch.acked()
- }
- default:
- log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
- }
- }
- client.exp.delClient(client)
-}
-
-// Send all the data on a single channel to a client asking for a Recv.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
- for {
- val, ok := nch.recv()
- if !ok {
- if err := client.encode(&hdr, payClosed, nil); err != nil {
- expLog("error encoding server closed message:", err)
- }
- break
- }
- // We hold the lock during transmission to guarantee messages are
- // sent in sequence number order. Also, we increment first so the
- // value of client.SeqNum is the value of the highest used sequence
- // number, not one beyond.
- client.mu.Lock()
- client.seqNum++
- hdr.SeqNum = client.seqNum
- client.seqLock.Lock() // guarantee ordering of messages
- client.mu.Unlock()
- err := client.encode(&hdr, payData, val.Interface())
- client.seqLock.Unlock()
- if err != nil {
- expLog("error encoding client response:", err)
- client.sendError(&hdr, err.String())
- break
- }
- // Negative count means run forever.
- if count >= 0 {
- if count--; count <= 0 {
- break
- }
- }
- }
-}
-
-// Receive and deliver locally one item from a client asking for a Send
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveSend(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- // Create a new value for each received item.
- val := reflect.New(nch.ch.Type().Elem()).Elem()
- if err := client.decode(val); err != nil {
- expLog("value decode:", err, "; type ", nch.ch.Type())
- return
- }
- nch.send(val)
-}
-
-// Report that client has closed the channel that is sending to us.
-// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveClosed(hdr header) {
- nch := client.getChan(&hdr, Recv)
- if nch == nil {
- return
- }
- nch.close()
-}
-
-func (client *expClient) unackedCount() int64 {
- client.mu.Lock()
- n := client.seqNum - client.ackNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) seq() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-func (client *expClient) ack() int64 {
- client.mu.Lock()
- n := client.seqNum
- client.mu.Unlock()
- return n
-}
-
-// Serve waits for incoming connections on the listener
-// and serves the Exporter's channels on each.
-// It blocks until the listener is closed.
-func (exp *Exporter) Serve(listener net.Listener) {
- for {
- conn, err := listener.Accept()
- if err != nil {
- expLog("listen:", err)
- break
- }
- go exp.ServeConn(conn)
- }
-}
-
-// ServeConn exports the Exporter's channels on conn.
-// It blocks until the connection is terminated.
-func (exp *Exporter) ServeConn(conn io.ReadWriter) {
- exp.addClient(conn).run()
-}
-
-// NewExporter creates a new Exporter that exports a set of channels.
-func NewExporter() *Exporter {
- e := &Exporter{
- clientSet: &clientSet{
- names: make(map[string]*chanDir),
- clients: make(map[unackedCounter]bool),
- },
- }
- return e
-}
-
-// ListenAndServe exports the exporter's channels through the
-// given network and local address defined as in net.Listen.
-func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
- listener, err := net.Listen(network, localaddr)
- if err != nil {
- return err
- }
- go exp.Serve(listener)
- return nil
-}
-
-// addClient creates a new expClient and records its existence
-func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
- client := newClient(exp, conn)
- exp.mu.Lock()
- exp.clients[client] = true
- exp.mu.Unlock()
- return client
-}
-
-// delClient forgets the client existed
-func (exp *Exporter) delClient(client *expClient) {
- exp.mu.Lock()
- exp.clients[client] = false, false
- exp.mu.Unlock()
-}
-
-// Drain waits until all messages sent from this exporter/importer, including
-// those not yet sent to any client and possibly including those sent while
-// Drain was executing, have been received by the importer. In short, it
-// waits until all the exporter's messages have been received by a client.
-// If the timeout (measured in nanoseconds) is positive and Drain takes
-// longer than that to complete, an error is returned.
-func (exp *Exporter) Drain(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.drain(timeout)
-}
-
-// Sync waits until all clients of the exporter have received the messages
-// that were sent at the time Sync was invoked. Unlike Drain, it does not
-// wait for messages sent while it is running or messages that have not been
-// dispatched to any client. If the timeout (measured in nanoseconds) is
-// positive and Sync takes longer than that to complete, an error is
-// returned.
-func (exp *Exporter) Sync(timeout int64) os.Error {
- // This wrapper function is here so the method's comment will appear in godoc.
- return exp.clientSet.sync(timeout)
-}
-
-func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
- chanType := reflect.TypeOf(chT)
- if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.NewError("not a channel")
- }
- if dir != Send && dir != Recv {
- return reflect.Value{}, os.NewError("unknown channel direction")
- }
- switch chanType.ChanDir() {
- case reflect.BothDir:
- case reflect.SendDir:
- if dir != Recv {
- return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
- }
- case reflect.RecvDir:
- if dir != Send {
- return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
- }
- }
- return reflect.ValueOf(chT), nil
-}
-
-// Export exports a channel of a given type and specified direction. The
-// channel to be exported is provided in the call and may be of arbitrary
-// channel type.
-// Despite the literal signature, the effective signature is
-// Export(name string, chT chan T, dir Dir)
-func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
- ch, err := checkChan(chT, dir)
- if err != nil {
- return err
- }
- exp.mu.Lock()
- defer exp.mu.Unlock()
- _, present := exp.names[name]
- if present {
- return os.NewError("channel name already being exported:" + name)
- }
- exp.names[name] = &chanDir{ch, dir}
- return nil
-}
-
-// Hangup disassociates the named channel from the Exporter and closes
-// the channel. Messages in flight for the channel may be dropped.
-func (exp *Exporter) Hangup(name string) os.Error {
- exp.mu.Lock()
- chDir, ok := exp.names[name]
- if ok {
- exp.names[name] = nil, false
- }
- // TODO drop all instances of channel from client sets
- exp.mu.Unlock()
- if !ok {
- return os.NewError("netchan export: hangup: no such channel: " + name)
- }
- chDir.ch.Close()
- return nil
-}
diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go
deleted file mode 100644
index ec17d9777..000000000
--- a/src/pkg/netchan/import.go
+++ /dev/null
@@ -1,287 +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 netchan
-
-import (
- "io"
- "log"
- "net"
- "os"
- "reflect"
- "sync"
- "time"
-)
-
-// Import
-
-// impLog is a logging convenience function. The first argument must be a string.
-func impLog(args ...interface{}) {
- args[0] = "netchan import: " + args[0].(string)
- log.Print(args...)
-}
-
-// An Importer allows a set of channels to be imported from a single
-// remote machine/network port. A machine may have multiple
-// importers, even from the same machine/network port.
-type Importer struct {
- *encDec
- chanLock sync.Mutex // protects access to channel map
- names map[string]*netChan
- 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
-// from the given connection. The Exporter must be available and serving when
-// the Importer is created.
-func NewImporter(conn io.ReadWriter) *Importer {
- imp := new(Importer)
- imp.encDec = newEncDec(conn)
- 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
-}
-
-// Import imports a set of channels from the given network and address.
-func Import(network, remoteaddr string) (*Importer, os.Error) {
- conn, err := net.Dial(network, remoteaddr)
- if err != nil {
- return nil, err
- }
- return NewImporter(conn), nil
-}
-
-// shutdown closes all channels for which we are receiving data from the remote side.
-func (imp *Importer) shutdown() {
- imp.chanLock.Lock()
- for _, ich := range imp.chans {
- if ich.dir == Recv {
- ich.close()
- }
- }
- imp.chanLock.Unlock()
-}
-
-// Handle the data from a single imported data stream, which will
-// have the form
-// (response, data)*
-// The response identifies by name which channel is transmitting data.
-func (imp *Importer) run() {
- // Loop on responses; requests are sent by ImportNValues()
- hdr := new(header)
- hdrValue := reflect.ValueOf(hdr)
- ackHdr := new(header)
- err := new(error)
- errValue := reflect.ValueOf(err)
- for {
- *hdr = header{}
- if e := imp.decode(hdrValue); e != nil {
- if e != os.EOF {
- impLog("header:", e)
- imp.shutdown()
- }
- return
- }
- switch hdr.PayloadType {
- case payData:
- // done lower in loop
- case payError:
- if e := imp.decode(errValue); e != nil {
- impLog("error:", e)
- return
- }
- if err.Error != "" {
- impLog("response error:", err.Error)
- select {
- case imp.errors <- os.NewError(err.Error):
- continue // errors are not acknowledged
- default:
- imp.shutdown()
- return
- }
- }
- case payClosed:
- nch := imp.getChan(hdr.Id, false)
- if nch != nil {
- nch.close()
- }
- continue // closes are not acknowledged.
- case payAckSend:
- // we can receive spurious acks if the channel is
- // hung up, so we ask getChan to ignore any errors.
- nch := imp.getChan(hdr.Id, true)
- if nch != nil {
- nch.acked()
- imp.mu.Lock()
- imp.unacked--
- imp.mu.Unlock()
- }
- continue
- default:
- impLog("unexpected payload type:", hdr.PayloadType)
- return
- }
- nch := imp.getChan(hdr.Id, false)
- if nch == nil {
- continue
- }
- if nch.dir != Recv {
- impLog("cannot happen: receive from non-Recv channel")
- return
- }
- // Acknowledge receipt
- ackHdr.Id = hdr.Id
- ackHdr.SeqNum = hdr.SeqNum
- imp.encode(ackHdr, payAck, nil)
- // Create a new value for each received item.
- value := reflect.New(nch.ch.Type().Elem()).Elem()
- if e := imp.decode(value); e != nil {
- impLog("importer value decode:", e)
- return
- }
- nch.send(value)
- }
-}
-
-func (imp *Importer) getChan(id int, errOk bool) *netChan {
- imp.chanLock.Lock()
- ich := imp.chans[id]
- imp.chanLock.Unlock()
- if ich == nil {
- if !errOk {
- impLog("unknown id in netchan request: ", id)
- }
- return nil
- }
- return ich
-}
-
-// Errors returns a channel from which transmission and protocol errors
-// can be read. Clients of the importer are not required to read the error
-// channel for correct execution. However, if too many errors occur
-// without being read from the error channel, the importer will shut down.
-func (imp *Importer) Errors() chan os.Error {
- return imp.errors
-}
-
-// Import imports a channel of the given type, size and specified direction.
-// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
-func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error {
- return imp.ImportNValues(name, chT, dir, size, -1)
-}
-
-// ImportNValues imports a channel of the given type and specified
-// direction and then receives or transmits up to n values on that
-// channel. A value of n==-1 implies an unbounded number of values. The
-// channel will have buffer space for size values, or 1 value if size < 1.
-// The channel to be bound to the remote site's channel is provided
-// in the call and may be of arbitrary channel type.
-// Despite the literal signature, the effective signature is
-// ImportNValues(name string, chT chan T, dir Dir, size, n int) os.Error
-// Example usage:
-// imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
-// if err != nil { log.Fatal(err) }
-// ch := make(chan myType)
-// err = imp.ImportNValues("name", ch, Recv, 1, 1)
-// if err != nil { log.Fatal(err) }
-// fmt.Printf("%+v\n", <-ch)
-func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error {
- ch, err := checkChan(chT, dir)
- if err != nil {
- return err
- }
- imp.chanLock.Lock()
- defer imp.chanLock.Unlock()
- _, present := imp.names[name]
- if present {
- return os.NewError("channel name already being imported:" + name)
- }
- if size < 1 {
- size = 1
- }
- id := imp.maxId
- imp.maxId++
- nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n))
- imp.names[name] = nch
- imp.chans[id] = nch
- // Tell the other side about this channel.
- hdr := &header{Id: id}
- req := &request{Name: name, Count: int64(n), Dir: dir, Size: size}
- if err = imp.encode(hdr, payRequest, req); err != nil {
- impLog("request encode:", err)
- return err
- }
- if dir == Send {
- go func() {
- for i := 0; n == -1 || i < n; i++ {
- val, ok := nch.recv()
- if !ok {
- if err = imp.encode(hdr, payClosed, nil); err != nil {
- impLog("error encoding client closed message:", err)
- }
- 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()
- }
- }()
- }
- return nil
-}
-
-// Hangup disassociates the named channel from the Importer and closes
-// the channel. Messages in flight for the channel may be dropped.
-func (imp *Importer) Hangup(name string) os.Error {
- imp.chanLock.Lock()
- defer imp.chanLock.Unlock()
- nc := imp.names[name]
- if nc == nil {
- 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/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go
deleted file mode 100644
index 8c0f9a6e4..000000000
--- a/src/pkg/netchan/netchan_test.go
+++ /dev/null
@@ -1,435 +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 netchan
-
-import (
- "net"
- "strings"
- "testing"
- "time"
-)
-
-const count = 10 // number of items in most tests
-const closeCount = 5 // number of items when sender closes early
-
-const base = 23
-
-func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
- ch := make(chan int)
- err := exp.Export("exportedSend", ch, Send)
- if err != nil {
- t.Fatal("exportSend:", err)
- }
- go func() {
- for i := 0; i < n; i++ {
- ch <- base + i
- }
- close(ch)
- if done != nil {
- done <- true
- }
- }()
-}
-
-func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
- ch := make(chan int)
- err := exp.Export("exportedRecv", ch, Recv)
- expDone <- true
- if err != nil {
- t.Fatal("exportReceive:", err)
- }
- for i := 0; i < count; i++ {
- v, ok := <-ch
- if !ok {
- if i != closeCount {
- t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
- }
- break
- }
- if v != base+i {
- t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
- }
- }
-}
-
-func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
- ch := make(chan int)
- err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
- if err != nil {
- t.Fatal("importSend:", err)
- }
- go func() {
- for i := 0; i < n; i++ {
- ch <- base + i
- }
- close(ch)
- if done != nil {
- done <- true
- }
- }()
-}
-
-func importReceive(imp *Importer, t *testing.T, done chan bool) {
- ch := make(chan int)
- err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
- if err != nil {
- t.Fatal("importReceive:", err)
- }
- for i := 0; i < count; i++ {
- v, ok := <-ch
- if !ok {
- if i != closeCount {
- t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
- }
- break
- }
- if v != base+i {
- t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
- }
- }
- if done != nil {
- done <- true
- }
-}
-
-func TestExportSendImportReceive(t *testing.T) {
- exp, imp := pair(t)
- exportSend(exp, count, t, nil)
- importReceive(imp, t, nil)
-}
-
-func TestExportReceiveImportSend(t *testing.T) {
- exp, imp := pair(t)
- expDone := make(chan bool)
- done := make(chan bool)
- go func() {
- exportReceive(exp, t, expDone)
- done <- true
- }()
- <-expDone
- importSend(imp, count, t, nil)
- <-done
-}
-
-func TestClosingExportSendImportReceive(t *testing.T) {
- exp, imp := pair(t)
- exportSend(exp, closeCount, t, nil)
- importReceive(imp, t, nil)
-}
-
-func TestClosingImportSendExportReceive(t *testing.T) {
- exp, imp := pair(t)
- expDone := make(chan bool)
- done := make(chan bool)
- go func() {
- exportReceive(exp, t, expDone)
- done <- true
- }()
- <-expDone
- importSend(imp, closeCount, t, nil)
- <-done
-}
-
-func TestErrorForIllegalChannel(t *testing.T) {
- exp, imp := pair(t)
- // Now export a channel.
- ch := make(chan int, 1)
- err := exp.Export("aChannel", ch, Send)
- if err != nil {
- t.Fatal("export:", err)
- }
- ch <- 1234
- close(ch)
- // Now try to import a different channel.
- ch = make(chan int)
- err = imp.Import("notAChannel", ch, Recv, 1)
- if err != nil {
- t.Fatal("import:", err)
- }
- // Expect an error now. Start a timeout.
- timeout := make(chan bool, 1) // buffered so closure will not hang around.
- go func() {
- time.Sleep(10e9) // very long, to give even really slow machines a chance.
- timeout <- true
- }()
- select {
- case err = <-imp.Errors():
- if strings.Index(err.String(), "no such channel") < 0 {
- t.Error("wrong error for nonexistent channel:", err)
- }
- case <-timeout:
- t.Error("import of nonexistent channel did not receive an error")
- }
-}
-
-// Not a great test but it does at least invoke Drain.
-func TestExportDrain(t *testing.T) {
- exp, imp := pair(t)
- done := make(chan bool)
- go func() {
- exportSend(exp, closeCount, t, nil)
- done <- true
- }()
- <-done
- go importReceive(imp, t, done)
- exp.Drain(0)
- <-done
-}
-
-// Not a great test but it does at least invoke 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)
- done := make(chan bool)
- exportSend(exp, closeCount, t, nil)
- go importReceive(imp, t, done)
- exp.Sync(0)
- <-done
-}
-
-// Test hanging up the send side of an export.
-// TODO: test hanging up the receive side of an export.
-func TestExportHangup(t *testing.T) {
- exp, imp := pair(t)
- ech := make(chan int)
- err := exp.Export("exportedSend", ech, Send)
- if err != nil {
- t.Fatal("export:", err)
- }
- // Prepare to receive two values. We'll actually deliver only one.
- ich := make(chan int)
- err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
- if err != nil {
- t.Fatal("import exportedSend:", err)
- }
- // Send one value, receive it.
- const Value = 1234
- ech <- Value
- v := <-ich
- if v != Value {
- t.Fatal("expected", Value, "got", v)
- }
- // Now hang up the channel. Importer should see it close.
- exp.Hangup("exportedSend")
- v, ok := <-ich
- if ok {
- t.Fatal("expected channel to be closed; got value", v)
- }
-}
-
-// Test hanging up the send side of an import.
-// TODO: test hanging up the receive side of an import.
-func TestImportHangup(t *testing.T) {
- exp, imp := pair(t)
- ech := make(chan int)
- err := exp.Export("exportedRecv", ech, Recv)
- if err != nil {
- t.Fatal("export:", err)
- }
- // Prepare to Send two values. We'll actually deliver only one.
- ich := make(chan int)
- err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
- if err != nil {
- t.Fatal("import exportedRecv:", err)
- }
- // Send one value, receive it.
- const Value = 1234
- ich <- Value
- v := <-ech
- if v != Value {
- t.Fatal("expected", Value, "got", v)
- }
- // Now hang up the channel. Exporter should see it close.
- imp.Hangup("exportedRecv")
- v, ok := <-ech
- if ok {
- t.Fatal("expected channel to be closed; got value", v)
- }
-}
-
-// loop back exportedRecv to exportedSend,
-// but receive a value from ctlch before starting the loop.
-func exportLoopback(exp *Exporter, t *testing.T) {
- inch := make(chan int)
- if err := exp.Export("exportedRecv", inch, Recv); err != nil {
- t.Fatal("exportRecv")
- }
-
- outch := make(chan int)
- if err := exp.Export("exportedSend", outch, Send); err != nil {
- t.Fatal("exportSend")
- }
-
- ctlch := make(chan int)
- if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
- t.Fatal("exportRecv")
- }
-
- go func() {
- <-ctlch
- for i := 0; i < count; i++ {
- x := <-inch
- if x != base+i {
- t.Errorf("exportLoopback expected %d; got %d", i, x)
- }
- outch <- x
- }
- }()
-}
-
-// This test checks that channel operations can proceed
-// even when other concurrent operations are blocked.
-func TestIndependentSends(t *testing.T) {
- exp, imp := pair(t)
-
- exportLoopback(exp, t)
-
- importSend(imp, count, t, nil)
- done := make(chan bool)
- go importReceive(imp, t, done)
-
- // wait for export side to try to deliver some values.
- time.Sleep(0.25e9)
-
- ctlch := make(chan int)
- if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
- t.Fatal("importSend:", err)
- }
- ctlch <- 0
-
- <-done
-}
-
-// This test cross-connects a pair of exporter/importer pairs.
-type value struct {
- I int
- Source string
-}
-
-func TestCrossConnect(t *testing.T) {
- e1, i1 := pair(t)
- e2, i2 := pair(t)
-
- crossExport(e1, e2, t)
- crossImport(i1, i2, t)
-}
-
-// Export side of cross-traffic.
-func crossExport(e1, e2 *Exporter, t *testing.T) {
- s := make(chan value)
- err := e1.Export("exportedSend", s, Send)
- if err != nil {
- t.Fatal("exportSend:", err)
- }
-
- r := make(chan value)
- err = e2.Export("exportedReceive", r, Recv)
- if err != nil {
- t.Fatal("exportReceive:", err)
- }
-
- go crossLoop("export", s, r, t)
-}
-
-// Import side of cross-traffic.
-func crossImport(i1, i2 *Importer, t *testing.T) {
- s := make(chan value)
- err := i2.Import("exportedReceive", s, Send, 2)
- if err != nil {
- t.Fatal("import of exportedReceive:", err)
- }
-
- r := make(chan value)
- err = i1.Import("exportedSend", r, Recv, 2)
- if err != nil {
- t.Fatal("import of exported Send:", err)
- }
-
- crossLoop("import", s, r, t)
-}
-
-// Cross-traffic: send and receive 'count' numbers.
-func crossLoop(name string, s, r chan value, t *testing.T) {
- for si, ri := 0, 0; si < count && ri < count; {
- select {
- case s <- value{si, name}:
- si++
- case v := <-r:
- if v.I != ri {
- t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
- }
- ri++
- }
- }
-}
-
-const flowCount = 100
-
-// test flow control from exporter to importer.
-func TestExportFlowControl(t *testing.T) {
- exp, imp := pair(t)
-
- sendDone := make(chan bool, 1)
- exportSend(exp, flowCount, t, sendDone)
-
- ch := make(chan int)
- err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
- if err != nil {
- t.Fatal("importReceive:", err)
- }
-
- testFlow(sendDone, ch, flowCount, t)
-}
-
-// test flow control from importer to exporter.
-func TestImportFlowControl(t *testing.T) {
- exp, imp := pair(t)
-
- ch := make(chan int)
- err := exp.Export("exportedRecv", ch, Recv)
- if err != nil {
- t.Fatal("importReceive:", err)
- }
-
- sendDone := make(chan bool, 1)
- importSend(imp, flowCount, t, sendDone)
- testFlow(sendDone, ch, flowCount, t)
-}
-
-func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
- go func() {
- time.Sleep(0.5e9)
- sendDone <- false
- }()
-
- if <-sendDone {
- t.Fatal("send did not block")
- }
- n := 0
- for i := range ch {
- t.Log("after blocking, got value ", i)
- n++
- }
- if n != N {
- t.Fatalf("expected %d values; got %d", N, n)
- }
-}
-
-func pair(t *testing.T) (*Exporter, *Importer) {
- c0, c1 := net.Pipe()
- exp := NewExporter()
- go exp.ServeConn(c0)
- imp := NewImporter(c1)
- return exp, imp
-}
diff --git a/src/pkg/old/template/Makefile b/src/pkg/old/template/Makefile
deleted file mode 100644
index 5772cb4aa..000000000
--- a/src/pkg/old/template/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../../Make.inc
-
-TARG=old/template
-GOFILES=\
- doc.go\
- execute.go\
- format.go\
- parse.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/old/template/doc.go b/src/pkg/old/template/doc.go
deleted file mode 100644
index e778d801d..000000000
--- a/src/pkg/old/template/doc.go
+++ /dev/null
@@ -1,91 +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 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/src/pkg/old/template/execute.go b/src/pkg/old/template/execute.go
deleted file mode 100644
index 464b620c9..000000000
--- a/src/pkg/old/template/execute.go
+++ /dev/null
@@ -1,346 +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.
-
-// 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/src/pkg/old/template/format.go b/src/pkg/old/template/format.go
deleted file mode 100644
index 9156b0808..000000000
--- a/src/pkg/old/template/format.go
+++ /dev/null
@@ -1,77 +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.
-
-// Template library: default formatters
-
-package template
-
-import (
- "bytes"
- "fmt"
- "io"
-)
-
-// StringFormatter formats into the default string representation.
-// It is stored under the name "str" and is the default formatter.
-// You can override the default formatter by storing your default
-// under the name "" in your custom formatter map.
-func StringFormatter(w io.Writer, format string, value ...interface{}) {
- if len(value) == 1 {
- if b, ok := value[0].([]byte); ok {
- w.Write(b)
- return
- }
- }
- fmt.Fprint(w, value...)
-}
-
-var (
- esc_quot = []byte("&#34;") // shorter than "&quot;"
- esc_apos = []byte("&#39;") // shorter than "&apos;"
- esc_amp = []byte("&amp;")
- esc_lt = []byte("&lt;")
- esc_gt = []byte("&gt;")
-)
-
-// HTMLEscape writes to w the properly escaped HTML equivalent
-// of the plain text data s.
-func HTMLEscape(w io.Writer, s []byte) {
- var esc []byte
- last := 0
- for i, c := range s {
- switch c {
- case '"':
- esc = esc_quot
- case '\'':
- esc = esc_apos
- case '&':
- esc = esc_amp
- case '<':
- esc = esc_lt
- case '>':
- esc = esc_gt
- default:
- continue
- }
- w.Write(s[last:i])
- w.Write(esc)
- last = i + 1
- }
- w.Write(s[last:])
-}
-
-// HTMLFormatter formats arbitrary values for HTML
-func HTMLFormatter(w io.Writer, format string, value ...interface{}) {
- ok := false
- var b []byte
- if len(value) == 1 {
- b, ok = value[0].([]byte)
- }
- if !ok {
- var buf bytes.Buffer
- fmt.Fprint(&buf, value...)
- b = buf.Bytes()
- }
- HTMLEscape(w, b)
-}
diff --git a/src/pkg/old/template/parse.go b/src/pkg/old/template/parse.go
deleted file mode 100644
index dedf9ad8e..000000000
--- a/src/pkg/old/template/parse.go
+++ /dev/null
@@ -1,743 +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.
-
-// Code to parse a template.
-
-package template
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// Errors returned during parsing and execution. Users may extract the information and reformat
-// if they desire.
-type Error struct {
- Line int
- Msg string
-}
-
-func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
-
-// 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{'}'}
-var space = []byte{' '}
-var tab = []byte{'\t'}
-
-// The various types of "tokens", which are plain text or (usually) brace-delimited descriptors
-const (
- tokAlternates = iota
- tokComment
- tokEnd
- tokLiteral
- tokOr
- tokRepeated
- tokSection
- tokText
- tokVariable
-)
-
-// FormatterMap is the type describing the mapping from formatter
-// names to the functions that implement them.
-type FormatterMap map[string]func(io.Writer, string, ...interface{})
-
-// Built-in formatters.
-var builtins = FormatterMap{
- "html": HTMLFormatter,
- "str": StringFormatter,
- "": StringFormatter,
-}
-
-// The parsed state of a template is a vector of xxxElement structs.
-// Sections have line numbers so errors can be reported better during execution.
-
-// Plain text.
-type textElement struct {
- text []byte
-}
-
-// A literal such as .meta-left or .meta-right
-type literalElement struct {
- text []byte
-}
-
-// A variable invocation to be evaluated
-type variableElement struct {
- linenum int
- 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
- field string // cursor field for this block
- start int // first element
- or int // first element of .or block
- end int // one beyond last element
-}
-
-// A .repeated block, possibly with a .or and a .alternates
-type repeatedElement struct {
- sectionElement // It has the same structure...
- altstart int // ... except for alternates
- altend int
-}
-
-// Template is the type that represents a template definition.
-// It is unchanged after parsing.
-type Template struct {
- fmap FormatterMap // formatters for variables
- // Used during parsing:
- ldelim, rdelim []byte // delimiters; default {}
- buf []byte // input text to process
- p int // position in buf
- linenum int // position in input
- // Parsed results:
- elems []interface{}
-}
-
-// New creates a new template with the specified formatter map (which
-// may be nil) to define auxiliary functions for formatting variables.
-func New(fmap FormatterMap) *Template {
- t := new(Template)
- t.fmap = fmap
- t.ldelim = lbrace
- t.rdelim = rbrace
- t.elems = make([]interface{}, 0, 16)
- return t
-}
-
-// Report error and stop executing. The line number must be provided explicitly.
-func (t *Template) execError(st *state, line int, err string, args ...interface{}) {
- panic(&Error{line, fmt.Sprintf(err, args...)})
-}
-
-// Report error, panic to terminate parsing.
-// The line number comes from the template state.
-func (t *Template) parseError(err string, args ...interface{}) {
- panic(&Error{t.linenum, fmt.Sprintf(err, args...)})
-}
-
-// Is this an exported - upper case - name?
-func isExported(name string) bool {
- rune, _ := utf8.DecodeRuneInString(name)
- return unicode.IsUpper(rune)
-}
-
-// -- Lexical analysis
-
-// Is c a 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 {
- b := s[n:]
- if len(t) > len(b) { // not enough space left for a match.
- return false
- }
- for i, c := range t {
- if c != b[i] {
- return false
- }
- }
- return true
-}
-
-// 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
-// strings. Tokens stop at (but include, if plain text) a newline.
-// Action tokens on a line by themselves drop any space on
-// either side, up to and including the newline.
-func (t *Template) nextItem() []byte {
- startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
- start := t.p
- var i int
- newline := func() {
- t.linenum++
- i++
- }
- // Leading space up to but not including newline
- for i = start; i < len(t.buf); i++ {
- if t.buf[i] == '\n' || !isSpace(t.buf[i]) {
- break
- }
- }
- leadingSpace := i > start
- // What's left is nothing, newline, delimited string, or plain text
- switch {
- case i == len(t.buf):
- // EOF; nothing to do
- case t.buf[i] == '\n':
- newline()
- case equal(t.buf, i, t.ldelim):
- left := i // Start of left delimiter.
- right := -1 // Will be (immediately after) right delimiter.
- haveText := false // Delimiters contain text.
- i += len(t.ldelim)
- // Find the end of the action.
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- break
- }
- if 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
- break
- }
- haveText = true
- }
- if right < 0 {
- t.parseError("unmatched opening delimiter")
- return nil
- }
- // Is this a special action (starts with '.' or '#') and the only thing on the line?
- if startOfLine && haveText {
- firstChar := t.buf[left+len(t.ldelim)]
- if firstChar == '.' || firstChar == '#' {
- // It's special and the first thing on the line. Is it the last?
- for j := right; j < len(t.buf) && isSpace(t.buf[j]); j++ {
- if t.buf[j] == '\n' {
- // Yes it is. Drop the surrounding space and return the {.foo}
- t.linenum++
- t.p = j + 1
- return t.buf[left:right]
- }
- }
- }
- }
- // No it's not. If there's leading space, return that.
- if leadingSpace {
- // not trimming space: return leading space if there is some.
- t.p = left
- return t.buf[start:left]
- }
- // Return the word, leave the trailing space.
- start = left
- break
- default:
- for ; i < len(t.buf); i++ {
- if t.buf[i] == '\n' {
- newline()
- break
- }
- if equal(t.buf, i, t.ldelim) {
- break
- }
- }
- }
- item := t.buf[start:i]
- t.p = i
- return item
-}
-
-// Turn a byte array into a space-split array of strings,
-// taking into account quoted strings.
-func words(buf []byte) []string {
- s := make([]string, 0, 5)
- for i := 0; i < len(buf); {
- // One word per loop
- for i < len(buf) && isSpace(buf[i]) {
- i++
- }
- if i == len(buf) {
- break
- }
- // 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
-}
-
-// Analyze an item and return its token type and, if it's an action item, an array of
-// its constituent words.
-func (t *Template) analyze(item []byte) (tok int, w []string) {
- // item is known to be non-empty
- if !equal(item, 0, t.ldelim) { // doesn't start with left delimiter
- tok = tokText
- return
- }
- if !equal(item, len(item)-len(t.rdelim), t.rdelim) { // doesn't end with right delimiter
- t.parseError("internal error: unmatched opening delimiter") // lexing should prevent this
- return
- }
- if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents
- t.parseError("empty directive")
- return
- }
- // Comment
- if item[len(t.ldelim)] == '#' {
- tok = tokComment
- return
- }
- // Split into words
- w = words(item[len(t.ldelim) : len(item)-len(t.rdelim)]) // drop final delimiter
- if len(w) == 0 {
- t.parseError("empty directive")
- return
- }
- 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 first {
- case ".meta-left", ".meta-right", ".space", ".tab":
- tok = tokLiteral
- return
- case ".or":
- tok = tokOr
- return
- case ".end":
- tok = tokEnd
- return
- case ".section":
- if len(w) != 2 {
- t.parseError("incorrect fields for .section: %s", item)
- return
- }
- tok = tokSection
- return
- case ".repeated":
- if len(w) != 3 || w[1] != "section" {
- t.parseError("incorrect fields for .repeated: %s", item)
- return
- }
- tok = tokRepeated
- return
- case ".alternates":
- if len(w) != 2 || w[1] != "with" {
- t.parseError("incorrect fields for .alternates: %s", item)
- return
- }
- tok = tokAlternates
- return
- }
- t.parseError("bad directive: %s", item)
- return
-}
-
-// formatter returns the Formatter with the given name in the Template, or nil if none exists.
-func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}) {
- if t.fmap != nil {
- if fn := t.fmap[name]; fn != nil {
- return fn
- }
- }
- return builtins[name]
-}
-
-// -- Parsing
-
-// newVariable allocates a new variable-evaluation element.
-func (t *Template) newVariable(words []string) *variableElement {
- 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
- }
-
- 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,
- // but it's more dynamic to let the user change the map contents underfoot.
- // We do require the name to be present, though.
-
- // Is it in user-supplied map?
- for _, f := range formatters {
- if t.formatter(f) == nil {
- t.parseError("unknown formatter: %q", f)
- }
- }
-
- 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.
-// Otherwise return its details.
-func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
- tok, w = t.analyze(item)
- done = true // assume for simplicity
- switch tok {
- case tokComment:
- return
- case tokText:
- t.elems = append(t.elems, &textElement{item})
- return
- case tokLiteral:
- switch w[0] {
- case ".meta-left":
- t.elems = append(t.elems, &literalElement{t.ldelim})
- case ".meta-right":
- t.elems = append(t.elems, &literalElement{t.rdelim})
- case ".space":
- t.elems = append(t.elems, &literalElement{space})
- case ".tab":
- t.elems = append(t.elems, &literalElement{tab})
- default:
- t.parseError("internal error: unknown literal: %s", w[0])
- }
- return
- case tokVariable:
- t.elems = append(t.elems, t.newVariable(w))
- return
- }
- return false, tok, w
-}
-
-// parseRepeated and parseSection are mutually recursive
-
-func (t *Template) parseRepeated(words []string) *repeatedElement {
- r := new(repeatedElement)
- t.elems = append(t.elems, r)
- r.linenum = t.linenum
- r.field = words[2]
- // Scan section, collecting true and false (.or) blocks.
- r.start = len(t.elems)
- r.or = -1
- r.altstart = -1
- r.altend = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .repeated section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if r.or >= 0 {
- t.parseError("extra .or in .repeated section")
- break Loop
- }
- r.altend = len(t.elems)
- r.or = len(t.elems)
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- if r.altstart >= 0 {
- t.parseError("extra .alternates in .repeated section")
- break Loop
- }
- if r.or >= 0 {
- t.parseError(".alternates inside .or block in .repeated section")
- break Loop
- }
- r.altstart = len(t.elems)
- default:
- t.parseError("internal error: unknown repeated section item: %s", item)
- break Loop
- }
- }
- if r.altend < 0 {
- r.altend = len(t.elems)
- }
- r.end = len(t.elems)
- return r
-}
-
-func (t *Template) parseSection(words []string) *sectionElement {
- s := new(sectionElement)
- t.elems = append(t.elems, s)
- s.linenum = t.linenum
- s.field = words[1]
- // Scan section, collecting true and false (.or) blocks.
- s.start = len(t.elems)
- s.or = -1
-Loop:
- for {
- item := t.nextItem()
- if len(item) == 0 {
- t.parseError("missing .end for .section")
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokEnd:
- break Loop
- case tokOr:
- if s.or >= 0 {
- t.parseError("extra .or in .section")
- break Loop
- }
- s.or = len(t.elems)
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- case tokAlternates:
- t.parseError(".alternates not in .repeated")
- default:
- t.parseError("internal error: unknown section item: %s", item)
- }
- }
- s.end = len(t.elems)
- return s
-}
-
-func (t *Template) parse() {
- for {
- item := t.nextItem()
- if len(item) == 0 {
- break
- }
- done, tok, w := t.parseSimple(item)
- if done {
- continue
- }
- switch tok {
- case tokOr, tokEnd, tokAlternates:
- t.parseError("unexpected %s", w[0])
- case tokSection:
- t.parseSection(w)
- case tokRepeated:
- t.parseRepeated(w)
- default:
- t.parseError("internal error: bad directive in parse: %s", item)
- }
- }
-}
-
-// -- Execution
-
-// -- Public interface
-
-// Parse initializes a Template by parsing its definition. The string
-// s contains the template text. If any errors occur, Parse returns
-// the error.
-func (t *Template) Parse(s string) (err os.Error) {
- if t.elems == nil {
- return &Error{1, "template not allocated with New"}
- }
- if !validDelim(t.ldelim) || !validDelim(t.rdelim) {
- return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)}
- }
- defer checkError(&err)
- t.buf = []byte(s)
- t.p = 0
- t.linenum = 1
- t.parse()
- return nil
-}
-
-// ParseFile is like Parse but reads the template definition from the
-// named file.
-func (t *Template) ParseFile(filename string) (err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return err
- }
- return t.Parse(string(b))
-}
-
-// Execute applies a parsed template to the specified data object,
-// generating output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
- // Extract the driver data.
- val := reflect.ValueOf(data)
- defer checkError(&err)
- t.p = 0
- t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
- return nil
-}
-
-// SetDelims sets the left and right delimiters for operations in the
-// template. They are validated during parsing. They could be
-// validated here but it's better to keep the routine simple. The
-// delimiters are very rarely invalid and Parse has the necessary
-// error-handling interface already.
-func (t *Template) SetDelims(left, right string) {
- t.ldelim = []byte(left)
- t.rdelim = []byte(right)
-}
-
-// Parse creates a Template with default parameters (such as {} for
-// metacharacters). The string s contains the template text while
-// the formatter map fmap, which may be nil, defines auxiliary functions
-// for formatting variables. The template is returned. If any errors
-// occur, err will be non-nil.
-func Parse(s string, fmap FormatterMap) (t *Template, err os.Error) {
- t = New(fmap)
- err = t.Parse(s)
- if err != nil {
- t = nil
- }
- return
-}
-
-// ParseFile is a wrapper function that creates a Template with default
-// parameters (such as {} for metacharacters). The filename identifies
-// a file containing the template text, while the formatter map fmap, which
-// may be nil, defines auxiliary functions for formatting variables.
-// The template is returned. If any errors occur, err will be non-nil.
-func ParseFile(filename string, fmap FormatterMap) (t *Template, err os.Error) {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return Parse(string(b), fmap)
-}
-
-// MustParse is like Parse but panics if the template cannot be parsed.
-func MustParse(s string, fmap FormatterMap) *Template {
- t, err := Parse(s, fmap)
- if err != nil {
- panic("template.MustParse error: " + err.String())
- }
- return t
-}
-
-// MustParseFile is like ParseFile but panics if the file cannot be read
-// or the template cannot be parsed.
-func MustParseFile(filename string, fmap FormatterMap) *Template {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
- panic("template.MustParseFile error: " + err.String())
- }
- return MustParse(string(b), fmap)
-}
diff --git a/src/pkg/old/template/template_test.go b/src/pkg/old/template/template_test.go
deleted file mode 100644
index eae8011eb..000000000
--- a/src/pkg/old/template/template_test.go
+++ /dev/null
@@ -1,804 +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 template
-
-import (
- "bytes"
- "container/vector"
- "fmt"
- "io"
- "io/ioutil"
- "json"
- "os"
- "strings"
- "testing"
-)
-
-type Test struct {
- in, out, err string
-}
-
-type T struct {
- Item string
- Value string
-}
-
-type U struct {
- Mp map[string]int
-}
-
-type S struct {
- Header string
- HeaderPtr *string
- Integer int
- IntegerPtr *int
- NilPtr *int
- InnerT T
- InnerPointerT *T
- Data []T
- Pdata []*T
- Empty []*T
- Emptystring string
- Null []*T
- Vec *vector.Vector
- True bool
- False bool
- Mp map[string]string
- JSON interface{}
- Innermap U
- Stringmap map[string]string
- Ptrmap map[string]*string
- Iface interface{}
- Ifaceptr interface{}
-}
-
-func (s *S) PointerMethod() string { return "ptrmethod!" }
-
-func (s S) ValueMethod() string { return "valmethod!" }
-
-var t1 = T{"ItemNumber1", "ValueNumber1"}
-var t2 = T{"ItemNumber2", "ValueNumber2"}
-
-func uppercase(v interface{}) string {
- s := v.(string)
- t := ""
- for i := 0; i < len(s); i++ {
- c := s[i]
- if 'a' <= c && c <= 'z' {
- c = c + 'A' - 'a'
- }
- t += string(c)
- }
- return t
-}
-
-func plus1(v interface{}) string {
- i := v.(int)
- return fmt.Sprint(i + 1)
-}
-
-func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
- return func(w io.Writer, format string, v ...interface{}) {
- if len(v) != 1 {
- panic("test writer expected one arg")
- }
- io.WriteString(w, f(v[0]))
- }
-}
-
-func multiword(w io.Writer, format string, value ...interface{}) {
- for _, v := range value {
- fmt.Fprintf(w, "<%v>", v)
- }
-}
-
-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{
- // Simple
- &Test{"", "", ""},
- &Test{"abc", "abc", ""},
- &Test{"abc\ndef\n", "abc\ndef\n", ""},
- &Test{" {.meta-left} \n", "{", ""},
- &Test{" {.meta-right} \n", "}", ""},
- &Test{" {.space} \n", " ", ""},
- &Test{" {.tab} \n", "\t", ""},
- &Test{" {#comment} \n", "", ""},
- &Test{"\tSome Text\t\n", "\tSome Text\t\n", ""},
- &Test{" {.meta-right} {.meta-right} {.meta-right} \n", " } } } \n", ""},
-
- // Variables at top level
- &Test{
- in: "{Header}={Integer}\n",
-
- out: "Header=77\n",
- },
-
- &Test{
- in: "Pointers: {*HeaderPtr}={*IntegerPtr}\n",
-
- out: "Pointers: Header=77\n",
- },
-
- &Test{
- in: "Stars but not pointers: {*Header}={*Integer}\n",
-
- out: "Stars but not pointers: Header=77\n",
- },
-
- &Test{
- in: "nil pointer: {*NilPtr}={*Integer}\n",
-
- 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",
-
- out: "ptrmethod=ptrmethod!\n",
- },
-
- &Test{
- in: "valmethod={ValueMethod}\n",
-
- out: "valmethod=valmethod!\n",
- },
-
- // Section
- &Test{
- in: "{.section Data }\n" +
- "some text for the section\n" +
- "{.end}\n",
-
- out: "some text for the section\n",
- },
- &Test{
- in: "{.section Data }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n",
-
- out: "Header=77\n",
- },
- &Test{
- in: "{.section Pdata }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n",
-
- out: "Header=77\n",
- },
- &Test{
- in: "{.section Pdata }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data present\n",
- },
- &Test{
- in: "{.section Empty }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data not present\n",
- },
- &Test{
- in: "{.section Null }\n" +
- "data present\n" +
- "{.or}\n" +
- "data not present\n" +
- "{.end}\n",
-
- out: "data not present\n",
- },
- &Test{
- in: "{.section Pdata }\n" +
- "{Header}={Integer}\n" +
- "{.section @ }\n" +
- "{Header}={Integer}\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "Header=77\n" +
- "Header=77\n",
- },
-
- &Test{
- in: "{.section Data}{.end} {Header}\n",
-
- out: " Header\n",
- },
-
- &Test{
- in: "{.section Integer}{@}{.end}",
-
- out: "77",
- },
-
- // Repeated
- &Test{
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- &Test{
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.or}\n" +
- "this should not appear\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- &Test{
- in: "{.section @ }\n" +
- "{.repeated section Empty }\n" +
- "{Item}={Value}\n" +
- "{.or}\n" +
- "this should appear: empty field\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "this should appear: empty field\n",
- },
- &Test{
- in: "{.repeated section Pdata }\n" +
- "{Item}\n" +
- "{.alternates with}\n" +
- "is\nover\nmultiple\nlines\n" +
- "{.end}\n",
-
- out: "ItemNumber1\n" +
- "is\nover\nmultiple\nlines\n" +
- "ItemNumber2\n",
- },
- &Test{
- in: "{.repeated section Pdata }\n" +
- "{Item}\n" +
- "{.alternates with}\n" +
- "is\nover\nmultiple\nlines\n" +
- " {.end}\n",
-
- out: "ItemNumber1\n" +
- "is\nover\nmultiple\nlines\n" +
- "ItemNumber2\n",
- },
- &Test{
- in: "{.section Pdata }\n" +
- "{.repeated section @ }\n" +
- "{Item}={Value}\n" +
- "{.alternates with}DIVIDER\n" +
- "{.or}\n" +
- "this should not appear\n" +
- "{.end}\n" +
- "{.end}\n",
-
- out: "ItemNumber1=ValueNumber1\n" +
- "DIVIDER\n" +
- "ItemNumber2=ValueNumber2\n",
- },
- &Test{
- in: "{.repeated section Vec }\n" +
- "{@}\n" +
- "{.end}\n",
-
- out: "elt1\n" +
- "elt2\n",
- },
- // Same but with a space before {.end}: was a bug.
- &Test{
- in: "{.repeated section Vec }\n" +
- "{@} {.end}\n",
-
- out: "elt1 elt2 \n",
- },
- &Test{
- in: "{.repeated section Integer}{.end}",
-
- err: "line 1: .repeated: cannot repeat Integer (type int)",
- },
-
- // Nested names
- &Test{
- in: "{.section @ }\n" +
- "{InnerT.Item}={InnerT.Value}\n" +
- "{.end}",
-
- out: "ItemNumber1=ValueNumber1\n",
- },
- &Test{
- in: "{.section @ }\n" +
- "{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
- "{.end}",
-
- out: "ItemNumber1=ValueNumber1\n",
- },
-
- &Test{
- in: "{.section Emptystring}emptystring{.end}\n" +
- "{.section Header}header{.end}\n",
-
- out: "\nheader\n",
- },
-
- &Test{
- in: "{.section True}1{.or}2{.end}\n" +
- "{.section False}3{.or}4{.end}\n",
-
- out: "1\n4\n",
- },
-
- // Maps
-
- &Test{
- in: "{Mp.mapkey}\n",
-
- out: "Ahoy!\n",
- },
- &Test{
- in: "{Innermap.Mp.innerkey}\n",
-
- out: "55\n",
- },
- &Test{
- in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
-
- out: "55\n",
- },
- &Test{
- in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
-
- out: "1234\n",
- },
- &Test{
- in: "{Stringmap.stringkey1}\n",
-
- out: "stringresult\n",
- },
- &Test{
- in: "{.repeated section Stringmap}\n" +
- "{@}\n" +
- "{.end}",
-
- out: "stringresult\n" +
- "stringresult\n",
- },
- &Test{
- in: "{.repeated section Stringmap}\n" +
- "\t{@}\n" +
- "{.end}",
-
- out: "\tstringresult\n" +
- "\tstringresult\n",
- },
- &Test{
- in: "{*Ptrmap.stringkey1}\n",
-
- out: "pointedToString\n",
- },
- &Test{
- in: "{.repeated section Ptrmap}\n" +
- "{*@}\n" +
- "{.end}",
-
- out: "pointedToString\n" +
- "pointedToString\n",
- },
-
- // Interface values
-
- &Test{
- in: "{Iface}",
-
- out: "[1 2 3]",
- },
- &Test{
- in: "{.repeated section Iface}{@}{.alternates with} {.end}",
-
- out: "1 2 3",
- },
- &Test{
- in: "{.section Iface}{@}{.end}",
-
- out: "[1 2 3]",
- },
- &Test{
- in: "{.section Ifaceptr}{Item} {Value}{.end}",
-
- out: "Item Value",
- },
-}
-
-func TestAll(t *testing.T) {
- // Parse
- testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
- // ParseFile
- testAll(t, func(test *Test) (*Template, os.Error) {
- err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
- if err != nil {
- t.Error("unexpected write error:", err)
- return nil, err
- }
- return ParseFile("_test/test.tmpl", formatters)
- })
- // tmpl.ParseFile
- testAll(t, func(test *Test) (*Template, os.Error) {
- err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
- if err != nil {
- t.Error("unexpected write error:", err)
- return nil, err
- }
- tmpl := New(formatters)
- return tmpl, tmpl.ParseFile("_test/test.tmpl")
- })
-}
-
-func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
- s := new(S)
- // initialized by hand for clarity.
- s.Header = "Header"
- s.HeaderPtr = &s.Header
- s.Integer = 77
- s.IntegerPtr = &s.Integer
- s.InnerT = t1
- s.Data = []T{t1, t2}
- s.Pdata = []*T{&t1, &t2}
- s.Empty = []*T{}
- s.Null = nil
- s.Vec = new(vector.Vector)
- s.Vec.Push("elt1")
- s.Vec.Push("elt2")
- s.True = true
- s.False = false
- s.Mp = make(map[string]string)
- s.Mp["mapkey"] = "Ahoy!"
- json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON)
- s.Innermap.Mp = make(map[string]int)
- s.Innermap.Mp["innerkey"] = 55
- s.Stringmap = make(map[string]string)
- s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
- s.Stringmap["stringkey2"] = "stringresult"
- s.Ptrmap = make(map[string]*string)
- x := "pointedToString"
- s.Ptrmap["stringkey1"] = &x // the same value so repeated section is order-independent
- s.Ptrmap["stringkey2"] = &x
- s.Iface = []int{1, 2, 3}
- s.Ifaceptr = &T{"Item", "Value"}
-
- var buf bytes.Buffer
- for _, test := range tests {
- buf.Reset()
- tmpl, err := parseFunc(test)
- if err != nil {
- t.Error("unexpected parse error: ", err)
- continue
- }
- err = tmpl.Execute(&buf, s)
- if test.err == "" {
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- } else {
- if err == nil {
- t.Errorf("expected execute error %q, got nil", test.err)
- } else if err.String() != test.err {
- t.Errorf("expected execute error %q, got %q", test.err, err.String())
- }
- }
- if buf.String() != test.out {
- t.Errorf("for %q: expected %q got %q", test.in, test.out, buf.String())
- }
- }
-}
-
-func TestMapDriverType(t *testing.T) {
- mp := map[string]string{"footer": "Ahoy!"}
- tmpl, err := Parse("template: {footer}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, mp)
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: Ahoy!"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestMapNoEntry(t *testing.T) {
- mp := make(map[string]int)
- tmpl, err := Parse("template: {notthere}!", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, mp)
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: 0!"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestStringDriverType(t *testing.T) {
- tmpl, err := Parse("template: {@}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected execute error:", err)
- }
- s := b.String()
- expect := "template: hello"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestTwice(t *testing.T) {
- tmpl, err := Parse("template: {@}", nil)
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- s := b.String()
- expect := "template: hello"
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
- err = tmpl.Execute(&b, "hello")
- if err != nil {
- t.Error("unexpected parse error:", err)
- }
- s = b.String()
- expect += expect
- if s != expect {
- t.Errorf("failed passing string as data: expected %q got %q", expect, s)
- }
-}
-
-func TestCustomDelims(t *testing.T) {
- // try various lengths. zero should catch error.
- for i := 0; i < 7; i++ {
- for j := 0; j < 7; j++ {
- tmpl := New(nil)
- // first two chars deliberately the same to test equal left and right delims
- ldelim := "$!#$%^&"[0:i]
- rdelim := "$*&^%$!"[0:j]
- tmpl.SetDelims(ldelim, rdelim)
- // if braces, this would be template: {@}{.meta-left}{.meta-right}
- text := "template: " +
- ldelim + "@" + rdelim +
- ldelim + ".meta-left" + rdelim +
- ldelim + ".meta-right" + rdelim
- err := tmpl.Parse(text)
- if err != nil {
- if i == 0 || j == 0 { // expected
- continue
- }
- t.Error("unexpected parse error:", err)
- } else if i == 0 || j == 0 {
- t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim)
- continue
- }
- var b bytes.Buffer
- err = tmpl.Execute(&b, "hello")
- s := b.String()
- if s != "template: hello"+ldelim+rdelim {
- t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s)
- }
- }
- }
-}
-
-// Test that a variable evaluates to the field itself and does not further indirection
-func TestVarIndirection(t *testing.T) {
- s := new(S)
- // initialized by hand for clarity.
- s.InnerPointerT = &t1
-
- var buf bytes.Buffer
- input := "{.section @}{InnerPointerT}{.end}"
- tmpl, err := Parse(input, nil)
- if err != nil {
- t.Fatal("unexpected parse error:", err)
- }
- err = tmpl.Execute(&buf, s)
- if err != nil {
- t.Fatal("unexpected execute error:", err)
- }
- expect := fmt.Sprintf("%v", &t1) // output should be hex address of t1
- if buf.String() != expect {
- t.Errorf("for %q: expected %q got %q", input, expect, buf.String())
- }
-}
-
-func TestHTMLFormatterWithByte(t *testing.T) {
- s := "Test string."
- b := []byte(s)
- var buf bytes.Buffer
- HTMLFormatter(&buf, "", b)
- bs := buf.String()
- if bs != s {
- t.Errorf("munged []byte, expected: %s got: %s", s, bs)
- }
-}
-
-type UF struct {
- I int
- s string
-}
-
-func TestReferenceToUnexported(t *testing.T) {
- u := &UF{3, "hello"}
- var buf bytes.Buffer
- input := "{.section @}{I}{s}{.end}"
- tmpl, err := Parse(input, nil)
- if err != nil {
- t.Fatal("unexpected parse error:", err)
- }
- err = tmpl.Execute(&buf, u)
- if err == nil {
- t.Fatal("expected execute error, got none")
- }
- if strings.Index(err.String(), "not exported") < 0 {
- t.Fatal("expected unexported error; got", err)
- }
-}
-
-var formatterTests = []Test{
- {
- in: "{Header|uppercase}={Integer|+1}\n" +
- "{Header|html}={Integer|str}\n",
-
- out: "HEADER=78\n" +
- "Header=77\n",
- },
-
- {
- in: "{Header|uppercase}={Integer Header|multiword}\n" +
- "{Header|html}={Header Integer|multiword}\n" +
- "{Header|html}={Header Integer}\n",
-
- out: "HEADER=<77><Header>\n" +
- "Header=<Header><77>\n" +
- "Header=Header77\n",
- },
- {
- in: "{Raw}\n" +
- "{Raw|html}\n",
-
- out: "a <&> b\n" +
- "a &lt;&amp;&gt; b\n",
- },
- {
- in: "{Bytes}",
- out: "hello",
- },
- {
- in: "{Raw|uppercase|html|html}",
- out: "A &amp;lt;&amp;amp;&amp;gt; B",
- },
- {
- in: "{Header Integer|multiword|html}",
- out: "&lt;Header&gt;&lt;77&gt;",
- },
- {
- in: "{Integer|no_formatter|html}",
- err: `unknown formatter: "no_formatter"`,
- },
- {
- 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) {
- data := map[string]interface{}{
- "Header": "Header",
- "Integer": 77,
- "Raw": "a <&> b",
- "Bytes": []byte("hello"),
- }
- for _, c := range formatterTests {
- tmpl, err := Parse(c.in, formatters)
- if err != nil {
- if c.err == "" {
- t.Error("unexpected parse error:", err)
- continue
- }
- if strings.Index(err.String(), c.err) < 0 {
- t.Errorf("unexpected error: expected %q, got %q", c.err, err.String())
- continue
- }
- } else {
- if c.err != "" {
- t.Errorf("For %q, expected error, got none.", c.in)
- continue
- }
- buf := bytes.NewBuffer(nil)
- err = tmpl.Execute(buf, data)
- if err != nil {
- t.Error("unexpected Execute error: ", err)
- continue
- }
- actual := buf.String()
- if actual != c.out {
- t.Errorf("for %q: expected %q but got %q.", c.in, c.out, actual)
- }
- }
- }
-}
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
deleted file mode 100644
index 8923a8b48..000000000
--- a/src/pkg/os/Makefile
+++ /dev/null
@@ -1,100 +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.
-
-include ../../Make.inc
-
-TARG=os
-GOFILES=\
- error.go\
- env.go\
- exec.go\
- file.go\
- getwd.go\
- path.go\
- proc.go\
- stat_$(GOOS).go\
- time.go\
- types.go\
-
-GOFILES_freebsd=\
- dir_unix.go\
- error_posix.go\
- env_unix.go\
- file_posix.go\
- file_unix.go\
- path_unix.go\
- sys_bsd.go\
- exec_posix.go\
- exec_unix.go\
- signal_unix.go\
-
-GOFILES_darwin=\
- dir_unix.go\
- error_posix.go\
- env_unix.go\
- file_posix.go\
- file_unix.go\
- path_unix.go\
- sys_bsd.go\
- exec_posix.go\
- exec_unix.go\
- signal_unix.go\
-
-GOFILES_linux=\
- dir_unix.go\
- error_posix.go\
- env_unix.go\
- file_posix.go\
- file_unix.go\
- path_unix.go\
- sys_linux.go\
- exec_posix.go\
- exec_unix.go\
- signal_unix.go\
-
-GOFILES_openbsd=\
- dir_unix.go\
- error_posix.go\
- env_unix.go\
- file_posix.go\
- file_unix.go\
- path_unix.go\
- sys_bsd.go\
- exec_posix.go\
- exec_unix.go\
- signal_unix.go\
-
-GOFILES_windows=\
- dir_windows.go\
- error_posix.go\
- env_windows.go\
- file_posix.go\
- file_windows.go\
- path_windows.go\
- sys_windows.go\
- exec_posix.go\
- exec_windows.go\
- signal_windows.go\
-
-GOFILES_plan9=\
- dir_plan9.go\
- error_plan9.go\
- env_plan9.go\
- file_plan9.go\
- path_plan9.go\
- sys_plan9.go\
- exec_plan9.go\
- str.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-CLEANFILES+=signal_unix.go signal_windows.go
-
-include ../../Make.pkg
-
-signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go
- ./mkunixsignals.sh $< > $@ || rm -f $@
-
-signal_windows.go: ../syscall/ztypes_$(GOOS).go
- ./mkunixsignals.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/dir_plan9.go b/src/pkg/os/dir_plan9.go
index bbc2cb647..7fa4c7f44 100644
--- a/src/pkg/os/dir_plan9.go
+++ b/src/pkg/os/dir_plan9.go
@@ -5,25 +5,15 @@
package os
import (
+ "errors"
+ "io"
"syscall"
)
-// Readdir reads the contents of the directory associated with file and
-// 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) {
+var errShortStat = errors.New("short stat message")
+var errBadStat = errors.New("bad stat message format")
+
+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)
@@ -39,16 +29,16 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
- var e Error
+ var e error
d.nbuf, e = file.Read(d.buf[:])
- if e != nil && e != EOF {
+ if e != nil && e != io.EOF {
return result, &PathError{"readdir", file.name, e}
}
- if e == EOF {
+ if e == io.EOF {
break
}
if d.nbuf < syscall.STATFIXLEN {
- return result, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, errShortStat}
}
}
@@ -56,43 +46,29 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
m, _ := gbit16(d.buf[d.bufp:])
m += 2
if m < syscall.STATFIXLEN {
- return result, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, errShortStat}
}
dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
if e != nil {
return result, &PathError{"readdir", file.name, e}
}
- var f FileInfo
- fileInfoFromStat(&f, dir)
- result = append(result, f)
+ result = append(result, fileInfoFromStat(dir))
d.bufp += int(m)
n--
}
if n >= 0 && len(result) == 0 {
- return result, EOF
+ return result, io.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) {
+func (file *File) readdirnames(n int) (names []string, err error) {
fi, err := file.Readdir(n)
names = make([]string, len(fi))
for i := range fi {
- names[i] = fi[i].Name
+ names[i] = fi[i].Name()
}
return
}
@@ -160,12 +136,12 @@ func pdir(b []byte, d *Dir) []byte {
// 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) {
+func UnmarshalDir(b []byte) (d *Dir, err error) {
n := uint16(0)
n, b = gbit16(b)
if int(n) != len(b) {
- return nil, Ebadstat
+ return nil, errBadStat
}
d = new(Dir)
@@ -182,7 +158,7 @@ func UnmarshalDir(b []byte) (d *Dir, err Error) {
d.Muid, b = gstring(b)
if len(b) != 0 {
- return nil, Ebadstat
+ return nil, errBadStat
}
return d, nil
@@ -292,9 +268,9 @@ func pbit64(b []byte, x uint64) []byte {
// pstring appends a Go string s to a 9P message b.
func pstring(b []byte, s string) []byte {
if len(s) >= 1<<16 {
- panic(NewError("string too long"))
+ panic(errors.New("string too long"))
}
b = pbit16(b, uint16(len(s)))
- b = append(b, []byte(s)...)
+ b = append(b, s...)
return b
}
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
index 7835ed52b..f41f939a9 100644
--- a/src/pkg/os/dir_unix.go
+++ b/src/pkg/os/dir_unix.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package os
import (
+ "io"
"syscall"
)
@@ -12,19 +15,7 @@ const (
blockSize = 4096
)
-// 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) {
+func (f *File) readdirnames(n int) (names []string, err error) {
// If this file has no dirinfo, create one.
if f.dirinfo == nil {
f.dirinfo = new(dirInfo)
@@ -44,9 +35,9 @@ func (f *File) Readdirnames(n int) (names []string, err Error) {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
- var errno int
+ var errno error
d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
- if errno != 0 {
+ if errno != nil {
return names, NewSyscallError("readdirent", errno)
}
if d.nbuf <= 0 {
@@ -61,7 +52,7 @@ func (f *File) Readdirnames(n int) (names []string, err Error) {
n -= nc
}
if n >= 0 && len(names) == 0 {
- return names, EOF
+ return names, io.EOF
}
return names, nil
}
diff --git a/src/pkg/os/dir_windows.go b/src/pkg/os/dir_windows.go
index d76e88fdb..931316048 100644
--- a/src/pkg/os/dir_windows.go
+++ b/src/pkg/os/dir_windows.go
@@ -4,11 +4,11 @@
package os
-func (file *File) Readdirnames(n int) (names []string, err Error) {
+func (file *File) readdirnames(n int) (names []string, err error) {
fis, err := file.Readdir(n)
names = make([]string, len(fis))
for i, fi := range fis {
- names[i] = fi.Name
+ names[i] = fi.Name()
}
return names, err
}
diff --git a/src/pkg/os/doc.go b/src/pkg/os/doc.go
new file mode 100644
index 000000000..6a531e0d7
--- /dev/null
+++ b/src/pkg/os/doc.go
@@ -0,0 +1,124 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "time"
+
+// FindProcess looks for a running process by its pid.
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+func FindProcess(pid int) (p *Process, err error) {
+ return findProcess(pid)
+}
+
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The os/exec package provides
+// higher-level interfaces.
+//
+// If there is an error, it will be of type *PathError.
+func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
+ return startProcess(name, argv, attr)
+}
+
+// Release releases any resources associated with the Process p,
+// rendering it unusable in the future.
+// Release only needs to be called if Wait is not.
+func (p *Process) Release() error {
+ return p.release()
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() error {
+ return p.kill()
+}
+
+// Wait waits for the Process to exit, and then returns a
+// ProcessState describing its status and an error, if any.
+// Wait releases any resources associated with the Process.
+func (p *Process) Wait() (*ProcessState, error) {
+ return p.wait()
+}
+
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) error {
+ return p.signal(sig)
+}
+
+// UserTime returns the user CPU time of the exited process and its children.
+func (p *ProcessState) UserTime() time.Duration {
+ return p.userTime()
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+func (p *ProcessState) SystemTime() time.Duration {
+ return p.systemTime()
+}
+
+// Exited returns whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.success()
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as syscall.WaitStatus on Unix, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.sys()
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Rusage on Unix, to access its contents.
+func (p *ProcessState) SysUsage() interface{} {
+ return p.sysUsage()
+}
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err error) {
+ return hostname()
+}
+
+// Readdir reads the contents of the directory associated with file and
+// returns an array of up to n FileInfo values, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// 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 io.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 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 (f *File) Readdir(n int) (fi []FileInfo, err error) {
+ return f.readdir(n)
+}
+
+// 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 io.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 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) {
+ return f.readdirnames(n)
+}
diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go
index 3772c090b..eb265f241 100644
--- a/src/pkg/os/env.go
+++ b/src/pkg/os/env.go
@@ -6,7 +6,7 @@
package os
-func setenv_c(k, v string)
+import "syscall"
// Expand replaces ${var} or $var in the string based on the mapping function.
// Invocations of undefined variables are replaced with the empty string.
@@ -16,9 +16,9 @@ func Expand(s string, mapping func(string) string) string {
i := 0
for j := 0; j < len(s); j++ {
if s[j] == '$' && j+1 < len(s) {
- buf = append(buf, []byte(s[i:j])...)
+ buf = append(buf, s[i:j]...)
name, w := getShellName(s[j+1:])
- buf = append(buf, []byte(mapping(name))...)
+ buf = append(buf, mapping(name)...)
j += w
i = j + 1
}
@@ -26,10 +26,10 @@ func Expand(s string, mapping func(string) string) string {
return string(buf) + s[i:]
}
-// ShellExpand replaces ${var} or $var in the string according to the values
-// of the operating system's environment variables. References to undefined
+// ExpandEnv replaces ${var} or $var in the string according to the values
+// of the current environment variables. References to undefined
// variables are replaced by the empty string.
-func ShellExpand(s string) string {
+func ExpandEnv(s string) string {
return Expand(s, Getenv)
}
@@ -73,3 +73,31 @@ func getShellName(s string) (string, int) {
}
return s[:i], i
}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := syscall.Getenv(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an error, if any.
+func Setenv(key, value string) error {
+ err := syscall.Setenv(key, value)
+ if err != nil {
+ return NewSyscallError("setenv", err)
+ }
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+// Environ returns a copy of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ return syscall.Environ()
+}
diff --git a/src/pkg/os/env_plan9.go b/src/pkg/os/env_plan9.go
deleted file mode 100644
index 1fed89f92..000000000
--- a/src/pkg/os/env_plan9.go
+++ /dev/null
@@ -1,96 +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.
-
-// Plan 9 environment variables.
-
-package os
-
-import "syscall"
-
-// ENOENV is the Error indicating that an environment variable does not exist.
-var ENOENV = NewError("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err Error) {
- if len(key) == 0 {
- return "", EINVAL
- }
- f, e := Open("/env/" + key)
- if iserror(e) {
- return "", ENOENV
- }
- defer f.Close()
-
- l, _ := f.Seek(0, 2)
- f.Seek(0, 0)
- buf := make([]byte, l)
- n, e := f.Read(buf)
- if iserror(e) {
- return "", ENOENV
- }
-
- 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.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an Error, if any.
-func Setenv(key, value string) Error {
- if len(key) == 0 {
- return EINVAL
- }
-
- f, e := Create("/env/" + key)
- if iserror(e) {
- return e
- }
- defer f.Close()
-
- _, e = f.Write([]byte(value))
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- env := make([]string, 0, 100)
-
- f, e := Open("/env")
- if iserror(e) {
- panic(e)
- }
- defer f.Close()
-
- names, e := f.Readdirnames(-1)
- if iserror(e) {
- panic(e)
- }
-
- for _, k := range names {
- if v, e := Getenverror(k); !iserror(e) {
- env = append(env, k+"="+v)
- }
- }
- return env[0:len(env)]
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- return "/tmp"
-}
diff --git a/src/pkg/os/env_test.go b/src/pkg/os/env_test.go
index 04ff39072..991fa4d05 100644
--- a/src/pkg/os/env_test.go
+++ b/src/pkg/os/env_test.go
@@ -6,6 +6,7 @@ package os_test
import (
. "os"
+ "reflect"
"testing"
)
@@ -57,3 +58,13 @@ func TestExpand(t *testing.T) {
}
}
}
+
+func TestConsistentEnviron(t *testing.T) {
+ e0 := Environ()
+ for i := 0; i < 10; i++ {
+ e1 := Environ()
+ if !reflect.DeepEqual(e0, e1) {
+ t.Fatalf("environment changed")
+ }
+ }
+}
diff --git a/src/pkg/os/env_unix.go b/src/pkg/os/env_unix.go
deleted file mode 100644
index 9cc0b03d8..000000000
--- a/src/pkg/os/env_unix.go
+++ /dev/null
@@ -1,109 +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.
-
-// Unix environment variables.
-
-package os
-
-import (
- "sync"
-)
-
-// ENOENV is the Error indicating that an environment variable does not exist.
-var ENOENV = NewError("no such environment variable")
-
-var env map[string]string
-var once sync.Once
-
-func copyenv() {
- env = make(map[string]string)
- for _, s := range Envs {
- for j := 0; j < len(s); j++ {
- if s[j] == '=' {
- env[s[0:j]] = s[j+1:]
- break
- }
- }
- }
-}
-
-var envLock sync.RWMutex
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err Error) {
- once.Do(copyenv)
-
- if len(key) == 0 {
- return "", EINVAL
- }
-
- envLock.RLock()
- defer envLock.RUnlock()
-
- v, ok := env[key]
- if !ok {
- return "", ENOENV
- }
- return v, nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an Error, if any.
-func Setenv(key, value string) Error {
- once.Do(copyenv)
- if len(key) == 0 {
- return EINVAL
- }
-
- envLock.Lock()
- defer envLock.Unlock()
-
- env[key] = value
- setenv_c(key, value) // is a no-op if cgo isn't loaded
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- once.Do(copyenv) // prevent copyenv in Getenv/Setenv
-
- envLock.Lock()
- defer envLock.Unlock()
-
- env = make(map[string]string)
-
- // TODO(bradfitz): pass through to C
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- once.Do(copyenv)
- envLock.RLock()
- defer envLock.RUnlock()
- a := make([]string, len(env))
- i := 0
- for k, v := range env {
- a[i] = k + "=" + v
- i++
- }
- return a
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- dir := Getenv("TMPDIR")
- if dir == "" {
- dir = "/tmp"
- }
- return dir
-}
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
deleted file mode 100644
index e6ddc4065..000000000
--- a/src/pkg/os/env_windows.go
+++ /dev/null
@@ -1,127 +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.
-
-// Windows environment variables.
-
-package os
-
-import (
- "syscall"
- "utf16"
- "unsafe"
-)
-
-// ENOENV is the Error indicating that an environment variable does not exist.
-var ENOENV = NewError("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err Error) {
- b := make([]uint16, 100)
- n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
- if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
- return "", ENOENV
- }
- if n > uint32(len(b)) {
- b = make([]uint16, n)
- n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
- if n > uint32(len(b)) {
- n = 0
- }
- }
- if n == 0 {
- return "", NewSyscallError("GetEnvironmentVariable", e)
- }
- return string(utf16.Decode(b[0:n])), nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an Error, if any.
-func Setenv(key, value string) Error {
- var v *uint16
- if len(value) > 0 {
- v = syscall.StringToUTF16Ptr(value)
- }
- e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
- if e != 0 {
- return NewSyscallError("SetEnvironmentVariable", e)
- }
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- for _, s := range Environ() {
- // Environment variables can begin with =
- // so start looking for the separator = at j=1.
- // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
- for j := 1; j < len(s); j++ {
- if s[j] == '=' {
- Setenv(s[0:j], "")
- break
- }
- }
- }
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- s, e := syscall.GetEnvironmentStrings()
- if e != 0 {
- return nil
- }
- defer syscall.FreeEnvironmentStrings(s)
- r := make([]string, 0, 50) // Empty with room to grow.
- for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
- if p[i] == 0 {
- // empty string marks the end
- if i <= from {
- break
- }
- r = append(r, string(utf16.Decode(p[from:i])))
- from = i + 1
- }
- }
- return r
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- const pathSep = '\\'
- dirw := make([]uint16, syscall.MAX_PATH)
- n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
- if n > uint32(len(dirw)) {
- dirw = make([]uint16, n)
- n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
- if n > uint32(len(dirw)) {
- n = 0
- }
- }
- if n > 0 && dirw[n-1] == pathSep {
- n--
- }
- return string(utf16.Decode(dirw[0:n]))
-}
-
-func init() {
- var argc int32
- cmd := syscall.GetCommandLine()
- argv, e := syscall.CommandLineToArgv(cmd, &argc)
- if e != 0 {
- return
- }
- defer syscall.LocalFree(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/src/pkg/os/error.go b/src/pkg/os/error.go
index b4511dd2f..b88e49400 100644
--- a/src/pkg/os/error.go
+++ b/src/pkg/os/error.go
@@ -4,28 +4,59 @@
package os
-// An Error can represent any printable error condition.
-type Error interface {
- String() string
+import (
+ "errors"
+)
+
+// Portable analogs of some common system call errors.
+var (
+ ErrInvalid = errors.New("invalid argument")
+ ErrPermission = errors.New("permission denied")
+ ErrExist = errors.New("file already exists")
+ ErrNotExist = errors.New("file does not exist")
+)
+
+// PathError records an error and the operation and file path that caused it.
+type PathError struct {
+ Op string
+ Path string
+ Err error
}
-// // errorString is a helper type used by NewError.
-type errorString string
+func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
+
+// SyscallError records an error from a specific system call.
+type SyscallError struct {
+ Syscall string
+ Err error
+}
-func (e errorString) String() string { return string(e) }
+func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
-// 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.
+// NewSyscallError returns, as an error, a new SyscallError
+// with the given system call name and error details.
+// As a convenience, if err is nil, NewSyscallError returns nil.
+func NewSyscallError(syscall string, err error) error {
+ if err == nil {
+ return nil
+ }
+ return &SyscallError{syscall, err}
+}
-// // NewError returns a new error with error.String() == s.
-func NewError(s string) Error { return errorString(s) }
+// IsExist returns whether the error is known to report that a file or directory
+// already exists. It is satisfied by ErrExist as well as some syscall errors.
+func IsExist(err error) bool {
+ return isExist(err)
+}
-// PathError records an error and the operation and file path that caused it.
-type PathError struct {
- Op string
- Path string
- Error Error
+// IsNotExist returns whether the error is known to report that a file or directory
+// does not exist. It is satisfied by ErrNotExist as well as some syscall errors.
+func IsNotExist(err error) bool {
+ return isNotExist(err)
}
-func (e *PathError) String() string { return e.Op + " " + e.Path + ": " + e.Error.String() }
+// IsPermission returns whether the error is known to report that permission is denied.
+// It is satisfied by ErrPermission as well as some syscall errors.
+func IsPermission(err error) bool {
+ return isPermission(err)
+}
diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go
index cacfc150c..3c9dfb0b1 100644
--- a/src/pkg/os/error_plan9.go
+++ b/src/pkg/os/error_plan9.go
@@ -4,58 +4,35 @@
package os
-import syscall "syscall"
-
-// SyscallError records an error from a specific system call.
-type SyscallError struct {
- Syscall string
- Err string
+func isExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return contains(err.Error(), " exists")
}
-func (e *SyscallError) String() string { return e.Syscall + ": " + e.Err }
-
-// Note: If the name of the function NewSyscallError changes,
-// pkg/go/doc/doc.go should be adjusted since it hardwires
-// this name in a heuristic.
-
-// NewSyscallError returns, as an Error, a new SyscallError
-// with the given system call name and error details.
-// As a convenience, if err is nil, NewSyscallError returns nil.
-func NewSyscallError(syscall string, err syscall.Error) Error {
- if err == nil {
- return nil
+func isNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
}
- return &SyscallError{syscall, err.String()}
+ return contains(err.Error(), "does not exist")
}
-var (
- Eshortstat = NewError("stat buffer too small")
- Ebadstat = NewError("malformed stat buffer")
- Ebadfd = NewError("fd out of range or not open")
- Ebadarg = NewError("bad arg in system call")
- Enotdir = NewError("not a directory")
- Enonexist = NewError("file does not exist")
- Eexist = NewError("file already exists")
- Eio = NewError("i/o error")
- Eperm = NewError("permission denied")
-
- EINVAL = Ebadarg
- ENOTDIR = Enotdir
- ENOENT = Enonexist
- EEXIST = Eexist
- EIO = Eio
- EACCES = Eperm
- EPERM = Eperm
- EISDIR = syscall.EISDIR
-
- ENAMETOOLONG = NewError("file name too long")
- ERANGE = NewError("math result not representable")
- EPIPE = NewError("Broken Pipe")
- EPLAN9 = NewError("not supported by plan 9")
-)
-
-func iserror(err syscall.Error) bool {
- return err != nil
+func isPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return contains(err.Error(), "permission denied")
}
-func Errno(e syscall.Error) syscall.Error { return e }
+// contains is a local version of strings.Contains. It knows len(sep) > 1.
+func contains(s, sep string) bool {
+ n := len(sep)
+ c := sep[0]
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && s[i:i+n] == sep {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go
index d43f1786d..1685c1f21 100644
--- a/src/pkg/os/error_posix.go
+++ b/src/pkg/os/error_posix.go
@@ -2,89 +2,29 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package os
-
-import syscall "syscall"
-
-// Errno is the Unix error number. Names such as EINVAL are simple
-// wrappers to convert the error number into an Error.
-type Errno int64
-
-func (e Errno) String() string { return syscall.Errstr(int(e)) }
-
-func (e Errno) Temporary() bool {
- return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout()
-}
+// +build darwin freebsd linux netbsd openbsd
-func (e Errno) Timeout() bool {
- return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
-}
+package os
-// Commonly known Unix errors.
-var (
- EPERM Error = Errno(syscall.EPERM)
- ENOENT Error = Errno(syscall.ENOENT)
- ESRCH Error = Errno(syscall.ESRCH)
- EINTR Error = Errno(syscall.EINTR)
- EIO Error = Errno(syscall.EIO)
- ENXIO Error = Errno(syscall.ENXIO)
- E2BIG Error = Errno(syscall.E2BIG)
- ENOEXEC Error = Errno(syscall.ENOEXEC)
- EBADF Error = Errno(syscall.EBADF)
- ECHILD Error = Errno(syscall.ECHILD)
- EDEADLK Error = Errno(syscall.EDEADLK)
- ENOMEM Error = Errno(syscall.ENOMEM)
- EACCES Error = Errno(syscall.EACCES)
- EFAULT Error = Errno(syscall.EFAULT)
- EBUSY Error = Errno(syscall.EBUSY)
- EEXIST Error = Errno(syscall.EEXIST)
- EXDEV Error = Errno(syscall.EXDEV)
- ENODEV Error = Errno(syscall.ENODEV)
- ENOTDIR Error = Errno(syscall.ENOTDIR)
- EISDIR Error = Errno(syscall.EISDIR)
- EINVAL Error = Errno(syscall.EINVAL)
- ENFILE Error = Errno(syscall.ENFILE)
- EMFILE Error = Errno(syscall.EMFILE)
- ENOTTY Error = Errno(syscall.ENOTTY)
- EFBIG Error = Errno(syscall.EFBIG)
- ENOSPC Error = Errno(syscall.ENOSPC)
- ESPIPE Error = Errno(syscall.ESPIPE)
- EROFS Error = Errno(syscall.EROFS)
- EMLINK Error = Errno(syscall.EMLINK)
- EPIPE Error = Errno(syscall.EPIPE)
- EAGAIN Error = Errno(syscall.EAGAIN)
- EDOM Error = Errno(syscall.EDOM)
- ERANGE Error = Errno(syscall.ERANGE)
- EADDRINUSE Error = Errno(syscall.EADDRINUSE)
- ECONNREFUSED Error = Errno(syscall.ECONNREFUSED)
- ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG)
- EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT)
- ETIMEDOUT Error = Errno(syscall.ETIMEDOUT)
- ENOTCONN Error = Errno(syscall.ENOTCONN)
-)
+import "syscall"
-// SyscallError records an error from a specific system call.
-type SyscallError struct {
- Syscall string
- Errno Errno
+func isExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.EEXIST || err == ErrExist
}
-func (e *SyscallError) String() string { return e.Syscall + ": " + e.Errno.String() }
-
-// Note: If the name of the function NewSyscallError changes,
-// pkg/go/doc/doc.go should be adjusted since it hardwires
-// this name in a heuristic.
-
-// NewSyscallError returns, as an Error, a new SyscallError
-// with the given system call name and error details.
-// As a convenience, if errno is 0, NewSyscallError returns nil.
-func NewSyscallError(syscall string, errno int) Error {
- if errno == 0 {
- return nil
+func isNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
}
- return &SyscallError{syscall, Errno(errno)}
+ return err == syscall.ENOENT || err == ErrNotExist
}
-func iserror(errno int) bool {
- return errno != 0
+func isPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
}
diff --git a/src/pkg/os/error_test.go b/src/pkg/os/error_test.go
new file mode 100644
index 000000000..42f846fa3
--- /dev/null
+++ b/src/pkg/os/error_test.go
@@ -0,0 +1,81 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestErrIsExist(t *testing.T) {
+ f, err := ioutil.TempFile("", "_Go_ErrIsExist")
+ if err != nil {
+ t.Fatalf("open ErrIsExist tempfile: %s", err)
+ return
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ f2, err := os.OpenFile(f.Name(), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ if err == nil {
+ f2.Close()
+ t.Fatal("Open should have failed")
+ return
+ }
+ if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
+ t.Fatal(s)
+ return
+ }
+}
+
+func testErrNotExist(name string) string {
+ f, err := os.Open(name)
+ if err == nil {
+ f.Close()
+ return "Open should have failed"
+ }
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ return s
+ }
+
+ err = os.Chdir(name)
+ if err == nil {
+ return "Chdir should have failed"
+ }
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ return s
+ }
+ return ""
+}
+
+func TestErrIsNotExist(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "_Go_ErrIsNotExist")
+ if err != nil {
+ t.Fatalf("create ErrIsNotExist tempdir: %s", err)
+ return
+ }
+ defer os.RemoveAll(tmpDir)
+
+ name := filepath.Join(tmpDir, "NotExists")
+ if s := testErrNotExist(name); s != "" {
+ t.Fatal(s)
+ return
+ }
+
+ name = filepath.Join(name, "NotExists2")
+ if s := testErrNotExist(name); s != "" {
+ t.Fatal(s)
+ return
+ }
+}
+
+func checkErrorPredicate(predName string, pred func(error) bool, err error) string {
+ if !pred(err) {
+ return fmt.Sprintf("%s does not work as expected for %#v", predName, err)
+ }
+ return ""
+}
diff --git a/src/pkg/os/error_windows.go b/src/pkg/os/error_windows.go
new file mode 100644
index 000000000..5d692b073
--- /dev/null
+++ b/src/pkg/os/error_windows.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+func isExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.ERROR_ALREADY_EXISTS ||
+ err == syscall.ERROR_FILE_EXISTS || err == ErrExist
+}
+
+func isNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.ERROR_FILE_NOT_FOUND ||
+ err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
+}
+
+func isPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == ErrPermission
+}
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
index 33e223fd2..531b87ca5 100644
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -12,11 +12,11 @@ import (
// Process stores the information about a process created by StartProcess.
type Process struct {
Pid int
- handle int
- done bool // process has been successfuly waited on
+ handle uintptr
+ done bool // process has been successfully waited on
}
-func newProcess(pid, handle int) *Process {
+func newProcess(pid int, handle uintptr) *Process {
p := &Process{Pid: pid, handle: handle}
runtime.SetFinalizer(p, (*Process).Release)
return p
@@ -46,11 +46,22 @@ type ProcAttr struct {
Sys *syscall.SysProcAttr
}
-// A Signal can represent any operating system signal.
+// A Signal represents an operating system signal.
+// The usual underlying implementation is operating system-dependent:
+// on Unix it is syscall.Signal.
type Signal interface {
String() string
+ Signal() // to distinguish from other Stringers
}
+// The only signal values guaranteed to be present on all systems
+// are Interrupt (send the process an interrupt) and
+// Kill (force the process to exit).
+var (
+ Interrupt Signal = syscall.SIGINT
+ Kill Signal = syscall.SIGKILL
+)
+
// Getpid returns the process id of the caller.
func Getpid() int { return syscall.Getpid() }
diff --git a/src/pkg/os/exec/example_test.go b/src/pkg/os/exec/example_test.go
new file mode 100644
index 000000000..55eaac8ab
--- /dev/null
+++ b/src/pkg/os/exec/example_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec_test
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os/exec"
+ "strings"
+)
+
+func ExampleLookPath() {
+ path, err := exec.LookPath("fortune")
+ if err != nil {
+ log.Fatal("installing fortune is in your future")
+ }
+ fmt.Printf("fortune is available at %s\n", path)
+}
+
+func ExampleCommand() {
+ cmd := exec.Command("tr", "a-z", "A-Z")
+ cmd.Stdin = strings.NewReader("some input")
+ var out bytes.Buffer
+ cmd.Stdout = &out
+ err := cmd.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("in all caps: %q\n", out.String())
+}
+
+func ExampleCmd_Output() {
+ out, err := exec.Command("date").Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("The date is %s\n", out)
+}
+
+func ExampleCmd_Start() {
+ cmd := exec.Command("sleep", "5")
+ err := cmd.Start()
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Printf("Waiting for command to finish...")
+ err = cmd.Wait()
+ log.Printf("Command finished with error: %v", err)
+}
+
+func ExampleCmd_StdoutPipe() {
+ cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+ var person struct {
+ Name string
+ Age int
+ }
+ if err := json.NewDecoder(stdout).Decode(&person); err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Wait(); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s is %d years old\n", person.Name, person.Age)
+}
diff --git a/src/pkg/exec/exec.go b/src/pkg/os/exec/exec.go
index 3b20f2008..bbd04902b 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -9,6 +9,7 @@ package exec
import (
"bytes"
+ "errors"
"io"
"os"
"strconv"
@@ -18,12 +19,12 @@ import (
// 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
+ Name string
+ Err error
}
-func (e *Error) String() string {
- return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
+func (e *Error) Error() string {
+ return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
}
// Cmd represents an external command being prepared or run.
@@ -49,20 +50,28 @@ type Cmd struct {
// calling process's current directory.
Dir string
- // Stdin specifies the process's standard input.
- // If Stdin is nil, the process reads from DevNull.
+ // Stdin specifies the process's standard input. If Stdin is
+ // nil, the process reads from the null device (os.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 either is nil, Run connects the corresponding file descriptor
+ // to the null device (os.DevNull).
//
- // If Stdout and Stderr are are the same writer, at most one
+ // If Stdout and Stderr are the same writer, at most one
// goroutine at a time will call Write.
Stdout io.Writer
Stderr io.Writer
+ // ExtraFiles specifies additional open files to be inherited by the
+ // new process. It does not include standard input, standard output, or
+ // standard error. If non-nil, entry i becomes file descriptor 3+i.
+ //
+ // BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds.
+ // http://golang.org/issue/2603
+ ExtraFiles []*os.File
+
// SysProcAttr holds optional, operating system-specific attributes.
// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
SysProcAttr *syscall.SysProcAttr
@@ -70,13 +79,17 @@ type Cmd struct {
// 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
+ // ProcessState contains information about an exited process,
+ // available after a call to Wait or Run.
+ ProcessState *os.ProcessState
+
+ err 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
+ goroutine []func() error
+ errch chan error // one send per goroutine
}
// Command returns the Cmd struct to execute the named program with
@@ -127,7 +140,7 @@ func (c *Cmd) argv() []string {
return []string{c.Path}
}
-func (c *Cmd) stdin() (f *os.File, err os.Error) {
+func (c *Cmd) stdin() (f *os.File, err error) {
if c.Stdin == nil {
f, err = os.Open(os.DevNull)
c.closeAfterStart = append(c.closeAfterStart, f)
@@ -145,7 +158,7 @@ func (c *Cmd) stdin() (f *os.File, err os.Error) {
c.closeAfterStart = append(c.closeAfterStart, pr)
c.closeAfterWait = append(c.closeAfterWait, pw)
- c.goroutine = append(c.goroutine, func() os.Error {
+ c.goroutine = append(c.goroutine, func() error {
_, err := io.Copy(pw, c.Stdin)
if err1 := pw.Close(); err == nil {
err = err1
@@ -155,18 +168,18 @@ func (c *Cmd) stdin() (f *os.File, err os.Error) {
return pr, nil
}
-func (c *Cmd) stdout() (f *os.File, err os.Error) {
+func (c *Cmd) stdout() (f *os.File, err error) {
return c.writerDescriptor(c.Stdout)
}
-func (c *Cmd) stderr() (f *os.File, err os.Error) {
+func (c *Cmd) stderr() (f *os.File, err error) {
if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
return c.childFiles[1], nil
}
return c.writerDescriptor(c.Stderr)
}
-func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
+func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
if w == nil {
f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
c.closeAfterStart = append(c.closeAfterStart, f)
@@ -184,7 +197,7 @@ func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
c.closeAfterStart = append(c.closeAfterStart, pw)
c.closeAfterWait = append(c.closeAfterWait, pr)
- c.goroutine = append(c.goroutine, func() os.Error {
+ c.goroutine = append(c.goroutine, func() error {
_, err := io.Copy(w, pr)
return err
})
@@ -198,9 +211,9 @@ func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
// status.
//
// If the command fails to run or doesn't complete successfully, the
-// error is of type *os.Waitmsg. Other error types may be
+// error is of type *ExitError. Other error types may be
// returned for I/O problems.
-func (c *Cmd) Run() os.Error {
+func (c *Cmd) Run() error {
if err := c.Start(); err != nil {
return err
}
@@ -208,15 +221,15 @@ func (c *Cmd) Run() os.Error {
}
// Start starts the specified command but does not wait for it to complete.
-func (c *Cmd) Start() os.Error {
+func (c *Cmd) Start() error {
if c.err != nil {
return c.err
}
if c.Process != nil {
- return os.NewError("exec: already started")
+ return errors.New("exec: already started")
}
- type F func(*Cmd) (*os.File, os.Error)
+ type F func(*Cmd) (*os.File, error)
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
fd, err := setupFd(c)
if err != nil {
@@ -224,8 +237,9 @@ func (c *Cmd) Start() os.Error {
}
c.childFiles = append(c.childFiles, fd)
}
+ c.childFiles = append(c.childFiles, c.ExtraFiles...)
- var err os.Error
+ var err error
c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
Dir: c.Dir,
Files: c.childFiles,
@@ -240,9 +254,9 @@ func (c *Cmd) Start() os.Error {
fd.Close()
}
- c.errch = make(chan os.Error, len(c.goroutine))
+ c.errch = make(chan error, len(c.goroutine))
for _, fn := range c.goroutine {
- go func(fn func() os.Error) {
+ go func(fn func() error) {
c.errch <- fn()
}(fn)
}
@@ -250,6 +264,15 @@ func (c *Cmd) Start() os.Error {
return nil
}
+// An ExitError reports an unsuccessful exit by a command.
+type ExitError struct {
+ *os.ProcessState
+}
+
+func (e *ExitError) Error() string {
+ return e.ProcessState.String()
+}
+
// Wait waits for the command to exit.
// It must have been started by Start.
//
@@ -258,19 +281,20 @@ func (c *Cmd) Start() os.Error {
// status.
//
// If the command fails to run or doesn't complete successfully, the
-// error is of type *os.Waitmsg. Other error types may be
+// error is of type *ExitError. Other error types may be
// returned for I/O problems.
-func (c *Cmd) Wait() os.Error {
+func (c *Cmd) Wait() error {
if c.Process == nil {
- return os.NewError("exec: not started")
+ return errors.New("exec: not started")
}
if c.finished {
- return os.NewError("exec: Wait was already called")
+ return errors.New("exec: Wait was already called")
}
c.finished = true
- msg, err := c.Process.Wait(0)
+ state, err := c.Process.Wait()
+ c.ProcessState = state
- var copyError os.Error
+ var copyError error
for _ = range c.goroutine {
if err := <-c.errch; err != nil && copyError == nil {
copyError = err
@@ -283,17 +307,17 @@ func (c *Cmd) Wait() os.Error {
if err != nil {
return err
- } else if !msg.Exited() || msg.ExitStatus() != 0 {
- return msg
+ } else if !state.Success() {
+ return &ExitError{state}
}
return copyError
}
// Output runs the command and returns its standard output.
-func (c *Cmd) Output() ([]byte, os.Error) {
+func (c *Cmd) Output() ([]byte, error) {
if c.Stdout != nil {
- return nil, os.NewError("exec: Stdout already set")
+ return nil, errors.New("exec: Stdout already set")
}
var b bytes.Buffer
c.Stdout = &b
@@ -303,12 +327,12 @@ func (c *Cmd) Output() ([]byte, os.Error) {
// CombinedOutput runs the command and returns its combined standard
// output and standard error.
-func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
+func (c *Cmd) CombinedOutput() ([]byte, error) {
if c.Stdout != nil {
- return nil, os.NewError("exec: Stdout already set")
+ return nil, errors.New("exec: Stdout already set")
}
if c.Stderr != nil {
- return nil, os.NewError("exec: Stderr already set")
+ return nil, errors.New("exec: Stderr already set")
}
var b bytes.Buffer
c.Stdout = &b
@@ -319,12 +343,12 @@ func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
// 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) {
+func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
if c.Stdin != nil {
- return nil, os.NewError("exec: Stdin already set")
+ return nil, errors.New("exec: Stdin already set")
}
if c.Process != nil {
- return nil, os.NewError("exec: StdinPipe after process started")
+ return nil, errors.New("exec: StdinPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
@@ -339,12 +363,12 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, 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) {
+func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
if c.Stdout != nil {
- return nil, os.NewError("exec: Stdout already set")
+ return nil, errors.New("exec: Stdout already set")
}
if c.Process != nil {
- return nil, os.NewError("exec: StdoutPipe after process started")
+ return nil, errors.New("exec: StdoutPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
@@ -359,12 +383,12 @@ func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) {
// 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) {
+func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
if c.Stderr != nil {
- return nil, os.NewError("exec: Stderr already set")
+ return nil, errors.New("exec: Stderr already set")
}
if c.Process != nil {
- return nil, os.NewError("exec: StderrPipe after process started")
+ return nil, errors.New("exec: StderrPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/os/exec/exec_test.go
index 242120faa..52f4bce3a 100644
--- a/src/pkg/exec/exec_test.go
+++ b/src/pkg/os/exec/exec_test.go
@@ -9,14 +9,19 @@ import (
"bytes"
"fmt"
"io"
- "testing"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/http/httptest"
"os"
+ "runtime"
"strconv"
"strings"
+ "testing"
)
func helperCommand(s ...string) *Cmd {
- cs := []string{"-test.run=exec.TestHelperProcess", "--"}
+ cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
cmd := Command(os.Args[0], cs...)
cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
@@ -51,8 +56,8 @@ func TestCatStdin(t *testing.T) {
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)
+ if _, ok := err.(*ExitError); !ok {
+ t.Errorf("expected *ExitError from cat combined; got %T: %v", err, err)
}
s := string(bs)
sp := strings.SplitN(s, "\n", 2)
@@ -79,17 +84,17 @@ func TestNoExistBinary(t *testing.T) {
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 {
+ if werr, ok := err.(*ExitError); ok {
+ if s, e := werr.Error(), "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)
+ t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
}
}
func TestPipes(t *testing.T) {
- check := func(what string, err os.Error) {
+ check := func(what string, err error) {
if err != nil {
t.Fatalf("%s: %v", what, err)
}
@@ -139,6 +144,65 @@ func TestPipes(t *testing.T) {
check("Wait", err)
}
+func TestExtraFiles(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Logf("no operating system support; skipping")
+ return
+ }
+
+ // Ensure that file descriptors have not already been leaked into
+ // our environment.
+ for fd := os.Stderr.Fd() + 1; fd <= 101; fd++ {
+ err := os.NewFile(fd, "").Close()
+ if err == nil {
+ t.Logf("Something already leaked - closed fd %d", fd)
+ }
+ }
+
+ // Force network usage, to verify the epoll (or whatever) fd
+ // doesn't leak to the child,
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ // Force TLS root certs to be loaded (which might involve
+ // cgo), to make sure none of that potential C code leaks fds.
+ ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("Hello"))
+ }))
+ defer ts.Close()
+ http.Get(ts.URL) // ignore result; just calling to force root cert loading
+
+ tf, err := ioutil.TempFile("", "")
+ if err != nil {
+ t.Fatalf("TempFile: %v", err)
+ }
+ defer os.Remove(tf.Name())
+ defer tf.Close()
+
+ const text = "Hello, fd 3!"
+ _, err = tf.Write([]byte(text))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ _, err = tf.Seek(0, os.SEEK_SET)
+ if err != nil {
+ t.Fatalf("Seek: %v", err)
+ }
+
+ c := helperCommand("read3")
+ c.ExtraFiles = []*os.File{tf}
+ bs, err := c.CombinedOutput()
+ if err != nil {
+ t.Fatalf("CombinedOutput: %v; output %q", err, bs)
+ }
+ if string(bs) != text {
+ t.Errorf("got %q; want %q", string(bs), text)
+ }
+}
+
// TestHelperProcess isn't a real test. It's used as a helper process
// for TestParameterRun.
func TestHelperProcess(*testing.T) {
@@ -147,6 +211,13 @@ func TestHelperProcess(*testing.T) {
}
defer os.Exit(0)
+ // Determine which command to use to display open files.
+ ofcmd := "lsof"
+ switch runtime.GOOS {
+ case "freebsd", "netbsd", "openbsd":
+ ofcmd = "fstat"
+ }
+
args := os.Args
for len(args) > 0 {
if args[0] == "--" {
@@ -189,7 +260,7 @@ func TestHelperProcess(*testing.T) {
bufr := bufio.NewReader(os.Stdin)
for {
line, _, err := bufr.ReadLine()
- if err == os.EOF {
+ if err == io.EOF {
break
} else if err != nil {
os.Exit(1)
@@ -204,6 +275,46 @@ func TestHelperProcess(*testing.T) {
os.Exit(1)
}
}
+ case "read3": // read fd 3
+ fd3 := os.NewFile(3, "fd3")
+ bs, err := ioutil.ReadAll(fd3)
+ if err != nil {
+ fmt.Printf("ReadAll from fd 3: %v", err)
+ os.Exit(1)
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ // TODO(bradfitz): broken? Sometimes.
+ // http://golang.org/issue/2603
+ // Skip this additional part of the test for now.
+ default:
+ // Now verify that there are no other open fds.
+ var files []*os.File
+ for wantfd := os.Stderr.Fd() + 2; wantfd <= 100; wantfd++ {
+ f, err := os.Open(os.Args[0])
+ if err != nil {
+ fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
+ os.Exit(1)
+ }
+ if got := f.Fd(); got != wantfd {
+ fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
+ out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+ fmt.Print(string(out))
+ os.Exit(1)
+ }
+ files = append(files, f)
+ }
+ for _, f := range files {
+ f.Close()
+ }
+ }
+ // Referring to fd3 here ensures that it is not
+ // garbage collected, and therefore closed, while
+ // executing the wantfd loop above. It doesn't matter
+ // what we do with fd3 as long as we refer to it;
+ // closing it is the easy choice.
+ fd3.Close()
+ os.Stderr.Write(bs)
case "exit":
n, _ := strconv.Atoi(args[0])
os.Exit(n)
diff --git a/src/pkg/exec/lp_plan9.go b/src/pkg/os/exec/lp_plan9.go
index e4751a4df..0e229e03e 100644
--- a/src/pkg/exec/lp_plan9.go
+++ b/src/pkg/os/exec/lp_plan9.go
@@ -5,29 +5,31 @@
package exec
import (
+ "errors"
"os"
"strings"
+ "syscall"
)
// 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")
+var ErrNotFound = errors.New("executable file not found in $path")
-func findExecutable(file string) os.Error {
+func findExecutable(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
- if d.IsRegular() && d.Permission()&0111 != 0 {
+ if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
- return os.EPERM
+ return syscall.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) {
+func LookPath(file string) (string, error) {
// skip the path lookup for these prefixes
skip := []string{"/", "#", "./", "../"}
diff --git a/src/pkg/exec/lp_test.go b/src/pkg/os/exec/lp_test.go
index 77d8e848c..77d8e848c 100644
--- a/src/pkg/exec/lp_test.go
+++ b/src/pkg/os/exec/lp_test.go
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/os/exec/lp_unix.go
index 008fb11a8..216322199 100644
--- a/src/pkg/exec/lp_unix.go
+++ b/src/pkg/os/exec/lp_unix.go
@@ -2,31 +2,34 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package exec
import (
+ "errors"
"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")
+var ErrNotFound = errors.New("executable file not found in $PATH")
-func findExecutable(file string) os.Error {
+func findExecutable(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
- if d.IsRegular() && d.Permission()&0111 != 0 {
+ if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
return nil
}
- return os.EPERM
+ return os.ErrPermission
}
// LookPath searches for an executable binary named file
// in the directories named by the PATH environment variable.
// If file contains a slash, it is tried directly and the PATH is not consulted.
-func LookPath(file string) (string, os.Error) {
+func LookPath(file string) (string, error) {
// NOTE(rsc): I wish we could use the Plan 9 behavior here
// (only bypass the path if file begins with / or ./ or ../)
// but that would not match all the Unix shells.
@@ -44,8 +47,9 @@ func LookPath(file string) (string, os.Error) {
// Unix shell semantics: path element "" means "."
dir = "."
}
- if err := findExecutable(dir + "/" + file); err == nil {
- return dir + "/" + file, nil
+ path := dir + "/" + file
+ if err := findExecutable(path); err == nil {
+ return path, nil
}
}
return "", &Error{file, ErrNotFound}
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/os/exec/lp_windows.go
index 7581088eb..d8351d7e6 100644
--- a/src/pkg/exec/lp_windows.go
+++ b/src/pkg/os/exec/lp_windows.go
@@ -5,25 +5,26 @@
package exec
import (
+ "errors"
"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%")
+var ErrNotFound = errors.New("executable file not found in %PATH%")
-func chkStat(file string) os.Error {
+func chkStat(file string) error {
d, err := os.Stat(file)
if err != nil {
return err
}
- if d.IsRegular() {
- return nil
+ if d.IsDir() {
+ return os.ErrPermission
}
- return os.EPERM
+ return nil
}
-func findExecutable(file string, exts []string) (string, os.Error) {
+func findExecutable(file string, exts []string) (string, error) {
if len(exts) == 0 {
return file, chkStat(file)
}
@@ -38,10 +39,15 @@ func findExecutable(file string, exts []string) (string, os.Error) {
return f, nil
}
}
- return ``, os.ENOENT
+ return ``, os.ErrNotExist
}
-func LookPath(file string) (f string, err os.Error) {
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file contains a slash, it is tried directly and the PATH is not consulted.
+// LookPath also uses PATHEXT environment variable to match
+// a suitable candidate.
+func LookPath(file string) (f string, err error) {
x := os.Getenv(`PATHEXT`)
if x == `` {
x = `.COM;.EXE;.BAT;.CMD`
@@ -62,11 +68,10 @@ func LookPath(file string) (f string, err os.Error) {
}
return ``, &Error{file, err}
}
- if pathenv := os.Getenv(`PATH`); pathenv == `` {
- if f, err = findExecutable(`.\`+file, exts); err == nil {
- return
- }
- } else {
+ if f, err = findExecutable(`.\`+file, exts); err == nil {
+ return
+ }
+ if pathenv := os.Getenv(`PATH`); pathenv != `` {
for _, dir := range strings.Split(pathenv, `;`) {
if f, err = findExecutable(dir+`\`+file, exts); err == nil {
return
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 6f0722a22..41cc8c26f 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -5,33 +5,25 @@
package os
import (
+ "errors"
"runtime"
"syscall"
+ "time"
)
-// StartProcess starts a new process with the program, arguments and attributes
-// specified by name, argv and attr.
-func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
Sys: attr.Sys,
}
- // 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) {
+ if e != nil {
return nil, &PathError{"fork/exec", name, e}
}
@@ -45,13 +37,13 @@ func (note Plan9Note) String() string {
return string(note)
}
-func (p *Process) Signal(sig Signal) Error {
+func (p *Process) signal(sig Signal) error {
if p.done {
- return NewError("os: process already finished")
+ return errors.New("os: process already finished")
}
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
- if iserror(e) {
+ if e != nil {
return NewSyscallError("signal", e)
}
defer f.Close()
@@ -59,10 +51,9 @@ func (p *Process) Signal(sig Signal) Error {
return e
}
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() Error {
+func (p *Process) kill() error {
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
- if iserror(e) {
+ if e != nil {
return NewSyscallError("kill", e)
}
defer f.Close()
@@ -70,38 +61,17 @@ func (p *Process) Kill() Error {
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.
-// ForkExec is almost always a better way to execute a program.
-func Exec(name string, argv []string, envv []string) Error {
- e := syscall.Exec(name, argv, envv)
- if iserror(e) {
- return &PathError{"exec", name, e}
- }
-
- return nil
-}
-
-// Waitmsg stores the information about an exited process as reported by Wait.
-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
-// (WNOHANG etc.) affect the behavior of the Wait call.
-func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
var waitmsg syscall.Waitmsg
if p.Pid == -1 {
- return nil, EINVAL
+ return nil, ErrInvalid
}
for true {
err = syscall.Await(&waitmsg)
- if iserror(err) {
+ if err != nil {
return nil, NewSyscallError("wait", err)
}
@@ -111,25 +81,14 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
}
}
- return &Waitmsg{waitmsg}, nil
-}
-
-// Wait waits for process pid to exit or stop, and then returns a
-// Waitmsg describing its status and an Error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-// Wait is equivalent to calling FindProcess and then Wait
-// and Release on the result.
-func Wait(pid int, options int) (w *Waitmsg, err Error) {
- p, e := FindProcess(pid)
- if e != nil {
- return nil, e
+ ps = &ProcessState{
+ pid: waitmsg.Pid,
+ status: &waitmsg,
}
- defer p.Release()
- return p.Wait(options)
+ return ps, nil
}
-// Release releases any resources associated with the Process.
-func (p *Process) Release() Error {
+func (p *Process) release() error {
// NOOP for Plan 9.
p.Pid = -1
// no need for a finalizer anymore
@@ -137,17 +96,49 @@ func (p *Process) Release() Error {
return nil
}
-// FindProcess looks for a running process by its pid.
-// The Process it returns can be used to obtain information
-// about the underlying operating system process.
-func FindProcess(pid int) (p *Process, err Error) {
+func findProcess(pid int) (p *Process, err error) {
// NOOP for Plan 9.
return newProcess(pid, 0), nil
}
-func (w *Waitmsg) String() string {
- if w == nil {
+// ProcessState stores information about a process, as reported by Wait.
+type ProcessState struct {
+ pid int // The process's id.
+ status *syscall.Waitmsg // System-dependent status info.
+}
+
+// Pid returns the process id of the exited process.
+func (p *ProcessState) Pid() int {
+ return p.pid
+}
+
+func (p *ProcessState) exited() bool {
+ return p.status.Exited()
+}
+
+func (p *ProcessState) success() bool {
+ return p.status.ExitStatus() == 0
+}
+
+func (p *ProcessState) sys() interface{} {
+ return p.status
+}
+
+func (p *ProcessState) sysUsage() interface{} {
+ return p.status
+}
+
+func (p *ProcessState) userTime() time.Duration {
+ return time.Duration(p.status.Time[0]) * time.Millisecond
+}
+
+func (p *ProcessState) systemTime() time.Duration {
+ return time.Duration(p.status.Time[1]) * time.Millisecond
+}
+
+func (p *ProcessState) String() string {
+ if p == nil {
return "<nil>"
}
- return "exit status: " + w.Msg
+ return "exit status: " + p.status.Msg
}
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index f37bfab58..70351cfb3 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -2,29 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
package os
import (
- "runtime"
"syscall"
)
-type UnixSignal int32
-
-func (sig UnixSignal) String() string {
- s := runtime.Signame(int32(sig))
- if len(s) > 0 {
- return s
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+ // Double-check existence of the directory we want
+ // to chdir into. We can make the error clearer this way.
+ if attr != nil && attr.Dir != "" {
+ if _, err := Stat(attr.Dir); err != nil {
+ pe := err.(*PathError)
+ pe.Op = "chdir"
+ return nil, pe
+ }
}
- 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,
@@ -38,60 +34,42 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
}
pid, h, e := syscall.StartProcess(name, argv, sysattr)
- if iserror(e) {
- return nil, &PathError{"fork/exec", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"fork/exec", name, e}
}
return newProcess(pid, h), nil
}
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() Error {
- return p.Signal(SIGKILL)
+func (p *Process) kill() error {
+ return p.Signal(Kill)
}
-// 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.
-//
-// 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()
- }
- e := syscall.Exec(name, argv, envv)
- if iserror(e) {
- return &PathError{"exec", name, Errno(e)}
- }
- return nil
+// ProcessState stores information about a process, as reported by Wait.
+type ProcessState struct {
+ pid int // The process's id.
+ status syscall.WaitStatus // System-dependent status info.
+ rusage *syscall.Rusage
}
-// TODO(rsc): Should os implement its own syscall.WaitStatus
-// wrapper with the methods, or is exposing the underlying one enough?
-//
-// TODO(rsc): Certainly need to have Rusage struct,
-// since syscall one might have different field types across
-// different OS.
-
-// Waitmsg stores the information about an exited process as reported by Wait.
-type Waitmsg struct {
- Pid int // The process's id.
- syscall.WaitStatus // System-dependent status info.
- Rusage *syscall.Rusage // System-dependent resource usage info.
+// Pid returns the process id of the exited process.
+func (p *ProcessState) Pid() int {
+ return p.pid
}
-// Wait waits for process pid to exit or stop, and then returns a
-// Waitmsg describing its status and an Error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-// Wait is equivalent to calling FindProcess and then Wait
-// and Release on the result.
-func Wait(pid int, options int) (w *Waitmsg, err Error) {
- p, e := FindProcess(pid)
- if e != nil {
- return nil, e
- }
- defer p.Release()
- return p.Wait(options)
+func (p *ProcessState) exited() bool {
+ return p.status.Exited()
+}
+
+func (p *ProcessState) success() bool {
+ return p.status.ExitStatus() == 0
+}
+
+func (p *ProcessState) sys() interface{} {
+ return p.status
+}
+
+func (p *ProcessState) sysUsage() interface{} {
+ return p.rusage
}
// Convert i to decimal string.
@@ -121,26 +99,26 @@ func itod(i int) string {
return string(b[bp:])
}
-func (w *Waitmsg) String() string {
- if w == nil {
+func (p *ProcessState) String() string {
+ if p == nil {
return "<nil>"
}
- // TODO(austin) Use signal names when possible?
+ status := p.Sys().(syscall.WaitStatus)
res := ""
switch {
- case w.Exited():
- res = "exit status " + itod(w.ExitStatus())
- case w.Signaled():
- res = "signal " + itod(w.Signal())
- case w.Stopped():
- res = "stop signal " + itod(w.StopSignal())
- if w.StopSignal() == syscall.SIGTRAP && w.TrapCause() != 0 {
- res += " (trap " + itod(w.TrapCause()) + ")"
+ case status.Exited():
+ res = "exit status " + itod(status.ExitStatus())
+ case status.Signaled():
+ res = "signal " + itod(int(status.Signal()))
+ case status.Stopped():
+ res = "stop signal " + itod(int(status.StopSignal()))
+ if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
+ res += " (trap " + itod(status.TrapCause()) + ")"
}
- case w.Continued():
+ case status.Continued():
res = "continued"
}
- if w.CoreDump() {
+ if status.CoreDump() {
res += " (core dumped)"
}
return res
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 8a4b2e1b8..ecfe5353b 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_unix.go
@@ -2,65 +2,53 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package os
import (
+ "errors"
"runtime"
"syscall"
+ "time"
)
-// Options for Wait.
-const (
- WNOHANG = syscall.WNOHANG // Don't wait if no process has exited.
- WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported.
- WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED.
- WRUSAGE = 1 << 20 // Record resource usage.
-)
-
-// WRUSAGE must not be too high a bit, to avoid clashing with Linux's
-// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of
-// the options
-
-// Wait waits for the Process to exit or stop, and then returns a
-// Waitmsg describing its status and an Error, if any. The options
-// (WNOHANG etc.) affect the behavior of the Wait call.
-func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
if p.Pid == -1 {
- return nil, EINVAL
+ return nil, syscall.EINVAL
}
var status syscall.WaitStatus
- var rusage *syscall.Rusage
- if options&WRUSAGE != 0 {
- rusage = new(syscall.Rusage)
- options ^= WRUSAGE
- }
- pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
- if e != 0 {
+ var rusage syscall.Rusage
+ pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
+ if e != nil {
return nil, NewSyscallError("wait", e)
}
- if options&WSTOPPED == 0 {
+ if pid1 != 0 {
p.done = true
}
- w = new(Waitmsg)
- w.Pid = pid1
- w.WaitStatus = status
- w.Rusage = rusage
- return w, nil
+ ps = &ProcessState{
+ pid: pid1,
+ status: status,
+ rusage: &rusage,
+ }
+ return ps, nil
}
-// Signal sends a signal to the Process.
-func (p *Process) Signal(sig Signal) Error {
+func (p *Process) signal(sig Signal) error {
if p.done {
- return NewError("os: process already finished")
+ return errors.New("os: process already finished")
}
- if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
- return Errno(e)
+ s, ok := sig.(syscall.Signal)
+ if !ok {
+ return errors.New("os: unsupported signal type")
+ }
+ if e := syscall.Kill(p.Pid, s); e != nil {
+ return e
}
return nil
}
-// Release releases any resources associated with the Process.
-func (p *Process) Release() Error {
+func (p *Process) release() error {
// NOOP for unix.
p.Pid = -1
// no need for a finalizer anymore
@@ -68,10 +56,15 @@ func (p *Process) Release() Error {
return nil
}
-// FindProcess looks for a running process by its pid.
-// The Process it returns can be used to obtain information
-// about the underlying operating system process.
-func FindProcess(pid int) (p *Process, err Error) {
+func findProcess(pid int) (p *Process, err error) {
// NOOP for unix.
return newProcess(pid, 0), nil
}
+
+func (p *ProcessState) userTime() time.Duration {
+ return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond
+}
+
+func (p *ProcessState) systemTime() time.Duration {
+ return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond
+}
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index 65e94ac4a..5beca4a65 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -5,11 +5,14 @@
package os
import (
+ "errors"
"runtime"
"syscall"
+ "time"
+ "unsafe"
)
-func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
+func (p *Process) wait() (ps *ProcessState, err error) {
s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
switch s {
case syscall.WAIT_OBJECT_0:
@@ -17,50 +20,87 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
case syscall.WAIT_FAILED:
return nil, NewSyscallError("WaitForSingleObject", e)
default:
- return nil, NewError("os: unexpected result from WaitForSingleObject")
+ return nil, errors.New("os: unexpected result from WaitForSingleObject")
}
var ec uint32
e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
- if e != 0 {
+ if e != nil {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
+ var u syscall.Rusage
+ e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
+ if e != nil {
+ return nil, NewSyscallError("GetProcessTimes", e)
+ }
p.done = true
- return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
+ // NOTE(brainman): It seems that sometimes process is not dead
+ // when WaitForSingleObject returns. But we do not know any
+ // other way to wait for it. Sleeping for a while seems to do
+ // the trick sometimes. So we will sleep and smell the roses.
+ defer time.Sleep(5 * time.Millisecond)
+ defer p.Release()
+ return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
}
-// Signal sends a signal to the Process.
-func (p *Process) Signal(sig Signal) Error {
+func (p *Process) signal(sig Signal) error {
if p.done {
- return NewError("os: process already finished")
+ return errors.New("os: process already finished")
}
- switch sig.(UnixSignal) {
- case SIGKILL:
+ if sig == Kill {
e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
return NewSyscallError("TerminateProcess", e)
}
- return Errno(syscall.EWINDOWS)
+ // TODO(rsc): Handle Interrupt too?
+ return syscall.Errno(syscall.EWINDOWS)
}
-func (p *Process) Release() Error {
- if p.handle == -1 {
- return EINVAL
+func (p *Process) release() error {
+ if p.handle == uintptr(syscall.InvalidHandle) {
+ return syscall.EINVAL
}
e := syscall.CloseHandle(syscall.Handle(p.handle))
- if e != 0 {
+ if e != nil {
return NewSyscallError("CloseHandle", e)
}
- p.handle = -1
+ p.handle = uintptr(syscall.InvalidHandle)
// no need for a finalizer anymore
runtime.SetFinalizer(p, nil)
return nil
}
-func FindProcess(pid int) (p *Process, err Error) {
+func findProcess(pid int) (p *Process, err error) {
const da = syscall.STANDARD_RIGHTS_READ |
syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
h, e := syscall.OpenProcess(da, false, uint32(pid))
- if e != 0 {
+ if e != nil {
return nil, NewSyscallError("OpenProcess", e)
}
- return newProcess(pid, int(h)), nil
+ return newProcess(pid, uintptr(h)), nil
+}
+
+func init() {
+ var argc int32
+ cmd := syscall.GetCommandLine()
+ argv, e := syscall.CommandLineToArgv(cmd, &argc)
+ if e != nil {
+ return
+ }
+ 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)[:]))
+ }
+}
+
+func ftToDuration(ft *syscall.Filetime) time.Duration {
+ n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
+ return time.Duration(n*100) * time.Nanosecond
+}
+
+func (p *ProcessState) userTime() time.Duration {
+ return ftToDuration(&p.rusage.UserTime)
+}
+
+func (p *ProcessState) systemTime() time.Duration {
+ return ftToDuration(&p.rusage.KernelTime)
}
diff --git a/src/pkg/go/build/pkgtest/pkgtest.go b/src/pkg/os/export_test.go
index 9322f5ebd..9c6ef4297 100644
--- a/src/pkg/go/build/pkgtest/pkgtest.go
+++ b/src/pkg/os/export_test.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package pkgtest
+package os
-func Foo() {}
+// Export for testing.
-func Sqrt(x float64) float64
+var Atime = atime
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index 4335d45e5..4acf35d67 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -3,41 +3,66 @@
// license that can be found in the LICENSE file.
// Package os provides a platform-independent interface to operating system
-// functionality. The design is Unix-like.
+// functionality. The design is Unix-like, although the error handling is
+// Go-like; failing calls return values of type error rather than error numbers.
+// Often, more information is available within the error. For example,
+// if a call that takes a file name fails, such as Open or Stat, the error
+// will include the failing file name when printed and will be of type
+// *PathError, which may be unpacked for more information.
+//
// The os interface is intended to be uniform across all operating systems.
// Features not generally available appear in the system-specific package syscall.
+//
+// Here is a simple example, opening a file and reading some of it.
+//
+// file, err := os.Open("file.go") // For read access.
+// if err != nil {
+// log.Fatal(err)
+// }
+//
+// If the open fails, the error string will be self-explanatory, like
+//
+// open file.go: no such file or directory
+//
+// The file's data can then be read into a slice of bytes. Read and
+// Write take their byte counts from the length of the argument slice.
+//
+// data := make([]byte, 100)
+// count, err := file.Read(data)
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("read %d bytes: %q\n", count, data[:count])
+//
package os
import (
+ "io"
"syscall"
)
// Name returns the name of the file as presented to Open.
-func (file *File) Name() string { return file.name }
+func (f *File) Name() string { return f.name }
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
// standard output, and standard error file descriptors.
var (
- Stdin = NewFile(syscall.Stdin, "/dev/stdin")
- Stdout = NewFile(syscall.Stdout, "/dev/stdout")
- Stderr = NewFile(syscall.Stderr, "/dev/stderr")
+ Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
+ Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
+ Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
// Flags to Open wrapping those of the underlying system. Not all flags
// may be implemented on a given system.
const (
- O_RDONLY int = syscall.O_RDONLY // open the file read-only.
- O_WRONLY int = syscall.O_WRONLY // open the file write-only.
- O_RDWR int = syscall.O_RDWR // open the file read-write.
- O_APPEND int = syscall.O_APPEND // append data to the file when writing.
- O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
- O_CREATE int = syscall.O_CREAT // create a new file if none exists.
- O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
- O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
- O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
- O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
- O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
- O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
+ O_RDONLY int = syscall.O_RDONLY // open the file read-only.
+ O_WRONLY int = syscall.O_WRONLY // open the file write-only.
+ O_RDWR int = syscall.O_RDWR // open the file read-write.
+ O_APPEND int = syscall.O_APPEND // append data to the file when writing.
+ O_CREATE int = syscall.O_CREAT // create a new file if none exists.
+ O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
+ O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
+ O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
)
// Seek whence values.
@@ -47,52 +72,54 @@ const (
SEEK_END int = 2 // seek relative to the end
)
-type eofError int
-
-func (eofError) String() string { return "EOF" }
+// LinkError records an error during a link or symlink or rename
+// system call and the paths that caused it.
+type LinkError struct {
+ Op string
+ Old string
+ New string
+ Err error
+}
-// EOF is the Error returned by Read when no more input is available.
-// Functions should return EOF only to signal a graceful end of input.
-// If the EOF occurs unexpectedly in a structured data stream,
-// the appropriate error is either io.ErrUnexpectedEOF or some other error
-// giving more detail.
-var EOF Error = eofError(0)
+func (e *LinkError) Error() string {
+ return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
+}
// Read reads up to len(b) bytes from the File.
-// It returns the number of bytes read and an Error, if any.
-// EOF is signaled by a zero count with err set to EOF.
-func (file *File) Read(b []byte) (n int, err Error) {
- if file == nil {
- return 0, EINVAL
+// It returns the number of bytes read and an error, if any.
+// EOF is signaled by a zero count with err set to io.EOF.
+func (f *File) Read(b []byte) (n int, err error) {
+ if f == nil {
+ return 0, ErrInvalid
}
- n, e := file.read(b)
+ n, e := f.read(b)
if n < 0 {
n = 0
}
- if n == 0 && !iserror(e) {
- return 0, EOF
+ if n == 0 && len(b) > 0 && e == nil {
+ return 0, io.EOF
}
- if iserror(e) {
- err = &PathError{"read", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"read", f.name, e}
}
return n, err
}
// ReadAt reads len(b) bytes from the File starting at byte offset off.
-// It returns the number of bytes read and the Error, if any.
-// EOF is signaled by a zero count with err set to EOF.
-// ReadAt always returns a non-nil Error when n != len(b).
-func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
- if file == nil {
- return 0, EINVAL
+// It returns the number of bytes read and the error, if any.
+// ReadAt always returns a non-nil error when n < len(b).
+// At end of file, that error is io.EOF.
+func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
+ if f == nil {
+ return 0, ErrInvalid
}
for len(b) > 0 {
- m, e := file.pread(b, off)
- if m == 0 && !iserror(e) {
- return n, EOF
+ m, e := f.pread(b, off)
+ if m == 0 && e == nil {
+ return n, io.EOF
}
- if iserror(e) {
- err = &PathError{"read", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"read", f.name, e}
break
}
n += m
@@ -103,36 +130,36 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
}
// Write writes len(b) bytes to the File.
-// It returns the number of bytes written and an Error, if any.
-// Write returns a non-nil Error when n != len(b).
-func (file *File) Write(b []byte) (n int, err Error) {
- if file == nil {
- return 0, EINVAL
+// It returns the number of bytes written and an error, if any.
+// Write returns a non-nil error when n != len(b).
+func (f *File) Write(b []byte) (n int, err error) {
+ if f == nil {
+ return 0, ErrInvalid
}
- n, e := file.write(b)
+ n, e := f.write(b)
if n < 0 {
n = 0
}
- epipecheck(file, e)
+ epipecheck(f, e)
- if iserror(e) {
- err = &PathError{"write", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"write", f.name, e}
}
return n, err
}
// WriteAt writes len(b) bytes to the File starting at byte offset off.
-// It returns the number of bytes written and an Error, if any.
-// WriteAt returns a non-nil Error when n != len(b).
-func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
- if file == nil {
- return 0, EINVAL
+// It returns the number of bytes written and an error, if any.
+// WriteAt returns a non-nil error when n != len(b).
+func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
+ if f == nil {
+ return 0, ErrInvalid
}
for len(b) > 0 {
- m, e := file.pwrite(b, off)
- if iserror(e) {
- err = &PathError{"write", file.name, Errno(e)}
+ m, e := f.pwrite(b, off)
+ if e != nil {
+ err = &PathError{"write", f.name, e}
break
}
n += m
@@ -145,50 +172,52 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
// Seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
-// It returns the new offset and an Error, if any.
-func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
- r, e := file.seek(offset, whence)
- if !iserror(e) && file.dirinfo != nil && r != 0 {
+// It returns the new offset and an error, if any.
+func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
+ r, e := f.seek(offset, whence)
+ if e == nil && f.dirinfo != nil && r != 0 {
e = syscall.EISDIR
}
- if iserror(e) {
- return 0, &PathError{"seek", file.name, Errno(e)}
+ if e != nil {
+ return 0, &PathError{"seek", f.name, e}
}
return r, nil
}
// WriteString is like Write, but writes the contents of string s rather than
// an array of bytes.
-func (file *File) WriteString(s string) (ret int, err Error) {
- if file == nil {
- return 0, EINVAL
+func (f *File) WriteString(s string) (ret int, err error) {
+ if f == nil {
+ return 0, ErrInvalid
}
- return file.Write([]byte(s))
+ return f.Write([]byte(s))
}
// Mkdir creates a new directory with the specified name and permission bits.
-// It returns an error, if any.
-func Mkdir(name string, perm uint32) Error {
- e := syscall.Mkdir(name, perm)
- if iserror(e) {
- return &PathError{"mkdir", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Mkdir(name string, perm FileMode) error {
+ e := syscall.Mkdir(name, syscallMode(perm))
+ if e != nil {
+ return &PathError{"mkdir", name, e}
}
return nil
}
// Chdir changes the current working directory to the named directory.
-func Chdir(dir string) Error {
- if e := syscall.Chdir(dir); iserror(e) {
- return &PathError{"chdir", dir, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Chdir(dir string) error {
+ if e := syscall.Chdir(dir); e != nil {
+ return &PathError{"chdir", dir, e}
}
return nil
}
// Chdir changes the current working directory to the file,
// which must be a directory.
-func (f *File) Chdir() Error {
- if e := syscall.Fchdir(f.fd); iserror(e) {
- return &PathError{"chdir", f.name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func (f *File) Chdir() error {
+ if e := syscall.Fchdir(f.fd); e != nil {
+ return &PathError{"chdir", f.name, e}
}
return nil
}
@@ -196,8 +225,8 @@ func (f *File) Chdir() Error {
// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
-// It returns the File and an Error, if any.
-func Open(name string) (file *File, err Error) {
+// If there is an error, it will be of type *PathError.
+func Open(name string) (file *File, err error) {
return OpenFile(name, O_RDONLY, 0)
}
@@ -205,7 +234,7 @@ func Open(name string) (file *File, err Error) {
// it if it already exists. If successful, methods on the returned
// File can be used for I/O; the associated file descriptor has mode
// O_RDWR.
-// It returns the File and an Error, if any.
-func Create(name string) (file *File, err Error) {
+// If there is an error, it will be of type *PathError.
+func Create(name string) (file *File, err error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 1e94fb715..cb0e9ef92 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -5,32 +5,45 @@
package os
import (
+ "errors"
"runtime"
"syscall"
+ "time"
)
+var ErrPlan9 = errors.New("unimplemented on Plan 9")
+
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong 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
+func (f *File) Fd() uintptr {
+ if f == nil {
+ return ^(uintptr(0))
}
- return file.fd
+ return uintptr(f.fd)
}
// NewFile returns a new File with the given file descriptor and name.
-func NewFile(fd int, name string) *File {
- if fd < 0 {
+func NewFile(fd uintptr, name string) *File {
+ fdi := int(fd)
+ if fdi < 0 {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: fdi, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -41,22 +54,37 @@ type dirInfo struct {
bufp int // location of next record in buf.
}
-func epipecheck(file *File, e syscall.Error) {
+func epipecheck(file *File, e 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"
+// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
+func syscallMode(i FileMode) (o uint32) {
+ o |= uint32(i.Perm())
+ if i&ModeAppend != 0 {
+ o |= syscall.DMAPPEND
+ }
+ if i&ModeExclusive != 0 {
+ o |= syscall.DMEXCL
+ }
+ if i&ModeTemporary != 0 {
+ o |= syscall.DMTMP
+ }
+ return
+}
+
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
-// It returns the File and an Error, if any.
-func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+// If there is an error, it will be of type *PathError.
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
var (
fd int
- e syscall.Error
+ e error
create bool
excl bool
trunc bool
@@ -81,12 +109,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
syscall.ForkLock.RLock()
if (create && trunc) || excl {
- fd, e = syscall.Create(name, flag, perm)
+ fd, e = syscall.Create(name, flag, syscallMode(perm))
} else {
fd, e = syscall.Open(name, flag)
if e != nil && create {
- var e1 syscall.Error
- fd, e1 = syscall.Create(name, flag, perm)
+ var e1 error
+ fd, e1 = syscall.Create(name, flag, syscallMode(perm))
if e1 == nil {
e = nil
}
@@ -104,16 +132,20 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
}
}
- return NewFile(fd, name), nil
+ return NewFile(uintptr(fd), name), nil
}
// Close closes the File, rendering it unusable for I/O.
-// It returns an Error, if any.
-func (file *File) Close() Error {
+// It returns an error, if any.
+func (file *File) Close() error {
+ return file.file.close()
+}
+
+func (file *file) close() error {
if file == nil || file.fd < 0 {
- return Ebadfd
+ return ErrInvalid
}
- var err Error
+ var err error
syscall.ForkLock.RLock()
if e := syscall.Close(file.fd); e != nil {
err = &PathError{"close", file.name, e}
@@ -128,41 +160,42 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
-func (f *File) Stat() (fi *FileInfo, err Error) {
+func (f *File) Stat() (FileInfo, error) {
d, err := dirstat(f)
- if iserror(err) {
+ if err != nil {
return nil, err
}
- return fileInfoFromStat(new(FileInfo), d), err
+ return fileInfoFromStat(d), nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
-func (f *File) Truncate(size int64) Error {
+func (f *File) Truncate(size int64) error {
var d Dir
d.Null()
d.Length = uint64(size)
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return &PathError{"truncate", f.name, e}
}
return nil
}
+const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
+
// Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode uint32) Error {
+// If there is an error, it will be of type *PathError.
+func (f *File) Chmod(mode FileMode) error {
var d Dir
- var mask = ^uint32(0777)
- d.Null()
odir, e := dirstat(f)
- if iserror(e) {
+ if e != nil {
return &PathError{"chmod", f.name, e}
}
-
- d.Mode = (odir.Mode & mask) | (mode &^ mask)
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ d.Null()
+ d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return &PathError{"chmod", f.name, e}
}
return nil
@@ -171,15 +204,15 @@ func (f *File) Chmod(mode uint32) Error {
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
-func (f *File) Sync() (err Error) {
+func (f *File) Sync() (err error) {
if f == nil {
- return EINVAL
+ return ErrInvalid
}
var d Dir
d.Null()
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return NewSyscallError("fsync", e)
}
return nil
@@ -187,26 +220,26 @@ func (f *File) Sync() (err Error) {
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err syscall.Error) {
+func (f *File) read(b []byte) (n int, err error) {
return syscall.Read(f.fd, b)
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil.
-func (f *File) pread(b []byte, off int64) (n int, err syscall.Error) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
return syscall.Pread(f.fd, b, off)
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err syscall.Error) {
+func (f *File) write(b []byte) (n int, err error) {
return syscall.Write(f.fd, b)
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
return syscall.Pwrite(f.fd, b, off)
}
@@ -214,58 +247,59 @@ func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err syscall.Error) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
return syscall.Seek(f.fd, offset, whence)
}
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
-func Truncate(name string, size int64) Error {
+// If there is an error, it will be of type *PathError.
+func Truncate(name string, size int64) error {
var d Dir
d.Null()
d.Length = uint64(size)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"truncate", name, e}
}
return nil
}
// Remove removes the named file or directory.
-func Remove(name string) Error {
- if e := syscall.Remove(name); iserror(e) {
+// If there is an error, it will be of type *PathError.
+func Remove(name string) error {
+ if e := syscall.Remove(name); e != nil {
return &PathError{"remove", name, e}
}
return nil
}
// Rename renames a file.
-func Rename(oldname, newname string) Error {
+func Rename(oldname, newname string) error {
var d Dir
d.Null()
d.Name = newname
- if e := syscall.Wstat(oldname, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(oldname, pdir(nil, &d)); e != nil {
return &PathError{"rename", oldname, e}
}
return nil
}
// Chmod changes the mode of the named file to mode.
-func Chmod(name string, mode uint32) Error {
+// If there is an error, it will be of type *PathError.
+func Chmod(name string, mode FileMode) error {
var d Dir
- var mask = ^uint32(0777)
- d.Null()
odir, e := dirstat(name)
- if iserror(e) {
+ if e != nil {
return &PathError{"chmod", name, e}
}
-
- d.Mode = (odir.Mode & mask) | (mode &^ mask)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ d.Null()
+ d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"chmod", name, e}
}
return nil
@@ -274,58 +308,65 @@ func Chmod(name string, mode uint32) Error {
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
-// The argument times are in nanoseconds, although the underlying
-// filesystem may truncate or round the values to a more
-// coarse time unit.
-func Chtimes(name string, atimeNs int64, mtimeNs int64) Error {
+// The underlying filesystem may truncate or round the values to a
+// less precise time unit.
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
var d Dir
d.Null()
- d.Atime = uint32(atimeNs / 1e9)
- d.Mtime = uint32(mtimeNs / 1e9)
+ d.Atime = uint32(atime.Unix())
+ d.Mtime = uint32(mtime.Unix())
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"chtimes", name, e}
}
return nil
}
-func Pipe() (r *File, w *File, err Error) {
+func Pipe() (r *File, w *File, err error) {
var p [2]int
syscall.ForkLock.RLock()
- if e := syscall.Pipe(p[0:]); iserror(e) {
+ if e := syscall.Pipe(p[0:]); e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
syscall.ForkLock.RUnlock()
- return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+ return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
}
// not supported on Plan 9
// Link creates a hard link.
-func Link(oldname, newname string) Error {
- return EPLAN9
+// If there is an error, it will be of type *LinkError.
+func Link(oldname, newname string) error {
+ return &LinkError{"link", oldname, newname, ErrPlan9}
+}
+
+// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
+func Symlink(oldname, newname string) error {
+ return &LinkError{"symlink", oldname, newname, ErrPlan9}
}
-func Symlink(oldname, newname string) Error {
- return EPLAN9
+func Readlink(name string) (string, error) {
+ return "", ErrPlan9
}
-func Readlink(name string) (string, Error) {
- return "", EPLAN9
+func Chown(name string, uid, gid int) error {
+ return ErrPlan9
}
-func Chown(name string, uid, gid int) Error {
- return EPLAN9
+func Lchown(name string, uid, gid int) error {
+ return ErrPlan9
}
-func Lchown(name string, uid, gid int) Error {
- return EPLAN9
+func (f *File) Chown(uid, gid int) error {
+ return ErrPlan9
}
-func (f *File) Chown(uid, gid int) Error {
- return EPLAN9
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ return "/tmp"
}
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index 0791a0dc0..073bd56a4 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -2,15 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd windows
+
package os
import (
"syscall"
+ "time"
)
func sigpipe() // implemented in package runtime
-func epipecheck(file *File, e int) {
+func epipecheck(file *File, e error) {
if e == syscall.EPIPE {
file.nepipe++
if file.nepipe >= 10 {
@@ -21,111 +24,34 @@ func epipecheck(file *File, e int) {
}
}
-// Stat returns a FileInfo structure describing the named file and an error, if any.
-// If name names a valid symbolic link, the returned FileInfo describes
-// the file pointed at by the link and has fi.FollowedSymlink set to true.
-// If name names an invalid symbolic link, the returned FileInfo describes
-// the link itself and has fi.FollowedSymlink set to false.
-func Stat(name string) (fi *FileInfo, err Error) {
- var lstat, stat syscall.Stat_t
- e := syscall.Lstat(name, &lstat)
- if iserror(e) {
- return nil, &PathError{"stat", name, Errno(e)}
- }
- statp := &lstat
- if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
- e := syscall.Stat(name, &stat)
- if !iserror(e) {
- statp = &stat
- }
- }
- return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
-}
-
-// Lstat returns the FileInfo structure describing the named file and an
-// error, if any. If the file is a symbolic link, the returned FileInfo
-// describes the symbolic link. Lstat makes no attempt to follow the link.
-func Lstat(name string) (fi *FileInfo, err Error) {
- var stat syscall.Stat_t
- e := syscall.Lstat(name, &stat)
- if iserror(e) {
- return nil, &PathError{"lstat", name, Errno(e)}
- }
- return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
-}
-
-// Remove removes the named file or directory.
-func Remove(name string) Error {
- // System call interface forces us to know
- // whether name is a file or directory.
- // Try both: it is cheaper on average than
- // doing a Stat plus the right one.
- e := syscall.Unlink(name)
- if !iserror(e) {
- return nil
- }
- e1 := syscall.Rmdir(name)
- if !iserror(e1) {
- return nil
- }
-
- // Both failed: figure out which error to return.
- // OS X and Linux differ on whether unlink(dir)
- // returns EISDIR, so can't use that. However,
- // both agree that rmdir(file) returns ENOTDIR,
- // so we can use that to decide which error is real.
- // Rmdir might also return ENOTDIR if given a bad
- // file path, like /etc/passwd/foo, but in that case,
- // both errors will be ENOTDIR, so it's okay to
- // use the error from unlink.
- // For windows syscall.ENOTDIR is set
- // to syscall.ERROR_DIRECTORY, hopefully it should
- // do the trick.
- if e1 != syscall.ENOTDIR {
- e = e1
- }
- return &PathError{"remove", name, Errno(e)}
-}
-
-// LinkError records an error during a link or symlink or rename
-// system call and the paths that caused it.
-type LinkError struct {
- Op string
- Old string
- New string
- Error Error
-}
-
-func (e *LinkError) String() string {
- return e.Op + " " + e.Old + " " + e.New + ": " + e.Error.String()
-}
-
-// Link creates a hard link.
-func Link(oldname, newname string) Error {
+// Link creates newname as a hard link to the oldname file.
+// If there is an error, it will be of type *LinkError.
+func Link(oldname, newname string) error {
e := syscall.Link(oldname, newname)
- if iserror(e) {
- return &LinkError{"link", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"link", oldname, newname, e}
}
return nil
}
-// Symlink creates a symbolic link.
-func Symlink(oldname, newname string) Error {
+// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
+func Symlink(oldname, newname string) error {
e := syscall.Symlink(oldname, newname)
- if iserror(e) {
- return &LinkError{"symlink", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"symlink", oldname, newname, e}
}
return nil
}
-// Readlink reads the contents of a symbolic link: the destination of
-// the link. It returns the contents and an Error, if any.
-func Readlink(name string) (string, Error) {
+// Readlink returns the destination of the named symbolic link.
+// If there is an error, it will be of type *PathError.
+func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
- if iserror(e) {
- return "", &PathError{"readlink", name, Errno(e)}
+ if e != nil {
+ return "", &PathError{"readlink", name, e}
}
if n < len {
return string(b[0:n]), nil
@@ -136,62 +62,84 @@ func Readlink(name string) (string, Error) {
}
// Rename renames a file.
-func Rename(oldname, newname string) Error {
+func Rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
- if iserror(e) {
- return &LinkError{"rename", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"rename", oldname, newname, e}
}
return nil
}
+// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
+func syscallMode(i FileMode) (o uint32) {
+ o |= uint32(i.Perm())
+ if i&ModeSetuid != 0 {
+ o |= syscall.S_ISUID
+ }
+ if i&ModeSetgid != 0 {
+ o |= syscall.S_ISGID
+ }
+ if i&ModeSticky != 0 {
+ o |= syscall.S_ISVTX
+ }
+ // No mapping for Go's ModeTemporary (plan9 only).
+ return
+}
+
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
-func Chmod(name string, mode uint32) Error {
- if e := syscall.Chmod(name, mode); iserror(e) {
- return &PathError{"chmod", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Chmod(name string, mode FileMode) error {
+ if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
+ return &PathError{"chmod", name, e}
}
return nil
}
// Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode uint32) Error {
- if e := syscall.Fchmod(f.fd, mode); iserror(e) {
- return &PathError{"chmod", f.name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func (f *File) Chmod(mode FileMode) error {
+ if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
+ return &PathError{"chmod", f.name, e}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
-func Chown(name string, uid, gid int) Error {
- if e := syscall.Chown(name, uid, gid); iserror(e) {
- return &PathError{"chown", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Chown(name string, uid, gid int) error {
+ if e := syscall.Chown(name, uid, gid); e != nil {
+ return &PathError{"chown", name, e}
}
return nil
}
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
-func Lchown(name string, uid, gid int) Error {
- if e := syscall.Lchown(name, uid, gid); iserror(e) {
- return &PathError{"lchown", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Lchown(name string, uid, gid int) error {
+ if e := syscall.Lchown(name, uid, gid); e != nil {
+ return &PathError{"lchown", name, e}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
-func (f *File) Chown(uid, gid int) Error {
- if e := syscall.Fchown(f.fd, uid, gid); iserror(e) {
- return &PathError{"chown", f.name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func (f *File) Chown(uid, gid int) error {
+ if e := syscall.Fchown(f.fd, uid, gid); e != nil {
+ return &PathError{"chown", f.name, e}
}
return nil
}
// Truncate changes the size of the file.
// It does not change the I/O offset.
-func (f *File) Truncate(size int64) Error {
- if e := syscall.Ftruncate(f.fd, size); iserror(e) {
- return &PathError{"truncate", f.name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func (f *File) Truncate(size int64) error {
+ if e := syscall.Ftruncate(f.fd, size); e != nil {
+ return &PathError{"truncate", f.name, e}
}
return nil
}
@@ -199,11 +147,11 @@ func (f *File) Truncate(size int64) Error {
// Sync commits the current contents of the file to stable storage.
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
-func (file *File) Sync() (err Error) {
- if file == nil {
- return EINVAL
+func (f *File) Sync() (err error) {
+ if f == nil {
+ return syscall.EINVAL
}
- if e := syscall.Fsync(file.fd); iserror(e) {
+ if e := syscall.Fsync(f.fd); e != nil {
return NewSyscallError("fsync", e)
}
return nil
@@ -212,15 +160,17 @@ func (file *File) Sync() (err Error) {
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
-// The argument times are in nanoseconds, although the underlying
-// filesystem may truncate or round the values to a more
-// coarse time unit.
-func Chtimes(name string, atime_ns int64, mtime_ns int64) Error {
+// The underlying filesystem may truncate or round the values to a
+// less precise time unit.
+// If there is an error, it will be of type *PathError.
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
var utimes [2]syscall.Timeval
+ atime_ns := atime.Unix()*1e9 + int64(atime.Nanosecond())
+ mtime_ns := mtime.Unix()*1e9 + int64(mtime.Nanosecond())
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
- if e := syscall.Utimes(name, utimes[0:]); iserror(e) {
- return &PathError{"chtimes", name, Errno(e)}
+ if e := syscall.Utimes(name, utimes[0:]); e != nil {
+ return &PathError{"chtimes", name, e}
}
return nil
}
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index 301c2f473..6271c3189 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
package os
import (
@@ -11,6 +13,14 @@ import (
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong file descriptor.
+type file struct {
fd int
name string
dirinfo *dirInfo // nil unless directory being read
@@ -18,20 +28,21 @@ type File struct {
}
// Fd returns the integer Unix file descriptor referencing the open file.
-func (file *File) Fd() int {
- if file == nil {
- return -1
+func (f *File) Fd() uintptr {
+ if f == nil {
+ return ^(uintptr(0))
}
- return file.fd
+ return uintptr(f.fd)
}
// NewFile returns a new File with the given file descriptor and name.
-func NewFile(fd int, name string) *File {
- if fd < 0 {
+func NewFile(fd uintptr, name string) *File {
+ fdi := int(fd)
+ if fdi < 0 {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: fdi, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -50,31 +61,40 @@ const DevNull = "/dev/null"
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
-// It returns the File and an Error, if any.
-func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
- r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
+ if e != nil {
+ return nil, &PathError{"open", name, e}
}
// There's a race here with fork/exec, which we are
- // content to live with. See ../syscall/exec.go
- if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+ // content to live with. See ../syscall/exec_unix.go.
+ // On OS X 10.6, the O_CLOEXEC flag is not respected.
+ // On OS X 10.7, the O_CLOEXEC flag works.
+ // Without a cheap & reliable way to detect 10.6 vs 10.7 at
+ // runtime, we just always call syscall.CloseOnExec on Darwin.
+ // Once >=10.7 is prevalent, this extra call can removed.
+ if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
syscall.CloseOnExec(r)
}
- return NewFile(r, name), nil
+ return NewFile(uintptr(r), name), nil
}
// Close closes the File, rendering it unusable for I/O.
-// It returns an Error, if any.
-func (file *File) Close() Error {
+// It returns an error, if any.
+func (f *File) Close() error {
+ return f.file.close()
+}
+
+func (file *file) close() error {
if file == nil || file.fd < 0 {
- return EINVAL
+ return syscall.EINVAL
}
- var err Error
- if e := syscall.Close(file.fd); e != 0 {
- err = &PathError{"close", file.name, Errno(e)}
+ var err error
+ if e := syscall.Close(file.fd); e != nil {
+ err = &PathError{"close", file.name, e}
}
file.fd = -1 // so it can't be closed again
@@ -84,72 +104,95 @@ 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) {
+// If there is an error, it will be of type *PathError.
+func (f *File) Stat() (fi FileInfo, err error) {
+ var stat syscall.Stat_t
+ err = syscall.Fstat(f.fd, &stat)
+ if err != nil {
+ return nil, &PathError{"stat", f.name, err}
+ }
+ return fileInfoFromStat(&stat, f.name), nil
+}
+
+// Stat returns a FileInfo describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(name string) (fi FileInfo, err error) {
+ var stat syscall.Stat_t
+ err = syscall.Stat(name, &stat)
+ if err != nil {
+ return nil, &PathError{"stat", name, err}
+ }
+ return fileInfoFromStat(&stat, name), nil
+}
+
+// Lstat returns a FileInfo describing the named file.
+// If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+// If there is an error, it will be of type *PathError.
+func Lstat(name string) (fi FileInfo, err error) {
var stat syscall.Stat_t
- e := syscall.Fstat(file.fd, &stat)
- if e != 0 {
- return nil, &PathError{"stat", file.name, Errno(e)}
- }
- return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
-}
-
-// Readdir reads the contents of the directory associated with file and
-// returns an array of up to 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
-// 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
+ err = syscall.Lstat(name, &stat)
+ if err != nil {
+ return nil, &PathError{"lstat", name, err}
+ }
+ return fileInfoFromStat(&stat, name), nil
+}
+
+func (f *File) readdir(n int) (fi []FileInfo, err error) {
+ dirname := f.name
if dirname == "" {
dirname = "."
}
dirname += "/"
- names, err := file.Readdirnames(n)
+ names, err := f.Readdirnames(n)
fi = make([]FileInfo, len(names))
for i, filename := range names {
fip, err := Lstat(dirname + filename)
- if fip == nil || err != nil {
- fi[i].Name = filename // rest is already zeroed out
+ if err == nil {
+ fi[i] = fip
} else {
- fi[i] = *fip
+ fi[i] = &fileStat{name: filename}
}
}
- return
+ return fi, err
}
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err int) {
+func (f *File) read(b []byte) (n int, err error) {
return syscall.Read(f.fd, b)
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to 0.
-func (f *File) pread(b []byte, off int64) (n int, err int) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
return syscall.Pread(f.fd, b, off)
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err int) {
- return syscall.Write(f.fd, b)
+func (f *File) write(b []byte) (n int, err error) {
+ for {
+ m, err := syscall.Write(f.fd, b)
+ n += m
+
+ // If the syscall wrote some data but not all (short write)
+ // or it returned EINTR, then assume it stopped early for
+ // reasons that are uninteresting to the caller, and try again.
+ if 0 < m && m < len(b) || err == syscall.EINTR {
+ b = b[m:]
+ continue
+ }
+
+ return n, err
+ }
+ panic("not reached")
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
return syscall.Pwrite(f.fd, b, off)
}
@@ -157,19 +200,51 @@ func (f *File) pwrite(b []byte, off int64) (n int, err int) {
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
return syscall.Seek(f.fd, offset, whence)
}
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
-func Truncate(name string, size int64) Error {
- if e := syscall.Truncate(name, size); e != 0 {
- return &PathError{"truncate", name, Errno(e)}
+// If there is an error, it will be of type *PathError.
+func Truncate(name string, size int64) error {
+ if e := syscall.Truncate(name, size); e != nil {
+ return &PathError{"truncate", name, e}
}
return nil
}
+// Remove removes the named file or directory.
+// If there is an error, it will be of type *PathError.
+func Remove(name string) error {
+ // System call interface forces us to know
+ // whether name is a file or directory.
+ // Try both: it is cheaper on average than
+ // doing a Stat plus the right one.
+ e := syscall.Unlink(name)
+ if e == nil {
+ return nil
+ }
+ e1 := syscall.Rmdir(name)
+ if e1 == nil {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ // OS X and Linux differ on whether unlink(dir)
+ // returns EISDIR, so can't use that. However,
+ // both agree that rmdir(file) returns ENOTDIR,
+ // so we can use that to decide which error is real.
+ // Rmdir might also return ENOTDIR if given a bad
+ // file path, like /etc/passwd/foo, but in that case,
+ // both errors will be ENOTDIR, so it's okay to
+ // use the error from unlink.
+ if e1 != syscall.ENOTDIR {
+ e = e1
+ }
+ return &PathError{"remove", name, e}
+}
+
// basename removes trailing slashes and the leading directory name from path name
func basename(name string) string {
i := len(name) - 1
@@ -189,14 +264,14 @@ func basename(name string) string {
}
// 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) {
+// 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) {
+ if e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
@@ -204,5 +279,14 @@ func Pipe() (r *File, w *File, err Error) {
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
- return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+ return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ dir := Getenv("TMPDIR")
+ if dir == "" {
+ dir = "/tmp"
+ }
+ return dir
}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index 70dd6e241..88fa77bb8 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -5,13 +5,23 @@
package os
import (
+ "io"
"runtime"
"sync"
"syscall"
+ "unicode/utf16"
)
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong file descriptor.
+type file struct {
fd syscall.Handle
name string
dirinfo *dirInfo // nil unless directory being read
@@ -20,37 +30,39 @@ type File struct {
}
// Fd returns the Windows handle referencing the open file.
-func (file *File) Fd() syscall.Handle {
+func (file *File) Fd() uintptr {
if file == nil {
- return syscall.InvalidHandle
+ return uintptr(syscall.InvalidHandle)
}
- return file.fd
+ return uintptr(file.fd)
}
// NewFile returns a new File with the given file descriptor and name.
-func NewFile(fd syscall.Handle, name string) *File {
- if fd < 0 {
+func NewFile(fd uintptr, name string) *File {
+ h := syscall.Handle(fd)
+ if h == syscall.InvalidHandle {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: h, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
// Auxiliary information if the File describes a directory
type dirInfo struct {
- stat syscall.Stat_t
- usefirststat bool
+ data syscall.Win32finddata
+ needdata bool
+ path string
}
const DevNull = "NUL"
-func (file *File) isdir() bool { return file != nil && file.dirinfo != nil }
+func (f *file) isdir() bool { return f != nil && f.dirinfo != nil }
-func openFile(name string, flag int, perm uint32) (file *File, err Error) {
- r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+func openFile(name string, flag int, perm FileMode) (file *File, err error) {
+ r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
+ if e != nil {
+ return nil, &PathError{"open", name, e}
}
// There's a race here with fork/exec, which we are
@@ -59,17 +71,21 @@ func openFile(name string, flag int, perm uint32) (file *File, err Error) {
syscall.CloseOnExec(r)
}
- return NewFile(r, name), nil
+ return NewFile(uintptr(r), name), nil
}
-func openDir(name string) (file *File, err Error) {
+func openDir(name string) (file *File, err error) {
d := new(dirInfo)
- r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+"\\*"), &d.stat.Windata)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+ r, e := syscall.FindFirstFile(syscall.StringToUTF16Ptr(name+`\*`), &d.data)
+ if e != nil {
+ return nil, &PathError{"open", name, e}
+ }
+ d.path = name
+ if !isAbs(d.path) {
+ cwd, _ := Getwd()
+ d.path = cwd + `\` + d.path
}
- f := NewFile(r, name)
- d.usefirststat = true
+ f := NewFile(uintptr(r), name)
f.dirinfo = d
return f, nil
}
@@ -78,14 +94,17 @@ func openDir(name string) (file *File, err Error) {
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
-// It returns the File and an Error, if any.
-func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
+// If there is an error, it will be of type *PathError.
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+ if name == "" {
+ return nil, &PathError{"open", name, syscall.ENOENT}
+ }
// TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
r, e := openDir(name)
if e == nil {
if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
r.Close()
- return nil, &PathError{"open", name, EISDIR}
+ return nil, &PathError{"open", name, syscall.EISDIR}
}
return r, nil
}
@@ -93,33 +112,28 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
if e == nil {
return r, nil
}
- // Imitating Unix behavior by replacing syscall.ERROR_PATH_NOT_FOUND with
- // os.ENOTDIR. Not sure if we should go into that.
- if e2, ok := e.(*PathError); ok {
- if e3, ok := e2.Error.(Errno); ok {
- if e3 == Errno(syscall.ERROR_PATH_NOT_FOUND) {
- return nil, &PathError{"open", name, ENOTDIR}
- }
- }
- }
return nil, e
}
// Close closes the File, rendering it unusable for I/O.
-// It returns an Error, if any.
-func (file *File) Close() Error {
- if file == nil || file.fd < 0 {
- return EINVAL
+// It returns an error, if any.
+func (file *File) Close() error {
+ return file.file.close()
+}
+
+func (file *file) close() error {
+ if file == nil || file.fd == syscall.InvalidHandle {
+ return syscall.EINVAL
}
- var e int
+ var e error
if file.isdir() {
e = syscall.FindClose(syscall.Handle(file.fd))
} else {
e = syscall.CloseHandle(syscall.Handle(file.fd))
}
- var err Error
- if e != 0 {
- err = &PathError{"close", file.name, Errno(e)}
+ var err error
+ if e != nil {
+ err = &PathError{"close", file.name, e}
}
file.fd = syscall.InvalidHandle // so it can't be closed again
@@ -128,51 +142,13 @@ func (file *File) Close() Error {
return err
}
-func (file *File) statFile(name string) (fi *FileInfo, err Error) {
- var stat syscall.ByHandleFileInformation
- e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &stat)
- if e != 0 {
- return nil, &PathError{"stat", file.name, Errno(e)}
- }
- return fileInfoFromByHandleInfo(new(FileInfo), file.name, &stat), nil
-}
-
-// Stat returns the FileInfo structure describing file.
-// It returns the FileInfo and an error, if any.
-func (file *File) Stat() (fi *FileInfo, err Error) {
- if file == nil || file.fd < 0 {
- return nil, EINVAL
- }
- if file.isdir() {
- // I don't know any better way to do that for directory
- return Stat(file.name)
- }
- return file.statFile(file.name)
-}
-
-// Readdir reads the contents of the directory associated with file and
-// 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
-// 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) {
- if file == nil || file.fd < 0 {
- return nil, EINVAL
+func (file *File) readdir(n int) (fi []FileInfo, err error) {
+ if file == nil || file.fd == syscall.InvalidHandle {
+ return nil, syscall.EINVAL
}
if !file.isdir() {
- return nil, &PathError{"Readdir", file.name, ENOTDIR}
+ return nil, &PathError{"Readdir", file.name, syscall.ENOTDIR}
}
- di := file.dirinfo
wantAll := n <= 0
size := n
if wantAll {
@@ -180,16 +156,15 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
size = 100
}
fi = make([]FileInfo, 0, size) // Empty with room to grow.
+ d := &file.dirinfo.data
for n != 0 {
- if di.usefirststat {
- di.usefirststat = false
- } else {
- e := syscall.FindNextFile(syscall.Handle(file.fd), &di.stat.Windata)
- if e != 0 {
+ if file.dirinfo.needdata {
+ e := syscall.FindNextFile(syscall.Handle(file.fd), d)
+ if e != nil {
if e == syscall.ERROR_NO_MORE_FILES {
break
} else {
- err = &PathError{"FindNextFile", file.name, Errno(e)}
+ err = &PathError{"FindNextFile", file.name, e}
if !wantAll {
fi = nil
}
@@ -197,23 +172,30 @@ func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
}
}
}
- var f FileInfo
- fileInfoFromWin32finddata(&f, &di.stat.Windata)
- if f.Name == "." || f.Name == ".." { // Useless names
+ file.dirinfo.needdata = true
+ name := string(syscall.UTF16ToString(d.FileName[0:]))
+ if name == "." || name == ".." { // Useless names
continue
}
+ f := &fileStat{
+ name: name,
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSys(file.dirinfo.path+`\`+name, d.LastAccessTime, d.CreationTime),
+ }
n--
fi = append(fi, f)
}
if !wantAll && len(fi) == 0 {
- return fi, EOF
+ return fi, io.EOF
}
return fi, nil
}
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err int) {
+func (f *File) read(b []byte) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Read(f.fd, b)
@@ -222,11 +204,11 @@ func (f *File) read(b []byte) (n int, err int) {
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to 0.
-func (f *File) pread(b []byte, off int64) (n int, err int) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
curoffset, e := syscall.Seek(f.fd, 0, 1)
- if e != 0 {
+ if e != nil {
return 0, e
}
defer syscall.Seek(f.fd, curoffset, 0)
@@ -236,15 +218,15 @@ func (f *File) pread(b []byte, off int64) (n int, err int) {
}
var done uint32
e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err int) {
+func (f *File) write(b []byte) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Write(f.fd, b)
@@ -252,11 +234,11 @@ func (f *File) write(b []byte) (n int, err int) {
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
f.l.Lock()
defer f.l.Unlock()
curoffset, e := syscall.Seek(f.fd, 0, 1)
- if e != 0 {
+ if e != nil {
return 0, e
}
defer syscall.Seek(f.fd, curoffset, 0)
@@ -266,17 +248,17 @@ func (f *File) pwrite(b []byte, off int64) (n int, err int) {
}
var done uint32
e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
f.l.Lock()
defer f.l.Unlock()
return syscall.Seek(f.fd, offset, whence)
@@ -284,7 +266,7 @@ func (f *File) seek(offset int64, whence int) (ret int64, err int) {
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
-func Truncate(name string, size int64) Error {
+func Truncate(name string, size int64) error {
f, e := OpenFile(name, O_WRONLY|O_CREATE, 0666)
if e != nil {
return e
@@ -297,15 +279,45 @@ func Truncate(name string, size int64) Error {
return nil
}
+// Remove removes the named file or directory.
+// If there is an error, it will be of type *PathError.
+func Remove(name string) error {
+ p := &syscall.StringToUTF16(name)[0]
+
+ // Go file interface forces us to know whether
+ // name is a file or directory. Try both.
+ e := syscall.DeleteFile(p)
+ if e == nil {
+ return nil
+ }
+ e1 := syscall.RemoveDirectory(p)
+ if e1 == nil {
+ return nil
+ }
+
+ // Both failed: figure out which error to return.
+ if e1 != e {
+ a, e2 := syscall.GetFileAttributes(p)
+ if e2 != nil {
+ e = e2
+ } else {
+ if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+ e = e1
+ }
+ }
+ }
+ return &PathError{"remove", name, e}
+}
+
// 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) {
+// It returns the files and an error, if any.
+func Pipe() (r *File, w *File, err error) {
var p [2]syscall.Handle
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
- if iserror(e) {
+ if e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
@@ -313,5 +325,23 @@ func Pipe() (r *File, w *File, err Error) {
syscall.CloseOnExec(p[1])
syscall.ForkLock.RUnlock()
- return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
+ return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
+}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ const pathSep = '\\'
+ dirw := make([]uint16, syscall.MAX_PATH)
+ n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ dirw = make([]uint16, n)
+ n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+ if n > uint32(len(dirw)) {
+ n = 0
+ }
+ }
+ if n > 0 && dirw[n-1] == pathSep {
+ n--
+ }
+ return string(utf16.Decode(dirw[0:n]))
}
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
index 4c142ad3a..81d8fed92 100644
--- a/src/pkg/os/getwd.go
+++ b/src/pkg/os/getwd.go
@@ -12,7 +12,7 @@ import (
// current directory. If the current directory can be
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
-func Getwd() (string, Error) {
+func Getwd() (pwd string, err error) {
// If the operating system provides a Getwd call, use it.
if syscall.ImplementsGetwd {
s, e := syscall.Getwd()
@@ -27,10 +27,10 @@ func Getwd() (string, Error) {
// Clumsy but widespread kludge:
// if $PWD is set and matches ".", use it.
- pwd := Getenv("PWD")
+ pwd = Getenv("PWD")
if len(pwd) > 0 && pwd[0] == '/' {
d, err := Stat(pwd)
- if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+ if err == nil && SameFile(dot, d) {
return pwd, nil
}
}
@@ -42,7 +42,7 @@ func Getwd() (string, Error) {
// Can't stat root - no hope.
return "", err
}
- if root.Dev == dot.Dev && root.Ino == dot.Ino {
+ if SameFile(root, dot) {
return "/", nil
}
@@ -52,7 +52,7 @@ func Getwd() (string, Error) {
pwd = ""
for parent := ".."; ; parent = "../" + parent {
if len(parent) >= 1024 { // Sanity check
- return "", ENAMETOOLONG
+ return "", syscall.ENAMETOOLONG
}
fd, err := Open(parent)
if err != nil {
@@ -67,14 +67,14 @@ func Getwd() (string, Error) {
}
for _, name := range names {
d, _ := Lstat(parent + "/" + name)
- if d.Dev == dot.Dev && d.Ino == dot.Ino {
+ if SameFile(d, dot) {
pwd = "/" + name + pwd
goto Found
}
}
}
fd.Close()
- return "", ENOENT
+ return "", ErrNotExist
Found:
pd, err := fd.Stat()
@@ -82,7 +82,7 @@ func Getwd() (string, Error) {
return "", err
}
fd.Close()
- if pd.Dev == root.Dev && pd.Ino == root.Ino {
+ if SameFile(pd, root) {
break
}
// Set up for next round.
diff --git a/src/pkg/os/inotify/Makefile b/src/pkg/os/inotify/Makefile
deleted file mode 100644
index 90e18da57..000000000
--- a/src/pkg/os/inotify/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=os/inotify
-
-GOFILES_linux=\
- inotify_linux.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../../Make.pkg
diff --git a/src/pkg/os/inotify/inotify_linux.go b/src/pkg/os/inotify/inotify_linux.go
deleted file mode 100644
index 99fa51622..000000000
--- a/src/pkg/os/inotify/inotify_linux.go
+++ /dev/null
@@ -1,288 +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 inotify implements a wrapper for the Linux inotify system.
-
-Example:
- watcher, err := inotify.NewWatcher()
- if err != nil {
- log.Fatal(err)
- }
- err = watcher.Watch("/tmp")
- if err != nil {
- log.Fatal(err)
- }
- for {
- select {
- case ev := <-watcher.Event:
- log.Println("event:", ev)
- case err := <-watcher.Error:
- log.Println("error:", err)
- }
- }
-
-*/
-package inotify
-
-import (
- "fmt"
- "os"
- "strings"
- "syscall"
- "unsafe"
-)
-
-type Event struct {
- Mask uint32 // Mask of events
- Cookie uint32 // Unique cookie associating related events (for rename(2))
- Name string // File name (optional)
-}
-
-type watch struct {
- wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
- flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
-}
-
-type Watcher struct {
- fd int // File descriptor (as returned by the inotify_init() syscall)
- watches map[string]*watch // Map of inotify watches (key: path)
- paths map[int]string // Map of watched paths (key: watch descriptor)
- Error chan os.Error // Errors are sent on this channel
- Event chan *Event // Events are returned on this channel
- done chan bool // Channel for sending a "quit message" to the reader goroutine
- isClosed bool // Set to true when Close() is first called
-}
-
-// NewWatcher creates and returns a new inotify instance using inotify_init(2)
-func NewWatcher() (*Watcher, os.Error) {
- fd, errno := syscall.InotifyInit()
- if fd == -1 {
- return nil, os.NewSyscallError("inotify_init", errno)
- }
- w := &Watcher{
- fd: fd,
- watches: make(map[string]*watch),
- paths: make(map[int]string),
- Event: make(chan *Event),
- Error: make(chan os.Error),
- done: make(chan bool, 1),
- }
-
- go w.readEvents()
- return w, nil
-}
-
-// Close closes an inotify watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the inotify instance
-func (w *Watcher) Close() os.Error {
- if w.isClosed {
- return nil
- }
- w.isClosed = true
-
- // Send "quit" message to the reader goroutine
- w.done <- true
- for path := range w.watches {
- w.RemoveWatch(path)
- }
-
- return nil
-}
-
-// AddWatch adds path to the watched file set.
-// The flags are interpreted as described in inotify_add_watch(2).
-func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
- if w.isClosed {
- return os.NewError("inotify instance already closed")
- }
-
- watchEntry, found := w.watches[path]
- if found {
- watchEntry.flags |= flags
- flags |= syscall.IN_MASK_ADD
- }
- wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
- if wd == -1 {
- return &os.PathError{"inotify_add_watch", path, os.Errno(errno)}
- }
-
- if !found {
- w.watches[path] = &watch{wd: uint32(wd), flags: flags}
- w.paths[wd] = path
- }
- return nil
-}
-
-// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) Watch(path string) os.Error {
- return w.AddWatch(path, IN_ALL_EVENTS)
-}
-
-// RemoveWatch removes path from the watched file set.
-func (w *Watcher) RemoveWatch(path string) os.Error {
- watch, ok := w.watches[path]
- if !ok {
- return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
- }
- success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
- if success == -1 {
- return os.NewSyscallError("inotify_rm_watch", errno)
- }
- w.watches[path] = nil, false
- return nil
-}
-
-// readEvents reads from the inotify file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
-func (w *Watcher) readEvents() {
- var (
- buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
- n int // Number of bytes read with read()
- errno int // Syscall errno
- )
-
- for {
- n, errno = syscall.Read(w.fd, buf[0:])
- // See if there is a message on the "done" channel
- var done bool
- select {
- case done = <-w.done:
- default:
- }
-
- // If EOF or a "done" message is received
- if n == 0 || done {
- errno := syscall.Close(w.fd)
- if errno == -1 {
- w.Error <- os.NewSyscallError("close", errno)
- }
- close(w.Event)
- close(w.Error)
- return
- }
- if n < 0 {
- w.Error <- os.NewSyscallError("read", errno)
- continue
- }
- if n < syscall.SizeofInotifyEvent {
- w.Error <- os.NewError("inotify: short read in readEvents()")
- continue
- }
-
- var offset uint32 = 0
- // We don't know how many events we just read into the buffer
- // While the offset points to at least one whole event...
- for offset <= uint32(n-syscall.SizeofInotifyEvent) {
- // Point "raw" to the event in the buffer
- raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
- event := new(Event)
- event.Mask = uint32(raw.Mask)
- event.Cookie = uint32(raw.Cookie)
- nameLen := uint32(raw.Len)
- // If the event happened to the watched directory or the watched file, the kernel
- // doesn't append the filename to the event, but we would like to always fill the
- // the "Name" field with a valid filename. We retrieve the path of the watch from
- // the "paths" map.
- event.Name = w.paths[int(raw.Wd)]
- if nameLen > 0 {
- // Point "bytes" at the first byte of the filename
- bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
- // The filename is padded with NUL bytes. TrimRight() gets rid of those.
- event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
- }
- // Send the event on the events channel
- w.Event <- event
-
- // Move to the next event in the buffer
- offset += syscall.SizeofInotifyEvent + nameLen
- }
- }
-}
-
-// String formats the event e in the form
-// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
-func (e *Event) String() string {
- var events string = ""
-
- m := e.Mask
- for _, b := range eventBits {
- if m&b.Value != 0 {
- m &^= b.Value
- events += "|" + b.Name
- }
- }
-
- if m != 0 {
- events += fmt.Sprintf("|%#x", m)
- }
- if len(events) > 0 {
- events = " == " + events[1:]
- }
-
- return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
-}
-
-const (
- // Options for inotify_init() are not exported
- // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
- // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
-
- // Options for AddWatch
- IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
- IN_ONESHOT uint32 = syscall.IN_ONESHOT
- IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
-
- // The "IN_MASK_ADD" option is not exported, as AddWatch
- // adds it automatically, if there is already a watch for the given path
- // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
-
- // Events
- IN_ACCESS uint32 = syscall.IN_ACCESS
- IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
- IN_ATTRIB uint32 = syscall.IN_ATTRIB
- IN_CLOSE uint32 = syscall.IN_CLOSE
- IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
- IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
- IN_CREATE uint32 = syscall.IN_CREATE
- IN_DELETE uint32 = syscall.IN_DELETE
- IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
- IN_MODIFY uint32 = syscall.IN_MODIFY
- IN_MOVE uint32 = syscall.IN_MOVE
- IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
- IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
- IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
- IN_OPEN uint32 = syscall.IN_OPEN
-
- // Special events
- IN_ISDIR uint32 = syscall.IN_ISDIR
- IN_IGNORED uint32 = syscall.IN_IGNORED
- IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
- IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
-)
-
-var eventBits = []struct {
- Value uint32
- Name string
-}{
- {IN_ACCESS, "IN_ACCESS"},
- {IN_ATTRIB, "IN_ATTRIB"},
- {IN_CLOSE, "IN_CLOSE"},
- {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
- {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
- {IN_CREATE, "IN_CREATE"},
- {IN_DELETE, "IN_DELETE"},
- {IN_DELETE_SELF, "IN_DELETE_SELF"},
- {IN_MODIFY, "IN_MODIFY"},
- {IN_MOVE, "IN_MOVE"},
- {IN_MOVED_FROM, "IN_MOVED_FROM"},
- {IN_MOVED_TO, "IN_MOVED_TO"},
- {IN_MOVE_SELF, "IN_MOVE_SELF"},
- {IN_OPEN, "IN_OPEN"},
- {IN_ISDIR, "IN_ISDIR"},
- {IN_IGNORED, "IN_IGNORED"},
- {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
- {IN_UNMOUNT, "IN_UNMOUNT"},
-}
diff --git a/src/pkg/os/inotify/inotify_linux_test.go b/src/pkg/os/inotify/inotify_linux_test.go
deleted file mode 100644
index aa72604eb..000000000
--- a/src/pkg/os/inotify/inotify_linux_test.go
+++ /dev/null
@@ -1,96 +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 inotify
-
-import (
- "os"
- "time"
- "testing"
-)
-
-func TestInotifyEvents(t *testing.T) {
- // Create an inotify watcher instance and initialize it
- watcher, err := NewWatcher()
- if err != nil {
- t.Fatalf("NewWatcher() failed: %s", err)
- }
-
- // Add a watch for "_test"
- err = watcher.Watch("_test")
- if err != nil {
- t.Fatalf("Watcher.Watch() failed: %s", err)
- }
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- const testFile string = "_test/TestInotifyEvents.testfile"
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var eventsReceived = 0
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == testFile {
- eventsReceived++
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the inotify event queue
- _, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 1 s to be sure
- time.Sleep(1000e6) // 1000 ms
- if eventsReceived == 0 {
- t.Fatal("inotify event hasn't been received after 1 second")
- }
-
- // Try closing the inotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(1e9):
- t.Fatal("event stream was not closed after 1 second")
- }
-}
-
-func TestInotifyClose(t *testing.T) {
- watcher, _ := NewWatcher()
- watcher.Close()
-
- done := false
- go func() {
- watcher.Close()
- done = true
- }()
-
- time.Sleep(50e6) // 50 ms
- if !done {
- t.Fatal("double Close() test failed: second Close() call didn't return")
- }
-
- err := watcher.Watch("_test")
- if err == nil {
- t.Fatal("expected error on Watch() after Close(), got nil")
- }
-}
diff --git a/src/pkg/os/mkunixsignals.sh b/src/pkg/os/mkunixsignals.sh
deleted file mode 100755
index 4bbc43f3d..000000000
--- a/src/pkg/os/mkunixsignals.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-echo '// ./mkunix.sh' "$1"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
-echo
-
-cat <<EOH
-package os
-
-import (
- "syscall"
-)
-
-var _ = syscall.Open // in case there are zero signals
-
-const (
-EOH
-
-sed -n 's/^[ ]*\(SIG[A-Z0-9][A-Z0-9]*\)[ ].*/ \1 = UnixSignal(syscall.\1)/p' "$1"
-
-echo ")"
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 4d60333df..dec80cc09 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -11,18 +11,19 @@ import (
"io/ioutil"
. "os"
"path/filepath"
+ "runtime"
"strings"
"syscall"
"testing"
+ "time"
)
var dot = []string{
"dir_unix.go",
- "env_unix.go",
+ "env.go",
"error.go",
"file.go",
"os_test.go",
- "time.go",
"types.go",
"stat_darwin.go",
"stat_linux.go",
@@ -34,7 +35,7 @@ type sysDir struct {
}
var sysdir = func() (sd *sysDir) {
- switch syscall.OS {
+ switch runtime.GOOS {
case "windows":
sd = &sysDir{
Getenv("SystemRoot") + "\\system32\\drivers\\etc",
@@ -77,7 +78,7 @@ func size(name string, t *testing.T) int64 {
for {
n, e := file.Read(buf[0:])
len += n
- if e == EOF {
+ if e == io.EOF {
break
}
if e != nil {
@@ -88,7 +89,7 @@ func size(name string, t *testing.T) int64 {
}
func equal(name1, name2 string) (r bool) {
- switch syscall.OS {
+ switch runtime.GOOS {
case "windows":
r = strings.ToLower(name1) == strings.ToLower(name2)
default:
@@ -102,7 +103,7 @@ func newFile(testName string, t *testing.T) (f *File) {
// On Unix, override $TMPDIR in case the user
// has it set to an NFS-mounted directory.
dir := ""
- if syscall.OS != "windows" {
+ if runtime.GOOS != "windows" {
dir = "/tmp"
}
f, err := ioutil.TempFile(dir, "_Go_"+testName)
@@ -121,12 +122,12 @@ func TestStat(t *testing.T) {
if err != nil {
t.Fatal("stat failed:", err)
}
- if !equal(sfname, dir.Name) {
- t.Error("name should be ", sfname, "; is", dir.Name)
+ if !equal(sfname, dir.Name()) {
+ t.Error("name should be ", sfname, "; is", dir.Name())
}
filesize := size(path, t)
- if dir.Size != filesize {
- t.Error("size should be", filesize, "; is", dir.Size)
+ if dir.Size() != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size())
}
}
@@ -141,12 +142,12 @@ func TestFstat(t *testing.T) {
if err2 != nil {
t.Fatal("fstat failed:", err2)
}
- if !equal(sfname, dir.Name) {
- t.Error("name should be ", sfname, "; is", dir.Name)
+ if !equal(sfname, dir.Name()) {
+ t.Error("name should be ", sfname, "; is", dir.Name())
}
filesize := size(path, t)
- if dir.Size != filesize {
- t.Error("size should be", filesize, "; is", dir.Size)
+ if dir.Size() != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size())
}
}
@@ -156,12 +157,33 @@ func TestLstat(t *testing.T) {
if err != nil {
t.Fatal("lstat failed:", err)
}
- if !equal(sfname, dir.Name) {
- t.Error("name should be ", sfname, "; is", dir.Name)
+ if !equal(sfname, dir.Name()) {
+ t.Error("name should be ", sfname, "; is", dir.Name())
}
filesize := size(path, t)
- if dir.Size != filesize {
- t.Error("size should be", filesize, "; is", dir.Size)
+ if dir.Size() != filesize {
+ t.Error("size should be", filesize, "; is", dir.Size())
+ }
+}
+
+// Read with length 0 should not return EOF.
+func TestRead0(t *testing.T) {
+ path := sfdir + "/" + sfname
+ f, err := Open(path)
+ if err != nil {
+ t.Fatal("open failed:", err)
+ }
+ defer f.Close()
+
+ b := make([]byte, 0)
+ n, err := f.Read(b)
+ if n != 0 || err != nil {
+ t.Errorf("Read(0) = %d, %v, want 0, nil", n, err)
+ }
+ b = make([]byte, 100)
+ n, err = f.Read(b)
+ if n <= 0 || err != nil {
+ t.Errorf("Read(100) = %d, %v, want >0, nil", n, err)
}
}
@@ -207,7 +229,7 @@ func testReaddir(dir string, contents []string, t *testing.T) {
for _, m := range contents {
found := false
for _, n := range s {
- if equal(m, n.Name) {
+ if equal(m, n.Name()) {
if found {
t.Error("present twice:", m)
}
@@ -236,7 +258,7 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
count := 0
for {
d, err := file.Readdirnames(1)
- if err == EOF {
+ if err == io.EOF {
break
}
if err != nil {
@@ -256,7 +278,7 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
func TestReaddirnamesOneAtATime(t *testing.T) {
// big directory that doesn't change often.
dir := "/usr/bin"
- switch syscall.OS {
+ switch runtime.GOOS {
case "windows":
dir = Getenv("SystemRoot") + "\\system32"
case "plan9":
@@ -307,14 +329,14 @@ func TestReaddirNValues(t *testing.T) {
var d *File
openDir := func() {
- var err Error
+ var err error
d, err = Open(dir)
if err != nil {
t.Fatalf("Open directory: %v", err)
}
}
- readDirExpect := func(n, want int, wantErr Error) {
+ 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)
@@ -324,7 +346,7 @@ func TestReaddirNValues(t *testing.T) {
}
}
- readDirNamesExpect := func(n, want int, wantErr Error) {
+ 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)
@@ -334,7 +356,7 @@ func TestReaddirNValues(t *testing.T) {
}
}
- for _, fn := range []func(int, int, Error){readDirExpect, readDirNamesExpect} {
+ for _, fn := range []func(int, int, error){readDirExpect, readDirNamesExpect} {
// Test the slurp case
openDir()
fn(0, 105, nil)
@@ -353,14 +375,14 @@ func TestReaddirNValues(t *testing.T) {
fn(1, 1, nil)
fn(2, 2, nil)
fn(105, 102, nil) // and tests buffer >100 case
- fn(3, 0, EOF)
+ fn(3, 0, io.EOF)
d.Close()
}
}
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows or Plan 9.
- if syscall.OS == "windows" || syscall.OS == "plan9" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@@ -386,14 +408,14 @@ func TestHardLink(t *testing.T) {
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ if !SameFile(tostat, fromstat) {
t.Errorf("link %q, %q did not create hard link", to, from)
}
}
func TestSymLink(t *testing.T) {
// Symlinks are not supported under windows or Plan 9.
- if syscall.OS == "windows" || syscall.OS == "plan9" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
from, to := "symlinktestfrom", "symlinktestto"
@@ -411,32 +433,32 @@ func TestSymLink(t *testing.T) {
t.Fatalf("symlink %q, %q failed: %v", to, from, err)
}
defer Remove(from)
- tostat, err := Stat(to)
+ tostat, err := Lstat(to)
if err != nil {
t.Fatalf("stat %q failed: %v", to, err)
}
- if tostat.FollowedSymlink {
- t.Fatalf("stat %q claims to have followed a symlink", to)
+ if tostat.Mode()&ModeSymlink != 0 {
+ t.Fatalf("stat %q claims to have found a symlink", to)
}
fromstat, err := Stat(from)
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+ if !SameFile(tostat, fromstat) {
t.Errorf("symlink %q, %q did not create symlink", to, from)
}
fromstat, err = Lstat(from)
if err != nil {
t.Fatalf("lstat %q failed: %v", from, err)
}
- if !fromstat.IsSymlink() {
+ if fromstat.Mode()&ModeSymlink == 0 {
t.Fatalf("symlink %q, %q did not create symlink", to, from)
}
fromstat, err = Stat(from)
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if !fromstat.FollowedSymlink {
+ if fromstat.Mode()&ModeSymlink != 0 {
t.Fatalf("stat %q did not follow symlink", from)
}
s, err := Readlink(from)
@@ -455,7 +477,7 @@ func TestSymLink(t *testing.T) {
func TestLongSymlink(t *testing.T) {
// Symlinks are not supported under windows or Plan 9.
- if syscall.OS == "windows" || syscall.OS == "plan9" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
s := "0123456789abcdef"
@@ -508,7 +530,6 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
if err != nil {
t.Fatalf("StartProcess: %v", err)
}
- defer p.Release()
w.Close()
var b bytes.Buffer
@@ -519,13 +540,13 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
t.Errorf("exec %q returned %q wanted %q",
strings.Join(append([]string{cmd}, args...), " "), output, expect)
}
- p.Wait(0)
+ p.Wait()
}
func TestStartProcess(t *testing.T) {
var dir, cmd, le string
var args []string
- if syscall.OS == "windows" {
+ if runtime.GOOS == "windows" {
le = "\r\n"
cmd = Getenv("COMSPEC")
dir = Getenv("SystemRoot")
@@ -544,19 +565,19 @@ func TestStartProcess(t *testing.T) {
exec(t, cmddir, cmdbase, args, filepath.Clean(cmddir)+le)
}
-func checkMode(t *testing.T, path string, mode uint32) {
+func checkMode(t *testing.T, path string, mode FileMode) {
dir, err := Stat(path)
if err != nil {
t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
}
- if dir.Mode&0777 != mode {
- t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
+ if dir.Mode()&0777 != mode {
+ t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
}
}
func TestChmod(t *testing.T) {
// Chmod is not supported under windows.
- if syscall.OS == "windows" {
+ if runtime.GOOS == "windows" {
return
}
f := newFile("TestChmod", t)
@@ -574,73 +595,13 @@ func TestChmod(t *testing.T) {
checkMode(t, f.Name(), 0123)
}
-func checkUidGid(t *testing.T, path string, uid, gid int) {
- dir, err := Stat(path)
- if err != nil {
- t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
- }
- if dir.Uid != uid {
- t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
- }
- if dir.Gid != gid {
- t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
- }
-}
-
-func TestChown(t *testing.T) {
- // Chown is not supported under windows or Plan 9.
- // Plan9 provides a native ChownPlan9 version instead.
- if syscall.OS == "windows" || syscall.OS == "plan9" {
- return
- }
- // Use TempDir() to make sure we're on a local file system,
- // so that the group ids returned by Getgroups will be allowed
- // on the file. On NFS, the Getgroups groups are
- // basically useless.
- f := newFile("TestChown", t)
- defer Remove(f.Name())
- defer f.Close()
- dir, err := f.Stat()
- if err != nil {
- t.Fatalf("stat %s: %s", f.Name(), err)
- }
-
- // Can't change uid unless root, but can try
- // changing the group id. First try our current group.
- gid := Getgid()
- t.Log("gid:", gid)
- if err = Chown(f.Name(), -1, gid); err != nil {
- t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
- }
- checkUidGid(t, f.Name(), dir.Uid, gid)
-
- // Then try all the auxiliary groups.
- groups, err := Getgroups()
- if err != nil {
- t.Fatalf("getgroups: %s", err)
- }
- t.Log("groups: ", groups)
- for _, g := range groups {
- if err = Chown(f.Name(), -1, g); err != nil {
- t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
- }
- checkUidGid(t, f.Name(), dir.Uid, g)
-
- // change back to gid to test fd.Chown
- if err = f.Chown(-1, gid); err != nil {
- t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
- }
- checkUidGid(t, f.Name(), dir.Uid, gid)
- }
-}
-
func checkSize(t *testing.T, f *File, size int64) {
dir, err := f.Stat()
if err != nil {
t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
}
- if dir.Size != size {
- t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
+ if dir.Size() != size {
+ t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
}
}
@@ -692,43 +653,44 @@ func TestChtimes(t *testing.T) {
f.Write([]byte("hello, world\n"))
f.Close()
- preStat, err := Stat(f.Name())
+ st, err := Stat(f.Name())
if err != nil {
t.Fatalf("Stat %s: %s", f.Name(), err)
}
+ preStat := st
// Move access and modification time back a second
- const OneSecond = 1e9 // in nanoseconds
- err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+ at := Atime(preStat)
+ mt := preStat.ModTime()
+ err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
if err != nil {
t.Fatalf("Chtimes %s: %s", f.Name(), err)
}
- postStat, err := Stat(f.Name())
+ st, err = Stat(f.Name())
if err != nil {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
+ postStat := st
/* Plan 9:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
contents are accessed; also, it is set whenever mtime is set.
*/
- if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
- t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
- preStat.Atime_ns,
- postStat.Atime_ns)
+ pat := Atime(postStat)
+ pmt := postStat.ModTime()
+ if !pat.Before(at) && runtime.GOOS != "plan9" {
+ t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
}
- if postStat.Mtime_ns >= preStat.Mtime_ns {
- t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
- preStat.Mtime_ns,
- postStat.Mtime_ns)
+ if !pmt.Before(mt) {
+ t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
}
}
func TestChdirAndGetwd(t *testing.T) {
// TODO(brainman): file.Chdir() is not implemented on windows.
- if syscall.OS == "windows" {
+ if runtime.GOOS == "windows" {
return
}
fd, err := Open(".")
@@ -739,7 +701,7 @@ func TestChdirAndGetwd(t *testing.T) {
// (unlike, say, /var, /etc, and /tmp).
dirs := []string{"/", "/usr/bin"}
// /usr/bin does not usually exist on Plan 9.
- if syscall.OS == "plan9" {
+ if runtime.GOOS == "plan9" {
dirs = []string{"/", "/usr"}
}
for mode := 0; mode < 2; mode++ {
@@ -781,19 +743,6 @@ func TestChdirAndGetwd(t *testing.T) {
fd.Close()
}
-func TestTime(t *testing.T) {
- // Just want to check that Time() is getting something.
- // A common failure mode on Darwin is to get 0, 0,
- // because it returns the time in registers instead of
- // filling in the structure passed to the system call.
- // Too bad the compiler doesn't know that
- // 365.24*86400 is an integer.
- sec, nsec, err := Time()
- if sec < (2009-1970)*36524*864 {
- t.Errorf("Time() = %d, %d, %s; not plausible", sec, nsec, err)
- }
-}
-
func TestSeek(t *testing.T) {
f := newFile("TestSeek", t)
defer Remove(f.Name())
@@ -820,7 +769,7 @@ func TestSeek(t *testing.T) {
for i, tt := range tests {
off, err := f.Seek(tt.in, tt.whence)
if off != tt.out || err != nil {
- if e, ok := err.(*PathError); ok && e.Error == EINVAL && tt.out > 1<<32 {
+ if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
// Reiserfs rejects the big seeks.
// http://code.google.com/p/go/issues/detail?id=91
break
@@ -833,24 +782,24 @@ func TestSeek(t *testing.T) {
type openErrorTest struct {
path string
mode int
- error Error
+ error error
}
var openErrorTests = []openErrorTest{
{
sfdir + "/no-such-file",
O_RDONLY,
- ENOENT,
+ syscall.ENOENT,
},
{
sfdir,
O_WRONLY,
- EISDIR,
+ syscall.EISDIR,
},
{
sfdir + "/" + sfname + "/no-such-file",
O_WRONLY,
- ENOTDIR,
+ syscall.ENOTDIR,
},
}
@@ -864,22 +813,30 @@ func TestOpenError(t *testing.T) {
}
perr, ok := err.(*PathError)
if !ok {
- t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+ t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
}
- if perr.Error != tt.error {
- if syscall.OS == "plan9" {
- syscallErrStr := perr.Error.String()
- expectedErrStr := strings.Replace(tt.error.String(), "file ", "", 1)
+ if perr.Err != tt.error {
+ if runtime.GOOS == "plan9" {
+ syscallErrStr := perr.Err.Error()
+ expectedErrStr := strings.Replace(tt.error.Error(), "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())
+ t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Err.Error(), tt.error.Error())
}
}
}
}
+func TestOpenNoName(t *testing.T) {
+ f, err := Open("")
+ if err == nil {
+ t.Fatal(`Open("") succeeded`)
+ f.Close()
+ }
+}
+
func run(t *testing.T, cmd []string) string {
// Run /bin/hostname and collect output.
r, w, err := Pipe()
@@ -890,12 +847,11 @@ func run(t *testing.T, cmd []string) string {
if err != nil {
t.Fatal(err)
}
- defer p.Release()
w.Close()
var b bytes.Buffer
io.Copy(&b, r)
- _, err = p.Wait(0)
+ _, err = p.Wait()
if err != nil {
t.Fatalf("run hostname Wait: %v", err)
}
@@ -917,9 +873,10 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
- if syscall.OS == "windows" || syscall.OS == "plan9" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
+
// Check internal Hostname() against the output of /bin/hostname.
// Allow that the internal Hostname returns a Fully Qualified Domain Name
// and the /bin/hostname only returns the first component
@@ -947,7 +904,7 @@ func TestReadAt(t *testing.T) {
b := make([]byte, 5)
n, err := f.ReadAt(b, 7)
if err != nil || n != len(b) {
- t.Fatalf("ReadAt 7: %d, %r", n, err)
+ t.Fatalf("ReadAt 7: %d, %v", n, err)
}
if string(b) != "world" {
t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
@@ -1027,32 +984,85 @@ func TestAppend(t *testing.T) {
}
func TestStatDirWithTrailingSlash(t *testing.T) {
- // Create new dir, in _test so it will get
- // cleaned up by make if not by us.
- path := "_test/_TestStatDirWithSlash_"
- err := MkdirAll(path, 0777)
+ // Create new temporary directory and arrange to clean it up.
+ path, err := ioutil.TempDir("", "/_TestStatDirWithSlash_")
if err != nil {
- t.Fatalf("MkdirAll %q: %s", path, err)
+ t.Fatalf("TempDir: %s", err)
}
defer RemoveAll(path)
// Stat of path should succeed.
_, err = Stat(path)
if err != nil {
- t.Fatal("stat failed:", err)
+ t.Fatalf("stat %s failed: %s", path, err)
}
// Stat of path+"/" should succeed too.
- _, err = Stat(path + "/")
+ path += "/"
+ _, err = Stat(path)
if err != nil {
- t.Fatal("stat failed:", err)
+ t.Fatalf("stat %s failed: %s", path, err)
}
}
-func TestNilWaitmsgString(t *testing.T) {
- var w *Waitmsg
- s := w.String()
+func TestNilProcessStateString(t *testing.T) {
+ var ps *ProcessState
+ s := ps.String()
if s != "<nil>" {
- t.Errorf("(*Waitmsg)(nil).String() = %q, want %q", s, "<nil>")
+ t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>")
+ }
+}
+
+func TestSameFile(t *testing.T) {
+ fa, err := Create("a")
+ if err != nil {
+ t.Fatalf("Create(a): %v", err)
+ }
+ defer Remove(fa.Name())
+ fa.Close()
+ fb, err := Create("b")
+ if err != nil {
+ t.Fatalf("Create(b): %v", err)
+ }
+ defer Remove(fb.Name())
+ fb.Close()
+
+ ia1, err := Stat("a")
+ if err != nil {
+ t.Fatalf("Stat(a): %v", err)
+ }
+ ia2, err := Stat("a")
+ if err != nil {
+ t.Fatalf("Stat(a): %v", err)
+ }
+ if !SameFile(ia1, ia2) {
+ t.Errorf("files should be same")
+ }
+
+ ib, err := Stat("b")
+ if err != nil {
+ t.Fatalf("Stat(b): %v", err)
+ }
+ if SameFile(ia1, ib) {
+ t.Errorf("files should be different")
+ }
+}
+
+func TestDevNullFile(t *testing.T) {
+ f, err := Open(DevNull)
+ if err != nil {
+ t.Fatalf("Open(%s): %v", DevNull, err)
+ }
+ defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat(%s): %v", DevNull, err)
+ }
+ name := filepath.Base(DevNull)
+ if fi.Name() != name {
+ t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
+ }
+ if fi.Size() != 0 {
+ t.Fatalf("wrong file size have %d want 0", fi.Size())
}
}
diff --git a/src/pkg/os/os_unix_test.go b/src/pkg/os/os_unix_test.go
new file mode 100644
index 000000000..f8e330beb
--- /dev/null
+++ b/src/pkg/os/os_unix_test.go
@@ -0,0 +1,76 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd
+
+package os_test
+
+import (
+ . "os"
+ "runtime"
+ "syscall"
+ "testing"
+)
+
+func checkUidGid(t *testing.T, path string, uid, gid int) {
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+ }
+ sys := dir.Sys().(*syscall.Stat_t)
+ if int(sys.Uid) != uid {
+ t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
+ }
+ if int(sys.Gid) != gid {
+ t.Errorf("Stat %q: gid %d want %d", path, sys.Gid, gid)
+ }
+}
+
+func TestChown(t *testing.T) {
+ // Chown is not supported under windows or Plan 9.
+ // Plan9 provides a native ChownPlan9 version instead.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ return
+ }
+ // Use TempDir() to make sure we're on a local file system,
+ // so that the group ids returned by Getgroups will be allowed
+ // on the file. On NFS, the Getgroups groups are
+ // basically useless.
+ f := newFile("TestChown", t)
+ defer Remove(f.Name())
+ defer f.Close()
+ dir, err := f.Stat()
+ if err != nil {
+ t.Fatalf("stat %s: %s", f.Name(), err)
+ }
+
+ // Can't change uid unless root, but can try
+ // changing the group id. First try our current group.
+ gid := Getgid()
+ t.Log("gid:", gid)
+ if err = Chown(f.Name(), -1, gid); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ sys := dir.Sys().(*syscall.Stat_t)
+ checkUidGid(t, f.Name(), int(sys.Uid), gid)
+
+ // Then try all the auxiliary groups.
+ groups, err := Getgroups()
+ if err != nil {
+ t.Fatalf("getgroups: %s", err)
+ }
+ t.Log("groups: ", groups)
+ for _, g := range groups {
+ if err = Chown(f.Name(), -1, g); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
+ }
+ checkUidGid(t, f.Name(), int(sys.Uid), g)
+
+ // change back to gid to test fd.Chown
+ if err = f.Chown(-1, gid); err != nil {
+ t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+ }
+ checkUidGid(t, f.Name(), int(sys.Uid), gid)
+ }
+}
diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go
index a8dfce307..02a77ec80 100644
--- a/src/pkg/os/path.go
+++ b/src/pkg/os/path.go
@@ -4,6 +4,11 @@
package os
+import (
+ "io"
+ "syscall"
+)
+
// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
@@ -11,14 +16,14 @@ package os
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
-func MkdirAll(path string, perm uint32) Error {
+func MkdirAll(path string, perm FileMode) error {
// If path exists, stop with success or error.
dir, err := Stat(path)
if err == nil {
- if dir.IsDirectory() {
+ if dir.IsDir() {
return nil
}
- return &PathError{"mkdir", path, ENOTDIR}
+ return &PathError{"mkdir", path, syscall.ENOTDIR}
}
// Doesn't already exist; make sure parent does.
@@ -46,7 +51,7 @@ func MkdirAll(path string, perm uint32) Error {
// Handle arguments like "foo/." by
// double-checking that directory doesn't exist.
dir, err1 := Lstat(path)
- if err1 == nil && dir.IsDirectory() {
+ if err1 == nil && dir.IsDir() {
return nil
}
return err
@@ -58,7 +63,7 @@ func MkdirAll(path string, perm uint32) Error {
// It removes everything it can but returns the first error
// it encounters. If the path does not exist, RemoveAll
// returns nil (no error).
-func RemoveAll(path string) Error {
+func RemoveAll(path string) error {
// Simple case: if Remove works, we're done.
err := Remove(path)
if err == nil {
@@ -68,12 +73,12 @@ func RemoveAll(path string) Error {
// Otherwise, is this a directory we need to recurse into?
dir, serr := Lstat(path)
if serr != nil {
- if serr, ok := serr.(*PathError); ok && serr.Error == ENOENT {
+ if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
return nil
}
return serr
}
- if !dir.IsDirectory() {
+ if !dir.IsDir() {
// Not a directory; return the error from Remove.
return err
}
@@ -94,7 +99,7 @@ func RemoveAll(path string) Error {
err = err1
}
}
- if err1 == EOF {
+ if err1 == io.EOF {
break
}
// If Readdirnames returned an error, use it.
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index 31acbaa43..c1e3fb354 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -7,20 +7,19 @@ package os_test
import (
. "os"
"path/filepath"
- "testing"
"runtime"
"syscall"
+ "testing"
)
func TestMkdirAll(t *testing.T) {
- // Create new dir, in _test so it will get
- // cleaned up by make if not by us.
- path := "_test/_TestMkdirAll_/dir/./dir2"
+ tmpDir := TempDir()
+ path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
- defer RemoveAll("_test/_TestMkdirAll_")
+ defer RemoveAll(tmpDir + "/_TestMkdirAll_")
// Already exists, should succeed.
err = MkdirAll(path, 0777)
@@ -63,8 +62,8 @@ func TestMkdirAll(t *testing.T) {
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\`
+ if runtime.GOOS == "windows" {
+ path := tmpDir + `\_TestMkdirAll_\dir\.\dir2\`
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
@@ -73,8 +72,9 @@ func TestMkdirAll(t *testing.T) {
}
func TestRemoveAll(t *testing.T) {
+ tmpDir := TempDir()
// Work directory.
- path := "_test/_TestRemoveAll_"
+ path := tmpDir + "/_TestRemoveAll_"
fpath := path + "/file"
dpath := path + "/dir"
@@ -117,7 +117,7 @@ func TestRemoveAll(t *testing.T) {
// Determine if we should run the following test.
testit := true
- if syscall.OS == "windows" {
+ if runtime.GOOS == "windows" {
// Chmod is not supported under windows.
testit = false
} else {
@@ -171,19 +171,22 @@ func TestMkdirAllWithSymlink(t *testing.T) {
return
}
- err := Mkdir("_test/dir", 0755)
+ tmpDir := TempDir()
+ dir := tmpDir + "/dir"
+ err := Mkdir(dir, 0755)
if err != nil {
- t.Fatal(`Mkdir "_test/dir":`, err)
+ t.Fatalf("Mkdir %s: %s", dir, err)
}
- defer RemoveAll("_test/dir")
+ defer RemoveAll(dir)
- err = Symlink("dir", "_test/link")
+ link := tmpDir + "/link"
+ err = Symlink("dir", link)
if err != nil {
- t.Fatal(`Symlink "dir", "_test/link":`, err)
+ t.Fatalf("Symlink %s: %s", link, err)
}
- defer RemoveAll("_test/link")
+ defer RemoveAll(link)
- path := "_test/link/foo"
+ path := link + "/foo"
err = MkdirAll(path, 0755)
if err != nil {
t.Errorf("MkdirAll %q: %s", path, err)
@@ -199,7 +202,7 @@ func TestMkdirAllAtSlash(t *testing.T) {
if err != nil {
pathErr, ok := err.(*PathError)
// common for users not to be able to write to /
- if ok && pathErr.Error == EACCES {
+ if ok && pathErr.Err == syscall.EACCES {
return
}
t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
index 0d327cddd..30a167b1a 100644
--- a/src/pkg/os/path_unix.go
+++ b/src/pkg/os/path_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
package os
const (
diff --git a/src/pkg/os/proc.go b/src/pkg/os/proc.go
index dfe388f25..61545f445 100644
--- a/src/pkg/os/proc.go
+++ b/src/pkg/os/proc.go
@@ -8,8 +8,8 @@ package os
import "syscall"
-var Args []string // provided by runtime
-var Envs []string // provided by runtime
+// Args hold the command-line arguments, starting with the program name.
+var Args []string
// Getuid returns the numeric user id of the caller.
func Getuid() int { return syscall.Getuid() }
@@ -24,7 +24,7 @@ func Getgid() int { return syscall.Getgid() }
func Getegid() int { return syscall.Getegid() }
// Getgroups returns a list of the numeric ids of groups that the caller belongs to.
-func Getgroups() ([]int, Error) {
+func Getgroups() ([]int, error) {
gids, e := syscall.Getgroups()
return gids, NewSyscallError("getgroups", e)
}
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile
deleted file mode 100644
index 26f58760e..000000000
--- a/src/pkg/os/signal/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=os/signal
-GOFILES=\
- signal.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
new file mode 100644
index 000000000..d1984cf88
--- /dev/null
+++ b/src/pkg/os/signal/sig.s
@@ -0,0 +1,16 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Assembly to get into package runtime without using exported symbols.
+
+#ifdef GOARCH_arm
+#define JMP B
+#endif
+
+TEXT ·signal_enable(SB),7,$0
+ JMP runtime·signal_enable(SB)
+
+TEXT ·signal_recv(SB),7,$0
+ JMP runtime·signal_recv(SB)
+
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
index 520f3f8a9..dfdcf4061 100644
--- a/src/pkg/os/signal/signal.go
+++ b/src/pkg/os/signal/signal.go
@@ -1,33 +1,72 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package signal implements operating system-independent signal handling.
+// Package signal implements access to incoming signals.
package signal
+// BUG(rsc): This package is not yet implemented on Plan 9 and Windows.
+
import (
"os"
- "runtime"
+ "sync"
)
-// Incoming is the global signal channel.
-// All signals received by the program will be delivered to this channel.
-var Incoming <-chan os.Signal
+var handlers struct {
+ sync.Mutex
+ list []handler
+}
+
+type handler struct {
+ c chan<- os.Signal
+ sig os.Signal
+ all bool
+}
+
+// Notify causes package signal to relay incoming signals to c.
+// If no signals are listed, all incoming signals will be relayed to c.
+// Otherwise, just the listed signals will.
+//
+// Package signal will not block sending to c: the caller must ensure
+// that c has sufficient buffer space to keep up with the expected
+// signal rate. For a channel used for notification of just one signal value,
+// a buffer of size 1 is sufficient.
+//
+func Notify(c chan<- os.Signal, sig ...os.Signal) {
+ if c == nil {
+ panic("os/signal: Notify using nil channel")
+ }
-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 <- os.UnixSignal(sig)
+ handlers.Lock()
+ defer handlers.Unlock()
+ if len(sig) == 0 {
+ enableSignal(nil)
+ handlers.list = append(handlers.list, handler{c: c, all: true})
+ } else {
+ for _, s := range sig {
+ // We use nil as a special wildcard value for enableSignal,
+ // so filter it out of the list of arguments. This is safe because
+ // we will never get an incoming nil signal, so discarding the
+ // registration cannot affect the observed behavior.
+ if s != nil {
+ enableSignal(s)
+ handlers.list = append(handlers.list, handler{c: c, sig: s})
}
}
}
}
-func init() {
- runtime.Siginit()
- ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal
- Incoming = ch
- go process(ch)
+func process(sig os.Signal) {
+ handlers.Lock()
+ defer handlers.Unlock()
+
+ for _, h := range handlers.list {
+ if h.all || h.sig == sig {
+ // send but do not block for it
+ select {
+ case h.c <- sig:
+ default:
+ }
+ }
+ }
}
diff --git a/src/pkg/os/signal/signal_stub.go b/src/pkg/os/signal/signal_stub.go
new file mode 100644
index 000000000..fc227cf4c
--- /dev/null
+++ b/src/pkg/os/signal/signal_stub.go
@@ -0,0 +1,11 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+package signal
+
+import "os"
+
+func enableSignal(sig os.Signal) {}
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index 00eb29578..3494f8c34 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/os/signal/signal_test.go
@@ -2,19 +2,59 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package signal
import (
"os"
"syscall"
"testing"
+ "time"
)
-func TestSignal(t *testing.T) {
- // Send this process a SIGHUP.
- syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
+const sighup = syscall.SIGHUP
- if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
- t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
+func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
+ select {
+ case s := <-c:
+ if s != sig {
+ t.Fatalf("signal was %v, want %v", s, sig)
+ }
+ case <-time.After(1 * time.Second):
+ t.Fatalf("timeout waiting for %v", sig)
}
}
+
+func TestSignal(t *testing.T) {
+ // Ask for SIGHUP
+ c := make(chan os.Signal, 1)
+ Notify(c, sighup)
+
+ t.Logf("sighup...")
+ // Send this process a SIGHUP
+ syscall.Kill(syscall.Getpid(), sighup)
+ waitSig(t, c, sighup)
+
+ // Ask for everything we can get.
+ c1 := make(chan os.Signal, 1)
+ Notify(c1)
+
+ t.Logf("sigwinch...")
+ // Send this process a SIGWINCH
+ syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
+ waitSig(t, c1, syscall.SIGWINCH)
+
+ // Send two more SIGHUPs, to make sure that
+ // they get delivered on c1 and that not reading
+ // from c does not block everything.
+ t.Logf("sigwinch...")
+ syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
+ waitSig(t, c1, syscall.SIGHUP)
+ t.Logf("sigwinch...")
+ syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
+ waitSig(t, c1, syscall.SIGHUP)
+
+ // The first SIGHUP should be waiting for us on c.
+ waitSig(t, c, syscall.SIGHUP)
+}
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
new file mode 100644
index 000000000..20ee5f26a
--- /dev/null
+++ b/src/pkg/os/signal/signal_unix.go
@@ -0,0 +1,38 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd windows
+
+package signal
+
+import (
+ "os"
+ "syscall"
+)
+
+// In assembly.
+func signal_enable(uint32)
+func signal_recv() uint32
+
+func loop() {
+ for {
+ process(syscall.Signal(signal_recv()))
+ }
+}
+
+func init() {
+ signal_enable(0) // first call - initialize
+ go loop()
+}
+
+func enableSignal(sig os.Signal) {
+ switch sig := sig.(type) {
+ case nil:
+ signal_enable(^uint32(0))
+ case syscall.Signal:
+ signal_enable(uint32(sig))
+ default:
+ // Can ignore: this signal (whatever it is) will never come in.
+ }
+}
diff --git a/src/pkg/os/signal/signal_windows_test.go b/src/pkg/os/signal/signal_windows_test.go
new file mode 100644
index 000000000..8d807ff7b
--- /dev/null
+++ b/src/pkg/os/signal/signal_windows_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package signal
+
+import (
+ "flag"
+ "os"
+ "syscall"
+ "testing"
+ "time"
+)
+
+var runCtrlBreakTest = flag.Bool("run_ctlbrk_test", false, "force to run Ctrl+Break test")
+
+func sendCtrlBreak(t *testing.T) {
+ d, e := syscall.LoadDLL("kernel32.dll")
+ if e != nil {
+ t.Fatalf("LoadDLL: %v\n", e)
+ }
+ p, e := d.FindProc("GenerateConsoleCtrlEvent")
+ if e != nil {
+ t.Fatalf("FindProc: %v\n", e)
+ }
+ r, _, e := p.Call(0, 0)
+ if r == 0 {
+ t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
+ }
+}
+
+func TestCtrlBreak(t *testing.T) {
+ if !*runCtrlBreakTest {
+ t.Logf("test disabled; use -run_ctlbrk_test to enable")
+ return
+ }
+ go func() {
+ time.Sleep(1 * time.Second)
+ sendCtrlBreak(t)
+ }()
+ c := make(chan os.Signal, 10)
+ Notify(c)
+ select {
+ case s := <-c:
+ if s != os.Interrupt {
+ t.Fatalf("Wrong signal received: got %q, want %q\n", s, os.Interrupt)
+ }
+ case <-time.After(3 * time.Second):
+ t.Fatalf("Timeout waiting for Ctrl+Break\n")
+ }
+}
diff --git a/src/pkg/os/stat_darwin.go b/src/pkg/os/stat_darwin.go
index 0661a6d59..2e5967d5c 100644
--- a/src/pkg/os/stat_darwin.go
+++ b/src/pkg/os/stat_darwin.go
@@ -4,29 +4,58 @@
package os
-import "syscall"
+import (
+ "syscall"
+ "time"
+)
-func isSymlink(stat *syscall.Stat_t) bool {
- return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
- fi.Dev = uint64(stat.Dev)
- fi.Ino = 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 = stat.Size
- fi.Blksize = int64(stat.Blksize)
- fi.Blocks = stat.Blocks
- fi.Atime_ns = syscall.TimespecToNsec(stat.Atimespec)
- fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
- fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
- fi.Name = basename(name)
- if isSymlink(lstat) && !isSymlink(stat) {
- fi.FollowedSymlink = true
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtimespec),
+ sys: st,
}
- return fi
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK, syscall.S_IFWHT:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atimespec)
}
diff --git a/src/pkg/os/stat_freebsd.go b/src/pkg/os/stat_freebsd.go
index 454165d4e..6ba84f438 100644
--- a/src/pkg/os/stat_freebsd.go
+++ b/src/pkg/os/stat_freebsd.go
@@ -4,29 +4,58 @@
package os
-import "syscall"
+import (
+ "syscall"
+ "time"
+)
-func isSymlink(stat *syscall.Stat_t) bool {
- return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
-func fileInfoFromStat(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.Atimespec)
- fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtimespec)
- fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctimespec)
- fi.Name = basename(name)
- if isSymlink(lstat) && !isSymlink(stat) {
- fi.FollowedSymlink = true
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtimespec),
+ sys: st,
}
- return fi
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atimespec)
}
diff --git a/src/pkg/os/stat_linux.go b/src/pkg/os/stat_linux.go
index 7a3cf794d..00506b2b6 100644
--- a/src/pkg/os/stat_linux.go
+++ b/src/pkg/os/stat_linux.go
@@ -4,29 +4,58 @@
package os
-import "syscall"
+import (
+ "syscall"
+ "time"
+)
-func isSymlink(stat *syscall.Stat_t) bool {
- return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
- fi.Dev = stat.Dev
- fi.Ino = stat.Ino
- fi.Nlink = uint64(stat.Nlink)
- fi.Mode = stat.Mode
- fi.Uid = int(stat.Uid)
- fi.Gid = int(stat.Gid)
- fi.Rdev = stat.Rdev
- fi.Size = stat.Size
- fi.Blksize = int64(stat.Blksize)
- fi.Blocks = stat.Blocks
- fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
- fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
- fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
- fi.Name = basename(name)
- if isSymlink(lstat) && !isSymlink(stat) {
- fi.FollowedSymlink = true
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtim),
+ sys: st,
}
- return fi
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
diff --git a/src/pkg/os/stat_netbsd.go b/src/pkg/os/stat_netbsd.go
new file mode 100644
index 000000000..00506b2b6
--- /dev/null
+++ b/src/pkg/os/stat_netbsd.go
@@ -0,0 +1,61 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "time"
+)
+
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtim),
+ sys: st,
+ }
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
+}
diff --git a/src/pkg/os/stat_openbsd.go b/src/pkg/os/stat_openbsd.go
index 6d3a3813b..00506b2b6 100644
--- a/src/pkg/os/stat_openbsd.go
+++ b/src/pkg/os/stat_openbsd.go
@@ -4,29 +4,58 @@
package os
-import "syscall"
+import (
+ "syscall"
+ "time"
+)
-func isSymlink(stat *syscall.Stat_t) bool {
- return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
- fi.Dev = uint64(stat.Dev)
- fi.Ino = uint64(stat.Ino)
- fi.Nlink = uint64(stat.Nlink)
- fi.Mode = uint32(stat.Mode)
- fi.Uid = int(stat.Uid)
- fi.Gid = int(stat.Gid)
- fi.Rdev = uint64(stat.Rdev)
- fi.Size = int64(stat.Size)
- fi.Blksize = int64(stat.Blksize)
- fi.Blocks = stat.Blocks
- fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
- fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
- fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
- fi.Name = basename(name)
- if isSymlink(lstat) && !isSymlink(stat) {
- fi.FollowedSymlink = true
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+ fs := &fileStat{
+ name: basename(name),
+ size: int64(st.Size),
+ modTime: timespecToTime(st.Mtim),
+ sys: st,
}
- return fi
+ fs.mode = FileMode(st.Mode & 0777)
+ switch st.Mode & syscall.S_IFMT {
+ case syscall.S_IFBLK:
+ fs.mode |= ModeDevice
+ case syscall.S_IFCHR:
+ fs.mode |= ModeDevice | ModeCharDevice
+ case syscall.S_IFDIR:
+ fs.mode |= ModeDir
+ case syscall.S_IFIFO:
+ fs.mode |= ModeNamedPipe
+ case syscall.S_IFLNK:
+ fs.mode |= ModeSymlink
+ case syscall.S_IFREG:
+ // nothing to do
+ case syscall.S_IFSOCK:
+ fs.mode |= ModeSocket
+ }
+ if st.Mode&syscall.S_ISGID != 0 {
+ fs.mode |= ModeSetgid
+ }
+ if st.Mode&syscall.S_ISUID != 0 {
+ fs.mode |= ModeSetuid
+ }
+ if st.Mode&syscall.S_ISVTX != 0 {
+ fs.mode |= ModeSticky
+ }
+ return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+ return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
diff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
index 173a23f8b..a7990a359 100644
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -4,87 +4,103 @@
package os
-import "syscall"
-
-func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
- fi.Dev = uint64(d.Qid.Vers) | uint64(d.Qid.Type<<32)
- fi.Ino = d.Qid.Path
+import (
+ "syscall"
+ "time"
+)
+
+func sameFile(sys1, sys2 interface{}) bool {
+ a := sys1.(*Dir)
+ b := sys2.(*Dir)
+ return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
+}
- fi.Mode = uint32(d.Mode) & 0777
- if (d.Mode & syscall.DMDIR) == syscall.DMDIR {
- fi.Mode |= syscall.S_IFDIR
- } else {
- fi.Mode |= syscall.S_IFREG
+func fileInfoFromStat(d *Dir) FileInfo {
+ fs := &fileStat{
+ name: d.Name,
+ size: int64(d.Length),
+ modTime: time.Unix(int64(d.Mtime), 0),
+ sys: d,
}
-
- fi.Size = int64(d.Length)
- fi.Atime_ns = 1e9 * int64(d.Atime)
- fi.Mtime_ns = 1e9 * int64(d.Mtime)
- fi.Name = d.Name
- fi.FollowedSymlink = false
- return fi
+ fs.mode = FileMode(d.Mode & 0777)
+ if d.Mode&syscall.DMDIR != 0 {
+ fs.mode |= ModeDir
+ }
+ if d.Mode&syscall.DMAPPEND != 0 {
+ fs.mode |= ModeAppend
+ }
+ if d.Mode&syscall.DMEXCL != 0 {
+ fs.mode |= ModeExclusive
+ }
+ if d.Mode&syscall.DMTMP != 0 {
+ fs.mode |= ModeTemporary
+ }
+ return fs
}
// arg is an open *File or a path string.
-func dirstat(arg interface{}) (d *Dir, err Error) {
+func dirstat(arg interface{}) (d *Dir, err error) {
var name string
- nd := syscall.STATFIXLEN + 16*4
- for i := 0; i < 2; i++ { /* should work by the second try */
- buf := make([]byte, nd)
+ // This is big enough for most stat messages
+ // and rounded to a multiple of 128 bytes.
+ size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
- var n int
- var e syscall.Error
+ for i := 0; i < 2; i++ {
+ buf := make([]byte, size)
- switch syscallArg := arg.(type) {
+ var n int
+ switch a := arg.(type) {
case *File:
- name = syscallArg.name
- n, e = syscall.Fstat(syscallArg.fd, buf)
+ name = a.name
+ n, err = syscall.Fstat(a.fd, buf)
case string:
- name = syscallArg
- n, e = syscall.Stat(name, buf)
+ name = a
+ n, err = syscall.Stat(name, buf)
}
-
- if e != nil {
- return nil, &PathError{"stat", name, e}
+ if err != nil {
+ return nil, &PathError{"stat", name, err}
}
-
if n < syscall.STATFIXLEN {
- return nil, &PathError{"stat", name, Eshortstat}
+ return nil, &PathError{"stat", name, errShortStat}
}
- ntmp, _ := gbit16(buf)
- nd = int(ntmp)
-
- if nd <= n {
- d, e := UnmarshalDir(buf[:n])
+ // Pull the real size out of the stat message.
+ s, _ := gbit16(buf)
+ size = int(s)
- if e != nil {
- return nil, &PathError{"stat", name, e}
+ // If the stat message is larger than our buffer we will
+ // go around the loop and allocate one that is big enough.
+ if size <= n {
+ d, err = UnmarshalDir(buf[:n])
+ if err != nil {
+ return nil, &PathError{"stat", name, err}
}
- return d, e
+ return
}
}
-
- return nil, &PathError{"stat", name, Ebadstat}
+ return nil, &PathError{"stat", name, errBadStat}
}
-// Stat returns a FileInfo structure describing the named file and an error, if any.
-func Stat(name string) (fi *FileInfo, err Error) {
+// Stat returns a FileInfo structure describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(name string) (FileInfo, error) {
d, err := dirstat(name)
- if iserror(err) {
+ if err != nil {
return nil, err
}
- return fileInfoFromStat(new(FileInfo), d), err
+ return fileInfoFromStat(d), nil
}
-// 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),
+// Lstat returns the FileInfo structure describing the named file.
+// 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) {
- d, err := dirstat(name)
- if iserror(err) {
- return nil, err
- }
- return fileInfoFromStat(new(FileInfo), d), err
+// If there is an error, it will be of type *PathError.
+func Lstat(name string) (FileInfo, error) {
+ return Stat(name)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return time.Unix(int64(fi.Sys().(*Dir).Atime), 0)
}
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
index 11088436a..75351c805 100644
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -4,43 +4,255 @@
package os
-import "syscall"
+import (
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
- return fileInfoFromWin32finddata(fi, &stat.Windata)
+// Stat returns the FileInfo structure describing file.
+// If there is an error, it will be of type *PathError.
+func (file *File) Stat() (fi FileInfo, err error) {
+ if file == nil || file.fd < 0 {
+ return nil, syscall.EINVAL
+ }
+ if file.isdir() {
+ // I don't know any better way to do that for directory
+ return Stat(file.name)
+ }
+ if file.name == DevNull {
+ return statDevNull()
+ }
+ var d syscall.ByHandleFileInformation
+ e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d)
+ if e != nil {
+ return nil, &PathError{"GetFileInformationByHandle", file.name, e}
+ }
+ return &fileStat{
+ name: basename(file.name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSysFromFI(&d),
+ }, nil
}
-func fileInfoFromWin32finddata(fi *FileInfo, d *syscall.Win32finddata) *FileInfo {
- return setFileInfo(fi, string(syscall.UTF16ToString(d.FileName[0:])), d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
+// Stat returns a FileInfo structure describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(name string) (fi FileInfo, err error) {
+ if len(name) == 0 {
+ return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
+ }
+ if name == DevNull {
+ return statDevNull()
+ }
+ var d syscall.Win32FileAttributeData
+ e := syscall.GetFileAttributesEx(syscall.StringToUTF16Ptr(name), syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d)))
+ if e != nil {
+ return nil, &PathError{"GetFileAttributesEx", name, e}
+ }
+ path := name
+ if !isAbs(path) {
+ cwd, _ := Getwd()
+ path = cwd + `\` + path
+ }
+ return &fileStat{
+ name: basename(name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSys(path, d.LastAccessTime, d.CreationTime),
+ }, nil
+}
+
+// Lstat returns the FileInfo structure describing the named file.
+// If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+// If there is an error, it will be of type *PathError.
+func Lstat(name string) (fi FileInfo, err error) {
+ // No links on Windows
+ return Stat(name)
}
-func fileInfoFromByHandleInfo(fi *FileInfo, name string, d *syscall.ByHandleFileInformation) *FileInfo {
- for i := len(name) - 1; i >= 0; i-- {
+// statDevNull return FileInfo structure describing DevNull file ("NUL").
+// It creates invented data, since none of windows api will return
+// that information.
+func statDevNull() (fi FileInfo, err error) {
+ return &fileStat{
+ name: DevNull,
+ mode: ModeDevice | ModeCharDevice | 0666,
+ sys: &winSys{
+ // hopefully this will work for SameFile
+ vol: 0,
+ idxhi: 0,
+ idxlo: 0,
+ },
+ }, nil
+}
+
+// basename removes trailing slashes and the leading
+// directory name and drive letter from path name.
+func basename(name string) string {
+ // Remove drive letter
+ if len(name) == 2 && name[1] == ':' {
+ name = "."
+ } else if len(name) > 2 && name[1] == ':' {
+ name = name[2:]
+ }
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
if name[i] == '/' || name[i] == '\\' {
name = name[i+1:]
break
}
}
- return setFileInfo(fi, name, d.FileAttributes, d.FileSizeHigh, d.FileSizeLow, d.CreationTime, d.LastAccessTime, d.LastWriteTime)
+ return name
+}
+
+func isSlash(c uint8) bool {
+ return c == '\\' || c == '/'
+}
+
+func isAbs(path string) (b bool) {
+ v := volumeName(path)
+ if v == "" {
+ return false
+ }
+ path = path[len(v):]
+ if path == "" {
+ return false
+ }
+ return isSlash(path[0])
+}
+
+func volumeName(path string) (v string) {
+ if len(path) < 2 {
+ return ""
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' &&
+ ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z') {
+ return path[:2]
+ }
+ // is it UNC
+ if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
+ !isSlash(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if isSlash(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !isSlash(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if isSlash(path[n]) {
+ break
+ }
+ }
+ return path[:n]
+ }
+ break
+ }
+ }
+ }
+ return ""
}
-func setFileInfo(fi *FileInfo, name string, fa, sizehi, sizelo uint32, ctime, atime, wtime syscall.Filetime) *FileInfo {
- fi.Mode = 0
+type winSys struct {
+ sync.Mutex
+ path string
+ atime, ctime syscall.Filetime
+ vol, idxhi, idxlo uint32
+}
+
+func mkSize(hi, lo uint32) int64 {
+ return int64(hi)<<32 + int64(lo)
+}
+
+func mkModTime(mtime syscall.Filetime) time.Time {
+ return time.Unix(0, mtime.Nanoseconds())
+}
+
+func mkMode(fa uint32) (m FileMode) {
if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
- fi.Mode = fi.Mode | syscall.S_IFDIR
- } else {
- fi.Mode = fi.Mode | syscall.S_IFREG
+ m |= ModeDir
}
if fa&syscall.FILE_ATTRIBUTE_READONLY != 0 {
- fi.Mode = fi.Mode | 0444
+ m |= 0444
} else {
- fi.Mode = fi.Mode | 0666
- }
- fi.Size = int64(sizehi)<<32 + int64(sizelo)
- fi.Name = name
- fi.FollowedSymlink = false
- fi.Atime_ns = atime.Nanoseconds()
- fi.Mtime_ns = wtime.Nanoseconds()
- fi.Ctime_ns = ctime.Nanoseconds()
- return fi
+ m |= 0666
+ }
+ return m
+}
+
+func mkSys(path string, atime, ctime syscall.Filetime) *winSys {
+ return &winSys{
+ path: path,
+ atime: atime,
+ ctime: ctime,
+ }
+}
+
+func mkSysFromFI(i *syscall.ByHandleFileInformation) *winSys {
+ return &winSys{
+ atime: i.LastAccessTime,
+ ctime: i.CreationTime,
+ vol: i.VolumeSerialNumber,
+ idxhi: i.FileIndexHigh,
+ idxlo: i.FileIndexLow,
+ }
+}
+
+func (s *winSys) loadFileId() error {
+ if s.path == "" {
+ // already done
+ return nil
+ }
+ s.Lock()
+ defer s.Unlock()
+ h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if e != nil {
+ return e
+ }
+ defer syscall.CloseHandle(h)
+ var i syscall.ByHandleFileInformation
+ e = syscall.GetFileInformationByHandle(syscall.Handle(h), &i)
+ if e != nil {
+ return e
+ }
+ s.path = ""
+ s.vol = i.VolumeSerialNumber
+ s.idxhi = i.FileIndexHigh
+ s.idxlo = i.FileIndexLow
+ return nil
+}
+
+func sameFile(sys1, sys2 interface{}) bool {
+ s1 := sys1.(*winSys)
+ s2 := sys2.(*winSys)
+ e := s1.loadFileId()
+ if e != nil {
+ panic(e)
+ }
+ e = s2.loadFileId()
+ if e != nil {
+ panic(e)
+ }
+ return s1.vol == s2.vol && s1.idxhi == s2.idxhi && s1.idxlo == s2.idxlo
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+ return time.Unix(0, fi.Sys().(*winSys).atime.Nanoseconds())
}
diff --git a/src/pkg/os/str.go b/src/pkg/os/str.go
index 8dc9e4747..e3606b61e 100644
--- a/src/pkg/os/str.go
+++ b/src/pkg/os/str.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.
+// +build plan9
+
package os
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
index 188993b69..0f263f1c1 100644
--- a/src/pkg/os/sys_bsd.go
+++ b/src/pkg/os/sys_bsd.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.
+// +build darwin freebsd netbsd openbsd
+
// os code shared between *BSD systems including OS X (Darwin)
// and FreeBSD.
@@ -9,11 +11,10 @@ package os
import "syscall"
-func Hostname() (name string, err Error) {
- var errno int
- name, errno = syscall.Sysctl("kern.hostname")
- if errno != 0 {
- return "", NewSyscallError("sysctl kern.hostname", errno)
+func hostname() (name string, err error) {
+ name, err = syscall.Sysctl("kern.hostname")
+ if err != nil {
+ return "", NewSyscallError("sysctl kern.hostname", err)
}
return name, nil
}
diff --git a/src/pkg/os/sys_linux.go b/src/pkg/os/sys_linux.go
index 2accd6c1f..76cdf5043 100644
--- a/src/pkg/os/sys_linux.go
+++ b/src/pkg/os/sys_linux.go
@@ -6,8 +6,7 @@
package os
-// Hostname returns the host name reported by the kernel.
-func Hostname() (name string, err Error) {
+func hostname() (name string, err error) {
f, err := Open("/proc/sys/kernel/hostname")
if err != nil {
return "", err
diff --git a/src/pkg/os/sys_plan9.go b/src/pkg/os/sys_plan9.go
index c24cde05e..07a7905f4 100644
--- a/src/pkg/os/sys_plan9.go
+++ b/src/pkg/os/sys_plan9.go
@@ -6,7 +6,7 @@
package os
-func Hostname() (name string, err Error) {
+func hostname() (name string, err error) {
f, err := Open("#c/sysname")
if err != nil {
return "", err
diff --git a/src/pkg/os/sys_windows.go b/src/pkg/os/sys_windows.go
index a78798458..92617de5e 100644
--- a/src/pkg/os/sys_windows.go
+++ b/src/pkg/os/sys_windows.go
@@ -6,9 +6,9 @@ package os
import "syscall"
-func Hostname() (name string, err Error) {
+func hostname() (name string, err error) {
s, e := syscall.ComputerName()
- if e != 0 {
+ if e != nil {
return "", NewSyscallError("ComputerName", e)
}
return s, nil
diff --git a/src/pkg/os/time.go b/src/pkg/os/time.go
deleted file mode 100644
index 949574d19..000000000
--- a/src/pkg/os/time.go
+++ /dev/null
@@ -1,19 +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 os
-
-import "syscall"
-
-// Time returns the current time, in whole seconds and
-// fractional nanoseconds, plus an Error if any. The current
-// time is thus 1e9*sec+nsec, in nanoseconds. The zero of
-// time is the Unix epoch.
-func Time() (sec int64, nsec int64, err Error) {
- var tv syscall.Timeval
- if e := syscall.Gettimeofday(&tv); iserror(e) {
- return 0, 0, NewSyscallError("gettimeofday", e)
- }
- return int64(tv.Sec), int64(tv.Usec) * 1000, err
-}
diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go
index df57b59a3..0c95c9cec 100644
--- a/src/pkg/os/types.go
+++ b/src/pkg/os/types.go
@@ -4,53 +4,122 @@
package os
-import "syscall"
-
-// An operating-system independent representation of Unix data structures.
-// OS-specific routines in this directory convert the OS-local versions to these.
+import (
+ "syscall"
+ "time"
+)
// Getpagesize returns the underlying system's memory page size.
func Getpagesize() int { return syscall.Getpagesize() }
-// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
-type FileInfo struct {
- Dev uint64 // device number of file system holding file.
- Ino uint64 // inode number.
- Nlink uint64 // number of hard links.
- Mode uint32 // permission and mode bits.
- Uid int // user id of owner.
- Gid int // group id of owner.
- Rdev uint64 // device type for special file.
- Size int64 // length in bytes.
- Blksize int64 // size of blocks, in bytes.
- Blocks int64 // number of blocks allocated for file.
- Atime_ns int64 // access time; nanoseconds since epoch.
- Mtime_ns int64 // modified time; nanoseconds since epoch.
- Ctime_ns int64 // status change time; nanoseconds since epoch.
- Name string // base name of the file name provided in Open, Stat, etc.
- FollowedSymlink bool // followed a symlink to get this information
+// A FileInfo describes a file and is returned by Stat and Lstat
+type FileInfo interface {
+ Name() string // base name of the file
+ Size() int64 // length in bytes for regular files; system-dependent for others
+ Mode() FileMode // file mode bits
+ ModTime() time.Time // modification time
+ IsDir() bool // abbreviation for Mode().IsDir()
+ Sys() interface{} // underlying data source (can return nil)
}
-// IsFifo reports whether the FileInfo describes a FIFO file.
-func (f *FileInfo) IsFifo() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFIFO }
+// A FileMode represents a file's mode and permission bits.
+// The bits have the same definition on all systems, so that
+// information about files can be moved from one system
+// to another portably. Not all bits apply to all systems.
+// The only required bit is ModeDir for directories.
+type FileMode uint32
+
+// The defined file mode bits are the most significant bits of the FileMode.
+// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
+// The values of these bits should be considered part of the public API and
+// may be used in wire protocols or disk representations: they must not be
+// changed, although new bits might be added.
+const (
+ // The single letters are the abbreviations
+ // used by the String method's formatting.
+ ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
+ ModeAppend // a: append-only
+ ModeExclusive // l: exclusive use
+ ModeTemporary // T: temporary file (not backed up)
+ ModeSymlink // L: symbolic link
+ ModeDevice // D: device file
+ ModeNamedPipe // p: named pipe (FIFO)
+ ModeSocket // S: Unix domain socket
+ ModeSetuid // u: setuid
+ ModeSetgid // g: setgid
+ ModeCharDevice // c: Unix character device, when ModeDevice is set
+ ModeSticky // t: sticky
-// IsChar reports whether the FileInfo describes a character special file.
-func (f *FileInfo) IsChar() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFCHR }
+ // Mask for the type bits. For regular files, none will be set.
+ ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
-// IsDirectory reports whether the FileInfo describes a directory.
-func (f *FileInfo) IsDirectory() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFDIR }
+ ModePerm FileMode = 0777 // permission bits
+)
+
+func (m FileMode) String() string {
+ const str = "dalTLDpSugct"
+ var buf [32]byte // Mode is uint32.
+ w := 0
+ for i, c := range str {
+ if m&(1<<uint(32-1-i)) != 0 {
+ buf[w] = byte(c)
+ w++
+ }
+ }
+ if w == 0 {
+ buf[w] = '-'
+ w++
+ }
+ const rwx = "rwxrwxrwx"
+ for i, c := range rwx {
+ if m&(1<<uint(9-1-i)) != 0 {
+ buf[w] = byte(c)
+ } else {
+ buf[w] = '-'
+ }
+ w++
+ }
+ return string(buf[:w])
+}
-// IsBlock reports whether the FileInfo describes a block special file.
-func (f *FileInfo) IsBlock() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFBLK }
+// IsDir reports whether m describes a directory.
+// That is, it tests for the ModeDir bit being set in m.
+func (m FileMode) IsDir() bool {
+ return m&ModeDir != 0
+}
-// IsRegular reports whether the FileInfo describes a regular file.
-func (f *FileInfo) IsRegular() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFREG }
+// Perm returns the Unix permission bits in m.
+func (m FileMode) Perm() FileMode {
+ return m & ModePerm
+}
-// IsSymlink reports whether the FileInfo describes a symbolic link.
-func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFLNK }
+// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
+type fileStat struct {
+ name string
+ size int64
+ mode FileMode
+ modTime time.Time
+ sys interface{}
+}
-// IsSocket reports whether the FileInfo describes a socket.
-func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
+func (fs *fileStat) Name() string { return fs.name }
+func (fs *fileStat) Size() int64 { return fs.size }
+func (fs *fileStat) Mode() FileMode { return fs.mode }
+func (fs *fileStat) ModTime() time.Time { return fs.modTime }
+func (fs *fileStat) IsDir() bool { return fs.mode.IsDir() }
+func (fs *fileStat) Sys() interface{} { return fs.sys }
-// Permission returns the file permission bits.
-func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
+// SameFile reports whether fi1 and fi2 describe the same file.
+// For example, on Unix this means that the device and inode fields
+// of the two underlying structures are identical; on other systems
+// the decision may be based on the path names.
+// SameFile only applies to results returned by this package's Stat.
+// It returns false in other cases.
+func SameFile(fi1, fi2 FileInfo) bool {
+ fs1, ok1 := fi1.(*fileStat)
+ fs2, ok2 := fi2.(*fileStat)
+ if !ok1 || !ok2 {
+ return false
+ }
+ return sameFile(fs1.sys, fs2.sys)
+}
diff --git a/src/pkg/os/user/Makefile b/src/pkg/os/user/Makefile
deleted file mode 100644
index aabb54995..000000000
--- a/src/pkg/os/user/Makefile
+++ /dev/null
@@ -1,26 +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.
-
-include ../../../Make.inc
-
-TARG=os/user
-GOFILES=\
- user.go\
-
-ifeq ($(CGO_ENABLED),1)
-CGOFILES_linux=\
- lookup_unix.go
-CGOFILES_freebsd=\
- lookup_unix.go
-CGOFILES_darwin=\
- lookup_unix.go
-endif
-
-ifneq ($(CGOFILES_$(GOOS)),)
-CGOFILES+=$(CGOFILES_$(GOOS))
-else
-GOFILES+=lookup_stubs.go
-endif
-
-include ../../../Make.pkg
diff --git a/src/pkg/os/user/lookup_stubs.go b/src/pkg/os/user/lookup_stubs.go
index 2f08f70fd..415f869f2 100644
--- a/src/pkg/os/user/lookup_stubs.go
+++ b/src/pkg/os/user/lookup_stubs.go
@@ -2,18 +2,27 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !cgo,!windows
+
package user
import (
"fmt"
- "os"
"runtime"
)
-func Lookup(username string) (*User, os.Error) {
+func init() {
+ implemented = false
+}
+
+func Current() (*User, error) {
+ return nil, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func Lookup(username string) (*User, error) {
return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
-func LookupId(int) (*User, os.Error) {
+func LookupId(string) (*User, error) {
return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
diff --git a/src/pkg/os/user/lookup_unix.go b/src/pkg/os/user/lookup_unix.go
index 1b2c9e8c9..241957c33 100644
--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/os/user/lookup_unix.go
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux
+// +build cgo
+
package user
import (
"fmt"
- "os"
"runtime"
+ "strconv"
"strings"
+ "syscall"
"unsafe"
)
@@ -25,23 +29,28 @@ static int mygetpwuid_r(int uid, struct passwd *pwd,
*/
import "C"
-func init() {
- implemented = true
+// Current returns the current user.
+func Current() (*User, error) {
+ return lookup(syscall.Getuid(), "", false)
}
// Lookup looks up a user by username. If the user cannot be found,
// the returned error is of type UnknownUserError.
-func Lookup(username string) (*User, os.Error) {
+func Lookup(username string) (*User, error) {
return lookup(-1, username, true)
}
// LookupId looks up a user by userid. If the user cannot be found,
// the returned error is of type UnknownUserIdError.
-func LookupId(uid int) (*User, os.Error) {
- return lookup(uid, "", false)
+func LookupId(uid string) (*User, error) {
+ i, e := strconv.Atoi(uid)
+ if e != nil {
+ return nil, e
+ }
+ return lookup(i, "", false)
}
-func lookup(uid int, username string, lookupByName bool) (*User, os.Error) {
+func lookup(uid int, username string, lookupByName bool) (*User, error) {
var pwd C.struct_passwd
var result *C.struct_passwd
@@ -69,7 +78,7 @@ func lookup(uid int, username string, lookupByName bool) (*User, os.Error) {
C.size_t(bufSize),
&result)
if rv != 0 {
- return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(rv))
+ return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv))
}
if result == nil {
return nil, UnknownUserError(username)
@@ -84,15 +93,15 @@ func lookup(uid int, username string, lookupByName bool) (*User, os.Error) {
C.size_t(bufSize),
&result)
if rv != 0 {
- return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Errno(rv))
+ return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv))
}
if result == nil {
return nil, UnknownUserIdError(uid)
}
}
u := &User{
- Uid: int(pwd.pw_uid),
- Gid: int(pwd.pw_gid),
+ Uid: strconv.Itoa(int(pwd.pw_uid)),
+ Gid: strconv.Itoa(int(pwd.pw_gid)),
Username: C.GoString(pwd.pw_name),
Name: C.GoString(pwd.pw_gecos),
HomeDir: C.GoString(pwd.pw_dir),
diff --git a/src/pkg/os/user/lookup_windows.go b/src/pkg/os/user/lookup_windows.go
new file mode 100644
index 000000000..993687115
--- /dev/null
+++ b/src/pkg/os/user/lookup_windows.go
@@ -0,0 +1,117 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+func lookupFullName(domain, username, domainAndUser string) (string, error) {
+ // try domain controller first
+ name, e := syscall.TranslateAccountName(domainAndUser,
+ syscall.NameSamCompatible, syscall.NameDisplay, 50)
+ if e != nil {
+ // domain lookup failed, perhaps this pc is not part of domain
+ d := syscall.StringToUTF16Ptr(domain)
+ u := syscall.StringToUTF16Ptr(username)
+ var p *byte
+ e := syscall.NetUserGetInfo(d, u, 10, &p)
+ if e != nil {
+ return "", e
+ }
+ defer syscall.NetApiBufferFree(p)
+ i := (*syscall.UserInfo10)(unsafe.Pointer(p))
+ if i.FullName == nil {
+ return "", nil
+ }
+ name = syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(i.FullName))[:])
+ }
+ return name, nil
+}
+
+func newUser(usid *syscall.SID, gid, dir string) (*User, error) {
+ username, domain, t, e := usid.LookupAccount("")
+ if e != nil {
+ return nil, e
+ }
+ if t != syscall.SidTypeUser {
+ return nil, fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ domainAndUser := domain + `\` + username
+ uid, e := usid.String()
+ if e != nil {
+ return nil, e
+ }
+ name, e := lookupFullName(domain, username, domainAndUser)
+ if e != nil {
+ return nil, e
+ }
+ u := &User{
+ Uid: uid,
+ Gid: gid,
+ Username: domainAndUser,
+ Name: name,
+ HomeDir: dir,
+ }
+ return u, nil
+}
+
+// Current returns the current user.
+func Current() (*User, error) {
+ t, e := syscall.OpenCurrentProcessToken()
+ if e != nil {
+ return nil, e
+ }
+ u, e := t.GetTokenUser()
+ if e != nil {
+ return nil, e
+ }
+ pg, e := t.GetTokenPrimaryGroup()
+ if e != nil {
+ return nil, e
+ }
+ gid, e := pg.PrimaryGroup.String()
+ if e != nil {
+ return nil, e
+ }
+ dir, e := t.GetUserProfileDirectory()
+ if e != nil {
+ return nil, e
+ }
+ return newUser(u.User.Sid, gid, dir)
+}
+
+// BUG(brainman): Lookup and LookupId functions do not set
+// Gid and HomeDir fields in the User struct returned on windows.
+
+func newUserFromSid(usid *syscall.SID) (*User, error) {
+ // TODO(brainman): do not know where to get gid and dir fields
+ gid := "unknown"
+ dir := "Unknown directory"
+ return newUser(usid, gid, dir)
+}
+
+// Lookup looks up a user by username.
+func Lookup(username string) (*User, error) {
+ sid, _, t, e := syscall.LookupSID("", username)
+ if e != nil {
+ return nil, e
+ }
+ if t != syscall.SidTypeUser {
+ return nil, fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ return newUserFromSid(sid)
+}
+
+// LookupId looks up a user by userid.
+func LookupId(uid string) (*User, error) {
+ sid, e := syscall.StringToSid(uid)
+ if e != nil {
+ return nil, e
+ }
+ return newUserFromSid(sid)
+}
diff --git a/src/pkg/os/user/user.go b/src/pkg/os/user/user.go
index f71e11d8b..841f2263f 100644
--- a/src/pkg/os/user/user.go
+++ b/src/pkg/os/user/user.go
@@ -9,12 +9,16 @@ import (
"strconv"
)
-var implemented = false // set to true by lookup_unix.go's init
+var implemented = true // set to false by lookup_stubs.go's init
// User represents a user account.
+//
+// On posix systems Uid and Gid contain a decimal number
+// representing uid and gid. On windows Uid and Gid
+// contain security identifier (SID) in a string format.
type User struct {
- Uid int // user id
- Gid int // primary group id
+ Uid string // user id
+ Gid string // primary group id
Username string
Name string
HomeDir string
@@ -24,7 +28,7 @@ type User struct {
// a user cannot be found.
type UnknownUserIdError int
-func (e UnknownUserIdError) String() string {
+func (e UnknownUserIdError) Error() string {
return "user: unknown userid " + strconv.Itoa(int(e))
}
@@ -32,6 +36,6 @@ func (e UnknownUserIdError) String() string {
// a user cannot be found.
type UnknownUserError string
-func (e UnknownUserError) String() string {
+func (e UnknownUserError) Error() string {
return "user: unknown user " + string(e)
}
diff --git a/src/pkg/os/user/user_test.go b/src/pkg/os/user/user_test.go
index 59f15e4c6..b812ebce7 100644
--- a/src/pkg/os/user/user_test.go
+++ b/src/pkg/os/user/user_test.go
@@ -6,9 +6,7 @@ package user
import (
"os"
- "reflect"
"runtime"
- "syscall"
"testing"
)
@@ -18,7 +16,8 @@ func skip(t *testing.T) bool {
return true
}
- if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "darwin" {
+ switch runtime.GOOS {
+ case "linux", "freebsd", "darwin", "windows":
return false
}
@@ -26,36 +25,75 @@ func skip(t *testing.T) bool {
return true
}
-func TestLookup(t *testing.T) {
+func TestCurrent(t *testing.T) {
if skip(t) {
return
}
- // Test LookupId on the current user
- uid := syscall.Getuid()
- u, err := LookupId(uid)
+ u, err := Current()
if err != nil {
- t.Fatalf("LookupId: %v", err)
- }
- if e, g := uid, u.Uid; e != g {
- t.Errorf("expected Uid of %d; got %d", e, g)
+ t.Fatalf("Current: %v", err)
}
fi, err := os.Stat(u.HomeDir)
- if err != nil || !fi.IsDirectory() {
- t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", u.HomeDir, err, fi.IsDirectory())
+ if err != nil || !fi.IsDir() {
+ t.Errorf("expected a valid HomeDir; stat(%q): err=%v", u.HomeDir, err)
}
if u.Username == "" {
t.Fatalf("didn't get a username")
}
+}
+
+func compare(t *testing.T, want, got *User) {
+ if want.Uid != got.Uid {
+ t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)
+ }
+ if want.Username != got.Username {
+ t.Errorf("got Username=%q; want %q", got.Username, want.Username)
+ }
+ if want.Name != got.Name {
+ t.Errorf("got Name=%q; want %q", got.Name, want.Name)
+ }
+ // TODO(brainman): fix it once we know how.
+ if runtime.GOOS == "windows" {
+ t.Log("skipping Gid and HomeDir comparisons")
+ return
+ }
+ if want.Gid != got.Gid {
+ t.Errorf("got Gid=%q; want %q", got.Gid, want.Gid)
+ }
+ if want.HomeDir != got.HomeDir {
+ t.Errorf("got HomeDir=%q; want %q", got.HomeDir, want.HomeDir)
+ }
+}
+
+func TestLookup(t *testing.T) {
+ if skip(t) {
+ return
+ }
- // Test Lookup by username, using the username from LookupId
- un, err := Lookup(u.Username)
+ want, err := Current()
+ if err != nil {
+ t.Fatalf("Current: %v", err)
+ }
+ got, err := Lookup(want.Username)
if err != nil {
t.Fatalf("Lookup: %v", err)
}
- if !reflect.DeepEqual(u, un) {
- t.Errorf("Lookup by userid vs. name didn't match\n"+
- "LookupId(%d): %#v\n"+
- "Lookup(%q): %#v\n", uid, u, u.Username, un)
+ compare(t, want, got)
+}
+
+func TestLookupId(t *testing.T) {
+ if skip(t) {
+ return
+ }
+
+ want, err := Current()
+ if err != nil {
+ t.Fatalf("Current: %v", err)
+ }
+ got, err := LookupId(want.Uid)
+ if err != nil {
+ t.Fatalf("LookupId: %v", err)
}
+ compare(t, want, got)
}
diff --git a/src/pkg/patch/Makefile b/src/pkg/patch/Makefile
deleted file mode 100644
index 32db7bdc8..000000000
--- a/src/pkg/patch/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../Make.inc
-
-TARG=patch
-GOFILES=\
- apply.go\
- git.go\
- patch.go\
- textdiff.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/patch/apply.go b/src/pkg/patch/apply.go
deleted file mode 100644
index 0dd9080bf..000000000
--- a/src/pkg/patch/apply.go
+++ /dev/null
@@ -1,54 +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 patch
-
-import "os"
-
-// An Op is a single operation to execute to apply a patch.
-type Op struct {
- Verb Verb // action
- Src string // source file
- Dst string // destination file
- Mode int // mode for destination (if non-zero)
- Data []byte // data for destination (if non-nil)
-}
-
-// Apply applies the patch set to the files named in the patch set,
-// constructing an in-memory copy of the new file state.
-// It is the client's job to write the changes to the file system
-// if desired.
-//
-// The function readFile should return the contents of the named file.
-// Typically this function will be io.ReadFile.
-//
-func (set *Set) Apply(readFile func(string) ([]byte, os.Error)) ([]Op, os.Error) {
- op := make([]Op, len(set.File))
-
- for i, f := range set.File {
- o := &op[i]
- o.Verb = f.Verb
- o.Src = f.Src
- o.Dst = f.Dst
- o.Mode = f.NewMode
- if f.Diff != NoDiff || o.Verb != Edit {
- // Clients assume o.Data == nil means no data diff.
- // Start with a non-nil data.
- var old []byte = make([]byte, 0) // not nil
- var err os.Error
- if f.Src != "" {
- old, err = readFile(f.Src)
- if err != nil {
- return nil, &os.PathError{string(f.Verb), f.Src, err}
- }
- }
- o.Data, err = f.Diff.Apply(old)
- if err != nil {
- return nil, &os.PathError{string(f.Verb), f.Src, err}
- }
- }
- }
-
- return op, nil
-}
diff --git a/src/pkg/patch/git.go b/src/pkg/patch/git.go
deleted file mode 100644
index 651609726..000000000
--- a/src/pkg/patch/git.go
+++ /dev/null
@@ -1,121 +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 patch
-
-import (
- "bytes"
- "compress/zlib"
- "crypto/sha1"
- "encoding/git85"
- "fmt"
- "io"
- "os"
-)
-
-func gitSHA1(data []byte) []byte {
- if len(data) == 0 {
- // special case: 0 length is all zeros sum
- return make([]byte, 20)
- }
- h := sha1.New()
- fmt.Fprintf(h, "blob %d\x00", len(data))
- h.Write(data)
- return h.Sum()
-}
-
-// BUG(rsc): The Git binary delta format is not implemented, only Git binary literals.
-
-// GitBinaryLiteral represents a Git binary literal diff.
-type GitBinaryLiteral struct {
- OldSHA1 []byte // if non-empty, the SHA1 hash of the original
- New []byte // the new contents
-}
-
-// Apply implements the Diff interface's Apply method.
-func (d *GitBinaryLiteral) Apply(old []byte) ([]byte, os.Error) {
- if sum := gitSHA1(old); !bytes.HasPrefix(sum, d.OldSHA1) {
- return nil, ErrPatchFailure
- }
- return d.New, nil
-}
-
-func unhex(c byte) uint8 {
- switch {
- case '0' <= c && c <= '9':
- return c - '0'
- case 'a' <= c && c <= 'f':
- return c - 'a' + 10
- case 'A' <= c && c <= 'F':
- return c - 'A' + 10
- }
- return 255
-}
-
-func getHex(s []byte) (data []byte, rest []byte) {
- n := 0
- for n < len(s) && unhex(s[n]) != 255 {
- n++
- }
- n &^= 1 // Only take an even number of hex digits.
- data = make([]byte, n/2)
- for i := range data {
- data[i] = unhex(s[2*i])<<4 | unhex(s[2*i+1])
- }
- rest = s[n:]
- return
-}
-
-// ParseGitBinary parses raw as a Git binary patch.
-func ParseGitBinary(raw []byte) (Diff, os.Error) {
- var oldSHA1, newSHA1 []byte
- var sawBinary bool
-
- for {
- var first []byte
- first, raw, _ = getLine(raw, 1)
- first = bytes.TrimSpace(first)
- if s, ok := skip(first, "index "); ok {
- oldSHA1, s = getHex(s)
- if s, ok = skip(s, ".."); !ok {
- continue
- }
- newSHA1, s = getHex(s)
- continue
- }
- if _, ok := skip(first, "GIT binary patch"); ok {
- sawBinary = true
- continue
- }
- if n, _, ok := atoi(first, "literal ", 10); ok && sawBinary {
- data := make([]byte, n)
- d := git85.NewDecoder(bytes.NewBuffer(raw))
- z, err := zlib.NewReader(d)
- if err != nil {
- return nil, err
- }
- defer z.Close()
- if _, err = io.ReadFull(z, data); err != nil {
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- return nil, err
- }
- var buf [1]byte
- m, err := z.Read(buf[0:])
- if m != 0 || err != os.EOF {
- return nil, os.NewError("Git binary literal longer than expected")
- }
-
- if sum := gitSHA1(data); !bytes.HasPrefix(sum, newSHA1) {
- return nil, os.NewError("Git binary literal SHA1 mismatch")
- }
- return &GitBinaryLiteral{oldSHA1, data}, nil
- }
- if !sawBinary {
- return nil, os.NewError("unexpected Git patch header: " + string(first))
- }
- }
- panic("unreachable")
-}
diff --git a/src/pkg/patch/patch.go b/src/pkg/patch/patch.go
deleted file mode 100644
index fcc8307e0..000000000
--- a/src/pkg/patch/patch.go
+++ /dev/null
@@ -1,322 +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 patch implements parsing and execution of the textual and
-// binary patch descriptions used by version control tools such as
-// CVS, Git, Mercurial, and Subversion.
-package patch
-
-import (
- "bytes"
- "os"
- "path"
- "strings"
-)
-
-// A Set represents a set of patches to be applied as a single atomic unit.
-// Patch sets are often preceded by a descriptive header.
-type Set struct {
- Header string // free-form text
- File []*File
-}
-
-// A File represents a collection of changes to be made to a single file.
-type File struct {
- Verb Verb
- Src string // source for Verb == Copy, Verb == Rename
- Dst string
- OldMode, NewMode int // 0 indicates not used
- Diff // changes to data; == NoDiff if operation does not edit file
-}
-
-// A Verb is an action performed on a file.
-type Verb string
-
-const (
- Add Verb = "add"
- Copy Verb = "copy"
- Delete Verb = "delete"
- Edit Verb = "edit"
- Rename Verb = "rename"
-)
-
-// A Diff is any object that describes changes to transform
-// an old byte stream to a new one.
-type Diff interface {
- // Apply applies the changes listed in the diff
- // to the string s, returning the new version of the string.
- // Note that the string s need not be a text string.
- Apply(old []byte) (new []byte, err os.Error)
-}
-
-// NoDiff is a no-op Diff implementation: it passes the
-// old data through unchanged.
-var NoDiff Diff = noDiffType(0)
-
-type noDiffType int
-
-func (noDiffType) Apply(old []byte) ([]byte, os.Error) {
- return old, nil
-}
-
-// A SyntaxError represents a syntax error encountered while parsing a patch.
-type SyntaxError string
-
-func (e SyntaxError) String() string { return string(e) }
-
-var newline = []byte{'\n'}
-
-// Parse patches the patch text to create a patch Set.
-// The patch text typically comprises a textual header and a sequence
-// of file patches, as would be generated by CVS, Subversion,
-// Mercurial, or Git.
-func Parse(text []byte) (*Set, os.Error) {
- // Split text into files.
- // CVS and Subversion begin new files with
- // Index: file name.
- // ==================
- // diff -u blah blah
- //
- // Mercurial and Git use
- // diff [--git] a/file/path b/file/path.
- //
- // First look for Index: lines. If none, fall back on diff lines.
- text, files := sections(text, "Index: ")
- if len(files) == 0 {
- text, files = sections(text, "diff ")
- }
-
- set := &Set{string(text), make([]*File, len(files))}
-
- // Parse file header and then
- // parse files into patch chunks.
- // Each chunk begins with @@.
- for i, raw := range files {
- p := new(File)
- set.File[i] = p
-
- // First line of hdr is the Index: that
- // begins the section. After that is the file name.
- s, raw, _ := getLine(raw, 1)
- if hasPrefix(s, "Index: ") {
- p.Dst = string(bytes.TrimSpace(s[7:]))
- goto HaveName
- } else if hasPrefix(s, "diff ") {
- str := string(bytes.TrimSpace(s))
- i := strings.LastIndex(str, " b/")
- if i >= 0 {
- p.Dst = str[i+3:]
- goto HaveName
- }
- }
- return nil, SyntaxError("unexpected patch header line: " + string(s))
- HaveName:
- p.Dst = path.Clean(p.Dst)
- if strings.HasPrefix(p.Dst, "../") || strings.HasPrefix(p.Dst, "/") {
- return nil, SyntaxError("invalid path: " + p.Dst)
- }
-
- // Parse header lines giving file information:
- // new file mode %o - file created
- // deleted file mode %o - file deleted
- // old file mode %o - file mode changed
- // new file mode %o - file mode changed
- // rename from %s - file renamed from other file
- // rename to %s
- // copy from %s - file copied from other file
- // copy to %s
- p.Verb = Edit
- for len(raw) > 0 {
- oldraw := raw
- var l []byte
- l, raw, _ = getLine(raw, 1)
- l = bytes.TrimSpace(l)
- if m, s, ok := atoi(l, "new file mode ", 8); ok && len(s) == 0 {
- p.NewMode = m
- p.Verb = Add
- continue
- }
- if m, s, ok := atoi(l, "deleted file mode ", 8); ok && len(s) == 0 {
- p.OldMode = m
- p.Verb = Delete
- p.Src = p.Dst
- p.Dst = ""
- continue
- }
- if m, s, ok := atoi(l, "old file mode ", 8); ok && len(s) == 0 {
- // usually implies p.Verb = "rename" or "copy"
- // but we'll get that from the rename or copy line.
- p.OldMode = m
- continue
- }
- if m, s, ok := atoi(l, "old mode ", 8); ok && len(s) == 0 {
- p.OldMode = m
- continue
- }
- if m, s, ok := atoi(l, "new mode ", 8); ok && len(s) == 0 {
- p.NewMode = m
- continue
- }
- if s, ok := skip(l, "rename from "); ok && len(s) > 0 {
- p.Src = string(s)
- p.Verb = Rename
- continue
- }
- if s, ok := skip(l, "rename to "); ok && len(s) > 0 {
- p.Verb = Rename
- continue
- }
- if s, ok := skip(l, "copy from "); ok && len(s) > 0 {
- p.Src = string(s)
- p.Verb = Copy
- continue
- }
- if s, ok := skip(l, "copy to "); ok && len(s) > 0 {
- p.Verb = Copy
- continue
- }
- if s, ok := skip(l, "Binary file "); ok && len(s) > 0 {
- // Hg prints
- // Binary file foo has changed
- // when deleting a binary file.
- continue
- }
- if s, ok := skip(l, "RCS file: "); ok && len(s) > 0 {
- // CVS prints
- // RCS file: /cvs/plan9/bin/yesterday,v
- // retrieving revision 1.1
- // for each file.
- continue
- }
- if s, ok := skip(l, "retrieving revision "); ok && len(s) > 0 {
- // CVS prints
- // RCS file: /cvs/plan9/bin/yesterday,v
- // retrieving revision 1.1
- // for each file.
- continue
- }
- if hasPrefix(l, "===") || hasPrefix(l, "---") || hasPrefix(l, "+++") || hasPrefix(l, "diff ") {
- continue
- }
- if hasPrefix(l, "@@ -") {
- diff, err := ParseTextDiff(oldraw)
- if err != nil {
- return nil, err
- }
- p.Diff = diff
- break
- }
- if hasPrefix(l, "GIT binary patch") || (hasPrefix(l, "index ") && !hasPrefix(raw, "--- ")) {
- diff, err := ParseGitBinary(oldraw)
- if err != nil {
- return nil, err
- }
- p.Diff = diff
- break
- }
- if hasPrefix(l, "index ") {
- continue
- }
- return nil, SyntaxError("unexpected patch header line: " + string(l))
- }
- if p.Diff == nil {
- p.Diff = NoDiff
- }
- if p.Verb == Edit {
- p.Src = p.Dst
- }
- }
-
- return set, nil
-}
-
-// getLine returns the first n lines of data and the remainder.
-// If data has no newline, getLine returns data, nil, false
-func getLine(data []byte, n int) (first []byte, rest []byte, ok bool) {
- rest = data
- ok = true
- for ; n > 0; n-- {
- nl := bytes.Index(rest, newline)
- if nl < 0 {
- rest = nil
- ok = false
- break
- }
- rest = rest[nl+1:]
- }
- first = data[0 : len(data)-len(rest)]
- return
-}
-
-// sections returns a collection of file sections,
-// each of which begins with a line satisfying prefix.
-// text before the first instance of such a line is
-// returned separately.
-func sections(text []byte, prefix string) ([]byte, [][]byte) {
- n := 0
- for b := text; ; {
- if hasPrefix(b, prefix) {
- n++
- }
- nl := bytes.Index(b, newline)
- if nl < 0 {
- break
- }
- b = b[nl+1:]
- }
-
- sect := make([][]byte, n+1)
- n = 0
- for b := text; ; {
- if hasPrefix(b, prefix) {
- sect[n] = text[0 : len(text)-len(b)]
- n++
- text = b
- }
- nl := bytes.Index(b, newline)
- if nl < 0 {
- sect[n] = text
- break
- }
- b = b[nl+1:]
- }
- return sect[0], sect[1:]
-}
-
-// if s begins with the prefix t, skip returns
-// s with that prefix removed and ok == true.
-func skip(s []byte, t string) (ss []byte, ok bool) {
- if len(s) < len(t) || string(s[0:len(t)]) != t {
- return nil, false
- }
- return s[len(t):], true
-}
-
-// if s begins with the prefix t and then is a sequence
-// of digits in the given base, atoi returns the number
-// represented by the digits and s with the
-// prefix and the digits removed.
-func atoi(s []byte, t string, base int) (n int, ss []byte, ok bool) {
- if s, ok = skip(s, t); !ok {
- return
- }
- var i int
- for i = 0; i < len(s) && '0' <= s[i] && s[i] <= byte('0'+base-1); i++ {
- n = n*base + int(s[i]-'0')
- }
- if i == 0 {
- return
- }
- return n, s[i:], true
-}
-
-// hasPrefix returns true if s begins with t.
-func hasPrefix(s []byte, t string) bool {
- _, ok := skip(s, t)
- return ok
-}
-
-// splitLines returns the result of splitting s into lines.
-// The \n on each line is preserved.
-func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline) }
diff --git a/src/pkg/patch/patch_test.go b/src/pkg/patch/patch_test.go
deleted file mode 100644
index 0a4aef7ea..000000000
--- a/src/pkg/patch/patch_test.go
+++ /dev/null
@@ -1,390 +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 patch
-
-// TODO(rsc): test Apply
-
-import "testing"
-
-type Test struct {
- in string
- out string
- diff string
-}
-
-func TestFileApply(t *testing.T) {
- for i, test := range tests {
- set, err := Parse([]byte(test.diff))
- if err != nil {
- t.Errorf("#%d: Parse: %s", i, err)
- continue
- }
- if len(set.File) != 1 {
- t.Errorf("#%d: Parse returned %d patches, want 1", i, len(set.File))
- continue
- }
- new, err := set.File[0].Apply([]byte(test.in))
- if err != nil {
- t.Errorf("#%d: Apply: %s", i, err)
- continue
- }
- if s := string(new); s != test.out {
- t.Errorf("#%d:\n--- have\n%s--- want\n%s", i, s, test.out)
- }
- }
-}
-
-var tests = []Test{
- {
- "hello, world\n",
- "goodbye, world\n",
- "Index: a\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1 +1 @@\n" +
- "-hello, world\n" +
- "+goodbye, world\n",
- },
- {
- "hello, world\n",
- "goodbye, world\n",
- "Index: a\n" +
- "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1 +1 @@\n" +
- "-hello, world\n" +
- "+goodbye, world\n",
- },
- {
- "hello, world\n",
- "goodbye, world\n",
- "diff a/a b/b\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1,1 +1,1 @@\n" +
- "-hello, world\n" +
- "+goodbye, world\n",
- },
- {
- "hello, world",
- "goodbye, world\n",
- "diff --git a/a b/b\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1 +1 @@\n" +
- "-hello, world\n" +
- "\\ No newline at end of file\n" +
- "+goodbye, world\n",
- },
- {
- "hello, world\n",
- "goodbye, world",
- "Index: a\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1 +1 @@\n" +
- "-hello, world\n" +
- "+goodbye, world\n" +
- "\\ No newline at end of file\n",
- },
- {
- "hello, world",
- "goodbye, world",
- "Index: a\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1 +1 @@\n" +
- "-hello, world\n" +
- "\\ No newline at end of file\n" +
- "+goodbye, world\n" +
- "\\ No newline at end of file\n",
- },
- {
- "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\n",
- "a\nB\nC\nD\ne\nf\ng\nj\nk\nl\nm\nN\n",
- "Index: a\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1,14 +1,12 @@\n" +
- " a\n" +
- "-b\n" +
- "-c\n" +
- "-d\n" +
- "+B\n" +
- "+C\n" +
- "+D\n" +
- " e\n" +
- " f\n" +
- " g\n" +
- "-h\n" +
- "-i\n" +
- " j\n" +
- " k\n" +
- " l\n" +
- " m\n" +
- "-n\n" +
- "+N\n",
- },
- {
- "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
- "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
- "Index: a\n" +
- "--- a/a\n" +
- "+++ b/b\n" +
- "@@ -1,9 +1,6 @@\n" +
- " a\n" +
- " b\n" +
- " c\n" +
- "-d\n" +
- "-e\n" +
- "-f\n" +
- " g\n" +
- " h\n" +
- " i\n" +
- "@@ -11,8 +8,8 @@ j\n" +
- " k\n" +
- " l\n" +
- " m\n" +
- "-n\n" +
- "-o\n" +
- "+N\n" +
- "+O\n" +
- " p\n" +
- " q\n" +
- " r\n" +
- "\n" +
- "@@ -21,6 +18,7 @@ t\n" +
- " u\n" +
- " v\n" +
- " w\n" +
- "+d\n" +
- "+e\n" +
- "+f\n" +
- " x\n" +
- "-y\n" +
- "-z\n",
- },
- {
- "a\nb\nc\ng\nh\ni\nj\nk\nl\nm\nN\nO\np\nq\nr\ns\nt\nu\nv\nw\nd\ne\nf\nx\n",
- "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
- "Index: a\n" +
- "--- a/b\n" +
- "+++ b/a\n" +
- "@@ -1,6 +1,9 @@\n" +
- " a\n" +
- " b\n" +
- " c\n" +
- "+d\n" +
- "+e\n" +
- "+f\n" +
- " g\n" +
- " h\n" +
- " i\n" +
- "@@ -8,8 +11,8 @@ j\n" +
- " k\n" +
- " l\n" +
- " m\n" +
- "-N\n" +
- "-O\n" +
- "+n\n" +
- "+o\n" +
- " p\n" +
- " q\n" +
- " r\n" +
- "@@ -18,7 +21,6 @@ t\n" +
- " u\n" +
- " v\n" +
- " w\n" +
- "-d\n" +
- "-e\n" +
- "-f\n" +
- " x\n" +
- "+y\n" +
- "+z\n",
- },
- {
- "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
- "",
- "Index: a\n" +
- "deleted file mode 100644\n" +
- "--- a/a\n" +
- "+++ /dev/null\n" +
- "@@ -1,26 +0,0 @@\n" +
- "-a\n" +
- "-b\n" +
- "-c\n" +
- "-d\n" +
- "-e\n" +
- "-f\n" +
- "-g\n" +
- "-h\n" +
- "-i\n" +
- "-j\n" +
- "-k\n" +
- "-l\n" +
- "-m\n" +
- "-n\n" +
- "-o\n" +
- "-p\n" +
- "-q\n" +
- "-r\n" +
- "-s\n" +
- "-t\n" +
- "-u\n" +
- "-v\n" +
- "-w\n" +
- "-x\n" +
- "-y\n" +
- "-z\n",
- },
- {
- "",
- "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n",
- "Index: a\n" +
- "new file mode 100644\n" +
- "--- /dev/null\n" +
- "+++ b/a\n" +
- "@@ -0,0 +1,26 @@\n" +
- "+a\n" +
- "+b\n" +
- "+c\n" +
- "+d\n" +
- "+e\n" +
- "+f\n" +
- "+g\n" +
- "+h\n" +
- "+i\n" +
- "+j\n" +
- "+k\n" +
- "+l\n" +
- "+m\n" +
- "+n\n" +
- "+o\n" +
- "+p\n" +
- "+q\n" +
- "+r\n" +
- "+s\n" +
- "+t\n" +
- "+u\n" +
- "+v\n" +
- "+w\n" +
- "+x\n" +
- "+y\n" +
- "+z\n",
- },
- {
- "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
- "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
- "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
- "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
- "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
- "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
- "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
- "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
- "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
- "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
- "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
- "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
- "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
- "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
- "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
- "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
-
- "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
- "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
- "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
- "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
- "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
- "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
- "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
- "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
- "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
- "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
- "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
- "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
- "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
- "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
- "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
- "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
-
- // From git diff --binary
- "Index: a\n" +
- "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f 100644\n" +
- "GIT binary patch\n" +
- "literal 256\n" +
- "zcmV+b0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
- "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
- "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
- "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
- "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
- "G1edVN^?m&S\n" +
- "\n" +
- "literal 256\n" +
- "zcmV+b0ssEO*!g3O_r{yBJURLZjzW(de6Lg@hr`8ao8i5@!{FM?<CfaOue)`5WQJgh\n" +
- "zL!Jkms*;G*Fu9AB1YmK;yDgJua{(mtW54DdI2Bfy#2<yjU^zMsS5pirKf6SJR#u&d\n" +
- "z&-RGum<5IS{zM`AGs&bPzKI2kf_BM#uSh7wh82mqnEFBdJ&k}VGZ#gre`k4rk~=O;\n" +
- "z!O|O^&+SuIvPoFj>7SUR{&?Z&ba4b4huLTtXwa^Eq$T491AdFsP#>{p2;-CVPoeuU\n" +
- "z&zV|7pG(B5Xd3yBmjZwn@g*VOl)pg;Sv~4DBLlT!O}3Ao-yZ{gaNuu72$p$rx2{1e\n" +
- "Gy(*Pb;D3Ms\n" +
- "\n",
- },
- {
- "\xc2\xd8\xf9\x63\x8c\xf7\xc6\x9b\xb0\x3c\x39\xfa\x08\x8e\x42\x8f" +
- "\x1c\x7c\xaf\x54\x22\x87\xc3\xc5\x68\x9b\xe1\xbd\xbc\xc3\xe0\xda" +
- "\xcc\xe3\x96\xda\xc2\xaf\xbb\x75\x79\x64\x86\x60\x8a\x43\x9e\x07" +
- "\x9c\xaa\x92\x88\xd4\x30\xb9\x8b\x95\x04\x60\x71\xc7\xbb\x2d\x93" +
- "\x66\x73\x01\x24\xf3\x63\xbf\xe6\x1d\x38\x15\x56\x98\xc4\x1f\x85" +
- "\xc3\x60\x39\x3a\x0d\x57\x53\x0c\x29\x3f\xbb\x44\x7e\x56\x56\x9d" +
- "\x87\xcf\xf6\x88\xe8\x98\x05\x85\xf8\xfe\x44\x21\xfa\x33\xc9\xa4" +
- "\x22\xbe\x89\x05\x8b\x82\x76\xc9\x7c\xaf\x48\x28\xc4\x86\x15\x89" +
- "\xb9\x98\xfa\x41\xfc\x3d\x8d\x80\x29\x33\x17\x45\xa5\x7f\x67\x79" +
- "\x7f\x92\x3b\x2e\x4c\xc1\xd2\x1b\x9e\xcf\xed\x53\x56\xb2\x49\x58" +
- "\xd8\xe9\x9f\x98\xa3\xfe\x78\xe1\xe8\x74\x71\x04\x1a\x87\xd9\x68" +
- "\x18\x68\xd0\xae\x7b\xa4\x25\xe3\x06\x03\x7e\x8b\xd3\x50\x1f\xb1" +
- "\x67\x08\xe3\x93\xf4\x4f\xa1\xfb\x31\xcf\x99\x5a\x43\x9f\x4b\xc4" +
- "\xaa\x68\x1a\xf9\x8e\x97\x02\x80\x17\xf1\x25\x21\xdf\x94\xbf\x41" +
- "\x08\x59\x3d\xea\x36\x23\x03\xb5\x62\x4d\xb6\x8f\x9e\xdf\x1f\x03" +
- "\x7d\x70\xe0\x6f\x46\x08\x96\x79\x72\xb7\xae\x41\x2b\xbd\x2a\x95",
-
- "\x8e\x5f\xf8\x79\x36\x8d\xbe\x68\xc4\x2c\x78\x8a\x46\x28\x40\x3e" +
- "\xcf\x3b\xb9\x14\xaf\xfa\x04\x9e\x4b\xa2\x52\x51\x51\xf0\xad\xd3" +
- "\x03\x1c\x03\x79\x5f\x53\xc7\x1a\xd5\x28\xe2\xd9\x19\x37\xa4\xfa" +
- "\xdd\xff\xac\xb5\xa9\x42\x4e\x17\xeb\xb4\x0d\x20\x67\x08\x43\x21" +
- "\x7d\x12\x27\xfa\x96\x7a\x85\xf8\x04\x5f\xf4\xfe\xda\x9f\x66\xf2" +
- "\xba\x04\x39\x00\xab\x3f\x23\x20\x84\x53\xb4\x88\xb6\xee\xa2\x9e" +
- "\xc1\xca\xd4\x09\x2a\x27\x89\x2f\xcb\xba\xa6\x41\xb6\xe9\xc5\x08" +
- "\xff\xf5\x95\x35\xab\xbb\x5c\x62\x96\xe7\x7c\x8f\xf2\x40\x12\xc9" +
- "\x2d\xfe\xff\x75\x4f\x70\x47\xc9\xcd\x15\x0a\x1c\x23\xe7\x0f\x15" +
- "\x95\x75\x30\x8f\x6e\x9f\x7e\xa5\x9d\xd1\x65\x1c\x4d\x4e\xf4\x32" +
- "\x49\x9b\xa1\x30\x44\x62\x6f\xe2\xe6\x69\x09\xf8\x7c\x7c\xbe\x07" +
- "\xa9\xb6\x14\x7a\x6b\x85\xe4\xbf\x48\xbe\x5b\x3b\x70\xb3\x79\x3b" +
- "\xc4\x35\x9d\x86\xf1\xfe\x2b\x6f\x80\x74\x50\xf3\x96\x59\x53\x1a" +
- "\x75\x46\x9d\x57\x72\xb3\xb1\x26\xf5\x81\xcd\x96\x08\xbc\x2b\x10" +
- "\xdc\x80\xbd\xd0\xdf\x03\x6d\x8d\xec\x30\x2b\x4c\xdb\x4d\x3b\xef" +
- "\x7d\x3a\x39\xc8\x5a\xc4\xcc\x24\x37\xde\xe2\x95\x2b\x04\x97\xb0",
-
- // From hg diff --git
- "Index: a\n" +
- "index cb34d9b1743b7c410fa750be8a58eb355987110b..0a01764bc1b2fd29da317f72208f462ad342400f\n" +
- "GIT binary patch\n" +
- "literal 256\n" +
- "zc$@(M0ssDvU-)@8jlO8aEO?4WC_p~XJGm6E`UIX!qEb;&@U7DW90Pe@Q^y+BDB{@}\n" +
- "zH>CRA|E#sCLQWU!v<)C<2ty%#5-0kWdWHA|U-bUkpJwv91UUe!KO-Q7Q?!V-?xLQ-\n" +
- "z%G3!eCy6i1x~4(4>BR{D^_4ZNyIf+H=X{UyKoZF<{{MAPa7W3_6$%_9=MNQ?buf=^\n" +
- "zpMIsC(PbP>PV_QKo1rj7VsGN+X$kmze7*;%wiJ46h2+0TzFRwRvw1tjHJyg>{wr^Q\n" +
- "zbWrn_SyLKyMx9r3v#}=ifz6f(yekmgfW6S)18t4$Fe^;kO*`*>IyuN%#LOf&-r|)j\n" +
- "G1edVN^?m&S\n" +
- "\n",
- },
- {
- "",
- "",
- "Index: hello\n" +
- "===================================================================\n" +
- "old mode 100644\n" +
- "new mode 100755\n",
- },
-}
diff --git a/src/pkg/patch/textdiff.go b/src/pkg/patch/textdiff.go
deleted file mode 100644
index 482bd6781..000000000
--- a/src/pkg/patch/textdiff.go
+++ /dev/null
@@ -1,175 +0,0 @@
-package patch
-
-import (
- "bytes"
- "os"
-)
-
-type TextDiff []TextChunk
-
-// A TextChunk specifies an edit to a section of a file:
-// the text beginning at Line, which should be exactly Old,
-// is to be replaced with New.
-type TextChunk struct {
- Line int
- Old []byte
- New []byte
-}
-
-func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
- var chunkHeader []byte
-
- // Copy raw so it is safe to keep references to slices.
- _, chunks := sections(raw, "@@ -")
- delta := 0
- diff := make(TextDiff, len(chunks))
- for i, raw := range chunks {
- c := &diff[i]
-
- // Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
- chunk := splitLines(raw)
- chunkHeader = chunk[0]
- var ok bool
- var oldLine, oldCount, newLine, newCount int
- s := chunkHeader
- if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
- goto ErrChunkHdr
- }
- if len(s) == 0 || s[0] != ',' {
- oldCount = 1
- } else if oldCount, s, ok = atoi(s, ",", 10); !ok {
- goto ErrChunkHdr
- }
- if newLine, s, ok = atoi(s, " +", 10); !ok {
- goto ErrChunkHdr
- }
- if len(s) == 0 || s[0] != ',' {
- newCount = 1
- } else if newCount, s, ok = atoi(s, ",", 10); !ok {
- goto ErrChunkHdr
- }
- if !hasPrefix(s, " @@") {
- goto ErrChunkHdr
- }
-
- // Special case: for created or deleted files, the empty half
- // is given as starting at line 0. Translate to line 1.
- if oldCount == 0 && oldLine == 0 {
- oldLine = 1
- }
- if newCount == 0 && newLine == 0 {
- newLine = 1
- }
-
- // Count lines in text
- var dropOldNL, dropNewNL bool
- var nold, nnew int
- var lastch byte
- chunk = chunk[1:]
- for _, l := range chunk {
- if nold == oldCount && nnew == newCount && (len(l) == 0 || l[0] != '\\') {
- if len(bytes.TrimSpace(l)) != 0 {
- return nil, SyntaxError("too many chunk lines")
- }
- continue
- }
- if len(l) == 0 {
- return nil, SyntaxError("empty chunk line")
- }
- switch l[0] {
- case '+':
- nnew++
- case '-':
- nold++
- case ' ':
- nnew++
- nold++
- case '\\':
- if _, ok := skip(l, "\\ No newline at end of file"); ok {
- switch lastch {
- case '-':
- dropOldNL = true
- case '+':
- dropNewNL = true
- case ' ':
- dropOldNL = true
- dropNewNL = true
- default:
- return nil, SyntaxError("message `\\ No newline at end of file' out of context")
- }
- break
- }
- fallthrough
- default:
- return nil, SyntaxError("unexpected chunk line: " + string(l))
- }
- lastch = l[0]
- }
-
- // Does it match the header?
- if nold != oldCount || nnew != newCount {
- return nil, SyntaxError("chunk header does not match line count: " + string(chunkHeader))
- }
- if oldLine+delta != newLine {
- return nil, SyntaxError("chunk delta is out of sync with previous chunks")
- }
- delta += nnew - nold
- c.Line = oldLine
-
- var old, new bytes.Buffer
- nold = 0
- nnew = 0
- for _, l := range chunk {
- if nold == oldCount && nnew == newCount {
- break
- }
- ch, l := l[0], l[1:]
- if ch == '\\' {
- continue
- }
- if ch != '+' {
- old.Write(l)
- nold++
- }
- if ch != '-' {
- new.Write(l)
- nnew++
- }
- }
- c.Old = old.Bytes()
- c.New = new.Bytes()
- if dropOldNL {
- c.Old = c.Old[0 : len(c.Old)-1]
- }
- if dropNewNL {
- c.New = c.New[0 : len(c.New)-1]
- }
- }
- return diff, nil
-
-ErrChunkHdr:
- return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
-}
-
-var ErrPatchFailure = os.NewError("patch did not apply cleanly")
-
-// Apply applies the changes listed in the diff
-// to the data, returning the new version.
-func (d TextDiff) Apply(data []byte) ([]byte, os.Error) {
- var buf bytes.Buffer
- line := 1
- for _, c := range d {
- var ok bool
- var prefix []byte
- prefix, data, ok = getLine(data, c.Line-line)
- if !ok || !bytes.HasPrefix(data, c.Old) {
- return nil, ErrPatchFailure
- }
- buf.Write(prefix)
- data = data[len(c.Old):]
- buf.Write(c.New)
- line = c.Line + bytes.Count(c.Old, newline)
- }
- buf.Write(data)
- return buf.Bytes(), nil
-}
diff --git a/src/pkg/path/Makefile b/src/pkg/path/Makefile
deleted file mode 100644
index fc3e2519c..000000000
--- a/src/pkg/path/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../Make.inc
-
-TARG=path
-GOFILES=\
- match.go\
- path.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../Make.pkg
diff --git a/src/pkg/path/example_test.go b/src/pkg/path/example_test.go
new file mode 100644
index 000000000..fa8c28d2e
--- /dev/null
+++ b/src/pkg/path/example_test.go
@@ -0,0 +1,63 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path_test
+
+import (
+ "fmt"
+ "path"
+)
+
+func ExampleBase() {
+ fmt.Println(path.Base("/a/b"))
+ // Output: b
+}
+
+func ExampleClean() {
+ paths := []string{
+ "a/c",
+ "a//c",
+ "a/c/.",
+ "a/c/b/..",
+ "/../a/c",
+ "/../a/b/../././/c",
+ }
+
+ for _, p := range paths {
+ fmt.Printf("Clean(%q) = %q\n", p, path.Clean(p))
+ }
+
+ // Output:
+ // Clean("a/c") = "a/c"
+ // Clean("a//c") = "a/c"
+ // Clean("a/c/.") = "a/c"
+ // Clean("a/c/b/..") = "a/c"
+ // Clean("/../a/c") = "/a/c"
+ // Clean("/../a/b/../././/c") = "/a/c"
+}
+
+func ExampleDir() {
+ fmt.Println(path.Dir("/a/b/c"))
+ // Output: /a/b
+}
+
+func ExampleExt() {
+ fmt.Println(path.Ext("/a/b/c/bar.css"))
+ // Output: .css
+}
+
+func ExampleIsAbs() {
+ fmt.Println(path.IsAbs("/dev/null"))
+ // Output: true
+}
+
+func ExampleJoin() {
+ fmt.Println(path.Join("a", "b", "c"))
+ // Output: a/b/c
+}
+
+func ExampleSplit() {
+ fmt.Println(path.Split("static/myfile.css"))
+ // Output: static/ myfile.css
+}
diff --git a/src/pkg/path/filepath/Makefile b/src/pkg/path/filepath/Makefile
deleted file mode 100644
index af250ab33..000000000
--- a/src/pkg/path/filepath/Makefile
+++ /dev/null
@@ -1,32 +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.
-
-include ../../../Make.inc
-
-TARG=path/filepath
-GOFILES=\
- match.go\
- path.go\
-
-GOFILES_freebsd=\
- path_unix.go
-
-GOFILES_darwin=\
- path_unix.go
-
-GOFILES_linux=\
- path_unix.go
-
-GOFILES_openbsd=\
- path_unix.go
-
-GOFILES_plan9=\
- path_plan9.go
-
-GOFILES_windows=\
- path_windows.go
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../../Make.pkg
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 7fcc214c0..db8b0260c 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -5,13 +5,16 @@
package filepath
import (
+ "errors"
"os"
+ "runtime"
"sort"
"strings"
- "utf8"
+ "unicode/utf8"
)
-var ErrBadPattern = os.NewError("syntax error in pattern")
+// ErrBadPattern indicates a globbing pattern was malformed.
+var ErrBadPattern = errors.New("syntax error in pattern")
// Match returns true if name matches the shell file name pattern.
// The pattern syntax is:
@@ -32,9 +35,13 @@ var ErrBadPattern = os.NewError("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of name, not just a substring.
-// The only possible error return occurs when the pattern is malformed.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
//
-func Match(pattern, name string) (matched bool, err os.Error) {
+// On Windows, escaping is disabled. Instead, '\\' is treated as
+// path separator.
+//
+func Match(pattern, name string) (matched bool, err error) {
Pattern:
for len(pattern) > 0 {
var star bool
@@ -92,9 +99,11 @@ Scan:
for i = 0; i < len(pattern); i++ {
switch pattern[i] {
case '\\':
- // error check handled in matchChunk: bad pattern.
- if i+1 < len(pattern) {
- i++
+ if runtime.GOOS != "windows" {
+ // error check handled in matchChunk: bad pattern.
+ if i+1 < len(pattern) {
+ i++
+ }
}
case '[':
inrange = true
@@ -112,7 +121,7 @@ Scan:
// matchChunk checks whether chunk matches the beginning of s.
// If so, it returns the remainder of s (after the match).
// Chunk is all single-character operators: literals, char classes, and ?.
-func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+func matchChunk(chunk, s string) (rest string, ok bool, err error) {
for len(chunk) > 0 {
if len(s) == 0 {
return
@@ -136,7 +145,7 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
chunk = chunk[1:]
break
}
- var lo, hi int
+ var lo, hi rune
if lo, chunk, err = getEsc(chunk); err != nil {
return
}
@@ -164,10 +173,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
chunk = chunk[1:]
case '\\':
- chunk = chunk[1:]
- if len(chunk) == 0 {
- err = ErrBadPattern
- return
+ if runtime.GOOS != "windows" {
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
}
fallthrough
@@ -183,12 +194,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
}
// getEsc gets a possibly-escaped character from chunk, for a character class.
-func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+func getEsc(chunk string) (r rune, nchunk string, err error) {
if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
err = ErrBadPattern
return
}
- if chunk[0] == '\\' {
+ if chunk[0] == '\\' && runtime.GOOS != "windows" {
chunk = chunk[1:]
if len(chunk) == 0 {
err = ErrBadPattern
@@ -210,12 +221,11 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
// if there is no matching file. The syntax of patterns is the same
// as in Match. The pattern may describe hierarchical names such as
// /usr/*/bin/ed (assuming the Separator is '/').
-// The only possible error return occurs when the pattern is malformed.
//
-func Glob(pattern string) (matches []string, err os.Error) {
+func Glob(pattern string) (matches []string, err error) {
if !hasMeta(pattern) {
if _, err = os.Stat(pattern); err != nil {
- return
+ return nil, nil
}
return []string{pattern}, nil
}
@@ -252,14 +262,13 @@ func Glob(pattern string) (matches []string, err os.Error) {
// and appends them to matches. If the directory cannot be
// opened, it returns the existing matches. New matches are
// added in lexicographical order.
-// The only possible error return occurs when the pattern is malformed.
-func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
+func glob(dir, pattern string, matches []string) (m []string, e error) {
m = matches
fi, err := os.Stat(dir)
if err != nil {
return
}
- if !fi.IsDirectory() {
+ if !fi.IsDir() {
return
}
d, err := os.Open(dir)
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
index a1c8333f3..7b0ea8017 100644
--- a/src/pkg/path/filepath/match_test.go
+++ b/src/pkg/path/filepath/match_test.go
@@ -5,16 +5,16 @@
package filepath_test
import (
- "os"
. "path/filepath"
- "testing"
"runtime"
+ "strings"
+ "testing"
)
type MatchTest struct {
pattern, s string
match bool
- err os.Error
+ err error
}
var matchTests = []MatchTest{
@@ -69,29 +69,34 @@ var matchTests = []MatchTest{
{"*x", "xxx", true, nil},
}
-func errp(e os.Error) string {
+func errp(e error) string {
if e == nil {
return "<nil>"
}
- return e.String()
+ return e.Error()
}
func TestMatch(t *testing.T) {
- if runtime.GOOS == "windows" {
- // XXX: Don't pass for windows.
- return
- }
for _, tt := range matchTests {
- ok, err := Match(tt.pattern, tt.s)
+ pattern := tt.pattern
+ s := tt.s
+ if runtime.GOOS == "windows" {
+ if strings.Index(pattern, "\\") >= 0 {
+ // no escape allowed on windows.
+ continue
+ }
+ pattern = Clean(pattern)
+ s = Clean(s)
+ }
+ ok, err := Match(pattern, s)
if ok != tt.match || err != tt.err {
- t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err))
+ t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
}
}
}
// contains returns true if vector contains the string s.
func contains(vector []string, s string) bool {
- s = ToSlash(s)
for _, elem := range vector {
if elem == s {
return true
@@ -110,18 +115,30 @@ var globTests = []struct {
}
func TestGlob(t *testing.T) {
- if runtime.GOOS == "windows" {
- // XXX: Don't pass for windows.
- return
- }
for _, tt := range globTests {
- matches, err := Glob(tt.pattern)
+ pattern := tt.pattern
+ result := tt.result
+ if runtime.GOOS == "windows" {
+ pattern = Clean(pattern)
+ result = Clean(result)
+ }
+ matches, err := Glob(pattern)
+ if err != nil {
+ t.Errorf("Glob error for %q: %s", pattern, err)
+ continue
+ }
+ if !contains(matches, result) {
+ t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result)
+ }
+ }
+ for _, pattern := range []string{"no_match", "../*/no_match"} {
+ matches, err := Glob(pattern)
if err != nil {
- t.Errorf("Glob error for %q: %s", tt.pattern, err)
+ t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
- if !contains(matches, tt.result) {
- t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+ if len(matches) != 0 {
+ t.Errorf("Glob(%#q) = %#v want []", pattern, matches)
}
}
}
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index 3d5b915c1..1e7487263 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -7,9 +7,8 @@
package filepath
import (
- "bytes"
+ "errors"
"os"
- "runtime"
"sort"
"strings"
)
@@ -35,15 +34,18 @@ const (
// returns the string ".".
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
-// Getting Dot-Dot right,''
+// 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 == "" {
+ if len(vol) > 1 && vol[1] != ':' {
+ // should be UNC
+ return FromSlash(vol)
+ }
return vol + "."
}
-
rooted := os.IsPathSeparator(path[0])
// Invariants:
@@ -114,7 +116,8 @@ func Clean(path string) string {
}
// ToSlash returns the result of replacing each separator character
-// in path with a slash ('/') character.
+// in path with a slash ('/') character. Multiple separators are
+// replaced by multiple slashes.
func ToSlash(path string) string {
if Separator == '/' {
return path
@@ -123,7 +126,8 @@ func ToSlash(path string) string {
}
// FromSlash returns the result of replacing each slash ('/') character
-// in path with a separator character.
+// in path with a separator character. Multiple slashes are replaced
+// by multiple separators.
func FromSlash(path string) string {
if Separator == '/' {
return path
@@ -131,7 +135,9 @@ func FromSlash(path string) string {
return strings.Replace(path, "/", string(Separator), -1)
}
-// SplitList splits a list of paths joined by the OS-specific ListSeparator.
+// SplitList splits a list of paths joined by the OS-specific ListSeparator,
+// usually found in PATH or GOPATH environment variables.
+// Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
func SplitList(path string) []string {
if path == "" {
return []string{}
@@ -143,16 +149,19 @@ func SplitList(path string) []string {
// 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.
+// The returned values have the property that path = dir+file.
func Split(path string) (dir, file string) {
+ vol := VolumeName(path)
i := len(path) - 1
- for i >= 0 && !os.IsPathSeparator(path[i]) {
+ for i >= len(vol) && !os.IsPathSeparator(path[i]) {
i--
}
return path[:i+1], path[i+1:]
}
// Join joins any number of path elements into a single path, adding
-// a Separator if necessary. All empty strings are ignored.
+// a Separator if necessary. The result is Cleaned, in particular
+// all empty strings are ignored.
func Join(elem ...string) string {
for i, e := range elem {
if e != "" {
@@ -177,73 +186,17 @@ func Ext(path string) string {
// EvalSymlinks returns the path name after the evaluation of any symbolic
// 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,
- // expanding it if it's a symlink, and appending it to b
- var b bytes.Buffer
- for n := 0; path != ""; n++ {
- if n > maxIter {
- return "", os.NewError("EvalSymlinks: too many links in " + originalPath)
- }
-
- // find next path component, p
- i := strings.IndexRune(path, Separator)
- var p string
- if i == -1 {
- p, path = path, ""
- } else {
- p, path = path[:i], path[i+1:]
- }
-
- if p == "" {
- if b.Len() == 0 {
- // must be absolute path
- b.WriteRune(Separator)
- }
- continue
- }
-
- fi, err := os.Lstat(b.String() + p)
- if err != nil {
- return "", err
- }
- if !fi.IsSymlink() {
- b.WriteString(p)
- if path != "" {
- b.WriteRune(Separator)
- }
- continue
- }
-
- // it's a symlink, put it at the front of path
- dest, err := os.Readlink(b.String() + p)
- if err != nil {
- return "", err
- }
- if IsAbs(dest) {
- b.Reset()
- }
- path = dest + string(Separator) + path
- }
- return Clean(b.String()), nil
+// If path is relative the result will be relative to the current directory,
+// unless one of the components is an absolute symbolic link.
+func EvalSymlinks(path string) (string, error) {
+ return evalSymlinks(path)
}
// Abs returns an absolute representation of path.
// If the path is not absolute it will be joined with the current
// working directory to turn it into an absolute path. The absolute
// path name for a given file is not guaranteed to be unique.
-func Abs(path string) (string, os.Error) {
+func Abs(path string) (string, error) {
if IsAbs(path) {
return Clean(path), nil
}
@@ -254,40 +207,140 @@ func Abs(path string) (string, os.Error) {
return Join(wd, path), nil
}
-// Visitor methods are invoked for corresponding file tree entries
-// visited by Walk. The parameter path is the full path of f relative
-// to root.
-type Visitor interface {
- VisitDir(path string, f *os.FileInfo) bool
- VisitFile(path string, f *os.FileInfo)
+// Rel returns a relative path that is lexically equivalent to targpath when
+// joined to basepath with an intervening separator. That is,
+// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
+// On success, the returned path will always be relative to basepath,
+// even if basepath and targpath share no elements.
+// An error is returned if targpath can't be made relative to basepath or if
+// knowing the current working directory would be necessary to compute it.
+func Rel(basepath, targpath string) (string, error) {
+ baseVol := VolumeName(basepath)
+ targVol := VolumeName(targpath)
+ base := Clean(basepath)
+ targ := Clean(targpath)
+ if targ == base {
+ return ".", nil
+ }
+ base = base[len(baseVol):]
+ targ = targ[len(targVol):]
+ if base == "." {
+ base = ""
+ }
+ // Can't use IsAbs - `\a` and `a` are both relative in Windows.
+ baseSlashed := len(base) > 0 && base[0] == Separator
+ targSlashed := len(targ) > 0 && targ[0] == Separator
+ if baseSlashed != targSlashed || baseVol != targVol {
+ return "", errors.New("Rel: can't make " + targ + " relative to " + base)
+ }
+ // Position base[b0:bi] and targ[t0:ti] at the first differing elements.
+ bl := len(base)
+ tl := len(targ)
+ var b0, bi, t0, ti int
+ for {
+ for bi < bl && base[bi] != Separator {
+ bi++
+ }
+ for ti < tl && targ[ti] != Separator {
+ ti++
+ }
+ if targ[t0:ti] != base[b0:bi] {
+ break
+ }
+ if bi < bl {
+ bi++
+ }
+ if ti < tl {
+ ti++
+ }
+ b0 = bi
+ t0 = ti
+ }
+ if base[b0:bi] == ".." {
+ return "", errors.New("Rel: can't make " + targ + " relative to " + base)
+ }
+ if b0 != bl {
+ // Base elements left. Must go up before going down.
+ seps := strings.Count(base[b0:bl], string(Separator))
+ size := 2 + seps*3
+ if tl != t0 {
+ size += 1 + tl - t0
+ }
+ buf := make([]byte, size)
+ n := copy(buf, "..")
+ for i := 0; i < seps; i++ {
+ buf[n] = Separator
+ copy(buf[n+1:], "..")
+ n += 3
+ }
+ if t0 != tl {
+ buf[n] = Separator
+ copy(buf[n+1:], targ[t0:])
+ }
+ return string(buf), nil
+ }
+ return targ[t0:], nil
}
-func walk(path string, f *os.FileInfo, v Visitor, errors chan<- os.Error) {
- if !f.IsDirectory() {
- v.VisitFile(path, f)
- return
+// SkipDir is used as a return value from WalkFuncs to indicate that
+// the directory named in the call is to be skipped. It is not returned
+// as an error by any function.
+var SkipDir = errors.New("skip this directory")
+
+// WalkFunc is the type of the function called for each file or directory
+// visited by Walk. If there was a problem walking to the file or directory
+// named by path, the incoming error will describe the problem and the
+// function can decide how to handle that error (and Walk will not descend
+// into that directory). If an error is returned, processing stops. The
+// sole exception is that if path is a directory and the function returns the
+// special value SkipDir, the contents of the directory are skipped
+// and processing continues as usual on the next file.
+type WalkFunc func(path string, info os.FileInfo, err error) error
+
+// walk recursively descends path, calling w.
+func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
+ err := walkFn(path, info, nil)
+ if err != nil {
+ if info.IsDir() && err == SkipDir {
+ return nil
+ }
+ return err
}
- if !v.VisitDir(path, f) {
- return // skip directory entries
+ if !info.IsDir() {
+ return nil
}
list, err := readDir(path)
if err != nil {
- if errors != nil {
- errors <- err
+ return walkFn(path, info, err)
+ }
+
+ for _, fileInfo := range list {
+ if err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn); err != nil {
+ return err
}
}
+ return nil
+}
- for _, e := range list {
- walk(Join(path, e.Name), e, v, errors)
+// Walk walks the file tree rooted at root, calling walkFn for each file or
+// directory in the tree, including root. All errors that arise visiting files
+// and directories are filtered by walkFn. The files are walked in lexical
+// order, which makes the output deterministic but means that for very
+// large directories Walk can be inefficient.
+func Walk(root string, walkFn WalkFunc) error {
+ info, err := os.Lstat(root)
+ if err != nil {
+ return walkFn(root, nil, err)
}
+ return walk(root, info, walkFn)
}
// readDir reads the directory named by dirname and returns
-// a list of sorted directory entries.
+// a sorted list of directory entries.
// Copied from io/ioutil to avoid the circular import.
-func readDir(dirname string) ([]*os.FileInfo, os.Error) {
+func readDir(dirname string) ([]os.FileInfo, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
@@ -297,38 +350,16 @@ func readDir(dirname string) ([]*os.FileInfo, os.Error) {
if err != nil {
return nil, err
}
- fi := make(fileInfoList, len(list))
- for i := range list {
- fi[i] = &list[i]
- }
- sort.Sort(fi)
- return fi, nil
+ sort.Sort(byName(list))
+ return list, nil
}
-// A dirList implements sort.Interface.
-type fileInfoList []*os.FileInfo
+// byName implements sort.Interface.
+type byName []os.FileInfo
-func (f fileInfoList) Len() int { return len(f) }
-func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
-func (f fileInfoList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
-// Walk walks the file tree rooted at root, calling v.VisitDir or
-// v.VisitFile for each directory or file in the tree, including root.
-// If v.VisitDir returns false, Walk skips the directory's entries;
-// otherwise it invokes itself for each directory entry in sorted order.
-// An error reading a directory does not abort the Walk.
-// If errors != nil, Walk sends each directory read error
-// to the channel. Otherwise Walk discards the error.
-func Walk(root string, v Visitor, errors chan<- os.Error) {
- f, err := os.Lstat(root)
- if err != nil {
- if errors != nil {
- errors <- err
- }
- return // can't progress
- }
- walk(root, f, v, errors)
-}
+func (f byName) Len() int { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
@@ -342,6 +373,8 @@ func Base(path string) string {
for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
path = path[0 : len(path)-1]
}
+ // Throw away volume name
+ path = path[len(VolumeName(path)):]
// Find the last element
i := len(path) - 1
for i >= 0 && !os.IsPathSeparator(path[i]) {
@@ -356,3 +389,25 @@ func Base(path string) string {
}
return path
}
+
+// Dir returns all but the last element of path, typically the path's directory.
+// Trailing path separators are removed before processing.
+// If the path is empty, Dir returns ".".
+// If the path consists entirely of separators, Dir returns a single separator.
+// The returned path does not end in a separator unless it is the root directory.
+func Dir(path string) string {
+ vol := VolumeName(path)
+ i := len(path) - 1
+ for i >= len(vol) && !os.IsPathSeparator(path[i]) {
+ i--
+ }
+ dir := Clean(path[len(vol) : i+1])
+ last := len(dir) - 1
+ if last > 0 && os.IsPathSeparator(dir[last]) {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return vol + dir
+}
diff --git a/src/pkg/path/filepath/path_plan9.go b/src/pkg/path/filepath/path_plan9.go
index 17b873f1a..cf028a75c 100644
--- a/src/pkg/path/filepath/path_plan9.go
+++ b/src/pkg/path/filepath/path_plan9.go
@@ -17,7 +17,7 @@ func VolumeName(path string) string {
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index d2a10698e..b8766588c 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -5,6 +5,7 @@
package filepath_test
import (
+ "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -73,15 +74,23 @@ var wincleantests = []PathTest{
{`c:\abc`, `c:\abc`},
{`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
{`c:\abc\def\..\..`, `c:\`},
+ {`c:\..\abc`, `c:\abc`},
{`c:..\abc`, `c:..\abc`},
{`\`, `\`},
{`/`, `\`},
+ {`\\i\..\c$`, `\c$`},
+ {`\\i\..\i\c$`, `\i\c$`},
+ {`\\i\..\I\c$`, `\I\c$`},
+ {`\\host\share\foo\..\bar`, `\\host\share\bar`},
+ {`//host/share/foo/../baz`, `\\host\share\baz`},
+ {`\\a\b\..\c`, `\\a\b\c`},
+ {`\\a\b`, `\\a\b`},
}
func TestClean(t *testing.T) {
tests := cleantests
if runtime.GOOS == "windows" {
- for i, _ := range tests {
+ for i := range tests {
tests[i].result = filepath.FromSlash(tests[i].result)
}
tests = append(tests, wincleantests...)
@@ -146,9 +155,25 @@ var unixsplittests = []SplitTest{
{"/", "/", ""},
}
+var winsplittests = []SplitTest{
+ {`c:`, `c:`, ``},
+ {`c:/`, `c:/`, ``},
+ {`c:/foo`, `c:/`, `foo`},
+ {`c:/foo/bar`, `c:/foo/`, `bar`},
+ {`//host/share`, `//host/share`, ``},
+ {`//host/share/`, `//host/share/`, ``},
+ {`//host/share/foo`, `//host/share/`, `foo`},
+ {`\\host\share`, `\\host\share`, ``},
+ {`\\host\share\`, `\\host\share\`, ``},
+ {`\\host\share\foo`, `\\host\share\`, `foo`},
+}
+
func TestSplit(t *testing.T) {
var splittests []SplitTest
splittests = unixsplittests
+ if runtime.GOOS == "windows" {
+ splittests = append(splittests, winsplittests...)
+ }
for _, test := range splittests {
if d, f := filepath.Split(test.path); d != test.dir || f != test.file {
t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
@@ -186,6 +211,8 @@ var winjointests = []JoinTest{
{[]string{`C:\Windows\`, ``}, `C:\Windows`},
{[]string{`C:\`, `Windows`}, `C:\Windows`},
{[]string{`C:`, `Windows`}, `C:\Windows`},
+ {[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
+ {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
}
// join takes a []string and passes it to Join.
@@ -234,19 +261,19 @@ type Node struct {
var tree = &Node{
"testdata",
[]*Node{
- &Node{"a", nil, 0},
- &Node{"b", []*Node{}, 0},
- &Node{"c", nil, 0},
- &Node{
+ {"a", nil, 0},
+ {"b", []*Node{}, 0},
+ {"c", nil, 0},
+ {
"d",
[]*Node{
- &Node{"x", nil, 0},
- &Node{"y", []*Node{}, 0},
- &Node{
+ {"x", nil, 0},
+ {"y", []*Node{}, 0},
+ {
"z",
[]*Node{
- &Node{"u", nil, 0},
- &Node{"v", nil, 0},
+ {"u", nil, 0},
+ {"v", nil, 0},
},
0,
},
@@ -270,6 +297,7 @@ func makeTree(t *testing.T) {
fd, err := os.Create(path)
if err != nil {
t.Errorf("makeTree: %v", err)
+ return
}
fd.Close()
} else {
@@ -280,9 +308,9 @@ func makeTree(t *testing.T) {
func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) }
-func checkMarks(t *testing.T) {
+func checkMarks(t *testing.T, report bool) {
walkTree(tree, tree.name, func(path string, n *Node) {
- if n.mark != 1 {
+ if n.mark != 1 && report {
t.Errorf("node %s mark = %d; expected 1", path, n.mark)
}
n.mark = 0
@@ -290,86 +318,94 @@ func checkMarks(t *testing.T) {
}
// Assumes that each node name is unique. Good enough for a test.
-func mark(name string) {
- name = filepath.ToSlash(name)
+// If clear is true, any incoming error is cleared before return. The errors
+// are always accumulated, though.
+func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
+ if err != nil {
+ *errors = append(*errors, err)
+ if clear {
+ return nil
+ }
+ return err
+ }
+ name := info.Name()
walkTree(tree, tree.name, func(path string, n *Node) {
if n.name == name {
n.mark++
}
})
-}
-
-type TestVisitor struct{}
-
-func (v *TestVisitor) VisitDir(path string, f *os.FileInfo) bool {
- mark(f.Name)
- return true
-}
-
-func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
- mark(f.Name)
+ return nil
}
func TestWalk(t *testing.T) {
makeTree(t)
-
- // 1) ignore error handling, expect none
- v := &TestVisitor{}
- filepath.Walk(tree.name, v, nil)
- checkMarks(t)
-
- // 2) handle errors, expect none
- errors := make(chan os.Error, 64)
- filepath.Walk(tree.name, v, errors)
- select {
- case err := <-errors:
- t.Errorf("no error expected, found: %s", err)
- default:
- // ok
+ errors := make([]error, 0, 10)
+ clear := true
+ markFn := func(path string, info os.FileInfo, err error) error {
+ return mark(path, info, err, &errors, clear)
+ }
+ // Expect no errors.
+ err := filepath.Walk(tree.name, markFn)
+ if err != nil {
+ t.Fatalf("no error expected, found: %s", err)
}
- checkMarks(t)
+ if len(errors) != 0 {
+ t.Fatalf("unexpected errors: %s", errors)
+ }
+ checkMarks(t, true)
+ errors = errors[0: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.
+ // all.bash on those file systems, skip during go test -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)
+
+ // 3) capture errors, expect two.
// mark respective subtrees manually
markTree(tree.entries[1])
markTree(tree.entries[3])
// correct double-marking of directory itself
tree.entries[1].mark--
tree.entries[3].mark--
+ err := filepath.Walk(tree.name, markFn)
+ if err != nil {
+ t.Fatalf("expected no error return from Walk, got %s", err)
+ }
+ if len(errors) != 2 {
+ t.Errorf("expected 2 errors, got %d: %s", len(errors), errors)
+ }
+ // the inaccessible subtrees were marked manually
+ checkMarks(t, true)
+ errors = errors[0:0]
- // 3) handle errors, expect two
- errors = make(chan os.Error, 64)
- os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
- filepath.Walk(tree.name, v, errors)
- Loop:
- for i := 1; i <= 2; i++ {
- select {
- case <-errors:
- // ok
- default:
- t.Errorf("%d. error expected, none found", i)
- break Loop
- }
+ // 4) capture errors, stop after first error.
+ // mark respective subtrees manually
+ markTree(tree.entries[1])
+ markTree(tree.entries[3])
+ // correct double-marking of directory itself
+ tree.entries[1].mark--
+ tree.entries[3].mark--
+ clear = false // error will stop processing
+ err = filepath.Walk(tree.name, markFn)
+ if err == nil {
+ t.Fatalf("expected error return from Walk")
}
- select {
- case err := <-errors:
- t.Errorf("only two errors expected, found 3rd: %v", err)
- default:
- // ok
+ if len(errors) != 1 {
+ t.Errorf("expected 1 error, got %d: %s", len(errors), errors)
}
// the inaccessible subtrees were marked manually
- checkMarks(t)
+ checkMarks(t, false)
+ errors = errors[0:0]
+
+ // restore permissions
+ os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
+ os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
}
// cleanup
- os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0770)
- os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0770)
if err := os.RemoveAll(tree.name); err != nil {
t.Errorf("removeTree: %v", err)
}
@@ -389,14 +425,77 @@ var basetests = []PathTest{
{"a/b/c.x", "c.x"},
}
+var winbasetests = []PathTest{
+ {`c:\`, `\`},
+ {`c:.`, `.`},
+ {`c:\a\b`, `b`},
+ {`c:a\b`, `b`},
+ {`c:a\b\c`, `c`},
+ {`\\host\share\`, `\`},
+ {`\\host\share\a`, `a`},
+ {`\\host\share\a\b`, `b`},
+}
+
func TestBase(t *testing.T) {
- for _, test := range basetests {
- if s := filepath.ToSlash(filepath.Base(test.path)); s != test.result {
+ tests := basetests
+ if runtime.GOOS == "windows" {
+ // make unix tests work on windows
+ for i := range tests {
+ tests[i].result = filepath.Clean(tests[i].result)
+ }
+ // add windows specific tests
+ tests = append(tests, winbasetests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Base(test.path); s != test.result {
t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
}
}
}
+var dirtests = []PathTest{
+ {"", "."},
+ {".", "."},
+ {"/.", "/"},
+ {"/", "/"},
+ {"////", "/"},
+ {"/foo", "/"},
+ {"x/", "x"},
+ {"abc", "."},
+ {"abc/def", "abc"},
+ {"a/b/.x", "a/b"},
+ {"a/b/c.", "a/b"},
+ {"a/b/c.x", "a/b"},
+}
+
+var windirtests = []PathTest{
+ {`c:\`, `c:\`},
+ {`c:.`, `c:.`},
+ {`c:\a\b`, `c:\a`},
+ {`c:a\b`, `c:a`},
+ {`c:a\b\c`, `c:a\b`},
+ {`\\host\share\`, `\\host\share\`},
+ {`\\host\share\a`, `\\host\share\`},
+ {`\\host\share\a\b`, `\\host\share\a`},
+}
+
+func TestDir(t *testing.T) {
+ tests := dirtests
+ if runtime.GOOS == "windows" {
+ // make unix tests work on windows
+ for i := range tests {
+ tests[i].result = filepath.Clean(tests[i].result)
+ }
+ // add windows specific tests
+ tests = append(tests, windirtests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Dir(test.path); s != test.result {
+ t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
type IsAbsTest struct {
path string
isAbs bool
@@ -422,6 +521,8 @@ var winisabstests = []IsAbsTest{
{`\`, false},
{`\Windows`, false},
{`c:a\b`, false},
+ {`\\host\share\foo`, true},
+ {`//host/share/foo/bar`, true},
}
func TestIsAbs(t *testing.T) {
@@ -448,6 +549,7 @@ func TestIsAbs(t *testing.T) {
}
type EvalSymlinksTest struct {
+ // If dest is empty, the path is created; otherwise the dest is symlinked to the path.
path, dest string
}
@@ -457,6 +559,7 @@ var EvalSymlinksTestDirs = []EvalSymlinksTest{
{"test/dir/link3", "../../"},
{"test/link1", "../test"},
{"test/link2", "dir"},
+ {"test/linkabs", "/"},
}
var EvalSymlinksTests = []EvalSymlinksTest{
@@ -469,101 +572,150 @@ var EvalSymlinksTests = []EvalSymlinksTest{
{"test/link2/..", "test"},
{"test/dir/link3", "."},
{"test/link2/link3/test", "test"},
+ {"test/linkabs", "/"},
}
var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
{`c:\`, `c:\`},
}
-func testEvalSymlinks(t *testing.T, tests []EvalSymlinksTest) {
- for _, d := range tests {
- if p, err := filepath.EvalSymlinks(d.path); err != nil {
- t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
- } else if filepath.Clean(p) != filepath.Clean(d.dest) {
- t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
- }
- }
+// simpleJoin builds a file name from the directory and path.
+// It does not use Join because we don't want ".." to be evaluated.
+func simpleJoin(dir, path string) string {
+ return dir + string(filepath.Separator) + path
}
func TestEvalSymlinks(t *testing.T) {
- defer os.RemoveAll("test")
+ tmpDir, err := ioutil.TempDir("", "evalsymlink")
+ if err != nil {
+ t.Fatal("creating temp dir:", err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ // /tmp may itself be a symlink! Avoid the confusion, although
+ // it means trusting the thing we're testing.
+ tmpDir, err = filepath.EvalSymlinks(tmpDir)
+ if err != nil {
+ t.Fatal("eval symlink for tmp dir:", err)
+ }
+
+ // Create the symlink farm using relative paths.
for _, d := range EvalSymlinksTestDirs {
- var err os.Error
+ var err error
+ path := simpleJoin(tmpDir, d.path)
if d.dest == "" {
- err = os.Mkdir(d.path, 0755)
+ err = os.Mkdir(path, 0755)
} else {
if runtime.GOOS != "windows" {
- err = os.Symlink(d.dest, d.path)
+ err = os.Symlink(d.dest, path)
}
}
if err != nil {
t.Fatal(err)
}
}
+
var tests []EvalSymlinksTest
if runtime.GOOS == "windows" {
for _, d := range EvalSymlinksTests {
if d.path == d.dest {
// will test only real files and directories
tests = append(tests, d)
+ // test "canonical" names
+ d2 := EvalSymlinksTest{
+ path: strings.ToUpper(d.path),
+ dest: d.dest,
+ }
+ tests = append(tests, d2)
}
}
} else {
tests = EvalSymlinksTests
}
- // relative
- testEvalSymlinks(t, tests)
- // absolute
- goroot, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
- if err != nil {
- t.Fatalf("EvalSymlinks(%q) error: %v", os.Getenv("GOROOT"), err)
- }
- testroot := filepath.Join(goroot, "src", "pkg", "path", "filepath")
- for i, d := range tests {
- tests[i].path = filepath.Join(testroot, d.path)
- tests[i].dest = filepath.Join(testroot, d.dest)
- }
- if runtime.GOOS == "windows" {
- for _, d := range EvalSymlinksAbsWindowsTests {
- tests = append(tests, d)
+
+ // Evaluate the symlink farm.
+ for _, d := range tests {
+ path := simpleJoin(tmpDir, d.path)
+ dest := simpleJoin(tmpDir, d.dest)
+ if filepath.IsAbs(d.dest) {
+ dest = d.dest
+ }
+ if p, err := filepath.EvalSymlinks(path); err != nil {
+ t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+ } else if filepath.Clean(p) != filepath.Clean(dest) {
+ t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
}
}
- testEvalSymlinks(t, tests)
}
-// Test paths relative to $GOROOT/src
-var abstests = []string{
- "../AUTHORS",
- "pkg/../../AUTHORS",
- "Make.pkg",
- "pkg/Makefile",
+// Test directories relative to temporary directory.
+// The tests are run in absTestDirs[0].
+var absTestDirs = []string{
+ "a",
+ "a/b",
+ "a/b/c",
+}
- // Already absolute
- "$GOROOT/src/Make.pkg",
- "$GOROOT/src/../src/Make.pkg",
+// Test paths relative to temporary directory. $ expands to the directory.
+// The tests are run in absTestDirs[0].
+// We create absTestDirs first.
+var absTests = []string{
+ ".",
+ "b",
+ "../a",
+ "../a/b",
+ "../a/b/./c/../../.././a",
+ "$",
+ "$/.",
+ "$/a/../a/b",
+ "$/a/b/c/../../.././a",
}
func TestAbs(t *testing.T) {
oldwd, err := os.Getwd()
if err != nil {
- t.Fatal("Getwd failed: " + err.String())
+ t.Fatal("Getwd failed: ", err)
}
defer os.Chdir(oldwd)
- goroot := os.Getenv("GOROOT")
- cwd := filepath.Join(goroot, "src")
- os.Chdir(cwd)
- for _, path := range abstests {
- path = strings.Replace(path, "$GOROOT", goroot, -1)
- abspath, err := filepath.Abs(path)
+
+ root, err := ioutil.TempDir("", "TestAbs")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(root)
+
+ err = os.Chdir(root)
+ if err != nil {
+ t.Fatal("chdir failed: ", err)
+ }
+
+ for _, dir := range absTestDirs {
+ err = os.Mkdir(dir, 0777)
if err != nil {
- t.Errorf("Abs(%q) error: %v", path, err)
+ t.Fatal("Mkdir failed: ", err)
}
+ }
+
+ err = os.Chdir(absTestDirs[0])
+ if err != nil {
+ t.Fatal("chdir failed: ", err)
+ }
+
+ for _, path := range absTests {
+ path = strings.Replace(path, "$", root, -1)
info, err := os.Stat(path)
if err != nil {
t.Errorf("%s: %s", path, err)
+ continue
+ }
+
+ abspath, err := filepath.Abs(path)
+ if err != nil {
+ t.Errorf("Abs(%q) error: %v", path, err)
+ continue
}
absinfo, err := os.Stat(abspath)
- if err != nil || absinfo.Ino != info.Ino {
+ if err != nil || !os.SameFile(absinfo, info) {
t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
}
if !filepath.IsAbs(abspath) {
@@ -574,3 +726,146 @@ func TestAbs(t *testing.T) {
}
}
}
+
+type RelTests struct {
+ root, path, want string
+}
+
+var reltests = []RelTests{
+ {"a/b", "a/b", "."},
+ {"a/b/.", "a/b", "."},
+ {"a/b", "a/b/.", "."},
+ {"./a/b", "a/b", "."},
+ {"a/b", "./a/b", "."},
+ {"ab/cd", "ab/cde", "../cde"},
+ {"ab/cd", "ab/c", "../c"},
+ {"a/b", "a/b/c/d", "c/d"},
+ {"a/b", "a/b/../c", "../c"},
+ {"a/b/../c", "a/b", "../b"},
+ {"a/b/c", "a/c/d", "../../c/d"},
+ {"a/b", "c/d", "../../c/d"},
+ {"a/b/c/d", "a/b", "../.."},
+ {"a/b/c/d", "a/b/", "../.."},
+ {"a/b/c/d/", "a/b", "../.."},
+ {"a/b/c/d/", "a/b/", "../.."},
+ {"../../a/b", "../../a/b/c/d", "c/d"},
+ {"/a/b", "/a/b", "."},
+ {"/a/b/.", "/a/b", "."},
+ {"/a/b", "/a/b/.", "."},
+ {"/ab/cd", "/ab/cde", "../cde"},
+ {"/ab/cd", "/ab/c", "../c"},
+ {"/a/b", "/a/b/c/d", "c/d"},
+ {"/a/b", "/a/b/../c", "../c"},
+ {"/a/b/../c", "/a/b", "../b"},
+ {"/a/b/c", "/a/c/d", "../../c/d"},
+ {"/a/b", "/c/d", "../../c/d"},
+ {"/a/b/c/d", "/a/b", "../.."},
+ {"/a/b/c/d", "/a/b/", "../.."},
+ {"/a/b/c/d/", "/a/b", "../.."},
+ {"/a/b/c/d/", "/a/b/", "../.."},
+ {"/../../a/b", "/../../a/b/c/d", "c/d"},
+ {".", "a/b", "a/b"},
+ {".", "..", ".."},
+
+ // can't do purely lexically
+ {"..", ".", "err"},
+ {"..", "a", "err"},
+ {"../..", "..", "err"},
+ {"a", "/a", "err"},
+ {"/a", "a", "err"},
+}
+
+var winreltests = []RelTests{
+ {`C:a\b\c`, `C:a/b/d`, `..\d`},
+ {`C:\`, `D:\`, `err`},
+ {`C:`, `D:`, `err`},
+}
+
+func TestRel(t *testing.T) {
+ tests := append([]RelTests{}, reltests...)
+ if runtime.GOOS == "windows" {
+ for i := range tests {
+ tests[i].want = filepath.FromSlash(tests[i].want)
+ }
+ tests = append(tests, winreltests...)
+ }
+ for _, test := range tests {
+ got, err := filepath.Rel(test.root, test.path)
+ if test.want == "err" {
+ if err == nil {
+ t.Errorf("Rel(%q, %q)=%q, want error", test.root, test.path, got)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("Rel(%q, %q): want %q, got error: %s", test.root, test.path, test.want, err)
+ }
+ if got != test.want {
+ t.Errorf("Rel(%q, %q)=%q, want %q", test.root, test.path, got, test.want)
+ }
+ }
+}
+
+type VolumeNameTest struct {
+ path string
+ vol string
+}
+
+var volumenametests = []VolumeNameTest{
+ {`c:/foo/bar`, `c:`},
+ {`c:`, `c:`},
+ {`2:`, ``},
+ {``, ``},
+ {`\\\host`, ``},
+ {`\\\host\`, ``},
+ {`\\\host\share`, ``},
+ {`\\\host\\share`, ``},
+ {`\\host`, ``},
+ {`//host`, ``},
+ {`\\host\`, ``},
+ {`//host/`, ``},
+ {`\\host\share`, `\\host\share`},
+ {`//host/share`, `//host/share`},
+ {`\\host\share\`, `\\host\share`},
+ {`//host/share/`, `//host/share`},
+ {`\\host\share\foo`, `\\host\share`},
+ {`//host/share/foo`, `//host/share`},
+ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
+ {`//host/share//foo///bar////baz`, `//host/share`},
+ {`\\host\share\foo\..\bar`, `\\host\share`},
+ {`//host/share/foo/../bar`, `//host/share`},
+}
+
+func TestVolumeName(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ return
+ }
+ for _, v := range volumenametests {
+ if vol := filepath.VolumeName(v.path); vol != v.vol {
+ t.Errorf("VolumeName(%q)=%q, want %q", v.path, vol, v.vol)
+ }
+ }
+}
+
+func TestDriveLetterInEvalSymlinks(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ return
+ }
+ wd, _ := os.Getwd()
+ if len(wd) < 3 {
+ t.Errorf("Current directory path %q is too short", wd)
+ }
+ lp := strings.ToLower(wd)
+ up := strings.ToUpper(wd)
+ flp, err := filepath.EvalSymlinks(lp)
+ if err != nil {
+ t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err)
+ }
+ fup, err := filepath.EvalSymlinks(up)
+ if err != nil {
+ t.Fatalf("EvalSymlinks(%q) failed: %q", up, err)
+ }
+ if flp != fup {
+ t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup)
+ }
+}
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index b2a4151c1..305e30727 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/path/filepath/path_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
package filepath
import "strings"
@@ -17,7 +19,7 @@ func VolumeName(path string) string {
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/src/pkg/path/filepath/path_windows.go b/src/pkg/path/filepath/path_windows.go
index 2535697fd..3dcd03021 100644
--- a/src/pkg/path/filepath/path_windows.go
+++ b/src/pkg/path/filepath/path_windows.go
@@ -4,7 +4,13 @@
package filepath
-import "strings"
+import (
+ "strings"
+)
+
+func isSlash(c uint8) bool {
+ return c == '\\' || c == '/'
+}
// IsAbs returns true if the path is absolute.
func IsAbs(path string) (b bool) {
@@ -16,11 +22,12 @@ func IsAbs(path string) (b bool) {
if path == "" {
return false
}
- return path[0] == '/' || path[0] == '\\'
+ return isSlash(path[0])
}
// VolumeName returns leading volume name.
// Given "C:\foo\bar" it returns "C:" under windows.
+// Given "\\host\share\foo" it returns "\\host\share".
// On other platforms it returns "".
func VolumeName(path string) (v string) {
if len(path) < 2 {
@@ -28,16 +35,37 @@ func VolumeName(path string) (v string) {
}
// with drive letter
c := path[0]
- if path[1] == ':' &&
- ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
- 'A' <= c && c <= 'Z') {
+ if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
return path[:2]
}
+ // is it UNC
+ if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
+ !isSlash(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if isSlash(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !isSlash(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if isSlash(path[n]) {
+ break
+ }
+ }
+ return path[:n]
+ }
+ break
+ }
+ }
+ }
return ""
}
-// HasPrefix tests whether the path p begins with prefix.
-// It ignores case while comparing.
+// HasPrefix exists for historical compatibility and should not be used.
func HasPrefix(p, prefix string) bool {
if strings.HasPrefix(p, prefix) {
return true
diff --git a/src/pkg/path/filepath/symlink.go b/src/pkg/path/filepath/symlink.go
new file mode 100644
index 000000000..307dd0f8f
--- /dev/null
+++ b/src/pkg/path/filepath/symlink.go
@@ -0,0 +1,67 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package filepath
+
+import (
+ "bytes"
+ "errors"
+ "os"
+ "strings"
+)
+
+func evalSymlinks(path string) (string, error) {
+ const maxIter = 255
+ originalPath := path
+ // consume path by taking each frontmost path element,
+ // expanding it if it's a symlink, and appending it to b
+ var b bytes.Buffer
+ for n := 0; path != ""; n++ {
+ if n > maxIter {
+ return "", errors.New("EvalSymlinks: too many links in " + originalPath)
+ }
+
+ // find next path component, p
+ i := strings.IndexRune(path, Separator)
+ var p string
+ if i == -1 {
+ p, path = path, ""
+ } else {
+ p, path = path[:i], path[i+1:]
+ }
+
+ if p == "" {
+ if b.Len() == 0 {
+ // must be absolute path
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ fi, err := os.Lstat(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if fi.Mode()&os.ModeSymlink == 0 {
+ b.WriteString(p)
+ if path != "" {
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ // it's a symlink, put it at the front of path
+ dest, err := os.Readlink(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if IsAbs(dest) {
+ b.Reset()
+ }
+ path = dest + string(Separator) + path
+ }
+ return Clean(b.String()), nil
+}
diff --git a/src/pkg/path/filepath/symlink_windows.go b/src/pkg/path/filepath/symlink_windows.go
new file mode 100644
index 000000000..1ee939928
--- /dev/null
+++ b/src/pkg/path/filepath/symlink_windows.go
@@ -0,0 +1,63 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath
+
+import (
+ "syscall"
+)
+
+func toShort(path string) (string, error) {
+ p := syscall.StringToUTF16(path)
+ b := p // GetShortPathName says we can reuse buffer
+ n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ }
+ return syscall.UTF16ToString(b), nil
+}
+
+func toLong(path string) (string, error) {
+ p := syscall.StringToUTF16(path)
+ b := p // GetLongPathName says we can reuse buffer
+ n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ }
+ b = b[:n]
+ return syscall.UTF16ToString(b), nil
+}
+
+func evalSymlinks(path string) (string, error) {
+ p, err := toShort(path)
+ if err != nil {
+ return "", err
+ }
+ p, err = toLong(p)
+ if err != nil {
+ return "", err
+ }
+ // syscall.GetLongPathName does not change the case of the drive letter,
+ // but the result of EvalSymlinks must be unique, so we have
+ // EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
+ // Make drive letter upper case.
+ if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
+ p = string(p[0]+'A'-'a') + p[1:]
+ }
+ return Clean(p), nil
+}
diff --git a/src/pkg/path/match.go b/src/pkg/path/match.go
index efb8c5ce7..8154bf602 100644
--- a/src/pkg/path/match.go
+++ b/src/pkg/path/match.go
@@ -5,12 +5,13 @@
package path
import (
- "os"
+ "errors"
"strings"
- "utf8"
+ "unicode/utf8"
)
-var ErrBadPattern = os.NewError("syntax error in pattern")
+// ErrBadPattern indicates a globbing pattern was malformed.
+var ErrBadPattern = errors.New("syntax error in pattern")
// Match returns true if name matches the shell file name pattern.
// The pattern syntax is:
@@ -31,9 +32,10 @@ var ErrBadPattern = os.NewError("syntax error in pattern")
// lo '-' hi matches character c for lo <= c <= hi
//
// Match requires pattern to match all of name, not just a substring.
-// The only possible error return is when pattern is malformed.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
//
-func Match(pattern, name string) (matched bool, err os.Error) {
+func Match(pattern, name string) (matched bool, err error) {
Pattern:
for len(pattern) > 0 {
var star bool
@@ -111,7 +113,7 @@ Scan:
// matchChunk checks whether chunk matches the beginning of s.
// If so, it returns the remainder of s (after the match).
// Chunk is all single-character operators: literals, char classes, and ?.
-func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
+func matchChunk(chunk, s string) (rest string, ok bool, err error) {
for len(chunk) > 0 {
if len(s) == 0 {
return
@@ -136,7 +138,7 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
chunk = chunk[1:]
break
}
- var lo, hi int
+ var lo, hi rune
if lo, chunk, err = getEsc(chunk); err != nil {
return
}
@@ -183,7 +185,7 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
}
// getEsc gets a possibly-escaped character from chunk, for a character class.
-func getEsc(chunk string) (r int, nchunk string, err os.Error) {
+func getEsc(chunk string) (r rune, nchunk string, err error) {
if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
err = ErrBadPattern
return
diff --git a/src/pkg/path/match_test.go b/src/pkg/path/match_test.go
index f377f1083..730b6b903 100644
--- a/src/pkg/path/match_test.go
+++ b/src/pkg/path/match_test.go
@@ -4,15 +4,12 @@
package path
-import (
- "os"
- "testing"
-)
+import "testing"
type MatchTest struct {
pattern, s string
match bool
- err os.Error
+ err error
}
var matchTests = []MatchTest{
diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go
index 235384667..13abed0b0 100644
--- a/src/pkg/path/path.go
+++ b/src/pkg/path/path.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package path implements utility routines for manipulating slash-separated
-// filename paths.
+// paths.
package path
import (
@@ -25,7 +25,7 @@ import (
// returns the string ".".
//
// See also Rob Pike, ``Lexical File Names in Plan 9 or
-// Getting Dot-Dot right,''
+// Getting Dot-Dot Right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string {
if path == "" {
@@ -100,17 +100,19 @@ func Clean(path string) string {
return string(buf[0:w])
}
-// Split splits path immediately following the final path separator,
+// Split splits path immediately following the final slash.
// separating it into a directory and file name component.
-// If there is no separator in path, Split returns an empty dir and
+// If there is no slash path, Split returns an empty dir and
// file set to path.
+// The returned values have the property that path = dir+file.
func Split(path string) (dir, file string) {
i := strings.LastIndex(path, "/")
return path[:i+1], path[i+1:]
}
// Join joins any number of path elements into a single path, adding a
-// separating slash if necessary. All empty strings are ignored.
+// separating slash if necessary. The result is Cleaned; in particular,
+// all empty strings are ignored.
func Join(elem ...string) string {
for i, e := range elem {
if e != "" {
@@ -160,3 +162,22 @@ func Base(path string) string {
func IsAbs(path string) bool {
return len(path) > 0 && path[0] == '/'
}
+
+// Dir returns all but the last element of path, typically the path's directory.
+// The path is Cleaned and trailing slashes are removed before processing.
+// If the path is empty, Dir returns ".".
+// If the path consists entirely of slashes followed by non-slash bytes, Dir
+// returns a single slash. In any other case, the returned path does not end in a
+// slash.
+func Dir(path string) string {
+ dir, _ := Split(path)
+ dir = Clean(dir)
+ last := len(dir) - 1
+ if last > 0 && dir[last] == '/' {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return dir
+}
diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go
index 1fd57cc80..77f080433 100644
--- a/src/pkg/path/path_test.go
+++ b/src/pkg/path/path_test.go
@@ -8,11 +8,11 @@ import (
"testing"
)
-type CleanTest struct {
- path, clean string
+type PathTest struct {
+ path, result string
}
-var cleantests = []CleanTest{
+var cleantests = []PathTest{
// Already clean
{"", "."},
{"abc", "abc"},
@@ -64,8 +64,8 @@ var cleantests = []CleanTest{
func TestClean(t *testing.T) {
for _, test := range cleantests {
- if s := Clean(test.path); s != test.clean {
- t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+ if s := Clean(test.path); s != test.result {
+ t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
}
}
}
@@ -148,7 +148,7 @@ func TestExt(t *testing.T) {
}
}
-var basetests = []CleanTest{
+var basetests = []PathTest{
// Already clean
{"", "."},
{".", "."},
@@ -165,8 +165,31 @@ var basetests = []CleanTest{
func TestBase(t *testing.T) {
for _, test := range basetests {
- if s := Base(test.path); s != test.clean {
- t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+ if s := Base(test.path); s != test.result {
+ t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
+ }
+ }
+}
+
+var dirtests = []PathTest{
+ {"", "."},
+ {".", "."},
+ {"/.", "/"},
+ {"/", "/"},
+ {"////", "/"},
+ {"/foo", "/"},
+ {"x/", "x"},
+ {"abc", "."},
+ {"abc/def", "abc"},
+ {"a/b/.x", "a/b"},
+ {"a/b/c.", "a/b"},
+ {"a/b/c.x", "a/b"},
+}
+
+func TestDir(t *testing.T) {
+ for _, test := range dirtests {
+ if s := Dir(test.path); s != test.result {
+ t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
}
}
}
diff --git a/src/pkg/rand/Makefile b/src/pkg/rand/Makefile
deleted file mode 100644
index ec3b34180..000000000
--- a/src/pkg/rand/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../Make.inc
-
-TARG=rand
-GOFILES=\
- exp.go\
- normal.go\
- rand.go\
- rng.go\
- zipf.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/reflect/Makefile b/src/pkg/reflect/Makefile
deleted file mode 100644
index b946449a3..000000000
--- a/src/pkg/reflect/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=reflect
-GOFILES=\
- deepequal.go\
- type.go\
- value.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 9a41b504a..6bb061398 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -6,7 +6,7 @@ package reflect_test
import (
"bytes"
- "container/vector"
+ "encoding/base64"
"fmt"
"io"
"os"
@@ -16,6 +16,13 @@ import (
"unsafe"
)
+func TestBool(t *testing.T) {
+ v := ValueOf(true)
+ if v.Bool() != true {
+ t.Fatal("ValueOf(true).Bool() = false")
+ }
+}
+
type integer int
type T struct {
a int
@@ -57,7 +64,7 @@ var typeTests = []pair{
{struct{ x (**integer) }{}, "**reflect_test.integer"},
{struct{ x ([32]int32) }{}, "[32]int32"},
{struct{ x ([]int8) }{}, "[]int8"},
- {struct{ x (map[string]int32) }{}, "map[string] int32"},
+ {struct{ x (map[string]int32) }{}, "map[string]int32"},
{struct{ x (chan<- string) }{}, "chan<- string"},
{struct {
x struct {
@@ -173,7 +180,7 @@ var valueTests = []pair{
{new(**int8), "**int8(0)"},
{new([5]int32), "[5]int32{0, 0, 0, 0, 0}"},
{new(**integer), "**reflect_test.integer(0)"},
- {new(map[string]int32), "map[string] int32{<can't iterate on maps>}"},
+ {new(map[string]int32), "map[string]int32{<can't iterate on maps>}"},
{new(chan<- string), "chan<- string"},
{new(func(a int8, b int32)), "func(int8, int32)(0)"},
{new(struct {
@@ -215,7 +222,8 @@ func TestTypes(t *testing.T) {
func TestSet(t *testing.T) {
for i, tt := range valueTests {
- v := ValueOf(tt.i).Elem()
+ v := ValueOf(tt.i)
+ v = v.Elem()
switch v.Kind() {
case Int:
v.SetInt(132)
@@ -411,7 +419,7 @@ func TestAll(t *testing.T) {
testType(t, 8, typ.Elem(), "int32")
typ = TypeOf((map[string]*int32)(nil))
- testType(t, 9, typ, "map[string] *int32")
+ testType(t, 9, typ, "map[string]*int32")
mtyp := typ
testType(t, 10, mtyp.Key(), "string")
testType(t, 11, mtyp.Elem(), "*int32")
@@ -434,7 +442,7 @@ func TestInterfaceGet(t *testing.T) {
inter.E = 123.456
v1 := ValueOf(&inter)
v2 := v1.Elem().Field(0)
- assert(t, v2.Type().String(), "interface { }")
+ assert(t, v2.Type().String(), "interface {}")
i2 := v2.Interface()
v3 := ValueOf(i2)
assert(t, v3.Type().String(), "float64")
@@ -447,7 +455,7 @@ func TestInterfaceValue(t *testing.T) {
inter.E = 123.456
v1 := ValueOf(&inter)
v2 := v1.Elem().Field(0)
- assert(t, v2.Type().String(), "interface { }")
+ assert(t, v2.Type().String(), "interface {}")
v3 := v2.Elem()
assert(t, v3.Type().String(), "float64")
@@ -460,8 +468,8 @@ func TestInterfaceValue(t *testing.T) {
func TestFunctionValue(t *testing.T) {
var x interface{} = func() {}
v := ValueOf(x)
- if v.Interface() != v.Interface() || v.Interface() != x {
- t.Fatalf("TestFunction != itself")
+ if fmt.Sprint(v.Interface()) != fmt.Sprint(x) {
+ t.Fatalf("TestFunction returned wrong pointer")
}
assert(t, v.Type().String(), "func()")
}
@@ -621,6 +629,13 @@ type DeepEqualTest struct {
eq bool
}
+// Simple functions for DeepEqual tests.
+var (
+ fn1 func() // nil.
+ fn2 func() // nil.
+ fn3 = func() { fn1() } // Not nil.
+)
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{1, 1, true},
@@ -631,8 +646,9 @@ var deepEqualTests = []DeepEqualTest{
{make([]int, 10), make([]int, 10), true},
{&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
{Basic{1, 0.5}, Basic{1, 0.5}, true},
- {os.Error(nil), os.Error(nil), true},
+ {error(nil), error(nil), true},
{map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+ {fn1, fn2, true},
// Inequalities
{1, 2, false},
@@ -650,6 +666,16 @@ var deepEqualTests = []DeepEqualTest{
{map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
{nil, 1, false},
{1, nil, false},
+ {fn1, fn3, false},
+ {fn3, fn3, false},
+
+ // Nil vs empty: not the same.
+ {[]int{}, []int(nil), false},
+ {[]int{}, []int{}, true},
+ {[]int(nil), []int(nil), true},
+ {map[int]int{}, map[int]int(nil), false},
+ {map[int]int{}, map[int]int{}, true},
+ {map[int]int(nil), map[int]int(nil), true},
// Mismatched types
{1, 1.0, false},
@@ -877,19 +903,20 @@ func TestMap(t *testing.T) {
t.Errorf("Len = %d, want %d", n, len(m))
}
keys := mv.MapKeys()
- i := 0
newmap := MakeMap(mv.Type())
for k, v := range m {
// Check that returned Keys match keys in range.
- // These aren't required to be in the same order,
- // but they are in this implementation, which makes
- // the test easier.
- if i >= len(keys) {
- t.Errorf("Missing key #%d %q", i, k)
- } else if kv := keys[i]; kv.String() != k {
- t.Errorf("Keys[%q] = %d, want %d", i, kv.Int(), k)
+ // These aren't required to be in the same order.
+ seen := false
+ for _, kv := range keys {
+ if kv.String() == k {
+ seen = true
+ break
+ }
+ }
+ if !seen {
+ t.Errorf("Missing key %q", k)
}
- i++
// Check that value lookup is correct.
vv := mv.MapIndex(ValueOf(k))
@@ -1091,21 +1118,38 @@ func TestMethod(t *testing.T) {
}
// Curried method of value.
- i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
+ tfunc := TypeOf(func(int) int(nil))
+ v := ValueOf(p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.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()
+ v = ValueOf(p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.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(1).Call([]Value{ValueOf(10)})[0].Int()
+ v = ValueOf(&p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Pointer Value Method returned %d; want 250", i)
}
- i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ v = ValueOf(&p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
}
@@ -1120,11 +1164,19 @@ func TestMethod(t *testing.T) {
}
}{p}
pv := ValueOf(s).Field(0)
- i = pv.Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ v = pv.Method(0)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Interface Method returned %d; want 250", i)
}
- i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ v = pv.MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Interface MethodByName returned %d; want 250", i)
}
@@ -1322,8 +1374,19 @@ func TestFieldByName(t *testing.T) {
}
func TestImportPath(t *testing.T) {
- if path := TypeOf(vector.Vector{}).PkgPath(); path != "container/vector" {
- t.Errorf("TypeOf(vector.Vector{}).PkgPath() = %q, want \"container/vector\"", path)
+ tests := []struct {
+ t Type
+ path string
+ }{
+ {TypeOf(&base64.Encoding{}).Elem(), "encoding/base64"},
+ {TypeOf(uint(0)), ""},
+ {TypeOf(map[string]int{}), ""},
+ {TypeOf((*error)(nil)).Elem(), ""},
+ }
+ for _, test := range tests {
+ if path := test.t.PkgPath(); path != test.path {
+ t.Errorf("%v.PkgPath() = %q, want %q", test.t, path, test.path)
+ }
}
}
@@ -1475,20 +1538,36 @@ func TestAddr(t *testing.T) {
if p.X != 4 {
t.Errorf("Addr.Elem.Set valued to set value in top value")
}
+
+ // Verify that taking the address of a type gives us a pointer
+ // which we can convert back using the usual interface
+ // notation.
+ var s struct {
+ B *bool
+ }
+ ps := ValueOf(&s).Elem().Field(0).Addr().Interface()
+ *(ps.(**bool)) = new(bool)
+ if s.B == nil {
+ t.Errorf("Addr.Interface direct assignment failed")
+ }
}
func noAlloc(t *testing.T, n int, f func(int)) {
// once to prime everything
f(-1)
- runtime.MemStats.Mallocs = 0
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ oldmallocs := memstats.Mallocs
for j := 0; j < n; j++ {
f(j)
}
// A few allocs may happen in the testing package when GOMAXPROCS > 1, so don't
// require zero mallocs.
- if runtime.MemStats.Mallocs > 5 {
- t.Fatalf("%d mallocs after %d iterations", runtime.MemStats.Mallocs, n)
+ runtime.ReadMemStats(memstats)
+ mallocs := memstats.Mallocs - oldmallocs
+ if mallocs > 5 {
+ t.Fatalf("%d mallocs after %d iterations", mallocs, n)
}
}
@@ -1515,14 +1594,26 @@ func TestSmallNegativeInt(t *testing.T) {
func TestSlice(t *testing.T) {
xs := []int{1, 2, 3, 4, 5, 6, 7, 8}
v := ValueOf(xs).Slice(3, 5).Interface().([]int)
- if len(v) != 2 || v[0] != 4 || v[1] != 5 {
- t.Errorf("xs.Slice(3, 5) = %v", v)
+ if len(v) != 2 {
+ t.Errorf("len(xs.Slice(3, 5)) = %d", len(v))
+ }
+ if cap(v) != 5 {
+ t.Errorf("cap(xs.Slice(3, 5)) = %d", cap(v))
+ }
+ if !DeepEqual(v[0:5], xs[3:]) {
+ t.Errorf("xs.Slice(3, 5)[0:5] = %v", v[0:5])
}
- xa := [7]int{10, 20, 30, 40, 50, 60, 70}
+ xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80}
v = ValueOf(&xa).Elem().Slice(2, 5).Interface().([]int)
- if len(v) != 3 || v[0] != 30 || v[1] != 40 || v[2] != 50 {
- t.Errorf("xa.Slice(2, 5) = %v", v)
+ if len(v) != 3 {
+ t.Errorf("len(xa.Slice(2, 5)) = %d", len(v))
+ }
+ if cap(v) != 6 {
+ t.Errorf("cap(xa.Slice(2, 5)) = %d", cap(v))
+ }
+ if !DeepEqual(v[0:6], xa[2:]) {
+ t.Errorf("xs.Slice(2, 5)[0:6] = %v", v[0:6])
}
}
@@ -1563,6 +1654,31 @@ func TestTagGet(t *testing.T) {
}
}
+func TestBytes(t *testing.T) {
+ type B []byte
+ x := B{1, 2, 3, 4}
+ y := ValueOf(x).Bytes()
+ if !bytes.Equal(x, y) {
+ t.Fatalf("ValueOf(%v).Bytes() = %v", x, y)
+ }
+ if &x[0] != &y[0] {
+ t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
+ }
+}
+
+func TestSetBytes(t *testing.T) {
+ type B []byte
+ var x B
+ y := []byte{1, 2, 3, 4}
+ ValueOf(&x).Elem().SetBytes(y)
+ if !bytes.Equal(x, y) {
+ t.Fatalf("ValueOf(%v).Bytes() = %v", x, y)
+ }
+ if &x[0] != &y[0] {
+ t.Errorf("ValueOf(%p).Bytes() = %p", &x[0], &y[0])
+ }
+}
+
type Private struct {
x int
y **int
@@ -1627,3 +1743,15 @@ func isValid(v Value) {
panic("zero Value")
}
}
+
+func TestAlias(t *testing.T) {
+ x := string("hello")
+ v := ValueOf(&x).Elem()
+ oldvalue := v.Interface()
+ v.SetString("world")
+ newvalue := v.Interface()
+
+ if oldvalue != "hello" || newvalue != "world" {
+ t.Errorf("aliasing: old=%q new=%q, want hello, world", oldvalue, newvalue)
+ }
+}
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index 63c28fe20..c12e90f36 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -69,6 +69,9 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
return true
case Slice:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
if v1.Len() != v2.Len() {
return false
}
@@ -93,6 +96,9 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
return true
case Map:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
if v1.Len() != v2.Len() {
return false
}
@@ -102,6 +108,12 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
}
return true
+ case Func:
+ if v1.IsNil() && v2.IsNil() {
+ return true
+ }
+ // Can't do better than this:
+ return false
default:
// Normal equality suffices
return valueInterface(v1, false) == valueInterface(v2, false)
@@ -111,8 +123,8 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
// DeepEqual tests for deep equality. It uses normal == equality where possible
-// but will scan members of arrays, slices, and fields of structs. It correctly
-// handles recursive types.
+// but will scan members of arrays, slices, maps, and fields of structs. It correctly
+// handles recursive types. Functions are equal only if they are both nil.
func DeepEqual(a1, a2 interface{}) bool {
if a1 == nil || a2 == nil {
return a1 == a2
diff --git a/src/pkg/reflect/tostring_test.go b/src/pkg/reflect/tostring_test.go
index 5f5c52b77..7486a9bfc 100644
--- a/src/pkg/reflect/tostring_test.go
+++ b/src/pkg/reflect/tostring_test.go
@@ -23,14 +23,14 @@ func valueToString(val Value) string {
typ := val.Type()
switch val.Kind() {
case Int, Int8, Int16, Int32, Int64:
- return strconv.Itoa64(val.Int())
+ return strconv.FormatInt(val.Int(), 10)
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
- return strconv.Uitoa64(val.Uint())
+ return strconv.FormatUint(val.Uint(), 10)
case Float32, Float64:
- return strconv.Ftoa64(val.Float(), 'g', -1)
+ return strconv.FormatFloat(val.Float(), 'g', -1, 64)
case Complex64, Complex128:
c := val.Complex()
- return strconv.Ftoa64(real(c), 'g', -1) + "+" + strconv.Ftoa64(imag(c), 'g', -1) + "i"
+ return strconv.FormatFloat(real(c), 'g', -1, 64) + "+" + strconv.FormatFloat(imag(c), 'g', -1, 64) + "i"
case String:
return val.String()
case Bool:
@@ -88,7 +88,7 @@ func valueToString(val Value) string {
return typ.String() + "(" + valueToString(val.Elem()) + ")"
case Func:
v := val
- return typ.String() + "(" + strconv.Uitoa64(uint64(v.Pointer())) + ")"
+ return typ.String() + "(" + strconv.FormatUint(uint64(v.Pointer()), 10) + ")"
default:
panic("valueToString: can't print type " + typ.String())
}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index ef0fb87ea..64550b8f6 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -12,11 +12,10 @@
// for that type.
//
// See "The Laws of Reflection" for an introduction to reflection in Go:
-// http://blog.golang.org/2011/09/laws-of-reflection.html
+// http://golang.org/doc/articles/laws_of_reflection.html
package reflect
import (
- "runtime"
"strconv"
"sync"
"unsafe"
@@ -67,9 +66,10 @@ type Type interface {
// It returns an empty string for unnamed types.
Name() string
- // PkgPath returns the type's package path.
- // The package path is a full package import path like "container/vector".
- // PkgPath returns an empty string for unnamed types.
+ // PkgPath returns a named type's package path, that is, the import path
+ // that uniquely identifies the package, such as "encoding/base64".
+ // If the type was predeclared (string, error) or unnamed (*T, struct{}, []int),
+ // the package path will be the empty string.
PkgPath() string
// Size returns the number of bytes needed to store
@@ -78,7 +78,7 @@ type Type interface {
// String returns a string representation of the type.
// The string representation may use shortened package names
- // (e.g., vector instead of "container/vector") and is not
+ // (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for equality,
// compare the Types directly.
String() string
@@ -181,14 +181,14 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
- runtimeType() *runtime.Type
+ runtimeType() *runtimeType
common() *commonType
uncommon() *uncommonType
}
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
-type Kind uint8
+type Kind uint
const (
Invalid Kind = iota
@@ -221,127 +221,131 @@ const (
)
/*
- * Copy of data structures from ../runtime/type.go.
- * For comments, see the ones in that file.
- *
- * These data structures are known to the compiler and the runtime.
- *
- * Putting these types in runtime instead of reflect means that
- * reflect doesn't need to be autolinked into every binary, which
- * simplifies bootstrapping and package dependencies.
- * Unfortunately, it also means that reflect needs its own
- * copy in order to access the private fields.
+ * These data structures are known to the compiler (../../cmd/gc/reflect.c).
+ * A few are known to ../runtime/type.go to convey to debuggers.
*/
+// The compiler can only construct empty interface values at
+// compile time; non-empty interface values get created
+// during initialization. Type is an empty interface
+// so that the compiler can lay out references as data.
+// The underlying type is *reflect.ArrayType and so on.
+type runtimeType interface{}
+
// commonType is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
-
type commonType struct {
- size uintptr
- hash uint32
- alg uint8
- align uint8
- fieldAlign uint8
- kind uint8
- string *string
- *uncommonType
- ptrToThis *runtime.Type
-}
-
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+ _ uint8 // unused/padding
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+ ptrToThis *runtimeType // pointer to this type, if used in binary or has methods
+}
+
+// Method on non-interface type
type method struct {
- name *string
- pkgPath *string
- mtyp *runtime.Type
- typ *runtime.Type
- ifn unsafe.Pointer
- tfn unsafe.Pointer
-}
-
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ mtyp *runtimeType // method type (without receiver)
+ typ *runtimeType // .(*FuncType) underneath (with receiver)
+ ifn unsafe.Pointer // fn used in interface call (one-word receiver)
+ tfn unsafe.Pointer // fn used for normal method call
+}
+
+// uncommonType is present only for types with names or methods
+// (if T is a named type, the uncommonTypes for T and *T have methods).
+// Using a pointer to this struct reduces the overall size required
+// to describe an unnamed type with no methods.
type uncommonType struct {
- name *string
- pkgPath *string
- methods []method
+ name *string // name of type
+ pkgPath *string // import path; nil for built-in types like int, string
+ methods []method // methods associated with type
}
// ChanDir represents a channel type's direction.
type ChanDir int
const (
- RecvDir ChanDir = 1 << iota
- SendDir
- BothDir = RecvDir | SendDir
+ RecvDir ChanDir = 1 << iota // <-chan
+ SendDir // chan<-
+ BothDir = RecvDir | SendDir // chan
)
// arrayType represents a fixed array type.
type arrayType struct {
commonType `reflect:"array"`
- elem *runtime.Type
- slice *runtime.Type
+ elem *runtimeType // array element type
+ slice *runtimeType // slice type
len uintptr
}
// chanType represents a channel type.
type chanType struct {
commonType `reflect:"chan"`
- elem *runtime.Type
- dir uintptr
+ elem *runtimeType // channel element type
+ dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
type funcType struct {
commonType `reflect:"func"`
- dotdotdot bool
- in []*runtime.Type
- out []*runtime.Type
+ dotdotdot bool // last input parameter is ...
+ in []*runtimeType // input parameter types
+ out []*runtimeType // output parameter types
}
// imethod represents a method on an interface type
type imethod struct {
- name *string
- pkgPath *string
- typ *runtime.Type
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *runtimeType // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
commonType `reflect:"interface"`
- methods []imethod
+ methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
commonType `reflect:"map"`
- key *runtime.Type
- elem *runtime.Type
+ key *runtimeType // map key type
+ elem *runtimeType // map element (value) type
}
// ptrType represents a pointer type.
type ptrType struct {
commonType `reflect:"ptr"`
- elem *runtime.Type
+ elem *runtimeType // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
commonType `reflect:"slice"`
- elem *runtime.Type
+ elem *runtimeType // slice element type
}
// Struct field
type structField struct {
- name *string
- pkgPath *string
- typ *runtime.Type
- tag *string
- offset uintptr
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *runtimeType // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
type structType struct {
commonType `reflect:"struct"`
- fields []structField
+ fields []structField // sorted by offset
}
/*
@@ -351,11 +355,18 @@ type structType struct {
// Method represents a single method.
type Method struct {
- PkgPath string // empty for uppercase Name
+ // Name is the method name.
+ // PkgPath is the package path that qualifies a lower case (unexported)
+ // method name. It is empty for upper case (exported) method names.
+ // The combination of PkgPath and Name uniquely identifies a method
+ // in a method set.
+ // See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
- Type Type
- Func Value
- Index int
+ PkgPath string
+
+ Type Type // method type
+ Func Value // func with receiver as first argument
+ Index int // index for Type.Method
}
// High bit says whether type has
@@ -455,14 +466,15 @@ func (t *uncommonType) Method(i int) (m Method) {
if p.name != nil {
m.Name = *p.name
}
- flag := uint32(0)
+ fl := flag(Func) << flagKindShift
if p.pkgPath != nil {
m.PkgPath = *p.pkgPath
- flag |= flagRO
+ fl |= flagRO
}
- m.Type = toType(p.typ)
+ mt := toCommonType(p.typ)
+ m.Type = mt
fn := p.tfn
- m.Func = valueFromIword(flag, m.Type, iword(fn))
+ m.Func = Value{mt, fn, fl}
m.Index = i
return
}
@@ -557,7 +569,7 @@ func (t *commonType) Elem() Type {
tt := (*sliceType)(unsafe.Pointer(t))
return toType(tt.elem)
}
- panic("reflect; Elem of invalid type")
+ panic("reflect: Elem of invalid type")
}
func (t *commonType) Field(i int) StructField {
@@ -626,7 +638,7 @@ func (t *commonType) NumField() int {
func (t *commonType) NumIn() int {
if t.Kind() != Func {
- panic("reflect; NumIn of non-func type")
+ panic("reflect: NumIn of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return len(tt.in)
@@ -634,7 +646,7 @@ func (t *commonType) NumIn() int {
func (t *commonType) NumOut() int {
if t.Kind() != Func {
- panic("reflect; NumOut of non-func type")
+ panic("reflect: NumOut of non-func type")
}
tt := (*funcType)(unsafe.Pointer(t))
return len(tt.out)
@@ -693,14 +705,20 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
return
}
+// A StructField describes a single field in a struct.
type StructField struct {
- PkgPath string // empty for uppercase Name
- Name string
- Type Type
- Tag StructTag
- Offset uintptr
- Index []int
- Anonymous bool
+ // Name is the field name.
+ // PkgPath is the package path that qualifies a lower case (unexported)
+ // field name. It is empty for upper case (exported) field names.
+ // See http://golang.org/ref/spec#Uniqueness_of_identifiers
+ Name string
+ PkgPath string
+
+ Type Type // field type
+ Tag StructTag // field tag string
+ Offset uintptr // offset within struct, in bytes
+ Index []int // index sequence for Type.FieldByIndex
+ Anonymous bool // is an anonymous field
}
// A StructTag is the tag string in a struct field.
@@ -716,7 +734,7 @@ 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,
+// returned by Get is unspecified.
func (tag StructTag) Get(key string) string {
for tag != "" {
// skip leading space
@@ -768,7 +786,7 @@ func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
return
}
- p := t.fields[i]
+ p := &t.fields[i]
f.Type = toType(p.typ)
if p.name != nil {
f.Name = *p.name
@@ -787,6 +805,14 @@ func (t *structType) Field(i int) (f StructField) {
f.Tag = StructTag(*p.tag)
}
f.Offset = p.offset
+
+ // NOTE(rsc): This is the only allocation in the interface
+ // presented by a reflect.Type. It would be nice to avoid,
+ // at least in the common cases, but we need to make sure
+ // that misbehaving clients of reflect cannot affect other
+ // uses of reflect. One possibility is CL 5371098, but we
+ // postponed that ugliness until there is a demonstrated
+ // need for the performance. This is issue 2320.
f.Index = []int{i}
return
}
@@ -867,16 +893,18 @@ L:
if n == 1 {
// Found matching field.
- if len(ff.Index) <= depth {
+ if depth >= len(ff.Index) {
ff.Index = make([]int, depth+1)
}
- ff.Index[depth] = fi
+ if len(ff.Index) > 1 {
+ ff.Index[depth] = fi
+ }
} else {
// None or more than one matching field found.
fd = inf
}
- mark[t] = false, false
+ delete(mark, t)
return
}
@@ -897,26 +925,18 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (f StructField, pr
}
// Convert runtime type to reflect type.
-func toCommonType(p *runtime.Type) *commonType {
+func toCommonType(p *runtimeType) *commonType {
if p == nil {
return nil
}
- type hdr struct {
- x interface{}
- t commonType
- }
- x := unsafe.Pointer(p)
- if uintptr(x)&reflectFlags != 0 {
- panic("reflect: invalid interface value")
- }
- return &(*hdr)(x).t
+ return (*p).(*commonType)
}
-func toType(p *runtime.Type) Type {
+func toType(p *runtimeType) Type {
if p == nil {
return nil
}
- return toCommonType(p).toType()
+ return (*p).(*commonType)
}
// TypeOf returns the reflection Type of the value in the interface{}.
@@ -931,23 +951,25 @@ var ptrMap struct {
m map[*commonType]*ptrType
}
-func (t *commonType) runtimeType() *runtime.Type {
- // The runtime.Type always precedes the commonType in memory.
+func (t *commonType) runtimeType() *runtimeType {
+ // The runtimeType always precedes the commonType in memory.
// Adjust pointer to find it.
var rt struct {
- i runtime.Type
+ i runtimeType
ct commonType
}
- return (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
+ return (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
}
// PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type {
- // If t records its pointer-to type, use it.
- ct := t.(*commonType)
+ return t.(*commonType).ptrTo()
+}
+
+func (ct *commonType) ptrTo() *commonType {
if p := ct.ptrToThis; p != nil {
- return toType(p)
+ return toCommonType(p)
}
// Otherwise, synthesize one.
@@ -959,7 +981,7 @@ func PtrTo(t Type) Type {
if m := ptrMap.m; m != nil {
if p := m[ct]; p != nil {
ptrMap.RUnlock()
- return p.commonType.toType()
+ return &p.commonType
}
}
ptrMap.RUnlock()
@@ -971,20 +993,19 @@ func PtrTo(t Type) Type {
if p != nil {
// some other goroutine won the race and created it
ptrMap.Unlock()
- return p
+ return &p.commonType
}
var rt struct {
- i runtime.Type
+ i runtimeType
ptrType
}
- rt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))
+ rt.i = &rt.commonType
// 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 = &rt.ptrType
- bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
+ var ibyte interface{} = (*byte)(nil)
+ bp := (*ptrType)(unsafe.Pointer((**(**runtimeType)(unsafe.Pointer(&ibyte))).(*commonType)))
*p = *bp
s := "*" + *ct.string
@@ -999,11 +1020,11 @@ func PtrTo(t Type) Type {
p.uncommonType = nil
p.ptrToThis = nil
- p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
+ p.elem = (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
ptrMap.m[ct] = p
ptrMap.Unlock()
- return p.commonType.toType()
+ return &p.commonType
}
func (t *commonType) Implements(u Type) bool {
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 996ba0c3b..79476ad22 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -11,6 +11,7 @@ import (
"unsafe"
)
+const bigEndian = false // can be smarter if we find a big-endian machine
const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
@@ -54,13 +55,57 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) {
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
//
-// The fields of Value are exported so that clients can copy and
-// pass Values around, but they should not be edited or inspected
-// directly. A future language change may make it possible not to
-// export these fields while still keeping Values usable as values.
+// A Value can be used concurrently by multiple goroutines provided that
+// the underlying Go value can be used concurrently for the equivalent
+// direct operations.
type Value struct {
- Internal interface{}
- InternalMethod int
+ // typ holds the type of the value represented by a Value.
+ typ *commonType
+
+ // val holds the 1-word representation of the value.
+ // If flag's flagIndir bit is set, then val is a pointer to the data.
+ // Otherwise val is a word holding the actual data.
+ // When the data is smaller than a word, it begins at
+ // the first byte (in the memory address sense) of val.
+ // We use unsafe.Pointer so that the garbage collector
+ // knows that val could be a pointer.
+ val unsafe.Pointer
+
+ // flag holds metadata about the value.
+ // The lowest bits are flag bits:
+ // - flagRO: obtained via unexported field, so read-only
+ // - flagIndir: val holds a pointer to the data
+ // - flagAddr: v.CanAddr is true (implies flagIndir)
+ // - flagMethod: v is a method value.
+ // The next five bits give the Kind of the value.
+ // This repeats typ.Kind() except for method values.
+ // The remaining 23+ bits give a method number for method values.
+ // If flag.kind() != Func, code can assume that flagMethod is unset.
+ // If typ.size > ptrSize, code can assume that flagIndir is set.
+ flag
+
+ // A method value represents a curried method invocation
+ // like r.Read for some receiver r. The typ+val+flag bits describe
+ // the receiver r, but the flag's Kind bits say Func (methods are
+ // functions), and the top bits of the flag give the method number
+ // in r's type's method table.
+}
+
+type flag uintptr
+
+const (
+ flagRO flag = 1 << iota
+ flagIndir
+ flagAddr
+ flagMethod
+ flagKindShift = iota
+ flagKindWidth = 5 // there are 27 kinds
+ flagKindMask flag = 1<<flagKindWidth - 1
+ flagMethodShift = flagKindShift + flagKindWidth
+)
+
+func (f flag) kind() Kind {
+ return Kind((f >> flagKindShift) & flagKindMask)
}
// A ValueError occurs when a Value method is invoked on
@@ -71,7 +116,7 @@ type ValueError struct {
Kind Kind
}
-func (e *ValueError) String() string {
+func (e *ValueError) Error() string {
if e.Kind == 0 {
return "reflect: call of " + e.Method + " on zero Value"
}
@@ -92,17 +137,30 @@ func methodName() string {
// An iword is the word that would be stored in an
// interface to represent a given value v. Specifically, if v is
// bigger than a pointer, its word is a pointer to v's data.
-// Otherwise, its word is a zero uintptr with the data stored
-// in the leading bytes.
-type iword uintptr
+// Otherwise, its word holds the data stored
+// in its leading bytes (so is not a pointer).
+// Because the value sometimes holds a pointer, we use
+// unsafe.Pointer to represent it, so that if iword appears
+// in a struct, the garbage collector knows that might be
+// a pointer.
+type iword unsafe.Pointer
+
+func (v Value) iword() iword {
+ if v.flag&flagIndir != 0 && v.typ.size <= ptrSize {
+ // Have indirect but want direct word.
+ return loadIword(v.val, v.typ.size)
+ }
+ return iword(v.val)
+}
-func loadIword(p unsafe.Pointer, size uintptr) iword {
+// loadIword loads n bytes at p from memory into an iword.
+func loadIword(p unsafe.Pointer, n uintptr) iword {
// Run the copy ourselves instead of calling memmove
- // to avoid moving v to the heap.
- w := iword(0)
- switch size {
+ // to avoid moving w to the heap.
+ var w iword
+ switch n {
default:
- panic("reflect: internal error: loadIword of " + strconv.Itoa(int(size)) + "-byte value")
+ panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -124,12 +182,13 @@ func loadIword(p unsafe.Pointer, size uintptr) iword {
return w
}
-func storeIword(p unsafe.Pointer, w iword, size uintptr) {
+// storeIword stores n bytes from w into p.
+func storeIword(p unsafe.Pointer, w iword, n uintptr) {
// Run the copy ourselves instead of calling memmove
- // to avoid moving v to the heap.
- switch size {
+ // to avoid moving w to the heap.
+ switch n {
default:
- panic("reflect: internal error: storeIword of " + strconv.Itoa(int(size)) + "-byte value")
+ panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -152,7 +211,7 @@ func storeIword(p unsafe.Pointer, w iword, size uintptr) {
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
- typ *runtime.Type
+ typ *runtimeType
word iword
}
@@ -160,8 +219,8 @@ type emptyInterface struct {
type nonEmptyInterface struct {
// see ../runtime/iface.c:/Itab
itab *struct {
- ityp *runtime.Type // static interface type
- typ *runtime.Type // dynamic concrete type
+ ityp *runtimeType // static interface type
+ typ *runtimeType // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
@@ -170,209 +229,42 @@ type nonEmptyInterface struct {
word iword
}
-// 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 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
-// clients to make copies of Values.
-//
-// The internal method converts a Value into the expanded internalValue struct.
-// If we could avoid exporting fields we'd probably make internalValue the
-// definition of Value.
-//
-// If a Value is addressable (CanAddr returns true), then the Internal
-// interface value holds a pointer to the actual field data, and Set stores
-// through that pointer. If a Value is not addressable (CanAddr returns false),
-// then the Internal interface value holds the actual value.
-//
-// In addition to whether a value is addressable, we track whether it was
-// obtained by using an unexported struct field. Such values are allowed
-// to be read, mainly to make fmt.Print more useful, but they are not
-// allowed to be written. We call such values read-only.
-//
-// A Value can be set (via the Set, SetUint, etc. methods) only if it is both
-// addressable and not read-only.
-//
-// The two permission bits - addressable and read-only - are stored in
-// the bottom two bits of the type pointer in the interface value.
-//
-// ordinary value: Internal = value
-// addressable value: Internal = value, Internal.typ |= flagAddr
-// read-only value: Internal = value, Internal.typ |= flagRO
-// addressable, read-only value: Internal = value, Internal.typ |= flagAddr | flagRO
-//
-// It is important that the read-only values have the extra bit set
-// (as opposed to using the bit to mean writable), because client code
-// can grab the interface field and try to use it. Having the extra bit
-// set makes the type pointer compare not equal to any real type,
-// so that a client cannot, say, write through v.Internal.(*int).
-// The runtime routines that access interface types reject types with
-// low bits set.
-//
-// If a Value fv = v.Method(i), then fv = v with the InternalMethod
-// field set to i+1. Methods are never addressable.
-//
-// All in all, this is a lot of effort just to avoid making this new API
-// depend on a language change we'll probably do anyway, but
-// it's helpful to keep the two separate, and much of the logic is
-// necessary to implement the Interface method anyway.
-
-const (
- flagAddr uint32 = 1 << iota // holds address of value
- flagRO // read-only
-
- reflectFlags = 3
-)
-
-// An internalValue is the unpacked form of a Value.
-// The zero Value unpacks to a zero internalValue
-type internalValue struct {
- typ *commonType // type of value
- kind Kind // kind of value
- flag uint32
- word iword
- addr unsafe.Pointer
- rcvr iword
- method bool
- nilmethod bool
-}
-
-func (v Value) internal() internalValue {
- var iv internalValue
- eface := *(*emptyInterface)(unsafe.Pointer(&v.Internal))
- p := uintptr(unsafe.Pointer(eface.typ))
- iv.typ = toCommonType((*runtime.Type)(unsafe.Pointer(p &^ reflectFlags)))
- if iv.typ == nil {
- return iv
- }
- iv.flag = uint32(p & reflectFlags)
- iv.word = eface.word
- if iv.flag&flagAddr != 0 {
- iv.addr = unsafe.Pointer(iv.word)
- iv.typ = iv.typ.Elem().common()
- if iv.typ.size <= ptrSize {
- iv.word = loadIword(iv.addr, iv.typ.size)
- }
- } else {
- if iv.typ.size > ptrSize {
- iv.addr = unsafe.Pointer(iv.word)
- }
- }
- iv.kind = iv.typ.Kind()
-
- // Is this a method? If so, iv describes the receiver.
- // Rewrite to describe the method function.
- if v.InternalMethod != 0 {
- // If this Value is a method value (x.Method(i) for some Value x)
- // then we will invoke it using the interface form of the method,
- // which always passes the receiver as a single word.
- // Record that information.
- i := v.InternalMethod - 1
- if iv.kind == Interface {
- it := (*interfaceType)(unsafe.Pointer(iv.typ))
- if i < 0 || i >= len(it.methods) {
- panic("reflect: broken Value")
- }
- m := &it.methods[i]
- if m.pkgPath != nil {
- iv.flag |= flagRO
- }
- iv.typ = toCommonType(m.typ)
- iface := (*nonEmptyInterface)(iv.addr)
- if iface.itab == nil {
- iv.word = 0
- iv.nilmethod = true
- } else {
- iv.word = iword(iface.itab.fun[i])
- }
- iv.rcvr = iface.word
- } else {
- ut := iv.typ.uncommon()
- if ut == nil || i < 0 || i >= len(ut.methods) {
- panic("reflect: broken Value")
- }
- m := &ut.methods[i]
- if m.pkgPath != nil {
- iv.flag |= flagRO
- }
- iv.typ = toCommonType(m.mtyp)
- iv.rcvr = iv.word
- iv.word = iword(m.ifn)
- }
- iv.kind = Func
- iv.method = true
- iv.flag &^= flagAddr
- iv.addr = nil
+// mustBe panics if f's kind is not expected.
+// Making this a method on flag instead of on Value
+// (and embedding flag in Value) means that we can write
+// the very clear v.mustBe(Bool) and have it compile into
+// v.flag.mustBe(Bool), which will only bother to copy the
+// single important word for the receiver.
+func (f flag) mustBe(expected Kind) {
+ k := f.kind()
+ if k != expected {
+ panic(&ValueError{methodName(), k})
}
-
- return iv
}
-// packValue returns a Value with the given flag bits, type, and interface word.
-func packValue(flag uint32, typ *runtime.Type, word iword) Value {
- if typ == nil {
- panic("packValue")
+// mustBeExported panics if f records that the value was obtained using
+// an unexported field.
+func (f flag) mustBeExported() {
+ if f == 0 {
+ panic(&ValueError{methodName(), 0})
}
- t := uintptr(unsafe.Pointer(typ))
- t |= uintptr(flag)
- eface := emptyInterface{(*runtime.Type)(unsafe.Pointer(t)), word}
- return Value{Internal: *(*interface{})(unsafe.Pointer(&eface))}
-}
-
-// valueFromAddr returns a Value using the given type and address.
-func valueFromAddr(flag uint32, typ Type, addr unsafe.Pointer) Value {
- if flag&flagAddr != 0 {
- // Addressable, so the internal value is
- // an interface containing a pointer to the real value.
- return packValue(flag, PtrTo(typ).runtimeType(), iword(addr))
- }
-
- var w iword
- if n := typ.Size(); n <= ptrSize {
- // In line, so the interface word is the actual value.
- w = loadIword(addr, n)
- } else {
- // Not in line: the interface word is the address.
- w = iword(addr)
- }
- return packValue(flag, typ.runtimeType(), w)
-}
-
-// valueFromIword returns a Value using the given type and interface word.
-func valueFromIword(flag uint32, typ Type, w iword) Value {
- if flag&flagAddr != 0 {
- panic("reflect: internal error: valueFromIword addressable")
- }
- return packValue(flag, typ.runtimeType(), w)
-}
-
-func (iv internalValue) mustBe(want Kind) {
- if iv.kind != want {
- panic(&ValueError{methodName(), iv.kind})
- }
-}
-
-func (iv internalValue) mustBeExported() {
- if iv.kind == 0 {
- panic(&ValueError{methodName(), iv.kind})
- }
- if iv.flag&flagRO != 0 {
+ if f&flagRO != 0 {
panic(methodName() + " using value obtained using unexported field")
}
}
-func (iv internalValue) mustBeAssignable() {
- if iv.kind == 0 {
- panic(&ValueError{methodName(), iv.kind})
+// mustBeAssignable panics if f records that the value is not assignable,
+// which is to say that either it was obtained using an unexported field
+// or it is not addressable.
+func (f flag) mustBeAssignable() {
+ if f == 0 {
+ panic(&ValueError{methodName(), Invalid})
}
// Assignable if addressable and not read-only.
- if iv.flag&flagRO != 0 {
+ if f&flagRO != 0 {
panic(methodName() + " using value obtained using unexported field")
}
- if iv.flag&flagAddr == 0 {
+ if f&flagAddr == 0 {
panic(methodName() + " using unaddressable value")
}
}
@@ -383,19 +275,31 @@ func (iv internalValue) mustBeAssignable() {
// or slice element in order to call a method that requires a
// pointer receiver.
func (v Value) Addr() Value {
- iv := v.internal()
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return valueFromIword(iv.flag&flagRO, PtrTo(iv.typ.toType()), iword(iv.addr))
+ return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
}
// Bool returns v's underlying value.
// It panics if v's kind is not Bool.
func (v Value) Bool() bool {
- iv := v.internal()
- iv.mustBe(Bool)
- return *(*bool)(unsafe.Pointer(&iv.word))
+ v.mustBe(Bool)
+ if v.flag&flagIndir != 0 {
+ return *(*bool)(v.val)
+ }
+ return *(*bool)(unsafe.Pointer(&v.val))
+}
+
+// Bytes returns v's underlying value.
+// It panics if v's underlying value is not a slice of bytes.
+func (v Value) Bytes() []byte {
+ v.mustBe(Slice)
+ if v.typ.Elem().Kind() != Uint8 {
+ panic("reflect.Value.Bytes of non-byte slice")
+ }
+ // Slice is always bigger than a word; assume flagIndir.
+ return *(*[]byte)(v.val)
}
// CanAddr returns true if the value's address can be obtained with Addr.
@@ -404,8 +308,7 @@ func (v Value) Bool() bool {
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
func (v Value) CanAddr() bool {
- iv := v.internal()
- return iv.flag&flagAddr != 0
+ return v.flag&flagAddr != 0
}
// CanSet returns true if the value of v can be changed.
@@ -414,8 +317,7 @@ func (v Value) CanAddr() bool {
// If CanSet returns false, calling Set or any type-specific
// setter (e.g., SetBool, SetInt64) will panic.
func (v Value) CanSet() bool {
- iv := v.internal()
- return iv.flag&(flagAddr|flagRO) == flagAddr
+ return v.flag&(flagAddr|flagRO) == flagAddr
}
// Call calls the function v with the input arguments in.
@@ -427,10 +329,9 @@ func (v Value) CanSet() bool {
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
func (v Value) Call(in []Value) []Value {
- iv := v.internal()
- iv.mustBe(Func)
- iv.mustBeExported()
- return iv.call("Call", in)
+ v.mustBe(Func)
+ v.mustBeExported()
+ return v.call("Call", in)
}
// CallSlice calls the variadic function v with the input arguments in,
@@ -441,22 +342,60 @@ func (v Value) Call(in []Value) []Value {
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
func (v Value) CallSlice(in []Value) []Value {
- iv := v.internal()
- iv.mustBe(Func)
- iv.mustBeExported()
- return iv.call("CallSlice", in)
-}
-
-func (iv internalValue) call(method string, in []Value) []Value {
- if iv.word == 0 {
- if iv.nilmethod {
- panic("reflect.Value.Call: call of method on nil interface value")
+ v.mustBe(Func)
+ v.mustBeExported()
+ return v.call("CallSlice", in)
+}
+
+func (v Value) call(method string, in []Value) []Value {
+ // Get function pointer, type.
+ t := v.typ
+ var (
+ fn unsafe.Pointer
+ rcvr iword
+ )
+ if v.flag&flagMethod != 0 {
+ i := int(v.flag) >> flagMethodShift
+ if v.typ.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &tt.methods[i]
+ if m.pkgPath != nil {
+ panic(method + " of unexported method")
+ }
+ t = toCommonType(m.typ)
+ iface := (*nonEmptyInterface)(v.val)
+ if iface.itab == nil {
+ panic(method + " of method on nil interface value")
+ }
+ fn = iface.itab.fun[i]
+ rcvr = iface.word
+ } else {
+ ut := v.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &ut.methods[i]
+ if m.pkgPath != nil {
+ panic(method + " of unexported method")
+ }
+ fn = m.ifn
+ t = toCommonType(m.mtyp)
+ rcvr = v.iword()
}
+ } else if v.flag&flagIndir != 0 {
+ fn = *(*unsafe.Pointer)(v.val)
+ } else {
+ fn = v.val
+ }
+
+ if fn == nil {
panic("reflect.Value.Call: call of nil function")
}
isSlice := method == "CallSlice"
- t := iv.typ
n := t.NumIn()
if isSlice {
if !t.IsVariadic() {
@@ -518,8 +457,8 @@ func (iv internalValue) call(method string, in []Value) []Value {
// and probably wrong for gccgo, but so
// is most of this function.
size := uintptr(0)
- if iv.method {
- // extra word for interface value
+ if v.flag&flagMethod != 0 {
+ // extra word for receiver interface word
size += ptrSize
}
for i := 0; i < nin; i++ {
@@ -556,31 +495,30 @@ func (iv internalValue) call(method string, in []Value) []Value {
args := make([]*int, size/ptrSize)
ptr := uintptr(unsafe.Pointer(&args[0]))
off := uintptr(0)
- if iv.method {
+ if v.flag&flagMethod != 0 {
// Hard-wired first argument.
- *(*iword)(unsafe.Pointer(ptr)) = iv.rcvr
+ *(*iword)(unsafe.Pointer(ptr)) = rcvr
off = ptrSize
}
for i, v := range in {
- iv := v.internal()
- iv.mustBeExported()
+ v.mustBeExported()
targ := t.In(i).(*commonType)
a := uintptr(targ.align)
off = (off + a - 1) &^ (a - 1)
n := targ.size
addr := unsafe.Pointer(ptr + off)
- iv = convertForAssignment("reflect.Value.Call", addr, targ, iv)
- if iv.addr == nil {
- storeIword(addr, iv.word, n)
+ v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
+ if v.flag&flagIndir == 0 {
+ storeIword(addr, iword(v.val), n)
} else {
- memmove(addr, iv.addr, n)
+ memmove(addr, v.val, n)
}
off += n
}
off = (off + ptrSize - 1) &^ (ptrSize - 1)
// Call.
- call(unsafe.Pointer(iv.word), unsafe.Pointer(ptr), uint32(size))
+ call(fn, unsafe.Pointer(ptr), uint32(size))
// Copy return values out of args.
//
@@ -590,7 +528,8 @@ func (iv internalValue) call(method string, in []Value) []Value {
tv := t.Out(i)
a := uintptr(tv.Align())
off = (off + a - 1) &^ (a - 1)
- ret[i] = valueFromAddr(0, tv, unsafe.Pointer(ptr+off))
+ fl := flagIndir | flag(tv.Kind())<<flagKindShift
+ ret[i] = Value{tv.common(), unsafe.Pointer(ptr + off), fl}
off += tv.Size()
}
@@ -600,42 +539,42 @@ func (iv internalValue) call(method string, in []Value) []Value {
// Cap returns v's capacity.
// It panics if v's Kind is not Array, Chan, or Slice.
func (v Value) Cap() int {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Array:
- return iv.typ.Len()
+ return v.typ.Len()
case Chan:
- return int(chancap(iv.word))
+ return int(chancap(v.iword()))
case Slice:
- return (*SliceHeader)(iv.addr).Cap
+ // Slice is always bigger than a word; assume flagIndir.
+ return (*SliceHeader)(v.val).Cap
}
- panic(&ValueError{"reflect.Value.Cap", iv.kind})
+ panic(&ValueError{"reflect.Value.Cap", k})
}
// Close closes the channel v.
// It panics if v's Kind is not Chan.
func (v Value) Close() {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- ch := iv.word
- chanclose(ch)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ chanclose(v.iword())
}
// Complex returns v's underlying value, as a complex128.
// It panics if v's Kind is not Complex64 or Complex128
func (v Value) Complex() complex128 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Complex64:
- if iv.addr == nil {
- return complex128(*(*complex64)(unsafe.Pointer(&iv.word)))
+ if v.flag&flagIndir != 0 {
+ return complex128(*(*complex64)(v.val))
}
- return complex128(*(*complex64)(iv.addr))
+ return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
case Complex128:
- return *(*complex128)(iv.addr)
+ // complex128 is always bigger than a word; assume flagIndir.
+ return *(*complex128)(v.val)
}
- panic(&ValueError{"reflect.Value.Complex", iv.kind})
+ panic(&ValueError{"reflect.Value.Complex", k})
}
// Elem returns the value that the interface v contains
@@ -643,90 +582,94 @@ func (v Value) Complex() complex128 {
// It panics if v's Kind is not Interface or Ptr.
// It returns the zero Value if v is nil.
func (v Value) Elem() Value {
- iv := v.internal()
- return iv.Elem()
-}
-
-func (iv internalValue) Elem() Value {
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Interface:
- // Empty interface and non-empty interface have different layouts.
- // Convert to empty interface.
- var eface emptyInterface
- if iv.typ.NumMethod() == 0 {
- eface = *(*emptyInterface)(iv.addr)
+ var (
+ typ *commonType
+ val unsafe.Pointer
+ )
+ if v.typ.NumMethod() == 0 {
+ eface := (*emptyInterface)(v.val)
+ if eface.typ == nil {
+ // nil interface value
+ return Value{}
+ }
+ typ = toCommonType(eface.typ)
+ val = unsafe.Pointer(eface.word)
} else {
- iface := (*nonEmptyInterface)(iv.addr)
- if iface.itab != nil {
- eface.typ = iface.itab.typ
+ iface := (*nonEmptyInterface)(v.val)
+ if iface.itab == nil {
+ // nil interface value
+ return Value{}
}
- eface.word = iface.word
+ typ = toCommonType(iface.itab.typ)
+ val = unsafe.Pointer(iface.word)
}
- if eface.typ == nil {
- return Value{}
+ fl := v.flag & flagRO
+ fl |= flag(typ.Kind()) << flagKindShift
+ if typ.size > ptrSize {
+ fl |= flagIndir
}
- return valueFromIword(iv.flag&flagRO, toType(eface.typ), eface.word)
+ return Value{typ, val, fl}
case Ptr:
+ val := v.val
+ if v.flag&flagIndir != 0 {
+ val = *(*unsafe.Pointer)(val)
+ }
// The returned value's address is v's value.
- if iv.word == 0 {
+ if val == nil {
return Value{}
}
- return valueFromAddr(iv.flag&flagRO|flagAddr, iv.typ.Elem(), unsafe.Pointer(iv.word))
+ tt := (*ptrType)(unsafe.Pointer(v.typ))
+ typ := toCommonType(tt.elem)
+ fl := v.flag&flagRO | flagIndir | flagAddr
+ fl |= flag(typ.Kind() << flagKindShift)
+ return Value{typ, val, fl}
}
- panic(&ValueError{"reflect.Value.Elem", iv.kind})
+ panic(&ValueError{"reflect.Value.Elem", k})
}
// Field returns the i'th field of the struct v.
// It panics if v's Kind is not Struct or i is out of range.
func (v Value) Field(i int) Value {
- iv := v.internal()
- iv.mustBe(Struct)
- t := iv.typ.toType()
- if i < 0 || i >= t.NumField() {
+ v.mustBe(Struct)
+ tt := (*structType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.fields) {
panic("reflect: Field index out of range")
}
- f := t.Field(i)
+ field := &tt.fields[i]
+ typ := toCommonType(field.typ)
// Inherit permission bits from v.
- flag := iv.flag
+ fl := v.flag & (flagRO | flagIndir | flagAddr)
// Using an unexported field forces flagRO.
- if f.PkgPath != "" {
- flag |= flagRO
+ if field.pkgPath != nil {
+ fl |= flagRO
}
- return valueFromValueOffset(flag, f.Type, iv, f.Offset)
-}
+ fl |= flag(typ.Kind()) << flagKindShift
-// valueFromValueOffset returns a sub-value of outer
-// (outer is an array or a struct) with the given flag and type
-// starting at the given byte offset into outer.
-func valueFromValueOffset(flag uint32, typ Type, outer internalValue, offset uintptr) Value {
- if outer.addr != nil {
- return valueFromAddr(flag, typ, unsafe.Pointer(uintptr(outer.addr)+offset))
+ var val unsafe.Pointer
+ switch {
+ case fl&flagIndir != 0:
+ // Indirect. Just bump pointer.
+ val = unsafe.Pointer(uintptr(v.val) + field.offset)
+ case bigEndian:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+ default:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
}
- // outer is so tiny it is in line.
- // We have to use outer.word and derive
- // the new word (it cannot possibly be bigger).
- // In line, so not addressable.
- if flag&flagAddr != 0 {
- panic("reflect: internal error: misuse of valueFromValueOffset")
- }
- b := *(*[ptrSize]byte)(unsafe.Pointer(&outer.word))
- for i := uintptr(0); i < typ.Size(); i++ {
- b[i] = b[offset+i]
- }
- for i := typ.Size(); i < ptrSize; i++ {
- b[i] = 0
- }
- w := *(*iword)(unsafe.Pointer(&b))
- return valueFromIword(flag, typ, w)
+ return Value{typ, val, fl}
}
// FieldByIndex returns the nested field corresponding to index.
// It panics if v's Kind is not struct.
func (v Value) FieldByIndex(index []int) Value {
- v.internal().mustBe(Struct)
+ v.mustBe(Struct)
for i, x := range index {
if i > 0 {
if v.Kind() == Ptr && v.Elem().Kind() == Struct {
@@ -742,9 +685,8 @@ func (v Value) FieldByIndex(index []int) Value {
// It returns the zero Value if no field was found.
// It panics if v's Kind is not struct.
func (v Value) FieldByName(name string) Value {
- iv := v.internal()
- iv.mustBe(Struct)
- if f, ok := iv.typ.FieldByName(name); ok {
+ v.mustBe(Struct)
+ if f, ok := v.typ.FieldByName(name); ok {
return v.FieldByIndex(f.Index)
}
return Value{}
@@ -755,168 +697,202 @@ func (v Value) FieldByName(name string) Value {
// It panics if v's Kind is not struct.
// It returns the zero Value if no field was found.
func (v Value) FieldByNameFunc(match func(string) bool) Value {
- v.internal().mustBe(Struct)
- if f, ok := v.Type().FieldByNameFunc(match); ok {
+ v.mustBe(Struct)
+ if f, ok := v.typ.FieldByNameFunc(match); ok {
return v.FieldByIndex(f.Index)
}
return Value{}
}
-// Float returns v's underlying value, as an float64.
+// Float returns v's underlying value, as a float64.
// It panics if v's Kind is not Float32 or Float64
func (v Value) Float() float64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Float32:
- return float64(*(*float32)(unsafe.Pointer(&iv.word)))
+ if v.flag&flagIndir != 0 {
+ return float64(*(*float32)(v.val))
+ }
+ return float64(*(*float32)(unsafe.Pointer(&v.val)))
case Float64:
- // If the pointer width can fit an entire float64,
- // the value is in line when stored in an interface.
- if iv.addr == nil {
- return *(*float64)(unsafe.Pointer(&iv.word))
+ if v.flag&flagIndir != 0 {
+ return *(*float64)(v.val)
}
- // Otherwise we have a pointer.
- return *(*float64)(iv.addr)
+ return *(*float64)(unsafe.Pointer(&v.val))
}
- panic(&ValueError{"reflect.Value.Float", iv.kind})
+ panic(&ValueError{"reflect.Value.Float", k})
}
// Index returns v's i'th element.
// It panics if v's Kind is not Array or Slice or i is out of range.
func (v Value) Index(i int) Value {
- iv := v.internal()
- switch iv.kind {
- default:
- panic(&ValueError{"reflect.Value.Index", iv.kind})
+ k := v.kind()
+ switch k {
case Array:
- flag := iv.flag // element flag same as overall array
- t := iv.typ.toType()
- if i < 0 || i > t.Len() {
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ if i < 0 || i > int(tt.len) {
panic("reflect: array index out of range")
}
- typ := t.Elem()
- return valueFromValueOffset(flag, typ, iv, uintptr(i)*typ.Size())
+ typ := toCommonType(tt.elem)
+ fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array
+ fl |= flag(typ.Kind()) << flagKindShift
+ offset := uintptr(i) * typ.size
+
+ var val unsafe.Pointer
+ switch {
+ case fl&flagIndir != 0:
+ // Indirect. Just bump pointer.
+ val = unsafe.Pointer(uintptr(v.val) + offset)
+ case bigEndian:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+ default:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+ }
+ return Value{typ, val, fl}
case Slice:
// Element flag same as Elem of Ptr.
- // Addressable, possibly read-only.
- flag := iv.flag&flagRO | flagAddr
- s := (*SliceHeader)(iv.addr)
+ // Addressable, indirect, possibly read-only.
+ fl := flagAddr | flagIndir | v.flag&flagRO
+ s := (*SliceHeader)(v.val)
if i < 0 || i >= s.Len {
panic("reflect: slice index out of range")
}
- typ := iv.typ.Elem()
- addr := unsafe.Pointer(s.Data + uintptr(i)*typ.Size())
- return valueFromAddr(flag, typ, addr)
+ tt := (*sliceType)(unsafe.Pointer(v.typ))
+ typ := toCommonType(tt.elem)
+ fl |= flag(typ.Kind()) << flagKindShift
+ val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
+ return Value{typ, val, fl}
}
-
- panic("not reached")
+ panic(&ValueError{"reflect.Value.Index", k})
}
// Int returns v's underlying value, as an int64.
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
func (v Value) Int() int64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ var p unsafe.Pointer
+ if v.flag&flagIndir != 0 {
+ p = v.val
+ } else {
+ // The escape analysis is good enough that &v.val
+ // does not trigger a heap allocation.
+ p = unsafe.Pointer(&v.val)
+ }
+ switch k {
case Int:
- return int64(*(*int)(unsafe.Pointer(&iv.word)))
+ return int64(*(*int)(p))
case Int8:
- return int64(*(*int8)(unsafe.Pointer(&iv.word)))
+ return int64(*(*int8)(p))
case Int16:
- return int64(*(*int16)(unsafe.Pointer(&iv.word)))
+ return int64(*(*int16)(p))
case Int32:
- return int64(*(*int32)(unsafe.Pointer(&iv.word)))
+ return int64(*(*int32)(p))
case Int64:
- if iv.addr == nil {
- return *(*int64)(unsafe.Pointer(&iv.word))
- }
- return *(*int64)(iv.addr)
+ return int64(*(*int64)(p))
}
- panic(&ValueError{"reflect.Value.Int", iv.kind})
+ panic(&ValueError{"reflect.Value.Int", k})
}
// CanInterface returns true if Interface can be used without panicking.
func (v Value) CanInterface() bool {
- iv := v.internal()
- if iv.kind == Invalid {
- panic(&ValueError{"reflect.Value.CanInterface", iv.kind})
+ if v.flag == 0 {
+ panic(&ValueError{"reflect.Value.CanInterface", Invalid})
}
- return v.InternalMethod == 0 && iv.flag&flagRO == 0
+ return v.flag&(flagMethod|flagRO) == 0
}
-// Interface returns v's value as an interface{}.
+// Interface returns v's current value as an interface{}.
+// It is equivalent to:
+// var i interface{} = (v's underlying value)
// If v is a method obtained by invoking Value.Method
// (as opposed to Type.Method), Interface cannot return an
// interface value, so it panics.
-func (v Value) Interface() interface{} {
+// It also panics if the Value was obtained by accessing
+// unexported struct fields.
+func (v Value) Interface() (i interface{}) {
return valueInterface(v, true)
}
func valueInterface(v Value, safe bool) interface{} {
- iv := v.internal()
- return iv.valueInterface(safe)
-}
-
-func (iv internalValue) valueInterface(safe bool) interface{} {
- if iv.kind == 0 {
- panic(&ValueError{"reflect.Value.Interface", iv.kind})
+ if v.flag == 0 {
+ panic(&ValueError{"reflect.Value.Interface", 0})
}
- if iv.method {
+ if v.flag&flagMethod != 0 {
panic("reflect.Value.Interface: cannot create interface value for method with bound receiver")
}
- if safe && iv.flag&flagRO != 0 {
+ if safe && v.flag&flagRO != 0 {
// Do not allow access to unexported values via Interface,
// because they might be pointers that should not be
// writable or methods or function that should not be callable.
panic("reflect.Value.Interface: cannot return value obtained from unexported field or method")
}
- if iv.kind == Interface {
+
+ k := v.kind()
+ if k == Interface {
// Special case: return the element inside the interface.
- // Won't recurse further because an interface cannot contain an interface.
- if iv.IsNil() {
- return nil
+ // Empty interface has one layout, all interfaces with
+ // methods have a second layout.
+ if v.NumMethod() == 0 {
+ return *(*interface{})(v.val)
}
- return iv.Elem().Interface()
+ return *(*interface {
+ M()
+ })(v.val)
}
// Non-interface value.
var eface emptyInterface
- eface.typ = iv.typ.runtimeType()
- eface.word = iv.word
+ eface.typ = v.typ.runtimeType()
+ eface.word = v.iword()
+
+ if v.flag&flagIndir != 0 && v.typ.size > ptrSize {
+ // eface.word is a pointer to the actual data,
+ // which might be changed. We need to return
+ // a pointer to unchanging data, so make a copy.
+ ptr := unsafe_New(v.typ)
+ memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
+ eface.word = iword(ptr)
+ }
+
return *(*interface{})(unsafe.Pointer(&eface))
}
// InterfaceData returns the interface v's value as a uintptr pair.
// It panics if v's Kind is not Interface.
func (v Value) InterfaceData() [2]uintptr {
- iv := v.internal()
- iv.mustBe(Interface)
+ v.mustBe(Interface)
// We treat this as a read operation, so we allow
// it even for unexported data, because the caller
// has to import "unsafe" to turn it into something
// that can be abused.
- return *(*[2]uintptr)(iv.addr)
+ // Interface value is always bigger than a word; assume flagIndir.
+ return *(*[2]uintptr)(v.val)
}
// IsNil returns true if v is a nil value.
// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
func (v Value) IsNil() bool {
- return v.internal().IsNil()
-}
-
-func (iv internalValue) IsNil() bool {
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Chan, Func, Map, Ptr:
- if iv.method {
+ if v.flag&flagMethod != 0 {
panic("reflect: IsNil of method Value")
}
- return iv.word == 0
+ ptr := v.val
+ if v.flag&flagIndir != 0 {
+ ptr = *(*unsafe.Pointer)(ptr)
+ }
+ return ptr == nil
case Interface, Slice:
// Both interface and slice are nil if first word is 0.
- return *(*uintptr)(iv.addr) == 0
+ // Both are always bigger than a word; assume flagIndir.
+ return *(*unsafe.Pointer)(v.val) == nil
}
- panic(&ValueError{"reflect.Value.IsNil", iv.kind})
+ panic(&ValueError{"reflect.Value.IsNil", k})
}
// IsValid returns true if v represents a value.
@@ -925,32 +901,35 @@ func (iv internalValue) IsNil() bool {
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
func (v Value) IsValid() bool {
- return v.Internal != nil
+ return v.flag != 0
}
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
- return v.internal().kind
+ return v.kind()
}
// Len returns v's length.
// 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 {
+ k := v.kind()
+ switch k {
case Array:
- return iv.typ.Len()
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ return int(tt.len)
case Chan:
- return int(chanlen(iv.word))
+ return int(chanlen(v.iword()))
case Map:
- return int(maplen(iv.word))
+ return int(maplen(v.iword()))
case Slice:
- return (*SliceHeader)(iv.addr).Len
+ // Slice is bigger than a word; assume flagIndir.
+ return (*SliceHeader)(v.val).Len
case String:
- return (*StringHeader)(iv.addr).Len
+ // String is bigger than a word; assume flagIndir.
+ return (*StringHeader)(v.val).Len
}
- panic(&ValueError{"reflect.Value.Len", iv.kind})
+ panic(&ValueError{"reflect.Value.Len", k})
}
// MapIndex returns the value associated with key in the map v.
@@ -958,29 +937,29 @@ func (v Value) Len() int {
// It returns the zero Value if key is not found in the map or if v represents a nil map.
// As in Go, the key's value must be assignable to the map's key type.
func (v Value) MapIndex(key Value) Value {
- iv := v.internal()
- iv.mustBe(Map)
- typ := iv.typ.toType()
+ v.mustBe(Map)
+ tt := (*mapType)(unsafe.Pointer(v.typ))
- // Do not require ikey to be exported, so that DeepEqual
+ // Do not require key to be exported, so that DeepEqual
// and other programs can use all the keys returned by
// MapKeys as arguments to MapIndex. If either the map
// or the key is unexported, though, the result will be
- // considered unexported.
+ // considered unexported. This is consistent with the
+ // behavior for structs, which allow read but not write
+ // of unexported fields.
+ key = key.assignTo("reflect.Value.MapIndex", toCommonType(tt.key), nil)
- ikey := key.internal()
- ikey = convertForAssignment("reflect.Value.MapIndex", nil, typ.Key(), ikey)
- if iv.word == 0 {
- return Value{}
- }
-
- flag := (iv.flag | ikey.flag) & flagRO
- elemType := typ.Elem()
- elemWord, ok := mapaccess(typ.runtimeType(), iv.word, ikey.word)
+ word, ok := mapaccess(v.typ.runtimeType(), v.iword(), key.iword())
if !ok {
return Value{}
}
- return valueFromIword(flag, elemType, elemWord)
+ typ := toCommonType(tt.elem)
+ fl := (v.flag | key.flag) & flagRO
+ if typ.size > ptrSize {
+ fl |= flagIndir
+ }
+ fl |= flag(typ.Kind()) << flagKindShift
+ return Value{typ, unsafe.Pointer(word), fl}
}
// MapKeys returns a slice containing all the keys present in the map,
@@ -988,17 +967,22 @@ func (v Value) MapIndex(key Value) Value {
// It panics if v's Kind is not Map.
// It returns an empty slice if v represents a nil map.
func (v Value) MapKeys() []Value {
- iv := v.internal()
- iv.mustBe(Map)
- keyType := iv.typ.Key()
+ v.mustBe(Map)
+ tt := (*mapType)(unsafe.Pointer(v.typ))
+ keyType := toCommonType(tt.key)
+
+ fl := v.flag & flagRO
+ fl |= flag(keyType.Kind()) << flagKindShift
+ if keyType.size > ptrSize {
+ fl |= flagIndir
+ }
- flag := iv.flag & flagRO
- m := iv.word
+ m := v.iword()
mlen := int32(0)
- if m != 0 {
+ if m != nil {
mlen = maplen(m)
}
- it := mapiterinit(iv.typ.runtimeType(), m)
+ it := mapiterinit(v.typ.runtimeType(), m)
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
@@ -1006,7 +990,7 @@ func (v Value) MapKeys() []Value {
if !ok {
break
}
- a[i] = valueFromIword(flag, keyType, keyWord)
+ a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
mapiternext(it)
}
return a[:i]
@@ -1017,23 +1001,27 @@ func (v Value) MapKeys() []Value {
// a receiver; the returned function will always use v as the receiver.
// Method panics if i is out of range.
func (v Value) Method(i int) Value {
- iv := v.internal()
- if iv.kind == Invalid {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.Method", Invalid})
}
- if i < 0 || i >= iv.typ.NumMethod() {
+ if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() {
panic("reflect: Method index out of range")
}
- return Value{v.Internal, i + 1}
+ fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl |= flag(Func) << flagKindShift
+ fl |= flag(i)<<flagMethodShift | flagMethod
+ return Value{v.typ, v.val, fl}
}
// NumMethod returns the number of methods in the value's method set.
func (v Value) NumMethod() int {
- iv := v.internal()
- if iv.kind == Invalid {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.NumMethod", Invalid})
}
- return iv.typ.NumMethod()
+ if v.flag&flagMethod != 0 {
+ return 0
+ }
+ return v.typ.NumMethod()
}
// MethodByName returns a function value corresponding to the method
@@ -1042,49 +1030,51 @@ func (v Value) NumMethod() int {
// 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 {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.MethodByName", Invalid})
}
- m, ok := iv.typ.MethodByName(name)
- if ok {
- return Value{v.Internal, m.Index + 1}
+ if v.flag&flagMethod != 0 {
+ return Value{}
}
- return Value{}
+ m, ok := v.typ.MethodByName(name)
+ if !ok {
+ return Value{}
+ }
+ return v.Method(m.Index)
}
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int {
- iv := v.internal()
- iv.mustBe(Struct)
- return iv.typ.NumField()
+ v.mustBe(Struct)
+ tt := (*structType)(unsafe.Pointer(v.typ))
+ return len(tt.fields)
}
// OverflowComplex returns true if the complex128 x cannot be represented by v's type.
// It panics if v's Kind is not Complex64 or Complex128.
func (v Value) OverflowComplex(x complex128) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Complex64:
return overflowFloat32(real(x)) || overflowFloat32(imag(x))
case Complex128:
return false
}
- panic(&ValueError{"reflect.Value.OverflowComplex", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowComplex", k})
}
// OverflowFloat returns true if the float64 x cannot be represented by v's type.
// It panics if v's Kind is not Float32 or Float64.
func (v Value) OverflowFloat(x float64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Float32:
return overflowFloat32(x)
case Float64:
return false
}
- panic(&ValueError{"reflect.Value.OverflowFloat", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowFloat", k})
}
func overflowFloat32(x float64) bool {
@@ -1097,27 +1087,27 @@ func overflowFloat32(x float64) bool {
// OverflowInt returns true if the int64 x cannot be represented by v's type.
// It panics if v's Kind is not Int, Int8, int16, Int32, or Int64.
func (v Value) OverflowInt(x int64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Int, Int8, Int16, Int32, Int64:
- bitSize := iv.typ.size * 8
+ bitSize := v.typ.size * 8
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowInt", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowInt", k})
}
// OverflowUint returns true if the uint64 x cannot be represented by v's type.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) OverflowUint(x uint64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64:
- bitSize := iv.typ.size * 8
+ bitSize := v.typ.size * 8
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowUint", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowUint", k})
}
// Pointer returns v's value as a uintptr.
@@ -1126,17 +1116,21 @@ func (v Value) OverflowUint(x uint64) bool {
// without importing the unsafe package explicitly.
// It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer.
func (v Value) Pointer() uintptr {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Chan, Func, Map, Ptr, UnsafePointer:
- if iv.kind == Func && v.InternalMethod != 0 {
+ if k == Func && v.flag&flagMethod != 0 {
panic("reflect.Value.Pointer of method Value")
}
- return uintptr(iv.word)
+ p := v.val
+ if v.flag&flagIndir != 0 {
+ p = *(*unsafe.Pointer)(p)
+ }
+ return uintptr(p)
case Slice:
- return (*SliceHeader)(iv.addr).Data
+ return (*SliceHeader)(v.val).Data
}
- panic(&ValueError{"reflect.Value.Pointer", iv.kind})
+ panic(&ValueError{"reflect.Value.Pointer", k})
}
// Recv receives and returns a value from the channel v.
@@ -1145,25 +1139,26 @@ func (v Value) Pointer() uintptr {
// The boolean value ok is true if the value x corresponds to a send
// on the channel, false if it is a zero value received because the channel is closed.
func (v Value) Recv() (x Value, ok bool) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.recv(false)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.recv(false)
}
-// internal recv, possibly non-blocking (nb)
-func (iv internalValue) recv(nb bool) (val Value, ok bool) {
- t := iv.typ.toType()
- if t.ChanDir()&RecvDir == 0 {
+// internal recv, possibly non-blocking (nb).
+// v is known to be a channel.
+func (v Value) recv(nb bool) (val Value, ok bool) {
+ tt := (*chanType)(unsafe.Pointer(v.typ))
+ if ChanDir(tt.dir)&RecvDir == 0 {
panic("recv on send-only channel")
}
- ch := iv.word
- if ch == 0 {
- panic("recv on nil channel")
- }
- valWord, selected, ok := chanrecv(iv.typ.runtimeType(), ch, nb)
+ word, selected, ok := chanrecv(v.typ.runtimeType(), v.iword(), nb)
if selected {
- val = valueFromIword(0, t.Elem(), valWord)
+ typ := toCommonType(tt.elem)
+ fl := flag(typ.Kind()) << flagKindShift
+ if typ.size > ptrSize {
+ fl |= flagIndir
+ }
+ val = Value{typ, unsafe.Pointer(word), fl}
}
return
}
@@ -1172,115 +1167,115 @@ func (iv internalValue) recv(nb bool) (val Value, ok bool) {
// It panics if v's kind is not Chan or if x's type is not the same type as v's element type.
// As in Go, x's value must be assignable to the channel's element type.
func (v Value) Send(x Value) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- iv.send(x, false)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ v.send(x, false)
}
-// internal send, possibly non-blocking
-func (iv internalValue) send(x Value, nb bool) (selected bool) {
- t := iv.typ.toType()
- if t.ChanDir()&SendDir == 0 {
+// internal send, possibly non-blocking.
+// v is known to be a channel.
+func (v Value) send(x Value, nb bool) (selected bool) {
+ tt := (*chanType)(unsafe.Pointer(v.typ))
+ if ChanDir(tt.dir)&SendDir == 0 {
panic("send on recv-only channel")
}
- ix := x.internal()
- ix.mustBeExported() // do not let unexported x leak
- ix = convertForAssignment("reflect.Value.Send", nil, t.Elem(), ix)
- ch := iv.word
- if ch == 0 {
- panic("send on nil channel")
- }
- return chansend(iv.typ.runtimeType(), ch, ix.word, nb)
+ x.mustBeExported()
+ x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil)
+ return chansend(v.typ.runtimeType(), v.iword(), x.iword(), nb)
}
// Set assigns x to the value v.
// It panics if CanSet returns false.
// As in Go, x's value must be assignable to v's type.
func (v Value) Set(x Value) {
- iv := v.internal()
- ix := x.internal()
-
- iv.mustBeAssignable()
- ix.mustBeExported() // do not let unexported x leak
-
- ix = convertForAssignment("reflect.Set", iv.addr, iv.typ, ix)
-
- n := ix.typ.size
- if n <= ptrSize {
- storeIword(iv.addr, ix.word, n)
+ v.mustBeAssignable()
+ x.mustBeExported() // do not let unexported x leak
+ var target *interface{}
+ if v.kind() == Interface {
+ target = (*interface{})(v.val)
+ }
+ x = x.assignTo("reflect.Set", v.typ, target)
+ if x.flag&flagIndir != 0 {
+ memmove(v.val, x.val, v.typ.size)
} else {
- memmove(iv.addr, ix.addr, n)
+ storeIword(v.val, iword(x.val), v.typ.size)
}
}
// SetBool sets v's underlying value.
// It panics if v's Kind is not Bool or if CanSet() is false.
func (v Value) SetBool(x bool) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(Bool)
- *(*bool)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(Bool)
+ *(*bool)(v.val) = x
+}
+
+// SetBytes sets v's underlying value.
+// It panics if v's underlying value is not a slice of bytes.
+func (v Value) SetBytes(x []byte) {
+ v.mustBeAssignable()
+ v.mustBe(Slice)
+ if v.typ.Elem().Kind() != Uint8 {
+ panic("reflect.Value.SetBytes of non-byte slice")
+ }
+ *(*[]byte)(v.val) = x
}
// SetComplex sets v's underlying value to x.
// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false.
func (v Value) SetComplex(x complex128) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetComplex", iv.kind})
+ panic(&ValueError{"reflect.Value.SetComplex", k})
case Complex64:
- *(*complex64)(iv.addr) = complex64(x)
+ *(*complex64)(v.val) = complex64(x)
case Complex128:
- *(*complex128)(iv.addr) = x
+ *(*complex128)(v.val) = x
}
}
// SetFloat sets v's underlying value to x.
// It panics if v's Kind is not Float32 or Float64, or if CanSet() is false.
func (v Value) SetFloat(x float64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetFloat", iv.kind})
+ panic(&ValueError{"reflect.Value.SetFloat", k})
case Float32:
- *(*float32)(iv.addr) = float32(x)
+ *(*float32)(v.val) = float32(x)
case Float64:
- *(*float64)(iv.addr) = x
+ *(*float64)(v.val) = x
}
}
// SetInt sets v's underlying value to x.
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false.
func (v Value) SetInt(x int64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetInt", iv.kind})
+ panic(&ValueError{"reflect.Value.SetInt", k})
case Int:
- *(*int)(iv.addr) = int(x)
+ *(*int)(v.val) = int(x)
case Int8:
- *(*int8)(iv.addr) = int8(x)
+ *(*int8)(v.val) = int8(x)
case Int16:
- *(*int16)(iv.addr) = int16(x)
+ *(*int16)(v.val) = int16(x)
case Int32:
- *(*int32)(iv.addr) = int32(x)
+ *(*int32)(v.val) = int32(x)
case Int64:
- *(*int64)(iv.addr) = x
+ *(*int64)(v.val) = x
}
}
// SetLen sets v's length to n.
-// It panics if v's Kind is not Slice.
+// It panics if v's Kind is not Slice or if n is negative or
+// greater than the capacity of the slice.
func (v Value) SetLen(n int) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(Slice)
- s := (*SliceHeader)(iv.addr)
+ v.mustBeAssignable()
+ v.mustBe(Slice)
+ s := (*SliceHeader)(v.val)
if n < 0 || n > int(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
@@ -1293,94 +1288,97 @@ func (v Value) SetLen(n int) {
// As in Go, key's value must be assignable to the map's key type,
// and val's value must be assignable to the map's value type.
func (v Value) SetMapIndex(key, val Value) {
- iv := v.internal()
- ikey := key.internal()
- ival := val.internal()
-
- iv.mustBe(Map)
- iv.mustBeExported()
-
- ikey.mustBeExported()
- ikey = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Key(), ikey)
-
- if ival.kind != Invalid {
- ival.mustBeExported()
- ival = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Elem(), ival)
+ v.mustBe(Map)
+ v.mustBeExported()
+ key.mustBeExported()
+ tt := (*mapType)(unsafe.Pointer(v.typ))
+ key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil)
+ if val.typ != nil {
+ val.mustBeExported()
+ val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil)
}
-
- mapassign(iv.typ.runtimeType(), iv.word, ikey.word, ival.word, ival.kind != Invalid)
+ mapassign(v.typ.runtimeType(), v.iword(), key.iword(), val.iword(), val.typ != nil)
}
// SetUint sets v's underlying value to x.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64, or if CanSet() is false.
func (v Value) SetUint(x uint64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetUint", iv.kind})
+ panic(&ValueError{"reflect.Value.SetUint", k})
case Uint:
- *(*uint)(iv.addr) = uint(x)
+ *(*uint)(v.val) = uint(x)
case Uint8:
- *(*uint8)(iv.addr) = uint8(x)
+ *(*uint8)(v.val) = uint8(x)
case Uint16:
- *(*uint16)(iv.addr) = uint16(x)
+ *(*uint16)(v.val) = uint16(x)
case Uint32:
- *(*uint32)(iv.addr) = uint32(x)
+ *(*uint32)(v.val) = uint32(x)
case Uint64:
- *(*uint64)(iv.addr) = x
+ *(*uint64)(v.val) = x
case Uintptr:
- *(*uintptr)(iv.addr) = uintptr(x)
+ *(*uintptr)(v.val) = uintptr(x)
}
}
// SetPointer sets the unsafe.Pointer value v to x.
// It panics if v's Kind is not UnsafePointer.
func (v Value) SetPointer(x unsafe.Pointer) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(UnsafePointer)
- *(*unsafe.Pointer)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(UnsafePointer)
+ *(*unsafe.Pointer)(v.val) = x
}
// SetString sets v's underlying value to x.
// It panics if v's Kind is not String or if CanSet() is false.
func (v Value) SetString(x string) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(String)
- *(*string)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(String)
+ *(*string)(v.val) = x
}
// Slice returns a slice of v.
// It panics if v's Kind is not Array or Slice.
func (v Value) Slice(beg, end int) Value {
- iv := v.internal()
- if iv.kind != Array && iv.kind != Slice {
- panic(&ValueError{"reflect.Value.Slice", iv.kind})
- }
- cap := v.Cap()
- if beg < 0 || end < beg || end > cap {
- panic("reflect.Value.Slice: slice index out of bounds")
- }
- var typ Type
- var base uintptr
- switch iv.kind {
+ var (
+ cap int
+ typ *sliceType
+ base unsafe.Pointer
+ )
+ switch k := v.kind(); k {
+ default:
+ panic(&ValueError{"reflect.Value.Slice", k})
case Array:
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.Slice: slice of unaddressable array")
}
- typ = toType((*arrayType)(unsafe.Pointer(iv.typ)).slice)
- base = uintptr(iv.addr)
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ cap = int(tt.len)
+ typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice)))
+ base = v.val
case Slice:
- typ = iv.typ.toType()
- base = (*SliceHeader)(iv.addr).Data
+ typ = (*sliceType)(unsafe.Pointer(v.typ))
+ s := (*SliceHeader)(v.val)
+ base = unsafe.Pointer(s.Data)
+ cap = s.Cap
+
+ }
+ if beg < 0 || end < beg || end > cap {
+ panic("reflect.Value.Slice: slice index out of bounds")
}
- s := new(SliceHeader)
- s.Data = base + uintptr(beg)*typ.Elem().Size()
+
+ // Declare slice so that gc can see the base pointer in it.
+ var x []byte
+
+ // Reinterpret as *SliceHeader to edit.
+ s := (*SliceHeader)(unsafe.Pointer(&x))
+ s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size()
s.Len = end - beg
s.Cap = cap - beg
- return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(s))
+
+ fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+ return Value{typ.common(), unsafe.Pointer(&x), fl}
}
// String returns the string v's underlying value, as a string.
@@ -1388,14 +1386,15 @@ func (v Value) Slice(beg, end int) Value {
// Unlike the other getters, it does not panic if v's Kind is not String.
// Instead, it returns a string of the form "<T value>" where T is v's type.
func (v Value) String() string {
- iv := v.internal()
- switch iv.kind {
+ switch k := v.kind(); k {
case Invalid:
return "<invalid Value>"
case String:
- return *(*string)(iv.addr)
+ return *(*string)(v.val)
}
- return "<" + iv.typ.String() + " Value>"
+ // If you call String on a reflect.Value of other type, it's better to
+ // print something than to panic. Useful in debugging.
+ return "<" + v.typ.String() + " Value>"
}
// TryRecv attempts to receive a value from the channel v but will not block.
@@ -1404,10 +1403,9 @@ func (v Value) String() string {
// The boolean ok is true if the value x corresponds to a send
// on the channel, false if it is a zero value received because the channel is closed.
func (v Value) TryRecv() (x Value, ok bool) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.recv(true)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.recv(true)
}
// TrySend attempts to send x on the channel v but will not block.
@@ -1415,57 +1413,83 @@ func (v Value) TryRecv() (x Value, ok bool) {
// It returns true if the value was sent, false otherwise.
// As in Go, x's value must be assignable to the channel's element type.
func (v Value) TrySend(x Value) bool {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.send(x, true)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.send(x, true)
}
// Type returns v's type.
func (v Value) Type() Type {
- t := v.internal().typ
- if t == nil {
+ f := v.flag
+ if f == 0 {
panic(&ValueError{"reflect.Value.Type", Invalid})
}
- return t.toType()
+ if f&flagMethod == 0 {
+ // Easy case
+ return v.typ
+ }
+
+ // Method value.
+ // v.typ describes the receiver, not the method type.
+ i := int(v.flag) >> flagMethodShift
+ if v.typ.Kind() == Interface {
+ // Method on interface.
+ tt := (*interfaceType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &tt.methods[i]
+ return toCommonType(m.typ)
+ }
+ // Method on concrete type.
+ ut := v.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &ut.methods[i]
+ return toCommonType(m.mtyp)
}
// Uint returns v's underlying value, as a uint64.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) Uint() uint64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ var p unsafe.Pointer
+ if v.flag&flagIndir != 0 {
+ p = v.val
+ } else {
+ // The escape analysis is good enough that &v.val
+ // does not trigger a heap allocation.
+ p = unsafe.Pointer(&v.val)
+ }
+ switch k {
case Uint:
- return uint64(*(*uint)(unsafe.Pointer(&iv.word)))
+ return uint64(*(*uint)(p))
case Uint8:
- return uint64(*(*uint8)(unsafe.Pointer(&iv.word)))
+ return uint64(*(*uint8)(p))
case Uint16:
- return uint64(*(*uint16)(unsafe.Pointer(&iv.word)))
+ return uint64(*(*uint16)(p))
case Uint32:
- return uint64(*(*uint32)(unsafe.Pointer(&iv.word)))
- case Uintptr:
- return uint64(*(*uintptr)(unsafe.Pointer(&iv.word)))
+ return uint64(*(*uint32)(p))
case Uint64:
- if iv.addr == nil {
- return *(*uint64)(unsafe.Pointer(&iv.word))
- }
- return *(*uint64)(iv.addr)
+ return uint64(*(*uint64)(p))
+ case Uintptr:
+ return uint64(*(*uintptr)(p))
}
- panic(&ValueError{"reflect.Value.Uint", iv.kind})
+ panic(&ValueError{"reflect.Value.Uint", k})
}
// UnsafeAddr returns a pointer to v's data.
// It is for advanced clients that also import the "unsafe" package.
// It panics if v is not addressable.
func (v Value) UnsafeAddr() uintptr {
- iv := v.internal()
- if iv.kind == Invalid {
- panic(&ValueError{"reflect.Value.UnsafeAddr", iv.kind})
+ if v.typ == nil {
+ panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
}
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.UnsafeAddr of unaddressable value")
}
- return uintptr(iv.addr)
+ return uintptr(v.val)
}
// StringHeader is the runtime representation of a string.
@@ -1485,7 +1509,7 @@ type SliceHeader struct {
func typesMustMatch(what string, t1, t2 Type) {
if t1 != t2 {
- panic("reflect: " + what + ": " + t1.String() + " != " + t2.String())
+ panic(what + ": " + t1.String() + " != " + t2.String())
}
}
@@ -1520,7 +1544,7 @@ func grow(s Value, extra int) (Value, int, int) {
// Append appends the values x to a slice s and returns the resulting slice.
// As in Go, each x's value must be assignable to the slice's element type.
func Append(s Value, x ...Value) Value {
- s.internal().mustBe(Slice)
+ s.mustBe(Slice)
s, i0, i1 := grow(s, len(x))
for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
s.Index(i).Set(x[j])
@@ -1531,8 +1555,8 @@ func Append(s Value, x ...Value) Value {
// AppendSlice appends a slice t to a slice s and returns the resulting slice.
// The slices s and t must have the same element type.
func AppendSlice(s, t Value) Value {
- s.internal().mustBe(Slice)
- t.internal().mustBe(Slice)
+ s.mustBe(Slice)
+ t.mustBe(Slice)
typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem())
s, i0, i1 := grow(s, t.Len())
Copy(s.Slice(i0, i1), t)
@@ -1545,23 +1569,23 @@ func AppendSlice(s, t Value) Value {
// Dst and src each must have kind Slice or Array, and
// dst and src must have the same element type.
func Copy(dst, src Value) int {
- idst := dst.internal()
- isrc := src.internal()
-
- if idst.kind != Array && idst.kind != Slice {
- panic(&ValueError{"reflect.Copy", idst.kind})
+ dk := dst.kind()
+ if dk != Array && dk != Slice {
+ panic(&ValueError{"reflect.Copy", dk})
}
- if idst.kind == Array {
- idst.mustBeAssignable()
+ if dk == Array {
+ dst.mustBeAssignable()
}
- idst.mustBeExported()
- if isrc.kind != Array && isrc.kind != Slice {
- panic(&ValueError{"reflect.Copy", isrc.kind})
+ dst.mustBeExported()
+
+ sk := src.kind()
+ if sk != Array && sk != Slice {
+ panic(&ValueError{"reflect.Copy", sk})
}
- isrc.mustBeExported()
+ src.mustBeExported()
- de := idst.typ.Elem()
- se := isrc.typ.Elem()
+ de := dst.typ.Elem()
+ se := src.typ.Elem()
typesMustMatch("reflect.Copy", de, se)
n := dst.Len()
@@ -1571,7 +1595,7 @@ func Copy(dst, src Value) int {
// If sk is an in-line array, cannot take its address.
// Instead, copy element by element.
- if isrc.addr == nil {
+ if src.flag&flagIndir == 0 {
for i := 0; i < n; i++ {
dst.Index(i).Set(src.Index(i))
}
@@ -1580,15 +1604,15 @@ func Copy(dst, src Value) int {
// Copy via memmove.
var da, sa unsafe.Pointer
- if idst.kind == Array {
- da = idst.addr
+ if dk == Array {
+ da = dst.val
} else {
- da = unsafe.Pointer((*SliceHeader)(idst.addr).Data)
+ da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
}
- if isrc.kind == Array {
- sa = isrc.addr
+ if sk == Array {
+ sa = src.val
} else {
- sa = unsafe.Pointer((*SliceHeader)(isrc.addr).Data)
+ sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
}
memmove(da, sa, uintptr(n)*de.Size())
return n
@@ -1598,46 +1622,64 @@ func Copy(dst, src Value) int {
* constructors
*/
+// implemented in package runtime
+func unsafe_New(Type) unsafe.Pointer
+func unsafe_NewArray(Type, int) unsafe.Pointer
+
// MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity.
func MakeSlice(typ Type, len, cap int) Value {
if typ.Kind() != Slice {
- panic("reflect: MakeSlice of non-slice type")
+ panic("reflect.MakeSlice of non-slice type")
+ }
+ if len < 0 {
+ panic("reflect.MakeSlice: negative len")
}
- s := &SliceHeader{
- Data: uintptr(unsafe.NewArray(typ.Elem(), cap)),
- Len: len,
- Cap: cap,
+ if cap < 0 {
+ panic("reflect.MakeSlice: negative cap")
}
- return valueFromAddr(0, typ, unsafe.Pointer(s))
+ if len > cap {
+ panic("reflect.MakeSlice: len > cap")
+ }
+
+ // Declare slice so that gc can see the base pointer in it.
+ var x []byte
+
+ // Reinterpret as *SliceHeader to edit.
+ s := (*SliceHeader)(unsafe.Pointer(&x))
+ s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap))
+ s.Len = len
+ s.Cap = cap
+
+ return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
}
// MakeChan creates a new channel with the specified type and buffer size.
func MakeChan(typ Type, buffer int) Value {
if typ.Kind() != Chan {
- panic("reflect: MakeChan of non-chan type")
+ panic("reflect.MakeChan of non-chan type")
}
if buffer < 0 {
- panic("MakeChan: negative buffer size")
+ panic("reflect.MakeChan: negative buffer size")
}
if typ.ChanDir() != BothDir {
- panic("MakeChan: unidirectional channel type")
+ panic("reflect.MakeChan: unidirectional channel type")
}
ch := makechan(typ.runtimeType(), uint32(buffer))
- return valueFromIword(0, typ, ch)
+ return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift}
}
// MakeMap creates a new map of the specified type.
func MakeMap(typ Type) Value {
if typ.Kind() != Map {
- panic("reflect: MakeMap of non-map type")
+ panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.runtimeType())
- return valueFromIword(0, typ, m)
+ return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
}
// Indirect returns the value that v points to.
-// If v is a nil pointer, Indirect returns a nil Value.
+// If v is a nil pointer, Indirect returns a zero Value.
// If v is not a pointer, Indirect returns v.
func Indirect(v Value) Value {
if v.Kind() != Ptr {
@@ -1652,10 +1694,23 @@ func ValueOf(i interface{}) Value {
if i == nil {
return Value{}
}
+
+ // TODO(rsc): Eliminate this terrible hack.
+ // In the call to packValue, eface.typ doesn't escape,
+ // and eface.word is an integer. So it looks like
+ // i (= eface) doesn't escape. But really it does,
+ // because eface.word is actually a pointer.
+ escapes(i)
+
// For an interface value with the noAddr bit set,
// the representation is identical to an empty interface.
eface := *(*emptyInterface)(unsafe.Pointer(&i))
- return packValue(0, eface.typ, eface.word)
+ typ := toCommonType(eface.typ)
+ fl := flag(typ.Kind()) << flagKindShift
+ if typ.size > ptrSize {
+ fl |= flagIndir
+ }
+ return Value{typ, unsafe.Pointer(eface.word), fl}
}
// Zero returns a Value representing a zero value for the specified type.
@@ -1666,10 +1721,12 @@ func Zero(typ Type) Value {
if typ == nil {
panic("reflect: Zero(nil)")
}
- if typ.Size() <= ptrSize {
- return valueFromIword(0, typ, 0)
+ t := typ.common()
+ fl := flag(t.Kind()) << flagKindShift
+ if t.size <= ptrSize {
+ return Value{t, nil, fl}
}
- return valueFromAddr(0, typ, unsafe.New(typ))
+ return Value{t, unsafe_New(typ), fl | flagIndir}
}
// New returns a Value representing a pointer to a new zero value
@@ -1678,58 +1735,81 @@ func New(typ Type) Value {
if typ == nil {
panic("reflect: New(nil)")
}
- ptr := unsafe.New(typ)
- return valueFromIword(0, PtrTo(typ), iword(ptr))
+ ptr := unsafe_New(typ)
+ fl := flag(Ptr) << flagKindShift
+ return Value{typ.common().ptrTo(), ptr, fl}
+}
+
+// NewAt returns a Value representing a pointer to a value of the
+// specified type, using p as that pointer.
+func NewAt(typ Type, p unsafe.Pointer) Value {
+ fl := flag(Ptr) << flagKindShift
+ return Value{typ.common().ptrTo(), p, fl}
}
-// convertForAssignment
-func convertForAssignment(what string, addr unsafe.Pointer, dst Type, iv internalValue) internalValue {
- if iv.method {
- panic(what + ": cannot assign method value to type " + dst.String())
+// assignTo returns a value v that can be assigned directly to typ.
+// It panics if v is not assignable to typ.
+// For a conversion to an interface type, target is a suggested scratch space to use.
+func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value {
+ if v.flag&flagMethod != 0 {
+ panic(context + ": cannot assign method value to type " + dst.String())
}
- dst1 := dst.(*commonType)
- if directlyAssignable(dst1, iv.typ) {
+ switch {
+ case directlyAssignable(dst, v.typ):
// Overwrite type so that they match.
// Same memory layout, so no harm done.
- iv.typ = dst1
- return iv
- }
- if implements(dst1, iv.typ) {
- if addr == nil {
- addr = unsafe.Pointer(new(interface{}))
+ v.typ = dst
+ fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl |= flag(dst.Kind()) << flagKindShift
+ return Value{dst, v.val, fl}
+
+ case implements(dst, v.typ):
+ if target == nil {
+ target = new(interface{})
}
- x := iv.valueInterface(false)
+ x := valueInterface(v, false)
if dst.NumMethod() == 0 {
- *(*interface{})(addr) = x
+ *target = x
} else {
- ifaceE2I(dst1.runtimeType(), x, addr)
+ ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target))
}
- iv.addr = addr
- iv.word = iword(addr)
- iv.typ = dst1
- return iv
+ return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
}
// Failed.
- panic(what + ": value of type " + iv.typ.String() + " is not assignable to type " + dst.String())
+ panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
}
// implemented in ../pkg/runtime
func chancap(ch iword) int32
func chanclose(ch iword)
func chanlen(ch iword) int32
-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(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 chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool)
+func chansend(t *runtimeType, ch iword, val iword, nb bool) bool
+
+func makechan(typ *runtimeType, size uint32) (ch iword)
+func makemap(t *runtimeType) (m iword)
+func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool)
+func mapassign(t *runtimeType, m iword, key, val iword, ok bool)
+func mapiterinit(t *runtimeType, m iword) *byte
func mapiterkey(it *byte) (key iword, ok bool)
func mapiternext(it *byte)
func maplen(m iword) int32
func call(fn, arg unsafe.Pointer, n uint32)
-func ifaceE2I(t *runtime.Type, src interface{}, dst unsafe.Pointer)
+func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer)
+
+// Dummy annotation marking that the value x escapes,
+// for use in cases where the reflect code is so clever that
+// the compiler cannot follow.
+func escapes(x interface{}) {
+ if dummy.b {
+ dummy.x = x
+ }
+}
+
+var dummy struct {
+ b bool
+ x interface{}
+}
diff --git a/src/pkg/regexp/Makefile b/src/pkg/regexp/Makefile
deleted file mode 100644
index 9024e66da..000000000
--- a/src/pkg/regexp/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=regexp
-GOFILES=\
- regexp.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index 71edc4d18..f7b41a674 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -5,7 +5,6 @@
package regexp
import (
- "os"
"strings"
"testing"
)
@@ -24,16 +23,16 @@ var good_re = []string{
`[a-z]`,
`[a-abc-c\-\]\[]`,
`[a-z]+`,
- `[]`,
`[abc]`,
`[^1234]`,
`[^\n]`,
`\!\\`,
}
+/*
type stringError struct {
re string
- err os.Error
+ err error
}
var bad_re = []stringError{
@@ -51,11 +50,12 @@ var bad_re = []stringError{
{`a??`, ErrBadClosure},
{`\x`, ErrBadBackslash},
}
+*/
-func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
+func compileTest(t *testing.T, expr string, error error) *Regexp {
re, err := Compile(expr)
if err != error {
- t.Error("compiling `", expr, "`; unexpected error: ", err.String())
+ t.Error("compiling `", expr, "`; unexpected error: ", err.Error())
}
return re
}
@@ -66,11 +66,13 @@ func TestGoodCompile(t *testing.T) {
}
}
+/*
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)
@@ -174,6 +176,45 @@ var replaceTests = []ReplaceTest{
{"[a-c]*", "x", "def", "xdxexfx"},
{"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
{"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+
+ // Substitutions
+ {"a+", "($0)", "banana", "b(a)n(a)n(a)"},
+ {"a+", "(${0})", "banana", "b(a)n(a)n(a)"},
+ {"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"},
+ {"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"},
+ {"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, world"},
+ {"hello, (.+)", "goodbye, $1x", "hello, world", "goodbye, "},
+ {"hello, (.+)", "goodbye, ${1}x", "hello, world", "goodbye, worldx"},
+ {"hello, (.+)", "<$0><$1><$2><$3>", "hello, world", "<hello, world><world><><>"},
+ {"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, world!"},
+ {"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, world"},
+ {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "hihihi"},
+ {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "byebyebye"},
+ {"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", ""},
+ {"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "hiyz"},
+ {"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $x"},
+ {"a+", "${oops", "aaa", "${oops"},
+ {"a+", "$$", "aaa", "$"},
+ {"a+", "$", "aaa", "$"},
+}
+
+var replaceLiteralTests = []ReplaceTest{
+ // Substitutions
+ {"a+", "($0)", "banana", "b($0)n($0)n($0)"},
+ {"a+", "(${0})", "banana", "b(${0})n(${0})n(${0})"},
+ {"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"},
+ {"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"},
+ {"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, ${1}"},
+ {"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, $noun!"},
+ {"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, ${noun}"},
+ {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "$x$x$x"},
+ {"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "$x$x$x"},
+ {"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", "$xyz"},
+ {"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "${x}yz"},
+ {"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $$x"},
+ {"a+", "${oops", "aaa", "${oops"},
+ {"a+", "$$", "aaa", "$$"},
+ {"a+", "$", "aaa", "$"},
}
type ReplaceFuncTest struct {
@@ -197,13 +238,58 @@ func TestReplaceAll(t *testing.T) {
}
actual := re.ReplaceAllString(tc.input, tc.replacement)
if actual != tc.output {
- t.Errorf("%q.Replace(%q,%q) = %q; want %q",
+ t.Errorf("%q.ReplaceAllString(%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",
+ t.Errorf("%q.ReplaceAll(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+}
+
+func TestReplaceAllLiteral(t *testing.T) {
+ // Run ReplaceAll tests that do not have $ expansions.
+ for _, tc := range replaceTests {
+ if strings.Contains(tc.replacement, "$") {
+ continue
+ }
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllLiteralString(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement)))
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ }
+
+ // Run literal-specific tests.
+ for _, tc := range replaceLiteralTests {
+ re, err := Compile(tc.pattern)
+ if err != nil {
+ t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
+ continue
+ }
+ actual := re.ReplaceAllLiteralString(tc.input, tc.replacement)
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q",
+ tc.pattern, tc.input, tc.replacement, actual, tc.output)
+ }
+ // now try bytes
+ actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement)))
+ if actual != tc.output {
+ t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q",
tc.pattern, tc.input, tc.replacement, actual, tc.output)
}
}
@@ -240,7 +326,7 @@ var metaTests = []MetaTest{
{`foo`, `foo`, `foo`, true},
{`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
{`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators
- {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`, `!@#`, false},
+ {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
}
func TestQuoteMeta(t *testing.T) {
@@ -287,30 +373,45 @@ func TestLiteralPrefix(t *testing.T) {
}
}
-type numSubexpCase struct {
- input string
- expected int
+type subexpCase struct {
+ input string
+ num int
+ names []string
}
-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},
+var subexpCases = []subexpCase{
+ {``, 0, nil},
+ {`.*`, 0, nil},
+ {`abba`, 0, nil},
+ {`ab(b)a`, 1, []string{"", ""}},
+ {`ab(.*)a`, 1, []string{"", ""}},
+ {`(.*)ab(.*)a`, 2, []string{"", "", ""}},
+ {`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}},
+ {`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}},
+ {`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}},
+ {`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}},
+ {`(?P<foo>.*)(?P<bar>(a)b)(?P<foo>.*)a`, 4, []string{"", "foo", "bar", "", "foo"}},
}
-func TestNumSubexp(t *testing.T) {
- for _, c := range numSubexpCases {
+func TestSubexp(t *testing.T) {
+ for _, c := range subexpCases {
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)
+ if n != c.num {
+ t.Errorf("%q: NumSubexp = %d, want %d", c.input, n, c.num)
+ continue
+ }
+ names := re.SubexpNames()
+ if len(names) != 1+n {
+ t.Errorf("%q: len(SubexpNames) = %d, want %d", c.input, len(names), n)
+ continue
+ }
+ if c.names != nil {
+ for i := 0; i < 1+n; i++ {
+ if names[i] != c.names[i] {
+ t.Errorf("%q: SubexpNames[%d] = %q, want %q", c.input, i, names[i], c.names[i])
+ }
+ }
}
}
}
@@ -322,8 +423,7 @@ func BenchmarkLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -335,8 +435,7 @@ func BenchmarkNotLiteral(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -348,8 +447,7 @@ func BenchmarkMatchClass(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
@@ -363,8 +461,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
if !re.MatchString(x) {
- println("no match!")
- break
+ b.Fatalf("no match!")
}
}
}
diff --git a/src/pkg/exp/regexp/exec.go b/src/pkg/regexp/exec.go
index 0670bb9b1..333ca2554 100644
--- a/src/pkg/exp/regexp/exec.go
+++ b/src/pkg/regexp/exec.go
@@ -1,6 +1,13 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package regexp
-import "exp/regexp/syntax"
+import (
+ "io"
+ "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
@@ -34,6 +41,28 @@ type machine struct {
pool []*thread // pool of available threads
matched bool // whether a match was found
matchcap []int // capture information for the match
+
+ // cached inputs, to avoid allocation
+ inputBytes inputBytes
+ inputString inputString
+ inputReader inputReader
+}
+
+func (m *machine) newInputBytes(b []byte) input {
+ m.inputBytes.str = b
+ return &m.inputBytes
+}
+
+func (m *machine) newInputString(s string) input {
+ m.inputString.str = s
+ return &m.inputString
+}
+
+func (m *machine) newInputReader(r io.RuneReader) input {
+ m.inputReader.r = r
+ m.inputReader.atEOT = false
+ m.inputReader.pos = 0
+ return &m.inputReader
}
// progMachine returns a new machine running the prog p.
@@ -50,6 +79,13 @@ func progMachine(p *syntax.Prog) *machine {
return m
}
+func (m *machine) init(ncap int) {
+ for _, t := range m.pool {
+ t.cap = t.cap[:ncap]
+ }
+ m.matchcap = m.matchcap[:ncap]
+}
+
// alloc allocates a new thread with the given instruction.
// It uses the free pool if possible.
func (m *machine) alloc(i *syntax.Inst) *thread {
@@ -59,15 +95,17 @@ func (m *machine) alloc(i *syntax.Inst) *thread {
m.pool = m.pool[:n-1]
} else {
t = new(thread)
- t.cap = make([]int, cap(m.matchcap))
+ t.cap = make([]int, len(m.matchcap), 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.inputBytes.str = nil
+ m.inputString.str = ""
+ m.inputReader.r = nil
m.pool = append(m.pool, t)
}
@@ -84,29 +122,18 @@ func (m *machine) match(i input, pos int) bool {
m.matchcap[i] = -1
}
runq, nextq := &m.q0, &m.q1
- rune, rune1 := endOfText, endOfText
+ r, r1 := endOfText, endOfText
width, width1 := 0, 0
- rune, width = i.step(pos)
- if rune != endOfText {
- rune1, width1 = i.step(pos + width)
+ r, width = i.step(pos)
+ if r != endOfText {
+ r1, 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
+ flag = syntax.EmptyOpContext(-1, r)
+ } else {
+ flag = i.context(pos)
}
-
for {
if len(runq.dense) == 0 {
if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
@@ -117,42 +144,37 @@ func (m *machine) match(i input, pos int) bool {
// Have match; finished exploring alternatives.
break
}
- if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() {
+ if len(m.re.prefix) > 0 && r1 != 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)
+ r, width = i.step(pos)
+ r1, 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
+ m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag, nil)
}
- if rune1 == endOfText {
- flag |= syntax.EmptyEndText
- }
- m.step(runq, nextq, pos, pos+width, rune, flag)
+ flag = syntax.EmptyOpContext(r, r1)
+ m.step(runq, nextq, pos, pos+width, r, flag)
if width == 0 {
break
}
+ if len(m.matchcap) == 0 && m.matched {
+ // Found a match and not paying attention
+ // to where it is, so any match will do.
+ break
+ }
pos += width
- rune, width = rune1, width1
- if rune != endOfText {
- rune1, width1 = i.step(pos + width)
+ r, width = r1, width1
+ if r != endOfText {
+ r1, width1 = i.step(pos + width)
}
runq, nextq = nextq, runq
}
@@ -164,7 +186,8 @@ func (m *machine) match(i input, pos int) bool {
func (m *machine) clear(q *queue) {
for _, d := range q.dense {
if d.t != nil {
- m.free(d.t)
+ // m.free(d.t)
+ m.pool = append(m.pool, d.t)
}
}
q.dense = q.dense[:0]
@@ -175,45 +198,58 @@ func (m *machine) clear(q *queue) {
// 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) {
+func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond syntax.EmptyOp) {
+ longest := m.re.longest
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
- }
- */
-
+ if longest && m.matched && len(t.cap) > 0 && m.matchcap[0] < t.cap[0] {
+ // m.free(t)
+ m.pool = append(m.pool, t)
+ continue
+ }
i := t.inst
+ add := false
switch i.Op {
default:
panic("bad inst")
case syntax.InstMatch:
- if len(t.cap) > 0 {
+ if len(t.cap) > 0 && (!longest || !m.matched || m.matchcap[1] < pos) {
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)
+ if !longest {
+ // First-match mode: cut off all lower-priority threads.
+ for _, d := range runq.dense[j+1:] {
+ if d.t != nil {
+ // m.free(d.t)
+ m.pool = append(m.pool, d.t)
+ }
}
+ runq.dense = runq.dense[:0]
}
- runq.dense = runq.dense[:0]
+ m.matched = true
case syntax.InstRune:
- if i.MatchRune(c) {
- m.add(nextq, i.Out, nextPos, t.cap, nextCond)
- }
+ add = i.MatchRune(c)
+ case syntax.InstRune1:
+ add = c == i.Rune[0]
+ case syntax.InstRuneAny:
+ add = true
+ case syntax.InstRuneAnyNotNL:
+ add = c != '\n'
+ }
+ if add {
+ t = m.add(nextq, i.Out, nextPos, t.cap, nextCond, t)
+ }
+ if t != nil {
+ // m.free(t)
+ m.pool = append(m.pool, t)
}
- m.free(t)
}
runq.dense = runq.dense[:0]
}
@@ -222,12 +258,12 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos, c int, nextCond syntax.
// 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) {
+func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp, t *thread) *thread {
if pc == 0 {
- return
+ return t
}
if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc {
- return
+ return t
}
j := len(q.dense)
@@ -244,30 +280,36 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
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)
+ t = m.add(q, i.Out, pos, cap, cond, t)
+ t = m.add(q, i.Arg, pos, cap, cond, t)
case syntax.InstEmptyWidth:
if syntax.EmptyOp(i.Arg)&^cond == 0 {
- m.add(q, i.Out, pos, cap, cond)
+ t = m.add(q, i.Out, pos, cap, cond, t)
}
case syntax.InstNop:
- m.add(q, i.Out, pos, cap, cond)
+ t = m.add(q, i.Out, pos, cap, cond, t)
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)
+ m.add(q, i.Out, pos, cap, cond, nil)
cap[i.Arg] = opos
} else {
- m.add(q, i.Out, pos, cap, cond)
+ t = m.add(q, i.Out, pos, cap, cond, t)
+ }
+ case syntax.InstMatch, syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ if t == nil {
+ t = m.alloc(i)
+ } else {
+ t.inst = i
}
- case syntax.InstMatch, syntax.InstRune:
- t := m.alloc(i)
- if len(t.cap) > 0 {
+ if len(cap) > 0 && &t.cap[0] != &cap[0] {
copy(t.cap, cap)
}
d.t = t
+ t = nil
}
+ return t
}
// empty is a non-nil 0-element slice,
@@ -277,9 +319,17 @@ 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 {
+func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int {
m := re.get()
- m.matchcap = m.matchcap[:ncap]
+ var i input
+ if r != nil {
+ i = m.newInputReader(r)
+ } else if b != nil {
+ i = m.newInputBytes(b)
+ } else {
+ i = m.newInputString(s)
+ }
+ m.init(ncap)
if !m.match(i, pos) {
re.put(m)
return nil
diff --git a/src/pkg/regexp/exec_test.go b/src/pkg/regexp/exec_test.go
new file mode 100644
index 000000000..e668574a5
--- /dev/null
+++ b/src/pkg/regexp/exec_test.go
@@ -0,0 +1,709 @@
+// 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 (
+ "bufio"
+ "compress/bzip2"
+ "fmt"
+ "io"
+ "math/rand"
+ "os"
+ "path/filepath"
+ "regexp/syntax"
+ "strconv"
+ "strings"
+ "testing"
+ "unicode/utf8"
+)
+
+// TestRE2 tests this package's regexp API against test cases
+// considered during RE2's exhaustive tests, which run all possible
+// regexps over a given set of atoms and operators, up to a given
+// complexity, over all possible strings over a given alphabet,
+// up to a given size. Rather than try to link with RE2, we read a
+// log file containing the test cases and the expected matches.
+// The log file, re2.txt, is generated by running 'make exhaustive-log'
+// in the open source RE2 distribution. http://code.google.com/p/re2/
+//
+// The test file format is a sequence of stanzas like:
+//
+// strings
+// "abc"
+// "123x"
+// regexps
+// "[a-z]+"
+// 0-3;0-3
+// -;-
+// "([0-9])([0-9])([0-9])"
+// -;-
+// -;0-3 0-1 1-2 2-3
+//
+// The stanza begins by defining a set of strings, quoted
+// using Go double-quote syntax, one per line. Then the
+// regexps section gives a sequence of regexps to run on
+// the strings. In the block that follows a regexp, each line
+// gives the semicolon-separated match results of running
+// the regexp on the corresponding string.
+// Each match result is either a single -, meaning no match, or a
+// space-separated sequence of pairs giving the match and
+// submatch indices. An unmatched subexpression formats
+// its pair as a single - (not illustrated above). For now
+// each regexp run produces two match results, one for a
+// ``full match'' that restricts the regexp to matching the entire
+// string or nothing, and one for a ``partial match'' that gives
+// the leftmost first match found in the string.
+//
+// Lines beginning with # are comments. Lines beginning with
+// a capital letter are test names printed during RE2's test suite
+// and are echoed into t but otherwise ignored.
+//
+// At time of writing, re2.txt is 32 MB but compresses to 760 kB,
+// so we store re2.txt.gz in the repository and decompress it on the fly.
+//
+func TestRE2Search(t *testing.T) {
+ testRE2(t, "testdata/re2-search.txt")
+}
+
+func TestRE2Exhaustive(t *testing.T) {
+ if testing.Short() {
+ t.Log("skipping TestRE2Exhaustive during short test")
+ return
+ }
+ testRE2(t, "testdata/re2-exhaustive.txt.bz2")
+}
+
+func testRE2(t *testing.T, file string) {
+ f, err := os.Open(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ var txt io.Reader
+ if strings.HasSuffix(file, ".bz2") {
+ z := bzip2.NewReader(f)
+ txt = z
+ file = file[:len(file)-len(".bz2")] // for error messages
+ } else {
+ txt = f
+ }
+ lineno := 0
+ r := bufio.NewReader(txt)
+ var (
+ str []string
+ input []string
+ inStrings bool
+ re *Regexp
+ refull *Regexp
+ nfail int
+ ncase int
+ )
+ for {
+ line, err := r.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatalf("%s:%d: %v", file, lineno, err)
+ }
+ line = line[:len(line)-1] // chop \n
+ lineno++
+ switch {
+ case line == "":
+ t.Fatalf("%s:%d: unexpected blank line", file, lineno)
+ case line[0] == '#':
+ continue
+ case 'A' <= line[0] && line[0] <= 'Z':
+ // Test name.
+ t.Logf("%s\n", line)
+ continue
+ case line == "strings":
+ str = str[:0]
+ inStrings = true
+ case line == "regexps":
+ inStrings = false
+ case line[0] == '"':
+ q, err := strconv.Unquote(line)
+ if err != nil {
+ // Fatal because we'll get out of sync.
+ t.Fatalf("%s:%d: unquote %s: %v", file, lineno, line, err)
+ }
+ if inStrings {
+ str = append(str, q)
+ continue
+ }
+ // Is a regexp.
+ if len(input) != 0 {
+ t.Fatalf("%s:%d: out of sync: have %d strings left before %#q", file, lineno, len(input), q)
+ }
+ re, err = tryCompile(q)
+ if err != nil {
+ if err.Error() == "error parsing regexp: invalid escape sequence: `\\C`" {
+ // We don't and likely never will support \C; keep going.
+ continue
+ }
+ t.Errorf("%s:%d: compile %#q: %v", file, lineno, q, err)
+ if nfail++; nfail >= 100 {
+ t.Fatalf("stopping after %d errors", nfail)
+ }
+ continue
+ }
+ full := `\A(?:` + q + `)\z`
+ refull, err = tryCompile(full)
+ if err != nil {
+ // Fatal because q worked, so this should always work.
+ t.Fatalf("%s:%d: compile full %#q: %v", file, lineno, full, err)
+ }
+ input = str
+ case line[0] == '-' || '0' <= line[0] && line[0] <= '9':
+ // A sequence of match results.
+ ncase++
+ if re == nil {
+ // Failed to compile: skip results.
+ continue
+ }
+ if len(input) == 0 {
+ t.Fatalf("%s:%d: out of sync: no input remaining", file, lineno)
+ }
+ var text string
+ text, input = input[0], input[1:]
+ if !isSingleBytes(text) && strings.Contains(re.String(), `\B`) {
+ // RE2's \B considers every byte position,
+ // so it sees 'not word boundary' in the
+ // middle of UTF-8 sequences. This package
+ // only considers the positions between runes,
+ // so it disagrees. Skip those cases.
+ continue
+ }
+ res := strings.Split(line, ";")
+ if len(res) != len(run) {
+ t.Fatalf("%s:%d: have %d test results, want %d", file, lineno, len(res), len(run))
+ }
+ for i := range res {
+ have, suffix := run[i](re, refull, text)
+ want := parseResult(t, file, lineno, res[i])
+ if !same(have, want) {
+ t.Errorf("%s:%d: %#q%s.FindSubmatchIndex(%#q) = %v, want %v", file, lineno, re, suffix, text, have, want)
+ if nfail++; nfail >= 100 {
+ t.Fatalf("stopping after %d errors", nfail)
+ }
+ continue
+ }
+ b, suffix := match[i](re, refull, text)
+ if b != (want != nil) {
+ t.Errorf("%s:%d: %#q%s.MatchString(%#q) = %v, want %v", file, lineno, re, suffix, text, b, !b)
+ if nfail++; nfail >= 100 {
+ t.Fatalf("stopping after %d errors", nfail)
+ }
+ continue
+ }
+ }
+
+ default:
+ t.Fatalf("%s:%d: out of sync: %s\n", file, lineno, line)
+ }
+ }
+ if len(input) != 0 {
+ t.Fatalf("%s:%d: out of sync: have %d strings left at EOF", file, lineno, len(input))
+ }
+ t.Logf("%d cases tested", ncase)
+}
+
+var run = []func(*Regexp, *Regexp, string) ([]int, string){
+ runFull,
+ runPartial,
+ runFullLongest,
+ runPartialLongest,
+}
+
+func runFull(re, refull *Regexp, text string) ([]int, string) {
+ refull.longest = false
+ return refull.FindStringSubmatchIndex(text), "[full]"
+}
+
+func runPartial(re, refull *Regexp, text string) ([]int, string) {
+ re.longest = false
+ return re.FindStringSubmatchIndex(text), ""
+}
+
+func runFullLongest(re, refull *Regexp, text string) ([]int, string) {
+ refull.longest = true
+ return refull.FindStringSubmatchIndex(text), "[full,longest]"
+}
+
+func runPartialLongest(re, refull *Regexp, text string) ([]int, string) {
+ re.longest = true
+ return re.FindStringSubmatchIndex(text), "[longest]"
+}
+
+var match = []func(*Regexp, *Regexp, string) (bool, string){
+ matchFull,
+ matchPartial,
+ matchFullLongest,
+ matchPartialLongest,
+}
+
+func matchFull(re, refull *Regexp, text string) (bool, string) {
+ refull.longest = false
+ return refull.MatchString(text), "[full]"
+}
+
+func matchPartial(re, refull *Regexp, text string) (bool, string) {
+ re.longest = false
+ return re.MatchString(text), ""
+}
+
+func matchFullLongest(re, refull *Regexp, text string) (bool, string) {
+ refull.longest = true
+ return refull.MatchString(text), "[full,longest]"
+}
+
+func matchPartialLongest(re, refull *Regexp, text string) (bool, string) {
+ re.longest = true
+ return re.MatchString(text), "[longest]"
+}
+
+func isSingleBytes(s string) bool {
+ for _, c := range s {
+ if c >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+func tryCompile(s string) (re *Regexp, err error) {
+ // Protect against panic during Compile.
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("panic: %v", r)
+ }
+ }()
+ return Compile(s)
+}
+
+func parseResult(t *testing.T, file string, lineno int, res string) []int {
+ // A single - indicates no match.
+ if res == "-" {
+ return nil
+ }
+ // Otherwise, a space-separated list of pairs.
+ n := 1
+ for j := 0; j < len(res); j++ {
+ if res[j] == ' ' {
+ n++
+ }
+ }
+ out := make([]int, 2*n)
+ i := 0
+ n = 0
+ for j := 0; j <= len(res); j++ {
+ if j == len(res) || res[j] == ' ' {
+ // Process a single pair. - means no submatch.
+ pair := res[i:j]
+ if pair == "-" {
+ out[n] = -1
+ out[n+1] = -1
+ } else {
+ k := strings.Index(pair, "-")
+ if k < 0 {
+ t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
+ }
+ lo, err1 := strconv.Atoi(pair[:k])
+ hi, err2 := strconv.Atoi(pair[k+1:])
+ if err1 != nil || err2 != nil || lo > hi {
+ t.Fatalf("%s:%d: invalid pair %s", file, lineno, pair)
+ }
+ out[n] = lo
+ out[n+1] = hi
+ }
+ n += 2
+ i = j + 1
+ }
+ }
+ return out
+}
+
+func same(x, y []int) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, xi := range x {
+ if xi != y[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// TestFowler runs this package's regexp API against the
+// POSIX regular expression tests collected by Glenn Fowler
+// at http://www2.research.att.com/~gsf/testregex/.
+func TestFowler(t *testing.T) {
+ files, err := filepath.Glob("testdata/*.dat")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, file := range files {
+ t.Log(file)
+ testFowler(t, file)
+ }
+}
+
+var notab = MustCompilePOSIX(`[^\t]+`)
+
+func testFowler(t *testing.T, file string) {
+ f, err := os.Open(file)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer f.Close()
+ b := bufio.NewReader(f)
+ lineno := 0
+ lastRegexp := ""
+Reading:
+ for {
+ lineno++
+ line, err := b.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ t.Errorf("%s:%d: %v", file, lineno, err)
+ }
+ break Reading
+ }
+
+ // http://www2.research.att.com/~gsf/man/man1/testregex.html
+ //
+ // INPUT FORMAT
+ // Input lines may be blank, a comment beginning with #, or a test
+ // specification. A specification is five fields separated by one
+ // or more tabs. NULL denotes the empty string and NIL denotes the
+ // 0 pointer.
+ if line[0] == '#' || line[0] == '\n' {
+ continue Reading
+ }
+ line = line[:len(line)-1]
+ field := notab.FindAllString(line, -1)
+ for i, f := range field {
+ if f == "NULL" {
+ field[i] = ""
+ }
+ if f == "NIL" {
+ t.Logf("%s:%d: skip: %s", file, lineno, line)
+ continue Reading
+ }
+ }
+ if len(field) == 0 {
+ continue Reading
+ }
+
+ // Field 1: the regex(3) flags to apply, one character per REG_feature
+ // flag. The test is skipped if REG_feature is not supported by the
+ // implementation. If the first character is not [BEASKLP] then the
+ // specification is a global control line. One or more of [BEASKLP] may be
+ // specified; the test will be repeated for each mode.
+ //
+ // B basic BRE (grep, ed, sed)
+ // E REG_EXTENDED ERE (egrep)
+ // A REG_AUGMENTED ARE (egrep with negation)
+ // S REG_SHELL SRE (sh glob)
+ // K REG_SHELL|REG_AUGMENTED KRE (ksh glob)
+ // L REG_LITERAL LRE (fgrep)
+ //
+ // a REG_LEFT|REG_RIGHT implicit ^...$
+ // b REG_NOTBOL lhs does not match ^
+ // c REG_COMMENT ignore space and #...\n
+ // d REG_SHELL_DOT explicit leading . match
+ // e REG_NOTEOL rhs does not match $
+ // f REG_MULTIPLE multiple \n separated patterns
+ // g FNM_LEADING_DIR testfnmatch only -- match until /
+ // h REG_MULTIREF multiple digit backref
+ // i REG_ICASE ignore case
+ // j REG_SPAN . matches \n
+ // k REG_ESCAPE \ to ecape [...] delimiter
+ // l REG_LEFT implicit ^...
+ // m REG_MINIMAL minimal match
+ // n REG_NEWLINE explicit \n match
+ // o REG_ENCLOSED (|&) magic inside [@|&](...)
+ // p REG_SHELL_PATH explicit / match
+ // q REG_DELIMITED delimited pattern
+ // r REG_RIGHT implicit ...$
+ // s REG_SHELL_ESCAPED \ not special
+ // t REG_MUSTDELIM all delimiters must be specified
+ // u standard unspecified behavior -- errors not counted
+ // v REG_CLASS_ESCAPE \ special inside [...]
+ // w REG_NOSUB no subexpression match array
+ // x REG_LENIENT let some errors slide
+ // y REG_LEFT regexec() implicit ^...
+ // z REG_NULL NULL subexpressions ok
+ // $ expand C \c escapes in fields 2 and 3
+ // / field 2 is a regsubcomp() expression
+ // = field 3 is a regdecomp() expression
+ //
+ // Field 1 control lines:
+ //
+ // C set LC_COLLATE and LC_CTYPE to locale in field 2
+ //
+ // ?test ... output field 5 if passed and != EXPECTED, silent otherwise
+ // &test ... output field 5 if current and previous passed
+ // |test ... output field 5 if current passed and previous failed
+ // ; ... output field 2 if previous failed
+ // {test ... skip if failed until }
+ // } end of skip
+ //
+ // : comment comment copied as output NOTE
+ // :comment:test :comment: ignored
+ // N[OTE] comment comment copied as output NOTE
+ // T[EST] comment comment
+ //
+ // number use number for nmatch (20 by default)
+ flag := field[0]
+ switch flag[0] {
+ case '?', '&', '|', ';', '{', '}':
+ // Ignore all the control operators.
+ // Just run everything.
+ flag = flag[1:]
+ if flag == "" {
+ continue Reading
+ }
+ case ':':
+ i := strings.Index(flag[1:], ":")
+ if i < 0 {
+ t.Logf("skip: %s", line)
+ continue Reading
+ }
+ flag = flag[1+i+1:]
+ case 'C', 'N', 'T', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ t.Logf("skip: %s", line)
+ continue Reading
+ }
+
+ // Can check field count now that we've handled the myriad comment formats.
+ if len(field) < 4 {
+ t.Errorf("%s:%d: too few fields: %s", file, lineno, line)
+ continue Reading
+ }
+
+ // Expand C escapes (a.k.a. Go escapes).
+ if strings.Contains(flag, "$") {
+ f := `"` + field[1] + `"`
+ if field[1], err = strconv.Unquote(f); err != nil {
+ t.Errorf("%s:%d: cannot unquote %s", file, lineno, f)
+ }
+ f = `"` + field[2] + `"`
+ if field[2], err = strconv.Unquote(f); err != nil {
+ t.Errorf("%s:%d: cannot unquote %s", file, lineno, f)
+ }
+ }
+
+ // Field 2: the regular expression pattern; SAME uses the pattern from
+ // the previous specification.
+ //
+ if field[1] == "SAME" {
+ field[1] = lastRegexp
+ }
+ lastRegexp = field[1]
+
+ // Field 3: the string to match.
+ text := field[2]
+
+ // Field 4: the test outcome...
+ ok, shouldCompile, shouldMatch, pos := parseFowlerResult(field[3])
+ if !ok {
+ t.Errorf("%s:%d: cannot parse result %#q", file, lineno, field[3])
+ continue Reading
+ }
+
+ // Field 5: optional comment appended to the report.
+
+ Testing:
+ // Run test once for each specified capital letter mode that we support.
+ for _, c := range flag {
+ pattern := field[1]
+ syn := syntax.POSIX | syntax.ClassNL
+ switch c {
+ default:
+ continue Testing
+ case 'E':
+ // extended regexp (what we support)
+ case 'L':
+ // literal
+ pattern = QuoteMeta(pattern)
+ }
+
+ for _, c := range flag {
+ switch c {
+ case 'i':
+ syn |= syntax.FoldCase
+ }
+ }
+
+ re, err := compile(pattern, syn, true)
+ if err != nil {
+ if shouldCompile {
+ t.Errorf("%s:%d: %#q did not compile", file, lineno, pattern)
+ }
+ continue Testing
+ }
+ if !shouldCompile {
+ t.Errorf("%s:%d: %#q should not compile", file, lineno, pattern)
+ continue Testing
+ }
+ match := re.MatchString(text)
+ if match != shouldMatch {
+ t.Errorf("%s:%d: %#q.Match(%#q) = %v, want %v", file, lineno, pattern, text, match, shouldMatch)
+ continue Testing
+ }
+ have := re.FindStringSubmatchIndex(text)
+ if (len(have) > 0) != match {
+ t.Errorf("%s:%d: %#q.Match(%#q) = %v, but %#q.FindSubmatchIndex(%#q) = %v", file, lineno, pattern, text, match, pattern, text, have)
+ continue Testing
+ }
+ if len(have) > len(pos) {
+ have = have[:len(pos)]
+ }
+ if !same(have, pos) {
+ t.Errorf("%s:%d: %#q.FindSubmatchIndex(%#q) = %v, want %v", file, lineno, pattern, text, have, pos)
+ }
+ }
+ }
+}
+
+func parseFowlerResult(s string) (ok, compiled, matched bool, pos []int) {
+ // Field 4: the test outcome. This is either one of the posix error
+ // codes (with REG_ omitted) or the match array, a list of (m,n)
+ // entries with m and n being first and last+1 positions in the
+ // field 3 string, or NULL if REG_NOSUB is in effect and success
+ // is expected. BADPAT is acceptable in place of any regcomp(3)
+ // error code. The match[] array is initialized to (-2,-2) before
+ // each test. All array elements from 0 to nmatch-1 must be specified
+ // in the outcome. Unspecified endpoints (offset -1) are denoted by ?.
+ // Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a
+ // matched (?{...}) expression, where x is the text enclosed by {...},
+ // o is the expression ordinal counting from 1, and n is the length of
+ // the unmatched portion of the subject string. If x starts with a
+ // number then that is the return value of re_execf(), otherwise 0 is
+ // returned.
+ switch {
+ case s == "":
+ // Match with no position information.
+ ok = true
+ compiled = true
+ matched = true
+ return
+ case s == "NOMATCH":
+ // Match failure.
+ ok = true
+ compiled = true
+ matched = false
+ return
+ case 'A' <= s[0] && s[0] <= 'Z':
+ // All the other error codes are compile errors.
+ ok = true
+ compiled = false
+ return
+ }
+ compiled = true
+
+ var x []int
+ for s != "" {
+ var end byte = ')'
+ if len(x)%2 == 0 {
+ if s[0] != '(' {
+ ok = false
+ return
+ }
+ s = s[1:]
+ end = ','
+ }
+ i := 0
+ for i < len(s) && s[i] != end {
+ i++
+ }
+ if i == 0 || i == len(s) {
+ ok = false
+ return
+ }
+ var v = -1
+ var err error
+ if s[:i] != "?" {
+ v, err = strconv.Atoi(s[:i])
+ if err != nil {
+ ok = false
+ return
+ }
+ }
+ x = append(x, v)
+ s = s[i+1:]
+ }
+ if len(x)%2 != 0 {
+ ok = false
+ return
+ }
+ ok = true
+ matched = true
+ pos = x
+ return
+}
+
+var text []byte
+
+func makeText(n int) []byte {
+ if len(text) >= n {
+ return text[:n]
+ }
+ text = make([]byte, n)
+ for i := range text {
+ if rand.Intn(30) == 0 {
+ text[i] = '\n'
+ } else {
+ text[i] = byte(rand.Intn(0x7E+1-0x20) + 0x20)
+ }
+ }
+ return text
+}
+
+func benchmark(b *testing.B, re string, n int) {
+ r := MustCompile(re)
+ t := makeText(n)
+ b.ResetTimer()
+ b.SetBytes(int64(n))
+ for i := 0; i < b.N; i++ {
+ if r.Match(t) {
+ b.Fatal("match!")
+ }
+ }
+}
+
+const (
+ easy0 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
+ easy1 = "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"
+ medium = "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
+ hard = "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
+ parens = "([ -~])*(A)(B)(C)(D)(E)(F)(G)(H)(I)(J)(K)(L)(M)" +
+ "(N)(O)(P)(Q)(R)(S)(T)(U)(V)(W)(X)(Y)(Z)$"
+)
+
+func BenchmarkMatchEasy0_32(b *testing.B) { benchmark(b, easy0, 32<<0) }
+func BenchmarkMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) }
+func BenchmarkMatchEasy0_32K(b *testing.B) { benchmark(b, easy0, 32<<10) }
+func BenchmarkMatchEasy0_1M(b *testing.B) { benchmark(b, easy0, 1<<20) }
+func BenchmarkMatchEasy0_32M(b *testing.B) { benchmark(b, easy0, 32<<20) }
+func BenchmarkMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) }
+func BenchmarkMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) }
+func BenchmarkMatchEasy1_32K(b *testing.B) { benchmark(b, easy1, 32<<10) }
+func BenchmarkMatchEasy1_1M(b *testing.B) { benchmark(b, easy1, 1<<20) }
+func BenchmarkMatchEasy1_32M(b *testing.B) { benchmark(b, easy1, 32<<20) }
+func BenchmarkMatchMedium_32(b *testing.B) { benchmark(b, medium, 1<<0) }
+func BenchmarkMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) }
+func BenchmarkMatchMedium_32K(b *testing.B) { benchmark(b, medium, 32<<10) }
+func BenchmarkMatchMedium_1M(b *testing.B) { benchmark(b, medium, 1<<20) }
+func BenchmarkMatchMedium_32M(b *testing.B) { benchmark(b, medium, 32<<20) }
+func BenchmarkMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) }
+func BenchmarkMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) }
+func BenchmarkMatchHard_32K(b *testing.B) { benchmark(b, hard, 32<<10) }
+func BenchmarkMatchHard_1M(b *testing.B) { benchmark(b, hard, 1<<20) }
+func BenchmarkMatchHard_32M(b *testing.B) { benchmark(b, hard, 32<<20) }
diff --git a/src/pkg/regexp/find_test.go b/src/pkg/regexp/find_test.go
index 83b249e3c..e07eb7d5c 100644
--- a/src/pkg/regexp/find_test.go
+++ b/src/pkg/regexp/find_test.go
@@ -58,8 +58,8 @@ var findTests = []FindTest{
{`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
{`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
{`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
- {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
- {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+ {`\a\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)},
@@ -80,6 +80,32 @@ var findTests = []FindTest{
{`data`, "daXY data", build(1, 5, 9)},
{`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
{`zx+`, "zzx", build(1, 1, 3)},
+ {`ab$`, "abcab", build(1, 3, 5)},
+ {`(aa)*$`, "a", build(1, 1, 1, -1, -1)},
+ {`(?:.|(?:.a))`, "", nil},
+ {`(?:A(?:A|a))`, "Aa", build(1, 0, 2)},
+ {`(?:A|(?:A|a))`, "a", build(1, 0, 1)},
+ {`(a){0}`, "", build(1, 0, 0, -1, -1)},
+ {`(?-s)(?:(?:^).)`, "\n", nil},
+ {`(?s)(?:(?:^).)`, "\n", build(1, 0, 1)},
+ {`(?:(?:^).)`, "\n", nil},
+ {`\b`, "x", build(2, 0, 0, 1, 1)},
+ {`\b`, "xx", build(2, 0, 0, 2, 2)},
+ {`\b`, "x y", build(4, 0, 0, 1, 1, 2, 2, 3, 3)},
+ {`\b`, "xx yy", build(4, 0, 0, 2, 2, 3, 3, 5, 5)},
+ {`\B`, "x", nil},
+ {`\B`, "xx", build(1, 1, 1)},
+ {`\B`, "x y", nil},
+ {`\B`, "xx yy", build(2, 1, 1, 4, 4)},
+
+ // RE2 tests
+ {`[^\S\s]`, "abcd", nil},
+ {`[^\S[:space:]]`, "abcd", nil},
+ {`[^\D\d]`, "abcd", nil},
+ {`[^\D[:digit:]]`, "abcd", nil},
+ {`(?i)\W`, "x", nil},
+ {`(?i)\W`, "k", nil},
+ {`(?i)\W`, "s", nil},
// can backslash-escape any punctuation
{`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
@@ -209,7 +235,7 @@ func TestFindAll(t *testing.T) {
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)
+ 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)
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index e8d4c087c..54c53776c 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -1,29 +1,15 @@
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package regexp implements a simple regular expression library.
+// Package regexp implements regular expression search.
//
-// The syntax of the regular expressions accepted is:
+// 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.
//
-// regexp:
-// concatenation { '|' concatenation }
-// concatenation:
-// { closure }
-// closure:
-// term [ '*' | '+' | '?' ]
-// term:
-// '^'
-// '$'
-// '.'
-// character
-// '[' [ '^' ] { character-range } ']'
-// '(' regexp ')'
-// character-range:
-// character [ '-' character ]
-//
-// All characters are UTF-8-encoded code points. Backslashes escape special
-// characters, including inside character classes. The standard Go character
-// escapes are also recognized: \a \b \f \n \r \t \v.
+// 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:
@@ -71,542 +57,35 @@ package regexp
import (
"bytes"
"io"
- "os"
+ "regexp/syntax"
+ "strconv"
"strings"
- "utf8"
+ "sync"
+ "unicode"
+ "unicode/utf8"
)
var debug = false
-// Error is the local type for a parsing error.
-type Error string
-
-func (e Error) String() string {
- return string(e)
-}
-
-// Error codes returned by failures to parse an expression.
-var (
- ErrInternal = Error("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 (
- iStart = iota // beginning of program
- iEnd // end of program: success
- iBOT // '^' beginning of text
- iEOT // '$' end of text
- iChar // 'a' regular character
- iCharClass // [a-z] character class
- iAny // '.' any character including newline
- iNotNL // [^\n] special case: any character but newline
- iBra // '(' parenthesized expression: 2*braNum for left, 2*braNum+1 for right
- iAlt // '|' alternation
- iNop // do nothing; makes it easy to link without patching
-)
-
-// An instruction executed by the NFA
-type instr struct {
- kind int // the type of this instruction: iChar, iAny, etc.
- index int // used only in debugging; could be eliminated
- next *instr // the instruction to execute after this one
- // Special fields valid only for some items.
- char int // iChar
- braNum int // iBra, iEbra
- cclass *charClass // iCharClass
- left *instr // iAlt, other branch
-}
-
-func (i *instr) print() {
- switch i.kind {
- case iStart:
- print("start")
- case iEnd:
- print("end")
- case iBOT:
- print("bot")
- case iEOT:
- print("eot")
- case iChar:
- print("char ", string(i.char))
- case iCharClass:
- i.cclass.print()
- case iAny:
- print("any")
- case iNotNL:
- print("notnl")
- case iBra:
- if i.braNum&1 == 0 {
- print("bra", i.braNum/2)
- } else {
- print("ebra", i.braNum/2)
- }
- case iAlt:
- print("alt(", i.left.index, ")")
- case iNop:
- print("nop")
- }
-}
-
// Regexp is the representation of a compiled regular expression.
// The public interface is entirely through methods.
// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
- expr string // the original expression
- prefix string // initial plain text string
- prefixBytes []byte // initial plain text bytes
- inst []*instr
- start *instr // first instruction of machine
- prefixStart *instr // where to start if there is a prefix
- nbra int // number of brackets in expression, for subexpressions
-}
-
-type charClass struct {
- negate bool // is character class negated? ([^a-z])
- // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
- ranges []int
- cmin, cmax int
-}
-
-func (cclass *charClass) print() {
- print("charclass")
- if cclass.negate {
- print(" (negated)")
- }
- for i := 0; i < len(cclass.ranges); i += 2 {
- l := cclass.ranges[i]
- r := cclass.ranges[i+1]
- if l == r {
- print(" [", string(l), "]")
- } else {
- print(" [", string(l), "-", string(r), "]")
- }
- }
-}
-
-func (cclass *charClass) addRange(a, b int) {
- // range is a through b inclusive
- cclass.ranges = append(cclass.ranges, a, b)
- if a < cclass.cmin {
- cclass.cmin = a
- }
- if b > cclass.cmax {
- cclass.cmax = b
- }
-}
-
-func (cclass *charClass) matches(c int) bool {
- if c < cclass.cmin || c > cclass.cmax {
- return cclass.negate
- }
- ranges := cclass.ranges
- for i := 0; i < len(ranges); i = i + 2 {
- if ranges[i] <= c && c <= ranges[i+1] {
- return !cclass.negate
- }
- }
- return cclass.negate
-}
-
-func newCharClass() *instr {
- i := &instr{kind: iCharClass}
- i.cclass = new(charClass)
- i.cclass.ranges = make([]int, 0, 4)
- i.cclass.cmin = 0x10FFFF + 1 // MaxRune + 1
- i.cclass.cmax = -1
- return i
-}
-
-func (re *Regexp) add(i *instr) *instr {
- i.index = len(re.inst)
- re.inst = append(re.inst, i)
- return i
-}
-
-type parser struct {
- re *Regexp
- nlpar int // number of unclosed lpars
- pos int
- ch int
-}
-
-func (p *parser) error(err Error) {
- panic(err)
-}
-
-const endOfText = -1
-
-func (p *parser) c() int { return p.ch }
-
-func (p *parser) nextc() int {
- if p.pos >= len(p.re.expr) {
- p.ch = endOfText
- } else {
- c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
- p.ch = c
- p.pos += w
- }
- return p.ch
-}
-
-func newParser(re *Regexp) *parser {
- p := new(parser)
- p.re = re
- p.nextc() // load p.ch
- return p
-}
-
-func special(c int) bool {
- for _, r := range `\.+*?()|[]^$` {
- if c == r {
- return true
- }
- }
- return false
-}
-
-func ispunct(c int) bool {
- for _, r := range "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" {
- if c == r {
- return true
- }
- }
- return false
-}
-
-var escapes = []byte("abfnrtv")
-var escaped = []byte("\a\b\f\n\r\t\v")
-
-func escape(c int) int {
- for i, b := range escapes {
- if int(b) == c {
- return i
- }
- }
- return -1
-}
-
-func (p *parser) checkBackslash() int {
- c := p.c()
- if c == '\\' {
- c = p.nextc()
- switch {
- case c == endOfText:
- p.error(ErrExtraneousBackslash)
- case ispunct(c):
- // c is as delivered
- case escape(c) >= 0:
- c = int(escaped[escape(c)])
- default:
- p.error(ErrBadBackslash)
- }
- }
- return c
-}
-
-func (p *parser) charClass() *instr {
- i := newCharClass()
- cc := i.cclass
- if p.c() == '^' {
- cc.negate = true
- p.nextc()
- }
- left := -1
- for {
- switch c := p.c(); c {
- case ']', endOfText:
- if left >= 0 {
- p.error(ErrBadRange)
- }
- // Is it [^\n]?
- if cc.negate && len(cc.ranges) == 2 &&
- cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
- nl := &instr{kind: iNotNL}
- p.re.add(nl)
- return nl
- }
- // Special common case: "[a]" -> "a"
- if !cc.negate && len(cc.ranges) == 2 && cc.ranges[0] == cc.ranges[1] {
- c := &instr{kind: iChar, char: cc.ranges[0]}
- p.re.add(c)
- return c
- }
- p.re.add(i)
- return i
- case '-': // do this before backslash processing
- p.error(ErrBadRange)
- default:
- c = p.checkBackslash()
- p.nextc()
- switch {
- case left < 0: // first of pair
- if p.c() == '-' { // range
- p.nextc()
- left = c
- } else { // single char
- cc.addRange(c, c)
- }
- case left <= c: // second of pair
- cc.addRange(left, c)
- left = -1
- default:
- p.error(ErrBadRange)
- }
- }
- }
- panic("unreachable")
-}
-
-func (p *parser) term() (start, end *instr) {
- switch c := p.c(); c {
- case '|', endOfText:
- return nil, nil
- case '*', '+', '?':
- p.error(ErrBareClosure)
- case ')':
- if p.nlpar == 0 {
- p.error(ErrUnmatchedRpar)
- }
- return nil, nil
- case ']':
- p.error(ErrUnmatchedRbkt)
- case '^':
- p.nextc()
- start = p.re.add(&instr{kind: iBOT})
- return start, start
- case '$':
- p.nextc()
- start = p.re.add(&instr{kind: iEOT})
- return start, start
- case '.':
- p.nextc()
- start = p.re.add(&instr{kind: iAny})
- return start, start
- case '[':
- p.nextc()
- start = p.charClass()
- if p.c() != ']' {
- p.error(ErrUnmatchedLbkt)
- }
- p.nextc()
- return start, start
- case '(':
- p.nextc()
- p.nlpar++
- p.re.nbra++ // increment first so first subexpr is \1
- nbra := p.re.nbra
- start, end = p.regexp()
- if p.c() != ')' {
- p.error(ErrUnmatchedLpar)
- }
- p.nlpar--
- p.nextc()
- bra := &instr{kind: iBra, braNum: 2 * nbra}
- p.re.add(bra)
- ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
- p.re.add(ebra)
- if start == nil {
- if end == nil {
- p.error(ErrInternal)
- return
- }
- start = ebra
- } else {
- end.next = ebra
- }
- bra.next = start
- return bra, ebra
- default:
- c = p.checkBackslash()
- p.nextc()
- start = &instr{kind: iChar, char: c}
- p.re.add(start)
- return start, start
- }
- panic("unreachable")
-}
-
-func (p *parser) closure() (start, end *instr) {
- start, end = p.term()
- if start == nil {
- return
- }
- switch p.c() {
- case '*':
- // (start,end)*:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- end.next = alt // after end, do alt
- alt.left = start // alternate brach: return to start
- start = alt // alt becomes new (start, end)
- end = alt
- case '+':
- // (start,end)+:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- end.next = alt // after end, do alt
- alt.left = start // alternate brach: return to start
- end = alt // start is unchanged; end is alt
- case '?':
- // (start,end)?:
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- nop := &instr{kind: iNop}
- p.re.add(nop)
- alt.left = start // alternate branch is start
- alt.next = nop // follow on to nop
- end.next = nop // after end, go to nop
- start = alt // start is now alt
- end = nop // end is nop pointed to by both branches
- default:
- return
- }
- switch p.nextc() {
- case '*', '+', '?':
- p.error(ErrBadClosure)
- }
- return
-}
-
-func (p *parser) concatenation() (start, end *instr) {
- for {
- nstart, nend := p.closure()
- switch {
- case nstart == nil: // end of this concatenation
- if start == nil { // this is the empty string
- nop := p.re.add(&instr{kind: iNop})
- return nop, nop
- }
- return
- case start == nil: // this is first element of concatenation
- start, end = nstart, nend
- default:
- end.next = nstart
- end = nend
- }
- }
- panic("unreachable")
-}
-
-func (p *parser) regexp() (start, end *instr) {
- start, end = p.concatenation()
- for {
- switch p.c() {
- default:
- return
- case '|':
- p.nextc()
- nstart, nend := p.concatenation()
- alt := &instr{kind: iAlt}
- p.re.add(alt)
- alt.left = start
- alt.next = nstart
- nop := &instr{kind: iNop}
- p.re.add(nop)
- end.next = nop
- nend.next = nop
- start, end = alt, nop
- }
- }
- panic("unreachable")
-}
-
-func unNop(i *instr) *instr {
- for i.kind == iNop {
- i = i.next
- }
- return i
-}
-
-func (re *Regexp) eliminateNops() {
- for _, inst := range re.inst {
- if inst.kind == iEnd {
- continue
- }
- inst.next = unNop(inst.next)
- if inst.kind == iAlt {
- inst.left = unNop(inst.left)
- }
- }
-}
-
-func (re *Regexp) dump() {
- print("prefix <", re.prefix, ">\n")
- for _, inst := range re.inst {
- print(inst.index, ": ")
- inst.print()
- if inst.kind != iEnd {
- print(" -> ", inst.next.index)
- }
- print("\n")
- }
-}
-
-func (re *Regexp) doParse() {
- p := newParser(re)
- start := &instr{kind: iStart}
- re.add(start)
- s, e := p.regexp()
- start.next = s
- re.start = start
- e.next = re.add(&instr{kind: iEnd})
-
- if debug {
- re.dump()
- println()
- }
-
- re.eliminateNops()
- if debug {
- re.dump()
- println()
- }
- re.setPrefix()
- if debug {
- re.dump()
- println()
- }
-}
-
-// Extract regular text from the beginning of the pattern,
-// possibly after a leading iBOT.
-// That text can be used by doExecute to speed up matching.
-func (re *Regexp) setPrefix() {
- var b []byte
- var utf = make([]byte, utf8.UTFMax)
- var inst *instr
- // First instruction is start; skip that. Also skip any initial iBOT.
- inst = re.inst[0].next
- for inst.kind == iBOT {
- inst = inst.next
- }
-Loop:
- for ; inst.kind != iEnd; inst = inst.next {
- // stop if this is not a char
- if inst.kind != iChar {
- break
- }
- // stop if this char can be followed by a match for an empty string,
- // which includes closures, ^, and $.
- switch inst.next.kind {
- case iBOT, iEOT, iAlt:
- break Loop
- }
- n := utf8.EncodeRune(utf, inst.char)
- b = append(b, utf[0:n]...)
- }
- // point prefixStart instruction to first non-CHAR after prefix
- re.prefixStart = inst
- re.prefixBytes = b
- re.prefix = string(b)
+ // 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 rune // first rune in prefix
+ cond syntax.EmptyOp // empty-width conditions required at start of match
+ numSubexp int
+ subexpNames []string
+ longest bool
+
+ // cache of machines for running regexp
+ mu sync.Mutex
+ machine []*machine
}
// String returns the source text used to compile the regular expression.
@@ -614,21 +93,99 @@ func (re *Regexp) String() string {
return re.expr
}
-// Compile parses a regular expression and returns, if successful, a Regexp
-// object that can be used to match against text.
-func Compile(str string) (regexp *Regexp, error os.Error) {
- regexp = new(Regexp)
- // doParse will panic if there is a parse error.
- defer func() {
- if e := recover(); e != nil {
- regexp = nil
- error = e.(Error) // Will re-panic if error was not an Error, e.g. nil-pointer exception
- }
- }()
- regexp.expr = str
- regexp.inst = make([]*instr, 0, 10)
- regexp.doParse()
- return
+// Compile parses a regular expression and returns, if successful,
+// a Regexp object that can be used to match against text.
+//
+// When matching against text, the regexp returns a match that
+// begins as early as possible in the input (leftmost), and among those
+// it chooses the one that a backtracking search would have found first.
+// This so-called leftmost-first matching is the same semantics
+// that Perl, Python, and other implementations use, although this
+// package implements it without the expense of backtracking.
+// For POSIX leftmost-longest matching, see CompilePOSIX.
+func Compile(expr string) (*Regexp, error) {
+ return compile(expr, syntax.Perl, false)
+}
+
+// CompilePOSIX is like Compile but restricts the regular expression
+// to POSIX ERE (egrep) syntax and changes the match semantics to
+// leftmost-longest.
+//
+// That is, when matching against text, the regexp returns a match that
+// begins as early as possible in the input (leftmost), and among those
+// it chooses a match that is as long as possible.
+// This so-called leftmost-longest matching is the same semantics
+// that early regular expression implementations used and that POSIX
+// specifies.
+//
+// However, there can be multiple leftmost-longest matches, with different
+// submatch choices, and here this package diverges from POSIX.
+// Among the possible leftmost-longest matches, this package chooses
+// the one that a backtracking search would have found first, while POSIX
+// specifies that the match be chosen to maximize the length of the first
+// subexpression, then the second, and so on from left to right.
+// The POSIX rule is computationally prohibitive and not even well-defined.
+// See http://swtch.com/~rsc/regexp/regexp2.html#posix for details.
+func CompilePOSIX(expr string) (*Regexp, error) {
+ return compile(expr, syntax.POSIX, true)
+}
+
+func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
+ re, err := syntax.Parse(expr, mode)
+ if err != nil {
+ return nil, err
+ }
+ maxCap := re.MaxCap()
+ capNames := re.CapNames()
+
+ re = re.Simplify()
+ prog, err := syntax.Compile(re)
+ if err != nil {
+ return nil, err
+ }
+ regexp := &Regexp{
+ expr: expr,
+ prog: prog,
+ numSubexp: maxCap,
+ subexpNames: capNames,
+ cond: prog.StartCond(),
+ longest: longest,
+ }
+ 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)
+ }
+ 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.
@@ -637,124 +194,53 @@ func Compile(str string) (regexp *Regexp, error os.Error) {
func MustCompile(str string) *Regexp {
regexp, error := Compile(str)
if error != nil {
- panic(`regexp: compiling "` + str + `": ` + error.String())
+ panic(`regexp: Compile(` + quote(str) + `): ` + error.Error())
}
return regexp
}
-// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
-func (re *Regexp) NumSubexp() int { return re.nbra }
-
-// The match arena allows us to reduce the garbage generated by tossing
-// match vectors away as we execute. Matches are ref counted and returned
-// to a free list when no longer active. Increases a simple benchmark by 22X.
-type matchArena struct {
- head *matchVec
- len int // length of match vector
- pos int
- atBOT bool // whether we're at beginning of text
- atEOT bool // whether we're at end of text
-}
-
-type matchVec struct {
- m []int // pairs of bracketing submatches. 0th is start,end
- ref int
- next *matchVec
-}
-
-func (a *matchArena) new() *matchVec {
- if a.head == nil {
- const N = 10
- block := make([]matchVec, N)
- for i := 0; i < N; i++ {
- b := &block[i]
- b.next = a.head
- a.head = b
- }
- }
- m := a.head
- a.head = m.next
- m.ref = 0
- if m.m == nil {
- m.m = make([]int, a.len)
+// MustCompilePOSIX is like CompilePOSIX but panics if the expression cannot be parsed.
+// It simplifies safe initialization of global variables holding compiled regular
+// expressions.
+func MustCompilePOSIX(str string) *Regexp {
+ regexp, error := CompilePOSIX(str)
+ if error != nil {
+ panic(`regexp: CompilePOSIX(` + quote(str) + `): ` + error.Error())
}
- return m
+ return regexp
}
-func (a *matchArena) free(m *matchVec) {
- m.ref--
- if m.ref == 0 {
- m.next = a.head
- a.head = m
+func quote(s string) string {
+ if strconv.CanBackquote(s) {
+ return "`" + s + "`"
}
+ return strconv.Quote(s)
}
-func (a *matchArena) copy(m *matchVec) *matchVec {
- m1 := a.new()
- copy(m1.m, m.m)
- return m1
+// NumSubexp returns the number of parenthesized subexpressions in this Regexp.
+func (re *Regexp) NumSubexp() int {
+ return re.numSubexp
}
-func (a *matchArena) noMatch() *matchVec {
- m := a.new()
- for i := range m.m {
- m.m[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
- }
- m.ref = 1
- return m
+// SubexpNames returns the names of the parenthesized subexpressions
+// in this Regexp. The name for the first sub-expression is names[1],
+// so that if m is a match slice, the name for m[i] is SubexpNames()[i].
+// Since the Regexp as a whole cannot be named, names[0] is always
+// the empty string. The slice should not be modified.
+func (re *Regexp) SubexpNames() []string {
+ return re.subexpNames
}
-type state struct {
- inst *instr // next instruction to execute
- prefixed bool // this match began with a fixed prefix
- match *matchVec
-}
-
-// Append new state to to-do list. Leftmost-longest wins so avoid
-// adding a state that's already active. The matchVec will be inc-ref'ed
-// if it is assigned to a state.
-func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec) []state {
- switch inst.kind {
- case iBOT:
- if a.atBOT {
- s = a.addState(s, inst.next, prefixed, match)
- }
- return s
- case iEOT:
- if a.atEOT {
- s = a.addState(s, inst.next, prefixed, match)
- }
- return s
- case iBra:
- match.m[inst.braNum] = a.pos
- s = a.addState(s, inst.next, prefixed, match)
- return s
- }
- l := len(s)
- // States are inserted in order so it's sufficient to see if we have the same
- // instruction; no need to see if existing match is earlier (it is).
- for i := 0; i < l; i++ {
- if s[i].inst == inst {
- return s
- }
- }
- s = append(s, state{inst, prefixed, match})
- match.ref++
- if inst.kind == iAlt {
- s = a.addState(s, inst.left, prefixed, a.copy(match))
- // give other branch a copy of this match vector
- s = a.addState(s, inst.next, prefixed, a.copy(match))
- }
- return s
-}
+const endOfText rune = -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?
+ step(pos int) (r rune, width int) // advance one rune
+ canCheckPrefix() bool // can we look ahead without losing info?
hasPrefix(re *Regexp) bool
index(re *Regexp, pos int) int
+ context(pos int) syntax.EmptyOp
}
// inputString scans a string.
@@ -762,13 +248,13 @@ type inputString struct {
str string
}
-func newInputString(str string) *inputString {
- return &inputString{str: str}
-}
-
-func (i *inputString) step(pos int) (int, int) {
+func (i *inputString) step(pos int) (rune, int) {
if pos < len(i.str) {
- return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+ c := i.str[pos]
+ if c < utf8.RuneSelf {
+ return rune(c), 1
+ }
+ return utf8.DecodeRuneInString(i.str[pos:])
}
return endOfText, 0
}
@@ -785,18 +271,29 @@ func (i *inputString) index(re *Regexp, pos int) int {
return strings.Index(i.str[pos:], re.prefix)
}
+func (i *inputString) context(pos int) syntax.EmptyOp {
+ r1, r2 := endOfText, endOfText
+ if pos > 0 && pos <= len(i.str) {
+ r1, _ = utf8.DecodeLastRuneInString(i.str[:pos])
+ }
+ if pos < len(i.str) {
+ r2, _ = utf8.DecodeRuneInString(i.str[pos:])
+ }
+ return syntax.EmptyOpContext(r1, r2)
+}
+
// 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) {
+func (i *inputBytes) step(pos int) (rune, int) {
if pos < len(i.str) {
- return utf8.DecodeRune(i.str[pos:len(i.str)])
+ c := i.str[pos]
+ if c < utf8.RuneSelf {
+ return rune(c), 1
+ }
+ return utf8.DecodeRune(i.str[pos:])
}
return endOfText, 0
}
@@ -813,6 +310,17 @@ func (i *inputBytes) index(re *Regexp, pos int) int {
return bytes.Index(i.str[pos:], re.prefixBytes)
}
+func (i *inputBytes) context(pos int) syntax.EmptyOp {
+ r1, r2 := endOfText, endOfText
+ if pos > 0 && pos <= len(i.str) {
+ r1, _ = utf8.DecodeLastRune(i.str[:pos])
+ }
+ if pos < len(i.str) {
+ r2, _ = utf8.DecodeRune(i.str[pos:])
+ }
+ return syntax.EmptyOpContext(r1, r2)
+}
+
// inputReader scans a RuneReader.
type inputReader struct {
r io.RuneReader
@@ -820,11 +328,7 @@ type inputReader struct {
pos int
}
-func newInputReader(r io.RuneReader) *inputReader {
- return &inputReader{r: r}
-}
-
-func (i *inputReader) step(pos int) (int, int) {
+func (i *inputReader) step(pos int) (rune, int) {
if !i.atEOT && pos != i.pos {
return endOfText, 0
@@ -850,155 +354,40 @@ func (i *inputReader) index(re *Regexp, pos int) int {
return -1
}
-// Search match starting from pos bytes into the input.
-func (re *Regexp) doExecute(i input, pos int) []int {
- var s [2][]state
- s[0] = make([]state, 0, 10)
- s[1] = make([]state, 0, 10)
- in, out := 0, 1
- var final state
- found := false
- anchored := re.inst[0].next.kind == iBOT
- if anchored && pos > 0 {
- return nil
- }
- // fast check for initial plain substring
- if i.canCheckPrefix() && re.prefix != "" {
- advance := 0
- if anchored {
- if !i.hasPrefix(re) {
- return nil
- }
- } else {
- advance = i.index(re, pos)
- if advance == -1 {
- return nil
- }
- }
- pos += advance
- }
- // We look one character ahead so we can match $, which checks whether
- // we are at EOT.
- nextChar, nextWidth := i.step(pos)
- arena := &matchArena{
- len: 2 * (re.nbra + 1),
- pos: pos,
- atBOT: pos == 0,
- atEOT: nextChar == endOfText,
- }
- for c, startPos := 0, pos; c != endOfText; {
- if !found && (pos == startPos || !anchored) {
- // prime the pump if we haven't seen a match yet
- match := arena.noMatch()
- match.m[0] = pos
- s[out] = arena.addState(s[out], re.start.next, false, match)
- arena.free(match) // if addState saved it, ref was incremented
- } else if len(s[out]) == 0 {
- // machine has completed
- break
- }
- in, out = out, in // old out state is new in state
- // clear out old state
- old := s[out]
- for _, state := range old {
- arena.free(state.match)
- }
- s[out] = old[0:0] // truncate state vector
- c = nextChar
- thisPos := pos
- pos += nextWidth
- nextChar, nextWidth = i.step(pos)
- arena.atEOT = nextChar == endOfText
- arena.atBOT = false
- arena.pos = pos
- for _, st := range s[in] {
- switch st.inst.kind {
- case iBOT:
- case iEOT:
- case iChar:
- if c == st.inst.char {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iCharClass:
- if st.inst.cclass.matches(c) {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iAny:
- if c != endOfText {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iNotNL:
- if c != endOfText && c != '\n' {
- s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match)
- }
- case iBra:
- case iAlt:
- case iEnd:
- // choose leftmost longest
- if !found || // first
- st.match.m[0] < final.match.m[0] || // leftmost
- (st.match.m[0] == final.match.m[0] && thisPos > final.match.m[1]) { // longest
- if final.match != nil {
- arena.free(final.match)
- }
- final = st
- final.match.ref++
- final.match.m[1] = thisPos
- }
- found = true
- default:
- st.inst.print()
- panic("unknown instruction in execute")
- }
- }
- }
- if final.match == nil {
- return nil
- }
- // if match found, back up start of match by width of prefix.
- if final.prefixed && len(final.match.m) > 0 {
- final.match.m[0] -= len(re.prefix)
- }
- return final.match.m
+func (i *inputReader) context(pos int) syntax.EmptyOp {
+ return 0
}
// LiteralPrefix returns a literal string that must begin any match
// of the regular expression re. It returns the boolean true if the
// literal string comprises the entire regular expression.
func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
- c := make([]int, len(re.inst)-2) // minus start and end.
- // First instruction is start; skip that.
- i := 0
- for inst := re.inst[0].next; inst.kind != iEnd; inst = inst.next {
- // stop if this is not a char
- if inst.kind != iChar {
- return string(c[:i]), false
- }
- c[i] = inst.char
- i++
- }
- return string(c[:i]), true
+ 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 len(re.doExecute(newInputReader(r), 0)) > 0
+ return re.doExecute(r, nil, "", 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 len(re.doExecute(newInputString(s), 0)) > 0 }
+func (re *Regexp) MatchString(s string) bool {
+ return re.doExecute(nil, nil, 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 len(re.doExecute(newInputBytes(b), 0)) > 0 }
+func (re *Regexp) Match(b []byte) bool {
+ return re.doExecute(nil, 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) {
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) {
re, err := Compile(pattern)
if err != nil {
return false, err
@@ -1009,7 +398,7 @@ func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error)
// 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) {
+func MatchString(pattern string, s string) (matched bool, error error) {
re, err := Compile(pattern)
if err != nil {
return false, err
@@ -1020,7 +409,7 @@ func MatchString(pattern string, s string) (matched bool, error os.Error) {
// 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) {
+func Match(pattern string, b []byte) (matched bool, error error) {
re, err := Compile(pattern)
if err != nil {
return false, err
@@ -1028,41 +417,79 @@ func Match(pattern string, b []byte) (matched bool, error os.Error) {
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.
+// ReplaceAllString returns a copy of src, replacing matches of the Regexp
+// with the replacement string repl. Inside repl, $ signs are interpreted as
+// in Expand, so for instance $1 represents the text of the first submatch.
func (re *Regexp) ReplaceAllString(src, repl string) string {
- return re.ReplaceAllStringFunc(src, func(string) string { return repl })
+ n := 2
+ if strings.Index(repl, "$") >= 0 {
+ n = 2 * (re.numSubexp + 1)
+ }
+ b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte {
+ return re.expand(dst, repl, nil, src, match)
+ })
+ return string(b)
+}
+
+// ReplaceAllStringLiteral returns a copy of src, replacing matches of the Regexp
+// with the replacement string repl. The replacement repl is substituted directly,
+// without using Expand.
+func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
+ return string(re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
+ return append(dst, 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.
+// ReplaceAllStringFunc returns a copy of src in which all matches of the
+// Regexp have been replaced by the return value of of function repl applied
+// to the matched substring. The replacement returned by repl is substituted
+// directly, without using Expand.
func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
+ b := re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
+ return append(dst, repl(src[match[0]:match[1]])...)
+ })
+ return string(b)
+}
+
+func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst []byte, m []int) []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(newInputString(src), searchPos)
+ var buf []byte
+ var endPos int
+ if bsrc != nil {
+ endPos = len(bsrc)
+ } else {
+ endPos = len(src)
+ }
+ for searchPos <= endPos {
+ a := re.doExecute(nil, bsrc, src, searchPos, nmatch)
if len(a) == 0 {
break // no more matches
}
// Copy the unmatched characters before this match.
- io.WriteString(buf, src[lastMatchEnd:a[0]])
+ if bsrc != nil {
+ buf = append(buf, bsrc[lastMatchEnd:a[0]]...)
+ } else {
+ buf = append(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]]))
+ buf = repl(buf, a)
}
lastMatchEnd = a[1]
// Advance past this match; always advance at least one character.
- _, width := utf8.DecodeRuneInString(src[searchPos:])
+ var width int
+ if bsrc != nil {
+ _, width = utf8.DecodeRune(bsrc[searchPos:])
+ } else {
+ _, width = utf8.DecodeRuneInString(src[searchPos:])
+ }
if searchPos+width > a[1] {
searchPos += width
} else if searchPos+1 > a[1] {
@@ -1075,61 +502,56 @@ func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) str
}
// Copy the unmatched characters after the last match.
- io.WriteString(buf, src[lastMatchEnd:])
+ if bsrc != nil {
+ buf = append(buf, bsrc[lastMatchEnd:]...)
+ } else {
+ buf = append(buf, src[lastMatchEnd:]...)
+ }
- return buf.String()
+ return buf
}
-// 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.
+// ReplaceAll returns a copy of src, replacing matches of the Regexp
+// with the replacement string repl. Inside repl, $ signs are interpreted as
+// in Expand, so for instance $1 represents the text of the first submatch.
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)
- if len(a) == 0 {
- break // no more matches
+ n := 2
+ if bytes.IndexByte(repl, '$') >= 0 {
+ n = 2 * (re.numSubexp + 1)
+ }
+ srepl := ""
+ b := re.replaceAll(src, "", n, func(dst []byte, match []int) []byte {
+ if len(srepl) != len(repl) {
+ srepl = string(repl)
}
+ return re.expand(dst, srepl, src, "", match)
+ })
+ return b
+}
- // 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]
+// ReplaceAllLiteral returns a copy of src, replacing matches of the Regexp
+// with the replacement bytes repl. The replacement repl is substituted directly,
+// without using Expand.
+func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
+ return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
+ return append(dst, repl...)
+ })
+}
- // 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]
- }
- }
+// ReplaceAllFunc returns a copy of src in which all matches of the
+// Regexp have been replaced by the return value of of function repl applied
+// to the matched byte slice. The replacement returned by repl is substituted
+// directly, without using Expand.
+func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
+ return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
+ return append(dst, repl(src[match[0]:match[1]])...)
+ })
+}
- // Copy the unmatched characters after the last match.
- buf.Write(src[lastMatchEnd:])
+var specialBytes = []byte(`\.+*?()|[]{}^$`)
- return buf.Bytes()
+func special(b byte) bool {
+ return bytes.IndexByte(specialBytes, b) >= 0
}
// QuoteMeta returns a string that quotes all regular expression metacharacters
@@ -1141,7 +563,7 @@ func QuoteMeta(s string) string {
// A byte loop is correct because all metacharacters are ASCII.
j := 0
for i := 0; i < len(s); i++ {
- if special(int(s[i])) {
+ if special(s[i]) {
b[j] = '\\'
j++
}
@@ -1151,6 +573,23 @@ func QuoteMeta(s string) string {
return string(b[0:j])
}
+// The number of capture values in the program may correspond
+// to fewer capturing expressions than are in the regexp.
+// For example, "(a){0}" turns into an empty program, so the
+// maximum capture in the program is 0 but we need to return
+// an expression for \1. Pad appends -1s to the slice a as needed.
+func (re *Regexp) pad(a []int) []int {
+ if a == nil {
+ // No match.
+ return nil
+ }
+ n := (1 + re.numSubexp) * 2
+ for len(a) < n {
+ a = append(a, -1)
+ }
+ return a
+}
+
// 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
@@ -1161,13 +600,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
}
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)
+ matches := re.doExecute(nil, b, s, pos, re.prog.NumCap)
if len(matches) == 0 {
break
}
@@ -1198,7 +631,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
prevMatchEnd = matches[1]
if accept {
- deliver(matches)
+ deliver(re.pad(matches))
i++
}
}
@@ -1207,7 +640,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
// 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)
+ a := re.doExecute(nil, b, "", 0, 2)
if a == nil {
return nil
}
@@ -1219,7 +652,7 @@ func (re *Regexp) Find(b []byte) []byte {
// 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)
+ a := re.doExecute(nil, b, "", 0, 2)
if a == nil {
return nil
}
@@ -1232,7 +665,7 @@ func (re *Regexp) FindIndex(b []byte) (loc []int) {
// 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)
+ a := re.doExecute(nil, nil, s, 0, 2)
if a == nil {
return ""
}
@@ -1243,8 +676,8 @@ func (re *Regexp) FindString(s string) string {
// 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)
+func (re *Regexp) FindStringIndex(s string) (loc []int) {
+ a := re.doExecute(nil, nil, s, 0, 2)
if a == nil {
return nil
}
@@ -1255,8 +688,8 @@ func (re *Regexp) FindStringIndex(s string) []int {
// 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)
+func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
+ a := re.doExecute(r, nil, "", 0, 2)
if a == nil {
return nil
}
@@ -1269,26 +702,154 @@ func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
// comment.
// A return value of nil indicates no match.
func (re *Regexp) FindSubmatch(b []byte) [][]byte {
- a := re.doExecute(newInputBytes(b), 0)
+ a := re.doExecute(nil, b, "", 0, re.prog.NumCap)
if a == nil {
return nil
}
- ret := make([][]byte, len(a)/2)
+ ret := make([][]byte, 1+re.numSubexp)
for i := range ret {
- if a[2*i] >= 0 {
+ if 2*i < len(a) && a[2*i] >= 0 {
ret[i] = b[a[2*i]:a[2*i+1]]
}
}
return ret
}
+// Expand appends template to dst and returns the result; during the
+// append, Expand replaces variables in the template with corresponding
+// matches drawn from src. The match slice should have been returned by
+// FindSubmatchIndex.
+//
+// In the template, a variable is denoted by a substring of the form
+// $name or ${name}, where name is a non-empty sequence of letters,
+// digits, and underscores. A purely numeric name like $1 refers to
+// the submatch with the corresponding index; other names refer to
+// capturing parentheses named with the (?P<name>...) syntax. A
+// reference to an out of range or unmatched index or a name that is not
+// present in the regular expression is replaced with an empty string.
+//
+// In the $name form, name is taken to be as long as possible: $1x is
+// equivalent to ${1x}, not ${1}x, and, $10 is equivalent to ${10}, not ${1}0.
+//
+// To insert a literal $ in the output, use $$ in the template.
+func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte {
+ return re.expand(dst, string(template), src, "", match)
+}
+
+// ExpandString is like Expand but the template and source are strings.
+// It appends to and returns a byte slice in order to give the calling
+// code control over allocation.
+func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte {
+ return re.expand(dst, template, nil, src, match)
+}
+
+func (re *Regexp) expand(dst []byte, template string, bsrc []byte, src string, match []int) []byte {
+ for len(template) > 0 {
+ i := strings.Index(template, "$")
+ if i < 0 {
+ break
+ }
+ dst = append(dst, template[:i]...)
+ template = template[i:]
+ if len(template) > 1 && template[1] == '$' {
+ // Treat $$ as $.
+ dst = append(dst, '$')
+ template = template[2:]
+ continue
+ }
+ name, num, rest, ok := extract(template)
+ if !ok {
+ // Malformed; treat $ as raw text.
+ dst = append(dst, '$')
+ template = template[1:]
+ continue
+ }
+ template = rest
+ if num >= 0 {
+ if 2*num+1 < len(match) {
+ if bsrc != nil {
+ dst = append(dst, bsrc[match[2*num]:match[2*num+1]]...)
+ } else {
+ dst = append(dst, src[match[2*num]:match[2*num+1]]...)
+ }
+ }
+ } else {
+ for i, namei := range re.subexpNames {
+ if name == namei && 2*i+1 < len(match) && match[2*i] >= 0 {
+ if bsrc != nil {
+ dst = append(dst, bsrc[match[2*i]:match[2*i+1]]...)
+ } else {
+ dst = append(dst, src[match[2*i]:match[2*i+1]]...)
+ }
+ break
+ }
+ }
+ }
+ }
+ dst = append(dst, template...)
+ return dst
+}
+
+// extract returns the name from a leading "$name" or "${name}" in str.
+// If it is a number, extract returns num set to that number; otherwise num = -1.
+func extract(str string) (name string, num int, rest string, ok bool) {
+ if len(str) < 2 || str[0] != '$' {
+ return
+ }
+ brace := false
+ if str[1] == '{' {
+ brace = true
+ str = str[2:]
+ } else {
+ str = str[1:]
+ }
+ i := 0
+ for i < len(str) {
+ rune, size := utf8.DecodeRuneInString(str[i:])
+ if !unicode.IsLetter(rune) && !unicode.IsDigit(rune) && rune != '_' {
+ break
+ }
+ i += size
+ }
+ if i == 0 {
+ // empty name is not okay
+ return
+ }
+ name = str[:i]
+ if brace {
+ if i >= len(str) || str[i] != '}' {
+ // missing closing brace
+ return
+ }
+ i++
+ }
+
+ // Parse number.
+ num = 0
+ for i := 0; i < len(name); i++ {
+ if name[i] < '0' || '9' < name[i] || num >= 1e8 {
+ num = -1
+ break
+ }
+ num = num*10 + int(name[i]) - '0'
+ }
+ // Disallow leading zeros.
+ if name[0] == '0' && len(name) > 1 {
+ num = -1
+ }
+
+ rest = str[i:]
+ ok = true
+ return
+}
+
// 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)
+ return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap))
}
// FindStringSubmatch returns a slice of strings holding the text of the
@@ -1297,13 +858,13 @@ func (re *Regexp) FindSubmatchIndex(b []byte) []int {
// package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindStringSubmatch(s string) []string {
- a := re.doExecute(newInputString(s), 0)
+ a := re.doExecute(nil, nil, s, 0, re.prog.NumCap)
if a == nil {
return nil
}
- ret := make([]string, len(a)/2)
+ ret := make([]string, 1+re.numSubexp)
for i := range ret {
- if a[2*i] >= 0 {
+ if 2*i < len(a) && a[2*i] >= 0 {
ret[i] = s[a[2*i]:a[2*i+1]]
}
}
@@ -1316,7 +877,7 @@ func (re *Regexp) FindStringSubmatch(s string) []string {
// '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)
+ return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap))
}
// FindReaderSubmatchIndex returns a slice holding the index pairs
@@ -1325,7 +886,7 @@ func (re *Regexp) FindStringSubmatchIndex(s string) []int {
// 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)
+ return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap))
}
const startSize = 10 // The size at which to start a slice in the 'All' routines.
diff --git a/src/pkg/exp/regexp/syntax/compile.go b/src/pkg/regexp/syntax/compile.go
index 5ea2425c3..41955bfc2 100644
--- a/src/pkg/exp/regexp/syntax/compile.go
+++ b/src/pkg/regexp/syntax/compile.go
@@ -1,9 +1,10 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package syntax
-import (
- "os"
- "unicode"
-)
+import "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
@@ -75,7 +76,8 @@ type compiler struct {
}
// Compile compiles the regexp into a program to be executed.
-func Compile(re *Regexp) (*Prog, os.Error) {
+// The regexp should have been simplified already (returned from re.Simplify).
+func Compile(re *Regexp) (*Prog, error) {
var c compiler
c.init()
f := c.compile(re)
@@ -90,8 +92,8 @@ func (c *compiler) init() {
c.inst(InstFail)
}
-var anyRuneNotNL = []int{0, '\n' - 1, '\n' - 1, unicode.MaxRune}
-var anyRune = []int{0, unicode.MaxRune}
+var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
+var anyRune = []rune{0, unicode.MaxRune}
func (c *compiler) compile(re *Regexp) frag {
switch re.Op {
@@ -105,7 +107,7 @@ func (c *compiler) compile(re *Regexp) frag {
}
var f frag
for j := range re.Rune {
- f1 := c.rune(re.Rune[j : j+1])
+ f1 := c.rune(re.Rune[j:j+1], re.Flags)
if j == 0 {
f = f1
} else {
@@ -114,11 +116,11 @@ func (c *compiler) compile(re *Regexp) frag {
}
return f
case OpCharClass:
- return c.rune(re.Rune)
+ return c.rune(re.Rune, re.Flags)
case OpAnyCharNotNL:
- return c.rune(anyRuneNotNL)
+ return c.rune(anyRuneNotNL, 0)
case OpAnyChar:
- return c.rune(anyRune)
+ return c.rune(anyRune, 0)
case OpBeginLine:
return c.empty(EmptyBeginLine)
case OpEndLine:
@@ -261,9 +263,27 @@ func (c *compiler) empty(op EmptyOp) frag {
return f
}
-func (c *compiler) rune(rune []int) frag {
+func (c *compiler) rune(r []rune, flags Flags) frag {
f := c.inst(InstRune)
- c.p.Inst[f.i].Rune = rune
+ i := &c.p.Inst[f.i]
+ i.Rune = r
+ flags &= FoldCase // only relevant flag is FoldCase
+ if len(r) != 1 || unicode.SimpleFold(r[0]) == r[0] {
+ // and sometimes not even that
+ flags &^= FoldCase
+ }
+ i.Arg = uint32(flags)
f.out = patchList(f.i << 1)
+
+ // Special cases for exec machine.
+ switch {
+ case flags&FoldCase == 0 && (len(r) == 1 || len(r) == 2 && r[0] == r[1]):
+ i.Op = InstRune1
+ case len(r) == 2 && r[0] == 0 && r[1] == unicode.MaxRune:
+ i.Op = InstRuneAny
+ case len(r) == 4 && r[0] == 0 && r[1] == '\n'-1 && r[2] == '\n'+1 && r[3] == unicode.MaxRune:
+ i.Op = InstRuneAnyNotNL
+ }
+
return f
}
diff --git a/src/pkg/exp/regexp/syntax/make_perl_groups.pl b/src/pkg/regexp/syntax/make_perl_groups.pl
index 6d1b84b10..d024f5090 100755
--- a/src/pkg/exp/regexp/syntax/make_perl_groups.pl
+++ b/src/pkg/regexp/syntax/make_perl_groups.pl
@@ -57,7 +57,7 @@ sub ComputeClass($) {
sub PrintClass($$@) {
my ($cname, $name, @ranges) = @_;
- print "var code$cname = []int{ /* $name */\n";
+ print "var code$cname = []rune{ /* $name */\n";
for (my $i=0; $i<@ranges; $i++) {
my @a = @{$ranges[$i]};
printf "\t0x%x, 0x%x,\n", $a[0], $a[1];
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/regexp/syntax/parse.go
index 4eed18268..2df775025 100644
--- a/src/pkg/exp/regexp/syntax/parse.go
+++ b/src/pkg/regexp/syntax/parse.go
@@ -2,14 +2,17 @@
// 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 parse trees and compiles
+// parse trees into programs. Most clients of regular expressions will use
+// the facilities of package regexp (such as Compile and Match) instead of
+// this package.
package syntax
import (
- "os"
"sort"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// An Error describes a failure to parse a regular expression
@@ -19,7 +22,7 @@ type Error struct {
Expr string
}
-func (e *Error) String() string {
+func (e *Error) Error() string {
return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`"
}
@@ -82,7 +85,7 @@ type parser struct {
free *Regexp
numCap int // number of capturing groups seen
wholeRegexp string
- tmpClass []int // temporary char class work space
+ tmpClass []rune // temporary char class work space
}
func (p *parser) newRegexp(op Op) *Regexp {
@@ -149,7 +152,7 @@ func (p *parser) push(re *Regexp) *Regexp {
// 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 {
+func (p *parser) maybeConcat(r rune, flags Flags) bool {
n := len(p.stack)
if n < 2 {
return false
@@ -178,17 +181,35 @@ func (p *parser) maybeConcat(r int, flags Flags) bool {
}
// newLiteral returns a new OpLiteral Regexp with the given flags
-func (p *parser) newLiteral(r int, flags Flags) *Regexp {
+func (p *parser) newLiteral(r rune, flags Flags) *Regexp {
re := p.newRegexp(OpLiteral)
re.Flags = flags
+ if flags&FoldCase != 0 {
+ r = minFoldRune(r)
+ }
re.Rune0[0] = r
re.Rune = re.Rune0[:1]
return re
}
+// minFoldRune returns the minimum rune fold-equivalent to r.
+func minFoldRune(r rune) rune {
+ if r < minFold || r > maxFold {
+ return r
+ }
+ min := r
+ r0 := r
+ for r = unicode.SimpleFold(r); r != r0; r = unicode.SimpleFold(r) {
+ if min > r {
+ min = r
+ }
+ }
+ return min
+}
+
// literal pushes a literal regexp for the rune r on the stack
// and returns that regexp.
-func (p *parser) literal(r int) {
+func (p *parser) literal(r rune) {
p.push(p.newLiteral(r, p.flags))
}
@@ -200,27 +221,32 @@ func (p *parser) op(op Op) *Regexp {
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) {
+// repeat replaces the top stack element with itself repeated according to op, min, max.
+// before is the regexp suffix starting at the repetition operator.
+// after is the regexp suffix following after the repetition operator.
+// repeat returns an updated 'after' and an error, if any.
+func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) (string, error) {
flags := p.flags
if p.flags&PerlX != 0 {
- if len(t) > 0 && t[0] == '?' {
- t = t[1:]
+ if len(after) > 0 && after[0] == '?' {
+ after = after[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)]}
+ return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(after)]}
}
}
n := len(p.stack)
if n == 0 {
- return "", &Error{ErrMissingRepeatArgument, opstr}
+ return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
}
sub := p.stack[n-1]
+ if sub.Op >= opPseudo {
+ return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]}
+ }
re := p.newRegexp(op)
re.Min = min
re.Max = max
@@ -228,7 +254,7 @@ func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (strin
re.Sub = re.Sub0[:1]
re.Sub[0] = sub
p.stack[n-1] = re
- return t, nil
+ return after, nil
}
// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
@@ -346,7 +372,7 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
}
// Round 1: Factor out common literal prefixes.
- var str []int
+ var str []rune
var strflags Flags
start := 0
out := sub[:0]
@@ -357,7 +383,7 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
//
// Invariant: sub[start:i] consists of regexps that all begin
// with str as modified by strflags.
- var istr []int
+ var istr []rune
var iflags Flags
if i < len(sub) {
istr, iflags = p.leadingString(sub[i])
@@ -419,8 +445,7 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
// 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.
+ // Invariant: sub[start:i] consists of regexps that all begin with ifirst.
var ifirst *Regexp
if i < len(sub) {
ifirst = p.leadingRegexp(sub[i])
@@ -441,7 +466,6 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
} 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)
@@ -522,7 +546,7 @@ func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
// 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) {
+func (p *parser) leadingString(re *Regexp) ([]rune, Flags) {
if re.Op == OpConcat && len(re.Sub) > 0 {
re = re.Sub[0]
}
@@ -605,8 +629,10 @@ func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp {
}
return re
}
- re.Op = OpEmptyMatch
- return re
+ if reuse {
+ p.reuse(re)
+ }
+ return p.newRegexp(OpEmptyMatch)
}
func literalRegexp(s string, flags Flags) *Regexp {
@@ -616,7 +642,7 @@ func literalRegexp(s string, flags Flags) *Regexp {
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)
+ re.Rune = []rune(s)
break
}
re.Rune = append(re.Rune, c)
@@ -626,7 +652,10 @@ func literalRegexp(s string, flags Flags) *Regexp {
// Parsing.
-func Parse(s string, flags Flags) (*Regexp, os.Error) {
+// Parse parses a regular expression string s, controlled by the specified
+// Flags, and returns a regular expression parse tree. The syntax is
+// described in the top-level comment for package regexp.
+func Parse(s string, flags Flags) (*Regexp, error) {
if flags&Literal != 0 {
// Trivial parser for literal string.
if err := checkUTF8(s); err != nil {
@@ -638,8 +667,8 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
// Otherwise, must do real work.
var (
p parser
- err os.Error
- c int
+ err error
+ c rune
op Op
lastRepeat string
min, max int
@@ -704,6 +733,7 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
return nil, err
}
case '*', '+', '?':
+ before := t
switch t[0] {
case '*':
op = OpStar
@@ -712,21 +742,31 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
case '?':
op = OpQuest
}
- if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil {
+ after := t[1:]
+ if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
return nil, err
}
+ repeat = before
+ t = after
case '{':
op = OpRepeat
- min, max, tt, ok := p.parseRepeat(t)
+ before := t
+ min, max, after, 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 {
+ if min < 0 || min > 1000 || max > 1000 || max >= 0 && min > max {
+ // Numbers were too big, or max is present and min > max.
+ return nil, &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]}
+ }
+ if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
return nil, err
}
+ repeat = before
+ t = after
case '\\':
if p.flags&PerlX != 0 && len(t) >= 2 {
switch t[1] {
@@ -815,12 +855,14 @@ func Parse(s string, flags Flags) (*Regexp, os.Error) {
// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}.
// If s is not of that form, it returns ok == false.
+// If s has the right form but the values are too big, it returns min == -1, ok == true.
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 {
+ var ok1 bool
+ if min, s, ok1 = p.parseInt(s); !ok1 {
return
}
if s == "" {
@@ -835,8 +877,11 @@ func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) {
}
if s[0] == '}' {
max = -1
- } else if max, s, ok = p.parseInt(s); !ok {
+ } else if max, s, ok1 = p.parseInt(s); !ok1 {
return
+ } else if max < 0 {
+ // parseInt found too big a number
+ min = -1
}
}
if s == "" || s[0] != '}' {
@@ -850,7 +895,7 @@ func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) {
// 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) {
+func (p *parser) parsePerlFlags(s string) (rest string, err error) {
t := s
// Check for named captures, first introduced in Python's regexp library.
@@ -896,7 +941,7 @@ func (p *parser) parsePerlFlags(s string) (rest string, err os.Error) {
}
// Non-capturing group. Might also twiddle Perl flags.
- var c int
+ var c rune
t = t[2:] // skip (?
flags := p.flags
sign := +1
@@ -981,16 +1026,22 @@ func (p *parser) parseInt(s string) (n int, rest string, ok bool) {
if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' {
return
}
+ t := s
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
+ // Have digits, compute value.
+ t = t[:len(t)-len(s)]
+ for i := 0; i < len(t); i++ {
+ // Avoid overflow.
+ if n >= 1e8 {
+ n = -1
+ break
+ }
+ n = n*10 + int(t[i]) - '0'
+ }
return
}
@@ -1004,7 +1055,7 @@ func isCharClass(re *Regexp) bool {
}
// does re match r?
-func matchRune(re *Regexp, r int) bool {
+func matchRune(re *Regexp, r rune) bool {
switch re.Op {
case OpLiteral:
return len(re.Rune) == 1 && re.Rune[0] == r
@@ -1024,7 +1075,7 @@ func matchRune(re *Regexp, r int) bool {
}
// parseVerticalBar handles a | in the input.
-func (p *parser) parseVerticalBar() os.Error {
+func (p *parser) parseVerticalBar() error {
p.concat()
// The concatenation we just parsed is on top of the stack.
@@ -1053,18 +1104,18 @@ func mergeCharClass(dst, src *Regexp) {
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])
+ dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags)
} else {
dst.Rune = appendClass(dst.Rune, src.Rune)
}
case OpLiteral:
// both literal
- if src.Rune[0] == dst.Rune[0] {
+ if src.Rune[0] == dst.Rune[0] && src.Flags == dst.Flags {
break
}
dst.Op = OpCharClass
- dst.Rune = append(dst.Rune, dst.Rune[0])
- dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+ dst.Rune = appendLiteral(dst.Rune[:0], dst.Rune[0], dst.Flags)
+ dst.Rune = appendLiteral(dst.Rune, src.Rune[0], src.Flags)
}
}
@@ -1107,7 +1158,7 @@ func (p *parser) swapVerticalBar() bool {
}
// parseRightParen handles a ) in the input.
-func (p *parser) parseRightParen() os.Error {
+func (p *parser) parseRightParen() error {
p.concat()
if p.swapVerticalBar() {
// pop vertical bar
@@ -1125,6 +1176,8 @@ func (p *parser) parseRightParen() os.Error {
if re2.Op != opLeftParen {
return &Error{ErrMissingParen, p.wholeRegexp}
}
+ // Restore flags at time of paren.
+ p.flags = re2.Flags
if re2.Cap == 0 {
// Just for grouping.
p.push(re1)
@@ -1139,7 +1192,7 @@ func (p *parser) parseRightParen() os.Error {
// 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) {
+func (p *parser) parseEscape(s string) (r rune, rest string, err error) {
t := s[1:]
if t == "" {
return 0, "", &Error{ErrTrailingBackslash, ""}
@@ -1174,7 +1227,7 @@ Switch:
if t == "" || t[0] < '0' || t[0] > '7' {
break
}
- r = r*8 + int(t[0]) - '0'
+ r = r*8 + rune(t[0]) - '0'
t = t[1:]
}
return r, t, nil
@@ -1255,7 +1308,7 @@ Switch:
// 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) {
+func (p *parser) parseClassChar(s, wholeClass string) (r rune, rest string, err error) {
if s == "" {
return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass}
}
@@ -1271,13 +1324,13 @@ func (p *parser) parseClassChar(s, wholeClass string) (r int, rest string, err o
type charGroup struct {
sign int
- class []int
+ class []rune
}
// 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) {
+func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest string) {
if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
return
}
@@ -1291,7 +1344,7 @@ func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string
// 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) {
+func (p *parser) parseNamedClass(s string, r []rune) (out []rune, rest string, err error) {
if len(s) < 2 || s[0] != '[' || s[1] != ':' {
return
}
@@ -1309,7 +1362,7 @@ func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err
return p.appendGroup(r, g), s, nil
}
-func (p *parser) appendGroup(r []int, g charGroup) []int {
+func (p *parser) appendGroup(r []rune, g charGroup) []rune {
if p.flags&FoldCase == 0 {
if g.sign < 0 {
r = appendNegatedClass(r, g.class)
@@ -1330,9 +1383,18 @@ func (p *parser) appendGroup(r []int, g charGroup) []int {
return r
}
+var anyTable = &unicode.RangeTable{
+ R16: []unicode.Range16{{Lo: 0, Hi: 1<<16 - 1, Stride: 1}},
+ R32: []unicode.Range32{{Lo: 1 << 16, Hi: unicode.MaxRune, Stride: 1}},
+}
+
// unicodeTable returns the unicode.RangeTable identified by name
// and the table of additional fold-equivalent code points.
func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
+ // Special case: "Any" means any.
+ if name == "Any" {
+ return anyTable, anyTable
+ }
if t := unicode.Categories[name]; t != nil {
return t, unicode.FoldCategory[name]
}
@@ -1345,7 +1407,7 @@ func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
// 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) {
+func (p *parser) parseUnicodeClass(s string, r []rune) (out []rune, rest string, err error) {
if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
return
}
@@ -1418,7 +1480,7 @@ func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, e
// 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) {
+func (p *parser) parseClass(s string) (rest string, err error) {
t := s[1:] // chop [
re := p.newRegexp(OpCharClass)
re.Flags = p.flags
@@ -1477,7 +1539,7 @@ func (p *parser) parseClass(s string) (rest string, err os.Error) {
// Single character or simple range.
rng := t
- var lo, hi int
+ var lo, hi rune
if lo, t, err = p.parseClassChar(t, s); err != nil {
return "", err
}
@@ -1514,7 +1576,7 @@ func (p *parser) parseClass(s string) (rest string, err os.Error) {
// cleanClass sorts the ranges (pairs of elements of r),
// merges them, and eliminates duplicates.
-func cleanClass(rp *[]int) []int {
+func cleanClass(rp *[]rune) []rune {
// Sort by lo increasing, hi decreasing to break ties.
sort.Sort(ranges{rp})
@@ -1544,8 +1606,16 @@ func cleanClass(rp *[]int) []int {
return r[:w]
}
+// appendLiteral returns the result of appending the literal x to the class r.
+func appendLiteral(r []rune, x rune, flags Flags) []rune {
+ if flags&FoldCase != 0 {
+ return appendFoldedRange(r, x, x)
+ }
+ return appendRange(r, x, x)
+}
+
// appendRange returns the result of appending the range lo-hi to the class r.
-func appendRange(r []int, lo, hi int) []int {
+func appendRange(r []rune, lo, hi rune) []rune {
// 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
@@ -1578,7 +1648,7 @@ const (
// 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 {
+func appendFoldedRange(r []rune, lo, hi rune) []rune {
// Optimizations.
if lo <= minFold && hi >= maxFold {
// Range is full: folding can't add more.
@@ -1613,7 +1683,7 @@ func appendFoldedRange(r []int, lo, hi int) []int {
// 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 {
+func appendClass(r []rune, x []rune) []rune {
for i := 0; i < len(x); i += 2 {
r = appendRange(r, x[i], x[i+1])
}
@@ -1621,7 +1691,7 @@ func appendClass(r []int, x []int) []int {
}
// appendFolded returns the result of appending the case folding of the class x to the class r.
-func appendFoldedClass(r []int, x []int) []int {
+func appendFoldedClass(r []rune, x []rune) []rune {
for i := 0; i < len(x); i += 2 {
r = appendFoldedRange(r, x[i], x[i+1])
}
@@ -1630,8 +1700,8 @@ func appendFoldedClass(r []int, x []int) []int {
// 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
+func appendNegatedClass(r []rune, x []rune) []rune {
+ nextLo := '\u0000'
for i := 0; i < len(x); i += 2 {
lo, hi := x[i], x[i+1]
if nextLo <= lo-1 {
@@ -1646,9 +1716,9 @@ func appendNegatedClass(r []int, x []int) []int {
}
// appendTable returns the result of appending x to the class r.
-func appendTable(r []int, x *unicode.RangeTable) []int {
+func appendTable(r []rune, x *unicode.RangeTable) []rune {
for _, xr := range x.R16 {
- lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride)
if stride == 1 {
r = appendRange(r, lo, hi)
continue
@@ -1658,7 +1728,7 @@ func appendTable(r []int, x *unicode.RangeTable) []int {
}
}
for _, xr := range x.R32 {
- lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride)
if stride == 1 {
r = appendRange(r, lo, hi)
continue
@@ -1671,10 +1741,10 @@ func appendTable(r []int, x *unicode.RangeTable) []int {
}
// 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
+func appendNegatedTable(r []rune, x *unicode.RangeTable) []rune {
+ nextLo := '\u0000' // lo end of next class to add
for _, xr := range x.R16 {
- lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride)
if stride == 1 {
if nextLo <= lo-1 {
r = appendRange(r, nextLo, lo-1)
@@ -1690,7 +1760,7 @@ func appendNegatedTable(r []int, x *unicode.RangeTable) []int {
}
}
for _, xr := range x.R32 {
- lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ lo, hi, stride := rune(xr.Lo), rune(xr.Hi), rune(xr.Stride)
if stride == 1 {
if nextLo <= lo-1 {
r = appendRange(r, nextLo, lo-1)
@@ -1713,9 +1783,9 @@ func appendNegatedTable(r []int, x *unicode.RangeTable) []int {
// 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
+func negateClass(r []rune) []rune {
+ nextLo := '\u0000' // 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 {
@@ -1737,9 +1807,9 @@ func negateClass(r []int) []int {
// 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.
+// a *[]rune.
type ranges struct {
- p *[]int
+ p *[]rune
}
func (ra ranges) Less(i, j int) bool {
@@ -1760,7 +1830,7 @@ func (ra ranges) Swap(i, j int) {
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 {
+func checkUTF8(s string) error {
for s != "" {
rune, size := utf8.DecodeRuneInString(s)
if rune == utf8.RuneError && size == 1 {
@@ -1771,7 +1841,7 @@ func checkUTF8(s string) os.Error {
return nil
}
-func nextRune(s string) (c int, t string, err os.Error) {
+func nextRune(s string) (c rune, t string, err error) {
c, size := utf8.DecodeRuneInString(s)
if c == utf8.RuneError && size == 1 {
return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s}
@@ -1779,11 +1849,11 @@ func nextRune(s string) (c int, t string, err os.Error) {
return c, s[size:], nil
}
-func isalnum(c int) bool {
+func isalnum(c rune) bool {
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
}
-func unhex(c int) int {
+func unhex(c rune) rune {
if '0' <= c && c <= '9' {
return c - '0'
}
diff --git a/src/pkg/exp/regexp/syntax/parse_test.go b/src/pkg/regexp/syntax/parse_test.go
index 779b9afde..c6e63392c 100644
--- a/src/pkg/exp/regexp/syntax/parse_test.go
+++ b/src/pkg/regexp/syntax/parse_test.go
@@ -11,10 +11,12 @@ import (
"unicode"
)
-var parseTests = []struct {
+type parseTest struct {
Regexp string
Dump string
-}{
+}
+
+var parseTests = []parseTest{
// Base cases
{`a`, `lit{a}`},
{`a.`, `cat{lit{a}dot{}}`},
@@ -38,6 +40,12 @@ var parseTests = []struct {
{`a{2}?`, `nrep{2,2 lit{a}}`},
{`a{2,3}?`, `nrep{2,3 lit{a}}`},
{`a{2,}?`, `nrep{2,-1 lit{a}}`},
+ // Malformed { } are treated as literals.
+ {`x{1001`, `str{x{1001}`},
+ {`x{9876543210`, `str{x{9876543210}`},
+ {`x{9876543210,`, `str{x{9876543210,}`},
+ {`x{2,1`, `str{x{2,1}`},
+ {`x{1,9876543210`, `str{x{1,9876543210}`},
{``, `emp{}`},
{`|`, `emp{}`}, // alt{emp{}emp{}} but got factored
{`|x|`, `alt{emp{}lit{x}emp{}}`},
@@ -101,6 +109,8 @@ var parseTests = []struct {
{`\p{Lu}`, mkCharClass(unicode.IsUpper)},
{`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
{`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
+ {`\p{Any}`, `dot{}`},
+ {`\p{^Any}`, `cc{}`},
// Hex, octal.
{`[\012-\234]\141`, `cat{cc{0xa-0x9c}lit{a}}`},
@@ -162,14 +172,92 @@ var parseTests = []struct {
// 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}}}}`},
+
+ // Bug fixes.
+ {`(?:.)`, `dot{}`},
+ {`(?:x|(?:xa))`, `cat{lit{x}alt{emp{}lit{a}}}`},
+ {`(?:.|(?:.a))`, `cat{dot{}alt{emp{}lit{a}}}`},
+ {`(?:A(?:A|a))`, `cat{lit{A}litfold{A}}`},
+ {`(?:A|a)`, `litfold{A}`},
+ {`A|(?:A|a)`, `litfold{A}`},
+ {`(?s).`, `dot{}`},
+ {`(?-s).`, `dnl{}`},
+ {`(?:(?:^).)`, `cat{bol{}dot{}}`},
+ {`(?-s)(?:(?:^).)`, `cat{bol{}dnl{}}`},
+
+ // RE2 prefix_tests
+ {`abc|abd`, `cat{str{ab}cc{0x63-0x64}}`},
+ {`a(?:b)c|abd`, `cat{str{ab}cc{0x63-0x64}}`},
+ {`abc|abd|aef|bcx|bcy`,
+ `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}` +
+ `cat{str{bc}cc{0x78-0x79}}}`},
+ {`abc|x|abd`, `alt{str{abc}lit{x}str{abd}}`},
+ {`(?i)abc|ABD`, `cat{strfold{AB}cc{0x43-0x44 0x63-0x64}}`},
+ {`[ab]c|[ab]d`, `cat{cc{0x61-0x62}cc{0x63-0x64}}`},
+ {`(?:xx|yy)c|(?:xx|yy)d`,
+ `cat{alt{str{xx}str{yy}}cc{0x63-0x64}}`},
+ {`x{2}|x{2}[0-9]`,
+ `cat{rep{2,2 lit{x}}alt{emp{}cc{0x30-0x39}}}`},
+ {`x{2}y|x{2}[0-9]y`,
+ `cat{rep{2,2 lit{x}}alt{lit{y}cat{cc{0x30-0x39}lit{y}}}}`},
}
const testFlags = MatchNL | PerlX | UnicodeGroups
+func TestParseSimple(t *testing.T) {
+ testParseDump(t, parseTests, testFlags)
+}
+
+var foldcaseTests = []parseTest{
+ {`AbCdE`, `strfold{ABCDE}`},
+ {`[Aa]`, `litfold{A}`},
+ {`a`, `litfold{A}`},
+
+ // 0x17F is an old English long s (looks like an f) and folds to s.
+ // 0x212A is the Kelvin symbol and folds to k.
+ {`A[F-g]`, `cat{litfold{A}cc{0x41-0x7a 0x17f 0x212a}}`}, // [Aa][A-z...]
+ {`[[:upper:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+ {`[[:lower:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+}
+
+func TestParseFoldCase(t *testing.T) {
+ testParseDump(t, foldcaseTests, FoldCase)
+}
+
+var literalTests = []parseTest{
+ {"(|)^$.[*+?]{5,10},\\", "str{(|)^$.[*+?]{5,10},\\}"},
+}
+
+func TestParseLiteral(t *testing.T) {
+ testParseDump(t, literalTests, Literal)
+}
+
+var matchnlTests = []parseTest{
+ {`.`, `dot{}`},
+ {"\n", "lit{\n}"},
+ {`[^a]`, `cc{0x0-0x60 0x62-0x10ffff}`},
+ {`[a\n]`, `cc{0xa 0x61}`},
+}
+
+func TestParseMatchNL(t *testing.T) {
+ testParseDump(t, matchnlTests, MatchNL)
+}
+
+var nomatchnlTests = []parseTest{
+ {`.`, `dnl{}`},
+ {"\n", "lit{\n}"},
+ {`[^a]`, `cc{0x0-0x9 0xb-0x60 0x62-0x10ffff}`},
+ {`[a\n]`, `cc{0xa 0x61}`},
+}
+
+func TestParseNoMatchNL(t *testing.T) {
+ testParseDump(t, nomatchnlTests, 0)
+}
+
// Test Parse -> Dump.
-func TestParseDump(t *testing.T) {
- for _, tt := range parseTests {
- re, err := Parse(tt.Regexp, testFlags)
+func testParseDump(t *testing.T, tests []parseTest, flags Flags) {
+ for _, tt := range tests {
+ re, err := Parse(tt.Regexp, flags)
if err != nil {
t.Errorf("Parse(%#q): %v", tt.Regexp, err)
continue
@@ -283,10 +371,10 @@ func dumpRegexp(b *bytes.Buffer, re *Regexp) {
b.WriteByte('}')
}
-func mkCharClass(f func(int) bool) string {
+func mkCharClass(f func(rune) bool) string {
re := &Regexp{Op: OpCharClass}
- lo := -1
- for i := 0; i <= unicode.MaxRune; i++ {
+ lo := rune(-1)
+ for i := rune(0); i <= unicode.MaxRune; i++ {
if f(i) {
if lo < 0 {
lo = i
@@ -304,12 +392,12 @@ func mkCharClass(f func(int) bool) string {
return dump(re)
}
-func isUpperFold(rune int) bool {
- if unicode.IsUpper(rune) {
+func isUpperFold(r rune) bool {
+ if unicode.IsUpper(r) {
return true
}
- c := unicode.SimpleFold(rune)
- for c != rune {
+ c := unicode.SimpleFold(r)
+ for c != r {
if unicode.IsUpper(c) {
return true
}
@@ -319,8 +407,8 @@ func isUpperFold(rune int) bool {
}
func TestFoldConstants(t *testing.T) {
- last := -1
- for i := 0; i <= unicode.MaxRune; i++ {
+ last := rune(-1)
+ for i := rune(0); i <= unicode.MaxRune; i++ {
if unicode.SimpleFold(i) == i {
continue
}
@@ -339,8 +427,8 @@ func TestAppendRangeCollapse(t *testing.T) {
// 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++ {
+ var r []rune
+ for i := rune('A'); i <= 'Z'; i++ {
r = appendRange(r, i, i)
r = appendRange(r, i+'a'-'A', i+'a'-'A')
}
@@ -348,3 +436,116 @@ func TestAppendRangeCollapse(t *testing.T) {
t.Errorf("appendRange interlaced A-Z a-z = %s, want AZaz", string(r))
}
}
+
+var invalidRegexps = []string{
+ `(`,
+ `)`,
+ `(a`,
+ `(a|b|`,
+ `(a|b`,
+ `[a-z`,
+ `([a-z)`,
+ `x{1001}`,
+ `x{9876543210}`,
+ `x{2,1}`,
+ `x{1,9876543210}`,
+ "\xff", // Invalid UTF-8
+ "[\xff]",
+ "[\\\xff]",
+ "\\\xff",
+ `(?P<name>a`,
+ `(?P<name>`,
+ `(?P<name`,
+ `(?P<x y>a)`,
+ `(?P<>a)`,
+ `[a-Z]`,
+ `(?i)[a-Z]`,
+ `a{100000}`,
+ `a{100000,}`,
+}
+
+var onlyPerl = []string{
+ `[a-b-c]`,
+ `\Qabc\E`,
+ `\Q*+?{[\E`,
+ `\Q\\E`,
+ `\Q\\\E`,
+ `\Q\\\\E`,
+ `\Q\\\\\E`,
+ `(?:a)`,
+ `(?P<name>a)`,
+}
+
+var onlyPOSIX = []string{
+ "a++",
+ "a**",
+ "a?*",
+ "a+*",
+ "a{1}*",
+ ".{1}{2}.{3}",
+}
+
+func TestParseInvalidRegexps(t *testing.T) {
+ for _, regexp := range invalidRegexps {
+ if re, err := Parse(regexp, Perl); err == nil {
+ t.Errorf("Parse(%#q, Perl) = %s, should have failed", regexp, dump(re))
+ }
+ if re, err := Parse(regexp, POSIX); err == nil {
+ t.Errorf("Parse(%#q, POSIX) = %s, should have failed", regexp, dump(re))
+ }
+ }
+ for _, regexp := range onlyPerl {
+ if _, err := Parse(regexp, Perl); err != nil {
+ t.Errorf("Parse(%#q, Perl): %v", regexp, err)
+ }
+ if re, err := Parse(regexp, POSIX); err == nil {
+ t.Errorf("Parse(%#q, POSIX) = %s, should have failed", regexp, dump(re))
+ }
+ }
+ for _, regexp := range onlyPOSIX {
+ if re, err := Parse(regexp, Perl); err == nil {
+ t.Errorf("Parse(%#q, Perl) = %s, should have failed", regexp, dump(re))
+ }
+ if _, err := Parse(regexp, POSIX); err != nil {
+ t.Errorf("Parse(%#q, POSIX): %v", regexp, err)
+ }
+ }
+}
+
+func TestToStringEquivalentParse(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)
+ continue
+ }
+
+ s := re.String()
+ if s != tt.Regexp {
+ // If ToString didn't return the original regexp,
+ // it must have found one with fewer parens.
+ // Unfortunately we can't check the length here, because
+ // ToString produces "\\{" for a literal brace,
+ // but "{" is a shorter equivalent in some contexts.
+ nre, err := Parse(s, testFlags)
+ if err != nil {
+ t.Errorf("Parse(%#q.String() = %#q): %v", tt.Regexp, t, err)
+ continue
+ }
+ nd := dump(nre)
+ if d != nd {
+ t.Errorf("Parse(%#q) -> %#q; %#q vs %#q", tt.Regexp, s, d, nd)
+ }
+
+ ns := nre.String()
+ if s != ns {
+ t.Errorf("Parse(%#q) -> %#q -> %#q", tt.Regexp, s, ns)
+ }
+ }
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/perl_groups.go b/src/pkg/regexp/syntax/perl_groups.go
index 05b392c40..1a11ca62f 100644
--- a/src/pkg/exp/regexp/syntax/perl_groups.go
+++ b/src/pkg/regexp/syntax/perl_groups.go
@@ -3,17 +3,17 @@
package syntax
-var code1 = []int{ /* \d */
+var code1 = []rune{ /* \d */
0x30, 0x39,
}
-var code2 = []int{ /* \s */
+var code2 = []rune{ /* \s */
0x9, 0xa,
0xc, 0xd,
0x20, 0x20,
}
-var code3 = []int{ /* \w */
+var code3 = []rune{ /* \w */
0x30, 0x39,
0x41, 0x5a,
0x5f, 0x5f,
@@ -28,71 +28,71 @@ var perlGroup = map[string]charGroup{
`\w`: {+1, code3},
`\W`: {-1, code3},
}
-var code4 = []int{ /* [:alnum:] */
+var code4 = []rune{ /* [:alnum:] */
0x30, 0x39,
0x41, 0x5a,
0x61, 0x7a,
}
-var code5 = []int{ /* [:alpha:] */
+var code5 = []rune{ /* [:alpha:] */
0x41, 0x5a,
0x61, 0x7a,
}
-var code6 = []int{ /* [:ascii:] */
+var code6 = []rune{ /* [:ascii:] */
0x0, 0x7f,
}
-var code7 = []int{ /* [:blank:] */
+var code7 = []rune{ /* [:blank:] */
0x9, 0x9,
0x20, 0x20,
}
-var code8 = []int{ /* [:cntrl:] */
+var code8 = []rune{ /* [:cntrl:] */
0x0, 0x1f,
0x7f, 0x7f,
}
-var code9 = []int{ /* [:digit:] */
+var code9 = []rune{ /* [:digit:] */
0x30, 0x39,
}
-var code10 = []int{ /* [:graph:] */
+var code10 = []rune{ /* [:graph:] */
0x21, 0x7e,
}
-var code11 = []int{ /* [:lower:] */
+var code11 = []rune{ /* [:lower:] */
0x61, 0x7a,
}
-var code12 = []int{ /* [:print:] */
+var code12 = []rune{ /* [:print:] */
0x20, 0x7e,
}
-var code13 = []int{ /* [:punct:] */
+var code13 = []rune{ /* [:punct:] */
0x21, 0x2f,
0x3a, 0x40,
0x5b, 0x60,
0x7b, 0x7e,
}
-var code14 = []int{ /* [:space:] */
+var code14 = []rune{ /* [:space:] */
0x9, 0xd,
0x20, 0x20,
}
-var code15 = []int{ /* [:upper:] */
+var code15 = []rune{ /* [:upper:] */
0x41, 0x5a,
}
-var code16 = []int{ /* [:word:] */
+var code16 = []rune{ /* [:word:] */
0x30, 0x39,
0x41, 0x5a,
0x5f, 0x5f,
0x61, 0x7a,
}
-var code17 = []int{ /* [:xdigit:] */
+var code17 = []rune{ /* [:xdigit:] */
0x30, 0x39,
0x41, 0x46,
0x61, 0x66,
diff --git a/src/pkg/exp/regexp/syntax/prog.go b/src/pkg/regexp/syntax/prog.go
index bf85b720d..902d3b3a5 100644
--- a/src/pkg/exp/regexp/syntax/prog.go
+++ b/src/pkg/regexp/syntax/prog.go
@@ -1,8 +1,13 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package syntax
import (
"bytes"
"strconv"
+ "unicode"
)
// Compiled program.
@@ -27,6 +32,9 @@ const (
InstFail
InstNop
InstRune
+ InstRune1
+ InstRuneAny
+ InstRuneAnyNotNL
)
// An EmptyOp specifies a kind or mixture of zero-width assertions.
@@ -41,12 +49,47 @@ const (
EmptyNoWordBoundary
)
+// EmptyOpContext returns the zero-width assertions
+// satisfied at the position between the runes r1 and r2.
+// Passing r1 == -1 indicates that the position is
+// at the beginning of the text.
+// Passing r2 == -1 indicates that the position is
+// at the end of the text.
+func EmptyOpContext(r1, r2 rune) EmptyOp {
+ var op EmptyOp
+ if r1 < 0 {
+ op |= EmptyBeginText | EmptyBeginLine
+ }
+ if r1 == '\n' {
+ op |= EmptyBeginLine
+ }
+ if r2 < 0 {
+ op |= EmptyEndText | EmptyEndLine
+ }
+ if r2 == '\n' {
+ op |= EmptyEndLine
+ }
+ if IsWordChar(r1) != IsWordChar(r2) {
+ op |= EmptyWordBoundary
+ } else {
+ op |= EmptyNoWordBoundary
+ }
+ return op
+}
+
+// IsWordChar reports whether r is consider a ``word character''
+// during the evaluation of the \b and \B zero-width assertions.
+// These assertions are ASCII-only: the word characters are [A-Za-z0-9_].
+func IsWordChar(r rune) bool {
+ return 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' || '0' <= r && r <= '9' || r == '_'
+}
+
// 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
+ Rune []rune
}
func (p *Prog) String() string {
@@ -66,6 +109,16 @@ func (p *Prog) skipNop(pc uint32) *Inst {
return i
}
+// op returns i.Op but merges all the Rune special cases into InstRune
+func (i *Inst) op() InstOp {
+ op := i.Op
+ switch op {
+ case InstRune1, InstRuneAny, InstRuneAnyNotNL:
+ op = InstRune
+ }
+ return op
+}
+
// Prefix returns a literal string that all matches for the
// regexp must start with. Complete is true if the prefix
// is the entire match.
@@ -73,13 +126,13 @@ 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 {
+ 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 {
+ for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 {
buf.WriteRune(i.Rune[0])
i = p.skipNop(i.Out)
}
@@ -112,13 +165,23 @@ Loop:
// 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 {
+func (i *Inst) MatchRune(r rune) 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]
+ r0 := rune[0]
+ if r == r0 {
+ return true
+ }
+ if Flags(i.Arg)&FoldCase != 0 {
+ for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+ if r == r1 {
+ return true
+ }
+ }
+ }
+ return false
}
// Peek at the first few pairs.
@@ -151,17 +214,17 @@ func (i *Inst) MatchRune(r int) bool {
// 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')
+func wordRune(r rune) bool {
+ return r == '_' ||
+ ('A' <= r && r <= 'Z') ||
+ ('a' <= r && r <= 'z') ||
+ ('0' <= r && r <= '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 {
+func (i *Inst) MatchEmptyWidth(before rune, after rune) bool {
switch EmptyOp(i.Arg) {
case EmptyBeginLine:
return before == '\n' || before == -1
@@ -208,7 +271,7 @@ func dumpProg(b *bytes.Buffer, p *Prog) {
}
func u32(i uint32) string {
- return strconv.Uitoa64(uint64(i))
+ return strconv.FormatUint(uint64(i), 10)
}
func dumpInst(b *bytes.Buffer, i *Inst) {
@@ -232,6 +295,16 @@ func dumpInst(b *bytes.Buffer, i *Inst) {
// shouldn't happen
bw(b, "rune <nil>")
}
- bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+ bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)))
+ if Flags(i.Arg)&FoldCase != 0 {
+ bw(b, "/i")
+ }
+ bw(b, " -> ", u32(i.Out))
+ case InstRune1:
+ bw(b, "rune1 ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+ case InstRuneAny:
+ bw(b, "any -> ", u32(i.Out))
+ case InstRuneAnyNotNL:
+ bw(b, "anynotnl -> ", u32(i.Out))
}
}
diff --git a/src/pkg/exp/regexp/syntax/prog_test.go b/src/pkg/regexp/syntax/prog_test.go
index 7be4281c2..663d5a8d7 100644
--- a/src/pkg/exp/regexp/syntax/prog_test.go
+++ b/src/pkg/regexp/syntax/prog_test.go
@@ -1,3 +1,7 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package syntax
import (
@@ -9,7 +13,7 @@ var compileTests = []struct {
Prog string
}{
{"a", ` 0 fail
- 1* rune "a" -> 2
+ 1* rune1 "a" -> 2
2 match
`},
{"[A-M][n-z]", ` 0 fail
@@ -22,61 +26,71 @@ var compileTests = []struct {
2 match
`},
{"a?", ` 0 fail
- 1 rune "a" -> 3
+ 1 rune1 "a" -> 3
2* alt -> 1, 3
3 match
`},
{"a??", ` 0 fail
- 1 rune "a" -> 3
+ 1 rune1 "a" -> 3
2* alt -> 3, 1
3 match
`},
{"a+", ` 0 fail
- 1* rune "a" -> 2
+ 1* rune1 "a" -> 2
2 alt -> 1, 3
3 match
`},
{"a+?", ` 0 fail
- 1* rune "a" -> 2
+ 1* rune1 "a" -> 2
2 alt -> 3, 1
3 match
`},
{"a*", ` 0 fail
- 1 rune "a" -> 2
+ 1 rune1 "a" -> 2
2* alt -> 1, 3
3 match
`},
{"a*?", ` 0 fail
- 1 rune "a" -> 2
+ 1 rune1 "a" -> 2
2* alt -> 3, 1
3 match
`},
{"a+b+", ` 0 fail
- 1* rune "a" -> 2
+ 1* rune1 "a" -> 2
2 alt -> 1, 3
- 3 rune "b" -> 4
+ 3 rune1 "b" -> 4
4 alt -> 3, 5
5 match
`},
{"(a+)(b+)", ` 0 fail
1* cap 2 -> 2
- 2 rune "a" -> 3
+ 2 rune1 "a" -> 3
3 alt -> 2, 4
4 cap 3 -> 5
5 cap 4 -> 6
- 6 rune "b" -> 7
+ 6 rune1 "b" -> 7
7 alt -> 6, 8
8 cap 5 -> 9
9 match
`},
{"a+|b+", ` 0 fail
- 1 rune "a" -> 2
+ 1 rune1 "a" -> 2
2 alt -> 1, 6
- 3 rune "b" -> 4
+ 3 rune1 "b" -> 4
4 alt -> 3, 6
5* alt -> 1, 3
6 match
`},
+ {"A[Aa]", ` 0 fail
+ 1* rune1 "A" -> 2
+ 2 rune "A"/i -> 3
+ 3 match
+`},
+ {"(?:(?:^).)", ` 0 fail
+ 1* empty 4 -> 2
+ 2 anynotnl -> 3
+ 3 match
+`},
}
func TestCompile(t *testing.T) {
diff --git a/src/pkg/exp/regexp/syntax/regexp.go b/src/pkg/regexp/syntax/regexp.go
index 00a4addef..329a90e01 100644
--- a/src/pkg/exp/regexp/syntax/regexp.go
+++ b/src/pkg/regexp/syntax/regexp.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.
-// Package syntax parses regular expressions into syntax trees.
-// WORK IN PROGRESS.
package syntax
// Note to implementers:
@@ -22,8 +20,8 @@ type Regexp struct {
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
+ Rune []rune // matched runes, for OpLiteral, OpCharClass
+ Rune0 [2]rune // storage for short Rune
Min, Max int // min, max for OpRepeat
Cap int // capturing index, for OpCapture
Name string // capturing name, for OpCapture
@@ -164,9 +162,9 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
}
b.WriteRune(']')
case OpAnyCharNotNL:
- b.WriteString(`[^\n]`)
+ b.WriteString(`(?-s:.)`)
case OpAnyChar:
- b.WriteRune('.')
+ b.WriteString(`(?s:.)`)
case OpBeginLine:
b.WriteRune('^')
case OpEndLine:
@@ -174,7 +172,11 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
case OpBeginText:
b.WriteString(`\A`)
case OpEndText:
- b.WriteString(`\z`)
+ if re.Flags&WasDollar != 0 {
+ b.WriteString(`(?-m:$)`)
+ } else {
+ b.WriteString(`\z`)
+ }
case OpWordBoundary:
b.WriteString(`\b`)
case OpNoWordBoundary:
@@ -192,7 +194,7 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
}
b.WriteRune(')')
case OpStar, OpPlus, OpQuest, OpRepeat:
- if sub := re.Sub[0]; sub.Op > OpCapture {
+ if sub := re.Sub[0]; sub.Op > OpCapture || sub.Op == OpLiteral && len(sub.Rune) > 1 {
b.WriteString(`(?:`)
writeRegexp(b, sub)
b.WriteString(`)`)
@@ -217,6 +219,9 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
}
b.WriteRune('}')
}
+ if re.Flags&NonGreedy != 0 {
+ b.WriteRune('?')
+ }
case OpConcat:
for _, sub := range re.Sub {
if sub.Op == OpAlternate {
@@ -245,7 +250,7 @@ func (re *Regexp) String() string {
const meta = `\.+*?()|[]{}^$`
-func escape(b *bytes.Buffer, r int, force bool) {
+func escape(b *bytes.Buffer, r rune, force bool) {
if unicode.IsPrint(r) {
if strings.IndexRune(meta, r) >= 0 || force {
b.WriteRune('\\')
@@ -270,7 +275,7 @@ func escape(b *bytes.Buffer, r int, force bool) {
default:
if r < 0x100 {
b.WriteString(`\x`)
- s := strconv.Itob(r, 16)
+ s := strconv.FormatInt(int64(r), 16)
if len(s) == 1 {
b.WriteRune('0')
}
@@ -278,7 +283,37 @@ func escape(b *bytes.Buffer, r int, force bool) {
break
}
b.WriteString(`\x{`)
- b.WriteString(strconv.Itob(r, 16))
+ b.WriteString(strconv.FormatInt(int64(r), 16))
b.WriteString(`}`)
}
}
+
+// MaxCap walks the regexp to find the maximum capture index.
+func (re *Regexp) MaxCap() int {
+ m := 0
+ if re.Op == OpCapture {
+ m = re.Cap
+ }
+ for _, sub := range re.Sub {
+ if n := sub.MaxCap(); m < n {
+ m = n
+ }
+ }
+ return m
+}
+
+// CapNames walks the regexp to find the names of capturing groups.
+func (re *Regexp) CapNames() []string {
+ names := make([]string, re.MaxCap()+1)
+ re.capNames(names)
+ return names
+}
+
+func (re *Regexp) capNames(names []string) {
+ if re.Op == OpCapture {
+ names[re.Cap] = re.Name
+ }
+ for _, sub := range re.Sub {
+ sub.capNames(names)
+ }
+}
diff --git a/src/pkg/exp/regexp/syntax/simplify.go b/src/pkg/regexp/syntax/simplify.go
index 72390417b..72390417b 100644
--- a/src/pkg/exp/regexp/syntax/simplify.go
+++ b/src/pkg/regexp/syntax/simplify.go
diff --git a/src/pkg/exp/regexp/syntax/simplify_test.go b/src/pkg/regexp/syntax/simplify_test.go
index c8cec2183..879eff5be 100644
--- a/src/pkg/exp/regexp/syntax/simplify_test.go
+++ b/src/pkg/regexp/syntax/simplify_test.go
@@ -18,7 +18,7 @@ var simplifyTests = []struct {
{`(ab)*`, `(ab)*`},
{`(ab)+`, `(ab)+`},
{`(ab)?`, `(ab)?`},
- {`.`, `.`},
+ {`.`, `(?s:.)`},
{`^`, `^`},
{`$`, `$`},
{`[ac]`, `[ac]`},
@@ -97,22 +97,22 @@ var simplifyTests = []struct {
{`[^[:cntrl:][:^cntrl:]]`, `[^\x00-\x{10FFFF}]`},
// Full character classes
- {`[[:cntrl:][:^cntrl:]]`, `.`},
+ {`[[:cntrl:][:^cntrl:]]`, `(?s:.)`},
// Unicode case folding.
{`(?i)A`, `(?i:A)`},
- {`(?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`, `(?i:K)`},
+ {`(?i)\x{212a}`, "(?i:K)"},
{`(?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}]`, `.`},
+ {`(?i)[\x00-\x{10FFFF}]`, `(?s:.)`},
// Empty string as a regular expression.
// The empty string must be preserved inside parens in order
diff --git a/src/pkg/regexp/testdata/README b/src/pkg/regexp/testdata/README
new file mode 100644
index 000000000..b1b301be8
--- /dev/null
+++ b/src/pkg/regexp/testdata/README
@@ -0,0 +1,23 @@
+AT&T POSIX Test Files
+See textregex.c for copyright + license.
+
+testregex.c http://www2.research.att.com/~gsf/testregex/testregex.c
+basic.dat http://www2.research.att.com/~gsf/testregex/basic.dat
+nullsubexpr.dat http://www2.research.att.com/~gsf/testregex/nullsubexpr.dat
+repetition.dat http://www2.research.att.com/~gsf/testregex/repetition.dat
+
+The test data has been edited to reflect RE2/Go differences:
+ * In a star of a possibly empty match like (a*)* matching x,
+ the no match case runs the starred subexpression zero times,
+ not once. This is consistent with (a*)* matching a, which
+ runs the starred subexpression one time, not twice.
+ * The submatch choice is first match, not the POSIX rule.
+
+Such changes are marked with 'RE2/Go'.
+
+
+RE2 Test Files
+
+re2-exhaustive.txt.bz2 and re2-search.txt are built by running
+'make log' in the RE2 distribution. http://code.google.com/p/re2/.
+The exhaustive file is compressed because it is huge.
diff --git a/src/pkg/regexp/testdata/basic.dat b/src/pkg/regexp/testdata/basic.dat
new file mode 100644
index 000000000..7859290ba
--- /dev/null
+++ b/src/pkg/regexp/testdata/basic.dat
@@ -0,0 +1,221 @@
+NOTE all standard compliant implementations should pass these : 2002-05-31
+
+BE abracadabra$ abracadabracadabra (7,18)
+BE a...b abababbb (2,7)
+BE XXXXXX ..XXXXXX (2,8)
+E \) () (1,2)
+BE a] a]a (0,2)
+B } } (0,1)
+E \} } (0,1)
+BE \] ] (0,1)
+B ] ] (0,1)
+E ] ] (0,1)
+B { { (0,1)
+B } } (0,1)
+BE ^a ax (0,1)
+BE \^a a^a (1,3)
+BE a\^ a^ (0,2)
+BE a$ aa (1,2)
+BE a\$ a$ (0,2)
+BE ^$ NULL (0,0)
+E $^ NULL (0,0)
+E a($) aa (1,2)(2,2)
+E a*(^a) aa (0,1)(0,1)
+E (..)*(...)* a (0,0)
+E (..)*(...)* abcd (0,4)(2,4)
+E (ab|a)(bc|c) abc (0,3)(0,2)(2,3)
+E (ab)c|abc abc (0,3)(0,2)
+E a{0}b ab (1,2)
+E (a*)(b?)(b+)b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
+E (a*)(b{0,1})(b{1,})b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7)
+E a{9876543210} NULL BADBR
+E ((a|a)|a) a (0,1)(0,1)(0,1)
+E (a*)(a|aa) aaaa (0,4)(0,3)(3,4)
+E a*(a.|aa) aaaa (0,4)(2,4)
+E a(b)|c(d)|a(e)f aef (0,3)(?,?)(?,?)(1,2)
+E (a|b)?.* b (0,1)(0,1)
+E (a|b)c|a(b|c) ac (0,2)(0,1)
+E (a|b)c|a(b|c) ab (0,2)(?,?)(1,2)
+E (a|b)*c|(a|ab)*c abc (0,3)(1,2)
+E (a|b)*c|(a|ab)*c xc (1,2)
+E (.a|.b).*|.*(.a|.b) xa (0,2)(0,2)
+E a?(ab|ba)ab abab (0,4)(0,2)
+E a?(ac{0}b|ba)ab abab (0,4)(0,2)
+E ab|abab abbabab (0,2)
+E aba|bab|bba baaabbbaba (5,8)
+E aba|bab baaabbbaba (6,9)
+E (aa|aaa)*|(a|aaaaa) aa (0,2)(0,2)
+E (a.|.a.)*|(a|.a...) aa (0,2)(0,2)
+E ab|a xabc (1,3)
+E ab|a xxabc (2,4)
+Ei (Ab|cD)* aBcD (0,4)(2,4)
+BE [^-] --a (2,3)
+BE [a-]* --a (0,3)
+BE [a-m-]* --amoma-- (0,4)
+E :::1:::0:|:::1:1:0: :::0:::1:::1:::0: (8,17)
+E :::1:::0:|:::1:1:1: :::0:::1:::1:::0: (8,17)
+{E [[:upper:]] A (0,1) [[<element>]] not supported
+E [[:lower:]]+ `az{ (1,3)
+E [[:upper:]]+ @AZ[ (1,3)
+# No collation in Go
+#BE [[-]] [[-]] (2,4)
+#BE [[.NIL.]] NULL ECOLLATE
+#BE [[=aleph=]] NULL ECOLLATE
+}
+BE$ \n \n (0,1)
+BEn$ \n \n (0,1)
+BE$ [^a] \n (0,1)
+BE$ \na \na (0,2)
+E (a)(b)(c) abc (0,3)(0,1)(1,2)(2,3)
+BE xxx xxx (0,3)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 6, (0,6)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) 2/7 (0,3)
+E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 1,Feb 6 (5,11)
+E3 ((((((((((((((((((((((((((((((x)))))))))))))))))))))))))))))) x (0,1)(0,1)(0,1)
+E3 ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))* xx (0,2)(1,2)(1,2)
+E a?(ab|ba)* ababababababababababababababababababababababababababababababababababababababababa (0,81)(79,81)
+E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabbbbaa (18,25)
+E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabaa (18,22)
+E aaac|aabc|abac|abbc|baac|babc|bbac|bbbc baaabbbabac (7,11)
+BE$ .* \x01\xff (0,2)
+E aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa (53,57)
+L aaaa\nbbbb\ncccc\nddddd\neeeeee\nfffffff\ngggg\nhhhh\niiiii\njjjjj\nkkkkk\nllll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa NOMATCH
+E a*a*a*a*a*b aaaaaaaaab (0,10)
+BE ^ NULL (0,0)
+BE $ NULL (0,0)
+BE ^$ NULL (0,0)
+BE ^a$ a (0,1)
+BE abc abc (0,3)
+BE abc xabcy (1,4)
+BE abc ababc (2,5)
+BE ab*c abc (0,3)
+BE ab*bc abc (0,3)
+BE ab*bc abbc (0,4)
+BE ab*bc abbbbc (0,6)
+E ab+bc abbc (0,4)
+E ab+bc abbbbc (0,6)
+E ab?bc abbc (0,4)
+E ab?bc abc (0,3)
+E ab?c abc (0,3)
+BE ^abc$ abc (0,3)
+BE ^abc abcc (0,3)
+BE abc$ aabc (1,4)
+BE ^ abc (0,0)
+BE $ abc (3,3)
+BE a.c abc (0,3)
+BE a.c axc (0,3)
+BE a.*c axyzc (0,5)
+BE a[bc]d abd (0,3)
+BE a[b-d]e ace (0,3)
+BE a[b-d] aac (1,3)
+BE a[-b] a- (0,2)
+BE a[b-] a- (0,2)
+BE a] a] (0,2)
+BE a[]]b a]b (0,3)
+BE a[^bc]d aed (0,3)
+BE a[^-b]c adc (0,3)
+BE a[^]b]c adc (0,3)
+E ab|cd abc (0,2)
+E ab|cd abcd (0,2)
+E a\(b a(b (0,3)
+E a\(*b ab (0,2)
+E a\(*b a((b (0,4)
+E ((a)) abc (0,1)(0,1)(0,1)
+E (a)b(c) abc (0,3)(0,1)(2,3)
+E a+b+c aabbabc (4,7)
+E a* aaa (0,3)
+#E (a*)* - (0,0)(0,0)
+E (a*)* - (0,0)(?,?) RE2/Go
+E (a*)+ - (0,0)(0,0)
+#E (a*|b)* - (0,0)(0,0)
+E (a*|b)* - (0,0)(?,?) RE2/Go
+E (a+|b)* ab (0,2)(1,2)
+E (a+|b)+ ab (0,2)(1,2)
+E (a+|b)? ab (0,1)(0,1)
+BE [^ab]* cde (0,3)
+#E (^)* - (0,0)(0,0)
+E (^)* - (0,0)(?,?) RE2/Go
+BE a* NULL (0,0)
+E ([abc])*d abbbcd (0,6)(4,5)
+E ([abc])*bcd abcd (0,4)(0,1)
+E a|b|c|d|e e (0,1)
+E (a|b|c|d|e)f ef (0,2)(0,1)
+#E ((a*|b))* - (0,0)(0,0)(0,0)
+E ((a*|b))* - (0,0)(?,?)(?,?) RE2/Go
+BE abcd*efg abcdefg (0,7)
+BE ab* xabyabbbz (1,3)
+BE ab* xayabbbz (1,2)
+E (ab|cd)e abcde (2,5)(2,4)
+BE [abhgefdc]ij hij (0,3)
+E (a|b)c*d abcd (1,4)(1,2)
+E (ab|ab*)bc abc (0,3)(0,1)
+E a([bc]*)c* abc (0,3)(1,3)
+E a([bc]*)(c*d) abcd (0,4)(1,3)(3,4)
+E a([bc]+)(c*d) abcd (0,4)(1,3)(3,4)
+E a([bc]*)(c+d) abcd (0,4)(1,2)(2,4)
+E a[bcd]*dcdcde adcdcde (0,7)
+E (ab|a)b*c abc (0,3)(0,2)
+E ((a)(b)c)(d) abcd (0,4)(0,3)(0,1)(1,2)(3,4)
+BE [A-Za-z_][A-Za-z0-9_]* alpha (0,5)
+E ^a(bc+|b[eh])g|.h$ abh (1,3)
+E (bc+d$|ef*g.|h?i(j|k)) effgz (0,5)(0,5)
+E (bc+d$|ef*g.|h?i(j|k)) ij (0,2)(0,2)(1,2)
+E (bc+d$|ef*g.|h?i(j|k)) reffgz (1,6)(1,6)
+E (((((((((a))))))))) a (0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)
+BE multiple words multiple words yeah (0,14)
+E (.*)c(.*) abcde (0,5)(0,2)(3,5)
+BE abcd abcd (0,4)
+E a(bc)d abcd (0,4)(1,3)
+E a[-]?c ac (0,3)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qaddafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mo'ammar Gadhafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Kaddafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qadhafi (0,15)(?,?)(10,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gadafi (0,14)(?,?)(10,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadafi (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moamar Gaddafi (0,14)(?,?)(9,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadhdhafi (0,18)(?,?)(13,15)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Khaddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafy (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghadafi (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muamar Kaddafi (0,14)(?,?)(9,11)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Quathafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gheddafi (0,16)(?,?)(11,13)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Khadafy (0,15)(?,?)(11,12)
+E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Qudhafi (0,15)(?,?)(10,12)
+E a+(b|c)*d+ aabcdd (0,6)(3,4)
+E ^.+$ vivi (0,4)
+E ^(.+)$ vivi (0,4)(0,4)
+E ^([^!.]+).att.com!(.+)$ gryphon.att.com!eby (0,19)(0,7)(16,19)
+E ^([^!]+!)?([^!]+)$ bas (0,3)(?,?)(0,3)
+E ^([^!]+!)?([^!]+)$ bar!bas (0,7)(0,4)(4,7)
+E ^([^!]+!)?([^!]+)$ foo!bas (0,7)(0,4)(4,7)
+E ^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(4,8)(8,11)
+E ((foo)|(bar))!bas bar!bas (0,7)(0,3)(?,?)(0,3)
+E ((foo)|(bar))!bas foo!bar!bas (4,11)(4,7)(?,?)(4,7)
+E ((foo)|(bar))!bas foo!bas (0,7)(0,3)(0,3)
+E ((foo)|bar)!bas bar!bas (0,7)(0,3)
+E ((foo)|bar)!bas foo!bar!bas (4,11)(4,7)
+E ((foo)|bar)!bas foo!bas (0,7)(0,3)(0,3)
+E (foo|(bar))!bas bar!bas (0,7)(0,3)(0,3)
+E (foo|(bar))!bas foo!bar!bas (4,11)(4,7)(4,7)
+E (foo|(bar))!bas foo!bas (0,7)(0,3)
+E (foo|bar)!bas bar!bas (0,7)(0,3)
+E (foo|bar)!bas foo!bar!bas (4,11)(4,7)
+E (foo|bar)!bas foo!bas (0,7)(0,3)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bas (0,3)(?,?)(0,3)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bar!bas (0,7)(0,4)(4,7)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(?,?)(?,?)(4,8)(8,11)
+E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bas (0,7)(0,4)(4,7)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bas (0,3)(0,3)(?,?)(0,3)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bar!bas (0,7)(0,7)(0,4)(4,7)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11)
+E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bas (0,7)(0,7)(0,4)(4,7)
+E .*(/XXX).* /XXX (0,4)(0,4)
+E .*(\\XXX).* \XXX (0,4)(0,4)
+E \\XXX \XXX (0,4)
+E .*(/000).* /000 (0,4)(0,4)
+E .*(\\000).* \000 (0,4)(0,4)
+E \\000 \000 (0,4)
diff --git a/src/pkg/regexp/testdata/nullsubexpr.dat b/src/pkg/regexp/testdata/nullsubexpr.dat
new file mode 100644
index 000000000..2e18fbb91
--- /dev/null
+++ b/src/pkg/regexp/testdata/nullsubexpr.dat
@@ -0,0 +1,79 @@
+NOTE null subexpression matches : 2002-06-06
+
+E (a*)* a (0,1)(0,1)
+#E SAME x (0,0)(0,0)
+E SAME x (0,0)(?,?) RE2/Go
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a*)+ a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a+)* a (0,1)(0,1)
+E SAME x (0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E (a+)+ a (0,1)(0,1)
+E SAME x NOMATCH
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+
+E ([a]*)* a (0,1)(0,1)
+#E SAME x (0,0)(0,0)
+E SAME x (0,0)(?,?) RE2/Go
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E ([a]*)+ a (0,1)(0,1)
+E SAME x (0,0)(0,0)
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaax (0,6)(0,6)
+E ([^b]*)* a (0,1)(0,1)
+#E SAME b (0,0)(0,0)
+E SAME b (0,0)(?,?) RE2/Go
+E SAME aaaaaa (0,6)(0,6)
+E SAME aaaaaab (0,6)(0,6)
+E ([ab]*)* a (0,1)(0,1)
+E SAME aaaaaa (0,6)(0,6)
+E SAME ababab (0,6)(0,6)
+E SAME bababa (0,6)(0,6)
+E SAME b (0,1)(0,1)
+E SAME bbbbbb (0,6)(0,6)
+E SAME aaaabcde (0,5)(0,5)
+E ([^a]*)* b (0,1)(0,1)
+E SAME bbbbbb (0,6)(0,6)
+#E SAME aaaaaa (0,0)(0,0)
+E SAME aaaaaa (0,0)(?,?) RE2/Go
+E ([^ab]*)* ccccxx (0,6)(0,6)
+#E SAME ababab (0,0)(0,0)
+E SAME ababab (0,0)(?,?) RE2/Go
+
+E ((z)+|a)* zabcde (0,2)(1,2)
+
+#{E a+? aaaaaa (0,1) no *? +? mimimal match ops
+#E (a) aaa (0,1)(0,1)
+#E (a*?) aaa (0,0)(0,0)
+#E (a)*? aaa (0,0)
+#E (a*?)*? aaa (0,0)
+#}
+
+B \(a*\)*\(x\) x (0,1)(0,0)(0,1)
+B \(a*\)*\(x\) ax (0,2)(0,1)(1,2)
+B \(a*\)*\(x\) axa (0,2)(0,1)(1,2)
+B \(a*\)*\(x\)\(\1\) x (0,1)(0,0)(0,1)(1,1)
+B \(a*\)*\(x\)\(\1\) ax (0,2)(1,1)(1,2)(2,2)
+B \(a*\)*\(x\)\(\1\) axa (0,3)(0,1)(1,2)(2,3)
+B \(a*\)*\(x\)\(\1\)\(x\) axax (0,4)(0,1)(1,2)(2,3)(3,4)
+B \(a*\)*\(x\)\(\1\)\(x\) axxa (0,3)(1,1)(1,2)(2,2)(2,3)
+
+#E (a*)*(x) x (0,1)(0,0)(0,1)
+E (a*)*(x) x (0,1)(?,?)(0,1) RE2/Go
+E (a*)*(x) ax (0,2)(0,1)(1,2)
+E (a*)*(x) axa (0,2)(0,1)(1,2)
+
+E (a*)+(x) x (0,1)(0,0)(0,1)
+E (a*)+(x) ax (0,2)(0,1)(1,2)
+E (a*)+(x) axa (0,2)(0,1)(1,2)
+
+E (a*){2}(x) x (0,1)(0,0)(0,1)
+E (a*){2}(x) ax (0,2)(1,1)(1,2)
+E (a*){2}(x) axa (0,2)(1,1)(1,2)
diff --git a/src/pkg/regexp/testdata/re2-exhaustive.txt.bz2 b/src/pkg/regexp/testdata/re2-exhaustive.txt.bz2
new file mode 100644
index 000000000..a357f2801
--- /dev/null
+++ b/src/pkg/regexp/testdata/re2-exhaustive.txt.bz2
Binary files differ
diff --git a/src/pkg/regexp/testdata/re2-search.txt b/src/pkg/regexp/testdata/re2-search.txt
new file mode 100644
index 000000000..f648e5527
--- /dev/null
+++ b/src/pkg/regexp/testdata/re2-search.txt
@@ -0,0 +1,3667 @@
+# RE2 basic search tests built by make log
+# Thu Sep 8 13:43:43 EDT 2011
+Regexp.SearchTests
+strings
+""
+"a"
+regexps
+"a"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:a)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"zyzzyva"
+regexps
+"a"
+-;-;-;-
+-;6-7;-;6-7
+"^(?:a)$"
+-;-;-;-
+-;-;-;-
+"^(?:a)"
+-;-;-;-
+-;-;-;-
+"(?:a)$"
+-;-;-;-
+-;6-7;-;6-7
+strings
+""
+"aa"
+regexps
+"a+"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:a+)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:a+)"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"(?:a+)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+strings
+""
+"ab"
+regexps
+"(a+|b)+"
+-;-;-;-
+0-2 1-2;0-2 1-2;0-2 1-2;0-2 1-2
+"^(?:(a+|b)+)$"
+-;-;-;-
+0-2 1-2;0-2 1-2;0-2 1-2;0-2 1-2
+"^(?:(a+|b)+)"
+-;-;-;-
+0-2 1-2;0-2 1-2;0-2 1-2;0-2 1-2
+"(?:(a+|b)+)$"
+-;-;-;-
+0-2 1-2;0-2 1-2;0-2 1-2;0-2 1-2
+strings
+""
+"xabcdx"
+regexps
+"ab|cd"
+-;-;-;-
+-;1-3;-;1-3
+"^(?:ab|cd)$"
+-;-;-;-
+-;-;-;-
+"^(?:ab|cd)"
+-;-;-;-
+-;-;-;-
+"(?:ab|cd)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"hello\ngoodbye\n"
+regexps
+"h.*od?"
+-;-;-;-
+-;0-5;-;0-5
+"^(?:h.*od?)$"
+-;-;-;-
+-;-;-;-
+"^(?:h.*od?)"
+-;-;-;-
+-;0-5;-;0-5
+"(?:h.*od?)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"hello\ngoodbye\n"
+regexps
+"h.*o"
+-;-;-;-
+-;0-5;-;0-5
+"^(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+"^(?:h.*o)"
+-;-;-;-
+-;0-5;-;0-5
+"(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"goodbye\nhello\n"
+regexps
+"h.*o"
+-;-;-;-
+-;8-13;-;8-13
+"^(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+"^(?:h.*o)"
+-;-;-;-
+-;-;-;-
+"(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"hello world"
+regexps
+"h.*o"
+-;-;-;-
+-;0-8;-;0-8
+"^(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+"^(?:h.*o)"
+-;-;-;-
+-;0-8;-;0-8
+"(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"othello, world"
+regexps
+"h.*o"
+-;-;-;-
+-;2-11;-;2-11
+"^(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+"^(?:h.*o)"
+-;-;-;-
+-;-;-;-
+"(?:h.*o)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aaaaaaa"
+regexps
+"[^\\s\\S]"
+-;-;-;-
+-;-;-;-
+"^(?:[^\\s\\S])$"
+-;-;-;-
+-;-;-;-
+"^(?:[^\\s\\S])"
+-;-;-;-
+-;-;-;-
+"(?:[^\\s\\S])$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aaaaaaa"
+regexps
+"a"
+-;-;-;-
+-;0-1;-;0-1
+"^(?:a)$"
+-;-;-;-
+-;-;-;-
+"^(?:a)"
+-;-;-;-
+-;0-1;-;0-1
+"(?:a)$"
+-;-;-;-
+-;6-7;-;6-7
+strings
+""
+"aaaaaaa"
+regexps
+"a*"
+0-0;0-0;0-0;0-0
+0-7;0-7;0-7;0-7
+"^(?:a*)$"
+0-0;0-0;0-0;0-0
+0-7;0-7;0-7;0-7
+"^(?:a*)"
+0-0;0-0;0-0;0-0
+0-7;0-7;0-7;0-7
+"(?:a*)$"
+0-0;0-0;0-0;0-0
+0-7;0-7;0-7;0-7
+strings
+""
+""
+regexps
+"a*"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:a*)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:a*)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:a*)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+""
+regexps
+"a*"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:a*)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:a*)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:a*)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"xabcdx"
+regexps
+"ab|cd"
+-;-;-;-
+-;1-3;-;1-3
+"^(?:ab|cd)$"
+-;-;-;-
+-;-;-;-
+"^(?:ab|cd)"
+-;-;-;-
+-;-;-;-
+"(?:ab|cd)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"cab"
+regexps
+"a"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:a)$"
+-;-;-;-
+-;-;-;-
+"^(?:a)"
+-;-;-;-
+-;-;-;-
+"(?:a)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"cab"
+regexps
+"a*b"
+-;-;-;-
+-;1-3;-;1-3
+"^(?:a*b)$"
+-;-;-;-
+-;-;-;-
+"^(?:a*b)"
+-;-;-;-
+-;-;-;-
+"(?:a*b)$"
+-;-;-;-
+-;1-3;-;1-3
+strings
+""
+"x"
+regexps
+"((((((((((((((((((((x))))))))))))))))))))"
+-;-;-;-
+0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1
+"^(?:((((((((((((((((((((x)))))))))))))))))))))$"
+-;-;-;-
+0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1
+"^(?:((((((((((((((((((((x)))))))))))))))))))))"
+-;-;-;-
+0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1
+"(?:((((((((((((((((((((x)))))))))))))))))))))$"
+-;-;-;-
+0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1;0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1 0-1
+strings
+""
+"xxxabcdxxx"
+regexps
+"[abcd]"
+-;-;-;-
+-;3-4;-;3-4
+"^(?:[abcd])$"
+-;-;-;-
+-;-;-;-
+"^(?:[abcd])"
+-;-;-;-
+-;-;-;-
+"(?:[abcd])$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xxxabcdxxx"
+regexps
+"[^x]"
+-;-;-;-
+-;3-4;-;3-4
+"^(?:[^x])$"
+-;-;-;-
+-;-;-;-
+"^(?:[^x])"
+-;-;-;-
+-;-;-;-
+"(?:[^x])$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xxxabcdxxx"
+regexps
+"[abcd]+"
+-;-;-;-
+-;3-7;-;3-7
+"^(?:[abcd]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[abcd]+)"
+-;-;-;-
+-;-;-;-
+"(?:[abcd]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xxxabcdxxx"
+regexps
+"[^x]+"
+-;-;-;-
+-;3-7;-;3-7
+"^(?:[^x]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[^x]+)"
+-;-;-;-
+-;-;-;-
+"(?:[^x]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"fo"
+regexps
+"(fo|foo)"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:(fo|foo))$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:(fo|foo))"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"(?:(fo|foo))$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+strings
+""
+"foo"
+regexps
+"(foo|fo)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|fo))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|fo))"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:(foo|fo))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"aA"
+regexps
+"aa"
+-;-;-;-
+-;-;-;-
+"^(?:aa)$"
+-;-;-;-
+-;-;-;-
+"^(?:aa)"
+-;-;-;-
+-;-;-;-
+"(?:aa)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"Aa"
+regexps
+"a"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:a)$"
+-;-;-;-
+-;-;-;-
+"^(?:a)"
+-;-;-;-
+-;-;-;-
+"(?:a)$"
+-;-;-;-
+-;1-2;-;1-2
+strings
+""
+"A"
+regexps
+"a"
+-;-;-;-
+-;-;-;-
+"^(?:a)$"
+-;-;-;-
+-;-;-;-
+"^(?:a)"
+-;-;-;-
+-;-;-;-
+"(?:a)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc"
+regexps
+"ABC"
+-;-;-;-
+-;-;-;-
+"^(?:ABC)$"
+-;-;-;-
+-;-;-;-
+"^(?:ABC)"
+-;-;-;-
+-;-;-;-
+"(?:ABC)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"XABCY"
+regexps
+"abc"
+-;-;-;-
+-;-;-;-
+"^(?:abc)$"
+-;-;-;-
+-;-;-;-
+"^(?:abc)"
+-;-;-;-
+-;-;-;-
+"(?:abc)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xabcy"
+regexps
+"ABC"
+-;-;-;-
+-;-;-;-
+"^(?:ABC)$"
+-;-;-;-
+-;-;-;-
+"^(?:ABC)"
+-;-;-;-
+-;-;-;-
+"(?:ABC)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"foo|bar|[A-Z]"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:foo|bar|[A-Z])$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:foo|bar|[A-Z])"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"(?:foo|bar|[A-Z])$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+strings
+""
+"foo"
+regexps
+"^(foo|bar|[A-Z])"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z]))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z]))"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^(foo|bar|[A-Z]))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"foo\n"
+regexps
+"(foo|bar|[A-Z])$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])$)"
+-;-;-;-
+-;-;-;-
+"(?:(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"(foo|bar|[A-Z])$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|bar|[A-Z])$)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"foo\n"
+regexps
+"^(foo|bar|[A-Z])$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo|bar|[A-Z])$)"
+-;-;-;-
+-;-;-;-
+"(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"^(foo|bar|[A-Z])$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z])$)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"bar"
+regexps
+"^(foo|bar|[A-Z])$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(foo|bar|[A-Z])$)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"X"
+regexps
+"^(foo|bar|[A-Z])$"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"^(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"^(?:^(foo|bar|[A-Z])$)"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+strings
+""
+"XY"
+regexps
+"^(foo|bar|[A-Z])$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo|bar|[A-Z])$)"
+-;-;-;-
+-;-;-;-
+"(?:^(foo|bar|[A-Z])$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"fo"
+regexps
+"^(fo|foo)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^(fo|foo)$)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^(fo|foo)$)"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"(?:^(fo|foo)$)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+strings
+""
+"foo"
+regexps
+"^(fo|foo)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(fo|foo)$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^(fo|foo)$)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^(fo|foo)$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"fo"
+regexps
+"^^(fo|foo)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^^(fo|foo)$)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^^(fo|foo)$)"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"(?:^^(fo|foo)$)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+strings
+""
+"foo"
+regexps
+"^^(fo|foo)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^^(fo|foo)$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^^(fo|foo)$)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^^(fo|foo)$)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+""
+regexps
+"^$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"^^$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+""
+regexps
+"^$$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^$$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"^^$$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^$$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^^$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^^$$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^$$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^^$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"^^^^^^^^$$$$$$$$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^^^^^^^$$$$$$$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^^^^^^^$$$$$$$$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^^^^^^^^$$$$$$$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"^(?:^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^)"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"(?:^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"$"
+0-0;0-0;0-0;0-0
+-;1-1;-;1-1
+"^(?:$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:$)$"
+0-0;0-0;0-0;0-0
+-;1-1;-;1-1
+strings
+""
+"nofoo foo that"
+regexps
+"\\bfoo\\b"
+-;-;-;-
+-;6-9;-;6-9
+"^(?:\\bfoo\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bfoo\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bfoo\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"faoa x"
+regexps
+"a\\b"
+-;-;-;-
+-;3-4;-;3-4
+"^(?:a\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:a\\b)"
+-;-;-;-
+-;-;-;-
+"(?:a\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"bar x"
+regexps
+"\\bbar"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:\\bbar)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bbar)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:\\bbar)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo\nbar x"
+regexps
+"\\bbar"
+-;-;-;-
+-;4-7;-;4-7
+"^(?:\\bbar)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bbar)"
+-;-;-;-
+-;-;-;-
+"(?:\\bbar)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foobar"
+regexps
+"bar\\b"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:bar\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\b)"
+-;-;-;-
+-;-;-;-
+"(?:bar\\b)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"foobar\nxxx"
+regexps
+"bar\\b"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:bar\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\b)"
+-;-;-;-
+-;-;-;-
+"(?:bar\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"(foo|bar|[A-Z])\\b"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(foo|bar|[A-Z])\\b)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"foo\n"
+regexps
+"(foo|bar|[A-Z])\\b"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"^(?:(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])\\b)"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"(?:(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"\\b"
+-;-;-;-
+-;0-0;-;0-0
+"^(?:\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b)"
+-;-;-;-
+-;0-0;-;0-0
+"(?:\\b)$"
+-;-;-;-
+-;1-1;-;1-1
+strings
+""
+"foo"
+regexps
+"\\b(foo|bar|[A-Z])"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z]))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z]))"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:\\b(foo|bar|[A-Z]))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"X"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-1 0-1;0-1 0-1;0-1 0-1;0-1 0-1
+strings
+""
+"XY"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"bar"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"foo"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"foo\n"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"ffoo bbar N x"
+regexps
+"\\b(foo|bar|[A-Z])\\b"
+-;-;-;-
+-;10-11 10-11;-;10-11 10-11
+"^(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b(foo|bar|[A-Z])\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\b(foo|bar|[A-Z])\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"fo"
+regexps
+"\\b(fo|foo)\\b"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:\\b(fo|foo)\\b)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:\\b(fo|foo)\\b)"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"(?:\\b(fo|foo)\\b)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+strings
+""
+"foo"
+regexps
+"\\b(fo|foo)\\b"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(fo|foo)\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:\\b(fo|foo)\\b)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:\\b(fo|foo)\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+""
+regexps
+"\\b\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\b\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\b\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"\\b\\b"
+-;-;-;-
+-;0-0;-;0-0
+"^(?:\\b\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b\\b)"
+-;-;-;-
+-;0-0;-;0-0
+"(?:\\b\\b)$"
+-;-;-;-
+-;1-1;-;1-1
+strings
+""
+""
+regexps
+"\\b$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b$)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b$)"
+-;-;-;-
+-;-;-;-
+"(?:\\b$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"\\b$"
+-;-;-;-
+-;1-1;-;1-1
+"^(?:\\b$)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b$)"
+-;-;-;-
+-;-;-;-
+"(?:\\b$)$"
+-;-;-;-
+-;1-1;-;1-1
+strings
+""
+"y x"
+regexps
+"\\b$"
+-;-;-;-
+-;3-3;-;3-3
+"^(?:\\b$)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\b$)"
+-;-;-;-
+-;-;-;-
+"(?:\\b$)$"
+-;-;-;-
+-;3-3;-;3-3
+strings
+""
+"x"
+regexps
+"\\b.$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\b.$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\b.$)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\b.$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"fo"
+regexps
+"^\\b(fo|foo)\\b"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^\\b(fo|foo)\\b)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"^(?:^\\b(fo|foo)\\b)"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+"(?:^\\b(fo|foo)\\b)$"
+-;-;-;-
+0-2 0-2;0-2 0-2;0-2 0-2;0-2 0-2
+strings
+""
+"foo"
+regexps
+"^\\b(fo|foo)\\b"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^\\b(fo|foo)\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:^\\b(fo|foo)\\b)"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"(?:^\\b(fo|foo)\\b)$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+""
+regexps
+"^\\b"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b)"
+-;-;-;-
+-;-;-;-
+"(?:^\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\b"
+-;-;-;-
+-;0-0;-;0-0
+"^(?:^\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b)"
+-;-;-;-
+-;0-0;-;0-0
+"(?:^\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"^\\b\\b"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b\\b)"
+-;-;-;-
+-;-;-;-
+"(?:^\\b\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\b\\b"
+-;-;-;-
+-;0-0;-;0-0
+"^(?:^\\b\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b\\b)"
+-;-;-;-
+-;0-0;-;0-0
+"(?:^\\b\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"^\\b$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\b$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\b$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\b$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\b$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\b.$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^\\b.$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^\\b.$)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:^\\b.$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"x"
+regexps
+"^\\b.\\b$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^\\b.\\b$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^\\b.\\b$)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:^\\b.\\b$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+""
+regexps
+"^^^^^^^^\\b$$$$$$$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\b$$$$$$$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\b$$$$$$$)"
+-;-;-;-
+-;-;-;-
+"(?:^^^^^^^^\\b$$$$$$$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^^^^^^^^\\b.$$$$$$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^^^^^^^^\\b.$$$$$$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:^^^^^^^^\\b.$$$$$$)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:^^^^^^^^\\b.$$$$$$)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"x"
+regexps
+"^^^^^^^^\\b$$$$$$$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\b$$$$$$$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\b$$$$$$$)"
+-;-;-;-
+-;-;-;-
+"(?:^^^^^^^^\\b$$$$$$$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"n foo xfoox that"
+regexps
+"\\Bfoo\\B"
+-;-;-;-
+-;7-10;-;7-10
+"^(?:\\Bfoo\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bfoo\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\Bfoo\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"faoa x"
+regexps
+"a\\B"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:a\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:a\\B)"
+-;-;-;-
+-;-;-;-
+"(?:a\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"bar x"
+regexps
+"\\Bbar"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bbar)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bbar)"
+-;-;-;-
+-;-;-;-
+"(?:\\Bbar)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo\nbar x"
+regexps
+"\\Bbar"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bbar)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bbar)"
+-;-;-;-
+-;-;-;-
+"(?:\\Bbar)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foobar"
+regexps
+"bar\\B"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\B)"
+-;-;-;-
+-;-;-;-
+"(?:bar\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foobar\nxxx"
+regexps
+"bar\\B"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:bar\\B)"
+-;-;-;-
+-;-;-;-
+"(?:bar\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foox"
+regexps
+"(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"^(?:(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;0-3 0-3;-;0-3 0-3
+"(?:(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo\n"
+regexps
+"(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"\\B"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"\\B"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"\\B(foo|bar|[A-Z])"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z]))$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z]))"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z]))$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xXy"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;1-2 1-2;-;1-2 1-2
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"XY"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"XYZ"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;1-2 1-2;-;1-2 1-2
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abara"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;1-4 1-4;-;1-4 1-4
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xfoo_"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;1-4 1-4;-;1-4 1-4
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xfoo\n"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo bar vNx"
+regexps
+"\\B(foo|bar|[A-Z])\\B"
+-;-;-;-
+-;9-10 9-10;-;9-10 9-10
+"^(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|bar|[A-Z])\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|bar|[A-Z])\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xfoo"
+regexps
+"\\B(fo|foo)\\B"
+-;-;-;-
+-;1-3 1-3;-;1-3 1-3
+"^(?:\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(fo|foo)\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xfooo"
+regexps
+"\\B(foo|fo)\\B"
+-;-;-;-
+-;1-4 1-4;-;1-4 1-4
+"^(?:\\B(foo|fo)\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(foo|fo)\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(foo|fo)\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"\\B\\B"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B\\B)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:\\B\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"\\B\\B"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B\\B)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:\\B\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"\\B$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:\\B$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:\\B$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"\\B$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"y x"
+regexps
+"\\B$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:\\B$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"\\B.$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B.$)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B.$)"
+-;-;-;-
+-;-;-;-
+"(?:\\B.$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"fo"
+regexps
+"^\\B(fo|foo)\\B"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B(fo|foo)\\B)"
+-;-;-;-
+-;-;-;-
+"(?:^\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"^\\B(fo|foo)\\B"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B(fo|foo)\\B)"
+-;-;-;-
+-;-;-;-
+"(?:^\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"^\\B"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^\\B"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"^\\B\\B"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B\\B)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^\\B\\B)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^\\B\\B"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B\\B)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^\\B\\B)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+""
+regexps
+"^\\B$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^\\B$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^\\B$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^\\B$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^\\B$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^\\B$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\B.$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B.$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B.$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\B.$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^\\B.\\B$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B.\\B$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\B.\\B$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\B.\\B$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"^^^^^^^^\\B$$$$$$$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^^^^^^^\\B$$$$$$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^^^^^^^^\\B$$$$$$$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^^^^^^^^\\B$$$$$$$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^^^^^^^^\\B.$$$$$$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\B.$$$$$$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^^^^^^^^\\B.$$$$$$)"
+-;-;-;-
+-;-;-;-
+"(?:^^^^^^^^\\B.$$$$$$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^^^^^^^^\\B$$$$$$$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^^^^^^^\\B$$$$$$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^^^^^^^\\B$$$$$$$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^^^^^^^^\\B$$$$$$$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"\\bx\\b"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\bx\\b)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\bx\\b)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\bx\\b)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"x>"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;0-1;-;0-1
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;0-1;-;0-1
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"<x"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;1-2;-;1-2
+strings
+""
+"<x>"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"ax"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xb"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"axb"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"«x"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;2-3;-;2-3
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;2-3;-;2-3
+strings
+""
+"x»"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;0-1;-;0-1
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;0-1;-;0-1
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"«x»"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;2-3;-;2-3
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"axb"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"áxβ"
+regexps
+"\\bx\\b"
+-;-;-;-
+-;2-3;-;2-3
+"^(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\bx\\b)"
+-;-;-;-
+-;-;-;-
+"(?:\\bx\\b)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"axb"
+regexps
+"\\Bx\\B"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:\\Bx\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bx\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\Bx\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"áxβ"
+regexps
+"\\Bx\\B"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bx\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\Bx\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\Bx\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+""
+regexps
+"^$^$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$^$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^$^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+""
+regexps
+"^$^"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$^)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:^$^)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:^$^)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+""
+regexps
+"$^$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:$^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"^(?:$^$)"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+"(?:$^$)$"
+0-0;0-0;0-0;0-0
+0-0;0-0;0-0;0-0
+strings
+""
+"x"
+regexps
+"^$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"^$^"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x"
+regexps
+"$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\ny"
+regexps
+"^$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\ny"
+regexps
+"^$^"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\ny"
+regexps
+"$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\n\ny"
+regexps
+"^$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\n\ny"
+regexps
+"^$^"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^$^)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:^$^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"x\n\ny"
+regexps
+"$^$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:$^$)"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"(?:$^$)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"foo$bar"
+regexps
+"^(foo\\$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo\\$)$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^(foo\\$)$)"
+-;-;-;-
+-;-;-;-
+"(?:^(foo\\$)$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo$bar"
+regexps
+"(foo\\$)"
+-;-;-;-
+-;0-4 0-4;-;0-4 0-4
+"^(?:(foo\\$))$"
+-;-;-;-
+-;-;-;-
+"^(?:(foo\\$))"
+-;-;-;-
+-;0-4 0-4;-;0-4 0-4
+"(?:(foo\\$))$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc"
+regexps
+"^...$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^...$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^...$)"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"(?:^...$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+strings
+""
+"本"
+regexps
+"^本$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^本$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^本$)"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"(?:^本$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+strings
+""
+"日本語"
+regexps
+"^...$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"^(?:^...$)$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"^(?:^...$)"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"(?:^...$)$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+strings
+""
+".本."
+regexps
+"^...$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"^(?:^...$)$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"^(?:^...$)"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"(?:^...$)$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+strings
+""
+"本"
+regexps
+"^\\C\\C\\C$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^\\C\\C\\C$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"^(?:^\\C\\C\\C$)"
+-;-;-;-
+0-3;0-3;0-3;0-3
+"(?:^\\C\\C\\C$)$"
+-;-;-;-
+0-3;0-3;0-3;0-3
+strings
+""
+"本"
+regexps
+"^\\C$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\C$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\C$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\C$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"日本語"
+regexps
+"^\\C\\C\\C$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\C\\C\\C$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^\\C\\C\\C$)"
+-;-;-;-
+-;-;-;-
+"(?:^\\C\\C\\C$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"日本語"
+regexps
+"^...$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"^(?:^...$)$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"^(?:^...$)"
+-;-;-;-
+0-9;0-9;0-9;0-9
+"(?:^...$)$"
+-;-;-;-
+0-9;0-9;0-9;0-9
+strings
+""
+"日本語"
+regexps
+"^.........$"
+-;-;-;-
+-;-;-;-
+"^(?:^.........$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^.........$)"
+-;-;-;-
+-;-;-;-
+"(?:^.........$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+".本."
+regexps
+"^...$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"^(?:^...$)$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"^(?:^...$)"
+-;-;-;-
+0-5;0-5;0-5;0-5
+"(?:^...$)$"
+-;-;-;-
+0-5;0-5;0-5;0-5
+strings
+""
+".本."
+regexps
+"^.....$"
+-;-;-;-
+-;-;-;-
+"^(?:^.....$)$"
+-;-;-;-
+-;-;-;-
+"^(?:^.....$)"
+-;-;-;-
+-;-;-;-
+"(?:^.....$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"xfooo"
+regexps
+"\\B(fo|foo)\\B"
+-;-;-;-
+-;1-3 1-3;-;1-4 1-4
+"^(?:\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\B(fo|foo)\\B)"
+-;-;-;-
+-;-;-;-
+"(?:\\B(fo|foo)\\B)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"foo"
+regexps
+"(fo|foo)"
+-;-;-;-
+0-3 0-3;0-2 0-2;0-3 0-3;0-3 0-3
+"^(?:(fo|foo))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+"^(?:(fo|foo))"
+-;-;-;-
+0-3 0-3;0-2 0-2;0-3 0-3;0-3 0-3
+"(?:(fo|foo))$"
+-;-;-;-
+0-3 0-3;0-3 0-3;0-3 0-3;0-3 0-3
+strings
+""
+"a"
+regexps
+"\\141"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\141)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\141)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\141)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"0"
+regexps
+"\\060"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\060)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\060)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\060)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"00"
+regexps
+"\\0600"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\0600)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\0600)"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"(?:\\0600)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+strings
+""
+"08"
+regexps
+"\\608"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\608)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\608)"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"(?:\\608)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+strings
+""
+""
+regexps
+"\\01"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\01)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\01)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\01)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"8"
+regexps
+"\\018"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\018)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"^(?:\\018)"
+-;-;-;-
+0-2;0-2;0-2;0-2
+"(?:\\018)$"
+-;-;-;-
+0-2;0-2;0-2;0-2
+strings
+""
+"a"
+regexps
+"\\x{61}"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x{61})$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x{61})"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\x{61})$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"a"
+regexps
+"\\x61"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x61)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x61)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\x61)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"a"
+regexps
+"\\x{00000061}"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x{00000061})$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:\\x{00000061})"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:\\x{00000061})$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"aαβb"
+regexps
+"\\p{Greek}+"
+-;-;-;-
+-;1-5;-;1-5
+"^(?:\\p{Greek}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{Greek}+)"
+-;-;-;-
+-;-;-;-
+"(?:\\p{Greek}+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aαβb"
+regexps
+"\\P{Greek}+"
+-;-;-;-
+-;0-1;-;0-1
+"^(?:\\P{Greek}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\P{Greek}+)"
+-;-;-;-
+-;0-1;-;0-1
+"(?:\\P{Greek}+)$"
+-;-;-;-
+-;5-6;-;5-6
+strings
+""
+"aαβb"
+regexps
+"\\p{^Greek}+"
+-;-;-;-
+-;0-1;-;0-1
+"^(?:\\p{^Greek}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{^Greek}+)"
+-;-;-;-
+-;0-1;-;0-1
+"(?:\\p{^Greek}+)$"
+-;-;-;-
+-;5-6;-;5-6
+strings
+""
+"aαβb"
+regexps
+"\\P{^Greek}+"
+-;-;-;-
+-;1-5;-;1-5
+"^(?:\\P{^Greek}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\P{^Greek}+)"
+-;-;-;-
+-;-;-;-
+"(?:\\P{^Greek}+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc123"
+regexps
+"[^0-9]+"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:[^0-9]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[^0-9]+)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:[^0-9]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\p{Nd}+"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:\\p{Nd}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{Nd}+)"
+-;-;-;-
+-;-;-;-
+"(?:\\p{Nd}+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\p{^Nd}+"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:\\p{^Nd}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{^Nd}+)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:\\p{^Nd}+)$"
+-;-;-;-
+-;6-22;-;6-22
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\P{Nd}+"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:\\P{Nd}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\P{Nd}+)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:\\P{Nd}+)$"
+-;-;-;-
+-;6-22;-;6-22
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\P{^Nd}+"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:\\P{^Nd}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\P{^Nd}+)"
+-;-;-;-
+-;-;-;-
+"(?:\\P{^Nd}+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\pN+"
+-;-;-;-
+-;3-22;-;3-22
+"^(?:\\pN+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\pN+)"
+-;-;-;-
+-;-;-;-
+"(?:\\pN+)$"
+-;-;-;-
+-;3-22;-;3-22
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\p{N}+"
+-;-;-;-
+-;3-22;-;3-22
+"^(?:\\p{N}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{N}+)"
+-;-;-;-
+-;-;-;-
+"(?:\\p{N}+)$"
+-;-;-;-
+-;3-22;-;3-22
+strings
+""
+"abc123²³¼½¾₀₉"
+regexps
+"\\p{^N}+"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:\\p{^N}+)$"
+-;-;-;-
+-;-;-;-
+"^(?:\\p{^N}+)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:\\p{^N}+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abc123"
+regexps
+"\\p{Any}+"
+-;-;-;-
+0-6;0-6;0-6;0-6
+"^(?:\\p{Any}+)$"
+-;-;-;-
+0-6;0-6;0-6;0-6
+"^(?:\\p{Any}+)"
+-;-;-;-
+0-6;0-6;0-6;0-6
+"(?:\\p{Any}+)$"
+-;-;-;-
+0-6;0-6;0-6;0-6
+strings
+""
+"@AaB"
+regexps
+"(?i)[@-A]+"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:(?i)[@-A]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?i)[@-A]+)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:(?i)[@-A]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aAzZ"
+regexps
+"(?i)[A-Z]+"
+-;-;-;-
+0-4;0-4;0-4;0-4
+"^(?:(?i)[A-Z]+)$"
+-;-;-;-
+0-4;0-4;0-4;0-4
+"^(?:(?i)[A-Z]+)"
+-;-;-;-
+0-4;0-4;0-4;0-4
+"(?:(?i)[A-Z]+)$"
+-;-;-;-
+0-4;0-4;0-4;0-4
+strings
+""
+"Aa\\"
+regexps
+"(?i)[^\\\\]+"
+-;-;-;-
+-;0-2;-;0-2
+"^(?:(?i)[^\\\\]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?i)[^\\\\]+)"
+-;-;-;-
+-;0-2;-;0-2
+"(?:(?i)[^\\\\]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"acegikmoqsuwyACEGIKMOQSUWY"
+regexps
+"(?i)[acegikmoqsuwy]+"
+-;-;-;-
+0-26;0-26;0-26;0-26
+"^(?:(?i)[acegikmoqsuwy]+)$"
+-;-;-;-
+0-26;0-26;0-26;0-26
+"^(?:(?i)[acegikmoqsuwy]+)"
+-;-;-;-
+0-26;0-26;0-26;0-26
+"(?:(?i)[acegikmoqsuwy]+)$"
+-;-;-;-
+0-26;0-26;0-26;0-26
+strings
+""
+"@AaB"
+regexps
+"[@-A]+"
+-;-;-;-
+-;0-2;-;0-2
+"^(?:[@-A]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[@-A]+)"
+-;-;-;-
+-;0-2;-;0-2
+"(?:[@-A]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aAzZ"
+regexps
+"[A-Z]+"
+-;-;-;-
+-;1-2;-;1-2
+"^(?:[A-Z]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[A-Z]+)"
+-;-;-;-
+-;-;-;-
+"(?:[A-Z]+)$"
+-;-;-;-
+-;3-4;-;3-4
+strings
+""
+"Aa\\"
+regexps
+"[^\\\\]+"
+-;-;-;-
+-;0-2;-;0-2
+"^(?:[^\\\\]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[^\\\\]+)"
+-;-;-;-
+-;0-2;-;0-2
+"(?:[^\\\\]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"acegikmoqsuwyACEGIKMOQSUWY"
+regexps
+"[acegikmoqsuwy]+"
+-;-;-;-
+-;0-13;-;0-13
+"^(?:[acegikmoqsuwy]+)$"
+-;-;-;-
+-;-;-;-
+"^(?:[acegikmoqsuwy]+)"
+-;-;-;-
+-;0-13;-;0-13
+"(?:[acegikmoqsuwy]+)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"^abc"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:^abc)$"
+-;-;-;-
+-;-;-;-
+"^(?:^abc)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:^abc)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aabcdef"
+regexps
+"^abc"
+-;-;-;-
+-;-;-;-
+"^(?:^abc)$"
+-;-;-;-
+-;-;-;-
+"^(?:^abc)"
+-;-;-;-
+-;-;-;-
+"(?:^abc)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"^[ay]*[bx]+c"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+"^(?:^[ay]*[bx]+c)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aabcdef"
+regexps
+"^[ay]*[bx]+c"
+-;-;-;-
+-;0-4;-;0-4
+"^(?:^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+"^(?:^[ay]*[bx]+c)"
+-;-;-;-
+-;0-4;-;0-4
+"(?:^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"def$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:def$)$"
+-;-;-;-
+-;-;-;-
+"^(?:def$)"
+-;-;-;-
+-;-;-;-
+"(?:def$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"def$"
+-;-;-;-
+-;-;-;-
+"^(?:def$)$"
+-;-;-;-
+-;-;-;-
+"^(?:def$)"
+-;-;-;-
+-;-;-;-
+"(?:def$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"d[ex][fy]$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:d[ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:d[ex][fy]$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"d[ex][fy]$"
+-;-;-;-
+-;-;-;-
+"^(?:d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:d[ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"[dz][ex][fy]$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:[dz][ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:[dz][ex][fy]$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"[dz][ex][fy]$"
+-;-;-;-
+-;-;-;-
+"^(?:[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:[dz][ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"(?m)^abc"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:(?m)^abc)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)^abc)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:(?m)^abc)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aabcdef"
+regexps
+"(?m)^abc"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)^abc)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)^abc)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)^abc)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"(?m)^[ay]*[bx]+c"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:(?m)^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)^[ay]*[bx]+c)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:(?m)^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"aabcdef"
+regexps
+"(?m)^[ay]*[bx]+c"
+-;-;-;-
+-;0-4;-;0-4
+"^(?:(?m)^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)^[ay]*[bx]+c)"
+-;-;-;-
+-;0-4;-;0-4
+"(?:(?m)^[ay]*[bx]+c)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"(?m)def$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:(?m)def$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)def$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)def$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"(?m)def$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)def$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)def$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)def$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"(?m)d[ex][fy]$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:(?m)d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)d[ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)d[ex][fy]$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"(?m)d[ex][fy]$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)d[ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)d[ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"abcdef"
+regexps
+"(?m)[dz][ex][fy]$"
+-;-;-;-
+-;3-6;-;3-6
+"^(?:(?m)[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)[dz][ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)[dz][ex][fy]$)$"
+-;-;-;-
+-;3-6;-;3-6
+strings
+""
+"abcdeff"
+regexps
+"(?m)[dz][ex][fy]$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+"^(?:(?m)[dz][ex][fy]$)"
+-;-;-;-
+-;-;-;-
+"(?:(?m)[dz][ex][fy]$)$"
+-;-;-;-
+-;-;-;-
+strings
+""
+"a"
+regexps
+"^"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"^(?:^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^)"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"(?:^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"a"
+regexps
+"^^"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"^(?:^^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+"^(?:^^)"
+0-0;0-0;0-0;0-0
+-;0-0;-;0-0
+"(?:^^)$"
+0-0;0-0;0-0;0-0
+-;-;-;-
+strings
+""
+"a"
+regexps
+"a"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:a)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"a"
+regexps
+"ab*"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:ab*)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:ab*)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:ab*)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"a"
+regexps
+"a\\C*"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a\\C*)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"^(?:a\\C*)"
+-;-;-;-
+0-1;0-1;0-1;0-1
+"(?:a\\C*)$"
+-;-;-;-
+0-1;0-1;0-1;0-1
+strings
+""
+"baba"
+regexps
+"a\\C*|ba\\C"
+-;-;-;-
+-;0-3;-;0-3
+"^(?:a\\C*|ba\\C)$"
+-;-;-;-
+-;-;-;-
+"^(?:a\\C*|ba\\C)"
+-;-;-;-
+-;0-3;-;0-3
+"(?:a\\C*|ba\\C)$"
+-;-;-;-
+-;1-4;-;1-4
diff --git a/src/pkg/regexp/testdata/repetition.dat b/src/pkg/regexp/testdata/repetition.dat
new file mode 100644
index 000000000..e6361f51a
--- /dev/null
+++ b/src/pkg/regexp/testdata/repetition.dat
@@ -0,0 +1,163 @@
+NOTE implicit vs. explicit repetitions : 2009-02-02
+
+# Glenn Fowler <gsf@research.att.com>
+# conforming matches (column 4) must match one of the following BREs
+# NOMATCH
+# (0,.)\((\(.\),\(.\))(?,?)(\2,\3)\)*
+# (0,.)\((\(.\),\(.\))(\2,\3)(?,?)\)*
+# i.e., each 3-tuple has two identical elements and one (?,?)
+
+E ((..)|(.)) NULL NOMATCH
+E ((..)|(.))((..)|(.)) NULL NOMATCH
+E ((..)|(.))((..)|(.))((..)|(.)) NULL NOMATCH
+
+E ((..)|(.)){1} NULL NOMATCH
+E ((..)|(.)){2} NULL NOMATCH
+E ((..)|(.)){3} NULL NOMATCH
+
+E ((..)|(.))* NULL (0,0)
+
+E ((..)|(.)) a (0,1)(0,1)(?,?)(0,1)
+E ((..)|(.))((..)|(.)) a NOMATCH
+E ((..)|(.))((..)|(.))((..)|(.)) a NOMATCH
+
+E ((..)|(.)){1} a (0,1)(0,1)(?,?)(0,1)
+E ((..)|(.)){2} a NOMATCH
+E ((..)|(.)){3} a NOMATCH
+
+E ((..)|(.))* a (0,1)(0,1)(?,?)(0,1)
+
+E ((..)|(.)) aa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aa (0,2)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)
+E ((..)|(.))((..)|(.))((..)|(.)) aa NOMATCH
+
+E ((..)|(.)){1} aa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aa (0,2)(1,2)(?,?)(1,2)
+E ((..)|(.)){3} aa NOMATCH
+
+E ((..)|(.))* aa (0,2)(0,2)(0,2)(?,?)
+
+E ((..)|(.)) aaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaa (0,3)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)
+E ((..)|(.))((..)|(.))((..)|(.)) aaa (0,3)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)(2,3)(?,?)(2,3)
+
+E ((..)|(.)){1} aaa (0,2)(0,2)(0,2)(?,?)
+#E ((..)|(.)){2} aaa (0,3)(2,3)(?,?)(2,3)
+E ((..)|(.)){2} aaa (0,3)(2,3)(0,2)(2,3) RE2/Go
+E ((..)|(.)){3} aaa (0,3)(2,3)(?,?)(2,3)
+
+#E ((..)|(.))* aaa (0,3)(2,3)(?,?)(2,3)
+E ((..)|(.))* aaa (0,3)(2,3)(0,2)(2,3) RE2/Go
+
+E ((..)|(.)) aaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)(3,4)(?,?)(3,4)
+
+E ((..)|(.)){1} aaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaa (0,4)(2,4)(2,4)(?,?)
+#E ((..)|(.)){3} aaaa (0,4)(3,4)(?,?)(3,4)
+E ((..)|(.)){3} aaaa (0,4)(3,4)(0,2)(3,4) RE2/Go
+
+E ((..)|(.))* aaaa (0,4)(2,4)(2,4)(?,?)
+
+E ((..)|(.)) aaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaaa (0,5)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,5)(?,?)(4,5)
+
+E ((..)|(.)){1} aaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaaa (0,4)(2,4)(2,4)(?,?)
+#E ((..)|(.)){3} aaaaa (0,5)(4,5)(?,?)(4,5)
+E ((..)|(.)){3} aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go
+
+#E ((..)|(.))* aaaaa (0,5)(4,5)(?,?)(4,5)
+E ((..)|(.))* aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go
+
+E ((..)|(.)) aaaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.))((..)|(.)) aaaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)
+E ((..)|(.))((..)|(.))((..)|(.)) aaaaaa (0,6)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,6)(4,6)(?,?)
+
+E ((..)|(.)){1} aaaaaa (0,2)(0,2)(0,2)(?,?)
+E ((..)|(.)){2} aaaaaa (0,4)(2,4)(2,4)(?,?)
+E ((..)|(.)){3} aaaaaa (0,6)(4,6)(4,6)(?,?)
+
+E ((..)|(.))* aaaaaa (0,6)(4,6)(4,6)(?,?)
+
+NOTE additional repetition tests graciously provided by Chris Kuklewicz www.haskell.org 2009-02-02
+
+# These test a bug in OS X / FreeBSD / NetBSD, and libtree.
+# Linux/GLIBC gets the {8,} and {8,8} wrong.
+
+:HA#100:E X(.?){0,}Y X1234567Y (0,9)(7,8)
+:HA#101:E X(.?){1,}Y X1234567Y (0,9)(7,8)
+:HA#102:E X(.?){2,}Y X1234567Y (0,9)(7,8)
+:HA#103:E X(.?){3,}Y X1234567Y (0,9)(7,8)
+:HA#104:E X(.?){4,}Y X1234567Y (0,9)(7,8)
+:HA#105:E X(.?){5,}Y X1234567Y (0,9)(7,8)
+:HA#106:E X(.?){6,}Y X1234567Y (0,9)(7,8)
+:HA#107:E X(.?){7,}Y X1234567Y (0,9)(7,8)
+:HA#108:E X(.?){8,}Y X1234567Y (0,9)(8,8)
+#:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(7,8)
+:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(7,8)
+:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(7,8)
+:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(7,8)
+:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(7,8)
+:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(7,8)
+:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(7,8)
+:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(8,8) RE2/Go
+#:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(7,8)
+:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(8,8) RE2/Go
+:HA#118:E X(.?){8,8}Y X1234567Y (0,9)(8,8)
+
+# These test a fixed bug in my regex-tdfa that did not keep the expanded
+# form properly grouped, so right association did the wrong thing with
+# these ambiguous patterns (crafted just to test my code when I became
+# suspicious of my implementation). The first subexpression should use
+# "ab" then "a" then "bcd".
+
+# OS X / FreeBSD / NetBSD badly fail many of these, with impossible
+# results like (0,6)(4,5)(6,6).
+
+:HA#260:E (a|ab|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#261:E (a|ab|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#262:E (a|ab|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#263:E (a|ab|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#264:E (a|ab|c|bcd){4,}(d*) ababcd NOMATCH
+:HA#265:E (a|ab|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#266:E (a|ab|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#267:E (a|ab|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#268:E (a|ab|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#269:E (a|ab|c|bcd){4,10}(d*) ababcd NOMATCH
+:HA#270:E (a|ab|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#271:E (a|ab|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
+
+# The above worked on Linux/GLIBC but the following often fail.
+# They also trip up OS X / FreeBSD / NetBSD:
+
+#:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+:HA#284:E (ab|a|c|bcd){4,}(d*) ababcd NOMATCH
+#:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6)
+:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+:HA#289:E (ab|a|c|bcd){4,10}(d*) ababcd NOMATCH
+#:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6)
+:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
+#:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6)
+:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(4,5)(5,6) RE2/Go
diff --git a/src/pkg/regexp/testdata/testregex.c b/src/pkg/regexp/testdata/testregex.c
new file mode 100644
index 000000000..37545d057
--- /dev/null
+++ b/src/pkg/regexp/testdata/testregex.c
@@ -0,0 +1,2286 @@
+#pragma prototyped noticed
+
+/*
+ * regex(3) test harness
+ *
+ * build: cc -o testregex testregex.c
+ * help: testregex --man
+ * note: REG_* features are detected by #ifdef; if REG_* are enums
+ * then supply #define REG_foo REG_foo for each enum REG_foo
+ *
+ * Glenn Fowler <gsf@research.att.com>
+ * AT&T Research
+ *
+ * PLEASE: publish your tests so everyone can benefit
+ *
+ * The following license covers testregex.c and all associated test data.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of the
+ * Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following disclaimer:
+ *
+ * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2010-06-10 $\0\n";
+
+#if _PACKAGE_ast
+#include <ast.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#include <regex.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+#ifndef RE_DUP_MAX
+#define RE_DUP_MAX 32767
+#endif
+
+#if !_PACKAGE_ast
+#undef REG_DISCIPLINE
+#endif
+
+#ifndef REG_DELIMITED
+#undef _REG_subcomp
+#endif
+
+#define TEST_ARE 0x00000001
+#define TEST_BRE 0x00000002
+#define TEST_ERE 0x00000004
+#define TEST_KRE 0x00000008
+#define TEST_LRE 0x00000010
+#define TEST_SRE 0x00000020
+
+#define TEST_EXPAND 0x00000100
+#define TEST_LENIENT 0x00000200
+
+#define TEST_QUERY 0x00000400
+#define TEST_SUB 0x00000800
+#define TEST_UNSPECIFIED 0x00001000
+#define TEST_VERIFY 0x00002000
+#define TEST_AND 0x00004000
+#define TEST_OR 0x00008000
+
+#define TEST_DELIMIT 0x00010000
+#define TEST_OK 0x00020000
+#define TEST_SAME 0x00040000
+
+#define TEST_ACTUAL 0x00100000
+#define TEST_BASELINE 0x00200000
+#define TEST_FAIL 0x00400000
+#define TEST_PASS 0x00800000
+#define TEST_SUMMARY 0x01000000
+
+#define TEST_IGNORE_ERROR 0x02000000
+#define TEST_IGNORE_OVER 0x04000000
+#define TEST_IGNORE_POSITION 0x08000000
+
+#define TEST_CATCH 0x10000000
+#define TEST_VERBOSE 0x20000000
+
+#define TEST_DECOMP 0x40000000
+
+#define TEST_GLOBAL (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
+
+#ifdef REG_DISCIPLINE
+
+
+#include <stk.h>
+
+typedef struct Disc_s
+{
+ regdisc_t disc;
+ int ordinal;
+ Sfio_t* sp;
+} Disc_t;
+
+static void*
+compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
+{
+ Disc_t* dp = (Disc_t*)disc;
+
+ return (void*)((char*)0 + ++dp->ordinal);
+}
+
+static int
+execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
+{
+ Disc_t* dp = (Disc_t*)disc;
+
+ sfprintf(dp->sp, "{%-.*s}(%lu:%d)", xlen, xstr, (char*)data - (char*)0, slen);
+ return atoi(xstr);
+}
+
+static void*
+resizef(void* handle, void* data, size_t size)
+{
+ if (!size)
+ return 0;
+ return stkalloc((Sfio_t*)handle, size);
+}
+
+#endif
+
+#ifndef NiL
+#ifdef __STDC__
+#define NiL 0
+#else
+#define NiL (char*)0
+#endif
+#endif
+
+#define H(x) do{if(html)fprintf(stderr,x);}while(0)
+#define T(x) fprintf(stderr,x)
+
+static void
+help(int html)
+{
+H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
+H("<HTML>\n");
+H("<HEAD>\n");
+H("<TITLE>testregex man document</TITLE>\n");
+H("</HEAD>\n");
+H("<BODY bgcolor=white>\n");
+H("<PRE>\n");
+T("NAME\n");
+T(" testregex - regex(3) test harness\n");
+T("\n");
+T("SYNOPSIS\n");
+T(" testregex [ options ]\n");
+T("\n");
+T("DESCRIPTION\n");
+T(" testregex reads regex(3) test specifications, one per line, from the\n");
+T(" standard input and writes one output line for each failed test. A\n");
+T(" summary line is written after all tests are done. Each successful\n");
+T(" test is run again with REG_NOSUB. Unsupported features are noted\n");
+T(" before the first test, and tests requiring these features are\n");
+T(" silently ignored.\n");
+T("\n");
+T("OPTIONS\n");
+T(" -c catch signals and non-terminating calls\n");
+T(" -e ignore error return mismatches\n");
+T(" -h list help on standard error\n");
+T(" -n do not repeat successful tests with regnexec()\n");
+T(" -o ignore match[] overrun errors\n");
+T(" -p ignore negative position mismatches\n");
+T(" -s use stack instead of malloc\n");
+T(" -x do not repeat successful tests with REG_NOSUB\n");
+T(" -v list each test line\n");
+T(" -A list failed test lines with actual answers\n");
+T(" -B list all test lines with actual answers\n");
+T(" -F list failed test lines\n");
+T(" -P list passed test lines\n");
+T(" -S output one summary line\n");
+T("\n");
+T("INPUT FORMAT\n");
+T(" Input lines may be blank, a comment beginning with #, or a test\n");
+T(" specification. A specification is five fields separated by one\n");
+T(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
+T(" 0 pointer.\n");
+T("\n");
+T(" Field 1: the regex(3) flags to apply, one character per REG_feature\n");
+T(" flag. The test is skipped if REG_feature is not supported by the\n");
+T(" implementation. If the first character is not [BEASKLP] then the\n");
+T(" specification is a global control line. One or more of [BEASKLP] may be\n");
+T(" specified; the test will be repeated for each mode.\n");
+T("\n");
+T(" B basic BRE (grep, ed, sed)\n");
+T(" E REG_EXTENDED ERE (egrep)\n");
+T(" A REG_AUGMENTED ARE (egrep with negation)\n");
+T(" S REG_SHELL SRE (sh glob)\n");
+T(" K REG_SHELL|REG_AUGMENTED KRE (ksh glob)\n");
+T(" L REG_LITERAL LRE (fgrep)\n");
+T("\n");
+T(" a REG_LEFT|REG_RIGHT implicit ^...$\n");
+T(" b REG_NOTBOL lhs does not match ^\n");
+T(" c REG_COMMENT ignore space and #...\\n\n");
+T(" d REG_SHELL_DOT explicit leading . match\n");
+T(" e REG_NOTEOL rhs does not match $\n");
+T(" f REG_MULTIPLE multiple \\n separated patterns\n");
+T(" g FNM_LEADING_DIR testfnmatch only -- match until /\n");
+T(" h REG_MULTIREF multiple digit backref\n");
+T(" i REG_ICASE ignore case\n");
+T(" j REG_SPAN . matches \\n\n");
+T(" k REG_ESCAPE \\ to ecape [...] delimiter\n");
+T(" l REG_LEFT implicit ^...\n");
+T(" m REG_MINIMAL minimal match\n");
+T(" n REG_NEWLINE explicit \\n match\n");
+T(" o REG_ENCLOSED (|&) magic inside [@|&](...)\n");
+T(" p REG_SHELL_PATH explicit / match\n");
+T(" q REG_DELIMITED delimited pattern\n");
+T(" r REG_RIGHT implicit ...$\n");
+T(" s REG_SHELL_ESCAPED \\ not special\n");
+T(" t REG_MUSTDELIM all delimiters must be specified\n");
+T(" u standard unspecified behavior -- errors not counted\n");
+T(" v REG_CLASS_ESCAPE \\ special inside [...]\n");
+T(" w REG_NOSUB no subexpression match array\n");
+T(" x REG_LENIENT let some errors slide\n");
+T(" y REG_LEFT regexec() implicit ^...\n");
+T(" z REG_NULL NULL subexpressions ok\n");
+T(" $ expand C \\c escapes in fields 2 and 3\n");
+T(" / field 2 is a regsubcomp() expression\n");
+T(" = field 3 is a regdecomp() expression\n");
+T("\n");
+T(" Field 1 control lines:\n");
+T("\n");
+T(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
+T("\n");
+T(" ?test ... output field 5 if passed and != EXPECTED, silent otherwise\n");
+T(" &test ... output field 5 if current and previous passed\n");
+T(" |test ... output field 5 if current passed and previous failed\n");
+T(" ; ... output field 2 if previous failed\n");
+T(" {test ... skip if failed until }\n");
+T(" } end of skip\n");
+T("\n");
+T(" : comment comment copied as output NOTE\n");
+T(" :comment:test :comment: ignored\n");
+T(" N[OTE] comment comment copied as output NOTE\n");
+T(" T[EST] comment comment\n");
+T("\n");
+T(" number use number for nmatch (20 by default)\n");
+T("\n");
+T(" Field 2: the regular expression pattern; SAME uses the pattern from\n");
+T(" the previous specification. RE_DUP_MAX inside {...} expands to the\n");
+T(" value from <limits.h>.\n");
+T("\n");
+T(" Field 3: the string to match. X...{RE_DUP_MAX} expands to RE_DUP_MAX\n");
+T(" copies of X.\n");
+T("\n");
+T(" Field 4: the test outcome. This is either one of the posix error\n");
+T(" codes (with REG_ omitted) or the match array, a list of (m,n)\n");
+T(" entries with m and n being first and last+1 positions in the\n");
+T(" field 3 string, or NULL if REG_NOSUB is in effect and success\n");
+T(" is expected. BADPAT is acceptable in place of any regcomp(3)\n");
+T(" error code. The match[] array is initialized to (-2,-2) before\n");
+T(" each test. All array elements from 0 to nmatch-1 must be specified\n");
+T(" in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
+T(" Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
+T(" matched (?{...}) expression, where x is the text enclosed by {...},\n");
+T(" o is the expression ordinal counting from 1, and n is the length of\n");
+T(" the unmatched portion of the subject string. If x starts with a\n");
+T(" number then that is the return value of re_execf(), otherwise 0 is\n");
+T(" returned. RE_DUP_MAX[-+]N expands to the <limits.h> value -+N.\n");
+T("\n");
+T(" Field 5: optional comment appended to the report.\n");
+T("\n");
+T("CAVEAT\n");
+T(" If a regex implementation misbehaves with memory then all bets are off.\n");
+T("\n");
+T("CONTRIBUTORS\n");
+T(" Glenn Fowler gsf@research.att.com (ksh strmatch, regex extensions)\n");
+T(" David Korn dgk@research.att.com (ksh glob matcher)\n");
+T(" Doug McIlroy mcilroy@dartmouth.edu (ast regex/testre in C++)\n");
+T(" Tom Lord lord@regexps.com (rx tests)\n");
+T(" Henry Spencer henry@zoo.toronto.edu (original public regex)\n");
+T(" Andrew Hume andrew@research.att.com (gre tests)\n");
+T(" John Maddock John_Maddock@compuserve.com (regex++ tests)\n");
+T(" Philip Hazel ph10@cam.ac.uk (pcre tests)\n");
+T(" Ville Laurikari vl@iki.fi (libtre tests)\n");
+H("</PRE>\n");
+H("</BODY>\n");
+H("</HTML>\n");
+}
+
+#ifndef elementsof
+#define elementsof(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+#ifndef streq
+#define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
+#endif
+
+#define HUNG 2
+#define NOTEST (~0)
+
+#ifndef REG_TEST_DEFAULT
+#define REG_TEST_DEFAULT 0
+#endif
+
+#ifndef REG_EXEC_DEFAULT
+#define REG_EXEC_DEFAULT 0
+#endif
+
+static const char* unsupported[] =
+{
+ "BASIC",
+#ifndef REG_EXTENDED
+ "EXTENDED",
+#endif
+#ifndef REG_AUGMENTED
+ "AUGMENTED",
+#endif
+#ifndef REG_SHELL
+ "SHELL",
+#endif
+
+#ifndef REG_CLASS_ESCAPE
+ "CLASS_ESCAPE",
+#endif
+#ifndef REG_COMMENT
+ "COMMENT",
+#endif
+#ifndef REG_DELIMITED
+ "DELIMITED",
+#endif
+#ifndef REG_DISCIPLINE
+ "DISCIPLINE",
+#endif
+#ifndef REG_ESCAPE
+ "ESCAPE",
+#endif
+#ifndef REG_ICASE
+ "ICASE",
+#endif
+#ifndef REG_LEFT
+ "LEFT",
+#endif
+#ifndef REG_LENIENT
+ "LENIENT",
+#endif
+#ifndef REG_LITERAL
+ "LITERAL",
+#endif
+#ifndef REG_MINIMAL
+ "MINIMAL",
+#endif
+#ifndef REG_MULTIPLE
+ "MULTIPLE",
+#endif
+#ifndef REG_MULTIREF
+ "MULTIREF",
+#endif
+#ifndef REG_MUSTDELIM
+ "MUSTDELIM",
+#endif
+#ifndef REG_NEWLINE
+ "NEWLINE",
+#endif
+#ifndef REG_NOTBOL
+ "NOTBOL",
+#endif
+#ifndef REG_NOTEOL
+ "NOTEOL",
+#endif
+#ifndef REG_NULL
+ "NULL",
+#endif
+#ifndef REG_RIGHT
+ "RIGHT",
+#endif
+#ifndef REG_SHELL_DOT
+ "SHELL_DOT",
+#endif
+#ifndef REG_SHELL_ESCAPED
+ "SHELL_ESCAPED",
+#endif
+#ifndef REG_SHELL_GROUP
+ "SHELL_GROUP",
+#endif
+#ifndef REG_SHELL_PATH
+ "SHELL_PATH",
+#endif
+#ifndef REG_SPAN
+ "SPAN",
+#endif
+#if REG_NOSUB & REG_TEST_DEFAULT
+ "SUBMATCH",
+#endif
+#if !_REG_nexec
+ "regnexec",
+#endif
+#if !_REG_subcomp
+ "regsubcomp",
+#endif
+#if !_REG_decomp
+ "redecomp",
+#endif
+ 0
+};
+
+#ifndef REG_CLASS_ESCAPE
+#define REG_CLASS_ESCAPE NOTEST
+#endif
+#ifndef REG_COMMENT
+#define REG_COMMENT NOTEST
+#endif
+#ifndef REG_DELIMITED
+#define REG_DELIMITED NOTEST
+#endif
+#ifndef REG_ESCAPE
+#define REG_ESCAPE NOTEST
+#endif
+#ifndef REG_ICASE
+#define REG_ICASE NOTEST
+#endif
+#ifndef REG_LEFT
+#define REG_LEFT NOTEST
+#endif
+#ifndef REG_LENIENT
+#define REG_LENIENT 0
+#endif
+#ifndef REG_MINIMAL
+#define REG_MINIMAL NOTEST
+#endif
+#ifndef REG_MULTIPLE
+#define REG_MULTIPLE NOTEST
+#endif
+#ifndef REG_MULTIREF
+#define REG_MULTIREF NOTEST
+#endif
+#ifndef REG_MUSTDELIM
+#define REG_MUSTDELIM NOTEST
+#endif
+#ifndef REG_NEWLINE
+#define REG_NEWLINE NOTEST
+#endif
+#ifndef REG_NOTBOL
+#define REG_NOTBOL NOTEST
+#endif
+#ifndef REG_NOTEOL
+#define REG_NOTEOL NOTEST
+#endif
+#ifndef REG_NULL
+#define REG_NULL NOTEST
+#endif
+#ifndef REG_RIGHT
+#define REG_RIGHT NOTEST
+#endif
+#ifndef REG_SHELL_DOT
+#define REG_SHELL_DOT NOTEST
+#endif
+#ifndef REG_SHELL_ESCAPED
+#define REG_SHELL_ESCAPED NOTEST
+#endif
+#ifndef REG_SHELL_GROUP
+#define REG_SHELL_GROUP NOTEST
+#endif
+#ifndef REG_SHELL_PATH
+#define REG_SHELL_PATH NOTEST
+#endif
+#ifndef REG_SPAN
+#define REG_SPAN NOTEST
+#endif
+
+#define REG_UNKNOWN (-1)
+
+#ifndef REG_ENEWLINE
+#define REG_ENEWLINE (REG_UNKNOWN-1)
+#endif
+#ifndef REG_ENULL
+#ifndef REG_EMPTY
+#define REG_ENULL (REG_UNKNOWN-2)
+#else
+#define REG_ENULL REG_EMPTY
+#endif
+#endif
+#ifndef REG_ECOUNT
+#define REG_ECOUNT (REG_UNKNOWN-3)
+#endif
+#ifndef REG_BADESC
+#define REG_BADESC (REG_UNKNOWN-4)
+#endif
+#ifndef REG_EMEM
+#define REG_EMEM (REG_UNKNOWN-5)
+#endif
+#ifndef REG_EHUNG
+#define REG_EHUNG (REG_UNKNOWN-6)
+#endif
+#ifndef REG_EBUS
+#define REG_EBUS (REG_UNKNOWN-7)
+#endif
+#ifndef REG_EFAULT
+#define REG_EFAULT (REG_UNKNOWN-8)
+#endif
+#ifndef REG_EFLAGS
+#define REG_EFLAGS (REG_UNKNOWN-9)
+#endif
+#ifndef REG_EDELIM
+#define REG_EDELIM (REG_UNKNOWN-9)
+#endif
+
+static const struct { int code; char* name; } codes[] =
+{
+ REG_UNKNOWN, "UNKNOWN",
+ REG_NOMATCH, "NOMATCH",
+ REG_BADPAT, "BADPAT",
+ REG_ECOLLATE, "ECOLLATE",
+ REG_ECTYPE, "ECTYPE",
+ REG_EESCAPE, "EESCAPE",
+ REG_ESUBREG, "ESUBREG",
+ REG_EBRACK, "EBRACK",
+ REG_EPAREN, "EPAREN",
+ REG_EBRACE, "EBRACE",
+ REG_BADBR, "BADBR",
+ REG_ERANGE, "ERANGE",
+ REG_ESPACE, "ESPACE",
+ REG_BADRPT, "BADRPT",
+ REG_ENEWLINE, "ENEWLINE",
+ REG_ENULL, "ENULL",
+ REG_ECOUNT, "ECOUNT",
+ REG_BADESC, "BADESC",
+ REG_EMEM, "EMEM",
+ REG_EHUNG, "EHUNG",
+ REG_EBUS, "EBUS",
+ REG_EFAULT, "EFAULT",
+ REG_EFLAGS, "EFLAGS",
+ REG_EDELIM, "EDELIM",
+};
+
+static struct
+{
+ regmatch_t NOMATCH;
+ int errors;
+ int extracted;
+ int ignored;
+ int lineno;
+ int passed;
+ int signals;
+ int unspecified;
+ int verify;
+ int warnings;
+ char* file;
+ char* stack;
+ char* which;
+ jmp_buf gotcha;
+#ifdef REG_DISCIPLINE
+ Disc_t disc;
+#endif
+} state;
+
+static void
+quote(char* s, int len, unsigned long test)
+{
+ unsigned char* u = (unsigned char*)s;
+ unsigned char* e;
+ int c;
+#ifdef MB_CUR_MAX
+ int w;
+#endif
+
+ if (!u)
+ printf("NIL");
+ else if (!*u && len <= 1)
+ printf("NULL");
+ else if (test & TEST_EXPAND)
+ {
+ if (len < 0)
+ len = strlen((char*)u);
+ e = u + len;
+ if (test & TEST_DELIMIT)
+ printf("\"");
+ while (u < e)
+ switch (c = *u++)
+ {
+ case '\\':
+ printf("\\\\");
+ break;
+ case '"':
+ if (test & TEST_DELIMIT)
+ printf("\\\"");
+ else
+ printf("\"");
+ break;
+ case '\a':
+ printf("\\a");
+ break;
+ case '\b':
+ printf("\\b");
+ break;
+ case 033:
+ printf("\\e");
+ break;
+ case '\f':
+ printf("\\f");
+ break;
+ case '\n':
+ printf("\\n");
+ break;
+ case '\r':
+ printf("\\r");
+ break;
+ case '\t':
+ printf("\\t");
+ break;
+ case '\v':
+ printf("\\v");
+ break;
+ default:
+#ifdef MB_CUR_MAX
+ s = (char*)u - 1;
+ if ((w = mblen(s, (char*)e - s)) > 1)
+ {
+ u += w - 1;
+ fwrite(s, 1, w, stdout);
+ }
+ else
+#endif
+ if (!iscntrl(c) && isprint(c))
+ putchar(c);
+ else
+ printf("\\x%02x", c);
+ break;
+ }
+ if (test & TEST_DELIMIT)
+ printf("\"");
+ }
+ else
+ printf("%s", s);
+}
+
+static void
+report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
+{
+ if (state.file)
+ printf("%s:", state.file);
+ printf("%d:", state.lineno);
+ if (re)
+ {
+ printf(" ");
+ quote(re, -1, test|TEST_DELIMIT);
+ if (s)
+ {
+ printf(" versus ");
+ quote(s, len, test|TEST_DELIMIT);
+ }
+ }
+ if (test & TEST_UNSPECIFIED)
+ {
+ state.unspecified++;
+ printf(" unspecified behavior");
+ }
+ else
+ state.errors++;
+ if (state.which)
+ printf(" %s", state.which);
+ if (flags & REG_NOSUB)
+ printf(" NOSUB");
+ if (fun)
+ printf(" %s", fun);
+ if (comment[strlen(comment)-1] == '\n')
+ printf(" %s", comment);
+ else
+ {
+ printf(" %s: ", comment);
+ if (msg)
+ printf("%s: ", msg);
+ }
+}
+
+static void
+error(regex_t* preg, int code)
+{
+ char* msg;
+ char buf[256];
+
+ switch (code)
+ {
+ case REG_EBUS:
+ msg = "bus error";
+ break;
+ case REG_EFAULT:
+ msg = "memory fault";
+ break;
+ case REG_EHUNG:
+ msg = "did not terminate";
+ break;
+ default:
+ regerror(code, preg, msg = buf, sizeof buf);
+ break;
+ }
+ printf("%s\n", msg);
+}
+
+static void
+bad(char* comment, char* re, char* s, int len, unsigned long test)
+{
+ printf("bad test case ");
+ report(comment, NiL, re, s, len, NiL, 0, test);
+ exit(1);
+}
+
+static int
+escape(char* s)
+{
+ char* b;
+ char* t;
+ char* q;
+ char* e;
+ int c;
+
+ for (b = t = s; *t = *s; s++, t++)
+ if (*s == '\\')
+ switch (*++s)
+ {
+ case '\\':
+ break;
+ case 'a':
+ *t = '\a';
+ break;
+ case 'b':
+ *t = '\b';
+ break;
+ case 'c':
+ if (*t = *++s)
+ *t &= 037;
+ else
+ s--;
+ break;
+ case 'e':
+ case 'E':
+ *t = 033;
+ break;
+ case 'f':
+ *t = '\f';
+ break;
+ case 'n':
+ *t = '\n';
+ break;
+ case 'r':
+ *t = '\r';
+ break;
+ case 's':
+ *t = ' ';
+ break;
+ case 't':
+ *t = '\t';
+ break;
+ case 'v':
+ *t = '\v';
+ break;
+ case 'u':
+ case 'x':
+ c = 0;
+ q = c == 'u' ? (s + 5) : (char*)0;
+ e = s + 1;
+ while (!e || !q || s < q)
+ {
+ switch (*++s)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ c = (c << 4) + *s - 'a' + 10;
+ continue;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ c = (c << 4) + *s - 'A' + 10;
+ continue;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ c = (c << 4) + *s - '0';
+ continue;
+ case '{':
+ case '[':
+ if (s != e)
+ {
+ s--;
+ break;
+ }
+ e = 0;
+ continue;
+ case '}':
+ case ']':
+ if (e)
+ s--;
+ break;
+ default:
+ s--;
+ break;
+ }
+ break;
+ }
+ *t = c;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = *s - '0';
+ q = s + 2;
+ while (s < q)
+ {
+ switch (*++s)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = (c << 3) + *s - '0';
+ break;
+ default:
+ q = --s;
+ break;
+ }
+ }
+ *t = c;
+ break;
+ default:
+ *(s + 1) = 0;
+ bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
+ }
+ return t - b;
+}
+
+static void
+matchoffprint(int off)
+{
+ switch (off)
+ {
+ case -2:
+ printf("X");
+ break;
+ case -1:
+ printf("?");
+ break;
+ default:
+ printf("%d", off);
+ break;
+ }
+}
+
+static void
+matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
+{
+ int i;
+
+ for (; nmatch > nsub + 1; nmatch--)
+ if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0))
+ break;
+ for (i = 0; i < nmatch; i++)
+ {
+ printf("(");
+ matchoffprint(match[i].rm_so);
+ printf(",");
+ matchoffprint(match[i].rm_eo);
+ printf(")");
+ }
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
+ {
+ if (ans)
+ printf(" expected: %s", ans);
+ printf("\n");
+ }
+}
+
+static int
+matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
+{
+ char* p;
+ int i;
+ int m;
+ int n;
+
+ if (streq(ans, "OK"))
+ return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
+ for (i = 0, p = ans; i < nmatch && *p; i++)
+ {
+ if (*p == '{')
+ {
+#ifdef REG_DISCIPLINE
+ char* x;
+
+ if (!(x = sfstruse(state.disc.sp)))
+ bad("out of space [discipline string]\n", NiL, NiL, 0, 0);
+ if (strcmp(p, x))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ return 0;
+ report("callout failed", NiL, re, s, len, NiL, flags, test);
+ quote(p, -1, test);
+ printf(" expected, ");
+ quote(x, -1, test);
+ printf(" returned\n");
+ }
+#endif
+ break;
+ }
+ if (*p++ != '(')
+ bad("improper answer\n", re, s, -1, test);
+ if (*p == '?')
+ {
+ m = -1;
+ p++;
+ }
+ else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
+ {
+ m = RE_DUP_MAX;
+ p += 10;
+ if (*p == '+' || *p == '-')
+ m += strtol(p, &p, 10);
+ }
+ else
+ m = strtol(p, &p, 10);
+ if (*p++ != ',')
+ bad("improper answer\n", re, s, -1, test);
+ if (*p == '?')
+ {
+ n = -1;
+ p++;
+ }
+ else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
+ {
+ n = RE_DUP_MAX;
+ p += 10;
+ if (*p == '+' || *p == '-')
+ n += strtol(p, &p, 10);
+ }
+ else
+ n = strtol(p, &p, 10);
+ if (*p++ != ')')
+ bad("improper answer\n", re, s, -1, test);
+ if (m!=match[i].rm_so || n!=match[i].rm_eo)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
+ {
+ report("failed: match was", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch, nsub, ans, test);
+ }
+ return 0;
+ }
+ }
+ for (; i < nmatch; i++)
+ {
+ if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
+ {
+ if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
+ {
+ state.ignored++;
+ return 0;
+ }
+ if (!(test & TEST_SUMMARY))
+ {
+ report("failed: match was", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch, nsub, ans, test);
+ }
+ }
+ return 0;
+ }
+ }
+ if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
+ {
+ report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
+ matchprint(match, nmatch + 1, nsub, NiL, test);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static void
+sigunblock(int s)
+{
+#ifdef SIG_SETMASK
+ int op;
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ if (s)
+ {
+ sigaddset(&mask, s);
+ op = SIG_UNBLOCK;
+ }
+ else op = SIG_SETMASK;
+ sigprocmask(op, &mask, NiL);
+#else
+#ifdef sigmask
+ sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
+#endif
+#endif
+}
+
+static void
+gotcha(int sig)
+{
+ int ret;
+
+ signal(sig, gotcha);
+ alarm(0);
+ state.signals++;
+ switch (sig)
+ {
+ case SIGALRM:
+ ret = REG_EHUNG;
+ break;
+ case SIGBUS:
+ ret = REG_EBUS;
+ break;
+ default:
+ ret = REG_EFAULT;
+ break;
+ }
+ sigunblock(sig);
+ longjmp(state.gotcha, ret);
+}
+
+static char*
+getline(FILE* fp)
+{
+ static char buf[32 * 1024];
+
+ register char* s = buf;
+ register char* e = &buf[sizeof(buf)];
+ register char* b;
+
+ for (;;)
+ {
+ if (!(b = fgets(s, e - s, fp)))
+ return 0;
+ state.lineno++;
+ s += strlen(s);
+ if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
+ {
+ *s = 0;
+ break;
+ }
+ s--;
+ }
+ return buf;
+}
+
+static unsigned long
+note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
+{
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
+ {
+ printf("NOTE\t");
+ if (msg)
+ printf("%s: ", msg);
+ printf("skipping lines %d", state.lineno);
+ }
+ return skip | level;
+}
+
+#define TABS(n) &ts[7-((n)&7)]
+
+static char ts[] = "\t\t\t\t\t\t\t";
+
+static unsigned long
+extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
+{
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
+ {
+ state.extracted = 1;
+ if (test & TEST_OK)
+ {
+ state.passed++;
+ if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ if (msg && strcmp(msg, "EXPECTED"))
+ printf("NOTE\t%s\n", msg);
+ return skip;
+ }
+ test &= ~(TEST_PASS|TEST_QUERY);
+ }
+ if (test & (TEST_QUERY|TEST_VERIFY))
+ {
+ if (test & TEST_BASELINE)
+ test &= ~(TEST_BASELINE|TEST_PASS);
+ else
+ test |= TEST_PASS;
+ skip |= level;
+ }
+ if (!(test & TEST_OK))
+ {
+ if (test & TEST_UNSPECIFIED)
+ state.unspecified++;
+ else
+ state.errors++;
+ }
+ if (test & (TEST_PASS|TEST_SUMMARY))
+ return skip;
+ test &= ~TEST_DELIMIT;
+ printf("%s%s", spec, TABS(*tabs++));
+ if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
+ printf("SAME");
+ else
+ quote(re, -1, test);
+ printf("%s", TABS(*tabs++));
+ quote(s, -1, test);
+ printf("%s", TABS(*tabs++));
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || !accept && !match)
+ printf("%s", ans);
+ else if (accept)
+ printf("%s", accept);
+ else
+ matchprint(match, nmatch, nsub, NiL, test);
+ if (msg)
+ printf("%s%s", TABS(*tabs++), msg);
+ putchar('\n');
+ }
+ else if (test & TEST_QUERY)
+ skip = note(level, msg, skip, test);
+ else if (test & TEST_VERIFY)
+ state.extracted = 1;
+ return skip;
+}
+
+static int
+catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
+{
+ int eret;
+
+ if (!(test & TEST_CATCH))
+ {
+ regfree(preg);
+ eret = 0;
+ }
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ regfree(preg);
+ alarm(0);
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ else
+ {
+ report("failed", "regfree", re, NiL, -1, msg, flags, test);
+ error(preg, eret);
+ }
+ return eret;
+}
+
+static char*
+expand(char* os, char* ot)
+{
+ char* s = os;
+ char* t;
+ int n = 0;
+ int r;
+ long m;
+
+ for (;;)
+ {
+ switch (*s++)
+ {
+ case 0:
+ break;
+ case '{':
+ n++;
+ continue;
+ case '}':
+ n--;
+ continue;
+ case 'R':
+ if (n == 1 && !memcmp(s, "E_DUP_MAX", 9))
+ {
+ s--;
+ for (t = ot; os < s; *t++ = *os++);
+ r = ((t - ot) >= 5 && t[-1] == '{' && t[-2] == '.' && t[-3] == '.' && t[-4] == '.') ? t[-5] : 0;
+ os = ot;
+ m = RE_DUP_MAX;
+ if (*(s += 10) == '+' || *s == '-')
+ m += strtol(s, &s, 10);
+ if (r)
+ {
+ t -= 5;
+ while (m-- > 0)
+ *t++ = r;
+ while (*s && *s++ != '}');
+ }
+ else
+ t += snprintf(t, 32, "%ld", m);
+ while (*t = *s++)
+ t++;
+ break;
+ }
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ return os;
+}
+
+int
+main(int argc, char** argv)
+{
+ int flags;
+ int cflags;
+ int eflags;
+ int nmatch;
+ int nexec;
+ int nstr;
+ int cret;
+ int eret;
+ int nsub;
+ int i;
+ int j;
+ int expected;
+ int got;
+ int locale;
+ int subunitlen;
+ int testno;
+ unsigned long level;
+ unsigned long skip;
+ char* p;
+ char* line;
+ char* spec;
+ char* re;
+ char* s;
+ char* ans;
+ char* msg;
+ char* fun;
+ char* ppat;
+ char* subunit;
+ char* version;
+ char* field[6];
+ char* delim[6];
+ FILE* fp;
+ int tabs[6];
+ char unit[64];
+ regmatch_t match[100];
+ regex_t preg;
+
+ static char pat[32 * 1024];
+ static char patbuf[32 * 1024];
+ static char strbuf[32 * 1024];
+
+ int nonosub = REG_NOSUB == 0;
+ int nonexec = 0;
+
+ unsigned long test = 0;
+
+ static char* filter[] = { "-", 0 };
+
+ state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
+ p = unit;
+ version = (char*)id + 10;
+ while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
+ p++;
+ *p = 0;
+ while ((p = *++argv) && *p == '-')
+ for (;;)
+ {
+ switch (*++p)
+ {
+ case 0:
+ break;
+ case 'c':
+ test |= TEST_CATCH;
+ continue;
+ case 'e':
+ test |= TEST_IGNORE_ERROR;
+ continue;
+ case 'h':
+ case '?':
+ help(0);
+ return 2;
+ case '-':
+ help(p[1] == 'h');
+ return 2;
+ case 'n':
+ nonexec = 1;
+ continue;
+ case 'o':
+ test |= TEST_IGNORE_OVER;
+ continue;
+ case 'p':
+ test |= TEST_IGNORE_POSITION;
+ continue;
+ case 's':
+#ifdef REG_DISCIPLINE
+ if (!(state.stack = stkalloc(stkstd, 0)))
+ fprintf(stderr, "%s: out of space [stack]", unit);
+ state.disc.disc.re_resizef = resizef;
+ state.disc.disc.re_resizehandle = (void*)stkstd;
+#endif
+ continue;
+ case 'x':
+ nonosub = 1;
+ continue;
+ case 'v':
+ test |= TEST_VERBOSE;
+ continue;
+ case 'A':
+ test |= TEST_ACTUAL;
+ continue;
+ case 'B':
+ test |= TEST_BASELINE;
+ continue;
+ case 'F':
+ test |= TEST_FAIL;
+ continue;
+ case 'P':
+ test |= TEST_PASS;
+ continue;
+ case 'S':
+ test |= TEST_SUMMARY;
+ continue;
+ default:
+ fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
+ return 2;
+ }
+ break;
+ }
+ if (!*argv)
+ argv = filter;
+ locale = 0;
+ while (state.file = *argv++)
+ {
+ if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
+ {
+ state.file = 0;
+ fp = stdin;
+ }
+ else if (!(fp = fopen(state.file, "r")))
+ {
+ fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
+ return 2;
+ }
+ testno = state.errors = state.ignored = state.lineno = state.passed =
+ state.signals = state.unspecified = state.warnings = 0;
+ skip = 0;
+ level = 1;
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ printf("TEST\t%s ", unit);
+ if (s = state.file)
+ {
+ subunit = p = 0;
+ for (;;)
+ {
+ switch (*s++)
+ {
+ case 0:
+ break;
+ case '/':
+ subunit = s;
+ continue;
+ case '.':
+ p = s - 1;
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (!subunit)
+ subunit = state.file;
+ if (p < subunit)
+ p = s - 1;
+ subunitlen = p - subunit;
+ printf("%-.*s ", subunitlen, subunit);
+ }
+ else
+ subunit = 0;
+ for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
+ putchar(*s);
+ if (test & TEST_CATCH)
+ printf(", catch");
+ if (test & TEST_IGNORE_ERROR)
+ printf(", ignore error code mismatches");
+ if (test & TEST_IGNORE_POSITION)
+ printf(", ignore negative position mismatches");
+#ifdef REG_DISCIPLINE
+ if (state.stack)
+ printf(", stack");
+#endif
+ if (test & TEST_VERBOSE)
+ printf(", verbose");
+ printf("\n");
+#ifdef REG_VERSIONID
+ if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
+ s = pat;
+ else
+#endif
+#ifdef REG_TEST_VERSION
+ s = REG_TEST_VERSION;
+#else
+ s = "regex";
+#endif
+ printf("NOTE\t%s\n", s);
+ if (elementsof(unsupported) > 1)
+ {
+#if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
+ i = 0;
+#else
+ i = REG_EXTENDED != 0;
+#endif
+ for (got = 0; i < elementsof(unsupported) - 1; i++)
+ {
+ if (!got)
+ {
+ got = 1;
+ printf("NOTE\tunsupported: %s", unsupported[i]);
+ }
+ else
+ printf(",%s", unsupported[i]);
+ }
+ if (got)
+ printf("\n");
+ }
+ }
+#ifdef REG_DISCIPLINE
+ state.disc.disc.re_version = REG_VERSION;
+ state.disc.disc.re_compf = compf;
+ state.disc.disc.re_execf = execf;
+ if (!(state.disc.sp = sfstropen()))
+ bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
+ preg.re_disc = &state.disc.disc;
+#endif
+ if (test & TEST_CATCH)
+ {
+ signal(SIGALRM, gotcha);
+ signal(SIGBUS, gotcha);
+ signal(SIGSEGV, gotcha);
+ }
+ while (p = getline(fp))
+ {
+
+ /* parse: */
+
+ line = p;
+ if (*p == ':' && !isspace(*(p + 1)))
+ {
+ while (*++p && *p != ':');
+ if (!*p++)
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ continue;
+ }
+ }
+ while (isspace(*p))
+ p++;
+ if (*p == 0 || *p == '#' || *p == 'T')
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ continue;
+ }
+ if (*p == ':' || *p == 'N')
+ {
+ if (test & TEST_BASELINE)
+ printf("%s\n", line);
+ else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ {
+ while (*++p && !isspace(*p));
+ while (isspace(*p))
+ p++;
+ printf("NOTE %s\n", p);
+ }
+ continue;
+ }
+ j = 0;
+ i = 0;
+ field[i++] = p;
+ for (;;)
+ {
+ switch (*p++)
+ {
+ case 0:
+ p--;
+ j = 0;
+ goto checkfield;
+ case '\t':
+ *(delim[i] = p - 1) = 0;
+ j = 1;
+ checkfield:
+ s = field[i - 1];
+ if (streq(s, "NIL"))
+ field[i - 1] = 0;
+ else if (streq(s, "NULL"))
+ *s = 0;
+ while (*p == '\t')
+ {
+ p++;
+ j++;
+ }
+ tabs[i - 1] = j;
+ if (!*p)
+ break;
+ if (i >= elementsof(field))
+ bad("too many fields\n", NiL, NiL, 0, 0);
+ field[i++] = p;
+ /*FALLTHROUGH*/
+ default:
+ continue;
+ }
+ break;
+ }
+ if (!(spec = field[0]))
+ bad("NIL spec\n", NiL, NiL, 0, 0);
+
+ /* interpret: */
+
+ cflags = REG_TEST_DEFAULT;
+ eflags = REG_EXEC_DEFAULT;
+ test &= TEST_GLOBAL;
+ state.extracted = 0;
+ nmatch = 20;
+ nsub = -1;
+ for (p = spec; *p; p++)
+ {
+ if (isdigit(*p))
+ {
+ nmatch = strtol(p, &p, 10);
+ if (nmatch >= elementsof(match))
+ bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
+ p--;
+ continue;
+ }
+ switch (*p)
+ {
+ case 'A':
+ test |= TEST_ARE;
+ continue;
+ case 'B':
+ test |= TEST_BRE;
+ continue;
+ case 'C':
+ if (!(test & TEST_QUERY) && !(skip & level))
+ bad("locale must be nested\n", NiL, NiL, 0, 0);
+ test &= ~TEST_QUERY;
+ if (locale)
+ bad("locale nesting not supported\n", NiL, NiL, 0, 0);
+ if (i != 2)
+ bad("locale field expected\n", NiL, NiL, 0, 0);
+ if (!(skip & level))
+ {
+#if defined(LC_COLLATE) && defined(LC_CTYPE)
+ s = field[1];
+ if (!s || streq(s, "POSIX"))
+ s = "C";
+ if ((ans = setlocale(LC_COLLATE, s)) && streq(ans, "POSIX"))
+ ans = "C";
+ if (!ans || !streq(ans, s) && streq(s, "C"))
+ ans = 0;
+ else if ((ans = setlocale(LC_CTYPE, s)) && streq(ans, "POSIX"))
+ ans = "C";
+ if (!ans || !streq(ans, s) && streq(s, "C"))
+ skip = note(level, s, skip, test);
+ else
+ {
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ printf("NOTE \"%s\" locale\n", s);
+ locale = level;
+ }
+#else
+ skip = note(level, skip, test, "locales not supported");
+#endif
+ }
+ cflags = NOTEST;
+ continue;
+ case 'E':
+ test |= TEST_ERE;
+ continue;
+ case 'K':
+ test |= TEST_KRE;
+ continue;
+ case 'L':
+ test |= TEST_LRE;
+ continue;
+ case 'S':
+ test |= TEST_SRE;
+ continue;
+
+ case 'a':
+ cflags |= REG_LEFT|REG_RIGHT;
+ continue;
+ case 'b':
+ eflags |= REG_NOTBOL;
+ continue;
+ case 'c':
+ cflags |= REG_COMMENT;
+ continue;
+ case 'd':
+ cflags |= REG_SHELL_DOT;
+ continue;
+ case 'e':
+ eflags |= REG_NOTEOL;
+ continue;
+ case 'f':
+ cflags |= REG_MULTIPLE;
+ continue;
+ case 'g':
+ cflags |= NOTEST;
+ continue;
+ case 'h':
+ cflags |= REG_MULTIREF;
+ continue;
+ case 'i':
+ cflags |= REG_ICASE;
+ continue;
+ case 'j':
+ cflags |= REG_SPAN;
+ continue;
+ case 'k':
+ cflags |= REG_ESCAPE;
+ continue;
+ case 'l':
+ cflags |= REG_LEFT;
+ continue;
+ case 'm':
+ cflags |= REG_MINIMAL;
+ continue;
+ case 'n':
+ cflags |= REG_NEWLINE;
+ continue;
+ case 'o':
+ cflags |= REG_SHELL_GROUP;
+ continue;
+ case 'p':
+ cflags |= REG_SHELL_PATH;
+ continue;
+ case 'q':
+ cflags |= REG_DELIMITED;
+ continue;
+ case 'r':
+ cflags |= REG_RIGHT;
+ continue;
+ case 's':
+ cflags |= REG_SHELL_ESCAPED;
+ continue;
+ case 't':
+ cflags |= REG_MUSTDELIM;
+ continue;
+ case 'u':
+ test |= TEST_UNSPECIFIED;
+ continue;
+ case 'v':
+ cflags |= REG_CLASS_ESCAPE;
+ continue;
+ case 'w':
+ cflags |= REG_NOSUB;
+ continue;
+ case 'x':
+ if (REG_LENIENT)
+ cflags |= REG_LENIENT;
+ else
+ test |= TEST_LENIENT;
+ continue;
+ case 'y':
+ eflags |= REG_LEFT;
+ continue;
+ case 'z':
+ cflags |= REG_NULL;
+ continue;
+
+ case '$':
+ test |= TEST_EXPAND;
+ continue;
+
+ case '/':
+ test |= TEST_SUB;
+ continue;
+
+ case '=':
+ test |= TEST_DECOMP;
+ continue;
+
+ case '?':
+ test |= TEST_VERIFY;
+ test &= ~(TEST_AND|TEST_OR);
+ state.verify = state.passed;
+ continue;
+ case '&':
+ test |= TEST_VERIFY|TEST_AND;
+ test &= ~TEST_OR;
+ continue;
+ case '|':
+ test |= TEST_VERIFY|TEST_OR;
+ test &= ~TEST_AND;
+ continue;
+ case ';':
+ test |= TEST_OR;
+ test &= ~TEST_AND;
+ continue;
+
+ case '{':
+ level <<= 1;
+ if (skip & (level >> 1))
+ {
+ skip |= level;
+ cflags = NOTEST;
+ }
+ else
+ {
+ skip &= ~level;
+ test |= TEST_QUERY;
+ }
+ continue;
+ case '}':
+ if (level == 1)
+ bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
+ if ((skip & level) && !(skip & (level>>1)))
+ {
+ if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
+ {
+ if (test & (TEST_ACTUAL|TEST_FAIL))
+ printf("}\n");
+ else if (!(test & TEST_PASS))
+ printf("-%d\n", state.lineno);
+ }
+ }
+#if defined(LC_COLLATE) && defined(LC_CTYPE)
+ else if (locale & level)
+ {
+ locale = 0;
+ if (!(skip & level))
+ {
+ s = "C";
+ setlocale(LC_COLLATE, s);
+ setlocale(LC_CTYPE, s);
+ if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
+ printf("NOTE \"%s\" locale\n", s);
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
+ printf("}\n");
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
+ printf("}\n");
+ }
+#endif
+ level >>= 1;
+ cflags = NOTEST;
+ continue;
+
+ default:
+ bad("bad spec\n", spec, NiL, 0, test);
+ break;
+
+ }
+ break;
+ }
+ if ((cflags|eflags) == NOTEST || (skip & level) && (test & TEST_BASELINE))
+ {
+ if (test & TEST_BASELINE)
+ {
+ while (i > 1)
+ *delim[--i] = '\t';
+ printf("%s\n", line);
+ }
+ continue;
+ }
+ if (test & TEST_OR)
+ {
+ if (!(test & TEST_VERIFY))
+ {
+ test &= ~TEST_OR;
+ if (state.passed == state.verify && i > 1)
+ printf("NOTE\t%s\n", field[1]);
+ continue;
+ }
+ else if (state.passed > state.verify)
+ continue;
+ }
+ else if (test & TEST_AND)
+ {
+ if (state.passed == state.verify)
+ continue;
+ state.passed = state.verify;
+ }
+ if (i < ((test & TEST_DECOMP) ? 3 : 4))
+ bad("too few fields\n", NiL, NiL, 0, test);
+ while (i < elementsof(field))
+ field[i++] = 0;
+ if (re = field[1])
+ {
+ if (streq(re, "SAME"))
+ {
+ re = ppat;
+ test |= TEST_SAME;
+ }
+ else
+ {
+ if (test & TEST_EXPAND)
+ escape(re);
+ re = expand(re, patbuf);
+ strcpy(ppat = pat, re);
+ }
+ }
+ else
+ ppat = 0;
+ nstr = -1;
+ if (s = field[2])
+ {
+ s = expand(s, strbuf);
+ if (test & TEST_EXPAND)
+ {
+ nstr = escape(s);
+#if _REG_nexec
+ if (nstr != strlen(s))
+ nexec = nstr;
+#endif
+ }
+ }
+ if (!(ans = field[(test & TEST_DECOMP) ? 2 : 3]))
+ bad("NIL answer\n", NiL, NiL, 0, test);
+ msg = field[4];
+ fflush(stdout);
+ if (test & TEST_SUB)
+#if _REG_subcomp
+ cflags |= REG_DELIMITED;
+#else
+ continue;
+#endif
+#if !_REG_decomp
+ if (test & TEST_DECOMP)
+ continue;
+#endif
+
+ compile:
+
+ if (state.extracted || (skip & level))
+ continue;
+#if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
+#ifdef REG_EXTENDED
+ if (REG_EXTENDED != 0 && (test & TEST_BRE))
+#else
+ if (test & TEST_BRE)
+#endif
+ {
+ test &= ~TEST_BRE;
+ flags = cflags;
+ state.which = "BRE";
+ }
+ else
+#endif
+#ifdef REG_EXTENDED
+ if (test & TEST_ERE)
+ {
+ test &= ~TEST_ERE;
+ flags = cflags | REG_EXTENDED;
+ state.which = "ERE";
+ }
+ else
+#endif
+#ifdef REG_AUGMENTED
+ if (test & TEST_ARE)
+ {
+ test &= ~TEST_ARE;
+ flags = cflags | REG_AUGMENTED;
+ state.which = "ARE";
+ }
+ else
+#endif
+#ifdef REG_LITERAL
+ if (test & TEST_LRE)
+ {
+ test &= ~TEST_LRE;
+ flags = cflags | REG_LITERAL;
+ state.which = "LRE";
+ }
+ else
+#endif
+#ifdef REG_SHELL
+ if (test & TEST_SRE)
+ {
+ test &= ~TEST_SRE;
+ flags = cflags | REG_SHELL;
+ state.which = "SRE";
+ }
+ else
+#ifdef REG_AUGMENTED
+ if (test & TEST_KRE)
+ {
+ test &= ~TEST_KRE;
+ flags = cflags | REG_SHELL | REG_AUGMENTED;
+ state.which = "KRE";
+ }
+ else
+#endif
+#endif
+ {
+ if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
+ extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
+ continue;
+ }
+ if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
+ {
+ printf("test %-3d %s ", state.lineno, state.which);
+ quote(re, -1, test|TEST_DELIMIT);
+ printf(" ");
+ quote(s, nstr, test|TEST_DELIMIT);
+ printf("\n");
+ }
+
+ nosub:
+ fun = "regcomp";
+#if _REG_nexec
+ if (nstr >= 0 && nstr != strlen(s))
+ nexec = nstr;
+
+ else
+#endif
+ nexec = -1;
+ if (state.extracted || (skip & level))
+ continue;
+ if (!(test & TEST_QUERY))
+ testno++;
+#ifdef REG_DISCIPLINE
+ if (state.stack)
+ stkset(stkstd, state.stack, 0);
+ flags |= REG_DISCIPLINE;
+ state.disc.ordinal = 0;
+ sfstrseek(state.disc.sp, 0, SEEK_SET);
+#endif
+ if (!(test & TEST_CATCH))
+ cret = regcomp(&preg, re, flags);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ cret = regcomp(&preg, re, flags);
+ alarm(0);
+ }
+#if _REG_subcomp
+ if (!cret && (test & TEST_SUB))
+ {
+ fun = "regsubcomp";
+ p = re + preg.re_npat;
+ if (!(test & TEST_CATCH))
+ cret = regsubcomp(&preg, p, NiL, 0, 0);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ cret = regsubcomp(&preg, p, NiL, 0, 0);
+ alarm(0);
+ }
+ if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
+ {
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ cret = REG_EFLAGS;
+ }
+ }
+#endif
+#if _REG_decomp
+ if (!cret && (test & TEST_DECOMP))
+ {
+ char buf[128];
+
+ if ((j = nmatch) > sizeof(buf))
+ j = sizeof(buf);
+ fun = "regdecomp";
+ p = re + preg.re_npat;
+ if (!(test & TEST_CATCH))
+ i = regdecomp(&preg, -1, buf, j);
+ else if (!(cret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ i = regdecomp(&preg, -1, buf, j);
+ alarm(0);
+ }
+ if (!cret)
+ {
+ catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ if (i > j)
+ {
+ if (i != (strlen(ans) + 1))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ printf(" %d byte buffer supplied, %d byte buffer required\n", j, i);
+ }
+ }
+ else if (strcmp(buf, ans))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ quote(ans, -1, test|TEST_DELIMIT);
+ printf(" expected, ");
+ quote(buf, -1, test|TEST_DELIMIT);
+ printf(" returned\n");
+ }
+ continue;
+ }
+ }
+#endif
+ if (!cret)
+ {
+ if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
+ {
+ for (p = ans; *p; p++)
+ if (*p == '(')
+ nsub++;
+ else if (*p == '{')
+ nsub--;
+ if (nsub >= 0)
+ {
+ if (test & TEST_IGNORE_OVER)
+ {
+ if (nmatch > nsub)
+ nmatch = nsub + 1;
+ }
+ else if (nsub != preg.re_nsub)
+ {
+ if (nsub > preg.re_nsub)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
+ printf("at least %d expected, %d returned\n", nsub, preg.re_nsub);
+ state.errors++;
+ }
+ }
+ else
+ nsub = preg.re_nsub;
+ }
+ }
+ }
+ if (!(test & (TEST_DECOMP|TEST_SUB)) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else if (!(test & TEST_LENIENT))
+ {
+ report("failed", fun, re, NiL, -1, msg, flags, test);
+ printf("%s expected, OK returned\n", ans);
+ }
+ catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ continue;
+ }
+ }
+ else
+ {
+ if (test & TEST_LENIENT)
+ /* we'll let it go this time */;
+ else if (!*ans || ans[0]=='(' || cret == REG_BADPAT && streq(ans, "NOMATCH"))
+ {
+ got = 0;
+ for (i = 1; i < elementsof(codes); i++)
+ if (cret==codes[i].code)
+ got = i;
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed", fun, re, NiL, -1, msg, flags, test);
+ printf("%s returned: ", codes[got].name);
+ error(&preg, cret);
+ }
+ }
+ else
+ {
+ expected = got = 0;
+ for (i = 1; i < elementsof(codes); i++)
+ {
+ if (streq(ans, codes[i].name))
+ expected = i;
+ if (cret==codes[i].code)
+ got = i;
+ }
+ if (!expected)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
+ printf("%s expected, %s returned\n", ans, codes[got].name);
+ }
+ }
+ else if (cret != codes[expected].code && cret != REG_BADPAT)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else if (test & TEST_IGNORE_ERROR)
+ state.ignored++;
+ else
+ {
+ report("should fail and did", fun, re, NiL, -1, msg, flags, test);
+ printf("%s expected, %s returned: ", ans, codes[got].name);
+ state.errors--;
+ state.warnings++;
+ error(&preg, cret);
+ }
+ }
+ }
+ goto compile;
+ }
+
+#if _REG_nexec
+ execute:
+ if (nexec >= 0)
+ fun = "regnexec";
+ else
+#endif
+ fun = "regexec";
+
+ for (i = 0; i < elementsof(match); i++)
+ match[i] = state.NOMATCH;
+
+#if _REG_nexec
+ if (nexec >= 0)
+ {
+ eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
+ s[nexec] = 0;
+ }
+ else
+#endif
+ {
+ if (!(test & TEST_CATCH))
+ eret = regexec(&preg, s, nmatch, match, eflags);
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ eret = regexec(&preg, s, nmatch, match, eflags);
+ alarm(0);
+ }
+ }
+#if _REG_subcomp
+ if ((test & TEST_SUB) && !eret)
+ {
+ fun = "regsubexec";
+ if (!(test & TEST_CATCH))
+ eret = regsubexec(&preg, s, nmatch, match);
+ else if (!(eret = setjmp(state.gotcha)))
+ {
+ alarm(HUNG);
+ eret = regsubexec(&preg, s, nmatch, match);
+ alarm(0);
+ }
+ }
+#endif
+ if (flags & REG_NOSUB)
+ {
+ if (eret)
+ {
+ if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
+ error(&preg, eret);
+ }
+ }
+ }
+ else if (streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
+ error(&preg, eret);
+ }
+ }
+ }
+ else if (eret)
+ {
+ if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ if (eret != REG_NOMATCH)
+ error(&preg, eret);
+ else if (*ans)
+ printf("expected: %s\n", ans);
+ else
+ printf("\n");
+ }
+ }
+ }
+ else if (streq(ans, "NOMATCH"))
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ else
+ {
+ report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
+ matchprint(match, nmatch, nsub, NiL, test);
+ }
+ }
+#if _REG_subcomp
+ else if (test & TEST_SUB)
+ {
+ p = preg.re_sub->re_buf;
+ if (strcmp(p, ans))
+ {
+ report("failed", fun, re, s, nstr, msg, flags, test);
+ quote(ans, -1, test|TEST_DELIMIT);
+ printf(" expected, ");
+ quote(p, -1, test|TEST_DELIMIT);
+ printf(" returned\n");
+ }
+ }
+#endif
+ else if (!*ans)
+ {
+ if (match[0].rm_so != state.NOMATCH.rm_so)
+ {
+ if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
+ else
+ {
+ report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
+ matchprint(match, nmatch, nsub, NiL, test);
+ }
+ }
+ }
+ else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
+ {
+#if _REG_nexec
+ if (nexec < 0 && !nonexec)
+ {
+ nexec = nstr >= 0 ? nstr : strlen(s);
+ s[nexec] = '\n';
+ testno++;
+ goto execute;
+ }
+#endif
+ if (!(test & (TEST_DECOMP|TEST_SUB|TEST_VERIFY)) && !nonosub)
+ {
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ flags |= REG_NOSUB;
+ goto nosub;
+ }
+ if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
+ }
+ else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
+ skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
+ if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
+ continue;
+ goto compile;
+ }
+ if (test & TEST_SUMMARY)
+ printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
+ else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
+ {
+ printf("TEST\t%s", unit);
+ if (subunit)
+ printf(" %-.*s", subunitlen, subunit);
+ printf(", %d test%s", testno, testno == 1 ? "" : "s");
+ if (state.ignored)
+ printf(", %d ignored mismatche%s", state.ignored, state.ignored == 1 ? "" : "s");
+ if (state.warnings)
+ printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
+ if (state.unspecified)
+ printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
+ if (state.signals)
+ printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
+ printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
+ }
+ if (fp != stdin)
+ fclose(fp);
+ }
+ return 0;
+}
diff --git a/src/pkg/rpc/Makefile b/src/pkg/rpc/Makefile
deleted file mode 100644
index 191b10d05..000000000
--- a/src/pkg/rpc/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../Make.inc
-
-TARG=rpc
-GOFILES=\
- client.go\
- debug.go\
- server.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/rpc/jsonrpc/Makefile b/src/pkg/rpc/jsonrpc/Makefile
deleted file mode 100644
index b9a1ac2f7..000000000
--- a/src/pkg/rpc/jsonrpc/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=rpc/jsonrpc
-GOFILES=\
- client.go\
- server.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/runtime/386/arch.h b/src/pkg/runtime/386/arch.h
deleted file mode 100644
index d95c7aa81..000000000
--- a/src/pkg/runtime/386/arch.h
+++ /dev/null
@@ -1,3 +0,0 @@
-enum {
- thechar = '8'
-};
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 64bd2b771..5827ce134 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -2,167 +2,4 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-
-TARG=runtime
-
-# Set SIZE to 32 or 64.
-SIZE_386=32
-SIZE_amd64=64
-SIZE_arm=32
-SIZE=$(SIZE_$(GOARCH))
-
-CFLAGS_windows=-D__WINDOWS__
-CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
-
-GOFILES=\
- debug.go\
- error.go\
- extern.go\
- mem.go\
- sig.go\
- softfloat64.go\
- type.go\
- version.go\
- version_$(GOOS).go\
- version_$(GOARCH).go\
- runtime_defs.go\
-
-CLEANFILES+=version.go version_*.go
-
-OFILES_windows=\
- syscall.$O\
-
-# 386-specific object files
-OFILES_386=\
- vlop.$O\
- vlrt.$O\
-
-# arm-specific object files
-OFILES_arm=\
- memset.$O\
- softfloat.$O\
- vlop.$O\
- vlrt.$O\
-
-OFILES=\
- asm.$O\
- atomic.$O\
- cgocall.$O\
- chan.$O\
- closure.$O\
- cpuprof.$O\
- float.$O\
- complex.$O\
- hashmap.$O\
- iface.$O\
- malloc.$O\
- mcache.$O\
- mcentral.$O\
- mem.$O\
- memmove.$O\
- mfinal.$O\
- mfixalloc.$O\
- mgc0.$O\
- mheap.$O\
- mprof.$O\
- msize.$O\
- print.$O\
- proc.$O\
- rune.$O\
- runtime.$O\
- runtime1.$O\
- rt0.$O\
- sema.$O\
- signal.$O\
- sigqueue.$O\
- slice.$O\
- string.$O\
- symtab.$O\
- sys.$O\
- thread.$O\
- traceback.$O\
- $(OFILES_$(GOARCH))\
- $(OFILES_$(GOOS))\
-
-HFILES=\
- cgocall.h\
- runtime.h\
- hashmap.h\
- malloc.h\
- stack.h\
- $(GOARCH)/asm.h\
- $(GOOS)/os.h\
- $(GOOS)/signals.h\
- $(GOOS)/$(GOARCH)/defs.h\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-# For use by cgo.
-INSTALLFILES=$(pkgdir)/runtime.h $(pkgdir)/cgocall.h
-
-# special, out of the way compiler flag that means "add runtime metadata to output"
-GC+= -+
-
-include ../../Make.pkg
-
-$(pkgdir)/%.h: %.h
- @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)
- cp $< "$@"
-
-clean: clean-local
-
-clean-local:
- rm -f goc2c mkversion version.go */asm.h runtime.acid.* runtime_defs.go $$(ls *.goc | sed 's/goc$$/c/')
-
-$(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH)
- ./mkasmh.sh >$@.x
- mv -f $@.x $@
-
-goc2c: goc2c.c
- quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
-
-mkversion: mkversion.c
- quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
-
-version.go: mkversion
- GOROOT="$(GOROOT_FINAL)" ./mkversion >version.go
-
-version_$(GOARCH).go:
- (echo 'package runtime'; echo 'const theGoarch = "$(GOARCH)"') >$@
-
-version_$(GOOS).go:
- (echo 'package runtime'; echo 'const theGoos = "$(GOOS)"') >$@
-
-%.c: %.goc goc2c
- ./goc2c "`pwd`/$<" > $@.tmp
- mv -f $@.tmp $@
-
-%.$O: $(GOARCH)/%.c $(HFILES)
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOOS)/%.c $(HFILES)
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOOS)/$(GOARCH)/%.c $(HFILES)
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOARCH)/%.s $(GOARCH)/asm.h
- $(AS) $<
-
-%.$O: $(GOOS)/$(GOARCH)/%.s $(GOARCH)/asm.h
- $(AS) $<
-
-# for discovering offsets inside structs when debugging
-runtime.acid.$(GOARCH): runtime.h proc.c
- $(CC) $(CFLAGS) -a proc.c >$@
-
-# 386 traceback is really amd64 traceback
-ifeq ($(GOARCH),386)
-traceback.$O: amd64/traceback.c
- $(CC) $(CFLAGS) $<
-endif
-
-runtime_defs.go: proc.c iface.c hashmap.c chan.c
- CC="$(CC)" CFLAGS="$(CFLAGS)" ./mkgodefs.sh $^ > $@.x
- mv -f $@.x $@
+include ../../Make.dist
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.c
new file mode 100644
index 000000000..e3c42916e
--- /dev/null
+++ b/src/pkg/runtime/alg.c
@@ -0,0 +1,484 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+void
+runtime·memhash(uintptr *h, uintptr s, void *a)
+{
+ byte *b;
+ uintptr hash;
+
+ b = a;
+ if(sizeof(hash) == 4)
+ hash = 2860486313U;
+ else
+ hash = 33054211828000289ULL;
+ while(s > 0) {
+ if(sizeof(hash) == 4)
+ hash = (hash ^ *b) * 3267000013UL;
+ else
+ hash = (hash ^ *b) * 23344194077549503ULL;
+ b++;
+ s--;
+ }
+ *h ^= hash;
+}
+
+void
+runtime·memequal(bool *eq, uintptr s, void *a, void *b)
+{
+ byte *ba, *bb, *aend;
+
+ if(a == b) {
+ *eq = 1;
+ return;
+ }
+ ba = a;
+ bb = b;
+ aend = ba+s;
+ while(ba != aend) {
+ if(*ba != *bb) {
+ *eq = 0;
+ return;
+ }
+ ba++;
+ bb++;
+ }
+ *eq = 1;
+ return;
+}
+
+void
+runtime·memprint(uintptr s, void *a)
+{
+ uint64 v;
+
+ v = 0xbadb00b;
+ switch(s) {
+ case 1:
+ v = *(uint8*)a;
+ break;
+ case 2:
+ v = *(uint16*)a;
+ break;
+ case 4:
+ v = *(uint32*)a;
+ break;
+ case 8:
+ v = *(uint64*)a;
+ break;
+ }
+ runtime·printint(v);
+}
+
+void
+runtime·memcopy(uintptr s, void *a, void *b)
+{
+ if(b == nil) {
+ runtime·memclr(a, s);
+ return;
+ }
+ runtime·memmove(a, b, s);
+}
+
+void
+runtime·memequal0(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ *eq = true;
+}
+
+void
+runtime·memcopy0(uintptr s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+}
+
+void
+runtime·memequal8(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(uint8*)a == *(uint8*)b;
+}
+
+void
+runtime·memcopy8(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ *(uint8*)a = 0;
+ return;
+ }
+ *(uint8*)a = *(uint8*)b;
+}
+
+void
+runtime·memequal16(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(uint16*)a == *(uint16*)b;
+}
+
+void
+runtime·memcopy16(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ *(uint16*)a = 0;
+ return;
+ }
+ *(uint16*)a = *(uint16*)b;
+}
+
+void
+runtime·memequal32(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(uint32*)a == *(uint32*)b;
+}
+
+void
+runtime·memcopy32(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ *(uint32*)a = 0;
+ return;
+ }
+ *(uint32*)a = *(uint32*)b;
+}
+
+void
+runtime·memequal64(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(uint64*)a == *(uint64*)b;
+}
+
+void
+runtime·memcopy64(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ *(uint64*)a = 0;
+ return;
+ }
+ *(uint64*)a = *(uint64*)b;
+}
+
+void
+runtime·memequal128(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1];
+}
+
+void
+runtime·memcopy128(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ ((uint64*)a)[0] = 0;
+ ((uint64*)a)[1] = 0;
+ return;
+ }
+ ((uint64*)a)[0] = ((uint64*)b)[0];
+ ((uint64*)a)[1] = ((uint64*)b)[1];
+}
+
+void
+runtime·f32equal(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(float32*)a == *(float32*)b;
+}
+
+void
+runtime·f64equal(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = *(float64*)a == *(float64*)b;
+}
+
+void
+runtime·c64equal(bool *eq, uintptr s, void *a, void *b)
+{
+ Complex64 *ca, *cb;
+
+ USED(s);
+ ca = a;
+ cb = b;
+ *eq = ca->real == cb->real && ca->imag == cb->imag;
+}
+
+void
+runtime·c128equal(bool *eq, uintptr s, void *a, void *b)
+{
+ Complex128 *ca, *cb;
+
+ USED(s);
+ ca = a;
+ cb = b;
+ *eq = ca->real == cb->real && ca->imag == cb->imag;
+}
+
+// NOTE: Because NaN != NaN, a map can contain any
+// number of (mostly useless) entries keyed with NaNs.
+// To avoid long hash chains, we assign a random number
+// as the hash value for a NaN.
+
+void
+runtime·f32hash(uintptr *h, uintptr s, void *a)
+{
+ uintptr hash;
+ float32 f;
+
+ USED(s);
+ f = *(float32*)a;
+ if(f == 0)
+ hash = 0; // +0, -0
+ else if(f != f)
+ hash = runtime·fastrand1(); // any kind of NaN
+ else
+ hash = *(uint32*)a;
+ *h ^= (*h ^ hash ^ 2860486313U) * 3267000013U;
+}
+
+void
+runtime·f64hash(uintptr *h, uintptr s, void *a)
+{
+ uintptr hash;
+ float64 f;
+ uint64 u;
+
+ USED(s);
+ f = *(float64*)a;
+ if(f == 0)
+ hash = 0; // +0, -0
+ else if(f != f)
+ hash = runtime·fastrand1(); // any kind of NaN
+ else {
+ u = *(uint64*)a;
+ if(sizeof(uintptr) == 4)
+ hash = ((uint32)(u>>32) * 3267000013UL) ^ (uint32)u;
+ else
+ hash = u;
+ }
+ if(sizeof(uintptr) == 4)
+ *h = (*h ^ hash ^ 2860486313U) * 3267000013U;
+ else
+ *h = (*h ^ hash ^ 33054211828000289ULL) * 23344194077549503ULL;
+}
+
+void
+runtime·c64hash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ runtime·f32hash(h, 0, a);
+ runtime·f32hash(h, 0, (float32*)a+1);
+}
+
+void
+runtime·c128hash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ runtime·f64hash(h, 0, a);
+ runtime·f64hash(h, 0, (float64*)a+1);
+}
+
+void
+runtime·slicecopy(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ ((Slice*)a)->array = 0;
+ ((Slice*)a)->len = 0;
+ ((Slice*)a)->cap = 0;
+ return;
+ }
+ ((Slice*)a)->array = ((Slice*)b)->array;
+ ((Slice*)a)->len = ((Slice*)b)->len;
+ ((Slice*)a)->cap = ((Slice*)b)->cap;
+}
+
+void
+runtime·strhash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ runtime·memhash(h, ((String*)a)->len, ((String*)a)->str);
+}
+
+void
+runtime·strequal(bool *eq, uintptr s, void *a, void *b)
+{
+ int32 alen;
+
+ USED(s);
+ alen = ((String*)a)->len;
+ if(alen != ((String*)b)->len) {
+ *eq = false;
+ return;
+ }
+ runtime·memequal(eq, alen, ((String*)a)->str, ((String*)b)->str);
+}
+
+void
+runtime·strprint(uintptr s, void *a)
+{
+ USED(s);
+ runtime·printstring(*(String*)a);
+}
+
+void
+runtime·strcopy(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ ((String*)a)->str = 0;
+ ((String*)a)->len = 0;
+ return;
+ }
+ ((String*)a)->str = ((String*)b)->str;
+ ((String*)a)->len = ((String*)b)->len;
+}
+
+void
+runtime·interhash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ *h ^= runtime·ifacehash(*(Iface*)a);
+}
+
+void
+runtime·interprint(uintptr s, void *a)
+{
+ USED(s);
+ runtime·printiface(*(Iface*)a);
+}
+
+void
+runtime·interequal(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b);
+}
+
+void
+runtime·intercopy(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ ((Iface*)a)->tab = 0;
+ ((Iface*)a)->data = 0;
+ return;
+ }
+ ((Iface*)a)->tab = ((Iface*)b)->tab;
+ ((Iface*)a)->data = ((Iface*)b)->data;
+}
+
+void
+runtime·nilinterhash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ *h ^= runtime·efacehash(*(Eface*)a);
+}
+
+void
+runtime·nilinterprint(uintptr s, void *a)
+{
+ USED(s);
+ runtime·printeface(*(Eface*)a);
+}
+
+void
+runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ *eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b);
+}
+
+void
+runtime·nilintercopy(uintptr s, void *a, void *b)
+{
+ USED(s);
+ if(b == nil) {
+ ((Eface*)a)->type = 0;
+ ((Eface*)a)->data = 0;
+ return;
+ }
+ ((Eface*)a)->type = ((Eface*)b)->type;
+ ((Eface*)a)->data = ((Eface*)b)->data;
+}
+
+void
+runtime·nohash(uintptr *h, uintptr s, void *a)
+{
+ USED(s);
+ USED(a);
+ USED(h);
+ runtime·panicstring("hash of unhashable type");
+}
+
+void
+runtime·noequal(bool *eq, uintptr s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ USED(eq);
+ runtime·panicstring("comparing uncomparable types");
+}
+
+Alg
+runtime·algarray[] =
+{
+[AMEM] { runtime·memhash, runtime·memequal, runtime·memprint, runtime·memcopy },
+[ANOEQ] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy },
+[ASTRING] { runtime·strhash, runtime·strequal, runtime·strprint, runtime·strcopy },
+[AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
+[ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
+[ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
+[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
+[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
+[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
+[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
+[AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
+[AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
+[AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
+[AMEM32] { runtime·memhash, runtime·memequal32, runtime·memprint, runtime·memcopy32 },
+[AMEM64] { runtime·memhash, runtime·memequal64, runtime·memprint, runtime·memcopy64 },
+[AMEM128] { runtime·memhash, runtime·memequal128, runtime·memprint, runtime·memcopy128 },
+[ANOEQ0] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy0 },
+[ANOEQ8] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy8 },
+[ANOEQ16] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy16 },
+[ANOEQ32] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy32 },
+[ANOEQ64] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy64 },
+[ANOEQ128] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy128 },
+};
+
+// Runtime helpers.
+
+// func equal(t *Type, x T, y T) (ret bool)
+#pragma textflag 7
+void
+runtime·equal(Type *t, ...)
+{
+ byte *x, *y;
+ bool *ret;
+
+ x = (byte*)(&t+1);
+ y = x + t->size;
+ ret = (bool*)(y + t->size);
+ t->alg->equal(ret, t->size, x, y);
+}
diff --git a/src/pkg/runtime/amd64/arch.h b/src/pkg/runtime/amd64/arch.h
deleted file mode 100644
index fe10fd89f..000000000
--- a/src/pkg/runtime/amd64/arch.h
+++ /dev/null
@@ -1,3 +0,0 @@
-enum {
- thechar = '6'
-};
diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
new file mode 100644
index 000000000..a0798f99e
--- /dev/null
+++ b/src/pkg/runtime/arch_386.h
@@ -0,0 +1,4 @@
+enum {
+ thechar = '8',
+ CacheLineSize = 64
+};
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
new file mode 100644
index 000000000..dd1cfc18d
--- /dev/null
+++ b/src/pkg/runtime/arch_amd64.h
@@ -0,0 +1,4 @@
+enum {
+ thechar = '6',
+ CacheLineSize = 64
+};
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
new file mode 100644
index 000000000..c1a7a0f37
--- /dev/null
+++ b/src/pkg/runtime/arch_arm.h
@@ -0,0 +1,4 @@
+enum {
+ thechar = '5',
+ CacheLineSize = 32
+};
diff --git a/src/pkg/runtime/arm/arch.h b/src/pkg/runtime/arm/arch.h
deleted file mode 100644
index 3ddb626dd..000000000
--- a/src/pkg/runtime/arm/arch.h
+++ /dev/null
@@ -1,3 +0,0 @@
-enum {
- thechar = '5'
-};
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/asm_386.s
index a14518839..21bd293ab 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/asm_386.s
@@ -2,17 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "386/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT _rt0_386(SB),7,$0
- // Linux, Windows start the FPU in extended double precision.
- // Other operating systems use double precision.
- // Change to double precision to match them,
- // and to match other hardware that only has double.
- PUSHL $0x27F
- FLDCW 0(SP)
- POPL AX
-
// copy arguments forward on an even stack
MOVL 0(SP), AX // argc
LEAL 4(SP), BX // argv
@@ -21,17 +13,26 @@ TEXT _rt0_386(SB),7,$0
MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP)
+ // set default stack bounds.
+ // initcgo may update stackguard.
+ MOVL $runtime·g0(SB), BP
+ LEAL (-64*1024+104)(SP), BX
+ MOVL BX, g_stackguard(BP)
+ MOVL SP, g_stackbase(BP)
+
// if there is an initcgo, call it to let it
// initialize and to set up GS. if not,
// we set up GS ourselves.
MOVL initcgo(SB), AX
TESTL AX, AX
- JZ 4(PC)
+ JZ needtls
+ PUSHL BP
CALL AX
+ POPL BP
// skip runtime·ldt0setup(SB) and tls test after initcgo for non-windows
CMPL runtime·iswindows(SB), $0
JEQ ok
-
+needtls:
// skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases
CMPL runtime·isplan9(SB), $1
JEQ ok
@@ -57,10 +58,6 @@ ok:
// save m->g0 = g0
MOVL CX, m_g0(AX)
- // create istack out of the OS stack
- LEAL (-64*1024+104)(SP), AX // TODO: 104?
- MOVL AX, g_stackguard(CX)
- MOVL SP, g_stackbase(CX)
CALL runtime·emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
@@ -78,7 +75,7 @@ ok:
CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHL $runtime·mainstart(SB) // entry
+ PUSHL $runtime·main(SB) // entry
PUSHL $0 // arg size
CALL runtime·newproc(SB)
POPL AX
@@ -90,18 +87,18 @@ ok:
INT $3
RET
-TEXT runtime·mainstart(SB),7,$0
- CALL main·init(SB)
- CALL runtime·initdone(SB)
- CALL main·main(SB)
- PUSHL $0
- CALL runtime·exit(SB)
- POPL AX
+TEXT runtime·breakpoint(SB),7,$0
INT $3
RET
-TEXT runtime·breakpoint(SB),7,$0
- INT $3
+TEXT runtime·asminit(SB),7,$0
+ // Linux, Windows start the FPU in extended double precision.
+ // Other operating systems use double precision.
+ // Change to double precision to match them,
+ // and to match other hardware that only has double.
+ PUSHL $0x27F
+ FLDCW 0(SP)
+ POPL AX
RET
/*
@@ -428,21 +425,29 @@ TEXT runtime·cgocallback(SB),7,$12
// Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX)
MOVL m(CX), BP
+
+ // If m is nil, it is almost certainly because we have been called
+ // on a thread that Go did not create. We're going to crash as
+ // soon as we try to use m; instead, try to print a nice error and exit.
+ CMPL BP, $0
+ JNE 2(PC)
+ CALL runtime·badcallback(SB)
+
MOVL m_g0(BP), SI
PUSHL (g_sched+gobuf_sp)(SI)
MOVL SP, (g_sched+gobuf_sp)(SI)
- // Switch to m->curg stack and call runtime.cgocallback
+ // Switch to m->curg stack and call runtime.cgocallbackg
// with the three arguments. Because we are taking over
// the execution of m->curg but *not* resuming what had
// been running, we need to save that information (m->curg->gobuf)
// so that we can restore it when we're done.
// We can restore m->curg->gobuf.sp easily, because calling
- // runtime.cgocallback leaves SP unchanged upon return.
+ // runtime.cgocallbackg leaves SP unchanged upon return.
// To save m->curg->gobuf.pc, we push it onto the stack.
// This has the added benefit that it looks to the traceback
- // routine like cgocallback is going to return to that
- // PC (because we defined cgocallback to have
+ // routine like cgocallbackg is going to return to that
+ // PC (because we defined cgocallbackg to have
// a frame size of 12, the same amount that we use below),
// so that the traceback will seamlessly trace back into
// the earlier calls.
@@ -529,6 +534,15 @@ TEXT runtime·getcallersp(SB), 7, $0
MOVL sp+0(FP), AX
RET
+// int64 runtime·cputicks(void), so really
+// void runtime·cputicks(int64 *ticks)
+TEXT runtime·cputicks(SB),7,$0
+ RDTSC
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
TEXT runtime·ldt0setup(SB),7,$16
// set up ldt 7 to point at tls0
// ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
@@ -546,4 +560,13 @@ TEXT runtime·emptyfunc(SB),0,$0
TEXT runtime·abort(SB),7,$0
INT $0x3
+TEXT runtime·stackguard(SB),7,$0
+ MOVL SP, DX
+ MOVL DX, sp+0(FP)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL g_stackguard(BX), DX
+ MOVL DX, guard+4(FP)
+ RET
+
GLOBL runtime·tls0(SB), $32
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/asm_amd64.s
index 3e3818c10..d41ab96d0 100644
--- a/src/pkg/runtime/amd64/asm.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack
@@ -12,11 +12,20 @@ TEXT _rt0_amd64(SB),7,$-8
ANDQ $~15, SP
MOVQ AX, 16(SP)
MOVQ BX, 24(SP)
+
+ // create istack out of the given (operating system) stack.
+ // initcgo may update stackguard.
+ MOVQ $runtime·g0(SB), DI
+ LEAQ (-64*1024+104)(SP), BX
+ MOVQ BX, g_stackguard(DI)
+ MOVQ SP, g_stackbase(DI)
// if there is an initcgo, call it.
MOVQ initcgo(SB), AX
TESTQ AX, AX
JZ needtls
+ // g0 already in DI
+ MOVQ DI, CX // Win64 uses CX for first parameter
CALL AX
CMPL runtime·iswindows(SB), $0
JEQ ok
@@ -43,11 +52,6 @@ ok:
// save m->g0 = g0
MOVQ CX, m_g0(AX)
- // create istack out of the given (operating system) stack
- LEAQ (-8192+104)(SP), AX
- MOVQ AX, g_stackguard(CX)
- MOVQ SP, g_stackbase(CX)
-
CLD // convention is D is always left cleared
CALL runtime·check(SB)
@@ -60,7 +64,7 @@ ok:
CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHQ $runtime·mainstart(SB) // entry
+ PUSHQ $runtime·main(SB) // entry
PUSHQ $0 // arg size
CALL runtime·newproc(SB)
POPQ AX
@@ -69,23 +73,17 @@ ok:
// start this M
CALL runtime·mstart(SB)
- CALL runtime·notok(SB) // never returns
- RET
-
-TEXT runtime·mainstart(SB),7,$0
- CALL main·init(SB)
- CALL runtime·initdone(SB)
- CALL main·main(SB)
- PUSHQ $0
- CALL runtime·exit(SB)
- POPQ AX
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·breakpoint(SB),7,$0
BYTE $0xcc
RET
+TEXT runtime·asminit(SB),7,$0
+ // No per-thread init.
+ RET
+
/*
* go-routine
*/
@@ -448,19 +446,19 @@ TEXT runtime·asmcgocall(SB),7,$0
MOVQ (g_sched+gobuf_sp)(SI), SP
// Now on a scheduling stack (a pthread-created stack).
- SUBQ $32, SP
+ SUBQ $48, SP
ANDQ $~15, SP // alignment for gcc ABI
- MOVQ DI, 16(SP) // save g
- MOVQ DX, 8(SP) // save SP
+ MOVQ DI, 32(SP) // save g
+ MOVQ DX, 24(SP) // save SP
MOVQ BX, DI // DI = first argument in AMD64 ABI
MOVQ BX, CX // CX = first argument in Win64
CALL AX
// Restore registers, g, stack pointer.
get_tls(CX)
- MOVQ 16(SP), DI
+ MOVQ 32(SP), DI
MOVQ DI, g(CX)
- MOVQ 8(SP), SP
+ MOVQ 24(SP), SP
RET
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -473,21 +471,29 @@ TEXT runtime·cgocallback(SB),7,$24
// Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX)
MOVQ m(CX), BP
+
+ // If m is nil, it is almost certainly because we have been called
+ // on a thread that Go did not create. We're going to crash as
+ // soon as we try to use m; instead, try to print a nice error and exit.
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badcallback(SB)
+
MOVQ m_g0(BP), SI
PUSHQ (g_sched+gobuf_sp)(SI)
MOVQ SP, (g_sched+gobuf_sp)(SI)
- // Switch to m->curg stack and call runtime.cgocallback
+ // Switch to m->curg stack and call runtime.cgocallbackg
// with the three arguments. Because we are taking over
// the execution of m->curg but *not* resuming what had
// been running, we need to save that information (m->curg->gobuf)
// so that we can restore it when we're done.
// We can restore m->curg->gobuf.sp easily, because calling
- // runtime.cgocallback leaves SP unchanged upon return.
+ // runtime.cgocallbackg leaves SP unchanged upon return.
// To save m->curg->gobuf.pc, we push it onto the stack.
// This has the added benefit that it looks to the traceback
- // routine like cgocallback is going to return to that
- // PC (because we defined cgocallback to have
+ // routine like cgocallbackg is going to return to that
+ // PC (because we defined cgocallbackg to have
// a frame size of 24, the same amount that we use below),
// so that the traceback will seamlessly trace back into
// the earlier calls.
@@ -574,4 +580,20 @@ TEXT runtime·getcallersp(SB),7,$0
MOVQ sp+0(FP), AX
RET
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),7,$0
+ RDTSC
+ SHLQ $32, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·stackguard(SB),7,$0
+ MOVQ SP, DX
+ MOVQ DX, sp+0(FP)
+ get_tls(CX)
+ MOVQ g(CX), BX
+ MOVQ g_stackguard(BX), DX
+ MOVQ DX, guard+8(FP)
+ RET
+
GLOBL runtime·tls0(SB), $64
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/asm_arm.s
index 63153658f..423fda7a0 100644
--- a/src/pkg/runtime/arm/asm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "arm/asm.h"
+#include "zasm_GOOS_GOARCH.h"
// using frame size $-4 means do not save LR on stack.
TEXT _rt0_arm(SB),7,$-4
@@ -43,7 +43,7 @@ TEXT _rt0_arm(SB),7,$-4
BL runtime·schedinit(SB)
// create a new goroutine to start program
- MOVW $runtime·mainstart(SB), R0
+ MOVW $runtime·main(SB), R0
MOVW.W R0, -4(R13)
MOVW $8, R0
MOVW.W R0, -4(R13)
@@ -60,21 +60,6 @@ TEXT _rt0_arm(SB),7,$-4
MOVW R0, (R1) // fail hard
B runtime·_dep_dummy(SB) // Never reached
-
-TEXT runtime·mainstart(SB),7,$4
- BL main·init(SB)
- BL runtime·initdone(SB)
- EOR R0, R0
- MOVW R0, 0(R13)
- BL main·main(SB)
- MOVW $0, R0
- MOVW R0, 4(SP)
- BL runtime·exit(SB)
- MOVW $1234, R0
- MOVW $1001, R1
- MOVW R0, (R1) // fail hard
- RET
-
// TODO(kaib): remove these once i actually understand how the linker removes symbols
// pull in dummy dependencies
TEXT runtime·_dep_dummy(SB),7,$0
@@ -89,6 +74,10 @@ TEXT runtime·breakpoint(SB),7,$0
// no breakpoint yet; let program exit
RET
+TEXT runtime·asminit(SB),7,$0
+ // No per-thread init.
+ RET
+
/*
* go-routine
*/
@@ -280,6 +269,16 @@ TEXT runtime·getcallersp(SB),7,$-4
TEXT runtime·emptyfunc(SB),0,$0
RET
+// int64 runtime·cputicks(), so really
+// void runtime·cputicks(int64 *ticks)
+// stubbed: return int64(0)
+TEXT runtime·cputicks(SB),7,$0
+ MOVW 0(FP), R1
+ MOVW $0, R0
+ MOVW R0, 0(R1)
+ MOVW R0, 4(R1)
+ RET
+
TEXT runtime·abort(SB),7,$-4
MOVW $0, R0
MOVW (R0), R1
@@ -292,7 +291,7 @@ TEXT runtime·abort(SB),7,$-4
// }else
// return 0;
//
-// To implement runtime·cas in ../$GOOS/arm/sys.s
+// To implement runtime·cas in sys_$GOOS_arm.s
// using the native instructions, use:
//
// TEXT runtime·cas(SB),7,$0
@@ -314,3 +313,10 @@ casl:
casfail:
MOVW $0, R0
RET
+
+TEXT runtime·stackguard(SB),7,$0
+ MOVW R13, R1
+ MOVW g_stackguard(g), R2
+ MOVW R1, sp+0(FP)
+ MOVW R2, limit+4(FP)
+ RET
diff --git a/src/pkg/runtime/386/atomic.c b/src/pkg/runtime/atomic_386.c
index a4f2a114f..a4f2a114f 100644
--- a/src/pkg/runtime/386/atomic.c
+++ b/src/pkg/runtime/atomic_386.c
diff --git a/src/pkg/runtime/amd64/atomic.c b/src/pkg/runtime/atomic_amd64.c
index a4f2a114f..a4f2a114f 100644
--- a/src/pkg/runtime/amd64/atomic.c
+++ b/src/pkg/runtime/atomic_amd64.c
diff --git a/src/pkg/runtime/arm/atomic.c b/src/pkg/runtime/atomic_arm.c
index 52e4059ae..52e4059ae 100644
--- a/src/pkg/runtime/arm/atomic.c
+++ b/src/pkg/runtime/atomic_arm.c
diff --git a/src/pkg/runtime/callback_windows_386.c b/src/pkg/runtime/callback_windows_386.c
new file mode 100644
index 000000000..fcd292fbc
--- /dev/null
+++ b/src/pkg/runtime/callback_windows_386.c
@@ -0,0 +1,107 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Will keep all callbacks in a linked list, so they don't get garbage collected.
+typedef struct Callback Callback;
+struct Callback {
+ Callback* link;
+ void* gobody;
+ byte asmbody;
+};
+
+typedef struct Callbacks Callbacks;
+struct Callbacks {
+ Lock;
+ Callback* link;
+ int32 n;
+};
+
+static Callbacks cbs;
+
+// Call back from windows dll into go.
+byte *
+runtime·compilecallback(Eface fn, bool cleanstack)
+{
+ FuncType *ft;
+ Type *t;
+ int32 argsize, i, n;
+ byte *p;
+ Callback *c;
+
+ if(fn.type == nil || fn.type->kind != KindFunc)
+ runtime·panicstring("compilecallback: not a function");
+ ft = (FuncType*)fn.type;
+ if(ft->out.len != 1)
+ runtime·panicstring("compilecallback: function must have one output parameter");
+ if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
+ runtime·panicstring("compilecallback: output parameter size is wrong");
+ argsize = 0;
+ for(i=0; i<ft->in.len; i++) {
+ t = ((Type**)ft->in.array)[i];
+ if(t->size > sizeof(uintptr))
+ runtime·panicstring("compilecallback: input parameter size is wrong");
+ argsize += sizeof(uintptr);
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 1+4; // MOVL fn, AX
+ n += 1+4; // MOVL argsize, DX
+ n += 1+4; // MOVL callbackasm, CX
+ n += 2; // CALL CX
+ n += 1; // RET
+ if(cleanstack && argsize!=0)
+ n += 2; // ... argsize
+
+ runtime·lock(&cbs);
+ for(c = cbs.link; c != nil; c = c->link) {
+ if(c->gobody == fn.data) {
+ runtime·unlock(&cbs);
+ return &c->asmbody;
+ }
+ }
+ if(cbs.n >= 2000)
+ runtime·throw("too many callback functions");
+ c = runtime·mal(sizeof *c + n);
+ c->gobody = fn.data;
+ c->link = cbs.link;
+ cbs.link = c;
+ cbs.n++;
+ runtime·unlock(&cbs);
+
+ p = &c->asmbody;
+
+ // MOVL fn, AX
+ *p++ = 0xb8;
+ *(uint32*)p = (uint32)fn.data;
+ p += 4;
+
+ // MOVL argsize, DX
+ *p++ = 0xba;
+ *(uint32*)p = argsize;
+ p += 4;
+
+ // MOVL callbackasm, CX
+ *p++ = 0xb9;
+ *(uint32*)p = (uint32)runtime·callbackasm;
+ p += 4;
+
+ // CALL CX
+ *p++ = 0xff;
+ *p++ = 0xd1;
+
+ // RET argsize?
+ if(cleanstack && argsize!=0) {
+ *p++ = 0xc2;
+ *(uint16*)p = argsize;
+ } else
+ *p = 0xc3;
+
+ return &c->asmbody;
+}
diff --git a/src/pkg/runtime/callback_windows_amd64.c b/src/pkg/runtime/callback_windows_amd64.c
new file mode 100644
index 000000000..99d7cb9e3
--- /dev/null
+++ b/src/pkg/runtime/callback_windows_amd64.c
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Will keep all callbacks in a linked list, so they don't get garbage collected.
+typedef struct Callback Callback;
+struct Callback {
+ Callback* link;
+ void* gobody;
+ byte asmbody;
+};
+
+typedef struct Callbacks Callbacks;
+struct Callbacks {
+ Lock;
+ Callback* link;
+ int32 n;
+};
+
+static Callbacks cbs;
+
+// Call back from windows dll into go.
+byte *
+runtime·compilecallback(Eface fn, bool /*cleanstack*/)
+{
+ FuncType *ft;
+ Type *t;
+ int32 argsize, i, n;
+ byte *p;
+ Callback *c;
+
+ if(fn.type == nil || fn.type->kind != KindFunc)
+ runtime·panicstring("compilecallback: not a function");
+ ft = (FuncType*)fn.type;
+ if(ft->out.len != 1)
+ runtime·panicstring("compilecallback: function must have one output parameter");
+ if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
+ runtime·panicstring("compilecallback: output parameter size is wrong");
+ argsize = 0;
+ for(i=0; i<ft->in.len; i++) {
+ t = ((Type**)ft->in.array)[i];
+ if(t->size > sizeof(uintptr))
+ runtime·panicstring("compilecallback: input parameter size is wrong");
+ argsize += sizeof(uintptr);
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 2+8+1; // MOVQ fn, AX / PUSHQ AX
+ n += 2+8+1; // MOVQ argsize, AX / PUSHQ AX
+ n += 2+8; // MOVQ callbackasm, AX
+ n += 2; // JMP AX
+
+ runtime·lock(&cbs);
+ for(c = cbs.link; c != nil; c = c->link) {
+ if(c->gobody == fn.data) {
+ runtime·unlock(&cbs);
+ return &c->asmbody;
+ }
+ }
+ if(cbs.n >= 2000)
+ runtime·throw("too many callback functions");
+ c = runtime·mal(sizeof *c + n);
+ c->gobody = fn.data;
+ c->link = cbs.link;
+ cbs.link = c;
+ cbs.n++;
+ runtime·unlock(&cbs);
+
+ p = &c->asmbody;
+
+ // MOVQ fn, AX
+ *p++ = 0x48;
+ *p++ = 0xb8;
+ *(uint64*)p = (uint64)fn.data;
+ p += 8;
+ // PUSH AX
+ *p++ = 0x50;
+
+ // MOVQ argsize, AX
+ *p++ = 0x48;
+ *p++ = 0xb8;
+ *(uint64*)p = argsize;
+ p += 8;
+ // PUSH AX
+ *p++ = 0x50;
+
+ // MOVQ callbackasm, AX
+ *p++ = 0x48;
+ *p++ = 0xb8;
+ *(uint64*)p = (uint64)runtime·callbackasm;
+ p += 8;
+
+ // JMP AX
+ *p++ = 0xFF;
+ *p = 0xE0;
+
+ return &c->asmbody;
+}
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
deleted file mode 100644
index 766794797..000000000
--- a/src/pkg/runtime/cgo/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=runtime/cgo
-
-GOFILES=\
- cgo.go\
-
-ifeq ($(CGO_ENABLED),1)
-
-# Unwarranted chumminess with Make.pkg's cgo rules.
-# Do not try this at home.
-CGO_OFILES=\
- $(GOARCH).o\
- $(GOOS)_$(GOARCH).o\
- util.o\
-
-ifeq ($(GOOS),windows)
-CGO_LDFLAGS=-lm -mthreads
-else
-CGO_LDFLAGS=-lpthread
-CGO_OFILES+=setenv.o\
-
-endif
-
-OFILES=\
- iscgo.$O\
- callbacks.$O\
- _cgo_import.$O\
- $(CGO_OFILES)\
-
-ifeq ($(GOOS),freebsd)
-OFILES+=\
- freebsd.$O\
-
-endif
-
-endif
-
-include ../../../Make.pkg
-
-ifeq ($(CGO_ENABLED),1)
-_cgo_defun.c:
- echo >$@
-
-_cgo_main.c:
- echo 'int main() { return 0; }' >$@
-endif
-
-$(GOARCH).o: $(GOARCH).S
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
-
-$(GOOS)_$(GOARCH).o: $(GOOS)_$(GOARCH).c
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
-
-%.o: %.c
- $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -O2 -fPIC -o $@ -c $^
diff --git a/src/pkg/runtime/cgo/cgo.go b/src/pkg/runtime/cgo/cgo.go
index 5dcced1e4..414f3da36 100644
--- a/src/pkg/runtime/cgo/cgo.go
+++ b/src/pkg/runtime/cgo/cgo.go
@@ -9,6 +9,18 @@ for details on using cgo.
*/
package cgo
+/*
+
+#cgo darwin LDFLAGS: -lpthread
+#cgo freebsd LDFLAGS: -lpthread
+#cgo linux LDFLAGS: -lpthread
+#cgo netbsd LDFLAGS: -lpthread
+#cgo openbsd LDFLAGS: -lpthread
+#cgo windows LDFLAGS: -lm -mthreads
+
+*/
+import "C"
+
// Supports _cgo_panic by converting a string constant to an empty
// interface.
diff --git a/src/pkg/runtime/cgo/386.S b/src/pkg/runtime/cgo/gcc_386.S
index 9abab7ebd..9abab7ebd 100755..100644
--- a/src/pkg/runtime/cgo/386.S
+++ b/src/pkg/runtime/cgo/gcc_386.S
diff --git a/src/pkg/runtime/cgo/amd64.S b/src/pkg/runtime/cgo/gcc_amd64.S
index 083c2bc94..706ee6b58 100644
--- a/src/pkg/runtime/cgo/amd64.S
+++ b/src/pkg/runtime/cgo/gcc_amd64.S
@@ -5,7 +5,7 @@
/*
* Apple still insists on underscore prefixes for C function names.
*/
-#if defined(__APPLE__) || defined(_WIN32)
+#if defined(__APPLE__)
#define EXT(s) _##s
#else
#define EXT(s) s
@@ -32,7 +32,11 @@ EXT(crosscall_amd64):
pushq %r14
pushq %r15
+#if defined(_WIN64)
+ call *%rcx /* fn */
+#else
call *%rdi /* fn */
+#endif
popq %r15
popq %r14
@@ -58,10 +62,21 @@ EXT(crosscall2):
movq %r14, 0x30(%rsp)
movq %r15, 0x38(%rsp)
+#if defined(_WIN64)
+ // Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15
+ movq %rdi, 0x40(%rsp)
+ movq %rsi, 0x48(%rsp)
+
+ movq %rdx, 0(%rsp) /* arg */
+ movq %r8, 8(%rsp) /* argsize (includes padding) */
+
+ call *%rcx /* fn */
+#else
movq %rsi, 0(%rsp) /* arg */
movq %rdx, 8(%rsp) /* argsize (includes padding) */
call *%rdi /* fn */
+#endif
movq 0x10(%rsp), %rbx
movq 0x18(%rsp), %rbp
@@ -69,5 +84,9 @@ EXT(crosscall2):
movq 0x28(%rsp), %r13
movq 0x30(%rsp), %r14
movq 0x38(%rsp), %r15
+#if defined(__WIN64)
+ movq 0x40(%rsp), %rdi
+ movq 0x48(%rsp), %rsi
+#endif
addq $0x58, %rsp
ret
diff --git a/src/pkg/runtime/cgo/arm.S b/src/pkg/runtime/cgo/gcc_arm.S
index 32d862984..32d862984 100644
--- a/src/pkg/runtime/cgo/arm.S
+++ b/src/pkg/runtime/cgo/gcc_arm.S
diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/gcc_darwin_386.c
index 6d4e259be..2c30c666f 100644
--- a/src/pkg/runtime/cgo/darwin_386.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_386.c
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <string.h> /* for strerror */
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
@@ -38,8 +40,8 @@ inittls(void)
*
* The linker and runtime hard-code these constant offsets
* from %gs where we expect to find m and g.
- * Known to ../cmd/8l/obj.c:/468
- * and to ../pkg/runtime/darwin/386/sys.s:/468
+ * Known to ../../../cmd/8l/obj.c:/468
+ * and to ../sys_darwin_386.s:/468
*
* This is truly disgusting and a bit fragile, but taking care
* of it here protects the rest of the system from damage.
@@ -100,25 +102,40 @@ inittls(void)
}
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
inittls();
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
index 3471044c0..89dc7a4e8 100644
--- a/src/pkg/runtime/cgo/darwin_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <string.h> /* for strerror */
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
@@ -26,8 +28,8 @@ inittls(void)
*
* The linker and runtime hard-code these constant offsets
* from %gs where we expect to find m and g.
- * Known to ../cmd/6l/obj.c:/8a0
- * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
+ * Known to ../../../cmd/6l/obj.c:/8a0
+ * and to ../sys_darwin_amd64.s:/8a0
*
* As disgusting as on the 386; same justification.
*/
@@ -70,25 +72,40 @@ inittls(void)
}
void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
+
inittls();
}
-void (*initcgo) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index ae53201b4..2c97e2a33 100644
--- a/src/pkg/runtime/cgo/freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -2,30 +2,47 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <sys/types.h>
+#include <sys/signalvar.h>
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ SIGFILLSET(ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index 5afc1dfea..3beb4d7bb 100644
--- a/src/pkg/runtime/cgo/freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -2,30 +2,48 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <sys/types.h>
+#include <sys/signalvar.h>
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ SIGFILLSET(ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
+
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index e9df5ffdc..7d84acc11 100644
--- a/src/pkg/runtime/cgo/linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -4,25 +4,37 @@
#include <pthread.h>
#include <string.h>
+#include <signal.h>
#include "libcgo.h"
static void *threadentry(void*);
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
}
-void (*initcgo) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -32,6 +44,9 @@ libcgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index d9b8b3706..28cbf78c5 100644
--- a/src/pkg/runtime/cgo/linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -3,29 +3,45 @@
// license that can be found in the LICENSE file.
#include <pthread.h>
+#include <string.h> // strerror
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
void
-xinitcgo(void)
+xinitcgo(G* g)
{
+ pthread_attr_t attr;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ g->stackguard = (uintptr)&attr - size + 4096;
+ pthread_attr_destroy(&attr);
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c
index e556c433c..8397c75bb 100644
--- a/src/pkg/runtime/cgo/linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -5,11 +5,12 @@
#include "libcgo.h"
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ // unimplemented
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
diff --git a/src/pkg/runtime/cgo/setenv.c b/src/pkg/runtime/cgo/gcc_setenv.c
index c911b8392..7da4ad915 100644
--- a/src/pkg/runtime/cgo/setenv.c
+++ b/src/pkg/runtime/cgo/gcc_setenv.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
#include "libcgo.h"
#include <stdlib.h>
diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/gcc_util.c
index 9d96521f5..e06b6f64d 100644
--- a/src/pkg/runtime/cgo/util.c
+++ b/src/pkg/runtime/cgo/gcc_util.c
@@ -18,7 +18,7 @@ x_cgo_malloc(void *p)
void (*_cgo_malloc)(void*) = x_cgo_malloc;
-/* Stub for calling from Go */
+/* Stub for calling free from Go */
static void
x_cgo_free(void *p)
{
diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c
index f39309cb1..2b940d362 100755..100644
--- a/src/pkg/runtime/cgo/windows_386.c
+++ b/src/pkg/runtime/cgo/gcc_windows_386.c
@@ -8,22 +8,24 @@
static void *threadentry(void*);
-/* From what I've read 1MB is default for 32-bit Linux.
- Allocation granularity on Windows is typically 64 KB. */
+/* 1MB is default stack size for 32-bit Windows.
+ Allocation granularity on Windows is typically 64 KB.
+ The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (1*1024*1024)
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ int tmp;
+ g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
- ts->g->stackguard = STACKSIZE;
- _beginthread(threadentry, STACKSIZE, ts);
+ _beginthread(threadentry, 0, ts);
}
static void*
@@ -36,20 +38,15 @@ threadentry(void *v)
free(v);
ts.g->stackbase = (uintptr)&ts;
-
- /*
- * libcgo_sys_thread_start set stackguard to stack size;
- * change to actual guard pointer.
- */
- ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+ ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* Set specific keys in thread local storage.
*/
tls0 = (void*)LocalAlloc(LPTR, 32);
asm volatile (
- "movl %0, %%fs:0x2c\n" // MOVL tls0, 0x2c(FS)
- "movl %%fs:0x2c, %%eax\n" // MOVL 0x2c(FS), tmp
+ "movl %0, %%fs:0x14\n" // MOVL tls0, 0x14(FS)
+ "movl %%fs:0x14, %%eax\n" // MOVL 0x14(FS), tmp
"movl %1, 0(%%eax)\n" // MOVL g, 0(FS)
"movl %2, 4(%%eax)\n" // MOVL m, 4(FS)
:: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
diff --git a/src/pkg/runtime/cgo/windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c
index e8313e250..0d2f5d233 100755..100644
--- a/src/pkg/runtime/cgo/windows_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c
@@ -8,22 +8,24 @@
static void *threadentry(void*);
-/* From what I've read 2MB is default for 64-bit Linux.
- Allocation granularity on Windows is typically 64 KB. */
+/* 2MB is default stack size for 64-bit Windows.
+ Allocation granularity on Windows is typically 64 KB.
+ The constant is also hardcoded in cmd/ld/pe.c (keep synchronized). */
#define STACKSIZE (2*1024*1024)
static void
-xinitcgo(void)
+xinitcgo(G *g)
{
+ int tmp;
+ g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024;
}
-void (*initcgo)(void) = xinitcgo;
+void (*initcgo)(G*) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
{
- ts->g->stackguard = STACKSIZE;
- _beginthread(threadentry, STACKSIZE, ts);
+ _beginthread(threadentry, 0, ts);
}
static void*
@@ -36,20 +38,15 @@ threadentry(void *v)
free(v);
ts.g->stackbase = (uintptr)&ts;
-
- /*
- * libcgo_sys_thread_start set stackguard to stack size;
- * change to actual guard pointer.
- */
- ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
+ ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024;
/*
* Set specific keys in thread local storage.
*/
tls0 = (void*)LocalAlloc(LPTR, 64);
asm volatile (
- "movq %0, %%gs:0x58\n" // MOVL tls0, 0x58(GS)
- "movq %%gs:0x58, %%rax\n" // MOVQ 0x58(GS), tmp
+ "movq %0, %%gs:0x28\n" // MOVL tls0, 0x28(GS)
+ "movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp
"movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
"movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
:: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index 91032959c..c31d19d76 100644
--- a/src/pkg/runtime/cgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -42,7 +42,7 @@ struct ThreadStart
* Makes a local copy of the ThreadStart and
* calls libcgo_sys_thread_start(ts).
*/
-void (*libcgo_thread_start)(ThreadStart *ts);
+extern void (*libcgo_thread_start)(ThreadStart *ts);
/*
* Creates the new operating system thread (OS, arch dependent).
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 829448b02..7a26538ec 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "arch.h"
+#include "arch_GOARCH.h"
#include "stack.h"
#include "cgocall.h"
@@ -17,7 +17,7 @@
// so as not to block other goroutines or the garbage collector,
// and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame).
//
-// runtime.asmcgocall (in $GOARCH/asm.s) switches to the m->g0 stack
+// runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack
// (assumed to be an operating system-allocated stack, so safe to run
// gcc-compiled code on) and calls _cgo_Cfunc_f(frame).
//
@@ -55,7 +55,7 @@
// with 6c instead of gcc, can refer to dotted names like
// runtime.cgocallback and p.GoF.)
//
-// runtime.cgocallback (in $GOOS/asm.s) switches from m->g0's
+// runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's
// stack to the original g (m->curg)'s stack, on which it calls
// runtime.cgocallbackg(p.GoF, frame, framesize).
// As part of the stack switch, runtime.cgocallback saves the current
@@ -68,7 +68,7 @@
// stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will
// block until the $GOMAXPROCS limit allows running this goroutine.
// Once exitsyscall has returned, it is safe to do things like call the memory
-// allocator or invoke the Go callback function p.GoF. runtime.cgocallback
+// allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg
// first defers a function to unwind m->g0.sched.sp, so that if p.GoF
// panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack
// and the m->curg stack will be unwound in lock step.
@@ -92,9 +92,9 @@ static void unwindm(void);
void
runtime·cgocall(void (*fn)(void*), void *arg)
{
- Defer *d;
+ Defer d;
- if(!runtime·iscgo)
+ if(!runtime·iscgo && !Windows)
runtime·throw("cgocall unavailable");
if(fn == 0)
@@ -106,18 +106,18 @@ runtime·cgocall(void (*fn)(void*), void *arg)
* Lock g to m to ensure we stay on the same stack if we do a
* cgo callback.
*/
- d = nil;
+ d.nofree = false;
if(m->lockedg == nil) {
m->lockedg = g;
g->lockedm = m;
// Add entry to defer stack in case of panic.
- d = runtime·malloc(sizeof(*d));
- d->fn = (byte*)unlockm;
- d->siz = 0;
- d->link = g->defer;
- d->argp = (void*)-1; // unused because unwindm never recovers
- g->defer = d;
+ d.fn = (byte*)unlockm;
+ d.siz = 0;
+ d.link = g->defer;
+ d.argp = (void*)-1; // unused because unlockm never recovers
+ d.nofree = true;
+ g->defer = &d;
}
/*
@@ -135,11 +135,10 @@ runtime·cgocall(void (*fn)(void*), void *arg)
runtime·asmcgocall(fn, arg);
runtime·exitsyscall();
- if(d != nil) {
- if(g->defer != d || d->fn != (byte*)unlockm)
+ if(d.nofree) {
+ if(g->defer != &d || d.fn != (byte*)unlockm)
runtime·throw("runtime: bad defer entry in cgocallback");
- g->defer = d->link;
- runtime·free(d);
+ g->defer = d.link;
unlockm();
}
}
@@ -152,7 +151,7 @@ unlockm(void)
}
void
-runtime·Cgocalls(int64 ret)
+runtime·NumCgoCall(int64 ret)
{
M *m;
@@ -192,7 +191,7 @@ runtime·cfree(void *p)
void
runtime·cgocallbackg(void (*fn)(void), void *arg, uintptr argsize)
{
- Defer *d;
+ Defer d;
if(g != m->curg)
runtime·throw("runtime: bad g in cgocallback");
@@ -200,12 +199,12 @@ runtime·cgocallbackg(void (*fn)(void), void *arg, uintptr argsize)
runtime·exitsyscall(); // coming out of cgo call
// Add entry to defer stack in case of panic.
- d = runtime·malloc(sizeof(*d));
- d->fn = (byte*)unwindm;
- d->siz = 0;
- d->link = g->defer;
- d->argp = (void*)-1; // unused because unwindm never recovers
- g->defer = d;
+ d.fn = (byte*)unwindm;
+ d.siz = 0;
+ d.link = g->defer;
+ d.argp = (void*)-1; // unused because unwindm never recovers
+ d.nofree = true;
+ g->defer = &d;
// Invoke callback.
reflect·call((byte*)fn, arg, argsize);
@@ -213,10 +212,9 @@ runtime·cgocallbackg(void (*fn)(void), void *arg, uintptr argsize)
// Pop defer.
// Do not unwind m->g0->sched.sp.
// Our caller, cgocallback, will do that.
- if(g->defer != d || d->fn != (byte*)unwindm)
+ if(g->defer != &d || d.fn != (byte*)unwindm)
runtime·throw("runtime: bad defer entry in cgocallback");
- g->defer = d->link;
- runtime·free(d);
+ g->defer = d.link;
runtime·entersyscall(); // going back to cgo call
}
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index ef5342353..ef27144ef 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -92,11 +92,6 @@ runtime·makechan_c(ChanType *t, int64 hint)
if(hint < 0 || (int32)hint != hint || (elem->size > 0 && hint > ((uintptr)-1) / elem->size))
runtime·panicstring("makechan: size out of range");
- if(elem->alg >= nelem(runtime·algarray)) {
- runtime·printf("chan(alg=%d)\n", elem->alg);
- runtime·throw("runtime.makechan: unsupported elem type");
- }
-
// calculate rounded size of Hchan
n = sizeof(*c);
while(n & MAXALIGN)
@@ -104,16 +99,13 @@ runtime·makechan_c(ChanType *t, int64 hint)
// allocate memory in one call
c = (Hchan*)runtime·mal(n + hint*elem->size);
- if(runtime·destroylock)
- runtime·addfinalizer(c, destroychan, 0);
-
c->elemsize = elem->size;
- c->elemalg = &runtime·algarray[elem->alg];
+ c->elemalg = elem->alg;
c->elemalign = elem->align;
c->dataqsiz = hint;
if(debug)
- runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
+ runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; elemalign=%d; dataqsiz=%d\n",
c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz);
return c;
@@ -128,13 +120,6 @@ reflect·makechan(ChanType *t, uint32 size, Hchan *c)
FLUSH(&c);
}
-static void
-destroychan(Hchan *c)
-{
- runtime·destroylock(&c->Lock);
-}
-
-
// makechan(t *ChanType, hint int64) (hchan *chan any);
void
runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
@@ -171,6 +156,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
return;
}
g->status = Gwaiting;
+ g->waitreason = "chan send (nil chan)";
runtime·gosched();
return; // not reached
}
@@ -217,6 +203,7 @@ runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
mysg.selgen = NOSELGEN;
g->param = nil;
g->status = Gwaiting;
+ g->waitreason = "chan send";
enqueue(&c->sendq, &mysg);
runtime·unlock(c);
runtime·gosched();
@@ -244,6 +231,7 @@ asynch:
mysg.elem = nil;
mysg.selgen = NOSELGEN;
g->status = Gwaiting;
+ g->waitreason = "chan send";
enqueue(&c->sendq, &mysg);
runtime·unlock(c);
runtime·gosched();
@@ -293,6 +281,7 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
return;
}
g->status = Gwaiting;
+ g->waitreason = "chan receive (nil chan)";
runtime·gosched();
return; // not reached
}
@@ -332,6 +321,7 @@ runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *receive
mysg.selgen = NOSELGEN;
g->param = nil;
g->status = Gwaiting;
+ g->waitreason = "chan receive";
enqueue(&c->recvq, &mysg);
runtime·unlock(c);
runtime·gosched();
@@ -363,6 +353,7 @@ asynch:
mysg.elem = nil;
mysg.selgen = NOSELGEN;
g->status = Gwaiting;
+ g->waitreason = "chan receive";
enqueue(&c->recvq, &mysg);
runtime·unlock(c);
runtime·gosched();
@@ -595,6 +586,10 @@ newselect(int32 size, Select **selp)
if(size > 1)
n = size-1;
+ // allocate all the memory we need in a single allocation
+ // start with Select with size cases
+ // then lockorder with size entries
+ // then pollorder with size entries
sel = runtime·mal(sizeof(*sel) +
n*sizeof(sel->scase[0]) +
size*sizeof(sel->lockorder[0]) +
@@ -602,8 +597,8 @@ newselect(int32 size, Select **selp)
sel->tcase = size;
sel->ncase = 0;
- sel->pollorder = (void*)(sel->scase + size);
- sel->lockorder = (void*)(sel->pollorder + size);
+ sel->lockorder = (void*)(sel->scase + size);
+ sel->pollorder = (void*)(sel->lockorder + size);
*selp = sel;
if(debug)
@@ -780,6 +775,7 @@ void
runtime·block(void)
{
g->status = Gwaiting; // forever
+ g->waitreason = "select (no cases)";
runtime·gosched();
}
@@ -912,6 +908,7 @@ loop:
g->param = nil;
g->status = Gwaiting;
+ g->waitreason = "select";
selunlock(sel);
runtime·gosched();
@@ -1016,7 +1013,8 @@ syncsend:
selunlock(sel);
if(debug)
runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
- c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
+ if(sg->elem != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
gp = sg->g;
gp->param = sg;
runtime·ready(gp);
@@ -1043,6 +1041,9 @@ runtime·closechan(Hchan *c)
SudoG *sg;
G* gp;
+ if(c == nil)
+ runtime·panicstring("close of nil channel");
+
if(runtime·gcwaiting)
runtime·gosched();
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
index 46ddfd7e8..eb2c7c60d 100644
--- a/src/pkg/runtime/chan_test.go
+++ b/src/pkg/runtime/chan_test.go
@@ -59,6 +59,57 @@ func TestPseudoRandomSend(t *testing.T) {
t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
}
+func TestMultiConsumer(t *testing.T) {
+ const nwork = 23
+ const niter = 271828
+
+ pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31}
+
+ q := make(chan int, nwork*3)
+ r := make(chan int, nwork*3)
+
+ // workers
+ var wg sync.WaitGroup
+ for i := 0; i < nwork; i++ {
+ wg.Add(1)
+ go func(w int) {
+ for v := range q {
+ // mess with the fifo-ish nature of range
+ if pn[w%len(pn)] == v {
+ runtime.Gosched()
+ }
+ r <- v
+ }
+ wg.Done()
+ }(i)
+ }
+
+ // feeder & closer
+ expect := 0
+ go func() {
+ for i := 0; i < niter; i++ {
+ v := pn[i%len(pn)]
+ expect += v
+ q <- v
+ }
+ close(q) // no more work
+ wg.Wait() // workers done
+ close(r) // ... so there can be no more results
+ }()
+
+ // consume & check
+ n := 0
+ s := 0
+ for v := range r {
+ n++
+ s += v
+ }
+ if n != niter || s != expect {
+ t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)",
+ expect, s, niter, n)
+ }
+}
+
func BenchmarkSelectUncontended(b *testing.B) {
const CallsPerSched = 1000
procs := runtime.GOMAXPROCS(-1)
@@ -320,3 +371,12 @@ func BenchmarkChanCreation(b *testing.B) {
<-c
}
}
+
+func BenchmarkChanSem(b *testing.B) {
+ type Empty struct{}
+ c := make(chan Empty, 1)
+ for i := 0; i < b.N; i++ {
+ c <- Empty{}
+ <-c
+ }
+}
diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/closure_386.c
index b4d867711..b4d867711 100644
--- a/src/pkg/runtime/386/closure.c
+++ b/src/pkg/runtime/closure_386.c
diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/closure_amd64.c
index 481b4a888..481b4a888 100644
--- a/src/pkg/runtime/amd64/closure.c
+++ b/src/pkg/runtime/closure_amd64.c
diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/closure_arm.c
index 119e91b61..119e91b61 100644
--- a/src/pkg/runtime/arm/closure.c
+++ b/src/pkg/runtime/closure_arm.c
diff --git a/src/pkg/runtime/compiler.go b/src/pkg/runtime/compiler.go
new file mode 100644
index 000000000..562a46022
--- /dev/null
+++ b/src/pkg/runtime/compiler.go
@@ -0,0 +1,13 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+// Compiler is the name of the compiler toolchain that built the
+// running binary. Known toolchains are:
+//
+// gc The 5g/6g/8g compiler suite at code.google.com/p/go.
+// gccgo The gccgo front end, part of the GCC compiler suite.
+//
+const Compiler = "gc"
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.c
index 74b795b7e..05fa0cf61 100644
--- a/src/pkg/runtime/cpuprof.c
+++ b/src/pkg/runtime/cpuprof.c
@@ -49,6 +49,7 @@
// in the situation when normally the goroutine "owns" handoff.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
enum
diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h
deleted file mode 100644
index bb70207fd..000000000
--- a/src/pkg/runtime/darwin/386/defs.h
+++ /dev/null
@@ -1,289 +0,0 @@
-// godefs -f -m32 defs.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-enum {
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
- MACH_MSG_TYPE_MOVE_SEND = 0x11,
- MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
- MACH_MSG_TYPE_COPY_SEND = 0x13,
- MACH_MSG_TYPE_MAKE_SEND = 0x14,
- MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
- MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
- MACH_MSG_PORT_DESCRIPTOR = 0,
- MACH_MSG_OOL_DESCRIPTOR = 0x1,
- MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
- MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
- MACH_MSGH_BITS_COMPLEX = 0x80000000,
- MACH_SEND_MSG = 0x1,
- MACH_RCV_MSG = 0x2,
- MACH_RCV_LARGE = 0x4,
- MACH_SEND_TIMEOUT = 0x10,
- MACH_SEND_INTERRUPT = 0x40,
- MACH_SEND_CANCEL = 0x80,
- MACH_SEND_ALWAYS = 0x10000,
- MACH_SEND_TRAILER = 0x20000,
- MACH_RCV_TIMEOUT = 0x100,
- MACH_RCV_NOTIFY = 0x200,
- MACH_RCV_INTERRUPT = 0x400,
- MACH_RCV_OVERWRITE = 0x1000,
- NDR_PROTOCOL_2_0 = 0,
- NDR_INT_BIG_ENDIAN = 0,
- NDR_INT_LITTLE_ENDIAN = 0x1,
- NDR_FLOAT_IEEE = 0,
- NDR_CHAR_ASCII = 0,
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
- SA_USERTRAMP = 0x100,
- SA_64REGSET = 0x200,
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
- FPE_INTDIV = 0x7,
- FPE_INTOVF = 0x8,
- FPE_FLTDIV = 0x1,
- FPE_FLTOVF = 0x2,
- FPE_FLTUND = 0x3,
- FPE_FLTRES = 0x4,
- FPE_FLTINV = 0x5,
- FPE_FLTSUB = 0x6,
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
- ITIMER_REAL = 0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-};
-
-// Types
-#pragma pack on
-
-typedef struct MachBody MachBody;
-struct MachBody {
- uint32 msgh_descriptor_count;
-};
-
-typedef struct MachHeader MachHeader;
-struct MachHeader {
- uint32 msgh_bits;
- uint32 msgh_size;
- uint32 msgh_remote_port;
- uint32 msgh_local_port;
- uint32 msgh_reserved;
- int32 msgh_id;
-};
-
-typedef struct MachNDR MachNDR;
-struct MachNDR {
- uint8 mig_vers;
- uint8 if_vers;
- uint8 reserved1;
- uint8 mig_encoding;
- uint8 int_rep;
- uint8 char_rep;
- uint8 float_rep;
- uint8 reserved2;
-};
-
-typedef struct MachPort MachPort;
-struct MachPort {
- uint32 name;
- uint32 pad1;
- uint16 pad2;
- uint8 disposition;
- uint8 type;
-};
-
-typedef struct StackT StackT;
-struct StackT {
- void *ss_sp;
- uint32 ss_size;
- int32 ss_flags;
-};
-
-typedef union Sighandler Sighandler;
-union Sighandler {
- uint32 __sa_handler;
- uint32 __sa_sigaction;
-};
-
-typedef struct Sigaction Sigaction;
-struct Sigaction {
- Sighandler __sigaction_u;
- uint32 sa_tramp;
- uint32 sa_mask;
- int32 sa_flags;
-};
-
-typedef union Sigval Sigval;
-union Sigval {
- int32 sival_int;
- void *sival_ptr;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- void *si_addr;
- Sigval si_value;
- int32 si_band;
- uint32 __pad[7];
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-typedef struct FPControl FPControl;
-struct FPControl {
- byte pad_godefs_0[2];
-};
-
-typedef struct FPStatus FPStatus;
-struct FPStatus {
- byte pad_godefs_0[2];
-};
-
-typedef struct RegMMST RegMMST;
-struct RegMMST {
- int8 mmst_reg[10];
- int8 mmst_rsrv[6];
-};
-
-typedef struct RegXMM RegXMM;
-struct RegXMM {
- int8 xmm_reg[16];
-};
-
-typedef struct Regs Regs;
-struct Regs {
- uint32 eax;
- uint32 ebx;
- uint32 ecx;
- uint32 edx;
- uint32 edi;
- uint32 esi;
- uint32 ebp;
- uint32 esp;
- uint32 ss;
- uint32 eflags;
- uint32 eip;
- uint32 cs;
- uint32 ds;
- uint32 es;
- uint32 fs;
- uint32 gs;
-};
-
-typedef struct FloatState FloatState;
-struct FloatState {
- uint64 fpu_reserved;
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- int8 fpu_rsrv4[224];
- int32 fpu_reserved1;
-};
-
-typedef struct ExceptionState ExceptionState;
-struct ExceptionState {
- uint32 trapno;
- uint32 err;
- uint32 faultvaddr;
-};
-
-typedef struct Mcontext Mcontext;
-struct Mcontext {
- ExceptionState es;
- Regs ss;
- FloatState fs;
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
- int32 uc_onstack;
- uint32 uc_sigmask;
- StackT uc_stack;
- uint32 uc_link;
- uint32 uc_mcsize;
- Mcontext *uc_mcontext;
-};
-#pragma pack off
diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h
deleted file mode 100644
index 90f798e8a..000000000
--- a/src/pkg/runtime/darwin/amd64/defs.h
+++ /dev/null
@@ -1,305 +0,0 @@
-// godefs -f -m64 defs.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-enum {
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x1000,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
- MACH_MSG_TYPE_MOVE_SEND = 0x11,
- MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
- MACH_MSG_TYPE_COPY_SEND = 0x13,
- MACH_MSG_TYPE_MAKE_SEND = 0x14,
- MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
- MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
- MACH_MSG_PORT_DESCRIPTOR = 0,
- MACH_MSG_OOL_DESCRIPTOR = 0x1,
- MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
- MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
- MACH_MSGH_BITS_COMPLEX = 0x80000000,
- MACH_SEND_MSG = 0x1,
- MACH_RCV_MSG = 0x2,
- MACH_RCV_LARGE = 0x4,
- MACH_SEND_TIMEOUT = 0x10,
- MACH_SEND_INTERRUPT = 0x40,
- MACH_SEND_CANCEL = 0x80,
- MACH_SEND_ALWAYS = 0x10000,
- MACH_SEND_TRAILER = 0x20000,
- MACH_RCV_TIMEOUT = 0x100,
- MACH_RCV_NOTIFY = 0x200,
- MACH_RCV_INTERRUPT = 0x400,
- MACH_RCV_OVERWRITE = 0x1000,
- NDR_PROTOCOL_2_0 = 0,
- NDR_INT_BIG_ENDIAN = 0,
- NDR_INT_LITTLE_ENDIAN = 0x1,
- NDR_FLOAT_IEEE = 0,
- NDR_CHAR_ASCII = 0,
- SA_SIGINFO = 0x40,
- SA_RESTART = 0x2,
- SA_ONSTACK = 0x1,
- SA_USERTRAMP = 0x100,
- SA_64REGSET = 0x200,
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGEMT = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGBUS = 0xa,
- SIGSEGV = 0xb,
- SIGSYS = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGTERM = 0xf,
- SIGURG = 0x10,
- SIGSTOP = 0x11,
- SIGTSTP = 0x12,
- SIGCONT = 0x13,
- SIGCHLD = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGIO = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGINFO = 0x1d,
- SIGUSR1 = 0x1e,
- SIGUSR2 = 0x1f,
- FPE_INTDIV = 0x7,
- FPE_INTOVF = 0x8,
- FPE_FLTDIV = 0x1,
- FPE_FLTOVF = 0x2,
- FPE_FLTUND = 0x3,
- FPE_FLTRES = 0x4,
- FPE_FLTINV = 0x5,
- FPE_FLTSUB = 0x6,
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
- ITIMER_REAL = 0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
-};
-
-// Types
-#pragma pack on
-
-typedef struct MachBody MachBody;
-struct MachBody {
- uint32 msgh_descriptor_count;
-};
-
-typedef struct MachHeader MachHeader;
-struct MachHeader {
- uint32 msgh_bits;
- uint32 msgh_size;
- uint32 msgh_remote_port;
- uint32 msgh_local_port;
- uint32 msgh_reserved;
- int32 msgh_id;
-};
-
-typedef struct MachNDR MachNDR;
-struct MachNDR {
- uint8 mig_vers;
- uint8 if_vers;
- uint8 reserved1;
- uint8 mig_encoding;
- uint8 int_rep;
- uint8 char_rep;
- uint8 float_rep;
- uint8 reserved2;
-};
-
-typedef struct MachPort MachPort;
-struct MachPort {
- uint32 name;
- uint32 pad1;
- uint16 pad2;
- uint8 disposition;
- uint8 type;
-};
-
-typedef struct StackT StackT;
-struct StackT {
- void *ss_sp;
- uint64 ss_size;
- int32 ss_flags;
- byte pad_godefs_0[4];
-};
-
-typedef union Sighandler Sighandler;
-union Sighandler {
- uint64 __sa_handler;
- uint64 __sa_sigaction;
-};
-
-typedef struct Sigaction Sigaction;
-struct Sigaction {
- Sighandler __sigaction_u;
- uint64 sa_tramp;
- uint32 sa_mask;
- int32 sa_flags;
-};
-
-typedef union Sigval Sigval;
-union Sigval {
- int32 sival_int;
- void *sival_ptr;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- int32 si_pid;
- uint32 si_uid;
- int32 si_status;
- void *si_addr;
- Sigval si_value;
- int64 si_band;
- uint64 __pad[7];
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
- int64 tv_sec;
- int32 tv_usec;
- byte pad_godefs_0[4];
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-
-typedef struct FPControl FPControl;
-struct FPControl {
- byte pad_godefs_0[2];
-};
-
-typedef struct FPStatus FPStatus;
-struct FPStatus {
- byte pad_godefs_0[2];
-};
-
-typedef struct RegMMST RegMMST;
-struct RegMMST {
- int8 mmst_reg[10];
- int8 mmst_rsrv[6];
-};
-
-typedef struct RegXMM RegXMM;
-struct RegXMM {
- int8 xmm_reg[16];
-};
-
-typedef struct Regs Regs;
-struct Regs {
- uint64 rax;
- uint64 rbx;
- uint64 rcx;
- uint64 rdx;
- uint64 rdi;
- uint64 rsi;
- uint64 rbp;
- uint64 rsp;
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rip;
- uint64 rflags;
- uint64 cs;
- uint64 fs;
- uint64 gs;
-};
-
-typedef struct FloatState FloatState;
-struct FloatState {
- uint64 fpu_reserved;
- FPControl fpu_fcw;
- FPStatus fpu_fsw;
- uint8 fpu_ftw;
- uint8 fpu_rsrv1;
- uint16 fpu_fop;
- uint32 fpu_ip;
- uint16 fpu_cs;
- uint16 fpu_rsrv2;
- uint32 fpu_dp;
- uint16 fpu_ds;
- uint16 fpu_rsrv3;
- uint32 fpu_mxcsr;
- uint32 fpu_mxcsrmask;
- RegMMST fpu_stmm0;
- RegMMST fpu_stmm1;
- RegMMST fpu_stmm2;
- RegMMST fpu_stmm3;
- RegMMST fpu_stmm4;
- RegMMST fpu_stmm5;
- RegMMST fpu_stmm6;
- RegMMST fpu_stmm7;
- RegXMM fpu_xmm0;
- RegXMM fpu_xmm1;
- RegXMM fpu_xmm2;
- RegXMM fpu_xmm3;
- RegXMM fpu_xmm4;
- RegXMM fpu_xmm5;
- RegXMM fpu_xmm6;
- RegXMM fpu_xmm7;
- RegXMM fpu_xmm8;
- RegXMM fpu_xmm9;
- RegXMM fpu_xmm10;
- RegXMM fpu_xmm11;
- RegXMM fpu_xmm12;
- RegXMM fpu_xmm13;
- RegXMM fpu_xmm14;
- RegXMM fpu_xmm15;
- int8 fpu_rsrv4[96];
- int32 fpu_reserved1;
-};
-
-typedef struct ExceptionState ExceptionState;
-struct ExceptionState {
- uint32 trapno;
- uint32 err;
- uint64 faultvaddr;
-};
-
-typedef struct Mcontext Mcontext;
-struct Mcontext {
- ExceptionState es;
- Regs ss;
- FloatState fs;
- byte pad_godefs_0[4];
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
- int32 uc_onstack;
- uint32 uc_sigmask;
- StackT uc_stack;
- uint64 uc_link;
- uint64 uc_mcsize;
- Mcontext *uc_mcontext;
-};
-#pragma pack off
diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c
deleted file mode 100644
index 032a6bcbb..000000000
--- a/src/pkg/runtime/darwin/defs.c
+++ /dev/null
@@ -1,159 +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.
-
-/*
- * Input to godefs.
- *
- godefs -f -m64 defs.c >amd64/defs.h
- godefs -f -m32 defs.c >386/defs.h
- */
-
-#define __DARWIN_UNIX03 0
-
-#include <mach/mach.h>
-#include <mach/message.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <sys/mman.h>
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANON,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE,
- $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND,
- $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE,
- $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND,
- $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND,
- $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE,
- $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE,
-
- $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR,
- $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR,
- $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR,
- $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR,
-
- $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX,
-
- $MACH_SEND_MSG = MACH_SEND_MSG,
- $MACH_RCV_MSG = MACH_RCV_MSG,
- $MACH_RCV_LARGE = MACH_RCV_LARGE,
-
- $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT,
- $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT,
- $MACH_SEND_CANCEL = MACH_SEND_CANCEL,
- $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS,
- $MACH_SEND_TRAILER = MACH_SEND_TRAILER,
- $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT,
- $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY,
- $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT,
- $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE,
-
- $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0,
- $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN,
- $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN,
- $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE,
- $NDR_CHAR_ASCII = NDR_CHAR_ASCII,
-
- $SA_SIGINFO = SA_SIGINFO,
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
- $SA_USERTRAMP = SA_USERTRAMP,
- $SA_64REGSET = SA_64REGSET,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGEMT = SIGEMT,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGBUS = SIGBUS,
- $SIGSEGV = SIGSEGV,
- $SIGSYS = SIGSYS,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGTERM = SIGTERM,
- $SIGURG = SIGURG,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGCONT = SIGCONT,
- $SIGCHLD = SIGCHLD,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGIO = SIGIO,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGINFO = SIGINFO,
- $SIGUSR1 = SIGUSR1,
- $SIGUSR2 = SIGUSR2,
-
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
-
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
- $ITIMER_PROF = ITIMER_PROF,
-};
-
-typedef mach_msg_body_t $MachBody;
-typedef mach_msg_header_t $MachHeader;
-typedef NDR_record_t $MachNDR;
-typedef mach_msg_port_descriptor_t $MachPort;
-
-typedef stack_t $StackT;
-typedef union __sigaction_u $Sighandler;
-
-typedef struct __sigaction $Sigaction; // used in syscalls
-// typedef struct sigaction $Sigaction; // used by the C library
-typedef union sigval $Sigval;
-typedef siginfo_t $Siginfo;
-typedef struct timeval $Timeval;
-typedef struct itimerval $Itimerval;
-
-typedef struct fp_control $FPControl;
-typedef struct fp_status $FPStatus;
-typedef struct mmst_reg $RegMMST;
-typedef struct xmm_reg $RegXMM;
-
-#ifdef __LP64__
-// amd64
-typedef x86_thread_state64_t $Regs;
-typedef x86_float_state64_t $FloatState;
-typedef x86_exception_state64_t $ExceptionState;
-typedef struct mcontext64 $Mcontext;
-#else
-// 386
-typedef x86_thread_state32_t $Regs;
-typedef x86_float_state32_t $FloatState;
-typedef x86_exception_state32_t $ExceptionState;
-typedef struct mcontext32 $Mcontext;
-#endif
-
-typedef ucontext_t $Ucontext;
diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h
deleted file mode 100644
index 035027fad..000000000
--- a/src/pkg/runtime/darwin/signals.h
+++ /dev/null
@@ -1,51 +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.
-
-#define C SigCatch
-#define I SigIgnore
-#define R SigRestart
-#define Q SigQueue
-#define P SigPanic
-
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ Q+R, "SIGHUP: terminal line hangup",
- /* 2 */ Q+R, "SIGINT: interrupt",
- /* 3 */ C, "SIGQUIT: quit",
- /* 4 */ C, "SIGILL: illegal instruction",
- /* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */
- /* 6 */ C, "SIGABRT: abort",
- /* 7 */ C, "SIGEMT: emulate instruction executed",
- /* 8 */ C+P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ C+P, "SIGBUS: bus error",
- /* 11 */ C+P, "SIGSEGV: segmentation violation",
- /* 12 */ C, "SIGSYS: bad system call",
- /* 13 */ I, "SIGPIPE: write to broken pipe",
- /* 14 */ Q+I+R, "SIGALRM: alarm clock",
- /* 15 */ Q+R, "SIGTERM: termination",
- /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop",
- /* 18 */ Q+I+R, "SIGTSTP: keyboard stop",
- /* 19 */ 0, "SIGCONT: continue after stop",
- /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
- /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
- /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
- /* 23 */ Q+I+R, "SIGIO: i/o now possible",
- /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
- /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
- /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
- /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
- /* 28 */ Q+I+R, "SIGWINCH: window size change",
- /* 29 */ Q+I+R, "SIGINFO: status request from keyboard",
- /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
- /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
-};
-#undef C
-#undef I
-#undef R
-#undef Q
-#undef P
-
-#define NSIG 32
diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go
index 6370a57d8..b802fc63f 100644
--- a/src/pkg/runtime/debug.go
+++ b/src/pkg/runtime/debug.go
@@ -10,7 +10,6 @@ func Breakpoint()
// LockOSThread wires the calling goroutine to its current operating system thread.
// Until the calling goroutine exits or calls UnlockOSThread, it will always
// execute in that thread, and no other goroutine can.
-// LockOSThread cannot be used during init functions.
func LockOSThread()
// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
@@ -20,26 +19,18 @@ func UnlockOSThread()
// GOMAXPROCS sets the maximum number of CPUs that can be executing
// simultaneously and returns the previous setting. If n < 1, it does not
// change the current setting.
+// The number of logical CPUs on the local machine can be queried with NumCPU.
// This call will go away when the scheduler improves.
func GOMAXPROCS(n int) int
-// Cgocalls returns the number of cgo calls made by the current process.
-func Cgocalls() int64
+// NumCPU returns the number of logical CPUs on the local machine.
+func NumCPU() int
-// Goroutines returns the number of goroutines that currently exist.
-func Goroutines() int32
+// NumCgoCall returns the number of cgo calls made by the current process.
+func NumCgoCall() int64
-// Alloc allocates a block of the given size.
-// FOR TESTING AND DEBUGGING ONLY.
-func Alloc(uintptr) *byte
-
-// Free frees the block starting at the given pointer.
-// FOR TESTING AND DEBUGGING ONLY.
-func Free(*byte)
-
-// Lookup returns the base and size of the block containing the given pointer.
-// FOR TESTING AND DEBUGGING ONLY.
-func Lookup(*byte) (*byte, uintptr)
+// NumGoroutine returns the number of goroutines that currently exist.
+func NumGoroutine() int
// MemProfileRate controls the fraction of memory allocations
// that are recorded and reported in the memory profile.
@@ -92,11 +83,44 @@ func (r *MemProfileRecord) Stack() []uintptr {
// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes.
// These are sites where memory was allocated, but it has all
// been released back to the runtime.
+//
// Most clients should use the runtime/pprof package or
// the testing package's -test.memprofile flag instead
// of calling MemProfile directly.
func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)
+// A StackRecord describes a single execution stack.
+type StackRecord struct {
+ Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry
+}
+
+// Stack returns the stack trace associated with the record,
+// a prefix of r.Stack0.
+func (r *StackRecord) Stack() []uintptr {
+ for i, v := range r.Stack0 {
+ if v == 0 {
+ return r.Stack0[0:i]
+ }
+ }
+ return r.Stack0[0:]
+}
+
+// ThreadCreateProfile returns n, the number of records in the thread creation profile.
+// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true.
+// If len(p) < n, ThreadCreateProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling ThreadCreateProfile directly.
+func ThreadCreateProfile(p []StackRecord) (n int, ok bool)
+
+// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
+// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
+// If len(p) < n, GoroutineProfile does not change p and returns n, false.
+//
+// Most clients should use the runtime/pprof package instead
+// of calling GoroutineProfile directly.
+func GoroutineProfile(p []StackRecord) (n int, ok bool)
+
// CPUProfile returns the next chunk of binary CPU profiling stack trace data,
// blocking until data is available. If profiling is turned off and all the profile
// data accumulated while it was on has been returned, CPUProfile returns nil.
@@ -113,3 +137,9 @@ func CPUProfile() []byte
// the testing package's -test.cpuprofile flag instead of calling
// SetCPUProfileRate directly.
func SetCPUProfileRate(hz int)
+
+// Stack formats a stack trace of the calling goroutine into buf
+// and returns the number of bytes written to buf.
+// If all is true, Stack formats stack traces of all other goroutines
+// into buf after the trace for the current goroutine.
+func Stack(buf []byte, all bool) int
diff --git a/src/pkg/runtime/debug/Makefile b/src/pkg/runtime/debug/Makefile
deleted file mode 100644
index 885f66aca..000000000
--- a/src/pkg/runtime/debug/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=runtime/debug
-GOFILES=\
- stack.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go
index 94293bb93..f33f5072b 100644
--- a/src/pkg/runtime/debug/stack_test.go
+++ b/src/pkg/runtime/debug/stack_test.go
@@ -39,13 +39,20 @@ func TestStack(t *testing.T) {
if len(lines) <= 6 {
t.Fatal("too few lines")
}
- check(t, lines[0], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[1], "\t(*T).ptrmethod: return Stack()")
- check(t, lines[2], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[3], "\tT.method: return t.ptrmethod()")
- check(t, lines[4], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[5], "\tTestStack: b := T(0).method()")
- check(t, lines[6], "src/pkg/testing/testing.go")
+ n := 0
+ frame := func(line, code string) {
+ check(t, lines[n], line)
+ n++
+ // The source might not be available while running the test.
+ if strings.HasPrefix(lines[n], "\t") {
+ check(t, lines[n], code)
+ n++
+ }
+ }
+ frame("src/pkg/runtime/debug/stack_test.go", "\t(*T).ptrmethod: return Stack()")
+ frame("src/pkg/runtime/debug/stack_test.go", "\tT.method: return t.ptrmethod()")
+ frame("src/pkg/runtime/debug/stack_test.go", "\tTestStack: b := T(0).method()")
+ frame("src/pkg/testing/testing.go", "")
}
func check(t *testing.T, line, has string) {
diff --git a/src/pkg/runtime/defs1_linux.go b/src/pkg/runtime/defs1_linux.go
new file mode 100644
index 000000000..451817a67
--- /dev/null
+++ b/src/pkg/runtime/defs1_linux.go
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -cdefs
+
+GOARCH=amd64 cgo -cdefs defs.go defs1.go >amd64/defs.h
+*/
+
+package runtime
+
+/*
+#include <ucontext.h>
+#include <fcntl.h>
+*/
+import "C"
+
+const (
+ O_RDONLY = C.O_RDONLY
+ O_CLOEXEC = C.O_CLOEXEC
+)
+
+type Usigset C.__sigset_t
+type Fpxreg C.struct__libc_fpxreg
+type Xmmreg C.struct__libc_xmmreg
+type Fpstate C.struct__libc_fpstate
+type Fpxreg1 C.struct__fpxreg
+type Xmmreg1 C.struct__xmmreg
+type Fpstate1 C.struct__fpstate
+type Fpreg1 C.struct__fpreg
+type Sigaltstack C.struct_sigaltstack
+type Mcontext C.mcontext_t
+type Ucontext C.ucontext_t
+type Sigcontext C.struct_sigcontext
diff --git a/src/pkg/runtime/defs2_linux.go b/src/pkg/runtime/defs2_linux.go
new file mode 100644
index 000000000..9b0702955
--- /dev/null
+++ b/src/pkg/runtime/defs2_linux.go
@@ -0,0 +1,126 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+ * Input to cgo -cdefs
+
+GOARCH=386 cgo -cdefs defs2.go >386/defs.h
+
+The asm header tricks we have to use for Linux on amd64
+(see defs.c and defs1.c) don't work here, so this is yet another
+file. Sigh.
+*/
+
+package runtime
+
+/*
+#cgo CFLAGS: -I/home/rsc/pub/linux-2.6/arch/x86/include -I/home/rsc/pub/linux-2.6/include -D_LOOSE_KERNEL_NAMES -D__ARCH_SI_UID_T=__kernel_uid32_t
+
+#define size_t __kernel_size_t
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/siginfo.h>
+#include <asm-generic/fcntl.h>
+
+// This is the sigaction structure from the Linux 2.1.68 kernel which
+// is used with the rt_sigaction system call. For 386 this is not
+// defined in any public header file.
+
+struct kernel_sigaction {
+ __sighandler_t k_sa_handler;
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+ sigset_t sa_mask;
+};
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANONYMOUS
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_DONTNEED = C.MADV_DONTNEED
+
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+ SA_RESTORER = C.SA_RESTORER
+ SA_SIGINFO = C.SA_SIGINFO
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGBUS = C.SIGBUS
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGUSR1 = C.SIGUSR1
+ SIGSEGV = C.SIGSEGV
+ SIGUSR2 = C.SIGUSR2
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGSTKFLT = C.SIGSTKFLT
+ SIGCHLD = C.SIGCHLD
+ SIGCONT = C.SIGCONT
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGURG = C.SIGURG
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGIO = C.SIGIO
+ SIGPWR = C.SIGPWR
+ SIGSYS = C.SIGSYS
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+
+ O_RDONLY = C.O_RDONLY
+ O_CLOEXEC = C.O_CLOEXEC
+)
+
+type Fpreg C.struct__fpreg
+type Fpxreg C.struct__fpxreg
+type Xmmreg C.struct__xmmreg
+type Fpstate C.struct__fpstate
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Sigaction C.struct_kernel_sigaction
+type Siginfo C.siginfo_t
+type Sigaltstack C.struct_sigaltstack
+type Sigcontext C.struct_sigcontext
+type Ucontext C.struct_ucontext
+type Itimerval C.struct_itimerval
diff --git a/src/pkg/runtime/defs_arm_linux.go b/src/pkg/runtime/defs_arm_linux.go
new file mode 100644
index 000000000..db0a19154
--- /dev/null
+++ b/src/pkg/runtime/defs_arm_linux.go
@@ -0,0 +1,124 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+On a Debian Lenny arm linux distribution:
+
+cgo -cdefs defs_arm.c >arm/defs.h
+*/
+
+package runtime
+
+/*
+#cgo CFLAGS: -I/usr/src/linux-headers-2.6.26-2-versatile/include
+
+#define __ARCH_SI_UID_T int
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/siginfo.h>
+#include <linux/time.h>
+
+struct xsiginfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+ char _sifields[4];
+};
+
+#undef sa_handler
+#undef sa_flags
+#undef sa_restorer
+#undef sa_mask
+
+struct xsigaction {
+ void (*sa_handler)(void);
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ unsigned int sa_mask; // mask last for extensibility
+};
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANONYMOUS
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_DONTNEED = C.MADV_DONTNEED
+
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+ SA_RESTORER = C.SA_RESTORER
+ SA_SIGINFO = C.SA_SIGINFO
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGBUS = C.SIGBUS
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGUSR1 = C.SIGUSR1
+ SIGSEGV = C.SIGSEGV
+ SIGUSR2 = C.SIGUSR2
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGSTKFLT = C.SIGSTKFLT
+ SIGCHLD = C.SIGCHLD
+ SIGCONT = C.SIGCONT
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGURG = C.SIGURG
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGIO = C.SIGIO
+ SIGPWR = C.SIGPWR
+ SIGSYS = C.SIGSYS
+
+ FPE_INTDIV = C.FPE_INTDIV & 0xFFFF
+ FPE_INTOVF = C.FPE_INTOVF & 0xFFFF
+ FPE_FLTDIV = C.FPE_FLTDIV & 0xFFFF
+ FPE_FLTOVF = C.FPE_FLTOVF & 0xFFFF
+ FPE_FLTUND = C.FPE_FLTUND & 0xFFFF
+ FPE_FLTRES = C.FPE_FLTRES & 0xFFFF
+ FPE_FLTINV = C.FPE_FLTINV & 0xFFFF
+ FPE_FLTSUB = C.FPE_FLTSUB & 0xFFFF
+
+ BUS_ADRALN = C.BUS_ADRALN & 0xFFFF
+ BUS_ADRERR = C.BUS_ADRERR & 0xFFFF
+ BUS_OBJERR = C.BUS_OBJERR & 0xFFFF
+
+ SEGV_MAPERR = C.SEGV_MAPERR & 0xFFFF
+ SEGV_ACCERR = C.SEGV_ACCERR & 0xFFFF
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_PROF = C.ITIMER_PROF
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+)
+
+type Timespec C.struct_timespec
+type Sigaltstack C.struct_sigaltstack
+type Sigcontext C.struct_sigcontext
+type Ucontext C.struct_ucontext
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+type Siginfo C.struct_xsiginfo
+type Sigaction C.struct_xsigaction
diff --git a/src/pkg/runtime/defs_darwin.go b/src/pkg/runtime/defs_darwin.go
new file mode 100644
index 000000000..7f22b0b8e
--- /dev/null
+++ b/src/pkg/runtime/defs_darwin.go
@@ -0,0 +1,163 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 cgo -cdefs defs_darwin.go >defs_darwin_amd64.h
+GOARCH=386 cgo -cdefs defs_darwin.go >defs_darwin_386.h
+*/
+
+package runtime
+
+/*
+#define __DARWIN_UNIX03 0
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/mman.h>
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_DONTNEED = C.MADV_DONTNEED
+ MADV_FREE = C.MADV_FREE
+
+ MACH_MSG_TYPE_MOVE_RECEIVE = C.MACH_MSG_TYPE_MOVE_RECEIVE
+ MACH_MSG_TYPE_MOVE_SEND = C.MACH_MSG_TYPE_MOVE_SEND
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = C.MACH_MSG_TYPE_MOVE_SEND_ONCE
+ MACH_MSG_TYPE_COPY_SEND = C.MACH_MSG_TYPE_COPY_SEND
+ MACH_MSG_TYPE_MAKE_SEND = C.MACH_MSG_TYPE_MAKE_SEND
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = C.MACH_MSG_TYPE_MAKE_SEND_ONCE
+ MACH_MSG_TYPE_COPY_RECEIVE = C.MACH_MSG_TYPE_COPY_RECEIVE
+
+ MACH_MSG_PORT_DESCRIPTOR = C.MACH_MSG_PORT_DESCRIPTOR
+ MACH_MSG_OOL_DESCRIPTOR = C.MACH_MSG_OOL_DESCRIPTOR
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = C.MACH_MSG_OOL_PORTS_DESCRIPTOR
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = C.MACH_MSG_OOL_VOLATILE_DESCRIPTOR
+
+ MACH_MSGH_BITS_COMPLEX = C.MACH_MSGH_BITS_COMPLEX
+
+ MACH_SEND_MSG = C.MACH_SEND_MSG
+ MACH_RCV_MSG = C.MACH_RCV_MSG
+ MACH_RCV_LARGE = C.MACH_RCV_LARGE
+
+ MACH_SEND_TIMEOUT = C.MACH_SEND_TIMEOUT
+ MACH_SEND_INTERRUPT = C.MACH_SEND_INTERRUPT
+ MACH_SEND_ALWAYS = C.MACH_SEND_ALWAYS
+ MACH_SEND_TRAILER = C.MACH_SEND_TRAILER
+ MACH_RCV_TIMEOUT = C.MACH_RCV_TIMEOUT
+ MACH_RCV_NOTIFY = C.MACH_RCV_NOTIFY
+ MACH_RCV_INTERRUPT = C.MACH_RCV_INTERRUPT
+ MACH_RCV_OVERWRITE = C.MACH_RCV_OVERWRITE
+
+ NDR_PROTOCOL_2_0 = C.NDR_PROTOCOL_2_0
+ NDR_INT_BIG_ENDIAN = C.NDR_INT_BIG_ENDIAN
+ NDR_INT_LITTLE_ENDIAN = C.NDR_INT_LITTLE_ENDIAN
+ NDR_FLOAT_IEEE = C.NDR_FLOAT_IEEE
+ NDR_CHAR_ASCII = C.NDR_CHAR_ASCII
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+ SA_USERTRAMP = C.SA_USERTRAMP
+ SA_64REGSET = C.SA_64REGSET
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGINFO = C.SIGINFO
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+)
+
+type MachBody C.mach_msg_body_t
+type MachHeader C.mach_msg_header_t
+type MachNDR C.NDR_record_t
+type MachPort C.mach_msg_port_descriptor_t
+
+type StackT C.struct_sigaltstack
+type Sighandler C.union___sigaction_u
+
+type Sigaction C.struct___sigaction // used in syscalls
+// type Sigaction C.struct_sigaction // used by the C library
+type Sigval C.union_sigval
+type Siginfo C.siginfo_t
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+type FPControl C.struct_fp_control
+type FPStatus C.struct_fp_status
+type RegMMST C.struct_mmst_reg
+type RegXMM C.struct_xmm_reg
+
+type Regs64 C.struct_x86_thread_state64
+type FloatState64 C.struct_x86_float_state64
+type ExceptionState64 C.struct_x86_exception_state64
+type Mcontext64 C.struct_mcontext64
+
+type Regs32 C.struct_i386_thread_state
+type FloatState32 C.struct_i386_float_state
+type ExceptionState32 C.struct_i386_exception_state
+type Mcontext32 C.struct_mcontext32
+
+type Ucontext C.struct_ucontext
diff --git a/src/pkg/runtime/defs_darwin_386.h b/src/pkg/runtime/defs_darwin_386.h
new file mode 100644
index 000000000..92732f460
--- /dev/null
+++ b/src/pkg/runtime/defs_darwin_386.h
@@ -0,0 +1,366 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_darwin.go
+
+
+enum {
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_DONTNEED = 0x4,
+ MADV_FREE = 0x5,
+
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+
+ MACH_MSG_PORT_DESCRIPTOR = 0x0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+
+ NDR_PROTOCOL_2_0 = 0x0,
+ NDR_INT_BIG_ENDIAN = 0x0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0x0,
+ NDR_CHAR_ASCII = 0x0,
+
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+
+ FPE_INTDIV = 0x7,
+ FPE_INTOVF = 0x8,
+ FPE_FLTDIV = 0x1,
+ FPE_FLTOVF = 0x2,
+ FPE_FLTUND = 0x3,
+ FPE_FLTRES = 0x4,
+ FPE_FLTINV = 0x5,
+ FPE_FLTSUB = 0x6,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+typedef struct MachBody MachBody;
+typedef struct MachHeader MachHeader;
+typedef struct MachNDR MachNDR;
+typedef struct MachPort MachPort;
+typedef struct StackT StackT;
+typedef struct Sigaction Sigaction;
+typedef struct Siginfo Siginfo;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct FPControl FPControl;
+typedef struct FPStatus FPStatus;
+typedef struct RegMMST RegMMST;
+typedef struct RegXMM RegXMM;
+typedef struct Regs64 Regs64;
+typedef struct FloatState64 FloatState64;
+typedef struct ExceptionState64 ExceptionState64;
+typedef struct Mcontext64 Mcontext64;
+typedef struct Regs32 Regs32;
+typedef struct FloatState32 FloatState32;
+typedef struct ExceptionState32 ExceptionState32;
+typedef struct Mcontext32 Mcontext32;
+typedef struct Ucontext Ucontext;
+
+#pragma pack on
+
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+struct StackT {
+ byte *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+typedef byte Sighandler[4];
+
+struct Sigaction {
+ Sighandler __sigaction_u;
+ void *sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef byte Sigval[4];
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ byte *si_addr;
+ Sigval si_value;
+ int32 si_band;
+ uint32 __pad[7];
+};
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+struct FPControl {
+ byte Pad_cgo_0[2];
+};
+struct FPStatus {
+ byte Pad_cgo_0[2];
+};
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+struct Regs64 {
+ uint64 rax;
+ uint64 rbx;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rsp;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint64 rflags;
+ uint64 cs;
+ uint64 fs;
+ uint64 gs;
+};
+struct FloatState64 {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ RegXMM fpu_xmm8;
+ RegXMM fpu_xmm9;
+ RegXMM fpu_xmm10;
+ RegXMM fpu_xmm11;
+ RegXMM fpu_xmm12;
+ RegXMM fpu_xmm13;
+ RegXMM fpu_xmm14;
+ RegXMM fpu_xmm15;
+ int8 fpu_rsrv4[96];
+ int32 fpu_reserved1;
+};
+struct ExceptionState64 {
+ uint16 trapno;
+ uint16 cpu;
+ uint32 err;
+ uint64 faultvaddr;
+};
+struct Mcontext64 {
+ ExceptionState64 es;
+ Regs64 ss;
+ FloatState64 fs;
+};
+
+struct Regs32 {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ss;
+ uint32 eflags;
+ uint32 eip;
+ uint32 cs;
+ uint32 ds;
+ uint32 es;
+ uint32 fs;
+ uint32 gs;
+};
+struct FloatState32 {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ int8 fpu_rsrv4[224];
+ int32 fpu_reserved1;
+};
+struct ExceptionState32 {
+ uint16 trapno;
+ uint16 cpu;
+ uint32 err;
+ uint32 faultvaddr;
+};
+struct Mcontext32 {
+ ExceptionState32 es;
+ Regs32 ss;
+ FloatState32 fs;
+};
+
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ Ucontext *uc_link;
+ uint32 uc_mcsize;
+ Mcontext32 *uc_mcontext;
+};
+
+
+#pragma pack off
diff --git a/src/pkg/runtime/defs_darwin_amd64.h b/src/pkg/runtime/defs_darwin_amd64.h
new file mode 100644
index 000000000..d4fbfef49
--- /dev/null
+++ b/src/pkg/runtime/defs_darwin_amd64.h
@@ -0,0 +1,369 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_darwin.go
+
+
+enum {
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_DONTNEED = 0x4,
+ MADV_FREE = 0x5,
+
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+
+ MACH_MSG_PORT_DESCRIPTOR = 0x0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+
+ NDR_PROTOCOL_2_0 = 0x0,
+ NDR_INT_BIG_ENDIAN = 0x0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0x0,
+ NDR_CHAR_ASCII = 0x0,
+
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+
+ FPE_INTDIV = 0x7,
+ FPE_INTOVF = 0x8,
+ FPE_FLTDIV = 0x1,
+ FPE_FLTOVF = 0x2,
+ FPE_FLTUND = 0x3,
+ FPE_FLTRES = 0x4,
+ FPE_FLTINV = 0x5,
+ FPE_FLTSUB = 0x6,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+typedef struct MachBody MachBody;
+typedef struct MachHeader MachHeader;
+typedef struct MachNDR MachNDR;
+typedef struct MachPort MachPort;
+typedef struct StackT StackT;
+typedef struct Sigaction Sigaction;
+typedef struct Siginfo Siginfo;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct FPControl FPControl;
+typedef struct FPStatus FPStatus;
+typedef struct RegMMST RegMMST;
+typedef struct RegXMM RegXMM;
+typedef struct Regs64 Regs64;
+typedef struct FloatState64 FloatState64;
+typedef struct ExceptionState64 ExceptionState64;
+typedef struct Mcontext64 Mcontext64;
+typedef struct Regs32 Regs32;
+typedef struct FloatState32 FloatState32;
+typedef struct ExceptionState32 ExceptionState32;
+typedef struct Mcontext32 Mcontext32;
+typedef struct Ucontext Ucontext;
+
+#pragma pack on
+
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+struct StackT {
+ byte *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+};
+typedef byte Sighandler[8];
+
+struct Sigaction {
+ Sighandler __sigaction_u;
+ void *sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef byte Sigval[8];
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ byte *si_addr;
+ Sigval si_value;
+ int64 si_band;
+ uint64 __pad[7];
+};
+struct Timeval {
+ int64 tv_sec;
+ int32 tv_usec;
+ byte Pad_cgo_0[4];
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+struct FPControl {
+ byte Pad_cgo_0[2];
+};
+struct FPStatus {
+ byte Pad_cgo_0[2];
+};
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+struct Regs64 {
+ uint64 rax;
+ uint64 rbx;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rsp;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint64 rflags;
+ uint64 cs;
+ uint64 fs;
+ uint64 gs;
+};
+struct FloatState64 {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ RegXMM fpu_xmm8;
+ RegXMM fpu_xmm9;
+ RegXMM fpu_xmm10;
+ RegXMM fpu_xmm11;
+ RegXMM fpu_xmm12;
+ RegXMM fpu_xmm13;
+ RegXMM fpu_xmm14;
+ RegXMM fpu_xmm15;
+ int8 fpu_rsrv4[96];
+ int32 fpu_reserved1;
+};
+struct ExceptionState64 {
+ uint16 trapno;
+ uint16 cpu;
+ uint32 err;
+ uint64 faultvaddr;
+};
+struct Mcontext64 {
+ ExceptionState64 es;
+ Regs64 ss;
+ FloatState64 fs;
+ byte Pad_cgo_0[4];
+};
+
+struct Regs32 {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ss;
+ uint32 eflags;
+ uint32 eip;
+ uint32 cs;
+ uint32 ds;
+ uint32 es;
+ uint32 fs;
+ uint32 gs;
+};
+struct FloatState32 {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ int8 fpu_rsrv4[224];
+ int32 fpu_reserved1;
+};
+struct ExceptionState32 {
+ uint16 trapno;
+ uint16 cpu;
+ uint32 err;
+ uint32 faultvaddr;
+};
+struct Mcontext32 {
+ ExceptionState32 es;
+ Regs32 ss;
+ FloatState32 fs;
+};
+
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ Ucontext *uc_link;
+ uint64 uc_mcsize;
+ Mcontext64 *uc_mcontext;
+};
+
+
+#pragma pack off
diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go
new file mode 100644
index 000000000..306e32197
--- /dev/null
+++ b/src/pkg/runtime/defs_freebsd.go
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
+GOARCH=386 cgo -cdefs defs.go >386/defs.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/ucontext.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+#include <sys/thr.h>
+#include <sys/_sigset.h>
+#include <sys/unistd.h>
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+
+ UMTX_OP_WAIT = C.UMTX_OP_WAIT
+ UMTX_OP_WAKE = C.UMTX_OP_WAKE
+
+ EINTR = C.EINTR
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGINFO = C.SIGINFO
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+)
+
+type Rtprio C.struct_rtprio
+type ThrParam C.struct_thr_param
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.struct___sigset
+type Sigval C.union_sigval
+type StackT C.stack_t
+
+type Siginfo C.siginfo_t
+
+type Mcontext C.mcontext_t
+type Ucontext C.ucontext_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
diff --git a/src/pkg/runtime/freebsd/386/defs.h b/src/pkg/runtime/defs_freebsd_386.h
index ae12b2019..29fcb8b57 100644
--- a/src/pkg/runtime/freebsd/386/defs.h
+++ b/src/pkg/runtime/defs_freebsd_386.h
@@ -173,6 +173,12 @@ struct Ucontext {
byte pad_godefs_0[12];
};
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
typedef struct Timeval Timeval;
struct Timeval {
int32 tv_sec;
diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/defs_freebsd_amd64.h
index b101b1932..8a222dca4 100644
--- a/src/pkg/runtime/freebsd/amd64/defs.h
+++ b/src/pkg/runtime/defs_freebsd_amd64.h
@@ -184,6 +184,12 @@ struct Ucontext {
byte pad_godefs_0[12];
};
+typedef struct Timespec Timespec;
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+
typedef struct Timeval Timeval;
struct Timeval {
int64 tv_sec;
diff --git a/src/pkg/runtime/defs_linux.go b/src/pkg/runtime/defs_linux.go
new file mode 100644
index 000000000..c0275e111
--- /dev/null
+++ b/src/pkg/runtime/defs_linux.go
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -cdefs
+
+GOARCH=amd64 cgo -cdefs defs.go defs1.go >amd64/defs.h
+*/
+
+package runtime
+
+/*
+// Linux glibc and Linux kernel define different and conflicting
+// definitions for struct sigaction, struct timespec, etc.
+// We want the kernel ones, which are in the asm/* headers.
+// But then we'd get conflicts when we include the system
+// headers for things like ucontext_t, so that happens in
+// a separate file, defs1.go.
+
+#include <asm/posix_types.h>
+#define size_t __kernel_size_t
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+#include <asm/mman.h>
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANONYMOUS
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ MADV_DONTNEED = C.MADV_DONTNEED
+
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+ SA_RESTORER = C.SA_RESTORER
+ SA_SIGINFO = C.SA_SIGINFO
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGBUS = C.SIGBUS
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGUSR1 = C.SIGUSR1
+ SIGSEGV = C.SIGSEGV
+ SIGUSR2 = C.SIGUSR2
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGSTKFLT = C.SIGSTKFLT
+ SIGCHLD = C.SIGCHLD
+ SIGCONT = C.SIGCONT
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGURG = C.SIGURG
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGIO = C.SIGIO
+ SIGPWR = C.SIGPWR
+ SIGSYS = C.SIGSYS
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+)
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Sigaction C.struct_sigaction
+type Siginfo C.siginfo_t
+type Itimerval C.struct_itimerval
diff --git a/src/pkg/runtime/defs_linux_386.h b/src/pkg/runtime/defs_linux_386.h
new file mode 100644
index 000000000..02760f987
--- /dev/null
+++ b/src/pkg/runtime/defs_linux_386.h
@@ -0,0 +1,191 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs2.go
+
+
+enum {
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_DONTNEED = 0x4,
+
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGBUS = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGUSR1 = 0xa,
+ SIGSEGV = 0xb,
+ SIGUSR2 = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGSTKFLT = 0x10,
+ SIGCHLD = 0x11,
+ SIGCONT = 0x12,
+ SIGSTOP = 0x13,
+ SIGTSTP = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGURG = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGIO = 0x1d,
+ SIGPWR = 0x1e,
+ SIGSYS = 0x1f,
+
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+
+ O_RDONLY = 0x0,
+ O_CLOEXEC = 0x80000,
+};
+
+typedef struct Fpreg Fpreg;
+typedef struct Fpxreg Fpxreg;
+typedef struct Xmmreg Xmmreg;
+typedef struct Fpstate Fpstate;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Sigaction Sigaction;
+typedef struct Siginfo Siginfo;
+typedef struct Sigaltstack Sigaltstack;
+typedef struct Sigcontext Sigcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Itimerval Itimerval;
+
+#pragma pack on
+
+struct Fpreg {
+ uint16 significand[4];
+ uint16 exponent;
+};
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+struct Xmmreg {
+ uint32 element[4];
+};
+struct Fpstate {
+ uint32 cw;
+ uint32 sw;
+ uint32 tag;
+ uint32 ipoff;
+ uint32 cssel;
+ uint32 dataoff;
+ uint32 datasel;
+ Fpreg _st[8];
+ uint16 status;
+ uint16 magic;
+ uint32 _fxsr_env[6];
+ uint32 mxcsr;
+ uint32 reserved;
+ Fpxreg _fxsr_st[8];
+ Xmmreg _xmm[8];
+ uint32 padding1[44];
+ byte anon0[48];
+};
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+struct Sigaction {
+ void *k_sa_handler;
+ uint32 sa_flags;
+ void *sa_restorer;
+ uint32 sa_mask;
+};
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte _sifields[116];
+};
+struct Sigaltstack {
+ byte *ss_sp;
+ int32 ss_flags;
+ uint32 ss_size;
+};
+struct Sigcontext {
+ uint16 gs;
+ uint16 __gsh;
+ uint16 fs;
+ uint16 __fsh;
+ uint16 es;
+ uint16 __esh;
+ uint16 ds;
+ uint16 __dsh;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ebx;
+ uint32 edx;
+ uint32 ecx;
+ uint32 eax;
+ uint32 trapno;
+ uint32 err;
+ uint32 eip;
+ uint16 cs;
+ uint16 __csh;
+ uint32 eflags;
+ uint32 esp_at_signal;
+ uint16 ss;
+ uint16 __ssh;
+ Fpstate *fpstate;
+ uint32 oldmask;
+ uint32 cr2;
+};
+struct Ucontext {
+ uint32 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Sigcontext uc_mcontext;
+ uint32 uc_sigmask;
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+
+#pragma pack off
diff --git a/src/pkg/runtime/defs_linux_amd64.h b/src/pkg/runtime/defs_linux_amd64.h
new file mode 100644
index 000000000..bf5f79b0e
--- /dev/null
+++ b/src/pkg/runtime/defs_linux_amd64.h
@@ -0,0 +1,234 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs.go defs1.go
+
+
+enum {
+ PROT_NONE = 0x0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+
+ MADV_DONTNEED = 0x4,
+
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGBUS = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGUSR1 = 0xa,
+ SIGSEGV = 0xb,
+ SIGUSR2 = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGSTKFLT = 0x10,
+ SIGCHLD = 0x11,
+ SIGCONT = 0x12,
+ SIGSTOP = 0x13,
+ SIGTSTP = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGURG = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGIO = 0x1d,
+ SIGPWR = 0x1e,
+ SIGSYS = 0x1f,
+
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+
+ ITIMER_REAL = 0x0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Sigaction Sigaction;
+typedef struct Siginfo Siginfo;
+typedef struct Itimerval Itimerval;
+
+#pragma pack on
+
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+struct Sigaction {
+ void *sa_handler;
+ uint64 sa_flags;
+ void *sa_restorer;
+ uint64 sa_mask;
+};
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte Pad_cgo_0[4];
+ byte _sifields[112];
+};
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs.go defs1.go
+
+
+enum {
+ O_RDONLY = 0x0,
+ O_CLOEXEC = 0x80000,
+};
+
+typedef struct Usigset Usigset;
+typedef struct Fpxreg Fpxreg;
+typedef struct Xmmreg Xmmreg;
+typedef struct Fpstate Fpstate;
+typedef struct Fpxreg1 Fpxreg1;
+typedef struct Xmmreg1 Xmmreg1;
+typedef struct Fpstate1 Fpstate1;
+typedef struct Fpreg1 Fpreg1;
+typedef struct Sigaltstack Sigaltstack;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Sigcontext Sigcontext;
+
+#pragma pack on
+
+struct Usigset {
+ uint64 __val[16];
+};
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+struct Xmmreg {
+ uint32 element[4];
+};
+struct Fpstate {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg _st[8];
+ Xmmreg _xmm[16];
+ uint32 padding[24];
+};
+struct Fpxreg1 {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+struct Xmmreg1 {
+ uint32 element[4];
+};
+struct Fpstate1 {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg1 _st[8];
+ Xmmreg1 _xmm[16];
+ uint32 padding[24];
+};
+struct Fpreg1 {
+ uint16 significand[4];
+ uint16 exponent;
+};
+struct Sigaltstack {
+ byte *ss_sp;
+ int32 ss_flags;
+ byte Pad_cgo_0[4];
+ uint64 ss_size;
+};
+struct Mcontext {
+ int64 gregs[23];
+ Fpstate *fpregs;
+ uint64 __reserved1[8];
+};
+struct Ucontext {
+ uint64 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Mcontext uc_mcontext;
+ Usigset uc_sigmask;
+ Fpstate __fpregs_mem;
+};
+struct Sigcontext {
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rbx;
+ uint64 rdx;
+ uint64 rax;
+ uint64 rcx;
+ uint64 rsp;
+ uint64 rip;
+ uint64 eflags;
+ uint16 cs;
+ uint16 gs;
+ uint16 fs;
+ uint16 __pad0;
+ uint64 err;
+ uint64 trapno;
+ uint64 oldmask;
+ uint64 cr2;
+ Fpstate1 *fpstate;
+ uint64 __reserved1[8];
+};
+
+
+#pragma pack off
diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/defs_linux_arm.h
index 09b558ed0..9e5c83a07 100644
--- a/src/pkg/runtime/linux/arm/defs.h
+++ b/src/pkg/runtime/defs_linux_arm.h
@@ -11,6 +11,7 @@ enum {
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
MAP_FIXED = 0x10,
+ MADV_DONTNEED = 0x4,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
@@ -68,8 +69,6 @@ enum {
// Types
#pragma pack on
-typedef uint32 Sigset;
-
typedef struct Timespec Timespec;
struct Timespec {
int32 tv_sec;
diff --git a/src/pkg/runtime/defs_netbsd.go b/src/pkg/runtime/defs_netbsd.go
new file mode 100644
index 000000000..47c30cf10
--- /dev/null
+++ b/src/pkg/runtime/defs_netbsd.go
@@ -0,0 +1,111 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
+GOARCH=386 cgo -cdefs defs.go >386/defs.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+#include <sys/signal.h>
+#include <errno.h>
+#include <signal.h>
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+
+ EINTR = C.EINTR
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGINFO = C.SIGINFO
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+)
+
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.sigset_t
+type Siginfo C.siginfo_t
+type Sigval C.union_sigval
+
+type StackT C.stack_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+// This is a hack to avoid pulling in machine/fpu.h.
+type sfxsave64 struct{}
+type usavefpu struct{}
+
+type Sigcontext C.struct_sigcontext
diff --git a/src/pkg/runtime/defs_netbsd_386.h b/src/pkg/runtime/defs_netbsd_386.h
new file mode 100644
index 000000000..aff87fb3b
--- /dev/null
+++ b/src/pkg/runtime/defs_netbsd_386.h
@@ -0,0 +1,146 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef uint32 Sigset;
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ byte _data[116];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef void sfxsave64;
+
+typedef void usavefpu;
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ int32 sc_gs;
+ int32 sc_fs;
+ int32 sc_es;
+ int32 sc_ds;
+ int32 sc_edi;
+ int32 sc_esi;
+ int32 sc_ebp;
+ int32 sc_ebx;
+ int32 sc_edx;
+ int32 sc_ecx;
+ int32 sc_eax;
+ int32 sc_eip;
+ int32 sc_cs;
+ int32 sc_eflags;
+ int32 sc_esp;
+ int32 sc_ss;
+ int32 sc_onstack;
+ int32 sc_mask;
+ int32 sc_trapno;
+ int32 sc_err;
+ usavefpu *sc_fpstate;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/openbsd/amd64/defs.h b/src/pkg/runtime/defs_netbsd_amd64.h
index 4eb5cd205..27bf4b9d6 100644
--- a/src/pkg/runtime/openbsd/amd64/defs.h
+++ b/src/pkg/runtime/defs_netbsd_amd64.h
@@ -100,6 +100,13 @@ struct StackT {
byte pad_godefs_0[4];
};
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ byte pad_godefs_0[4];
+ int64 tv_nsec;
+};
+
typedef struct Timeval Timeval;
struct Timeval {
int64 tv_sec;
@@ -114,6 +121,8 @@ struct Itimerval {
typedef void sfxsave64;
+typedef void usavefpu;
+
typedef struct Sigcontext Sigcontext;
struct Sigcontext {
int64 sc_rdi;
diff --git a/src/pkg/runtime/defs_openbsd.go b/src/pkg/runtime/defs_openbsd.go
new file mode 100644
index 000000000..47c30cf10
--- /dev/null
+++ b/src/pkg/runtime/defs_openbsd.go
@@ -0,0 +1,111 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
+GOARCH=386 cgo -cdefs defs.go >386/defs.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+#include <sys/signal.h>
+#include <errno.h>
+#include <signal.h>
+*/
+import "C"
+
+const (
+ PROT_NONE = C.PROT_NONE
+ PROT_READ = C.PROT_READ
+ PROT_WRITE = C.PROT_WRITE
+ PROT_EXEC = C.PROT_EXEC
+
+ MAP_ANON = C.MAP_ANON
+ MAP_PRIVATE = C.MAP_PRIVATE
+ MAP_FIXED = C.MAP_FIXED
+
+ SA_SIGINFO = C.SA_SIGINFO
+ SA_RESTART = C.SA_RESTART
+ SA_ONSTACK = C.SA_ONSTACK
+
+ EINTR = C.EINTR
+
+ SIGHUP = C.SIGHUP
+ SIGINT = C.SIGINT
+ SIGQUIT = C.SIGQUIT
+ SIGILL = C.SIGILL
+ SIGTRAP = C.SIGTRAP
+ SIGABRT = C.SIGABRT
+ SIGEMT = C.SIGEMT
+ SIGFPE = C.SIGFPE
+ SIGKILL = C.SIGKILL
+ SIGBUS = C.SIGBUS
+ SIGSEGV = C.SIGSEGV
+ SIGSYS = C.SIGSYS
+ SIGPIPE = C.SIGPIPE
+ SIGALRM = C.SIGALRM
+ SIGTERM = C.SIGTERM
+ SIGURG = C.SIGURG
+ SIGSTOP = C.SIGSTOP
+ SIGTSTP = C.SIGTSTP
+ SIGCONT = C.SIGCONT
+ SIGCHLD = C.SIGCHLD
+ SIGTTIN = C.SIGTTIN
+ SIGTTOU = C.SIGTTOU
+ SIGIO = C.SIGIO
+ SIGXCPU = C.SIGXCPU
+ SIGXFSZ = C.SIGXFSZ
+ SIGVTALRM = C.SIGVTALRM
+ SIGPROF = C.SIGPROF
+ SIGWINCH = C.SIGWINCH
+ SIGINFO = C.SIGINFO
+ SIGUSR1 = C.SIGUSR1
+ SIGUSR2 = C.SIGUSR2
+
+ FPE_INTDIV = C.FPE_INTDIV
+ FPE_INTOVF = C.FPE_INTOVF
+ FPE_FLTDIV = C.FPE_FLTDIV
+ FPE_FLTOVF = C.FPE_FLTOVF
+ FPE_FLTUND = C.FPE_FLTUND
+ FPE_FLTRES = C.FPE_FLTRES
+ FPE_FLTINV = C.FPE_FLTINV
+ FPE_FLTSUB = C.FPE_FLTSUB
+
+ BUS_ADRALN = C.BUS_ADRALN
+ BUS_ADRERR = C.BUS_ADRERR
+ BUS_OBJERR = C.BUS_OBJERR
+
+ SEGV_MAPERR = C.SEGV_MAPERR
+ SEGV_ACCERR = C.SEGV_ACCERR
+
+ ITIMER_REAL = C.ITIMER_REAL
+ ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+ ITIMER_PROF = C.ITIMER_PROF
+)
+
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.sigset_t
+type Siginfo C.siginfo_t
+type Sigval C.union_sigval
+
+type StackT C.stack_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+// This is a hack to avoid pulling in machine/fpu.h.
+type sfxsave64 struct{}
+type usavefpu struct{}
+
+type Sigcontext C.struct_sigcontext
diff --git a/src/pkg/runtime/defs_openbsd_386.h b/src/pkg/runtime/defs_openbsd_386.h
new file mode 100644
index 000000000..aff87fb3b
--- /dev/null
+++ b/src/pkg/runtime/defs_openbsd_386.h
@@ -0,0 +1,146 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef uint32 Sigset;
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ byte _data[116];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef void sfxsave64;
+
+typedef void usavefpu;
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ int32 sc_gs;
+ int32 sc_fs;
+ int32 sc_es;
+ int32 sc_ds;
+ int32 sc_edi;
+ int32 sc_esi;
+ int32 sc_ebp;
+ int32 sc_ebx;
+ int32 sc_edx;
+ int32 sc_ecx;
+ int32 sc_eax;
+ int32 sc_eip;
+ int32 sc_cs;
+ int32 sc_eflags;
+ int32 sc_esp;
+ int32 sc_ss;
+ int32 sc_onstack;
+ int32 sc_mask;
+ int32 sc_trapno;
+ int32 sc_err;
+ usavefpu *sc_fpstate;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/defs_openbsd_amd64.h b/src/pkg/runtime/defs_openbsd_amd64.h
new file mode 100644
index 000000000..27bf4b9d6
--- /dev/null
+++ b/src/pkg/runtime/defs_openbsd_amd64.h
@@ -0,0 +1,158 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ EINTR = 0x4,
+ SIGHUP = 0x1,
+ SIGINT = 0x2,
+ SIGQUIT = 0x3,
+ SIGILL = 0x4,
+ SIGTRAP = 0x5,
+ SIGABRT = 0x6,
+ SIGEMT = 0x7,
+ SIGFPE = 0x8,
+ SIGKILL = 0x9,
+ SIGBUS = 0xa,
+ SIGSEGV = 0xb,
+ SIGSYS = 0xc,
+ SIGPIPE = 0xd,
+ SIGALRM = 0xe,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x1,
+ FPE_INTOVF = 0x2,
+ FPE_FLTDIV = 0x3,
+ FPE_FLTOVF = 0x4,
+ FPE_FLTUND = 0x5,
+ FPE_FLTRES = 0x6,
+ FPE_FLTINV = 0x7,
+ FPE_FLTSUB = 0x8,
+ BUS_ADRALN = 0x1,
+ BUS_ADRERR = 0x2,
+ BUS_OBJERR = 0x3,
+ SEGV_MAPERR = 0x1,
+ SEGV_ACCERR = 0x2,
+ ITIMER_REAL = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef uint32 Sigset;
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_code;
+ int32 si_errno;
+ byte pad_godefs_0[4];
+ byte _data[120];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ byte pad_godefs_0[4];
+ int64 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+
+typedef void sfxsave64;
+
+typedef void usavefpu;
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ int64 sc_rdi;
+ int64 sc_rsi;
+ int64 sc_rdx;
+ int64 sc_rcx;
+ int64 sc_r8;
+ int64 sc_r9;
+ int64 sc_r10;
+ int64 sc_r11;
+ int64 sc_r12;
+ int64 sc_r13;
+ int64 sc_r14;
+ int64 sc_r15;
+ int64 sc_rbp;
+ int64 sc_rbx;
+ int64 sc_rax;
+ int64 sc_gs;
+ int64 sc_fs;
+ int64 sc_es;
+ int64 sc_ds;
+ int64 sc_trapno;
+ int64 sc_err;
+ int64 sc_rip;
+ int64 sc_cs;
+ int64 sc_rflags;
+ int64 sc_rsp;
+ int64 sc_ss;
+ sfxsave64 *sc_fpstate;
+ int32 sc_onstack;
+ int32 sc_mask;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/defs_plan9_386.h
index 58fd9d94d..58fd9d94d 100644
--- a/src/pkg/runtime/plan9/386/defs.h
+++ b/src/pkg/runtime/defs_plan9_386.h
diff --git a/src/pkg/runtime/defs_windows.go b/src/pkg/runtime/defs_windows.go
new file mode 100644
index 000000000..0d525b932
--- /dev/null
+++ b/src/pkg/runtime/defs_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
+GOARCH=386 cgo -cdefs defs.go >386/defs.h
+*/
+
+package runtime
+
+/*
+#include <signal.h>
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <wincon.h>
+
+#ifndef _X86_
+typedef struct {} FLOATING_SAVE_AREA;
+#endif
+#ifndef _AMD64_
+typedef struct {} M128A;
+#endif
+*/
+import "C"
+
+const (
+ PROT_NONE = 0
+ PROT_READ = 1
+ PROT_WRITE = 2
+ PROT_EXEC = 4
+
+ MAP_ANON = 1
+ MAP_PRIVATE = 2
+
+ DUPLICATE_SAME_ACCESS = C.DUPLICATE_SAME_ACCESS
+ THREAD_PRIORITY_HIGHEST = C.THREAD_PRIORITY_HIGHEST
+
+ SIGINT = C.SIGINT
+ CTRL_C_EVENT = C.CTRL_C_EVENT
+ CTRL_BREAK_EVENT = C.CTRL_BREAK_EVENT
+
+ CONTEXT_CONTROL = C.CONTEXT_CONTROL
+ CONTEXT_FULL = C.CONTEXT_FULL
+
+ EXCEPTION_ACCESS_VIOLATION = C.STATUS_ACCESS_VIOLATION
+ EXCEPTION_BREAKPOINT = C.STATUS_BREAKPOINT
+ EXCEPTION_FLT_DENORMAL_OPERAND = C.STATUS_FLOAT_DENORMAL_OPERAND
+ EXCEPTION_FLT_DIVIDE_BY_ZERO = C.STATUS_FLOAT_DIVIDE_BY_ZERO
+ EXCEPTION_FLT_INEXACT_RESULT = C.STATUS_FLOAT_INEXACT_RESULT
+ EXCEPTION_FLT_OVERFLOW = C.STATUS_FLOAT_OVERFLOW
+ EXCEPTION_FLT_UNDERFLOW = C.STATUS_FLOAT_UNDERFLOW
+ EXCEPTION_INT_DIVIDE_BY_ZERO = C.STATUS_INTEGER_DIVIDE_BY_ZERO
+ EXCEPTION_INT_OVERFLOW = C.STATUS_INTEGER_OVERFLOW
+)
+
+type SystemInfo C.SYSTEM_INFO
+type ExceptionRecord C.EXCEPTION_RECORD
+type FloatingSaveArea C.FLOATING_SAVE_AREA
+type M128a C.M128A
+type Context C.CONTEXT
diff --git a/src/pkg/runtime/windows/386/defs.h b/src/pkg/runtime/defs_windows_386.h
index 49fc19504..e64a82faf 100644
--- a/src/pkg/runtime/windows/386/defs.h
+++ b/src/pkg/runtime/defs_windows_386.h
@@ -10,9 +10,13 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1,
MAP_PRIVATE = 0x2,
+ DUPLICATE_SAME_ACCESS = 0x2,
+ THREAD_PRIORITY_HIGHEST = 0x2,
SIGINT = 0x2,
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 0x1,
+ CONTEXT_CONTROL = 0x10001,
+ CONTEXT_FULL = 0x10007,
EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
EXCEPTION_BREAKPOINT = 0x80000003,
EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
@@ -27,6 +31,20 @@ enum {
// Types
#pragma pack on
+typedef struct SystemInfo SystemInfo;
+struct SystemInfo {
+ byte Pad_godefs_0[4];
+ uint32 dwPageSize;
+ void *lpMinimumApplicationAddress;
+ void *lpMaximumApplicationAddress;
+ uint32 dwActiveProcessorMask;
+ uint32 dwNumberOfProcessors;
+ uint32 dwProcessorType;
+ uint32 dwAllocationGranularity;
+ uint16 wProcessorLevel;
+ uint16 wProcessorRevision;
+};
+
typedef struct ExceptionRecord ExceptionRecord;
struct ExceptionRecord {
uint32 ExceptionCode;
diff --git a/src/pkg/runtime/defs_windows_amd64.h b/src/pkg/runtime/defs_windows_amd64.h
new file mode 100644
index 000000000..da4c19d90
--- /dev/null
+++ b/src/pkg/runtime/defs_windows_amd64.h
@@ -0,0 +1,114 @@
+// c:\go\bin\godefs.exe -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1,
+ MAP_PRIVATE = 0x2,
+ DUPLICATE_SAME_ACCESS = 0x2,
+ THREAD_PRIORITY_HIGHEST = 0x2,
+ SIGINT = 0x2,
+ CTRL_C_EVENT = 0,
+ CTRL_BREAK_EVENT = 0x1,
+ CONTEXT_CONTROL = 0x100001,
+ CONTEXT_FULL = 0x10000b,
+ EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
+ EXCEPTION_BREAKPOINT = 0x80000003,
+ EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
+ EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
+ EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
+ EXCEPTION_FLT_OVERFLOW = 0xc0000091,
+ EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
+ EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
+ EXCEPTION_INT_OVERFLOW = 0xc0000095,
+};
+
+// Types
+#pragma pack on
+
+typedef struct SystemInfo SystemInfo;
+struct SystemInfo {
+ byte Pad_godefs_0[4];
+ uint32 dwPageSize;
+ void *lpMinimumApplicationAddress;
+ void *lpMaximumApplicationAddress;
+ uint64 dwActiveProcessorMask;
+ uint32 dwNumberOfProcessors;
+ uint32 dwProcessorType;
+ uint32 dwAllocationGranularity;
+ uint16 wProcessorLevel;
+ uint16 wProcessorRevision;
+};
+
+typedef struct ExceptionRecord ExceptionRecord;
+struct ExceptionRecord {
+ uint32 ExceptionCode;
+ uint32 ExceptionFlags;
+ ExceptionRecord *ExceptionRecord;
+ void *ExceptionAddress;
+ uint32 NumberParameters;
+ byte pad_godefs_0[4];
+ uint64 ExceptionInformation[15];
+};
+
+typedef struct M128a M128a;
+struct M128a {
+ uint64 Low;
+ int64 High;
+};
+
+typedef struct Context Context;
+struct Context {
+ uint64 P1Home;
+ uint64 P2Home;
+ uint64 P3Home;
+ uint64 P4Home;
+ uint64 P5Home;
+ uint64 P6Home;
+ uint32 ContextFlags;
+ uint32 MxCsr;
+ uint16 SegCs;
+ uint16 SegDs;
+ uint16 SegEs;
+ uint16 SegFs;
+ uint16 SegGs;
+ uint16 SegSs;
+ uint32 EFlags;
+ uint64 Dr0;
+ uint64 Dr1;
+ uint64 Dr2;
+ uint64 Dr3;
+ uint64 Dr6;
+ uint64 Dr7;
+ uint64 Rax;
+ uint64 Rcx;
+ uint64 Rdx;
+ uint64 Rbx;
+ uint64 Rsp;
+ uint64 Rbp;
+ uint64 Rsi;
+ uint64 Rdi;
+ uint64 R8;
+ uint64 R9;
+ uint64 R10;
+ uint64 R11;
+ uint64 R12;
+ uint64 R13;
+ uint64 R14;
+ uint64 R15;
+ uint64 Rip;
+ byte Pad_godefs_0[512];
+ M128a VectorRegister[26];
+ uint64 VectorControl;
+ uint64 DebugControl;
+ uint64 LastBranchToRip;
+ uint64 LastBranchFromRip;
+ uint64 LastExceptionToRip;
+ uint64 LastExceptionFromRip;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index 6c37f888f..b6b520cf2 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -6,20 +6,17 @@ package runtime
// The Error interface identifies a run time error.
type Error interface {
- String() string
+ error
// RuntimeError is a no-op function but
// serves to distinguish types that are runtime
- // errors from ordinary os.Errors: a type is a
+ // errors from ordinary errors: a type is a
// runtime error if it has a RuntimeError method.
RuntimeError()
}
// A TypeAssertionError explains a failed type assertion.
type TypeAssertionError struct {
- interfaceType Type // interface had this type
- concreteType Type // concrete value had this type
- assertedType Type // asserted type
interfaceString string
concreteString string
assertedString string
@@ -28,12 +25,12 @@ type TypeAssertionError struct {
func (*TypeAssertionError) RuntimeError() {}
-func (e *TypeAssertionError) String() string {
+func (e *TypeAssertionError) Error() string {
inter := e.interfaceString
if inter == "" {
inter = "interface"
}
- if e.concreteType == nil {
+ if e.concreteString == "" {
return "interface conversion: " + inter + " is nil, not " + e.assertedString
}
if e.missingMethod == "" {
@@ -44,40 +41,10 @@ func (e *TypeAssertionError) String() string {
": missing method " + e.missingMethod
}
-// Concrete returns the type of the concrete value in the failed type assertion.
-// If the interface value was nil, Concrete returns nil.
-func (e *TypeAssertionError) Concrete() Type {
- return e.concreteType
-}
-
-// Asserted returns the type incorrectly asserted by the type assertion.
-func (e *TypeAssertionError) Asserted() Type {
- return e.assertedType
-}
-
-// If the type assertion is to an interface type, MissingMethod returns the
-// name of a method needed to satisfy that interface type but not implemented
-// by Concrete. If there are multiple such methods,
-// MissingMethod returns one; which one is unspecified.
-// If the type assertion is not to an interface type, MissingMethod returns an empty string.
-func (e *TypeAssertionError) MissingMethod() string {
- return e.missingMethod
-}
-
// For calling from C.
-func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
- var t1, t2, t3 Type
+func newTypeAssertionError(ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
var s1, s2, s3, meth string
- if pt1 != nil {
- t1 = *pt1
- }
- if pt2 != nil {
- t2 = *pt2
- }
- if pt3 != nil {
- t3 = *pt3
- }
if ps1 != nil {
s1 = *ps1
}
@@ -90,7 +57,7 @@ func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *st
if pmeth != nil {
meth = *pmeth
}
- *ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
+ *ret = &TypeAssertionError{s1, s2, s3, meth}
}
// An errorString represents a runtime error described by a single string.
@@ -98,7 +65,7 @@ type errorString string
func (e errorString) RuntimeError() {}
-func (e errorString) String() string {
+func (e errorString) Error() string {
return "runtime error: " + string(e)
}
@@ -123,6 +90,8 @@ func printany(i interface{}) {
print("nil")
case stringer:
print(v.String())
+ case error:
+ print(v.Error())
case int:
print(v)
case string:
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index 53c5fcba4..51921135b 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -18,6 +18,10 @@ var F64toint = f64toint
func entersyscall()
func exitsyscall()
+func golockedOSThread() bool
+func stackguard() (sp, limit uintptr)
var Entersyscall = entersyscall
var Exitsyscall = exitsyscall
+var LockedOSThread = golockedOSThread
+var Stackguard = stackguard
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index 9da3423c6..5fbfe547e 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -19,15 +19,15 @@ func Gosched()
func Goexit()
// Caller reports file and line number information about function invocations on
-// the calling goroutine's stack. The argument skip is the number of stack frames to
-// ascend, with 0 identifying the the caller of Caller. The return values report the
+// the calling goroutine's stack. The argument skip is the number of stack frames
+// to ascend, with 0 identifying the caller of Caller. The return values report the
// program counter, file name, and line number within the file of the corresponding
// call. The boolean ok is false if it was not possible to recover the information.
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
// Callers fills the slice pc with the program counters of function invocations
// on the calling goroutine's stack. The argument skip is the number of stack frames
-// to skip before recording in pc, with 0 starting at the caller of Caller.
+// to skip before recording in pc, with 0 starting at the caller of Callers.
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int
@@ -59,65 +59,15 @@ func (f *Func) Entry() uintptr { return f.entry }
// The result will not be accurate if pc is not a program
// counter within f.
func (f *Func) FileLine(pc uintptr) (file string, line int) {
- // NOTE(rsc): If you edit this function, also edit
- // symtab.c:/^funcline. That function also has the
- // comments explaining the logic.
- targetpc := pc
-
- var pcQuant uintptr = 1
- if GOARCH == "arm" {
- pcQuant = 4
- }
-
- p := f.pcln
- pc = f.pc0
- line = int(f.ln0)
- i := 0
- //print("FileLine start pc=", pc, " targetpc=", targetpc, " line=", line,
- // " tab=", p, " ", p[0], " quant=", pcQuant, " GOARCH=", GOARCH, "\n")
- for {
- for i < len(p) && p[i] > 128 {
- pc += pcQuant * uintptr(p[i]-128)
- i++
- }
- //print("pc<", pc, " targetpc=", targetpc, " line=", line, "\n")
- if pc > targetpc || i >= len(p) {
- break
- }
- if p[i] == 0 {
- if i+5 > len(p) {
- break
- }
- line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
- i += 5
- } else if p[i] <= 64 {
- line += int(p[i])
- i++
- } else {
- line -= int(p[i] - 64)
- i++
- }
- //print("pc=", pc, " targetpc=", targetpc, " line=", line, "\n")
- pc += pcQuant
- }
- file = f.src
- return
+ return funcline_go(f, pc)
}
+// implemented in symtab.c
+func funcline_go(*Func, uintptr) (string, int)
+
// mid returns the current os thread (m) id.
func mid() uint32
-// Semacquire waits until *s > 0 and then atomically decrements it.
-// It is intended as a simple sleep primitive for use by the synchronization
-// library and should not be used directly.
-func Semacquire(s *uint32)
-
-// Semrelease atomically increments *s and notifies a waiting goroutine
-// if one is blocked in Semacquire.
-// It is intended as a simple wakeup primitive for use by the synchronization
-// library and should not be used directly.
-func Semrelease(s *uint32)
-
// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
// with an associated finalizer, it clears the association and runs
@@ -131,8 +81,8 @@ func Semrelease(s *uint32)
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
// The argument f must be a function that takes a single argument
-// of x's type and returns no arguments. If either of these is not
-// true, SetFinalizer aborts the program.
+// of x's type and can have arbitrary ignored return values.
+// If either of these is not true, SetFinalizer aborts the program.
//
// Finalizers are run in dependency order: if A points at B, both have
// finalizers, and they are otherwise unreachable, only the finalizer
@@ -156,9 +106,6 @@ func Semrelease(s *uint32)
// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
-//
-// TODO(rsc): allow f to have (ignored) return values
-//
func SetFinalizer(x, f interface{})
func getgoroot() string
@@ -183,10 +130,10 @@ func Version() string {
return theVersion
}
-// GOOS is the Go tree's operating system target:
+// GOOS is the running program's operating system target:
// one of darwin, freebsd, linux, and so on.
const GOOS string = theGoos
-// GOARCH is the Go tree's architecture target:
+// GOARCH is the running program's architecture target:
// 386, amd64, or arm.
const GOARCH string = theGoarch
diff --git a/src/pkg/runtime/freebsd/defs.c b/src/pkg/runtime/freebsd/defs.c
deleted file mode 100644
index 2ce4fdc51..000000000
--- a/src/pkg/runtime/freebsd/defs.c
+++ /dev/null
@@ -1,108 +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.
-
-/*
- * Input to godefs.
- *
- godefs -f -m64 defs.c >amd64/defs.h
- godefs -f -m32 defs.c >386/defs.h
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/ucontext.h>
-#include <sys/umtx.h>
-#include <sys/rtprio.h>
-#include <sys/thr.h>
-#include <sys/_sigset.h>
-#include <sys/unistd.h>
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANON,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $SA_SIGINFO = SA_SIGINFO,
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
-
- $UMTX_OP_WAIT = UMTX_OP_WAIT,
- $UMTX_OP_WAKE = UMTX_OP_WAKE,
-
- $EINTR = EINTR,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGEMT = SIGEMT,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGBUS = SIGBUS,
- $SIGSEGV = SIGSEGV,
- $SIGSYS = SIGSYS,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGTERM = SIGTERM,
- $SIGURG = SIGURG,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGCONT = SIGCONT,
- $SIGCHLD = SIGCHLD,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGIO = SIGIO,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGINFO = SIGINFO,
- $SIGUSR1 = SIGUSR1,
- $SIGUSR2 = SIGUSR2,
-
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
-
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
- $ITIMER_PROF = ITIMER_PROF,
-};
-
-typedef struct rtprio $Rtprio;
-typedef struct thr_param $ThrParam;
-typedef struct sigaltstack $Sigaltstack;
-typedef struct __sigset $Sigset;
-typedef union sigval $Sigval;
-typedef stack_t $StackT;
-
-typedef siginfo_t $Siginfo;
-
-typedef mcontext_t $Mcontext;
-typedef ucontext_t $Ucontext;
-typedef struct timeval $Timeval;
-typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
deleted file mode 100644
index 007856c6b..000000000
--- a/src/pkg/runtime/freebsd/os.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-
-int32 runtime·thr_new(ThrParam*, int32);
-void runtime·sigpanic(void);
-void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
-struct sigaction;
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtiem·setitimerval(int32, Itimerval*, Itimerval*);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/freebsd/signals.h
deleted file mode 100644
index 63a84671d..000000000
--- a/src/pkg/runtime/freebsd/signals.h
+++ /dev/null
@@ -1,52 +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.
-
-#define C SigCatch
-#define I SigIgnore
-#define R SigRestart
-#define Q SigQueue
-#define P SigPanic
-
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ Q+R, "SIGHUP: terminal line hangup",
- /* 2 */ Q+R, "SIGINT: interrupt",
- /* 3 */ C, "SIGQUIT: quit",
- /* 4 */ C, "SIGILL: illegal instruction",
- /* 5 */ C, "SIGTRAP: trace trap",
- /* 6 */ C, "SIGABRT: abort",
- /* 7 */ C, "SIGEMT: EMT instruction",
- /* 8 */ C+P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ C+P, "SIGBUS: bus error",
- /* 11 */ C+P, "SIGSEGV: segmentation violation",
- /* 12 */ C, "SIGSYS: bad system call",
- /* 13 */ I, "SIGPIPE: write to broken pipe",
- /* 14 */ Q+I+R, "SIGALRM: alarm clock",
- /* 15 */ Q+R, "SIGTERM: termination",
- /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop, unblockable",
- /* 18 */ Q+I+R, "SIGTSTP: stop from tty",
- /* 19 */ 0, "SIGCONT: continue",
- /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
- /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
- /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
- /* 23 */ Q+I+R, "SIGIO: i/o now possible",
- /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
- /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
- /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
- /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
- /* 28 */ Q+I+R, "SIGWINCH: window size change",
- /* 29 */ Q+I+R, "SIGINFO: information request",
- /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
- /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
- /* 32 */ Q+I+R, "SIGTHR: reserved",
-};
-#undef C
-#undef I
-#undef R
-#undef Q
-#undef P
-
-#define NSIG 33
diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
deleted file mode 100644
index f8c550f57..000000000
--- a/src/pkg/runtime/freebsd/thread.c
+++ /dev/null
@@ -1,201 +0,0 @@
-// Use of this source file is governed by a BSD-style
-// license that can be found in the LICENSE file.`
-
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "stack.h"
-
-extern SigTab runtime·sigtab[];
-extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
-
-// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
-// thus the code is largely similar. See linux/thread.c for comments.
-
-static void
-umtx_wait(uint32 *addr, uint32 val)
-{
- int32 ret;
-
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
- if(ret >= 0 || ret == -EINTR)
- return;
-
- runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
- *(int32*)0x1005 = 0x1005;
-}
-
-static void
-umtx_wake(uint32 *addr)
-{
- int32 ret;
-
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
- if(ret >= 0)
- return;
-
- runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
- *(int32*)0x1006 = 0x1006;
-}
-
-// See linux/thread.c for comments about the algorithm.
-static void
-umtx_lock(Lock *l)
-{
- uint32 v;
-
-again:
- v = l->key;
- if((v&1) == 0){
- if(runtime·cas(&l->key, v, v|1))
- return;
- goto again;
- }
-
- if(!runtime·cas(&l->key, v, v+2))
- goto again;
-
- umtx_wait(&l->key, v+2);
-
- for(;;){
- v = l->key;
- if(v < 2)
- runtime·throw("bad lock key");
- if(runtime·cas(&l->key, v, v-2))
- break;
- }
-
- goto again;
-}
-
-static void
-umtx_unlock(Lock *l)
-{
- uint32 v;
-
-again:
- v = l->key;
- if((v&1) == 0)
- runtime·throw("unlock of unlocked lock");
- if(!runtime·cas(&l->key, v, v&~1))
- goto again;
-
- if(v&~1)
- umtx_wake(&l->key);
-}
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks < 0)
- runtime·throw("lock count");
- m->locks++;
- umtx_lock(l);
-}
-
-void
-runtime·unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- runtime·throw("lock count");
- umtx_unlock(l);
-}
-
-// Event notifications.
-void
-runtime·noteclear(Note *n)
-{
- n->lock.key = 0;
- umtx_lock(&n->lock);
-}
-
-void
-runtime·notesleep(Note *n)
-{
- umtx_lock(&n->lock);
- umtx_unlock(&n->lock);
-}
-
-void
-runtime·notewakeup(Note *n)
-{
- umtx_unlock(&n->lock);
-}
-
-void runtime·thr_start(void*);
-
-void
-runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- ThrParam param;
-
- USED(fn); // thr_start assumes fn == mstart
- USED(g); // thr_start assumes g == m->g0
-
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, m->id, m->tls[0], &m);
- }
-
- runtime·memclr((byte*)&param, sizeof param);
-
- param.start_func = runtime·thr_start;
- param.arg = m;
- param.stack_base = (int8*)g->stackbase;
- param.stack_size = (byte*)stk - (byte*)g->stackbase;
- param.child_tid = (intptr*)&m->procid;
- param.parent_tid = nil;
- param.tls_base = (int8*)&m->tls[0];
- param.tls_size = sizeof m->tls;
-
- m->tls[0] = m->id; // so 386 asm can find it
-
- runtime·thr_new(&param, sizeof param);
-}
-
-void
-runtime·osinit(void)
-{
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-void
-runtime·minit(void)
-{
- // Initialize signal handling
- m->gsignal = runtime·malg(32*1024);
- runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
-}
-
-void
-runtime·sigpanic(void)
-{
- switch(g->sig) {
- case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- runtime·panicstring("invalid memory address or nil pointer dereference");
- runtime·printf("unexpected fault address %p\n", g->sigcode1);
- runtime·throw("fault");
- case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
- runtime·panicstring("invalid memory address or nil pointer dereference");
- runtime·printf("unexpected fault address %p\n", g->sigcode1);
- runtime·throw("fault");
- case SIGFPE:
- switch(g->sigcode0) {
- case FPE_INTDIV:
- runtime·panicstring("integer divide by zero");
- case FPE_INTOVF:
- runtime·panicstring("integer overflow");
- }
- runtime·panicstring("floating point error");
- }
- runtime·panicstring(runtime·sigtab[g->sig].name);
-}
diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go
new file mode 100644
index 000000000..65894a6fd
--- /dev/null
+++ b/src/pkg/runtime/gc_test.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "testing"
+)
+
+func TestGcSys(t *testing.T) {
+ memstats := new(runtime.MemStats)
+ runtime.GC()
+ runtime.ReadMemStats(memstats)
+ sys := memstats.Sys
+
+ itercount := 1000000
+ if testing.Short() {
+ itercount = 100000
+ }
+ for i := 0; i < itercount; i++ {
+ workthegc()
+ }
+
+ // Should only be using a few MB.
+ runtime.ReadMemStats(memstats)
+ if sys > memstats.Sys {
+ sys = 0
+ } else {
+ sys = memstats.Sys - sys
+ }
+ t.Logf("used %d extra bytes", sys)
+ if sys > 4<<20 {
+ t.Fatalf("using too much memory: %d bytes", sys)
+ }
+}
+
+func workthegc() []byte {
+ return make([]byte, 1029)
+}
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 22664b548..1def96727 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -6,41 +6,15 @@
#include "hashmap.h"
#include "type.h"
-/* Return a pointer to the struct/union of type "type"
- whose "field" field is addressed by pointer "p". */
-
struct Hmap { /* a hash table; initialize with hash_init() */
uint32 count; /* elements in table - must be first */
-
uint8 datasize; /* amount of data to store in entry */
uint8 max_power; /* max power of 2 to create sub-tables */
- uint8 max_probes; /* max entries to probe before rehashing */
- uint8 indirectval; /* storing pointers to values */
+ uint8 indirectval; /* storing pointers to values */
+ uint8 valoff; /* offset of value in key+value data block */
int32 changes; /* inc'ed whenever a subtable is created/grown */
- hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */
- uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */
- void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */
+ uintptr hash0; /* hash seed */
struct hash_subtable *st; /* first-level table */
-
- uint32 keysize;
- uint32 valsize;
- uint32 datavo;
-
- // three sets of offsets: the digit counts how many
- // of key, value are passed as inputs:
- // 0 = func() (key, value)
- // 1 = func(key) (value)
- // 2 = func(key, value)
- uint32 ko0;
- uint32 vo0;
- uint32 ko1;
- uint32 vo1;
- uint32 po1;
- uint32 ko2;
- uint32 vo2;
- uint32 po2;
- Alg* keyalg;
- Alg* valalg;
};
struct hash_entry {
@@ -58,7 +32,7 @@ struct hash_subtable {
struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
};
-#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y)))
+#define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key->size, (x), (y)), (eq))
#define HASH_REHASH 0x2 /* an internal flag */
/* the number of bits used is stored in the flags word too */
@@ -79,6 +53,7 @@ struct hash_subtable {
#define HASH_OFFSET(base, byte_offset) \
((struct hash_entry *) (((byte *) (base)) + (byte_offset)))
+#define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */
/* return a hash layer with 2**power empty entries */
static struct hash_subtable *
@@ -87,8 +62,8 @@ hash_subtable_new (Hmap *h, int32 power, int32 used)
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
int32 bytes = elemsize << power;
struct hash_subtable *st;
- int32 limit_bytes = h->max_probes * elemsize;
- int32 max_probes = h->max_probes;
+ int32 limit_bytes = HASH_MAX_PROBES * elemsize;
+ int32 max_probes = HASH_MAX_PROBES;
if (bytes < limit_bytes) {
limit_bytes = bytes;
@@ -127,12 +102,7 @@ init_sizes (int64 hint, int32 *init_power, int32 *max_power)
}
static void
-hash_init (Hmap *h,
- int32 datasize,
- hash_hash_t (*data_hash) (uint32, void *),
- uint32 (*data_eq) (uint32, void *, void *),
- void (*data_del) (uint32, void *, void *),
- int64 hint)
+hash_init (Hmap *h, int32 datasize, int64 hint)
{
int32 init_power;
int32 max_power;
@@ -143,16 +113,13 @@ hash_init (Hmap *h,
init_sizes (hint, &init_power, &max_power);
h->datasize = datasize;
h->max_power = max_power;
- h->max_probes = 15;
assert (h->datasize == datasize);
assert (h->max_power == max_power);
assert (sizeof (void *) <= h->datasize || h->max_power == 255);
h->count = 0;
h->changes = 0;
- h->data_hash = data_hash;
- h->data_eq = data_eq;
- h->data_del = data_del;
h->st = hash_subtable_new (h, init_power, 0);
+ h->hash0 = runtime·fastrand1();
}
static void
@@ -199,11 +166,11 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
}
static int32
-hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+hash_insert_internal (MapType*, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
Hmap *h, void *data, void **pres);
static void
-hash_conv (Hmap *h,
+hash_conv (MapType *t, Hmap *h,
struct hash_subtable *st, int32 flags,
hash_hash_t hash,
struct hash_entry *e)
@@ -238,13 +205,13 @@ hash_conv (Hmap *h,
(ne <= st->last && (e_hash = ne->hash) != HASH_NIL &&
(e_hash & prefix_mask) == current)) {
struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
- int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
+ int32 rc = hash_insert_internal (t, &new_st, new_flags, e->hash, h, e->data, &dummy_result);
assert (rc == 0);
memcpy(dummy_result, e->data, h->datasize);
e = ne;
while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
- rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
+ rc = hash_insert_internal (t, &new_st, new_flags, e_hash, h, e->data, &dummy_result);
assert (rc == 0);
memcpy(dummy_result, e->data, h->datasize);
e = HASH_OFFSET (e, elemsize);
@@ -266,7 +233,7 @@ hash_conv (Hmap *h,
}
static void
-hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
+hash_grow (MapType *t, Hmap *h, struct hash_subtable **pst, int32 flags)
{
struct hash_subtable *old_st = *pst;
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -280,7 +247,7 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) {
hash_hash_t hash = e->hash;
if (hash != HASH_NIL) {
- int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
+ int32 rc = hash_insert_internal (t, pst, flags, e->hash, h, e->data, &dummy_result);
assert (rc == 0);
memcpy(dummy_result, e->data, h->datasize);
used++;
@@ -290,16 +257,20 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
}
static int32
-hash_lookup (Hmap *h, void *data, void **pres)
+hash_lookup (MapType *t, Hmap *h, void *data, void **pres)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ hash_hash_t hash;
struct hash_subtable *st = h->st;
int32 used = 0;
hash_hash_t e_hash;
struct hash_entry *e;
struct hash_entry *end_e;
-
+ bool eq;
+
+ hash = h->hash0;
+ (*t->key->alg->hash) (&hash, t->key->size, data);
+ hash &= ~HASH_MASK;
hash += HASH_ADJUST (hash);
for (;;) {
int32 shift = HASH_BITS - (st->power + used);
@@ -319,7 +290,7 @@ hash_lookup (Hmap *h, void *data, void **pres)
e = HASH_OFFSET (e, elemsize);
}
while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
- if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
+ if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */
*pres = e->data;
return (1);
}
@@ -331,16 +302,20 @@ hash_lookup (Hmap *h, void *data, void **pres)
}
static int32
-hash_remove (Hmap *h, void *data, void *arg)
+hash_remove (MapType *t, Hmap *h, void *data)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ hash_hash_t hash;
struct hash_subtable *st = h->st;
int32 used = 0;
hash_hash_t e_hash;
struct hash_entry *e;
struct hash_entry *end_e;
+ bool eq;
+ hash = h->hash0;
+ (*t->key->alg->hash) (&hash, t->key->size, data);
+ hash &= ~HASH_MASK;
hash += HASH_ADJUST (hash);
for (;;) {
int32 shift = HASH_BITS - (st->power + used);
@@ -360,8 +335,9 @@ hash_remove (Hmap *h, void *data, void *arg)
e = HASH_OFFSET (e, elemsize);
}
while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
- if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
- (*h->data_del) (h->datavo, arg, e->data);
+ if (HASH_DATA_EQ (eq, t, h, data, e->data)) { /* a match */
+ if (h->indirectval)
+ free (*(void**)((byte*)e->data + h->valoff));
hash_remove_n (st, e, 1);
h->count--;
return (1);
@@ -373,10 +349,11 @@ hash_remove (Hmap *h, void *data, void *arg)
}
static int32
-hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
Hmap *h, void *data, void **pres)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ bool eq;
if ((flags & HASH_REHASH) == 0) {
hash += HASH_ADJUST (hash);
@@ -409,7 +386,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
int32 ins_i = i;
hash_hash_t ins_e_hash;
while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) {
- if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */
+ if (HASH_DATA_EQ (eq, t, h, data, ins_e->data)) { /* a match */
*pres = ins_e->data;
return (1);
}
@@ -447,17 +424,22 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
}
h->changes++;
if (st->power < h->max_power) {
- hash_grow (h, pst, flags);
+ hash_grow (t, h, pst, flags);
} else {
- hash_conv (h, st, flags, hash, start_e);
+ hash_conv (t, h, st, flags, hash, start_e);
}
}
}
static int32
-hash_insert (Hmap *h, void *data, void **pres)
+hash_insert (MapType *t, Hmap *h, void *data, void **pres)
{
- int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres);
+ uintptr hash;
+ int32 rc;
+
+ hash = h->hash0;
+ (*t->key->alg->hash) (&hash, t->key->size, data);
+ rc = hash_insert_internal (t, &h->st, 0, hash, h, data, pres);
h->count += (rc == 0); /* increment count if element didn't previously exist */
return (rc);
@@ -506,22 +488,29 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
static void *
hash_next (struct hash_iter *it)
{
- int32 elemsize = it->elemsize;
- struct hash_iter_sub *sub = &it->subtable_state[it->i];
- struct hash_entry *e = sub->e;
- struct hash_entry *last = sub->last;
- hash_hash_t e_hash = 0;
+ int32 elemsize;
+ struct hash_iter_sub *sub;
+ struct hash_entry *e;
+ struct hash_entry *last;
+ hash_hash_t e_hash;
if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */
+ if (~it->last_hash == 0)
+ return (0);
it->changes = it->h->changes;
it->i = 0;
iter_restart (it, it->h->st, 0);
- sub = &it->subtable_state[it->i];
- e = sub->e;
- last = sub->last;
}
+ elemsize = it->elemsize;
+
+Again:
+ e_hash = 0;
+ sub = &it->subtable_state[it->i];
+ e = sub->e;
+ last = sub->last;
+
if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
- struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
+ struct hash_entry *start = HASH_OFFSET (e, -(elemsize * HASH_MAX_PROBES));
struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
hash_hash_t last_hash = it->last_hash;
if (start < sub->start) {
@@ -542,8 +531,20 @@ hash_next (struct hash_iter *it)
}
if (e > last) {
if (it->i == 0) {
- it->last_hash = HASH_OFFSET (e, -elemsize)->hash;
- sub->e = e;
+ if(!it->cycled) {
+ // Wrap to zero and iterate up until it->cycle.
+ it->cycled = true;
+ it->last_hash = 0;
+ it->subtable_state[0].e = it->h->st->entry;
+ it->subtable_state[0].start = it->h->st->entry;
+ it->subtable_state[0].last = it->h->st->last;
+ goto Again;
+ }
+ // Set last_hash to impossible value and
+ // break it->changes, so that check at top of
+ // hash_next will be used if we get called again.
+ it->last_hash = ~(uintptr_t)0;
+ it->changes--;
return (0);
} else {
it->i--;
@@ -552,6 +553,15 @@ hash_next (struct hash_iter *it)
last = sub->last;
}
} else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
+ if(it->cycled && e->hash > it->cycle) {
+ // Already returned this.
+ // Set last_hash to impossible value and
+ // break it->changes, so that check at top of
+ // hash_next will be used if we get called again.
+ it->last_hash = ~(uintptr_t)0;
+ it->changes--;
+ return (0);
+ }
it->last_hash = e->hash;
sub->e = HASH_OFFSET (e, elemsize);
return (e->data);
@@ -571,16 +581,28 @@ hash_next (struct hash_iter *it)
}
static void
-hash_iter_init (Hmap *h, struct hash_iter *it)
+hash_iter_init (MapType *t, Hmap *h, struct hash_iter *it)
{
it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
it->changes = h->changes;
it->i = 0;
it->h = h;
+ it->t = t;
it->last_hash = 0;
it->subtable_state[0].e = h->st->entry;
it->subtable_state[0].start = h->st->entry;
it->subtable_state[0].last = h->st->last;
+
+ // fastrand1 returns 31 useful bits.
+ // We don't care about not having a bottom bit but we
+ // do want top bits.
+ if(sizeof(void*) == 8)
+ it->cycle = (uint64)runtime·fastrand1()<<33 | (uint64)runtime·fastrand1()<<2;
+ else
+ it->cycle = runtime·fastrand1()<<1;
+ it->cycled = false;
+ it->last_hash = it->cycle;
+ iter_restart(it, it->h->st, 0);
}
static void
@@ -662,24 +684,6 @@ enum {
MaxValsize = 256 - 64
};
-static void
-donothing(uint32 s, void *a, void *b)
-{
- USED(s);
- USED(a);
- USED(b);
-}
-
-static void
-freedata(uint32 datavo, void *a, void *b)
-{
- void *p;
-
- USED(a);
- p = *(void**)((byte*)b + datavo);
- free(p);
-}
-
static void**
hash_indirect(Hmap *h, void *p)
{
@@ -695,8 +699,7 @@ Hmap*
runtime·makemap_c(MapType *typ, int64 hint)
{
Hmap *h;
- int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
- void (*data_del)(uint32, void*, void*);
+ int32 valsize_in_hash;
Type *key, *val;
key = typ->key;
@@ -705,68 +708,30 @@ runtime·makemap_c(MapType *typ, int64 hint)
if(hint < 0 || (int32)hint != hint)
runtime·panicstring("makemap: size out of range");
- keyalg = key->alg;
- valalg = val->alg;
- keysize = key->size;
- valsize = val->size;
-
- if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) {
- runtime·printf("map(keyalg=%d)\n", keyalg);
+ if(key->alg->hash == runtime·nohash)
runtime·throw("runtime.makemap: unsupported map key type");
- }
-
- if(valalg >= nelem(runtime·algarray)) {
- runtime·printf("map(valalg=%d)\n", valalg);
- runtime·throw("runtime.makemap: unsupported map value type");
- }
h = runtime·mal(sizeof(*h));
- valsize_in_hash = valsize;
- data_del = donothing;
- if (valsize > MaxValsize) {
+ valsize_in_hash = val->size;
+ if (val->size > MaxValsize) {
h->indirectval = 1;
- data_del = freedata;
valsize_in_hash = sizeof(void*);
}
- // align value inside data so that mark-sweep gc can find it.
- // might remove in the future and just assume datavo == keysize.
- h->datavo = keysize;
+ // Align value inside data so that mark-sweep gc can find it.
+ h->valoff = key->size;
if(valsize_in_hash >= sizeof(void*))
- h->datavo = runtime·rnd(keysize, sizeof(void*));
+ h->valoff = runtime·rnd(key->size, sizeof(void*));
- hash_init(h, h->datavo+valsize_in_hash,
- runtime·algarray[keyalg].hash,
- runtime·algarray[keyalg].equal,
- data_del,
- hint);
-
- h->keysize = keysize;
- h->valsize = valsize;
- h->keyalg = &runtime·algarray[keyalg];
- h->valalg = &runtime·algarray[valalg];
+ hash_init(h, h->valoff+valsize_in_hash, hint);
// these calculations are compiler dependent.
// figure out offsets of map call arguments.
- // func() (key, val)
- h->ko0 = runtime·rnd(sizeof(h), Structrnd);
- h->vo0 = runtime·rnd(h->ko0+keysize, val->align);
-
- // func(key) (val[, pres])
- h->ko1 = runtime·rnd(sizeof(h), key->align);
- h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
- h->po1 = h->vo1 + valsize;
-
- // func(key, val[, pres])
- h->ko2 = runtime·rnd(sizeof(h), key->align);
- h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
- h->po2 = h->vo2 + valsize;
-
if(debug) {
- runtime·printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
- h, keysize, valsize, keyalg, valalg, h->ko0, h->vo0, h->ko1, h->vo1, h->po1, h->ko2, h->vo2, h->po2);
+ runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
+ h, key->size, val->size, key->alg, val->alg);
}
return h;
@@ -795,9 +760,9 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
byte *res;
Type *elem;
+ elem = t->elem;
if(h == nil) {
- elem = t->elem;
- runtime·algarray[elem->alg].copy(elem->size, av, nil);
+ elem->alg->copy(elem->size, av, nil);
*pres = false;
return;
}
@@ -806,12 +771,12 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
runtime·gosched();
res = nil;
- if(hash_lookup(h, ak, (void**)&res)) {
+ if(hash_lookup(t, h, ak, (void**)&res)) {
*pres = true;
- h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
+ elem->alg->copy(elem->size, av, hash_indirect(h, res+h->valoff));
} else {
*pres = false;
- h->valalg->copy(h->valsize, av, nil);
+ elem->alg->copy(elem->size, av, nil);
}
}
@@ -823,13 +788,8 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
byte *ak, *av;
bool pres;
- if(h == nil) {
- ak = (byte*)(&h + 1);
- av = ak + runtime·rnd(t->key->size, Structrnd);
- } else {
- ak = (byte*)&h + h->ko1;
- av = (byte*)&h + h->vo1;
- }
+ ak = (byte*)(&h + 1);
+ av = ak + runtime·rnd(t->key->size, Structrnd);
runtime·mapaccess(t, h, ak, av, &pres);
@@ -837,9 +797,9 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
runtime·prints("runtime.mapaccess1: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- h->keyalg->print(h->keysize, ak);
+ t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
- h->valalg->print(h->valsize, av);
+ t->elem->alg->print(t->elem->size, av);
runtime·prints("; pres=");
runtime·printbool(pres);
runtime·prints("\n");
@@ -853,15 +813,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
{
byte *ak, *av, *ap;
- if(h == nil) {
- ak = (byte*)(&h + 1);
- av = ak + runtime·rnd(t->key->size, Structrnd);
- ap = av + t->elem->size;
- } else {
- ak = (byte*)&h + h->ko1;
- av = (byte*)&h + h->vo1;
- ap = (byte*)&h + h->po1;
- }
+ ak = (byte*)(&h + 1);
+ av = ak + runtime·rnd(t->key->size, Structrnd);
+ ap = av + t->elem->size;
runtime·mapaccess(t, h, ak, av, ap);
@@ -869,9 +823,9 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
runtime·prints("runtime.mapaccess2: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- h->keyalg->print(h->keysize, ak);
+ t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
- h->valalg->print(h->valsize, av);
+ t->elem->alg->print(t->key->size, av);
runtime·prints("; pres=");
runtime·printbool(*ap);
runtime·prints("\n");
@@ -910,33 +864,31 @@ runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
byte *res;
int32 hit;
- USED(t);
-
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
if(runtime·gcwaiting)
runtime·gosched();
- res = nil;
if(av == nil) {
- hash_remove(h, ak, (void**)&res);
+ hash_remove(t, h, ak);
return;
}
- hit = hash_insert(h, ak, (void**)&res);
+ res = nil;
+ hit = hash_insert(t, h, ak, (void**)&res);
if(!hit && h->indirectval)
- *(void**)(res+h->datavo) = runtime·mal(h->valsize);
- h->keyalg->copy(h->keysize, res, ak);
- h->valalg->copy(h->valsize, hash_indirect(h, res+h->datavo), av);
+ *(void**)(res+h->valoff) = runtime·mal(t->elem->size);
+ t->key->alg->copy(t->key->size, res, ak);
+ t->elem->alg->copy(t->elem->size, hash_indirect(h, res+h->valoff), av);
if(debug) {
runtime·prints("mapassign: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- h->keyalg->print(h->keysize, ak);
+ t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
- h->valalg->print(h->valsize, av);
+ t->elem->alg->print(t->elem->size, av);
runtime·prints("; hit=");
runtime·printint(hit);
runtime·prints("; res=");
@@ -955,36 +907,30 @@ runtime·mapassign1(MapType *t, Hmap *h, ...)
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
- ak = (byte*)&h + h->ko2;
- av = (byte*)&h + h->vo2;
+ ak = (byte*)(&h + 1);
+ av = ak + runtime·rnd(t->key->size, t->elem->align);
runtime·mapassign(t, h, ak, av);
}
-// mapassign2(mapType *type, hmap *map[any]any, key any, val any, pres bool);
+// mapdelete(mapType *type, hmap *map[any]any, key any)
#pragma textflag 7
void
-runtime·mapassign2(MapType *t, Hmap *h, ...)
+runtime·mapdelete(MapType *t, Hmap *h, ...)
{
- byte *ak, *av, *ap;
+ byte *ak;
if(h == nil)
- runtime·panicstring("assignment to entry in nil map");
+ runtime·panicstring("deletion of entry in nil map");
- ak = (byte*)&h + h->ko2;
- av = (byte*)&h + h->vo2;
- ap = (byte*)&h + h->po2;
-
- if(*ap == false)
- av = nil; // delete
-
- runtime·mapassign(t, h, ak, av);
+ ak = (byte*)(&h + 1);
+ runtime·mapassign(t, h, ak, nil);
if(debug) {
- runtime·prints("mapassign2: map=");
+ runtime·prints("mapdelete: map=");
runtime·printpointer(h);
runtime·prints("; key=");
- h->keyalg->print(h->keysize, ak);
+ t->key->alg->print(t->key->size, ak);
runtime·prints("\n");
}
}
@@ -1000,11 +946,11 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
- if(h->keysize <= sizeof(key))
+ if(t->key->size <= sizeof(key))
ak = (byte*)&key;
else
ak = (byte*)key;
- if(h->valsize <= sizeof(val))
+ if(t->elem->size <= sizeof(val))
av = (byte*)&val;
else
av = (byte*)val;
@@ -1015,13 +961,13 @@ reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
void
-runtime·mapiterinit(MapType*, Hmap *h, struct hash_iter *it)
+runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
{
if(h == nil) {
it->data = nil;
return;
}
- hash_iter_init(h, it);
+ hash_iter_init(t, h, it);
it->data = hash_next(it);
if(debug) {
runtime·prints("runtime.mapiterinit: map=");
@@ -1076,15 +1022,17 @@ runtime·mapiter1(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *res;
+ Type *key;
h = it->h;
- ak = (byte*)&it + h->ko0;
+ ak = (byte*)(&it + 1);
res = it->data;
if(res == nil)
runtime·throw("runtime.mapiter1: key:val nil pointer");
- h->keyalg->copy(h->keysize, ak, res);
+ key = it->t->key;
+ key->alg->copy(key->size, ak, res);
if(debug) {
runtime·prints("mapiter2: iter=");
@@ -1098,14 +1046,14 @@ runtime·mapiter1(struct hash_iter *it, ...)
bool
runtime·mapiterkey(struct hash_iter *it, void *ak)
{
- Hmap *h;
byte *res;
+ Type *key;
- h = it->h;
res = it->data;
if(res == nil)
return false;
- h->keyalg->copy(h->keysize, ak, res);
+ key = it->t->key;
+ key->alg->copy(key->size, ak, res);
return true;
}
@@ -1116,20 +1064,20 @@ runtime·mapiterkey(struct hash_iter *it, void *ak)
void
reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
{
- Hmap *h;
byte *res;
+ Type *tkey;
key = 0;
ok = false;
- h = it->h;
res = it->data;
if(res == nil) {
key = 0;
ok = false;
} else {
+ tkey = it->t->key;
key = 0;
- if(h->keysize <= sizeof(key))
- h->keyalg->copy(h->keysize, (byte*)&key, res);
+ if(tkey->size <= sizeof(key))
+ tkey->alg->copy(tkey->size, (byte*)&key, res);
else
key = (uintptr)res;
ok = true;
@@ -1158,17 +1106,19 @@ runtime·mapiter2(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *av, *res;
+ MapType *t;
- h = it->h;
- ak = (byte*)&it + h->ko0;
- av = (byte*)&it + h->vo0;
+ t = it->t;
+ ak = (byte*)(&it + 1);
+ av = ak + runtime·rnd(t->key->size, t->elem->align);
res = it->data;
if(res == nil)
runtime·throw("runtime.mapiter2: key:val nil pointer");
- h->keyalg->copy(h->keysize, ak, res);
- h->valalg->copy(h->valsize, av, hash_indirect(h, res+h->datavo));
+ h = it->h;
+ t->key->alg->copy(t->key->size, ak, res);
+ t->elem->alg->copy(t->elem->size, av, hash_indirect(h, res+h->valoff));
if(debug) {
runtime·prints("mapiter2: iter=");
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 81b0cff88..4c10cf6ef 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -66,7 +66,7 @@
#define malloc runtime·mal
#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
#define memcpy(a,b,c) runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c))
-#define assert(a) if(!(a)) runtime·throw("assert")
+#define assert(a) if(!(a)) runtime·throw("hashmap assert")
#define free(x) runtime·free(x)
#define memmove(a,b,c) runtime·memmove(a, b, c)
@@ -82,8 +82,11 @@ struct hash_iter {
int32 elemsize; /* size of elements in table */
int32 changes; /* number of changes observed last time */
int32 i; /* stack pointer in subtable_state */
+ bool cycled; /* have reached the end and wrapped to 0 */
hash_hash_t last_hash; /* last hash value returned */
+ hash_hash_t cycle; /* hash value where we started */
struct Hmap *h; /* the hash table */
+ MapType *t; /* the map type */
struct hash_iter_sub {
struct hash_entry *e; /* pointer into subtable */
struct hash_entry *start; /* start of subtable */
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 000f834cf..2b60c4f23 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -3,17 +3,10 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "type.h"
#include "malloc.h"
-enum
-{
- // If an empty interface has these bits set in its type
- // pointer, it was copied from a reflect.Value and is
- // not a valid empty interface.
- reflectFlags = 3,
-};
-
void
runtime·printiface(Iface i)
{
@@ -126,7 +119,7 @@ search:
if(!canfail) {
throw:
// didn't find method
- runtime·newTypeAssertionError(nil, type, inter,
+ runtime·newTypeAssertionError(
nil, type->string, inter->string,
iname, &err);
if(locked)
@@ -158,17 +151,18 @@ out:
static void
copyin(Type *t, void *src, void **dst)
{
- int32 wid, alg;
+ uintptr size;
void *p;
+ Alg *alg;
- wid = t->size;
+ size = t->size;
alg = t->alg;
- if(wid <= sizeof(*dst))
- runtime·algarray[alg].copy(wid, dst, src);
+ if(size <= sizeof(*dst))
+ alg->copy(size, dst, src);
else {
- p = runtime·mal(wid);
- runtime·algarray[alg].copy(wid, p, src);
+ p = runtime·mal(size);
+ alg->copy(size, p, src);
*dst = p;
}
}
@@ -176,15 +170,16 @@ copyin(Type *t, void *src, void **dst)
static void
copyout(Type *t, void **src, void *dst)
{
- int32 wid, alg;
+ uintptr size;
+ Alg *alg;
- wid = t->size;
+ size = t->size;
alg = t->alg;
- if(wid <= sizeof(*src))
- runtime·algarray[alg].copy(wid, dst, src);
+ if(size <= sizeof(*src))
+ alg->copy(size, dst, src);
else
- runtime·algarray[alg].copy(wid, dst, *src);
+ alg->copy(size, dst, *src);
}
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
@@ -240,13 +235,13 @@ assertI2Tret(Type *t, Iface i, byte *ret)
tab = i.tab;
if(tab == nil) {
- runtime·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(
nil, nil, t->string,
nil, &err);
runtime·panic(err);
}
if(tab->type != t) {
- runtime·newTypeAssertionError(tab->inter, tab->type, t,
+ runtime·newTypeAssertionError(
tab->inter->string, tab->type->string, t->string,
nil, &err);
runtime·panic(err);
@@ -286,8 +281,6 @@ runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
assertE2Tret(t, e, ret);
}
@@ -297,16 +290,14 @@ assertE2Tret(Type *t, Eface e, byte *ret)
{
Eface err;
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
if(e.type == nil) {
- runtime·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(
nil, nil, t->string,
nil, &err);
runtime·panic(err);
}
if(e.type != t) {
- runtime·newTypeAssertionError(nil, e.type, t,
+ runtime·newTypeAssertionError(
nil, e.type->string, t->string,
nil, &err);
runtime·panic(err);
@@ -323,8 +314,6 @@ runtime·assertE2T2(Type *t, Eface e, ...)
bool *ok;
int32 wid;
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
ret = (byte*)(&e+1);
wid = t->size;
ok = (bool*)(ret + wid);
@@ -363,7 +352,7 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- runtime·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
@@ -418,7 +407,7 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- runtime·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
@@ -460,12 +449,10 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
Type *t;
Eface err;
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- runtime·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
@@ -493,8 +480,6 @@ runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
void
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
if(e.type == nil) {
ok = 0;
ret.data = nil;
@@ -517,12 +502,10 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
Type *t;
Eface err;
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- runtime·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(
nil, nil, inter->string,
nil, &err);
runtime·panic(err);
@@ -535,8 +518,6 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
void
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
USED(inter);
ret = e;
ok = e.type != nil;
@@ -547,23 +528,27 @@ runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
static uintptr
ifacehash1(void *data, Type *t)
{
- int32 alg, wid;
+ Alg *alg;
+ uintptr size, h;
Eface err;
if(t == nil)
return 0;
alg = t->alg;
- wid = t->size;
- if(runtime·algarray[alg].hash == runtime·nohash) {
+ size = t->size;
+ if(alg->hash == runtime·nohash) {
// calling nohash will panic too,
// but we can print a better error.
runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
runtime·panic(err);
}
- if(wid <= sizeof(data))
- return runtime·algarray[alg].hash(wid, &data);
- return runtime·algarray[alg].hash(wid, data);
+ h = 0;
+ if(size <= sizeof(data))
+ alg->hash(&h, size, &data);
+ else
+ alg->hash(&h, size, data);
+ return h;
}
uintptr
@@ -583,22 +568,27 @@ runtime·efacehash(Eface a)
static bool
ifaceeq1(void *data1, void *data2, Type *t)
{
- int32 alg, wid;
+ uintptr size;
+ Alg *alg;
Eface err;
+ bool eq;
alg = t->alg;
- wid = t->size;
+ size = t->size;
- if(runtime·algarray[alg].equal == runtime·noequal) {
+ if(alg->equal == runtime·noequal) {
// calling noequal will panic too,
// but we can print a better error.
runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
runtime·panic(err);
}
- if(wid <= sizeof(data1))
- return runtime·algarray[alg].equal(wid, &data1, &data2);
- return runtime·algarray[alg].equal(wid, data1, data2);
+ eq = 0;
+ if(size <= sizeof(data1))
+ alg->equal(&eq, size, &data1, &data2);
+ else
+ alg->equal(&eq, size, data1, data2);
+ return eq;
}
bool
@@ -614,10 +604,6 @@ runtime·ifaceeq_c(Iface i1, Iface i2)
bool
runtime·efaceeq_c(Eface e1, Eface e2)
{
- if(((uintptr)e1.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
- if(((uintptr)e2.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
if(e1.type != e2.type)
return false;
if(e1.type == nil)
@@ -660,8 +646,6 @@ runtime·efacethash(Eface e1, uint32 ret)
{
Type *t;
- if(((uintptr)e1.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
ret = 0;
t = e1.type;
if(t != nil)
@@ -670,10 +654,8 @@ runtime·efacethash(Eface e1, uint32 ret)
}
void
-unsafe·Typeof(Eface e, Eface ret)
+reflect·unsafe_Typeof(Eface e, Eface ret)
{
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
if(e.type == nil) {
ret.type = nil;
ret.data = nil;
@@ -684,73 +666,10 @@ unsafe·Typeof(Eface e, Eface ret)
}
void
-unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
-{
- uintptr *p;
- uintptr x;
-
- if(((uintptr)e.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
- if(e.type == nil) {
- rettype.type = nil;
- rettype.data = nil;
- retaddr = 0;
- } else {
- rettype = *(Eface*)e.type;
- if(e.type->size <= sizeof(uintptr)) {
- // Copy data into x ...
- x = 0;
- runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
-
- // but then build pointer to x so that Reflect
- // always returns pointer to data.
- p = runtime·mal(sizeof(uintptr));
- *p = x;
- } else {
- // Already a pointer, but still make a copy,
- // to preserve value semantics for interface data.
- p = runtime·mal(e.type->size);
- runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
- }
- retaddr = p;
- }
- FLUSH(&rettype);
- FLUSH(&retaddr);
-}
-
-void
-unsafe·Unreflect(Eface typ, void *addr, Eface e)
-{
- if(((uintptr)typ.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
-
- // Reflect library has reinterpreted typ
- // as its own kind of type structure.
- // We know that the pointer to the original
- // type structure sits before the data pointer.
- e.type = (Type*)((Eface*)typ.data-1);
-
- // Interface holds either pointer to data
- // or copy of original data.
- if(e.type->size <= sizeof(uintptr))
- runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
- else {
- // Easier: already a pointer to data.
- // TODO(rsc): Should this make a copy?
- e.data = addr;
- }
-
- FLUSH(&e);
-}
-
-void
-unsafe·New(Eface typ, void *ret)
+reflect·unsafe_New(Eface typ, void *ret)
{
Type *t;
- if(((uintptr)typ.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
-
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
@@ -765,14 +684,11 @@ unsafe·New(Eface typ, void *ret)
}
void
-unsafe·NewArray(Eface typ, uint32 n, void *ret)
+reflect·unsafe_NewArray(Eface typ, uint32 n, void *ret)
{
uint64 size;
Type *t;
- if(((uintptr)typ.type&reflectFlags) != 0)
- runtime·throw("invalid interface value");
-
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h
deleted file mode 100644
index 73fe23ef9..000000000
--- a/src/pkg/runtime/linux/386/defs.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-enum {
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x20,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- SA_RESTART = 0x10000000,
- SA_ONSTACK = 0x8000000,
- SA_RESTORER = 0x4000000,
- SA_SIGINFO = 0x4,
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGBUS = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGUSR1 = 0xa,
- SIGSEGV = 0xb,
- SIGUSR2 = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGSTKFLT = 0x10,
- SIGCHLD = 0x11,
- SIGCONT = 0x12,
- SIGSTOP = 0x13,
- SIGTSTP = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGURG = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGIO = 0x1d,
- SIGPWR = 0x1e,
- SIGSYS = 0x1f,
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
- ITIMER_REAL = 0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
- O_RDONLY = 0,
- O_CLOEXEC = 02000000,
-};
-
-// Types
-#pragma pack on
-
-typedef struct Fpreg Fpreg;
-struct Fpreg {
- uint16 significand[4];
- uint16 exponent;
-};
-
-typedef struct Fpxreg Fpxreg;
-struct Fpxreg {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-
-typedef struct Xmmreg Xmmreg;
-struct Xmmreg {
- uint32 element[4];
-};
-
-typedef struct Fpstate Fpstate;
-struct Fpstate {
- uint32 cw;
- uint32 sw;
- uint32 tag;
- uint32 ipoff;
- uint32 cssel;
- uint32 dataoff;
- uint32 datasel;
- Fpreg _st[8];
- uint16 status;
- uint16 magic;
- uint32 _fxsr_env[6];
- uint32 mxcsr;
- uint32 reserved;
- Fpxreg _fxsr_st[8];
- Xmmreg _xmm[8];
- uint32 padding1[44];
- byte Pad_godefs_0[48];
-};
-
-typedef struct Timespec Timespec;
-struct Timespec {
- int32 tv_sec;
- int32 tv_nsec;
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
- int32 tv_sec;
- int32 tv_usec;
-};
-
-typedef struct Sigaction Sigaction;
-struct Sigaction {
- void *k_sa_handler;
- uint32 sa_flags;
- void *sa_restorer;
- uint32 sa_mask;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- byte _sifields[116];
-};
-
-typedef struct Sigaltstack Sigaltstack;
-struct Sigaltstack {
- void *ss_sp;
- int32 ss_flags;
- uint32 ss_size;
-};
-
-typedef struct Sigcontext Sigcontext;
-struct Sigcontext {
- uint16 gs;
- uint16 __gsh;
- uint16 fs;
- uint16 __fsh;
- uint16 es;
- uint16 __esh;
- uint16 ds;
- uint16 __dsh;
- uint32 edi;
- uint32 esi;
- uint32 ebp;
- uint32 esp;
- uint32 ebx;
- uint32 edx;
- uint32 ecx;
- uint32 eax;
- uint32 trapno;
- uint32 err;
- uint32 eip;
- uint16 cs;
- uint16 __csh;
- uint32 eflags;
- uint32 esp_at_signal;
- uint16 ss;
- uint16 __ssh;
- Fpstate *fpstate;
- uint32 oldmask;
- uint32 cr2;
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
- uint32 uc_flags;
- Ucontext *uc_link;
- Sigaltstack uc_stack;
- Sigcontext uc_mcontext;
- uint32 uc_sigmask;
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-#pragma pack off
diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h
deleted file mode 100644
index 8053dd16f..000000000
--- a/src/pkg/runtime/linux/amd64/defs.h
+++ /dev/null
@@ -1,236 +0,0 @@
-// godefs -f -m64 defs.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-enum {
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x20,
- MAP_PRIVATE = 0x2,
- MAP_FIXED = 0x10,
- SA_RESTART = 0x10000000,
- SA_ONSTACK = 0x8000000,
- SA_RESTORER = 0x4000000,
- SA_SIGINFO = 0x4,
- SIGHUP = 0x1,
- SIGINT = 0x2,
- SIGQUIT = 0x3,
- SIGILL = 0x4,
- SIGTRAP = 0x5,
- SIGABRT = 0x6,
- SIGBUS = 0x7,
- SIGFPE = 0x8,
- SIGKILL = 0x9,
- SIGUSR1 = 0xa,
- SIGSEGV = 0xb,
- SIGUSR2 = 0xc,
- SIGPIPE = 0xd,
- SIGALRM = 0xe,
- SIGSTKFLT = 0x10,
- SIGCHLD = 0x11,
- SIGCONT = 0x12,
- SIGSTOP = 0x13,
- SIGTSTP = 0x14,
- SIGTTIN = 0x15,
- SIGTTOU = 0x16,
- SIGURG = 0x17,
- SIGXCPU = 0x18,
- SIGXFSZ = 0x19,
- SIGVTALRM = 0x1a,
- SIGPROF = 0x1b,
- SIGWINCH = 0x1c,
- SIGIO = 0x1d,
- SIGPWR = 0x1e,
- SIGSYS = 0x1f,
- FPE_INTDIV = 0x1,
- FPE_INTOVF = 0x2,
- FPE_FLTDIV = 0x3,
- FPE_FLTOVF = 0x4,
- FPE_FLTUND = 0x5,
- FPE_FLTRES = 0x6,
- FPE_FLTINV = 0x7,
- FPE_FLTSUB = 0x8,
- BUS_ADRALN = 0x1,
- BUS_ADRERR = 0x2,
- BUS_OBJERR = 0x3,
- SEGV_MAPERR = 0x1,
- SEGV_ACCERR = 0x2,
- ITIMER_REAL = 0,
- ITIMER_VIRTUAL = 0x1,
- ITIMER_PROF = 0x2,
- O_RDONLY = 0,
- O_CLOEXEC = 02000000,
-};
-
-// Types
-#pragma pack on
-
-typedef struct Timespec Timespec;
-struct Timespec {
- int64 tv_sec;
- int64 tv_nsec;
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
- int64 tv_sec;
- int64 tv_usec;
-};
-
-typedef struct Sigaction Sigaction;
-struct Sigaction {
- void *sa_handler;
- uint64 sa_flags;
- void *sa_restorer;
- uint64 sa_mask;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
- int32 si_signo;
- int32 si_errno;
- int32 si_code;
- byte pad_godefs_0[4];
- byte _sifields[112];
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
- Timeval it_interval;
- Timeval it_value;
-};
-#pragma pack off
-// godefs -f -m64 defs1.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-
-// Types
-#pragma pack on
-
-typedef struct Usigset Usigset;
-struct Usigset {
- uint64 __val[16];
-};
-
-typedef struct Fpxreg Fpxreg;
-struct Fpxreg {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-
-typedef struct Xmmreg Xmmreg;
-struct Xmmreg {
- uint32 element[4];
-};
-
-typedef struct Fpstate Fpstate;
-struct Fpstate {
- uint16 cwd;
- uint16 swd;
- uint16 ftw;
- uint16 fop;
- uint64 rip;
- uint64 rdp;
- uint32 mxcsr;
- uint32 mxcr_mask;
- Fpxreg _st[8];
- Xmmreg _xmm[16];
- uint32 padding[24];
-};
-
-typedef struct Fpxreg1 Fpxreg1;
-struct Fpxreg1 {
- uint16 significand[4];
- uint16 exponent;
- uint16 padding[3];
-};
-
-typedef struct Xmmreg1 Xmmreg1;
-struct Xmmreg1 {
- uint32 element[4];
-};
-
-typedef struct Fpstate1 Fpstate1;
-struct Fpstate1 {
- uint16 cwd;
- uint16 swd;
- uint16 ftw;
- uint16 fop;
- uint64 rip;
- uint64 rdp;
- uint32 mxcsr;
- uint32 mxcr_mask;
- Fpxreg1 _st[8];
- Xmmreg1 _xmm[16];
- uint32 padding[24];
-};
-
-typedef struct Fpreg1 Fpreg1;
-struct Fpreg1 {
- uint16 significand[4];
- uint16 exponent;
-};
-
-typedef struct Sigaltstack Sigaltstack;
-struct Sigaltstack {
- void *ss_sp;
- int32 ss_flags;
- byte pad_godefs_0[4];
- uint64 ss_size;
-};
-
-typedef struct Mcontext Mcontext;
-struct Mcontext {
- int64 gregs[23];
- Fpstate *fpregs;
- uint64 __reserved1[8];
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
- uint64 uc_flags;
- Ucontext *uc_link;
- Sigaltstack uc_stack;
- Mcontext uc_mcontext;
- Usigset uc_sigmask;
- Fpstate __fpregs_mem;
-};
-
-typedef struct Sigcontext Sigcontext;
-struct Sigcontext {
- uint64 r8;
- uint64 r9;
- uint64 r10;
- uint64 r11;
- uint64 r12;
- uint64 r13;
- uint64 r14;
- uint64 r15;
- uint64 rdi;
- uint64 rsi;
- uint64 rbp;
- uint64 rbx;
- uint64 rdx;
- uint64 rax;
- uint64 rcx;
- uint64 rsp;
- uint64 rip;
- uint64 eflags;
- uint16 cs;
- uint16 gs;
- uint16 fs;
- uint16 __pad0;
- uint64 err;
- uint64 trapno;
- uint64 oldmask;
- uint64 cr2;
- Fpstate1 *fpstate;
- uint64 __reserved1[8];
-};
-#pragma pack off
diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c
deleted file mode 100644
index 5dda78789..000000000
--- a/src/pkg/runtime/linux/defs.c
+++ /dev/null
@@ -1,95 +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.
-
-/*
- * Input to godefs
- godefs -f -m64 defs.c >amd64/defs.h
- godefs -f -m64 defs1.c >>amd64/defs.h
- */
-
-// Linux glibc and Linux kernel define different and conflicting
-// definitions for struct sigaction, struct timespec, etc.
-// We want the kernel ones, which are in the asm/* headers.
-// But then we'd get conflicts when we include the system
-// headers for things like ucontext_t, so that happens in
-// a separate file, defs1.c.
-
-#include <asm/posix_types.h>
-#define size_t __kernel_size_t
-#include <asm/signal.h>
-#include <asm/siginfo.h>
-#include <asm/mman.h>
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANONYMOUS,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
- $SA_RESTORER = SA_RESTORER,
- $SA_SIGINFO = SA_SIGINFO,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGBUS = SIGBUS,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGUSR1 = SIGUSR1,
- $SIGSEGV = SIGSEGV,
- $SIGUSR2 = SIGUSR2,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGSTKFLT = SIGSTKFLT,
- $SIGCHLD = SIGCHLD,
- $SIGCONT = SIGCONT,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGURG = SIGURG,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGIO = SIGIO,
- $SIGPWR = SIGPWR,
- $SIGSYS = SIGSYS,
-
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
-
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
- $ITIMER_PROF = ITIMER_PROF,
-};
-
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-typedef struct sigaction $Sigaction;
-typedef siginfo_t $Siginfo;
-typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/linux/defs1.c b/src/pkg/runtime/linux/defs1.c
deleted file mode 100644
index e737f8e9e..000000000
--- a/src/pkg/runtime/linux/defs1.c
+++ /dev/null
@@ -1,24 +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.
-
-/*
- * Input to godefs
- godefs -f -m64 defs.c >amd64/defs.h
- godefs -f -m64 defs1.c >>amd64/defs.h
- */
-
-#include <ucontext.h>
-
-typedef __sigset_t $Usigset;
-typedef struct _libc_fpxreg $Fpxreg;
-typedef struct _libc_xmmreg $Xmmreg;
-typedef struct _libc_fpstate $Fpstate;
-typedef struct _fpxreg $Fpxreg1;
-typedef struct _xmmreg $Xmmreg1;
-typedef struct _fpstate $Fpstate1;
-typedef struct _fpreg $Fpreg1;
-typedef struct sigaltstack $Sigaltstack;
-typedef mcontext_t $Mcontext;
-typedef ucontext_t $Ucontext;
-typedef struct sigcontext $Sigcontext;
diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c
deleted file mode 100644
index ff641fff2..000000000
--- a/src/pkg/runtime/linux/defs2.c
+++ /dev/null
@@ -1,120 +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.
-
-/*
- * Input to godefs
- godefs -f -m32 \
- -f -I/home/rsc/pub/linux-2.6/arch/x86/include \
- -f -I/home/rsc/pub/linux-2.6/include \
- -f -D_LOOSE_KERNEL_NAMES \
- -f -D__ARCH_SI_UID_T'='__kernel_uid32_t \
- defs2.c >386/defs.h
-
- * The asm header tricks we have to use for Linux on amd64
- * (see defs.c and defs1.c) don't work here, so this is yet another
- * file. Sigh.
- */
-
-#include <asm/signal.h>
-#include <asm/mman.h>
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-#include <asm/siginfo.h>
-
-/*
-#include <sys/signal.h>
-#include <sys/mman.h>
-#include <ucontext.h>
-*/
-
-/* This is the sigaction structure from the Linux 2.1.68 kernel which
- is used with the rt_sigaction system call. For 386 this is not
- defined in any public header file. */
-
-struct kernel_sigaction {
- __sighandler_t k_sa_handler;
- unsigned long sa_flags;
- void (*sa_restorer) (void);
- sigset_t sa_mask;
-};
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANONYMOUS,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
- $SA_RESTORER = SA_RESTORER,
- $SA_SIGINFO = SA_SIGINFO,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGBUS = SIGBUS,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGUSR1 = SIGUSR1,
- $SIGSEGV = SIGSEGV,
- $SIGUSR2 = SIGUSR2,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGSTKFLT = SIGSTKFLT,
- $SIGCHLD = SIGCHLD,
- $SIGCONT = SIGCONT,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGURG = SIGURG,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGIO = SIGIO,
- $SIGPWR = SIGPWR,
- $SIGSYS = SIGSYS,
-
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
-
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
- $ITIMER_PROF = ITIMER_PROF,
-};
-
-typedef struct _fpreg $Fpreg;
-typedef struct _fpxreg $Fpxreg;
-typedef struct _xmmreg $Xmmreg;
-typedef struct _fpstate $Fpstate;
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-typedef struct kernel_sigaction $Sigaction;
-typedef siginfo_t $Siginfo;
-typedef struct sigaltstack $Sigaltstack;
-typedef struct sigcontext $Sigcontext;
-typedef struct ucontext $Ucontext;
-typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c
deleted file mode 100644
index 1f935046e..000000000
--- a/src/pkg/runtime/linux/defs_arm.c
+++ /dev/null
@@ -1,122 +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.
-
-/*
- * Input to godefs
- * On a Debian Lenny arm linux distribution:
- godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c
- */
-
-#define __ARCH_SI_UID_T int
-
-#include <asm/signal.h>
-#include <asm/mman.h>
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-#include <asm/siginfo.h>
-#include <linux/time.h>
-
-/*
-#include <sys/signal.h>
-#include <sys/mman.h>
-#include <ucontext.h>
-*/
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANONYMOUS,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
- $SA_RESTORER = SA_RESTORER,
- $SA_SIGINFO = SA_SIGINFO,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGBUS = SIGBUS,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGUSR1 = SIGUSR1,
- $SIGSEGV = SIGSEGV,
- $SIGUSR2 = SIGUSR2,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGSTKFLT = SIGSTKFLT,
- $SIGCHLD = SIGCHLD,
- $SIGCONT = SIGCONT,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGURG = SIGURG,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGIO = SIGIO,
- $SIGPWR = SIGPWR,
- $SIGSYS = SIGSYS,
-
- $FPE_INTDIV = FPE_INTDIV & 0xFFFF,
- $FPE_INTOVF = FPE_INTOVF & 0xFFFF,
- $FPE_FLTDIV = FPE_FLTDIV & 0xFFFF,
- $FPE_FLTOVF = FPE_FLTOVF & 0xFFFF,
- $FPE_FLTUND = FPE_FLTUND & 0xFFFF,
- $FPE_FLTRES = FPE_FLTRES & 0xFFFF,
- $FPE_FLTINV = FPE_FLTINV & 0xFFFF,
- $FPE_FLTSUB = FPE_FLTSUB & 0xFFFF,
-
- $BUS_ADRALN = BUS_ADRALN & 0xFFFF,
- $BUS_ADRERR = BUS_ADRERR & 0xFFFF,
- $BUS_OBJERR = BUS_OBJERR & 0xFFFF,
-
- $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF,
- $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_PROF = ITIMER_PROF,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
-};
-
-typedef sigset_t $Sigset;
-typedef struct timespec $Timespec;
-typedef struct sigaltstack $Sigaltstack;
-typedef struct sigcontext $Sigcontext;
-typedef struct ucontext $Ucontext;
-typedef struct timeval $Timeval;
-typedef struct itimerval $Itimerval;
-
-struct xsiginfo {
- int si_signo;
- int si_errno;
- int si_code;
- char _sifields[4];
-};
-
-typedef struct xsiginfo $Siginfo;
-
-#undef sa_handler
-#undef sa_flags
-#undef sa_restorer
-#undef sa_mask
-
-struct xsigaction {
- void (*sa_handler)(void);
- unsigned long sa_flags;
- void (*sa_restorer)(void);
- unsigned int sa_mask; /* mask last for extensibility */
-};
-
-typedef struct xsigaction $Sigaction;
diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h
deleted file mode 100644
index 919b80ea2..000000000
--- a/src/pkg/runtime/linux/signals.h
+++ /dev/null
@@ -1,51 +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.
-
-#define C SigCatch
-#define I SigIgnore
-#define R SigRestart
-#define Q SigQueue
-#define P SigPanic
-
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ Q+R, "SIGHUP: terminal line hangup",
- /* 2 */ Q+R, "SIGINT: interrupt",
- /* 3 */ C, "SIGQUIT: quit",
- /* 4 */ C+P, "SIGILL: illegal instruction",
- /* 5 */ C, "SIGTRAP: trace trap",
- /* 6 */ C, "SIGABRT: abort",
- /* 7 */ C+P, "SIGBUS: bus error",
- /* 8 */ C+P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ Q+I+R, "SIGUSR1: user-defined signal 1",
- /* 11 */ C+P, "SIGSEGV: segmentation violation",
- /* 12 */ Q+I+R, "SIGUSR2: user-defined signal 2",
- /* 13 */ I, "SIGPIPE: write to broken pipe",
- /* 14 */ Q+I+R, "SIGALRM: alarm clock",
- /* 15 */ Q+R, "SIGTERM: termination",
- /* 16 */ C, "SIGSTKFLT: stack fault",
- /* 17 */ Q+I+R, "SIGCHLD: child status has changed",
- /* 18 */ 0, "SIGCONT: continue",
- /* 19 */ 0, "SIGSTOP: stop, unblockable",
- /* 20 */ Q+I+R, "SIGTSTP: keyboard stop",
- /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
- /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
- /* 23 */ Q+I+R, "SIGURG: urgent condition on socket",
- /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
- /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
- /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
- /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
- /* 28 */ Q+I+R, "SIGWINCH: window size change",
- /* 29 */ Q+I+R, "SIGIO: i/o now possible",
- /* 30 */ Q+I+R, "SIGPWR: power failure restart",
- /* 31 */ C, "SIGSYS: bad system call",
-};
-#undef C
-#undef I
-#undef R
-#undef Q
-#undef P
-
-#define NSIG 32
diff --git a/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c
new file mode 100644
index 000000000..b4465bff1
--- /dev/null
+++ b/src/pkg/runtime/lock_futex.c
@@ -0,0 +1,156 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd linux
+
+#include "runtime.h"
+
+// This implementation depends on OS-specific implementations of
+//
+// runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//
+// runtime·futexwakeup(uint32 *addr, uint32 cnt)
+// If any procs are sleeping on addr, wake up at most cnt.
+
+enum
+{
+ MUTEX_UNLOCKED = 0,
+ MUTEX_LOCKED = 1,
+ MUTEX_SLEEPING = 2,
+
+ ACTIVE_SPIN = 4,
+ ACTIVE_SPIN_CNT = 30,
+ PASSIVE_SPIN = 1,
+};
+
+// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
+// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
+// Note that there can be spinning threads during all states - they do not
+// affect mutex's state.
+void
+runtime·lock(Lock *l)
+{
+ uint32 i, v, wait, spin;
+
+ if(m->locks++ < 0)
+ runtime·throw("runtime·lock: lock count");
+
+ // Speculative grab for lock.
+ v = runtime·xchg(&l->key, MUTEX_LOCKED);
+ if(v == MUTEX_UNLOCKED)
+ return;
+
+ // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
+ // depending on whether there is a thread sleeping
+ // on this mutex. If we ever change l->key from
+ // MUTEX_SLEEPING to some other value, we must be
+ // careful to change it back to MUTEX_SLEEPING before
+ // returning, to ensure that the sleeping thread gets
+ // its wakeup call.
+ wait = v;
+
+ // On uniprocessor's, no point spinning.
+ // On multiprocessors, spin for ACTIVE_SPIN attempts.
+ spin = 0;
+ if(runtime·ncpu > 1)
+ spin = ACTIVE_SPIN;
+
+ for(;;) {
+ // Try for lock, spinning.
+ for(i = 0; i < spin; i++) {
+ while(l->key == MUTEX_UNLOCKED)
+ if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ return;
+ runtime·procyield(ACTIVE_SPIN_CNT);
+ }
+
+ // Try for lock, rescheduling.
+ for(i=0; i < PASSIVE_SPIN; i++) {
+ while(l->key == MUTEX_UNLOCKED)
+ if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ return;
+ runtime·osyield();
+ }
+
+ // Sleep.
+ v = runtime·xchg(&l->key, MUTEX_SLEEPING);
+ if(v == MUTEX_UNLOCKED)
+ return;
+ wait = MUTEX_SLEEPING;
+ runtime·futexsleep(&l->key, MUTEX_SLEEPING, -1);
+ }
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ uint32 v;
+
+ if(--m->locks < 0)
+ runtime·throw("runtime·unlock: lock count");
+
+ v = runtime·xchg(&l->key, MUTEX_UNLOCKED);
+ if(v == MUTEX_UNLOCKED)
+ runtime·throw("unlock of unlocked lock");
+ if(v == MUTEX_SLEEPING)
+ runtime·futexwakeup(&l->key, 1);
+}
+
+// One-time notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->key = 0;
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ runtime·xchg(&n->key, 1);
+ runtime·futexwakeup(&n->key, 1);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ if(m->profilehz > 0)
+ runtime·setprof(false);
+ while(runtime·atomicload(&n->key) == 0)
+ runtime·futexsleep(&n->key, 0, -1);
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+}
+
+void
+runtime·notetsleep(Note *n, int64 ns)
+{
+ int64 deadline, now;
+
+ if(ns < 0) {
+ runtime·notesleep(n);
+ return;
+ }
+
+ if(runtime·atomicload(&n->key) != 0)
+ return;
+
+ if(m->profilehz > 0)
+ runtime·setprof(false);
+ deadline = runtime·nanotime() + ns;
+ for(;;) {
+ runtime·futexsleep(&n->key, 0, ns);
+ if(runtime·atomicload(&n->key) != 0)
+ break;
+ now = runtime·nanotime();
+ if(now >= deadline)
+ break;
+ ns = deadline - now;
+ }
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+}
diff --git a/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c
new file mode 100644
index 000000000..1d9c37fdb
--- /dev/null
+++ b/src/pkg/runtime/lock_sema.c
@@ -0,0 +1,230 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin netbsd openbsd plan9 windows
+
+#include "runtime.h"
+
+// This implementation depends on OS-specific implementations of
+//
+// uintptr runtime·semacreate(void)
+// Create a semaphore, which will be assigned to m->waitsema.
+// The zero value is treated as absence of any semaphore,
+// so be sure to return a non-zero value.
+//
+// int32 runtime·semasleep(int64 ns)
+// If ns < 0, acquire m->waitsema and return 0.
+// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
+// Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
+//
+// int32 runtime·semawakeup(M *mp)
+// Wake up mp, which is or will soon be sleeping on mp->waitsema.
+//
+
+enum
+{
+ LOCKED = 1,
+
+ ACTIVE_SPIN = 4,
+ ACTIVE_SPIN_CNT = 30,
+ PASSIVE_SPIN = 1,
+};
+
+void
+runtime·lock(Lock *l)
+{
+ uintptr v;
+ uint32 i, spin;
+
+ if(m->locks++ < 0)
+ runtime·throw("runtime·lock: lock count");
+
+ // Speculative grab for lock.
+ if(runtime·casp(&l->waitm, nil, (void*)LOCKED))
+ return;
+
+ if(m->waitsema == 0)
+ m->waitsema = runtime·semacreate();
+
+ // On uniprocessor's, no point spinning.
+ // On multiprocessors, spin for ACTIVE_SPIN attempts.
+ spin = 0;
+ if(runtime·ncpu > 1)
+ spin = ACTIVE_SPIN;
+
+ for(i=0;; i++) {
+ v = (uintptr)runtime·atomicloadp(&l->waitm);
+ if((v&LOCKED) == 0) {
+unlocked:
+ if(runtime·casp(&l->waitm, (void*)v, (void*)(v|LOCKED)))
+ return;
+ i = 0;
+ }
+ if(i<spin)
+ runtime·procyield(ACTIVE_SPIN_CNT);
+ else if(i<spin+PASSIVE_SPIN)
+ runtime·osyield();
+ else {
+ // Someone else has it.
+ // l->waitm points to a linked list of M's waiting
+ // for this lock, chained through m->nextwaitm.
+ // Queue this M.
+ for(;;) {
+ m->nextwaitm = (void*)(v&~LOCKED);
+ if(runtime·casp(&l->waitm, (void*)v, (void*)((uintptr)m|LOCKED)))
+ break;
+ v = (uintptr)runtime·atomicloadp(&l->waitm);
+ if((v&LOCKED) == 0)
+ goto unlocked;
+ }
+ if(v&LOCKED) {
+ // Queued. Wait.
+ runtime·semasleep(-1);
+ i = 0;
+ }
+ }
+ }
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ uintptr v;
+ M *mp;
+
+ if(--m->locks < 0)
+ runtime·throw("runtime·unlock: lock count");
+
+ for(;;) {
+ v = (uintptr)runtime·atomicloadp(&l->waitm);
+ if(v == LOCKED) {
+ if(runtime·casp(&l->waitm, (void*)LOCKED, nil))
+ break;
+ } else {
+ // Other M's are waiting for the lock.
+ // Dequeue an M.
+ mp = (void*)(v&~LOCKED);
+ if(runtime·casp(&l->waitm, (void*)v, mp->nextwaitm)) {
+ // Dequeued an M. Wake it.
+ runtime·semawakeup(mp);
+ break;
+ }
+ }
+ }
+}
+
+// One-time notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->waitm = nil;
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ M *mp;
+
+ do
+ mp = runtime·atomicloadp(&n->waitm);
+ while(!runtime·casp(&n->waitm, mp, (void*)LOCKED));
+
+ // Successfully set waitm to LOCKED.
+ // What was it before?
+ if(mp == nil) {
+ // Nothing was waiting. Done.
+ } else if(mp == (M*)LOCKED) {
+ // Two notewakeups! Not allowed.
+ runtime·throw("notewakeup - double wakeup");
+ } else {
+ // Must be the waiting m. Wake it up.
+ runtime·semawakeup(mp);
+ }
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ if(m->waitsema == 0)
+ m->waitsema = runtime·semacreate();
+ if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup)
+ if(n->waitm != (void*)LOCKED)
+ runtime·throw("notesleep - waitm out of sync");
+ return;
+ }
+ // Queued. Sleep.
+ if(m->profilehz > 0)
+ runtime·setprof(false);
+ runtime·semasleep(-1);
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+}
+
+void
+runtime·notetsleep(Note *n, int64 ns)
+{
+ M *mp;
+ int64 deadline, now;
+
+ if(ns < 0) {
+ runtime·notesleep(n);
+ return;
+ }
+
+ if(m->waitsema == 0)
+ m->waitsema = runtime·semacreate();
+
+ // Register for wakeup on n->waitm.
+ if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup already)
+ if(n->waitm != (void*)LOCKED)
+ runtime·throw("notetsleep - waitm out of sync");
+ return;
+ }
+
+ if(m->profilehz > 0)
+ runtime·setprof(false);
+ deadline = runtime·nanotime() + ns;
+ for(;;) {
+ // Registered. Sleep.
+ if(runtime·semasleep(ns) >= 0) {
+ // Acquired semaphore, semawakeup unregistered us.
+ // Done.
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+ return;
+ }
+
+ // Interrupted or timed out. Still registered. Semaphore not acquired.
+ now = runtime·nanotime();
+ if(now >= deadline)
+ break;
+
+ // Deadline hasn't arrived. Keep sleeping.
+ ns = deadline - now;
+ }
+
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+
+ // Deadline arrived. Still registered. Semaphore not acquired.
+ // Want to give up and return, but have to unregister first,
+ // so that any notewakeup racing with the return does not
+ // try to grant us the semaphore when we don't expect it.
+ for(;;) {
+ mp = runtime·atomicloadp(&n->waitm);
+ if(mp == m) {
+ // No wakeup yet; unregister if possible.
+ if(runtime·casp(&n->waitm, mp, nil))
+ return;
+ } else if(mp == (M*)LOCKED) {
+ // Wakeup happened so semaphore is available.
+ // Grab it to avoid getting out of sync.
+ if(runtime·semasleep(-1) < 0)
+ runtime·throw("runtime: unable to acquire - semaphore out of sync");
+ return;
+ } else {
+ runtime·throw("runtime: unexpected waitm - semaphore out of sync");
+ }
+ }
+}
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index b9fe36db6..fbdd6bb02 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -8,12 +8,15 @@
package runtime
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "stack.h"
#include "malloc.h"
-#include "defs.h"
+#include "defs_GOOS_GOARCH.h"
#include "type.h"
+#pragma dataflag 16 /* mark mheap as 'no pointers', hiding from garbage collector */
MHeap runtime·mheap;
+
extern MStats mstats; // defined in extern.go
extern volatile int32 runtime·MemProfileRate;
@@ -80,11 +83,12 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
m->mcache->next_sample -= size;
else {
// pick next profile time
+ // If you change this, also change allocmcache.
if(rate > 0x3fffffff) // make 2*rate not overflow
rate = 0x3fffffff;
m->mcache->next_sample = runtime·fastrand1() % (2*rate);
profile:
- runtime·setblockspecial(v);
+ runtime·setblockspecial(v, true);
runtime·MProf_Malloc(v, size);
}
}
@@ -113,7 +117,7 @@ runtime·free(void *v)
if(v == nil)
return;
- // If you change this also change mgc0.c:/^sweepspan,
+ // If you change this also change mgc0.c:/^sweep,
// which has a copy of the guts of free.
if(m->mallocing)
@@ -205,6 +209,7 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
MCache*
runtime·allocmcache(void)
{
+ int32 rate;
MCache *c;
runtime·lock(&runtime·mheap);
@@ -212,6 +217,14 @@ runtime·allocmcache(void)
mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
mstats.mcache_sys = runtime·mheap.cachealloc.sys;
runtime·unlock(&runtime·mheap);
+
+ // Set first allocation sample size.
+ rate = runtime·MemProfileRate;
+ if(rate > 0x3fffffff) // make 2*rate not overflow
+ rate = 0x3fffffff;
+ if(rate != 0)
+ c->next_sample = runtime·fastrand1() % (2*rate);
+
return c;
}
@@ -248,13 +261,26 @@ runtime·mallocinit(void)
byte *p;
uintptr arena_size, bitmap_size;
extern byte end[];
+ byte *want;
+ uintptr limit;
+
+ p = nil;
+ arena_size = 0;
+ bitmap_size = 0;
+
+ // for 64-bit build
+ USED(p);
+ USED(arena_size);
+ USED(bitmap_size);
runtime·InitSizes();
+ limit = runtime·memlimit();
+
// Set up the allocation arena, a contiguous area of memory where
// allocated data will be found. The arena begins with a bitmap large
// enough to hold 4 bits per allocated word.
- if(sizeof(void*) == 8) {
+ if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
// On a 64-bit machine, allocate from a single contiguous reservation.
// 16 GB should be big enough for now.
//
@@ -277,12 +303,13 @@ runtime·mallocinit(void)
// Actually we reserve 17 GB (because the bitmap ends up being 1 GB)
// but it hardly matters: fc is not valid UTF-8 either, and we have to
// allocate 15 GB before we get that far.
+ //
+ // If this fails we fall back to the 32 bit memory mechanism
arena_size = 16LL<<30;
bitmap_size = arena_size / (sizeof(void*)*8/4);
p = runtime·SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size);
- if(p == nil)
- runtime·throw("runtime: cannot reserve arena virtual address space");
- } else {
+ }
+ if (p == nil) {
// On a 32-bit machine, we can't typically get away
// with a giant virtual address space reservation.
// Instead we map the memory information bitmap
@@ -302,16 +329,26 @@ runtime·mallocinit(void)
// of address space, which is probably too much in a 32-bit world.
bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
arena_size = 512<<20;
+ if(limit > 0 && arena_size+bitmap_size > limit) {
+ bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
+ arena_size = bitmap_size * 8;
+ }
// SysReserve treats the address we ask for, end, as a hint,
// not as an absolute requirement. If we ask for the end
// of the data segment but the operating system requires
// a little more space before we can start allocating, it will
- // give out a slightly higher pointer. That's fine.
- // Run with what we get back.
- p = runtime·SysReserve(end, bitmap_size + arena_size);
+ // give out a slightly higher pointer. Except QEMU, which
+ // is buggy, as usual: it won't adjust the pointer upward.
+ // So adjust it upward a little bit ourselves: 1/4 MB to get
+ // away from the running binary image and then round up
+ // to a MB boundary.
+ want = (byte*)(((uintptr)end + (1<<18) + (1<<20) - 1)&~((1<<20)-1));
+ p = runtime·SysReserve(want, bitmap_size + arena_size);
if(p == nil)
runtime·throw("runtime: cannot reserve arena virtual address space");
+ if((uintptr)p & (((uintptr)1<<PageShift)-1))
+ runtime·printf("runtime: SysReserve returned unaligned address %p; asked for %p", p, bitmap_size+arena_size);
}
if((uintptr)p & (((uintptr)1<<PageShift)-1))
runtime·throw("runtime: SysReserve returned unaligned address");
@@ -334,6 +371,22 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
{
byte *p;
+ if(n > h->arena_end - h->arena_used) {
+ // We are in 32-bit mode, maybe we didn't use all possible address space yet.
+ // Reserve some more space.
+ byte *new_end;
+ uintptr needed;
+
+ needed = (uintptr)h->arena_used + n - (uintptr)h->arena_end;
+ // Round wanted arena size to a multiple of 256MB.
+ needed = (needed + (256<<20) - 1) & ~((256<<20)-1);
+ new_end = h->arena_end + needed;
+ if(new_end <= h->arena_start + MaxArena32) {
+ p = runtime·SysReserve(h->arena_end, new_end - h->arena_end);
+ if(p == h->arena_end)
+ h->arena_end = new_end;
+ }
+ }
if(n <= h->arena_end - h->arena_used) {
// Keep taking from our reservation.
p = h->arena_used;
@@ -343,8 +396,8 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
return p;
}
- // On 64-bit, our reservation is all we have.
- if(sizeof(void*) == 8)
+ // If using 64-bit, our reservation is all we have.
+ if(sizeof(void*) == 8 && (uintptr)h->bitmap >= 0xffffffffU)
return nil;
// On 32-bit, once the reservation is gone we can
@@ -355,7 +408,8 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
return nil;
if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
- runtime·printf("runtime: memory allocated by OS not in usable range\n");
+ runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
+ p, h->arena_start, h->arena_start+MaxArena32);
runtime·SysFree(p, n);
return nil;
}
@@ -378,8 +432,10 @@ runtime·mal(uintptr n)
return runtime·mallocgc(n, 0, 1, 1);
}
-func new(n uint32) (ret *uint8) {
- ret = runtime·mal(n);
+func new(typ *Type) (ret *uint8) {
+ uint32 flag = typ->kind&KindNoPointers ? FlagNoPointers : 0;
+ ret = runtime·mallocgc(typ->size, flag, 1, 1);
+ FLUSH(&ret);
}
void*
@@ -418,18 +474,6 @@ runtime·stackfree(void *v, uintptr n)
runtime·free(v);
}
-func Alloc(n uintptr) (p *byte) {
- p = runtime·malloc(n);
-}
-
-func Free(p *byte) {
- runtime·free(p);
-}
-
-func Lookup(p *byte) (base *byte, size uintptr) {
- runtime·mlookup(p, &base, &size, nil);
-}
-
func GC() {
runtime·gc(1);
}
@@ -443,8 +487,7 @@ func SetFinalizer(obj Eface, finalizer Eface) {
if(obj.type == nil) {
runtime·printf("runtime.SetFinalizer: first argument is nil interface\n");
- throw:
- runtime·throw("runtime.SetFinalizer");
+ goto throw;
}
if(obj.type->kind != KindPtr) {
runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
@@ -456,11 +499,8 @@ func SetFinalizer(obj Eface, finalizer Eface) {
}
nret = 0;
if(finalizer.type != nil) {
- if(finalizer.type->kind != KindFunc) {
- badfunc:
- runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
- goto throw;
- }
+ if(finalizer.type->kind != KindFunc)
+ goto badfunc;
ft = (FuncType*)finalizer.type;
if(ft->dotdotdot || ft->in.len != 1 || *(Type**)ft->in.array != obj.type)
goto badfunc;
@@ -472,11 +512,16 @@ func SetFinalizer(obj Eface, finalizer Eface) {
nret += t->size;
}
nret = (nret + sizeof(void*)-1) & ~(sizeof(void*)-1);
-
- if(runtime·getfinalizer(obj.data, 0)) {
- runtime·printf("runtime.SetFinalizer: finalizer already set\n");
- goto throw;
- }
}
- runtime·addfinalizer(obj.data, finalizer.data, nret);
+
+ if(!runtime·addfinalizer(obj.data, finalizer.data, nret)) {
+ runtime·printf("runtime.SetFinalizer: finalizer already set\n");
+ goto throw;
+ }
+ return;
+
+badfunc:
+ runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+throw:
+ runtime·throw("runtime.SetFinalizer");
}
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 5bc80f4df..d846f6810 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -120,6 +120,12 @@ enum
#else
MHeapMap_Bits = 20,
#endif
+
+ // Max number of threads to run garbage collection.
+ // 2, 3, and 4 are all plausible maximums depending
+ // on the hardware details of the machine. The garbage
+ // collector scales well to 4 cpus.
+ MaxGcproc = 4,
};
// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
@@ -192,13 +198,14 @@ struct MStats
uint64 nlookup; // number of pointer lookups
uint64 nmalloc; // number of mallocs
uint64 nfree; // number of frees
-
+
// Statistics about malloc heap.
// protected by mheap.Lock
uint64 heap_alloc; // bytes allocated and still in use
uint64 heap_sys; // bytes obtained from system
uint64 heap_idle; // bytes in idle spans
uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_released; // bytes released to the OS
uint64 heap_objects; // total number of allocated objects
// Statistics about allocation of low-level fixed-size structures.
@@ -210,16 +217,17 @@ struct MStats
uint64 mcache_inuse; // MCache structures
uint64 mcache_sys;
uint64 buckhash_sys; // profiling bucket hash table
-
+
// Statistics about garbage collector.
// Protected by stopping the world during GC.
uint64 next_gc; // next GC (in heap_alloc time)
+ uint64 last_gc; // last GC (in absolute time)
uint64 pause_total_ns;
uint64 pause_ns[256];
uint32 numgc;
bool enablegc;
bool debuggc;
-
+
// Statistics about allocation size classes.
struct {
uint32 size;
@@ -228,7 +236,7 @@ struct MStats
} by_size[NumSizeClasses];
};
-#define mstats runtime·MemStats /* name shared with Go */
+#define mstats runtime·memStats /* name shared with Go */
extern MStats mstats;
@@ -240,7 +248,7 @@ extern MStats mstats;
//
// class_to_size[i] = largest size in class i
// class_to_allocnpages[i] = number of pages to allocate when
-// making new objects in class i
+// making new objects in class i
// class_to_transfercount[i] = number of objects to move when
// taking a bunch of objects out of the central lists
// and putting them in the thread free list.
@@ -279,7 +287,7 @@ struct MCache
int64 nmalloc;
int64 nfree;
} local_by_size[NumSizeClasses];
-
+
};
void* runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
@@ -298,14 +306,16 @@ struct MSpan
{
MSpan *next; // in a span linked list
MSpan *prev; // in a span linked list
- MSpan *allnext; // in the list of all spans
+ MSpan *allnext; // in the list of all spans
PageID start; // starting page number
uintptr npages; // number of pages in span
MLink *freelist; // list of free objects
uint32 ref; // number of allocated objects in this span
uint32 sizeclass; // size class
uint32 state; // MSpanInUse etc
- byte *limit; // end of data in span
+ int64 unusedsince; // First time spotted by GC in MSpanFree state
+ uintptr npreleased; // number of pages released to the OS
+ byte *limit; // end of data in span
};
void runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
@@ -352,14 +362,14 @@ struct MHeap
byte *arena_start;
byte *arena_used;
byte *arena_end;
-
+
// central free lists for small size classes.
// the union makes sure that the MCentrals are
- // spaced 64 bytes apart, so that each MCentral.Lock
+ // spaced CacheLineSize bytes apart, so that each MCentral.Lock
// gets its own cache line.
union {
MCentral;
- byte pad[64];
+ byte pad[CacheLineSize];
} central[NumSizeClasses];
FixAlloc spanalloc; // allocator for Span*
@@ -375,6 +385,7 @@ MSpan* runtime·MHeap_LookupMaybe(MHeap *h, void *v);
void runtime·MGetSizeClassInfo(int32 sizeclass, uintptr *size, int32 *npages, int32 *nobj);
void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
void runtime·MHeap_MapBits(MHeap *h);
+void runtime·MHeap_Scavenger(void);
void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
@@ -387,7 +398,7 @@ int32 runtime·checking;
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·setblockspecial(void*, bool);
void runtime·purgecachedstats(M*);
enum
@@ -400,23 +411,9 @@ enum
void runtime·MProf_Malloc(void*, uintptr);
void runtime·MProf_Free(void*, uintptr);
+void runtime·MProf_GC(void);
+int32 runtime·helpgc(bool*);
+void runtime·gchelper(void);
-// Malloc profiling settings.
-// Must match definition in extern.go.
-enum {
- MProf_None = 0,
- MProf_Sample = 1,
- MProf_All = 2,
-};
-extern int32 runtime·malloc_profile;
-
-typedef struct Finalizer Finalizer;
-struct Finalizer
-{
- Finalizer *next; // for use by caller of getfinalizer
- void (*fn)(void*);
- void *arg;
- int32 nret;
-};
-
-Finalizer* runtime·getfinalizer(void*, bool);
+bool runtime·getfinalizer(void *p, bool del, void (**fn)(void*), int32 *nret);
+void runtime·walkfintab(void (*fn)(void*));
diff --git a/src/pkg/runtime/malloc1.go b/src/pkg/runtime/malloc1.go
new file mode 100644
index 000000000..da92f4c2f
--- /dev/null
+++ b/src/pkg/runtime/malloc1.go
@@ -0,0 +1,26 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// trivial malloc test
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+func main() {
+ memstats := new(runtime.MemStats)
+ runtime.Free(runtime.Alloc(1))
+ runtime.ReadMemStats(memstats)
+ if *chatty {
+ fmt.Printf("%+v %v\n", memstats, uint64(0))
+ }
+}
diff --git a/src/pkg/runtime/mallocrand.go b/src/pkg/runtime/mallocrand.go
new file mode 100644
index 000000000..f1bcb89cf
--- /dev/null
+++ b/src/pkg/runtime/mallocrand.go
@@ -0,0 +1,93 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Random malloc test.
+
+package main
+
+import (
+ "flag"
+ "math/rand"
+ "runtime"
+ "unsafe"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var footprint uint64
+var allocated uint64
+
+func bigger() {
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ if f := memstats.Sys; footprint < f {
+ footprint = f
+ if *chatty {
+ println("Footprint", footprint, " for ", allocated)
+ }
+ if footprint > 1e9 {
+ println("too big")
+ panic("fail")
+ }
+ }
+}
+
+// Prime the data structures by allocating one of
+// each block in order. After this, there should be
+// little reason to ask for more memory from the OS.
+func prime() {
+ for i := 0; i < 16; i++ {
+ b := runtime.Alloc(1 << uint(i))
+ runtime.Free(b)
+ }
+ for i := uintptr(0); i < 256; i++ {
+ b := runtime.Alloc(i << 12)
+ runtime.Free(b)
+ }
+}
+
+func memset(b *byte, c byte, n uintptr) {
+ np := uintptr(n)
+ for i := uintptr(0); i < np; i++ {
+ *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(b)) + i)) = c
+ }
+}
+
+func main() {
+ flag.Parse()
+ // prime()
+ var blocks [1]struct {
+ base *byte
+ siz uintptr
+ }
+ for i := 0; i < 1<<10; i++ {
+ if i%(1<<10) == 0 && *chatty {
+ println(i)
+ }
+ b := rand.Int() % len(blocks)
+ if blocks[b].base != nil {
+ // println("Free", blocks[b].siz, blocks[b].base)
+ runtime.Free(blocks[b].base)
+ blocks[b].base = nil
+ allocated -= uint64(blocks[b].siz)
+ continue
+ }
+ siz := uintptr(rand.Int() >> (11 + rand.Uint32()%20))
+ base := runtime.Alloc(siz)
+ // ptr := uintptr(syscall.BytePtr(base))+uintptr(siz/2)
+ // obj, size, ref, ok := allocator.find(ptr)
+ // if obj != base || *ref != 0 || !ok {
+ // println("find", siz, obj, ref, ok)
+ // panic("fail")
+ // }
+ blocks[b].base = base
+ blocks[b].siz = siz
+ allocated += uint64(siz)
+ // println("Alloc", siz, base)
+ memset(base, 0xbb, siz)
+ bigger()
+ }
+}
diff --git a/src/pkg/runtime/mallocrep.go b/src/pkg/runtime/mallocrep.go
new file mode 100644
index 000000000..03ee71edb
--- /dev/null
+++ b/src/pkg/runtime/mallocrep.go
@@ -0,0 +1,72 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Repeated malloc test.
+
+// +build ignore
+
+package main
+
+import (
+ "flag"
+ "runtime"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+
+var oldsys uint64
+var memstats runtime.MemStats
+
+func bigger() {
+ st := &memstats
+ runtime.ReadMemStats(st)
+ if oldsys < st.Sys {
+ oldsys = st.Sys
+ if *chatty {
+ println(st.Sys, " system bytes for ", st.Alloc, " Go bytes")
+ }
+ if st.Sys > 1e9 {
+ println("too big")
+ panic("fail")
+ }
+ }
+}
+
+func main() {
+ runtime.GC() // clean up garbage from init
+ runtime.ReadMemStats(&memstats) // first call can do some allocations
+ runtime.MemProfileRate = 0 // disable profiler
+ stacks := memstats.Alloc // ignore stacks
+ flag.Parse()
+ for i := 0; i < 1<<7; i++ {
+ for j := 1; j <= 1<<22; j <<= 1 {
+ if i == 0 && *chatty {
+ println("First alloc:", j)
+ }
+ if a := memstats.Alloc - stacks; a != 0 {
+ println("no allocations but stats report", a, "bytes allocated")
+ panic("fail")
+ }
+ b := runtime.Alloc(uintptr(j))
+ runtime.ReadMemStats(&memstats)
+ during := memstats.Alloc - stacks
+ runtime.Free(b)
+ runtime.ReadMemStats(&memstats)
+ if a := memstats.Alloc - stacks; a != 0 {
+ println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
+ panic("fail")
+ }
+ bigger()
+ }
+ if i%(1<<10) == 0 && *chatty {
+ println(i)
+ }
+ if i == 0 {
+ if *chatty {
+ println("Primed", i)
+ }
+ // runtime.frozen = true
+ }
+ }
+}
diff --git a/src/pkg/runtime/mallocrep1.go b/src/pkg/runtime/mallocrep1.go
new file mode 100644
index 000000000..41c104c0b
--- /dev/null
+++ b/src/pkg/runtime/mallocrep1.go
@@ -0,0 +1,143 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// Repeated malloc test.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "runtime"
+ "strconv"
+)
+
+var chatty = flag.Bool("v", false, "chatty")
+var reverse = flag.Bool("r", false, "reverse")
+var longtest = flag.Bool("l", false, "long test")
+
+var b []*byte
+var stats = new(runtime.MemStats)
+
+func OkAmount(size, n uintptr) bool {
+ if n < size {
+ return false
+ }
+ if size < 16*8 {
+ if n > size+16 {
+ return false
+ }
+ } else {
+ if n > size*9/8 {
+ return false
+ }
+ }
+ return true
+}
+
+func AllocAndFree(size, count int) {
+ if *chatty {
+ fmt.Printf("size=%d count=%d ...\n", size, count)
+ }
+ runtime.ReadMemStats(stats)
+ n1 := stats.Alloc
+ for i := 0; i < count; i++ {
+ b[i] = runtime.Alloc(uintptr(size))
+ base, n := runtime.Lookup(b[i])
+ if base != b[i] || !OkAmount(uintptr(size), n) {
+ println("lookup failed: got", base, n, "for", b[i])
+ panic("fail")
+ }
+ runtime.ReadMemStats(stats)
+ if stats.Sys > 1e9 {
+ println("too much memory allocated")
+ panic("fail")
+ }
+ }
+ runtime.ReadMemStats(stats)
+ n2 := stats.Alloc
+ if *chatty {
+ fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+ }
+ n3 := stats.Alloc
+ for j := 0; j < count; j++ {
+ i := j
+ if *reverse {
+ i = count - 1 - j
+ }
+ alloc := uintptr(stats.Alloc)
+ base, n := runtime.Lookup(b[i])
+ if base != b[i] || !OkAmount(uintptr(size), n) {
+ println("lookup failed: got", base, n, "for", b[i])
+ panic("fail")
+ }
+ runtime.Free(b[i])
+ runtime.ReadMemStats(stats)
+ if stats.Alloc != uint64(alloc-n) {
+ println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
+ panic("fail")
+ }
+ if stats.Sys > 1e9 {
+ println("too much memory allocated")
+ panic("fail")
+ }
+ }
+ runtime.ReadMemStats(stats)
+ n4 := stats.Alloc
+
+ if *chatty {
+ fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
+ }
+ if n2-n1 != n3-n4 {
+ println("wrong alloc count: ", n2-n1, n3-n4)
+ panic("fail")
+ }
+}
+
+func atoi(s string) int {
+ i, _ := strconv.Atoi(s)
+ return i
+}
+
+func main() {
+ runtime.MemProfileRate = 0 // disable profiler
+ flag.Parse()
+ b = make([]*byte, 10000)
+ if flag.NArg() > 0 {
+ AllocAndFree(atoi(flag.Arg(0)), atoi(flag.Arg(1)))
+ return
+ }
+ maxb := 1 << 22
+ if !*longtest {
+ maxb = 1 << 19
+ }
+ for j := 1; j <= maxb; j <<= 1 {
+ n := len(b)
+ max := uintptr(1 << 28)
+ if !*longtest {
+ max = uintptr(maxb)
+ }
+ if uintptr(j)*uintptr(n) > max {
+ n = int(max / uintptr(j))
+ }
+ if n < 10 {
+ n = 10
+ }
+ for m := 1; m <= n; {
+ AllocAndFree(j, m)
+ if m == n {
+ break
+ }
+ m = 5 * m / 4
+ if m < 4 {
+ m++
+ }
+ if m > n {
+ m = n
+ }
+ }
+ }
+}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 711e938fc..518e00c12 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -7,6 +7,7 @@
// See malloc.h for an overview.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
void*
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 29b03b58f..ff0c2d11a 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -15,6 +15,7 @@
// so that it is faster to move those lists between MCaches and MCentrals.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
static bool MCentral_Grow(MCentral *c);
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index 93d155a7f..76680086c 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -6,9 +6,9 @@ package runtime
import "unsafe"
-type MemStatsType struct {
+// A MemStats records statistics about the memory allocator.
+type MemStats struct {
// General statistics.
- // Not locked during update; approximate.
Alloc uint64 // bytes allocated and still in use
TotalAlloc uint64 // bytes allocated (even if freed)
Sys uint64 // bytes obtained from system (should be sum of XxxSys below)
@@ -17,11 +17,12 @@ type MemStatsType struct {
Frees uint64 // number of frees
// Main allocation heap statistics.
- HeapAlloc uint64 // bytes allocated and still in use
- HeapSys uint64 // bytes obtained from system
- HeapIdle uint64 // bytes in idle spans
- HeapInuse uint64 // bytes in non-idle span
- HeapObjects uint64 // total number of allocated objects
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapReleased uint64 // bytes released to the OS
+ HeapObjects uint64 // total number of allocated objects
// Low-level fixed-size structure allocator statistics.
// Inuse is bytes used now.
@@ -35,7 +36,8 @@ type MemStatsType struct {
BuckHashSys uint64 // profiling bucket hash table
// Garbage collector statistics.
- NextGC uint64
+ NextGC uint64 // next run in HeapAlloc time (bytes)
+ LastGC uint64 // last run in absolute time (ns)
PauseTotalNs uint64
PauseNs [256]uint64 // most recent GC pause times
NumGC uint32
@@ -43,7 +45,6 @@ type MemStatsType struct {
DebugGC bool
// Per-size allocation statistics.
- // Not locked during update; approximate.
// 61 is NumSizeClasses in the C code.
BySize [61]struct {
Size uint32
@@ -54,21 +55,17 @@ type MemStatsType struct {
var sizeof_C_MStats uintptr // filled in by malloc.goc
+var memStats MemStats
+
func init() {
- if sizeof_C_MStats != unsafe.Sizeof(MemStats) {
- println(sizeof_C_MStats, unsafe.Sizeof(MemStats))
+ if sizeof_C_MStats != unsafe.Sizeof(memStats) {
+ println(sizeof_C_MStats, unsafe.Sizeof(memStats))
panic("MStats vs MemStatsType size mismatch")
}
}
-// MemStats holds statistics about the memory system.
-// The statistics may be out of date, as the information is
-// updated lazily from per-thread caches.
-// Use UpdateMemStats to bring the statistics up to date.
-var MemStats MemStatsType
-
-// UpdateMemStats brings MemStats up to date.
-func UpdateMemStats()
+// ReadMemStats populates m with memory allocator statistics.
+func ReadMemStats(m *MemStats)
// GC runs a garbage collection.
func GC()
diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/mem_darwin.c
index 935c032bc..cde5601cf 100644
--- a/src/pkg/runtime/darwin/mem.c
+++ b/src/pkg/runtime/mem_darwin.c
@@ -1,6 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "malloc.h"
void*
@@ -18,9 +23,8 @@ runtime·SysAlloc(uintptr n)
void
runtime·SysUnused(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call madvise MADV_DONTNEED
+ // Linux's MADV_DONTNEED is like BSD's MADV_FREE.
+ runtime·madvise(v, n, MADV_FREE);
}
void
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/mem_freebsd.c
index 07abf2cfe..d1c22583d 100644
--- a/src/pkg/runtime/freebsd/mem.c
+++ b/src/pkg/runtime/mem_freebsd.c
@@ -1,6 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "malloc.h"
void*
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
new file mode 100644
index 000000000..b3e79cc41
--- /dev/null
+++ b/src/pkg/runtime/mem_linux.c
@@ -0,0 +1,131 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+ ENOMEM = 12,
+ _PAGE_SIZE = 4096,
+};
+
+static int32
+addrspace_free(void *v, uintptr n)
+{
+ int32 errval;
+ uintptr chunk;
+ uintptr off;
+ static byte vec[4096];
+
+ for(off = 0; off < n; off += chunk) {
+ chunk = _PAGE_SIZE * sizeof vec;
+ if(chunk > (n - off))
+ chunk = n - off;
+ errval = runtime·mincore((int8*)v + off, chunk, vec);
+ // errval is 0 if success, or -(error_code) if error.
+ if (errval == 0 || errval != -ENOMEM)
+ return 0;
+ }
+ return 1;
+}
+
+static void *
+mmap_fixed(byte *v, uintptr n, int32 prot, int32 flags, int32 fd, uint32 offset)
+{
+ void *p;
+
+ p = runtime·mmap(v, n, prot, flags, fd, offset);
+ if(p != v && addrspace_free(v, n)) {
+ // On some systems, mmap ignores v without
+ // MAP_FIXED, so retry if the address space is free.
+ if(p > (void*)4096)
+ runtime·munmap(p, n);
+ p = runtime·mmap(v, n, prot, flags|MAP_FIXED, fd, offset);
+ }
+ return p;
+}
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+ p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096) {
+ if(p == (void*)EACCES) {
+ runtime·printf("runtime: mmap: access denied\n");
+ runtime·printf("if you're running SELinux, enable execmem for this process.\n");
+ runtime·exit(2);
+ }
+ return nil;
+ }
+ return p;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ runtime·madvise(v, n, MADV_DONTNEED);
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ void *p;
+
+ // On 64-bit, people with ulimit -v set complain if we reserve too
+ // much address space. Instead, assume that the reservation is okay
+ // if we can reserve at least 64K and check the assumption in SysMap.
+ // Only user-mode Linux (UML) rejects these requests.
+ if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (p != v)
+ return nil;
+ runtime·munmap(p, 64<<10);
+ return v;
+ }
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if((uintptr)p < 4096 || -(uintptr)p < 4096)
+ return nil;
+ return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+ p = mmap_fixed(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/openbsd/mem.c b/src/pkg/runtime/mem_netbsd.c
index 07abf2cfe..34ff31d90 100644
--- a/src/pkg/runtime/openbsd/mem.c
+++ b/src/pkg/runtime/mem_netbsd.c
@@ -1,8 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "malloc.h"
+enum
+{
+ ENOMEM = 12,
+};
+
void*
runtime·SysAlloc(uintptr n)
{
@@ -33,19 +43,20 @@ runtime·SysFree(void *v, uintptr n)
void*
runtime·SysReserve(void *v, uintptr n)
{
+ void *p;
+
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
if(sizeof(void*) == 8)
return v;
-
- return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-}
-enum
-{
- ENOMEM = 12,
-};
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (p == ((void *)-ENOMEM))
+ return nil;
+ else
+ return p;
+}
void
runtime·SysMap(void *v, uintptr n)
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/mem_openbsd.c
index ad0fac6d3..34ff31d90 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/mem_openbsd.c
@@ -1,6 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "malloc.h"
enum
@@ -8,41 +13,16 @@ enum
ENOMEM = 12,
};
-static int32
-addrspace_free(void *v, uintptr n)
-{
- uintptr page_size = 4096;
- uintptr off;
- int8 one_byte;
-
- for(off = 0; off < n; off += page_size) {
- int32 errval = runtime·mincore((int8 *)v + off, page_size, (void *)&one_byte);
- // errval is 0 if success, or -(error_code) if error.
- if (errval == 0 || errval != -ENOMEM)
- return 0;
- }
- USED(v);
- USED(n);
- return 1;
-}
-
-
void*
runtime·SysAlloc(uintptr n)
{
- void *p;
+ void *v;
mstats.sys += n;
- p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096) {
- if(p == (void*)EACCES) {
- runtime·printf("runtime: mmap: access denied\n");
- runtime·printf("if you're running SELinux, enable execmem for this process.\n");
- runtime·exit(2);
- }
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
return nil;
- }
- return p;
+ return v;
}
void
@@ -70,12 +50,12 @@ runtime·SysReserve(void *v, uintptr n)
// and check the assumption in SysMap.
if(sizeof(void*) == 8)
return v;
-
+
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p < (void*)4096) {
+ if (p == ((void *)-ENOMEM))
return nil;
- }
- return p;
+ else
+ return p;
}
void
@@ -88,15 +68,7 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p != v && addrspace_free(v, n)) {
- // On some systems, mmap ignores v without
- // MAP_FIXED, so retry if the address space is free.
- if(p > (void*)4096) {
- runtime·munmap(p, n);
- }
- p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- }
- if(p == (void*)ENOMEM)
+ if(p == (void*)-ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
@@ -106,7 +78,7 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)ENOMEM)
+ if(p == (void*)-ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/mem_plan9.c
index f795b2c01..15cbc176b 100644
--- a/src/pkg/runtime/plan9/mem.c
+++ b/src/pkg/runtime/mem_plan9.c
@@ -3,8 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
-#include "os.h"
+#include "os_GOOS.h"
extern byte end[];
static byte *bloc = { end };
@@ -26,7 +27,7 @@ runtime·SysAlloc(uintptr nbytes)
bl = ((uintptr)bloc + Round) & ~Round;
if(runtime·brk_((void*)(bl + nbytes)) < 0) {
runtime·unlock(&memlock);
- return (void*)-1;
+ return nil;
}
bloc = (byte*)bl + nbytes;
runtime·unlock(&memlock);
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/mem_windows.c
index 5d2291fa3..7840daa22 100644
--- a/src/pkg/runtime/windows/mem.c
+++ b/src/pkg/runtime/mem_windows.c
@@ -3,8 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "os.h"
-#include "defs.h"
+#include "arch_GOARCH.h"
+#include "os_GOOS.h"
+#include "defs_GOOS_GOARCH.h"
#include "malloc.h"
enum {
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/memmove_386.s
index 203a8187c..203a8187c 100644
--- a/src/pkg/runtime/386/memmove.s
+++ b/src/pkg/runtime/memmove_386.s
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/memmove_amd64.s
index e78be8145..e78be8145 100644
--- a/src/pkg/runtime/amd64/memmove.s
+++ b/src/pkg/runtime/memmove_amd64.s
diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/memmove_arm.s
index 5c0e57404..5c0e57404 100644
--- a/src/pkg/runtime/arm/memmove.s
+++ b/src/pkg/runtime/memmove_arm.s
diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/memset_arm.s
index 974b8da7a..974b8da7a 100644
--- a/src/pkg/runtime/arm/memset.s
+++ b/src/pkg/runtime/memset_arm.s
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
index f3138145b..c6f2b5421 100644
--- a/src/pkg/runtime/mfinal.c
+++ b/src/pkg/runtime/mfinal.c
@@ -3,12 +3,17 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
-// Lock to protect finalizer data structures.
-// Cannot reuse mheap.Lock because the finalizer
-// maintenance requires allocation.
-static Lock finlock;
+enum { debug = 0 };
+
+typedef struct Fin Fin;
+struct Fin
+{
+ void (*fn)(void*);
+ int32 nret;
+};
// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
// Table size is power of 3 so that hash can be key % max.
@@ -20,15 +25,24 @@ static Lock finlock;
typedef struct Fintab Fintab;
struct Fintab
{
+ Lock;
void **key;
- Finalizer **val;
+ Fin *val;
int32 nkey; // number of non-nil entries in key
int32 ndead; // number of dead (-1) entries in key
int32 max; // size of key, val allocations
};
+#define TABSZ 17
+#define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ])
+
+static struct {
+ Fintab;
+ uint8 pad[CacheLineSize - sizeof(Fintab)];
+} fintab[TABSZ];
+
static void
-addfintab(Fintab *t, void *k, Finalizer *v)
+addfintab(Fintab *t, void *k, void (*fn)(void*), int32 nret)
{
int32 i, j;
@@ -51,29 +65,31 @@ addfintab(Fintab *t, void *k, Finalizer *v)
ret:
t->key[i] = k;
- t->val[i] = v;
+ t->val[i].fn = fn;
+ t->val[i].nret = nret;
}
-static Finalizer*
-lookfintab(Fintab *t, void *k, bool del)
+static bool
+lookfintab(Fintab *t, void *k, bool del, Fin *f)
{
int32 i, j;
- Finalizer *v;
if(t->max == 0)
- return nil;
+ return false;
i = (uintptr)k % (uintptr)t->max;
for(j=0; j<t->max; j++) {
if(t->key[i] == nil)
- return nil;
+ return false;
if(t->key[i] == k) {
- v = t->val[i];
+ if(f)
+ *f = t->val[i];
if(del) {
t->key[i] = (void*)-1;
- t->val[i] = nil;
+ t->val[i].fn = nil;
+ t->val[i].nret = 0;
t->ndead++;
}
- return v;
+ return true;
}
if(++i == t->max)
i = 0;
@@ -81,88 +97,100 @@ lookfintab(Fintab *t, void *k, bool del)
// cannot happen - table is known to be non-full
runtime·throw("finalizer table inconsistent");
- return nil;
+ return false;
}
-static Fintab fintab;
-
-// add finalizer; caller is responsible for making sure not already in table
-void
-runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
+static void
+resizefintab(Fintab *tab)
{
Fintab newtab;
+ void *k;
int32 i;
- byte *base;
- Finalizer *e;
+
+ runtime·memclr((byte*)&newtab, sizeof newtab);
+ newtab.max = tab->max;
+ if(newtab.max == 0)
+ newtab.max = 3*3*3;
+ else if(tab->ndead < tab->nkey/2) {
+ // grow table if not many dead values.
+ // otherwise just rehash into table of same size.
+ newtab.max *= 3;
+ }
- e = nil;
- if(f != nil) {
- e = runtime·mal(sizeof *e);
- e->fn = f;
- e->nret = nret;
+ newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1);
+ newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+
+ for(i=0; i<tab->max; i++) {
+ k = tab->key[i];
+ if(k != nil && k != (void*)-1)
+ addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret);
}
+
+ runtime·free(tab->key);
+ runtime·free(tab->val);
+
+ tab->key = newtab.key;
+ tab->val = newtab.val;
+ tab->nkey = newtab.nkey;
+ tab->ndead = newtab.ndead;
+ tab->max = newtab.max;
+}
- runtime·lock(&finlock);
- if(!runtime·mlookup(p, &base, nil, nil) || p != base) {
- runtime·unlock(&finlock);
- runtime·throw("addfinalizer on invalid pointer");
+bool
+runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
+{
+ Fintab *tab;
+ byte *base;
+
+ if(debug) {
+ if(!runtime·mlookup(p, &base, nil, nil) || p != base)
+ runtime·throw("addfinalizer on invalid pointer");
}
+
+ tab = TAB(p);
+ runtime·lock(tab);
if(f == nil) {
- lookfintab(&fintab, p, 1);
- runtime·unlock(&finlock);
- return;
+ if(lookfintab(tab, p, true, nil))
+ runtime·setblockspecial(p, false);
+ runtime·unlock(tab);
+ return true;
}
- if(lookfintab(&fintab, p, 0)) {
- runtime·unlock(&finlock);
- runtime·throw("double finalizer");
+ if(lookfintab(tab, p, false, nil)) {
+ runtime·unlock(tab);
+ return false;
}
- runtime·setblockspecial(p);
- if(fintab.nkey >= fintab.max/2+fintab.max/4) {
+ if(tab->nkey >= tab->max/2+tab->max/4) {
// keep table at most 3/4 full:
// allocate new table and rehash.
-
- runtime·memclr((byte*)&newtab, sizeof newtab);
- newtab.max = fintab.max;
- if(newtab.max == 0)
- newtab.max = 3*3*3;
- else if(fintab.ndead < fintab.nkey/2) {
- // grow table if not many dead values.
- // otherwise just rehash into table of same size.
- newtab.max *= 3;
- }
-
- newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], FlagNoPointers, 0, 1);
- newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
-
- for(i=0; i<fintab.max; i++) {
- void *k;
-
- k = fintab.key[i];
- if(k != nil && k != (void*)-1)
- addfintab(&newtab, k, fintab.val[i]);
- }
- runtime·free(fintab.key);
- runtime·free(fintab.val);
- fintab = newtab;
+ resizefintab(tab);
}
- addfintab(&fintab, p, e);
- runtime·unlock(&finlock);
+ addfintab(tab, p, f, nret);
+ runtime·setblockspecial(p, true);
+ runtime·unlock(tab);
+ return true;
}
// get finalizer; if del, delete finalizer.
-// caller is responsible for updating RefHasFinalizer bit.
-Finalizer*
-runtime·getfinalizer(void *p, bool del)
+// caller is responsible for updating RefHasFinalizer (special) bit.
+bool
+runtime·getfinalizer(void *p, bool del, void (**fn)(void*), int32 *nret)
{
- Finalizer *f;
+ Fintab *tab;
+ bool res;
+ Fin f;
- runtime·lock(&finlock);
- f = lookfintab(&fintab, p, del);
- runtime·unlock(&finlock);
- return f;
+ tab = TAB(p);
+ runtime·lock(tab);
+ res = lookfintab(tab, p, del, &f);
+ runtime·unlock(tab);
+ if(res==false)
+ return false;
+ *fn = f.fn;
+ *nret = f.nret;
+ return true;
}
void
@@ -170,12 +198,15 @@ runtime·walkfintab(void (*fn)(void*))
{
void **key;
void **ekey;
+ int32 i;
- runtime·lock(&finlock);
- key = fintab.key;
- ekey = key + fintab.max;
- for(; key < ekey; key++)
- if(*key != nil && *key != ((void*)-1))
- fn(*key);
- runtime·unlock(&finlock);
+ for(i=0; i<TABSZ; i++) {
+ runtime·lock(&fintab[i]);
+ key = fintab[i].key;
+ ekey = key + fintab[i].max;
+ for(; key < ekey; key++)
+ if(*key != nil && *key != ((void*)-1))
+ fn(*key);
+ runtime·unlock(&fintab[i]);
+ }
}
diff --git a/src/pkg/runtime/mfinal_test.go b/src/pkg/runtime/mfinal_test.go
new file mode 100644
index 000000000..de632717a
--- /dev/null
+++ b/src/pkg/runtime/mfinal_test.go
@@ -0,0 +1,64 @@
+// 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 (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func fin(v *int) {
+}
+
+func BenchmarkFinalizer(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ var wg sync.WaitGroup
+ wg.Add(procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var data [CallsPerSched]*int
+ for i := 0; i < CallsPerSched; i++ {
+ data[i] = new(int)
+ }
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for i := 0; i < CallsPerSched; i++ {
+ runtime.SetFinalizer(data[i], fin)
+ }
+ for i := 0; i < CallsPerSched; i++ {
+ runtime.SetFinalizer(data[i], nil)
+ }
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
+
+func BenchmarkFinalizerRun(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ var wg sync.WaitGroup
+ wg.Add(procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for i := 0; i < CallsPerSched; i++ {
+ v := new(int)
+ runtime.SetFinalizer(v, fin)
+ }
+ runtime.GC()
+ }
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c
index ab9df3196..c916d588f 100644
--- a/src/pkg/runtime/mfixalloc.c
+++ b/src/pkg/runtime/mfixalloc.c
@@ -7,6 +7,7 @@
// See malloc.h for overview.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
// Initialize f to allocate objects of the given size,
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 78ea2aa2b..e043864c1 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -5,14 +5,15 @@
// Garbage collector.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
#include "stack.h"
enum {
Debug = 0,
- UseCas = 1,
PtrSize = sizeof(void*),
-
+ DebugMark = 0, // run second pass to check mark
+
// Four bits per word (see #defines below).
wordsPerBitmapWord = sizeof(void*)*8/4,
bitShift = sizeof(void*)*8/4,
@@ -51,30 +52,86 @@ enum {
#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
-static uint64 nlookup;
-static uint64 nsizelookup;
-static uint64 naddrlookup;
+// Holding worldsema grants an M the right to try to stop the world.
+// The procedure is:
+//
+// runtime·semacquire(&runtime·worldsema);
+// m->gcing = 1;
+// runtime·stoptheworld();
+//
+// ... do stuff ...
+//
+// m->gcing = 0;
+// runtime·semrelease(&runtime·worldsema);
+// runtime·starttheworld();
+//
+uint32 runtime·worldsema = 1;
+
+// TODO: Make these per-M.
+static uint64 nhandoff;
+
static int32 gctrace;
typedef struct Workbuf Workbuf;
struct Workbuf
{
Workbuf *next;
- uintptr nw;
- byte *w[2048-2];
+ uintptr nobj;
+ byte *obj[512-2];
+};
+
+typedef struct Finalizer Finalizer;
+struct Finalizer
+{
+ void (*fn)(void*);
+ void *arg;
+ int32 nret;
+};
+
+typedef struct FinBlock FinBlock;
+struct FinBlock
+{
+ FinBlock *alllink;
+ FinBlock *next;
+ int32 cnt;
+ int32 cap;
+ Finalizer fin[1];
};
extern byte data[];
extern byte etext[];
-extern byte end[];
+extern byte ebss[];
static G *fing;
-static Finalizer *finq;
+static FinBlock *finq; // list of finalizers that are to be executed
+static FinBlock *finc; // cache of free blocks
+static FinBlock *allfin; // list of all blocks
+static Lock finlock;
static int32 fingwait;
static void runfinq(void);
static Workbuf* getempty(Workbuf*);
static Workbuf* getfull(Workbuf*);
+static void putempty(Workbuf*);
+static Workbuf* handoff(Workbuf*);
+
+static struct {
+ Lock fmu;
+ Workbuf *full;
+ Lock emu;
+ Workbuf *empty;
+ uint32 nproc;
+ volatile uint32 nwait;
+ volatile uint32 ndone;
+ Note alldone;
+ Lock markgate;
+ Lock sweepgate;
+ MSpan *spans;
+
+ Lock;
+ byte *chunk;
+ uintptr nchunk;
+} work;
// scanblock scans a block of n bytes starting at pointer b for references
// to other objects, scanning any it finds recursively until there are no
@@ -85,13 +142,14 @@ static Workbuf* getfull(Workbuf*);
static void
scanblock(byte *b, int64 n)
{
- byte *obj, *arena_start, *p;
+ byte *obj, *arena_start, *arena_used, *p;
void **vp;
- uintptr size, *bitp, bits, shift, i, j, x, xbits, off;
+ uintptr size, *bitp, bits, shift, i, j, x, xbits, off, nobj, nproc;
MSpan *s;
PageID k;
- void **bw, **w, **ew;
+ void **wp;
Workbuf *wbuf;
+ bool keepworking;
if((int64)(uintptr)n != n || n < 0) {
runtime·printf("scanblock %p %D\n", b, n);
@@ -100,11 +158,19 @@ scanblock(byte *b, int64 n)
// Memory arena parameters.
arena_start = runtime·mheap.arena_start;
-
+ arena_used = runtime·mheap.arena_used;
+ nproc = work.nproc;
+
wbuf = nil; // current work buffer
- ew = nil; // end of work buffer
- bw = nil; // beginning of work buffer
- w = nil; // current pointer into work buffer
+ wp = nil; // storage for next queued pointer (write pointer)
+ nobj = 0; // number of queued objects
+
+ // Scanblock helpers pass b==nil.
+ // The main proc needs to return to make more
+ // calls to scanblock. But if work.nproc==1 then
+ // might as well process blocks as soon as we
+ // have them.
+ keepworking = b == nil || work.nproc == 1;
// Align b to a word boundary.
off = (uintptr)b & (PtrSize-1);
@@ -120,17 +186,17 @@ scanblock(byte *b, int64 n)
runtime·printf("scanblock %p %D\n", b, n);
vp = (void**)b;
- n /= PtrSize;
+ n >>= (2+PtrSize/8); /* n /= PtrSize (4 or 8) */
for(i=0; i<n; i++) {
obj = (byte*)vp[i];
-
+
// Words outside the arena cannot be pointers.
- if((byte*)obj < arena_start || (byte*)obj >= runtime·mheap.arena_used)
+ if((byte*)obj < arena_start || (byte*)obj >= arena_used)
continue;
-
+
// obj may be a pointer to a live object.
// Try to find the beginning of the object.
-
+
// Round down to word boundary.
obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
@@ -158,8 +224,6 @@ scanblock(byte *b, int64 n)
// Otherwise consult span table to find beginning.
// (Manually inlined copy of MHeap_LookupMaybe.)
- nlookup++;
- naddrlookup++;
k = (uintptr)obj>>PageShift;
x = k;
if(sizeof(void*) == 8)
@@ -188,83 +252,67 @@ scanblock(byte *b, int64 n)
found:
// Now we have bits, bitp, and shift correct for
// obj pointing at the base of the object.
- // If not allocated or already marked, done.
- if((bits & bitAllocated) == 0 || (bits & bitMarked) != 0)
+ // Only care about allocated and not marked.
+ if((bits & (bitAllocated|bitMarked)) != bitAllocated)
continue;
- *bitp |= bitMarked<<shift;
+ if(nproc == 1)
+ *bitp |= bitMarked<<shift;
+ else {
+ for(;;) {
+ x = *bitp;
+ if(x & (bitMarked<<shift))
+ goto continue_obj;
+ if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+ break;
+ }
+ }
// If object has no pointers, don't need to scan further.
if((bits & bitNoPointers) != 0)
continue;
+ // If another proc wants a pointer, give it some.
+ if(nobj > 4 && work.nwait > 0 && work.full == nil) {
+ wbuf->nobj = nobj;
+ wbuf = handoff(wbuf);
+ nobj = wbuf->nobj;
+ wp = wbuf->obj + nobj;
+ }
+
// If buffer is full, get a new one.
- if(w >= ew) {
+ if(wbuf == nil || nobj >= nelem(wbuf->obj)) {
+ if(wbuf != nil)
+ wbuf->nobj = nobj;
wbuf = getempty(wbuf);
- bw = wbuf->w;
- w = bw;
- ew = bw + nelem(wbuf->w);
+ wp = wbuf->obj;
+ nobj = 0;
}
- *w++ = obj;
+ *wp++ = obj;
+ nobj++;
+ continue_obj:;
}
-
+
// Done scanning [b, b+n). Prepare for the next iteration of
// the loop by setting b and n to the parameters for the next block.
- // Fetch b from the work buffers.
- if(w <= bw) {
+ // Fetch b from the work buffer.
+ if(nobj == 0) {
+ if(!keepworking) {
+ putempty(wbuf);
+ return;
+ }
// Emptied our buffer: refill.
wbuf = getfull(wbuf);
if(wbuf == nil)
- break;
- bw = wbuf->w;
- ew = wbuf->w + nelem(wbuf->w);
- w = bw+wbuf->nw;
+ return;
+ nobj = wbuf->nobj;
+ wp = wbuf->obj + wbuf->nobj;
}
- b = *--w;
-
- // Figure out n = size of b. Start by loading bits for b.
- off = (uintptr*)b - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
-
- // Might be small; look for nearby block boundary.
- // A block boundary is marked by either bitBlockBoundary
- // or bitAllocated being set (see notes near their definition).
- enum {
- boundary = bitBlockBoundary|bitAllocated
- };
- // Look for a block boundary both after and before b
- // in the same bitmap word.
- //
- // A block boundary j words after b is indicated by
- // bits>>j & boundary
- // assuming shift+j < bitShift. (If shift+j >= bitShift then
- // we'll be bleeding other bit types like bitMarked into our test.)
- // Instead of inserting the conditional shift+j < bitShift into the loop,
- // we can let j range from 1 to bitShift as long as we first
- // apply a mask to keep only the bits corresponding
- // to shift+j < bitShift aka j < bitShift-shift.
- bits &= (boundary<<(bitShift-shift)) - boundary;
-
- // A block boundary j words before b is indicated by
- // xbits>>(shift-j) & boundary
- // (assuming shift >= j). There is no cleverness here
- // avoid the test, because when j gets too large the shift
- // turns negative, which is undefined in C.
-
- for(j=1; j<bitShift; j++) {
- if(((bits>>j)&boundary) != 0 || shift>=j && ((xbits>>(shift-j))&boundary) != 0) {
- n = j*PtrSize;
- goto scan;
- }
- }
-
- // Fall back to asking span about size class.
+ b = *--wp;
+ nobj--;
+
+ // Ask span about size class.
// (Manually inlined copy of MHeap_Lookup.)
- nlookup++;
- nsizelookup++;
x = (uintptr)b>>PageShift;
if(sizeof(void*) == 8)
x -= (uintptr)arena_start>>PageShift;
@@ -273,33 +321,126 @@ scanblock(byte *b, int64 n)
n = s->npages<<PageShift;
else
n = runtime·class_to_size[s->sizeclass];
- scan:;
}
}
-static struct {
- Workbuf *full;
- Workbuf *empty;
- byte *chunk;
- uintptr nchunk;
-} work;
+// debug_scanblock is the debug copy of scanblock.
+// it is simpler, slower, single-threaded, recursive,
+// and uses bitSpecial as the mark bit.
+static void
+debug_scanblock(byte *b, int64 n)
+{
+ byte *obj, *p;
+ void **vp;
+ uintptr size, *bitp, bits, shift, i, xbits, off;
+ MSpan *s;
+
+ if(!DebugMark)
+ runtime·throw("debug_scanblock without DebugMark");
+
+ if((int64)(uintptr)n != n || n < 0) {
+ runtime·printf("debug_scanblock %p %D\n", b, n);
+ runtime·throw("debug_scanblock");
+ }
+
+ // Align b to a word boundary.
+ off = (uintptr)b & (PtrSize-1);
+ if(off != 0) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
+ }
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ obj = (byte*)vp[i];
+
+ // Words outside the arena cannot be pointers.
+ if((byte*)obj < runtime·mheap.arena_start || (byte*)obj >= runtime·mheap.arena_used)
+ continue;
+
+ // Round down to word boundary.
+ obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+
+ // Consult span table to find beginning.
+ s = runtime·MHeap_LookupMaybe(&runtime·mheap, obj);
+ if(s == nil)
+ continue;
+
+
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ obj = p;
+ size = (uintptr)s->npages<<PageShift;
+ } else {
+ if((byte*)obj >= (byte*)s->limit)
+ continue;
+ size = runtime·class_to_size[s->sizeclass];
+ int32 i = ((byte*)obj - p)/size;
+ obj = p+i*size;
+ }
+
+ // Now that we know the object header, reload bits.
+ off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start;
+ bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ shift = off % wordsPerBitmapWord;
+ xbits = *bitp;
+ bits = xbits >> shift;
+
+ // Now we have bits, bitp, and shift correct for
+ // obj pointing at the base of the object.
+ // If not allocated or already marked, done.
+ if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0) // NOTE: bitSpecial not bitMarked
+ continue;
+ *bitp |= bitSpecial<<shift;
+ if(!(bits & bitMarked))
+ runtime·printf("found unmarked block %p in %p\n", obj, vp+i);
+
+ // If object has no pointers, don't need to scan further.
+ if((bits & bitNoPointers) != 0)
+ continue;
+
+ debug_scanblock(obj, size);
+ }
+}
// Get an empty work buffer off the work.empty list,
// allocating new buffers as needed.
static Workbuf*
getempty(Workbuf *b)
{
- if(b != nil) {
- b->nw = nelem(b->w);
- b->next = work.full;
- work.full = b;
- }
- b = work.empty;
- if(b != nil) {
- work.empty = b->next;
- return b;
+ if(work.nproc == 1) {
+ // Put b on full list.
+ if(b != nil) {
+ b->next = work.full;
+ work.full = b;
+ }
+ // Grab from empty list if possible.
+ b = work.empty;
+ if(b != nil) {
+ work.empty = b->next;
+ goto haveb;
+ }
+ } else {
+ // Put b on full list.
+ if(b != nil) {
+ runtime·lock(&work.fmu);
+ b->next = work.full;
+ work.full = b;
+ runtime·unlock(&work.fmu);
+ }
+ // Grab from empty list if possible.
+ runtime·lock(&work.emu);
+ b = work.empty;
+ if(b != nil)
+ work.empty = b->next;
+ runtime·unlock(&work.emu);
+ if(b != nil)
+ goto haveb;
}
-
+
+ // Need to allocate.
+ runtime·lock(&work);
if(work.nchunk < sizeof *b) {
work.nchunk = 1<<20;
work.chunk = runtime·SysAlloc(work.nchunk);
@@ -307,28 +448,124 @@ getempty(Workbuf *b)
b = (Workbuf*)work.chunk;
work.chunk += sizeof *b;
work.nchunk -= sizeof *b;
+ runtime·unlock(&work);
+
+haveb:
+ b->nobj = 0;
return b;
}
+static void
+putempty(Workbuf *b)
+{
+ if(b == nil)
+ return;
+
+ if(work.nproc == 1) {
+ b->next = work.empty;
+ work.empty = b;
+ return;
+ }
+
+ runtime·lock(&work.emu);
+ b->next = work.empty;
+ work.empty = b;
+ runtime·unlock(&work.emu);
+}
+
// Get a full work buffer off the work.full list, or return nil.
static Workbuf*
getfull(Workbuf *b)
{
- if(b != nil) {
- b->nw = 0;
- b->next = work.empty;
- work.empty = b;
+ int32 i;
+ Workbuf *b1;
+
+ if(work.nproc == 1) {
+ // Put b on empty list.
+ if(b != nil) {
+ b->next = work.empty;
+ work.empty = b;
+ }
+ // Grab from full list if possible.
+ // Since work.nproc==1, no one else is
+ // going to give us work.
+ b = work.full;
+ if(b != nil)
+ work.full = b->next;
+ return b;
+ }
+
+ putempty(b);
+
+ // Grab buffer from full list if possible.
+ for(;;) {
+ b1 = work.full;
+ if(b1 == nil)
+ break;
+ runtime·lock(&work.fmu);
+ if(work.full != nil) {
+ b1 = work.full;
+ work.full = b1->next;
+ runtime·unlock(&work.fmu);
+ return b1;
+ }
+ runtime·unlock(&work.fmu);
+ }
+
+ runtime·xadd(&work.nwait, +1);
+ for(i=0;; i++) {
+ b1 = work.full;
+ if(b1 != nil) {
+ runtime·lock(&work.fmu);
+ if(work.full != nil) {
+ runtime·xadd(&work.nwait, -1);
+ b1 = work.full;
+ work.full = b1->next;
+ runtime·unlock(&work.fmu);
+ return b1;
+ }
+ runtime·unlock(&work.fmu);
+ continue;
+ }
+ if(work.nwait == work.nproc)
+ return nil;
+ if(i < 10)
+ runtime·procyield(20);
+ else if(i < 20)
+ runtime·osyield();
+ else
+ runtime·usleep(100);
}
- b = work.full;
- if(b != nil)
- work.full = b->next;
- return b;
+}
+
+static Workbuf*
+handoff(Workbuf *b)
+{
+ int32 n;
+ Workbuf *b1;
+
+ // Make new buffer with half of b's pointers.
+ b1 = getempty(nil);
+ n = b->nobj/2;
+ b->nobj -= n;
+ b1->nobj = n;
+ runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]);
+ nhandoff += n;
+
+ // Put b on full list - let first half of b get stolen.
+ runtime·lock(&work.fmu);
+ b->next = work.full;
+ work.full = b;
+ runtime·unlock(&work.fmu);
+
+ return b1;
}
// Scanstack calls scanblock on each of gp's stack segments.
static void
-scanstack(G *gp)
+scanstack(void (*scanblock)(byte*, int64), G *gp)
{
+ M *mp;
int32 n;
Stktop *stk;
byte *sp, *guard;
@@ -339,6 +576,9 @@ scanstack(G *gp)
if(gp == g) {
// Scanning our own stack: start at &gp.
sp = (byte*)&gp;
+ } else if((mp = gp->m) != nil && mp->helpgc) {
+ // gchelper's stack is in active use and has no interesting pointers.
+ return;
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
@@ -387,17 +627,25 @@ markfin(void *v)
scanblock(v, size);
}
-// Mark
static void
-mark(void)
+debug_markfin(void *v)
+{
+ uintptr size;
+
+ if(!runtime·mlookup(v, &v, &size, nil))
+ runtime·throw("debug_mark - finalizer inconsistency");
+ debug_scanblock(v, size);
+}
+
+// Mark
+static void
+mark(void (*scan)(byte*, int64))
{
G *gp;
+ FinBlock *fb;
// mark data+bss.
- // skip runtime·mheap itself, which has no interesting pointers
- // and is mostly zeroed and would not otherwise be paged in.
- scanblock(data, (byte*)&runtime·mheap - data);
- scanblock((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1));
+ scan(data, ebss - data);
// mark stacks
for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
@@ -410,21 +658,66 @@ mark(void)
case Grunning:
if(gp != g)
runtime·throw("mark - world not stopped");
- scanstack(gp);
+ scanstack(scan, gp);
break;
case Grunnable:
case Gsyscall:
case Gwaiting:
- scanstack(gp);
+ scanstack(scan, gp);
break;
}
}
// mark things pointed at by objects with finalizers
- runtime·walkfintab(markfin);
+ if(scan == debug_scanblock)
+ runtime·walkfintab(debug_markfin);
+ else
+ runtime·walkfintab(markfin);
+
+ for(fb=allfin; fb; fb=fb->alllink)
+ scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]));
+
+ // in multiproc mode, join in the queued work.
+ scan(nil, 0);
+}
+
+static bool
+handlespecial(byte *p, uintptr size)
+{
+ void (*fn)(void*);
+ int32 nret;
+ FinBlock *block;
+ Finalizer *f;
+
+ if(!runtime·getfinalizer(p, true, &fn, &nret)) {
+ runtime·setblockspecial(p, false);
+ runtime·MProf_Free(p, size);
+ return false;
+ }
+
+ runtime·lock(&finlock);
+ if(finq == nil || finq->cnt == finq->cap) {
+ if(finc == nil) {
+ finc = runtime·SysAlloc(PageSize);
+ finc->cap = (PageSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
+ finc->alllink = allfin;
+ allfin = finc;
+ }
+ block = finc;
+ finc = block->next;
+ block->next = finq;
+ finq = block;
+ }
+ f = &finq->fin[finq->cnt];
+ finq->cnt++;
+ f->fn = fn;
+ f->nret = nret;
+ f->arg = p;
+ runtime·unlock(&finlock);
+ return true;
}
-// Sweep frees or calls finalizers for blocks not marked in the mark phase.
+// Sweep frees or collects finalizers for blocks not marked in the mark phase.
// It clears the mark bits in preparation for the next GC round.
static void
sweep(void)
@@ -434,9 +727,24 @@ sweep(void)
uintptr size;
byte *p;
MCache *c;
- Finalizer *f;
+ byte *arena_start;
+ int64 now;
+
+ arena_start = runtime·mheap.arena_start;
+ now = runtime·nanotime();
+
+ for(;;) {
+ s = work.spans;
+ if(s == nil)
+ break;
+ if(!runtime·casp(&work.spans, s, s->allnext))
+ continue;
+
+ // Stamp newly unused spans. The scavenger will use that
+ // info to potentially give back some pages to the OS.
+ if(s->state == MSpanFree && s->unusedsince == 0)
+ s->unusedsince = now;
- for(s = runtime·mheap.allspans; s != nil; s = s->allnext) {
if(s->state != MSpanInUse)
continue;
@@ -451,13 +759,15 @@ sweep(void)
npages = runtime·class_to_allocnpages[cl];
n = (npages << PageShift) / size;
}
-
- // sweep through n objects of given size starting at p.
+
+ // Sweep through n objects of given size starting at p.
+ // This thread owns the span now, so it can manipulate
+ // the block bitmap without atomic operations.
for(; n > 0; n--, p += size) {
uintptr off, *bitp, shift, bits;
- off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;
- bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+ off = (uintptr*)p - (uintptr*)arena_start;
+ bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
bits = *bitp>>shift;
@@ -465,20 +775,21 @@ sweep(void)
continue;
if((bits & bitMarked) != 0) {
+ if(DebugMark) {
+ if(!(bits & bitSpecial))
+ runtime·printf("found spurious mark on %p\n", p);
+ *bitp &= ~(bitSpecial<<shift);
+ }
*bitp &= ~(bitMarked<<shift);
continue;
}
- if((bits & bitSpecial) != 0) {
- // Special means it has a finalizer or is being profiled.
- f = runtime·getfinalizer(p, 1);
- if(f != nil) {
- f->arg = p;
- f->next = finq;
- finq = f;
+ // Special means it has a finalizer or is being profiled.
+ // In DebugMark mode, the bit has been coopted so
+ // we have to assume all blocks are special.
+ if(DebugMark || (bits & bitSpecial) != 0) {
+ if(handlespecial(p, size))
continue;
- }
- runtime·MProf_Free(p, size);
}
// Mark freed; restore block boundary bit.
@@ -503,10 +814,22 @@ sweep(void)
}
}
-// Semaphore, not Lock, so that the goroutine
-// reschedules when there is contention rather
-// than spinning.
-static uint32 gcsema = 1;
+void
+runtime·gchelper(void)
+{
+ // Wait until main proc is ready for mark help.
+ runtime·lock(&work.markgate);
+ runtime·unlock(&work.markgate);
+ scanblock(nil, 0);
+
+ // Wait until main proc is ready for sweep help.
+ runtime·lock(&work.sweepgate);
+ runtime·unlock(&work.sweepgate);
+ sweep();
+
+ if(runtime·xadd(&work.ndone, +1) == work.nproc-1)
+ runtime·notewakeup(&work.alldone);
+}
// Initialized from $GOGC. GOGC=off means no gc.
//
@@ -523,7 +846,7 @@ static void
stealcache(void)
{
M *m;
-
+
for(m=runtime·allm; m; m=m->alllink)
runtime·MCache_ReleaseAll(m->mcache);
}
@@ -561,7 +884,7 @@ runtime·gc(int32 force)
int64 t0, t1, t2, t3;
uint64 heap0, heap1, obj0, obj1;
byte *p;
- Finalizer *fp;
+ bool extra;
// The gc is turned off (via enablegc) until
// the bootstrap has completed.
@@ -582,7 +905,7 @@ runtime·gc(int32 force)
gcpercent = -1;
else
gcpercent = runtime·atoi(p);
-
+
p = runtime·getenv("GOGCTRACE");
if(p != nil)
gctrace = runtime·atoi(p);
@@ -590,30 +913,47 @@ runtime·gc(int32 force)
if(gcpercent < 0)
return;
- runtime·semacquire(&gcsema);
+ runtime·semacquire(&runtime·worldsema);
if(!force && mstats.heap_alloc < mstats.next_gc) {
- runtime·semrelease(&gcsema);
+ runtime·semrelease(&runtime·worldsema);
return;
}
t0 = runtime·nanotime();
- nlookup = 0;
- nsizelookup = 0;
- naddrlookup = 0;
+ nhandoff = 0;
m->gcing = 1;
runtime·stoptheworld();
- if(runtime·mheap.Lock.key != 0)
- runtime·throw("runtime·mheap locked during gc");
cachestats();
heap0 = mstats.heap_alloc;
obj0 = mstats.nmalloc - mstats.nfree;
- mark();
+ runtime·lock(&work.markgate);
+ runtime·lock(&work.sweepgate);
+
+ extra = false;
+ work.nproc = 1;
+ if(runtime·gomaxprocs > 1 && runtime·ncpu > 1) {
+ runtime·noteclear(&work.alldone);
+ work.nproc += runtime·helpgc(&extra);
+ }
+ work.nwait = 0;
+ work.ndone = 0;
+
+ runtime·unlock(&work.markgate); // let the helpers in
+ mark(scanblock);
+ if(DebugMark)
+ mark(debug_scanblock);
t1 = runtime·nanotime();
+
+ work.spans = runtime·mheap.allspans;
+ runtime·unlock(&work.sweepgate); // let the helpers in
sweep();
+ if(work.nproc > 1)
+ runtime·notesleep(&work.alldone);
t2 = runtime·nanotime();
+
stealcache();
cachestats();
@@ -621,8 +961,7 @@ runtime·gc(int32 force)
m->gcing = 0;
m->locks++; // disable gc during the mallocs in newproc
- fp = finq;
- if(fp != nil) {
+ if(finq != nil) {
// kick off or wake up goroutine to run queued finalizers
if(fing == nil)
fing = runtime·newproc1((byte*)runfinq, nil, 0, 0, runtime·gc);
@@ -638,53 +977,68 @@ runtime·gc(int32 force)
obj1 = mstats.nmalloc - mstats.nfree;
t3 = runtime·nanotime();
+ mstats.last_gc = t3;
mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t3 - t0;
mstats.pause_total_ns += t3 - t0;
mstats.numgc++;
if(mstats.debuggc)
runtime·printf("pause %D\n", t3-t0);
-
+
if(gctrace) {
- runtime·printf("gc%d: %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D pointer lookups (%D size, %D addr)\n",
- mstats.numgc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
+ runtime·printf("gc%d(%d): %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D handoff\n",
+ mstats.numgc, work.nproc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
heap0>>20, heap1>>20, obj0, obj1,
mstats.nmalloc, mstats.nfree,
- nlookup, nsizelookup, naddrlookup);
+ nhandoff);
}
-
- runtime·semrelease(&gcsema);
- runtime·starttheworld();
- // give the queued finalizers, if any, a chance to run
- if(fp != nil)
+ runtime·MProf_GC();
+ runtime·semrelease(&runtime·worldsema);
+
+ // If we could have used another helper proc, start one now,
+ // in the hope that it will be available next time.
+ // It would have been even better to start it before the collection,
+ // but doing so requires allocating memory, so it's tricky to
+ // coordinate. This lazy approach works out in practice:
+ // we don't mind if the first couple gc rounds don't have quite
+ // the maximum number of procs.
+ runtime·starttheworld(extra);
+
+ // give the queued finalizers, if any, a chance to run
+ if(finq != nil)
runtime·gosched();
-
+
if(gctrace > 1 && !force)
runtime·gc(1);
}
void
-runtime·UpdateMemStats(void)
+runtime·ReadMemStats(MStats *stats)
{
- // Have to acquire gcsema to stop the world,
+ // Have to acquire worldsema 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.
- runtime·semacquire(&gcsema);
+ runtime·semacquire(&runtime·worldsema);
m->gcing = 1;
runtime·stoptheworld();
cachestats();
+ *stats = mstats;
m->gcing = 0;
- runtime·semrelease(&gcsema);
- runtime·starttheworld();
+ runtime·semrelease(&runtime·worldsema);
+ runtime·starttheworld(false);
}
static void
runfinq(void)
{
- Finalizer *f, *next;
+ Finalizer *f;
+ FinBlock *fb, *next;
byte *frame;
+ uint32 framesz, framecap, i;
+ frame = nil;
+ framecap = 0;
for(;;) {
// There's no need for a lock in this section
// because it only conflicts with the garbage
@@ -692,24 +1046,34 @@ runfinq(void)
// runs when everyone else is stopped, and
// runfinq only stops at the gosched() or
// during the calls in the for loop.
- f = finq;
+ fb = finq;
finq = nil;
- if(f == nil) {
+ if(fb == nil) {
fingwait = 1;
g->status = Gwaiting;
+ g->waitreason = "finalizer wait";
runtime·gosched();
continue;
}
- for(; f; f=next) {
- next = f->next;
- frame = runtime·mal(sizeof(uintptr) + f->nret);
- *(void**)frame = f->arg;
- reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret);
- runtime·free(frame);
- f->fn = nil;
- f->arg = nil;
- f->next = nil;
- runtime·free(f);
+ for(; fb; fb=next) {
+ next = fb->next;
+ for(i=0; i<fb->cnt; i++) {
+ f = &fb->fin[i];
+ framesz = sizeof(uintptr) + f->nret;
+ if(framecap < framesz) {
+ runtime·free(frame);
+ frame = runtime·mal(framesz);
+ framecap = framesz;
+ }
+ *(void**)frame = f->arg;
+ runtime·setblockspecial(f->arg, false);
+ reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret);
+ f->fn = nil;
+ f->arg = nil;
+ }
+ fb->cnt = 0;
+ fb->next = finc;
+ finc = fb;
}
runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
}
@@ -859,6 +1223,9 @@ runtime·blockspecial(void *v)
{
uintptr *b, off, shift;
+ if(DebugMark)
+ return true;
+
off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
@@ -867,17 +1234,23 @@ runtime·blockspecial(void *v)
}
void
-runtime·setblockspecial(void *v)
+runtime·setblockspecial(void *v, bool s)
{
uintptr *b, off, shift, bits, obits;
+ if(DebugMark)
+ return;
+
off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
shift = off % wordsPerBitmapWord;
for(;;) {
obits = *b;
- bits = obits | (bitSpecial<<shift);
+ if(s)
+ bits = obits | (bitSpecial<<shift);
+ else
+ bits = obits & ~(bitSpecial<<shift);
if(runtime·singleproc) {
*b = bits;
break;
@@ -888,7 +1261,7 @@ runtime·setblockspecial(void *v)
}
}
}
-
+
void
runtime·MHeap_MapBits(MHeap *h)
{
@@ -899,7 +1272,7 @@ runtime·MHeap_MapBits(MHeap *h)
bitmapChunk = 8192
};
uintptr n;
-
+
n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
n = (n+bitmapChunk-1) & ~(bitmapChunk-1);
if(h->bitmap_mapped >= n)
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index 37d505681..c877bfca9 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -13,6 +13,7 @@
// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
@@ -101,6 +102,9 @@ HaveSpan:
runtime·throw("MHeap_AllocLocked - bad npages");
runtime·MSpanList_Remove(s);
s->state = MSpanInUse;
+ mstats.heap_idle -= s->npages<<PageShift;
+ mstats.heap_released -= s->npreleased<<PageShift;
+ s->npreleased = 0;
if(s->npages > npage) {
// Trim extra and put it back in the heap.
@@ -276,7 +280,10 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
runtime·throw("MHeap_FreeLocked - invalid free");
}
+ mstats.heap_idle += s->npages<<PageShift;
s->state = MSpanFree;
+ s->unusedsince = 0;
+ s->npreleased = 0;
runtime·MSpanList_Remove(s);
sp = (uintptr*)(s->start<<PageShift);
@@ -289,6 +296,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
*tp |= *sp; // propagate "needs zeroing" mark
s->start = t->start;
s->npages += t->npages;
+ s->npreleased = t->npreleased; // absorb released pages
p -= t->npages;
h->map[p] = s;
runtime·MSpanList_Remove(t);
@@ -301,6 +309,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
tp = (uintptr*)(t->start<<PageShift);
*sp |= *tp; // propagate "needs zeroing" mark
s->npages += t->npages;
+ s->npreleased += t->npreleased;
h->map[p + s->npages - 1] = s;
runtime·MSpanList_Remove(t);
t->state = MSpanDead;
@@ -314,8 +323,84 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
runtime·MSpanList_Insert(&h->free[s->npages], s);
else
runtime·MSpanList_Insert(&h->large, s);
+}
- // TODO(rsc): IncrementalScavenge() to return memory to OS.
+// Release (part of) unused memory to OS.
+// Goroutine created at startup.
+// Loop forever.
+void
+runtime·MHeap_Scavenger(void)
+{
+ MHeap *h;
+ MSpan *s, *list;
+ uint64 tick, now, forcegc, limit;
+ uint32 k, i;
+ uintptr released, sumreleased;
+ byte *env;
+ bool trace;
+ Note note;
+
+ // If we go two minutes without a garbage collection, force one to run.
+ forcegc = 2*60*1e9;
+ // If a span goes unused for 5 minutes after a garbage collection,
+ // we hand it back to the operating system.
+ limit = 5*60*1e9;
+ // Make wake-up period small enough for the sampling to be correct.
+ if(forcegc < limit)
+ tick = forcegc/2;
+ else
+ tick = limit/2;
+
+ trace = false;
+ env = runtime·getenv("GOGCTRACE");
+ if(env != nil)
+ trace = runtime·atoi(env) > 0;
+
+ h = &runtime·mheap;
+ for(k=0;; k++) {
+ runtime·noteclear(&note);
+ runtime·entersyscall();
+ runtime·notetsleep(&note, tick);
+ runtime·exitsyscall();
+
+ runtime·lock(h);
+ now = runtime·nanotime();
+ if(now - mstats.last_gc > forcegc) {
+ runtime·unlock(h);
+ runtime·gc(1);
+ runtime·lock(h);
+ now = runtime·nanotime();
+ if (trace)
+ runtime·printf("scvg%d: GC forced\n", k);
+ }
+ sumreleased = 0;
+ for(i=0; i < nelem(h->free)+1; i++) {
+ if(i < nelem(h->free))
+ list = &h->free[i];
+ else
+ list = &h->large;
+ if(runtime·MSpanList_IsEmpty(list))
+ continue;
+ for(s=list->next; s != list; s=s->next) {
+ if(s->unusedsince != 0 && (now - s->unusedsince) > limit) {
+ released = (s->npages - s->npreleased) << PageShift;
+ mstats.heap_released += released;
+ sumreleased += released;
+ s->npreleased = s->npages;
+ runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
+ }
+ }
+ }
+ runtime·unlock(h);
+
+ if(trace) {
+ if(sumreleased > 0)
+ runtime·printf("scvg%d: %p MB released\n", k, sumreleased>>20);
+ runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
+ k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
+ mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
+ }
+ }
}
// Initialize a new span with the given start and npages.
@@ -330,6 +415,8 @@ runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
span->ref = 0;
span->sizeclass = 0;
span->state = 0;
+ span->unusedsince = 0;
+ span->npreleased = 0;
}
// Initialize an empty doubly-linked list.
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index 328e2d5ba..f37fe2149 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -3,23 +3,48 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+trap "rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h" EXIT INT TERM
set -e
+SYS=$1
+export GOOS=$(echo $SYS | sed 's/_.*//')
+export GOARCH=$(echo $SYS | sed 's/.*_//')
+shift
+
+case "$GOARCH" in
+386) CC=8c;;
+amd64) CC=6c;;
+arm) CC=5c;;
+esac
+CC="$GOROOT/bin/tool/$CC"
+export CC
+
+export CFLAGS="-Dos_$GOOS -Darch_$GOARCH"
+
+cp arch_$GOARCH.h arch_GOARCH.h
+cp defs_${GOOS}_$GOARCH.h defs_GOOS_GOARCH.h
+cp os_$GOOS.h os_GOOS.h
+cp signals_$GOOS.h signals_GOOS.h
+
cat <<'EOF'
// Assembly constants.
-// AUTOMATICALLY GENERATED BY mkasmh.sh DURING BUILD
+// AUTO-GENERATED by autogen.sh; DO NOT EDIT
EOF
+if [ ! -x "$CC" ]; then
+ echo "// dummy file for cmd/go to correctly generate buildscript"
+ exit
+fi
case "$GOARCH" in
386)
# The offsets 0 and 4 are also known to:
# ../../cmd/8l/pass.c:/D_GS
- # ../../libcgo/linux_386.c:/^threadentry
- # ../../libcgo/darwin_386.c:/^threadentry
+ # cgo/gcc_linux_386.c:/^threadentry
+ # cgo/gcc_darwin_386.c:/^threadentry
case "$GOOS" in
windows)
- echo '#define get_tls(r) MOVL 0x2c(FS), r'
+ echo '#define get_tls(r) MOVL 0x14(FS), r'
echo '#define g(r) 0(r)'
echo '#define m(r) 4(r)'
;;
@@ -63,15 +88,15 @@ case "$GOARCH" in
amd64)
case "$GOOS" in
windows)
- echo '#define get_tls(r) MOVQ 0x58(GS), r'
+ echo '#define get_tls(r) MOVQ 0x28(GS), r'
echo '#define g(r) 0(r)'
echo '#define m(r) 8(r)'
;;
*)
# The offsets 0 and 8 are known to:
# ../../cmd/6l/pass.c:/D_GS
- # ../../libcgo/linux_amd64.c:/^threadentry
- # ../../libcgo/darwin_amd64.c:/^threadentry
+ # cgo/gcc_linux_amd64.c:/^threadentry
+ # cgo/gcc_darwin_amd64.c:/^threadentry
#
echo '#define get_tls(r)'
echo '#define g(r) 0(GS)'
@@ -91,11 +116,13 @@ arm)
esac
echo
+"$CC" $CFLAGS -a proc.c |
awk '
{ gsub(/\r/, ""); }
/^aggr G$/ { aggr="g" }
/^aggr M$/ { aggr = "m" }
/^aggr Gobuf$/ { aggr = "gobuf" }
+/^aggr WinCall$/ { aggr = "wincall" }
/^}/ { aggr = "" }
# Gobuf 24 sched;
@@ -108,5 +135,4 @@ aggr != "" && /^ / {
offset=$(NF-1);
printf("#define %s_%s %s\n", aggr, name, offset);
}
-' runtime.acid.$GOARCH
-
+'
diff --git a/src/pkg/runtime/mkgodefs.sh b/src/pkg/runtime/mkgodefs.sh
deleted file mode 100755
index b6e97213e..000000000
--- a/src/pkg/runtime/mkgodefs.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-# 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.
-
-set -e
-
-cat <<EOF
-// Go definitions for C variables and types.
-// AUTOMATICALLY GENERATED BY THE FOLLOWING COMMAND. DO NOT EDIT.
-// CC="$CC" CFLAGS="$CFLAGS" ./mkgodefs.sh $@
-
-package runtime
-import "unsafe"
-var _ unsafe.Pointer
-
-EOF
-
-for i in "$@"; do
- $CC $CFLAGS -q $i
-done | awk '
-/^func/ { next }
-/^const/ { next }
-/^\/\/.*type/ { next }
-
-/^(const|func|type|var) / {
- if(seen[$2]++) {
- skip = /{[^}]*$/;
- next;
- }
-}
-
-skip {
- skip = !/^}/
- next;
-}
-
-{print}
-'
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
index 0d96aa356..94ad0d9e5 100644
--- a/src/pkg/runtime/mkversion.c
+++ b/src/pkg/runtime/mkversion.c
@@ -1,8 +1,14 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
#include <u.h>
#include <libc.h>
char *template =
- "// generated by mkversion.c; do not edit.\n"
+ "// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n"
"package runtime\n"
"const defaultGoroot = `%s`\n"
"const theVersion = \"%s\"\n";
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 517f96a31..0bbce8583 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -7,8 +7,9 @@
package runtime
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
-#include "defs.h"
+#include "defs_GOOS_GOARCH.h"
#include "type.h"
// NOTE(rsc): Everything here could use cas if contention became an issue.
@@ -25,6 +26,10 @@ struct Bucket
uintptr frees;
uintptr alloc_bytes;
uintptr free_bytes;
+ uintptr recent_allocs; // since last gc
+ uintptr recent_frees;
+ uintptr recent_alloc_bytes;
+ uintptr recent_free_bytes;
uintptr hash;
uintptr nstk;
uintptr stk[1];
@@ -38,7 +43,7 @@ static uintptr bucketmem;
// Return the bucket for stk[0:nstk], allocating new bucket if needed.
static Bucket*
-stkbucket(uintptr *stk, int32 nstk)
+stkbucket(uintptr *stk, int32 nstk, bool alloc)
{
int32 i;
uintptr h;
@@ -65,6 +70,9 @@ stkbucket(uintptr *stk, int32 nstk)
runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
+ if(!alloc)
+ return nil;
+
b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
bucketmem += sizeof *b + nstk*sizeof stk[0];
runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
@@ -77,6 +85,26 @@ stkbucket(uintptr *stk, int32 nstk)
return b;
}
+// Record that a gc just happened: all the 'recent' statistics are now real.
+void
+runtime·MProf_GC(void)
+{
+ Bucket *b;
+
+ runtime·lock(&proflock);
+ for(b=buckets; b; b=b->allnext) {
+ b->allocs += b->recent_allocs;
+ b->frees += b->recent_frees;
+ b->alloc_bytes += b->recent_alloc_bytes;
+ b->free_bytes += b->recent_free_bytes;
+ b->recent_allocs = 0;
+ b->recent_frees = 0;
+ b->recent_alloc_bytes = 0;
+ b->recent_free_bytes = 0;
+ }
+ runtime·unlock(&proflock);
+}
+
// Map from pointer to Bucket* that allocated it.
// Three levels:
// Linked-list hash table for top N-20 bits.
@@ -197,9 +225,9 @@ runtime·MProf_Malloc(void *p, uintptr size)
m->nomemprof++;
nstk = runtime·callers(1, stk, 32);
runtime·lock(&proflock);
- b = stkbucket(stk, nstk);
- b->allocs++;
- b->alloc_bytes += size;
+ b = stkbucket(stk, nstk, true);
+ b->recent_allocs++;
+ b->recent_alloc_bytes += size;
setaddrbucket((uintptr)p, b);
runtime·unlock(&proflock);
m->nomemprof--;
@@ -218,8 +246,8 @@ runtime·MProf_Free(void *p, uintptr size)
runtime·lock(&proflock);
b = getaddrbucket((uintptr)p);
if(b != nil) {
- b->frees++;
- b->free_bytes += size;
+ b->recent_frees++;
+ b->recent_free_bytes += size;
}
runtime·unlock(&proflock);
m->nomemprof--;
@@ -229,7 +257,7 @@ runtime·MProf_Free(void *p, uintptr size)
// Go interface to profile data. (Declared in extern.go)
// Assumes Go sizeof(int) == sizeof(int32)
-// Must match MemProfileRecord in extern.go.
+// Must match MemProfileRecord in debug.go.
typedef struct Record Record;
struct Record {
int64 alloc_bytes, free_bytes;
@@ -272,3 +300,105 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
}
runtime·unlock(&proflock);
}
+
+// Must match StackRecord in debug.go.
+typedef struct TRecord TRecord;
+struct TRecord {
+ uintptr stk[32];
+};
+
+func ThreadCreateProfile(p Slice) (n int32, ok bool) {
+ TRecord *r;
+ M *first, *m;
+
+ first = runtime·atomicloadp(&runtime·allm);
+ n = 0;
+ for(m=first; m; m=m->alllink)
+ n++;
+ ok = false;
+ if(n <= p.len) {
+ ok = true;
+ r = (TRecord*)p.array;
+ for(m=first; m; m=m->alllink) {
+ runtime·memmove(r->stk, m->createstack, sizeof r->stk);
+ r++;
+ }
+ }
+}
+
+func Stack(b Slice, all bool) (n int32) {
+ byte *pc, *sp;
+
+ sp = runtime·getcallersp(&b);
+ pc = runtime·getcallerpc(&b);
+
+ if(all) {
+ runtime·semacquire(&runtime·worldsema);
+ m->gcing = 1;
+ runtime·stoptheworld();
+ }
+
+ if(b.len == 0)
+ n = 0;
+ else{
+ g->writebuf = (byte*)b.array;
+ g->writenbuf = b.len;
+ runtime·goroutineheader(g);
+ runtime·traceback(pc, sp, 0, g);
+ if(all)
+ runtime·tracebackothers(g);
+ n = b.len - g->writenbuf;
+ g->writebuf = nil;
+ g->writenbuf = 0;
+ }
+
+ if(all) {
+ m->gcing = 0;
+ runtime·semrelease(&runtime·worldsema);
+ runtime·starttheworld(false);
+ }
+}
+
+static void
+saveg(byte *pc, byte *sp, G *g, TRecord *r)
+{
+ int32 n;
+
+ n = runtime·gentraceback(pc, sp, 0, g, 0, r->stk, nelem(r->stk));
+ if(n < nelem(r->stk))
+ r->stk[n] = 0;
+}
+
+func GoroutineProfile(b Slice) (n int32, ok bool) {
+ byte *pc, *sp;
+ TRecord *r;
+ G *gp;
+
+ sp = runtime·getcallersp(&b);
+ pc = runtime·getcallerpc(&b);
+
+ ok = false;
+ n = runtime·gcount();
+ if(n <= b.len) {
+ runtime·semacquire(&runtime·worldsema);
+ m->gcing = 1;
+ runtime·stoptheworld();
+
+ n = runtime·gcount();
+ if(n <= b.len) {
+ ok = true;
+ r = (TRecord*)b.array;
+ saveg(pc, sp, g, r++);
+ for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
+ if(gp == g || gp->status == Gdead)
+ continue;
+ saveg(gp->sched.pc, gp->sched.sp, gp, r++);
+ }
+ }
+
+ m->gcing = 0;
+ runtime·semrelease(&runtime·worldsema);
+ runtime·starttheworld(false);
+ }
+}
+
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index 770ef38ce..e6cfcdb02 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -26,6 +26,7 @@
// TODO(rsc): Compute max waste for any given size.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
int32 runtime·class_to_size[NumSizeClasses];
diff --git a/src/pkg/runtime/openbsd/defs.c b/src/pkg/runtime/openbsd/defs.c
deleted file mode 100644
index d8adec981..000000000
--- a/src/pkg/runtime/openbsd/defs.c
+++ /dev/null
@@ -1,103 +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.
-
-/*
- * Input to godefs.
- *
- godefs -f -m64 defs.c >amd64/defs.h
- godefs -f -m32 defs.c >386/defs.h
- */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/unistd.h>
-#include <sys/signal.h>
-#include <machine/mcontext.h>
-#include <errno.h>
-#include <signal.h>
-
-enum {
- $PROT_NONE = PROT_NONE,
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $PROT_EXEC = PROT_EXEC,
-
- $MAP_ANON = MAP_ANON,
- $MAP_PRIVATE = MAP_PRIVATE,
- $MAP_FIXED = MAP_FIXED,
-
- $SA_SIGINFO = SA_SIGINFO,
- $SA_RESTART = SA_RESTART,
- $SA_ONSTACK = SA_ONSTACK,
-
- $EINTR = EINTR,
-
- $SIGHUP = SIGHUP,
- $SIGINT = SIGINT,
- $SIGQUIT = SIGQUIT,
- $SIGILL = SIGILL,
- $SIGTRAP = SIGTRAP,
- $SIGABRT = SIGABRT,
- $SIGEMT = SIGEMT,
- $SIGFPE = SIGFPE,
- $SIGKILL = SIGKILL,
- $SIGBUS = SIGBUS,
- $SIGSEGV = SIGSEGV,
- $SIGSYS = SIGSYS,
- $SIGPIPE = SIGPIPE,
- $SIGALRM = SIGALRM,
- $SIGTERM = SIGTERM,
- $SIGURG = SIGURG,
- $SIGSTOP = SIGSTOP,
- $SIGTSTP = SIGTSTP,
- $SIGCONT = SIGCONT,
- $SIGCHLD = SIGCHLD,
- $SIGTTIN = SIGTTIN,
- $SIGTTOU = SIGTTOU,
- $SIGIO = SIGIO,
- $SIGXCPU = SIGXCPU,
- $SIGXFSZ = SIGXFSZ,
- $SIGVTALRM = SIGVTALRM,
- $SIGPROF = SIGPROF,
- $SIGWINCH = SIGWINCH,
- $SIGINFO = SIGINFO,
- $SIGUSR1 = SIGUSR1,
- $SIGUSR2 = SIGUSR2,
-
- $FPE_INTDIV = FPE_INTDIV,
- $FPE_INTOVF = FPE_INTOVF,
- $FPE_FLTDIV = FPE_FLTDIV,
- $FPE_FLTOVF = FPE_FLTOVF,
- $FPE_FLTUND = FPE_FLTUND,
- $FPE_FLTRES = FPE_FLTRES,
- $FPE_FLTINV = FPE_FLTINV,
- $FPE_FLTSUB = FPE_FLTSUB,
-
- $BUS_ADRALN = BUS_ADRALN,
- $BUS_ADRERR = BUS_ADRERR,
- $BUS_OBJERR = BUS_OBJERR,
-
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
-
- $ITIMER_REAL = ITIMER_REAL,
- $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
- $ITIMER_PROF = ITIMER_PROF,
-};
-
-typedef struct sigaltstack $Sigaltstack;
-typedef sigset_t $Sigset;
-typedef siginfo_t $Siginfo;
-typedef union sigval $Sigval;
-
-typedef stack_t $StackT;
-
-typedef struct timeval $Timeval;
-typedef struct itimerval $Itimerval;
-
-// This is a hack to avoid pulling in machine/fpu.h and struct fxsave64.
-typedef void $sfxsave64;
-
-typedef struct sigcontext $Sigcontext;
diff --git a/src/pkg/runtime/openbsd/os.h b/src/pkg/runtime/openbsd/os.h
deleted file mode 100644
index eba53b7cc..000000000
--- a/src/pkg/runtime/openbsd/os.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-
-struct sigaction;
-
-void runtime·sigpanic(void);
-void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
-void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void runtime·setitimerval(int32, Itimerval*, Itimerval*);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/openbsd/signals.h b/src/pkg/runtime/openbsd/signals.h
deleted file mode 100644
index 63a84671d..000000000
--- a/src/pkg/runtime/openbsd/signals.h
+++ /dev/null
@@ -1,52 +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.
-
-#define C SigCatch
-#define I SigIgnore
-#define R SigRestart
-#define Q SigQueue
-#define P SigPanic
-
-SigTab runtime·sigtab[] = {
- /* 0 */ 0, "SIGNONE: no trap",
- /* 1 */ Q+R, "SIGHUP: terminal line hangup",
- /* 2 */ Q+R, "SIGINT: interrupt",
- /* 3 */ C, "SIGQUIT: quit",
- /* 4 */ C, "SIGILL: illegal instruction",
- /* 5 */ C, "SIGTRAP: trace trap",
- /* 6 */ C, "SIGABRT: abort",
- /* 7 */ C, "SIGEMT: EMT instruction",
- /* 8 */ C+P, "SIGFPE: floating-point exception",
- /* 9 */ 0, "SIGKILL: kill",
- /* 10 */ C+P, "SIGBUS: bus error",
- /* 11 */ C+P, "SIGSEGV: segmentation violation",
- /* 12 */ C, "SIGSYS: bad system call",
- /* 13 */ I, "SIGPIPE: write to broken pipe",
- /* 14 */ Q+I+R, "SIGALRM: alarm clock",
- /* 15 */ Q+R, "SIGTERM: termination",
- /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
- /* 17 */ 0, "SIGSTOP: stop, unblockable",
- /* 18 */ Q+I+R, "SIGTSTP: stop from tty",
- /* 19 */ 0, "SIGCONT: continue",
- /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
- /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
- /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
- /* 23 */ Q+I+R, "SIGIO: i/o now possible",
- /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
- /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
- /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
- /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
- /* 28 */ Q+I+R, "SIGWINCH: window size change",
- /* 29 */ Q+I+R, "SIGINFO: information request",
- /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
- /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
- /* 32 */ Q+I+R, "SIGTHR: reserved",
-};
-#undef C
-#undef I
-#undef R
-#undef Q
-#undef P
-
-#define NSIG 33
diff --git a/src/pkg/runtime/openbsd/thread.c b/src/pkg/runtime/openbsd/thread.c
deleted file mode 100644
index 7e9ba5d67..000000000
--- a/src/pkg/runtime/openbsd/thread.c
+++ /dev/null
@@ -1,156 +0,0 @@
-// Use of this source file is governed by a BSD-style
-// license that can be found in the LICENSE file.`
-
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "stack.h"
-
-extern SigTab runtime·sigtab[];
-
-extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-extern void runtime·sys_sched_yield(void);
-
-// Basic spinlocks using CAS. We can improve on these later.
-static void
-lock(Lock *l)
-{
- uint32 v;
- int32 ret;
-
- for(;;) {
- if(runtime·cas(&l->key, 0, 1))
- return;
- runtime·sys_sched_yield();
- }
-}
-
-static void
-unlock(Lock *l)
-{
- uint32 v;
- int32 ret;
-
- for (;;) {
- v = l->key;
- if((v&1) == 0)
- runtime·throw("unlock of unlocked lock");
- if(runtime·cas(&l->key, v, 0))
- break;
- }
-}
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks < 0)
- runtime·throw("lock count");
- m->locks++;
- lock(l);
-}
-
-void
-runtime·unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- runtime·throw("lock count");
- unlock(l);
-}
-
-// Event notifications.
-void
-runtime·noteclear(Note *n)
-{
- n->lock.key = 0;
- lock(&n->lock);
-}
-
-void
-runtime·notesleep(Note *n)
-{
- lock(&n->lock);
- unlock(&n->lock);
-}
-
-void
-runtime·notewakeup(Note *n)
-{
- unlock(&n->lock);
-}
-
-// From OpenBSD's sys/param.h
-#define RFPROC (1<<4) /* change child (else changes curproc) */
-#define RFMEM (1<<5) /* share `address space' */
-#define RFNOWAIT (1<<6) /* parent need not wait() on child */
-#define RFTHREAD (1<<13) /* create a thread, not a process */
-
-void
-runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- int32 flags;
- int32 ret;
-
- flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT;
-
- if (0) {
- runtime·printf(
- "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, m->id, m->tls[0], &m);
- }
-
- m->tls[0] = m->id; // so 386 asm can find it
-
- if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
- runtime·printf("runtime: is kern.rthreads disabled?\n");
-
- runtime·throw("runtime.newosproc");
- }
-}
-
-void
-runtime·osinit(void)
-{
-}
-
-void
-runtime·goenvs(void)
-{
- runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-void
-runtime·minit(void)
-{
- // Initialize signal handling
- m->gsignal = runtime·malg(32*1024);
- runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
-}
-
-void
-runtime·sigpanic(void)
-{
- switch(g->sig) {
- case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- runtime·panicstring("invalid memory address or nil pointer dereference");
- runtime·printf("unexpected fault address %p\n", g->sigcode1);
- runtime·throw("fault");
- case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
- runtime·panicstring("invalid memory address or nil pointer dereference");
- runtime·printf("unexpected fault address %p\n", g->sigcode1);
- runtime·throw("fault");
- case SIGFPE:
- switch(g->sigcode0) {
- case FPE_INTDIV:
- runtime·panicstring("integer divide by zero");
- case FPE_INTOVF:
- runtime·panicstring("integer overflow");
- }
- runtime·panicstring("floating point error");
- }
- runtime·panicstring(runtime·sigtab[g->sig].name);
-}
diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/os_darwin.h
index db3c2e8a7..eb5d2daa3 100644
--- a/src/pkg/runtime/darwin/os.h
+++ b/src/pkg/runtime/os_darwin.h
@@ -9,7 +9,7 @@ int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void));
void runtime·bsdthread_register(void);
int32 runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
uint32 runtime·mach_reply_port(void);
-void runtime·mach_semacquire(uint32);
+int32 runtime·mach_semacquire(uint32, int64);
uint32 runtime·mach_semcreate(void);
void runtime·mach_semdestroy(uint32);
void runtime·mach_semrelease(uint32);
@@ -18,9 +18,15 @@ uint32 runtime·mach_task_self(void);
uint32 runtime·mach_task_self(void);
uint32 runtime·mach_thread_self(void);
uint32 runtime·mach_thread_self(void);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+typedef uint32 Sigset;
+void runtime·sigprocmask(int32, Sigset*, Sigset*);
struct Sigaction;
void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
struct StackT;
void runtime·sigaltstack(struct StackT*, struct StackT*);
@@ -29,3 +35,10 @@ void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·raisesigpipe(void);
+
+#define NSIG 32
+#define SI_USER 0 /* empirically true, but not what headers say */
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h
new file mode 100644
index 000000000..5e8de5434
--- /dev/null
+++ b/src/pkg/runtime/os_freebsd.h
@@ -0,0 +1,26 @@
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+int32 runtime·thr_new(ThrParam*, int32);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+struct sigaction;
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·sigprocmask(Sigset *, Sigset *);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+void runtime·raisesigpipe(void);
+
+#define NSIG 33
+#define SI_USER 0
+
+#define RLIMIT_AS 10
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+ int64 rlim_cur;
+ int64 rlim_max;
+};
+int32 runtime·getrlimit(int32, Rlimit*);
diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/os_linux.h
index 0bb8d0339..87daa3bb1 100644
--- a/src/pkg/runtime/linux/os.h
+++ b/src/pkg/runtime/os_linux.h
@@ -11,9 +11,33 @@ int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·raisesigpipe(void);
+
+#define NSIG 65
+#define SI_USER 0
+
+// It's hard to tease out exactly how big a Sigset is, but
+// rt_sigprocmask crashes if we get it wrong, so if binaries
+// are running, this is right.
+typedef struct Sigset Sigset;
+struct Sigset
+{
+ uint32 mask[2];
+};
+void runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
+#define SIG_SETMASK 2
+
+#define RLIMIT_AS 9
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+ uintptr rlim_cur;
+ uintptr rlim_max;
+};
+int32 runtime·getrlimit(int32, Rlimit*);
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
new file mode 100644
index 000000000..4ecf78d88
--- /dev/null
+++ b/src/pkg/runtime/os_netbsd.h
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+struct sigaction;
+
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+void runtime·raisesigpipe(void);
+
+#define NSIG 33
+#define SI_USER 0
diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h
new file mode 100644
index 000000000..4ecf78d88
--- /dev/null
+++ b/src/pkg/runtime/os_openbsd.h
@@ -0,0 +1,21 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+struct sigaction;
+
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+void runtime·raisesigpipe(void);
+
+#define NSIG 33
+#define SI_USER 0
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/os_plan9.h
index b2f7357ec..cc6343c8e 100644
--- a/src/pkg/runtime/plan9/os.h
+++ b/src/pkg/runtime/os_plan9.h
@@ -2,16 +2,30 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes);
-extern void runtime·exits(int8* msg);
-extern int32 runtime·brk_(void*);
+// Plan 9-specific system calls
+int32 runtime·open(uint8 *file, int32 mode);
+int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset);
+int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset);
+int32 runtime·read(int32 fd, void *buf, int32 nbytes);
+int32 runtime·close(int32 fd);
+void runtime·exits(int8* msg);
+int32 runtime·brk_(void*);
+int32 runtime·sleep(int32 ms);
+int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
+int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
+int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
/* open */
enum
{
- OREAD = 0,
- OWRITE = 1,
- ORDWR = 2
+ OREAD = 0,
+ OWRITE = 1,
+ ORDWR = 2,
+ OEXEC = 3,
+ OTRUNC = 16,
+ OCEXEC = 32,
+ ORCLOSE = 64,
+ OEXCL = 0x1000
};
/* rfork */
@@ -52,6 +66,4 @@ struct Tos {
/* top of stack is here */
};
-extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
-extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
-extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
+#define NSIG 1
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/os_windows.h
index bc9678733..9d387b7ad 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/os_windows.h
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-extern void *runtime·LoadLibraryEx;
+extern void *runtime·LoadLibrary;
extern void *runtime·GetProcAddress;
// Call a Windows function with stdcall conventions,
@@ -10,12 +10,11 @@ extern void *runtime·GetProcAddress;
#pragma varargck countpos runtime·stdcall 2
#pragma varargck type runtime·stdcall void*
#pragma varargck type runtime·stdcall uintptr
-void *runtime·stdcall_raw(void *fn, uintptr nargs, void *args);
+void runtime·asmstdcall(void *c);
void *runtime·stdcall(void *fn, int32 count, ...);
-uintptr runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err);
-uintptr runtime·getlasterror(void);
-void runtime·setlasterror(uintptr err);
+uint32 runtime·getlasterror(void);
+void runtime·setlasterror(uint32 err);
// Function to be called by windows CreateThread
// to start new os thread.
@@ -28,3 +27,6 @@ uint32 runtime·ctrlhandler(uint32 type);
// Windows dll function to go callback entry.
byte *runtime·compilecallback(Eface fn, bool cleanstack);
void *runtime·callbackasm(void);
+
+// TODO(brainman): should not need those
+#define NSIG 65
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
deleted file mode 100644
index 776989242..000000000
--- a/src/pkg/runtime/plan9/thread.c
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-#include "os.h"
-
-int8 *goos = "plan9";
-
-void
-runtime·minit(void)
-{
-}
-
-void
-runtime·osinit(void)
-{
-}
-
-void
-runtime·goenvs(void)
-{
-}
-
-void
-runtime·initsig(int32 queue)
-{
-}
-
-extern Tos *_tos;
-void
-runtime·exit(int32)
-{
- int32 fd;
- uint8 buf[128];
- uint8 tmp[16];
- uint8 *p, *q;
- int32 pid;
-
- runtime·memclr(buf, sizeof buf);
- runtime·memclr(tmp, sizeof tmp);
- pid = _tos->pid;
-
- /* build path string /proc/pid/notepg */
- for(q=tmp; pid > 0;) {
- *q++ = '0' + (pid%10);
- pid = pid/10;
- }
- p = buf;
- runtime·memmove((void*)p, (void*)"/proc/", 6);
- p += 6;
- for(q--; q >= tmp;)
- *p++ = *q--;
- runtime·memmove((void*)p, (void*)"/notepg", 7);
-
- /* post interrupt note */
- fd = runtime·open(buf, OWRITE);
- runtime·write(fd, "interrupt", 9);
- runtime·exits(nil);
-}
-
-void
-runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- m->tls[0] = m->id; // so 386 asm can find it
- if(0){
- runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
- }
-
- if (runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0 )
- runtime·throw("newosproc: rfork failed");
-}
-
-// Blocking locks.
-
-// Implement Locks, using semaphores.
-// l->key is the number of threads who want the lock.
-// In a race, one thread increments l->key from 0 to 1
-// and the others increment it from >0 to >1. The thread
-// who does the 0->1 increment gets the lock, and the
-// others wait on the semaphore. When the 0->1 thread
-// releases the lock by decrementing l->key, l->key will
-// be >0, so it will increment the semaphore to wake up
-// one of the others. This is the same algorithm used
-// in Plan 9's user-level locks.
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks < 0)
- runtime·throw("lock count");
- m->locks++;
-
- if(runtime·xadd(&l->key, 1) == 1)
- return; // changed from 0 -> 1; we hold lock
- // otherwise wait in kernel
- while(runtime·plan9_semacquire(&l->sema, 1) < 0) {
- /* interrupted; try again */
- }
-}
-
-void
-runtime·unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- runtime·throw("lock count");
-
- if(runtime·xadd(&l->key, -1) == 0)
- return; // changed from 1 -> 0: no contention
-
- runtime·plan9_semrelease(&l->sema, 1);
-}
-
-
-// User-level semaphore implementation:
-// try to do the operations in user space on u,
-// but when it's time to block, fall back on the kernel semaphore k.
-// This is the same algorithm used in Plan 9.
-void
-runtime·usemacquire(Usema *s)
-{
- if((int32)runtime·xadd(&s->u, -1) < 0)
- while(runtime·plan9_semacquire(&s->k, 1) < 0) {
- /* interrupted; try again */
- }
-}
-
-void
-runtime·usemrelease(Usema *s)
-{
- if((int32)runtime·xadd(&s->u, 1) <= 0)
- runtime·plan9_semrelease(&s->k, 1);
-}
-
-
-// Event notifications.
-void
-runtime·noteclear(Note *n)
-{
- n->wakeup = 0;
-}
-
-void
-runtime·notesleep(Note *n)
-{
- while(!n->wakeup)
- runtime·usemacquire(&n->sema);
-}
-
-void
-runtime·notewakeup(Note *n)
-{
- n->wakeup = 1;
- runtime·usemrelease(&n->sema);
-}
-
-void
-os·sigpipe(void)
-{
- runtime·throw("too many writes on closed pipe");
-}
-
-/*
- * placeholder - once notes are implemented,
- * a signal generating a panic must appear as
- * a call to this function for correct handling by
- * traceback.
- */
-void
-runtime·sigpanic(void)
-{
-}
diff --git a/src/pkg/runtime/pprof/Makefile b/src/pkg/runtime/pprof/Makefile
deleted file mode 100644
index 8bccc0cc0..000000000
--- a/src/pkg/runtime/pprof/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=runtime/pprof
-GOFILES=\
- pprof.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
index fdeceb4e8..f67e8a8f9 100644
--- a/src/pkg/runtime/pprof/pprof.go
+++ b/src/pkg/runtime/pprof/pprof.go
@@ -10,17 +10,354 @@ package pprof
import (
"bufio"
+ "bytes"
"fmt"
"io"
- "os"
"runtime"
+ "sort"
+ "strings"
"sync"
+ "text/tabwriter"
)
-// WriteHeapProfile writes a pprof-formatted heap profile to w.
-// If a write to w returns an error, WriteHeapProfile returns that error.
-// Otherwise, WriteHeapProfile returns nil.
-func WriteHeapProfile(w io.Writer) os.Error {
+// BUG(rsc): A bug in the OS X Snow Leopard 64-bit kernel prevents
+// CPU profiling from giving accurate results on that system.
+
+// A Profile is a collection of stack traces showing the call sequences
+// that led to instances of a particular event, such as allocation.
+// Packages can create and maintain their own profiles; the most common
+// use is for tracking resources that must be explicitly closed, such as files
+// or network connections.
+//
+// A Profile's methods can be called from multiple goroutines simultaneously.
+//
+// Each Profile has a unique name. A few profiles are predefined:
+//
+// goroutine - stack traces of all current goroutines
+// heap - a sampling of all heap allocations
+// threadcreate - stack traces that led to the creation of new OS threads
+//
+// These predefine profiles maintain themselves and panic on an explicit
+// Add or Remove method call.
+//
+// The CPU profile is not available as a Profile. It has a special API,
+// the StartCPUProfile and StopCPUProfile functions, because it streams
+// output to a writer during profiling.
+//
+type Profile struct {
+ name string
+ mu sync.Mutex
+ m map[interface{}][]uintptr
+ count func() int
+ write func(io.Writer, int) error
+}
+
+// profiles records all registered profiles.
+var profiles struct {
+ mu sync.Mutex
+ m map[string]*Profile
+}
+
+var goroutineProfile = &Profile{
+ name: "goroutine",
+ count: countGoroutine,
+ write: writeGoroutine,
+}
+
+var threadcreateProfile = &Profile{
+ name: "threadcreate",
+ count: countThreadCreate,
+ write: writeThreadCreate,
+}
+
+var heapProfile = &Profile{
+ name: "heap",
+ count: countHeap,
+ write: writeHeap,
+}
+
+func lockProfiles() {
+ profiles.mu.Lock()
+ if profiles.m == nil {
+ // Initial built-in profiles.
+ profiles.m = map[string]*Profile{
+ "goroutine": goroutineProfile,
+ "threadcreate": threadcreateProfile,
+ "heap": heapProfile,
+ }
+ }
+}
+
+func unlockProfiles() {
+ profiles.mu.Unlock()
+}
+
+// NewProfile creates a new profile with the given name.
+// If a profile with that name already exists, NewProfile panics.
+// The convention is to use a 'import/path.' prefix to create
+// separate name spaces for each package.
+func NewProfile(name string) *Profile {
+ lockProfiles()
+ defer unlockProfiles()
+ if name == "" {
+ panic("pprof: NewProfile with empty name")
+ }
+ if profiles.m[name] != nil {
+ panic("pprof: NewProfile name already in use: " + name)
+ }
+ p := &Profile{
+ name: name,
+ m: map[interface{}][]uintptr{},
+ }
+ profiles.m[name] = p
+ return p
+}
+
+// Lookup returns the profile with the given name, or nil if no such profile exists.
+func Lookup(name string) *Profile {
+ lockProfiles()
+ defer unlockProfiles()
+ return profiles.m[name]
+}
+
+// Profiles returns a slice of all the known profiles, sorted by name.
+func Profiles() []*Profile {
+ lockProfiles()
+ defer unlockProfiles()
+
+ var all []*Profile
+ for _, p := range profiles.m {
+ all = append(all, p)
+ }
+
+ sort.Sort(byName(all))
+ return all
+}
+
+type byName []*Profile
+
+func (x byName) Len() int { return len(x) }
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byName) Less(i, j int) bool { return x[i].name < x[j].name }
+
+// Name returns this profile's name, which can be passed to Lookup to reobtain the profile.
+func (p *Profile) Name() string {
+ return p.name
+}
+
+// Count returns the number of execution stacks currently in the profile.
+func (p *Profile) Count() int {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.count != nil {
+ return p.count()
+ }
+ return len(p.m)
+}
+
+// Add adds the current execution stack to the profile, associated with value.
+// Add stores value in an internal map, so value must be suitable for use as
+// a map key and will not be garbage collected until the corresponding
+// call to Remove. Add panics if the profile already contains a stack for value.
+//
+// The skip parameter has the same meaning as runtime.Caller's skip
+// and controls where the stack trace begins. Passing skip=0 begins the
+// trace in the function calling Add. For example, given this
+// execution stack:
+//
+// Add
+// called from rpc.NewClient
+// called from mypkg.Run
+// called from main.main
+//
+// Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient.
+// Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run.
+//
+func (p *Profile) Add(value interface{}, skip int) {
+ if p.name == "" {
+ panic("pprof: use of uninitialized Profile")
+ }
+ if p.write != nil {
+ panic("pprof: Add called on built-in Profile " + p.name)
+ }
+
+ stk := make([]uintptr, 32)
+ n := runtime.Callers(skip+1, stk[:])
+
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.m[value] != nil {
+ panic("pprof: Profile.Add of duplicate value")
+ }
+ p.m[value] = stk[:n]
+}
+
+// Remove removes the execution stack associated with value from the profile.
+// It is a no-op if the value is not in the profile.
+func (p *Profile) Remove(value interface{}) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ delete(p.m, value)
+}
+
+// WriteTo writes a pprof-formatted snapshot of the profile to w.
+// If a write to w returns an error, WriteTo returns that error.
+// Otherwise, WriteTo returns nil.
+//
+// The debug parameter enables additional output.
+// Passing debug=0 prints only the hexadecimal addresses that pprof needs.
+// Passing debug=1 adds comments translating addresses to function names
+// and line numbers, so that a programmer can read the profile without tools.
+//
+// The predefined profiles may assign meaning to other debug values;
+// for example, when printing the "goroutine" profile, debug=2 means to
+// print the goroutine stacks in the same form that a Go program uses
+// when dying due to an unrecovered panic.
+func (p *Profile) WriteTo(w io.Writer, debug int) error {
+ if p.name == "" {
+ panic("pprof: use of zero Profile")
+ }
+ if p.write != nil {
+ return p.write(w, debug)
+ }
+
+ // Obtain consistent snapshot under lock; then process without lock.
+ var all [][]uintptr
+ p.mu.Lock()
+ for _, stk := range p.m {
+ all = append(all, stk)
+ }
+ p.mu.Unlock()
+
+ // Map order is non-deterministic; make output deterministic.
+ sort.Sort(stackProfile(all))
+
+ return printCountProfile(w, debug, p.name, stackProfile(all))
+}
+
+type stackProfile [][]uintptr
+
+func (x stackProfile) Len() int { return len(x) }
+func (x stackProfile) Stack(i int) []uintptr { return x[i] }
+func (x stackProfile) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x stackProfile) Less(i, j int) bool {
+ t, u := x[i], x[j]
+ for k := 0; k < len(t) && k < len(u); k++ {
+ if t[k] != u[k] {
+ return t[k] < u[k]
+ }
+ }
+ return len(t) < len(u)
+}
+
+// A countProfile is a set of stack traces to be printed as counts
+// grouped by stack trace. There are multiple implementations:
+// all that matters is that we can find out how many traces there are
+// and obtain each trace in turn.
+type countProfile interface {
+ Len() int
+ Stack(i int) []uintptr
+}
+
+// printCountProfile prints a countProfile at the specified debug level.
+func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
+ fmt.Fprintf(w, "%s profile: total %d\n", name, p.Len())
+
+ // Build count of each stack.
+ var buf bytes.Buffer
+ key := func(stk []uintptr) string {
+ buf.Reset()
+ fmt.Fprintf(&buf, "@")
+ for _, pc := range stk {
+ fmt.Fprintf(&buf, " %#x", pc)
+ }
+ return buf.String()
+ }
+ m := map[string]int{}
+ n := p.Len()
+ for i := 0; i < n; i++ {
+ m[key(p.Stack(i))]++
+ }
+
+ // Print stacks, listing count on first occurrence of a unique stack.
+ for i := 0; i < n; i++ {
+ stk := p.Stack(i)
+ s := key(stk)
+ if count := m[s]; count != 0 {
+ fmt.Fprintf(w, "%d %s\n", count, s)
+ if debug > 0 {
+ printStackRecord(w, stk, false)
+ }
+ delete(m, s)
+ }
+ }
+
+ if tw != nil {
+ tw.Flush()
+ }
+ return b.Flush()
+}
+
+// printStackRecord prints the function + source line information
+// for a single stack trace.
+func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
+ show := allFrames
+ for _, pc := range stk {
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ show = true
+ fmt.Fprintf(w, "#\t%#x\n", pc)
+ } else {
+ file, line := f.FileLine(pc)
+ name := f.Name()
+ // Hide runtime.goexit and any runtime functions at the beginning.
+ // This is useful mainly for allocation traces.
+ if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
+ continue
+ }
+ show = true
+ fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, f.Name(), pc-f.Entry(), file, line)
+ }
+ }
+ if !show {
+ // We didn't print anything; do it again,
+ // and this time include runtime functions.
+ printStackRecord(w, stk, true)
+ return
+ }
+ fmt.Fprintf(w, "\n")
+}
+
+// Interface to system profiles.
+
+type byInUseBytes []runtime.MemProfileRecord
+
+func (x byInUseBytes) Len() int { return len(x) }
+func (x byInUseBytes) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byInUseBytes) Less(i, j int) bool { return x[i].InUseBytes() > x[j].InUseBytes() }
+
+// WriteHeapProfile is shorthand for Lookup("heap").WriteTo(w, 0).
+// It is preserved for backwards compatibility.
+func WriteHeapProfile(w io.Writer) error {
+ return writeHeap(w, 0)
+}
+
+// countHeap returns the number of records in the heap profile.
+func countHeap() int {
+ n, _ := runtime.MemProfile(nil, false)
+ return n
+}
+
+// writeHeapProfile writes the current runtime heap profile to w.
+func writeHeap(w io.Writer, debug int) error {
// Find out how many records there are (MemProfile(nil, false)),
// allocate that many records, and get the data.
// There's a race—more records might be added between
@@ -42,6 +379,16 @@ func WriteHeapProfile(w io.Writer) os.Error {
// Profile grew; try again.
}
+ sort.Sort(byInUseBytes(p))
+
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
var total runtime.MemProfileRecord
for i := range p {
r := &p[i]
@@ -54,59 +401,135 @@ func WriteHeapProfile(w io.Writer) os.Error {
// Technically the rate is MemProfileRate not 2*MemProfileRate,
// but early versions of the C++ heap profiler reported 2*MemProfileRate,
// so that's what pprof has come to expect.
- b := bufio.NewWriter(w)
- fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
+ fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
total.InUseObjects(), total.InUseBytes(),
total.AllocObjects, total.AllocBytes,
2*runtime.MemProfileRate)
for i := range p {
r := &p[i]
- fmt.Fprintf(b, "%d: %d [%d: %d] @",
+ fmt.Fprintf(w, "%d: %d [%d: %d] @",
r.InUseObjects(), r.InUseBytes(),
r.AllocObjects, r.AllocBytes)
for _, pc := range r.Stack() {
- fmt.Fprintf(b, " %#x", pc)
+ fmt.Fprintf(w, " %#x", pc)
+ }
+ fmt.Fprintf(w, "\n")
+ if debug > 0 {
+ printStackRecord(w, r.Stack(), false)
}
- fmt.Fprintf(b, "\n")
}
// Print memstats information too.
- // Pprof will ignore, but useful for people.
- s := &runtime.MemStats
- fmt.Fprintf(b, "\n# runtime.MemStats\n")
- fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
- fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
- fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
- fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
- fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
-
- fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
- fmt.Fprintf(b, "# HeapSys = %d\n", s.HeapSys)
- fmt.Fprintf(b, "# HeapIdle = %d\n", s.HeapIdle)
- fmt.Fprintf(b, "# HeapInuse = %d\n", s.HeapInuse)
-
- fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
- fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
- fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
- fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys)
-
- fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
- fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
- fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
- fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
- fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
-
- fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
- fmt.Fprintf(b, "# (Excluding large blocks.)\n")
- for _, t := range s.BySize {
- if t.Mallocs > 0 {
- fmt.Fprintf(b, "# %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
- }
+ // Pprof will ignore, but useful for people
+ if debug > 0 {
+ s := new(runtime.MemStats)
+ runtime.ReadMemStats(s)
+ fmt.Fprintf(w, "\n# runtime.MemStats\n")
+ fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
+ fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
+ fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
+ fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
+ fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
+
+ fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
+ fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
+ fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
+ fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
+
+ fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+ fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+ fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+ fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+ fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+ fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+ fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+ fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
+ fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
+ }
+
+ if tw != nil {
+ tw.Flush()
}
return b.Flush()
}
+// countThreadCreate returns the size of the current ThreadCreateProfile.
+func countThreadCreate() int {
+ n, _ := runtime.ThreadCreateProfile(nil)
+ return n
+}
+
+// writeThreadCreate writes the current runtime ThreadCreateProfile to w.
+func writeThreadCreate(w io.Writer, debug int) error {
+ return writeRuntimeProfile(w, debug, "threadcreate", runtime.ThreadCreateProfile)
+}
+
+// countGoroutine returns the number of goroutines.
+func countGoroutine() int {
+ return runtime.NumGoroutine()
+}
+
+// writeGoroutine writes the current runtime GoroutineProfile to w.
+func writeGoroutine(w io.Writer, debug int) error {
+ if debug >= 2 {
+ return writeGoroutineStacks(w)
+ }
+ return writeRuntimeProfile(w, debug, "goroutine", runtime.GoroutineProfile)
+}
+
+func writeGoroutineStacks(w io.Writer) error {
+ // We don't know how big the buffer needs to be to collect
+ // all the goroutines. Start with 1 MB and try a few times, doubling each time.
+ // Give up and use a truncated trace if 64 MB is not enough.
+ buf := make([]byte, 1<<20)
+ for i := 0; ; i++ {
+ n := runtime.Stack(buf, true)
+ if n < len(buf) {
+ buf = buf[:n]
+ break
+ }
+ if len(buf) >= 64<<20 {
+ // Filled 64 MB - stop there.
+ break
+ }
+ buf = make([]byte, 2*len(buf))
+ }
+ _, err := w.Write(buf)
+ return err
+}
+
+func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord) (int, bool)) error {
+ // Find out how many records there are (fetch(nil)),
+ // allocate that many records, and get the data.
+ // There's a race—more records might be added between
+ // the two calls—so allocate a few extra records for safety
+ // and also try again if we're very unlucky.
+ // The loop should only execute one iteration in the common case.
+ var p []runtime.StackRecord
+ n, ok := fetch(nil)
+ for {
+ // Allocate room for a slightly bigger profile,
+ // in case a few more entries have been added
+ // since the call to ThreadProfile.
+ p = make([]runtime.StackRecord, n+10)
+ n, ok = fetch(p)
+ if ok {
+ p = p[0:n]
+ break
+ }
+ // Profile grew; try again.
+ }
+
+ return printCountProfile(w, debug, name, runtimeProfile(p))
+}
+
+type runtimeProfile []runtime.StackRecord
+
+func (p runtimeProfile) Len() int { return len(p) }
+func (p runtimeProfile) Stack(i int) []uintptr { return p[i].Stack() }
+
var cpu struct {
sync.Mutex
profiling bool
@@ -116,7 +539,7 @@ var cpu struct {
// StartCPUProfile enables CPU profiling for the current process.
// While profiling, the profile will be buffered and written to w.
// StartCPUProfile returns an error if profiling is already enabled.
-func StartCPUProfile(w io.Writer) os.Error {
+func StartCPUProfile(w io.Writer) error {
// The runtime routines allow a variable profiling rate,
// but in practice operating systems cannot trigger signals
// at more than about 500 Hz, and our processing of the
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index 4486d5525..82bb2a292 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -7,6 +7,7 @@ package pprof_test
import (
"bytes"
"hash/crc32"
+ "os/exec"
"runtime"
. "runtime/pprof"
"strings"
@@ -17,14 +18,20 @@ import (
func TestCPUProfile(t *testing.T) {
switch runtime.GOOS {
case "darwin":
- // see Apple Bug Report #9177434 (copied into change description)
- return
+ out, err := exec.Command("uname", "-a").CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ vers := string(out)
+ t.Logf("uname -a: %v", vers)
+ // Lion uses "Darwin Kernel Version 11".
+ if strings.Contains(vers, "Darwin Kernel Version 10") && strings.Contains(vers, "RELEASE_X86_64") {
+ t.Logf("skipping test on known-broken kernel (64-bit Leopard / Snow Leopard)")
+ return
+ }
case "plan9":
// unimplemented
return
- case "windows":
- // unimplemented
- return
}
buf := make([]byte, 100000)
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index 3ce779495..6702c3cde 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -9,6 +9,26 @@
static void vprintf(int8*, byte*);
+// write to goroutine-local buffer if diverting output,
+// or else standard error.
+static void
+gwrite(void *v, int32 n)
+{
+ if(g == nil || g->writebuf == nil) {
+ runtime·write(2, v, n);
+ return;
+ }
+
+ if(g->writenbuf == 0)
+ return;
+
+ if(n > g->writenbuf)
+ n = g->writenbuf;
+ runtime·memmove(g->writebuf, v, n);
+ g->writebuf += n;
+ g->writenbuf -= n;
+}
+
void
runtime·dump(byte *p, int32 n)
{
@@ -29,7 +49,7 @@ runtime·dump(byte *p, int32 n)
void
runtime·prints(int8 *s)
{
- runtime·write(2, s, runtime·findnull((byte*)s));
+ gwrite(s, runtime·findnull((byte*)s));
}
#pragma textflag 7
@@ -51,7 +71,7 @@ vprintf(int8 *s, byte *base)
uintptr arg, narg;
byte *v;
-// lock(&debuglock);
+ //runtime·lock(&debuglock);
lp = p = s;
arg = 0;
@@ -59,7 +79,7 @@ vprintf(int8 *s, byte *base)
if(*p != '%')
continue;
if(p > lp)
- runtime·write(2, lp, p-lp);
+ gwrite(lp, p-lp);
p++;
narg = 0;
switch(*p) {
@@ -150,9 +170,9 @@ vprintf(int8 *s, byte *base)
lp = p+1;
}
if(p > lp)
- runtime·write(2, lp, p-lp);
+ gwrite(lp, p-lp);
-// unlock(&debuglock);
+ //runtime·unlock(&debuglock);
}
#pragma textflag 7
@@ -176,10 +196,10 @@ void
runtime·printbool(bool v)
{
if(v) {
- runtime·write(2, (byte*)"true", 4);
+ gwrite((byte*)"true", 4);
return;
}
- runtime·write(2, (byte*)"false", 5);
+ gwrite((byte*)"false", 5);
}
void
@@ -190,15 +210,15 @@ runtime·printfloat(float64 v)
float64 h;
if(runtime·isNaN(v)) {
- runtime·write(2, "NaN", 3);
+ gwrite("NaN", 3);
return;
}
if(runtime·isInf(v, 1)) {
- runtime·write(2, "+Inf", 4);
+ gwrite("+Inf", 4);
return;
}
if(runtime·isInf(v, -1)) {
- runtime·write(2, "-Inf", 4);
+ gwrite("-Inf", 4);
return;
}
@@ -257,16 +277,16 @@ runtime·printfloat(float64 v)
buf[n+4] = (e/100) + '0';
buf[n+5] = (e/10)%10 + '0';
buf[n+6] = (e%10) + '0';
- runtime·write(2, buf, n+7);
+ gwrite(buf, n+7);
}
void
runtime·printcomplex(Complex128 v)
{
- runtime·write(2, "(", 1);
+ gwrite("(", 1);
runtime·printfloat(v.real);
runtime·printfloat(v.imag);
- runtime·write(2, "i)", 2);
+ gwrite("i)", 2);
}
void
@@ -281,14 +301,14 @@ runtime·printuint(uint64 v)
break;
v = v/10;
}
- runtime·write(2, buf+i, nelem(buf)-i);
+ gwrite(buf+i, nelem(buf)-i);
}
void
runtime·printint(int64 v)
{
if(v < 0) {
- runtime·write(2, "-", 1);
+ gwrite("-", 1);
v = -v;
}
runtime·printuint(v);
@@ -308,7 +328,7 @@ runtime·printhex(uint64 v)
buf[--i] = '0';
buf[--i] = 'x';
buf[--i] = '0';
- runtime·write(2, buf+i, nelem(buf)-i);
+ gwrite(buf+i, nelem(buf)-i);
}
void
@@ -323,23 +343,23 @@ runtime·printstring(String v)
extern uint32 runtime·maxstring;
if(v.len > runtime·maxstring) {
- runtime·write(2, "[invalid string]", 16);
+ gwrite("[invalid string]", 16);
return;
}
if(v.len > 0)
- runtime·write(2, v.str, v.len);
+ gwrite(v.str, v.len);
}
void
runtime·printsp(void)
{
- runtime·write(2, " ", 1);
+ gwrite(" ", 1);
}
void
runtime·printnl(void)
{
- runtime·write(2, "\n", 1);
+ gwrite("\n", 1);
}
void
@@ -348,4 +368,4 @@ runtime·typestring(Eface e, String s)
s = *e.type->string;
FLUSH(&s);
}
-
+
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 5f396b49f..04a992628 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -3,18 +3,16 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "arch.h"
-#include "defs.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
#include "malloc.h"
-#include "os.h"
+#include "os_GOOS.h"
#include "stack.h"
bool runtime·iscgo;
static void unwindstack(G*, byte*);
static void schedule(G*);
-static void acquireproc(void);
-static void releaseproc(void);
typedef struct Sched Sched;
@@ -70,9 +68,11 @@ struct Sched {
volatile uint32 atomic; // atomic scheduling word (see below)
- int32 predawn; // running initialization, don't run new g's.
int32 profilehz; // cpu profiling rate
+ bool init; // running initialization
+ bool lockmain; // init called runtime.LockOSThread
+
Note stopped; // one g can set waitstop and wait here for m's to stop
};
@@ -128,7 +128,9 @@ Sched runtime·sched;
int32 runtime·gomaxprocs;
bool runtime·singleproc;
-// An m that is waiting for notewakeup(&m->havenextg). This may be
+static bool canaddmcpu(void);
+
+// An m that is waiting for notewakeup(&m->havenextg). This may
// only be accessed while the scheduler lock is held. This is used to
// minimize the number of times we call notewakeup while the scheduler
// lock is held, since the m will normally move quickly to lock the
@@ -162,6 +164,9 @@ setmcpumax(uint32 n)
}
}
+// Keep trace of scavenger's goroutine for deadlock detection.
+static G *scvg;
+
// The bootstrap sequence is:
//
// call osinit
@@ -169,11 +174,7 @@ setmcpumax(uint32 n)
// make & queue new G
// call runtime·mstart
//
-// The new G does:
-//
-// call main·init_function
-// call initdone
-// call main·main
+// The new G calls runtime·main.
void
runtime·schedinit(void)
{
@@ -199,13 +200,53 @@ runtime·schedinit(void)
n = maxgomaxprocs;
runtime·gomaxprocs = n;
}
- setmcpumax(runtime·gomaxprocs);
+ // wait for the main goroutine to start before taking
+ // GOMAXPROCS into account.
+ setmcpumax(1);
runtime·singleproc = runtime·gomaxprocs == 1;
- runtime·sched.predawn = 1;
+ canaddmcpu(); // mcpu++ to account for bootstrap m
+ m->helpgc = 1; // flag to tell schedule() to mcpu--
+ runtime·sched.grunning++;
+
+ mstats.enablegc = 1;
m->nomemprof--;
}
+extern void main·init(void);
+extern void main·main(void);
+
+// The main goroutine.
+void
+runtime·main(void)
+{
+ // Lock the main goroutine onto this, the main OS thread,
+ // during initialization. Most programs won't care, but a few
+ // do require certain calls to be made by the main thread.
+ // Those can arrange for main.main to run in the main thread
+ // by calling runtime.LockOSThread during initialization
+ // to preserve the lock.
+ runtime·LockOSThread();
+ // From now on, newgoroutines may use non-main threads.
+ setmcpumax(runtime·gomaxprocs);
+ runtime·sched.init = true;
+ scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main);
+ main·init();
+ runtime·sched.init = false;
+ if(!runtime·sched.lockmain)
+ runtime·UnlockOSThread();
+
+ // The deadlock detection has false negatives.
+ // Let scvg start up, to eliminate the false negative
+ // for the trivial program func main() { select{} }.
+ runtime·gosched();
+
+ main·main();
+ runtime·exit(0);
+ for(;;)
+ *(int32*)runtime·main = 0;
+}
+
// Lock the scheduler.
static void
schedlock(void)
@@ -226,27 +267,45 @@ schedunlock(void)
runtime·notewakeup(&m->havenextg);
}
-// Called after main·init_function; main·main will be called on return.
void
-runtime·initdone(void)
+runtime·goexit(void)
{
- // Let's go.
- runtime·sched.predawn = 0;
- mstats.enablegc = 1;
-
- // If main·init_function started other goroutines,
- // kick off new m's to handle them, like ready
- // would have, had it not been pre-dawn.
- schedlock();
- matchmg();
- schedunlock();
+ g->status = Gmoribund;
+ runtime·gosched();
}
void
-runtime·goexit(void)
+runtime·goroutineheader(G *g)
{
- g->status = Gmoribund;
- runtime·gosched();
+ int8 *status;
+
+ switch(g->status) {
+ case Gidle:
+ status = "idle";
+ break;
+ case Grunnable:
+ status = "runnable";
+ break;
+ case Grunning:
+ status = "running";
+ break;
+ case Gsyscall:
+ status = "syscall";
+ break;
+ case Gwaiting:
+ if(g->waitreason)
+ status = g->waitreason;
+ else
+ status = "waiting";
+ break;
+ case Gmoribund:
+ status = "moribund";
+ break;
+ default:
+ status = "???";
+ break;
+ }
+ runtime·printf("goroutine %d [%s]:\n", g->goid, status);
}
void
@@ -257,7 +316,8 @@ runtime·tracebackothers(G *me)
for(g = runtime·allg; g != nil; g = g->alllink) {
if(g == me || g->status == Gdead)
continue;
- runtime·printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
+ runtime·printf("\n");
+ runtime·goroutineheader(g);
runtime·traceback(g->sched.pc, g->sched.sp, 0, g);
}
}
@@ -277,17 +337,22 @@ runtime·idlegoroutine(void)
static void
mcommoninit(M *m)
{
+ m->id = runtime·sched.mcount++;
+ m->fastrand = 0x49f6428aUL + m->id + runtime·cputicks();
+ m->stackalloc = runtime·malloc(sizeof(*m->stackalloc));
+ runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil);
+
+ if(m->mcache == nil)
+ m->mcache = runtime·allocmcache();
+
+ runtime·callers(1, m->createstack, nelem(m->createstack));
+
// Add to runtime·allm so garbage collector doesn't free m
// when it is just in a register or thread-local storage.
m->alllink = runtime·allm;
- // runtime·Cgocalls() iterates over allm w/o schedlock,
+ // runtime·NumCgoCall() iterates over allm w/o schedlock,
// so we need to publish it safely.
runtime·atomicstorep(&runtime·allm, m);
-
- m->id = runtime·sched.mcount++;
- m->fastrand = 0x49f6428aUL + m->id;
- m->stackalloc = runtime·malloc(sizeof(*m->stackalloc));
- runtime·FixAlloc_Init(m->stackalloc, FixedStack, runtime·SysAlloc, nil, nil);
}
// Try to increment mcpu. Report whether succeeded.
@@ -387,7 +452,7 @@ mget(G *g)
M *m;
// if g has its own m, use it.
- if((m = g->lockedm) != nil)
+ if(g && (m = g->lockedm) != nil)
return m;
// otherwise use general m pool.
@@ -428,8 +493,7 @@ readylocked(G *g)
g->status = Grunnable;
gput(g);
- if(!runtime·sched.predawn)
- matchmg();
+ matchmg();
}
static void
@@ -472,6 +536,7 @@ nextgandunlock(void)
G *gp;
uint32 v;
+top:
if(atomic_mcpu(runtime·sched.atomic) >= maxgomaxprocs)
runtime·throw("negative mcpu");
@@ -530,9 +595,27 @@ nextgandunlock(void)
mput(m);
}
- v = runtime·atomicload(&runtime·sched.atomic);
- if(runtime·sched.grunning == 0)
+ // Look for deadlock situation.
+ // There is a race with the scavenger that causes false negatives:
+ // if the scavenger is just starting, then we have
+ // scvg != nil && grunning == 0 && gwait == 0
+ // and we do not detect a deadlock. It is possible that we should
+ // add that case to the if statement here, but it is too close to Go 1
+ // to make such a subtle change. Instead, we work around the
+ // false negative in trivial programs by calling runtime.gosched
+ // from the main goroutine just before main.main.
+ // See runtime·main above.
+ //
+ // On a related note, it is also possible that the scvg == nil case is
+ // wrong and should include gwait, but that does not happen in
+ // standard Go programs, which all start the scavenger.
+ //
+ if((scvg == nil && runtime·sched.grunning == 0) ||
+ (scvg != nil && runtime·sched.grunning == 1 && runtime·sched.gwait == 0 &&
+ (scvg->status == Grunning || scvg->status == Gsyscall))) {
runtime·throw("all goroutines are asleep - deadlock!");
+ }
+
m->nextg = nil;
m->waitnextg = 1;
runtime·noteclear(&m->havenextg);
@@ -541,6 +624,7 @@ nextgandunlock(void)
// Entersyscall might have decremented mcpu too, but if so
// it will see the waitstop and take the slow path.
// Exitsyscall never increments mcpu beyond mcpumax.
+ v = runtime·atomicload(&runtime·sched.atomic);
if(atomic_waitstop(v) && atomic_mcpu(v) <= atomic_mcpumax(v)) {
// set waitstop = 0 (known to be 1)
runtime·xadd(&runtime·sched.atomic, -1<<waitstopShift);
@@ -549,12 +633,50 @@ nextgandunlock(void)
schedunlock();
runtime·notesleep(&m->havenextg);
+ if(m->helpgc) {
+ runtime·gchelper();
+ m->helpgc = 0;
+ runtime·lock(&runtime·sched);
+ goto top;
+ }
if((gp = m->nextg) == nil)
runtime·throw("bad m->nextg in nextgoroutine");
m->nextg = nil;
return gp;
}
+int32
+runtime·helpgc(bool *extra)
+{
+ M *mp;
+ int32 n, max;
+
+ // Figure out how many CPUs to use.
+ // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+ max = runtime·gomaxprocs;
+ if(max > runtime·ncpu)
+ max = runtime·ncpu;
+ if(max > MaxGcproc)
+ max = MaxGcproc;
+
+ // We're going to use one CPU no matter what.
+ // Figure out the max number of additional CPUs.
+ max--;
+
+ runtime·lock(&runtime·sched);
+ n = 0;
+ while(n < max && (mp = mget(nil)) != nil) {
+ n++;
+ mp->helpgc = 1;
+ mp->waitnextg = 0;
+ runtime·notewakeup(&mp->havenextg);
+ }
+ runtime·unlock(&runtime·sched);
+ if(extra)
+ *extra = n != max;
+ return n;
+}
+
void
runtime·stoptheworld(void)
{
@@ -591,15 +713,29 @@ runtime·stoptheworld(void)
schedunlock();
}
-// TODO(rsc): Remove. This is only temporary,
-// for the mark and sweep collector.
void
-runtime·starttheworld(void)
+runtime·starttheworld(bool extra)
{
+ M *m;
+
schedlock();
runtime·gcwaiting = 0;
setmcpumax(runtime·gomaxprocs);
matchmg();
+ if(extra && canaddmcpu()) {
+ // Start a new m that will (we hope) be idle
+ // and so available to help when the next
+ // garbage collection happens.
+ // canaddmcpu above did mcpu++
+ // (necessary, because m will be doing various
+ // initialization work so is definitely running),
+ // but m is not running a specific goroutine,
+ // so set the helpgc flag as a signal to m's
+ // first schedule(nil) to mcpu-- and grunning--.
+ m = runtime·newm();
+ m->helpgc = 1;
+ runtime·sched.grunning++;
+ }
schedunlock();
}
@@ -609,16 +745,20 @@ runtime·mstart(void)
{
if(g != m->g0)
runtime·throw("bad runtime·mstart");
- if(m->mcache == nil)
- m->mcache = runtime·allocmcache();
// Record top of stack for use by mcall.
// Once we call schedule we're never coming back,
// so other calls can reuse this stack space.
runtime·gosave(&m->g0->sched);
m->g0->sched.pc = (void*)-1; // make sure it is never used
-
+ runtime·asminit();
runtime·minit();
+
+ // Install signal handlers; after minit so that minit can
+ // prepare the thread to be able to handle the signals.
+ if(m == &runtime·m0)
+ runtime·initsig();
+
schedule(nil);
}
@@ -636,52 +776,60 @@ struct CgoThreadStart
};
// Kick off new m's as needed (up to mcpumax).
-// There are already `other' other cpus that will
-// start looking for goroutines shortly.
// Sched is locked.
static void
matchmg(void)
{
- G *g;
+ G *gp;
+ M *mp;
if(m->mallocing || m->gcing)
return;
while(haveg() && canaddmcpu()) {
- g = gget();
- if(g == nil)
+ gp = gget();
+ if(gp == nil)
runtime·throw("gget inconsistency");
- // Find the m that will run g.
- M *m;
- if((m = mget(g)) == nil){
- m = runtime·malloc(sizeof(M));
- mcommoninit(m);
-
- if(runtime·iscgo) {
- CgoThreadStart ts;
-
- if(libcgo_thread_start == nil)
- runtime·throw("libcgo_thread_start missing");
- // pthread_create will make us a stack.
- m->g0 = runtime·malg(-1);
- ts.m = m;
- ts.g = m->g0;
- ts.fn = runtime·mstart;
- runtime·asmcgocall(libcgo_thread_start, &ts);
- } else {
- if(Windows)
- // windows will layout sched stack on os stack
- m->g0 = runtime·malg(-1);
- else
- m->g0 = runtime·malg(8192);
- runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart);
- }
- }
- mnextg(m, g);
+ // Find the m that will run gp.
+ if((mp = mget(gp)) == nil)
+ mp = runtime·newm();
+ mnextg(mp, gp);
}
}
+// Create a new m. It will start off with a call to runtime·mstart.
+M*
+runtime·newm(void)
+{
+ M *m;
+
+ m = runtime·malloc(sizeof(M));
+ mcommoninit(m);
+
+ if(runtime·iscgo) {
+ CgoThreadStart ts;
+
+ if(libcgo_thread_start == nil)
+ runtime·throw("libcgo_thread_start missing");
+ // pthread_create will make us a stack.
+ m->g0 = runtime·malg(-1);
+ ts.m = m;
+ ts.g = m->g0;
+ ts.fn = runtime·mstart;
+ runtime·asmcgocall(libcgo_thread_start, &ts);
+ } else {
+ if(Windows)
+ // windows will layout sched stack on os stack
+ m->g0 = runtime·malg(-1);
+ else
+ m->g0 = runtime·malg(8192);
+ runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart);
+ }
+
+ return m;
+}
+
// One round of scheduler: find a goroutine and run it.
// The argument is the goroutine that was running before
// schedule was called, or nil if this is the first call.
@@ -694,9 +842,6 @@ schedule(G *gp)
schedlock();
if(gp != nil) {
- if(runtime·sched.predawn)
- runtime·throw("init rescheduling");
-
// Just finished running gp.
gp->m = nil;
runtime·sched.grunning--;
@@ -732,6 +877,19 @@ schedule(G *gp)
gp->readyonstop = 0;
readylocked(gp);
}
+ } else if(m->helpgc) {
+ // Bootstrap m or new m started by starttheworld.
+ // atomic { mcpu-- }
+ v = runtime·xadd(&runtime·sched.atomic, -1<<mcpuShift);
+ if(atomic_mcpu(v) > maxgomaxprocs)
+ runtime·throw("negative mcpu in scheduler");
+ // Compensate for increment in starttheworld().
+ runtime·sched.grunning--;
+ m->helpgc = 0;
+ } else if(m->nextg != nil) {
+ // New m started by matchmg.
+ } else {
+ runtime·throw("invalid m state in scheduler");
}
// Find (or wait for) g to run. Unlocks runtime·sched.
@@ -786,8 +944,8 @@ runtime·entersyscall(void)
{
uint32 v;
- if(runtime·sched.predawn)
- return;
+ if(m->profilehz > 0)
+ runtime·setprof(false);
// Leave SP around for gc and traceback.
runtime·gosave(&g->sched);
@@ -840,9 +998,6 @@ runtime·exitsyscall(void)
{
uint32 v;
- if(runtime·sched.predawn)
- return;
-
// Fast path.
// If we can do the mcpu++ bookkeeping and
// find that we still have mcpu <= mcpumax, then we can
@@ -855,6 +1010,9 @@ runtime·exitsyscall(void)
// Garbage collector isn't running (since we are),
// so okay to clear gcstack.
g->gcstack = nil;
+
+ if(m->profilehz > 0)
+ runtime·setprof(true);
return;
}
@@ -879,11 +1037,15 @@ runtime·exitsyscall(void)
g->gcstack = nil;
}
+// Called from runtime·lessstack when returning from a function which
+// allocated a new stack segment. The function's return value is in
+// m->cret.
void
runtime·oldstack(void)
{
Stktop *top, old;
uint32 argsize;
+ uintptr cret;
byte *sp;
G *g1;
int32 goid;
@@ -907,9 +1069,16 @@ runtime·oldstack(void)
g1->stackbase = old.stackbase;
g1->stackguard = old.stackguard;
- runtime·gogo(&old.gobuf, m->cret);
+ cret = m->cret;
+ m->cret = 0; // drop reference
+ runtime·gogo(&old.gobuf, cret);
}
+// Called from reflect·call or from runtime·morestack when a new
+// stack segment is needed. Allocate a new stack big enough for
+// m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
+// and then act as though runtime·lessstack called the function at
+// m->morepc.
void
runtime·newstack(void)
{
@@ -968,6 +1137,9 @@ runtime·newstack(void)
top->argp = m->moreargp;
top->argsize = argsize;
top->free = free;
+ m->moreargp = nil;
+ m->morebuf.pc = nil;
+ m->morebuf.sp = nil;
// copy flag from panic
top->panic = g1->ispanic;
@@ -979,7 +1151,7 @@ runtime·newstack(void)
sp = (byte*)top;
if(argsize > 0) {
sp -= argsize;
- runtime·memmove(sp, m->moreargp, argsize);
+ runtime·memmove(sp, top->argp, argsize);
}
if(thechar == '5') {
// caller would have saved its LR below args.
@@ -997,6 +1169,10 @@ runtime·newstack(void)
*(int32*)345 = 123; // never return
}
+// Hook used by runtime·malg to call runtime·stackalloc on the
+// scheduler stack. This exists because runtime·stackalloc insists
+// on being called on the scheduler stack, to avoid trying to grow
+// the stack while allocating a new stack segment.
static void
mstackalloc(G *gp)
{
@@ -1004,12 +1180,18 @@ mstackalloc(G *gp)
runtime·gogo(&gp->sched, 0);
}
+// Allocate a new g, with a stack big enough for stacksize bytes.
G*
runtime·malg(int32 stacksize)
{
G *newg;
byte *stk;
+ if(StackTop < sizeof(Stktop)) {
+ runtime·printf("runtime: SizeofStktop=%d, should be >=%d\n", (int32)StackTop, (int32)sizeof(Stktop));
+ runtime·throw("runtime: bad stack.h");
+ }
+
newg = runtime·malloc(sizeof(G));
if(stacksize >= 0) {
if(g == m->g0) {
@@ -1030,15 +1212,13 @@ runtime·malg(int32 stacksize)
return newg;
}
-/*
- * Newproc and deferproc need to be textflag 7
- * (no possible stack split when nearing overflow)
- * because they assume that the arguments to fn
- * are available sequentially beginning at &arg0.
- * If a stack split happened, only the one word
- * arg0 would be copied. It's okay if any functions
- * they call split the stack below the newproc frame.
- */
+// Create a new g running fn with siz bytes of arguments.
+// Put it on the queue of g's waiting to run.
+// The compiler turns a go statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred. It's OK for this to call
+// functions that split the stack.
#pragma textflag 7
void
runtime·newproc(int32 siz, byte* fn, ...)
@@ -1052,6 +1232,10 @@ runtime·newproc(int32 siz, byte* fn, ...)
runtime·newproc1(fn, argp, siz, 0, runtime·getcallerpc(&siz));
}
+// Create a new g running fn with narg bytes of arguments starting
+// at argp and returning nret bytes of results. callerpc is the
+// address of the go statement that created this. The new g is put
+// on the queue of g's waiting to run.
G*
runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
{
@@ -1062,7 +1246,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
//printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret);
siz = narg + nret;
siz = (siz+7) & ~7;
-
+
// We could instead create a secondary stack frame
// and make it look like goexit was on the original but
// the call to the actual goroutine function was split.
@@ -1073,15 +1257,18 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
schedlock();
if((newg = gfget()) != nil){
- newg->status = Gwaiting;
if(newg->stackguard - StackGuard != newg->stack0)
runtime·throw("invalid stack in newg");
} else {
newg = runtime·malg(StackMin);
- newg->status = Gwaiting;
- newg->alllink = runtime·allg;
- runtime·allg = newg;
+ if(runtime·lastg == nil)
+ runtime·allg = newg;
+ else
+ runtime·lastg->alllink = newg;
+ runtime·lastg = newg;
}
+ newg->status = Gwaiting;
+ newg->waitreason = "new goroutine";
sp = newg->stackbase;
sp -= siz;
@@ -1109,6 +1296,12 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
//printf(" goid=%d\n", newg->goid);
}
+// Create a new deferred function fn with siz bytes of arguments.
+// The compiler turns a defer statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred. It's OK for this to call
+// functions that split the stack.
#pragma textflag 7
uintptr
runtime·deferproc(int32 siz, byte* fn, ...)
@@ -1137,6 +1330,16 @@ runtime·deferproc(int32 siz, byte* fn, ...)
return 0;
}
+// Run a deferred function if there is one.
+// The compiler inserts a call to this at the end of any
+// function which calls defer.
+// If there is a deferred function, this will call runtime·jmpdefer,
+// which will jump to the deferred function such that it appears
+// to have been called by the caller of deferreturn at the point
+// just before deferreturn was called. The effect is that deferreturn
+// is called again and again until there are no more deferred functions.
+// Cannot split the stack because we reuse the caller's frame to
+// call the deferred function.
#pragma textflag 7
void
runtime·deferreturn(uintptr arg0)
@@ -1153,10 +1356,12 @@ runtime·deferreturn(uintptr arg0)
runtime·memmove(argp, d->args, d->siz);
g->defer = d->link;
fn = d->fn;
- runtime·free(d);
+ if(!d->nofree)
+ runtime·free(d);
runtime·jmpdefer(fn, argp);
}
+// Run all deferred functions for the current goroutine.
static void
rundefer(void)
{
@@ -1165,7 +1370,8 @@ rundefer(void)
while((d = g->defer) != nil) {
g->defer = d->link;
reflect·call(d->fn, d->args, d->siz);
- runtime·free(d);
+ if(!d->nofree)
+ runtime·free(d);
}
}
@@ -1197,6 +1403,7 @@ unwindstack(G *gp, byte *sp)
}
}
+// Print all currently active panics. Used when crashing.
static void
printpanics(Panic *p)
{
@@ -1213,6 +1420,7 @@ printpanics(Panic *p)
static void recovery(G*);
+// The implementation of the predeclared function panic.
void
runtime·panic(Eface e)
{
@@ -1245,7 +1453,8 @@ runtime·panic(Eface e)
runtime·mcall(recovery);
runtime·throw("recovery failed"); // mcall should not return
}
- runtime·free(d);
+ if(!d->nofree)
+ runtime·free(d);
}
// ran out of deferred calls - old-school panic now
@@ -1254,6 +1463,9 @@ runtime·panic(Eface e)
runtime·dopanic(0);
}
+// Unwind the stack after a deferred function calls recover
+// after a panic. Then arrange to continue running as though
+// the caller of the deferred function returned normally.
static void
recovery(G *gp)
{
@@ -1280,11 +1492,15 @@ recovery(G *gp)
else
gp->sched.sp = (byte*)d->argp - 2*sizeof(uintptr);
gp->sched.pc = d->pc;
- runtime·free(d);
+ if(!d->nofree)
+ runtime·free(d);
runtime·gogo(&gp->sched, 1);
}
-#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */
+// The implementation of the predeclared function recover.
+// Cannot split the stack because it needs to reliably
+// find the stack segment of its caller.
+#pragma textflag 7
void
runtime·recover(byte *argp, Eface ret)
{
@@ -1396,15 +1612,7 @@ runtime·Gosched(void)
runtime·gosched();
}
-void
-runtime·LockOSThread(void)
-{
- if(runtime·sched.predawn)
- runtime·throw("cannot wire during init");
- m->lockedg = g;
- g->lockedm = m;
-}
-
+// Implementation of runtime.GOMAXPROCS.
// delete when scheduler is stronger
int32
runtime·gomaxprocsfunc(int32 n)
@@ -1445,8 +1653,23 @@ runtime·gomaxprocsfunc(int32 n)
}
void
+runtime·LockOSThread(void)
+{
+ if(m == &runtime·m0 && runtime·sched.init) {
+ runtime·sched.lockmain = true;
+ return;
+ }
+ m->lockedg = g;
+ g->lockedm = m;
+}
+
+void
runtime·UnlockOSThread(void)
{
+ if(m == &runtime·m0 && runtime·sched.init) {
+ runtime·sched.lockmain = false;
+ return;
+ }
m->lockedg = nil;
g->lockedm = nil;
}
@@ -1457,6 +1680,14 @@ runtime·lockedOSThread(void)
return g->lockedm != nil && m->lockedg != nil;
}
+// for testing of callbacks
+void
+runtime·golockedOSThread(bool ret)
+{
+ ret = runtime·lockedOSThread();
+ FLUSH(&ret);
+}
+
// for testing of wire, unwire
void
runtime·mid(uint32 ret)
@@ -1466,13 +1697,19 @@ runtime·mid(uint32 ret)
}
void
-runtime·Goroutines(int32 ret)
+runtime·NumGoroutine(int32 ret)
{
ret = runtime·sched.gcount;
FLUSH(&ret);
}
int32
+runtime·gcount(void)
+{
+ return runtime·sched.gcount;
+}
+
+int32
runtime·mcount(void)
{
return runtime·sched.mcount;
@@ -1497,6 +1734,7 @@ static struct {
uintptr pcbuf[100];
} prof;
+// Called if we receive a SIGPROF signal.
void
runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
{
@@ -1516,6 +1754,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
runtime·unlock(&prof);
}
+// Arrange to call fn with a traceback hz times a second.
void
runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
{
@@ -1546,8 +1785,10 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
void (*libcgo_setenv)(byte**);
+// Update the C environment if cgo is loaded.
+// Called from syscall.Setenv.
void
-os·setenv_c(String k, String v)
+syscall·setenv_c(String k, String v)
{
byte *arg[2];
@@ -1562,7 +1803,7 @@ os·setenv_c(String k, String v)
runtime·memmove(arg[1], v.str, v.len);
arg[1][v.len] = 0;
- runtime·asmcgocall(libcgo_setenv, arg);
+ runtime·asmcgocall((void*)libcgo_setenv, arg);
runtime·free(arg[0]);
runtime·free(arg[1]);
}
diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/rt0_darwin_386.s
index 30b497f5e..30b497f5e 100644
--- a/src/pkg/runtime/darwin/386/rt0.s
+++ b/src/pkg/runtime/rt0_darwin_386.s
diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/rt0_darwin_amd64.s
index 4cfab5876..4cfab5876 100644
--- a/src/pkg/runtime/darwin/amd64/rt0.s
+++ b/src/pkg/runtime/rt0_darwin_amd64.s
diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/rt0_freebsd_386.s
index 3ca981b3a..3ca981b3a 100644
--- a/src/pkg/runtime/freebsd/386/rt0.s
+++ b/src/pkg/runtime/rt0_freebsd_386.s
diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/rt0_freebsd_amd64.s
index 5d2eeeeff..5d2eeeeff 100644
--- a/src/pkg/runtime/freebsd/amd64/rt0.s
+++ b/src/pkg/runtime/rt0_freebsd_amd64.s
diff --git a/src/pkg/runtime/rt0_linux_386.s b/src/pkg/runtime/rt0_linux_386.s
new file mode 100644
index 000000000..83149540e
--- /dev/null
+++ b/src/pkg/runtime/rt0_linux_386.s
@@ -0,0 +1,17 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_386_linux(SB),7,$0
+ CALL runtime·linux_setup_vdso(SB)
+ JMP _rt0_386(SB)
+
+TEXT _fallback_vdso(SB),7,$0
+ INT $0x80
+ RET
+
+DATA runtime·_vdso(SB)/4, $_fallback_vdso(SB)
+GLOBL runtime·_vdso(SB), $4
+
diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/rt0_linux_amd64.s
index dac9ae181..dac9ae181 100644
--- a/src/pkg/runtime/linux/amd64/rt0.s
+++ b/src/pkg/runtime/rt0_linux_amd64.s
diff --git a/src/pkg/runtime/rt0_linux_arm.s b/src/pkg/runtime/rt0_linux_arm.s
new file mode 100644
index 000000000..e08cf907d
--- /dev/null
+++ b/src/pkg/runtime/rt0_linux_arm.s
@@ -0,0 +1,60 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_arm_linux(SB),7,$-4
+ // We first need to detect the kernel ABI, and warn the user
+ // if the system only supports OABI
+ // The strategy here is to call some EABI syscall to see if
+ // SIGILL is received.
+ // To catch SIGILL, we have to first setup sigaction, this is
+ // a chicken-and-egg problem, because we can't do syscall if
+ // we don't know the kernel ABI... Oh, not really, we can do
+ // syscall in Thumb mode.
+
+ // set up sa_handler
+ MOVW $bad_abi<>(SB), R0 // sa_handler
+ MOVW $0, R1 // sa_flags
+ MOVW $0, R2 // sa_restorer
+ MOVW $0, R3 // sa_mask
+ MOVM.DB.W [R0-R3], (R13)
+ MOVW $4, R0 // SIGILL
+ MOVW R13, R1 // sa
+ MOVW $0, R2 // old_sa
+ MOVW $8, R3 // c
+ MOVW $174, R7 // sys_sigaction
+ BL oabi_syscall<>(SB)
+ ADD $16, R13
+ // do an EABI syscall
+ MOVW $20, R7 // sys_getpid
+ SWI $0 // this will trigger SIGILL on OABI systems
+
+ B _rt0_arm(SB)
+
+TEXT bad_abi<>(SB),7,$-4
+ // give diagnosis and exit
+ MOVW $2, R0 // stderr
+ MOVW $bad_abi_msg(SB), R1 // data
+ MOVW $45, R2 // len
+ MOVW $4, R7 // sys_write
+ BL oabi_syscall<>(SB)
+ MOVW $1, R0
+ MOVW $1, R7 // sys_exit
+ BL oabi_syscall<>(SB)
+ B 0(PC)
+
+DATA bad_abi_msg+0x00(SB)/8, $"This pro"
+DATA bad_abi_msg+0x08(SB)/8, $"gram can"
+DATA bad_abi_msg+0x10(SB)/8, $" only be"
+DATA bad_abi_msg+0x18(SB)/8, $" run on "
+DATA bad_abi_msg+0x20(SB)/8, $"EABI ker"
+DATA bad_abi_msg+0x28(SB)/4, $"nels"
+DATA bad_abi_msg+0x2c(SB)/1, $0xa
+GLOBL bad_abi_msg(SB), $45
+
+TEXT oabi_syscall<>(SB),7,$-4
+ ADD $1, PC, R4
+ WORD $0xe12fff14 //BX (R4) // enter thumb mode
+ // TODO(minux): only supports little-endian CPUs
+ WORD $0x4770df01 // swi $1; bx lr
+
diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/rt0_netbsd_386.s
index 8838b4891..829e4133b 100644
--- a/src/pkg/runtime/linux/arm/rt0.s
+++ b/src/pkg/runtime/rt0_netbsd_386.s
@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_arm_linux(SB),7,$0
- B _rt0_arm(SB)
+TEXT _rt0_386_netbsd(SB),7,$0
+ JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/rt0_netbsd_amd64.s
index 223e6d2ea..85482b98d 100644
--- a/src/pkg/runtime/linux/386/rt0.s
+++ b/src/pkg/runtime/rt0_netbsd_amd64.s
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
-
-TEXT _rt0_386_linux(SB),7,$0
- JMP _rt0_386(SB)
-
+TEXT _rt0_amd64_netbsd(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), DX
+ MOVQ SP, DI
+ JMP DX
diff --git a/src/pkg/runtime/rt0_openbsd_386.s b/src/pkg/runtime/rt0_openbsd_386.s
new file mode 100644
index 000000000..e7e0da78f
--- /dev/null
+++ b/src/pkg/runtime/rt0_openbsd_386.s
@@ -0,0 +1,6 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_386_openbsd(SB),7,$0
+ JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/openbsd/amd64/rt0.s b/src/pkg/runtime/rt0_openbsd_amd64.s
index e7fce5969..e7fce5969 100644
--- a/src/pkg/runtime/openbsd/amd64/rt0.s
+++ b/src/pkg/runtime/rt0_openbsd_amd64.s
diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/rt0_plan9_386.s
index b56c8b325..b56c8b325 100644
--- a/src/pkg/runtime/plan9/386/rt0.s
+++ b/src/pkg/runtime/rt0_plan9_386.s
diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/rt0_windows_386.s
index 3b023de2f..3b023de2f 100644
--- a/src/pkg/runtime/windows/386/rt0.s
+++ b/src/pkg/runtime/rt0_windows_386.s
diff --git a/src/pkg/runtime/windows/amd64/rt0.s b/src/pkg/runtime/rt0_windows_amd64.s
index 35978bc74..dc1408adc 100644
--- a/src/pkg/runtime/windows/amd64/rt0.s
+++ b/src/pkg/runtime/rt0_windows_amd64.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT _rt0_amd64_windows(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index b74705e5f..629c39e98 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -5,7 +5,7 @@
"""GDB Pretty printers and convenience functions for Go's runtime structures.
This script is loaded by GDB when it finds a .debug_gdb_scripts
-section in the compiled binary. The [68]l linkers emit this with a
+section in the compiled binary. The [68]l linkers emit this with a
path to this file based on the path to the runtime package.
"""
@@ -58,6 +58,8 @@ class SliceTypePrinter:
return str(self.val.type)[6:] # skip 'struct '
def children(self):
+ if self.val["len"] > self.val["cap"]:
+ return
ptr = self.val["array"]
for idx in range(self.val["len"]):
yield ('[%d]' % idx, (ptr + idx).dereference())
@@ -85,7 +87,7 @@ class MapTypePrinter:
stab = self.val['st']
i = 0
for v in self.traverse_hash(stab):
- yield ("[%d]" % i, v['key'])
+ yield ("[%d]" % i, v['key'])
yield ("[%d]" % (i + 1), v['val'])
i += 2
@@ -122,10 +124,10 @@ class ChanTypePrinter:
return str(self.val.type)
def children(self):
- # see chan.c chanbuf()
- et = [x.type for x in self.val['free'].type.target().fields() if x.name == 'elem'][0]
- ptr = (self.val.address + 1).cast(et.pointer())
- for i in range(self.val["qcount"]):
+ # see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem
+ et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0]
+ ptr = (self.val.address + 1).cast(et.pointer())
+ for i in range(self.val["qcount"]):
j = (self.val["recvx"] + i) % self.val["dataqsiz"]
yield ('[%d]' % i, (ptr + j).dereference())
@@ -184,10 +186,10 @@ def lookup_type(name):
except:
pass
+_rctp_type = gdb.lookup_type("struct runtime.commonType").pointer()
+_rtp_type = gdb.lookup_type("struct runtime._type").pointer()
-def iface_dtype(obj):
- "Decode type of the data field of an eface or iface struct."
-
+def iface_commontype(obj):
if is_iface(obj):
go_type_ptr = obj['tab']['_type']
elif is_eface(obj):
@@ -195,16 +197,43 @@ def iface_dtype(obj):
else:
return
- ct = gdb.lookup_type("struct runtime.commonType").pointer()
- dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference()
+ # sanity check: reflection type description ends in a loop.
+ tt = go_type_ptr['_type'].cast(_rtp_type).dereference()['_type']
+ if tt != tt.cast(_rtp_type).dereference()['_type']:
+ return
+
+ return go_type_ptr['ptr'].cast(_rctp_type).dereference()
+
+
+def iface_dtype(obj):
+ "Decode type of the data field of an eface or iface struct."
+ # known issue: dtype_name decoded from runtime.commonType is "nested.Foo"
+ # but the dwarf table lists it as "full/path/to/nested.Foo"
+
+ dynamic_go_type = iface_commontype(obj)
+ if dynamic_go_type is None:
+ return
dtype_name = dynamic_go_type['string'].dereference()['str'].string()
- type_size = int(dynamic_go_type['size'])
- uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
+
dynamic_gdb_type = lookup_type(dtype_name)
+ if dynamic_gdb_type is None:
+ return
+
+ type_size = int(dynamic_go_type['size'])
+ uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
if type_size > uintptr_size:
- dynamic_gdb_type = dynamic_gdb_type.pointer()
+ dynamic_gdb_type = dynamic_gdb_type.pointer()
+
return dynamic_gdb_type
+def iface_dtype_name(obj):
+ "Decode type name of the data field of an eface or iface struct."
+
+ dynamic_go_type = iface_commontype(obj)
+ if dynamic_go_type is None:
+ return
+ return dynamic_go_type['string'].dereference()['str'].string()
+
class IfacePrinter:
"""Pretty print interface values
@@ -224,6 +253,10 @@ class IfacePrinter:
dtype = iface_dtype(self.val)
except:
return "<bad dynamic type>"
+
+ if dtype is None: # trouble looking up, print something reasonable
+ return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
+
try:
return self.val['data'].cast(dtype).dereference()
except:
@@ -244,7 +277,7 @@ goobjfile.pretty_printers.append(ifacematcher)
class GoLenFunc(gdb.Function):
"Length of strings, slices, maps or channels"
- how = ((StringTypePrinter, 'len' ),
+ how = ((StringTypePrinter, 'len'),
(SliceTypePrinter, 'len'),
(MapTypePrinter, 'count'),
(ChanTypePrinter, 'qcount'))
@@ -293,7 +326,7 @@ class DTypeFunc(gdb.Function):
# Commands
#
-sts = ( 'idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
def linked_list(ptr, linkfield):
while ptr:
@@ -316,8 +349,8 @@ class GoroutinesCmd(gdb.Command):
s = ' '
if ptr['m']:
s = '*'
- pc = ptr['sched']['pc'].cast(vp)
- sp = ptr['sched']['sp'].cast(vp)
+ pc = ptr['sched']['pc'].cast(vp)
+ sp = ptr['sched']['sp'].cast(vp)
blk = gdb.block_for_pc(long((pc)))
print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
@@ -359,10 +392,10 @@ class GoroutineCmd(gdb.Command):
gdb.parse_and_eval('$sp = 0x%x' % long(sp))
try:
gdb.execute(cmd)
- finally:
+ finally:
gdb.parse_and_eval('$pc = $save_pc')
- gdb.parse_and_eval('$sp = $save_sp')
- save_frame.select()
+ gdb.parse_and_eval('$sp = $save_sp')
+ save_frame.select()
class GoIfaceCmd(gdb.Command):
@@ -380,8 +413,12 @@ class GoIfaceCmd(gdb.Command):
print "Can't parse ", obj, ": ", e
continue
- dtype = iface_dtype(obj)
- if not dtype:
+ if obj['data'] == 0:
+ dtype = "nil"
+ else:
+ dtype = iface_dtype(obj)
+
+ if dtype is None:
print "Not an interface: ", obj.type
continue
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 49aba7da0..ebb5544fb 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -51,12 +51,15 @@ runtime·dopanic(int32 unused)
static bool didothers;
if(g->sig != 0)
- runtime·printf("\n[signal %x code=%p addr=%p pc=%p]\n",
+ runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
g->sig, g->sigcode0, g->sigcode1, g->sigpc);
- runtime·printf("\n");
if(runtime·gotraceback()){
- runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ if(g != m->g0) {
+ runtime·printf("\n");
+ runtime·goroutineheader(g);
+ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ }
if(!didothers) {
didothers = true;
runtime·tracebackothers(g);
@@ -116,7 +119,7 @@ void
runtime·panicstring(int8 *s)
{
Eface err;
-
+
if(m->gcing) {
runtime·printf("panic: %s\n", s);
runtime·throw("panic during gc");
@@ -169,7 +172,7 @@ static int32 argc;
static uint8** argv;
Slice os·Args;
-Slice os·Envs;
+Slice syscall·envs;
void
runtime·args(int32 c, uint8 **v)
@@ -186,7 +189,7 @@ runtime·goargs(void)
{
String *s;
int32 i;
-
+
// for windows implementation see "os" package
if(Windows)
return;
@@ -204,16 +207,16 @@ runtime·goenvs_unix(void)
{
String *s;
int32 i, n;
-
+
for(n=0; argv[argc+1+n] != 0; n++)
;
s = runtime·malloc(n*sizeof s[0]);
for(i=0; i<n; i++)
s[i] = runtime·gostringnocopy(argv[argc+1+i]);
- os·Envs.array = (byte*)s;
- os·Envs.len = n;
- os·Envs.cap = n;
+ syscall·envs.array = (byte*)s;
+ syscall·envs.len = n;
+ syscall·envs.cap = n;
}
byte*
@@ -226,8 +229,8 @@ runtime·getenv(int8 *s)
bs = (byte*)s;
len = runtime·findnull(bs);
- envv = (String*)os·Envs.array;
- envc = os·Envs.len;
+ envv = (String*)syscall·envs.array;
+ envc = syscall·envs.len;
for(i=0; i<envc; i++){
if(envv[i].len <= len)
continue;
@@ -275,8 +278,8 @@ runtime·check(void)
uint32 f;
int64 g;
uint64 h;
- float32 i;
- float64 j;
+ float32 i, i1;
+ float64 j, j1;
void* k;
uint16* l;
struct x1 {
@@ -316,351 +319,29 @@ runtime·check(void)
if(z != 4)
runtime·throw("cas4");
- runtime·initsig(0);
-}
-
-/*
- * map and chan helpers for
- * dealing with unknown types
- */
-static uintptr
-memhash(uint32 s, void *a)
-{
- byte *b;
- uintptr hash;
-
- b = a;
- if(sizeof(hash) == 4)
- hash = 2860486313U;
- else
- hash = 33054211828000289ULL;
- while(s > 0) {
- if(sizeof(hash) == 4)
- hash = (hash ^ *b) * 3267000013UL;
- else
- hash = (hash ^ *b) * 23344194077549503ULL;
- b++;
- s--;
- }
- return hash;
-}
-
-static uint32
-memequal(uint32 s, void *a, void *b)
-{
- byte *ba, *bb, *aend;
-
- if(a == b)
- return 1;
- ba = a;
- bb = b;
- aend = ba+s;
- while(ba != aend) {
- if(*ba != *bb)
- return 0;
- ba++;
- bb++;
- }
- return 1;
-}
-
-static void
-memprint(uint32 s, void *a)
-{
- uint64 v;
-
- v = 0xbadb00b;
- switch(s) {
- case 1:
- v = *(uint8*)a;
- break;
- case 2:
- v = *(uint16*)a;
- break;
- case 4:
- v = *(uint32*)a;
- break;
- case 8:
- v = *(uint64*)a;
- break;
- }
- runtime·printint(v);
-}
-
-static void
-memcopy(uint32 s, void *a, void *b)
-{
- if(b == nil) {
- runtime·memclr(a,s);
- return;
- }
- runtime·memmove(a,b,s);
-}
-
-static uint32
-memequal8(uint32 s, uint8 *a, uint8 *b)
-{
- USED(s);
- return *a == *b;
-}
-
-static void
-memcopy8(uint32 s, uint8 *a, uint8 *b)
-{
- USED(s);
- if(b == nil) {
- *a = 0;
- return;
- }
- *a = *b;
-}
-
-static uint32
-memequal16(uint32 s, uint16 *a, uint16 *b)
-{
- USED(s);
- return *a == *b;
-}
-
-static void
-memcopy16(uint32 s, uint16 *a, uint16 *b)
-{
- USED(s);
- if(b == nil) {
- *a = 0;
- return;
- }
- *a = *b;
-}
-
-static uint32
-memequal32(uint32 s, uint32 *a, uint32 *b)
-{
- USED(s);
- return *a == *b;
-}
-
-static void
-memcopy32(uint32 s, uint32 *a, uint32 *b)
-{
- USED(s);
- if(b == nil) {
- *a = 0;
- return;
- }
- *a = *b;
-}
-
-static uint32
-memequal64(uint32 s, uint64 *a, uint64 *b)
-{
- USED(s);
- return *a == *b;
-}
+ *(uint64*)&j = ~0ULL;
+ if(j == j)
+ runtime·throw("float64nan");
+ if(!(j != j))
+ runtime·throw("float64nan1");
-static void
-memcopy64(uint32 s, uint64 *a, uint64 *b)
-{
- USED(s);
- if(b == nil) {
- *a = 0;
- return;
- }
- *a = *b;
-}
+ *(uint64*)&j1 = ~1ULL;
+ if(j == j1)
+ runtime·throw("float64nan2");
+ if(!(j != j1))
+ runtime·throw("float64nan3");
-static uint32
-memequal128(uint32 s, uint64 *a, uint64 *b)
-{
- USED(s);
- return a[0] == b[0] && a[1] == b[1];
-}
+ *(uint32*)&i = ~0UL;
+ if(i == i)
+ runtime·throw("float32nan");
+ if(!(i != i))
+ runtime·throw("float32nan1");
-static void
-memcopy128(uint32 s, uint64 *a, uint64 *b)
-{
- USED(s);
- if(b == nil) {
- a[0] = 0;
- a[1] = 0;
- return;
- }
- a[0] = b[0];
- a[1] = b[1];
-}
-
-static void
-slicecopy(uint32 s, Slice *a, Slice *b)
-{
- USED(s);
- if(b == nil) {
- a->array = 0;
- a->len = 0;
- a->cap = 0;
- return;
- }
- a->array = b->array;
- a->len = b->len;
- a->cap = b->cap;
-}
-
-static uintptr
-strhash(uint32 s, String *a)
-{
- USED(s);
- return memhash((*a).len, (*a).str);
-}
-
-static uint32
-strequal(uint32 s, String *a, String *b)
-{
- int32 alen;
-
- USED(s);
- alen = a->len;
- if(alen != b->len)
- return false;
- return memequal(alen, a->str, b->str);
-}
-
-static void
-strprint(uint32 s, String *a)
-{
- USED(s);
- runtime·printstring(*a);
-}
-
-static void
-strcopy(uint32 s, String *a, String *b)
-{
- USED(s);
- if(b == nil) {
- a->str = 0;
- a->len = 0;
- return;
- }
- a->str = b->str;
- a->len = b->len;
-}
-
-static uintptr
-interhash(uint32 s, Iface *a)
-{
- USED(s);
- return runtime·ifacehash(*a);
-}
-
-static void
-interprint(uint32 s, Iface *a)
-{
- USED(s);
- runtime·printiface(*a);
-}
-
-static uint32
-interequal(uint32 s, Iface *a, Iface *b)
-{
- USED(s);
- return runtime·ifaceeq_c(*a, *b);
-}
-
-static void
-intercopy(uint32 s, Iface *a, Iface *b)
-{
- USED(s);
- if(b == nil) {
- a->tab = 0;
- a->data = 0;
- return;
- }
- a->tab = b->tab;
- a->data = b->data;
-}
-
-static uintptr
-nilinterhash(uint32 s, Eface *a)
-{
- USED(s);
- return runtime·efacehash(*a);
-}
-
-static void
-nilinterprint(uint32 s, Eface *a)
-{
- USED(s);
- runtime·printeface(*a);
-}
-
-static uint32
-nilinterequal(uint32 s, Eface *a, Eface *b)
-{
- USED(s);
- return runtime·efaceeq_c(*a, *b);
-}
-
-static void
-nilintercopy(uint32 s, Eface *a, Eface *b)
-{
- USED(s);
- if(b == nil) {
- a->type = 0;
- a->data = 0;
- return;
- }
- a->type = b->type;
- a->data = b->data;
-}
-
-uintptr
-runtime·nohash(uint32 s, void *a)
-{
- USED(s);
- USED(a);
- runtime·panicstring("hash of unhashable type");
- return 0;
-}
-
-uint32
-runtime·noequal(uint32 s, void *a, void *b)
-{
- USED(s);
- USED(a);
- USED(b);
- runtime·panicstring("comparing uncomparable types");
- return 0;
-}
-
-Alg
-runtime·algarray[] =
-{
-[AMEM] { memhash, memequal, memprint, memcopy },
-[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy },
-[ASTRING] { strhash, strequal, strprint, strcopy },
-[AINTER] { interhash, interequal, interprint, intercopy },
-[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, nilintercopy },
-[ASLICE] { runtime·nohash, runtime·noequal, memprint, slicecopy },
-[AMEM8] { memhash, memequal8, memprint, memcopy8 },
-[AMEM16] { memhash, memequal16, memprint, memcopy16 },
-[AMEM32] { memhash, memequal32, memprint, memcopy32 },
-[AMEM64] { memhash, memequal64, memprint, memcopy64 },
-[AMEM128] { memhash, memequal128, memprint, memcopy128 },
-[ANOEQ8] { runtime·nohash, runtime·noequal, memprint, memcopy8 },
-[ANOEQ16] { runtime·nohash, runtime·noequal, memprint, memcopy16 },
-[ANOEQ32] { runtime·nohash, runtime·noequal, memprint, memcopy32 },
-[ANOEQ64] { runtime·nohash, runtime·noequal, memprint, memcopy64 },
-[ANOEQ128] { runtime·nohash, runtime·noequal, memprint, memcopy128 },
-};
-
-int64
-runtime·nanotime(void)
-{
- int64 sec;
- int32 usec;
-
- sec = 0;
- usec = 0;
- runtime·gettime(&sec, &usec);
- return sec*1000000000 + (int64)usec*1000;
+ *(uint32*)&i1 = ~1UL;
+ if(i == i1)
+ runtime·throw("float32nan2");
+ if(!(i != i1))
+ runtime·throw("float32nan3");
}
void
@@ -703,7 +384,13 @@ runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool r
void
runtime·Callers(int32 skip, Slice pc, int32 retn)
{
- retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
+ // runtime.callers uses pc.array==nil as a signal
+ // to print a stack trace. Pick off 0-length pc here
+ // so that we don't let a nil pc slice get to it.
+ if(pc.len == 0)
+ retn = 0;
+ else
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
FLUSH(&retn);
}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 526a320ea..6f5aea11d 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -43,21 +43,19 @@ typedef int32 intptr;
*/
typedef uint8 bool;
typedef uint8 byte;
-typedef struct Alg Alg;
typedef struct Func Func;
typedef struct G G;
typedef struct Gobuf Gobuf;
-typedef struct Lock Lock;
+typedef union Lock Lock;
typedef struct M M;
typedef struct Mem Mem;
typedef union Note Note;
typedef struct Slice Slice;
typedef struct Stktop Stktop;
typedef struct String String;
-typedef struct Usema Usema;
typedef struct SigTab SigTab;
typedef struct MCache MCache;
-typedef struct FixAlloc FixAlloc;
+typedef struct FixAlloc FixAlloc;
typedef struct Iface Iface;
typedef struct Itab Itab;
typedef struct Eface Eface;
@@ -70,6 +68,9 @@ typedef struct Hmap Hmap;
typedef struct Hchan Hchan;
typedef struct Complex64 Complex64;
typedef struct Complex128 Complex128;
+typedef struct WinCall WinCall;
+typedef struct Timers Timers;
+typedef struct Timer Timer;
/*
* per-cpu declaration.
@@ -116,32 +117,15 @@ enum
/*
* structures
*/
-struct Lock
+union Lock
{
- uint32 key;
-#ifdef __WINDOWS__
- void* event;
-#else
- uint32 sema; // for OS X
-#endif
-};
-struct Usema
-{
- uint32 u;
- uint32 k;
+ uint32 key; // futex-based impl
+ M* waitm; // linked list of waiting M's (sema-based impl)
};
union Note
{
- struct { // Linux
- uint32 state;
- };
- struct { // Windows
- Lock lock;
- };
- struct { // OS X
- int32 wakeup;
- Usema sema;
- };
+ uint32 key; // futex-based impl
+ M* waitm; // waiting M (sema-based impl)
};
struct String
{
@@ -184,8 +168,8 @@ struct Gobuf
};
struct G
{
- byte* stackguard; // cannot move - also known to linker, libmach, libcgo
- byte* stackbase; // cannot move - also known to libmach, libcgo
+ byte* stackguard; // cannot move - also known to linker, libmach, runtime/cgo
+ byte* stackbase; // cannot move - also known to libmach, runtime/cgo
Defer* defer;
Panic* panic;
Gobuf sched;
@@ -199,6 +183,7 @@ struct G
int16 status;
int32 goid;
uint32 selgen; // valid sudog pointer
+ int8* waitreason; // if status==Gwaiting
G* schedlink;
bool readyonstop;
bool ispanic;
@@ -206,10 +191,13 @@ struct G
M* lockedm;
M* idlem;
int32 sig;
+ int32 writenbuf;
+ byte* writebuf;
uintptr sigcode0;
uintptr sigcode1;
uintptr sigpc;
uintptr gopc; // pc of go statement that created this goroutine
+ uintptr end[];
};
struct M
{
@@ -235,6 +223,7 @@ struct M
int32 waitnextg;
int32 dying;
int32 profilehz;
+ int32 helpgc;
uint32 fastrand;
uint64 ncgocall;
Note havenextg;
@@ -246,14 +235,19 @@ struct M
FixAlloc *stackalloc;
G* lockedg;
G* idleg;
+ uintptr createstack[32]; // Stack that created this thread.
uint32 freglo[16]; // D[i] lsb and F[i]
uint32 freghi[16]; // D[i] msb and F[i+16]
uint32 fflag; // floating point compare flags
-#ifdef __WINDOWS__
-#ifdef _64BIT
- void* gostack;
-#endif
+ M* nextwaitm; // next M waiting for lock
+ uintptr waitsema; // semaphore for parking on locks
+ uint32 waitsemacount;
+ uint32 waitsemalock;
+
+#ifdef GOOS_windows
+ void* thread; // thread handle
#endif
+ uintptr end[];
};
struct Stktop
@@ -268,13 +262,6 @@ struct Stktop
uintptr free; // if free>0, call stackfree using free as size
bool panic; // is this frame the top of a panic?
};
-struct Alg
-{
- uintptr (*hash)(uint32, void*);
- uint32 (*equal)(uint32, void*, void*);
- void (*print)(uint32, void*);
- void (*copy)(uint32, void*, void*);
-};
struct SigTab
{
int32 flags;
@@ -282,11 +269,11 @@ struct SigTab
};
enum
{
- SigCatch = 1<<0,
- SigIgnore = 1<<1,
- SigRestart = 1<<2,
- SigQueue = 1<<3,
- SigPanic = 1<<4,
+ SigNotify = 1<<0, // let signal.Notify have signal, even if from kernel
+ SigKill = 1<<1, // if signal.Notify doesn't take it, exit quietly
+ SigThrow = 1<<2, // if signal.Notify doesn't take it, exit loudly
+ SigPanic = 1<<3, // if the signal is from the kernel, panic
+ SigDefault = 1<<4, // if the signal isn't explicitly requested, don't monitor it
};
// NOTE(rsc): keep in sync with extern.go:/type.Func.
@@ -305,7 +292,17 @@ struct Func
int32 locals; // number of 32-bit locals
};
-#ifdef __WINDOWS__
+struct WinCall
+{
+ void (*fn)(void*);
+ uintptr n; // number of parameters
+ void* args; // parameters
+ uintptr r1; // return values
+ uintptr r2;
+ uintptr err; // error number
+};
+
+#ifdef GOOS_windows
enum {
Windows = 1
};
@@ -315,6 +312,33 @@ enum {
};
#endif
+struct Timers
+{
+ Lock;
+ G *timerproc;
+ bool sleeping;
+ bool rescheduling;
+ Note waitnote;
+ Timer **t;
+ int32 len;
+ int32 cap;
+};
+
+// Package time knows the layout of this structure.
+// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+struct Timer
+{
+ int32 i; // heap index
+
+ // Timer wakes up at when, and then at when+period, ... (period > 0 only)
+ // each time calling f(now, arg) in the timer goroutine, so f must be
+ // a well-behaved function and not block.
+ int64 when;
+ int64 period;
+ void (*f)(int64, Eface);
+ Eface arg;
+};
+
/*
* defined macros
* you need super-gopher-guru privilege
@@ -327,31 +351,78 @@ enum {
/*
* known to compiler
*/
+enum {
+ Structrnd = sizeof(uintptr)
+};
+
+/*
+ * type algorithms - known to compiler
+ */
enum
{
AMEM,
- ANOEQ,
- ASTRING,
- AINTER,
- ANILINTER,
- ASLICE,
+ AMEM0,
AMEM8,
AMEM16,
AMEM32,
AMEM64,
AMEM128,
+ ANOEQ,
+ ANOEQ0,
ANOEQ8,
ANOEQ16,
ANOEQ32,
ANOEQ64,
ANOEQ128,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ ASLICE,
+ AFLOAT32,
+ AFLOAT64,
+ ACPLX64,
+ ACPLX128,
Amax
};
+typedef struct Alg Alg;
+struct Alg
+{
+ void (*hash)(uintptr*, uintptr, void*);
+ void (*equal)(bool*, uintptr, void*, void*);
+ void (*print)(uintptr, void*);
+ void (*copy)(uintptr, void*, void*);
+};
+extern Alg runtime·algarray[Amax];
-enum {
- Structrnd = sizeof(uintptr)
-};
+void runtime·memhash(uintptr*, uintptr, void*);
+void runtime·nohash(uintptr*, uintptr, void*);
+void runtime·strhash(uintptr*, uintptr, void*);
+void runtime·interhash(uintptr*, uintptr, void*);
+void runtime·nilinterhash(uintptr*, uintptr, void*);
+
+void runtime·memequal(bool*, uintptr, void*, void*);
+void runtime·noequal(bool*, uintptr, void*, void*);
+void runtime·strequal(bool*, uintptr, void*, void*);
+void runtime·interequal(bool*, uintptr, void*, void*);
+void runtime·nilinterequal(bool*, uintptr, void*, void*);
+
+void runtime·memprint(uintptr, void*);
+void runtime·strprint(uintptr, void*);
+void runtime·interprint(uintptr, void*);
+void runtime·nilinterprint(uintptr, void*);
+
+void runtime·memcopy(uintptr, void*, void*);
+void runtime·memcopy8(uintptr, void*, void*);
+void runtime·memcopy16(uintptr, void*, void*);
+void runtime·memcopy32(uintptr, void*, void*);
+void runtime·memcopy64(uintptr, void*, void*);
+void runtime·memcopy128(uintptr, void*, void*);
+void runtime·memcopy(uintptr, void*, void*);
+void runtime·strcopy(uintptr, void*, void*);
+void runtime·algslicecopy(uintptr, void*, void*);
+void runtime·intercopy(uintptr, void*, void*);
+void runtime·nilintercopy(uintptr, void*, void*);
/*
* deferred subroutine calls
@@ -359,6 +430,7 @@ enum {
struct Defer
{
int32 siz;
+ bool nofree;
byte* argp; // where args were copied from
byte* pc;
byte* fn;
@@ -380,17 +452,17 @@ struct Panic
/*
* external data
*/
-extern Alg runtime·algarray[Amax];
extern String runtime·emptystring;
G* runtime·allg;
+G* runtime·lastg;
M* runtime·allm;
extern int32 runtime·gomaxprocs;
extern bool runtime·singleproc;
extern uint32 runtime·panicking;
extern int32 runtime·gcwaiting; // gc is waiting to run
int8* runtime·goos;
+int32 runtime·ncpu;
extern bool runtime·iscgo;
-extern void (*runtime·destroylock)(Lock*);
/*
* common functions and data
@@ -431,8 +503,10 @@ String runtime·gostringn(byte*, int32);
Slice runtime·gobytes(byte*, int32);
String runtime·gostringnocopy(byte*);
String runtime·gostringw(uint16*);
-void runtime·initsig(int32);
+void runtime·initsig(void);
+void runtime·sigenable(uint32 sig);
int32 runtime·gotraceback(void);
+void runtime·goroutineheader(G*);
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
void runtime·tracebackothers(G*);
int32 runtime·write(int32, void*, int32);
@@ -455,6 +529,7 @@ int32 runtime·atoi(byte*);
void runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void));
void runtime·signalstack(byte*, int32);
G* runtime·malg(int32);
+void runtime·asminit(void);
void runtime·minit(void);
Func* runtime·findfunc(uintptr);
int32 runtime·funcline(Func*, uintptr);
@@ -466,29 +541,27 @@ bool runtime·ifaceeq_c(Iface, Iface);
bool runtime·efaceeq_c(Eface, Eface);
uintptr runtime·ifacehash(Iface);
uintptr runtime·efacehash(Eface);
-uintptr runtime·nohash(uint32, void*);
-uint32 runtime·noequal(uint32, void*, void*);
void* runtime·malloc(uintptr size);
void runtime·free(void *v);
-void runtime·addfinalizer(void*, void(*fn)(void*), int32);
-void runtime·walkfintab(void (*fn)(void*));
+bool runtime·addfinalizer(void*, void(*fn)(void*), int32);
void runtime·runpanic(Panic*);
void* runtime·getcallersp(void*);
int32 runtime·mcount(void);
+int32 runtime·gcount(void);
void runtime·mcall(void(*)(G*));
uint32 runtime·fastrand1(void);
void runtime·exit(int32);
void runtime·breakpoint(void);
void runtime·gosched(void);
+void runtime·tsleep(int64);
+M* runtime·newm(void);
void runtime·goexit(void);
void runtime·asmcgocall(void (*fn)(void*), void*);
void runtime·entersyscall(void);
void runtime·exitsyscall(void);
G* runtime·newproc1(byte*, byte*, int32, int32, void*);
-void runtime·siginit(void);
bool runtime·sigsend(int32 sig);
-void runtime·gettime(int64*, int32*);
int32 runtime·callers(int32, uintptr*, int32);
int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32);
int64 runtime·nanotime(void);
@@ -497,6 +570,8 @@ void runtime·startpanic(void);
void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
void runtime·resetcpuprofiler(int32);
void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
+void runtime·usleep(uint32);
+int64 runtime·cputicks(void);
#pragma varargck argpos runtime·printf 1
#pragma varargck type "d" int32
@@ -513,10 +588,9 @@ void runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
#pragma varargck type "s" uint8*
#pragma varargck type "S" String
-// TODO(rsc): Remove. These are only temporary,
-// for the mark and sweep collector.
void runtime·stoptheworld(void);
-void runtime·starttheworld(void);
+void runtime·starttheworld(bool);
+extern uint32 runtime·worldsema;
/*
* mutual exclusion locks. in the uncontended case,
@@ -538,10 +612,28 @@ void runtime·unlock(Lock*);
* subsequent noteclear must be called only after
* previous notesleep has returned, e.g. it's disallowed
* to call noteclear straight after notewakeup.
+ *
+ * notetsleep is like notesleep but wakes up after
+ * a given number of nanoseconds even if the event
+ * has not yet happened. if a goroutine uses notetsleep to
+ * wake up early, it must wait to call noteclear until it
+ * can be sure that no other goroutine is calling
+ * notewakeup.
*/
void runtime·noteclear(Note*);
void runtime·notesleep(Note*);
void runtime·notewakeup(Note*);
+void runtime·notetsleep(Note*, int64);
+
+/*
+ * low-level synchronization for implementing the above
+ */
+uintptr runtime·semacreate(void);
+int32 runtime·semasleep(int64);
+void runtime·semawakeup(M*);
+// or
+void runtime·futexsleep(uint32*, uint32, int64);
+void runtime·futexwakeup(uint32*, uint32);
/*
* This is consistent across Linux and BSD.
@@ -554,7 +646,8 @@ void runtime·notewakeup(Note*);
* low level C-called
*/
uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
-void runtime·munmap(uint8*, uintptr);
+void runtime·munmap(byte*, uintptr);
+void runtime·madvise(byte*, uintptr, int32);
void runtime·memclr(byte*, uintptr);
void runtime·setcallerpc(void*, void*);
void* runtime·getcallerpc(void*);
@@ -582,9 +675,8 @@ void runtime·panicslice(void);
/*
* runtime c-called (but written in Go)
*/
-void runtime·newError(String, Eface*);
void runtime·printany(Eface);
-void runtime·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
+void runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
void runtime·newErrorString(String, Eface*);
void runtime·fadd64c(uint64, uint64, uint64*);
void runtime·fsub64c(uint64, uint64, uint64*);
@@ -613,10 +705,11 @@ float64 runtime·ldexp(float64 d, int32 e);
float64 runtime·modf(float64 d, float64 *ip);
void runtime·semacquire(uint32*);
void runtime·semrelease(uint32*);
-String runtime·signame(int32 sig);
int32 runtime·gomaxprocsfunc(int32 n);
void runtime·procyield(uint32);
void runtime·osyield(void);
+void runtime·LockOSThread(void);
+void runtime·UnlockOSThread(void);
void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
@@ -626,10 +719,22 @@ void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
Hmap* runtime·makemap_c(MapType*, int64);
Hchan* runtime·makechan_c(ChanType*, int64);
-void runtime·chansend(ChanType*, Hchan*, void*, bool*);
-void runtime·chanrecv(ChanType*, Hchan*, void*, bool*, bool*);
+void runtime·chansend(ChanType*, Hchan*, byte*, bool*);
+void runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
int32 runtime·chanlen(Hchan*);
int32 runtime·chancap(Hchan*);
+bool runtime·showframe(Func*);
void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*);
+uintptr runtime·memlimit(void);
+
+// If appropriate, ask the operating system to control whether this
+// thread should receive profiling signals. This is only necessary on OS X.
+// An operating system should not deliver a profiling signal to a
+// thread that is not actually executing (what good is that?), but that's
+// what OS X prefers to do. When profiling is turned on, we mask
+// away the profiling signal when threads go to sleep, so that OS X
+// is forced to deliver the signal to a thread that's actually running.
+// This is a no-op on other systems.
+void runtime·setprof(bool);
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index da2d0c572..667131c1e 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -8,3 +8,7 @@ package runtime
func GOMAXPROCS(n int32) (ret int32) {
ret = runtime·gomaxprocsfunc(n);
}
+
+func NumCPU() (ret int32) {
+ ret = runtime·ncpu;
+}
diff --git a/src/pkg/runtime/runtime_linux_test.go b/src/pkg/runtime/runtime_linux_test.go
new file mode 100644
index 000000000..5344ed205
--- /dev/null
+++ b/src/pkg/runtime/runtime_linux_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ . "runtime"
+ "syscall"
+ "testing"
+)
+
+var pid, tid int
+
+func init() {
+ // Record pid and tid of init thread for use during test.
+ // The call to LockOSThread is just to exercise it;
+ // we can't test that it does anything.
+ // Instead we're testing that the conditions are good
+ // for how it is used in init (must be on main thread).
+ pid, tid = syscall.Getpid(), syscall.Gettid()
+ LockOSThread()
+}
+
+func TestLockOSThread(t *testing.T) {
+ if pid != tid {
+ t.Fatalf("pid=%d but tid=%d", pid, tid)
+ }
+}
diff --git a/src/pkg/runtime/runtime_test.go b/src/pkg/runtime/runtime_test.go
new file mode 100644
index 000000000..d68b363e9
--- /dev/null
+++ b/src/pkg/runtime/runtime_test.go
@@ -0,0 +1,40 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "io"
+ "testing"
+)
+
+var errf error
+
+func errfn() error {
+ return errf
+}
+
+func errfn1() error {
+ return io.EOF
+}
+
+func BenchmarkIfaceCmp100(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < 100; j++ {
+ if errfn() == io.EOF {
+ b.Fatal("bad comparison")
+ }
+ }
+ }
+}
+
+func BenchmarkIfaceCmpNil100(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < 100; j++ {
+ if errfn1() == nil {
+ b.Fatal("bad comparison")
+ }
+ }
+ }
+}
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index ae84351ed..2300c56aa 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -17,8 +17,9 @@
// See Mullender and Cox, ``Semaphores in Plan 9,''
// http://swtch.com/semaphore.pdf
-package runtime
+package sync
#include "runtime.h"
+#include "arch_GOARCH.h"
typedef struct Sema Sema;
struct Sema
@@ -45,11 +46,7 @@ struct SemaRoot
static union
{
SemaRoot;
- // Modern processors tend to have 64-byte cache lines,
- // potentially with 128-byte effective cache line size for reading.
- // While there are hypothetical architectures
- // with 16-4096 byte cache lines, 128 looks like a good compromise.
- uint8 pad[128];
+ uint8 pad[CacheLineSize];
} semtable[SEMTABLESZ];
static SemaRoot*
@@ -129,6 +126,7 @@ runtime·semacquire(uint32 volatile *addr)
// (we set nwait above), so go to sleep.
semqueue(root, addr, &s);
g->status = Gwaiting;
+ g->waitreason = "semacquire";
runtime·unlock(root);
runtime·gosched();
if(cansemacquire(addr))
@@ -171,10 +169,10 @@ runtime·semrelease(uint32 volatile *addr)
runtime·ready(s->g);
}
-func Semacquire(addr *uint32) {
+func runtime_Semacquire(addr *uint32) {
runtime·semacquire(addr);
}
-func Semrelease(addr *uint32) {
+func runtime_Semrelease(addr *uint32) {
runtime·semrelease(addr);
}
diff --git a/src/pkg/runtime/sig.go b/src/pkg/runtime/sig.go
deleted file mode 100644
index 6d560b900..000000000
--- a/src/pkg/runtime/sig.go
+++ /dev/null
@@ -1,16 +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 runtime
-
-// Sigrecv returns a bitmask of signals that have arrived since the last call to Sigrecv.
-// It blocks until at least one signal arrives.
-func Sigrecv() uint32
-
-// Signame returns a string describing the signal, or "" if the signal is unknown.
-func Signame(sig int32) string
-
-// Siginit enables receipt of signals via Sigrecv. It should typically
-// be called during initialization.
-func Siginit()
diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/signal_darwin_386.c
index 29170b669..9e986352b 100644
--- a/src/pkg/runtime/darwin/386/signal.c
+++ b/src/pkg/runtime/signal_darwin_386.c
@@ -3,12 +3,12 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "signals.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signals_GOOS.h"
void
-runtime·dumpregs(Regs *r)
+runtime·dumpregs(Regs32 *r)
{
runtime·printf("eax %x\n", r->eax);
runtime·printf("ebx %x\n", r->ebx);
@@ -25,33 +25,30 @@ runtime·dumpregs(Regs *r)
runtime·printf("gs %x\n", r->gs);
}
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
- Mcontext *mc;
- Regs *r;
+ Mcontext32 *mc;
+ Regs32 *r;
uintptr *sp;
byte *pc;
+ SigTab *t;
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
+ if(gp != m->g0 && gp != m->gsignal)
+ runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
@@ -62,7 +59,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
if(pc[0] == 0xF6 || pc[0] == 0xF7)
info->si_code = FPE_INTDIV;
}
-
+
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -87,15 +84,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG){
runtime·printf("Signal %d\n", sig);
@@ -116,11 +114,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
}
void
-runtime·sigignore(int32, Siginfo*, void*)
-{
-}
-
-void
runtime·signalstack(byte *p, int32 n)
{
StackT st;
@@ -131,8 +124,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -141,54 +134,7 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
if(restart)
sa.sa_flags |= SA_RESTART;
sa.sa_mask = ~0U;
- sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
- sa.__sigaction_u.__sa_sigaction = (uintptr)fn;
+ sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
+ *(uintptr*)sa.__sigaction_u = (uintptr)fn;
runtime·sigaction(i, &sa, nil);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/signal_darwin_amd64.c
index 036a3aca7..d9c5f48e7 100644
--- a/src/pkg/runtime/darwin/amd64/signal.c
+++ b/src/pkg/runtime/signal_darwin_amd64.c
@@ -3,12 +3,12 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "signals.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signals_GOOS.h"
void
-runtime·dumpregs(Regs *r)
+runtime·dumpregs(Regs64 *r)
{
runtime·printf("rax %X\n", r->rax);
runtime·printf("rbx %X\n", r->rbx);
@@ -33,33 +33,30 @@ runtime·dumpregs(Regs *r)
runtime·printf("gs %X\n", r->gs);
}
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
- Mcontext *mc;
- Regs *r;
+ Mcontext64 *mc;
+ Regs64 *r;
uintptr *sp;
byte *pc;
+ SigTab *t;
uc = context;
mc = uc->uc_mcontext;
r = &mc->ss;
if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
+ if(gp != m->g0 && gp != m->gsignal)
+ runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Work around Leopard bug that doesn't set FPE_INTDIV.
// Look at instruction to see if it is a divide.
// Not necessary in Snow Leopard (si_code will be != 0).
@@ -72,7 +69,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
if(pc[0] == 0xF6 || pc[0] == 0xF7)
info->si_code = FPE_INTDIV;
}
-
+
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -81,7 +78,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
gp->sigpc = r->rip;
-
+
// Only push runtime·sigpanic if r->rip != 0.
// If r->rip == 0, probably panicked because of a
// call to a nil func. Not pushing that onto sp will
@@ -97,15 +94,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG){
runtime·printf("Signal %d\n", sig);
@@ -126,11 +124,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
}
void
-runtime·sigignore(int32, Siginfo*, void*)
-{
-}
-
-void
runtime·signalstack(byte *p, int32 n)
{
StackT st;
@@ -141,8 +134,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -151,54 +144,7 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
if(restart)
sa.sa_flags |= SA_RESTART;
sa.sa_mask = ~0ULL;
- sa.sa_tramp = (uintptr)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
- sa.__sigaction_u.__sa_sigaction = (uintptr)fn;
+ sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
+ *(uintptr*)sa.__sigaction_u = (uintptr)fn;
runtime·sigaction(i, &sa, nil);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/signal_freebsd_386.c
index 2fe7ecd70..80da95d98 100644
--- a/src/pkg/runtime/freebsd/386/signal.c
+++ b/src/pkg/runtime/signal_freebsd_386.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
extern void runtime·sigtramp(void);
@@ -36,20 +36,13 @@ runtime·dumpregs(Mcontext *r)
runtime·printf("gs %x\n", r->mc_gs);
}
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
Mcontext *r;
uintptr *sp;
+ SigTab *t;
uc = context;
r = &uc->uc_mcontext;
@@ -59,7 +52,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -84,15 +80,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
@@ -111,13 +108,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
runtime·exit(2);
}
-// Called from kernel on signal stack, so no stack split.
-#pragma textflag 7
-void
-runtime·sigignore(void)
-{
-}
-
void
runtime·signalstack(byte *p, int32 n)
{
@@ -129,8 +119,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -144,50 +134,3 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/signal_freebsd_amd64.c
index 8015e366e..e4307682f 100644
--- a/src/pkg/runtime/freebsd/amd64/signal.c
+++ b/src/pkg/runtime/signal_freebsd_amd64.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
extern void runtime·sigtramp(void);
@@ -44,20 +44,13 @@ runtime·dumpregs(Mcontext *r)
runtime·printf("gs %X\n", r->mc_gs);
}
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
Mcontext *r;
uintptr *sp;
+ SigTab *t;
uc = context;
r = &uc->uc_mcontext;
@@ -67,7 +60,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -92,15 +88,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
@@ -119,13 +116,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
runtime·exit(2);
}
-// Called from kernel on signal stack, so no stack split.
-#pragma textflag 7
-void
-runtime·sigignore(void)
-{
-}
-
void
runtime·signalstack(byte *p, int32 n)
{
@@ -137,8 +127,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -152,50 +142,3 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/signal_linux_386.c
index 8916e10bd..b154ad887 100644
--- a/src/pkg/runtime/linux/386/signal.c
+++ b/src/pkg/runtime/signal_linux_386.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
void
runtime·dumpregs(Sigcontext *r)
@@ -30,23 +30,15 @@ runtime·dumpregs(Sigcontext *r)
* and calls sighandler().
*/
extern void runtime·sigtramp(void);
-extern void runtime·sigignore(void); // just returns
extern void runtime·sigreturn(void); // calls runtime·sigreturn
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
Sigcontext *r;
uintptr *sp;
+ SigTab *t;
uc = context;
r = &uc->uc_mcontext;
@@ -56,7 +48,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -81,15 +76,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
@@ -119,8 +115,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -136,49 +132,27 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
runtime·rt_sigaction(i, &sa, nil, 8);
}
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
+#define AT_NULL 0
+#define AT_SYSINFO 32
+extern uint32 runtime·_vdso;
+#pragma textflag 7
void
-runtime·resetcpuprofiler(int32 hz)
+runtime·linux_setup_vdso(int32 argc, void *argv_list)
{
- Itimerval it;
+ byte **argv = &argv_list;
+ byte **envp;
+ uint32 *auxv;
+
+ // skip envp to get to ELF auxiliary vector.
+ for(envp = &argv[argc+1]; *envp != nil; envp++)
+ ;
+ envp++;
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
+ for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
+ if(auxv[0] == AT_SYSINFO) {
+ runtime·_vdso = auxv[1];
+ break;
+ }
}
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
}
diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/signal_linux_amd64.c
index ee90271ed..14095ba61 100644
--- a/src/pkg/runtime/linux/amd64/signal.c
+++ b/src/pkg/runtime/signal_linux_amd64.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
void
runtime·dumpregs(Sigcontext *r)
@@ -38,17 +38,8 @@ runtime·dumpregs(Sigcontext *r)
* and calls sighandler().
*/
extern void runtime·sigtramp(void);
-extern void runtime·sigignore(void); // just returns
extern void runtime·sigreturn(void); // calls runtime·sigreturn
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
@@ -56,6 +47,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
Mcontext *mc;
Sigcontext *r;
uintptr *sp;
+ SigTab *t;
uc = context;
mc = &uc->uc_mcontext;
@@ -66,7 +58,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -91,15 +86,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
@@ -129,8 +125,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -145,50 +141,3 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.sa_handler = fn;
runtime·rt_sigaction(i, &sa, nil, 8);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/signal_linux_arm.c
index 88a84d112..176a4ce56 100644
--- a/src/pkg/runtime/linux/arm/signal.c
+++ b/src/pkg/runtime/signal_linux_arm.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
void
runtime·dumpregs(Sigcontext *r)
@@ -38,22 +38,14 @@ runtime·dumpregs(Sigcontext *r)
* and calls sighandler().
*/
extern void runtime·sigtramp(void);
-extern void runtime·sigignore(void); // just returns
extern void runtime·sigreturn(void); // calls runtime·sigreturn
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Ucontext *uc;
Sigcontext *r;
+ SigTab *t;
uc = context;
r = &uc->uc_mcontext;
@@ -63,7 +55,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -84,12 +79,15 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+Throw:
if(runtime·panicking) // traceback already printed
runtime·exit(2);
runtime·panicking = 1;
@@ -124,8 +122,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -140,50 +138,3 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.sa_handler = fn;
runtime·rt_sigaction(i, &sa, nil, 8);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/signal_netbsd_386.c b/src/pkg/runtime/signal_netbsd_386.c
new file mode 100644
index 000000000..39d829484
--- /dev/null
+++ b/src/pkg/runtime/signal_netbsd_386.c
@@ -0,0 +1,132 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("eax %x\n", r->sc_eax);
+ runtime·printf("ebx %x\n", r->sc_ebx);
+ runtime·printf("ecx %x\n", r->sc_ecx);
+ runtime·printf("edx %x\n", r->sc_edx);
+ runtime·printf("edi %x\n", r->sc_edi);
+ runtime·printf("esi %x\n", r->sc_esi);
+ runtime·printf("ebp %x\n", r->sc_ebp);
+ runtime·printf("esp %x\n", r->sc_esp);
+ runtime·printf("eip %x\n", r->sc_eip);
+ runtime·printf("eflags %x\n", r->sc_eflags);
+ runtime·printf("cs %x\n", r->sc_cs);
+ runtime·printf("fs %x\n", r->sc_fs);
+ runtime·printf("gs %x\n", r->sc_gs);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Sigcontext *r = context;
+ uintptr *sp;
+ SigTab *t;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */
+ gp->sigpc = r->sc_eip;
+
+ // Only push runtime·sigpanic if r->sc_eip != 0.
+ // If r->sc_eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->sc_eip != 0) {
+ sp = (uintptr*)r->sc_esp;
+ *--sp = r->sc_eip;
+ r->sc_esp = (uintptr)sp;
+ }
+ r->sc_eip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->sc_eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
diff --git a/src/pkg/runtime/openbsd/amd64/signal.c b/src/pkg/runtime/signal_netbsd_amd64.c
index 01bc76d20..8b4f624e7 100644
--- a/src/pkg/runtime/openbsd/amd64/signal.c
+++ b/src/pkg/runtime/signal_netbsd_amd64.c
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
extern void runtime·sigtramp(void);
@@ -44,19 +44,12 @@ runtime·dumpregs(Sigcontext *r)
runtime·printf("gs %X\n", r->sc_gs);
}
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
{
Sigcontext *r = context;
uintptr *sp;
+ SigTab *t;
if(sig == SIGPROF) {
runtime·sigprof((uint8*)r->sc_rip,
@@ -64,7 +57,10 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -89,16 +85,16 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
return;
}
- if(runtime·sigtab[sig].flags & SigQueue) {
- if(runtime·sigsend(sig)
- || (runtime·sigtab[sig].flags & SigIgnore))
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
return;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- }
-
- if(runtime·panicking) // traceback already printed
+ if(t->flags & SigKill)
runtime·exit(2);
- runtime·panicking = 1;
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
if(sig < 0 || sig >= NSIG)
runtime·printf("Signal %d\n", sig);
@@ -117,13 +113,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
runtime·exit(2);
}
-// Called from kernel on signal stack, so no stack split.
-#pragma textflag 7
-void
-runtime·sigignore(void)
-{
-}
-
void
runtime·signalstack(byte *p, int32 n)
{
@@ -135,8 +124,8 @@ runtime·signalstack(byte *p, int32 n)
runtime·sigaltstack(&st, nil);
}
-static void
-sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
{
Sigaction sa;
@@ -150,50 +139,3 @@ sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.__sigaction_u.__sa_sigaction = (void*)fn;
runtime·sigaction(i, &sa, nil);
}
-
-void
-runtime·initsig(int32 queue)
-{
- int32 i;
- void *fn;
-
- runtime·siginit();
-
- for(i = 0; i<NSIG; i++) {
- if(runtime·sigtab[i].flags) {
- if((runtime·sigtab[i].flags & SigQueue) != queue)
- continue;
- if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
- fn = runtime·sighandler;
- else
- fn = runtime·sigignore;
- sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
- }
- }
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- Itimerval it;
-
- runtime·memclr((byte*)&it, sizeof it);
- if(hz == 0) {
- runtime·setitimer(ITIMER_PROF, &it, nil);
- sigaction(SIGPROF, SIG_IGN, true);
- } else {
- sigaction(SIGPROF, runtime·sighandler, true);
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_usec = 1000000 / hz;
- it.it_value = it.it_interval;
- runtime·setitimer(ITIMER_PROF, &it, nil);
- }
- m->profilehz = hz;
-}
-
-void
-os·sigpipe(void)
-{
- sigaction(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
-}
diff --git a/src/pkg/runtime/signal_openbsd_386.c b/src/pkg/runtime/signal_openbsd_386.c
new file mode 100644
index 000000000..39d829484
--- /dev/null
+++ b/src/pkg/runtime/signal_openbsd_386.c
@@ -0,0 +1,132 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("eax %x\n", r->sc_eax);
+ runtime·printf("ebx %x\n", r->sc_ebx);
+ runtime·printf("ecx %x\n", r->sc_ecx);
+ runtime·printf("edx %x\n", r->sc_edx);
+ runtime·printf("edi %x\n", r->sc_edi);
+ runtime·printf("esi %x\n", r->sc_esi);
+ runtime·printf("ebp %x\n", r->sc_ebp);
+ runtime·printf("esp %x\n", r->sc_esp);
+ runtime·printf("eip %x\n", r->sc_eip);
+ runtime·printf("eflags %x\n", r->sc_eflags);
+ runtime·printf("cs %x\n", r->sc_cs);
+ runtime·printf("fs %x\n", r->sc_fs);
+ runtime·printf("gs %x\n", r->sc_gs);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Sigcontext *r = context;
+ uintptr *sp;
+ SigTab *t;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */
+ gp->sigpc = r->sc_eip;
+
+ // Only push runtime·sigpanic if r->sc_eip != 0.
+ // If r->sc_eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->sc_eip != 0) {
+ sp = (uintptr*)r->sc_esp;
+ *--sp = r->sc_eip;
+ r->sc_esp = (uintptr)sp;
+ }
+ r->sc_eip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->sc_eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
diff --git a/src/pkg/runtime/signal_openbsd_amd64.c b/src/pkg/runtime/signal_openbsd_amd64.c
new file mode 100644
index 000000000..8b4f624e7
--- /dev/null
+++ b/src/pkg/runtime/signal_openbsd_amd64.c
@@ -0,0 +1,141 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+#include "os_GOOS.h"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("rax %X\n", r->sc_rax);
+ runtime·printf("rbx %X\n", r->sc_rbx);
+ runtime·printf("rcx %X\n", r->sc_rcx);
+ runtime·printf("rdx %X\n", r->sc_rdx);
+ runtime·printf("rdi %X\n", r->sc_rdi);
+ runtime·printf("rsi %X\n", r->sc_rsi);
+ runtime·printf("rbp %X\n", r->sc_rbp);
+ runtime·printf("rsp %X\n", r->sc_rsp);
+ runtime·printf("r8 %X\n", r->sc_r8);
+ runtime·printf("r9 %X\n", r->sc_r9);
+ runtime·printf("r10 %X\n", r->sc_r10);
+ runtime·printf("r11 %X\n", r->sc_r11);
+ runtime·printf("r12 %X\n", r->sc_r12);
+ runtime·printf("r13 %X\n", r->sc_r13);
+ runtime·printf("r14 %X\n", r->sc_r14);
+ runtime·printf("r15 %X\n", r->sc_r15);
+ runtime·printf("rip %X\n", r->sc_rip);
+ runtime·printf("rflags %X\n", r->sc_rflags);
+ runtime·printf("cs %X\n", r->sc_cs);
+ runtime·printf("fs %X\n", r->sc_fs);
+ runtime·printf("gs %X\n", r->sc_gs);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Sigcontext *r = context;
+ uintptr *sp;
+ SigTab *t;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->sc_rip,
+ (uint8*)r->sc_rsp, nil, gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(info->si_code != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil)
+ goto Throw;
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = *(uintptr*)((byte*)info + 16); /* si_addr */
+ gp->sigpc = r->sc_rip;
+
+ // Only push runtime·sigpanic if r->mc_rip != 0.
+ // If r->mc_rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->sc_rip != 0) {
+ sp = (uintptr*)r->sc_rsp;
+ *--sp = r->sc_rip;
+ r->sc_rsp = (uintptr)sp;
+ }
+ r->sc_rip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(info->si_code == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->sc_rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/signal_plan9_386.c
index 364fd1c41..d26688516 100644
--- a/src/pkg/runtime/plan9/386/signal.c
+++ b/src/pkg/runtime/signal_plan9_386.c
@@ -5,14 +5,9 @@
#include "runtime.h"
void
-runtime·gettime(int64*, int32*)
+runtime·sigenable(uint32 sig)
{
-}
-
-String
-runtime·signame(int32)
-{
- return runtime·emptystring;
+ USED(sig);
}
void
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
new file mode 100644
index 000000000..9b7e8b03a
--- /dev/null
+++ b/src/pkg/runtime/signal_unix.c
@@ -0,0 +1,70 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux openbsd netbsd
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+extern SigTab runtime·sigtab[];
+
+void
+runtime·initsig(void)
+{
+ int32 i;
+ SigTab *t;
+
+ // First call: basic setup.
+ for(i = 0; i<NSIG; i++) {
+ t = &runtime·sigtab[i];
+ if((t->flags == 0) || (t->flags & SigDefault))
+ continue;
+ runtime·setsig(i, runtime·sighandler, true);
+ }
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+ int32 i;
+ SigTab *t;
+
+ for(i = 0; i<NSIG; i++) {
+ // ~0 means all signals.
+ if(~sig == 0 || i == sig) {
+ t = &runtime·sigtab[i];
+ if(t->flags & SigDefault) {
+ runtime·setsig(i, runtime·sighandler, true);
+ t->flags &= ~SigDefault; // make this idempotent
+ }
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ runtime·setprof(false);
+ } else {
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ runtime·setprof(true);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·setsig(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/signal_windows_386.c
index cc6a2302f..a248374db 100644
--- a/src/pkg/runtime/windows/386/signal.c
+++ b/src/pkg/runtime/signal_windows_386.c
@@ -3,8 +3,8 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
void
runtime·dumpregs(Context *r)
@@ -24,19 +24,10 @@ runtime·dumpregs(Context *r)
runtime·printf("gs %x\n", r->SegGs);
}
-void
-runtime·initsig(int32)
-{
- runtime·siginit();
-}
-
uint32
-runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
+runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
uintptr *sp;
- G *gp;
-
- USED(frame);
switch(info->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
@@ -44,7 +35,7 @@ runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
return 1;
}
- if((gp = m->curg) != nil && runtime·issigpanic(info->ExceptionCode)) {
+ if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -90,9 +81,13 @@ runtime·sighandler(ExceptionRecord *info, void *frame, Context *r)
}
void
-runtime·resetcpuprofiler(int32 hz)
+runtime·sigenable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
+runtime·dosigprof(Context *r, G *gp)
{
- // TODO: Enable profiling interrupts.
-
- m->profilehz = hz;
+ runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
}
diff --git a/src/pkg/runtime/signal_windows_amd64.c b/src/pkg/runtime/signal_windows_amd64.c
new file mode 100644
index 000000000..1cdf1cac4
--- /dev/null
+++ b/src/pkg/runtime/signal_windows_amd64.c
@@ -0,0 +1,100 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·dumpregs(Context *r)
+{
+ runtime·printf("rax %X\n", r->Rax);
+ runtime·printf("rbx %X\n", r->Rbx);
+ runtime·printf("rcx %X\n", r->Rcx);
+ runtime·printf("rdx %X\n", r->Rdx);
+ runtime·printf("rdi %X\n", r->Rdi);
+ runtime·printf("rsi %X\n", r->Rsi);
+ runtime·printf("rbp %X\n", r->Rbp);
+ runtime·printf("rsp %X\n", r->Rsp);
+ runtime·printf("r8 %X\n", r->R8 );
+ runtime·printf("r9 %X\n", r->R9 );
+ runtime·printf("r10 %X\n", r->R10);
+ runtime·printf("r11 %X\n", r->R11);
+ runtime·printf("r12 %X\n", r->R12);
+ runtime·printf("r13 %X\n", r->R13);
+ runtime·printf("r14 %X\n", r->R14);
+ runtime·printf("r15 %X\n", r->R15);
+ runtime·printf("rip %X\n", r->Rip);
+ runtime·printf("rflags %X\n", r->EFlags);
+ runtime·printf("cs %X\n", (uint64)r->SegCs);
+ runtime·printf("fs %X\n", (uint64)r->SegFs);
+ runtime·printf("gs %X\n", (uint64)r->SegGs);
+}
+
+uint32
+runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
+{
+ uintptr *sp;
+
+ switch(info->ExceptionCode) {
+ case EXCEPTION_BREAKPOINT:
+ return 1;
+ }
+
+ if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = info->ExceptionCode;
+ gp->sigcode0 = info->ExceptionInformation[0];
+ gp->sigcode1 = info->ExceptionInformation[1];
+ gp->sigpc = r->Rip;
+
+ // Only push runtime·sigpanic if r->rip != 0.
+ // If r->rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->Rip != 0) {
+ sp = (uintptr*)r->Rsp;
+ *--sp = r->Rip;
+ r->Rsp = (uintptr)sp;
+ }
+ r->Rip = (uintptr)runtime·sigpanic;
+ return 0;
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
+ info->ExceptionInformation[0], info->ExceptionInformation[1]);
+
+ runtime·printf("PC=%X\n", r->Rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->Rip, (void*)r->Rsp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+ return 0;
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
+runtime·dosigprof(Context *r, G *gp)
+{
+ runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
+}
diff --git a/src/pkg/runtime/signals_darwin.h b/src/pkg/runtime/signals_darwin.h
new file mode 100644
index 000000000..229b58590
--- /dev/null
+++ b/src/pkg/runtime/signals_darwin.h
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_freebsd.h b/src/pkg/runtime/signals_freebsd.h
new file mode 100644
index 000000000..4d27e050d
--- /dev/null
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+ /* 32 */ N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_linux.h b/src/pkg/runtime/signals_linux.h
new file mode 100644
index 000000000..345a6c5d1
--- /dev/null
+++ b/src/pkg/runtime/signals_linux.h
@@ -0,0 +1,83 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ P, "SIGBUS: bus error",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ N, "SIGUSR1: user-defined signal 1",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ N, "SIGUSR2: user-defined signal 2",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ T, "SIGSTKFLT: stack fault",
+ /* 17 */ N, "SIGCHLD: child status has changed",
+ /* 18 */ 0, "SIGCONT: continue",
+ /* 19 */ 0, "SIGSTOP: stop, unblockable",
+ /* 20 */ N+D, "SIGTSTP: keyboard stop",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGURG: urgent condition on socket",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGIO: i/o now possible",
+ /* 30 */ N, "SIGPWR: power failure restart",
+ /* 31 */ N, "SIGSYS: bad system call",
+ /* 32 */ N, "signal 32",
+ /* 33 */ N, "signal 33",
+ /* 34 */ N, "signal 34",
+ /* 35 */ N, "signal 35",
+ /* 36 */ N, "signal 36",
+ /* 37 */ N, "signal 37",
+ /* 38 */ N, "signal 38",
+ /* 39 */ N, "signal 39",
+ /* 40 */ N, "signal 40",
+ /* 41 */ N, "signal 41",
+ /* 42 */ N, "signal 42",
+ /* 43 */ N, "signal 43",
+ /* 44 */ N, "signal 44",
+ /* 45 */ N, "signal 45",
+ /* 46 */ N, "signal 46",
+ /* 47 */ N, "signal 47",
+ /* 48 */ N, "signal 48",
+ /* 49 */ N, "signal 49",
+ /* 50 */ N, "signal 50",
+ /* 51 */ N, "signal 51",
+ /* 52 */ N, "signal 52",
+ /* 53 */ N, "signal 53",
+ /* 54 */ N, "signal 54",
+ /* 55 */ N, "signal 55",
+ /* 56 */ N, "signal 56",
+ /* 57 */ N, "signal 57",
+ /* 58 */ N, "signal 58",
+ /* 59 */ N, "signal 59",
+ /* 60 */ N, "signal 60",
+ /* 61 */ N, "signal 61",
+ /* 62 */ N, "signal 62",
+ /* 63 */ N, "signal 63",
+ /* 64 */ N, "signal 64",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_netbsd.h b/src/pkg/runtime/signals_netbsd.h
new file mode 100644
index 000000000..4d27e050d
--- /dev/null
+++ b/src/pkg/runtime/signals_netbsd.h
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+ /* 32 */ N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/signals_openbsd.h b/src/pkg/runtime/signals_openbsd.h
new file mode 100644
index 000000000..4d27e050d
--- /dev/null
+++ b/src/pkg/runtime/signals_openbsd.h
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ N+K, "SIGHUP: terminal line hangup",
+ /* 2 */ N+K, "SIGINT: interrupt",
+ /* 3 */ N+T, "SIGQUIT: quit",
+ /* 4 */ T, "SIGILL: illegal instruction",
+ /* 5 */ T, "SIGTRAP: trace trap",
+ /* 6 */ N+T, "SIGABRT: abort",
+ /* 7 */ T, "SIGEMT: emulate instruction executed",
+ /* 8 */ P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ P, "SIGBUS: bus error",
+ /* 11 */ P, "SIGSEGV: segmentation violation",
+ /* 12 */ T, "SIGSYS: bad system call",
+ /* 13 */ N, "SIGPIPE: write to broken pipe",
+ /* 14 */ N, "SIGALRM: alarm clock",
+ /* 15 */ N+K, "SIGTERM: termination",
+ /* 16 */ N, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ N+D, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ N, "SIGCHLD: child status has changed",
+ /* 21 */ N+D, "SIGTTIN: background read from tty",
+ /* 22 */ N+D, "SIGTTOU: background write to tty",
+ /* 23 */ N, "SIGIO: i/o now possible",
+ /* 24 */ N, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ N, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ N, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ N, "SIGPROF: profiling alarm clock",
+ /* 28 */ N, "SIGWINCH: window size change",
+ /* 29 */ N, "SIGINFO: status request from keyboard",
+ /* 30 */ N, "SIGUSR1: user-defined signal 1",
+ /* 31 */ N, "SIGUSR2: user-defined signal 2",
+ /* 32 */ N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/signals_plan9.h
index 5df757613..5df757613 100644
--- a/src/pkg/runtime/plan9/signals.h
+++ b/src/pkg/runtime/signals_plan9.h
diff --git a/src/pkg/runtime/windows/signals.h b/src/pkg/runtime/signals_windows.h
index 6943714b0..6943714b0 100644
--- a/src/pkg/runtime/windows/signals.h
+++ b/src/pkg/runtime/signals_windows.h
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
index 504590a54..b49fdba86 100644
--- a/src/pkg/runtime/sigqueue.goc
+++ b/src/pkg/runtime/sigqueue.goc
@@ -11,7 +11,7 @@
//
// Ownership for sig.Note passes back and forth between
// the signal handler and the signal goroutine in rounds.
-// The initial state is that sig.note is cleared (setup by siginit).
+// The initial state is that sig.note is cleared (setup by signal_enable).
// At the beginning of each round, mask == 0.
// The round goes through three stages:
//
@@ -38,37 +38,34 @@
package runtime
#include "runtime.h"
-#include "defs.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
static struct {
Note;
- uint32 mask;
+ uint32 mask[(NSIG+31)/32];
+ uint32 wanted[(NSIG+31)/32];
+ uint32 kick;
bool inuse;
} sig;
-void
-runtime·siginit(void)
-{
- runtime·noteclear(&sig);
-}
-
// Called from sighandler to send a signal back out of the signal handling thread.
bool
runtime·sigsend(int32 s)
{
uint32 bit, mask;
- if(!sig.inuse)
+ if(!sig.inuse || s < 0 || s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
return false;
- bit = 1 << s;
+ bit = 1 << (s&31);
for(;;) {
- mask = sig.mask;
+ mask = sig.mask[s/32];
if(mask & bit)
break; // signal already in queue
- if(runtime·cas(&sig.mask, mask, mask|bit)) {
+ if(runtime·cas(&sig.mask[s/32], mask, mask|bit)) {
// Added to queue.
- // Only send a wakeup for the first signal in each round.
- if(mask == 0)
+ // Only send a wakeup if the receiver needs a kick.
+ if(runtime·cas(&sig.kick, 1, 0))
runtime·notewakeup(&sig);
break;
}
@@ -76,24 +73,79 @@ runtime·sigsend(int32 s)
return true;
}
-// Called to receive a bitmask of queued signals.
-func Sigrecv() (m uint32) {
- runtime·entersyscall();
- runtime·notesleep(&sig);
- runtime·exitsyscall();
- runtime·noteclear(&sig);
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+func signal_recv() (m uint32) {
+ static uint32 recv[nelem(sig.mask)];
+ int32 i, more;
+
for(;;) {
- m = sig.mask;
- if(runtime·cas(&sig.mask, m, 0))
- break;
+ // Serve from local copy if there are bits left.
+ for(i=0; i<NSIG; i++) {
+ if(recv[i/32]&(1U<<(i&31))) {
+ recv[i/32] ^= 1U<<(i&31);
+ m = i;
+ goto done;
+ }
+ }
+
+ // Get a new local copy.
+ // Ask for a kick if more signals come in
+ // during or after our check (before the sleep).
+ if(sig.kick == 0) {
+ runtime·noteclear(&sig);
+ runtime·cas(&sig.kick, 0, 1);
+ }
+
+ more = 0;
+ for(i=0; i<nelem(sig.mask); i++) {
+ for(;;) {
+ m = sig.mask[i];
+ if(runtime·cas(&sig.mask[i], m, 0))
+ break;
+ }
+ recv[i] = m;
+ if(m != 0)
+ more = 1;
+ }
+ if(more)
+ continue;
+
+ // Sleep waiting for more.
+ runtime·entersyscall();
+ runtime·notesleep(&sig);
+ runtime·exitsyscall();
}
-}
-func Signame(sig int32) (name String) {
- name = runtime·signame(sig);
+done:;
+ // goc requires that we fall off the end of functions
+ // that return values instead of using our own return
+ // statements.
}
-func Siginit() {
- runtime·initsig(SigQueue);
- sig.inuse = true; // enable reception of signals; cannot disable
+// Must only be called from a single goroutine at a time.
+func signal_enable(s uint32) {
+ int32 i;
+
+ if(!sig.inuse) {
+ // The first call to signal_enable is for us
+ // to use for initialization. It does not pass
+ // signal information in m.
+ sig.inuse = true; // enable reception of signals; cannot disable
+ runtime·noteclear(&sig);
+ return;
+ }
+
+ if(~s == 0) {
+ // Special case: want everything.
+ for(i=0; i<nelem(sig.wanted); i++)
+ sig.wanted[i] = ~(uint32)0;
+ runtime·sigenable(s);
+ return;
+ }
+
+ if(s >= nelem(sig.wanted)*32)
+ return;
+ sig.wanted[s/32] |= 1U<<(s&31);
+ runtime·sigenable(s);
}
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 70534279b..e5726c93b 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "type.h"
#include "malloc.h"
@@ -10,8 +11,7 @@ static int32 debug = 0;
static void makeslice1(SliceType*, int32, int32, Slice*);
static void growslice1(SliceType*, Slice, int32, Slice *);
-static void appendslice1(SliceType*, Slice, Slice, Slice*);
- void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
+ void runtime·copy(Slice to, Slice fm, uintptr width, int32 ret);
// see also unsafe·NewArray
// makeslice(typ *Type, len, cap int64) (ary []any);
@@ -28,13 +28,18 @@ runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
if(debug) {
runtime·printf("makeslice(%S, %D, %D); ret=",
*t->string, len, cap);
- runtime·printslice(ret);
+ runtime·printslice(ret);
}
}
+// Dummy word to use as base pointer for make([]T, 0).
+// Since you cannot take the address of such a slice,
+// you can't tell that they all have the same base pointer.
+static uintptr zerobase;
+
static void
makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
-{
+{
uintptr size;
size = cap*t->elem->size;
@@ -42,7 +47,9 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
ret->len = len;
ret->cap = cap;
- if((t->elem->kind&KindNoPointers))
+ if(cap == 0)
+ ret->array = (byte*)&zerobase;
+ else if((t->elem->kind&KindNoPointers))
ret->array = runtime·mallocgc(size, FlagNoPointers, 1, 1);
else
ret->array = runtime·mal(size);
@@ -52,14 +59,31 @@ makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
void
runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
{
- appendslice1(t, x, y, &ret);
+ int32 m;
+ uintptr w;
+
+ m = x.len+y.len;
+
+ if(m < x.len)
+ runtime·throw("append: slice overflow");
+
+ if(m > x.cap)
+ growslice1(t, x, m, &ret);
+ else
+ ret = x;
+
+ w = t->elem->size;
+ runtime·memmove(ret.array + ret.len*w, y.array, y.len*w);
+ ret.len += y.len;
+ FLUSH(&ret);
}
-static void
-appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
+
+// appendstr([]byte, string) []byte
+void
+runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
{
int32 m;
- uintptr w;
m = x.len+y.len;
@@ -67,15 +91,16 @@ appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
runtime·throw("append: slice overflow");
if(m > x.cap)
- growslice1(t, x, m, ret);
+ growslice1(t, x, m, &ret);
else
- *ret = x;
+ ret = x;
- w = t->elem->size;
- runtime·memmove(ret->array + ret->len*w, y.array, y.len*w);
- ret->len += y.len;
+ runtime·memmove(ret.array + ret.len, y.str, y.len);
+ ret.len += y.len;
+ FLUSH(&ret);
}
+
// growslice(type *Type, x, []T, n int64) []T
void
runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
@@ -96,9 +121,9 @@ runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
if(debug) {
runtime·printf("growslice(%S,", *t->string);
- runtime·printslice(old);
+ runtime·printslice(old);
runtime·printf(", new cap=%D) =", cap);
- runtime·printslice(ret);
+ runtime·printslice(ret);
}
}
@@ -265,9 +290,9 @@ runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, S
}
}
-// slicecopy(to any, fr any, wid uint32) int
+// copy(to any, fr any, wid uint32) int
void
-runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
+runtime·copy(Slice to, Slice fm, uintptr width, int32 ret)
{
if(fm.len == 0 || to.len == 0 || width == 0) {
ret = 0;
@@ -307,11 +332,11 @@ runtime·slicestringcopy(Slice to, String fm, int32 ret)
ret = 0;
goto out;
}
-
+
ret = fm.len;
if(to.len < ret)
ret = to.len;
-
+
runtime·memmove(to.array, fm.str, ret);
out:
diff --git a/src/pkg/runtime/softfloat64.go b/src/pkg/runtime/softfloat64.go
index e0c3b7b73..4fcf8f269 100644
--- a/src/pkg/runtime/softfloat64.go
+++ b/src/pkg/runtime/softfloat64.go
@@ -4,7 +4,7 @@
// Software IEEE754 64-bit floating point.
// Only referred to (and thus linked in) by arm port
-// and by gotest in this directory.
+// and by tests in this directory.
package runtime
diff --git a/src/pkg/runtime/softfloat64_test.go b/src/pkg/runtime/softfloat64_test.go
index fb7f3d3c0..df63010fb 100644
--- a/src/pkg/runtime/softfloat64_test.go
+++ b/src/pkg/runtime/softfloat64_test.go
@@ -6,7 +6,7 @@ package runtime_test
import (
"math"
- "rand"
+ "math/rand"
. "runtime"
"testing"
)
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/softfloat_arm.c
index 0a071dada..fbe0b0413 100644
--- a/src/pkg/runtime/arm/softfloat.c
+++ b/src/pkg/runtime/softfloat_arm.c
@@ -15,7 +15,7 @@
#define FLAGS_V (1 << 28)
void runtime·abort(void);
-void math·sqrtGoC(uint64, uint64*);
+void math·sqrtC(uint64, uint64*);
static uint32 trace = 0;
@@ -359,7 +359,7 @@ stage3: // regd, regm are 4bit variables
break;
case 0xeeb10bc0: // D[regd] = sqrt D[regm]
- math·sqrtGoC(getd(regm), &uval);
+ math·sqrtC(getd(regm), &uval);
putd(regd, uval);
if(trace)
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index 44d5533f4..d42385d6c 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -57,8 +57,8 @@ enum {
// to each stack below the usual guard area for OS-specific
// purposes like signal handling. Used on Windows because
// it does not use a separate stack.
-#ifdef __WINDOWS__
- StackSystem = 2048,
+#ifdef GOOS_windows
+ StackSystem = 512 * sizeof(uintptr),
#else
StackSystem = 0,
#endif
@@ -94,4 +94,9 @@ enum {
// The maximum number of bytes that a chain of NOSPLIT
// functions can use.
StackLimit = StackGuard - StackSystem - StackSmall,
+
+ // The assumed size of the top-of-stack data block.
+ // The actual size can be smaller than this but cannot be larger.
+ // Checked in proc.c's runtime.malg.
+ StackTop = 72,
};
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
new file mode 100644
index 000000000..01c6b6e2f
--- /dev/null
+++ b/src/pkg/runtime/stack_test.go
@@ -0,0 +1,1528 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test stack split logic by calling functions of every frame size
+// from near 0 up to and beyond the default segment size (4k).
+// Each of those functions reports its SP + stack limit, and then
+// the test (the caller) checks that those make sense. By not
+// doing the actual checking and reporting from the suspect functions,
+// we minimize the possibility of crashes during the test itself.
+//
+// Exhaustive test for http://golang.org/issue/3310.
+// The linker used to get a few sizes near the segment size wrong:
+//
+// --- FAIL: TestStackSplit (0.01 seconds)
+// stack_test.go:22: after runtime_test.stack3812: sp=0x7f7818d5d078 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3816: sp=0x7f7818d5d078 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3820: sp=0x7f7818d5d070 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3824: sp=0x7f7818d5d070 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3828: sp=0x7f7818d5d068 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3832: sp=0x7f7818d5d068 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3836: sp=0x7f7818d5d060 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3840: sp=0x7f7818d5d060 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3844: sp=0x7f7818d5d058 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3848: sp=0x7f7818d5d058 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3852: sp=0x7f7818d5d050 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3856: sp=0x7f7818d5d050 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3860: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
+// stack_test.go:22: after runtime_test.stack3864: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
+// FAIL
+
+package runtime_test
+
+import (
+ . "runtime"
+ "testing"
+ "unsafe"
+)
+
+// See stack.h.
+const (
+ StackGuard = 256
+ StackLimit = 128
+)
+
+func TestStackSplit(t *testing.T) {
+ for _, f := range splitTests {
+ sp, guard := f()
+ bottom := guard - StackGuard
+ if sp < bottom+StackLimit {
+ fun := FuncForPC(*(*uintptr)(unsafe.Pointer(&f)))
+ t.Errorf("after %s: sp=%#x < limit=%#x (guard=%#x, bottom=%#x)",
+ fun.Name(), sp, bottom+StackLimit, guard, bottom)
+ }
+ }
+}
+
+var splitTests = []func() (uintptr, uintptr){
+ // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt
+ stack4, stack8, stack12, stack16, stack20, stack24, stack28,
+ stack32, stack36, stack40, stack44, stack48, stack52, stack56,
+ stack60, stack64, stack68, stack72, stack76, stack80, stack84,
+ stack88, stack92, stack96, stack100, stack104, stack108, stack112,
+ stack116, stack120, stack124, stack128, stack132, stack136,
+ stack140, stack144, stack148, stack152, stack156, stack160,
+ stack164, stack168, stack172, stack176, stack180, stack184,
+ stack188, stack192, stack196, stack200, stack204, stack208,
+ stack212, stack216, stack220, stack224, stack228, stack232,
+ stack236, stack240, stack244, stack248, stack252, stack256,
+ stack260, stack264, stack268, stack272, stack276, stack280,
+ stack284, stack288, stack292, stack296, stack300, stack304,
+ stack308, stack312, stack316, stack320, stack324, stack328,
+ stack332, stack336, stack340, stack344, stack348, stack352,
+ stack356, stack360, stack364, stack368, stack372, stack376,
+ stack380, stack384, stack388, stack392, stack396, stack400,
+ stack404, stack408, stack412, stack416, stack420, stack424,
+ stack428, stack432, stack436, stack440, stack444, stack448,
+ stack452, stack456, stack460, stack464, stack468, stack472,
+ stack476, stack480, stack484, stack488, stack492, stack496,
+ stack500, stack504, stack508, stack512, stack516, stack520,
+ stack524, stack528, stack532, stack536, stack540, stack544,
+ stack548, stack552, stack556, stack560, stack564, stack568,
+ stack572, stack576, stack580, stack584, stack588, stack592,
+ stack596, stack600, stack604, stack608, stack612, stack616,
+ stack620, stack624, stack628, stack632, stack636, stack640,
+ stack644, stack648, stack652, stack656, stack660, stack664,
+ stack668, stack672, stack676, stack680, stack684, stack688,
+ stack692, stack696, stack700, stack704, stack708, stack712,
+ stack716, stack720, stack724, stack728, stack732, stack736,
+ stack740, stack744, stack748, stack752, stack756, stack760,
+ stack764, stack768, stack772, stack776, stack780, stack784,
+ stack788, stack792, stack796, stack800, stack804, stack808,
+ stack812, stack816, stack820, stack824, stack828, stack832,
+ stack836, stack840, stack844, stack848, stack852, stack856,
+ stack860, stack864, stack868, stack872, stack876, stack880,
+ stack884, stack888, stack892, stack896, stack900, stack904,
+ stack908, stack912, stack916, stack920, stack924, stack928,
+ stack932, stack936, stack940, stack944, stack948, stack952,
+ stack956, stack960, stack964, stack968, stack972, stack976,
+ stack980, stack984, stack988, stack992, stack996, stack1000,
+ stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
+ stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
+ stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
+ stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
+ stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
+ stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
+ stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
+ stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
+ stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
+ stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
+ stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
+ stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
+ stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
+ stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
+ stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
+ stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
+ stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
+ stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
+ stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
+ stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
+ stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
+ stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
+ stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
+ stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
+ stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
+ stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
+ stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
+ stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
+ stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
+ stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
+ stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
+ stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
+ stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
+ stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
+ stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
+ stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
+ stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
+ stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
+ stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
+ stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
+ stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
+ stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
+ stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
+ stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
+ stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
+ stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
+ stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
+ stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
+ stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
+ stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
+ stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
+ stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
+ stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
+ stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
+ stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
+ stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
+ stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
+ stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
+ stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
+ stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
+ stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
+ stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
+ stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
+ stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
+ stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
+ stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
+ stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
+ stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
+ stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
+ stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
+ stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
+ stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
+ stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
+ stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
+ stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
+ stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
+ stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
+ stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
+ stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
+ stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
+ stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
+ stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
+ stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
+ stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
+ stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
+ stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
+ stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
+ stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
+ stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
+ stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
+ stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
+ stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
+ stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
+ stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
+ stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
+ stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
+ stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
+ stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
+ stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
+ stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
+ stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
+ stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
+ stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
+ stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
+ stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
+ stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
+ stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
+ stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
+ stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
+ stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
+ stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
+ stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
+ stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
+ stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
+ stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
+ stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
+ stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
+ stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
+ stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
+ stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
+ stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
+ stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
+ stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
+ stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
+ stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
+ stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
+ stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
+ stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
+ stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
+ stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
+ stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
+ stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
+ stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
+ stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
+ stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
+ stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
+ stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
+ stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
+ stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
+ stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
+ stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
+ stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
+ stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
+ stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
+ stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
+ stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
+ stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
+ stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
+ stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
+ stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
+ stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
+ stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
+ stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
+ stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
+ stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
+ stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
+ stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
+ stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
+ stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
+ stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
+ stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
+ stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
+ stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
+ stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
+ stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
+ stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
+ stack4988, stack4992, stack4996, stack5000,
+}
+
+var Used byte
+
+func use(buf []byte) {
+ for _, c := range buf {
+ Used += c
+ }
+}
+
+// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
+func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() }
+func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() }
+func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() }
+func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() }
+func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() }
+func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() }
+func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() }
+func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() }
+func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() }
+func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() }
+func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() }
+func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() }
+func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() }
+func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() }
+func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() }
+func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() }
+func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() }
+func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() }
+func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() }
+func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() }
+func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() }
+func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() }
+func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() }
+func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() }
+func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() }
+func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() }
+func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() }
+func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() }
+func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() }
+func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() }
+func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() }
+func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() }
+func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() }
+func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() }
+func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() }
+func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() }
+func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() }
+func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() }
+func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() }
+func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() }
+func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() }
+func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() }
+func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() }
+func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() }
+func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() }
+func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() }
+func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() }
+func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() }
+func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() }
+func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() }
+func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() }
+func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() }
+func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() }
+func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() }
+func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() }
+func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() }
+func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() }
+func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() }
+func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() }
+func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() }
+func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() }
+func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() }
+func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() }
+func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() }
+func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() }
+func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() }
+func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() }
+func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() }
+func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() }
+func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() }
+func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() }
+func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() }
+func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() }
+func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() }
+func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() }
+func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() }
+func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() }
+func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() }
+func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() }
+func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() }
+func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() }
+func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() }
+func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() }
+func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() }
+func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() }
+func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() }
+func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() }
+func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() }
+func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() }
+func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() }
+func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() }
+func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() }
+func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() }
+func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() }
+func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() }
+func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() }
+func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() }
+func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() }
+func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() }
+func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() }
+func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() }
+func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() }
+func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() }
+func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() }
+func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() }
+func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() }
+func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() }
+func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() }
+func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() }
+func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() }
+func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() }
+func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() }
+func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() }
+func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() }
+func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() }
+func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() }
+func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() }
+func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() }
+func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() }
+func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() }
+func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() }
+func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() }
+func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() }
+func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() }
+func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() }
+func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() }
+func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() }
+func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() }
+func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() }
+func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() }
+func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() }
+func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() }
+func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() }
+func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() }
+func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() }
+func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() }
+func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() }
+func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() }
+func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() }
+func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() }
+func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() }
+func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() }
+func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() }
+func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() }
+func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() }
+func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() }
+func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() }
+func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() }
+func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() }
+func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() }
+func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() }
+func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() }
+func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() }
+func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() }
+func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() }
+func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() }
+func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() }
+func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() }
+func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() }
+func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() }
+func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() }
+func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() }
+func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() }
+func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() }
+func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() }
+func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() }
+func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() }
+func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() }
+func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() }
+func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() }
+func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() }
+func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() }
+func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() }
+func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() }
+func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() }
+func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() }
+func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() }
+func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() }
+func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() }
+func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() }
+func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() }
+func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() }
+func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() }
+func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() }
+func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() }
+func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() }
+func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() }
+func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() }
+func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() }
+func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() }
+func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() }
+func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() }
+func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() }
+func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() }
+func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() }
+func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() }
+func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() }
+func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() }
+func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() }
+func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() }
+func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() }
+func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() }
+func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() }
+func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() }
+func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() }
+func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() }
+func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() }
+func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() }
+func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() }
+func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() }
+func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() }
+func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() }
+func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() }
+func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() }
+func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() }
+func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() }
+func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() }
+func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() }
+func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() }
+func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() }
+func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() }
+func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() }
+func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() }
+func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() }
+func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() }
+func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() }
+func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() }
+func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() }
+func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() }
+func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() }
+func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() }
+func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() }
+func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() }
+func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() }
+func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() }
+func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() }
+func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() }
+func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() }
+func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() }
+func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() }
+func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() }
+func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() }
+func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() }
+func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() }
+func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() }
+func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() }
+func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() }
+func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() }
+func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() }
+func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
+func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
+func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
+func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
+func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
+func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
+func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
+func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
+func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
+func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
+func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
+func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
+func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
+func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
+func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
+func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
+func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
+func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
+func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
+func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
+func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
+func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
+func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
+func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
+func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
+func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
+func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
+func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
+func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
+func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
+func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
+func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
+func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
+func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
+func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
+func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
+func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
+func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
+func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
+func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
+func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
+func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
+func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
+func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
+func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
+func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
+func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
+func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
+func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
+func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
+func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
+func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
+func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
+func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
+func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
+func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
+func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
+func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
+func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
+func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
+func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
+func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
+func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
+func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
+func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
+func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
+func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
+func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
+func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
+func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
+func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
+func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
+func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
+func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
+func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
+func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
+func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
+func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
+func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
+func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
+func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
+func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
+func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
+func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
+func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
+func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
+func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
+func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
+func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
+func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
+func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
+func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
+func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
+func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
+func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
+func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
+func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
+func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
+func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
+func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
+func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
+func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
+func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
+func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
+func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
+func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
+func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
+func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
+func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
+func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
+func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
+func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
+func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
+func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
+func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
+func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
+func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
+func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
+func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
+func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
+func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
+func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
+func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
+func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
+func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
+func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
+func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
+func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
+func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
+func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
+func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
+func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
+func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
+func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
+func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
+func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
+func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
+func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
+func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
+func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
+func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
+func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
+func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
+func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
+func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
+func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
+func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
+func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
+func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
+func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
+func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
+func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
+func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
+func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
+func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
+func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
+func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
+func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
+func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
+func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
+func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
+func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
+func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
+func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
+func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
+func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
+func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
+func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
+func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
+func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
+func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
+func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
+func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
+func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
+func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
+func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
+func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
+func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
+func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
+func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
+func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
+func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
+func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
+func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
+func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
+func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
+func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
+func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
+func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
+func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
+func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
+func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
+func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
+func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
+func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
+func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
+func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
+func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
+func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
+func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
+func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
+func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
+func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
+func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
+func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
+func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
+func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
+func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
+func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
+func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
+func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
+func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
+func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
+func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
+func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
+func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
+func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
+func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
+func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
+func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
+func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
+func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
+func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
+func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
+func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
+func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
+func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
+func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
+func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
+func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
+func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
+func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
+func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
+func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
+func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
+func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
+func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
+func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
+func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
+func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
+func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
+func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
+func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
+func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
+func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
+func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
+func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
+func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
+func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
+func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
+func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
+func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
+func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
+func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
+func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
+func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
+func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
+func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
+func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
+func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
+func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
+func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
+func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
+func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
+func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
+func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
+func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
+func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
+func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
+func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
+func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
+func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
+func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
+func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
+func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
+func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
+func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
+func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
+func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
+func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
+func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
+func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
+func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
+func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
+func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
+func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
+func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
+func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
+func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
+func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
+func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
+func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
+func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
+func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
+func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
+func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
+func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
+func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
+func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
+func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
+func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
+func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
+func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
+func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
+func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
+func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
+func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
+func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
+func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
+func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
+func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
+func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
+func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
+func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
+func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
+func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
+func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
+func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
+func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
+func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
+func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
+func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
+func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
+func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
+func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
+func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
+func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
+func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
+func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
+func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
+func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
+func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
+func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
+func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
+func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
+func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
+func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
+func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
+func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
+func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
+func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
+func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
+func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
+func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
+func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
+func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
+func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
+func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
+func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
+func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
+func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
+func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
+func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
+func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
+func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
+func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
+func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
+func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
+func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
+func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
+func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
+func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
+func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
+func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
+func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
+func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
+func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
+func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
+func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
+func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
+func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
+func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
+func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
+func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
+func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
+func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
+func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
+func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
+func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
+func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
+func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
+func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
+func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
+func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
+func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
+func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
+func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
+func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
+func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
+func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
+func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
+func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
+func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
+func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
+func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
+func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
+func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
+func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
+func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
+func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
+func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
+func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
+func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
+func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
+func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
+func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
+func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
+func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
+func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
+func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
+func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
+func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
+func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
+func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
+func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
+func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
+func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
+func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
+func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
+func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
+func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
+func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
+func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
+func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
+func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
+func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
+func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
+func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
+func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
+func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
+func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
+func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
+func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
+func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
+func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
+func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
+func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
+func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
+func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
+func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
+func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
+func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
+func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
+func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
+func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
+func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
+func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
+func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
+func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
+func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
+func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
+func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
+func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
+func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
+func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
+func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
+func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
+func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
+func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
+func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
+func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
+func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
+func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
+func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
+func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
+func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
+func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
+func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
+func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
+func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
+func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
+func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
+func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
+func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
+func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
+func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
+func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
+func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
+func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
+func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
+func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
+func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
+func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
+func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
+func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
+func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
+func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
+func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
+func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
+func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
+func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
+func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
+func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
+func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
+func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
+func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
+func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
+func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
+func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
+func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
+func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
+func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
+func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
+func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
+func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
+func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
+func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
+func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
+func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
+func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
+func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
+func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
+func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
+func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
+func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
+func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
+func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
+func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
+func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
+func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
+func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
+func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
+func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
+func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
+func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
+func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
+func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
+func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
+func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
+func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
+func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
+func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
+func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
+func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
+func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
+func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
+func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
+func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
+func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
+func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
+func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
+func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
+func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
+func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
+func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
+func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
+func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
+func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
+func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
+func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
+func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
+func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
+func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
+func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
+func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
+func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
+func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
+func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
+func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
+func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
+func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
+func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
+func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
+func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
+func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
+func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
+func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
+func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
+func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
+func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
+func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
+func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
+func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
+func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
+func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
+func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
+func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
+func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
+func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
+func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
+func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
+func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
+func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
+func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
+func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
+func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
+func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
+func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
+func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
+func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
+func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
+func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
+func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
+func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
+func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
+func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
+func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
+func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
+func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
+func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
+func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
+func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
+func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
+func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
+func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
+func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
+func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
+func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
+func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
+func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
+func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
+func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
+func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
+func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
+func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
+func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
+func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
+func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
+func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
+func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
+func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
+func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
+func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
+func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
+func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
+func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
+func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
+func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
+func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
+func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
+func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
+func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
+func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
+func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
+func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
+func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
+func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
+func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
+func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
+func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
+func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
+func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
+func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
+func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
+func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
+func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
+func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
+func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
+func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
+func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
+func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
+func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
+func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
+func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
+func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
+func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
+func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
+func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
+func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
+func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
+func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
+func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
+func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
+func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
+func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
+func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
+func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
+func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
+func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
+func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
+func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
+func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
+func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
+func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
+func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
+func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
+func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
+func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
+func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
+func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
+func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
+func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
+func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
+func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
+func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
+func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
+func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
+func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
+func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
+func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
+func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
+func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
+func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
+func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
+func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
+func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
+func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
+func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
+func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
+func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
+func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
+func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
+func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
+func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
+func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
+func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
+func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
+func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
+func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
+func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
+func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
+func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
+func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
+func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
+func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
+func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
+func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
+func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
+func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
+func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
+func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
+func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
+func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
+func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
+func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
+func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
+func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
+func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
+func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
+func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
+func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
+func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
+func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
+func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
+func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
+func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
+func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
+func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
+func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
+func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
+func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
+func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
+func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
+func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
+func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
+func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
+func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
+func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
+func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
+func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
+func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
+func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
+func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
+func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
+func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
+func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
+func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
+func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
+func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
+func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
+func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
+func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
+func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
+func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
+func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
+func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
+func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
+func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
+func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
+func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
+func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
+func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
+func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
+func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
+func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
+func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
+func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
+func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
+func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
+func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
+func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
+func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
+func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
+func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
+func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
+func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
+func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
+func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
+func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
+func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
+func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
+func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
+func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
+func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
+func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
+func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
+func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
+func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
+func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
+func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
+func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
+func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
+func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
+func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
+func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
+func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
+func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
+func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
+func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
+func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
+func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
+func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
+func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
+func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
+func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
+func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
+func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
+func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
+func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
+func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
+func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
+func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
+func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
+func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
+func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
+func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
+func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
+func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
+func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
+func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
+func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
+func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
+func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
+func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
+func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
+func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
+func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
+func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
+func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
+func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
+func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
+func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
+func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
+func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
+func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
+func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
+func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
+func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
+func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
+func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
+func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
+func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
+func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
+func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
+func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
+func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
+func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
+func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
+func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
+func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
+func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
+func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
+func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
+func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
+func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
+func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
+func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
+func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
+func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
+func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
+func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
+func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
+func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
+func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
+func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
+func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
+func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
+func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
+func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
+func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
+func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
+func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
+func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
+func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
+func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
+func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
+func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
+func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
+func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
+func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
+func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
+func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
+func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
+func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
+func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
+func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
+func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
+func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
+func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
+func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
+func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
+func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
+func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
+func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
+func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
+func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
+func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
+func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
+func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
+func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
+func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
+func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
+func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
+func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
+func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
+func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
+func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
+func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
+func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
+func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
+func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
+func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
+func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
+func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
+func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
+func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
+func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
+func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
+func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
+func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
+func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
+func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
+func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
+func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
+func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
+func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
+func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
+func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
+func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
+func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
+func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
+func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
+func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
+func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
+func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
+func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
+func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
+func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
+func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
+func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
+func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
+func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
+func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
+func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
+func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
+func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
+func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
+func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
+func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
+func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
+func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
+func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
+func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
+func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
+func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
+func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
+func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
+func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
+func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
+func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
+func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
+func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
+func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
+func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
+func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
+func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
+func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
+func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
+func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
+func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
+func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
+func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
+func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
+func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
+func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
+func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
+func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
+func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
+func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
+func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
+func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
+func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
+func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
+func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
+func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
+func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
+func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
+func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
+func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
+func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
+func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index 48bf3183b..7e1f8a1e8 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -4,6 +4,7 @@
package runtime
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
String runtime·emptystring;
@@ -34,16 +35,18 @@ runtime·findnullw(uint16 *s)
uint32 runtime·maxstring = 256;
-String
-runtime·gostringsize(int32 l)
+static String
+gostringsize(int32 l)
{
String s;
uint32 ms;
if(l == 0)
return runtime·emptystring;
- s.str = runtime·mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
+ // leave room for NUL for C runtime (e.g., callers of getenv)
+ s.str = runtime·mallocgc(l+1, FlagNoPointers, 1, 0);
s.len = l;
+ s.str[l] = 0;
for(;;) {
ms = runtime·maxstring;
if((uint32)l <= ms || runtime·cas(&runtime·maxstring, ms, (uint32)l))
@@ -59,7 +62,7 @@ runtime·gostring(byte *str)
String s;
l = runtime·findnull(str);
- s = runtime·gostringsize(l);
+ s = gostringsize(l);
runtime·memmove(s.str, str, l);
return s;
}
@@ -69,7 +72,7 @@ runtime·gostringn(byte *str, int32 l)
{
String s;
- s = runtime·gostringsize(l);
+ s = gostringsize(l);
runtime·memmove(s.str, str, l);
return s;
}
@@ -80,6 +83,8 @@ runtime·gobytes(byte *p, int32 n)
Slice sl;
sl.array = runtime·mallocgc(n, FlagNoPointers, 1, 0);
+ sl.len = n;
+ sl.cap = n;
runtime·memmove(sl.array, p, n);
return sl;
}
@@ -97,18 +102,23 @@ runtime·gostringnocopy(byte *str)
String
runtime·gostringw(uint16 *str)
{
- int32 n, i;
+ int32 n1, n2, i;
byte buf[8];
String s;
- n = 0;
- for(i=0; str[i]; i++)
- n += runtime·runetochar(buf, str[i]);
- s = runtime·gostringsize(n+4);
- n = 0;
+ n1 = 0;
for(i=0; str[i]; i++)
- n += runtime·runetochar(s.str+n, str[i]);
- s.len = n;
+ n1 += runtime·runetochar(buf, str[i]);
+ s = gostringsize(n1+4);
+ n2 = 0;
+ for(i=0; str[i]; i++) {
+ // check for race
+ if(n2 >= n1)
+ break;
+ n2 += runtime·runetochar(s.str+n2, str[i]);
+ }
+ s.len = n2;
+ s.str[s.len] = 0;
return s;
}
@@ -122,7 +132,7 @@ runtime·catstring(String s1, String s2)
if(s2.len == 0)
return s1;
- s3 = runtime·gostringsize(s1.len + s2.len);
+ s3 = gostringsize(s1.len + s2.len);
runtime·memmove(s3.str, s1.str, s1.len);
runtime·memmove(s3.str+s1.len, s2.str, s2.len);
return s3;
@@ -141,7 +151,7 @@ concatstring(int32 n, String *s)
l += s[i].len;
}
- out = runtime·gostringsize(l);
+ out = gostringsize(l);
l = 0;
for(i=0; i<n; i++) {
runtime·memmove(out.str+l, s[i].str, s[i].len);
@@ -251,23 +261,24 @@ func slicestring1(si String, lindex int32) (so String) {
}
func intstring(v int64) (s String) {
- s = runtime·gostringsize(8);
+ s = gostringsize(8);
s.len = runtime·runetochar(s.str, v);
+ s.str[s.len] = 0;
}
func slicebytetostring(b Slice) (s String) {
- s = runtime·gostringsize(b.len);
+ s = gostringsize(b.len);
runtime·memmove(s.str, b.array, s.len);
}
func stringtoslicebyte(s String) (b Slice) {
- b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 1);
+ b.array = runtime·mallocgc(s.len, FlagNoPointers, 1, 0);
b.len = s.len;
b.cap = s.len;
runtime·memmove(b.array, s.str, s.len);
}
-func sliceinttostring(b Slice) (s String) {
+func slicerunetostring(b Slice) (s String) {
int32 siz1, siz2, i;
int32 *a;
byte dum[8];
@@ -278,7 +289,7 @@ func sliceinttostring(b Slice) (s String) {
siz1 += runtime·runetochar(dum, a[i]);
}
- s = runtime·gostringsize(siz1+4);
+ s = gostringsize(siz1+4);
siz2 = 0;
for(i=0; i<b.len; i++) {
// check for race
@@ -287,15 +298,16 @@ func sliceinttostring(b Slice) (s String) {
siz2 += runtime·runetochar(s.str+siz2, a[i]);
}
s.len = siz2;
+ s.str[s.len] = 0;
}
-func stringtosliceint(s String) (b Slice) {
+func stringtoslicerune(s String) (b Slice) {
int32 n;
int32 dum, *r;
uint8 *p, *ep;
// two passes.
- // unlike sliceinttostring, no race because strings are immutable.
+ // unlike slicerunetostring, no race because strings are immutable.
p = s.str;
ep = s.str+s.len;
n = 0;
@@ -304,7 +316,7 @@ func stringtosliceint(s String) (b Slice) {
n++;
}
- b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 1);
+ b.array = runtime·mallocgc(n*sizeof(r[0]), FlagNoPointers, 1, 0);
b.len = n;
b.cap = n;
p = s.str;
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index d2ebf9b40..f29276bd7 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -13,9 +13,9 @@
// and figure out exactly what we want.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "arch.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
extern byte pclntab[], epclntab[], symtab[], esymtab[];
@@ -381,6 +381,15 @@ runtime·funcline(Func *f, uintptr targetpc)
return line;
}
+void
+runtime·funcline_go(Func *f, uintptr targetpc, String retfile, int32 retline)
+{
+ retfile = f->src;
+ retline = runtime·funcline(f, targetpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+}
+
static void
buildfuncs(void)
{
@@ -428,13 +437,17 @@ runtime·findfunc(uintptr addr)
// (Before enabling the signal handler,
// SetCPUProfileRate calls findfunc to trigger
// the initialization outside the handler.)
- if(runtime·atomicload(&funcinit) == 0) {
- runtime·lock(&funclock);
- if(funcinit == 0) {
- buildfuncs();
- runtime·atomicstore(&funcinit, 1);
+ // Avoid deadlock on fault during malloc
+ // by not calling buildfuncs if we're already in malloc.
+ if(!m->mallocing && !m->gcing) {
+ if(runtime·atomicload(&funcinit) == 0) {
+ runtime·lock(&funclock);
+ if(funcinit == 0) {
+ buildfuncs();
+ runtime·atomicstore(&funcinit, 1);
+ }
+ runtime·unlock(&funclock);
}
- runtime·unlock(&funclock);
}
if(nfunc == 0)
@@ -464,3 +477,43 @@ runtime·findfunc(uintptr addr)
runtime·prints("findfunc unreachable\n");
return nil;
}
+
+static bool
+hasprefix(String s, int8 *p)
+{
+ int32 i;
+
+ for(i=0; i<s.len; i++) {
+ if(p[i] == 0)
+ return 1;
+ if(p[i] != s.str[i])
+ return 0;
+ }
+ return p[i] == 0;
+}
+
+static bool
+contains(String s, int8 *p)
+{
+ int32 i;
+
+ if(p[0] == 0)
+ return 1;
+ for(i=0; i<s.len; i++) {
+ if(s.str[i] != p[0])
+ continue;
+ if(hasprefix((String){s.str + i, s.len - i}, p))
+ return 1;
+ }
+ return 0;
+}
+
+bool
+runtime·showframe(Func *f)
+{
+ static int32 traceback = -1;
+
+ if(traceback < 0)
+ traceback = runtime·gotraceback();
+ return traceback > 1 || contains(f->name, ".") && !hasprefix(f->name, "runtime.");
+}
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/sys_darwin_386.s
index 87fbdbb79..3cf3506ad 100644
--- a/src/pkg/runtime/darwin/386/sys.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -6,17 +6,13 @@
// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
-#include "386/asm.h"
-
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
+#include "zasm_GOOS_GOARCH.h"
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),7,$0
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Exit this OS thread (like pthread_exit, which eventually
@@ -25,7 +21,7 @@ TEXT runtime·exit1(SB),7,$0
MOVL $361, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$0
@@ -48,11 +44,18 @@ TEXT runtime·mmap(SB),7,$0
INT $0x80
RET
+TEXT runtime·madvise(SB),7,$0
+ MOVL $75, AX
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
TEXT runtime·munmap(SB),7,$0
MOVL $73, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB),7,$0
@@ -60,27 +63,57 @@ TEXT runtime·setitimer(SB),7,$0
INT $0x80
RET
-// void gettime(int64 *sec, int32 *usec)
-TEXT runtime·gettime(SB), 7, $32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
LEAL 12(SP), AX // must be non-nil, unused
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
MOVL $116, AX
INT $0x80
+ MOVL DX, BX
- MOVL sec+0(FP), DI
- MOVL AX, (DI)
- MOVL $0, 4(DI) // zero extend 32 -> 64
+ // sec is in AX, usec in BX
+ MOVL AX, sec+0(FP)
+ MOVL $0, sec+4(FP)
+ IMULL $1000, BX
+ MOVL BX, nsec+8(FP)
+ RET
- MOVL usec+4(FP), DI
- MOVL DX, (DI)
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB), 7, $32
+ LEAL 12(SP), AX // must be non-nil, unused
+ MOVL AX, 4(SP)
+ MOVL $0, 8(SP) // time zone pointer
+ MOVL $116, AX
+ INT $0x80
+ MOVL DX, BX
+
+ // sec is in AX, usec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ IMULL $1000, BX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·sigprocmask(SB),7,$0
+ MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaction(SB),7,$0
MOVL $46, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Sigtramp's job is to call the actual signal handler.
@@ -93,13 +126,18 @@ TEXT runtime·sigaction(SB),7,$0
// 20(FP) context
TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BP
+ CMPL BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
-
+
// g = m->gsignal
- MOVL m(CX), BP
MOVL m_gsignal(BP), BP
MOVL BP, g(CX)
@@ -111,7 +149,7 @@ TEXT runtime·sigtramp(SB),7,$40
MOVL context+16(FP), BX
MOVL BX, 8(SP)
MOVL DI, 12(SP)
-
+
MOVL handler+0(FP), BX
CALL BX
@@ -128,14 +166,34 @@ TEXT runtime·sigtramp(SB),7,$40
MOVL BX, 8(SP)
MOVL $184, AX // sigreturn(ucontext, infostyle)
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·usleep(SB),7,$32
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVL AX, 24(SP) // sec
+ MOVL DX, 28(SP) // usec
+
+ // select(0, 0, 0, 0, &tv)
+ MOVL $0, 0(SP) // "return PC" - ignored
+ MOVL $0, 4(SP)
+ MOVL $0, 8(SP)
+ MOVL $0, 12(SP)
+ MOVL $0, 16(SP)
+ LEAL 24(SP), AX
+ MOVL AX, 20(SP)
+ MOVL $93, AX
+ INT $0x80
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
@@ -211,7 +269,7 @@ TEXT runtime·bsdthread_register(SB),7,$40
MOVL $0, 24(SP) // dispatchqueue_offset
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Invoke Mach system call.
@@ -288,7 +346,7 @@ TEXT runtime·setldt(SB),7,$32
* To accommodate that rewrite, we translate the
* address and limit here so that 0x468(GS) maps to 0(address).
*
- * See ../../../../libcgo/darwin_386.c for the derivation
+ * See cgo/gcc_darwin_386.c:/468 for the derivation
* of the constant.
*/
SUBL $0x468, BX
@@ -309,3 +367,12 @@ TEXT runtime·setldt(SB),7,$32
XORL AX, AX
MOVW GS, AX
RET
+
+TEXT runtime·sysctl(SB),7,$0
+ MOVL $202, AX
+ INT $0x80
+ JAE 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/sys_darwin_amd64.s
index 8d1b20f11..90571baae 100644
--- a/src/pkg/runtime/darwin/amd64/sys.s
+++ b/src/pkg/runtime/sys_darwin_amd64.s
@@ -11,14 +11,14 @@
// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
//
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Exit this OS thread (like pthread_exit, which eventually
@@ -27,7 +27,7 @@ TEXT runtime·exit1(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$0
@@ -55,16 +55,51 @@ TEXT runtime·setitimer(SB), 7, $0
SYSCALL
RET
-// void gettime(int64 *sec, int32 *usec)
-TEXT runtime·gettime(SB), 7, $32
+TEXT runtime·madvise(SB), 7, $0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL 24(SP), DX // arg 3 advice
+ MOVL $(0x2000000+75), AX // syscall entry madvise
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
MOVQ SP, DI // must be non-nil, unused
MOVQ $0, SI
MOVL $(0x2000000+116), AX
SYSCALL
- MOVQ sec+0(FP), DI
- MOVQ AX, (DI)
- MOVQ usec+8(FP), DI
- MOVL DX, (DI)
+
+ // sec is in AX, usec in DX
+ MOVQ AX, sec+0(FP)
+ IMULQ $1000, DX
+ MOVL DX, nsec+8(FP)
+ RET
+
+// int64 nanotime(void)
+TEXT runtime·nanotime(SB), 7, $32
+ MOVQ SP, DI // must be non-nil, unused
+ MOVQ $0, SI
+ MOVL $(0x2000000+116), AX
+ SYSCALL
+
+ // sec is in AX, usec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ IMULQ $1000, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·sigprocmask(SB),7,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process)
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaction(SB),7,$0
@@ -76,18 +111,23 @@ TEXT runtime·sigaction(SB),7,$0
MOVL $(0x2000000+46), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
-
+
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 48(SP)
-
+
// g = m->gsignal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -129,12 +169,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $(0x2000000+73), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
@@ -143,7 +178,25 @@ TEXT runtime·sigaltstack(SB),7,$0
MOVQ $(0x2000000+53), AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·usleep(SB),7,$16
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVQ AX, 0(SP) // sec
+ MOVL DX, 8(SP) // usec
+
+ // select(0, 0, 0, 0, &tv)
+ MOVL $0, DI
+ MOVL $0, SI
+ MOVL $0, DX
+ MOVL $0, R10
+ MOVQ SP, R8
+ MOVL $(0x2000000+93), AX
+ SYSCALL
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
@@ -189,7 +242,7 @@ TEXT runtime·bsdthread_start(SB),7,$0
POPQ SI
POPQ CX
POPQ DX
-
+
get_tls(BX)
MOVQ CX, m(BX)
MOVQ SI, m_procid(CX) // thread port is m->procid
@@ -213,7 +266,7 @@ TEXT runtime·bsdthread_register(SB),7,$0
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
@@ -284,8 +337,8 @@ TEXT runtime·mach_semaphore_signal_all(SB),7,$0
// set tls base to DI
TEXT runtime·settls(SB),7,$32
/*
- * Same as in ../386/sys.s:/ugliness, different constant.
- * See ../../../../libcgo/darwin_amd64.c for the derivation
+ * Same as in sys_darwin_386.s:/ugliness, different constant.
+ * See cgo/gcc_darwin_amd64.c for the derivation
* of the constant.
*/
SUBQ $0x8a0, DI
@@ -293,3 +346,18 @@ TEXT runtime·settls(SB),7,$32
MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3
SYSCALL
RET
+
+TEXT runtime·sysctl(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVQ 40(SP), R8
+ MOVQ 48(SP), R9
+ MOVL $(0x2000000+202), AX // syscall entry
+ SYSCALL
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/sys_freebsd_386.s
index 765e2fcc4..a72d8972b 100644
--- a/src/pkg/runtime/freebsd/386/sys.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -6,7 +6,7 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "386/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT runtime·sys_umtx_op(SB),7,$-4
MOVL $454, AX
@@ -45,14 +45,14 @@ TEXT runtime·thr_start(SB),7,$0
TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-4
MOVL $431, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-4
@@ -60,6 +60,11 @@ TEXT runtime·write(SB),7,$-4
INT $0x80
RET
+TEXT runtime·getrlimit(SB),7,$-4
+ MOVL $194, AX
+ INT $0x80
+ RET
+
TEXT runtime·raisesigpipe(SB),7,$12
// thr_self(&8(SP))
LEAL 8(SP), AX
@@ -74,10 +79,6 @@ TEXT runtime·raisesigpipe(SB),7,$12
INT $0x80
RET
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
-
TEXT runtime·mmap(SB),7,$32
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
@@ -98,7 +99,7 @@ TEXT runtime·munmap(SB),7,$-4
MOVL $73, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB), 7, $-4
@@ -106,39 +107,69 @@ TEXT runtime·setitimer(SB), 7, $-4
INT $0x80
RET
-TEXT runtime·gettime(SB), 7, $32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
MOVL $0, 8(SP)
INT $0x80
+ MOVL 12(SP), AX // sec
+ MOVL 16(SP), BX // usec
- MOVL 12(SP), BX // sec
- MOVL sec+0(FP), DI
- MOVL BX, (DI)
- MOVL $0, 4(DI) // zero extend 32 -> 64 bits
+ // sec is in AX, usec in BX
+ MOVL AX, sec+0(FP)
+ MOVL $0, sec+4(FP)
+ IMULL $1000, BX
+ MOVL BX, nsec+8(FP)
+ RET
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB), 7, $32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+ MOVL 12(SP), AX // sec
MOVL 16(SP), BX // usec
- MOVL usec+4(FP), DI
- MOVL BX, (DI)
+
+ // sec is in AX, usec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ IMULL $1000, BX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
RET
+
TEXT runtime·sigaction(SB),7,$-4
MOVL $416, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
- MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
@@ -164,14 +195,32 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL AX, 4(SP)
MOVL $417, AX // sigreturn(ucontext)
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·usleep(SB),7,$20
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVL AX, 12(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVL AX, 16(SP) // tv_nsec
+
+ MOVL $0, 0(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 4(SP) // arg 1 - rqtp
+ MOVL $0, 8(SP) // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ INT $0x80
RET
/*
@@ -193,7 +242,7 @@ int i386_set_ldt(int, const union ldt_entry *, int);
// setldt(int entry, int address, int limit)
TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
- // see comment in linux/386/sys.s; freebsd is similar
+ // see comment in sys_linux_386.s; freebsd is similar
ADDL $0x8, BX
// set up data_desc
@@ -236,4 +285,40 @@ TEXT runtime·i386_set_ldt(SB),7,$16
INT $3
RET
+TEXT runtime·sysctl(SB),7,$28
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - name
+ MOVSL // arg 2 - namelen
+ MOVSL // arg 3 - oldp
+ MOVSL // arg 4 - oldlenp
+ MOVSL // arg 5 - newp
+ MOVSL // arg 6 - newlen
+ MOVL $202, AX // sys___sysctl
+ INT $0x80
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+TEXT runtime·osyield(SB),7,$-4
+ MOVL $331, AX // sys_sched_yield
+ INT $0x80
+ RET
+
+TEXT runtime·sigprocmask(SB),7,$16
+ MOVL $0, 0(SP) // syscall gap
+ MOVL $3, 4(SP) // arg 1 - how (SIG_SETMASK)
+ MOVL args+0(FP), AX
+ MOVL AX, 8(SP) // arg 2 - set
+ MOVL args+4(FP), AX
+ MOVL AX, 12(SP) // arg 3 - oset
+ MOVL $340, AX // sys_sigprocmask
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/sys_freebsd_amd64.s
index c5cc082e4..36e034a80 100644
--- a/src/pkg/runtime/freebsd/amd64/sys.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -6,7 +6,7 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT runtime·sys_umtx_op(SB),7,$0
MOVQ 8(SP), DI
@@ -26,7 +26,7 @@ TEXT runtime·thr_new(SB),7,$0
RET
TEXT runtime·thr_start(SB),7,$0
- MOVQ DI, R13 // m
+ MOVQ DI, R13 // m
// set up FS to point at m->tls
LEAQ m_tls(R13), DI
@@ -47,14 +47,14 @@ TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $1, AX
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-8
MOVQ 8(SP), DI // arg 1 exit status
MOVL $431, AX
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-8
@@ -65,6 +65,13 @@ TEXT runtime·write(SB),7,$-8
SYSCALL
RET
+TEXT runtime·getrlimit(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $194, AX
+ SYSCALL
+ RET
+
TEXT runtime·raisesigpipe(SB),7,$16
// thr_self(&8(SP))
LEAQ 8(SP), DI // arg 1 &8(SP)
@@ -85,19 +92,34 @@ TEXT runtime·setitimer(SB), 7, $-8
SYSCALL
RET
-TEXT runtime·gettime(SB), 7, $32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
MOVL $116, AX
LEAQ 8(SP), DI
MOVQ $0, SI
SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
- MOVQ 8(SP), BX // sec
- MOVQ sec+0(FP), DI
- MOVQ BX, (DI)
+ // sec is in AX, usec in DX
+ MOVQ AX, sec+0(FP)
+ IMULQ $1000, DX
+ MOVL DX, nsec+8(FP)
+ RET
- MOVL 16(SP), BX // usec
- MOVQ usec+8(FP), DI
- MOVL BX, (DI)
+TEXT runtime·nanotime(SB), 7, $32
+ MOVL $116, AX
+ LEAQ 8(SP), DI
+ MOVQ $0, SI
+ SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
+
+ // sec is in AX, usec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ IMULQ $1000, DX
+ ADDQ DX, AX
RET
TEXT runtime·sigaction(SB),7,$-8
@@ -107,18 +129,23 @@ TEXT runtime·sigaction(SB),7,$-8
MOVL $416, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -152,12 +179,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $73, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$-8
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$-8
@@ -166,7 +188,23 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVQ $53, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·usleep(SB),7,$16
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVQ AX, 0(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVQ AX, 8(SP) // tv_nsec
+
+ MOVQ SP, DI // arg 1 - rqtp
+ MOVQ $0, SI // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ SYSCALL
RET
// set tls base to DI
@@ -178,5 +216,35 @@ TEXT runtime·settls(SB),7,$8
MOVQ $165, AX // sysarch
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sysctl(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - name
+ MOVL 16(SP), SI // arg 2 - namelen
+ MOVQ 24(SP), DX // arg 3 - oldp
+ MOVQ 32(SP), R10 // arg 4 - oldlenp
+ MOVQ 40(SP), R8 // arg 5 - newp
+ MOVQ 48(SP), R9 // arg 6 - newlen
+ MOVQ $202, AX // sys___sysctl
+ SYSCALL
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+TEXT runtime·osyield(SB),7,$-4
+ MOVL $331, AX // sys_sched_yield
+ SYSCALL
+ RET
+
+TEXT runtime·sigprocmask(SB),7,$0
+ MOVL $3, DI // arg 1 - how (SIG_SETMASK)
+ MOVQ 8(SP), SI // arg 2 - set
+ MOVQ 16(SP), DX // arg 3 - oset
+ MOVL $340, AX // sys_sigprocmask
+ SYSCALL
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
RET
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/sys_linux_386.s
index 0b4a34986..602d9ddac 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -6,19 +6,19 @@
// System calls and other sys.stuff for 386, Linux
//
-#include "386/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT runtime·exit(SB),7,$0
MOVL $252, AX // syscall number
MOVL 4(SP), BX
- INT $0x80
+ CALL *runtime·_vdso(SB)
INT $3 // not reached
RET
TEXT runtime·exit1(SB),7,$0
MOVL $1, AX // exit - exit the current os thread
MOVL 4(SP), BX
- INT $0x80
+ CALL *runtime·_vdso(SB)
INT $3 // not reached
RET
@@ -27,13 +27,13 @@ TEXT runtime·open(SB),7,$0
MOVL 4(SP), BX
MOVL 8(SP), CX
MOVL 12(SP), DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·close(SB),7,$0
MOVL $6, AX // syscall - close
MOVL 4(SP), BX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·write(SB),7,$0
@@ -41,7 +41,7 @@ TEXT runtime·write(SB),7,$0
MOVL 4(SP), BX
MOVL 8(SP), CX
MOVL 12(SP), DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·read(SB),7,$0
@@ -49,16 +49,41 @@ TEXT runtime·read(SB),7,$0
MOVL 4(SP), BX
MOVL 8(SP), CX
MOVL 12(SP), DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
+ RET
+
+TEXT runtime·getrlimit(SB),7,$0
+ MOVL $191, AX // syscall - ugetrlimit
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ CALL *runtime·_vdso(SB)
+ RET
+
+TEXT runtime·usleep(SB),7,$8
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVL AX, 0(SP)
+ MOVL DX, 4(SP)
+
+ // select(0, 0, 0, 0, &tv)
+ MOVL $142, AX
+ MOVL $0, BX
+ MOVL $0, CX
+ MOVL $0, DX
+ MOVL $0, SI
+ LEAL 0(SP), DI
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·raisesigpipe(SB),7,$12
MOVL $224, AX // syscall - gettid
- INT $0x80
+ CALL *runtime·_vdso(SB)
MOVL AX, 0(SP) // arg 1 tid
MOVL $13, 4(SP) // arg 2 SIGPIPE
MOVL $238, AX // syscall - tkill
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·setitimer(SB),7,$0-24
@@ -66,7 +91,7 @@ TEXT runtime·setitimer(SB),7,$0-24
MOVL 4(SP), BX
MOVL 8(SP), CX
MOVL 12(SP), DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·mincore(SB),7,$0-24
@@ -74,24 +99,60 @@ TEXT runtime·mincore(SB),7,$0-24
MOVL 4(SP), BX
MOVL 8(SP), CX
MOVL 12(SP), DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
-TEXT runtime·gettime(SB), 7, $32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
MOVL $78, AX // syscall - gettimeofday
LEAL 8(SP), BX
MOVL $0, CX
MOVL $0, DX
- INT $0x80
+ CALL *runtime·_vdso(SB)
+ MOVL 8(SP), AX // sec
+ MOVL 12(SP), BX // usec
- MOVL 8(SP), BX // sec
- MOVL sec+0(FP), DI
- MOVL BX, (DI)
- MOVL $0, 4(DI) // zero extend 32 -> 64 bits
+ // sec is in AX, usec in BX
+ MOVL AX, sec+0(FP)
+ MOVL $0, sec+4(FP)
+ IMULL $1000, BX
+ MOVL BX, nsec+8(FP)
+ RET
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB), 7, $32
+ MOVL $78, AX // syscall - gettimeofday
+ LEAL 8(SP), BX
+ MOVL $0, CX
+ MOVL $0, DX
+ CALL *runtime·_vdso(SB)
+ MOVL 8(SP), AX // sec
MOVL 12(SP), BX // usec
- MOVL usec+4(FP), DI
- MOVL BX, (DI)
+
+ // sec is in AX, usec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ IMULL $1000, BX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·rtsigprocmask(SB),7,$0
+ MOVL $175, AX // syscall entry
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ CALL *runtime·_vdso(SB)
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
RET
TEXT runtime·rt_sigaction(SB),7,$0
@@ -100,21 +161,27 @@ TEXT runtime·rt_sigaction(SB),7,$0
MOVL 8(SP), CX
MOVL 12(SP), DX
MOVL 16(SP), SI
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
-
+
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
-
+
// g = m->gsignal
MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
-
+
// copy arguments for call to sighandler
MOVL sig+0(FP), BX
MOVL BX, 0(SP)
@@ -125,20 +192,19 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL DI, 12(SP)
CALL runtime·sighandler(SB)
-
+
// restore g
get_tls(CX)
MOVL 20(SP), BX
MOVL BX, g(CX)
-
- RET
-TEXT runtime·sigignore(SB),7,$0
RET
TEXT runtime·sigreturn(SB),7,$0
MOVL $173, AX // rt_sigreturn
- INT $0x80
+ // Sigreturn expects same SP as signal handler,
+ // so cannot CALL *runtime._vsdo(SB) here.
+ INT $0x80
INT $3 // not reached
RET
@@ -151,7 +217,7 @@ TEXT runtime·mmap(SB),7,$0
MOVL 20(SP), DI
MOVL 24(SP), BP
SHRL $12, BP
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS 3(PC)
NOTL AX
@@ -162,7 +228,18 @@ TEXT runtime·munmap(SB),7,$0
MOVL $91, AX // munmap
MOVL 4(SP), BX
MOVL 8(SP), CX
- INT $0x80
+ CALL *runtime·_vdso(SB)
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·madvise(SB),7,$0
+ MOVL $219, AX // madvise
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS 2(PC)
INT $3
@@ -178,7 +255,7 @@ TEXT runtime·futex(SB),7,$0
MOVL 16(SP), SI
MOVL 20(SP), DI
MOVL 24(SP), BP
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
@@ -199,6 +276,10 @@ TEXT runtime·clone(SB),7,$0
MOVL SI, 8(CX)
MOVL $1234, 12(CX)
+ // cannot use CALL *runtime·_vdso(SB) here, because
+ // the stack changes during the system call (after
+ // CALL *runtime·_vdso(SB), the child is still using
+ // the parent's stack when executing its RET instruction).
INT $0x80
// In parent, return.
@@ -214,7 +295,7 @@ TEXT runtime·clone(SB),7,$0
// Initialize AX to Linux tid
MOVL $224, AX
- INT $0x80
+ CALL *runtime·_vdso(SB)
// In child on new stack. Reload registers (paranoia).
MOVL 0(SP), BX // m
@@ -262,7 +343,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVL $186, AX // sigaltstack
MOVL new+4(SP), BX
MOVL old+8(SP), CX
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS 2(PC)
INT $3
@@ -323,7 +404,7 @@ TEXT runtime·setldt(SB),7,$32
MOVL AX, CX // user_desc
MOVL $16, DX // sizeof(user_desc)
MOVL $123, AX // syscall - modify_ldt
- INT $0x80
+ CALL *runtime·_vdso(SB)
// breakpoint on error
CMPL AX, $0xfffff001
@@ -340,5 +421,5 @@ TEXT runtime·setldt(SB),7,$32
TEXT runtime·osyield(SB),7,$0
MOVL $158, AX
- INT $0x80
+ CALL *runtime·_vdso(SB)
RET
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/sys_linux_amd64.s
index 8b4dcd921..657ab7e0b 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -6,7 +6,7 @@
// System calls and other sys.stuff for AMD64, Linux
//
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
TEXT runtime·exit(SB),7,$0-8
MOVL 8(SP), DI
@@ -50,6 +50,31 @@ TEXT runtime·read(SB),7,$0-24
SYSCALL
RET
+TEXT runtime·getrlimit(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $97, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·usleep(SB),7,$16
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVQ AX, 0(SP)
+ MOVQ DX, 8(SP)
+
+ // select(0, 0, 0, 0, &tv)
+ MOVL $0, DI
+ MOVL $0, SI
+ MOVL $0, DX
+ MOVL $0, R10
+ MOVQ SP, R8
+ MOVL $23, AX
+ SYSCALL
+ RET
+
TEXT runtime·raisesigpipe(SB),7,$12
MOVL $186, AX // syscall - gettid
SYSCALL
@@ -75,19 +100,46 @@ TEXT runtime·mincore(SB),7,$0-24
SYSCALL
RET
-TEXT runtime·gettime(SB), 7, $32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
LEAQ 8(SP), DI
MOVQ $0, SI
MOVQ $0xffffffffff600000, AX
CALL AX
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
- MOVQ 8(SP), BX // sec
- MOVQ sec+0(FP), DI
- MOVQ BX, (DI)
+ // sec is in AX, usec in DX
+ MOVQ AX, sec+0(FP)
+ IMULQ $1000, DX
+ MOVL DX, nsec+8(FP)
+ RET
- MOVL 16(SP), BX // usec
- MOVQ usec+8(FP), DI
- MOVL BX, (DI)
+TEXT runtime·nanotime(SB), 7, $32
+ LEAQ 8(SP), DI
+ MOVQ $0, SI
+ MOVQ $0xffffffffff600000, AX
+ CALL AX
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
+
+ // sec is in AX, usec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ IMULQ $1000, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·rtsigprocmask(SB),7,$0-32
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL 32(SP), R10
+ MOVL $14, AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·rt_sigaction(SB),7,$0-32
@@ -102,12 +154,17 @@ TEXT runtime·rt_sigaction(SB),7,$0-32
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->gsignal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -124,9 +181,6 @@ TEXT runtime·sigtramp(SB),7,$64
MOVQ R10, g(BX)
RET
-TEXT runtime·sigignore(SB),7,$0
- RET
-
TEXT runtime·sigreturn(SB),7,$0
MOVL $15, AX // rt_sigreturn
SYSCALL
@@ -156,12 +210,18 @@ TEXT runtime·munmap(SB),7,$0
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·notok(SB),7,$0
- MOVQ $0xf1, BP
- MOVQ BP, (BP)
+TEXT runtime·madvise(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ $28, AX // madvise
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ MOVL $0xf1, 0xf1 // crash
RET
// int64 futex(int32 *uaddr, int32 op, int32 val,
@@ -195,10 +255,10 @@ TEXT runtime·clone(SB),7,$0
CMPQ AX, $0
JEQ 2(PC)
RET
-
+
// In child, on new stack.
MOVQ SI, SP
-
+
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
@@ -230,7 +290,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// set tls base to DI
@@ -243,7 +303,7 @@ TEXT runtime·settls(SB),7,$32
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·osyield(SB),7,$0
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/sys_linux_arm.s
index 8619f0945..03e173d26 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -6,12 +6,9 @@
// System calls and other sys.stuff for arm, Linux
//
-#include "arm/asm.h"
+#include "zasm_GOOS_GOARCH.h"
-// OABI
-//#define SYS_BASE 0x00900000
-
-// EABI
+// for EABI, as we don't support OABI
#define SYS_BASE 0x0
#define SYS_exit (SYS_BASE + 1)
@@ -23,16 +20,20 @@
#define SYS_clone (SYS_BASE + 120)
#define SYS_rt_sigreturn (SYS_BASE + 173)
#define SYS_rt_sigaction (SYS_BASE + 174)
+#define SYS_rt_sigprocmask (SYS_BASE + 175)
#define SYS_sigaltstack (SYS_BASE + 186)
#define SYS_mmap2 (SYS_BASE + 192)
#define SYS_futex (SYS_BASE + 240)
#define SYS_exit_group (SYS_BASE + 248)
#define SYS_munmap (SYS_BASE + 91)
+#define SYS_madvise (SYS_BASE + 220)
#define SYS_setitimer (SYS_BASE + 104)
#define SYS_mincore (SYS_BASE + 219)
#define SYS_gettid (SYS_BASE + 224)
#define SYS_tkill (SYS_BASE + 238)
#define SYS_sched_yield (SYS_BASE + 158)
+#define SYS_select (SYS_BASE + 142) // newselect
+#define SYS_ugetrlimit (SYS_BASE + 191)
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
@@ -67,6 +68,13 @@ TEXT runtime·read(SB),7,$0
SWI $0
RET
+TEXT runtime·getrlimit(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_ugetrlimit, R7
+ SWI $0
+ RET
+
TEXT runtime·exit(SB),7,$-4
MOVW 0(FP), R0
MOVW $SYS_exit_group, R7
@@ -101,6 +109,9 @@ TEXT runtime·mmap(SB),7,$0
MOVW 20(FP), R5
MOVW $SYS_mmap2, R7
SWI $0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ RSB.HI $0, R0
RET
TEXT runtime·munmap(SB),7,$0
@@ -108,6 +119,22 @@ TEXT runtime·munmap(SB),7,$0
MOVW 4(FP), R1
MOVW $SYS_munmap, R7
SWI $0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
+ RET
+
+TEXT runtime·madvise(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW $SYS_madvise, R7
+ SWI $0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
RET
TEXT runtime·setitimer(SB),7,$0
@@ -126,31 +153,45 @@ TEXT runtime·mincore(SB),7,$0
SWI $0
RET
-TEXT runtime·gettime(SB),7,$32
- /* dummy version - return 0,0 */
- MOVW $0, R1
- MOVW 0(FP), R0
- MOVW R1, 0(R0)
- MOVW R1, 4(R0)
- MOVW 4(FP), R0
- MOVW R1, 0(R0)
-
-/*
- attempt at real version - seg faults
-
- MOVW $8(SP), R0
+TEXT time·now(SB), 7, $32
+ MOVW $8(R13), R0 // timeval
+ MOVW $0, R1 // zone
+ MOVW $SYS_gettimeofday, R7
+ SWI $0
+
+ MOVW 8(R13), R0 // sec
+ MOVW 12(R13), R2 // usec
+
+ MOVW R0, 0(FP)
MOVW $0, R1
+ MOVW R1, 4(FP)
+ MOVW $1000, R3
+ MUL R3, R2
+ MOVW R2, 8(FP)
+ RET
+
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB),7,$32
+ MOVW $8(R13), R0 // timeval
+ MOVW $0, R1 // zone
MOVW $SYS_gettimeofday, R7
SWI $0
-
- MOVW 0(FP), R0 // sec
- MOVW 8(SP), R1
- MOVW R1, 0(R0)
-
- MOVW 4(FP), R0 // usec
- MOVW 12(SP), R1
- MOVW R1, 0(R0)
-*/
+
+ MOVW 8(R13), R0 // sec
+ MOVW 12(R13), R2 // usec
+
+ MOVW $1000000000, R3
+ MULLU R0, R3, (R1, R0)
+ MOVW $1000, R3
+ MOVW $0, R4
+ MUL R3, R2
+ ADD.S R2, R0
+ ADC R4, R1
+
+ MOVW 0(FP), R3
+ MOVW R0, 0(R3)
+ MOVW R1, 4(R3)
RET
// int32 futex(int32 *uaddr, int32 op, int32 val,
@@ -245,16 +286,17 @@ TEXT runtime·sigaltstack(SB),7,$0
MOVW 4(FP), R1
MOVW $SYS_sigaltstack, R7
SWI $0
- RET
-
-TEXT runtime·sigignore(SB),7,$0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
RET
TEXT runtime·sigtramp(SB),7,$24
// save g
MOVW g, R3
MOVW g, 20(R13)
-
+
// g = m->gsignal
MOVW m_gsignal(m), g
@@ -265,12 +307,21 @@ TEXT runtime·sigtramp(SB),7,$24
MOVW R3, 16(R13)
BL runtime·sighandler(SB)
-
+
// restore g
MOVW 20(R13), g
RET
+TEXT runtime·rtsigprocmask(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW $SYS_rt_sigprocmask, R7
+ SWI $0
+ RET
+
TEXT runtime·rt_sigaction(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
@@ -285,8 +336,25 @@ TEXT runtime·sigreturn(SB),7,$0
SWI $0
RET
-// Use kernel version instead of native armcas in ../../arm.s.
-// See ../../../sync/atomic/asm_linux_arm.s for details.
+TEXT runtime·usleep(SB),7,$12
+ MOVW usec+0(FP), R0
+ MOVW R0, R1
+ MOVW $1000000, R2
+ DIV R2, R0
+ MOD R2, R1
+ MOVW R0, 4(SP)
+ MOVW R1, 8(SP)
+ MOVW $0, R0
+ MOVW $0, R1
+ MOVW $0, R2
+ MOVW $0, R3
+ MOVW $4(SP), R4
+ MOVW $SYS_select, R7
+ SWI $0
+ RET
+
+// Use kernel version instead of native armcas in asm_arm.s.
+// See ../sync/atomic/asm_linux_arm.s for details.
TEXT cas<>(SB),7,$0
MOVW $0xffff0fc0, PC
diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s
new file mode 100644
index 000000000..11f8c7aaa
--- /dev/null
+++ b/src/pkg/runtime/sys_netbsd_386.s
@@ -0,0 +1,325 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for 386, NetBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-4
+ MOVL $1, AX
+ INT $0x80
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·exit1(SB),7,$-4
+ MOVL $302, AX // sys_threxit
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·write(SB),7,$-4
+ MOVL $4, AX // sys_write
+ INT $0x80
+ RET
+
+TEXT runtime·usleep(SB),7,$20
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVL AX, 12(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVL AX, 16(SP) // tv_nsec
+
+ MOVL $0, 0(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 4(SP) // arg 1 - rqtp
+ MOVL $0, 8(SP) // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $299, AX // sys_getthrid
+ INT $0x80
+ MOVL $0, 0(SP)
+ MOVL AX, 4(SP) // arg 1 - pid
+ MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
+ MOVL $37, AX // sys_kill
+ INT $0x80
+ RET
+
+TEXT runtime·mmap(SB),7,$36
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - addr
+ MOVSL // arg 2 - len
+ MOVSL // arg 3 - prot
+ MOVSL // arg 4 - flags
+ MOVSL // arg 5 - fd
+ MOVL $0, AX
+ STOSL // arg 6 - pad
+ MOVSL // arg 7 - offset
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
+ MOVL $197, AX // sys_mmap
+ INT $0x80
+ JCC 2(PC)
+ NEGL AX
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX // sys_munmap
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·setitimer(SB),7,$-4
+ MOVL $83, AX
+ INT $0x80
+ RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+ MOVL 12(SP), AX // sec
+ MOVL 16(SP), BX // usec
+
+ // sec is in AX, usec in BX
+ MOVL AX, sec+0(FP)
+ MOVL $0, sec+4(FP)
+ IMULL $1000, BX
+ MOVL BX, nsec+8(FP)
+ RET
+
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB),7,$32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+ MOVL 12(SP), AX // sec
+ MOVL 16(SP), BX // usec
+
+ // sec is in AX, usec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ IMULL $1000, BX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-4
+ MOVL $46, AX // sys_sigaction
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sigtramp(SB),7,$44
+ get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for call to sighandler
+ MOVL signo+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+4(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+8(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+ // call sigreturn
+ MOVL context+8(FP), AX
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - sigcontext
+ MOVL $103, AX // sys_sigreturn
+ INT $0x80
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·rfork_thread(SB),7,$8
+ MOVL flags+8(SP), AX
+ MOVL stack+12(SP), CX
+
+ // Copy m, g, fn off parent stack for use by child.
+ SUBL $16, CX
+ MOVL mm+16(SP), SI
+ MOVL SI, 0(CX)
+ MOVL gg+20(SP), SI
+ MOVL SI, 4(CX)
+ MOVL fn+24(SP), SI
+ MOVL SI, 8(CX)
+ MOVL $1234, 12(CX)
+ MOVL CX, SI
+
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - flags
+ MOVL $251, AX // sys_rfork
+ INT $0x80
+
+ // Return if rfork syscall failed
+ JCC 4(PC)
+ NEGL AX
+ MOVL AX, 48(SP)
+ RET
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 3(PC)
+ MOVL AX, 48(SP)
+ RET
+
+ // In child, on new stack.
+ MOVL SI, SP
+
+ // Paranoia: check that SP is as we expect.
+ MOVL 12(SP), BP
+ CMPL BP, $1234
+ JEQ 2(PC)
+ INT $3
+
+ // Reload registers
+ MOVL 0(SP), BX // m
+ MOVL 4(SP), DX // g
+ MOVL 8(SP), SI // fn
+
+ // Initialize m->procid to thread ID
+ MOVL $299, AX // sys_getthrid
+ INT $0x80
+ MOVL AX, m_procid(BX)
+
+ // Set FS to point at m->tls
+ LEAL m_tls(BX), BP
+ PUSHAL // save registers
+ PUSHL BP
+ CALL runtime·settls(SB)
+ POPL AX
+ POPAL
+
+ // Now segment is established. Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ CALL runtime·stackcheck(SB) // smashes AX, CX
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL runtime·emptyfunc(SB)
+ POPAL
+
+ // Call fn
+ CALL SI
+
+ CALL runtime·exit1(SB)
+ MOVL $0x1234, 0x1005
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVL $288, AX // sys_sigaltstack
+ MOVL new+4(SP), BX
+ MOVL old+8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·setldt(SB),7,$8
+ // Under NetBSD we set the GS base instead of messing with the LDT.
+ MOVL 16(SP), AX // tls0
+ MOVL AX, 0(SP)
+ CALL runtime·settls(SB)
+ RET
+
+TEXT runtime·settls(SB),7,$16
+ // adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+ MOVL 20(SP), CX
+ ADDL $8, CX
+ MOVL CX, 0(CX)
+ MOVL $0, 0(SP) // syscall gap
+ MOVL $9, 4(SP) // I386_SET_GSBASE (machine/sysarch.h)
+ MOVL CX, 8(SP) // pointer to base
+ MOVL $165, AX // sys_sysarch
+ INT $0x80
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·osyield(SB),7,$-4
+ MOVL $298, AX // sys_sched_yield
+ INT $0x80
+ RET
+
+TEXT runtime·thrsleep(SB),7,$-4
+ MOVL $300, AX // sys_thrsleep
+ INT $0x80
+ RET
+
+TEXT runtime·thrwakeup(SB),7,$-4
+ MOVL $301, AX // sys_thrwakeup
+ INT $0x80
+ RET
+
+TEXT runtime·sysctl(SB),7,$28
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - name
+ MOVSL // arg 2 - namelen
+ MOVSL // arg 3 - oldp
+ MOVSL // arg 4 - oldlenp
+ MOVSL // arg 5 - newp
+ MOVSL // arg 6 - newlen
+ MOVL $202, AX // sys___sysctl
+ INT $0x80
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s
new file mode 100644
index 000000000..0b83cd4d8
--- /dev/null
+++ b/src/pkg/runtime/sys_netbsd_amd64.s
@@ -0,0 +1,268 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for AMD64, NetBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+
+// int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·rfork_thread(SB),7,$0
+ MOVL flags+8(SP), DI
+ MOVQ stack+16(SP), SI
+
+ // Copy m, g, fn off parent stack for use by child.
+ MOVQ mm+24(SP), R8
+ MOVQ gg+32(SP), R9
+ MOVQ fn+40(SP), R12
+
+ MOVL $251, AX // sys_rfork
+ SYSCALL
+
+ // Return if rfork syscall failed
+ JCC 3(PC)
+ NEGL AX
+ RET
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, on new stack.
+ MOVQ SI, SP
+
+ // Initialize m->procid to thread ID
+ MOVL $299, AX // sys_getthrid
+ SYSCALL
+ MOVQ AX, m_procid(R8)
+
+ // Set FS to point at m->tls.
+ LEAQ m_tls(R8), DI
+ CALL runtime·settls(SB)
+
+ // In child, set up new stack
+ get_tls(CX)
+ MOVQ R8, m(CX)
+ MOVQ R9, g(CX)
+ CALL runtime·stackcheck(SB)
+
+ // Call fn
+ CALL R12
+
+ // It shouldn't return. If it does, exit
+ MOVL $302, AX // sys_threxit
+ SYSCALL
+ JMP -3(PC) // keep exiting
+
+TEXT runtime·osyield(SB),7,$0
+ MOVL $298, AX // sys_sched_yield
+ SYSCALL
+ RET
+
+TEXT runtime·thrsleep(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - ident
+ MOVL 16(SP), SI // arg 2 - clock_id
+ MOVQ 24(SP), DX // arg 3 - tp
+ MOVQ 32(SP), R10 // arg 4 - lock
+ MOVL $300, AX // sys_thrsleep
+ SYSCALL
+ RET
+
+TEXT runtime·thrwakeup(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - ident
+ MOVL 16(SP), SI // arg 2 - n
+ MOVL $301, AX // sys_thrwakeup
+ SYSCALL
+ RET
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - exit status
+ MOVL $1, AX // sys_exit
+ SYSCALL
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·exit1(SB),7,$-8
+ MOVL $302, AX // sys_threxit
+ SYSCALL
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - fd
+ MOVQ 16(SP), SI // arg 2 - buf
+ MOVL 24(SP), DX // arg 3 - nbyte
+ MOVL $4, AX // sys_write
+ SYSCALL
+ RET
+
+TEXT runtime·usleep(SB),7,$16
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVQ AX, 0(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVQ AX, 8(SP) // tv_nsec
+
+ MOVQ SP, DI // arg 1 - rqtp
+ MOVQ $0, SI // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ SYSCALL
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$16
+ MOVL $299, AX // sys_getthrid
+ SYSCALL
+ MOVQ AX, DI // arg 1 - pid
+ MOVQ $13, SI // arg 2 - signum == SIGPIPE
+ MOVL $37, AX // sys_kill
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - which
+ MOVQ 16(SP), SI // arg 2 - itv
+ MOVQ 24(SP), DX // arg 3 - oitv
+ MOVL $83, AX // sys_setitimer
+ SYSCALL
+ RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
+ LEAQ 8(SP), DI // arg 1 - tp
+ MOVQ $0, SI // arg 2 - tzp
+ MOVL $116, AX // sys_gettimeofday
+ SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
+
+ // sec is in AX, usec in DX
+ MOVQ AX, sec+0(FP)
+ IMULQ $1000, DX
+ MOVL DX, nsec+8(FP)
+ RET
+
+TEXT runtime·nanotime(SB),7,$32
+ LEAQ 8(SP), DI // arg 1 - tp
+ MOVQ $0, SI // arg 2 - tzp
+ MOVL $116, AX // sys_gettimeofday
+ SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
+
+ // sec is in AX, usec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ IMULQ $1000, DX
+ ADDQ DX, AX
+ RET
+
+TEXT runtime·sigaction(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 - signum
+ MOVQ 16(SP), SI // arg 2 - nsa
+ MOVQ 24(SP), DX // arg 3 - osa
+ MOVL $46, AX
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 40(SP)
+
+ // g = m->signal
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), R10
+ MOVQ R10, g(BX)
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - addr
+ MOVQ 16(SP), SI // arg 2 - len
+ MOVL 24(SP), DX // arg 3 - prot
+ MOVL 28(SP), R10 // arg 4 - flags
+ MOVL 32(SP), R8 // arg 5 - fd
+ MOVQ 36(SP), R9
+ SUBQ $16, SP
+ MOVQ R9, 8(SP) // arg 7 - offset (passed on stack)
+ MOVQ $0, R9 // arg 6 - pad
+ MOVL $197, AX
+ SYSCALL
+ JCC 2(PC)
+ NEGL AX
+ ADDQ $16, SP
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - addr
+ MOVQ 16(SP), SI // arg 2 - len
+ MOVL $73, AX // sys_munmap
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI // arg 1 - nss
+ MOVQ old+16(SP), SI // arg 2 - oss
+ MOVQ $288, AX // sys_sigaltstack
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$8
+ // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+ ADDQ $16, DI
+ MOVQ DI, 0(SP)
+ MOVQ SP, SI
+ MOVQ $12, DI // AMD64_SET_FSBASE (machine/sysarch.h)
+ MOVQ $165, AX // sys_sysarch
+ SYSCALL
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sysctl(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - name
+ MOVL 16(SP), SI // arg 2 - namelen
+ MOVQ 24(SP), DX // arg 3 - oldp
+ MOVQ 32(SP), R10 // arg 4 - oldlenp
+ MOVQ 40(SP), R8 // arg 5 - newp
+ MOVQ 48(SP), R9 // arg 6 - newlen
+ MOVQ $202, AX // sys___sysctl
+ SYSCALL
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
new file mode 100644
index 000000000..593b4a9df
--- /dev/null
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -0,0 +1,325 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// System calls and other sys.stuff for 386, OpenBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-4
+ MOVL $1, AX
+ INT $0x80
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·exit1(SB),7,$-4
+ MOVL $302, AX // sys_threxit
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·write(SB),7,$-4
+ MOVL $4, AX // sys_write
+ INT $0x80
+ RET
+
+TEXT runtime·usleep(SB),7,$20
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVL AX, 12(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVL AX, 16(SP) // tv_nsec
+
+ MOVL $0, 0(SP)
+ LEAL 12(SP), AX
+ MOVL AX, 4(SP) // arg 1 - rqtp
+ MOVL $0, 8(SP) // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $299, AX // sys_getthrid
+ INT $0x80
+ MOVL $0, 0(SP)
+ MOVL AX, 4(SP) // arg 1 - pid
+ MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
+ MOVL $37, AX // sys_kill
+ INT $0x80
+ RET
+
+TEXT runtime·mmap(SB),7,$36
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - addr
+ MOVSL // arg 2 - len
+ MOVSL // arg 3 - prot
+ MOVSL // arg 4 - flags
+ MOVSL // arg 5 - fd
+ MOVL $0, AX
+ STOSL // arg 6 - pad
+ MOVSL // arg 7 - offset
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
+ MOVL $197, AX // sys_mmap
+ INT $0x80
+ JCC 2(PC)
+ NEGL AX
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX // sys_munmap
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·setitimer(SB),7,$-4
+ MOVL $83, AX
+ INT $0x80
+ RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+ MOVL 12(SP), AX // sec
+ MOVL 16(SP), BX // usec
+
+ // sec is in AX, usec in BX
+ MOVL AX, sec+0(FP)
+ MOVL $0, sec+4(FP)
+ IMULL $1000, BX
+ MOVL BX, nsec+8(FP)
+ RET
+
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB),7,$32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+ MOVL 12(SP), AX // sec
+ MOVL 16(SP), BX // usec
+
+ // sec is in AX, usec in BX
+ // convert to DX:AX nsec
+ MOVL $1000000000, CX
+ MULL CX
+ IMULL $1000, BX
+ ADDL BX, AX
+ ADCL $0, DX
+
+ MOVL ret+0(FP), DI
+ MOVL AX, 0(DI)
+ MOVL DX, 4(DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-4
+ MOVL $46, AX // sys_sigaction
+ INT $0x80
+ JAE 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sigtramp(SB),7,$44
+ get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for call to sighandler
+ MOVL signo+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+4(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+8(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+ // call sigreturn
+ MOVL context+8(FP), AX
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - sigcontext
+ MOVL $103, AX // sys_sigreturn
+ INT $0x80
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·rfork_thread(SB),7,$8
+ MOVL flags+8(SP), AX
+ MOVL stack+12(SP), CX
+
+ // Copy m, g, fn off parent stack for use by child.
+ SUBL $16, CX
+ MOVL mm+16(SP), SI
+ MOVL SI, 0(CX)
+ MOVL gg+20(SP), SI
+ MOVL SI, 4(CX)
+ MOVL fn+24(SP), SI
+ MOVL SI, 8(CX)
+ MOVL $1234, 12(CX)
+ MOVL CX, SI
+
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - flags
+ MOVL $251, AX // sys_rfork
+ INT $0x80
+
+ // Return if rfork syscall failed
+ JCC 4(PC)
+ NEGL AX
+ MOVL AX, 48(SP)
+ RET
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 3(PC)
+ MOVL AX, 48(SP)
+ RET
+
+ // In child, on new stack.
+ MOVL SI, SP
+
+ // Paranoia: check that SP is as we expect.
+ MOVL 12(SP), BP
+ CMPL BP, $1234
+ JEQ 2(PC)
+ INT $3
+
+ // Reload registers
+ MOVL 0(SP), BX // m
+ MOVL 4(SP), DX // g
+ MOVL 8(SP), SI // fn
+
+ // Initialize m->procid to thread ID
+ MOVL $299, AX // sys_getthrid
+ INT $0x80
+ MOVL AX, m_procid(BX)
+
+ // Set FS to point at m->tls
+ LEAL m_tls(BX), BP
+ PUSHAL // save registers
+ PUSHL BP
+ CALL runtime·settls(SB)
+ POPL AX
+ POPAL
+
+ // Now segment is established. Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ CALL runtime·stackcheck(SB) // smashes AX, CX
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL runtime·emptyfunc(SB)
+ POPAL
+
+ // Call fn
+ CALL SI
+
+ CALL runtime·exit1(SB)
+ MOVL $0x1234, 0x1005
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVL $288, AX // sys_sigaltstack
+ MOVL new+4(SP), BX
+ MOVL old+8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·setldt(SB),7,$8
+ // Under OpenBSD we set the GS base instead of messing with the LDT.
+ MOVL 16(SP), AX // tls0
+ MOVL AX, 0(SP)
+ CALL runtime·settls(SB)
+ RET
+
+TEXT runtime·settls(SB),7,$16
+ // adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+ MOVL 20(SP), CX
+ ADDL $8, CX
+ MOVL CX, 0(CX)
+ MOVL $0, 0(SP) // syscall gap
+ MOVL $9, 4(SP) // I386_SET_GSBASE (machine/sysarch.h)
+ MOVL CX, 8(SP) // pointer to base
+ MOVL $165, AX // sys_sysarch
+ INT $0x80
+ JCC 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·osyield(SB),7,$-4
+ MOVL $298, AX // sys_sched_yield
+ INT $0x80
+ RET
+
+TEXT runtime·thrsleep(SB),7,$-4
+ MOVL $300, AX // sys_thrsleep
+ INT $0x80
+ RET
+
+TEXT runtime·thrwakeup(SB),7,$-4
+ MOVL $301, AX // sys_thrwakeup
+ INT $0x80
+ RET
+
+TEXT runtime·sysctl(SB),7,$28
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - name
+ MOVSL // arg 2 - namelen
+ MOVSL // arg 3 - oldp
+ MOVSL // arg 4 - oldlenp
+ MOVSL // arg 5 - newp
+ MOVSL // arg 6 - newlen
+ MOVL $202, AX // sys___sysctl
+ INT $0x80
+ JCC 3(PC)
+ NEGL AX
+ RET
+ MOVL $0, AX
+ RET
+
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/openbsd/amd64/sys.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 2a238dffb..d2d48e6b5 100644
--- a/src/pkg/runtime/openbsd/amd64/sys.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -6,7 +6,7 @@
// /usr/src/sys/kern/syscalls.master for syscall numbers.
//
-#include "amd64/asm.h"
+#include "zasm_GOOS_GOARCH.h"
// int64 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
TEXT runtime·rfork_thread(SB),7,$0
@@ -55,26 +55,26 @@ TEXT runtime·rfork_thread(SB),7,$0
// It shouldn't return. If it does, exit
MOVL $302, AX // sys_threxit
SYSCALL
- JMP -3(PC) // keep exiting
+ JMP -3(PC) // keep exiting
-TEXT runtime·sys_sched_yield(SB),7,$0
- MOVL $298, AX
+TEXT runtime·osyield(SB),7,$0
+ MOVL $298, AX // sys_sched_yield
SYSCALL
RET
-TEXT runtime·sys_thrsleep(SB),7,$0
- MOVQ 8(SP), DI
- MOVL 16(SP), SI
- MOVQ 24(SP), DX
- MOVQ 32(SP), R10
- MOVL $300, AX
+TEXT runtime·thrsleep(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - ident
+ MOVL 16(SP), SI // arg 2 - clock_id
+ MOVQ 24(SP), DX // arg 3 - tp
+ MOVQ 32(SP), R10 // arg 4 - lock
+ MOVL $300, AX // sys_thrsleep
SYSCALL
RET
-TEXT runtime·sys_thrwakeup(SB),7,$0
- MOVQ 8(SP), DI
- MOVL 16(SP), SI
- MOVL $301, AX
+TEXT runtime·thrwakeup(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - ident
+ MOVL 16(SP), SI // arg 2 - n
+ MOVL $301, AX // sys_thrwakeup
SYSCALL
RET
@@ -83,13 +83,13 @@ TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 - exit status
MOVL $1, AX // sys_exit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-8
MOVL $302, AX // sys_threxit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-8
@@ -100,6 +100,22 @@ TEXT runtime·write(SB),7,$-8
SYSCALL
RET
+TEXT runtime·usleep(SB),7,$16
+ MOVL $0, DX
+ MOVL usec+0(FP), AX
+ MOVL $1000000, CX
+ DIVL CX
+ MOVQ AX, 0(SP) // tv_sec
+ MOVL $1000, AX
+ MULL DX
+ MOVQ AX, 8(SP) // tv_nsec
+
+ MOVQ SP, DI // arg 1 - rqtp
+ MOVQ $0, SI // arg 2 - rmtp
+ MOVL $240, AX // sys_nanosleep
+ SYSCALL
+ RET
+
TEXT runtime·raisesigpipe(SB),7,$16
MOVL $299, AX // sys_getthrid
SYSCALL
@@ -117,19 +133,34 @@ TEXT runtime·setitimer(SB),7,$-8
SYSCALL
RET
-TEXT runtime·gettime(SB),7,$32
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), 7, $32
LEAQ 8(SP), DI // arg 1 - tp
MOVQ $0, SI // arg 2 - tzp
MOVL $116, AX // sys_gettimeofday
SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
- MOVQ 8(SP), BX // sec
- MOVQ sec+0(FP), DI
- MOVQ BX, (DI)
+ // sec is in AX, usec in DX
+ MOVQ AX, sec+0(FP)
+ IMULQ $1000, DX
+ MOVL DX, nsec+8(FP)
+ RET
- MOVL 16(SP), BX // usec
- MOVQ usec+8(FP), DI
- MOVL BX, (DI)
+TEXT runtime·nanotime(SB),7,$32
+ LEAQ 8(SP), DI // arg 1 - tp
+ MOVQ $0, SI // arg 2 - tzp
+ MOVL $116, AX // sys_gettimeofday
+ SYSCALL
+ MOVQ 8(SP), AX // sec
+ MOVL 16(SP), DX // usec
+
+ // sec is in AX, usec in DX
+ // return nsec in AX
+ IMULQ $1000000000, AX
+ IMULQ $1000, DX
+ ADDQ DX, AX
RET
TEXT runtime·sigaction(SB),7,$-8
@@ -139,18 +170,23 @@ TEXT runtime·sigaction(SB),7,$-8
MOVL $46, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -190,12 +226,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $73, AX // sys_munmap
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$-8
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$-8
@@ -204,7 +235,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVQ $288, AX // sys_sigaltstack
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// set tls base to DI
@@ -217,5 +248,21 @@ TEXT runtime·settls(SB),7,$8
MOVQ $165, AX // sys_sysarch
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
+ RET
+
+TEXT runtime·sysctl(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 - name
+ MOVL 16(SP), SI // arg 2 - namelen
+ MOVQ 24(SP), DX // arg 3 - oldp
+ MOVQ 32(SP), R10 // arg 4 - oldlenp
+ MOVQ 40(SP), R8 // arg 5 - newp
+ MOVQ 48(SP), R9 // arg 6 - newlen
+ MOVQ $202, AX // sys___sysctl
+ SYSCALL
+ JCC 3(PC)
+ NEGL AX
RET
+ MOVL $0, AX
+ RET
+
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/sys_plan9_386.s
index 1cb570b68..94c36aa41 100644
--- a/src/pkg/runtime/plan9/386/sys.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "defs.h"
-#include "386/asm.h"
+#include "defs_GOOS_GOARCH.h"
+#include "zasm_GOOS_GOARCH.h"
// setldt(int entry, int address, int limit)
TEXT runtime·setldt(SB),7,$0
@@ -14,11 +14,21 @@ TEXT runtime·open(SB),7,$0
INT $64
RET
-TEXT runtime·write(SB),7,$0
- MOVL $20, AX
+TEXT runtime·pread(SB),7,$0
+ MOVL $50, AX
INT $64
RET
+TEXT runtime·pwrite(SB),7,$0
+ MOVL $51, AX
+ INT $64
+ RET
+
+TEXT runtime·close(SB),7,$0
+ MOVL $4, AX
+ INT $64
+ RET
+
TEXT runtime·exits(SB),7,$0
MOVL $8, AX
INT $64
@@ -29,6 +39,11 @@ TEXT runtime·brk_(SB),7,$0
INT $64
RET
+TEXT runtime·sleep(SB),7,$0
+ MOVL $17, AX
+ INT $64
+ RET
+
TEXT runtime·plan9_semacquire(SB),7,$0
MOVL $37, AX
INT $64
@@ -73,9 +88,9 @@ TEXT runtime·rfork(SB),7,$0
MOVL 0(BX), BX
// more paranoia; check that stack splitting code works
- PUSHAL
+ PUSHL SI
CALL runtime·emptyfunc(SB)
- POPAL
+ POPL SI
CALL SI // fn()
CALL runtime·exit(SB)
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/sys_windows_386.s
index 703f77d55..d5646bfea 100644
--- a/src/pkg/runtime/windows/386/sys.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -2,47 +2,80 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "386/asm.h"
-
-// void *stdcall_raw(void *fn, int32 count, uintptr *args)
-TEXT runtime·stdcall_raw(SB),7,$0
- // Copy arguments from stack.
- MOVL fn+0(FP), AX
- MOVL count+4(FP), CX // words
- MOVL args+8(FP), BP
-
- // Switch to m->g0 if needed.
- get_tls(DI)
- MOVL m(DI), DX
- MOVL m_g0(DX), SI
- CMPL g(DI), SI
- MOVL SP, BX
- JEQ 2(PC)
- MOVL (g_sched+gobuf_sp)(SI), SP
- PUSHL BX
- PUSHL g(DI)
- MOVL SI, g(DI)
+#include "zasm_GOOS_GOARCH.h"
+
+// void runtime·asmstdcall(void *c);
+TEXT runtime·asmstdcall(SB),7,$0
+ MOVL c+0(FP), BX
- // Copy args to new stack.
- MOVL CX, BX
- SALL $2, BX
- SUBL BX, SP // room for args
+ // SetLastError(0).
+ MOVL $0, 0x34(FS)
+
+ // Copy args to the stack.
+ MOVL SP, BP
+ MOVL wincall_n(BX), CX // words
+ MOVL CX, AX
+ SALL $2, AX
+ SUBL AX, SP // room for args
MOVL SP, DI
- MOVL BP, SI
+ MOVL wincall_args(BX), SI
CLD
REP; MOVSL
- // Call stdcall function.
- CALL AX
+ // Call stdcall or cdecl function.
+ // DI SI BP BX are preserved, SP is not
+ CALL wincall_fn(BX)
+ MOVL BP, SP
- // Restore original SP, g.
- get_tls(DI)
- POPL g(DI)
- POPL SP
+ // Return result.
+ MOVL c+0(FP), BX
+ MOVL AX, wincall_r1(BX)
+ MOVL DX, wincall_r2(BX)
- // Someday the convention will be D is always cleared.
- CLD
+ // GetLastError().
+ MOVL 0x34(FS), AX
+ MOVL AX, wincall_err(BX)
+
+ RET
+
+TEXT runtime·badcallback(SB),7,$24
+ // stderr
+ MOVL $-12, 0(SP)
+ MOVL SP, BP
+ CALL *runtime·GetStdHandle(SB)
+ MOVL BP, SP
+
+ MOVL AX, 0(SP) // handle
+ MOVL $runtime·badcallbackmsg(SB), DX // pointer
+ MOVL DX, 4(SP)
+ MOVL runtime·badcallbacklen(SB), DX // count
+ MOVL DX, 8(SP)
+ LEAL 20(SP), DX // written count
+ MOVL $0, 0(DX)
+ MOVL DX, 12(SP)
+ MOVL $0, 16(SP) // overlapped
+ CALL *runtime·WriteFile(SB)
+ MOVL BP, SI
+ RET
+TEXT runtime·badsignal(SB),7,$24
+ // stderr
+ MOVL $-12, 0(SP)
+ MOVL SP, BP
+ CALL *runtime·GetStdHandle(SB)
+ MOVL BP, SP
+
+ MOVL AX, 0(SP) // handle
+ MOVL $runtime·badsignalmsg(SB), DX // pointer
+ MOVL DX, 4(SP)
+ MOVL runtime·badsignallen(SB), DX // count
+ MOVL DX, 8(SP)
+ LEAL 20(SP), DX // written count
+ MOVL $0, 0(DX)
+ MOVL DX, 12(SP)
+ MOVL $0, 16(SP) // overlapped
+ CALL *runtime·WriteFile(SB)
+ MOVL BP, SI
RET
// faster get/set last error
@@ -55,92 +88,101 @@ TEXT runtime·setlasterror(SB),7,$0
MOVL AX, 0x34(FS)
RET
-TEXT runtime·sigtramp(SB),7,$0
- PUSHL BP // cdecl
- PUSHL BX
- PUSHL SI
- PUSHL DI
- PUSHL 0(FS)
- CALL runtime·sigtramp1(SB)
- POPL 0(FS)
- POPL DI
- POPL SI
- POPL BX
- POPL BP
- RET
-
-TEXT runtime·sigtramp1(SB),0,$16-40
+TEXT runtime·sigtramp(SB),7,$28
// unwinding?
- MOVL info+24(FP), BX
- MOVL 4(BX), CX // exception flags
- ANDL $6, CX
+ MOVL info+0(FP), CX
+ TESTL $6, 4(CX) // exception flags
MOVL $1, AX
JNZ sigdone
- // place ourselves at the top of the SEH chain to
- // ensure SEH frames lie within thread stack bounds
- MOVL frame+28(FP), CX // our SEH frame
- MOVL CX, 0(FS)
-
// copy arguments for call to sighandler
- MOVL BX, 0(SP)
+ MOVL CX, 0(SP)
+ MOVL context+8(FP), CX
MOVL CX, 4(SP)
- MOVL context+32(FP), BX
- MOVL BX, 8(SP)
- MOVL dispatcher+36(FP), BX
+
+ get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), AX
+ CMPL AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
+ MOVL g(CX), CX
+ MOVL CX, 8(SP)
+
MOVL BX, 12(SP)
+ MOVL BP, 16(SP)
+ MOVL SI, 20(SP)
+ MOVL DI, 24(SP)
CALL runtime·sighandler(SB)
- TESTL AX, AX
- JZ sigdone
-
- // call windows default handler early
- MOVL 4(SP), BX // our SEH frame
- MOVL 0(BX), BX // SEH frame of default handler
- MOVL BX, 4(SP) // set establisher frame
- CALL 4(BX)
+ // AX is set to report result back to Windows
+ MOVL 24(SP), DI
+ MOVL 20(SP), SI
+ MOVL 16(SP), BP
+ MOVL 12(SP), BX
sigdone:
RET
-// Windows runs the ctrl handler in a new thread.
TEXT runtime·ctrlhandler(SB),7,$0
+ PUSHL $runtime·ctrlhandler1(SB)
+ CALL runtime·externalthreadhandler(SB)
+ MOVL 4(SP), CX
+ ADDL $12, SP
+ JMP CX
+
+TEXT runtime·profileloop(SB),7,$0
+ PUSHL $runtime·profileloop1(SB)
+ CALL runtime·externalthreadhandler(SB)
+ MOVL 4(SP), CX
+ ADDL $12, SP
+ JMP CX
+
+TEXT runtime·externalthreadhandler(SB),7,$0
PUSHL BP
MOVL SP, BP
PUSHL BX
PUSHL SI
PUSHL DI
- PUSHL 0x2c(FS)
- MOVL SP, BX
+ PUSHL 0x14(FS)
+ MOVL SP, DX
// setup dummy m, g
- SUBL $(m_fflag+4), SP // at least space for m_fflag
+ SUBL $m_end, SP // space for M
+ MOVL SP, 0(SP)
+ MOVL $m_end, 4(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
+
LEAL m_tls(SP), CX
- MOVL CX, 0x2c(FS)
+ MOVL CX, 0x14(FS)
MOVL SP, m(CX)
- MOVL SP, DX
- SUBL $8, SP // space for g_stack{guard,base}
+ MOVL SP, BX
+ SUBL $g_end, SP // space for G
MOVL SP, g(CX)
- MOVL SP, m_g0(DX)
+ MOVL SP, m_g0(BX)
+
+ MOVL SP, 0(SP)
+ MOVL $g_end, 4(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
LEAL -4096(SP), CX
MOVL CX, g_stackguard(SP)
- MOVL BX, g_stackbase(SP)
+ MOVL DX, g_stackbase(SP)
- PUSHL 8(BP)
- CALL runtime·ctrlhandler1(SB)
+ PUSHL 16(BP) // arg for handler
+ CALL 8(BP)
POPL CX
get_tls(CX)
MOVL g(CX), CX
MOVL g_stackbase(CX), SP
- POPL 0x2c(FS)
+ POPL 0x14(FS)
POPL DI
POPL SI
POPL BX
POPL BP
- MOVL 0(SP), CX
- ADDL $8, SP
- JMP CX
+ RET
// Called from dynamic function created by ../thread.c compilecallback,
// running on Windows stack (not Go stack).
@@ -214,7 +256,7 @@ TEXT runtime·tstart(SB),7,$0
// Set up tls.
LEAL m_tls(CX), SI
- MOVL SI, 0x2c(FS)
+ MOVL SI, 0x14(FS)
MOVL CX, m(SI)
MOVL DX, g(SI)
@@ -252,5 +294,5 @@ TEXT runtime·tstart_stdcall(SB),7,$0
// setldt(int entry, int address, int limit)
TEXT runtime·setldt(SB),7,$0
MOVL address+4(FP), CX
- MOVL CX, 0x2c(FS)
+ MOVL CX, 0x14(FS)
RET
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
new file mode 100644
index 000000000..11909cda2
--- /dev/null
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -0,0 +1,342 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "zasm_GOOS_GOARCH.h"
+
+// maxargs should be divisible by 2, as Windows stack
+// must be kept 16-byte aligned on syscall entry.
+#define maxargs 16
+
+// void runtime·asmstdcall(void *c);
+TEXT runtime·asmstdcall(SB),7,$0
+ // asmcgocall will put first argument into CX.
+ PUSHQ CX // save for later
+ MOVQ wincall_fn(CX), AX
+ MOVQ wincall_args(CX), SI
+ MOVQ wincall_n(CX), CX
+
+ // SetLastError(0).
+ MOVQ 0x30(GS), DI
+ MOVL $0, 0x68(DI)
+
+ SUBQ $(maxargs*8), SP // room for args
+
+ // Fast version, do not store args on the stack.
+ CMPL CX, $4
+ JLE loadregs
+
+ // Check we have enough room for args.
+ CMPL CX, $maxargs
+ JLE 2(PC)
+ INT $3 // not enough room -> crash
+
+ // Copy args to the stack.
+ MOVQ SP, DI
+ CLD
+ REP; MOVSQ
+ MOVQ SP, SI
+
+loadregs:
+ // Load first 4 args into correspondent registers.
+ MOVQ 0(SI), CX
+ MOVQ 8(SI), DX
+ MOVQ 16(SI), R8
+ MOVQ 24(SI), R9
+
+ // Call stdcall function.
+ CALL AX
+
+ ADDQ $(maxargs*8), SP
+
+ // Return result.
+ POPQ CX
+ MOVQ AX, wincall_r1(CX)
+
+ // GetLastError().
+ MOVQ 0x30(GS), DI
+ MOVL 0x68(DI), AX
+ MOVQ AX, wincall_err(CX)
+
+ RET
+
+// This should be called on a system stack,
+// so we don't need to concern about split stack.
+TEXT runtime·badcallback(SB),7,$0
+ SUBQ $48, SP
+
+ // stderr
+ MOVQ $-12, CX // stderr
+ MOVQ CX, 0(SP)
+ MOVQ runtime·GetStdHandle(SB), AX
+ CALL AX
+
+ MOVQ AX, CX // handle
+ MOVQ CX, 0(SP)
+ MOVQ $runtime·badcallbackmsg(SB), DX // pointer
+ MOVQ DX, 8(SP)
+ MOVL $runtime·badcallbacklen(SB), R8 // count
+ MOVQ R8, 16(SP)
+ LEAQ 40(SP), R9 // written count
+ MOVQ $0, 0(R9)
+ MOVQ R9, 24(SP)
+ MOVQ $0, 32(SP) // overlapped
+ MOVQ runtime·WriteFile(SB), AX
+ CALL AX
+
+ ADDQ $48, SP
+ RET
+
+TEXT runtime·badsignal(SB),7,$48
+ // stderr
+ MOVQ $-12, CX // stderr
+ MOVQ CX, 0(SP)
+ MOVQ runtime·GetStdHandle(SB), AX
+ CALL AX
+
+ MOVQ AX, CX // handle
+ MOVQ CX, 0(SP)
+ MOVQ $runtime·badsignalmsg(SB), DX // pointer
+ MOVQ DX, 8(SP)
+ MOVL $runtime·badsignallen(SB), R8 // count
+ MOVQ R8, 16(SP)
+ LEAQ 40(SP), R9 // written count
+ MOVQ $0, 0(R9)
+ MOVQ R9, 24(SP)
+ MOVQ $0, 32(SP) // overlapped
+ MOVQ runtime·WriteFile(SB), AX
+ CALL AX
+
+ RET
+
+// faster get/set last error
+TEXT runtime·getlasterror(SB),7,$0
+ MOVQ 0x30(GS), AX
+ MOVL 0x68(AX), AX
+ RET
+
+TEXT runtime·setlasterror(SB),7,$0
+ MOVL err+0(FP), AX
+ MOVQ 0x30(GS), CX
+ MOVL AX, 0x68(CX)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$0
+ // CX: exception record
+ // R8: context
+
+ // unwinding?
+ TESTL $6, 4(CX) // exception flags
+ MOVL $1, AX
+ JNZ sigdone
+
+ // copy arguments for call to sighandler.
+
+ // Stack adjustment is here to hide from 6l,
+ // which doesn't understand that sigtramp
+ // runs on essentially unlimited stack.
+ SUBQ $56, SP
+ MOVQ CX, 0(SP)
+ MOVQ R8, 8(SP)
+
+ get_tls(CX)
+
+ // check that m exists
+ MOVQ m(CX), AX
+ CMPQ AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
+ MOVQ g(CX), CX
+ MOVQ CX, 16(SP)
+
+ MOVQ BX, 24(SP)
+ MOVQ BP, 32(SP)
+ MOVQ SI, 40(SP)
+ MOVQ DI, 48(SP)
+
+ CALL runtime·sighandler(SB)
+
+ MOVQ 24(SP), BX
+ MOVQ 32(SP), BP
+ MOVQ 40(SP), SI
+ MOVQ 48(SP), DI
+ ADDQ $56, SP
+
+sigdone:
+ RET
+
+TEXT runtime·ctrlhandler(SB),7,$8
+ MOVQ CX, 16(SP) // spill
+ MOVQ $runtime·ctrlhandler1(SB), CX
+ MOVQ CX, 0(SP)
+ CALL runtime·externalthreadhandler(SB)
+ RET
+
+TEXT runtime·profileloop(SB),7,$8
+ MOVQ $runtime·profileloop1(SB), CX
+ MOVQ CX, 0(SP)
+ CALL runtime·externalthreadhandler(SB)
+ RET
+
+TEXT runtime·externalthreadhandler(SB),7,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ PUSHQ BX
+ PUSHQ SI
+ PUSHQ DI
+ PUSHQ 0x28(GS)
+ MOVQ SP, DX
+
+ // setup dummy m, g
+ SUBQ $m_end, SP // space for M
+ MOVQ SP, 0(SP)
+ MOVQ $m_end, 8(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
+
+ LEAQ m_tls(SP), CX
+ MOVQ CX, 0x28(GS)
+ MOVQ SP, m(CX)
+ MOVQ SP, BX
+ SUBQ $g_end, SP // space for G
+ MOVQ SP, g(CX)
+ MOVQ SP, m_g0(BX)
+
+ MOVQ SP, 0(SP)
+ MOVQ $g_end, 8(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
+ LEAQ -8192(SP), CX
+ MOVQ CX, g_stackguard(SP)
+ MOVQ DX, g_stackbase(SP)
+
+ PUSHQ 32(BP) // arg for handler
+ CALL 16(BP)
+ POPQ CX
+
+ get_tls(CX)
+ MOVQ g(CX), CX
+ MOVQ g_stackbase(CX), SP
+ POPQ 0x28(GS)
+ POPQ DI
+ POPQ SI
+ POPQ BX
+ POPQ BP
+ RET
+
+// Continuation of thunk function created for each callback by ../thread.c compilecallback,
+// runs on Windows stack (not Go stack).
+// Thunk code designed to have minimal size for it is copied many (up to thousands) times.
+//
+// thunk:
+// MOVQ $fn, AX
+// PUSHQ AX
+// MOVQ $argsize, AX
+// PUSHQ AX
+// MOVQ $runtime·callbackasm, AX
+// JMP AX
+TEXT runtime·callbackasm(SB),7,$0
+ // Construct args vector for cgocallback().
+ // By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
+ // args from the 5th on are on the stack.
+ // In any case, even if function has 0,1,2,3,4 args, there is reserved
+ // but uninitialized "shadow space" for the first 4 args.
+ // The values are in registers.
+ MOVQ CX, (24+0)(SP)
+ MOVQ DX, (24+8)(SP)
+ MOVQ R8, (24+16)(SP)
+ MOVQ R9, (24+24)(SP)
+ // 6l does not accept writing POPQs here issuing a warning "unbalanced PUSH/POP"
+ MOVQ 0(SP), DX // POPQ DX
+ MOVQ 8(SP), AX // POPQ AX
+ ADDQ $16, SP
+
+ // preserve whatever's at the memory location that
+ // the callback will use to store the return value
+ LEAQ 8(SP), CX // args vector, skip return address
+ PUSHQ 0(CX)(DX*1) // store 8 bytes from just after the args array
+ ADDQ $8, DX // extend argsize by size of return value
+
+ // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
+ // as required by windows callback convention.
+ // 6l does not allow writing many PUSHQs here issuing a warning "nosplit stack overflow"
+ // the warning has no sense as this code uses os thread stack
+ PUSHFQ
+ SUBQ $64, SP
+ MOVQ DI, 56(SP)
+ MOVQ SI, 48(SP)
+ MOVQ BP, 40(SP)
+ MOVQ BX, 32(SP)
+ MOVQ R12, 24(SP)
+ MOVQ R13, 16(SP)
+ MOVQ R14, 8(SP)
+ MOVQ R15, 0(SP)
+
+ // prepare call stack. use SUBQ to hide from stack frame checks
+ // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+ SUBQ $24, SP
+ MOVQ DX, 16(SP) // uintptr framesize
+ MOVQ CX, 8(SP) // void *frame
+ MOVQ AX, 0(SP) // void (*fn)(void*)
+ CLD
+ CALL runtime·cgocallback(SB)
+ MOVQ 0(SP), AX
+ MOVQ 8(SP), CX
+ MOVQ 16(SP), DX
+ ADDQ $24, SP
+
+ // restore registers as required for windows callback
+ // 6l does not allow writing many POPs here issuing a warning "nosplit stack overflow"
+ MOVQ 0(SP), R15
+ MOVQ 8(SP), R14
+ MOVQ 16(SP), R13
+ MOVQ 24(SP), R12
+ MOVQ 32(SP), BX
+ MOVQ 40(SP), BP
+ MOVQ 48(SP), SI
+ MOVQ 56(SP), DI
+ ADDQ $64, SP
+ POPFQ
+
+ MOVL -8(CX)(DX*1), AX // return value
+ POPQ -8(CX)(DX*1) // restore bytes just after the args
+ RET
+
+TEXT runtime·setstacklimits(SB),7,$0
+ MOVQ 0x30(GS), CX
+ MOVQ $0, 0x10(CX)
+ MOVQ $0xffffffffffff, AX
+ MOVQ AX, 0x08(CX)
+ RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT runtime·tstart_stdcall(SB),7,$0
+ // CX contains first arg newm
+ MOVQ m_g0(CX), DX // g
+
+ // Layout new m scheduler stack on os stack.
+ MOVQ SP, AX
+ MOVQ AX, g_stackbase(DX)
+ SUBQ $(64*1024), AX // stack size
+ MOVQ AX, g_stackguard(DX)
+
+ // Set up tls.
+ LEAQ m_tls(CX), SI
+ MOVQ SI, 0x28(GS)
+ MOVQ CX, m(SI)
+ MOVQ DX, g(SI)
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ CALL runtime·setstacklimits(SB)
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+ CALL runtime·mstart(SB)
+
+ XORL AX, AX // return 0 == success
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$0
+ CALL runtime·setstacklimits(SB)
+ MOVQ DI, 0x28(GS)
+ RET
diff --git a/src/pkg/runtime/syscall_windows.goc b/src/pkg/runtime/syscall_windows.goc
new file mode 100644
index 000000000..781ec908d
--- /dev/null
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -0,0 +1,145 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+#include "runtime.h"
+#include "os_GOOS.h"
+#include "cgocall.h"
+
+func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
+ WinCall c;
+
+ c.fn = runtime·LoadLibrary;
+ c.n = 1;
+ c.args = &filename;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ handle = c.r1;
+ if(handle == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr) {
+ WinCall c;
+
+ USED(procname);
+ c.fn = runtime·GetProcAddress;
+ c.n = 2;
+ c.args = &handle;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ proc = c.r1;
+ if(proc == 0)
+ err = c.err;
+ else
+ err = 0;
+}
+
+func NewCallback(fn Eface) (code uintptr) {
+ code = (uintptr)runtime·compilecallback(fn, true);
+}
+
+func NewCallbackCDecl(fn Eface) (code uintptr) {
+ code = (uintptr)runtime·compilecallback(fn, false);
+}
+
+func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ WinCall c;
+
+ USED(a2);
+ USED(a3);
+ c.fn = (void*)fn;
+ c.n = nargs;
+ c.args = &a1;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ WinCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ c.fn = (void*)fn;
+ c.n = nargs;
+ c.args = &a1;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ WinCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ USED(a7);
+ USED(a8);
+ USED(a9);
+ c.fn = (void*)fn;
+ c.n = nargs;
+ c.args = &a1;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ WinCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ USED(a7);
+ USED(a8);
+ USED(a9);
+ USED(a10);
+ USED(a11);
+ USED(a12);
+ c.fn = (void*)fn;
+ c.n = nargs;
+ c.args = &a1;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
+
+func Syscall15(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr, a13 uintptr, a14 uintptr, a15 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+ WinCall c;
+
+ USED(a2);
+ USED(a3);
+ USED(a4);
+ USED(a5);
+ USED(a6);
+ USED(a7);
+ USED(a8);
+ USED(a9);
+ USED(a10);
+ USED(a11);
+ USED(a12);
+ USED(a13);
+ USED(a14);
+ USED(a15);
+ c.fn = (void*)fn;
+ c.n = nargs;
+ c.args = &a1;
+ runtime·cgocall(runtime·asmstdcall, &c);
+ err = c.err;
+ r1 = c.r1;
+ r2 = c.r2;
+}
diff --git a/src/pkg/runtime/syscall_windows_test.go b/src/pkg/runtime/syscall_windows_test.go
new file mode 100644
index 000000000..c8327fdef
--- /dev/null
+++ b/src/pkg/runtime/syscall_windows_test.go
@@ -0,0 +1,243 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "runtime"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+type DLL struct {
+ *syscall.DLL
+ t *testing.T
+}
+
+func GetDLL(t *testing.T, name string) *DLL {
+ d, e := syscall.LoadDLL(name)
+ if e != nil {
+ t.Fatal(e)
+ }
+ return &DLL{DLL: d, t: t}
+}
+
+func (d *DLL) Proc(name string) *syscall.Proc {
+ p, e := d.FindProc(name)
+ if e != nil {
+ d.t.Fatal(e)
+ }
+ return p
+}
+
+func TestStdCall(t *testing.T) {
+ type Rect struct {
+ left, top, right, bottom int32
+ }
+ res := Rect{}
+ expected := Rect{1, 1, 40, 60}
+ a, _, _ := GetDLL(t, "user32.dll").Proc("UnionRect").Call(
+ uintptr(unsafe.Pointer(&res)),
+ uintptr(unsafe.Pointer(&Rect{10, 1, 14, 60})),
+ uintptr(unsafe.Pointer(&Rect{1, 2, 40, 50})))
+ if a != 1 || res.left != expected.left ||
+ res.top != expected.top ||
+ res.right != expected.right ||
+ res.bottom != expected.bottom {
+ t.Error("stdcall USER32.UnionRect returns", a, "res=", res)
+ }
+}
+
+func Test64BitReturnStdCall(t *testing.T) {
+
+ const (
+ VER_BUILDNUMBER = 0x0000004
+ VER_MAJORVERSION = 0x0000002
+ VER_MINORVERSION = 0x0000001
+ VER_PLATFORMID = 0x0000008
+ VER_PRODUCT_TYPE = 0x0000080
+ VER_SERVICEPACKMAJOR = 0x0000020
+ VER_SERVICEPACKMINOR = 0x0000010
+ VER_SUITENAME = 0x0000040
+
+ VER_EQUAL = 1
+ VER_GREATER = 2
+ VER_GREATER_EQUAL = 3
+ VER_LESS = 4
+ VER_LESS_EQUAL = 5
+
+ ERROR_OLD_WIN_VERSION syscall.Errno = 1150
+ )
+
+ type OSVersionInfoEx struct {
+ OSVersionInfoSize uint32
+ MajorVersion uint32
+ MinorVersion uint32
+ BuildNumber uint32
+ PlatformId uint32
+ CSDVersion [128]uint16
+ ServicePackMajor uint16
+ ServicePackMinor uint16
+ SuiteMask uint16
+ ProductType byte
+ Reserve byte
+ }
+
+ d := GetDLL(t, "kernel32.dll")
+
+ var m1, m2 uintptr
+ VerSetConditionMask := d.Proc("VerSetConditionMask")
+ m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MAJORVERSION, VER_GREATER_EQUAL)
+ m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_MINORVERSION, VER_GREATER_EQUAL)
+ m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)
+ m1, m2, _ = VerSetConditionMask.Call(m1, m2, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL)
+
+ vi := OSVersionInfoEx{
+ MajorVersion: 5,
+ MinorVersion: 1,
+ ServicePackMajor: 2,
+ ServicePackMinor: 0,
+ }
+ vi.OSVersionInfoSize = uint32(unsafe.Sizeof(vi))
+ r, _, e2 := d.Proc("VerifyVersionInfoW").Call(
+ uintptr(unsafe.Pointer(&vi)),
+ VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR,
+ m1, m2)
+ if r == 0 && e2 != ERROR_OLD_WIN_VERSION {
+ t.Errorf("VerifyVersionInfo failed: %s", e2)
+ }
+}
+
+func TestCDecl(t *testing.T) {
+ var buf [50]byte
+ a, _, _ := GetDLL(t, "user32.dll").Proc("wsprintfA").Call(
+ uintptr(unsafe.Pointer(&buf[0])),
+ uintptr(unsafe.Pointer(syscall.StringBytePtr("%d %d %d"))),
+ 1000, 2000, 3000)
+ if string(buf[:a]) != "1000 2000 3000" {
+ t.Error("cdecl USER32.wsprintfA returns", a, "buf=", buf[:a])
+ }
+}
+
+func TestEnumWindows(t *testing.T) {
+ d := GetDLL(t, "user32.dll")
+ isWindows := d.Proc("IsWindow")
+ counter := 0
+ cb := syscall.NewCallback(func(hwnd syscall.Handle, lparam uintptr) uintptr {
+ if lparam != 888 {
+ t.Error("lparam was not passed to callback")
+ }
+ b, _, _ := isWindows.Call(uintptr(hwnd))
+ if b == 0 {
+ t.Error("USER32.IsWindow returns FALSE")
+ }
+ counter++
+ return 1 // continue enumeration
+ })
+ a, _, _ := d.Proc("EnumWindows").Call(cb, 888)
+ if a == 0 {
+ t.Error("USER32.EnumWindows returns FALSE")
+ }
+ if counter == 0 {
+ t.Error("Callback has been never called or your have no windows")
+ }
+}
+
+func callback(hwnd syscall.Handle, lparam uintptr) uintptr {
+ (*(*func())(unsafe.Pointer(&lparam)))()
+ return 0 // stop enumeration
+}
+
+// nestedCall calls into Windows, back into Go, and finally to f.
+func nestedCall(t *testing.T, f func()) {
+ c := syscall.NewCallback(callback)
+ d := GetDLL(t, "user32.dll")
+ defer d.Release()
+ d.Proc("EnumWindows").Call(c, uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&f))))
+}
+
+func TestCallback(t *testing.T) {
+ var x = false
+ nestedCall(t, func() { x = true })
+ if !x {
+ t.Fatal("nestedCall did not call func")
+ }
+}
+
+func TestCallbackGC(t *testing.T) {
+ nestedCall(t, runtime.GC)
+}
+
+func TestCallbackPanic(t *testing.T) {
+ // Make sure panic during callback unwinds properly.
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on entry to TestCallbackPanic")
+ }
+ defer func() {
+ s := recover()
+ if s == nil {
+ t.Fatal("did not panic")
+ }
+ if s.(string) != "callback panic" {
+ t.Fatal("wrong panic:", s)
+ }
+ if runtime.LockedOSThread() {
+ t.Fatal("locked OS thread on exit from TestCallbackPanic")
+ }
+ }()
+ nestedCall(t, func() { panic("callback panic") })
+ panic("nestedCall returned")
+}
+
+func TestCallbackPanicLoop(t *testing.T) {
+ // Make sure we don't blow out m->g0 stack.
+ for i := 0; i < 100000; i++ {
+ TestCallbackPanic(t)
+ }
+}
+
+func TestCallbackPanicLocked(t *testing.T) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if !runtime.LockedOSThread() {
+ t.Fatal("runtime.LockOSThread didn't")
+ }
+ defer func() {
+ s := recover()
+ if s == nil {
+ t.Fatal("did not panic")
+ }
+ if s.(string) != "callback panic" {
+ t.Fatal("wrong panic:", s)
+ }
+ if !runtime.LockedOSThread() {
+ t.Fatal("lost lock on OS thread after panic")
+ }
+ }()
+ nestedCall(t, func() { panic("callback panic") })
+ panic("nestedCall returned")
+}
+
+func TestBlockingCallback(t *testing.T) {
+ c := make(chan int)
+ go func() {
+ for i := 0; i < 10; i++ {
+ c <- <-c
+ }
+ }()
+ nestedCall(t, func() {
+ for i := 0; i < 10; i++ {
+ c <- i
+ if j := <-c; j != i {
+ t.Errorf("out of sync %d != %d", j, i)
+ }
+ }
+ })
+}
+
+func TestCallbackInAnotherThread(t *testing.T) {
+ // TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread()
+}
diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/thread_darwin.c
index 6733e815e..6a83e48a3 100644
--- a/src/pkg/runtime/darwin/thread.c
+++ b/src/pkg/runtime/thread_darwin.c
@@ -3,12 +3,16 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "stack.h"
extern SigTab runtime·sigtab[];
+static Sigset sigset_all = ~(Sigset)0;
+static Sigset sigset_none;
+static Sigset sigset_prof = 1<<(SIGPROF-1);
+
static void
unimplemented(int8 *name)
{
@@ -17,137 +21,54 @@ unimplemented(int8 *name)
*(int32*)1231 = 1231;
}
-// Thread-safe allocation of a semaphore.
-// Psema points at a kernel semaphore key.
-// It starts out zero, meaning no semaphore.
-// Fill it in, being careful of others calling initsema
-// simultaneously.
-static void
-initsema(uint32 *psema)
-{
- uint32 sema;
-
- if(*psema != 0) // already have one
- return;
-
- sema = runtime·mach_semcreate();
- if(!runtime·cas(psema, 0, sema)){
- // Someone else filled it in. Use theirs.
- runtime·mach_semdestroy(sema);
- return;
- }
-}
-
-
-// Blocking locks.
-
-// Implement Locks, using semaphores.
-// l->key is the number of threads who want the lock.
-// In a race, one thread increments l->key from 0 to 1
-// and the others increment it from >0 to >1. The thread
-// who does the 0->1 increment gets the lock, and the
-// others wait on the semaphore. When the 0->1 thread
-// releases the lock by decrementing l->key, l->key will
-// be >0, so it will increment the semaphore to wake up
-// one of the others. This is the same algorithm used
-// in Plan 9's user-level locks.
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks < 0)
- runtime·throw("lock count");
- m->locks++;
-
- if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait
- // Allocate semaphore if needed.
- if(l->sema == 0)
- initsema(&l->sema);
- runtime·mach_semacquire(l->sema);
- }
-}
-
-void
-runtime·unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- runtime·throw("lock count");
-
- if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting
- // Allocate semaphore if needed.
- if(l->sema == 0)
- initsema(&l->sema);
- runtime·mach_semrelease(l->sema);
- }
-}
-
-static void
-destroylock(Lock *l)
-{
- if(l->sema != 0) {
- runtime·mach_semdestroy(l->sema);
- l->sema = 0;
- }
-}
-
-// User-level semaphore implementation:
-// try to do the operations in user space on u,
-// but when it's time to block, fall back on the kernel semaphore k.
-// This is the same algorithm used in Plan 9.
-void
-runtime·usemacquire(Usema *s)
-{
- if((int32)runtime·xadd(&s->u, -1) < 0) {
- if(s->k == 0)
- initsema(&s->k);
- runtime·mach_semacquire(s->k);
- }
-}
-
-void
-runtime·usemrelease(Usema *s)
+int32
+runtime·semasleep(int64 ns)
{
- if((int32)runtime·xadd(&s->u, 1) <= 0) {
- if(s->k == 0)
- initsema(&s->k);
- runtime·mach_semrelease(s->k);
- }
+ int32 v;
+
+ if(m->profilehz > 0)
+ runtime·setprof(false);
+ v = runtime·mach_semacquire(m->waitsema, ns);
+ if(m->profilehz > 0)
+ runtime·setprof(true);
+ return v;
}
-
-// Event notifications.
void
-runtime·noteclear(Note *n)
+runtime·semawakeup(M *mp)
{
- n->wakeup = 0;
+ runtime·mach_semrelease(mp->waitsema);
}
-void
-runtime·notesleep(Note *n)
+uintptr
+runtime·semacreate(void)
{
- while(!n->wakeup)
- runtime·usemacquire(&n->sema);
+ return runtime·mach_semcreate();
}
-void
-runtime·notewakeup(Note *n)
-{
- n->wakeup = 1;
- runtime·usemrelease(&n->sema);
-}
-
-
// BSD interface for threading.
void
runtime·osinit(void)
{
- // Register our thread-creation callback (see {amd64,386}/sys.s)
+ // Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
// but only if we're not using cgo. If we are using cgo we need
// to let the C pthread libary install its own thread-creation callback.
if(!runtime·iscgo)
runtime·bsdthread_register();
- runtime·destroylock = destroylock;
+
+ // Use sysctl to fetch hw.ncpu.
+ uint32 mib[2];
+ uint32 out;
+ int32 ret;
+ uintptr nout;
+
+ mib[0] = 6;
+ mib[1] = 3;
+ nout = sizeof out;
+ out = 0;
+ ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+ if(ret >= 0)
+ runtime·ncpu = out;
}
void
@@ -160,13 +81,19 @@ void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int32 errno;
+ Sigset oset;
m->tls[0] = m->id; // so 386 asm can find it
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, m, g, fn, m->id, m->tls[0], &m);
}
- if((errno = runtime·bsdthread_create(stk, m, g, fn)) < 0) {
+
+ runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
+ errno = runtime·bsdthread_create(stk, m, g, fn);
+ runtime·sigprocmask(SIG_SETMASK, &oset, nil);
+
+ if(errno < 0) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
runtime·throw("runtime.newosproc");
}
@@ -179,6 +106,11 @@ runtime·minit(void)
// Initialize signal handling.
m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+
+ if(m->profilehz > 0)
+ runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+ else
+ runtime·sigprocmask(SIG_SETMASK, &sigset_prof, nil);
}
// Mach IPC, to get at semaphores
@@ -342,6 +274,7 @@ enum
// Mach calls that get interrupted by Unix signals
// return this error code. We retry them.
KERN_ABORTED = 14,
+ KERN_OPERATION_TIMED_OUT = 49,
};
typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
@@ -427,22 +360,31 @@ runtime·mach_semdestroy(uint32 sem)
}
}
-// The other calls have simple system call traps in sys.s
+// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
int32 runtime·mach_semaphore_wait(uint32 sema);
int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
int32 runtime·mach_semaphore_signal(uint32 sema);
int32 runtime·mach_semaphore_signal_all(uint32 sema);
-void
-runtime·mach_semacquire(uint32 sem)
+int32
+runtime·mach_semacquire(uint32 sem, int64 ns)
{
int32 r;
+ if(ns >= 0) {
+ r = runtime·mach_semaphore_timedwait(sem, ns/1000000000LL, ns%1000000000LL);
+ if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT)
+ return -1;
+ if(r != 0)
+ macherror(r, "semaphore_wait");
+ return 0;
+ }
while((r = runtime·mach_semaphore_wait(sem)) != 0) {
if(r == KERN_ABORTED) // interrupted
continue;
macherror(r, "semaphore_wait");
}
+ return 0;
}
void
@@ -462,13 +404,19 @@ runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
@@ -482,3 +430,70 @@ runtime·sigpanic(void)
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
+
+// TODO(rsc): place holder to fix build.
+void
+runtime·osyield(void)
+{
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ // NOTE(rsc): Could use getrlimit here,
+ // like on FreeBSD or Linux, but Darwin doesn't enforce
+ // ulimit -v, so it's unclear why we'd try to stay within
+ // the limit.
+ return 0;
+}
+
+// NOTE(rsc): On OS X, when the CPU profiling timer expires, the SIGPROF
+// signal is not guaranteed to be sent to the thread that was executing to
+// cause it to expire. It can and often does go to a sleeping thread, which is
+// not interesting for our profile. This is filed Apple Bug Report #9177434,
+// copied to http://code.google.com/p/go/source/detail?r=35b716c94225.
+// To work around this bug, we disable receipt of the profiling signal on
+// a thread while in blocking system calls. This forces the kernel to deliver
+// the profiling signal to an executing thread.
+//
+// The workaround fails on OS X machines using a 64-bit Snow Leopard kernel.
+// In that configuration, the kernel appears to want to deliver SIGPROF to the
+// sleeping threads regardless of signal mask and, worse, does not deliver
+// the signal until the thread wakes up on its own.
+//
+// If necessary, we can switch to using ITIMER_REAL for OS X and handle
+// the kernel-generated SIGALRM by generating our own SIGALRMs to deliver
+// to all the running threads. SIGALRM does not appear to be affected by
+// the 64-bit Snow Leopard bug. However, as of this writing Mountain Lion
+// is in preview, making Snow Leopard two versions old, so it is unclear how
+// much effort we need to spend on one buggy kernel.
+
+// Control whether profiling signal can be delivered to this thread.
+void
+runtime·setprof(bool on)
+{
+ if(on)
+ runtime·sigprocmask(SIG_UNBLOCK, &sigset_prof, nil);
+ else
+ runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_freebsd.c b/src/pkg/runtime/thread_freebsd.c
new file mode 100644
index 000000000..4c546178f
--- /dev/null
+++ b/src/pkg/runtime/thread_freebsd.c
@@ -0,0 +1,217 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
+
+// From FreeBSD's <sys/sysctl.h>
+#define CTL_HW 6
+#define HW_NCPU 3
+
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+static Sigset sigset_none = { 0, 0, 0, 0, };
+
+static int32
+getncpu(void)
+{
+ uint32 mib[2];
+ uint32 out;
+ int32 ret;
+ uintptr nout;
+
+ // Fetch hw.ncpu via sysctl.
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ nout = sizeof out;
+ out = 0;
+ ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+ if(ret >= 0)
+ return out;
+ else
+ return 1;
+}
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments.
+
+void
+runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+{
+ int32 ret;
+ Timespec ts, *tsp;
+
+ if(ns < 0)
+ tsp = nil;
+ else {
+ ts.tv_sec = ns / 1000000000LL;
+ ts.tv_nsec = ns % 1000000000LL;
+ tsp = &ts;
+ }
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, tsp);
+ if(ret >= 0 || ret == -EINTR)
+ return;
+
+ runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
+ *(int32*)0x1005 = 0x1005;
+}
+
+void
+runtime·futexwakeup(uint32 *addr, uint32 cnt)
+{
+ int32 ret;
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil);
+ if(ret >= 0)
+ return;
+
+ runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+ *(int32*)0x1006 = 0x1006;
+}
+
+void runtime·thr_start(void*);
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ ThrParam param;
+ Sigset oset;
+
+ USED(fn); // thr_start assumes fn == mstart
+ USED(g); // thr_start assumes g == m->g0
+
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ runtime·sigprocmask(&sigset_all, &oset);
+ runtime·memclr((byte*)&param, sizeof param);
+
+ param.start_func = runtime·thr_start;
+ param.arg = m;
+ param.stack_base = (int8*)g->stackbase;
+ param.stack_size = (byte*)stk - (byte*)g->stackbase;
+ param.child_tid = (intptr*)&m->procid;
+ param.parent_tid = nil;
+ param.tls_base = (int8*)&m->tls[0];
+ param.tls_size = sizeof m->tls;
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ runtime·thr_new(&param, sizeof param);
+ runtime·sigprocmask(&oset, nil);
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getncpu();
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+ runtime·sigprocmask(&sigset_none, nil);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ Rlimit rl;
+ extern byte text[], end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = end - text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/thread_linux.c
index 4878a00f2..858be7036 100644
--- a/src/pkg/runtime/linux/thread.c
+++ b/src/pkg/runtime/thread_linux.c
@@ -3,17 +3,19 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-#include "defs.h"
-#include "os.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
#include "stack.h"
extern SigTab runtime·sigtab[];
-static int32 proccount;
int32 runtime·open(uint8*, int32, int32);
int32 runtime·close(int32);
int32 runtime·read(int32, void*, int32);
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 };
+static Sigset sigset_none;
+
// Linux futex.
//
// futexsleep(uint32 *addr, uint32 val)
@@ -25,14 +27,6 @@ int32 runtime·read(int32, void*, int32);
enum
{
- MUTEX_UNLOCKED = 0,
- MUTEX_LOCKED = 1,
- MUTEX_SLEEPING = 2,
-
- ACTIVE_SPIN = 4,
- ACTIVE_SPIN_CNT = 30,
- PASSIVE_SPIN = 1,
-
FUTEX_WAIT = 0,
FUTEX_WAKE = 1,
@@ -40,34 +34,37 @@ enum
EAGAIN = 11,
};
-// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT).
-// I wonder if the timespec that gets to the kernel
-// actually has two 32-bit numbers in it, so that
-// a 64-bit 1<<40 ends up being 0 seconds,
-// 1<<8 nanoseconds.
-static Timespec longtime =
-{
- 1<<30, // 34 years
- 0
-};
-
// Atomically,
// if(*addr == val) sleep
// Might be woken up spuriously; that's allowed.
-static void
-futexsleep(uint32 *addr, uint32 val)
+// Don't sleep longer than ns; ns < 0 means forever.
+void
+runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
{
+ Timespec ts, *tsp;
+
+ if(ns < 0)
+ tsp = nil;
+ else {
+ ts.tv_sec = ns/1000000000LL;
+ ts.tv_nsec = ns%1000000000LL;
+ // Avoid overflow
+ if(ts.tv_sec > 1<<30)
+ ts.tv_sec = 1<<30;
+ tsp = &ts;
+ }
+
// Some Linux kernels have a bug where futex of
// FUTEX_WAIT returns an internal error code
// as an errno. Libpthread ignores the return value
// here, and so can we: as it says a few lines up,
// spurious wakeups are allowed.
- runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+ runtime·futex(addr, FUTEX_WAIT, val, tsp, nil, 0);
}
// If any procs are sleeping on addr, wake up at most cnt.
-static void
-futexwakeup(uint32 *addr, uint32 cnt)
+void
+runtime·futexwakeup(uint32 *addr, uint32 cnt)
{
int64 ret;
@@ -113,115 +110,6 @@ getproccount(void)
return cnt ? cnt : 1;
}
-// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING.
-// MUTEX_SLEEPING means that there is presumably at least one sleeping thread.
-// Note that there can be spinning threads during all states - they do not
-// affect mutex's state.
-static void
-futexlock(Lock *l)
-{
- uint32 i, v, wait, spin;
-
- // Speculative grab for lock.
- v = runtime·xchg(&l->key, MUTEX_LOCKED);
- if(v == MUTEX_UNLOCKED)
- return;
-
- // wait is either MUTEX_LOCKED or MUTEX_SLEEPING
- // depending on whether there is a thread sleeping
- // on this mutex. If we ever change l->key from
- // MUTEX_SLEEPING to some other value, we must be
- // careful to change it back to MUTEX_SLEEPING before
- // returning, to ensure that the sleeping thread gets
- // its wakeup call.
- wait = v;
-
- if(proccount == 0)
- proccount = getproccount();
-
- // On uniprocessor's, no point spinning.
- // On multiprocessors, spin for ACTIVE_SPIN attempts.
- spin = 0;
- if(proccount > 1)
- spin = ACTIVE_SPIN;
-
- for(;;) {
- // Try for lock, spinning.
- for(i = 0; i < spin; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime·procyield(ACTIVE_SPIN_CNT);
- }
-
- // Try for lock, rescheduling.
- for(i=0; i < PASSIVE_SPIN; i++) {
- while(l->key == MUTEX_UNLOCKED)
- if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
- return;
- runtime·osyield();
- }
-
- // Sleep.
- v = runtime·xchg(&l->key, MUTEX_SLEEPING);
- if(v == MUTEX_UNLOCKED)
- return;
- wait = MUTEX_SLEEPING;
- futexsleep(&l->key, MUTEX_SLEEPING);
- }
-}
-
-static void
-futexunlock(Lock *l)
-{
- uint32 v;
-
- v = runtime·xchg(&l->key, MUTEX_UNLOCKED);
- if(v == MUTEX_UNLOCKED)
- runtime·throw("unlock of unlocked lock");
- if(v == MUTEX_SLEEPING)
- futexwakeup(&l->key, 1);
-}
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks++ < 0)
- runtime·throw("runtime·lock: lock count");
- futexlock(l);
-}
-
-void
-runtime·unlock(Lock *l)
-{
- if(--m->locks < 0)
- runtime·throw("runtime·unlock: lock count");
- futexunlock(l);
-}
-
-
-// One-time notifications.
-void
-runtime·noteclear(Note *n)
-{
- n->state = 0;
-}
-
-void
-runtime·notewakeup(Note *n)
-{
- runtime·xchg(&n->state, 1);
- futexwakeup(&n->state, 1<<30);
-}
-
-void
-runtime·notesleep(Note *n)
-{
- while(runtime·atomicload(&n->state) == 0)
- futexsleep(&n->state, 0);
-}
-
-
// Clone, the Linux rfork.
enum
{
@@ -250,6 +138,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int32 ret;
int32 flags;
+ Sigset oset;
/*
* note: strace gets confused if we use CLONE_PTRACE here.
@@ -267,7 +156,13 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
stk, m, g, fn, runtime·clone, m->id, m->tls[0], &m);
}
- if((ret = runtime·clone(flags, stk, m, g, fn)) < 0) {
+ // Disable signals during clone, so that the new thread starts
+ // with signals disabled. It will enable them in minit.
+ runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset);
+ ret = runtime·clone(flags, stk, m, g, fn);
+ runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset);
+
+ if(ret < 0) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret);
runtime·throw("runtime.newosproc");
}
@@ -276,6 +171,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
void
runtime·osinit(void)
{
+ runtime·ncpu = getproccount();
}
void
@@ -291,6 +187,7 @@ runtime·minit(void)
// Initialize signal handling.
m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+ runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
}
void
@@ -298,13 +195,19 @@ runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
- if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ }
runtime·panicstring("invalid memory address or nil pointer dereference");
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
- if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGFPE:
@@ -318,3 +221,57 @@ runtime·sigpanic(void)
}
runtime·panicstring(runtime·sigtab[g->sig].name);
}
+
+uintptr
+runtime·memlimit(void)
+{
+ Rlimit rl;
+ extern byte text[], end[];
+ uintptr used;
+
+ if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+ return 0;
+ if(rl.rlim_cur >= 0x7fffffff)
+ return 0;
+
+ // Estimate our VM footprint excluding the heap.
+ // Not an exact science: use size of binary plus
+ // some room for thread stacks.
+ used = end - text + (64<<20);
+ if(used >= rl.rlim_cur)
+ return 0;
+
+ // If there's not at least 16 MB left, we're probably
+ // not going to be able to do much. Treat as no limit.
+ rl.rlim_cur -= used;
+ if(rl.rlim_cur < (16<<20))
+ return 0;
+
+ return rl.rlim_cur - used;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/thread_netbsd.c
new file mode 100644
index 000000000..1b2df85cd
--- /dev/null
+++ b/src/pkg/runtime/thread_netbsd.c
@@ -0,0 +1,235 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "stack.h"
+
+enum
+{
+ ESRCH = 3,
+ ENOTSUP = 91,
+
+ // From NetBSD's sys/time.h
+ CLOCK_REALTIME = 0,
+ CLOCK_VIRTUAL = 1,
+ CLOCK_PROF = 2,
+ CLOCK_MONOTONIC = 3
+};
+
+extern SigTab runtime·sigtab[];
+
+extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock);
+extern int32 runtime·thrwakeup(void *ident, int32 n);
+
+// From NetBSD's <sys/sysctl.h>
+#define CTL_HW 6
+#define HW_NCPU 3
+
+static int32
+getncpu(void)
+{
+ uint32 mib[2];
+ uint32 out;
+ int32 ret;
+ uintptr nout;
+
+ // Fetch hw.ncpu via sysctl.
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ nout = sizeof out;
+ out = 0;
+ ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+ if(ret >= 0)
+ return out;
+ else
+ return 1;
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ return 1;
+}
+
+int32
+runtime·semasleep(int64 ns)
+{
+ Timespec ts;
+
+ // spin-mutex lock
+ while(runtime·xchg(&m->waitsemalock, 1))
+ runtime·osyield();
+
+ for(;;) {
+ // lock held
+ if(m->waitsemacount == 0) {
+ // sleep until semaphore != 0 or timeout.
+ // thrsleep unlocks m->waitsemalock.
+ if(ns < 0)
+ runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock);
+ else {
+ ns += runtime·nanotime();
+ ts.tv_sec = ns/1000000000LL;
+ ts.tv_nsec = ns%1000000000LL;
+ runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock);
+ }
+ // reacquire lock
+ while(runtime·xchg(&m->waitsemalock, 1))
+ runtime·osyield();
+ }
+
+ // lock held (again)
+ if(m->waitsemacount != 0) {
+ // semaphore is available.
+ m->waitsemacount--;
+ // spin-mutex unlock
+ runtime·atomicstore(&m->waitsemalock, 0);
+ return 0; // semaphore acquired
+ }
+
+ // semaphore not available.
+ // if there is a timeout, stop now.
+ // otherwise keep trying.
+ if(ns >= 0)
+ break;
+ }
+
+ // lock held but giving up
+ // spin-mutex unlock
+ runtime·atomicstore(&m->waitsemalock, 0);
+ return -1;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ uint32 ret;
+
+ // spin-mutex lock
+ while(runtime·xchg(&mp->waitsemalock, 1))
+ runtime·osyield();
+ mp->waitsemacount++;
+ ret = runtime·thrwakeup(&mp->waitsemacount, 1);
+ if(ret != 0 && ret != ESRCH)
+ runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
+ // spin-mutex unlock
+ runtime·atomicstore(&mp->waitsemalock, 0);
+}
+
+// From NetBSD's sys/param.h
+#define RFPROC (1<<4) /* change child (else changes curproc) */
+#define RFMEM (1<<5) /* share `address space' */
+#define RFNOWAIT (1<<6) /* parent need not wait() on child */
+#define RFTHREAD (1<<13) /* create a thread, not a process */
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int32 flags;
+ int32 ret;
+
+ flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT;
+
+ if (0) {
+ runtime·printf(
+ "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
+ if (ret == -ENOTSUP)
+ runtime·printf("runtime: is kern.rthreads disabled?\n");
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getncpu();
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ return 0;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_openbsd.c b/src/pkg/runtime/thread_openbsd.c
new file mode 100644
index 000000000..d0f947210
--- /dev/null
+++ b/src/pkg/runtime/thread_openbsd.c
@@ -0,0 +1,235 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "stack.h"
+
+enum
+{
+ ESRCH = 3,
+ ENOTSUP = 91,
+
+ // From OpenBSD's sys/time.h
+ CLOCK_REALTIME = 0,
+ CLOCK_VIRTUAL = 1,
+ CLOCK_PROF = 2,
+ CLOCK_MONOTONIC = 3
+};
+
+extern SigTab runtime·sigtab[];
+
+extern int64 runtime·rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock);
+extern int32 runtime·thrwakeup(void *ident, int32 n);
+
+// From OpenBSD's <sys/sysctl.h>
+#define CTL_HW 6
+#define HW_NCPU 3
+
+static int32
+getncpu(void)
+{
+ uint32 mib[2];
+ uint32 out;
+ int32 ret;
+ uintptr nout;
+
+ // Fetch hw.ncpu via sysctl.
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ nout = sizeof out;
+ out = 0;
+ ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+ if(ret >= 0)
+ return out;
+ else
+ return 1;
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ return 1;
+}
+
+int32
+runtime·semasleep(int64 ns)
+{
+ Timespec ts;
+
+ // spin-mutex lock
+ while(runtime·xchg(&m->waitsemalock, 1))
+ runtime·osyield();
+
+ for(;;) {
+ // lock held
+ if(m->waitsemacount == 0) {
+ // sleep until semaphore != 0 or timeout.
+ // thrsleep unlocks m->waitsemalock.
+ if(ns < 0)
+ runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock);
+ else {
+ ns += runtime·nanotime();
+ ts.tv_sec = ns/1000000000LL;
+ ts.tv_nsec = ns%1000000000LL;
+ runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock);
+ }
+ // reacquire lock
+ while(runtime·xchg(&m->waitsemalock, 1))
+ runtime·osyield();
+ }
+
+ // lock held (again)
+ if(m->waitsemacount != 0) {
+ // semaphore is available.
+ m->waitsemacount--;
+ // spin-mutex unlock
+ runtime·atomicstore(&m->waitsemalock, 0);
+ return 0; // semaphore acquired
+ }
+
+ // semaphore not available.
+ // if there is a timeout, stop now.
+ // otherwise keep trying.
+ if(ns >= 0)
+ break;
+ }
+
+ // lock held but giving up
+ // spin-mutex unlock
+ runtime·atomicstore(&m->waitsemalock, 0);
+ return -1;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ uint32 ret;
+
+ // spin-mutex lock
+ while(runtime·xchg(&mp->waitsemalock, 1))
+ runtime·osyield();
+ mp->waitsemacount++;
+ ret = runtime·thrwakeup(&mp->waitsemacount, 1);
+ if(ret != 0 && ret != ESRCH)
+ runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
+ // spin-mutex unlock
+ runtime·atomicstore(&mp->waitsemalock, 0);
+}
+
+// From OpenBSD's sys/param.h
+#define RFPROC (1<<4) /* change child (else changes curproc) */
+#define RFMEM (1<<5) /* share `address space' */
+#define RFNOWAIT (1<<6) /* parent need not wait() on child */
+#define RFTHREAD (1<<13) /* create a thread, not a process */
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int32 flags;
+ int32 ret;
+
+ flags = RFPROC | RFTHREAD | RFMEM | RFNOWAIT;
+
+ if (0) {
+ runtime·printf(
+ "newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ if((ret = runtime·rfork_thread(flags, stk, m, g, fn)) < 0) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
+ if (ret == -ENOTSUP)
+ runtime·printf("runtime: is kern.rthreads disabled?\n");
+ runtime·throw("runtime.newosproc");
+ }
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getncpu();
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ return 0;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c
new file mode 100644
index 000000000..3b0dca69f
--- /dev/null
+++ b/src/pkg/runtime/thread_plan9.c
@@ -0,0 +1,269 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+
+int8 *goos = "plan9";
+
+void
+runtime·minit(void)
+{
+}
+
+static int32
+getproccount(void)
+{
+ int32 fd, i, n, ncpu;
+ byte buf[2048];
+
+ fd = runtime·open((byte*)"/dev/sysstat", OREAD);
+ if(fd < 0)
+ return 1;
+ ncpu = 0;
+ for(;;) {
+ n = runtime·read(fd, buf, sizeof buf);
+ if(n <= 0)
+ break;
+ for(i = 0; i < n; i++) {
+ if(buf[i] == '\n')
+ ncpu++;
+ }
+ }
+ runtime·close(fd);
+ return ncpu > 0 ? ncpu : 1;
+}
+
+void
+runtime·osinit(void)
+{
+ runtime·ncpu = getproccount();
+}
+
+void
+runtime·goenvs(void)
+{
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+void
+runtime·osyield(void)
+{
+ runtime·sleep(0);
+}
+
+void
+runtime·usleep(uint32 µs)
+{
+ uint32 ms;
+
+ ms = µs/1000;
+ if(ms == 0)
+ ms = 1;
+ runtime·sleep(ms);
+}
+
+int64
+runtime·nanotime(void)
+{
+ static int32 fd = -1;
+ byte b[8];
+ uint32 hi, lo;
+
+ // As long as all goroutines share the same file
+ // descriptor table we can get away with using
+ // just a static fd. Without a lock the file can
+ // be opened twice but that's okay.
+ //
+ // Using /dev/bintime gives us a latency on the
+ // order of ten microseconds between two calls.
+ //
+ // The naïve implementation (without the cached
+ // file descriptor) is roughly four times slower
+ // in 9vx on a 2.16 GHz Intel Core 2 Duo.
+
+ if(fd < 0 && (fd = runtime·open((byte*)"/dev/bintime", OREAD|OCEXEC)) < 0)
+ return 0;
+ if(runtime·pread(fd, b, sizeof b, 0) != sizeof b)
+ return 0;
+ hi = b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
+ lo = b[4]<<24 | b[5]<<16 | b[6]<<8 | b[7];
+ return (int64)hi<<32 | (int64)lo;
+}
+
+void
+time·now(int64 sec, int32 nsec)
+{
+ int64 ns;
+
+ ns = runtime·nanotime();
+ sec = ns / 1000000000LL;
+ nsec = ns - sec * 1000000000LL;
+ FLUSH(&sec);
+ FLUSH(&nsec);
+}
+
+extern Tos *_tos;
+void
+runtime·exit(int32)
+{
+ int32 fd;
+ uint8 buf[128];
+ uint8 tmp[16];
+ uint8 *p, *q;
+ int32 pid;
+
+ runtime·memclr(buf, sizeof buf);
+ runtime·memclr(tmp, sizeof tmp);
+ pid = _tos->pid;
+
+ /* build path string /proc/pid/notepg */
+ for(q=tmp; pid > 0;) {
+ *q++ = '0' + (pid%10);
+ pid = pid/10;
+ }
+ p = buf;
+ runtime·memmove((void*)p, (void*)"/proc/", 6);
+ p += 6;
+ for(q--; q >= tmp;)
+ *p++ = *q--;
+ runtime·memmove((void*)p, (void*)"/notepg", 7);
+
+ /* post interrupt note */
+ fd = runtime·open(buf, OWRITE);
+ runtime·write(fd, "interrupt", 9);
+ runtime·exits(nil);
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
+ }
+
+ if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0)
+ runtime·throw("newosproc: rfork failed");
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ return 1;
+}
+
+int32
+runtime·semasleep(int64 ns)
+{
+ int32 ret;
+ int32 ms;
+
+ if(ns >= 0) {
+ // TODO: Plan 9 needs a new system call, tsemacquire.
+ // The kernel implementation is the same as semacquire
+ // except with a tsleep and check for timeout.
+ // It would be great if the implementation returned the
+ // value that was added to the semaphore, so that on
+ // timeout the return value would be 0, on success 1.
+ // Then the error string does not have to be parsed
+ // to detect timeout.
+ //
+ // If a negative time indicates no timeout, then
+ // semacquire can be implemented (in the kernel)
+ // as tsemacquire(p, v, -1).
+ runtime·throw("semasleep: timed sleep not implemented on Plan 9");
+
+ /*
+ if(ns < 0)
+ ms = -1;
+ else if(ns/1000 > 0x7fffffffll)
+ ms = 0x7fffffff;
+ else
+ ms = ns/1000;
+ ret = runtime·plan9_tsemacquire(&m->waitsemacount, 1, ms);
+ if(ret == 1)
+ return 0; // success
+ return -1; // timeout or interrupted
+ */
+ }
+
+ while(runtime·plan9_semacquire(&m->waitsemacount, 1) < 0) {
+ /* interrupted; try again */
+ }
+ return 0; // success
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ runtime·plan9_semrelease(&mp->waitsemacount, 1);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+/*
+ * placeholder - once notes are implemented,
+ * a signal generating a panic must appear as
+ * a call to this function for correct handling by
+ * traceback.
+ */
+void
+runtime·sigpanic(void)
+{
+}
+
+int32
+runtime·read(int32 fd, void *buf, int32 nbytes)
+{
+ return runtime·pread(fd, buf, nbytes, -1LL);
+}
+
+int32
+runtime·write(int32 fd, void *buf, int32 nbytes)
+{
+ return runtime·pwrite(fd, buf, nbytes, -1LL);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ return 0;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
+}
diff --git a/src/pkg/runtime/thread_windows.c b/src/pkg/runtime/thread_windows.c
new file mode 100644
index 000000000..f684d3733
--- /dev/null
+++ b/src/pkg/runtime/thread_windows.c
@@ -0,0 +1,430 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "type.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
+#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
+#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
+#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
+#pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll"
+#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
+#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
+#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
+#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
+#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
+#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
+#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
+#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
+#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
+#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+
+extern void *runtime·CloseHandle;
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·CreateWaitableTimer;
+extern void *runtime·DuplicateHandle;
+extern void *runtime·ExitProcess;
+extern void *runtime·FreeEnvironmentStringsW;
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetStdHandle;
+extern void *runtime·GetSystemInfo;
+extern void *runtime·GetSystemTimeAsFileTime;
+extern void *runtime·GetThreadContext;
+extern void *runtime·LoadLibrary;
+extern void *runtime·ResumeThread;
+extern void *runtime·SetConsoleCtrlHandler;
+extern void *runtime·SetEvent;
+extern void *runtime·SetThreadPriority;
+extern void *runtime·SetWaitableTimer;
+extern void *runtime·Sleep;
+extern void *runtime·SuspendThread;
+extern void *runtime·timeBeginPeriod;
+extern void *runtime·WaitForSingleObject;
+extern void *runtime·WriteFile;
+
+static int32
+getproccount(void)
+{
+ SystemInfo info;
+
+ runtime·stdcall(runtime·GetSystemInfo, 1, &info);
+ return info.dwNumberOfProcessors;
+}
+
+void
+runtime·osinit(void)
+{
+ // -1 = current process, -2 = current thread
+ runtime·stdcall(runtime·DuplicateHandle, 7,
+ (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
+ (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+ runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
+ runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
+ runtime·ncpu = getproccount();
+}
+
+void
+runtime·goenvs(void)
+{
+ extern Slice syscall·envs;
+
+ uint16 *env;
+ String *s;
+ int32 i, n;
+ uint16 *p;
+
+ env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
+
+ n = 0;
+ for(p=env; *p; n++)
+ p += runtime·findnullw(p)+1;
+
+ s = runtime·malloc(n*sizeof s[0]);
+
+ p = env;
+ for(i=0; i<n; i++) {
+ s[i] = runtime·gostringw(p);
+ p += runtime·findnullw(p)+1;
+ }
+ syscall·envs.array = (byte*)s;
+ syscall·envs.len = n;
+ syscall·envs.cap = n;
+
+ runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
+}
+
+void
+runtime·exit(int32 code)
+{
+ runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
+}
+
+int32
+runtime·write(int32 fd, void *buf, int32 n)
+{
+ void *handle;
+ uint32 written;
+
+ written = 0;
+ switch(fd) {
+ case 1:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
+ break;
+ case 2:
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
+ break;
+ default:
+ return -1;
+ }
+ runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
+ return written;
+}
+
+void
+runtime·osyield(void)
+{
+ runtime·stdcall(runtime·Sleep, 1, (uintptr)0);
+}
+
+void
+runtime·usleep(uint32 us)
+{
+ us /= 1000;
+ if(us == 0)
+ us = 1;
+ runtime·stdcall(runtime·Sleep, 1, (uintptr)us);
+}
+
+#define INFINITE ((uintptr)0xFFFFFFFF)
+
+int32
+runtime·semasleep(int64 ns)
+{
+ uintptr ms;
+
+ if(ns < 0)
+ ms = INFINITE;
+ else if(ns/1000000 > 0x7fffffffLL)
+ ms = 0x7fffffff;
+ else {
+ ms = ns/1000000;
+ if(ms == 0)
+ ms = 1;
+ }
+ if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0)
+ return -1; // timeout
+ return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+ runtime·stdcall(runtime·SetEvent, 1, mp->waitsema);
+}
+
+uintptr
+runtime·semacreate(void)
+{
+ return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
+}
+
+#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ void *thandle;
+
+ USED(stk);
+ USED(g); // assuming g = m->g0
+ USED(fn); // assuming fn = mstart
+
+ thandle = runtime·stdcall(runtime·CreateThread, 6,
+ nil, (uintptr)0x20000, runtime·tstart_stdcall, m,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
+ if(thandle == nil) {
+ runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
+ runtime·throw("runtime.newosproc");
+ }
+ runtime·atomicstorep(&m->thread, thandle);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+}
+
+int64
+runtime·nanotime(void)
+{
+ int64 filetime;
+
+ runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime);
+
+ // Filetime is 100s of nanoseconds since January 1, 1601.
+ // Convert to nanoseconds since January 1, 1970.
+ return (filetime - 116444736000000000LL) * 100LL;
+}
+
+void
+time·now(int64 sec, int32 usec)
+{
+ int64 ns;
+
+ ns = runtime·nanotime();
+ sec = ns / 1000000000LL;
+ usec = ns - sec * 1000000000LL;
+ FLUSH(&sec);
+ FLUSH(&usec);
+}
+
+// Calling stdcall on os stack.
+#pragma textflag 7
+void *
+runtime·stdcall(void *fn, int32 count, ...)
+{
+ WinCall c;
+
+ c.fn = fn;
+ c.n = count;
+ c.args = (uintptr*)&count + 1;
+ runtime·asmcgocall(runtime·asmstdcall, &c);
+ return (void*)c.r1;
+}
+
+uint32
+runtime·issigpanic(uint32 code)
+{
+ switch(code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_OVERFLOW:
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ return 1;
+ }
+ return 0;
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ if(g->sigcode1 < 0x1000) {
+ if(g->sigpc == 0)
+ runtime·panicstring("call of nil func value");
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ runtime·panicstring("integer divide by zero");
+ case EXCEPTION_INT_OVERFLOW:
+ runtime·panicstring("integer overflow");
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_UNDERFLOW:
+ runtime·panicstring("floating point error");
+ }
+ runtime·throw("fault");
+}
+
+extern void *runtime·sigtramp;
+
+void
+runtime·initsig(void)
+{
+ // following line keeps sigtramp alive at link stage
+ // if there's a better way please write it here
+ void *p = runtime·sigtramp;
+ USED(p);
+}
+
+uint32
+runtime·ctrlhandler1(uint32 type)
+{
+ int32 s;
+
+ switch(type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ s = SIGINT;
+ break;
+ default:
+ return 0;
+ }
+
+ if(runtime·sigsend(s))
+ return 1;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ return 0;
+}
+
+extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·profileloop(void);
+static void *profiletimer;
+
+static void
+profilem(M *mp)
+{
+ extern M runtime·m0;
+ extern uint32 runtime·tls0[];
+ byte rbuf[sizeof(Context)+15];
+ Context *r;
+ void *tls;
+ G *gp;
+
+ tls = mp->tls;
+ if(mp == &runtime·m0)
+ tls = runtime·tls0;
+ gp = *(G**)tls;
+
+ if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
+ // align Context to 16 bytes
+ r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+ r->ContextFlags = CONTEXT_CONTROL;
+ runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+ runtime·dosigprof(r, gp);
+ }
+}
+
+void
+runtime·profileloop1(void)
+{
+ M *mp, *allm;
+ void *thread;
+
+ runtime·stdcall(runtime·SetThreadPriority, 2,
+ (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
+
+ for(;;) {
+ runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
+ allm = runtime·atomicloadp(&runtime·allm);
+ for(mp = allm; mp != nil; mp = mp->alllink) {
+ thread = runtime·atomicloadp(&mp->thread);
+ if(thread == nil)
+ continue;
+ runtime·stdcall(runtime·SuspendThread, 1, thread);
+ if(mp->profilehz != 0)
+ profilem(mp);
+ runtime·stdcall(runtime·ResumeThread, 1, thread);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ static Lock lock;
+ void *timer, *thread;
+ int32 ms;
+ int64 due;
+
+ runtime·lock(&lock);
+ if(profiletimer == nil) {
+ timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
+ runtime·atomicstorep(&profiletimer, timer);
+ thread = runtime·stdcall(runtime·CreateThread, 6,
+ nil, nil, runtime·profileloop, nil, nil, nil);
+ runtime·stdcall(runtime·CloseHandle, 1, thread);
+ }
+ runtime·unlock(&lock);
+
+ ms = 0;
+ due = 1LL<<63;
+ if(hz > 0) {
+ ms = 1000 / hz;
+ if(ms == 0)
+ ms = 1;
+ due = ms * -10000;
+ }
+ runtime·stdcall(runtime·SetWaitableTimer, 6,
+ profiletimer, &due, (uintptr)ms, nil, nil, nil);
+ runtime·atomicstore((uint32*)&m->profilehz, hz);
+}
+
+void
+os·sigpipe(void)
+{
+ runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+ return 0;
+}
+
+void
+runtime·setprof(bool on)
+{
+ USED(on);
+}
+
+int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n";
+int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1;
+
+int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
+int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
new file mode 100644
index 000000000..a6b835247
--- /dev/null
+++ b/src/pkg/runtime/time.goc
@@ -0,0 +1,253 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Time-related runtime and pieces of package time.
+
+package time
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+static Timers timers;
+static void addtimer(Timer*);
+static bool deltimer(Timer*);
+
+// Package time APIs.
+// Godoc uses the comments in package time, not these.
+
+// time.now is implemented in assembly.
+
+// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
+func Sleep(ns int64) {
+ g->status = Gwaiting;
+ g->waitreason = "sleep";
+ runtime·tsleep(ns);
+}
+
+// startTimer adds t to the timer heap.
+func startTimer(t *Timer) {
+ addtimer(t);
+}
+
+// stopTimer removes t from the timer heap if it is there.
+// It returns true if t was removed, false if t wasn't even there.
+func stopTimer(t *Timer) (stopped bool) {
+ stopped = deltimer(t);
+}
+
+// C runtime.
+
+static void timerproc(void);
+static void siftup(int32);
+static void siftdown(int32);
+
+// Ready the goroutine e.data.
+static void
+ready(int64 now, Eface e)
+{
+ USED(now);
+
+ runtime·ready(e.data);
+}
+
+// Put the current goroutine to sleep for ns nanoseconds.
+// The caller must have set g->status and g->waitreason.
+void
+runtime·tsleep(int64 ns)
+{
+ Timer t;
+
+ if(ns <= 0)
+ return;
+
+ t.when = runtime·nanotime() + ns;
+ t.period = 0;
+ t.f = ready;
+ t.arg.data = g;
+ addtimer(&t);
+ runtime·gosched();
+}
+
+// Add a timer to the heap and start or kick the timer proc
+// if the new timer is earlier than any of the others.
+static void
+addtimer(Timer *t)
+{
+ int32 n;
+ Timer **nt;
+
+ runtime·lock(&timers);
+ if(timers.len >= timers.cap) {
+ // Grow slice.
+ n = 16;
+ if(n <= timers.cap)
+ n = timers.cap*3 / 2;
+ nt = runtime·malloc(n*sizeof nt[0]);
+ runtime·memmove(nt, timers.t, timers.len*sizeof nt[0]);
+ runtime·free(timers.t);
+ timers.t = nt;
+ timers.cap = n;
+ }
+ t->i = timers.len++;
+ timers.t[t->i] = t;
+ siftup(t->i);
+ if(t->i == 0) {
+ // siftup moved to top: new earliest deadline.
+ if(timers.sleeping) {
+ timers.sleeping = false;
+ runtime·notewakeup(&timers.waitnote);
+ }
+ if(timers.rescheduling) {
+ timers.rescheduling = false;
+ runtime·ready(timers.timerproc);
+ }
+ }
+ if(timers.timerproc == nil)
+ timers.timerproc = runtime·newproc1((byte*)timerproc, nil, 0, 0, addtimer);
+ runtime·unlock(&timers);
+}
+
+// Delete timer t from the heap.
+// Do not need to update the timerproc:
+// if it wakes up early, no big deal.
+static bool
+deltimer(Timer *t)
+{
+ int32 i;
+
+ runtime·lock(&timers);
+
+ // t may not be registered anymore and may have
+ // a bogus i (typically 0, if generated by Go).
+ // Verify it before proceeding.
+ i = t->i;
+ if(i < 0 || i >= timers.len || timers.t[i] != t) {
+ runtime·unlock(&timers);
+ return false;
+ }
+
+ timers.len--;
+ if(i == timers.len) {
+ timers.t[i] = nil;
+ } else {
+ timers.t[i] = timers.t[timers.len];
+ timers.t[timers.len] = nil;
+ timers.t[i]->i = i;
+ siftup(i);
+ siftdown(i);
+ }
+ runtime·unlock(&timers);
+ return true;
+}
+
+// Timerproc runs the time-driven events.
+// It sleeps until the next event in the timers heap.
+// If addtimer inserts a new earlier event, addtimer
+// wakes timerproc early.
+static void
+timerproc(void)
+{
+ int64 delta, now;
+ Timer *t;
+ void (*f)(int64, Eface);
+ Eface arg;
+
+ for(;;) {
+ runtime·lock(&timers);
+ now = runtime·nanotime();
+ for(;;) {
+ if(timers.len == 0) {
+ delta = -1;
+ break;
+ }
+ t = timers.t[0];
+ delta = t->when - now;
+ if(delta > 0)
+ break;
+ if(t->period > 0) {
+ // leave in heap but adjust next time to fire
+ t->when += t->period * (1 + -delta/t->period);
+ siftdown(0);
+ } else {
+ // remove from heap
+ timers.t[0] = timers.t[--timers.len];
+ timers.t[0]->i = 0;
+ siftdown(0);
+ t->i = -1; // mark as removed
+ }
+ f = t->f;
+ arg = t->arg;
+ runtime·unlock(&timers);
+ f(now, arg);
+ runtime·lock(&timers);
+ }
+ if(delta < 0) {
+ // No timers left - put goroutine to sleep.
+ timers.rescheduling = true;
+ g->status = Gwaiting;
+ g->waitreason = "timer goroutine (idle)";
+ runtime·unlock(&timers);
+ runtime·gosched();
+ continue;
+ }
+ // At least one timer pending. Sleep until then.
+ timers.sleeping = true;
+ runtime·noteclear(&timers.waitnote);
+ runtime·unlock(&timers);
+ runtime·entersyscall();
+ runtime·notetsleep(&timers.waitnote, delta);
+ runtime·exitsyscall();
+ }
+}
+
+// heap maintenance algorithms.
+
+static void
+siftup(int32 i)
+{
+ int32 p;
+ Timer **t, *tmp;
+
+ t = timers.t;
+ while(i > 0) {
+ p = (i-1)/2; // parent
+ if(t[i]->when >= t[p]->when)
+ break;
+ tmp = t[i];
+ t[i] = t[p];
+ t[p] = tmp;
+ t[i]->i = i;
+ t[p]->i = p;
+ i = p;
+ }
+}
+
+static void
+siftdown(int32 i)
+{
+ int32 c, len;
+ Timer **t, *tmp;
+
+ t = timers.t;
+ len = timers.len;
+ for(;;) {
+ c = i*2 + 1; // left child
+ if(c >= len) {
+ break;
+ }
+ if(c+1 < len && t[c+1]->when < t[c]->when)
+ c++;
+ if(t[c]->when >= t[i]->when)
+ break;
+ tmp = t[i];
+ t[i] = t[c];
+ t[c] = tmp;
+ t[i]->i = i;
+ t[c]->i = c;
+ i = c;
+ }
+}
diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/traceback_arm.c
index 5628b8349..22e0bc3a6 100644
--- a/src/pkg/runtime/arm/traceback.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
void runtime·deferproc(void);
@@ -117,27 +118,29 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
else if(pcbuf != nil)
pcbuf[n++] = pc;
else {
- // Print during crash.
- // main+0xf /home/rsc/go/src/runtime/x.go:23
- // main(0x1, 0x2, 0x3)
- runtime·printf("[%p] %S", fp, f->name);
- if(pc > f->entry)
- runtime·printf("+%p", (uintptr)(pc - f->entry));
- tracepc = pc; // back up to CALL instruction for funcline.
- if(n > 0 && pc > f->entry && !waspanic)
- tracepc -= sizeof(uintptr);
- runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
- runtime·printf("\t%S(", f->name);
- for(i = 0; i < f->args; i++) {
- if(i != 0)
- runtime·prints(", ");
- runtime·printhex(((uintptr*)fp)[1+i]);
- if(i >= 4) {
- runtime·prints(", ...");
- break;
+ if(runtime·showframe(f)) {
+ // Print during crash.
+ // main(0x1, 0x2, 0x3)
+ // /home/rsc/go/src/runtime/x.go:23 +0xf
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry && !waspanic)
+ tracepc -= sizeof(uintptr);
+ runtime·printf("%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)fp)[1+i]);
+ if(i >= 4) {
+ runtime·prints(", ...");
+ break;
+ }
}
+ runtime·prints(")\n");
+ runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
+ if(pc > f->entry)
+ runtime·printf(" +%p", (uintptr)(pc - f->entry));
+ runtime·printf("\n");
}
- runtime·prints(")\n");
n++;
}
@@ -181,14 +184,15 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
sp += 12;
}
- if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) {
- runtime·printf("----- goroutine created by -----\n%S", f->name);
- if(pc > f->entry)
- runtime·printf("+%p", (uintptr)(pc - f->entry));
+ if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && g->goid != 1) {
+ runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry)
tracepc -= sizeof(uintptr);
- runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
+ if(pc > f->entry)
+ runtime·printf(" +%p", (uintptr)(pc - f->entry));
+ runtime·printf("\n");
}
return n;
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/traceback_x86.c
index 3e85d36bd..be35bab00 100644
--- a/src/pkg/runtime/amd64/traceback.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build amd64 386
+
#include "runtime.h"
+#include "arch_GOARCH.h"
#include "malloc.h"
static uintptr isclosureentry(uintptr);
@@ -123,27 +126,30 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
else if(pcbuf != nil)
pcbuf[n++] = pc;
else {
- // Print during crash.
- // main+0xf /home/rsc/go/src/runtime/x.go:23
- // main(0x1, 0x2, 0x3)
- runtime·printf("%S", f->name);
- if(pc > f->entry)
- runtime·printf("+%p", (uintptr)(pc - f->entry));
- tracepc = pc; // back up to CALL instruction for funcline.
- if(n > 0 && pc > f->entry && !waspanic)
- tracepc--;
- runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
- runtime·printf("\t%S(", f->name);
- for(i = 0; i < f->args; i++) {
- if(i != 0)
- runtime·prints(", ");
- runtime·printhex(((uintptr*)fp)[i]);
- if(i >= 4) {
- runtime·prints(", ...");
- break;
+ if(runtime·showframe(f)) {
+ // Print during crash.
+ // main(0x1, 0x2, 0x3)
+ // /home/rsc/go/src/runtime/x.go:23 +0xf
+ //
+ tracepc = pc; // back up to CALL instruction for funcline.
+ if(n > 0 && pc > f->entry && !waspanic)
+ tracepc--;
+ runtime·printf("%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)fp)[i]);
+ if(i >= 4) {
+ runtime·prints(", ...");
+ break;
+ }
}
+ runtime·prints(")\n");
+ runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
+ if(pc > f->entry)
+ runtime·printf(" +%p", (uintptr)(pc - f->entry));
+ runtime·printf("\n");
}
- runtime·prints(")\n");
n++;
}
@@ -189,14 +195,16 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr
fp = nil;
}
- if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil) {
- runtime·printf("----- goroutine created by -----\n%S", f->name);
- if(pc > f->entry)
- runtime·printf("+%p", (uintptr)(pc - f->entry));
+ // Show what created goroutine, except main goroutine (goid 1).
+ if(pcbuf == nil && (pc = g->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && g->goid != 1) {
+ runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline.
if(n > 0 && pc > f->entry)
tracepc--;
- runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
+ if(pc > f->entry)
+ runtime·printf(" +%p", (uintptr)(pc - f->entry));
+ runtime·printf("\n");
}
return n;
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 30f3ec642..6af6b237f 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -4,205 +4,51 @@
/*
* Runtime type representation.
- *
- * The following files know the exact layout of these
- * data structures and must be kept in sync with this file:
- *
- * ../../cmd/gc/reflect.c
- * ../../cmd/ld/dwarf.c decodetype_*
- * ../reflect/type.go
- * type.h
+ * This file exists only to provide types that 6l can turn into
+ * DWARF information for use by gdb. Nothing else uses these.
+ * They should match the same types in ../reflect/type.go.
+ * For comments see ../reflect/type.go.
*/
package runtime
import "unsafe"
-// The compiler can only construct empty interface values at
-// compile time; non-empty interface values get created
-// during initialization. Type is an empty interface
-// so that the compiler can lay out references as data.
-type Type interface{}
-
-// All types begin with a few common fields needed for
-// the interface runtime.
type commonType struct {
- size uintptr // size in bytes
- hash uint32 // hash of type; avoids computation in hash tables
- alg uint8 // algorithm for copy+hash+cmp (../runtime/runtime.h:/AMEM)
- align uint8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- kind uint8 // enumeration for C
- string *string // string form; unnecessary but undeniably useful
- *uncommonType // (relatively) uncommon fields
- ptrToThis *Type // pointer to this type, if used in binary or has methods
-}
-
-// Values for commonType.kind.
-const (
- kindBool = 1 + iota
- kindInt
- kindInt8
- kindInt16
- kindInt32
- kindInt64
- kindUint
- kindUint8
- kindUint16
- kindUint32
- kindUint64
- kindUintptr
- kindFloat32
- kindFloat64
- kindComplex64
- kindComplex128
- kindArray
- kindChan
- kindFunc
- kindInterface
- kindMap
- kindPtr
- kindSlice
- kindString
- kindStruct
- kindUnsafePointer
-
- kindNoPointers = 1 << 7 // OR'ed into kind
-)
-
-// Method on non-interface type
-type _method struct { // underscore is to avoid collision with C
- name *string // name of method
- pkgPath *string // nil for exported Names; otherwise import path
- mtyp *Type // method type (without receiver)
- typ *Type // .(*FuncType) underneath (with receiver)
- ifn unsafe.Pointer // fn used in interface call (one-word receiver)
- tfn unsafe.Pointer // fn used for normal method call
+ size uintptr
+ hash uint32
+ _ uint8
+ align uint8
+ fieldAlign uint8
+ kind uint8
+ alg *uintptr
+ string *string
+ *uncommonType
+ ptrToThis *interface{}
+}
+
+type _method struct {
+ name *string
+ pkgPath *string
+ mtyp *interface{}
+ typ *interface{}
+ ifn unsafe.Pointer
+ tfn unsafe.Pointer
}
-// uncommonType is present only for types with names or methods
-// (if T is a named type, the uncommonTypes for T and *T have methods).
-// Using a pointer to this struct reduces the overall size required
-// to describe an unnamed type with no methods.
type uncommonType struct {
- name *string // name of type
- pkgPath *string // import path; nil for built-in types like int, string
- methods []_method // methods associated with type
-}
-
-// BoolType represents a boolean type.
-type BoolType commonType
-
-// FloatType represents a float type.
-type FloatType commonType
-
-// ComplexType represents a complex type.
-type ComplexType commonType
-
-// IntType represents an int type.
-type IntType commonType
-
-// UintType represents a uint type.
-type UintType commonType
-
-// StringType represents a string type.
-type StringType commonType
-
-// UintptrType represents a uintptr type.
-type UintptrType commonType
-
-// UnsafePointerType represents an unsafe.Pointer type.
-type UnsafePointerType commonType
-
-// ArrayType represents a fixed array type.
-type ArrayType struct {
- commonType
- elem *Type // array element type
- slice *Type // slice type
- len uintptr
-}
-
-// SliceType represents a slice type.
-type SliceType struct {
- commonType
- elem *Type // slice element type
-}
-
-// ChanDir represents a channel type's direction.
-type ChanDir int
-
-const (
- RecvDir ChanDir = 1 << iota // <-chan
- SendDir // chan<-
- BothDir = RecvDir | SendDir // chan
-)
-
-// ChanType represents a channel type.
-type ChanType struct {
- commonType
- elem *Type // channel element type
- dir uintptr // channel direction (ChanDir)
-}
-
-// FuncType represents a function type.
-type FuncType struct {
- commonType
- dotdotdot bool // last input parameter is ...
- in []*Type // input parameter types
- out []*Type // output parameter types
+ name *string
+ pkgPath *string
+ methods []_method
}
-// Method on interface type
-type _imethod struct { // underscore is to avoid collision with C
- name *string // name of method
- pkgPath *string // nil for exported Names; otherwise import path
- typ *Type // .(*FuncType) underneath
+type _imethod struct {
+ name *string
+ pkgPath *string
+ typ *interface{}
}
-// InterfaceType represents an interface type.
-type InterfaceType struct {
+type interfaceType struct {
commonType
- methods []_imethod // sorted by hash
-}
-
-// MapType represents a map type.
-type MapType struct {
- commonType
- key *Type // map key type
- elem *Type // map element (value) type
-}
-
-// PtrType represents a pointer type.
-type PtrType struct {
- commonType
- elem *Type // pointer element (pointed at) type
-}
-
-// Struct field
-type structField struct {
- name *string // nil for embedded fields
- pkgPath *string // nil for exported Names; otherwise import path
- typ *Type // type of field
- tag *string // nil if no tag
- offset uintptr // byte offset of field within struct
-}
-
-// StructType represents a struct type.
-type StructType struct {
- commonType
- fields []structField // sorted by offset
-}
-
-/*
- * Must match iface.c:/Itab and compilers.
- * NOTE: this is the version used by the reflection code, there is another
- * one in iface_defs.go that is closer to the original C version.
- */
-type Itable struct {
- Itype *Type // (*tab.inter).(*InterfaceType) is the interface type
- Type *Type
- link *Itable
- bad int32
- unused int32
- Fn [100000]uintptr // bigger than we'll ever see
+ methods []_imethod
}
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 8c80c62d3..c1d9facd1 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -23,10 +23,11 @@ struct CommonType
{
uintptr size;
uint32 hash;
- uint8 alg;
+ uint8 _unused;
uint8 align;
uint8 fieldAlign;
uint8 kind;
+ Alg *alg;
String *string;
UncommonType *x;
Type *ptrto;
diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/vlop_386.s
index 28f6da82d..28f6da82d 100644
--- a/src/pkg/runtime/386/vlop.s
+++ b/src/pkg/runtime/vlop_386.s
diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/vlop_arm.s
index fc679f0ee..fc679f0ee 100644
--- a/src/pkg/runtime/arm/vlop.s
+++ b/src/pkg/runtime/vlop_arm.s
diff --git a/src/pkg/runtime/386/vlrt.c b/src/pkg/runtime/vlrt_386.c
index 1631dbe10..1631dbe10 100644
--- a/src/pkg/runtime/386/vlrt.c
+++ b/src/pkg/runtime/vlrt_386.c
diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/vlrt_arm.c
index 50f33710b..50f33710b 100644
--- a/src/pkg/runtime/arm/vlrt.c
+++ b/src/pkg/runtime/vlrt_arm.c
diff --git a/src/pkg/runtime/windows/amd64/defs.h b/src/pkg/runtime/windows/amd64/defs.h
deleted file mode 100644
index 830c6a855..000000000
--- a/src/pkg/runtime/windows/amd64/defs.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// g:\opensource\go\bin\godefs.exe -f -m64 defs.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Constants
-enum {
- PROT_NONE = 0,
- PROT_READ = 0x1,
- PROT_WRITE = 0x2,
- PROT_EXEC = 0x4,
- MAP_ANON = 0x1,
- MAP_PRIVATE = 0x2,
- SIGINT = 0x2,
- CTRL_C_EVENT = 0,
- CTRL_BREAK_EVENT = 0x1,
- EXCEPTION_ACCESS_VIOLATION = 0xc0000005,
- EXCEPTION_BREAKPOINT = 0x80000003,
- EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d,
- EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e,
- EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f,
- EXCEPTION_FLT_OVERFLOW = 0xc0000091,
- EXCEPTION_FLT_UNDERFLOW = 0xc0000093,
- EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094,
- EXCEPTION_INT_OVERFLOW = 0xc0000095,
-};
-
-// Types
-#pragma pack on
-
-typedef struct ExceptionRecord ExceptionRecord;
-struct ExceptionRecord {
- uint32 ExceptionCode;
- uint32 ExceptionFlags;
- ExceptionRecord *ExceptionRecord;
- void *ExceptionAddress;
- uint32 NumberParameters;
- byte pad_godefs_0[4];
- uint64 ExceptionInformation[15];
-};
-#pragma pack off
diff --git a/src/pkg/runtime/windows/amd64/signal.c b/src/pkg/runtime/windows/amd64/signal.c
deleted file mode 100644
index 1fc3eb060..000000000
--- a/src/pkg/runtime/windows/amd64/signal.c
+++ /dev/null
@@ -1,20 +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.
-
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-
-void
-runtime·initsig(int32 queue)
-{
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
- // TODO: Enable profiling interrupts.
-
- m->profilehz = hz;
-}
diff --git a/src/pkg/runtime/windows/amd64/sys.s b/src/pkg/runtime/windows/amd64/sys.s
deleted file mode 100644
index 2009d164e..000000000
--- a/src/pkg/runtime/windows/amd64/sys.s
+++ /dev/null
@@ -1,130 +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.
-
-#include "amd64/asm.h"
-
-// void *stdcall_raw(void *fn, uintptr nargs, void *args)
-TEXT runtime·stdcall_raw(SB),7,$8
- MOVQ fn+0(FP), AX
- MOVQ nargs+8(FP), CX
- MOVQ args+16(FP), R11
-
- // Switch to m->g0 if needed.
- get_tls(DI)
- MOVQ m(DI), DX
- MOVQ g(DI), SI
- MOVQ SI, 0(SP) // save g
- MOVQ SP, m_gostack(DX) // save SP
- MOVQ m_g0(DX), SI
- CMPQ g(DI), SI
- JEQ 3(PC)
- MOVQ (g_sched+gobuf_sp)(SI), SP
- ANDQ $~15, SP
- MOVQ SI, g(DI)
-
- SUBQ $0x60, SP
-
- // Copy args to new stack.
- MOVQ SP, DI
- MOVQ R11, SI
- CLD
- REP; MOVSQ
- MOVQ 0(R11), CX
- MOVQ 8(R11), DX
- MOVQ 16(R11), R8
- MOVQ 24(R11), R9
-
- // Call stdcall function.
- CALL AX
-
- // Restore original SP, g.
- get_tls(DI)
- MOVQ m(DI), DX
- MOVQ m_gostack(DX), SP // restore SP
- MOVQ 0(SP), SI // restore g
- MOVQ SI, g(DI)
-
- RET
-
-// faster get/set last error
-TEXT runtime·getlasterror(SB),7,$0
- MOVQ 0x30(GS), AX
- MOVL 0x68(AX), AX
- RET
-
-TEXT runtime·setlasterror(SB),7,$0
- MOVL err+0(FP), AX
- MOVQ 0x30(GS), CX
- MOVL AX, 0x68(CX)
- RET
-
-// Windows runs the ctrl handler in a new thread.
-TEXT runtime·ctrlhandler(SB),7,$0
- // TODO
- RET
-
-TEXT runtime·callbackasm(SB),7,$0
- // TODO
- RET
-
-// void tstart(M *newm);
-TEXT runtime·tstart(SB),7,$0
- MOVQ newm+8(SP), CX // m
- MOVQ m_g0(CX), DX // g
-
- MOVQ SP, DI // remember stack
-
- // Layout new m scheduler stack on os stack.
- MOVQ SP, AX
- MOVQ AX, g_stackbase(DX)
- SUBQ $(64*1024), AX // stack size
- MOVQ AX, g_stackguard(DX)
-
- // Set up tls.
- LEAQ m_tls(CX), SI
- MOVQ SI, 0x58(GS)
- MOVQ CX, m(SI)
- MOVQ DX, g(SI)
-
- // Someday the convention will be D is always cleared.
- CLD
-
- PUSHQ DI // original stack
-
- CALL runtime·stackcheck(SB) // clobbers AX,CX
-
- CALL runtime·mstart(SB)
-
- POPQ DI // original stack
- MOVQ DI, SP
-
- RET
-
-// uint32 tstart_stdcall(M *newm);
-TEXT runtime·tstart_stdcall(SB),7,$0
- MOVQ CX, BX // stdcall first arg in RCX
-
- PUSHQ BX
- CALL runtime·tstart+0(SB)
- POPQ BX
-
- // Adjust stack for stdcall to return properly.
- MOVQ (SP), AX // save return address
- ADDQ $8, SP // remove single parameter
- MOVQ AX, (SP) // restore return address
-
- XORL AX, AX // return 0 == success
-
- RET
-
-TEXT runtime·notok(SB),7,$0
- MOVQ $0xf1, BP
- MOVQ BP, (BP)
- RET
-
-// set tls base to DI
-TEXT runtime·settls(SB),7,$0
- MOVQ DI, 0x58(GS)
- RET
-
diff --git a/src/pkg/runtime/windows/defs.c b/src/pkg/runtime/windows/defs.c
deleted file mode 100644
index 3b2824940..000000000
--- a/src/pkg/runtime/windows/defs.c
+++ /dev/null
@@ -1,37 +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.
-
-#include <signal.h>
-#include <stdarg.h>
-#include <windef.h>
-#include <winbase.h>
-#include <wincon.h>
-
-enum {
- $PROT_NONE = 0,
- $PROT_READ = 1,
- $PROT_WRITE = 2,
- $PROT_EXEC = 4,
-
- $MAP_ANON = 1,
- $MAP_PRIVATE = 2,
-
- $SIGINT = SIGINT,
- $CTRL_C_EVENT = CTRL_C_EVENT,
- $CTRL_BREAK_EVENT = CTRL_BREAK_EVENT,
-
- $EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION,
- $EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT,
- $EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND,
- $EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO,
- $EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT,
- $EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW,
- $EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW,
- $EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO,
- $EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW,
-};
-
-typedef EXCEPTION_RECORD $ExceptionRecord;
-typedef FLOATING_SAVE_AREA $FloatingSaveArea;
-typedef CONTEXT $Context;
diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc
deleted file mode 100644
index 85071e051..000000000
--- a/src/pkg/runtime/windows/syscall.goc
+++ /dev/null
@@ -1,67 +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 syscall
-#include "runtime.h"
-#include "os.h"
-
-func loadlibraryex(filename uintptr) (handle uintptr) {
- uintptr args[3] = { filename };
- handle = runtime·syscall(runtime·LoadLibraryEx, 3, args, nil);
-}
-
-func getprocaddress(handle uintptr, procname uintptr) (proc uintptr) {
- USED(procname);
- proc = runtime·syscall(runtime·GetProcAddress, 2, &handle, nil);
-}
-
-func NewCallback(fn Eface) (code uintptr) {
- code = (uintptr)runtime·compilecallback(fn, true);
-}
-
-func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- USED(a2);
- USED(a3);
- r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
- r2 = 0;
-}
-
-func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- USED(a2);
- USED(a3);
- USED(a4);
- USED(a5);
- USED(a6);
- r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
- r2 = 0;
-}
-
-func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- USED(a2);
- USED(a3);
- USED(a4);
- USED(a5);
- USED(a6);
- USED(a7);
- USED(a8);
- USED(a9);
- r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
- r2 = 0;
-}
-
-func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
- USED(a2);
- USED(a3);
- USED(a4);
- USED(a5);
- USED(a6);
- USED(a7);
- USED(a8);
- USED(a9);
- USED(a10);
- USED(a11);
- USED(a12);
- r1 = runtime·syscall((void*)fn, nargs, &a1, &err);
- r2 = 0;
-}
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
deleted file mode 100644
index e08d1b6f0..000000000
--- a/src/pkg/runtime/windows/thread.c
+++ /dev/null
@@ -1,432 +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.
-
-#include "runtime.h"
-#include "type.h"
-#include "defs.h"
-#include "os.h"
-
-#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
-#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
-#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
-#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
-#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
-#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
-#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
-#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
-#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
-#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
-#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
-#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
-#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-
-extern void *runtime·CloseHandle;
-extern void *runtime·CreateEvent;
-extern void *runtime·CreateThread;
-extern void *runtime·ExitProcess;
-extern void *runtime·FreeEnvironmentStringsW;
-extern void *runtime·GetEnvironmentStringsW;
-extern void *runtime·GetProcAddress;
-extern void *runtime·GetStdHandle;
-extern void *runtime·LoadLibraryEx;
-extern void *runtime·QueryPerformanceCounter;
-extern void *runtime·QueryPerformanceFrequency;
-extern void *runtime·SetConsoleCtrlHandler;
-extern void *runtime·SetEvent;
-extern void *runtime·WaitForSingleObject;
-extern void *runtime·WriteFile;
-
-static int64 timerfreq;
-static void destroylock(Lock *l);
-
-void
-runtime·osinit(void)
-{
- runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
- runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
- runtime·destroylock = destroylock;
-}
-
-void
-runtime·goenvs(void)
-{
- extern Slice os·Envs;
-
- uint16 *env;
- String *s;
- int32 i, n;
- uint16 *p;
-
- env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
-
- n = 0;
- for(p=env; *p; n++)
- p += runtime·findnullw(p)+1;
-
- s = runtime·malloc(n*sizeof s[0]);
-
- p = env;
- for(i=0; i<n; i++) {
- s[i] = runtime·gostringw(p);
- p += runtime·findnullw(p)+1;
- }
- os·Envs.array = (byte*)s;
- os·Envs.len = n;
- os·Envs.cap = n;
-
- runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
-}
-
-void
-runtime·exit(int32 code)
-{
- runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
-}
-
-int32
-runtime·write(int32 fd, void *buf, int32 n)
-{
- void *handle;
- uint32 written;
-
- written = 0;
- switch(fd) {
- case 1:
- handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
- break;
- case 2:
- handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
- break;
- default:
- return -1;
- }
- runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
- return written;
-}
-
-// Thread-safe allocation of an event.
-static void
-initevent(void **pevent)
-{
- void *event;
-
- event = runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
- if(!runtime·casp(pevent, 0, event)) {
- // Someone else filled it in. Use theirs.
- runtime·stdcall(runtime·CloseHandle, 1, event);
- }
-}
-
-static void
-eventlock(Lock *l)
-{
- // Allocate event if needed.
- if(l->event == 0)
- initevent(&l->event);
-
- if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
- runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, (uintptr)-1);
-}
-
-static void
-eventunlock(Lock *l)
-{
- if(runtime·xadd(&l->key, -1) > 0) // someone else is waiting
- runtime·stdcall(runtime·SetEvent, 1, l->event);
-}
-
-void
-runtime·lock(Lock *l)
-{
- if(m->locks < 0)
- runtime·throw("lock count");
- m->locks++;
- eventlock(l);
-}
-
-void
-runtime·unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- runtime·throw("lock count");
- eventunlock(l);
-}
-
-static void
-destroylock(Lock *l)
-{
- if(l->event != 0)
- runtime·stdcall(runtime·CloseHandle, 1, l->event);
-}
-
-void
-runtime·noteclear(Note *n)
-{
- n->lock.key = 0; // memset(n, 0, sizeof *n)
- eventlock(&n->lock);
-}
-
-void
-runtime·notewakeup(Note *n)
-{
- eventunlock(&n->lock);
-}
-
-void
-runtime·notesleep(Note *n)
-{
- eventlock(&n->lock);
- eventunlock(&n->lock); // Let other sleepers find out too.
-}
-
-void
-runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- void *thandle;
-
- USED(stk);
- USED(g); // assuming g = m->g0
- USED(fn); // assuming fn = mstart
-
- thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
- if(thandle == 0) {
- runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
- runtime·throw("runtime.newosproc");
- }
-}
-
-// Called to initialize a new m (including the bootstrap m).
-void
-runtime·minit(void)
-{
-}
-
-void
-runtime·gettime(int64 *sec, int32 *usec)
-{
- int64 count;
-
- runtime·stdcall(runtime·QueryPerformanceCounter, 1, &count);
- *sec = count / timerfreq;
- count %= timerfreq;
- *usec = count*1000000 / timerfreq;
-}
-
-// Calling stdcall on os stack.
-#pragma textflag 7
-void *
-runtime·stdcall(void *fn, int32 count, ...)
-{
- return runtime·stdcall_raw(fn, count, (uintptr*)&count + 1);
-}
-
-uintptr
-runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err)
-{
- G *oldlock;
- uintptr ret;
-
- /*
- * Lock g to m to ensure we stay on the same stack if we do a callback.
- */
- oldlock = m->lockedg;
- m->lockedg = g;
- g->lockedm = m;
-
- runtime·entersyscall();
- runtime·setlasterror(0);
- ret = (uintptr)runtime·stdcall_raw(fn, nargs, args);
- if(err)
- *err = runtime·getlasterror();
- runtime·exitsyscall();
-
- m->lockedg = oldlock;
- if(oldlock == nil)
- g->lockedm = nil;
-
- return ret;
-}
-
-uint32
-runtime·issigpanic(uint32 code)
-{
- switch(code) {
- case EXCEPTION_ACCESS_VIOLATION:
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- case EXCEPTION_INT_OVERFLOW:
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_FLT_INEXACT_RESULT:
- case EXCEPTION_FLT_OVERFLOW:
- case EXCEPTION_FLT_UNDERFLOW:
- return 1;
- }
- return 0;
-}
-
-void
-runtime·sigpanic(void)
-{
- switch(g->sig) {
- case EXCEPTION_ACCESS_VIOLATION:
- if(g->sigcode1 < 0x1000)
- runtime·panicstring("invalid memory address or nil pointer dereference");
- runtime·printf("unexpected fault address %p\n", g->sigcode1);
- runtime·throw("fault");
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- runtime·panicstring("integer divide by zero");
- case EXCEPTION_INT_OVERFLOW:
- runtime·panicstring("integer overflow");
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- case EXCEPTION_FLT_INEXACT_RESULT:
- case EXCEPTION_FLT_OVERFLOW:
- case EXCEPTION_FLT_UNDERFLOW:
- runtime·panicstring("floating point error");
- }
- runtime·throw("fault");
-}
-
-String
-runtime·signame(int32 sig)
-{
- int8 *s;
-
- switch(sig) {
- case SIGINT:
- s = "SIGINT: interrupt";
- break;
- default:
- return runtime·emptystring;
- }
- return runtime·gostringnocopy((byte*)s);
-}
-
-uint32
-runtime·ctrlhandler1(uint32 type)
-{
- int32 s;
-
- switch(type) {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- s = SIGINT;
- break;
- default:
- return 0;
- }
-
- if(runtime·sigsend(s))
- return 1;
- runtime·exit(2); // SIGINT, SIGTERM, etc
- return 0;
-}
-
-// Will keep all callbacks in a linked list, so they don't get garbage collected.
-typedef struct Callback Callback;
-struct Callback {
- Callback* link;
- void* gobody;
- byte asmbody;
-};
-
-typedef struct Callbacks Callbacks;
-struct Callbacks {
- Lock;
- Callback* link;
- int32 n;
-};
-
-static Callbacks cbs;
-
-// Call back from windows dll into go.
-byte *
-runtime·compilecallback(Eface fn, bool cleanstack)
-{
- FuncType *ft;
- Type *t;
- int32 argsize, i, n;
- byte *p;
- Callback *c;
-
- if(fn.type == nil || fn.type->kind != KindFunc)
- runtime·panicstring("compilecallback: not a function");
- ft = (FuncType*)fn.type;
- if(ft->out.len != 1)
- runtime·panicstring("compilecallback: function must have one output parameter");
- if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
- runtime·panicstring("compilecallback: output parameter size is wrong");
- argsize = 0;
- for(i=0; i<ft->in.len; i++) {
- t = ((Type**)ft->in.array)[i];
- if(t->size != sizeof(uintptr))
- runtime·panicstring("compilecallback: input parameter size is wrong");
- argsize += t->size;
- }
-
- // compute size of new fn.
- // must match code laid out below.
- n = 1+4; // MOVL fn, AX
- n += 1+4; // MOVL argsize, DX
- n += 1+4; // MOVL callbackasm, CX
- n += 2; // CALL CX
- n += 1; // RET
- if(cleanstack)
- n += 2; // ... argsize
-
- runtime·lock(&cbs);
- for(c = cbs.link; c != nil; c = c->link) {
- if(c->gobody == fn.data) {
- runtime·unlock(&cbs);
- return &c->asmbody;
- }
- }
- if(cbs.n >= 2000)
- runtime·throw("too many callback functions");
- c = runtime·mal(sizeof *c + n);
- c->gobody = fn.data;
- c->link = cbs.link;
- cbs.link = c;
- cbs.n++;
- runtime·unlock(&cbs);
-
- p = &c->asmbody;
-
- // MOVL fn, AX
- *p++ = 0xb8;
- *(uint32*)p = (uint32)fn.data;
- p += 4;
-
- // MOVL argsize, DX
- *p++ = 0xba;
- *(uint32*)p = argsize;
- p += 4;
-
- // MOVL callbackasm, CX
- *p++ = 0xb9;
- *(uint32*)p = (uint32)runtime·callbackasm;
- p += 4;
-
- // CALL CX
- *p++ = 0xff;
- *p++ = 0xd1;
-
- // RET argsize?
- if(cleanstack) {
- *p++ = 0xc2;
- *(uint16*)p = argsize;
- } else
- *p = 0xc3;
-
- return &c->asmbody;
-}
-
-void
-os·sigpipe(void)
-{
- runtime·throw("too many writes on closed pipe");
-}
diff --git a/src/pkg/scanner/Makefile b/src/pkg/scanner/Makefile
deleted file mode 100644
index db4752513..000000000
--- a/src/pkg/scanner/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=scanner
-GOFILES=\
- scanner.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/smtp/Makefile b/src/pkg/smtp/Makefile
deleted file mode 100644
index 0e7d8d5f7..000000000
--- a/src/pkg/smtp/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=smtp
-GOFILES=\
- auth.go\
- smtp.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/sort/Makefile b/src/pkg/sort/Makefile
deleted file mode 100644
index 9deaabfec..000000000
--- a/src/pkg/sort/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=sort
-GOFILES=\
- search.go\
- sort.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/sort/example_interface_test.go b/src/pkg/sort/example_interface_test.go
new file mode 100644
index 000000000..4c88821be
--- /dev/null
+++ b/src/pkg/sort/example_interface_test.go
@@ -0,0 +1,77 @@
+// 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 sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+type Grams int
+
+func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }
+
+type Organ struct {
+ Name string
+ Weight Grams
+}
+
+type Organs []*Organ
+
+func (s Organs) Len() int { return len(s) }
+func (s Organs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// ByName implements sort.Interface by providing Less and using the Len and
+// Swap methods of the embedded Organs value.
+type ByName struct{ Organs }
+
+func (s ByName) Less(i, j int) bool { return s.Organs[i].Name < s.Organs[j].Name }
+
+// ByWeight implements sort.Interface by providing Less and using the Len and
+// Swap methods of the embedded Organs value.
+type ByWeight struct{ Organs }
+
+func (s ByWeight) Less(i, j int) bool { return s.Organs[i].Weight < s.Organs[j].Weight }
+
+func ExampleInterface() {
+ s := []*Organ{
+ {"brain", 1340},
+ {"heart", 290},
+ {"liver", 1494},
+ {"pancreas", 131},
+ {"prostate", 62},
+ {"spleen", 162},
+ }
+
+ sort.Sort(ByWeight{s})
+ fmt.Println("Organs by weight:")
+ printOrgans(s)
+
+ sort.Sort(ByName{s})
+ fmt.Println("Organs by name:")
+ printOrgans(s)
+
+ // Output:
+ // Organs by weight:
+ // prostate (62g)
+ // pancreas (131g)
+ // spleen (162g)
+ // heart (290g)
+ // brain (1340g)
+ // liver (1494g)
+ // Organs by name:
+ // brain (1340g)
+ // heart (290g)
+ // liver (1494g)
+ // pancreas (131g)
+ // prostate (62g)
+ // spleen (162g)
+}
+
+func printOrgans(s []*Organ) {
+ for _, o := range s {
+ fmt.Printf("%-8s (%v)\n", o.Name, o.Weight)
+ }
+}
diff --git a/src/pkg/sort/example_reverse_test.go b/src/pkg/sort/example_reverse_test.go
new file mode 100644
index 000000000..7c7f05bf3
--- /dev/null
+++ b/src/pkg/sort/example_reverse_test.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.
+
+package sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+// Reverse embeds a sort.Interface value and implements a reverse sort over
+// that value.
+type Reverse struct {
+ // This embedded Interface permits Reverse to use the methods of
+ // another Interface implementation.
+ sort.Interface
+}
+
+// Less returns the opposite of the embedded implementation's Less method.
+func (r Reverse) Less(i, j int) bool {
+ return r.Interface.Less(j, i)
+}
+
+func ExampleInterface_reverse() {
+ s := []int{5, 2, 6, 3, 1, 4} // unsorted
+ sort.Sort(Reverse{sort.IntSlice(s)})
+ fmt.Println(s)
+ // Output: [6 5 4 3 2 1]
+}
diff --git a/src/pkg/sort/example_test.go b/src/pkg/sort/example_test.go
new file mode 100644
index 000000000..f57d02546
--- /dev/null
+++ b/src/pkg/sort/example_test.go
@@ -0,0 +1,17 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+func ExampleInts() {
+ s := []int{5, 2, 6, 3, 1, 4} // unsorted
+ sort.Ints(s)
+ fmt.Println(s)
+ // Output: [1 2 3 4 5 6]
+}
diff --git a/src/pkg/sort/export_test.go b/src/pkg/sort/export_test.go
new file mode 100644
index 000000000..b6e30ceb5
--- /dev/null
+++ b/src/pkg/sort/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+func Heapsort(data Interface) {
+ heapSort(data, 0, data.Len())
+}
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index 0a4a4375f..62a4d55e7 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -37,10 +37,47 @@ func insertionSort(data Interface, a, b int) {
}
}
+// siftDown implements the heap property on data[lo, hi).
+// first is an offset into the array where the root of the heap lies.
+func siftDown(data Interface, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && data.Less(first+child, first+child+1) {
+ child++
+ }
+ if !data.Less(first+root, first+child) {
+ return
+ }
+ data.Swap(first+root, first+child)
+ root = child
+ }
+}
+
+func heapSort(data Interface, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+
+ // Build heap with greatest element at top.
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDown(data, i, hi, first)
+ }
+
+ // Pop elements, largest first, into end of data.
+ for i := hi - 1; i >= 0; i-- {
+ data.Swap(first, first+i)
+ siftDown(data, lo, i, first)
+ }
+}
+
// Quicksort, following Bentley and McIlroy,
// ``Engineering a Sort Function,'' SP&E November 1993.
-// Move the median of the three values data[a], data[b], data[c] into data[a].
+// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
func medianOfThree(data Interface, a, b, c int) {
m0 := b
m1 := a
@@ -123,16 +160,21 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
return lo + b - a, hi - (d - c)
}
-func quickSort(data Interface, a, b int) {
+func quickSort(data Interface, a, b, maxDepth int) {
for b-a > 7 {
+ if maxDepth == 0 {
+ heapSort(data, a, b)
+ return
+ }
+ maxDepth--
mlo, mhi := doPivot(data, a, b)
// Avoiding recursion on the larger subproblem guarantees
// a stack depth of at most lg(b-a).
if mlo-a < b-mhi {
- quickSort(data, a, mlo)
+ quickSort(data, a, mlo, maxDepth)
a = mhi // i.e., quickSort(data, mhi, b)
} else {
- quickSort(data, mhi, b)
+ quickSort(data, mhi, b, maxDepth)
b = mlo // i.e., quickSort(data, a, mlo)
}
}
@@ -141,8 +183,21 @@ func quickSort(data Interface, a, b int) {
}
}
-func Sort(data Interface) { quickSort(data, 0, data.Len()) }
+// Sort sorts data.
+// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
+// data.Less and data.Swap. The sort is not guaranteed to be stable.
+func Sort(data Interface) {
+ // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
+ n := data.Len()
+ maxDepth := 0
+ for i := n; i > 0; i >>= 1 {
+ maxDepth++
+ }
+ maxDepth *= 2
+ quickSort(data, 0, n, maxDepth)
+}
+// IsSorted reports whether data is sorted.
func IsSorted(data Interface) bool {
n := data.Len()
for i := n - 1; i > 0; i-- {
@@ -189,14 +244,18 @@ func (p StringSlice) Sort() { Sort(p) }
// 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/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go
index 5007a92a5..ee8a9d0e8 100644
--- a/src/pkg/sort/sort_test.go
+++ b/src/pkg/sort/sort_test.go
@@ -7,7 +7,7 @@ package sort_test
import (
"fmt"
"math"
- "rand"
+ "math/rand"
. "sort"
"strconv"
"testing"
@@ -169,6 +169,13 @@ func (d *testingData) Swap(i, j int) {
d.data[i], d.data[j] = d.data[j], d.data[i]
}
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
func lg(n int) int {
i := 0
for 1<<uint(i) < n {
@@ -177,7 +184,7 @@ func lg(n int) int {
return i
}
-func TestBentleyMcIlroy(t *testing.T) {
+func testBentleyMcIlroy(t *testing.T, sort func(Interface)) {
sizes := []int{100, 1023, 1024, 1025}
if testing.Short() {
sizes = []int{100, 127, 128, 129}
@@ -253,7 +260,7 @@ func TestBentleyMcIlroy(t *testing.T) {
desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode])
d := &testingData{desc, t, mdata[0:n], n * lg(n) * 12 / 10, 0}
- Sort(d)
+ sort(d)
// If we were testing C qsort, we'd have to make a copy
// of the slice and sort it ourselves and then compare
@@ -274,9 +281,58 @@ func TestBentleyMcIlroy(t *testing.T) {
}
}
-func min(a, b int) int {
- if a < b {
- return a
+func TestSortBM(t *testing.T) {
+ testBentleyMcIlroy(t, Sort)
+}
+
+func TestHeapsortBM(t *testing.T) {
+ testBentleyMcIlroy(t, Heapsort)
+}
+
+// This is based on the "antiquicksort" implementation by M. Douglas McIlroy.
+// See http://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info.
+type adversaryTestingData struct {
+ data []int
+ keys map[int]int
+ candidate int
+}
+
+func (d *adversaryTestingData) Len() int { return len(d.data) }
+
+func (d *adversaryTestingData) Less(i, j int) bool {
+ if _, present := d.keys[i]; !present {
+ if _, present := d.keys[j]; !present {
+ if i == d.candidate {
+ d.keys[i] = len(d.keys)
+ } else {
+ d.keys[j] = len(d.keys)
+ }
+ }
}
- return b
+
+ if _, present := d.keys[i]; !present {
+ d.candidate = i
+ return false
+ }
+ if _, present := d.keys[j]; !present {
+ d.candidate = j
+ return true
+ }
+
+ return d.keys[i] >= d.keys[j]
+}
+
+func (d *adversaryTestingData) Swap(i, j int) {
+ d.data[i], d.data[j] = d.data[j], d.data[i]
+}
+
+func TestAdversary(t *testing.T) {
+ const size = 100
+ data := make([]int, size)
+ for i := 0; i < size; i++ {
+ data[i] = i
+ }
+
+ d := &adversaryTestingData{data, make(map[int]int), 0}
+ Sort(d) // This should degenerate to heapsort.
}
diff --git a/src/pkg/strconv/Makefile b/src/pkg/strconv/Makefile
deleted file mode 100644
index 823355d85..000000000
--- a/src/pkg/strconv/Makefile
+++ /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.
-
-include ../../Make.inc
-
-TARG=strconv
-GOFILES=\
- atob.go\
- atof.go\
- atoi.go\
- decimal.go\
- ftoa.go\
- itoa.go\
- quote.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/strconv/atob.go b/src/pkg/strconv/atob.go
index 98ce75079..d0cb09721 100644
--- a/src/pkg/strconv/atob.go
+++ b/src/pkg/strconv/atob.go
@@ -4,25 +4,32 @@
package strconv
-import "os"
-
-// Atob returns the boolean value represented by the string.
+// ParseBool returns the boolean value represented by the string.
// 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) {
+func ParseBool(str string) (value bool, err error) {
switch str {
case "1", "t", "T", "true", "TRUE", "True":
return true, nil
case "0", "f", "F", "false", "FALSE", "False":
return false, nil
}
- return false, &NumError{str, os.EINVAL}
+ return false, syntaxError("ParseBool", str)
}
-// Btoa returns "true" or "false" according to the value of the boolean argument
-func Btoa(b bool) string {
+// FormatBool returns "true" or "false" according to the value of b
+func FormatBool(b bool) string {
if b {
return "true"
}
return "false"
}
+
+// AppendBool appends "true" or "false", according to the value of b,
+// to dst and returns the extended buffer.
+func AppendBool(dst []byte, b bool) []byte {
+ if b {
+ return append(dst, "true"...)
+ }
+ return append(dst, "false"...)
+}
diff --git a/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
index 541e60d1e..a7c1454eb 100644
--- a/src/pkg/strconv/atob_test.go
+++ b/src/pkg/strconv/atob_test.go
@@ -5,7 +5,6 @@
package strconv_test
import (
- "os"
. "strconv"
"testing"
)
@@ -13,12 +12,12 @@ import (
type atobTest struct {
in string
out bool
- err os.Error
+ err error
}
var atobtests = []atobTest{
- {"", false, os.EINVAL},
- {"asdf", false, os.EINVAL},
+ {"", false, ErrSyntax},
+ {"asdf", false, ErrSyntax},
{"0", false, nil},
{"f", false, nil},
{"F", false, nil},
@@ -33,16 +32,16 @@ var atobtests = []atobTest{
{"True", true, nil},
}
-func TestAtob(t *testing.T) {
+func TestParseBool(t *testing.T) {
for _, test := range atobtests {
- b, e := Atob(test.in)
+ b, e := ParseBool(test.in)
if test.err != nil {
// expect an error
if e == nil {
t.Errorf("%s: expected %s but got nil", test.in, test.err)
} else {
// NumError assertion must succeed; it's the only thing we return.
- if test.err != e.(*NumError).Error {
+ if test.err != e.(*NumError).Err {
t.Errorf("%s: expected %s but got %s", test.in, test.err, e)
}
}
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 38b38053c..cd3031b0e 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -12,10 +12,7 @@ package strconv
// 2) Multiply/divide decimal by powers of two until in range [0.5, 1)
// 3) Multiply by 2^precision and round to get mantissa.
-import (
- "math"
- "os"
-)
+import "math"
var optimize = true // can change for testing
@@ -55,9 +52,10 @@ func special(s string) (f float64, ok bool) {
return
}
-// TODO(rsc): Better truncation handling.
-func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
+func (b *decimal) set(s string) (ok bool) {
i := 0
+ b.neg = false
+ b.trunc = false
// optional sign
if i >= len(s) {
@@ -67,12 +65,11 @@ func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
case s[i] == '+':
i++
case s[i] == '-':
- neg = true
+ b.neg = true
i++
}
// digits
- b := new(decimal)
sawdot := false
sawdigits := false
for ; i < len(s); i++ {
@@ -91,8 +88,12 @@ func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
b.dp--
continue
}
- b.d[b.nd] = s[i]
- b.nd++
+ if b.nd < len(b.d) {
+ b.d[b.nd] = s[i]
+ b.nd++
+ } else if s[i] != '0' {
+ b.trunc = true
+ }
continue
}
break
@@ -137,7 +138,6 @@ func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
return
}
- d = b
ok = true
return
}
@@ -145,7 +145,7 @@ func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
// decimal power of ten to binary power of two.
var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26}
-func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uint64, overflow bool) {
+func (d *decimal) floatBits(flt *floatInfo) (b uint64, overflow bool) {
var exp int
var mant uint64
@@ -209,7 +209,8 @@ func decimalToFloatBits(neg bool, d *decimal, trunc bool, flt *floatInfo) (b uin
}
// Extract 1+flt.mantbits bits.
- mant = d.Shift(int(1 + flt.mantbits)).RoundedInteger()
+ d.Shift(int(1 + flt.mantbits))
+ mant = d.RoundedInteger()
// Rounding might have added a bit; shift down.
if mant == 2<<flt.mantbits {
@@ -236,7 +237,7 @@ out:
// Assemble bits.
bits := mant & (uint64(1)<<flt.mantbits - 1)
bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
- if neg {
+ if d.neg {
bits |= 1 << flt.mantbits << flt.expbits
}
return bits, overflow
@@ -244,28 +245,40 @@ out:
// Compute exact floating-point integer from d's digits.
// Caller is responsible for avoiding overflow.
-func decimalAtof64Int(neg bool, d *decimal) float64 {
+func (d *decimal) atof64int() float64 {
f := 0.0
for i := 0; i < d.nd; i++ {
f = f*10 + float64(d.d[i]-'0')
}
- if neg {
- f *= -1 // BUG work around 6g f = -f.
+ if d.neg {
+ f = -f
}
return f
}
-func decimalAtof32Int(neg bool, d *decimal) float32 {
+func (d *decimal) atof32int() float32 {
f := float32(0)
for i := 0; i < d.nd; i++ {
f = f*10 + float32(d.d[i]-'0')
}
- if neg {
- f *= -1 // BUG work around 6g f = -f.
+ if d.neg {
+ f = -f
}
return f
}
+// Reads a uint64 decimal mantissa, which might be truncated.
+func (d *decimal) atou64() (mant uint64, digits int) {
+ const uint64digits = 19
+ for i, c := range d.d[:d.nd] {
+ if i == uint64digits {
+ return mant, i
+ }
+ mant = 10*mant + uint64(c-'0')
+ }
+ return mant, d.nd
+}
+
// Exact powers of 10.
var float64pow10 = []float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
@@ -281,7 +294,7 @@ var float32pow10 = []float32{1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1
// value is exact integer * exact power of ten
// value is exact integer / exact power of ten
// These all produce potentially inexact but correctly rounded answers.
-func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
+func (d *decimal) atof64() (f float64, ok bool) {
// Exact integers are <= 10^15.
// Exact powers of ten are <= 10^22.
if d.nd > 15 {
@@ -289,11 +302,11 @@ func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
}
switch {
case d.dp == d.nd: // int
- f := decimalAtof64Int(neg, d)
+ f := d.atof64int()
return f, true
case d.dp > d.nd && d.dp <= 15+22: // int * 10^k
- f := decimalAtof64Int(neg, d)
+ f := d.atof64int()
k := d.dp - d.nd
// If exponent is big but number of digits is not,
// can move a few zeros into the integer part.
@@ -304,7 +317,7 @@ func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
return f * float64pow10[k], true
case d.dp < d.nd && d.nd-d.dp <= 22: // int / 10^k
- f := decimalAtof64Int(neg, d)
+ f := d.atof64int()
return f / float64pow10[d.nd-d.dp], true
}
return
@@ -312,7 +325,7 @@ func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
// If possible to convert decimal d to 32-bit float f exactly,
// entirely in floating-point math, do so, avoiding the machinery above.
-func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
+func (d *decimal) atof32() (f float32, ok bool) {
// Exact integers are <= 10^7.
// Exact powers of ten are <= 10^10.
if d.nd > 7 {
@@ -320,11 +333,11 @@ func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
}
switch {
case d.dp == d.nd: // int
- f := decimalAtof32Int(neg, d)
+ f := d.atof32int()
return f, true
case d.dp > d.nd && d.dp <= 7+10: // int * 10^k
- f := decimalAtof32Int(neg, d)
+ f := d.atof32int()
k := d.dp - d.nd
// If exponent is big but number of digits is not,
// can move a few zeros into the integer part.
@@ -335,81 +348,91 @@ func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
return f * float32pow10[k], true
case d.dp < d.nd && d.nd-d.dp <= 10: // int / 10^k
- f := decimalAtof32Int(neg, d)
+ f := d.atof32int()
return f / float32pow10[d.nd-d.dp], true
}
return
}
-// Atof32 converts the string s to a 32-bit floating-point number.
-//
-// If s is well-formed and near a valid floating point number,
-// Atof32 returns the nearest floating point number rounded
-// using IEEE754 unbiased rounding.
-//
-// The errors that Atof32 returns have concrete type *NumError
-// and include err.Num = s.
-//
-// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL.
-//
-// If s is syntactically well-formed but is more than 1/2 ULP
-// away from the largest floating point number of the given size,
-// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
-func Atof32(s string) (f float32, err os.Error) {
+const fnParseFloat = "ParseFloat"
+
+func atof32(s string) (f float32, err error) {
if val, ok := special(s); ok {
return float32(val), nil
}
- neg, d, trunc, ok := stringToDecimal(s)
- if !ok {
- return 0, &NumError{s, os.EINVAL}
+ var d decimal
+ if !d.set(s) {
+ return 0, syntaxError(fnParseFloat, s)
}
if optimize {
- if f, ok := decimalAtof32(neg, d, trunc); ok {
+ if f, ok := d.atof32(); ok {
return f, nil
}
}
- b, ovf := decimalToFloatBits(neg, d, trunc, &float32info)
+ b, ovf := d.floatBits(&float32info)
f = math.Float32frombits(uint32(b))
if ovf {
- err = &NumError{s, os.ERANGE}
+ err = rangeError(fnParseFloat, s)
}
return f, err
}
-// Atof64 converts the string s to a 64-bit floating-point number.
-// Except for the type of its result, its definition is the same as that
-// of Atof32.
-func Atof64(s string) (f float64, err os.Error) {
+func atof64(s string) (f float64, err error) {
if val, ok := special(s); ok {
return val, nil
}
- neg, d, trunc, ok := stringToDecimal(s)
- if !ok {
- return 0, &NumError{s, os.EINVAL}
+ var d decimal
+ if !d.set(s) {
+ return 0, syntaxError(fnParseFloat, s)
}
if optimize {
- if f, ok := decimalAtof64(neg, d, trunc); ok {
+ if f, ok := d.atof64(); ok {
return f, nil
}
+
+ // Try another fast path.
+ ext := new(extFloat)
+ if ok := ext.AssignDecimal(&d); ok {
+ b, ovf := ext.floatBits()
+ f = math.Float64frombits(b)
+ if ovf {
+ err = rangeError(fnParseFloat, s)
+ }
+ return f, err
+ }
}
- b, ovf := decimalToFloatBits(neg, d, trunc, &float64info)
+ b, ovf := d.floatBits(&float64info)
f = math.Float64frombits(b)
if ovf {
- err = &NumError{s, os.ERANGE}
+ err = rangeError(fnParseFloat, s)
}
return f, err
}
-// AtofN converts the string s to a 64-bit floating-point number,
-// but it rounds the result assuming that it will be stored in a value
-// of n bits (32 or 64).
-func AtofN(s string, n int) (f float64, err os.Error) {
- if n == 32 {
- f1, err1 := Atof32(s)
+// ParseFloat converts the string s to a floating-point number
+// with the precision specified by bitSize: 32 for float32, or 64 for float64.
+// When bitSize=32, the result still has type float64, but it will be
+// convertible to float32 without changing its value.
+//
+// If s is well-formed and near a valid floating point number,
+// ParseFloat returns the nearest floating point number rounded
+// using IEEE754 unbiased rounding.
+//
+// The errors that ParseFloat returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, ParseFloat returns err.Error = ErrSyntax.
+//
+// If s is syntactically well-formed but is more than 1/2 ULP
+// away from the largest floating point number of the given size,
+// ParseFloat returns f = ±Inf, err.Error = ErrRange.
+func ParseFloat(s string, bitSize int) (f float64, err error) {
+ if bitSize == 32 {
+ f1, err1 := atof32(s)
return float64(f1), err1
}
- f1, err1 := Atof64(s)
+ f1, err1 := atof64(s)
return f1, err1
}
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
index 0fdd0ea98..599502382 100644
--- a/src/pkg/strconv/atof_test.go
+++ b/src/pkg/strconv/atof_test.go
@@ -5,24 +5,27 @@
package strconv_test
import (
- "os"
+ "math"
+ "math/rand"
"reflect"
. "strconv"
+ "strings"
"testing"
+ "time"
)
type atofTest struct {
in string
out string
- err os.Error
+ err error
}
var atoftests = []atofTest{
- {"", "0", os.EINVAL},
+ {"", "0", ErrSyntax},
{"1", "1", nil},
{"+1", "1", nil},
- {"1x", "0", os.EINVAL},
- {"1.1.", "0", os.EINVAL},
+ {"1x", "0", ErrSyntax},
+ {"1.1.", "0", ErrSyntax},
{"1e23", "1e+23", nil},
{"1E23", "1e+23", nil},
{"100000000000000000000000", "1e+23", nil},
@@ -34,6 +37,7 @@ var atoftests = []atofTest{
{"100000000000000016777215", "1.0000000000000001e+23", nil},
{"100000000000000016777216", "1.0000000000000003e+23", nil},
{"-1", "-1", nil},
+ {"-0.1", "-0.1", nil},
{"-0", "-0", nil},
{"1e-20", "1e-20", nil},
{"625e-3", "0.625", nil},
@@ -55,28 +59,28 @@ var atoftests = []atofTest{
{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
{"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
// next float64 - too large
- {"1.7976931348623159e308", "+Inf", os.ERANGE},
- {"-1.7976931348623159e308", "-Inf", os.ERANGE},
+ {"1.7976931348623159e308", "+Inf", ErrRange},
+ {"-1.7976931348623159e308", "-Inf", ErrRange},
// the border is ...158079
// borderline - okay
{"1.7976931348623158e308", "1.7976931348623157e+308", nil},
{"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
// borderline - too large
- {"1.797693134862315808e308", "+Inf", os.ERANGE},
- {"-1.797693134862315808e308", "-Inf", os.ERANGE},
+ {"1.797693134862315808e308", "+Inf", ErrRange},
+ {"-1.797693134862315808e308", "-Inf", ErrRange},
// a little too large
{"1e308", "1e+308", nil},
- {"2e308", "+Inf", os.ERANGE},
- {"1e309", "+Inf", os.ERANGE},
+ {"2e308", "+Inf", ErrRange},
+ {"1e309", "+Inf", ErrRange},
// way too large
- {"1e310", "+Inf", os.ERANGE},
- {"-1e310", "-Inf", os.ERANGE},
- {"1e400", "+Inf", os.ERANGE},
- {"-1e400", "-Inf", os.ERANGE},
- {"1e400000", "+Inf", os.ERANGE},
- {"-1e400000", "-Inf", os.ERANGE},
+ {"1e310", "+Inf", ErrRange},
+ {"-1e310", "-Inf", ErrRange},
+ {"1e400", "+Inf", ErrRange},
+ {"-1e400", "-Inf", ErrRange},
+ {"1e400000", "+Inf", ErrRange},
+ {"-1e400000", "-Inf", ErrRange},
// denormalized
{"1e-305", "1e-305", nil},
@@ -98,63 +102,106 @@ var atoftests = []atofTest{
// try to overflow exponent
{"1e-4294967296", "0", nil},
- {"1e+4294967296", "+Inf", os.ERANGE},
+ {"1e+4294967296", "+Inf", ErrRange},
{"1e-18446744073709551616", "0", nil},
- {"1e+18446744073709551616", "+Inf", os.ERANGE},
+ {"1e+18446744073709551616", "+Inf", ErrRange},
// Parse errors
- {"1e", "0", os.EINVAL},
- {"1e-", "0", os.EINVAL},
- {".e-1", "0", os.EINVAL},
+ {"1e", "0", ErrSyntax},
+ {"1e-", "0", ErrSyntax},
+ {".e-1", "0", ErrSyntax},
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
{"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
{"2.2250738585072011e-308", "2.225073858507201e-308", nil},
+
+ // A very large number (initially wrongly parsed by the fast algorithm).
+ {"4.630813248087435e+307", "4.630813248087435e+307", nil},
+
+ // A different kind of very large number.
+ {"22.222222222222222", "22.22222222222222", nil},
+ {"2." + strings.Repeat("2", 4000) + "e+1", "22.22222222222222", nil},
+
+ // Exactly halfway between 1 and math.Nextafter(1, 2).
+ // Round to even (down).
+ {"1.00000000000000011102230246251565404236316680908203125", "1", nil},
+ // Slightly lower; still round down.
+ {"1.00000000000000011102230246251565404236316680908203124", "1", nil},
+ // Slightly higher; round up.
+ {"1.00000000000000011102230246251565404236316680908203126", "1.0000000000000002", nil},
+ // Slightly higher, but you have to read all the way to the end.
+ {"1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", "1.0000000000000002", nil},
}
+type atofSimpleTest struct {
+ x float64
+ s string
+}
+
+var (
+ atofRandomTests []atofSimpleTest
+ benchmarksRandomBits [1024]string
+ benchmarksRandomNormal [1024]string
+)
+
func init() {
// The atof routines return NumErrors wrapping
// the error and the string. Convert the table above.
for i := range atoftests {
test := &atoftests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseFloat", test.in, test.err}
}
}
+
+ // Generate random inputs for tests and benchmarks
+ rand.Seed(time.Now().UnixNano())
+ if testing.Short() {
+ atofRandomTests = make([]atofSimpleTest, 100)
+ } else {
+ atofRandomTests = make([]atofSimpleTest, 10000)
+ }
+ for i := range atofRandomTests {
+ n := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ x := math.Float64frombits(n)
+ s := FormatFloat(x, 'g', -1, 64)
+ atofRandomTests[i] = atofSimpleTest{x, s}
+ }
+
+ for i := range benchmarksRandomBits {
+ bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ x := math.Float64frombits(bits)
+ benchmarksRandomBits[i] = FormatFloat(x, 'g', -1, 64)
+ }
+
+ for i := range benchmarksRandomNormal {
+ x := rand.NormFloat64()
+ benchmarksRandomNormal[i] = FormatFloat(x, 'g', -1, 64)
+ }
}
func testAtof(t *testing.T, opt bool) {
oldopt := SetOptimize(opt)
for i := 0; i < len(atoftests); i++ {
test := &atoftests[i]
- out, err := Atof64(test.in)
- outs := Ftoa64(out, 'g', -1)
- if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("Atof64(%v) = %v, %v want %v, %v",
- test.in, out, err, test.out, test.err)
- }
-
- out, err = AtofN(test.in, 64)
- outs = FtoaN(out, 'g', -1, 64)
+ out, err := ParseFloat(test.in, 64)
+ outs := FormatFloat(out, 'g', -1, 64)
if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v",
+ t.Errorf("ParseFloat(%v, 64) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
if float64(float32(out)) == out {
- out32, err := Atof32(test.in)
- outs := Ftoa32(out32, 'g', -1)
- if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("Atof32(%v) = %v, %v want %v, %v # %v",
- test.in, out32, err, test.out, test.err, out)
+ out, err := ParseFloat(test.in, 32)
+ out32 := float32(out)
+ if float64(out32) != out {
+ t.Errorf("ParseFloat(%v, 32) = %v, not a float32 (closest is %v)", test.in, out, float64(out32))
+ continue
}
-
- out, err := AtofN(test.in, 32)
- out32 = float32(out)
- outs = FtoaN(float64(out32), 'g', -1, 32)
+ outs := FormatFloat(float64(out32), 'g', -1, 32)
if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v",
+ t.Errorf("ParseFloat(%v, 32) = %v, %v want %v, %v # %v",
test.in, out32, err, test.out, test.err, out)
}
}
@@ -166,26 +213,89 @@ func TestAtof(t *testing.T) { testAtof(t, true) }
func TestAtofSlow(t *testing.T) { testAtof(t, false) }
+func TestAtofRandom(t *testing.T) {
+ for _, test := range atofRandomTests {
+ x, _ := ParseFloat(test.s, 64)
+ switch {
+ default:
+ t.Errorf("number %s badly parsed as %b (expected %b)", test.s, x, test.x)
+ case x == test.x:
+ case math.IsNaN(test.x) && math.IsNaN(x):
+ }
+ }
+ t.Logf("tested %d random numbers", len(atofRandomTests))
+}
+
+var roundTripCases = []struct {
+ f float64
+ s string
+}{
+ // Issue 2917.
+ // This test will break the optimized conversion if the
+ // FPU is using 80-bit registers instead of 64-bit registers,
+ // usually because the operating system initialized the
+ // thread with 80-bit precision and the Go runtime didn't
+ // fix the FP control word.
+ {8865794286000691 << 39, "4.87402195346389e+27"},
+ {8865794286000692 << 39, "4.8740219534638903e+27"},
+}
+
+func TestRoundTrip(t *testing.T) {
+ for _, tt := range roundTripCases {
+ old := SetOptimize(false)
+ s := FormatFloat(tt.f, 'g', -1, 64)
+ if s != tt.s {
+ t.Errorf("no-opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s)
+ }
+ f, err := ParseFloat(tt.s, 64)
+ if f != tt.f || err != nil {
+ t.Errorf("no-opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f)
+ }
+ SetOptimize(true)
+ s = FormatFloat(tt.f, 'g', -1, 64)
+ if s != tt.s {
+ t.Errorf("opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s)
+ }
+ f, err = ParseFloat(tt.s, 64)
+ if f != tt.f || err != nil {
+ t.Errorf("opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f)
+ }
+ SetOptimize(old)
+ }
+}
+
func BenchmarkAtof64Decimal(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atof64("33909")
+ ParseFloat("33909", 64)
}
}
func BenchmarkAtof64Float(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atof64("339.7784")
+ ParseFloat("339.7784", 64)
}
}
func BenchmarkAtof64FloatExp(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atof64("-5.09e75")
+ ParseFloat("-5.09e75", 64)
}
}
func BenchmarkAtof64Big(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atof64("123456789123456789123456789")
+ ParseFloat("123456789123456789123456789", 64)
+ }
+}
+
+func BenchmarkAtof64RandomBits(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ParseFloat(benchmarksRandomBits[i%1024], 64)
+ }
+}
+
+func BenchmarkAtof64RandomFloats(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ParseFloat(benchmarksRandomNormal[i%1024], 64)
}
}
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index 584594216..59ef264d1 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -4,24 +4,36 @@
package strconv
-import "os"
+import "errors"
+// ErrRange indicates that a value is out of range for the target type.
+var ErrRange = errors.New("value out of range")
+
+// ErrSyntax indicates that a value does not have the right syntax for the target type.
+var ErrSyntax = errors.New("invalid syntax")
+
+// A NumError records a failed conversion.
type NumError struct {
- Num string
- Error os.Error
+ Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
+ Num string // the input
+ Err error // the reason the conversion failed (ErrRange, ErrSyntax)
+}
+
+func (e *NumError) Error() string {
+ return "strconv." + e.Func + ": " + `parsing "` + e.Num + `": ` + e.Err.Error()
}
-func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
+func syntaxError(fn, str string) *NumError {
+ return &NumError{fn, str, ErrSyntax}
+}
-func computeIntsize() uint {
- siz := uint(8)
- for 1<<siz != 0 {
- siz *= 2
- }
- return siz
+func rangeError(fn, str string) *NumError {
+ return &NumError{fn, str, ErrRange}
}
-var IntSize = computeIntsize()
+const intSize = 32 << uint(^uint(0)>>63)
+
+const IntSize = intSize // number of bits in int, uint (32 or 64)
// Return the first number n such that n*base >= 1<<64.
func cutoff64(base int) uint64 {
@@ -31,22 +43,18 @@ func cutoff64(base int) uint64 {
return (1<<64-1)/uint64(base) + 1
}
-// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
-// and returns the corresponding value n. If b == 0, the base
-// is taken from the string prefix: base 16 for "0x", base 8 for "0",
-// and base 10 otherwise.
-//
-// The errors that Btoui64 returns have concrete type *NumError
-// and include err.Num = s. If s is empty or contains invalid
-// digits, err.Error = os.EINVAL; if the value corresponding
-// to s cannot be represented by a uint64, err.Error = os.ERANGE.
-func Btoui64(s string, b int) (n uint64, err os.Error) {
- var cutoff uint64
+// ParseUint is like ParseInt but for unsigned numbers.
+func ParseUint(s string, b int, bitSize int) (n uint64, err error) {
+ var cutoff, maxVal uint64
+
+ if bitSize == 0 {
+ bitSize = int(IntSize)
+ }
s0 := s
switch {
case len(s) < 1:
- err = os.EINVAL
+ err = ErrSyntax
goto Error
case 2 <= b && b <= 36:
@@ -59,7 +67,7 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
b = 16
s = s[2:]
if len(s) < 1 {
- err = os.EINVAL
+ err = ErrSyntax
goto Error
}
case s[0] == '0':
@@ -69,12 +77,13 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
}
default:
- err = os.NewError("invalid base " + Itoa(b))
+ err = errors.New("invalid base " + Itoa(b))
goto Error
}
n = 0
cutoff = cutoff64(b)
+ maxVal = 1<<uint(bitSize) - 1
for i := 0; i < len(s); i++ {
var v byte
@@ -88,28 +97,28 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
v = d - 'A' + 10
default:
n = 0
- err = os.EINVAL
+ err = ErrSyntax
goto Error
}
if int(v) >= b {
n = 0
- err = os.EINVAL
+ err = ErrSyntax
goto Error
}
if n >= cutoff {
// n*b overflows
n = 1<<64 - 1
- err = os.ERANGE
+ err = ErrRange
goto Error
}
n *= uint64(b)
n1 := n + uint64(v)
- if n1 < n {
+ if n1 < n || n1 > maxVal {
// n+v overflows
n = 1<<64 - 1
- err = os.ERANGE
+ err = ErrRange
goto Error
}
n = n1
@@ -118,24 +127,33 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
return n, nil
Error:
- return n, &NumError{s0, err}
+ return n, &NumError{"ParseUint", s0, err}
}
-// Atoui64 interprets a string s as a decimal number and
-// returns the corresponding value n.
+// ParseInt interprets a string s in the given base (2 to 36) and
+// returns the corresponding value i. If base == 0, the base is
+// implied by the string's prefix: base 16 for "0x", base 8 for
+// "0", and base 10 otherwise.
//
-// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits.
-// It returns err == os.ERANGE if s cannot be represented by a uint64.
-func Atoui64(s string) (n uint64, err os.Error) {
- return Btoui64(s, 10)
-}
+// The bitSize argument specifies the integer type
+// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
+// correspond to int, int8, int16, int32, and int64.
+//
+// The errors that ParseInt returns have concrete type *NumError
+// and include err.Num = s. If s is empty or contains invalid
+// digits, err.Error = ErrSyntax; if the value corresponding
+// to s cannot be represented by a signed integer of the
+// given size, err.Error = ErrRange.
+func ParseInt(s string, base int, bitSize int) (i int64, err error) {
+ const fnParseInt = "ParseInt"
+
+ if bitSize == 0 {
+ bitSize = int(IntSize)
+ }
-// Btoi64 is like Btoui64 but allows signed numbers and
-// returns its result in an int64.
-func Btoi64(s string, base int) (i int64, err os.Error) {
// Empty string bad.
if len(s) == 0 {
- return 0, &NumError{s, os.EINVAL}
+ return 0, syntaxError(fnParseInt, s)
}
// Pick off leading sign.
@@ -150,16 +168,18 @@ func Btoi64(s string, base int) (i int64, err os.Error) {
// Convert unsigned and check range.
var un uint64
- un, err = Btoui64(s, base)
- if err != nil && err.(*NumError).Error != os.ERANGE {
+ un, err = ParseUint(s, base, bitSize)
+ if err != nil && err.(*NumError).Err != ErrRange {
+ err.(*NumError).Func = fnParseInt
err.(*NumError).Num = s0
return 0, err
}
- if !neg && un >= 1<<63 {
- return 1<<63 - 1, &NumError{s0, os.ERANGE}
+ cutoff := uint64(1 << uint(bitSize-1))
+ if !neg && un >= cutoff {
+ return int64(cutoff - 1), rangeError(fnParseInt, s0)
}
- if neg && un > 1<<63 {
- return -1 << 63, &NumError{s0, os.ERANGE}
+ if neg && un > cutoff {
+ return -int64(cutoff), rangeError(fnParseInt, s0)
}
n := int64(un)
if neg {
@@ -168,35 +188,8 @@ func Btoi64(s string, base int) (i int64, err os.Error) {
return n, nil
}
-// Atoi64 is like Atoui64 but allows signed numbers and
-// returns its result in an int64.
-func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
-
-// Atoui is like Atoui64 but returns its result as a uint.
-func Atoui(s string) (i uint, err os.Error) {
- i1, e1 := Atoui64(s)
- if e1 != nil && e1.(*NumError).Error != os.ERANGE {
- return 0, e1
- }
- i = uint(i1)
- if uint64(i) != i1 {
- return ^uint(0), &NumError{s, os.ERANGE}
- }
- return i, nil
-}
-
-// Atoi is like Atoi64 but returns its result as an int.
-func Atoi(s string) (i int, err os.Error) {
- i1, e1 := Atoi64(s)
- if e1 != nil && e1.(*NumError).Error != os.ERANGE {
- return 0, e1
- }
- i = int(i1)
- if int64(i) != i1 {
- if i1 < 0 {
- return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
- }
- return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
- }
- return i, nil
+// Atoi is shorthand for ParseInt(s, 10, 0).
+func Atoi(s string) (i int, err error) {
+ i64, err := ParseInt(s, 10, 0)
+ return int(i64), err
}
diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go
index 0b9f29553..d0e7b61db 100644
--- a/src/pkg/strconv/atoi_test.go
+++ b/src/pkg/strconv/atoi_test.go
@@ -5,7 +5,6 @@
package strconv_test
import (
- "os"
"reflect"
. "strconv"
"testing"
@@ -14,51 +13,51 @@ import (
type atoui64Test struct {
in string
out uint64
- err os.Error
+ err error
}
var atoui64tests = []atoui64Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"1", 1, nil},
{"12345", 12345, nil},
{"012345", 12345, nil},
- {"12345x", 0, os.EINVAL},
+ {"12345x", 0, ErrSyntax},
{"98765432100", 98765432100, nil},
{"18446744073709551615", 1<<64 - 1, nil},
- {"18446744073709551616", 1<<64 - 1, os.ERANGE},
- {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551616", 1<<64 - 1, ErrRange},
+ {"18446744073709551620", 1<<64 - 1, ErrRange},
}
var btoui64tests = []atoui64Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"1", 1, nil},
{"12345", 12345, nil},
{"012345", 012345, nil},
{"0x12345", 0x12345, nil},
{"0X12345", 0x12345, nil},
- {"12345x", 0, os.EINVAL},
+ {"12345x", 0, ErrSyntax},
{"98765432100", 98765432100, nil},
{"18446744073709551615", 1<<64 - 1, nil},
- {"18446744073709551616", 1<<64 - 1, os.ERANGE},
- {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551616", 1<<64 - 1, ErrRange},
+ {"18446744073709551620", 1<<64 - 1, ErrRange},
{"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
- {"0x10000000000000000", 1<<64 - 1, os.ERANGE},
+ {"0x10000000000000000", 1<<64 - 1, ErrRange},
{"01777777777777777777777", 1<<64 - 1, nil},
- {"01777777777777777777778", 0, os.EINVAL},
- {"02000000000000000000000", 1<<64 - 1, os.ERANGE},
+ {"01777777777777777777778", 0, ErrSyntax},
+ {"02000000000000000000000", 1<<64 - 1, ErrRange},
{"0200000000000000000000", 1 << 61, nil},
}
type atoi64Test struct {
in string
out int64
- err os.Error
+ err error
}
var atoi64tests = []atoi64Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"-0", 0, nil},
{"1", 1, nil},
@@ -71,14 +70,14 @@ var atoi64tests = []atoi64Test{
{"-98765432100", -98765432100, nil},
{"9223372036854775807", 1<<63 - 1, nil},
{"-9223372036854775807", -(1<<63 - 1), nil},
- {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"9223372036854775808", 1<<63 - 1, ErrRange},
{"-9223372036854775808", -1 << 63, nil},
- {"9223372036854775809", 1<<63 - 1, os.ERANGE},
- {"-9223372036854775809", -1 << 63, os.ERANGE},
+ {"9223372036854775809", 1<<63 - 1, ErrRange},
+ {"-9223372036854775809", -1 << 63, ErrRange},
}
var btoi64tests = []atoi64Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"-0", 0, nil},
{"1", 1, nil},
@@ -89,44 +88,44 @@ var btoi64tests = []atoi64Test{
{"-012345", -012345, nil},
{"0x12345", 0x12345, nil},
{"-0X12345", -0x12345, nil},
- {"12345x", 0, os.EINVAL},
- {"-12345x", 0, os.EINVAL},
+ {"12345x", 0, ErrSyntax},
+ {"-12345x", 0, ErrSyntax},
{"98765432100", 98765432100, nil},
{"-98765432100", -98765432100, nil},
{"9223372036854775807", 1<<63 - 1, nil},
{"-9223372036854775807", -(1<<63 - 1), nil},
- {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"9223372036854775808", 1<<63 - 1, ErrRange},
{"-9223372036854775808", -1 << 63, nil},
- {"9223372036854775809", 1<<63 - 1, os.ERANGE},
- {"-9223372036854775809", -1 << 63, os.ERANGE},
+ {"9223372036854775809", 1<<63 - 1, ErrRange},
+ {"-9223372036854775809", -1 << 63, ErrRange},
}
type atoui32Test struct {
in string
out uint32
- err os.Error
+ err error
}
var atoui32tests = []atoui32Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"1", 1, nil},
{"12345", 12345, nil},
{"012345", 12345, nil},
- {"12345x", 0, os.EINVAL},
+ {"12345x", 0, ErrSyntax},
{"987654321", 987654321, nil},
{"4294967295", 1<<32 - 1, nil},
- {"4294967296", 1<<32 - 1, os.ERANGE},
+ {"4294967296", 1<<32 - 1, ErrRange},
}
type atoi32Test struct {
in string
out int32
- err os.Error
+ err error
}
var atoi32tests = []atoi32Test{
- {"", 0, os.EINVAL},
+ {"", 0, ErrSyntax},
{"0", 0, nil},
{"-0", 0, nil},
{"1", 1, nil},
@@ -135,16 +134,16 @@ var atoi32tests = []atoi32Test{
{"-12345", -12345, nil},
{"012345", 12345, nil},
{"-012345", -12345, nil},
- {"12345x", 0, os.EINVAL},
- {"-12345x", 0, os.EINVAL},
+ {"12345x", 0, ErrSyntax},
+ {"-12345x", 0, ErrSyntax},
{"987654321", 987654321, nil},
{"-987654321", -987654321, nil},
{"2147483647", 1<<31 - 1, nil},
{"-2147483647", -(1<<31 - 1), nil},
- {"2147483648", 1<<31 - 1, os.ERANGE},
+ {"2147483648", 1<<31 - 1, ErrRange},
{"-2147483648", -1 << 31, nil},
- {"2147483649", 1<<31 - 1, os.ERANGE},
- {"-2147483649", -1 << 31, os.ERANGE},
+ {"2147483649", 1<<31 - 1, ErrRange},
+ {"-2147483649", -1 << 31, ErrRange},
}
func init() {
@@ -153,45 +152,45 @@ func init() {
for i := range atoui64tests {
test := &atoui64tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseUint", test.in, test.err}
}
}
for i := range btoui64tests {
test := &btoui64tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseUint", test.in, test.err}
}
}
for i := range atoi64tests {
test := &atoi64tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseInt", test.in, test.err}
}
}
for i := range btoi64tests {
test := &btoi64tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseInt", test.in, test.err}
}
}
for i := range atoui32tests {
test := &atoui32tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseUint", test.in, test.err}
}
}
for i := range atoi32tests {
test := &atoi32tests[i]
if test.err != nil {
- test.err = &NumError{test.in, test.err}
+ test.err = &NumError{"ParseInt", test.in, test.err}
}
}
}
-func TestAtoui64(t *testing.T) {
+func TestParseUint64(t *testing.T) {
for i := range atoui64tests {
test := &atoui64tests[i]
- out, err := Atoui64(test.in)
+ out, err := ParseUint(test.in, 10, 64)
if test.out != out || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -199,21 +198,21 @@ func TestAtoui64(t *testing.T) {
}
}
-func TestBtoui64(t *testing.T) {
+func TestParseUint64Base(t *testing.T) {
for i := range btoui64tests {
test := &btoui64tests[i]
- out, err := Btoui64(test.in, 0)
+ out, err := ParseUint(test.in, 0, 64)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Btoui64(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseUint(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
}
-func TestAtoi64(t *testing.T) {
+func TestParseInt64(t *testing.T) {
for i := range atoi64tests {
test := &atoi64tests[i]
- out, err := Atoi64(test.in)
+ out, err := ParseInt(test.in, 10, 64)
if test.out != out || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -221,23 +220,23 @@ func TestAtoi64(t *testing.T) {
}
}
-func TestBtoi64(t *testing.T) {
+func TestParseInt64Base(t *testing.T) {
for i := range btoi64tests {
test := &btoi64tests[i]
- out, err := Btoi64(test.in, 0)
+ out, err := ParseInt(test.in, 0, 64)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Btoi64(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
}
-func TestAtoui(t *testing.T) {
+func TestParseUint(t *testing.T) {
switch IntSize {
case 32:
for i := range atoui32tests {
test := &atoui32tests[i]
- out, err := Atoui(test.in)
+ out, err := ParseUint(test.in, 10, 0)
if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoui(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -246,7 +245,7 @@ func TestAtoui(t *testing.T) {
case 64:
for i := range atoui64tests {
test := &atoui64tests[i]
- out, err := Atoui(test.in)
+ out, err := ParseUint(test.in, 10, 0)
if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoui(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -255,12 +254,12 @@ func TestAtoui(t *testing.T) {
}
}
-func TestAtoi(t *testing.T) {
+func TestParseInt(t *testing.T) {
switch IntSize {
case 32:
for i := range atoi32tests {
test := &atoi32tests[i]
- out, err := Atoi(test.in)
+ out, err := ParseInt(test.in, 10, 0)
if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoi(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -269,7 +268,7 @@ func TestAtoi(t *testing.T) {
case 64:
for i := range atoi64tests {
test := &atoi64tests[i]
- out, err := Atoi(test.in)
+ out, err := ParseInt(test.in, 10, 0)
if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("Atoi(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
@@ -280,24 +279,24 @@ func TestAtoi(t *testing.T) {
func BenchmarkAtoi(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atoi("12345678")
+ ParseInt("12345678", 10, 0)
}
}
func BenchmarkAtoiNeg(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atoi("-12345678")
+ ParseInt("-12345678", 10, 0)
}
}
func BenchmarkAtoi64(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atoi64("12345678901234")
+ ParseInt("12345678901234", 10, 64)
}
}
func BenchmarkAtoi64Neg(b *testing.B) {
for i := 0; i < b.N; i++ {
- Atoi64("-12345678901234")
+ ParseInt("-12345678901234", 10, 64)
}
}
diff --git a/src/pkg/strconv/decimal.go b/src/pkg/strconv/decimal.go
index 783065bfb..a75071dcc 100644
--- a/src/pkg/strconv/decimal.go
+++ b/src/pkg/strconv/decimal.go
@@ -12,11 +12,11 @@
package strconv
type decimal struct {
- // TODO(rsc): Can make d[] a bit smaller and add
- // truncated bool;
- d [2000]byte // digits
- nd int // number of digits used
- dp int // decimal point
+ d [800]byte // digits
+ nd int // number of digits used
+ dp int // decimal point
+ neg bool
+ trunc bool // discarded nonzero digits beyond d[:nd]
}
func (a *decimal) String() string {
@@ -101,12 +101,6 @@ func (a *decimal) Assign(v uint64) {
trim(a)
}
-func newDecimal(i uint64) *decimal {
- a := new(decimal)
- a.Assign(i)
- return a
-}
-
// Maximum shift that we can do in one pass without overflow.
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
const maxShift = 27
@@ -150,8 +144,12 @@ func rightShift(a *decimal, k uint) {
for n > 0 {
dig := n >> k
n -= dig << k
- a.d[w] = byte(dig + '0')
- w++
+ if w < len(a.d) {
+ a.d[w] = byte(dig + '0')
+ w++
+ } else if dig > 0 {
+ a.trunc = true
+ }
n = n * 10
}
@@ -247,7 +245,11 @@ func leftShift(a *decimal, k uint) {
quo := n / 10
rem := n - 10*quo
w--
- a.d[w] = byte(rem + '0')
+ if w < len(a.d) {
+ a.d[w] = byte(rem + '0')
+ } else if rem != 0 {
+ a.trunc = true
+ }
n = quo
}
@@ -256,18 +258,24 @@ func leftShift(a *decimal, k uint) {
quo := n / 10
rem := n - 10*quo
w--
- a.d[w] = byte(rem + '0')
+ if w < len(a.d) {
+ a.d[w] = byte(rem + '0')
+ } else if rem != 0 {
+ a.trunc = true
+ }
n = quo
}
a.nd += delta
+ if a.nd >= len(a.d) {
+ a.nd = len(a.d)
+ }
a.dp += delta
trim(a)
}
// Binary shift left (k > 0) or right (k < 0).
-// Returns receiver for convenience.
-func (a *decimal) Shift(k int) *decimal {
+func (a *decimal) Shift(k int) {
switch {
case a.nd == 0:
// nothing to do: a == 0
@@ -284,7 +292,6 @@ func (a *decimal) Shift(k int) *decimal {
}
rightShift(a, uint(-k))
}
- return a
}
// If we chop a at nd digits, should we round up?
@@ -293,6 +300,10 @@ func shouldRoundUp(a *decimal, nd int) bool {
return false
}
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
+ // if we truncated, a little higher than what's recorded - always round up
+ if a.trunc {
+ return true
+ }
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
}
// not halfway - digit tells all
@@ -300,36 +311,33 @@ func shouldRoundUp(a *decimal, nd int) bool {
}
// Round a to nd digits (or fewer).
-// Returns receiver for convenience.
// If nd is zero, it means we're rounding
// just to the left of the digits, as in
// 0.09 -> 0.1.
-func (a *decimal) Round(nd int) *decimal {
+func (a *decimal) Round(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
if shouldRoundUp(a, nd) {
- return a.RoundUp(nd)
+ a.RoundUp(nd)
+ } else {
+ a.RoundDown(nd)
}
- return a.RoundDown(nd)
}
// Round a down to nd digits (or fewer).
-// Returns receiver for convenience.
-func (a *decimal) RoundDown(nd int) *decimal {
+func (a *decimal) RoundDown(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
a.nd = nd
trim(a)
- return a
}
// Round a up to nd digits (or fewer).
-// Returns receiver for convenience.
-func (a *decimal) RoundUp(nd int) *decimal {
+func (a *decimal) RoundUp(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
// round up
@@ -338,7 +346,7 @@ func (a *decimal) RoundUp(nd int) *decimal {
if c < '9' { // can stop after this digit
a.d[i]++
a.nd = i + 1
- return a
+ return
}
}
@@ -347,7 +355,6 @@ func (a *decimal) RoundUp(nd int) *decimal {
a.d[0] = '1'
a.nd = 1
a.dp++
- return a
}
// Extract integer part, rounded appropriately.
diff --git a/src/pkg/strconv/decimal_test.go b/src/pkg/strconv/decimal_test.go
index 9b7903516..13a127f5b 100644
--- a/src/pkg/strconv/decimal_test.go
+++ b/src/pkg/strconv/decimal_test.go
@@ -32,7 +32,9 @@ var shifttests = []shiftTest{
func TestDecimalShift(t *testing.T) {
for i := 0; i < len(shifttests); i++ {
test := &shifttests[i]
- s := NewDecimal(test.i).Shift(test.shift).String()
+ d := NewDecimal(test.i)
+ d.Shift(test.shift)
+ s := d.String()
if s != test.out {
t.Errorf("Decimal %v << %v = %v, want %v",
test.i, test.shift, s, test.out)
@@ -68,17 +70,23 @@ var roundtests = []roundTest{
func TestDecimalRound(t *testing.T) {
for i := 0; i < len(roundtests); i++ {
test := &roundtests[i]
- s := NewDecimal(test.i).RoundDown(test.nd).String()
+ d := NewDecimal(test.i)
+ d.RoundDown(test.nd)
+ s := d.String()
if s != test.down {
t.Errorf("Decimal %v RoundDown %d = %v, want %v",
test.i, test.nd, s, test.down)
}
- s = NewDecimal(test.i).Round(test.nd).String()
+ d = NewDecimal(test.i)
+ d.Round(test.nd)
+ s = d.String()
if s != test.round {
t.Errorf("Decimal %v Round %d = %v, want %v",
test.i, test.nd, s, test.down)
}
- s = NewDecimal(test.i).RoundUp(test.nd).String()
+ d = NewDecimal(test.i)
+ d.RoundUp(test.nd)
+ s = d.String()
if s != test.up {
t.Errorf("Decimal %v RoundUp %d = %v, want %v",
test.i, test.nd, s, test.up)
@@ -108,7 +116,9 @@ var roundinttests = []roundIntTest{
func TestDecimalRoundedInteger(t *testing.T) {
for i := 0; i < len(roundinttests); i++ {
test := roundinttests[i]
- int := NewDecimal(test.i).Shift(test.shift).RoundedInteger()
+ d := NewDecimal(test.i)
+ d.Shift(test.shift)
+ int := d.RoundedInteger()
if int != test.int {
t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v",
test.i, test.shift, int, test.int)
diff --git a/src/pkg/strconv/extfloat.go b/src/pkg/strconv/extfloat.go
new file mode 100644
index 000000000..aa5e5607c
--- /dev/null
+++ b/src/pkg/strconv/extfloat.go
@@ -0,0 +1,501 @@
+// 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 strconv
+
+import "math"
+
+// An extFloat represents an extended floating-point number, with more
+// precision than a float64. It does not try to save bits: the
+// number represented by the structure is mant*(2^exp), with a negative
+// sign if neg is true.
+type extFloat struct {
+ mant uint64
+ exp int
+ neg bool
+}
+
+// Powers of ten taken from double-conversion library.
+// http://code.google.com/p/double-conversion/
+const (
+ firstPowerOfTen = -348
+ stepPowerOfTen = 8
+)
+
+var smallPowersOfTen = [...]extFloat{
+ {1 << 63, -63, false}, // 1
+ {0xa << 60, -60, false}, // 1e1
+ {0x64 << 57, -57, false}, // 1e2
+ {0x3e8 << 54, -54, false}, // 1e3
+ {0x2710 << 50, -50, false}, // 1e4
+ {0x186a0 << 47, -47, false}, // 1e5
+ {0xf4240 << 44, -44, false}, // 1e6
+ {0x989680 << 40, -40, false}, // 1e7
+}
+
+var powersOfTen = [...]extFloat{
+ {0xfa8fd5a0081c0288, -1220, false}, // 10^-348
+ {0xbaaee17fa23ebf76, -1193, false}, // 10^-340
+ {0x8b16fb203055ac76, -1166, false}, // 10^-332
+ {0xcf42894a5dce35ea, -1140, false}, // 10^-324
+ {0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
+ {0xe61acf033d1a45df, -1087, false}, // 10^-308
+ {0xab70fe17c79ac6ca, -1060, false}, // 10^-300
+ {0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
+ {0xbe5691ef416bd60c, -1007, false}, // 10^-284
+ {0x8dd01fad907ffc3c, -980, false}, // 10^-276
+ {0xd3515c2831559a83, -954, false}, // 10^-268
+ {0x9d71ac8fada6c9b5, -927, false}, // 10^-260
+ {0xea9c227723ee8bcb, -901, false}, // 10^-252
+ {0xaecc49914078536d, -874, false}, // 10^-244
+ {0x823c12795db6ce57, -847, false}, // 10^-236
+ {0xc21094364dfb5637, -821, false}, // 10^-228
+ {0x9096ea6f3848984f, -794, false}, // 10^-220
+ {0xd77485cb25823ac7, -768, false}, // 10^-212
+ {0xa086cfcd97bf97f4, -741, false}, // 10^-204
+ {0xef340a98172aace5, -715, false}, // 10^-196
+ {0xb23867fb2a35b28e, -688, false}, // 10^-188
+ {0x84c8d4dfd2c63f3b, -661, false}, // 10^-180
+ {0xc5dd44271ad3cdba, -635, false}, // 10^-172
+ {0x936b9fcebb25c996, -608, false}, // 10^-164
+ {0xdbac6c247d62a584, -582, false}, // 10^-156
+ {0xa3ab66580d5fdaf6, -555, false}, // 10^-148
+ {0xf3e2f893dec3f126, -529, false}, // 10^-140
+ {0xb5b5ada8aaff80b8, -502, false}, // 10^-132
+ {0x87625f056c7c4a8b, -475, false}, // 10^-124
+ {0xc9bcff6034c13053, -449, false}, // 10^-116
+ {0x964e858c91ba2655, -422, false}, // 10^-108
+ {0xdff9772470297ebd, -396, false}, // 10^-100
+ {0xa6dfbd9fb8e5b88f, -369, false}, // 10^-92
+ {0xf8a95fcf88747d94, -343, false}, // 10^-84
+ {0xb94470938fa89bcf, -316, false}, // 10^-76
+ {0x8a08f0f8bf0f156b, -289, false}, // 10^-68
+ {0xcdb02555653131b6, -263, false}, // 10^-60
+ {0x993fe2c6d07b7fac, -236, false}, // 10^-52
+ {0xe45c10c42a2b3b06, -210, false}, // 10^-44
+ {0xaa242499697392d3, -183, false}, // 10^-36
+ {0xfd87b5f28300ca0e, -157, false}, // 10^-28
+ {0xbce5086492111aeb, -130, false}, // 10^-20
+ {0x8cbccc096f5088cc, -103, false}, // 10^-12
+ {0xd1b71758e219652c, -77, false}, // 10^-4
+ {0x9c40000000000000, -50, false}, // 10^4
+ {0xe8d4a51000000000, -24, false}, // 10^12
+ {0xad78ebc5ac620000, 3, false}, // 10^20
+ {0x813f3978f8940984, 30, false}, // 10^28
+ {0xc097ce7bc90715b3, 56, false}, // 10^36
+ {0x8f7e32ce7bea5c70, 83, false}, // 10^44
+ {0xd5d238a4abe98068, 109, false}, // 10^52
+ {0x9f4f2726179a2245, 136, false}, // 10^60
+ {0xed63a231d4c4fb27, 162, false}, // 10^68
+ {0xb0de65388cc8ada8, 189, false}, // 10^76
+ {0x83c7088e1aab65db, 216, false}, // 10^84
+ {0xc45d1df942711d9a, 242, false}, // 10^92
+ {0x924d692ca61be758, 269, false}, // 10^100
+ {0xda01ee641a708dea, 295, false}, // 10^108
+ {0xa26da3999aef774a, 322, false}, // 10^116
+ {0xf209787bb47d6b85, 348, false}, // 10^124
+ {0xb454e4a179dd1877, 375, false}, // 10^132
+ {0x865b86925b9bc5c2, 402, false}, // 10^140
+ {0xc83553c5c8965d3d, 428, false}, // 10^148
+ {0x952ab45cfa97a0b3, 455, false}, // 10^156
+ {0xde469fbd99a05fe3, 481, false}, // 10^164
+ {0xa59bc234db398c25, 508, false}, // 10^172
+ {0xf6c69a72a3989f5c, 534, false}, // 10^180
+ {0xb7dcbf5354e9bece, 561, false}, // 10^188
+ {0x88fcf317f22241e2, 588, false}, // 10^196
+ {0xcc20ce9bd35c78a5, 614, false}, // 10^204
+ {0x98165af37b2153df, 641, false}, // 10^212
+ {0xe2a0b5dc971f303a, 667, false}, // 10^220
+ {0xa8d9d1535ce3b396, 694, false}, // 10^228
+ {0xfb9b7cd9a4a7443c, 720, false}, // 10^236
+ {0xbb764c4ca7a44410, 747, false}, // 10^244
+ {0x8bab8eefb6409c1a, 774, false}, // 10^252
+ {0xd01fef10a657842c, 800, false}, // 10^260
+ {0x9b10a4e5e9913129, 827, false}, // 10^268
+ {0xe7109bfba19c0c9d, 853, false}, // 10^276
+ {0xac2820d9623bf429, 880, false}, // 10^284
+ {0x80444b5e7aa7cf85, 907, false}, // 10^292
+ {0xbf21e44003acdd2d, 933, false}, // 10^300
+ {0x8e679c2f5e44ff8f, 960, false}, // 10^308
+ {0xd433179d9c8cb841, 986, false}, // 10^316
+ {0x9e19db92b4e31ba9, 1013, false}, // 10^324
+ {0xeb96bf6ebadf77d9, 1039, false}, // 10^332
+ {0xaf87023b9bf0ee6b, 1066, false}, // 10^340
+}
+
+// floatBits returns the bits of the float64 that best approximates
+// the extFloat passed as receiver. Overflow is set to true if
+// the resulting float64 is ±Inf.
+func (f *extFloat) floatBits() (bits uint64, overflow bool) {
+ flt := &float64info
+ f.Normalize()
+
+ exp := f.exp + 63
+
+ // Exponent too small.
+ if exp < flt.bias+1 {
+ n := flt.bias + 1 - exp
+ f.mant >>= uint(n)
+ exp += n
+ }
+
+ // Extract 1+flt.mantbits bits.
+ mant := f.mant >> (63 - flt.mantbits)
+ if f.mant&(1<<(62-flt.mantbits)) != 0 {
+ // Round up.
+ mant += 1
+ }
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<<flt.mantbits {
+ mant >>= 1
+ exp++
+ }
+
+ // Infinities.
+ if exp-flt.bias >= 1<<flt.expbits-1 {
+ goto overflow
+ }
+
+ // Denormalized?
+ if mant&(1<<flt.mantbits) == 0 {
+ exp = flt.bias
+ }
+ goto out
+
+overflow:
+ // ±Inf
+ mant = 0
+ exp = 1<<flt.expbits - 1 + flt.bias
+ overflow = true
+
+out:
+ // Assemble bits.
+ bits = mant & (uint64(1)<<flt.mantbits - 1)
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+ if f.neg {
+ bits |= 1 << (flt.mantbits + flt.expbits)
+ }
+ return
+}
+
+// Assign sets f to the value of x.
+func (f *extFloat) Assign(x float64) {
+ if x < 0 {
+ x = -x
+ f.neg = true
+ }
+ x, f.exp = math.Frexp(x)
+ f.mant = uint64(x * float64(1<<64))
+ f.exp -= 64
+}
+
+// AssignComputeBounds sets f to the value of x and returns
+// lower, upper such that any number in the closed interval
+// [lower, upper] is converted back to x.
+func (f *extFloat) AssignComputeBounds(x float64) (lower, upper extFloat) {
+ // Special cases.
+ bits := math.Float64bits(x)
+ flt := &float64info
+ neg := bits>>(flt.expbits+flt.mantbits) != 0
+ expBiased := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
+ mant := bits & (uint64(1)<<flt.mantbits - 1)
+
+ if expBiased == 0 {
+ // denormalized.
+ f.mant = mant
+ f.exp = 1 + flt.bias - int(flt.mantbits)
+ } else {
+ f.mant = mant | 1<<flt.mantbits
+ f.exp = expBiased + flt.bias - int(flt.mantbits)
+ }
+ f.neg = neg
+
+ upper = extFloat{mant: 2*f.mant + 1, exp: f.exp - 1, neg: f.neg}
+ if mant != 0 || expBiased == 1 {
+ lower = extFloat{mant: 2*f.mant - 1, exp: f.exp - 1, neg: f.neg}
+ } else {
+ lower = extFloat{mant: 4*f.mant - 1, exp: f.exp - 2, neg: f.neg}
+ }
+ return
+}
+
+// Normalize normalizes f so that the highest bit of the mantissa is
+// set, and returns the number by which the mantissa was left-shifted.
+func (f *extFloat) Normalize() uint {
+ if f.mant == 0 {
+ return 0
+ }
+ exp_before := f.exp
+ for f.mant < (1 << 55) {
+ f.mant <<= 8
+ f.exp -= 8
+ }
+ for f.mant < (1 << 63) {
+ f.mant <<= 1
+ f.exp -= 1
+ }
+ return uint(exp_before - f.exp)
+}
+
+// Multiply sets f to the product f*g: the result is correctly rounded,
+// but not normalized.
+func (f *extFloat) Multiply(g extFloat) {
+ fhi, flo := f.mant>>32, uint64(uint32(f.mant))
+ ghi, glo := g.mant>>32, uint64(uint32(g.mant))
+
+ // Cross products.
+ cross1 := fhi * glo
+ cross2 := flo * ghi
+
+ // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
+ f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
+ rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+ // Round up.
+ rem += (1 << 31)
+
+ f.mant += (rem >> 32)
+ f.exp = f.exp + g.exp + 64
+}
+
+var uint64pow10 = [...]uint64{
+ 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// AssignDecimal sets f to an approximate value of the decimal d. It
+// returns true if the value represented by f is guaranteed to be the
+// best approximation of d after being rounded to a float64.
+func (f *extFloat) AssignDecimal(d *decimal) (ok bool) {
+ const uint64digits = 19
+ const errorscale = 8
+ mant10, digits := d.atou64()
+ exp10 := d.dp - digits
+ errors := 0 // An upper bound for error, computed in errorscale*ulp.
+
+ if digits < d.nd {
+ // the decimal number was truncated.
+ errors += errorscale / 2
+ }
+
+ f.mant = mant10
+ f.exp = 0
+ f.neg = d.neg
+
+ // Multiply by powers of ten.
+ i := (exp10 - firstPowerOfTen) / stepPowerOfTen
+ if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
+ return false
+ }
+ adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
+
+ // We multiply by exp%step
+ if digits+adjExp <= uint64digits {
+ // We can multiply the mantissa
+ f.mant *= uint64(float64pow10[adjExp])
+ f.Normalize()
+ } else {
+ f.Normalize()
+ f.Multiply(smallPowersOfTen[adjExp])
+ errors += errorscale / 2
+ }
+
+ // We multiply by 10 to the exp - exp%step.
+ f.Multiply(powersOfTen[i])
+ if errors > 0 {
+ errors += 1
+ }
+ errors += errorscale / 2
+
+ // Normalize
+ shift := f.Normalize()
+ errors <<= shift
+
+ // Now f is a good approximation of the decimal.
+ // Check whether the error is too large: that is, if the mantissa
+ // is perturbated by the error, the resulting float64 will change.
+ // The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
+ //
+ // In many cases the approximation will be good enough.
+ const denormalExp = -1023 - 63
+ flt := &float64info
+ var extrabits uint
+ if f.exp <= denormalExp {
+ extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+ } else {
+ extrabits = uint(63 - flt.mantbits)
+ }
+
+ halfway := uint64(1) << (extrabits - 1)
+ mant_extra := f.mant & (1<<extrabits - 1)
+
+ // Do a signed comparison here! If the error estimate could make
+ // the mantissa round differently for the conversion to double,
+ // then we can't give a definite answer.
+ if int64(halfway)-int64(errors) < int64(mant_extra) &&
+ int64(mant_extra) < int64(halfway)+int64(errors) {
+ return false
+ }
+ return true
+}
+
+// Frexp10 is an analogue of math.Frexp for decimal powers. It scales
+// f by an approximate power of ten 10^-exp, and returns exp10, so
+// that f*10^exp10 has the same value as the old f, up to an ulp,
+// as well as the index of 10^-exp in the powersOfTen table.
+// The arguments expMin and expMax constrain the final value of the
+// binary exponent of f.
+func (f *extFloat) frexp10(expMin, expMax int) (exp10, index int) {
+ // it is illegal to call this function with a too restrictive exponent range.
+ if expMax-expMin <= 25 {
+ panic("strconv: invalid exponent range")
+ }
+ // Find power of ten such that x * 10^n has a binary exponent
+ // between expMin and expMax
+ approxExp10 := -(f.exp + 100) * 28 / 93 // log(10)/log(2) is close to 93/28.
+ i := (approxExp10 - firstPowerOfTen) / stepPowerOfTen
+Loop:
+ for {
+ exp := f.exp + powersOfTen[i].exp + 64
+ switch {
+ case exp < expMin:
+ i++
+ case exp > expMax:
+ i--
+ default:
+ break Loop
+ }
+ }
+ // Apply the desired decimal shift on f. It will have exponent
+ // in the desired range. This is multiplication by 10^-exp10.
+ f.Multiply(powersOfTen[i])
+
+ return -(firstPowerOfTen + i*stepPowerOfTen), i
+}
+
+// frexp10Many applies a common shift by a power of ten to a, b, c.
+func frexp10Many(expMin, expMax int, a, b, c *extFloat) (exp10 int) {
+ exp10, i := c.frexp10(expMin, expMax)
+ a.Multiply(powersOfTen[i])
+ b.Multiply(powersOfTen[i])
+ return
+}
+
+// ShortestDecimal stores in d the shortest decimal representation of f
+// which belongs to the open interval (lower, upper), where f is supposed
+// to lie. It returns false whenever the result is unsure. The implementation
+// uses the Grisu3 algorithm.
+func (f *extFloat) ShortestDecimal(d *decimal, lower, upper *extFloat) bool {
+ if f.mant == 0 {
+ d.d[0] = '0'
+ d.nd = 1
+ d.dp = 0
+ d.neg = f.neg
+ }
+ const minExp = -60
+ const maxExp = -32
+ upper.Normalize()
+ // Uniformize exponents.
+ if f.exp > upper.exp {
+ f.mant <<= uint(f.exp - upper.exp)
+ f.exp = upper.exp
+ }
+ if lower.exp > upper.exp {
+ lower.mant <<= uint(lower.exp - upper.exp)
+ lower.exp = upper.exp
+ }
+
+ exp10 := frexp10Many(minExp, maxExp, lower, f, upper)
+ // Take a safety margin due to rounding in frexp10Many, but we lose precision.
+ upper.mant++
+ lower.mant--
+
+ // The shortest representation of f is either rounded up or down, but
+ // in any case, it is a truncation of upper.
+ shift := uint(-upper.exp)
+ integer := uint32(upper.mant >> shift)
+ fraction := upper.mant - (uint64(integer) << shift)
+
+ // How far we can go down from upper until the result is wrong.
+ allowance := upper.mant - lower.mant
+ // How far we should go to get a very precise result.
+ targetDiff := upper.mant - f.mant
+
+ // Count integral digits: there are at most 10.
+ var integerDigits int
+ for i, pow := range uint64pow10 {
+ if uint64(integer) >= pow {
+ integerDigits = i + 1
+ }
+ }
+ for i := 0; i < integerDigits; i++ {
+ pow := uint64pow10[integerDigits-i-1]
+ digit := integer / uint32(pow)
+ d.d[i] = byte(digit + '0')
+ integer -= digit * uint32(pow)
+ // evaluate whether we should stop.
+ if currentDiff := uint64(integer)<<shift + fraction; currentDiff < allowance {
+ d.nd = i + 1
+ d.dp = integerDigits + exp10
+ d.neg = f.neg
+ // Sometimes allowance is so large the last digit might need to be
+ // decremented to get closer to f.
+ return adjustLastDigit(d, currentDiff, targetDiff, allowance, pow<<shift, 2)
+ }
+ }
+ d.nd = integerDigits
+ d.dp = d.nd + exp10
+ d.neg = f.neg
+
+ // Compute digits of the fractional part. At each step fraction does not
+ // overflow. The choice of minExp implies that fraction is less than 2^60.
+ var digit int
+ multiplier := uint64(1)
+ for {
+ fraction *= 10
+ multiplier *= 10
+ digit = int(fraction >> shift)
+ d.d[d.nd] = byte(digit + '0')
+ d.nd++
+ fraction -= uint64(digit) << shift
+ if fraction < allowance*multiplier {
+ // We are in the admissible range. Note that if allowance is about to
+ // overflow, that is, allowance > 2^64/10, the condition is automatically
+ // true due to the limited range of fraction.
+ return adjustLastDigit(d,
+ fraction, targetDiff*multiplier, allowance*multiplier,
+ 1<<shift, multiplier*2)
+ }
+ }
+ return false
+}
+
+// adjustLastDigit modifies d = x-currentDiff*ε, to get closest to
+// d = x-targetDiff*ε, without becoming smaller than x-maxDiff*ε.
+// It assumes that a decimal digit is worth ulpDecimal*ε, and that
+// all data is known with a error estimate of ulpBinary*ε.
+func adjustLastDigit(d *decimal, currentDiff, targetDiff, maxDiff, ulpDecimal, ulpBinary uint64) bool {
+ if ulpDecimal < 2*ulpBinary {
+ // Approximation is too wide.
+ return false
+ }
+ for currentDiff+ulpDecimal/2+ulpBinary < targetDiff {
+ d.d[d.nd-1]--
+ currentDiff += ulpDecimal
+ }
+ if currentDiff+ulpDecimal <= targetDiff+ulpDecimal/2+ulpBinary {
+ // we have two choices, and don't know what to do.
+ return false
+ }
+ if currentDiff < ulpBinary || currentDiff > maxDiff-ulpBinary {
+ // we went too far
+ return false
+ }
+ if d.nd == 1 && d.d[0] == '0' {
+ // the number has actually reached zero.
+ d.nd = 0
+ d.dp = 0
+ }
+ return true
+}
diff --git a/src/pkg/strconv/fp_test.go b/src/pkg/strconv/fp_test.go
index 3096957f5..171defa44 100644
--- a/src/pkg/strconv/fp_test.go
+++ b/src/pkg/strconv/fp_test.go
@@ -7,6 +7,7 @@ package strconv_test
import (
"bufio"
"fmt"
+ "io"
"os"
"strconv"
"strings"
@@ -25,12 +26,12 @@ func pow2(i int) float64 {
return pow2(i/2) * pow2(i-i/2)
}
-// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent)
-// itself, passes the rest on to strconv.Atof64.
+// Wrapper around strconv.ParseFloat(x, 64). Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.ParseFloat.
func myatof64(s string) (f float64, ok bool) {
a := strings.SplitN(s, "p", 2)
if len(a) == 2 {
- n, err := strconv.Atoi64(a[0])
+ n, err := strconv.ParseInt(a[0], 10, 64)
if err != nil {
return 0, false
}
@@ -62,15 +63,15 @@ func myatof64(s string) (f float64, ok bool) {
}
return v * pow2(e), true
}
- f1, err := strconv.Atof64(s)
+ f1, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, false
}
return f1, true
}
-// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent)
-// itself, passes the rest on to strconv.Atof32.
+// Wrapper around strconv.ParseFloat(x, 32). Handles dddddp+ddd (binary exponent)
+// itself, passes the rest on to strconv.ParseFloat.
func myatof32(s string) (f float32, ok bool) {
a := strings.SplitN(s, "p", 2)
if len(a) == 2 {
@@ -86,7 +87,8 @@ func myatof32(s string) (f float32, ok bool) {
}
return float32(float64(n) * pow2(e)), true
}
- f1, err1 := strconv.Atof32(s)
+ f64, err1 := strconv.ParseFloat(s, 32)
+ f1 := float32(f64)
if err1 != nil {
return 0, false
}
@@ -96,7 +98,7 @@ func myatof32(s string) (f float32, ok bool) {
func TestFp(t *testing.T) {
f, err := os.Open("testfp.txt")
if err != nil {
- t.Fatal("testfp: open testfp.txt:", err.String())
+ t.Fatal("testfp: open testfp.txt:", err)
}
defer f.Close()
@@ -105,11 +107,11 @@ func TestFp(t *testing.T) {
lineno := 0
for {
line, err2 := b.ReadString('\n')
- if err2 == os.EOF {
+ if err2 == io.EOF {
break
}
if err2 != nil {
- t.Fatal("testfp: read testfp.txt: " + err2.String())
+ t.Fatal("testfp: read testfp.txt: " + err2.Error())
}
line = line[0 : len(line)-1]
lineno++
diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go
index b6049c545..8eefbee79 100644
--- a/src/pkg/strconv/ftoa.go
+++ b/src/pkg/strconv/ftoa.go
@@ -22,8 +22,10 @@ type floatInfo struct {
var float32info = floatInfo{23, 8, -127}
var float64info = floatInfo{52, 11, -1023}
-// Ftoa32 converts the 32-bit floating-point number f to a string,
-// according to the format fmt and precision prec.
+// FormatFloat converts the floating-point number f to a string,
+// according to the format fmt and precision prec. It rounds the
+// result assuming that the original was obtained from a floating-point
+// value of bitSize bits (32 for float32, 64 for float64).
//
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
@@ -38,32 +40,31 @@ var float64info = floatInfo{52, 11, -1023}
// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
-// necessary such that Atof32 will return f exactly.
-//
-// Ftoa32(f) is not the same as Ftoa64(float32(f)),
-// because correct rounding and the number of digits
-// needed to identify f depend on the precision of the representation.
-func Ftoa32(f float32, fmt byte, prec int) string {
- return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
+// necessary such that ParseFloat will return f exactly.
+func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
+ return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
}
-// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
-func Ftoa64(f float64, fmt byte, prec int) string {
- return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
+// AppendFloat appends the string form of the floating-point number f,
+// as generated by FormatFloat, to dst and returns the extended buffer.
+func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
+ return genericFtoa(dst, f, fmt, prec, bitSize)
}
-// FtoaN converts the 64-bit floating-point number f to a string,
-// according to the format fmt and precision prec, but it rounds the
-// result assuming that it was obtained from a floating-point value
-// of n bits (32 or 64).
-func FtoaN(f float64, fmt byte, prec int, n int) string {
- if n == 32 {
- return Ftoa32(float32(f), fmt, prec)
+func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
+ var bits uint64
+ var flt *floatInfo
+ switch bitSize {
+ case 32:
+ bits = uint64(math.Float32bits(float32(val)))
+ flt = &float32info
+ case 64:
+ bits = math.Float64bits(val)
+ flt = &float64info
+ default:
+ panic("strconv: illegal AppendFloat/FormatFloat bitSize")
}
- return Ftoa64(f, fmt, prec)
-}
-func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
neg := bits>>(flt.expbits+flt.mantbits) != 0
exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
mant := bits & (uint64(1)<<flt.mantbits - 1)
@@ -71,13 +72,16 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
switch exp {
case 1<<flt.expbits - 1:
// Inf, NaN
- if mant != 0 {
- return "NaN"
- }
- if neg {
- return "-Inf"
+ var s string
+ switch {
+ case mant != 0:
+ s = "NaN"
+ case neg:
+ s = "-Inf"
+ default:
+ s = "+Inf"
}
- return "+Inf"
+ return append(dst, s...)
case 0:
// denormalized
@@ -91,30 +95,46 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
// Pick off easy binary format.
if fmt == 'b' {
- return fmtB(neg, mant, exp, flt)
+ return fmtB(dst, neg, mant, exp, flt)
}
- // Create exact decimal representation.
- // The shift is exp - flt.mantbits because mant is a 1-bit integer
- // followed by a flt.mantbits fraction, and we are treating it as
- // a 1+flt.mantbits-bit integer.
- d := newDecimal(mant).Shift(exp - int(flt.mantbits))
-
- // Round appropriately.
// Negative precision means "only as much as needed to be exact."
- shortest := false
- if prec < 0 {
- shortest = true
- roundShortest(d, mant, exp, flt)
- switch fmt {
- case 'e', 'E':
- prec = d.nd - 1
- case 'f':
- prec = max(d.nd-d.dp, 0)
- case 'g', 'G':
- prec = d.nd
+ shortest := prec < 0
+
+ d := new(decimal)
+ if shortest {
+ ok := false
+ if optimize && bitSize == 64 {
+ // Try Grisu3 algorithm.
+ f := new(extFloat)
+ lower, upper := f.AssignComputeBounds(val)
+ ok = f.ShortestDecimal(d, &lower, &upper)
+ }
+ if !ok {
+ // Create exact decimal representation.
+ // The shift is exp - flt.mantbits because mant is a 1-bit integer
+ // followed by a flt.mantbits fraction, and we are treating it as
+ // a 1+flt.mantbits-bit integer.
+ d.Assign(mant)
+ d.Shift(exp - int(flt.mantbits))
+ roundShortest(d, mant, exp, flt)
+ }
+ // Precision for shortest representation mode.
+ if prec < 0 {
+ switch fmt {
+ case 'e', 'E':
+ prec = d.nd - 1
+ case 'f':
+ prec = max(d.nd-d.dp, 0)
+ case 'g', 'G':
+ prec = d.nd
+ }
}
} else {
+ // Create exact decimal representation.
+ d.Assign(mant)
+ d.Shift(exp - int(flt.mantbits))
+ // Round appropriately.
switch fmt {
case 'e', 'E':
d.Round(prec + 1)
@@ -130,9 +150,9 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
switch fmt {
case 'e', 'E':
- return fmtE(neg, d, prec, fmt)
+ return fmtE(dst, neg, d, prec, fmt)
case 'f':
- return fmtF(neg, d, prec)
+ return fmtF(dst, neg, d, prec)
case 'g', 'G':
// trailing fractional zeros in 'e' form will be trimmed.
eprec := prec
@@ -150,15 +170,16 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
if prec > d.nd {
prec = d.nd
}
- return fmtE(neg, d, prec-1, fmt+'e'-'g')
+ return fmtE(dst, neg, d, prec-1, fmt+'e'-'g')
}
if prec > d.dp {
prec = d.nd
}
- return fmtF(neg, d, max(prec-d.dp, 0))
+ return fmtF(dst, neg, d, max(prec-d.dp, 0))
}
- return "%" + string(fmt)
+ // unknown format
+ return append(dst, '%', fmt)
}
// Round d (= mant * 2^exp) to the shortest number of digits
@@ -171,19 +192,32 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
return
}
- // TODO(rsc): Unless exp == minexp, if the number of digits in d
- // is less than 17, it seems likely that it would be
- // the shortest possible number already. So maybe we can
- // bail out without doing the extra multiprecision math here.
-
// Compute upper and lower such that any decimal number
// between upper and lower (possibly inclusive)
// will round to the original floating point number.
+ // We may see at once that the number is already shortest.
+ //
+ // Suppose d is not denormal, so that 2^exp <= d < 10^dp.
+ // The closest shorter number is at least 10^(dp-nd) away.
+ // The lower/upper bounds computed below are at distance
+ // at most 2^(exp-mantbits).
+ //
+ // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
+ // or equivalently log2(10)*(dp-nd) > exp-mantbits.
+ // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
+ minexp := flt.bias + 1 // minimum possible exponent
+ if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
+ // The number is already shortest.
+ return
+ }
+
// d = mant << (exp - mantbits)
// Next highest floating point number is mant+1 << exp-mantbits.
// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
- upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
+ upper := new(decimal)
+ upper.Assign(mant*2 + 1)
+ upper.Shift(exp - int(flt.mantbits) - 1)
// d = mant << (exp - mantbits)
// Next lowest floating point number is mant-1 << exp-mantbits,
@@ -191,7 +225,6 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// in which case the next lowest is mant*2-1 << exp-mantbits-1.
// Either way, call it mantlo << explo-mantbits.
// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
- minexp := flt.bias + 1 // minimum possible exponent
var mantlo uint64
var explo int
if mant > 1<<flt.mantbits || exp == minexp {
@@ -201,7 +234,9 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
mantlo = mant*2 - 1
explo = exp - 1
}
- lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
+ lower := new(decimal)
+ lower.Assign(mantlo*2 + 1)
+ lower.Shift(explo - int(flt.mantbits) - 1)
// The upper and lower bounds are possible outputs only if
// the original mantissa is even, so that IEEE round-to-even
@@ -230,7 +265,7 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// Okay to round up if upper has a different digit and
// either upper is inclusive or upper is bigger than the result of rounding up.
- okup := m != u && (inclusive || i+1 < upper.nd)
+ okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
// If it's okay to do either, then round to the nearest one.
// If it's okay to do only one, do it.
@@ -249,121 +284,103 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
}
// %e: -d.ddddde±dd
-func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
- buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
- w := 0 // write index
-
+func fmtE(dst []byte, neg bool, d *decimal, prec int, fmt byte) []byte {
// sign
if neg {
- buf[w] = '-'
- w++
+ dst = append(dst, '-')
}
// first digit
- if d.nd == 0 {
- buf[w] = '0'
- } else {
- buf[w] = d.d[0]
+ ch := byte('0')
+ if d.nd != 0 {
+ ch = d.d[0]
}
- w++
+ dst = append(dst, ch)
// .moredigits
if prec > 0 {
- buf[w] = '.'
- w++
- for i := 0; i < prec; i++ {
- if 1+i < d.nd {
- buf[w] = d.d[1+i]
- } else {
- buf[w] = '0'
+ dst = append(dst, '.')
+ for i := 1; i <= prec; i++ {
+ ch = '0'
+ if i < d.nd {
+ ch = d.d[i]
}
- w++
+ dst = append(dst, ch)
}
}
// e±
- buf[w] = fmt
- w++
+ dst = append(dst, fmt)
exp := d.dp - 1
if d.nd == 0 { // special case: 0 has exponent 0
exp = 0
}
if exp < 0 {
- buf[w] = '-'
+ ch = '-'
exp = -exp
} else {
- buf[w] = '+'
+ ch = '+'
}
- w++
+ dst = append(dst, ch)
// dddd
- // count digits
- n := 0
- for e := exp; e > 0; e /= 10 {
- n++
- }
- // leading zeros
- for i := n; i < 2; i++ {
- buf[w] = '0'
- w++
+ var buf [3]byte
+ i := len(buf)
+ for exp >= 10 {
+ i--
+ buf[i] = byte(exp%10 + '0')
+ exp /= 10
}
- // digits
- w += n
- n = 0
- for e := exp; e > 0; e /= 10 {
- n++
- buf[w-n] = byte(e%10 + '0')
+ // exp < 10
+ i--
+ buf[i] = byte(exp + '0')
+
+ // leading zeroes
+ if i > len(buf)-2 {
+ i--
+ buf[i] = '0'
}
- return string(buf[0:w])
+ return append(dst, buf[i:]...)
}
// %f: -ddddddd.ddddd
-func fmtF(neg bool, d *decimal, prec int) string {
- buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
- w := 0
-
+func fmtF(dst []byte, neg bool, d *decimal, prec int) []byte {
// sign
if neg {
- buf[w] = '-'
- w++
+ dst = append(dst, '-')
}
// integer, padded with zeros as needed.
if d.dp > 0 {
var i int
for i = 0; i < d.dp && i < d.nd; i++ {
- buf[w] = d.d[i]
- w++
+ dst = append(dst, d.d[i])
}
for ; i < d.dp; i++ {
- buf[w] = '0'
- w++
+ dst = append(dst, '0')
}
} else {
- buf[w] = '0'
- w++
+ dst = append(dst, '0')
}
// fraction
if prec > 0 {
- buf[w] = '.'
- w++
+ dst = append(dst, '.')
for i := 0; i < prec; i++ {
- if d.dp+i < 0 || d.dp+i >= d.nd {
- buf[w] = '0'
- } else {
- buf[w] = d.d[d.dp+i]
+ ch := byte('0')
+ if j := d.dp + i; 0 <= j && j < d.nd {
+ ch = d.d[j]
}
- w++
+ dst = append(dst, ch)
}
}
- return string(buf[0:w])
+ return dst
}
// %b: -ddddddddp+ddd
-func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
+func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
var buf [50]byte
w := len(buf)
exp -= int(flt.mantbits)
@@ -394,7 +411,7 @@ func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
w--
buf[w] = '-'
}
- return string(buf[w:])
+ return append(dst, buf[w:]...)
}
func max(a, b int) int {
diff --git a/src/pkg/strconv/ftoa_test.go b/src/pkg/strconv/ftoa_test.go
index 6d361a138..7d8617a85 100644
--- a/src/pkg/strconv/ftoa_test.go
+++ b/src/pkg/strconv/ftoa_test.go
@@ -6,6 +6,7 @@ package strconv_test
import (
"math"
+ "math/rand"
. "strconv"
"testing"
)
@@ -123,28 +124,133 @@ var ftoatests = []ftoaTest{
{2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
{2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+
+ // Issue 2625.
+ {383260575764816448, 'f', 0, "383260575764816448"},
+ {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
}
func TestFtoa(t *testing.T) {
for i := 0; i < len(ftoatests); i++ {
test := &ftoatests[i]
- s := Ftoa64(test.f, test.fmt, test.prec)
- if s != test.s {
- t.Error("test", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
- }
- s = FtoaN(test.f, test.fmt, test.prec, 64)
+ s := FormatFloat(test.f, test.fmt, test.prec, 64)
if s != test.s {
t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
}
+ x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 64)
+ if string(x) != "abc"+test.s {
+ t.Error("AppendFloat testN=64", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x))
+ }
if float64(float32(test.f)) == test.f && test.fmt != 'b' {
- s := Ftoa32(float32(test.f), test.fmt, test.prec)
- if s != test.s {
- t.Error("test32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
- }
- s = FtoaN(test.f, test.fmt, test.prec, 32)
+ s := FormatFloat(test.f, test.fmt, test.prec, 32)
if s != test.s {
t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s)
}
+ x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 32)
+ if string(x) != "abc"+test.s {
+ t.Error("AppendFloat testN=32", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x))
+ }
+ }
+ }
+}
+
+func TestFtoaRandom(t *testing.T) {
+ N := int(1e4)
+ if testing.Short() {
+ N = 100
+ }
+ t.Logf("testing %d random numbers with fast and slow FormatFloat", N)
+ for i := 0; i < N; i++ {
+ bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+ x := math.Float64frombits(bits)
+ shortFast := FormatFloat(x, 'g', -1, 64)
+ SetOptimize(false)
+ shortSlow := FormatFloat(x, 'g', -1, 64)
+ SetOptimize(true)
+ if shortSlow != shortFast {
+ t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow)
}
}
}
+
+func TestAppendFloatDoesntAllocate(t *testing.T) {
+ n := numAllocations(func() {
+ var buf [64]byte
+ AppendFloat(buf[:0], 1.23, 'g', 5, 64)
+ })
+ want := 1 // TODO(bradfitz): this might be 0, once escape analysis is better
+ if n != want {
+ t.Errorf("with local buffer, did %d allocations, want %d", n, want)
+ }
+ n = numAllocations(func() {
+ AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64)
+ })
+ if n != 0 {
+ t.Errorf("with reused buffer, did %d allocations, want 0", n)
+ }
+}
+
+func BenchmarkFormatFloatDecimal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(33909, 'g', -1, 64)
+ }
+}
+
+func BenchmarkFormatFloat(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(339.7784, 'g', -1, 64)
+ }
+}
+
+func BenchmarkFormatFloatExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(-5.09e75, 'g', -1, 64)
+ }
+}
+
+func BenchmarkFormatFloatNegExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(-5.11e-95, 'g', -1, 64)
+ }
+}
+
+func BenchmarkFormatFloatBig(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ FormatFloat(123456789123456789123456789, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatDecimal(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 33909, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloat(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 339.7784, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatExp(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, -5.09e75, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatNegExp(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, -5.11e-95, 'g', -1, 64)
+ }
+}
+
+func BenchmarkAppendFloatBig(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ AppendFloat(dst, 123456789123456789123456789, 'g', -1, 64)
+ }
+}
diff --git a/src/pkg/strconv/internal_test.go b/src/pkg/strconv/internal_test.go
index 9a7f4f086..d0fa80edf 100644
--- a/src/pkg/strconv/internal_test.go
+++ b/src/pkg/strconv/internal_test.go
@@ -6,7 +6,11 @@
package strconv
-func NewDecimal(i uint64) *decimal { return newDecimal(i) }
+func NewDecimal(i uint64) *decimal {
+ d := new(decimal)
+ d.Assign(i)
+ return d
+}
func SetOptimize(b bool) bool {
old := optimize
diff --git a/src/pkg/strconv/isprint.go b/src/pkg/strconv/isprint.go
new file mode 100644
index 000000000..a03a07bfb
--- /dev/null
+++ b/src/pkg/strconv/isprint.go
@@ -0,0 +1,521 @@
+// DO NOT EDIT. GENERATED BY
+// go run makeisprint.go >x && mv x isprint.go
+
+package strconv
+
+// (474+134+42)*2 + (180)*4 = 2020 bytes
+
+var isPrint16 = []uint16{
+ 0x0020, 0x007e,
+ 0x00a1, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x085b,
+ 0x085e, 0x085e,
+ 0x0900, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a39,
+ 0x0a3c, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0ab9,
+ 0x0abc, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b8a,
+ 0x0b8e, 0x0b95,
+ 0x0b99, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c39,
+ 0x0c3d, 0x0c4d,
+ 0x0c55, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0cb9,
+ 0x0cbc, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0ce3,
+ 0x0ce6, 0x0cf2,
+ 0x0d02, 0x0d3a,
+ 0x0d3d, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d96,
+ 0x0d9a, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e84,
+ 0x0e87, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0ea7,
+ 0x0eaa, 0x0ebd,
+ 0x0ec0, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f6c,
+ 0x0f71, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x124d,
+ 0x1250, 0x125d,
+ 0x1260, 0x128d,
+ 0x1290, 0x12b5,
+ 0x12b8, 0x12c5,
+ 0x12c8, 0x1315,
+ 0x1318, 0x135a,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x1773,
+ 0x1780, 0x17b3,
+ 0x17b6, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180d,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f7d,
+ 0x1f80, 0x1fd3,
+ 0x1fd6, 0x1fef,
+ 0x1ff2, 0x1ffe,
+ 0x2010, 0x2027,
+ 0x2030, 0x205e,
+ 0x2070, 0x2071,
+ 0x2074, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2e31,
+ 0x2e80, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3001, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa791,
+ 0xa7a0, 0xa7a9,
+ 0xa7fa, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe6b,
+ 0xfe70, 0xfefc,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffee,
+ 0xfffc, 0xfffd,
+}
+
+var isNotPrint16 = []uint16{
+ 0x00ad,
+ 0x038b,
+ 0x038d,
+ 0x03a2,
+ 0x0560,
+ 0x0588,
+ 0x06dd,
+ 0x083f,
+ 0x0978,
+ 0x0980,
+ 0x0984,
+ 0x09a9,
+ 0x09b1,
+ 0x09de,
+ 0x0a04,
+ 0x0a29,
+ 0x0a31,
+ 0x0a34,
+ 0x0a37,
+ 0x0a3d,
+ 0x0a5d,
+ 0x0a84,
+ 0x0a8e,
+ 0x0a92,
+ 0x0aa9,
+ 0x0ab1,
+ 0x0ab4,
+ 0x0ac6,
+ 0x0aca,
+ 0x0af0,
+ 0x0b04,
+ 0x0b29,
+ 0x0b31,
+ 0x0b34,
+ 0x0b5e,
+ 0x0b84,
+ 0x0b91,
+ 0x0b9b,
+ 0x0b9d,
+ 0x0bc9,
+ 0x0c04,
+ 0x0c0d,
+ 0x0c11,
+ 0x0c29,
+ 0x0c34,
+ 0x0c45,
+ 0x0c49,
+ 0x0c57,
+ 0x0c84,
+ 0x0c8d,
+ 0x0c91,
+ 0x0ca9,
+ 0x0cb4,
+ 0x0cc5,
+ 0x0cc9,
+ 0x0cdf,
+ 0x0cf0,
+ 0x0d04,
+ 0x0d0d,
+ 0x0d11,
+ 0x0d45,
+ 0x0d49,
+ 0x0d84,
+ 0x0db2,
+ 0x0dbc,
+ 0x0dd5,
+ 0x0dd7,
+ 0x0e83,
+ 0x0e89,
+ 0x0e98,
+ 0x0ea0,
+ 0x0ea4,
+ 0x0ea6,
+ 0x0eac,
+ 0x0eba,
+ 0x0ec5,
+ 0x0ec7,
+ 0x0f48,
+ 0x0f98,
+ 0x0fbd,
+ 0x0fcd,
+ 0x1249,
+ 0x1257,
+ 0x1259,
+ 0x1289,
+ 0x12b1,
+ 0x12bf,
+ 0x12c1,
+ 0x12d7,
+ 0x1311,
+ 0x1680,
+ 0x170d,
+ 0x176d,
+ 0x1771,
+ 0x1a5f,
+ 0x1f58,
+ 0x1f5a,
+ 0x1f5c,
+ 0x1f5e,
+ 0x1fb5,
+ 0x1fc5,
+ 0x1fdc,
+ 0x1ff5,
+ 0x208f,
+ 0x2700,
+ 0x27cb,
+ 0x27cd,
+ 0x2c2f,
+ 0x2c5f,
+ 0x2da7,
+ 0x2daf,
+ 0x2db7,
+ 0x2dbf,
+ 0x2dc7,
+ 0x2dcf,
+ 0x2dd7,
+ 0x2ddf,
+ 0x2e9a,
+ 0x3040,
+ 0x318f,
+ 0x321f,
+ 0x32ff,
+ 0xa78f,
+ 0xa9ce,
+ 0xab27,
+ 0xfb37,
+ 0xfb3d,
+ 0xfb3f,
+ 0xfb42,
+ 0xfb45,
+ 0xfe53,
+ 0xfe67,
+ 0xfe75,
+ 0xffe7,
+}
+
+var isPrint32 = []uint32{
+ 0x010000, 0x01004d,
+ 0x010050, 0x01005d,
+ 0x010080, 0x0100fa,
+ 0x010100, 0x010102,
+ 0x010107, 0x010133,
+ 0x010137, 0x01018a,
+ 0x010190, 0x01019b,
+ 0x0101d0, 0x0101fd,
+ 0x010280, 0x01029c,
+ 0x0102a0, 0x0102d0,
+ 0x010300, 0x010323,
+ 0x010330, 0x01034a,
+ 0x010380, 0x0103c3,
+ 0x0103c8, 0x0103d5,
+ 0x010400, 0x01049d,
+ 0x0104a0, 0x0104a9,
+ 0x010800, 0x010805,
+ 0x010808, 0x010838,
+ 0x01083c, 0x01083c,
+ 0x01083f, 0x01085f,
+ 0x010900, 0x01091b,
+ 0x01091f, 0x010939,
+ 0x01093f, 0x01093f,
+ 0x010a00, 0x010a06,
+ 0x010a0c, 0x010a33,
+ 0x010a38, 0x010a3a,
+ 0x010a3f, 0x010a47,
+ 0x010a50, 0x010a58,
+ 0x010a60, 0x010a7f,
+ 0x010b00, 0x010b35,
+ 0x010b39, 0x010b55,
+ 0x010b58, 0x010b72,
+ 0x010b78, 0x010b7f,
+ 0x010c00, 0x010c48,
+ 0x010e60, 0x010e7e,
+ 0x011000, 0x01104d,
+ 0x011052, 0x01106f,
+ 0x011080, 0x0110c1,
+ 0x012000, 0x01236e,
+ 0x012400, 0x012462,
+ 0x012470, 0x012473,
+ 0x013000, 0x01342e,
+ 0x016800, 0x016a38,
+ 0x01b000, 0x01b001,
+ 0x01d000, 0x01d0f5,
+ 0x01d100, 0x01d126,
+ 0x01d129, 0x01d172,
+ 0x01d17b, 0x01d1dd,
+ 0x01d200, 0x01d245,
+ 0x01d300, 0x01d356,
+ 0x01d360, 0x01d371,
+ 0x01d400, 0x01d49f,
+ 0x01d4a2, 0x01d4a2,
+ 0x01d4a5, 0x01d4a6,
+ 0x01d4a9, 0x01d50a,
+ 0x01d50d, 0x01d546,
+ 0x01d54a, 0x01d6a5,
+ 0x01d6a8, 0x01d7cb,
+ 0x01d7ce, 0x01d7ff,
+ 0x01f000, 0x01f02b,
+ 0x01f030, 0x01f093,
+ 0x01f0a0, 0x01f0ae,
+ 0x01f0b1, 0x01f0be,
+ 0x01f0c1, 0x01f0df,
+ 0x01f100, 0x01f10a,
+ 0x01f110, 0x01f169,
+ 0x01f170, 0x01f19a,
+ 0x01f1e6, 0x01f202,
+ 0x01f210, 0x01f23a,
+ 0x01f240, 0x01f248,
+ 0x01f250, 0x01f251,
+ 0x01f300, 0x01f320,
+ 0x01f330, 0x01f37c,
+ 0x01f380, 0x01f393,
+ 0x01f3a0, 0x01f3ca,
+ 0x01f3e0, 0x01f3f0,
+ 0x01f400, 0x01f4fc,
+ 0x01f500, 0x01f53d,
+ 0x01f550, 0x01f567,
+ 0x01f5fb, 0x01f625,
+ 0x01f628, 0x01f62d,
+ 0x01f630, 0x01f640,
+ 0x01f645, 0x01f64f,
+ 0x01f680, 0x01f6c5,
+ 0x01f700, 0x01f773,
+ 0x020000, 0x02a6d6,
+ 0x02a700, 0x02b734,
+ 0x02b740, 0x02b81d,
+ 0x02f800, 0x02fa1d,
+ 0x0e0100, 0x0e01ef,
+}
+
+var isNotPrint32 = []uint16{ // add 0x10000 to each entry
+ 0x000c,
+ 0x0027,
+ 0x003b,
+ 0x003e,
+ 0x031f,
+ 0x039e,
+ 0x0809,
+ 0x0836,
+ 0x0856,
+ 0x0a04,
+ 0x0a14,
+ 0x0a18,
+ 0x10bd,
+ 0xd455,
+ 0xd49d,
+ 0xd4ad,
+ 0xd4ba,
+ 0xd4bc,
+ 0xd4c4,
+ 0xd506,
+ 0xd515,
+ 0xd51d,
+ 0xd53a,
+ 0xd53f,
+ 0xd545,
+ 0xd551,
+ 0xf0d0,
+ 0xf12f,
+ 0xf336,
+ 0xf3c5,
+ 0xf43f,
+ 0xf441,
+ 0xf4f8,
+ 0xf600,
+ 0xf611,
+ 0xf615,
+ 0xf617,
+ 0xf619,
+ 0xf61b,
+ 0xf61f,
+ 0xf62c,
+ 0xf634,
+}
diff --git a/src/pkg/strconv/itoa.go b/src/pkg/strconv/itoa.go
index a0a749664..ca40dd7ef 100644
--- a/src/pkg/strconv/itoa.go
+++ b/src/pkg/strconv/itoa.go
@@ -4,54 +4,124 @@
package strconv
-// Uitob64 returns the string representation of i in the given base.
-func Uitob64(u uint64, base uint) string {
- if base < 2 || 36 < base {
- panic("invalid base " + Uitoa(base))
- }
- if u == 0 {
- return "0"
- }
+// FormatUint returns the string representation of i in the given base.
+func FormatUint(i uint64, base int) string {
+ _, s := formatBits(nil, i, base, false, false)
+ return s
+}
- // Assemble decimal in reverse order.
- var buf [64]byte
- j := len(buf)
- b := uint64(base)
- for u > 0 {
- j--
- buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]
- u /= b
- }
+// FormatInt returns the string representation of i in the given base.
+func FormatInt(i int64, base int) string {
+ _, s := formatBits(nil, uint64(i), base, i < 0, false)
+ return s
+}
+
+// Itoa is shorthand for FormatInt(i, 10).
+func Itoa(i int) string {
+ return FormatInt(int64(i), 10)
+}
+
+// AppendInt appends the string form of the integer i,
+// as generated by FormatInt, to dst and returns the extended buffer.
+func AppendInt(dst []byte, i int64, base int) []byte {
+ dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
+ return dst
+}
- return string(buf[j:])
+// AppendUint appends the string form of the unsigned integer i,
+// as generated by FormatUint, to dst and returns the extended buffer.
+func AppendUint(dst []byte, i uint64, base int) []byte {
+ dst, _ = formatBits(dst, i, base, false, true)
+ return dst
}
-// Itob64 returns the string representation of i in the given base.
-func Itob64(i int64, base uint) string {
- if i == 0 {
- return "0"
+const (
+ digits = "0123456789abcdefghijklmnopqrstuvwxyz"
+ digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+ digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+)
+
+var shifts = [len(digits) + 1]uint{
+ 1 << 1: 1,
+ 1 << 2: 2,
+ 1 << 3: 3,
+ 1 << 4: 4,
+ 1 << 5: 5,
+}
+
+// formatBits computes the string representation of u in the given base.
+// If neg is set, u is treated as negative int64 value. If append_ is
+// set, the string is appended to dst and the resulting byte slice is
+// returned as the first result value; otherwise the string is returned
+// as the second result value.
+//
+func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) {
+ if base < 2 || base > len(digits) {
+ panic("strconv: illegal AppendInt/FormatInt base")
}
+ // 2 <= base && base <= len(digits)
- if i < 0 {
- return "-" + Uitob64(-uint64(i), base)
+ var a [64 + 1]byte // +1 for sign of 64bit value in base 2
+ i := len(a)
+
+ if neg {
+ u = -u
}
- return Uitob64(uint64(i), base)
-}
-// Itoa64 returns the decimal string representation of i.
-func Itoa64(i int64) string { return Itob64(i, 10) }
+ // convert bits
+ if base == 10 {
+ // common case: use constants for / and % because
+ // the compiler can optimize it into a multiply+shift,
+ // and unroll loop
+ for u >= 100 {
+ i -= 2
+ q := u / 100
+ j := uintptr(u - q*100)
+ a[i+1] = digits01[j]
+ a[i+0] = digits10[j]
+ u = q
+ }
+ if u >= 10 {
+ i--
+ q := u / 10
+ a[i] = digits[uintptr(u-q*10)]
+ u = q
+ }
-// Uitoa64 returns the decimal string representation of i.
-func Uitoa64(i uint64) string { return Uitob64(i, 10) }
+ } else if s := shifts[base]; s > 0 {
+ // base is power of 2: use shifts and masks instead of / and %
+ b := uint64(base)
+ m := uintptr(b) - 1 // == 1<<s - 1
+ for u >= b {
+ i--
+ a[i] = digits[uintptr(u)&m]
+ u >>= s
+ }
-// Uitob returns the string representation of i in the given base.
-func Uitob(i uint, base uint) string { return Uitob64(uint64(i), base) }
+ } else {
+ // general case
+ b := uint64(base)
+ for u >= b {
+ i--
+ a[i] = digits[uintptr(u%b)]
+ u /= b
+ }
+ }
-// Itob returns the string representation of i in the given base.
-func Itob(i int, base uint) string { return Itob64(int64(i), base) }
+ // u < base
+ i--
+ a[i] = digits[uintptr(u)]
-// Itoa returns the decimal string representation of i.
-func Itoa(i int) string { return Itob64(int64(i), 10) }
+ // add sign, if any
+ if neg {
+ i--
+ a[i] = '-'
+ }
-// Uitoa returns the decimal string representation of i.
-func Uitoa(i uint) string { return Uitob64(uint64(i), 10) }
+ if append_ {
+ d = append(dst, a[i:]...)
+ return
+ }
+ s = string(a[i:])
+ return
+}
diff --git a/src/pkg/strconv/itoa_test.go b/src/pkg/strconv/itoa_test.go
index 8514b21e4..1486ee214 100644
--- a/src/pkg/strconv/itoa_test.go
+++ b/src/pkg/strconv/itoa_test.go
@@ -5,13 +5,14 @@
package strconv_test
import (
+ "runtime"
. "strconv"
"testing"
)
type itob64Test struct {
in int64
- base uint
+ base int
out string
}
@@ -60,73 +61,43 @@ var itob64tests = []itob64Test{
func TestItoa(t *testing.T) {
for _, test := range itob64tests {
- s := Itob64(test.in, test.base)
+ s := FormatInt(test.in, test.base)
if s != test.out {
- t.Errorf("Itob64(%v, %v) = %v want %v",
+ t.Errorf("FormatInt(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
-
- if test.in >= 0 {
- s := Uitob64(uint64(test.in), test.base)
- if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v",
- test.in, test.base, s, test.out)
- }
+ x := AppendInt([]byte("abc"), test.in, test.base)
+ if string(x) != "abc"+test.out {
+ t.Errorf("AppendInt(%q, %v, %v) = %q want %v",
+ "abc", test.in, test.base, x, test.out)
}
- if int64(int(test.in)) == test.in {
- s := Itob(int(test.in), test.base)
+ if test.in >= 0 {
+ s := FormatUint(uint64(test.in), test.base)
if s != test.out {
- t.Errorf("Itob(%v, %v) = %v want %v",
+ t.Errorf("FormatUint(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
-
- if test.in >= 0 {
- s := Uitob(uint(test.in), test.base)
- if s != test.out {
- t.Errorf("Uitob(%v, %v) = %v want %v",
- test.in, test.base, s, test.out)
- }
+ x := AppendUint(nil, uint64(test.in), test.base)
+ if string(x) != test.out {
+ t.Errorf("AppendUint(%q, %v, %v) = %q want %v",
+ "abc", uint64(test.in), test.base, x, test.out)
}
}
- if test.base == 10 {
- s := Itoa64(test.in)
+ if test.base == 10 && int64(int(test.in)) == test.in {
+ s := Itoa(int(test.in))
if s != test.out {
- t.Errorf("Itoa64(%v) = %v want %v",
+ t.Errorf("Itoa(%v) = %v want %v",
test.in, s, test.out)
}
-
- if test.in >= 0 {
- s := Uitob64(uint64(test.in), test.base)
- if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v",
- test.in, test.base, s, test.out)
- }
- }
-
- if int64(int(test.in)) == test.in {
- s := Itoa(int(test.in))
- if s != test.out {
- t.Errorf("Itoa(%v) = %v want %v",
- test.in, s, test.out)
- }
-
- if test.in >= 0 {
- s := Uitoa(uint(test.in))
- if s != test.out {
- t.Errorf("Uitoa(%v) = %v want %v",
- test.in, s, test.out)
- }
- }
- }
}
}
}
type uitob64Test struct {
in uint64
- base uint
+ base int
out string
}
@@ -141,34 +112,79 @@ var uitob64tests = []uitob64Test{
func TestUitoa(t *testing.T) {
for _, test := range uitob64tests {
- s := Uitob64(test.in, test.base)
+ s := FormatUint(test.in, test.base)
if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v",
+ t.Errorf("FormatUint(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
+ x := AppendUint([]byte("abc"), test.in, test.base)
+ if string(x) != "abc"+test.out {
+ t.Errorf("AppendUint(%q, %v, %v) = %q want %v",
+ "abc", test.in, test.base, x, test.out)
+ }
- if uint64(uint(test.in)) == test.in {
- s := Uitob(uint(test.in), test.base)
- if s != test.out {
- t.Errorf("Uitob(%v, %v) = %v want %v",
- test.in, test.base, s, test.out)
- }
+ }
+}
+
+func numAllocations(f func()) int {
+ runtime.GC()
+ memstats := new(runtime.MemStats)
+ runtime.ReadMemStats(memstats)
+ n0 := memstats.Mallocs
+ f()
+ runtime.ReadMemStats(memstats)
+ return int(memstats.Mallocs - n0)
+}
+
+var globalBuf [64]byte
+
+func TestAppendUintDoesntAllocate(t *testing.T) {
+ n := numAllocations(func() {
+ var buf [64]byte
+ AppendInt(buf[:0], 123, 10)
+ })
+ want := 1 // TODO(bradfitz): this might be 0, once escape analysis is better
+ if n != want {
+ t.Errorf("with local buffer, did %d allocations, want %d", n, want)
+ }
+ n = numAllocations(func() {
+ AppendInt(globalBuf[:0], 123, 10)
+ })
+ if n != 0 {
+ t.Errorf("with reused buffer, did %d allocations, want 0", n)
+ }
+}
+
+func BenchmarkFormatInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, test := range itob64tests {
+ FormatInt(test.in, test.base)
}
+ }
+}
- if test.base == 10 {
- s := Uitoa64(test.in)
- if s != test.out {
- t.Errorf("Uitoa64(%v) = %v want %v",
- test.in, s, test.out)
- }
+func BenchmarkAppendInt(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ for _, test := range itob64tests {
+ AppendInt(dst, test.in, test.base)
+ }
+ }
+}
- if uint64(uint(test.in)) == test.in {
- s := Uitoa(uint(test.in))
- if s != test.out {
- t.Errorf("Uitoa(%v) = %v want %v",
- test.in, s, test.out)
- }
- }
+func BenchmarkFormatUint(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, test := range uitob64tests {
+ FormatUint(test.in, test.base)
+ }
+ }
+}
+
+func BenchmarkAppendUint(b *testing.B) {
+ dst := make([]byte, 0, 30)
+ for i := 0; i < b.N; i++ {
+ for _, test := range uitob64tests {
+ AppendUint(dst, test.in, test.base)
}
}
}
diff --git a/src/pkg/strconv/makeisprint.go b/src/pkg/strconv/makeisprint.go
new file mode 100644
index 000000000..8a6699bdb
--- /dev/null
+++ b/src/pkg/strconv/makeisprint.go
@@ -0,0 +1,162 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// makeisprint generates the tables for strconv's compact isPrint.
+package main
+
+import (
+ "fmt"
+ "os"
+ "unicode"
+)
+
+var (
+ range16 []uint16
+ except16 []uint16
+ range32 []uint32
+ except32 []uint32
+)
+
+// bsearch16 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch16 returns len(a).
+func bsearch16(a []uint16, x uint16) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+// bsearch32 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch32 returns len(a).
+func bsearch32(a []uint32, x uint32) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+func isPrint(r rune) bool {
+ // Same algorithm, either on uint16 or uint32 value.
+ // First, find first i such that rang[i] >= x.
+ // This is the index of either the start or end of a pair that might span x.
+ // The start is even (rang[i&^1]) and the end is odd (rang[i|1]).
+ // If we find x in a range, make sure x is not in exception list.
+
+ if 0 <= r && r < 1<<16 {
+ rr, rang, except := uint16(r), range16, except16
+ i := bsearch16(rang, rr)
+ if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
+ return false
+ }
+ j := bsearch16(except, rr)
+ return j >= len(except) || except[j] != rr
+ }
+
+ rr, rang, except := uint32(r), range32, except32
+ i := bsearch32(rang, rr)
+ if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
+ return false
+ }
+ j := bsearch32(except, rr)
+ return j >= len(except) || except[j] != rr
+}
+
+func scan(min, max rune) (rang, except []uint32) {
+ lo := rune(-1)
+ for i := min; ; i++ {
+ if (i > max || !unicode.IsPrint(i)) && lo >= 0 {
+ // End range, but avoid flip flop.
+ if i+1 <= max && unicode.IsPrint(i+1) {
+ except = append(except, uint32(i))
+ continue
+ }
+ rang = append(rang, uint32(lo), uint32(i-1))
+ lo = -1
+ }
+ if i > max {
+ break
+ }
+ if lo < 0 && unicode.IsPrint(i) {
+ lo = i
+ }
+ }
+ return
+}
+
+func to16(x []uint32) []uint16 {
+ var y []uint16
+ for _, v := range x {
+ if uint32(uint16(v)) != v {
+ panic("bad 32->16 conversion")
+ }
+ y = append(y, uint16(v))
+ }
+ return y
+}
+
+func main() {
+ rang, except := scan(0, 0xFFFF)
+ range16 = to16(rang)
+ except16 = to16(except)
+ range32, except32 = scan(0x10000, unicode.MaxRune)
+
+ for i := rune(0); i <= unicode.MaxRune; i++ {
+ if isPrint(i) != unicode.IsPrint(i) {
+ fmt.Fprintf(os.Stderr, "%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
+ return
+ }
+ }
+
+ fmt.Printf("// DO NOT EDIT. GENERATED BY\n")
+ fmt.Printf("// go run makeisprint.go >x && mv x isprint.go\n\n")
+ fmt.Printf("package strconv\n\n")
+
+ fmt.Printf("// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
+ len(range16), len(except16), len(except32),
+ len(range32),
+ (len(range16)+len(except16)+len(except32))*2+
+ (len(range32))*4)
+
+ fmt.Printf("var isPrint16 = []uint16{\n")
+ for i := 0; i < len(range16); i += 2 {
+ fmt.Printf("\t%#04x, %#04x,\n", range16[i], range16[i+1])
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isNotPrint16 = []uint16{\n")
+ for _, r := range except16 {
+ fmt.Printf("\t%#04x,\n", r)
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isPrint32 = []uint32{\n")
+ for i := 0; i < len(range32); i += 2 {
+ fmt.Printf("\t%#06x, %#06x,\n", range32[i], range32[i+1])
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
+ for _, r := range except32 {
+ if r >= 0x20000 {
+ fmt.Fprintf(os.Stderr, "%U too big for isNotPrint32\n", r)
+ return
+ }
+ fmt.Printf("\t%#04x,\n", r-0x10000)
+ }
+ fmt.Printf("}\n")
+}
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 05e49d32d..8a73f9d3b 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -5,118 +5,138 @@
package strconv
import (
- "bytes"
- "os"
- "strings"
- "unicode"
- "utf8"
+ "unicode/utf8"
)
const lowerhex = "0123456789abcdef"
func quoteWith(s string, quote byte, ASCIIonly bool) string {
- var buf bytes.Buffer
- buf.WriteByte(quote)
+ var runeTmp [utf8.UTFMax]byte
+ buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+ buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
- rune := int(s[0])
+ r := rune(s[0])
width = 1
- if rune >= utf8.RuneSelf {
- rune, width = utf8.DecodeRuneInString(s)
+ if r >= utf8.RuneSelf {
+ r, 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])
+ if width == 1 && r == utf8.RuneError {
+ buf = append(buf, `\x`...)
+ buf = append(buf, lowerhex[s[0]>>4])
+ buf = append(buf, lowerhex[s[0]&0xF])
continue
}
- if rune == int(quote) || rune == '\\' { // always backslashed
- buf.WriteByte('\\')
- buf.WriteByte(byte(rune))
+ if r == rune(quote) || r == '\\' { // always backslashed
+ buf = append(buf, '\\')
+ buf = append(buf, byte(r))
continue
}
if ASCIIonly {
- if rune <= unicode.MaxASCII && unicode.IsPrint(rune) {
- buf.WriteRune(rune)
+ if r < utf8.RuneSelf && IsPrint(r) {
+ buf = append(buf, byte(r))
continue
}
- } else if unicode.IsPrint(rune) {
- buf.WriteRune(rune)
+ } else if IsPrint(r) {
+ n := utf8.EncodeRune(runeTmp[:], r)
+ buf = append(buf, runeTmp[:n]...)
continue
}
- switch rune {
+ switch r {
case '\a':
- buf.WriteString(`\a`)
+ buf = append(buf, `\a`...)
case '\b':
- buf.WriteString(`\b`)
+ buf = append(buf, `\b`...)
case '\f':
- buf.WriteString(`\f`)
+ buf = append(buf, `\f`...)
case '\n':
- buf.WriteString(`\n`)
+ buf = append(buf, `\n`...)
case '\r':
- buf.WriteString(`\r`)
+ buf = append(buf, `\r`...)
case '\t':
- buf.WriteString(`\t`)
+ buf = append(buf, `\t`...)
case '\v':
- buf.WriteString(`\v`)
+ buf = append(buf, `\v`...)
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
+ case r < ' ':
+ buf = append(buf, `\x`...)
+ buf = append(buf, lowerhex[s[0]>>4])
+ buf = append(buf, lowerhex[s[0]&0xF])
+ case r > utf8.MaxRune:
+ r = 0xFFFD
fallthrough
- case rune < 0x10000:
- buf.WriteString(`\u`)
+ case r < 0x10000:
+ buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
- buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
- buf.WriteString(`\U`)
+ buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
- buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
}
- buf.WriteByte(quote)
- return buf.String()
+ buf = append(buf, quote)
+ return string(buf)
}
// 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.
+// IsPrint.
func Quote(s string) string {
return quoteWith(s, '"', false)
}
+// AppendQuote appends a double-quoted Go string literal representing s,
+// as generated by Quote, to dst and returns the extended buffer.
+func AppendQuote(dst []byte, s string) []byte {
+ return append(dst, Quote(s)...)
+}
+
// 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.
+// non-ASCII characters and non-printable characters as defined by IsPrint.
func QuoteToASCII(s string) string {
return quoteWith(s, '"', true)
}
+// AppendQuoteToASCII appends a double-quoted Go string literal representing s,
+// as generated by QuoteToASCII, to dst and returns the extended buffer.
+func AppendQuoteToASCII(dst []byte, s string) []byte {
+ return append(dst, QuoteToASCII(s)...)
+}
+
// 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 {
+// for control characters and non-printable characters as defined by IsPrint.
+func QuoteRune(r rune) string {
// TODO: avoid the allocation here.
- return quoteWith(string(rune), '\'', false)
+ return quoteWith(string(r), '\'', false)
+}
+
+// AppendQuoteRune appends a single-quoted Go character literal representing the rune,
+// as generated by QuoteRune, to dst and returns the extended buffer.
+func AppendQuoteRune(dst []byte, r rune) []byte {
+ return append(dst, QuoteRune(r)...)
}
// 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 {
+// by IsPrint.
+func QuoteRuneToASCII(r rune) string {
// TODO: avoid the allocation here.
- return quoteWith(string(rune), '\'', true)
+ return quoteWith(string(r), '\'', true)
+}
+
+// AppendQuoteRune appends a single-quoted Go character literal representing the rune,
+// as generated by QuoteRuneToASCII, to dst and returns the extended buffer.
+func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
+ return append(dst, QuoteRuneToASCII(r)...)
}
// CanBackquote returns whether the string s would be
@@ -130,8 +150,8 @@ func CanBackquote(s string) bool {
return true
}
-func unhex(b byte) (v int, ok bool) {
- c := int(b)
+func unhex(b byte) (v rune, ok bool) {
+ c := rune(b)
switch {
case '0' <= c && c <= '9':
return c - '0', true
@@ -157,22 +177,22 @@ func unhex(b byte) (v int, ok bool) {
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
// If set to a double quote, it permits \" and disallows unescaped ".
// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
-func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string, err os.Error) {
+func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
// easy cases
switch c := s[0]; {
case c == quote && (quote == '\'' || quote == '"'):
- err = os.EINVAL
+ err = ErrSyntax
return
case c >= utf8.RuneSelf:
r, size := utf8.DecodeRuneInString(s)
return r, true, s[size:], nil
case c != '\\':
- return int(s[0]), false, s[1:], nil
+ return rune(s[0]), false, s[1:], nil
}
// hard case: c is backslash
if len(s) <= 1 {
- err = os.EINVAL
+ err = ErrSyntax
return
}
c := s[1]
@@ -203,15 +223,15 @@ func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string,
case 'U':
n = 8
}
- v := 0
+ var v rune
if len(s) < n {
- err = os.EINVAL
+ err = ErrSyntax
return
}
for j := 0; j < n; j++ {
x, ok := unhex(s[j])
if !ok {
- err = os.EINVAL
+ err = ErrSyntax
return
}
v = v<<4 | x
@@ -222,28 +242,29 @@ func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string,
value = v
break
}
- if v > unicode.MaxRune {
- err = os.EINVAL
+ if v > utf8.MaxRune {
+ err = ErrSyntax
return
}
value = v
multibyte = true
case '0', '1', '2', '3', '4', '5', '6', '7':
- v := int(c) - '0'
+ v := rune(c) - '0'
if len(s) < 2 {
- err = os.EINVAL
+ err = ErrSyntax
return
}
for j := 0; j < 2; j++ { // one digit already; two more
- x := int(s[j]) - '0'
+ x := rune(s[j]) - '0'
if x < 0 || x > 7 {
+ err = ErrSyntax
return
}
v = (v << 3) | x
}
s = s[2:]
if v > 255 {
- err = os.EINVAL
+ err = ErrSyntax
return
}
value = v
@@ -251,12 +272,12 @@ func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string,
value = '\\'
case '\'', '"':
if c != quote {
- err = os.EINVAL
+ err = ErrSyntax
return
}
- value = int(c)
+ value = rune(c)
default:
- err = os.EINVAL
+ err = ErrSyntax
return
}
tail = s
@@ -268,28 +289,45 @@ func UnquoteChar(s string, quote byte) (value int, multibyte bool, tail string,
// that s quotes. (If s is single-quoted, it would be a Go
// character literal; Unquote returns the corresponding
// one-character string.)
-func Unquote(s string) (t string, err os.Error) {
+func Unquote(s string) (t string, err error) {
n := len(s)
if n < 2 {
- return "", os.EINVAL
+ return "", ErrSyntax
}
quote := s[0]
if quote != s[n-1] {
- return "", os.EINVAL
+ return "", ErrSyntax
}
s = s[1 : n-1]
if quote == '`' {
- if strings.Contains(s, "`") {
- return "", os.EINVAL
+ if contains(s, '`') {
+ return "", ErrSyntax
}
return s, nil
}
if quote != '"' && quote != '\'' {
- return "", os.EINVAL
+ return "", ErrSyntax
+ }
+ if contains(s, '\n') {
+ return "", ErrSyntax
}
- var buf bytes.Buffer
+ // Is it trivial? Avoid allocation.
+ if !contains(s, '\\') && !contains(s, quote) {
+ switch quote {
+ case '"':
+ return s, nil
+ case '\'':
+ r, size := utf8.DecodeRuneInString(s)
+ if size == len(s) && (r != utf8.RuneError || size != 1) {
+ return s, nil
+ }
+ }
+ }
+
+ var runeTmp [utf8.UTFMax]byte
+ buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
for len(s) > 0 {
c, multibyte, ss, err := UnquoteChar(s, quote)
if err != nil {
@@ -297,14 +335,107 @@ func Unquote(s string) (t string, err os.Error) {
}
s = ss
if c < utf8.RuneSelf || !multibyte {
- buf.WriteByte(byte(c))
+ buf = append(buf, byte(c))
} else {
- buf.WriteString(string(c))
+ n := utf8.EncodeRune(runeTmp[:], c)
+ buf = append(buf, runeTmp[:n]...)
}
if quote == '\'' && len(s) != 0 {
// single-quoted must be single character
- return "", os.EINVAL
+ return "", ErrSyntax
+ }
+ }
+ return string(buf), nil
+}
+
+// contains reports whether the string contains the byte c.
+func contains(s string, c byte) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return true
+ }
+ }
+ return false
+}
+
+// bsearch16 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch16 returns len(a).
+func bsearch16(a []uint16, x uint16) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
}
}
- return buf.String(), nil
+ return i
+}
+
+// bsearch32 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch32 returns len(a).
+func bsearch32(a []uint32, x uint32) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+// TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests
+// to give the same answer. It allows this package not to depend on unicode,
+// and therefore not pull in all the Unicode tables. If the linker were better
+// at tossing unused tables, we could get rid of this implementation.
+// That would be nice.
+
+// IsPrint reports whether the rune is defined as printable by Go, with
+// the same definition as unicode.IsPrint: letters, numbers, punctuation,
+// symbols and ASCII space.
+func IsPrint(r rune) bool {
+ // Fast check for Latin-1
+ if r <= 0xFF {
+ if 0x20 <= r && r <= 0x7E {
+ // All the ASCII is printable from space through DEL-1.
+ return true
+ }
+ if 0xA1 <= r && r <= 0xFF {
+ // Similarly for ¡ through ÿ...
+ return r != 0xAD // ...except for the bizarre soft hyphen.
+ }
+ return false
+ }
+
+ // Same algorithm, either on uint16 or uint32 value.
+ // First, find first i such that isPrint[i] >= x.
+ // This is the index of either the start or end of a pair that might span x.
+ // The start is even (isPrint[i&^1]) and the end is odd (isPrint[i|1]).
+ // If we find x in a range, make sure x is not in isNotPrint list.
+
+ if 0 <= r && r < 1<<16 {
+ rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16
+ i := bsearch16(isPrint, rr)
+ if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr {
+ return false
+ }
+ j := bsearch16(isNotPrint, rr)
+ return j >= len(isNotPrint) || isNotPrint[j] != rr
+ }
+
+ rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32
+ i := bsearch32(isPrint, rr)
+ if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr {
+ return false
+ }
+ if r >= 0x20000 {
+ return true
+ }
+ r -= 0x10000
+ j := bsearch16(isNotPrint, uint16(r))
+ return j >= len(isNotPrint) || isNotPrint[j] != uint16(r)
}
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 4d615db44..61d9bf9a5 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -5,11 +5,25 @@
package strconv_test
import (
- "os"
. "strconv"
"testing"
+ "unicode"
)
+// Verify that our isPrint agrees with unicode.IsPrint
+func TestIsPrint(t *testing.T) {
+ n := 0
+ for r := rune(0); r <= unicode.MaxRune; r++ {
+ if IsPrint(r) != unicode.IsPrint(r) {
+ t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r))
+ n++
+ if n > 10 {
+ return
+ }
+ }
+ }
+}
+
type quoteTest struct {
in string
out string
@@ -30,6 +44,9 @@ func TestQuote(t *testing.T) {
if out := Quote(tt.in); out != tt.out {
t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
}
+ if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
+ t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
+ }
}
}
@@ -38,11 +55,14 @@ func TestQuoteToASCII(t *testing.T) {
if out := QuoteToASCII(tt.in); out != tt.ascii {
t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
}
+ if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
+ t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
+ }
}
}
type quoteRuneTest struct {
- in int
+ in rune
out string
ascii string
}
@@ -64,6 +84,9 @@ func TestQuoteRune(t *testing.T) {
if out := QuoteRune(tt.in); out != tt.out {
t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
}
+ if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
+ t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
+ }
}
}
@@ -72,6 +95,9 @@ func TestQuoteRuneToASCII(t *testing.T) {
if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
}
+ if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
+ t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
+ }
}
}
@@ -168,6 +194,7 @@ var unquotetests = []unQuoteTest{
{"`\\xFF`", `\xFF`},
{"`\\377`", `\377`},
{"`\\`", `\`},
+ {"`\n`", "\n"},
{"` `", ` `},
{"` `", ` `},
}
@@ -179,7 +206,13 @@ var misquoted = []string{
`"'`,
`b"`,
`"\"`,
+ `"\9"`,
+ `"\19"`,
+ `"\129"`,
`'\'`,
+ `'\9'`,
+ `'\19'`,
+ `'\129'`,
`'ab'`,
`"\x1!"`,
`"\U12345678"`,
@@ -189,6 +222,9 @@ var misquoted = []string{
"`\"",
`"\'"`,
`'\"'`,
+ "\"\n\"",
+ "\"\\n\n\"",
+ "'\n'",
}
func TestUnquote(t *testing.T) {
@@ -206,8 +242,20 @@ func TestUnquote(t *testing.T) {
}
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)
+ if out, err := Unquote(s); out != "" || err != ErrSyntax {
+ t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", ErrSyntax)
}
}
}
+
+func BenchmarkUnquoteEasy(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Unquote(`"Give me a rock, paper and scissors and I will move the world."`)
+ }
+}
+
+func BenchmarkUnquoteHard(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`)
+ }
+}
diff --git a/src/pkg/strings/Makefile b/src/pkg/strings/Makefile
deleted file mode 100644
index c1be58243..000000000
--- a/src/pkg/strings/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=strings
-GOFILES=\
- reader.go\
- strings.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/strings/example_test.go b/src/pkg/strings/example_test.go
new file mode 100644
index 000000000..114171072
--- /dev/null
+++ b/src/pkg/strings/example_test.go
@@ -0,0 +1,182 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+ "fmt"
+ "strings"
+)
+
+func ExampleFields() {
+ fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz "))
+ // Output: Fields are: ["foo" "bar" "baz"]
+}
+
+func ExampleContains() {
+ fmt.Println(strings.Contains("seafood", "foo"))
+ fmt.Println(strings.Contains("seafood", "bar"))
+ fmt.Println(strings.Contains("seafood", ""))
+ fmt.Println(strings.Contains("", ""))
+ // Output:
+ // true
+ // false
+ // true
+ // true
+}
+
+func ExampleContainsAny() {
+ fmt.Println(strings.ContainsAny("team", "i"))
+ fmt.Println(strings.ContainsAny("failure", "u & i"))
+ fmt.Println(strings.ContainsAny("foo", ""))
+ fmt.Println(strings.ContainsAny("", ""))
+ // Output:
+ // false
+ // true
+ // false
+ // false
+}
+
+func ExampleCount() {
+ fmt.Println(strings.Count("cheese", "e"))
+ fmt.Println(strings.Count("five", "")) // before & after each rune
+
+ // Output:
+ // 3
+ // 5
+}
+
+func ExampleEqualFold() {
+ fmt.Println(strings.EqualFold("Go", "go"))
+ // Output: true
+}
+
+func ExampleIndex() {
+ fmt.Println(strings.Index("chicken", "ken"))
+ fmt.Println(strings.Index("chicken", "dmr"))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleIndexRune() {
+ fmt.Println(strings.IndexRune("chicken", 'k'))
+ fmt.Println(strings.IndexRune("chicken", 'd'))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleLastIndex() {
+ fmt.Println(strings.Index("go gopher", "go"))
+ fmt.Println(strings.LastIndex("go gopher", "go"))
+ fmt.Println(strings.LastIndex("go gopher", "rodent"))
+ // Output:
+ // 0
+ // 3
+ // -1
+}
+
+func ExampleJoin() {
+ s := []string{"foo", "bar", "baz"}
+ fmt.Println(strings.Join(s, ", "))
+ // Output: foo, bar, baz
+}
+
+func ExampleRepeat() {
+ fmt.Println("ba" + strings.Repeat("na", 2))
+ // Output: banana
+}
+
+func ExampleReplace() {
+ fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2))
+ fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1))
+ // Output:
+ // oinky oinky oink
+ // moo moo moo
+}
+
+func ExampleSplit() {
+ fmt.Printf("%q\n", strings.Split("a,b,c", ","))
+ fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
+ fmt.Printf("%q\n", strings.Split(" xyz ", ""))
+ fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
+ // Output:
+ // ["a" "b" "c"]
+ // ["" "man " "plan " "canal panama"]
+ // [" " "x" "y" "z" " "]
+ // [""]
+}
+
+func ExampleSplitN() {
+ fmt.Printf("%q\n", strings.SplitN("a,b,c", ",", 2))
+ z := strings.SplitN("a,b,c", ",", 0)
+ fmt.Printf("%q (nil = %v)\n", z, z == nil)
+ // Output:
+ // ["a" "b,c"]
+ // [] (nil = true)
+}
+
+func ExampleSplitAfter() {
+ fmt.Printf("%q\n", strings.SplitAfter("a,b,c", ","))
+ // Output: ["a," "b," "c"]
+}
+
+func ExampleSplitAfterN() {
+ fmt.Printf("%q\n", strings.SplitAfterN("a,b,c", ",", 2))
+ // Output: ["a," "b,c"]
+}
+
+func ExampleTitle() {
+ fmt.Println(strings.Title("her royal highness"))
+ // Output: Her Royal Highness
+}
+
+func ExampleToTitle() {
+ fmt.Println(strings.ToTitle("loud noises"))
+ fmt.Println(strings.ToTitle("хлеб"))
+ // Output:
+ // LOUD NOISES
+ // ХЛЕБ
+}
+
+func ExampleTrim() {
+ fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
+ // Output: ["Achtung"]
+}
+
+func ExampleMap() {
+ rot13 := func(r rune) rune {
+ switch {
+ case r >= 'A' && r <= 'Z':
+ return 'A' + (r-'A'+13)%26
+ case r >= 'a' && r <= 'z':
+ return 'a' + (r-'a'+13)%26
+ }
+ return r
+ }
+ fmt.Println(strings.Map(rot13, "'Twas brillig and the slithy gopher..."))
+ // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
+}
+
+func ExampleTrimSpace() {
+ fmt.Println(strings.TrimSpace(" \t\n a lone gopher \n\t\r\n"))
+ // Output: a lone gopher
+}
+
+func ExampleNewReplacer() {
+ r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
+ fmt.Println(r.Replace("This is <b>HTML</b>!"))
+ // Output: This is &lt;b&gt;HTML&lt;/b&gt;!
+}
+
+func ExampleToUpper() {
+ fmt.Println(strings.ToUpper("Gopher"))
+ // Output: GOPHER
+}
+
+func ExampleToLower() {
+ fmt.Println(strings.ToLower("Gopher"))
+ // Output: gopher
+}
diff --git a/src/pkg/strings/export_test.go b/src/pkg/strings/export_test.go
new file mode 100644
index 000000000..dcfec513c
--- /dev/null
+++ b/src/pkg/strings/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings
+
+func (r *Replacer) Replacer() interface{} {
+ return r.r
+}
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index eb515de00..856980555 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/strings/reader.go
@@ -5,12 +5,14 @@
package strings
import (
- "os"
- "utf8"
+ "errors"
+ "io"
+ "unicode/utf8"
)
-// A Reader implements the io.Reader, io.ByteScanner, and
-// io.RuneScanner interfaces by reading from a string.
+// A Reader implements the io.Reader, io.ReaderAt, io.Seeker,
+// io.ByteScanner, and io.RuneScanner interfaces by reading
+// from a string.
type Reader struct {
s string
i int // current reading index
@@ -20,12 +22,18 @@ type Reader struct {
// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int {
+ if r.i >= len(r.s) {
+ return 0
+ }
return len(r.s) - r.i
}
-func (r *Reader) Read(b []byte) (n int, err os.Error) {
+func (r *Reader) Read(b []byte) (n int, err error) {
+ if len(b) == 0 {
+ return 0, nil
+ }
if r.i >= len(r.s) {
- return 0, os.EOF
+ return 0, io.EOF
}
n = copy(b, r.s[r.i:])
r.i += n
@@ -33,9 +41,23 @@ func (r *Reader) Read(b []byte) (n int, err os.Error) {
return
}
-func (r *Reader) ReadByte() (b byte, err os.Error) {
+func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+ if off < 0 {
+ return 0, errors.New("strings: invalid offset")
+ }
+ if off >= int64(len(r.s)) {
+ return 0, io.EOF
+ }
+ n = copy(b, r.s[int(off):])
+ if n < len(b) {
+ err = io.EOF
+ }
+ return
+}
+
+func (r *Reader) ReadByte() (b byte, err error) {
if r.i >= len(r.s) {
- return 0, os.EOF
+ return 0, io.EOF
}
b = r.s[r.i]
r.i++
@@ -43,49 +65,61 @@ func (r *Reader) ReadByte() (b byte, err os.Error) {
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 {
+func (r *Reader) UnreadByte() error {
if r.i <= 0 {
- return os.NewError("strings.Reader: at beginning of string")
+ return errors.New("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) {
+func (r *Reader) ReadRune() (ch rune, size int, err error) {
if r.i >= len(r.s) {
- return 0, 0, os.EOF
+ return 0, 0, io.EOF
}
r.prevRune = r.i
if c := r.s[r.i]; c < utf8.RuneSelf {
r.i++
- return int(c), 1, nil
+ return rune(c), 1, nil
}
- rune, size = utf8.DecodeRuneInString(r.s[r.i:])
+ ch, 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 {
+func (r *Reader) UnreadRune() error {
if r.prevRune < 0 {
- return os.NewError("strings.Reader: previous operation was not ReadRune")
+ return errors.New("strings.Reader: previous operation was not ReadRune")
}
r.i = r.prevRune
r.prevRune = -1
return nil
}
+// Seek implements the io.Seeker interface.
+func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+ var abs int64
+ switch whence {
+ case 0:
+ abs = offset
+ case 1:
+ abs = int64(r.i) + offset
+ case 2:
+ abs = int64(len(r.s)) + offset
+ default:
+ return 0, errors.New("strings: invalid whence")
+ }
+ if abs < 0 {
+ return 0, errors.New("strings: negative position")
+ }
+ if abs >= 1<<31 {
+ return 0, errors.New("strings: position out of range")
+ }
+ r.i = int(abs)
+ return abs, 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, 0, -1} }
diff --git a/src/pkg/strings/reader_test.go b/src/pkg/strings/reader_test.go
new file mode 100644
index 000000000..a99ae2a0e
--- /dev/null
+++ b/src/pkg/strings/reader_test.go
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestReader(t *testing.T) {
+ r := strings.NewReader("0123456789")
+ tests := []struct {
+ off int64
+ seek int
+ n int
+ want string
+ wantpos int64
+ seekerr string
+ }{
+ {seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
+ {seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
+ {seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
+ {seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"},
+ {seek: os.SEEK_SET, off: 1<<31 - 1},
+ {seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"},
+ {seek: os.SEEK_SET, n: 5, want: "01234"},
+ {seek: os.SEEK_CUR, n: 5, want: "56789"},
+ {seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+ }
+
+ for i, tt := range tests {
+ pos, err := r.Seek(tt.off, tt.seek)
+ if err == nil && tt.seekerr != "" {
+ t.Errorf("%d. want seek error %q", i, tt.seekerr)
+ continue
+ }
+ if err != nil && err.Error() != tt.seekerr {
+ t.Errorf("%d. seek error = %q; want %q", i, err.Error(), tt.seekerr)
+ continue
+ }
+ if tt.wantpos != 0 && tt.wantpos != pos {
+ t.Errorf("%d. pos = %d, want %d", i, pos, tt.wantpos)
+ }
+ buf := make([]byte, tt.n)
+ n, err := r.Read(buf)
+ if err != nil {
+ t.Errorf("%d. read = %v", i, err)
+ continue
+ }
+ got := string(buf[:n])
+ if got != tt.want {
+ t.Errorf("%d. got %q; want %q", i, got, tt.want)
+ }
+ }
+}
+
+func TestReaderAt(t *testing.T) {
+ r := strings.NewReader("0123456789")
+ tests := []struct {
+ off int64
+ n int
+ want string
+ wanterr interface{}
+ }{
+ {0, 10, "0123456789", nil},
+ {1, 10, "123456789", io.EOF},
+ {1, 9, "123456789", nil},
+ {11, 10, "", io.EOF},
+ {0, 0, "", nil},
+ {-1, 0, "", "strings: invalid offset"},
+ }
+ for i, tt := range tests {
+ b := make([]byte, tt.n)
+ rn, err := r.ReadAt(b, tt.off)
+ got := string(b[:rn])
+ if got != tt.want {
+ t.Errorf("%d. got %q; want %q", i, got, tt.want)
+ }
+ if fmt.Sprintf("%v", err) != fmt.Sprintf("%v", tt.wanterr) {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.wanterr)
+ }
+ }
+}
diff --git a/src/pkg/strings/replace.go b/src/pkg/strings/replace.go
new file mode 100644
index 000000000..f53a96ee0
--- /dev/null
+++ b/src/pkg/strings/replace.go
@@ -0,0 +1,312 @@
+// 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 strings
+
+import "io"
+
+// A Replacer replaces a list of strings with replacements.
+type Replacer struct {
+ r replacer
+}
+
+// replacer is the interface that a replacement algorithm needs to implement.
+type replacer interface {
+ Replace(s string) string
+ WriteString(w io.Writer, s string) (n int, err error)
+}
+
+// byteBitmap represents bytes which are sought for replacement.
+// byteBitmap is 256 bits wide, with a bit set for each old byte to be
+// replaced.
+type byteBitmap [256 / 32]uint32
+
+func (m *byteBitmap) set(b byte) {
+ m[b>>5] |= uint32(1 << (b & 31))
+}
+
+// NewReplacer returns a new Replacer from a list of old, new string pairs.
+// Replacements are performed in order, without overlapping matches.
+func NewReplacer(oldnew ...string) *Replacer {
+ if len(oldnew)%2 == 1 {
+ panic("strings.NewReplacer: odd argument count")
+ }
+
+ // Possible implementations.
+ var (
+ bb byteReplacer
+ bs byteStringReplacer
+ gen genericReplacer
+ )
+
+ allOldBytes, allNewBytes := true, true
+ for len(oldnew) > 0 {
+ old, new := oldnew[0], oldnew[1]
+ oldnew = oldnew[2:]
+ if len(old) != 1 {
+ allOldBytes = false
+ }
+ if len(new) != 1 {
+ allNewBytes = false
+ }
+
+ // generic
+ gen.p = append(gen.p, pair{old, new})
+
+ // byte -> string
+ if allOldBytes {
+ bs.old.set(old[0])
+ bs.new[old[0]] = []byte(new)
+ }
+
+ // byte -> byte
+ if allOldBytes && allNewBytes {
+ bb.old.set(old[0])
+ bb.new[old[0]] = new[0]
+ }
+ }
+
+ if allOldBytes && allNewBytes {
+ return &Replacer{r: &bb}
+ }
+ if allOldBytes {
+ return &Replacer{r: &bs}
+ }
+ return &Replacer{r: &gen}
+}
+
+// Replace returns a copy of s with all replacements performed.
+func (r *Replacer) Replace(s string) string {
+ return r.r.Replace(s)
+}
+
+// WriteString writes s to w with all replacements performed.
+func (r *Replacer) WriteString(w io.Writer, s string) (n int, err error) {
+ return r.r.WriteString(w, s)
+}
+
+// genericReplacer is the fully generic (and least optimized) algorithm.
+// It's used as a fallback when nothing faster can be used.
+type genericReplacer struct {
+ p []pair
+}
+
+type pair struct{ old, new string }
+
+type appendSliceWriter struct {
+ b []byte
+}
+
+func (w *appendSliceWriter) Write(p []byte) (int, error) {
+ w.b = append(w.b, p...)
+ return len(p), nil
+}
+
+func (r *genericReplacer) Replace(s string) string {
+ // TODO(bradfitz): optimized version
+ n, _ := r.WriteString(discard, s)
+ w := appendSliceWriter{make([]byte, 0, n)}
+ r.WriteString(&w, s)
+ return string(w.b)
+}
+
+func (r *genericReplacer) WriteString(w io.Writer, s string) (n int, err error) {
+ lastEmpty := false // the last replacement was of the empty string
+Input:
+ // TODO(bradfitz): optimized version
+ for i := 0; i < len(s); {
+ for _, p := range r.p {
+ if p.old == "" && lastEmpty {
+ // Don't let old match twice in a row.
+ // (it doesn't advance the input and
+ // would otherwise loop forever)
+ continue
+ }
+ if HasPrefix(s[i:], p.old) {
+ if p.new != "" {
+ wn, err := w.Write([]byte(p.new))
+ n += wn
+ if err != nil {
+ return n, err
+ }
+ }
+ i += len(p.old)
+ lastEmpty = p.old == ""
+ continue Input
+ }
+ }
+ wn, err := w.Write([]byte{s[i]})
+ n += wn
+ if err != nil {
+ return n, err
+ }
+ i++
+ }
+
+ // Final empty match at end.
+ for _, p := range r.p {
+ if p.old == "" {
+ if p.new != "" {
+ wn, err := w.Write([]byte(p.new))
+ n += wn
+ if err != nil {
+ return n, err
+ }
+ }
+ break
+ }
+ }
+
+ return n, nil
+}
+
+// byteReplacer is the implementation that's used when all the "old"
+// and "new" values are single ASCII bytes.
+type byteReplacer struct {
+ // old has a bit set for each old byte that should be replaced.
+ old byteBitmap
+
+ // replacement byte, indexed by old byte. only valid if
+ // corresponding old bit is set.
+ new [256]byte
+}
+
+func (r *byteReplacer) Replace(s string) string {
+ var buf []byte // lazily allocated
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ if buf == nil {
+ buf = []byte(s)
+ }
+ buf[i] = r.new[b]
+ }
+ }
+ if buf == nil {
+ return s
+ }
+ return string(buf)
+}
+
+func (r *byteReplacer) WriteString(w io.Writer, s string) (n int, err error) {
+ // TODO(bradfitz): use io.WriteString with slices of s, avoiding allocation.
+ bufsize := 32 << 10
+ if len(s) < bufsize {
+ bufsize = len(s)
+ }
+ buf := make([]byte, bufsize)
+
+ for len(s) > 0 {
+ ncopy := copy(buf, s[:])
+ s = s[ncopy:]
+ for i, b := range buf[:ncopy] {
+ if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ buf[i] = r.new[b]
+ }
+ }
+ wn, err := w.Write(buf[:ncopy])
+ n += wn
+ if err != nil {
+ return n, err
+ }
+ }
+ return n, nil
+}
+
+// byteStringReplacer is the implementation that's used when all the
+// "old" values are single ASCII bytes but the "new" values vary in
+// size.
+type byteStringReplacer struct {
+ // old has a bit set for each old byte that should be replaced.
+ old byteBitmap
+
+ // replacement string, indexed by old byte. only valid if
+ // corresponding old bit is set.
+ new [256][]byte
+}
+
+func (r *byteStringReplacer) Replace(s string) string {
+ newSize := 0
+ anyChanges := false
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ anyChanges = true
+ newSize += len(r.new[b])
+ } else {
+ newSize++
+ }
+ }
+ if !anyChanges {
+ return s
+ }
+ buf := make([]byte, newSize)
+ bi := buf
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ n := copy(bi[:], r.new[b])
+ bi = bi[n:]
+ } else {
+ bi[0] = b
+ bi = bi[1:]
+ }
+ }
+ return string(buf)
+}
+
+// WriteString maintains one buffer that's at most 32KB. The bytes in
+// s are enumerated and the buffer is filled. If it reaches its
+// capacity or a byte has a replacement, the buffer is flushed to w.
+func (r *byteStringReplacer) WriteString(w io.Writer, s string) (n int, err error) {
+ // TODO(bradfitz): use io.WriteString with slices of s instead.
+ bufsize := 32 << 10
+ if len(s) < bufsize {
+ bufsize = len(s)
+ }
+ buf := make([]byte, bufsize)
+ bi := buf[:0]
+
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ var new []byte
+ if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
+ new = r.new[b]
+ } else {
+ bi = append(bi, b)
+ }
+ if len(bi) == cap(bi) || (len(bi) > 0 && len(new) > 0) {
+ nw, err := w.Write(bi)
+ n += nw
+ if err != nil {
+ return n, err
+ }
+ bi = buf[:0]
+ }
+ if len(new) > 0 {
+ nw, err := w.Write(new)
+ n += nw
+ if err != nil {
+ return n, err
+ }
+ }
+ }
+ if len(bi) > 0 {
+ nw, err := w.Write(bi)
+ n += nw
+ if err != nil {
+ return n, err
+ }
+ }
+ return n, nil
+}
+
+// strings is too low-level to import io/ioutil
+var discard io.Writer = devNull(0)
+
+type devNull int
+
+func (devNull) Write(p []byte) (int, error) {
+ return len(p), nil
+}
diff --git a/src/pkg/strings/replace_test.go b/src/pkg/strings/replace_test.go
new file mode 100644
index 000000000..23c7e2e53
--- /dev/null
+++ b/src/pkg/strings/replace_test.go
@@ -0,0 +1,174 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ . "strings"
+ "testing"
+)
+
+var _ = log.Printf
+
+type ReplacerTest struct {
+ r *Replacer
+ in string
+ out string
+}
+
+var htmlEscaper = NewReplacer("&", "&amp;", "<", "&lt;", ">", "&gt;", "\"", "&quot;")
+
+// The http package's old HTML escaping function.
+func oldhtmlEscape(s string) string {
+ s = Replace(s, "&", "&amp;", -1)
+ s = Replace(s, "<", "&lt;", -1)
+ s = Replace(s, ">", "&gt;", -1)
+ s = Replace(s, "\"", "&quot;", -1)
+ s = Replace(s, "'", "&apos;", -1)
+ return s
+}
+
+var replacer = NewReplacer("aaa", "3[aaa]", "aa", "2[aa]", "a", "1[a]", "i", "i",
+ "longerst", "most long", "longer", "medium", "long", "short",
+ "X", "Y", "Y", "Z")
+
+var capitalLetters = NewReplacer("a", "A", "b", "B")
+
+var blankToXReplacer = NewReplacer("", "X", "o", "O")
+
+var ReplacerTests = []ReplacerTest{
+ // byte->string
+ {htmlEscaper, "No changes", "No changes"},
+ {htmlEscaper, "I <3 escaping & stuff", "I &lt;3 escaping &amp; stuff"},
+ {htmlEscaper, "&&&", "&amp;&amp;&amp;"},
+
+ // generic
+ {replacer, "fooaaabar", "foo3[aaa]b1[a]r"},
+ {replacer, "long, longerst, longer", "short, most long, medium"},
+ {replacer, "XiX", "YiY"},
+
+ // byte->byte
+ {capitalLetters, "brad", "BrAd"},
+ {capitalLetters, Repeat("a", (32<<10)+123), Repeat("A", (32<<10)+123)},
+
+ // hitting "" special case
+ {blankToXReplacer, "oo", "XOXOX"},
+}
+
+func TestReplacer(t *testing.T) {
+ for i, tt := range ReplacerTests {
+ if s := tt.r.Replace(tt.in); s != tt.out {
+ t.Errorf("%d. Replace(%q) = %q, want %q", i, tt.in, s, tt.out)
+ }
+ var buf bytes.Buffer
+ n, err := tt.r.WriteString(&buf, tt.in)
+ if err != nil {
+ t.Errorf("%d. WriteString: %v", i, err)
+ continue
+ }
+ got := buf.String()
+ if got != tt.out {
+ t.Errorf("%d. WriteString(%q) wrote %q, want %q", i, tt.in, got, tt.out)
+ continue
+ }
+ if n != len(tt.out) {
+ t.Errorf("%d. WriteString(%q) wrote correct string but reported %d bytes; want %d (%q)",
+ i, tt.in, n, len(tt.out), tt.out)
+ }
+ }
+}
+
+// pickAlgorithmTest is a test that verifies that given input for a
+// Replacer that we pick the correct algorithm.
+type pickAlgorithmTest struct {
+ r *Replacer
+ want string // name of algorithm
+}
+
+var pickAlgorithmTests = []pickAlgorithmTest{
+ {capitalLetters, "*strings.byteReplacer"},
+ {NewReplacer("12", "123"), "*strings.genericReplacer"},
+ {NewReplacer("1", "12"), "*strings.byteStringReplacer"},
+ {htmlEscaper, "*strings.byteStringReplacer"},
+}
+
+func TestPickAlgorithm(t *testing.T) {
+ for i, tt := range pickAlgorithmTests {
+ got := fmt.Sprintf("%T", tt.r.Replacer())
+ if got != tt.want {
+ t.Errorf("%d. algorithm = %s, want %s", i, got, tt.want)
+ }
+ }
+}
+
+func BenchmarkGenericMatch(b *testing.B) {
+ str := Repeat("A", 100) + Repeat("B", 100)
+ generic := NewReplacer("a", "A", "b", "B", "12", "123") // varying lengths forces generic
+ for i := 0; i < b.N; i++ {
+ generic.Replace(str)
+ }
+}
+
+func BenchmarkByteByteNoMatch(b *testing.B) {
+ str := Repeat("A", 100) + Repeat("B", 100)
+ for i := 0; i < b.N; i++ {
+ capitalLetters.Replace(str)
+ }
+}
+
+func BenchmarkByteByteMatch(b *testing.B) {
+ str := Repeat("a", 100) + Repeat("b", 100)
+ for i := 0; i < b.N; i++ {
+ capitalLetters.Replace(str)
+ }
+}
+
+func BenchmarkByteStringMatch(b *testing.B) {
+ str := "<" + Repeat("a", 99) + Repeat("b", 99) + ">"
+ for i := 0; i < b.N; i++ {
+ htmlEscaper.Replace(str)
+ }
+}
+
+func BenchmarkHTMLEscapeNew(b *testing.B) {
+ str := "I <3 to escape HTML & other text too."
+ for i := 0; i < b.N; i++ {
+ htmlEscaper.Replace(str)
+ }
+}
+
+func BenchmarkHTMLEscapeOld(b *testing.B) {
+ str := "I <3 to escape HTML & other text too."
+ for i := 0; i < b.N; i++ {
+ oldhtmlEscape(str)
+ }
+}
+
+// BenchmarkByteByteReplaces compares byteByteImpl against multiple Replaces.
+func BenchmarkByteByteReplaces(b *testing.B) {
+ str := Repeat("a", 100) + Repeat("b", 100)
+ for i := 0; i < b.N; i++ {
+ Replace(Replace(str, "a", "A", -1), "b", "B", -1)
+ }
+}
+
+// BenchmarkByteByteMap compares byteByteImpl against Map.
+func BenchmarkByteByteMap(b *testing.B) {
+ str := Repeat("a", 100) + Repeat("b", 100)
+ fn := func(r rune) rune {
+ switch r {
+ case 'a':
+ return 'A'
+ case 'b':
+ return 'B'
+ }
+ return r
+ }
+ for i := 0; i < b.N; i++ {
+ Map(fn, str)
+ }
+}
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index c547297e6..b411ba5d8 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -7,7 +7,7 @@ package strings
import (
"unicode"
- "utf8"
+ "unicode/utf8"
)
// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
@@ -21,11 +21,12 @@ func explode(s string, n int) []string {
n = l
}
a := make([]string, n)
- var size, rune int
+ var size int
+ var ch rune
i, cur := 0, 0
for ; i+1 < n; i++ {
- rune, size = utf8.DecodeRuneInString(s[cur:])
- a[i] = string(rune)
+ ch, size = utf8.DecodeRuneInString(s[cur:])
+ a[i] = string(ch)
cur += size
}
// add the rest, if there is any
@@ -63,7 +64,17 @@ func Count(s, sep string) int {
// Contains returns true if substr is within s.
func Contains(s, substr string) bool {
- return Index(s, substr) != -1
+ return Index(s, substr) >= 0
+}
+
+// ContainsAny returns true if any Unicode code points in chars are within s.
+func ContainsAny(s, chars string) bool {
+ return IndexAny(s, chars) >= 0
+}
+
+// ContainsRune returns true if the Unicode code point r is within s.
+func ContainsRune(s string, r rune) bool {
+ return IndexRune(s, r) >= 0
}
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
@@ -117,11 +128,11 @@ func LastIndex(s, sep string) int {
}
// IndexRune returns the index of the first instance of the Unicode code point
-// rune, or -1 if rune is not present in s.
-func IndexRune(s string, rune int) int {
+// r, or -1 if rune is not present in s.
+func IndexRune(s string, r rune) int {
switch {
- case rune < 0x80:
- b := byte(rune)
+ case r < 0x80:
+ b := byte(r)
for i := 0; i < len(s); i++ {
if s[i] == b {
return i
@@ -129,7 +140,7 @@ func IndexRune(s string, rune int) int {
}
default:
for i, c := range s {
- if c == rune {
+ if c == r {
return i
}
}
@@ -241,7 +252,7 @@ func Fields(s string) []string {
// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
// and returns an array of slices of s. If all code points in s satisfy f(c) or the
// string is empty, an empty slice is returned.
-func FieldsFunc(s string, f func(int) bool) []string {
+func FieldsFunc(s string, f func(rune) bool) []string {
// First count the fields.
n := 0
inField := false
@@ -268,7 +279,7 @@ func FieldsFunc(s string, f func(int) bool) []string {
fieldStart = i
}
}
- if fieldStart != -1 { // Last field might end at EOF.
+ if fieldStart >= 0 { // Last field might end at EOF.
a[na] = s[fieldStart:]
}
return a
@@ -310,7 +321,7 @@ func HasSuffix(s, suffix string) bool {
// Map returns a copy of the string s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement.
-func Map(mapping func(rune int) int, s string) string {
+func Map(mapping func(rune) rune, s string) string {
// In the worst case, the string can grow when mapped, making
// things unpleasant. But it's so rare we barge in assuming it's
// fine. It could also shrink but that falls out naturally.
@@ -321,18 +332,18 @@ func Map(mapping func(rune int) int, s string) string {
var b []byte
for i, c := range s {
- rune := mapping(c)
+ r := mapping(c)
if b == nil {
- if rune == c {
+ if r == c {
continue
}
b = make([]byte, maxbytes)
nbytes = copy(b, s[:i])
}
- if rune >= 0 {
+ if r >= 0 {
wid := 1
- if rune >= utf8.RuneSelf {
- wid = utf8.RuneLen(rune)
+ if r >= utf8.RuneSelf {
+ wid = utf8.RuneLen(r)
}
if nbytes+wid > maxbytes {
// Grow the buffer.
@@ -341,7 +352,7 @@ func Map(mapping func(rune int) int, s string) string {
copy(nb, b[0:nbytes])
b = nb
}
- nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], r)
}
}
if b == nil {
@@ -375,44 +386,44 @@ func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r int) int { return _case.ToUpper(r) }, s)
+ return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r int) int { return _case.ToLower(r) }, s)
+ return Map(func(r rune) rune { return _case.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r int) int { return _case.ToTitle(r) }, s)
+ return Map(func(r rune) rune { 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 {
+func isSeparator(r rune) bool {
// ASCII alphanumerics and underscore are not separators
- if rune <= 0x7F {
+ if r <= 0x7F {
switch {
- case '0' <= rune && rune <= '9':
+ case '0' <= r && r <= '9':
return false
- case 'a' <= rune && rune <= 'z':
+ case 'a' <= r && r <= 'z':
return false
- case 'A' <= rune && rune <= 'Z':
+ case 'A' <= r && r <= 'Z':
return false
- case rune == '_':
+ case r == '_':
return false
}
return true
}
// Letters and digits are not separators
- if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ if unicode.IsLetter(r) || unicode.IsDigit(r) {
return false
}
// Otherwise, all we can do for now is treat spaces as separators.
- return unicode.IsSpace(rune)
+ return unicode.IsSpace(r)
}
// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
@@ -425,7 +436,7 @@ func Title(s string) string {
// the closure once per rune.
prev := ' '
return Map(
- func(r int) int {
+ func(r rune) rune {
if isSeparator(prev) {
prev = r
return unicode.ToTitle(r)
@@ -438,7 +449,7 @@ func Title(s string) string {
// TrimLeftFunc returns a slice of the string s with all leading
// Unicode code points c satisfying f(c) removed.
-func TrimLeftFunc(s string, f func(r int) bool) string {
+func TrimLeftFunc(s string, f func(rune) bool) string {
i := indexFunc(s, f, false)
if i == -1 {
return ""
@@ -448,7 +459,7 @@ func TrimLeftFunc(s string, f func(r int) bool) string {
// TrimRightFunc returns a slice of the string s with all trailing
// Unicode code points c satisfying f(c) removed.
-func TrimRightFunc(s string, f func(r int) bool) string {
+func TrimRightFunc(s string, f func(rune) bool) string {
i := lastIndexFunc(s, f, false)
if i >= 0 && s[i] >= utf8.RuneSelf {
_, wid := utf8.DecodeRuneInString(s[i:])
@@ -461,34 +472,34 @@ func TrimRightFunc(s string, f func(r int) bool) string {
// TrimFunc returns a slice of the string s with all leading
// and trailing Unicode code points c satisfying f(c) removed.
-func TrimFunc(s string, f func(r int) bool) string {
+func TrimFunc(s string, f func(rune) bool) string {
return TrimRightFunc(TrimLeftFunc(s, f), f)
}
// IndexFunc returns the index into s of the first Unicode
// code point satisfying f(c), or -1 if none do.
-func IndexFunc(s string, f func(r int) bool) int {
+func IndexFunc(s string, f func(rune) bool) int {
return indexFunc(s, f, true)
}
// LastIndexFunc returns the index into s of the last
// Unicode code point satisfying f(c), or -1 if none do.
-func LastIndexFunc(s string, f func(r int) bool) int {
+func LastIndexFunc(s string, f func(rune) bool) int {
return lastIndexFunc(s, f, true)
}
// indexFunc is the same as IndexFunc except that if
// truth==false, the sense of the predicate function is
// inverted.
-func indexFunc(s string, f func(r int) bool, truth bool) int {
+func indexFunc(s string, f func(rune) bool, truth bool) int {
start := 0
for start < len(s) {
wid := 1
- rune := int(s[start])
- if rune >= utf8.RuneSelf {
- rune, wid = utf8.DecodeRuneInString(s[start:])
+ r := rune(s[start])
+ if r >= utf8.RuneSelf {
+ r, wid = utf8.DecodeRuneInString(s[start:])
}
- if f(rune) == truth {
+ if f(r) == truth {
return start
}
start += wid
@@ -499,19 +510,19 @@ func indexFunc(s string, f func(r int) bool, truth bool) int {
// lastIndexFunc is the same as LastIndexFunc except that if
// truth==false, the sense of the predicate function is
// inverted.
-func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
+func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
for i := len(s); i > 0; {
- rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ r, size := utf8.DecodeLastRuneInString(s[0:i])
i -= size
- if f(rune) == truth {
+ if f(r) == truth {
return i
}
}
return -1
}
-func makeCutsetFunc(cutset string) func(rune int) bool {
- return func(rune int) bool { return IndexRune(cutset, rune) != -1 }
+func makeCutsetFunc(cutset string) func(rune) bool {
+ return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}
// Trim returns a slice of the string s with all leading and
@@ -583,3 +594,58 @@ func Replace(s, old, new string, n int) string {
w += copy(t[w:], s[start:])
return string(t[0:w])
}
+
+// EqualFold reports whether s and t, interpreted as UTF-8 strings,
+// are equal under Unicode case-folding.
+func EqualFold(s, t string) bool {
+ for s != "" && t != "" {
+ // Extract first rune from each string.
+ var sr, tr rune
+ if s[0] < utf8.RuneSelf {
+ sr, s = rune(s[0]), s[1:]
+ } else {
+ r, size := utf8.DecodeRuneInString(s)
+ sr, s = r, s[size:]
+ }
+ if t[0] < utf8.RuneSelf {
+ tr, t = rune(t[0]), t[1:]
+ } else {
+ r, size := utf8.DecodeRuneInString(t)
+ tr, t = r, t[size:]
+ }
+
+ // If they match, keep going; if not, return false.
+
+ // Easy case.
+ if tr == sr {
+ continue
+ }
+
+ // Make sr < tr to simplify what follows.
+ if tr < sr {
+ tr, sr = sr, tr
+ }
+ // Fast check for ASCII.
+ if tr < utf8.RuneSelf && 'A' <= sr && sr <= 'Z' {
+ // ASCII, and sr is upper case. tr must be lower case.
+ if tr == sr+'a'-'A' {
+ continue
+ }
+ return false
+ }
+
+ // General case. SimpleFold(x) returns the next equivalent rune > x
+ // or wraps around to smaller values.
+ r := unicode.SimpleFold(sr)
+ for r != sr && r < tr {
+ r = unicode.SimpleFold(r)
+ }
+ if r == tr {
+ continue
+ }
+ return false
+ }
+
+ // One string is empty. Are both?
+ return s == t
+}
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index 409d4da0e..54046d68a 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -6,14 +6,13 @@ package strings_test
import (
"bytes"
- "os"
+ "io"
"reflect"
- "strconv"
. "strings"
"testing"
"unicode"
+ "unicode/utf8"
"unsafe"
- "utf8"
)
func eq(a, b []string) bool {
@@ -120,13 +119,11 @@ func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", l
func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
-type IndexRuneTest struct {
+var indexRuneTests = []struct {
s string
- rune int
+ rune rune
out int
-}
-
-var indexRuneTests = []IndexRuneTest{
+}{
{"a A x", 'A', 2},
{"some_text=some_value", '=', 9},
{"☺a", 'a', 3},
@@ -145,7 +142,7 @@ const benchmarkString = "some_text=some☺value"
func BenchmarkIndexRune(b *testing.B) {
if got := IndexRune(benchmarkString, '☺'); got != 14 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 14, got=%d", got)
}
for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, '☺')
@@ -154,7 +151,7 @@ func BenchmarkIndexRune(b *testing.B) {
func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 17, got=%d", got)
}
for i := 0; i < b.N; i++ {
IndexRune(benchmarkString, 'v')
@@ -163,20 +160,18 @@ func BenchmarkIndexRuneFastPath(b *testing.B) {
func BenchmarkIndex(b *testing.B) {
if got := Index(benchmarkString, "v"); got != 17 {
- panic("wrong index: got=" + strconv.Itoa(got))
+ b.Fatalf("wrong index: expected 17, got=%d", got)
}
for i := 0; i < b.N; i++ {
Index(benchmarkString, "v")
}
}
-type ExplodeTest struct {
+var explodetests = []struct {
s string
n int
a []string
-}
-
-var explodetests = []ExplodeTest{
+}{
{"", -1, []string{}},
{abcd, 4, []string{"a", "b", "c", "d"}},
{faces, 3, []string{"☺", "☻", "☹"}},
@@ -308,15 +303,16 @@ func TestFields(t *testing.T) {
}
}
+var FieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+}
+
func TestFieldsFunc(t *testing.T) {
- pred := func(c int) bool { return c == 'X' }
- var fieldsFuncTests = []FieldsTest{
- {"", []string{}},
- {"XX", []string{}},
- {"XXhiXXX", []string{"hi"}},
- {"aXXbXXXcX", []string{"a", "b", "c"}},
- }
- for _, tt := range fieldsFuncTests {
+ pred := func(c rune) bool { return c == 'X' }
+ for _, tt := range FieldsFuncTests {
a := FieldsFunc(tt.s, pred)
if !eq(a, tt.a) {
t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
@@ -377,31 +373,31 @@ var trimSpaceTests = []StringTest{
{"x ☺ ", "x ☺"},
}
-func tenRunes(rune int) string {
- r := make([]int, 10)
+func tenRunes(ch rune) string {
+ r := make([]rune, 10)
for i := range r {
- r[i] = rune
+ r[i] = ch
}
return string(r)
}
// User-defined self-inverse mapping function
-func rot13(rune int) int {
- step := 13
- if rune >= 'a' && rune <= 'z' {
- return ((rune - 'a' + step) % 26) + 'a'
+func rot13(r rune) rune {
+ step := rune(13)
+ if r >= 'a' && r <= 'z' {
+ return ((r - 'a' + step) % 26) + 'a'
}
- if rune >= 'A' && rune <= 'Z' {
- return ((rune - 'A' + step) % 26) + 'A'
+ if r >= 'A' && r <= 'Z' {
+ return ((r - 'A' + step) % 26) + 'A'
}
- return rune
+ return r
}
func TestMap(t *testing.T) {
// Run a couple of awful growth/shrinkage tests
a := tenRunes('a')
// 1. Grow. This triggers two reallocations in Map.
- maxRune := func(rune int) int { return unicode.MaxRune }
+ maxRune := func(rune) rune { return unicode.MaxRune }
m := Map(maxRune, a)
expect := tenRunes(unicode.MaxRune)
if m != expect {
@@ -409,7 +405,7 @@ func TestMap(t *testing.T) {
}
// 2. Shrink
- minRune := func(rune int) int { return 'a' }
+ minRune := func(rune) rune { return 'a' }
m = Map(minRune, tenRunes(unicode.MaxRune))
expect = a
if m != expect {
@@ -431,9 +427,9 @@ func TestMap(t *testing.T) {
}
// 5. Drop
- dropNotLatin := func(rune int) int {
- if unicode.Is(unicode.Latin, rune) {
- return rune
+ dropNotLatin := func(r rune) rune {
+ if unicode.Is(unicode.Latin, r) {
+ return r
}
return -1
}
@@ -444,8 +440,8 @@ func TestMap(t *testing.T) {
}
// 6. Identity
- identity := func(rune int) int {
- return rune
+ identity := func(r rune) rune {
+ return r
}
orig := "Input string that we expect not to be copied."
m = Map(identity, orig)
@@ -460,8 +456,8 @@ func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTest
func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
func BenchmarkMapNoChanges(b *testing.B) {
- identity := func(rune int) int {
- return rune
+ identity := func(r rune) rune {
+ return r
}
for i := 0; i < b.N; i++ {
Map(identity, "Some string that won't be modified.")
@@ -491,49 +487,48 @@ func TestSpecialCase(t *testing.T) {
func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
-type TrimTest struct {
- f func(string, string) string
+var trimTests = []struct {
+ f string
in, cutset, out string
-}
-
-var trimTests = []TrimTest{
- {Trim, "abba", "a", "bb"},
- {Trim, "abba", "ab", ""},
- {TrimLeft, "abba", "ab", ""},
- {TrimRight, "abba", "ab", ""},
- {TrimLeft, "abba", "a", "bba"},
- {TrimRight, "abba", "a", "abb"},
- {Trim, "<tag>", "<>", "tag"},
- {Trim, "* listitem", " *", "listitem"},
- {Trim, `"quote"`, `"`, "quote"},
- {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+}{
+ {"Trim", "abba", "a", "bb"},
+ {"Trim", "abba", "ab", ""},
+ {"TrimLeft", "abba", "ab", ""},
+ {"TrimRight", "abba", "ab", ""},
+ {"TrimLeft", "abba", "a", "bba"},
+ {"TrimRight", "abba", "a", "abb"},
+ {"Trim", "<tag>", "<>", "tag"},
+ {"Trim", "* listitem", " *", "listitem"},
+ {"Trim", `"quote"`, `"`, "quote"},
+ {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
//empty string tests
- {Trim, "abba", "", "abba"},
- {Trim, "", "123", ""},
- {Trim, "", "", ""},
- {TrimLeft, "abba", "", "abba"},
- {TrimLeft, "", "123", ""},
- {TrimLeft, "", "", ""},
- {TrimRight, "abba", "", "abba"},
- {TrimRight, "", "123", ""},
- {TrimRight, "", "", ""},
- {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+ {"Trim", "abba", "", "abba"},
+ {"Trim", "", "123", ""},
+ {"Trim", "", "", ""},
+ {"TrimLeft", "abba", "", "abba"},
+ {"TrimLeft", "", "123", ""},
+ {"TrimLeft", "", "", ""},
+ {"TrimRight", "abba", "", "abba"},
+ {"TrimRight", "", "123", ""},
+ {"TrimRight", "", "", ""},
+ {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
- actual := tc.f(tc.in, tc.cutset)
- var name string
- switch tc.f {
- case Trim:
- name = "Trim"
- case TrimLeft:
- name = "TrimLeft"
- case TrimRight:
- name = "TrimRight"
+ name := tc.f
+ var f func(string, string) string
+ switch name {
+ case "Trim":
+ f = Trim
+ case "TrimLeft":
+ f = TrimLeft
+ case "TrimRight":
+ f = TrimRight
default:
- t.Error("Undefined trim function")
+ t.Errorf("Undefined trim function %s", name)
}
+ actual := f(tc.in, tc.cutset)
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
}
@@ -541,7 +536,7 @@ func TestTrim(t *testing.T) {
}
type predicate struct {
- f func(r int) bool
+ f func(rune) bool
name string
}
@@ -549,27 +544,25 @@ var isSpace = predicate{unicode.IsSpace, "IsSpace"}
var isDigit = predicate{unicode.IsDigit, "IsDigit"}
var isUpper = predicate{unicode.IsUpper, "IsUpper"}
var isValidRune = predicate{
- func(r int) bool {
+ func(r rune) bool {
return r != utf8.RuneError
},
"IsValidRune",
}
-type TrimFuncTest struct {
- f predicate
- in, out string
-}
-
func not(p predicate) predicate {
return predicate{
- func(r int) bool {
+ func(r rune) bool {
return !p.f(r)
},
"not " + p.name,
}
}
-var trimFuncTests = []TrimFuncTest{
+var trimFuncTests = []struct {
+ f predicate
+ in, out string
+}{
{isSpace, space + " hello " + space, "hello"},
{isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
{isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
@@ -588,13 +581,11 @@ func TestTrimFunc(t *testing.T) {
}
}
-type IndexFuncTest struct {
+var indexFuncTests = []struct {
in string
f predicate
first, last int
-}
-
-var indexFuncTests = []IndexFuncTest{
+}{
{"", isValidRune, -1, -1},
{"abc", isDigit, -1, -1},
{"0123", isDigit, 0, 3},
@@ -650,13 +641,13 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
func TestCaseConsistency(t *testing.T) {
// Make a string of all the runes.
- numRunes := unicode.MaxRune + 1
+ numRunes := int(unicode.MaxRune + 1)
if testing.Short() {
numRunes = 1000
}
- a := make([]int, numRunes)
+ a := make([]rune, numRunes)
for i := range a {
- a[i] = i
+ a[i] = rune(i)
}
s := string(a)
// convert the cases.
@@ -692,12 +683,10 @@ func TestCaseConsistency(t *testing.T) {
*/
}
-type RepeatTest struct {
+var RepeatTests = []struct {
in, out string
count int
-}
-
-var RepeatTests = []RepeatTest{
+}{
{"", "", 0},
{"", "", 1},
{"", "", 2},
@@ -717,7 +706,7 @@ func TestRepeat(t *testing.T) {
}
}
-func runesEqual(a, b []int) bool {
+func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
}
@@ -729,34 +718,32 @@ func runesEqual(a, b []int) bool {
return true
}
-type RunesTest struct {
+var RunesTests = []struct {
in string
- out []int
+ out []rune
lossy bool
-}
-
-var RunesTests = []RunesTest{
- {"", []int{}, false},
- {" ", []int{32}, false},
- {"ABC", []int{65, 66, 67}, false},
- {"abc", []int{97, 98, 99}, false},
- {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
- {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
- {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+}{
+ {"", []rune{}, false},
+ {" ", []rune{32}, false},
+ {"ABC", []rune{65, 66, 67}, false},
+ {"abc", []rune{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []rune{26085, 26412, 35486}, false},
+ {"ab\x80c", []rune{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []rune{97, 98, 0xFFFD, 99}, true},
}
func TestRunes(t *testing.T) {
for _, tt := range RunesTests {
- a := []int(tt.in)
+ a := []rune(tt.in)
if !runesEqual(a, tt.out) {
- t.Errorf("[]int(%q) = %v; want %v", tt.in, a, tt.out)
+ t.Errorf("[]rune(%q) = %v; want %v", tt.in, a, tt.out)
continue
}
if !tt.lossy {
// can only test reassembly if we didn't lose information
s := string(a)
if s != tt.in {
- t.Errorf("string([]int(%q)) = %x; want %x", tt.in, s, tt.in)
+ t.Errorf("string([]rune(%q)) = %x; want %x", tt.in, s, tt.in)
}
}
}
@@ -772,7 +759,7 @@ func TestReadByte(t *testing.T) {
var res bytes.Buffer
for {
b, e := reader.ReadByte()
- if e == os.EOF {
+ if e == io.EOF {
break
}
if e != nil {
@@ -812,7 +799,7 @@ func TestReadRune(t *testing.T) {
res := ""
for {
r, z, e := reader.ReadRune()
- if e == os.EOF {
+ if e == io.EOF {
break
}
if e != nil {
@@ -846,14 +833,12 @@ func TestReadRune(t *testing.T) {
}
}
-type ReplaceTest struct {
+var ReplaceTests = []struct {
in string
old, new string
n int
out string
-}
-
-var ReplaceTests = []ReplaceTest{
+}{
{"hello", "l", "L", 0, "hello"},
{"hello", "l", "L", -1, "heLLo"},
{"hello", "x", "X", -1, "hello"},
@@ -883,11 +868,9 @@ func TestReplace(t *testing.T) {
}
}
-type TitleTest struct {
+var TitleTests = []struct {
in, out string
-}
-
-var TitleTests = []TitleTest{
+}{
{"", ""},
{"a", "A"},
{" aaa aaa aaa ", " Aaa Aaa Aaa "},
@@ -905,12 +888,10 @@ func TestTitle(t *testing.T) {
}
}
-type ContainsTest struct {
+var ContainsTests = []struct {
str, substr string
expected bool
-}
-
-var ContainsTests = []ContainsTest{
+}{
{"abc", "bc", true},
{"abc", "bcd", false},
{"abc", "", true},
@@ -925,3 +906,81 @@ func TestContains(t *testing.T) {
}
}
}
+
+var ContainsAnyTests = []struct {
+ str, substr string
+ expected bool
+}{
+ {"", "", false},
+ {"", "a", false},
+ {"", "abc", false},
+ {"a", "", false},
+ {"a", "a", true},
+ {"aaa", "a", true},
+ {"abc", "xyz", false},
+ {"abc", "xcz", true},
+ {"a☺b☻c☹d", "uvw☻xyz", true},
+ {"aRegExp*", ".(|)*+?^$[]", true},
+ {dots + dots + dots, " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+ for _, ct := range ContainsAnyTests {
+ if ContainsAny(ct.str, ct.substr) != ct.expected {
+ t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
+
+var ContainsRuneTests = []struct {
+ str string
+ r rune
+ expected bool
+}{
+ {"", 'a', false},
+ {"a", 'a', true},
+ {"aaa", 'a', true},
+ {"abc", 'y', false},
+ {"abc", 'c', true},
+ {"a☺b☻c☹d", 'x', false},
+ {"a☺b☻c☹d", '☻', true},
+ {"aRegExp*", '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+ for _, ct := range ContainsRuneTests {
+ if ContainsRune(ct.str, ct.r) != ct.expected {
+ t.Errorf("ContainsRune(%s, %s) = %v, want %v",
+ ct.str, ct.r, !ct.expected, ct.expected)
+ }
+ }
+}
+
+var EqualFoldTests = []struct {
+ s, t string
+ out bool
+}{
+ {"abc", "abc", true},
+ {"ABcd", "ABcd", true},
+ {"123abc", "123ABC", true},
+ {"αβδ", "ΑΒΔ", true},
+ {"abc", "xyz", false},
+ {"abc", "XYZ", false},
+ {"abcdefghijk", "abcdefghijX", false},
+ {"abcdefghijk", "abcdefghij\u212A", true},
+ {"abcdefghijK", "abcdefghij\u212A", true},
+ {"abcdefghijkz", "abcdefghij\u212Ay", false},
+ {"abcdefghijKz", "abcdefghij\u212Ay", false},
+}
+
+func TestEqualFold(t *testing.T) {
+ for _, tt := range EqualFoldTests {
+ if out := EqualFold(tt.s, tt.t); out != tt.out {
+ t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.s, tt.t, out, tt.out)
+ }
+ if out := EqualFold(tt.t, tt.s); out != tt.out {
+ t.Errorf("EqualFold(%#q, %#q) = %v, want %v", tt.t, tt.s, out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/sync/Makefile b/src/pkg/sync/Makefile
deleted file mode 100644
index e8a766226..000000000
--- a/src/pkg/sync/Makefile
+++ /dev/null
@@ -1,15 +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.
-
-include ../../Make.inc
-
-TARG=sync
-GOFILES=\
- cond.go\
- mutex.go\
- once.go \
- rwmutex.go\
- waitgroup.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/sync/atomic/Makefile b/src/pkg/sync/atomic/Makefile
deleted file mode 100644
index 38d8998c0..000000000
--- a/src/pkg/sync/atomic/Makefile
+++ /dev/null
@@ -1,18 +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.
-
-include ../../../Make.inc
-
-TARG=sync/atomic
-GOFILES=\
- doc.go\
-
-OFILES=\
- asm_$(GOARCH).$O\
-
-ifeq ($(GOARCH),arm)
-OFILES+=asm_$(GOOS)_$(GOARCH).$O
-endif
-
-include ../../../Make.pkg
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index 914d2feeb..a406852f4 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -18,6 +18,9 @@ TEXT ·CompareAndSwapUint32(SB),7,$0
TEXT ·CompareAndSwapUintptr(SB),7,$0
JMP ·CompareAndSwapUint32(SB)
+TEXT ·CompareAndSwapPointer(SB),7,$0
+ JMP ·CompareAndSwapUint32(SB)
+
TEXT ·CompareAndSwapInt64(SB),7,$0
JMP ·CompareAndSwapUint64(SB)
@@ -94,3 +97,55 @@ TEXT ·LoadUint32(SB),7,$0
MOVL 0(AX), AX
MOVL AX, ret+4(FP)
RET
+
+TEXT ·LoadInt64(SB),7,$0
+ JMP ·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),7,$0
+ MOVL addrptr+0(FP), AX
+ // MOVQ and EMMS were introduced on the Pentium MMX.
+ // MOVQ (%EAX), %MM0
+ BYTE $0x0f; BYTE $0x6f; BYTE $0x00
+ // MOVQ %MM0, 0x8(%ESP)
+ BYTE $0x0f; BYTE $0x7f; BYTE $0x44; BYTE $0x24; BYTE $0x08
+ EMMS
+ RET
+
+TEXT ·LoadUintptr(SB),7,$0
+ JMP ·LoadUint32(SB)
+
+TEXT ·LoadPointer(SB),7,$0
+ JMP ·LoadUint32(SB)
+
+TEXT ·StoreInt32(SB),7,$0
+ JMP ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),7,$0
+ MOVL addrptr+0(FP), BP
+ MOVL val+4(FP), AX
+ XCHGL AX, 0(BP)
+ RET
+
+TEXT ·StoreInt64(SB),7,$0
+ JMP ·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),7,$0
+ MOVL addrptr+0(FP), AX
+ // MOVQ and EMMS were introduced on the Pentium MMX.
+ // MOVQ 0x8(%ESP), %MM0
+ BYTE $0x0f; BYTE $0x6f; BYTE $0x44; BYTE $0x24; BYTE $0x08
+ // MOVQ %MM0, (%EAX)
+ BYTE $0x0f; BYTE $0x7f; BYTE $0x00
+ EMMS
+ // This is essentially a no-op, but it provides required memory fencing.
+ // It can be replaced with MFENCE, but MFENCE was introduced only on the Pentium4 (SSE2).
+ XORL AX, AX
+ LOCK
+ XADDL AX, (SP)
+ RET
+
+TEXT ·StoreUintptr(SB),7,$0
+ JMP ·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),7,$0
+ JMP ·StoreUint32(SB)
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
index 428295063..6f8bde068 100644
--- a/src/pkg/sync/atomic/asm_amd64.s
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -17,6 +17,9 @@ TEXT ·CompareAndSwapUint32(SB),7,$0
TEXT ·CompareAndSwapUintptr(SB),7,$0
JMP ·CompareAndSwapUint64(SB)
+TEXT ·CompareAndSwapPointer(SB),7,$0
+ JMP ·CompareAndSwapUint64(SB)
+
TEXT ·CompareAndSwapInt64(SB),7,$0
JMP ·CompareAndSwapUint64(SB)
@@ -67,3 +70,47 @@ TEXT ·LoadUint32(SB),7,$0
MOVL AX, ret+8(FP)
RET
+TEXT ·LoadInt64(SB),7,$0
+ JMP ·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),7,$0
+ MOVQ addrptr+0(FP), AX
+ MOVQ 0(AX), AX
+ MOVQ AX, ret+8(FP)
+ RET
+
+TEXT ·LoadUintptr(SB),7,$0
+ JMP ·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),7,$0
+ MOVQ addrptr+0(FP), AX
+ MOVQ 0(AX), AX
+ MOVQ AX, ret+8(FP)
+ RET
+
+TEXT ·StoreInt32(SB),7,$0
+ JMP ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),7,$0
+ MOVQ addrptr+0(FP), BP
+ MOVL val+8(FP), AX
+ XCHGL AX, 0(BP)
+ RET
+
+TEXT ·StoreInt64(SB),7,$0
+ JMP ·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),7,$0
+ MOVQ addrptr+0(FP), BP
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BP)
+ RET
+
+TEXT ·StoreUintptr(SB),7,$0
+ JMP ·StorePointer(SB)
+
+TEXT ·StorePointer(SB),7,$0
+ MOVQ addrptr+0(FP), BP
+ MOVQ val+8(FP), AX
+ XCHGQ AX, 0(BP)
+ RET
diff --git a/src/pkg/sync/atomic/asm_arm.s b/src/pkg/sync/atomic/asm_arm.s
index 95e2f5be4..2d10a922b 100644
--- a/src/pkg/sync/atomic/asm_arm.s
+++ b/src/pkg/sync/atomic/asm_arm.s
@@ -79,6 +79,30 @@ add64loop:
MOVW R5, rethi+16(FP)
RET
+TEXT ·armLoadUint64(SB),7,$0
+ BL fastCheck64<>(SB)
+ MOVW addrptr+0(FP), R1
+load64loop:
+ LDREXD (R1), R2 // loads R2 and R3
+ STREXD R2, (R1), R0 // stores R2 and R3
+ CMP $0, R0
+ BNE load64loop
+ MOVW R2, vallo+4(FP)
+ MOVW R3, valhi+8(FP)
+ RET
+
+TEXT ·armStoreUint64(SB),7,$0
+ BL fastCheck64<>(SB)
+ MOVW addrptr+0(FP), R1
+ MOVW vallo+4(FP), R2
+ MOVW valhi+8(FP), R3
+store64loop:
+ LDREXD (R1), R4 // loads R4 and R5
+ STREXD R2, (R1), R0 // stores R2 and R3
+ CMP $0, R0
+ BNE store64loop
+ RET
+
// Check for broken 64-bit LDREXD as found in QEMU.
// LDREXD followed by immediate STREXD should succeed.
// If it fails, try a few times just to be sure (maybe our thread got
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index 9ac411944..25dc85804 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -50,6 +50,9 @@ cascheck:
TEXT ·CompareAndSwapUintptr(SB),7,$0
B ·CompareAndSwapUint32(SB)
+TEXT ·CompareAndSwapPointer(SB),7,$0
+ B ·CompareAndSwapUint32(SB)
+
TEXT ·AddInt32(SB),7,$0
B ·AddUint32(SB)
@@ -96,3 +99,39 @@ loadloop1:
BCC loadloop1
MOVW R1, val+4(FP)
RET
+
+TEXT ·LoadInt64(SB),7,$0
+ B ·armLoadUint64(SB)
+
+TEXT ·LoadUint64(SB),7,$0
+ B ·armLoadUint64(SB)
+
+TEXT ·LoadUintptr(SB),7,$0
+ B ·LoadUint32(SB)
+
+TEXT ·LoadPointer(SB),7,$0
+ B ·LoadUint32(SB)
+
+TEXT ·StoreInt32(SB),7,$0
+ B ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),7,$0
+ MOVW addrptr+0(FP), R2
+ MOVW val+4(FP), R1
+storeloop1:
+ MOVW 0(R2), R0
+ BL cas<>(SB)
+ BCC storeloop1
+ RET
+
+TEXT ·StoreInt64(SB),7,$0
+ B ·armStoreUint64(SB)
+
+TEXT ·StoreUint64(SB),7,$0
+ B ·armStoreUint64(SB)
+
+TEXT ·StoreUintptr(SB),7,$0
+ B ·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),7,$0
+ B ·StoreUint32(SB)
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index 2229e58d0..f60d997ce 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -164,17 +164,17 @@ func TestCompareAndSwapInt32(t *testing.T) {
for val := int32(1); val+val > val; val += val {
x.i = val
if !CompareAndSwapInt32(&x.i, val, val+1) {
- t.Errorf("should have swapped %#x %#x", val, val+1)
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
x.i = val + 1
if CompareAndSwapInt32(&x.i, val, val+2) {
- t.Errorf("should not have swapped %#x %#x", val, val+2)
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
}
if x.before != magic32 || x.after != magic32 {
@@ -193,17 +193,17 @@ func TestCompareAndSwapUint32(t *testing.T) {
for val := uint32(1); val+val > val; val += val {
x.i = val
if !CompareAndSwapUint32(&x.i, val, val+1) {
- t.Errorf("should have swapped %#x %#x", val, val+1)
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
x.i = val + 1
if CompareAndSwapUint32(&x.i, val, val+2) {
- t.Errorf("should not have swapped %#x %#x", val, val+2)
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
}
if x.before != magic32 || x.after != magic32 {
@@ -226,17 +226,17 @@ func TestCompareAndSwapInt64(t *testing.T) {
for val := int64(1); val+val > val; val += val {
x.i = val
if !CompareAndSwapInt64(&x.i, val, val+1) {
- t.Errorf("should have swapped %#x %#x", val, val+1)
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
x.i = val + 1
if CompareAndSwapInt64(&x.i, val, val+2) {
- t.Errorf("should not have swapped %#x %#x", val, val+2)
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
}
if x.before != magic64 || x.after != magic64 {
@@ -259,17 +259,17 @@ func TestCompareAndSwapUint64(t *testing.T) {
for val := uint64(1); val+val > val; val += val {
x.i = val
if !CompareAndSwapUint64(&x.i, val, val+1) {
- t.Errorf("should have swapped %#x %#x", val, val+1)
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
x.i = val + 1
if CompareAndSwapUint64(&x.i, val, val+2) {
- t.Errorf("should not have swapped %#x %#x", val, val+2)
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
}
if x.before != magic64 || x.after != magic64 {
@@ -290,17 +290,48 @@ func TestCompareAndSwapUintptr(t *testing.T) {
for val := uintptr(1); val+val > val; val += val {
x.i = val
if !CompareAndSwapUintptr(&x.i, val, val+1) {
- t.Errorf("should have swapped %#x %#x", val, val+1)
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
x.i = val + 1
if CompareAndSwapUintptr(&x.i, val, val+2) {
- t.Errorf("should not have swapped %#x %#x", val, val+2)
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
}
if x.i != val+1 {
- t.Errorf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestCompareAndSwapPointer(t *testing.T) {
+ var x struct {
+ before uintptr
+ i unsafe.Pointer
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ for val := uintptr(1); val+val > val; val += val {
+ x.i = unsafe.Pointer(val)
+ if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) {
+ t.Fatalf("should have swapped %#x %#x", val, val+1)
+ }
+ if x.i != unsafe.Pointer(val+1) {
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
+ }
+ x.i = unsafe.Pointer(val + 1)
+ if CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+2)) {
+ t.Fatalf("should not have swapped %#x %#x", val, val+2)
+ }
+ if x.i != unsafe.Pointer(val+1) {
+ t.Fatalf("wrong x.i after swap: x.i=%#x val+1=%#x", x.i, val+1)
}
}
if x.before != magicptr || x.after != magicptr {
@@ -348,6 +379,236 @@ func TestLoadUint32(t *testing.T) {
}
}
+func TestLoadInt64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before int64
+ i int64
+ after int64
+ }
+ x.before = magic64
+ x.after = magic64
+ for delta := int64(1); delta+delta > delta; delta += delta {
+ k := LoadInt64(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestLoadUint64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before uint64
+ i uint64
+ after uint64
+ }
+ x.before = magic64
+ x.after = magic64
+ for delta := uint64(1); delta+delta > delta; delta += delta {
+ k := LoadUint64(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestLoadUintptr(t *testing.T) {
+ var x struct {
+ before uintptr
+ i uintptr
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ for delta := uintptr(1); delta+delta > delta; delta += delta {
+ k := LoadUintptr(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestLoadPointer(t *testing.T) {
+ var x struct {
+ before uintptr
+ i unsafe.Pointer
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ for delta := uintptr(1); delta+delta > delta; delta += delta {
+ k := LoadPointer(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i = unsafe.Pointer(uintptr(x.i) + delta)
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestStoreInt32(t *testing.T) {
+ var x struct {
+ before int32
+ i int32
+ after int32
+ }
+ x.before = magic32
+ x.after = magic32
+ v := int32(0)
+ for delta := int32(1); delta+delta > delta; delta += delta {
+ StoreInt32(&x.i, v)
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestStoreUint32(t *testing.T) {
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ }
+ x.before = magic32
+ x.after = magic32
+ v := uint32(0)
+ for delta := uint32(1); delta+delta > delta; delta += delta {
+ StoreUint32(&x.i, v)
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestStoreInt64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before int64
+ i int64
+ after int64
+ }
+ x.before = magic64
+ x.after = magic64
+ v := int64(0)
+ for delta := int64(1); delta+delta > delta; delta += delta {
+ StoreInt64(&x.i, v)
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v += delta
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestStoreUint64(t *testing.T) {
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ var x struct {
+ before uint64
+ i uint64
+ after uint64
+ }
+ x.before = magic64
+ x.after = magic64
+ v := uint64(0)
+ for delta := uint64(1); delta+delta > delta; delta += delta {
+ StoreUint64(&x.i, v)
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v += delta
+ }
+ if x.before != magic64 || x.after != magic64 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, uint64(magic64), uint64(magic64))
+ }
+}
+
+func TestStoreUintptr(t *testing.T) {
+ var x struct {
+ before uintptr
+ i uintptr
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ v := uintptr(0)
+ for delta := uintptr(1); delta+delta > delta; delta += delta {
+ StoreUintptr(&x.i, v)
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v += delta
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
+func TestStorePointer(t *testing.T) {
+ var x struct {
+ before uintptr
+ i unsafe.Pointer
+ after uintptr
+ }
+ var m uint64 = magic64
+ magicptr := uintptr(m)
+ x.before = magicptr
+ x.after = magicptr
+ v := unsafe.Pointer(uintptr(0))
+ for delta := uintptr(1); delta+delta > delta; delta += delta {
+ StorePointer(&x.i, unsafe.Pointer(v))
+ if x.i != v {
+ t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
+ }
+ v = unsafe.Pointer(uintptr(v) + delta)
+ }
+ if x.before != magicptr || x.after != magicptr {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magicptr, magicptr)
+ }
+}
+
// Tests of correct behavior, with contention.
// (Is the function atomic?)
//
@@ -366,6 +627,7 @@ var hammer32 = []struct {
{"CompareAndSwapInt32", hammerCompareAndSwapInt32},
{"CompareAndSwapUint32", hammerCompareAndSwapUint32},
{"CompareAndSwapUintptr", hammerCompareAndSwapUintptr32},
+ {"CompareAndSwapPointer", hammerCompareAndSwapPointer32},
}
func init() {
@@ -374,6 +636,7 @@ func init() {
// 64-bit system; clear uintptr tests
hammer32[2].f = nil
hammer32[5].f = nil
+ hammer32[6].f = nil
}
}
@@ -436,6 +699,20 @@ func hammerCompareAndSwapUintptr32(uval *uint32, count int) {
}
}
+func hammerCompareAndSwapPointer32(uval *uint32, count int) {
+ // only safe when uintptr is 32-bit.
+ // not called on 64-bit systems.
+ val := (*unsafe.Pointer)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapPointer(val, v, unsafe.Pointer(uintptr(v)+1)) {
+ break
+ }
+ }
+ }
+}
+
func TestHammer32(t *testing.T) {
const p = 4
n := 100000
@@ -460,7 +737,7 @@ func TestHammer32(t *testing.T) {
<-c
}
if val != uint32(n)*p {
- t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
+ t.Fatalf("%s: val=%d want %d", tt.name, val, n*p)
}
}
}
@@ -475,6 +752,7 @@ var hammer64 = []struct {
{"CompareAndSwapInt64", hammerCompareAndSwapInt64},
{"CompareAndSwapUint64", hammerCompareAndSwapUint64},
{"CompareAndSwapUintptr", hammerCompareAndSwapUintptr64},
+ {"CompareAndSwapPointer", hammerCompareAndSwapPointer64},
}
func init() {
@@ -483,6 +761,7 @@ func init() {
// 32-bit system; clear uintptr tests
hammer64[2].f = nil
hammer64[5].f = nil
+ hammer64[6].f = nil
}
}
@@ -545,6 +824,20 @@ func hammerCompareAndSwapUintptr64(uval *uint64, count int) {
}
}
+func hammerCompareAndSwapPointer64(uval *uint64, count int) {
+ // only safe when uintptr is 64-bit.
+ // not called on 32-bit systems.
+ val := (*unsafe.Pointer)(unsafe.Pointer(uval))
+ for i := 0; i < count; i++ {
+ for {
+ v := *val
+ if CompareAndSwapPointer(val, v, unsafe.Pointer(uintptr(v)+1)) {
+ break
+ }
+ }
+ }
+}
+
func TestHammer64(t *testing.T) {
if test64err != nil {
t.Logf("Skipping 64-bit tests: %v", test64err)
@@ -573,63 +866,141 @@ func TestHammer64(t *testing.T) {
<-c
}
if val != uint64(n)*p {
- t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
+ t.Fatalf("%s: val=%d want %d", tt.name, val, n*p)
}
}
}
-func hammerLoadInt32(t *testing.T, uval *uint32) {
- val := (*int32)(unsafe.Pointer(uval))
- for {
- v := LoadInt32(val)
+func hammerStoreLoadInt32(t *testing.T, valp unsafe.Pointer) {
+ val := (*int32)(valp)
+ v := LoadInt32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("Int32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ StoreInt32(val, new)
+}
+
+func hammerStoreLoadUint32(t *testing.T, valp unsafe.Pointer) {
+ val := (*uint32)(valp)
+ v := LoadUint32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("Uint32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ StoreUint32(val, new)
+}
+
+func hammerStoreLoadInt64(t *testing.T, valp unsafe.Pointer) {
+ val := (*int64)(valp)
+ v := LoadInt64(val)
+ vlo := v & ((1 << 32) - 1)
+ vhi := v >> 32
+ if vlo != vhi {
+ t.Fatalf("Int64: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<32
+ StoreInt64(val, new)
+}
+
+func hammerStoreLoadUint64(t *testing.T, valp unsafe.Pointer) {
+ val := (*uint64)(valp)
+ v := LoadUint64(val)
+ vlo := v & ((1 << 32) - 1)
+ vhi := v >> 32
+ if vlo != vhi {
+ t.Fatalf("Uint64: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<32
+ StoreUint64(val, new)
+}
+
+func hammerStoreLoadUintptr(t *testing.T, valp unsafe.Pointer) {
+ val := (*uintptr)(valp)
+ var test64 uint64 = 1 << 50
+ arch32 := uintptr(test64) == 0
+ v := LoadUintptr(val)
+ new := v
+ if arch32 {
vlo := v & ((1 << 16) - 1)
vhi := v >> 16
if vlo != vhi {
- t.Fatalf("LoadInt32: %#x != %#x", vlo, vhi)
+ t.Fatalf("Uintptr: %#x != %#x", vlo, vhi)
}
- new := v + 1 + 1<<16
+ new = v + 1 + 1<<16
if vlo == 1e4 {
new = 0
}
- if CompareAndSwapInt32(val, v, new) {
- break
+ } else {
+ vlo := v & ((1 << 32) - 1)
+ vhi := v >> 32
+ if vlo != vhi {
+ t.Fatalf("Uintptr: %#x != %#x", vlo, vhi)
}
+ inc := uint64(1 + 1<<32)
+ new = v + uintptr(inc)
}
+ StoreUintptr(val, new)
}
-func hammerLoadUint32(t *testing.T, val *uint32) {
- for {
- v := LoadUint32(val)
+func hammerStoreLoadPointer(t *testing.T, valp unsafe.Pointer) {
+ val := (*unsafe.Pointer)(valp)
+ var test64 uint64 = 1 << 50
+ arch32 := uintptr(test64) == 0
+ v := uintptr(LoadPointer(val))
+ new := v
+ if arch32 {
vlo := v & ((1 << 16) - 1)
vhi := v >> 16
if vlo != vhi {
- t.Fatalf("LoadUint32: %#x != %#x", vlo, vhi)
+ t.Fatalf("Pointer: %#x != %#x", vlo, vhi)
}
- new := v + 1 + 1<<16
+ new = v + 1 + 1<<16
if vlo == 1e4 {
new = 0
}
- if CompareAndSwapUint32(val, v, new) {
- break
+ } else {
+ vlo := v & ((1 << 32) - 1)
+ vhi := v >> 32
+ if vlo != vhi {
+ t.Fatalf("Pointer: %#x != %#x", vlo, vhi)
}
+ inc := uint64(1 + 1<<32)
+ new = v + uintptr(inc)
}
+ StorePointer(val, unsafe.Pointer(new))
}
-func TestHammerLoad(t *testing.T) {
- tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32}
- n := 100000
+func TestHammerStoreLoad(t *testing.T) {
+ var tests []func(*testing.T, unsafe.Pointer)
+ tests = append(tests, hammerStoreLoadInt32, hammerStoreLoadUint32,
+ hammerStoreLoadUintptr, hammerStoreLoadPointer)
+ if test64err == nil {
+ tests = append(tests, hammerStoreLoadInt64, hammerStoreLoadUint64)
+ }
+ n := int(1e6)
if testing.Short() {
- n = 10000
+ n = int(1e4)
}
const procs = 8
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
for _, tt := range tests {
c := make(chan int)
- var val uint32
+ var val uint64
for p := 0; p < procs; p++ {
go func() {
for i := 0; i < n; i++ {
- tt(t, &val)
+ tt(t, unsafe.Pointer(&val))
}
c <- 1
}()
@@ -639,3 +1010,185 @@ func TestHammerLoad(t *testing.T) {
}
}
}
+
+func TestStoreLoadSeqCst32(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := int32(1e3)
+ if testing.Short() {
+ N = int32(1e2)
+ }
+ c := make(chan bool, 2)
+ X := [2]int32{}
+ ack := [2][3]int32{{-1, -1, -1}, {-1, -1, -1}}
+ for p := 0; p < 2; p++ {
+ go func(me int) {
+ he := 1 - me
+ for i := int32(1); i < N; i++ {
+ StoreInt32(&X[me], i)
+ my := LoadInt32(&X[he])
+ StoreInt32(&ack[me][i%3], my)
+ for w := 1; LoadInt32(&ack[he][i%3]) == -1; w++ {
+ if w%1000 == 0 {
+ runtime.Gosched()
+ }
+ }
+ his := LoadInt32(&ack[he][i%3])
+ if (my != i && my != i-1) || (his != i && his != i-1) {
+ t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ }
+ if my != i && his != i {
+ t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ }
+ StoreInt32(&ack[me][(i-1)%3], -1)
+ }
+ c <- true
+ }(p)
+ }
+ <-c
+ <-c
+}
+
+func TestStoreLoadSeqCst64(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := int64(1e3)
+ if testing.Short() {
+ N = int64(1e2)
+ }
+ c := make(chan bool, 2)
+ X := [2]int64{}
+ ack := [2][3]int64{{-1, -1, -1}, {-1, -1, -1}}
+ for p := 0; p < 2; p++ {
+ go func(me int) {
+ he := 1 - me
+ for i := int64(1); i < N; i++ {
+ StoreInt64(&X[me], i)
+ my := LoadInt64(&X[he])
+ StoreInt64(&ack[me][i%3], my)
+ for w := 1; LoadInt64(&ack[he][i%3]) == -1; w++ {
+ if w%1000 == 0 {
+ runtime.Gosched()
+ }
+ }
+ his := LoadInt64(&ack[he][i%3])
+ if (my != i && my != i-1) || (his != i && his != i-1) {
+ t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ }
+ if my != i && his != i {
+ t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ }
+ StoreInt64(&ack[me][(i-1)%3], -1)
+ }
+ c <- true
+ }(p)
+ }
+ <-c
+ <-c
+}
+
+func TestStoreLoadRelAcq32(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := int32(1e3)
+ if testing.Short() {
+ N = int32(1e2)
+ }
+ c := make(chan bool, 2)
+ type Data struct {
+ signal int32
+ pad1 [128]int8
+ data1 int32
+ pad2 [128]int8
+ data2 float32
+ }
+ var X Data
+ for p := int32(0); p < 2; p++ {
+ go func(p int32) {
+ for i := int32(1); i < N; i++ {
+ if (i+p)%2 == 0 {
+ X.data1 = i
+ X.data2 = float32(i)
+ StoreInt32(&X.signal, i)
+ } else {
+ for w := 1; LoadInt32(&X.signal) != i; w++ {
+ if w%1000 == 0 {
+ runtime.Gosched()
+ }
+ }
+ d1 := X.data1
+ d2 := X.data2
+ if d1 != i || d2 != float32(i) {
+ t.Fatalf("incorrect data: %d/%d (%d)", d1, d2, i)
+ }
+ }
+ }
+ c <- true
+ }(p)
+ }
+ <-c
+ <-c
+}
+
+func TestStoreLoadRelAcq64(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
+ if test64err != nil {
+ t.Logf("Skipping 64-bit tests: %v", test64err)
+ return
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+ N := int64(1e3)
+ if testing.Short() {
+ N = int64(1e2)
+ }
+ c := make(chan bool, 2)
+ type Data struct {
+ signal int64
+ pad1 [128]int8
+ data1 int64
+ pad2 [128]int8
+ data2 float64
+ }
+ var X Data
+ for p := int64(0); p < 2; p++ {
+ go func(p int64) {
+ for i := int64(1); i < N; i++ {
+ if (i+p)%2 == 0 {
+ X.data1 = i
+ X.data2 = float64(i)
+ StoreInt64(&X.signal, i)
+ } else {
+ for w := 1; LoadInt64(&X.signal) != i; w++ {
+ if w%1000 == 0 {
+ runtime.Gosched()
+ }
+ }
+ d1 := X.data1
+ d2 := X.data2
+ if d1 != i || d2 != float64(i) {
+ t.Fatalf("incorrect data: %d/%d (%d)", d1, d2, i)
+ }
+ }
+ }
+ c <- true
+ }(p)
+ }
+ <-c
+ <-c
+}
diff --git a/src/pkg/sync/atomic/doc.go b/src/pkg/sync/atomic/doc.go
index b35eb539c..ecb4808ce 100644
--- a/src/pkg/sync/atomic/doc.go
+++ b/src/pkg/sync/atomic/doc.go
@@ -22,9 +22,13 @@
//
package atomic
+import (
+ "unsafe"
+)
+
// BUG(rsc): On ARM, the 64-bit functions use instructions unavailable before ARM 11.
//
-// On x86-32, the 64-bit functions use instructions unavailable before the Pentium.
+// On x86-32, the 64-bit functions use instructions unavailable before the Pentium MMX.
// CompareAndSwapInt32 executes the compare-and-swap operation for an int32 value.
func CompareAndSwapInt32(val *int32, old, new int32) (swapped bool)
@@ -41,6 +45,9 @@ func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool)
// CompareAndSwapUintptr executes the compare-and-swap operation for a uintptr value.
func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool)
+// CompareAndSwapPointer executes the compare-and-swap operation for a unsafe.Pointer value.
+func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool)
+
// AddInt32 atomically adds delta to *val and returns the new value.
func AddInt32(val *int32, delta int32) (new int32)
@@ -59,9 +66,39 @@ func AddUintptr(val *uintptr, delta uintptr) (new uintptr)
// LoadInt32 atomically loads *addr.
func LoadInt32(addr *int32) (val int32)
+// LoadInt64 atomically loads *addr.
+func LoadInt64(addr *int64) (val int64)
+
// LoadUint32 atomically loads *addr.
func LoadUint32(addr *uint32) (val uint32)
+// LoadUint64 atomically loads *addr.
+func LoadUint64(addr *uint64) (val uint64)
+
+// LoadUintptr atomically loads *addr.
+func LoadUintptr(addr *uintptr) (val uintptr)
+
+// LoadPointer atomically loads *addr.
+func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer)
+
+// StoreInt32 atomically stores val into *addr.
+func StoreInt32(addr *int32, val int32)
+
+// StoreInt64 atomically stores val into *addr.
+func StoreInt64(addr *int64, val int64)
+
+// StoreUint32 atomically stores val into *addr.
+func StoreUint32(addr *uint32, val uint32)
+
+// StoreUint64 atomically stores val into *addr.
+func StoreUint64(addr *uint64, val uint64)
+
+// StoreUintptr atomically stores val into *addr.
+func StoreUintptr(addr *uintptr, val uintptr)
+
+// StorePointer atomically stores val into *addr.
+func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer)
+
// Helper for ARM. Linker will discard on other systems
func panic64() {
panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
diff --git a/src/pkg/sync/cond.go b/src/pkg/sync/cond.go
index 75494b535..1fc3deaf1 100644
--- a/src/pkg/sync/cond.go
+++ b/src/pkg/sync/cond.go
@@ -4,8 +4,6 @@
package sync
-import "runtime"
-
// Cond implements a condition variable, a rendezvous point
// for goroutines waiting for or announcing the occurrence
// of an event.
@@ -43,9 +41,10 @@ func NewCond(l Locker) *Cond {
// Wait atomically unlocks c.L and suspends execution
// of the calling goroutine. After later resuming execution,
-// Wait locks c.L before returning.
+// Wait locks c.L before returning. Unlike in other systems,
+// Wait cannot return unless awoken by Broadcast or Signal.
//
-// Because L is not locked when Wait first resumes, the caller
+// Because c.L is not locked when Wait first resumes, the caller
// typically cannot assume that the condition is true when
// Wait returns. Instead, the caller should Wait in a loop:
//
@@ -65,7 +64,7 @@ func (c *Cond) Wait() {
c.newWaiters++
c.m.Unlock()
c.L.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
c.L.Lock()
}
@@ -84,7 +83,7 @@ func (c *Cond) Signal() {
}
if c.oldWaiters > 0 {
c.oldWaiters--
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.m.Unlock()
}
@@ -98,13 +97,13 @@ func (c *Cond) Broadcast() {
// Wake both generations.
if c.oldWaiters > 0 {
for i := 0; i < c.oldWaiters; i++ {
- runtime.Semrelease(c.oldSema)
+ runtime_Semrelease(c.oldSema)
}
c.oldWaiters = 0
}
if c.newWaiters > 0 {
for i := 0; i < c.newWaiters; i++ {
- runtime.Semrelease(c.newSema)
+ runtime_Semrelease(c.newSema)
}
c.newWaiters = 0
c.newSema = nil
diff --git a/src/pkg/sync/example_test.go b/src/pkg/sync/example_test.go
new file mode 100644
index 000000000..156492400
--- /dev/null
+++ b/src/pkg/sync/example_test.go
@@ -0,0 +1,54 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+ "fmt"
+ "net/http"
+ "sync"
+)
+
+// This example fetches several URLs concurrently,
+// using a WaitGroup to block until all the fetches are complete.
+func ExampleWaitGroup() {
+ var wg sync.WaitGroup
+ var urls = []string{
+ "http://www.golang.org/",
+ "http://www.google.com/",
+ "http://www.somestupidname.com/",
+ }
+ for _, url := range urls {
+ // Increment the WaitGroup counter.
+ wg.Add(1)
+ // Launch a goroutine to fetch the URL.
+ go func(url string) {
+ // Fetch the URL.
+ http.Get(url)
+ // Decrement the counter.
+ wg.Done()
+ }(url)
+ }
+ // Wait for all HTTP fetches to complete.
+ wg.Wait()
+}
+
+func ExampleOnce() {
+ var once sync.Once
+ onceBody := func() {
+ fmt.Printf("Only once\n")
+ }
+ done := make(chan bool)
+ for i := 0; i < 10; i++ {
+ go func() {
+ once.Do(onceBody)
+ done <- true
+ }()
+ }
+ for i := 0; i < 10; i++ {
+ <-done
+ }
+ // Output:
+ // Only once
+}
diff --git a/src/pkg/sync/export_test.go b/src/pkg/sync/export_test.go
new file mode 100644
index 000000000..fa5983a2d
--- /dev/null
+++ b/src/pkg/sync/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// Export for testing.
+var Runtime_Semacquire = runtime_Semacquire
+var Runtime_Semrelease = runtime_Semrelease
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index 2d46c8994..9494cc3f8 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -6,12 +6,11 @@
// exclusion locks. Other than the Once and WaitGroup types, most are intended
// for use by low-level library routines. Higher-level synchronization is
// better done via channels and communication.
+//
+// Values containing the types defined in this package should not be copied.
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
@@ -58,7 +57,7 @@ func (m *Mutex) Lock() {
if old&mutexLocked == 0 {
break
}
- runtime.Semacquire(&m.sema)
+ runtime_Semacquire(&m.sema)
awoke = true
}
}
@@ -87,7 +86,7 @@ func (m *Mutex) Unlock() {
// Grab the right to wake someone.
new = (old - 1<<mutexWaiterShift) | mutexWoken
if atomic.CompareAndSwapInt32(&m.state, old, new) {
- runtime.Semrelease(&m.sema)
+ runtime_Semrelease(&m.sema)
return
}
old = m.state
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index 47758844f..bf78c6f60 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_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.
-// GOMAXPROCS=10 gotest
+// GOMAXPROCS=10 go test
package sync_test
@@ -15,8 +15,8 @@ import (
func HammerSemaphore(s *uint32, loops int, cdone chan bool) {
for i := 0; i < loops; i++ {
- runtime.Semacquire(s)
- runtime.Semrelease(s)
+ Runtime_Semacquire(s)
+ Runtime_Semrelease(s)
}
cdone <- true
}
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
index 157a3667a..37075af17 100644
--- a/src/pkg/sync/once_test.go
+++ b/src/pkg/sync/once_test.go
@@ -5,9 +5,9 @@
package sync_test
import (
+ "runtime"
. "sync"
"sync/atomic"
- "runtime"
"testing"
)
diff --git a/src/pkg/sync/runtime.go b/src/pkg/sync/runtime.go
new file mode 100644
index 000000000..e99599c11
--- /dev/null
+++ b/src/pkg/sync/runtime.go
@@ -0,0 +1,18 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// defined in package runtime
+
+// Semacquire waits until *s > 0 and then atomically decrements it.
+// It is intended as a simple sleep primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semacquire(s *uint32)
+
+// Semrelease atomically increments *s and notifies a waiting goroutine
+// if one is blocked in Semacquire.
+// It is intended as a simple wakeup primitive for use by the synchronization
+// library and should not be used directly.
+func runtime_Semrelease(s *uint32)
diff --git a/src/pkg/runtime/sema_test.go b/src/pkg/sync/runtime_sema_test.go
index d95bb1ec5..57a8dbee7 100644
--- a/src/pkg/runtime/sema_test.go
+++ b/src/pkg/sync/runtime_sema_test.go
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package runtime_test
+package sync_test
import (
"runtime"
+ . "sync"
"sync/atomic"
"testing"
)
@@ -25,8 +26,8 @@ func BenchmarkSemaUncontended(b *testing.B) {
for atomic.AddInt32(&N, -1) >= 0 {
runtime.Gosched()
for g := 0; g < CallsPerSched; g++ {
- runtime.Semrelease(&sem.sem)
- runtime.Semacquire(&sem.sem)
+ Runtime_Semrelease(&sem.sem)
+ Runtime_Semacquire(&sem.sem)
}
}
c <- true
@@ -48,7 +49,7 @@ func benchmarkSema(b *testing.B, block, work bool) {
if block {
for p := 0; p < procs/2; p++ {
go func() {
- runtime.Semacquire(&sem)
+ Runtime_Semacquire(&sem)
c2 <- true
}()
}
@@ -59,18 +60,18 @@ func benchmarkSema(b *testing.B, block, work bool) {
for atomic.AddInt32(&N, -1) >= 0 {
runtime.Gosched()
for g := 0; g < CallsPerSched; g++ {
- runtime.Semrelease(&sem)
+ Runtime_Semrelease(&sem)
if work {
for i := 0; i < LocalWork; i++ {
foo *= 2
foo /= 2
}
}
- runtime.Semacquire(&sem)
+ Runtime_Semacquire(&sem)
}
}
c <- foo == 42
- runtime.Semrelease(&sem)
+ Runtime_Semrelease(&sem)
}()
}
if block {
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
index cb1a47720..782a9c319 100644
--- a/src/pkg/sync/rwmutex.go
+++ b/src/pkg/sync/rwmutex.go
@@ -4,10 +4,7 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// An RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers
@@ -29,7 +26,7 @@ const rwmutexMaxReaders = 1 << 30
func (rw *RWMutex) RLock() {
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
// A writer is pending, wait for it.
- runtime.Semacquire(&rw.readerSem)
+ runtime_Semacquire(&rw.readerSem)
}
}
@@ -42,7 +39,7 @@ func (rw *RWMutex) RUnlock() {
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
// The last reader unblocks the writer.
- runtime.Semrelease(&rw.writerSem)
+ runtime_Semrelease(&rw.writerSem)
}
}
}
@@ -60,7 +57,7 @@ func (rw *RWMutex) Lock() {
r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
- runtime.Semacquire(&rw.writerSem)
+ runtime_Semacquire(&rw.writerSem)
}
}
@@ -75,7 +72,7 @@ func (rw *RWMutex) Unlock() {
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
- runtime.Semrelease(&rw.readerSem)
+ runtime_Semrelease(&rw.readerSem)
}
// Allow other writers to proceed.
rw.w.Unlock()
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index dc8ce9653..39d5d6540 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_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.
-// GOMAXPROCS=10 gotest
+// GOMAXPROCS=10 go test
package sync_test
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index a4c9b7e43..0165b1ffb 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -4,31 +4,13 @@
package sync
-import (
- "runtime"
- "sync/atomic"
-)
+import "sync/atomic"
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for. Then each of the goroutines
// runs and calls Done when finished. At the same time,
// Wait can be used to block until all goroutines have finished.
-//
-// For example:
-//
-// for i := 0; i < n; i++ {
-// if !condition(i) {
-// continue
-// }
-// wg.Add(1)
-// go func() {
-// // Do something.
-// wg.Done()
-// }()
-// }
-// wg.Wait()
-//
type WaitGroup struct {
m Mutex
counter int32
@@ -60,7 +42,7 @@ func (wg *WaitGroup) Add(delta int) {
}
wg.m.Lock()
for i := int32(0); i < wg.waiters; i++ {
- runtime.Semrelease(wg.sema)
+ runtime_Semrelease(wg.sema)
}
wg.waiters = 0
wg.sema = nil
@@ -93,5 +75,5 @@ func (wg *WaitGroup) Wait() {
}
s := wg.sema
wg.m.Unlock()
- runtime.Semacquire(s)
+ runtime_Semacquire(s)
}
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
deleted file mode 100644
index f626d0998..000000000
--- a/src/pkg/syscall/Makefile
+++ /dev/null
@@ -1,58 +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.
-
-include ../../Make.inc
-
-TARG=syscall
-GOFILES=\
- str.go\
- syscall.go\
- syscall_$(GOARCH).go\
- syscall_$(GOOS).go\
- syscall_$(GOOS)_$(GOARCH).go\
- zerrors_$(GOOS)_$(GOARCH).go\
- zsyscall_$(GOOS)_$(GOARCH).go\
- zsysnum_$(GOOS)_$(GOARCH).go\
- ztypes_$(GOOS)_$(GOARCH).go\
-
-GOFILES_freebsd=\
- bpf_bsd.go\
- exec_unix.go\
- route_bsd.go\
- route_freebsd.go\
- sockcmsg_unix.go\
- syscall_bsd.go\
- syscall_unix.go\
-
-GOFILES_darwin=\
- bpf_bsd.go\
- exec_unix.go\
- route_bsd.go\
- route_darwin.go\
- sockcmsg_unix.go\
- syscall_bsd.go\
- syscall_unix.go\
-
-GOFILES_linux=\
- exec_unix.go\
- lsf_linux.go\
- netlink_linux.go\
- sockcmsg_linux.go\
- sockcmsg_unix.go\
- syscall_unix.go\
-
-GOFILES_windows=\
- exec_windows.go\
- zerrors_windows.go\
- ztypes_windows.go\
-
-GOFILES_plan9=\
- exec_plan9.go\
-
-OFILES=\
- asm_$(GOOS)_$(GOARCH).$O\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../Make.pkg
diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s
index 82f170b5b..22e00e45b 100644
--- a/src/pkg/syscall/asm_linux_386.s
+++ b/src/pkg/syscall/asm_linux_386.s
@@ -17,7 +17,7 @@ TEXT ·Syscall(SB),7,$0
MOVL 16(SP), DX
MOVL $0, SI
MOVL $0, DI
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS ok
MOVL $-1, 20(SP) // r1
@@ -43,7 +43,7 @@ TEXT ·Syscall6(SB),7,$0
MOVL 20(SP), SI
MOVL 24(SP), DI
MOVL 28(SP), BP
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS ok6
MOVL $-1, 32(SP) // r1
@@ -67,7 +67,7 @@ TEXT ·RawSyscall(SB),7,$0
MOVL 16(SP), DX
MOVL $0, SI
MOVL $0, DI
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS ok1
MOVL $-1, 20(SP) // r1
@@ -90,7 +90,7 @@ TEXT ·RawSyscall6(SB),7,$0
MOVL 20(SP), SI
MOVL 24(SP), DI
MOVL 28(SP), BP
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS ok2
MOVL $-1, 32(SP) // r1
@@ -116,7 +116,7 @@ TEXT ·socketcall(SB),7,$0
MOVL $0, DX
MOVL $0, SI
MOVL $0, DI
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS oksock
MOVL $-1, 32(SP) // n
@@ -139,7 +139,7 @@ TEXT ·rawsocketcall(SB),7,$0
MOVL $0, DX
MOVL $0, SI
MOVL $0, DI
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS oksock1
MOVL $-1, 32(SP) // n
@@ -165,7 +165,7 @@ TEXT ·Seek(SB),7,$0
MOVL 8(SP), DX // offset-low
LEAL 20(SP), SI // result pointer
MOVL 16(SP), DI // whence
- INT $0x80
+ CALL *runtime·_vdso(SB)
CMPL AX, $0xfffff001
JLS okseek
MOVL $-1, 20(SP) // newoffset low
diff --git a/src/pkg/syscall/asm_netbsd_386.s b/src/pkg/syscall/asm_netbsd_386.s
new file mode 100644
index 000000000..ec2065fc7
--- /dev/null
+++ b/src/pkg/syscall/asm_netbsd_386.s
@@ -0,0 +1,137 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for 386, NetBSD
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok6
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok9
+ MOVL $-1, 44(SP) // r1
+ MOVL $-1, 48(SP) // r2
+ MOVL AX, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVL AX, 44(SP) // r1
+ MOVL DX, 48(SP) // r2
+ MOVL $0, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok1
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ RET
+ok1:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok2
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ RET
+ok2:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_netbsd_amd64.s b/src/pkg/syscall/asm_netbsd_amd64.s
new file mode 100644
index 000000000..240e41c8f
--- /dev/null
+++ b/src/pkg/syscall/asm_netbsd_amd64.s
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for AMD64, NetBSD
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
+// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
+// Trap # in AX, args in DI SI DX, return in AX DX
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ SYSCALL
+ JCC ok
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ SYSCALL
+ JCC ok6
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 64(SP), R11
+ MOVQ 72(SP), R12
+ MOVQ 80(SP), R13
+ SUBQ $32, SP
+ MOVQ R11, 8(SP) // arg 7
+ MOVQ R12, 16(SP) // arg 8
+ MOVQ R13, 24(SP) // arg 9
+ SYSCALL
+ JCC ok9
+ ADDQ $32, SP
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ ADDQ $32, SP
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok1
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ RET
+ok1:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok2
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ RET
+ok2:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_openbsd_386.s b/src/pkg/syscall/asm_openbsd_386.s
new file mode 100644
index 000000000..daa115f26
--- /dev/null
+++ b/src/pkg/syscall/asm_openbsd_386.s
@@ -0,0 +1,137 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for 386, OpenBSD
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok6
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok9
+ MOVL $-1, 44(SP) // r1
+ MOVL $-1, 48(SP) // r2
+ MOVL AX, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVL AX, 44(SP) // r1
+ MOVL DX, 48(SP) // r2
+ MOVL $0, 52(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok1
+ MOVL $-1, 20(SP) // r1
+ MOVL $-1, 24(SP) // r2
+ MOVL AX, 28(SP) // errno
+ RET
+ok1:
+ MOVL AX, 20(SP) // r1
+ MOVL DX, 24(SP) // r2
+ MOVL $0, 28(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVL 4(SP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok2
+ MOVL $-1, 32(SP) // r1
+ MOVL $-1, 36(SP) // r2
+ MOVL AX, 40(SP) // errno
+ RET
+ok2:
+ MOVL AX, 32(SP) // r1
+ MOVL DX, 36(SP) // r2
+ MOVL $0, 40(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_openbsd_amd64.s b/src/pkg/syscall/asm_openbsd_amd64.s
new file mode 100644
index 000000000..e19c6a9a6
--- /dev/null
+++ b/src/pkg/syscall/asm_openbsd_amd64.s
@@ -0,0 +1,130 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System call support for AMD64, OpenBSD
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
+// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
+// Trap # in AX, args in DI SI DX, return in AX DX
+
+TEXT ·Syscall(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ SYSCALL
+ JCC ok
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ SYSCALL
+ JCC ok6
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),7,$0
+ CALL runtime·entersyscall(SB)
+ MOVQ 8(SP), AX // syscall entry
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 64(SP), R11
+ MOVQ 72(SP), R12
+ MOVQ 80(SP), R13
+ SUBQ $32, SP
+ MOVQ R11, 8(SP) // arg 7
+ MOVQ R12, 16(SP) // arg 8
+ MOVQ R13, 24(SP) // arg 9
+ SYSCALL
+ JCC ok9
+ ADDQ $32, SP
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ ADDQ $32, SP
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok1
+ MOVQ $-1, 40(SP) // r1
+ MOVQ $0, 48(SP) // r2
+ MOVQ AX, 56(SP) // errno
+ RET
+ok1:
+ MOVQ AX, 40(SP) // r1
+ MOVQ DX, 48(SP) // r2
+ MOVQ $0, 56(SP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),7,$0
+ MOVQ 16(SP), DI
+ MOVQ 24(SP), SI
+ MOVQ 32(SP), DX
+ MOVQ 40(SP), R10
+ MOVQ 48(SP), R8
+ MOVQ 56(SP), R9
+ MOVQ 8(SP), AX // syscall entry
+ SYSCALL
+ JCC ok2
+ MOVQ $-1, 64(SP) // r1
+ MOVQ $0, 72(SP) // r2
+ MOVQ AX, 80(SP) // errno
+ RET
+ok2:
+ MOVQ AX, 64(SP) // r1
+ MOVQ DX, 72(SP) // r2
+ MOVQ $0, 80(SP) // errno
+ RET
diff --git a/src/pkg/syscall/bpf_bsd.go b/src/pkg/syscall/bpf_bsd.go
index 1eac9a3d8..f98036c42 100644
--- a/src/pkg/syscall/bpf_bsd.go
+++ b/src/pkg/syscall/bpf_bsd.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.
+// +build darwin freebsd netbsd openbsd
+
// Berkeley packet filter for BSD variants
package syscall
@@ -18,54 +20,54 @@ func BpfJump(code, k, jt, jf int) *BpfInsn {
return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
-func BpfBuflen(fd int) (int, int) {
+func BpfBuflen(fd int) (int, error) {
var l int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return l, 0
+ return l, nil
}
-func SetBpfBuflen(fd, l int) (int, int) {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
- if e := int(ep); e != 0 {
- return 0, e
+func SetBpfBuflen(fd, l int) (int, error) {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return l, 0
+ return l, nil
}
-func BpfDatalink(fd int) (int, int) {
+func BpfDatalink(fd int) (int, error) {
var t int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return t, 0
+ return t, nil
}
-func SetBpfDatalink(fd, t int) (int, int) {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
- if e := int(ep); e != 0 {
- return 0, e
+func SetBpfDatalink(fd, t int) (int, error) {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return t, 0
+ return t, nil
}
-func SetBpfPromisc(fd, m int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfPromisc(fd, m int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func FlushBpf(fd int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
- if e := int(ep); e != 0 {
- return e
+func FlushBpf(fd int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
type ivalue struct {
@@ -73,95 +75,95 @@ type ivalue struct {
value int16
}
-func BpfInterface(fd int, name string) (string, int) {
+func BpfInterface(fd int, name string) (string, error) {
var iv ivalue
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
- if e := int(ep); e != 0 {
- return "", e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
+ if err != 0 {
+ return "", Errno(err)
}
- return name, 0
+ return name, nil
}
-func SetBpfInterface(fd int, name string) int {
+func SetBpfInterface(fd int, name string) error {
var iv ivalue
copy(iv.name[:], []byte(name))
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func BpfTimeout(fd int) (*Timeval, int) {
+func BpfTimeout(fd int) (*Timeval, error) {
var tv Timeval
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
- if e := int(ep); e != 0 {
- return nil, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
+ if err != 0 {
+ return nil, Errno(err)
}
- return &tv, 0
+ return &tv, nil
}
-func SetBpfTimeout(fd int, tv *Timeval) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfTimeout(fd int, tv *Timeval) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func BpfStats(fd int) (*BpfStat, int) {
+func BpfStats(fd int) (*BpfStat, error) {
var s BpfStat
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
- if e := int(ep); e != 0 {
- return nil, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
+ if err != 0 {
+ return nil, Errno(err)
}
- return &s, 0
+ return &s, nil
}
-func SetBpfImmediate(fd, m int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfImmediate(fd, m int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func SetBpf(fd int, i []BpfInsn) int {
+func SetBpf(fd int, i []BpfInsn) error {
var p BpfProgram
p.Len = uint32(len(i))
p.Insns = (*BpfInsn)(unsafe.Pointer(&i[0]))
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func CheckBpfVersion(fd int) int {
+func CheckBpfVersion(fd int) error {
var v BpfVersion
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
+ if err != 0 {
+ return Errno(err)
}
if v.Major != BPF_MAJOR_VERSION || v.Minor != BPF_MINOR_VERSION {
return EINVAL
}
- return 0
+ return nil
}
-func BpfHeadercmpl(fd int) (int, int) {
+func BpfHeadercmpl(fd int) (int, error) {
var f int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return f, 0
+ return f, nil
}
-func SetBpfHeadercmpl(fd, f int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfHeadercmpl(fd, f int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
diff --git a/src/pkg/syscall/dll_windows.go b/src/pkg/syscall/dll_windows.go
new file mode 100644
index 000000000..2a45991dd
--- /dev/null
+++ b/src/pkg/syscall/dll_windows.go
@@ -0,0 +1,249 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "sync"
+)
+
+// DLLError describes reasons for DLL load failures.
+type DLLError struct {
+ Err error
+ ObjName string
+ Msg string
+}
+
+func (e *DLLError) Error() string { return e.Msg }
+
+// Implemented in ../runtime/windows/syscall.goc.
+func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
+func loadlibrary(filename *uint16) (handle, err Errno)
+func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)
+
+// A DLL implements access to a single DLL.
+type DLL struct {
+ Name string
+ Handle Handle
+}
+
+// LoadDLL loads DLL file into memory.
+func LoadDLL(name string) (dll *DLL, err error) {
+ h, e := loadlibrary(StringToUTF16Ptr(name))
+ if e != 0 {
+ return nil, &DLLError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to load " + name + ": " + e.Error(),
+ }
+ }
+ d := &DLL{
+ Name: name,
+ Handle: Handle(h),
+ }
+ return d, nil
+}
+
+// MustLoadDLL is like LoadDLL but panics if load operation failes.
+func MustLoadDLL(name string) *DLL {
+ d, e := LoadDLL(name)
+ if e != nil {
+ panic(e)
+ }
+ return d
+}
+
+// FindProc searches DLL d for procedure named name and returns *Proc
+// if found. It returns an error if search fails.
+func (d *DLL) FindProc(name string) (proc *Proc, err error) {
+ a, e := getprocaddress(uintptr(d.Handle), StringBytePtr(name))
+ if e != 0 {
+ return nil, &DLLError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
+ }
+ }
+ p := &Proc{
+ Dll: d,
+ Name: name,
+ addr: a,
+ }
+ return p, nil
+}
+
+// MustFindProc is like FindProc but panics if search fails.
+func (d *DLL) MustFindProc(name string) *Proc {
+ p, e := d.FindProc(name)
+ if e != nil {
+ panic(e)
+ }
+ return p
+}
+
+// Release unloads DLL d from memory.
+func (d *DLL) Release() (err error) {
+ return FreeLibrary(d.Handle)
+}
+
+// A Proc implements access to a procedure inside a DLL.
+type Proc struct {
+ Dll *DLL
+ Name string
+ addr uintptr
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *Proc) Addr() uintptr {
+ return p.addr
+}
+
+// Call executes procedure p with arguments a.
+func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
+ switch len(a) {
+ case 0:
+ return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
+ case 1:
+ return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
+ case 2:
+ return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
+ case 3:
+ return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
+ case 4:
+ return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
+ case 5:
+ return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
+ case 6:
+ return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
+ case 7:
+ return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
+ case 8:
+ return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
+ case 9:
+ return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
+ case 10:
+ return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
+ case 11:
+ return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
+ case 12:
+ return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
+ case 13:
+ return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
+ case 14:
+ return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
+ case 15:
+ return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
+ default:
+ panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
+ }
+ return
+}
+
+// A LazyDLL implements access to a single DLL.
+// It will delay the load of the DLL until the first
+// call to its Handle method or to one of its
+// LazyProc's Addr method.
+type LazyDLL struct {
+ mu sync.Mutex
+ dll *DLL // non nil once DLL is loaded
+ Name string
+}
+
+// Load loads DLL file d.Name into memory. It returns an error if fails.
+// Load will not try to load DLL, if it is already loaded into memory.
+func (d *LazyDLL) Load() error {
+ if d.dll == nil {
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.dll == nil {
+ dll, e := LoadDLL(d.Name)
+ if e != nil {
+ return e
+ }
+ d.dll = dll
+ }
+ }
+ return nil
+}
+
+// mustLoad is like Load but panics if search fails.
+func (d *LazyDLL) mustLoad() {
+ e := d.Load()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Handle returns d's module handle.
+func (d *LazyDLL) Handle() uintptr {
+ d.mustLoad()
+ return uintptr(d.dll.Handle)
+}
+
+// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
+func (d *LazyDLL) NewProc(name string) *LazyProc {
+ return &LazyProc{l: d, Name: name}
+}
+
+// NewLazyDLL creates new LazyDLL associated with DLL file.
+func NewLazyDLL(name string) *LazyDLL {
+ return &LazyDLL{Name: name}
+}
+
+// A LazyProc implements access to a procedure inside a LazyDLL.
+// It delays the lookup until the Addr method is called.
+type LazyProc struct {
+ mu sync.Mutex
+ Name string
+ l *LazyDLL
+ proc *Proc
+}
+
+// Find searches DLL for procedure named p.Name. It returns
+// an error if search fails. Find will not search procedure,
+// if it is already found and loaded into memory.
+func (p *LazyProc) Find() error {
+ if p.proc == nil {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.proc == nil {
+ e := p.l.Load()
+ if e != nil {
+ return e
+ }
+ proc, e := p.l.dll.FindProc(p.Name)
+ if e != nil {
+ return e
+ }
+ p.proc = proc
+ }
+ }
+ return nil
+}
+
+// mustFind is like Find but panics if search fails.
+func (p *LazyProc) mustFind() {
+ e := p.Find()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *LazyProc) Addr() uintptr {
+ p.mustFind()
+ return p.proc.Addr()
+}
+
+// Call executes procedure p with arguments a.
+func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
+ p.mustFind()
+ return p.proc.Call(a...)
+}
diff --git a/src/pkg/syscall/env_plan9.go b/src/pkg/syscall/env_plan9.go
new file mode 100644
index 000000000..2848d9b32
--- /dev/null
+++ b/src/pkg/syscall/env_plan9.go
@@ -0,0 +1,128 @@
+// 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.
+
+// Plan 9 environment variables.
+
+package syscall
+
+import (
+ "errors"
+ "sync"
+)
+
+var (
+ // envOnce guards initialization by copyenv, which populates env.
+ envOnce sync.Once
+
+ // envLock guards env.
+ envLock sync.RWMutex
+
+ // env maps from an environment variable to its value.
+ env map[string]string
+)
+
+func readenv(key string) (string, error) {
+ fd, err := Open("/env/"+key, O_RDONLY)
+ if err != nil {
+ return "", err
+ }
+ defer Close(fd)
+ l, _ := Seek(fd, 0, 2)
+ Seek(fd, 0, 0)
+ buf := make([]byte, l)
+ n, err := Read(fd, buf)
+ if err != nil {
+ return "", err
+ }
+ if n > 0 && buf[n-1] == 0 {
+ buf = buf[:n-1]
+ }
+ return string(buf), nil
+}
+
+func writeenv(key, value string) error {
+ fd, err := Create("/env/"+key, O_RDWR, 0666)
+ if err != nil {
+ return err
+ }
+ defer Close(fd)
+ _, err = Write(fd, []byte(value))
+ return err
+}
+
+func copyenv() {
+ env = make(map[string]string)
+ fd, err := Open("/env", O_RDONLY)
+ if err != nil {
+ return
+ }
+ defer Close(fd)
+ files, err := readdirnames(fd)
+ if err != nil {
+ return
+ }
+ for _, key := range files {
+ v, err := readenv(key)
+ if err != nil {
+ continue
+ }
+ env[key] = v
+ }
+}
+
+func Getenv(key string) (value string, found bool) {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return "", false
+ }
+
+ envLock.RLock()
+ defer envLock.RUnlock()
+
+ v, ok := env[key]
+ if !ok {
+ return "", false
+ }
+ return v, true
+}
+
+func Setenv(key, value string) error {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return errors.New("zero length key")
+ }
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ err := writeenv(key, value)
+ if err != nil {
+ return err
+ }
+ env[key] = value
+ return nil
+}
+
+func Clearenv() {
+ envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env = make(map[string]string)
+ RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
+}
+
+func Environ() []string {
+ envOnce.Do(copyenv)
+ envLock.RLock()
+ defer envLock.RUnlock()
+ a := make([]string, len(env))
+ i := 0
+ for k, v := range env {
+ a[i] = k + "=" + v
+ i++
+ }
+ return a
+}
diff --git a/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
new file mode 100644
index 000000000..8b1868c27
--- /dev/null
+++ b/src/pkg/syscall/env_unix.go
@@ -0,0 +1,109 @@
+// 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.
+
+// +build darwin freebsd linux netbsd openbsd
+
+// Unix environment variables.
+
+package syscall
+
+import "sync"
+
+var (
+ // envOnce guards initialization by copyenv, which populates env.
+ envOnce sync.Once
+
+ // envLock guards env and envs.
+ envLock sync.RWMutex
+
+ // env maps from an environment variable to its first occurrence in envs.
+ env map[string]int
+
+ // envs is provided by the runtime. elements are expected to be
+ // of the form "key=value".
+ envs []string
+)
+
+// setenv_c is provided by the runtime, but is a no-op if cgo isn't
+// loaded.
+func setenv_c(k, v string)
+
+func copyenv() {
+ env = make(map[string]int)
+ for i, s := range envs {
+ for j := 0; j < len(s); j++ {
+ if s[j] == '=' {
+ key := s[:j]
+ if _, ok := env[key]; !ok {
+ env[key] = i
+ }
+ break
+ }
+ }
+ }
+}
+
+func Getenv(key string) (value string, found bool) {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return "", false
+ }
+
+ envLock.RLock()
+ defer envLock.RUnlock()
+
+ i, ok := env[key]
+ if !ok {
+ return "", false
+ }
+ s := envs[i]
+ for i := 0; i < len(s); i++ {
+ if s[i] == '=' {
+ return s[i+1:], true
+ }
+ }
+ return "", false
+}
+
+func Setenv(key, value string) error {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return EINVAL
+ }
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ i, ok := env[key]
+ kv := key + "=" + value
+ if ok {
+ envs[i] = kv
+ } else {
+ i = len(envs)
+ envs = append(envs, kv)
+ }
+ env[key] = i
+ setenv_c(key, value)
+ return nil
+}
+
+func Clearenv() {
+ envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env = make(map[string]int)
+ envs = []string{}
+ // TODO(bradfitz): pass through to C
+}
+
+func Environ() []string {
+ envOnce.Do(copyenv)
+ envLock.RLock()
+ defer envLock.RUnlock()
+ a := make([]string, len(envs))
+ copy(a, envs)
+ return a
+}
diff --git a/src/pkg/syscall/env_windows.go b/src/pkg/syscall/env_windows.go
new file mode 100644
index 000000000..8308f10a2
--- /dev/null
+++ b/src/pkg/syscall/env_windows.go
@@ -0,0 +1,77 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows environment variables.
+
+package syscall
+
+import (
+ "unicode/utf16"
+ "unsafe"
+)
+
+func Getenv(key string) (value string, found bool) {
+ b := make([]uint16, 100)
+ n, e := GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, e = GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n > uint32(len(b)) {
+ n = 0
+ }
+ }
+ if n == 0 {
+ return "", false
+ }
+ return string(utf16.Decode(b[0:n])), true
+}
+
+func Setenv(key, value string) error {
+ var v *uint16
+ if len(value) > 0 {
+ v = StringToUTF16Ptr(value)
+ }
+ e := SetEnvironmentVariable(StringToUTF16Ptr(key), v)
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func Clearenv() {
+ for _, s := range Environ() {
+ // Environment variables can begin with =
+ // so start looking for the separator = at j=1.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ for j := 1; j < len(s); j++ {
+ if s[j] == '=' {
+ Setenv(s[0:j], "")
+ break
+ }
+ }
+ }
+}
+
+func Environ() []string {
+ s, e := GetEnvironmentStrings()
+ if e != nil {
+ return nil
+ }
+ defer FreeEnvironmentStrings(s)
+ r := make([]string, 0, 50) // Empty with room to grow.
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
diff --git a/src/pkg/syscall/exec_bsd.go b/src/pkg/syscall/exec_bsd.go
new file mode 100644
index 000000000..9c3af5ec9
--- /dev/null
+++ b/src/pkg/syscall/exec_bsd.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.
+
+// +build darwin freebsd netbsd openbsd
+
+package syscall
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+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
+}
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+// The calls to RawSyscall are okay because they are assembly
+// functions that do not grow the stack.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., err1).
+ var (
+ r1, r2 uintptr
+ err1 Errno
+ nextfd int
+ i int
+ )
+
+ fd := make([]int, len(attr.Files))
+ for i, ufd := range attr.Files {
+ fd[i] = int(ufd)
+ }
+
+ darwin := runtime.GOOS == "darwin"
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
+ if err1 != 0 {
+ return 0, err1
+ }
+
+ // On Darwin:
+ // r1 = child pid in both parent and child.
+ // r2 = 0 in parent, 1 in child.
+ // Convert to normal Unix r1 = 0 in child.
+ if darwin && r2 == 1 {
+ r1 = 0
+ }
+
+ if r1 != 0 {
+ // parent; return PID
+ return int(r1), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Enable tracing if requested.
+ if sys.Ptrace {
+ _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Session ID
+ if sys.Setsid {
+ _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Set process group
+ if sys.Setpgid {
+ _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ groups := uintptr(0)
+ if ngroups > 0 {
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ }
+ _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ nextfd = int(len(fd))
+ if pipe < nextfd {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ continue
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ continue
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ }
+
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Time to exec.
+ _, _, err1 = RawSyscall(SYS_EXECVE,
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])),
+ uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+ // send error code on pipe
+ RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ for {
+ RawSyscall(SYS_EXIT, 253, 0, 0)
+ }
+
+ // Calling panic is not actually safe,
+ // but the for loop above won't break
+ // and this shuts up the compiler.
+ panic("unreached")
+}
diff --git a/src/pkg/syscall/exec_linux.go b/src/pkg/syscall/exec_linux.go
new file mode 100644
index 000000000..70f3e6217
--- /dev/null
+++ b/src/pkg/syscall/exec_linux.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.
+
+// +build linux
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+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
+ Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
+}
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork. This means
+// no rescheduling, no malloc calls, and no new stack segments.
+// The calls to RawSyscall are okay because they are assembly
+// functions that do not grow the stack.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+ // Declare all variables at top in case any
+ // declarations require heap allocation (e.g., err1).
+ var (
+ r1 uintptr
+ err1 Errno
+ nextfd int
+ i int
+ )
+
+ // guard against side effects of shuffling fds below.
+ fd := make([]int, len(attr.Files))
+ for i, ufd := range attr.Files {
+ fd[i] = int(ufd)
+ }
+
+ // About to call fork.
+ // No more allocation or calls of non-assembly functions.
+ r1, _, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
+ if err1 != 0 {
+ return 0, err1
+ }
+
+ if r1 != 0 {
+ // parent; return PID
+ return int(r1), 0
+ }
+
+ // Fork succeeded, now in child.
+
+ // Parent death signal
+ if sys.Pdeathsig != 0 {
+ _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+
+ // Signal self if parent is already dead. This might cause a
+ // duplicate signal in rare cases, but it won't matter when
+ // using SIGKILL.
+ r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
+ if r1 == 1 {
+ pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ _, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+ }
+
+ // Enable tracing if requested.
+ if sys.Ptrace {
+ _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Session ID
+ if sys.Setsid {
+ _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Set process group
+ if sys.Setpgid {
+ _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ groups := uintptr(0)
+ if ngroups > 0 {
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+ }
+ _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Chdir
+ if dir != nil {
+ _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Pass 1: look for fd[i] < i and move those up above len(fd)
+ // so that pass 2 won't stomp on an fd it needs later.
+ nextfd = int(len(fd))
+ if pipe < nextfd {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ pipe = nextfd
+ nextfd++
+ }
+ for i = 0; i < len(fd); i++ {
+ if fd[i] >= 0 && fd[i] < int(i) {
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+ fd[i] = nextfd
+ nextfd++
+ if nextfd == pipe { // don't stomp on pipe
+ nextfd++
+ }
+ }
+ }
+
+ // Pass 2: dup fd[i] down onto i.
+ for i = 0; i < len(fd); i++ {
+ if fd[i] == -1 {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ continue
+ }
+ if fd[i] == int(i) {
+ // dup2(i, i) won't clear close-on-exec flag on Linux,
+ // probably not elsewhere either.
+ _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ continue
+ }
+ // The new fd is created NOT close-on-exec,
+ // which is exactly what we want.
+ _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // By convention, we don't close-on-exec the fds we are
+ // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+ // Programs that know they inherit fds >= 3 will need
+ // to set them close-on-exec.
+ for i = len(fd); i < 3; i++ {
+ RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
+ }
+
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ // Time to exec.
+ _, _, err1 = RawSyscall(SYS_EXECVE,
+ uintptr(unsafe.Pointer(argv0)),
+ uintptr(unsafe.Pointer(&argv[0])),
+ uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+ // send error code on pipe
+ RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ for {
+ RawSyscall(SYS_EXIT, 253, 0, 0)
+ }
+
+ // Calling panic is not actually safe,
+ // but the for loop above won't break
+ // and this shuts up the compiler.
+ panic("unreached")
+}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index 66ab1fced..7e4e180fa 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -71,13 +71,13 @@ func StringSlicePtr(ss []string) []*byte {
return bb
}
-// 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:]
}
-// 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)
@@ -85,7 +85,7 @@ func gstring(b []byte) (string, []byte) {
}
// readdirnames returns the names of files inside the directory represented by dirfd.
-func readdirnames(dirfd int) (names []string, err Error) {
+func readdirnames(dirfd int) (names []string, err error) {
result := make([]string, 0, 100)
var buf [STATMAX]byte
@@ -117,7 +117,7 @@ func readdirnames(dirfd int) (names []string, err Error) {
// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
-func readdupdevice() (fds []int, err Error) {
+func readdupdevice() (fds []int, err error) {
dupdevfd, err := Open("#d", O_RDONLY)
if err != nil {
@@ -169,7 +169,7 @@ func init() {
// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err Error) {
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err error) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., errbuf).
var (
@@ -182,7 +182,10 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
)
// guard against side effects of shuffling fds below.
- fd := append([]int(nil), attr.Files...)
+ fd := make([]int, len(attr.Files))
+ for i, ufd := range attr.Files {
+ fd[i] = int(ufd)
+ }
if envv != nil {
clearenv = RFCENVG
@@ -314,7 +317,7 @@ childerror:
panic("unreached")
}
-func cexecPipe(p []int) Error {
+func cexecPipe(p []int) error {
e := Pipe(p)
if e != nil {
return e
@@ -338,9 +341,9 @@ type envItem struct {
}
type ProcAttr struct {
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []uintptr // File descriptors.
Sys *SysProcAttr
}
@@ -351,7 +354,7 @@ type SysProcAttr struct {
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
-func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
+func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
var (
p [2]int
n int
@@ -423,7 +426,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
for _, fd := range openFds {
isReserved := false
for _, reservedFd := range attr.Files {
- if fd == reservedFd {
+ if fd == int(reservedFd) {
isReserved = true
break
}
@@ -478,18 +481,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
}
// Combination of fork and exec, careful to be thread safe.
-func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
+func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
return forkExec(argv0, argv, attr)
}
// StartProcess wraps ForkExec for package os.
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err Error) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
pid, err = forkExec(argv0, argv, attr)
return pid, 0, err
}
// Ordinary exec.
-func Exec(argv0 string, argv []string, envv []string) (err Error) {
+func Exec(argv0 string, argv []string, envv []string) (err error) {
if envv != nil {
r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
if int(r1) == -1 {
@@ -516,10 +519,10 @@ func Exec(argv0 string, argv []string, envv []string) (err Error) {
}
}
- _, _, e := Syscall(SYS_EXEC,
+ _, _, e1 := Syscall(SYS_EXEC,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
0)
- return NewError(e)
+ return e1
}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index 94f075622..dfaa0374a 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
// Fork, exec, wait, etc.
package syscall
import (
+ "runtime"
"sync"
"unsafe"
)
@@ -73,9 +76,9 @@ func StringSlicePtr(ss []string) []*byte {
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
-func SetNonblock(fd int, nonblocking bool) (errno int) {
+func SetNonblock(fd int, nonblocking bool) (err error) {
flag, err := fcntl(fd, F_GETFL, 0)
- if err != 0 {
+ if err != nil {
return err
}
if nonblocking {
@@ -87,202 +90,6 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
return err
}
-// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
-// If a dup or exec fails, write the errno int to pipe.
-// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
-// In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork. This means
-// no rescheduling, no malloc calls, and no new stack segments.
-// The calls to RawSyscall are okay because they are assembly
-// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, 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
- var nextfd int
- var i int
-
- // guard against side effects of shuffling fds below.
- fd := append([]int(nil), attr.Files...)
-
- darwin := OS == "darwin"
-
- // About to call fork.
- // No more allocation or calls of non-assembly functions.
- r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
- if err1 != 0 {
- return 0, int(err1)
- }
-
- // On Darwin:
- // r1 = child pid in both parent and child.
- // r2 = 0 in parent, 1 in child.
- // Convert to normal Unix r1 = 0 in child.
- if darwin && r2 == 1 {
- r1 = 0
- }
-
- if r1 != 0 {
- // parent; return PID
- return int(r1), 0
- }
-
- // Fork succeeded, now in child.
-
- // Enable tracing if requested.
- if sys.Ptrace {
- _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Session ID
- if sys.Setsid {
- _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Set process group
- if sys.Setpgid {
- _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Chroot
- if chroot != nil {
- _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // User and groups
- if cred := sys.Credential; cred != nil {
- ngroups := uintptr(len(cred.Groups))
- groups := uintptr(0)
- if ngroups > 0 {
- groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
- }
- _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
- if err1 != 0 {
- goto childerror
- }
- _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
- if err1 != 0 {
- goto childerror
- }
- _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Chdir
- if dir != nil {
- _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Pass 1: look for fd[i] < i and move those up above len(fd)
- // so that pass 2 won't stomp on an fd it needs later.
- nextfd = int(len(fd))
- if pipe < nextfd {
- _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
- if err1 != 0 {
- goto childerror
- }
- RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
- pipe = nextfd
- nextfd++
- }
- for i = 0; i < len(fd); i++ {
- if fd[i] >= 0 && fd[i] < int(i) {
- _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
- if err1 != 0 {
- goto childerror
- }
- RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
- fd[i] = nextfd
- nextfd++
- if nextfd == pipe { // don't stomp on pipe
- nextfd++
- }
- }
- }
-
- // Pass 2: dup fd[i] down onto i.
- for i = 0; i < len(fd); i++ {
- if fd[i] == -1 {
- RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
- continue
- }
- if fd[i] == int(i) {
- // dup2(i, i) won't clear close-on-exec flag on Linux,
- // probably not elsewhere either.
- _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
- if err1 != 0 {
- goto childerror
- }
- continue
- }
- // The new fd is created NOT close-on-exec,
- // which is exactly what we want.
- _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // By convention, we don't close-on-exec the fds we are
- // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
- // Programs that know they inherit fds >= 3 will need
- // to set them close-on-exec.
- for i = len(fd); i < 3; i++ {
- RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
- }
-
- // Detach fd 0 from tty
- if sys.Noctty {
- _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Make fd 0 the tty
- if sys.Setctty {
- _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
- if err1 != 0 {
- goto childerror
- }
- }
-
- // Time to exec.
- _, _, err1 = RawSyscall(SYS_EXECVE,
- uintptr(unsafe.Pointer(argv0)),
- uintptr(unsafe.Pointer(&argv[0])),
- uintptr(unsafe.Pointer(&envv[0])))
-
-childerror:
- // send error code on pipe
- RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
- for {
- RawSyscall(SYS_EXIT, 253, 0, 0)
- }
-
- // Calling panic is not actually safe,
- // but the for loop above won't break
- // and this shuts up the compiler.
- panic("unreached")
-}
-
// Credential holds user and group identities to be assumed
// by a child process started by StartProcess.
type Credential struct {
@@ -294,29 +101,19 @@ type Credential struct {
// ProcAttr holds attributes that will be applied to a new process started
// by StartProcess.
type ProcAttr struct {
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []uintptr // File descriptors.
Sys *SysProcAttr
}
-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) {
+func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
var p [2]int
var n int
- var err1 uintptr
+ var err1 Errno
var wstatus WaitStatus
if attr == nil {
@@ -335,7 +132,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
argvp := StringSlicePtr(argv)
envvp := StringSlicePtr(attr.Env)
- if OS == "freebsd" && len(argv[0]) > len(argv0) {
+ if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
}
@@ -354,19 +151,20 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
ForkLock.Lock()
// Allocate child status pipe close on exec.
- if err = Pipe(p[0:]); err != 0 {
+ if err = Pipe(p[0:]); err != nil {
goto error
}
- if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
+ if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
goto error
}
- if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
+ if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != nil {
goto error
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
- if err != 0 {
+ pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
+ if err1 != 0 {
+ err = Errno(err1)
goto error
}
ForkLock.Unlock()
@@ -375,11 +173,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
Close(p[1])
n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
Close(p[0])
- if err != 0 || n != 0 {
+ if err != nil || n != 0 {
if n == int(unsafe.Sizeof(err1)) {
- err = int(err1)
+ err = Errno(err1)
}
- if err == 0 {
+ if err == nil {
err = EPIPE
}
@@ -393,7 +191,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
}
// Read got EOF, so pipe closed on exec, so exec succeeded.
- return pid, 0
+ return pid, nil
error:
if p[0] >= 0 {
@@ -405,21 +203,21 @@ error:
}
// Combination of fork and exec, careful to be thread safe.
-func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
+func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
return forkExec(argv0, argv, attr)
}
// StartProcess wraps ForkExec for package os.
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
pid, err = forkExec(argv0, argv, attr)
return pid, 0, err
}
// Ordinary exec.
-func Exec(argv0 string, argv []string, envv []string) (err int) {
+func Exec(argv0 string, argv []string, envv []string) (err error) {
_, _, err1 := RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0])))
- return int(err1)
+ return Errno(err1)
}
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
index e8b540ad1..4dc4d059d 100644
--- a/src/pkg/syscall/exec_windows.go
+++ b/src/pkg/syscall/exec_windows.go
@@ -8,8 +8,8 @@ package syscall
import (
"sync"
+ "unicode/utf16"
"unsafe"
- "utf16"
)
var ForkLock sync.RWMutex
@@ -100,7 +100,7 @@ func makeCmdLine(args []string) string {
// Last bytes are two UCS-2 NULs, or four NUL bytes.
func createEnvBlock(envv []string) *uint16 {
if len(envv) == 0 {
- return &utf16.Encode([]int("\x00\x00"))[0]
+ return &utf16.Encode([]rune("\x00\x00"))[0]
}
length := 0
for _, s := range envv {
@@ -118,54 +118,54 @@ func createEnvBlock(envv []string) *uint16 {
}
copy(b[i:i+1], []byte{0})
- return &utf16.Encode([]int(string(b)))[0]
+ return &utf16.Encode([]rune(string(b)))[0]
}
func CloseOnExec(fd Handle) {
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
}
-func SetNonblock(fd Handle, nonblocking bool) (errno int) {
- return 0
+func SetNonblock(fd Handle, nonblocking bool) (err error) {
+ return nil
}
// getFullPath retrieves the full path of the specified file.
// Just a wrapper for Windows GetFullPathName api.
-func getFullPath(name string) (path string, err int) {
+func getFullPath(name string) (path string, err error) {
p := StringToUTF16Ptr(name)
buf := make([]uint16, 100)
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
- if err != 0 {
+ if err != nil {
return "", err
}
if n > uint32(len(buf)) {
// Windows is asking for bigger buffer.
buf = make([]uint16, n)
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
- if err != 0 {
+ if err != nil {
return "", err
}
if n > uint32(len(buf)) {
return "", EINVAL
}
}
- return UTF16ToString(buf[:n]), 0
+ return UTF16ToString(buf[:n]), nil
}
func isSlash(c uint8) bool {
return c == '\\' || c == '/'
}
-func normalizeDir(dir string) (name string, err int) {
+func normalizeDir(dir string) (name string, err error) {
ndir, err := getFullPath(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
// dir cannot have \\server\share\path form
return "", EINVAL
}
- return ndir, 0
+ return ndir, nil
}
func volToUpper(ch int) int {
@@ -175,13 +175,13 @@ func volToUpper(ch int) int {
return ch
}
-func joinExeDirAndFName(dir, p string) (name string, err int) {
+func joinExeDirAndFName(dir, p string) (name string, err error) {
if len(p) == 0 {
return "", EINVAL
}
if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
// \\server\share\path form
- return p, 0
+ return p, nil
}
if len(p) > 1 && p[1] == ':' {
// has drive letter
@@ -189,10 +189,10 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
return "", EINVAL
}
if isSlash(p[2]) {
- return p, 0
+ return p, nil
} else {
d, err := normalizeDir(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
@@ -204,7 +204,7 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
} else {
// no drive letter
d, err := normalizeDir(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if isSlash(p[0]) {
@@ -220,7 +220,7 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
type ProcAttr struct {
Dir string
Env []string
- Files []Handle
+ Files []uintptr
Sys *SysProcAttr
}
@@ -232,7 +232,7 @@ type SysProcAttr struct {
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
if len(argv0) == 0 {
return 0, 0, EWINDOWS
}
@@ -255,9 +255,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
// argv0 relative to the current directory, and, only once the new
// process is started, it does Chdir(attr.Dir). We are adjusting
// for that difference here by making argv0 absolute.
- var err int
+ var err error
argv0, err = joinExeDirAndFName(attr.Dir, argv0)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
}
@@ -294,7 +294,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
for i := range attr.Files {
if attr.Files[i] > 0 {
err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
defer CloseHandle(Handle(fd[i]))
@@ -314,14 +314,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
pi := new(ProcessInformation)
err = CreateProcess(argv0p, argvp, nil, nil, true, CREATE_UNICODE_ENVIRONMENT, createEnvBlock(attr.Env), dirp, si, pi)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
defer CloseHandle(Handle(pi.Thread))
- return int(pi.ProcessId), int(pi.Process), 0
+ return int(pi.ProcessId), uintptr(pi.Process), nil
}
-func Exec(argv0 string, argv []string, envv []string) (err int) {
+func Exec(argv0 string, argv []string, envv []string) (err error) {
return EWINDOWS
}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
index f2bd2b757..05d653b4a 100644
--- a/src/pkg/syscall/lsf_linux.go
+++ b/src/pkg/syscall/lsf_linux.go
@@ -18,10 +18,10 @@ func LsfJump(code, k, jt, jf int) *SockFilter {
return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
-func LsfSocket(ifindex, proto int) (int, int) {
+func LsfSocket(ifindex, proto int) (int, error) {
var lsall SockaddrLinklayer
s, e := Socket(AF_PACKET, SOCK_RAW, proto)
- if e != 0 {
+ if e != nil {
return 0, e
}
p := (*[2]byte)(unsafe.Pointer(&lsall.Protocol))
@@ -29,11 +29,11 @@ func LsfSocket(ifindex, proto int) (int, int) {
p[1] = byte(proto)
lsall.Ifindex = ifindex
e = Bind(s, &lsall)
- if e != 0 {
+ if e != nil {
Close(s)
return 0, e
}
- return s, 0
+ return s, nil
}
type iflags struct {
@@ -41,17 +41,17 @@ type iflags struct {
flags uint16
}
-func SetLsfPromisc(name string, m bool) int {
+func SetLsfPromisc(name string, m bool) error {
s, e := Socket(AF_INET, SOCK_DGRAM, 0)
- if e != 0 {
+ if e != nil {
return e
}
defer Close(s)
var ifl iflags
copy(ifl.name[:], []byte(name))
_, _, ep := Syscall(SYS_IOCTL, uintptr(s), SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
- if e := int(ep); e != 0 {
- return e
+ if ep != 0 {
+ return Errno(ep)
}
if m {
ifl.flags |= uint16(IFF_PROMISC)
@@ -59,20 +59,20 @@ func SetLsfPromisc(name string, m bool) int {
ifl.flags &= ^uint16(IFF_PROMISC)
}
_, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
- if e := int(ep); e != 0 {
- return e
+ if ep != 0 {
+ return Errno(ep)
}
- return 0
+ return nil
}
-func AttachLsf(fd int, i []SockFilter) int {
+func AttachLsf(fd int, i []SockFilter) error {
var p SockFprog
p.Len = uint16(len(i))
p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
}
-func DetachLsf(fd int) int {
+func DetachLsf(fd int) error {
var dummy int
return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index 7d0c1ac2a..9e2d98f0d 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -79,6 +79,8 @@ GOOSARCH="${GOOS}_${GOARCH}"
mksyscall="./mksyscall.pl"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
+mksysctl=""
+zsysctl="zsysctl_$GOOSARCH.go"
run="sh"
case "$1" in
@@ -107,65 +109,93 @@ _* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
-freebsd_386)
- mkerrors="$mkerrors -f -m32"
- mksyscall="./mksyscall.pl -l32"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
- mktypes="godefs -gsyscall -f-m32"
- ;;
-freebsd_amd64)
- mkerrors="$mkerrors -f -m64"
- mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
- mktypes="godefs -gsyscall -f-m64"
- ;;
darwin_386)
- mkerrors="$mkerrors -f -m32"
+ mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32"
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
- mktypes="godefs -gsyscall -f-m32"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
darwin_amd64)
- mkerrors="$mkerrors -f -m64"
+ mkerrors="$mkerrors -m64"
mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
- mktypes="godefs -gsyscall -f-m64"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="./mksyscall.pl -l32"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+freebsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
linux_386)
- mkerrors="$mkerrors -f -m32"
+ mkerrors="$mkerrors -m32"
mksyscall="./mksyscall.pl -l32"
mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_32.h"
- mktypes="godefs -gsyscall -f-m32"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
linux_amd64)
- mkerrors="$mkerrors -f -m64"
+ mkerrors="$mkerrors -m64"
mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd_64.h"
- mktypes="godefs -gsyscall -f-m64"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
linux_arm)
mkerrors="$mkerrors"
- mksyscall="./mksyscall.pl -b32"
- mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd.h"
- mktypes="godefs -gsyscall"
+ mksyscall="./mksyscall.pl -l32 -arm"
+ mksysnum="curl -s 'http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=arch/arm/include/asm/unistd.h;hb=HEAD' | ./mksysnum_linux.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="./mksyscall.pl -l32 -netbsd"
+ mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+netbsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="./mksyscall.pl -netbsd"
+ mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_386)
+ mkerrors="$mkerrors -m32"
+ mksyscall="./mksyscall.pl -l32 -openbsd"
+ mksysctl="./mksysctl_openbsd.pl"
+ zsysctl="zsysctl_openbsd.go"
+ mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+openbsd_amd64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="./mksyscall.pl -openbsd"
+ mksysctl="./mksysctl_openbsd.pl"
+ zsysctl="zsysctl_openbsd.go"
+ mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+plan9_386)
+ mkerrors=
+ mksyscall="./mksyscall.pl -l32 -plan9"
+ mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
+ mktypes="XXX"
;;
windows_386)
mksyscall="./mksyscall_windows.pl -l32"
mksysnum=
mktypes=
- mkerrors="./mkerrors_windows.sh -f -m32"
+ mkerrors="./mkerrors_windows.sh -m32"
zerrors="zerrors_windows.go"
;;
windows_amd64)
mksyscall="./mksyscall_windows.pl"
mksysnum=
mktypes=
- mkerrors="./mkerrors_windows.sh -f -m32"
+ mkerrors="./mkerrors_windows.sh -m32"
zerrors="zerrors_windows.go"
;;
-plan9_386)
- mkerrors=
- mksyscall="./mksyscall.pl -l32 -plan9"
- mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
- mktypes="godefs -gsyscall -f -m32"
- ;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
@@ -176,11 +206,15 @@ esac
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
- darwin | freebsd)
+ darwin | freebsd | netbsd | openbsd)
syscall_goos="syscall_bsd.go $syscall_goos"
;;
+ windows)
+ syscall_goos="$syscall_goos security_windows.go"
+ ;;
esac
+ if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
- if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.c |gofmt >ztypes_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index c90cd1c00..9aacec29c 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -15,6 +15,46 @@ GCC=gcc
uname=$(uname)
+includes_Darwin='
+#define _DARWIN_C_SOURCE
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
+#include <termios.h>
+'
+
+includes_FreeBSD='
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <termios.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
+'
+
includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
@@ -27,6 +67,7 @@ includes_Linux='
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/if_addr.h>
@@ -40,51 +81,56 @@ includes_Linux='
#include <linux/wait.h>
#include <net/if.h>
#include <net/if_arp.h>
+#include <net/route.h>
#include <netpacket/packet.h>
'
-includes_Darwin='
-#define _DARWIN_C_SOURCE
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
+includes_NetBSD='
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/event.h>
-#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
-#include <sys/mman.h>
+#include <sys/termios.h>
+#include <sys/ttycom.h>
#include <sys/wait.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
+#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
-#include <termios.h>
+#include <netinet/if_ether.h>
'
-includes_FreeBSD='
+includes_OpenBSD='
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
+#include <sys/termios.h>
+#include <sys/ttycom.h>
#include <sys/wait.h>
-#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
-#include <termios.h>
+#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
+#include <netinet/if_ether.h>
+#include <net/if_bridge.h>
'
includes='
#include <sys/types.h>
+#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
@@ -95,32 +141,28 @@ includes='
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
+#include <sys/resource.h>
'
-ccflags=""
-next=false
-for i
-do
- if $next; then
- ccflags="$ccflags $i"
- next=false
- elif [ "$i" = "-f" ]; then
- next=true
- fi
-done
-
-# Write godefs input.
+ccflags="$@"
+
+# Write go tool cgo -godefs input.
(
+ echo package syscall
+ echo
+ echo '/*'
indirect="includes_$(uname)"
echo "${!indirect} $includes"
+ echo '*/'
+ echo 'import "C"'
echo
- echo 'enum {'
+ echo 'const ('
# The gcc command line prints all the #defines
# it encounters while processing the input
echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
awk '
- $1 != "#define" || $2 ~ /\(/ {next}
+ $1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
@@ -134,7 +176,8 @@ done
$2 ~ /^E[A-Z0-9_]+$/ ||
$2 ~ /^SIG[^_]/ ||
$2 ~ /^IN_/ ||
- $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV)_/ ||
+ $2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
$2 == "IFNAMSIZ" ||
@@ -146,43 +189,75 @@ done
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 !~ "NLA_TYPE_MASK" &&
- $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|RTM|RTN|RTPROT|RTA|RTAX|RTNH|ARPHRD|ETH_P)_/ ||
+ $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
+ $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
+ $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
$2 !~ /^(BPF_TIMEVAL)$/ &&
$2 ~ /^(BPF|DLT)_/ ||
$2 !~ "WMESGLEN" &&
- $2 ~ /^W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", $2, $2)}
+ $2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
$2 ~ /^__WCOREFLAG$/ {next}
- $2 ~ /^__W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", substr($2,3), $2)}
+ $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
{next}
' | sort
- echo '};'
-) >_const.c
+ echo ')'
+) >_const.go
-# Pull out just the error names for later.
+# Pull out the error names for later.
errors=$(
echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
sort
)
+# Pull out the signal names for later.
+signals=$(
+ echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ sort
+)
+
+# Again, writing regexps to a file.
+echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
+ sort >_error.grep
+echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ sort >_signal.grep
+
echo '// mkerrors.sh' "$@"
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
-godefs -c $GCC "$@" -gsyscall "$@" _const.c
+go tool cgo -godefs -- "$@" _const.go >_error.out
+cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
+echo
+echo '// Errors'
+echo 'const ('
+cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
+echo ')'
-# Run C program to print error strings.
+echo
+echo '// Signals'
+echo 'const ('
+cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
+echo ')'
+
+# Run C program to print error and syscall strings.
(
/bin/echo "
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
+#include <signal.h>
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
@@ -195,6 +270,16 @@ int errors[] = {
/bin/echo ' '$i,
done
+ /bin/echo "
+};
+
+int signals[] = {
+"
+ for i in $signals
+ do
+ /bin/echo ' '$i,
+ done
+
# Use /bin/echo to avoid builtin echo,
# which interprets \n itself
/bin/echo '
@@ -210,7 +295,7 @@ int
main(void)
{
int i, j, e;
- char buf[1024];
+ char buf[1024], *p;
printf("\n\n// Error table\n");
printf("var errors = [...]string {\n");
@@ -226,10 +311,30 @@ main(void)
printf("\t%d: \"%s\",\n", e, buf);
}
printf("}\n\n");
+
+ printf("\n\n// Signal table\n");
+ printf("var signals = [...]string {\n");
+ qsort(signals, nelem(signals), sizeof signals[0], intcmp);
+ for(i=0; i<nelem(signals); i++) {
+ e = signals[i];
+ if(i > 0 && signals[i-1] == e)
+ continue;
+ strcpy(buf, strsignal(e));
+ // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
+ if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
+ buf[0] += a - A;
+ // cut trailing : number.
+ p = strrchr(buf, ":"[0]);
+ if(p)
+ *p = '\0';
+ printf("\t%d: \"%s\",\n", e, buf);
+ }
+ printf("}\n\n");
+
return 0;
}
'
) >_errors.c
-$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.c
+$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
index af95edd00..13badcd92 100755
--- a/src/pkg/syscall/mkerrors_windows.sh
+++ b/src/pkg/syscall/mkerrors_windows.sh
@@ -76,7 +76,7 @@ done
# These are go errors that will be mapped directly to windows errors
goerrors='
ENOENT:ERROR_FILE_NOT_FOUND
-ENOTDIR:ERROR_DIRECTORY
+ENOTDIR:ERROR_PATH_NOT_FOUND
'
# Pull out just the error names for later.
@@ -158,7 +158,7 @@ main(void)
printf("\n// Go names for Windows errors.\n");
printf("const (\n");
for(i=0; i<nelem(goerrors); i++) {
- printf("\t%s = %s\n", goerrors[i].goname, goerrors[i].winname);
+ printf("\t%s Errno = %s\n", goerrors[i].goname, goerrors[i].winname);
}
printf(")\n");
@@ -171,7 +171,7 @@ main(void)
for(i=0; i<nelem(errors); i++) {
printf("\t%s", errors[i].name);
if(iota) {
- printf(" = APPLICATION_ERROR + iota");
+ printf(" Errno = APPLICATION_ERROR + iota");
iota = !iota;
}
printf("\n");
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index ed6525972..09949688e 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -25,6 +25,9 @@ my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
my $errors = 0;
my $_32bit = "";
my $plan9 = 0;
+my $openbsd = 0;
+my $netbsd = 0;
+my $arm = 0; # 64-bit value should use (even, odd)-pair
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
@@ -37,6 +40,18 @@ if($ARGV[0] eq "-plan9") {
$plan9 = 1;
shift;
}
+if($ARGV[0] eq "-openbsd") {
+ $openbsd = 1;
+ shift;
+}
+if($ARGV[0] eq "-netbsd") {
+ $netbsd = 1;
+ shift;
+}
+if($ARGV[0] eq "-arm") {
+ $arm = 1;
+ shift;
+}
if($ARGV[0] =~ /^-/) {
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
@@ -73,7 +88,7 @@ while(<>) {
next if !/^\/\/sys / && !$nonblock;
# Line must be of the form
- # func Open(path string, mode int, perm int) (fd int, errno int)
+ # func Open(path string, mode int, perm int) (fd int, errno error)
# Split into name, in params, out params.
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
@@ -115,7 +130,21 @@ while(<>) {
$text .= "\n";
push @args, "uintptr(_p$n)", "uintptr(len($name))";
$n++;
+ } elsif($type eq "int64" && ($openbsd || $netbsd)) {
+ push @args, "0";
+ if($_32bit eq "big-endian") {
+ push @args, "uintptr($name>>32)", "uintptr($name)";
+ } elsif($_32bit eq "little-endian") {
+ push @args, "uintptr($name)", "uintptr($name>>32)";
+ } else {
+ push @args, "uintptr($name)";
+ }
} elsif($type eq "int64" && $_32bit ne "") {
+ if(@args % 2 && $arm) {
+ # arm abi specifies 64-bit argument uses
+ # (even, odd) pair
+ push @args, "0"
+ }
if($_32bit eq "big-endian") {
push @args, "uintptr($name>>32)", "uintptr($name)";
} else {
@@ -163,15 +192,17 @@ while(<>) {
# Assign return values.
my $body = "";
my @ret = ("_", "_", "_");
+ my $do_errno = 0;
for(my $i=0; $i<@out; $i++) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
my $reg = "";
- if($name eq "errno" && !$plan9) {
+ if($name eq "err" && !$plan9) {
$reg = "e1";
$ret[2] = $reg;
- } elsif ($name eq "err" && $plan9) {
- $ret[0] = "r0";
+ $do_errno = 1;
+ } elsif($name eq "err" && $plan9) {
+ $ret[0] = "r0";
$ret[2] = "e1";
next;
} else {
@@ -194,7 +225,9 @@ while(<>) {
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
- $body .= "\t$name = $type($reg)\n";
+ if($reg ne "e1" || $plan9) {
+ $body .= "\t$name = $type($reg)\n";
+ }
}
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
$text .= "\t$call\n";
@@ -204,12 +237,14 @@ while(<>) {
$text .= $body;
if ($plan9 && $ret[2] eq "e1") {
- $text .= "\terr = nil\n";
$text .= "\tif int(r0) == -1 {\n";
- $text .= "\t\terr = NewError(e1)\n";
+ $text .= "\t\terr = e1\n";
+ $text .= "\t}\n";
+ } elsif ($do_errno) {
+ $text .= "\tif e1 != 0 {\n";
+ $text .= "\t\terr = e1\n";
$text .= "\t}\n";
}
-
$text .= "\treturn\n";
$text .= "}\n\n";
}
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_windows.pl
index 4b245976e..1fb51125b 100755
--- a/src/pkg/syscall/mksyscall_windows.pl
+++ b/src/pkg/syscall/mksyscall_windows.pl
@@ -11,16 +11,16 @@
# This includes return parameters.
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
-# * If the return parameter is an error number, it must be named errno.
+# * If the return parameter is an error number, it must be named err.
# * If go func name needs to be different from it's winapi dll name,
# the winapi name could be specified at the end, after "=" sign, like
-# //sys LoadLibrary(libname string) (handle uint32, errno int) = LoadLibraryA
-# * Each function, that returns errno, needs to supply a condition,
+# //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+# * Each function that returns err needs to supply a condition,
# that return value of winapi will be tested against to
-# detect failure. This would set errno to windows "last-error",
-# otherwise it will be 0. The value can be provided
+# detect failure. This would set err to windows "last-error",
+# otherwise it will be nil. The value can be provided
# at end of //sys declaration, like
-# //sys LoadLibrary(libname string) (handle uint32, errno int) [failretval==-1] = LoadLibraryA
+# //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
# and is [failretval==0] by default.
use strict;
@@ -64,6 +64,7 @@ sub parseparam($) {
return ($1, $2);
}
+my $package = "";
my $text = "";
my $vars = "";
my $mods = "";
@@ -73,10 +74,14 @@ while(<>) {
s/\s+/ /g;
s/^\s+//;
s/\s+$//;
+ $package = $1 if !$package && /^package (\S+)$/;
next if !/^\/\/sys /;
+ my $syscalldot = "";
+ $syscalldot = "syscall." if $package ne "syscall";
+
# Line must be of the form
- # func Open(path string, mode int, perm int) (fd int, errno int)
+ # func Open(path string, mode int, perm int) (fd int, err error)
# Split into name, in params, out params.
if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
@@ -96,7 +101,7 @@ while(<>) {
my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
- $mods .= "\t$modvname = NewLazyDLL(\"$modname.dll\")\n";
+ $mods .= "\t$modvname = ${syscalldot}NewLazyDLL(\"$modname.dll\")\n";
}
# System call name.
@@ -165,26 +170,31 @@ while(<>) {
my $nargs = @args;
# Determine which form to use; pad args with zeros.
- my $asm = "Syscall";
+ my $asm = "${syscalldot}Syscall";
if(@args <= 3) {
while(@args < 3) {
push @args, "0";
}
} elsif(@args <= 6) {
- $asm = "Syscall6";
+ $asm = "${syscalldot}Syscall6";
while(@args < 6) {
push @args, "0";
}
} elsif(@args <= 9) {
- $asm = "Syscall9";
+ $asm = "${syscalldot}Syscall9";
while(@args < 9) {
push @args, "0";
}
} elsif(@args <= 12) {
- $asm = "Syscall12";
+ $asm = "${syscalldot}Syscall12";
while(@args < 12) {
push @args, "0";
}
+ } elsif(@args <= 15) {
+ $asm = "${syscalldot}Syscall15";
+ while(@args < 15) {
+ push @args, "0";
+ }
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
@@ -202,7 +212,7 @@ while(<>) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
my $reg = "";
- if($name eq "errno") {
+ if($name eq "err") {
$reg = "e1";
$ret[2] = $reg;
} else {
@@ -233,7 +243,7 @@ while(<>) {
if($i == 0) {
if($type eq "bool") {
$failexpr = "!$name";
- } elsif($name eq "errno") {
+ } elsif($name eq "err") {
$ret[$i] = "r1";
$failexpr = "int(r1) $failcond";
} else {
@@ -241,16 +251,19 @@ while(<>) {
}
}
$failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
- if($name eq "errno") {
- # Set errno to "last error" only if returned value indicate failure
+ if($name eq "err") {
+ # Set err to "last error" only if returned value indicate failure
$body .= "\tif $failexpr {\n";
$body .= "\t\tif $reg != 0 {\n";
$body .= "\t\t\t$name = $type($reg)\n";
$body .= "\t\t} else {\n";
- $body .= "\t\t\t$name = EINVAL\n";
+ $body .= "\t\t\t$name = ${syscalldot}EINVAL\n";
$body .= "\t\t}\n";
- $body .= "\t} else {\n";
- $body .= "\t\t$name = 0\n";
+ $body .= "\t}\n";
+ } elsif($rettype eq "error") {
+ # Set $reg to "error" only if returned value indicate failure
+ $body .= "\tif $reg != 0 {\n";
+ $body .= "\t\t$name = ${syscalldot}Errno($reg)\n";
$body .= "\t}\n";
} else {
$body .= "\t$name = $rettype($reg)\n";
@@ -279,9 +292,14 @@ print <<EOF;
// $cmdline
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-package syscall
+package $package
import "unsafe"
+EOF
+
+print "import \"syscall\"\n" if $package ne "syscall";
+
+print <<EOF;
var (
$mods
diff --git a/src/pkg/syscall/mksysctl_openbsd.pl b/src/pkg/syscall/mksysctl_openbsd.pl
new file mode 100755
index 000000000..8e5ccaac2
--- /dev/null
+++ b/src/pkg/syscall/mksysctl_openbsd.pl
@@ -0,0 +1,257 @@
+#!/usr/bin/perl
+
+# 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 the header files for OpenBSD and generate a Go usable sysctl MIB.
+#
+# Build a MIB with each entry being an array containing the level, type and
+# a hash that will contain additional entries if the current entry is a node.
+# We then walk this MIB and create a flattened sysctl name to OID hash.
+#
+
+use strict;
+
+my $debug = 0;
+my %ctls = ();
+
+my @headers = qw (
+ sys/sysctl.h
+ sys/socket.h
+ sys/tty.h
+ sys/malloc.h
+ sys/mount.h
+ sys/namei.h
+ sys/sem.h
+ sys/shm.h
+ sys/vmmeter.h
+ uvm/uvm_param.h
+ uvm/uvm_swap_encrypt.h
+ ddb/db_var.h
+ net/if.h
+ net/if_pfsync.h
+ net/pipex.h
+ netinet/in.h
+ netinet/icmp_var.h
+ netinet/igmp_var.h
+ netinet/ip_ah.h
+ netinet/ip_carp.h
+ netinet/ip_divert.h
+ netinet/ip_esp.h
+ netinet/ip_ether.h
+ netinet/ip_gre.h
+ netinet/ip_ipcomp.h
+ netinet/ip_ipip.h
+ netinet/pim_var.h
+ netinet/tcp_var.h
+ netinet/udp_var.h
+ netinet6/in6.h
+ netinet6/ip6_divert.h
+ netinet6/pim6_var.h
+ netinet/icmp6.h
+ netmpls/mpls.h
+);
+
+my @ctls = qw (
+ kern
+ vm
+ fs
+ net
+ #debug # Special handling required
+ hw
+ #machdep # Arch specific
+ user
+ ddb
+ #vfs # Special handling required
+ fs.posix
+ kern.forkstat
+ kern.intrcnt
+ kern.malloc
+ kern.nchstats
+ kern.seminfo
+ kern.shminfo
+ kern.timecounter
+ kern.tty
+ kern.watchdog
+ net.bpf
+ net.ifq
+ net.inet
+ net.inet.ah
+ net.inet.carp
+ net.inet.divert
+ net.inet.esp
+ net.inet.etherip
+ net.inet.gre
+ net.inet.icmp
+ net.inet.igmp
+ net.inet.ip
+ net.inet.ip.ifq
+ net.inet.ipcomp
+ net.inet.ipip
+ net.inet.mobileip
+ net.inet.pfsync
+ net.inet.pim
+ net.inet.tcp
+ net.inet.udp
+ net.inet6
+ net.inet6.divert
+ net.inet6.ip6
+ net.inet6.icmp6
+ net.inet6.pim6
+ net.inet6.tcp6
+ net.inet6.udp6
+ net.mpls
+ net.mpls.ifq
+ net.key
+ net.pflow
+ net.pfsync
+ net.pipex
+ net.rt
+ vm.swapencrypt
+ #vfsgenctl # Special handling required
+);
+
+# Node name "fixups"
+my %ctl_map = (
+ "ipproto" => "net.inet",
+ "net.inet.ipproto" => "net.inet",
+ "net.inet6.ipv6proto" => "net.inet6",
+ "net.inet6.ipv6" => "net.inet6.ip6",
+ "net.inet.icmpv6" => "net.inet6.icmp6",
+ "net.inet6.divert6" => "net.inet6.divert",
+ "net.inet6.tcp6" => "net.inet.tcp",
+ "net.inet6.udp6" => "net.inet.udp",
+ "mpls" => "net.mpls",
+ "swpenc" => "vm.swapencrypt"
+);
+
+# Node mappings
+my %node_map = (
+ "net.inet.ip.ifq" => "net.ifq",
+ "net.inet.pfsync" => "net.pfsync",
+ "net.mpls.ifq" => "net.ifq"
+);
+
+my $ctlname;
+my %mib = ();
+my %sysctl = ();
+my $node;
+
+sub debug() {
+ print STDERR "$_[0]\n" if $debug;
+}
+
+# Walk the MIB and build a sysctl name to OID mapping.
+sub build_sysctl() {
+ my ($node, $name, $oid) = @_;
+ my %node = %{$node};
+ my @oid = @{$oid};
+
+ foreach my $key (sort keys %node) {
+ my @node = @{$node{$key}};
+ my $nodename = $name.($name ne '' ? '.' : '').$key;
+ my @nodeoid = (@oid, $node[0]);
+ if ($node[1] eq 'CTLTYPE_NODE') {
+ if (exists $node_map{$nodename}) {
+ $node = \%mib;
+ $ctlname = $node_map{$nodename};
+ foreach my $part (split /\./, $ctlname) {
+ $node = \%{@{$$node{$part}}[2]};
+ }
+ } else {
+ $node = $node[2];
+ }
+ &build_sysctl($node, $nodename, \@nodeoid);
+ } elsif ($node[1] ne '') {
+ $sysctl{$nodename} = \@nodeoid;
+ }
+ }
+}
+
+foreach my $ctl (@ctls) {
+ $ctls{$ctl} = $ctl;
+}
+
+# Build MIB
+foreach my $header (@headers) {
+ &debug("Processing $header...");
+ open HEADER, "/usr/include/$header" ||
+ print STDERR "Failed to open $header\n";
+ while (<HEADER>) {
+ if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ ||
+ $_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ ||
+ $_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) {
+ if ($1 eq 'CTL_NAMES') {
+ # Top level.
+ $node = \%mib;
+ } else {
+ # Node.
+ my $nodename = lc($2);
+ if ($header =~ /^netinet\//) {
+ $ctlname = "net.inet.$nodename";
+ } elsif ($header =~ /^netinet6\//) {
+ $ctlname = "net.inet6.$nodename";
+ } elsif ($header =~ /^net\//) {
+ $ctlname = "net.$nodename";
+ } else {
+ $ctlname = "$nodename";
+ $ctlname =~ s/^(fs|net|kern)_/$1\./;
+ }
+ if (exists $ctl_map{$ctlname}) {
+ $ctlname = $ctl_map{$ctlname};
+ }
+ if (not exists $ctls{$ctlname}) {
+ &debug("Ignoring $ctlname...");
+ next;
+ }
+
+ # Walk down from the top of the MIB.
+ $node = \%mib;
+ foreach my $part (split /\./, $ctlname) {
+ if (not exists $$node{$part}) {
+ &debug("Missing node $part");
+ $$node{$part} = [ 0, '', {} ];
+ }
+ $node = \%{@{$$node{$part}}[2]};
+ }
+ }
+
+ # Populate current node with entries.
+ my $i = -1;
+ while (defined($_) && $_ !~ /^}/) {
+ $_ = <HEADER>;
+ $i++ if $_ =~ /{.*}/;
+ next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/;
+ $$node{$1} = [ $i, $2, {} ];
+ }
+ }
+ }
+ close HEADER;
+}
+
+&build_sysctl(\%mib, "", []);
+
+print <<EOF;
+// mksysctl_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall;
+
+type mibentry struct {
+ ctlname string
+ ctloid []_C_int
+}
+
+var sysctlMib = []mibentry {
+EOF
+
+foreach my $name (sort keys %sysctl) {
+ my @oid = @{$sysctl{$name}};
+ print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n";
+}
+
+print <<EOF;
+}
+EOF
diff --git a/src/pkg/syscall/mksysnum_linux.pl b/src/pkg/syscall/mksysnum_linux.pl
index ecf364188..d11666a1d 100755
--- a/src/pkg/syscall/mksysnum_linux.pl
+++ b/src/pkg/syscall/mksysnum_linux.pl
@@ -28,7 +28,7 @@ while(<>){
$prev = $2;
fmt($1, $2);
}
- elsif(/^#define __NR_(\w+)\s+\(\w+\+([0-9]+)\)/){
+ elsif(/^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)/){
fmt($1, $prev+$2)
}
}
diff --git a/src/pkg/syscall/mksysnum_netbsd.pl b/src/pkg/syscall/mksysnum_netbsd.pl
new file mode 100755
index 000000000..a300810ba
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_netbsd.pl
@@ -0,0 +1,51 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go 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 system call table for OpenBSD from master list
+# (for example, /usr/src/sys/kern/syscalls.master).
+
+use strict;
+
+my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+EOF
+
+my $line = '';
+while(<>){
+ if($line =~ /^(.*)\\$/) {
+ # Handle continuation
+ $line = $1;
+ $_ =~ s/^\s+//;
+ $line .= $_;
+ } else {
+ # New line
+ $line = $_;
+ }
+ next if $line =~ /\\$/;
+ if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) {
+ my $num = $1;
+ my $proto = $6;
+ my $compat = $8;
+ my $name = "$7_$9";
+
+ $name = "$7_$11" if $11 ne '';
+ $name =~ y/a-z/A-Z/;
+
+ if($compat eq '' || $compat eq '30' || $compat eq '50') {
+ print " $name = $num; // $proto\n";
+ }
+ }
+}
+
+print <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/mksysnum_openbsd.pl b/src/pkg/syscall/mksysnum_openbsd.pl
new file mode 100755
index 000000000..e041888ea
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_openbsd.pl
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go 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 system call table for OpenBSD from master list
+# (for example, /usr/src/sys/kern/syscalls.master).
+
+use strict;
+
+my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+EOF
+
+while(<>){
+ if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){
+ my $num = $1;
+ my $proto = $3;
+ my $name = $4;
+ $name =~ y/a-z/A-Z/;
+
+ # There are multiple entries for enosys and nosys, so comment them out.
+ if($name =~ /^SYS_E?NOSYS$/){
+ $name = "// $name";
+ }
+ if($name eq 'SYS_SYS_EXIT'){
+ $name = 'SYS_EXIT';
+ }
+
+ print " $name = $num; // $proto\n";
+ }
+}
+
+print <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/netlink_linux.go b/src/pkg/syscall/netlink_linux.go
index 681027ab9..dc0f68470 100644
--- a/src/pkg/syscall/netlink_linux.go
+++ b/src/pkg/syscall/netlink_linux.go
@@ -63,31 +63,28 @@ func newNetlinkRouteRequest(proto, seq, family int) []byte {
// 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) {
+func NetlinkRIB(proto, family int) ([]byte, error) {
var (
- s int
- e int
lsanl SockaddrNetlink
- seq int
tab []byte
)
- s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
- if e != 0 {
+ s, e := Socket(AF_NETLINK, SOCK_RAW, 0)
+ if e != nil {
return nil, e
}
defer Close(s)
lsanl.Family = AF_NETLINK
e = Bind(s, &lsanl)
- if e != 0 {
+ if e != nil {
return nil, e
}
- seq++
+ seq := 1
wb := newNetlinkRouteRequest(proto, seq, family)
e = Sendto(s, wb, 0, &lsanl)
- if e != 0 {
+ if e != nil {
return nil, e
}
@@ -100,7 +97,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
rb = make([]byte, Getpagesize())
nr, _, e = Recvfrom(s, rb, 0)
- if e != 0 {
+ if e != nil {
return nil, e
}
if nr < NLMSG_HDRLEN {
@@ -111,7 +108,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
msgs, _ := ParseNetlinkMessage(rb)
for _, m := range msgs {
- if lsa, e = Getsockname(s); e != 0 {
+ if lsa, e = Getsockname(s); e != nil {
return nil, e
}
switch v := lsa.(type) {
@@ -132,7 +129,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
}
done:
- return tab, 0
+ return tab, nil
}
// NetlinkMessage represents the netlink message.
@@ -143,18 +140,18 @@ type NetlinkMessage struct {
// ParseNetlinkMessage parses buf as netlink messages and returns
// the slice containing the NetlinkMessage structs.
-func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
+func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, error) {
var (
h *NlMsghdr
dbuf []byte
dlen int
- e int
+ e error
msgs []NetlinkMessage
)
for len(buf) >= NLMSG_HDRLEN {
h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
- if e != 0 {
+ if e != nil {
break
}
m := NetlinkMessage{}
@@ -167,12 +164,12 @@ func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
return msgs, e
}
-func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
+func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, error) {
h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
if h.Len < NLMSG_HDRLEN || int(h.Len) > len(buf) {
return nil, nil, 0, EINVAL
}
- return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
+ return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}
// NetlinkRouteAttr represents the netlink route attribute.
@@ -184,28 +181,30 @@ type NetlinkRouteAttr struct {
// ParseNetlinkRouteAttr parses msg's payload as netlink route
// attributes and returns the slice containing the NetlinkRouteAttr
// structs.
-func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
+func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, error) {
var (
buf []byte
a *RtAttr
alen int
vbuf []byte
- e int
+ e error
attrs []NetlinkRouteAttr
)
switch msg.Header.Type {
- case RTM_NEWLINK:
+ case RTM_NEWLINK, RTM_DELLINK:
buf = msg.Data[SizeofIfInfomsg:]
- case RTM_NEWADDR:
+ case RTM_NEWADDR, RTM_DELADDR:
buf = msg.Data[SizeofIfAddrmsg:]
+ case RTM_NEWROUTE, RTM_DELROUTE:
+ buf = msg.Data[SizeofRtMsg:]
default:
return nil, EINVAL
}
for len(buf) >= SizeofRtAttr {
a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
- if e != 0 {
+ if e != nil {
break
}
ra := NetlinkRouteAttr{}
@@ -215,13 +214,13 @@ func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
buf = buf[alen:]
}
- return attrs, 0
+ return attrs, nil
}
-func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
+func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, error) {
h := (*RtAttr)(unsafe.Pointer(&buf[0]))
if h.Len < SizeofRtAttr || int(h.Len) > len(buf) {
return nil, nil, 0, EINVAL
}
- return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
+ return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), nil
}
diff --git a/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
index 93e345d71..e17d976b1 100644
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.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.
+// +build darwin freebsd netbsd openbsd
+
// Routing sockets and messages
package syscall
@@ -27,29 +29,24 @@ func rsaAlignOf(salen int) int {
// RouteRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
-func RouteRIB(facility, param int) ([]byte, int) {
- var (
- tab []byte
- e int
- )
-
+func RouteRIB(facility, param int) ([]byte, error) {
mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
// Find size.
n := uintptr(0)
- if e = sysctl(mib, nil, &n, nil, 0); e != 0 {
- return nil, e
+ if err := sysctl(mib, nil, &n, nil, 0); err != nil {
+ return nil, err
}
if n == 0 {
- return nil, 0
+ return nil, nil
}
- tab = make([]byte, n)
- if e = sysctl(mib, &tab[0], &n, nil, 0); e != 0 {
- return nil, e
+ tab := make([]byte, n)
+ if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil {
+ return nil, err
}
- return tab[:n], 0
+ return tab[:n], nil
}
// RoutingMessage represents a routing message.
@@ -72,9 +69,52 @@ type RouteMessage struct {
Data []byte
}
-func (m *RouteMessage) sockaddr() (sas []Sockaddr) {
- // TODO: implement this in the near future
- return nil
+const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
+
+func (m *RouteMessage) sockaddr() []Sockaddr {
+ var (
+ af int
+ sas [4]Sockaddr
+ )
+
+ buf := m.Data[:]
+ for i := uint(0); i < RTAX_MAX; i++ {
+ if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
+ continue
+ }
+ rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
+ switch i {
+ case RTAX_DST, RTAX_GATEWAY:
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
+ return nil
+ }
+ if i == RTAX_DST {
+ af = int(rsa.Family)
+ }
+ sas[i] = sa
+ case RTAX_NETMASK, RTAX_GENMASK:
+ switch af {
+ case AF_INET:
+ rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&buf[0]))
+ sa := new(SockaddrInet4)
+ for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
+ sa.Addr[j] = rsa4.Addr[j]
+ }
+ sas[i] = sa
+ case AF_INET6:
+ rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&buf[0]))
+ sa := new(SockaddrInet6)
+ for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
+ sa.Addr[j] = rsa6.Addr[j]
+ }
+ sas[i] = sa
+ }
+ }
+ buf = buf[rsaAlignOf(int(rsa.Len)):]
+ }
+
+ return sas[:]
}
// InterfaceMessage represents a routing message containing
@@ -88,8 +128,8 @@ func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
if m.Header.Addrs&RTA_IFP == 0 {
return nil
}
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
- if e != 0 {
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+ if err != nil {
return nil
}
return append(sas, sa)
@@ -117,12 +157,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
switch i {
case RTAX_IFA:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
+ return nil
+ }
+ sas = append(sas, sa)
+ case RTAX_NETMASK:
+ if rsa.Family == AF_UNSPEC {
+ rsa.Family = AF_INET // an old fasion, AF_UNSPEC means AF_INET
+ }
+ sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ if err != nil {
return nil
}
sas = append(sas, sa)
- case RTAX_NETMASK, RTAX_BRD:
+ case RTAX_BRD:
// nothing to do
}
buf = buf[rsaAlignOf(int(rsa.Len)):]
@@ -133,7 +182,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses buf as routing messages and returns
// the slice containing the RoutingMessage interfaces.
-func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
+func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, err error) {
for len(buf) >= anyMessageLen {
any := (*anyMessage)(unsafe.Pointer(&buf[0]))
if any.Version != RTM_VERSION {
@@ -142,11 +191,11 @@ func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
msgs = append(msgs, any.toRoutingMessage(buf))
buf = buf[any.Msglen:]
}
- return msgs, 0
+ return msgs, nil
}
// ParseRoutingMessage parses msg's payload as raw sockaddrs and
// returns the slice containing the Sockaddr interfaces.
-func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, errno int) {
- return append(sas, msg.sockaddr()...), 0
+func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
+ return append(sas, msg.sockaddr()...), nil
}
diff --git a/src/pkg/syscall/route_darwin.go b/src/pkg/syscall/route_darwin.go
index 9d3a701da..410e70a13 100644
--- a/src/pkg/syscall/route_darwin.go
+++ b/src/pkg/syscall/route_darwin.go
@@ -63,7 +63,7 @@ func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
switch i {
case RTAX_IFA:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
sas = append(sas, sa)
diff --git a/src/pkg/syscall/route_freebsd.go b/src/pkg/syscall/route_freebsd.go
index 0d61d08b0..094e17044 100644
--- a/src/pkg/syscall/route_freebsd.go
+++ b/src/pkg/syscall/route_freebsd.go
@@ -63,7 +63,7 @@ func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
switch i {
case RTAX_IFA:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
sas = append(sas, sa)
diff --git a/src/pkg/syscall/route_netbsd.go b/src/pkg/syscall/route_netbsd.go
new file mode 100644
index 000000000..d6d9031bc
--- /dev/null
+++ b/src/pkg/syscall/route_netbsd.go
@@ -0,0 +1,35 @@
+// 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.
+
+// Routing sockets and messages for NetBSD
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+ switch any.Type {
+ case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ rtm := &RouteMessage{}
+ rtm.Header = p.Header
+ rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+ return rtm
+ case RTM_IFINFO:
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ ifm := &InterfaceMessage{}
+ ifm.Header = p.Header
+ ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+ return ifm
+ case RTM_NEWADDR, RTM_DELADDR:
+ p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+ ifam := &InterfaceAddrMessage{}
+ ifam.Header = p.Header
+ ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+ return ifam
+ }
+ return nil
+}
diff --git a/src/pkg/syscall/route_openbsd.go b/src/pkg/syscall/route_openbsd.go
new file mode 100644
index 000000000..30e1cac46
--- /dev/null
+++ b/src/pkg/syscall/route_openbsd.go
@@ -0,0 +1,35 @@
+// 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.
+
+// Routing sockets and messages for OpenBSD
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+ switch any.Type {
+ case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ rtm := &RouteMessage{}
+ rtm.Header = p.Header
+ rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+ return rtm
+ case RTM_IFINFO:
+ p := (*InterfaceMessage)(unsafe.Pointer(any))
+ ifm := &InterfaceMessage{}
+ ifm.Header = p.Header
+ ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+ return ifm
+ case RTM_NEWADDR, RTM_DELADDR:
+ p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+ ifam := &InterfaceAddrMessage{}
+ ifam.Header = p.Header
+ ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+ return ifam
+ }
+ return nil
+}
diff --git a/src/pkg/syscall/security_windows.go b/src/pkg/syscall/security_windows.go
new file mode 100644
index 000000000..bd40fe586
--- /dev/null
+++ b/src/pkg/syscall/security_windows.go
@@ -0,0 +1,359 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+const (
+ STANDARD_RIGHTS_REQUIRED = 0xf0000
+ STANDARD_RIGHTS_READ = 0x20000
+ STANDARD_RIGHTS_WRITE = 0x20000
+ STANDARD_RIGHTS_EXECUTE = 0x20000
+ STANDARD_RIGHTS_ALL = 0x1F0000
+)
+
+const (
+ NameUnknown = 0
+ NameFullyQualifiedDN = 1
+ NameSamCompatible = 2
+ NameDisplay = 3
+ NameUniqueId = 6
+ NameCanonical = 7
+ NameUserPrincipal = 8
+ NameCanonicalEx = 9
+ NameServicePrincipal = 10
+ NameDnsDomain = 12
+)
+
+// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
+// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
+//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
+//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
+
+// TranslateAccountName converts a directory service
+// object name from one format to another.
+func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
+ u := StringToUTF16Ptr(username)
+ b := make([]uint16, 50)
+ n := uint32(len(b))
+ e := TranslateName(u, from, to, &b[0], &n)
+ if e != nil {
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", e
+ }
+ // make receive buffers of requested size and try again
+ b = make([]uint16, n)
+ e = TranslateName(u, from, to, &b[0], &n)
+ if e != nil {
+ return "", e
+ }
+ }
+ return UTF16ToString(b), nil
+}
+
+type UserInfo10 struct {
+ Name *uint16
+ Comment *uint16
+ UsrComment *uint16
+ FullName *uint16
+}
+
+//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
+//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
+
+const (
+ // do not reorder
+ SidTypeUser = 1 << iota
+ SidTypeGroup
+ SidTypeDomain
+ SidTypeAlias
+ SidTypeWellKnownGroup
+ SidTypeDeletedAccount
+ SidTypeInvalid
+ SidTypeUnknown
+ SidTypeComputer
+ SidTypeLabel
+)
+
+//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
+//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
+//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
+//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
+//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
+
+// The security identifier (SID) structure is a variable-length
+// structure used to uniquely identify users or groups.
+type SID struct{}
+
+// StringToSid converts a string-format security identifier
+// sid into a valid, functional sid.
+func StringToSid(s string) (*SID, error) {
+ var sid *SID
+ e := ConvertStringSidToSid(StringToUTF16Ptr(s), &sid)
+ if e != nil {
+ return nil, e
+ }
+ defer LocalFree((Handle)(unsafe.Pointer(sid)))
+ return sid.Copy()
+}
+
+// LookupSID retrieves a security identifier sid for the account
+// and the name of the domain on which the account was found.
+// System specify target computer to search.
+func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
+ if len(account) == 0 {
+ return nil, "", 0, EINVAL
+ }
+ acc := StringToUTF16Ptr(account)
+ var sys *uint16
+ if len(system) > 0 {
+ sys = StringToUTF16Ptr(system)
+ }
+ db := make([]uint16, 50)
+ dn := uint32(len(db))
+ b := make([]byte, 50)
+ n := uint32(len(b))
+ sid = (*SID)(unsafe.Pointer(&b[0]))
+ e := LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+ if e != nil {
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return nil, "", 0, e
+ }
+ // make receive buffers of requested size and try again
+ b = make([]byte, n)
+ sid = (*SID)(unsafe.Pointer(&b[0]))
+ db = make([]uint16, dn)
+ e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+ if e != nil {
+ return nil, "", 0, e
+ }
+ }
+ return sid, UTF16ToString(db), accType, nil
+}
+
+// String converts sid to a string format
+// suitable for display, storage, or transmission.
+func (sid *SID) String() (string, error) {
+ var s *uint16
+ e := ConvertSidToStringSid(sid, &s)
+ if e != nil {
+ return "", e
+ }
+ defer LocalFree((Handle)(unsafe.Pointer(s)))
+ return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
+}
+
+// Len returns the length, in bytes, of a valid security identifier sid.
+func (sid *SID) Len() int {
+ return int(GetLengthSid(sid))
+}
+
+// Copy creates a duplicate of security identifier sid.
+func (sid *SID) Copy() (*SID, error) {
+ b := make([]byte, sid.Len())
+ sid2 := (*SID)(unsafe.Pointer(&b[0]))
+ e := CopySid(uint32(len(b)), sid2, sid)
+ if e != nil {
+ return nil, e
+ }
+ return sid2, nil
+}
+
+// LookupAccount retrieves the name of the account for this sid
+// and the name of the first domain on which this sid is found.
+// System specify target computer to search for.
+func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
+ var sys *uint16
+ if len(system) > 0 {
+ sys = StringToUTF16Ptr(system)
+ }
+ b := make([]uint16, 50)
+ n := uint32(len(b))
+ db := make([]uint16, 50)
+ dn := uint32(len(db))
+ e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+ if e != nil {
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", "", 0, e
+ }
+ // make receive buffers of requested size and try again
+ b = make([]uint16, n)
+ db = make([]uint16, dn)
+ e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
+ if e != nil {
+ return "", "", 0, e
+ }
+ }
+ return UTF16ToString(b), UTF16ToString(db), accType, nil
+}
+
+const (
+ // do not reorder
+ TOKEN_ASSIGN_PRIMARY = 1 << iota
+ TOKEN_DUPLICATE
+ TOKEN_IMPERSONATE
+ TOKEN_QUERY
+ TOKEN_QUERY_SOURCE
+ TOKEN_ADJUST_PRIVILEGES
+ TOKEN_ADJUST_GROUPS
+ TOKEN_ADJUST_DEFAULT
+
+ TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT
+ TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
+ TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT
+ TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
+)
+
+const (
+ // do not reorder
+ TokenUser = 1 + iota
+ TokenGroups
+ TokenPrivileges
+ TokenOwner
+ TokenPrimaryGroup
+ TokenDefaultDacl
+ TokenSource
+ TokenType
+ TokenImpersonationLevel
+ TokenStatistics
+ TokenRestrictedSids
+ TokenSessionId
+ TokenGroupsAndPrivileges
+ TokenSessionReference
+ TokenSandBoxInert
+ TokenAuditPolicy
+ TokenOrigin
+ TokenElevationType
+ TokenLinkedToken
+ TokenElevation
+ TokenHasRestrictions
+ TokenAccessInformation
+ TokenVirtualizationAllowed
+ TokenVirtualizationEnabled
+ TokenIntegrityLevel
+ TokenUIAccess
+ TokenMandatoryPolicy
+ TokenLogonSid
+ MaxTokenInfoClass
+)
+
+type SIDAndAttributes struct {
+ Sid *SID
+ Attributes uint32
+}
+
+type Tokenuser struct {
+ User SIDAndAttributes
+}
+
+type Tokenprimarygroup struct {
+ PrimaryGroup *SID
+}
+
+//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
+//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
+//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
+
+// An access token contains the security information for a logon session.
+// The system creates an access token when a user logs on, and every
+// process executed on behalf of the user has a copy of the token.
+// The token identifies the user, the user's groups, and the user's
+// privileges. The system uses the token to control access to securable
+// objects and to control the ability of the user to perform various
+// system-related operations on the local computer.
+type Token Handle
+
+// OpenCurrentProcessToken opens the access token
+// associated with current process.
+func OpenCurrentProcessToken() (Token, error) {
+ p, e := GetCurrentProcess()
+ if e != nil {
+ return 0, e
+ }
+ var t Token
+ e = OpenProcessToken(p, TOKEN_QUERY, &t)
+ if e != nil {
+ return 0, e
+ }
+ return t, nil
+}
+
+// Close releases access to access token.
+func (t Token) Close() error {
+ return CloseHandle(Handle(t))
+}
+
+// getInfo retrieves a specified type of information about an access token.
+func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
+ b := make([]byte, initSize)
+ var n uint32
+ e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+ if e != nil {
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return nil, e
+ }
+ // make receive buffers of requested size and try again
+ b = make([]byte, n)
+ e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+ if e != nil {
+ return nil, e
+ }
+ }
+ return unsafe.Pointer(&b[0]), nil
+}
+
+// GetTokenUser retrieves access token t user account information.
+func (t Token) GetTokenUser() (*Tokenuser, error) {
+ i, e := t.getInfo(TokenUser, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*Tokenuser)(i), nil
+}
+
+// GetTokenPrimaryGroup retrieves access token t primary group information.
+// A pointer to a SID structure representing a group that will become
+// the primary group of any objects created by a process using this access token.
+func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
+ i, e := t.getInfo(TokenPrimaryGroup, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*Tokenprimarygroup)(i), nil
+}
+
+// GetUserProfileDirectory retrieves path to the
+// root directory of the access token t user's profile.
+func (t Token) GetUserProfileDirectory() (string, error) {
+ b := make([]uint16, 100)
+ n := uint32(len(b))
+ e := GetUserProfileDirectory(t, &b[0], &n)
+ if e != nil {
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", e
+ }
+ // make receive buffers of requested size and try again
+ b = make([]uint16, n)
+ e = GetUserProfileDirectory(t, &b[0], &n)
+ if e != nil {
+ return "", e
+ }
+ }
+ return UTF16ToString(b), nil
+}
diff --git a/src/pkg/syscall/sockcmsg_linux.go b/src/pkg/syscall/sockcmsg_linux.go
index b025ca521..0b4caa1d0 100644
--- a/src/pkg/syscall/sockcmsg_linux.go
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -26,7 +26,7 @@ func UnixCredentials(ucred *Ucred) []byte {
// ParseUnixCredentials decodes a socket control message that contains
// credentials in a Ucred structure. To receive such a message, the
// SO_PASSCRED option must be enabled on the socket.
-func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
+func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
if msg.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
@@ -34,5 +34,5 @@ func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
return nil, EINVAL
}
ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
- return &ucred, 0
+ return &ucred, nil
}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index b437560e7..d279decb6 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
// Socket control messages
package syscall
@@ -45,17 +47,17 @@ type SocketControlMessage struct {
Data []byte
}
-func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
+func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
var (
h *Cmsghdr
dbuf []byte
- e int
+ e error
cmsgs []SocketControlMessage
)
for len(buf) >= CmsgLen(0) {
h, dbuf, e = socketControlMessageHeaderAndData(buf)
- if e != 0 {
+ if e != nil {
break
}
m := SocketControlMessage{}
@@ -68,12 +70,12 @@ func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
return cmsgs, e
}
-func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
+func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
return nil, nil, EINVAL
}
- return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
+ return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
}
// UnixRights encodes a set of open file descriptors into a socket
@@ -97,7 +99,7 @@ func UnixRights(fds ...int) []byte {
// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
-func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
+func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
if msg.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
@@ -109,5 +111,5 @@ func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
j++
}
- return fds, 0
+ return fds, nil
}
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
index 9f777f59e..335559fc3 100644
--- a/src/pkg/syscall/syscall.go
+++ b/src/pkg/syscall/syscall.go
@@ -9,8 +9,9 @@
// packages rather than this one if you can.
// For details of the functions and data types in this package consult
// the manuals for the appropriate operating system.
-// These calls return errno == 0 to indicate success; otherwise
-// errno is an operating system error number describing the failure.
+// These calls return err == nil to indicate success; otherwise
+// err is an operating system error describing the failure.
+// On most systems, that error has type syscall.Errno.
package syscall
// StringByteSlice returns a NUL-terminated slice of bytes
@@ -26,5 +27,21 @@ func StringByteSlice(s string) []byte {
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
// Single-word zero for use when we need a valid pointer to 0 bytes.
-// See mksyscall.sh.
+// See mksyscall.pl.
var _zero uintptr
+
+func (ts *Timespec) Unix() (sec int64, nsec int64) {
+ return int64(ts.Sec), int64(ts.Nsec)
+}
+
+func (tv *Timeval) Unix() (sec int64, nsec int64) {
+ return int64(tv.Sec), int64(tv.Usec) * 1000
+}
+
+func (ts *Timespec) Nano() int64 {
+ return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}
+
+func (tv *Timeval) Nano() int64 {
+ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index f59e8b109..c1a822aa1 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.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.
+// +build darwin freebsd netbsd openbsd
+
// BSD system call wrappers shared by *BSD based systems
// including OS X (Darwin) and FreeBSD. Like the other
// syscall_*.go files it is compiled as Go code but also
@@ -10,7 +12,10 @@
package syscall
-import "unsafe"
+import (
+ "runtime"
+ "unsafe"
+)
/*
* Pseudo-system calls
@@ -20,22 +25,22 @@ import "unsafe"
// even linking this function into the binary. See ../os/getwd.go.
const ImplementsGetwd = false
-func Getwd() (string, int) { return "", ENOTSUP }
+func Getwd() (string, error) { return "", ENOTSUP }
/*
* Wrapped
*/
-//sysnb getgroups(ngid int, gid *_Gid_t) (n int, errno int)
-//sysnb setgroups(ngid int, gid *_Gid_t) (errno int)
+//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
+//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
-func Getgroups() (gids []int, errno int) {
+func Getgroups() (gids []int, err error) {
n, err := getgroups(0, nil)
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
if n == 0 {
- return nil, 0
+ return nil, nil
}
// Sanity check group count. Max is 16 on BSD.
@@ -45,8 +50,8 @@ func Getgroups() (gids []int, errno int) {
a := make([]_Gid_t, n)
n, err = getgroups(n, &a[0])
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
gids = make([]int, n)
for i, v := range a[0:n] {
@@ -55,7 +60,7 @@ func Getgroups() (gids []int, errno int) {
return
}
-func Setgroups(gids []int) (errno int) {
+func Setgroups(gids []int) (err error) {
if len(gids) == 0 {
return setgroups(0, nil)
}
@@ -67,7 +72,7 @@ func Setgroups(gids []int) (errno int) {
return setgroups(len(a), &a[0])
}
-func ReadDirent(fd int, buf []byte) (n int, errno int) {
+func ReadDirent(fd int, buf []byte) (n int, err error) {
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
// TODO(rsc): Can we use a single global basep for all calls?
return Getdirentries(fd, buf, new(uintptr))
@@ -101,8 +106,8 @@ func (w WaitStatus) ExitStatus() int {
func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
-func (w WaitStatus) Signal() int {
- sig := int(w & mask)
+func (w WaitStatus) Signal() Signal {
+ sig := Signal(w & mask)
if sig == stopped || sig == 0 {
return -1
}
@@ -111,51 +116,46 @@ func (w WaitStatus) Signal() int {
func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
-func (w WaitStatus) Stopped() bool { return w&mask == stopped && w>>shift != SIGSTOP }
+func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
-func (w WaitStatus) Continued() bool { return w&mask == stopped && w>>shift == SIGSTOP }
+func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
-func (w WaitStatus) StopSignal() int {
+func (w WaitStatus) StopSignal() Signal {
if !w.Stopped() {
return -1
}
- return int(w>>shift) & 0xFF
+ return Signal(w>>shift) & 0xFF
}
func (w WaitStatus) TrapCause() int { return -1 }
-//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int)
+//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error)
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
var status _C_int
- wpid, errno = wait4(pid, &status, options, rusage)
+ wpid, err = wait4(pid, &status, options, rusage)
if wstatus != nil {
*wstatus = WaitStatus(status)
}
return
}
-func Sleep(ns int64) (errno int) {
- tv := NsecToTimeval(ns)
- return Select(0, nil, nil, nil, &tv)
-}
-
-//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
-//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sys Shutdown(s int, how int) (errno int)
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys Shutdown(s int, how int) (err error)
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
type Sockaddr interface {
- sockaddr() (ptr uintptr, len _Socklen, errno int) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr uintptr, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -164,7 +164,7 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return 0, 0, EINVAL
}
@@ -176,7 +176,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
}
type SockaddrInet6 struct {
@@ -186,7 +186,7 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return 0, 0, EINVAL
}
@@ -199,7 +199,7 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
}
type SockaddrUnix struct {
@@ -207,7 +207,7 @@ type SockaddrUnix struct {
raw RawSockaddrUnix
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) || n == 0 {
@@ -218,10 +218,10 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < n; i++ {
sa.raw.Path[i] = int8(name[i])
}
- return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), 0
+ return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
}
-func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
if sa.Index == 0 {
return 0, 0, EINVAL
}
@@ -235,10 +235,10 @@ func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.raw.Data); i++ {
sa.raw.Data[i] = sa.Data[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_LINK:
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
@@ -253,7 +253,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Data); i++ {
sa.Data[i] = pp.Data[i]
}
- return sa, 0
+ return sa, nil
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
@@ -271,7 +271,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
}
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
- return sa, 0
+ return sa, nil
case AF_INET:
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
@@ -281,7 +281,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
case AF_INET6:
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
@@ -292,132 +292,168 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
}
return nil, EAFNOSUPPORT
}
-func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- nfd, errno = accept(fd, &rsa, &len)
- if errno != 0 {
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
return
}
- sa, errno = anyToSockaddr(&rsa)
- if errno != 0 {
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
Close(nfd)
nfd = 0
}
return
}
-func Getsockname(fd int) (sa Sockaddr, errno int) {
+func Getsockname(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if errno = getsockname(fd, &rsa, &len); errno != 0 {
+ if err = getsockname(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-func Getpeername(fd int) (sa Sockaddr, errno int) {
+func Getpeername(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if errno = getpeername(fd, &rsa, &len); errno != 0 {
+ if err = getpeername(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-func Bind(fd int, sa Sockaddr) (errno int) {
+func Bind(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return bind(fd, ptr, n)
}
-func Connect(fd int, sa Sockaddr) (errno int) {
+func Connect(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return connect(fd, ptr, n)
}
-func Socket(domain, typ, proto int) (fd, errno int) {
+func Socket(domain, typ, proto int) (fd int, err error) {
if domain == AF_INET6 && SocketDisableIPv6 {
return -1, EAFNOSUPPORT
}
- fd, errno = socket(domain, typ, proto)
+ fd, err = socket(domain, typ, proto)
return
}
-//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (err error)
-func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
- errno = socketpair(domain, typ, proto, &fd)
+func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
+ err = socketpair(domain, typ, proto, &fd)
return
}
-func GetsockoptInt(fd, level, opt int) (value, errno int) {
+func GetsockoptByte(fd, level, opt int) (value byte, err error) {
+ var n byte
+ vallen := _Socklen(1)
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return n, err
+}
+
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := _Socklen(4)
- errno = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
- return int(n), errno
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return int(n), err
+}
+
+func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
+ vallen := _Socklen(4)
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ return value, err
+}
+
+func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
+ var value IPMreq
+ vallen := _Socklen(SizeofIPMreq)
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
}
-func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
+ var value IPv6Mreq
+ vallen := _Socklen(SizeofIPv6Mreq)
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
+}
+
+func SetsockoptByte(fd, level, opt int, value byte) (err error) {
+ var n = byte(value)
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 1)
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
}
-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), 4)
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
}
-func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
}
-func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
-func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
-func SetsockoptString(fd, level, opt int, s string) (errno int) {
+func SetsockoptString(fd, level, opt int, s string) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
}
-//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if n, errno = recvfrom(fd, p, flags, &rsa, &len); errno != 0 {
+ if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
return
}
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
return
}
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
-func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
ptr, n, err := to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return sendto(fd, p, flags, ptr, n)
}
-//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
@@ -439,27 +475,27 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
msg.Iov = &iov
msg.Iovlen = 1
- if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
return
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
}
return
}
-//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
var ptr uintptr
var salen _Socklen
if to != nil {
- var err int
+ var err error
ptr, salen, err = to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
}
@@ -483,24 +519,15 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ if err = sendmsg(fd, &msg, flags); err != nil {
return
}
return
}
-// TODO:
-// FreeBSD has IP_SENDIF. Darwin probably needs BSDLLCTest, see:
-// http://developer.apple.com/mac/library/samplecode/BSDLLCTest/index.html
+//sys kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error)
-// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
- return ENOSYS
-}
-
-//sys kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int)
-
-func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno int) {
+func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) {
var change, event uintptr
if len(changes) > 0 {
change = uintptr(unsafe.Pointer(&changes[0]))
@@ -511,106 +538,90 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno
return kevent(kq, change, len(changes), event, len(events), timeout)
}
-//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) = SYS___SYSCTL
-
-// Translate "kern.hostname" to []_C_int{0,1,2,3}.
-func nametomib(name string) (mib []_C_int, errno int) {
- const siz = unsafe.Sizeof(mib[0])
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
- // NOTE(rsc): It seems strange to set the buffer to have
- // size CTL_MAXNAME+2 but use only CTL_MAXNAME
- // as the size. I don't know why the +2 is here, but the
- // kernel uses +2 for its own implementation of this function.
- // I am scared that if we don't include the +2 here, the kernel
- // will silently write 2 words farther than we specify
- // and we'll get memory corruption.
- var buf [CTL_MAXNAME + 2]_C_int
- n := uintptr(CTL_MAXNAME) * siz
-
- p := (*byte)(unsafe.Pointer(&buf[0]))
- bytes := StringByteSlice(name)
-
- // Magic sysctl: "setting" 0.3 to a string name
- // lets you read back the array of integers form.
- if errno = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); errno != 0 {
- return nil, errno
- }
- return buf[0 : n/siz], 0
-}
-
-func Sysctl(name string) (value string, errno int) {
+func Sysctl(name string) (value string, err error) {
// Translate name to mib number.
- mib, errno := nametomib(name)
- if errno != 0 {
- return "", errno
+ mib, err := nametomib(name)
+ if err != nil {
+ return "", err
}
// Find size.
n := uintptr(0)
- if errno = sysctl(mib, nil, &n, nil, 0); errno != 0 {
- return "", errno
+ if err = sysctl(mib, nil, &n, nil, 0); err != nil {
+ return "", err
}
if n == 0 {
- return "", 0
+ // TODO(jsing): Remove after OpenBSD 5.2 release.
+ // Work around a bug that was fixed after OpenBSD 5.0.
+ // The length for kern.hostname and kern.domainname is always
+ // returned as 0 when a nil value is passed for oldp.
+ if runtime.GOOS == "openbsd" && (name == "kern.hostname" || name == "kern.domainname") {
+ // MAXHOSTNAMELEN
+ n = 256
+ } else {
+ return "", nil
+ }
}
// Read into buffer of that size.
buf := make([]byte, n)
- if errno = sysctl(mib, &buf[0], &n, nil, 0); errno != 0 {
- return "", errno
+ if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil {
+ return "", err
}
// Throw away terminating NUL.
if n > 0 && buf[n-1] == '\x00' {
n--
}
- return string(buf[0:n]), 0
+ return string(buf[0:n]), nil
}
-func SysctlUint32(name string) (value uint32, errno int) {
+func SysctlUint32(name string) (value uint32, err error) {
// Translate name to mib number.
- mib, errno := nametomib(name)
- if errno != 0 {
- return 0, errno
+ mib, err := nametomib(name)
+ if err != nil {
+ return 0, err
}
// Read into buffer of that size.
n := uintptr(4)
buf := make([]byte, 4)
- if errno = sysctl(mib, &buf[0], &n, nil, 0); errno != 0 {
- return 0, errno
+ if err = sysctl(mib, &buf[0], &n, nil, 0); err != nil {
+ return 0, err
}
if n != 4 {
return 0, EIO
}
- return *(*uint32)(unsafe.Pointer(&buf[0])), 0
+ return *(*uint32)(unsafe.Pointer(&buf[0])), nil
}
-//sys utimes(path string, timeval *[2]Timeval) (errno int)
-func Utimes(path string, tv []Timeval) (errno int) {
+//sys utimes(path string, timeval *[2]Timeval) (err error)
+func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-//sys futimes(fd int, timeval *[2]Timeval) (errno int)
-func Futimes(fd int, tv []Timeval) (errno int) {
+//sys futimes(fd int, timeval *[2]Timeval) (err error)
+func Futimes(fd int, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return futimes(fd, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
// TODO: wrap
-// Acct(name nil-string) (errno int)
-// Gethostuuid(uuid *byte, timeout *Timespec) (errno int)
-// Madvise(addr *byte, len int, behav int) (errno int)
-// Mprotect(addr *byte, len int, prot int) (errno int)
-// Msync(addr *byte, len int, flags int) (errno int)
-// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int)
+// Acct(name nil-string) (err error)
+// Gethostuuid(uuid *byte, timeout *Timespec) (err error)
+// Madvise(addr *byte, len int, behav int) (err error)
+// Mprotect(addr *byte, len int, prot int) (err error)
+// Msync(addr *byte, len int, flags int) (err error)
+// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error)
var mapper = &mmapper{
active: make(map[*byte][]byte),
@@ -618,10 +629,10 @@ var mapper = &mmapper{
munmap: munmap,
}
-func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
return mapper.Mmap(fd, offset, length, prot, flags)
}
-func Munmap(b []byte) (errno int) {
+func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index 1bbf1b19a..c712f94d4 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -14,8 +14,6 @@ package syscall
import "unsafe"
-const OS = "darwin"
-
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -28,6 +26,31 @@ type SockaddrDatalink struct {
raw RawSockaddrDatalink
}
+// Translate "kern.hostname" to []_C_int{0,1,2,3}.
+func nametomib(name string) (mib []_C_int, err error) {
+ const siz = unsafe.Sizeof(mib[0])
+
+ // NOTE(rsc): It seems strange to set the buffer to have
+ // size CTL_MAXNAME+2 but use only CTL_MAXNAME
+ // as the size. I don't know why the +2 is here, but the
+ // kernel uses +2 for its own implementation of this function.
+ // I am scared that if we don't include the +2 here, the kernel
+ // will silently write 2 words farther than we specify
+ // and we'll get memory corruption.
+ var buf [CTL_MAXNAME + 2]_C_int
+ n := uintptr(CTL_MAXNAME) * siz
+
+ p := (*byte)(unsafe.Pointer(&buf[0]))
+ bytes := StringByteSlice(name)
+
+ // Magic sysctl: "setting" 0.3 to a string name
+ // lets you read back the array of integers form.
+ if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
+ return nil, err
+ }
+ return buf[0 : n/siz], nil
+}
+
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number
// bytes consumed from buf, the number of entries added
@@ -56,22 +79,22 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
return origlen - len(buf), count, names
}
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
-func PtraceAttach(pid int) (errno int) { return ptrace(PT_ATTACH, pid, 0, 0) }
-func PtraceDetach(pid int) (errno int) { return ptrace(PT_DETACH, pid, 0, 0) }
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
+func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
+func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
-//sysnb pipe() (r int, w int, errno int)
+//sysnb pipe() (r int, w int, err error)
-func Pipe(p []int) (errno int) {
+func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
- p[0], p[1], errno = pipe()
+ p[0], p[1], err = pipe()
return
}
// TODO
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
@@ -79,97 +102,97 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
* Wrapped
*/
-//sys kill(pid int, signum int, posix int) (errno int)
+//sys kill(pid int, signum int, posix int) (err error)
-func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
+func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1) }
/*
* Exposed directly
*/
-//sys Access(path string, mode uint32) (errno int)
-//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int)
-//sys Chdir(path string) (errno int)
-//sys Chflags(path string, flags int) (errno int)
-//sys Chmod(path string, mode uint32) (errno int)
-//sys Chown(path string, uid int, gid int) (errno int)
-//sys Chroot(path string) (errno int)
-//sys Close(fd int) (errno int)
-//sysnb Dup(fd int) (nfd int, errno int)
-//sysnb Dup2(from int, to int) (errno int)
-//sys Exchangedata(path1 string, path2 string, options int) (errno int)
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chflags(path string, flags int) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sysnb Dup(fd int) (nfd int, err error)
+//sysnb Dup2(from int, to int) (err error)
+//sys Exchangedata(path1 string, path2 string, options int) (err error)
//sys Exit(code int)
-//sys Fchdir(fd int) (errno int)
-//sys Fchflags(path string, flags int) (errno int)
-//sys Fchmod(fd int, mode uint32) (errno int)
-//sys Fchown(fd int, uid int, gid int) (errno int)
-//sys Flock(fd int, how int) (errno int)
-//sys Fpathconf(fd int, name int) (val int, errno int)
-//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
-//sys Fstatfs(fd int, stat *Statfs_t) (errno int) = SYS_FSTATFS64
-//sys Fsync(fd int) (errno int)
-//sys Ftruncate(fd int, length int64) (errno int)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) = SYS_GETDIRENTRIES64
+//sys Fchdir(fd int) (err error)
+//sys Fchflags(path string, flags int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Flock(fd int, how int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int) = SYS_GETFSSTAT64
+//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error) = SYS_GETFSSTAT64
//sysnb Getgid() (gid int)
-//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
//sysnb Getpid() (pid int)
//sysnb Getppid() (ppid int)
-//sys Getpriority(which int, who int) (prio int, errno int)
-//sysnb Getrlimit(which int, lim *Rlimit) (errno int)
-//sysnb Getrusage(who int, rusage *Rusage) (errno int)
-//sysnb Getsid(pid int) (sid int, errno int)
+//sys Getpriority(which int, who int) (prio int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
+//sysnb Getsid(pid int) (sid int, err error)
//sysnb Getuid() (uid int)
//sysnb Issetugid() (tainted bool)
-//sys Kqueue() (fd int, errno int)
-//sys Lchown(path string, uid int, gid int) (errno int)
-//sys Link(path string, link string) (errno int)
-//sys Listen(s int, backlog int) (errno int)
-//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
-//sys Mkdir(path string, mode uint32) (errno int)
-//sys Mkfifo(path string, mode uint32) (errno int)
-//sys Mknod(path string, mode uint32, dev int) (errno int)
-//sys Open(path string, mode int, perm uint32) (fd int, errno int)
-//sys Pathconf(path string, name int) (val int, errno int)
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
-//sys Read(fd int, p []byte) (n int, errno int)
-//sys Readlink(path string, buf []byte) (n int, errno int)
-//sys Rename(from string, to string) (errno int)
-//sys Revoke(path string) (errno int)
-//sys Rmdir(path string) (errno int)
-//sys Seek(fd int, offset int64, whence int) (newoffset int64, errno int) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int)
-//sys Setegid(egid int) (errno int)
-//sysnb Seteuid(euid int) (errno int)
-//sysnb Setgid(gid int) (errno int)
-//sys Setlogin(name string) (errno int)
-//sysnb Setpgid(pid int, pgid int) (errno int)
-//sys Setpriority(which int, who int, prio int) (errno int)
-//sys Setprivexec(flag int) (errno int)
-//sysnb Setregid(rgid int, egid int) (errno int)
-//sysnb Setreuid(ruid int, euid int) (errno int)
-//sysnb Setrlimit(which int, lim *Rlimit) (errno int)
-//sysnb Setsid() (pid int, errno int)
-//sysnb Settimeofday(tp *Timeval) (errno int)
-//sysnb Setuid(uid int) (errno int)
-//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
-//sys Statfs(path string, stat *Statfs_t) (errno int) = SYS_STATFS64
-//sys Symlink(path string, link string) (errno int)
-//sys Sync() (errno int)
-//sys Truncate(path string, length int64) (errno int)
+//sys Kqueue() (fd int, err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Revoke(path string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sys Setlogin(name string) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sys Setprivexec(flag int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tp *Timeval) (err error)
+//sysnb Setuid(uid int) (err error)
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
-//sys Undelete(path string) (errno int)
-//sys Unlink(path string) (errno int)
-//sys Unmount(path string, flags int) (errno int)
-//sys Write(fd int, p []byte) (n int, errno int)
-//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int)
-//sys munmap(addr uintptr, length uintptr) (errno int)
-//sys read(fd int, buf *byte, nbuf int) (n int, errno int)
-//sys write(fd int, buf *byte, nbuf int) (n int, errno int)
+//sys Undelete(path string) (err error)
+//sys Unlink(path string) (err error)
+//sys Unmount(path string, flags int) (err error)
+//sys Write(fd int, p []byte) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys read(fd int, buf *byte, nbuf int) (n int, err error)
+//sys write(fd int, buf *byte, nbuf int) (n int, err error)
/*
* Unimplemented
diff --git a/src/pkg/syscall/syscall_darwin_386.go b/src/pkg/syscall/syscall_darwin_386.go
index d76b22844..9a8a97de5 100644
--- a/src/pkg/syscall/syscall_darwin_386.go
+++ b/src/pkg/syscall/syscall_darwin_386.go
@@ -23,8 +23,8 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, errno int)
-func Gettimeofday(tv *Timeval) (errno int) {
+//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
@@ -52,4 +52,4 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/pkg/syscall/syscall_darwin_amd64.go b/src/pkg/syscall/syscall_darwin_amd64.go
index ed4372304..2d25e591e 100644
--- a/src/pkg/syscall/syscall_darwin_amd64.go
+++ b/src/pkg/syscall/syscall_darwin_amd64.go
@@ -23,8 +23,8 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, errno int)
-func Gettimeofday(tv *Timeval) (errno int) {
+//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index 18988c0a8..6556ea8de 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -14,8 +14,6 @@ package syscall
import "unsafe"
-const OS = "freebsd"
-
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -28,6 +26,31 @@ type SockaddrDatalink struct {
raw RawSockaddrDatalink
}
+// Translate "kern.hostname" to []_C_int{0,1,2,3}.
+func nametomib(name string) (mib []_C_int, err error) {
+ const siz = unsafe.Sizeof(mib[0])
+
+ // NOTE(rsc): It seems strange to set the buffer to have
+ // size CTL_MAXNAME+2 but use only CTL_MAXNAME
+ // as the size. I don't know why the +2 is here, but the
+ // kernel uses +2 for its own implementation of this function.
+ // I am scared that if we don't include the +2 here, the kernel
+ // will silently write 2 words farther than we specify
+ // and we'll get memory corruption.
+ var buf [CTL_MAXNAME + 2]_C_int
+ n := uintptr(CTL_MAXNAME) * siz
+
+ p := (*byte)(unsafe.Pointer(&buf[0]))
+ bytes := StringByteSlice(name)
+
+ // Magic sysctl: "setting" 0.3 to a string name
+ // lets you read back the array of integers form.
+ if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
+ return nil, err
+ }
+ return buf[0 : n/siz], nil
+}
+
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number
// bytes consumed from buf, the number of entries added
@@ -56,109 +79,120 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
return origlen - len(buf), count, names
}
-//sysnb pipe() (r int, w int, errno int)
+//sysnb pipe() (r int, w int, err error)
-func Pipe(p []int) (errno int) {
+func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
- p[0], p[1], errno = pipe()
+ p[0], p[1], err = pipe()
return
}
// TODO
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
+func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
+ var value IPMreqn
+ vallen := _Socklen(SizeofIPMreqn)
+ errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, errno
+}
+
+func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
/*
* Exposed directly
*/
-//sys Access(path string, mode uint32) (errno int)
-//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int)
-//sys Chdir(path string) (errno int)
-//sys Chflags(path string, flags int) (errno int)
-//sys Chmod(path string, mode uint32) (errno int)
-//sys Chown(path string, uid int, gid int) (errno int)
-//sys Chroot(path string) (errno int)
-//sys Close(fd int) (errno int)
-//sysnb Dup(fd int) (nfd int, errno int)
-//sysnb Dup2(from int, to int) (errno int)
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chflags(path string, flags int) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sysnb Dup(fd int) (nfd int, err error)
+//sysnb Dup2(from int, to int) (err error)
//sys Exit(code int)
-//sys Fchdir(fd int) (errno int)
-//sys Fchflags(path string, flags int) (errno int)
-//sys Fchmod(fd int, mode uint32) (errno int)
-//sys Fchown(fd int, uid int, gid int) (errno int)
-//sys Flock(fd int, how int) (errno int)
-//sys Fpathconf(fd int, name int) (val int, errno int)
-//sys Fstat(fd int, stat *Stat_t) (errno int)
-//sys Fstatfs(fd int, stat *Statfs_t) (errno int)
-//sys Fsync(fd int) (errno int)
-//sys Ftruncate(fd int, length int64) (errno int)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int)
+//sys Fchdir(fd int) (err error)
+//sys Fchflags(path string, flags int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Flock(fd int, how int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
-//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int)
+//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
//sysnb Getgid() (gid int)
-//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pgrp int)
//sysnb Getpid() (pid int)
//sysnb Getppid() (ppid int)
-//sys Getpriority(which int, who int) (prio int, errno int)
-//sysnb Getrlimit(which int, lim *Rlimit) (errno int)
-//sysnb Getrusage(who int, rusage *Rusage) (errno int)
-//sysnb Getsid(pid int) (sid int, errno int)
-//sysnb Gettimeofday(tv *Timeval) (errno int)
+//sys Getpriority(which int, who int) (prio int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
+//sysnb Getsid(pid int) (sid int, err error)
+//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Getuid() (uid int)
//sys Issetugid() (tainted bool)
-//sys Kill(pid int, signum int) (errno int)
-//sys Kqueue() (fd int, errno int)
-//sys Lchown(path string, uid int, gid int) (errno int)
-//sys Link(path string, link string) (errno int)
-//sys Listen(s int, backlog int) (errno int)
-//sys Lstat(path string, stat *Stat_t) (errno int)
-//sys Mkdir(path string, mode uint32) (errno int)
-//sys Mkfifo(path string, mode uint32) (errno int)
-//sys Mknod(path string, mode uint32, dev int) (errno int)
-//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int)
-//sys Open(path string, mode int, perm uint32) (fd int, errno int)
-//sys Pathconf(path string, name int) (val int, errno int)
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
-//sys Read(fd int, p []byte) (n int, errno int)
-//sys Readlink(path string, buf []byte) (n int, errno int)
-//sys Rename(from string, to string) (errno int)
-//sys Revoke(path string) (errno int)
-//sys Rmdir(path string) (errno int)
-//sys Seek(fd int, offset int64, whence int) (newoffset int64, errno int) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int)
-//sysnb Setegid(egid int) (errno int)
-//sysnb Seteuid(euid int) (errno int)
-//sysnb Setgid(gid int) (errno int)
-//sys Setlogin(name string) (errno int)
-//sysnb Setpgid(pid int, pgid int) (errno int)
-//sys Setpriority(which int, who int, prio int) (errno int)
-//sysnb Setregid(rgid int, egid int) (errno int)
-//sysnb Setreuid(ruid int, euid int) (errno int)
-//sysnb Setrlimit(which int, lim *Rlimit) (errno int)
-//sysnb Setsid() (pid int, errno int)
-//sysnb Settimeofday(tp *Timeval) (errno int)
-//sysnb Setuid(uid int) (errno int)
-//sys Stat(path string, stat *Stat_t) (errno int)
-//sys Statfs(path string, stat *Statfs_t) (errno int)
-//sys Symlink(path string, link string) (errno int)
-//sys Sync() (errno int)
-//sys Truncate(path string, length int64) (errno int)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Kqueue() (fd int, err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Revoke(path string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sys Setlogin(name string) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tp *Timeval) (err error)
+//sysnb Setuid(uid int) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, stat *Statfs_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
-//sys Undelete(path string) (errno int)
-//sys Unlink(path string) (errno int)
-//sys Unmount(path string, flags int) (errno int)
-//sys Write(fd int, p []byte) (n int, errno int)
-//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int)
-//sys munmap(addr uintptr, length uintptr) (errno int)
-//sys read(fd int, buf *byte, nbuf int) (n int, errno int)
-//sys write(fd int, buf *byte, nbuf int) (n int, errno int)
+//sys Undelete(path string) (err error)
+//sys Unlink(path string) (err error)
+//sys Unmount(path string, flags int) (err error)
+//sys Write(fd int, p []byte) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys read(fd int, buf *byte, nbuf int) (n int, err error)
+//sys write(fd int, buf *byte, nbuf int) (n int, err error)
/*
* Unimplemented
diff --git a/src/pkg/syscall/syscall_freebsd_386.go b/src/pkg/syscall/syscall_freebsd_386.go
index d3b5a1bfe..fa322c596 100644
--- a/src/pkg/syscall/syscall_freebsd_386.go
+++ b/src/pkg/syscall/syscall_freebsd_386.go
@@ -41,4 +41,4 @@ func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 9fc2605c4..89fb68192 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -13,51 +13,49 @@ package syscall
import "unsafe"
-const OS = "linux"
-
/*
* Wrapped
*/
-//sys open(path string, mode int, perm uint32) (fd int, errno int)
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+//sys open(path string, mode int, perm uint32) (fd int, err error)
+func Open(path string, mode int, perm uint32) (fd int, err error) {
return open(path, mode|O_LARGEFILE, perm)
}
-//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int)
-func Openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int) {
+//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
+func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
return openat(dirfd, path, flags|O_LARGEFILE, mode)
}
-//sysnb pipe(p *[2]_C_int) (errno int)
-func Pipe(p []int) (errno int) {
+//sysnb pipe(p *[2]_C_int) (err error)
+func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
- errno = pipe(&pp)
+ err = pipe(&pp)
p[0] = int(pp[0])
p[1] = int(pp[1])
return
}
-//sys utimes(path string, times *[2]Timeval) (errno int)
-func Utimes(path string, tv []Timeval) (errno int) {
+//sys utimes(path string, times *[2]Timeval) (err error)
+func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int)
-func Futimesat(dirfd int, path string, tv []Timeval) (errno int) {
+//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (err error)
+func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-func Futimes(fd int, tv []Timeval) (errno int) {
+func Futimes(fd int, tv []Timeval) (err error) {
// Believe it or not, this is the best we can do on Linux
// (and is what glibc does).
return Utimes("/proc/self/fd/"+itoa(fd), tv)
@@ -65,27 +63,27 @@ func Futimes(fd int, tv []Timeval) (errno int) {
const ImplementsGetwd = true
-//sys Getcwd(buf []byte) (n int, errno int)
-func Getwd() (wd string, errno int) {
+//sys Getcwd(buf []byte) (n int, err error)
+func Getwd() (wd string, err error) {
var buf [PathMax]byte
n, err := Getcwd(buf[0:])
- if err != 0 {
+ if err != nil {
return "", err
}
// Getcwd returns the number of bytes written to buf, including the NUL.
if n < 1 || n > len(buf) || buf[n-1] != 0 {
return "", EINVAL
}
- return string(buf[0 : n-1]), 0
+ return string(buf[0 : n-1]), nil
}
-func Getgroups() (gids []int, errno int) {
+func Getgroups() (gids []int, err error) {
n, err := getgroups(0, nil)
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
if n == 0 {
- return nil, 0
+ return nil, nil
}
// Sanity check group count. Max is 1<<16 on Linux.
@@ -95,8 +93,8 @@ func Getgroups() (gids []int, errno int) {
a := make([]_Gid_t, n)
n, err = getgroups(n, &a[0])
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
gids = make([]int, n)
for i, v := range a[0:n] {
@@ -105,7 +103,7 @@ func Getgroups() (gids []int, errno int) {
return
}
-func Setgroups(gids []int) (errno int) {
+func Setgroups(gids []int) (err error) {
if len(gids) == 0 {
return setgroups(0, nil)
}
@@ -153,18 +151,18 @@ func (w WaitStatus) ExitStatus() int {
return int(w>>shift) & 0xFF
}
-func (w WaitStatus) Signal() int {
+func (w WaitStatus) Signal() Signal {
if !w.Signaled() {
return -1
}
- return int(w & mask)
+ return Signal(w & mask)
}
-func (w WaitStatus) StopSignal() int {
+func (w WaitStatus) StopSignal() Signal {
if !w.Stopped() {
return -1
}
- return int(w>>shift) & 0xFF
+ return Signal(w>>shift) & 0xFF
}
func (w WaitStatus) TrapCause() int {
@@ -174,20 +172,18 @@ func (w WaitStatus) TrapCause() int {
return int(w>>shift) >> 8
}
-//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int)
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error)
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
var status _C_int
- wpid, errno = wait4(pid, &status, options, rusage)
+ wpid, err = wait4(pid, &status, options, rusage)
if wstatus != nil {
*wstatus = WaitStatus(status)
}
return
}
-func Sleep(nsec int64) (errno int) {
- tv := NsecToTimeval(nsec)
- _, err := Select(0, nil, nil, nil, &tv)
- return err
+func Mkfifo(path string, mode uint32) (err error) {
+ return Mknod(path, mode|S_IFIFO, 0)
}
// For testing: clients can set this flag to force
@@ -195,7 +191,7 @@ func Sleep(nsec int64) (errno int) {
var SocketDisableIPv6 bool
type Sockaddr interface {
- sockaddr() (ptr uintptr, len _Socklen, errno int) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr uintptr, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -204,7 +200,7 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return 0, 0, EINVAL
}
@@ -215,7 +211,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, nil
}
type SockaddrInet6 struct {
@@ -225,7 +221,7 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return 0, 0, EINVAL
}
@@ -237,7 +233,7 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, nil
}
type SockaddrUnix struct {
@@ -245,7 +241,7 @@ type SockaddrUnix struct {
raw RawSockaddrUnix
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) || n == 0 {
@@ -263,7 +259,7 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
sl--
}
- return uintptr(unsafe.Pointer(&sa.raw)), sl, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), sl, nil
}
type SockaddrLinklayer struct {
@@ -276,7 +272,7 @@ type SockaddrLinklayer struct {
raw RawSockaddrLinklayer
}
-func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
return 0, 0, EINVAL
}
@@ -289,7 +285,7 @@ func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, nil
}
type SockaddrNetlink struct {
@@ -300,15 +296,15 @@ type SockaddrNetlink struct {
raw RawSockaddrNetlink
}
-func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, int) {
+func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, error) {
sa.raw.Family = AF_NETLINK
sa.raw.Pad = sa.Pad
sa.raw.Pid = sa.Pid
sa.raw.Groups = sa.Groups
- return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, 0
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
@@ -317,7 +313,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
sa.Pad = pp.Pad
sa.Pid = pp.Pid
sa.Groups = pp.Groups
- return sa, 0
+ return sa, nil
case AF_PACKET:
pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
@@ -330,7 +326,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
@@ -355,7 +351,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
}
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
- return sa, 0
+ return sa, nil
case AF_INET:
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
@@ -365,7 +361,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
case AF_INET6:
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
@@ -376,124 +372,159 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
}
return nil, EAFNOSUPPORT
}
-func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- nfd, errno = accept(fd, &rsa, &len)
- if errno != 0 {
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
return
}
- sa, errno = anyToSockaddr(&rsa)
- if errno != 0 {
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
Close(nfd)
nfd = 0
}
return
}
-func Getsockname(fd int) (sa Sockaddr, errno int) {
+func Getsockname(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if errno = getsockname(fd, &rsa, &len); errno != 0 {
+ if err = getsockname(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-func Getpeername(fd int) (sa Sockaddr, errno int) {
+func Getpeername(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if errno = getpeername(fd, &rsa, &len); errno != 0 {
+ if err = getpeername(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-func Bind(fd int, sa Sockaddr) (errno int) {
+func Bind(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return bind(fd, ptr, n)
}
-func Connect(fd int, sa Sockaddr) (errno int) {
+func Connect(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return connect(fd, ptr, n)
}
-func Socket(domain, typ, proto int) (fd, errno int) {
+func Socket(domain, typ, proto int) (fd int, err error) {
if domain == AF_INET6 && SocketDisableIPv6 {
return -1, EAFNOSUPPORT
}
- fd, errno = socket(domain, typ, proto)
+ fd, err = socket(domain, typ, proto)
return
}
-func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
- errno = socketpair(domain, typ, proto, &fd)
+func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
+ err = socketpair(domain, typ, proto, &fd)
return
}
-func GetsockoptInt(fd, level, opt int) (value, errno int) {
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := _Socklen(4)
- errno = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
- return int(n), errno
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+ return int(n), err
+}
+
+func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
+ vallen := _Socklen(4)
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ return value, err
}
-func SetsockoptInt(fd, level, opt int, value int) (errno int) {
+func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
+ var value IPMreq
+ vallen := _Socklen(SizeofIPMreq)
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
+}
+
+func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
+ var value IPMreqn
+ vallen := _Socklen(SizeofIPMreqn)
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
+}
+
+func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
+ var value IPv6Mreq
+ vallen := _Socklen(SizeofIPv6Mreq)
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
+}
+
+func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
}
-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), 4)
+}
+
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
}
-func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), unsafe.Sizeof(*l))
}
-func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
-func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
+func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
-func SetsockoptString(fd, level, opt int, s string) (errno int) {
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+}
+
+func SetsockoptString(fd, level, opt int, s string) (err error) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
}
-func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
- if n, errno = recvfrom(fd, p, flags, &rsa, &len); errno != 0 {
+ if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
return
}
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
return
}
-func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
ptr, n, err := to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return sendto(fd, p, flags, ptr, n)
}
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
@@ -515,25 +546,25 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
msg.Iov = &iov
msg.Iovlen = 1
- if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
return
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
}
return
}
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
var ptr uintptr
var salen _Socklen
if to != nil {
- var err int
+ var err error
ptr, salen, err = to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
}
@@ -557,20 +588,20 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ if err = sendmsg(fd, &msg, flags); err != nil {
return
}
return
}
// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
+func BindToDevice(fd int, device string) (err error) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
}
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
-func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) {
// The peek requests are machine-size oriented, so we wrap it
// to retrieve arbitrary-length data.
@@ -586,9 +617,9 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno in
// boundary.
n := 0
if addr%sizeofPtr != 0 {
- errno = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return 0, errno
+ err = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return 0, err
}
n += copy(out, buf[addr%sizeofPtr:])
out = out[n:]
@@ -596,29 +627,29 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno in
// Remainder.
for len(out) > 0 {
- // We use an internal buffer to gaurantee alignment.
+ // We use an internal buffer to guarantee alignment.
// It's not documented if this is necessary, but we're paranoid.
- errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return n, errno
+ err = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return n, err
}
copied := copy(out, buf[0:])
n += copied
out = out[copied:]
}
- return n, 0
+ return n, nil
}
-func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) {
return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out)
}
-func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
return ptracePeek(PTRACE_PEEKDATA, pid, addr, out)
}
-func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, err error) {
// As for ptracePeek, we need to align our accesses to deal
// with the possibility of straddling an invalid page.
@@ -626,15 +657,15 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
n := 0
if addr%sizeofPtr != 0 {
var buf [sizeofPtr]byte
- errno = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return 0, errno
+ err = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return 0, err
}
n += copy(buf[addr%sizeofPtr:], data)
word := *((*uintptr)(unsafe.Pointer(&buf[0])))
- errno = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
- if errno != 0 {
- return 0, errno
+ err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
+ if err != nil {
+ return 0, err
}
data = data[n:]
}
@@ -642,9 +673,9 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Interior.
for len(data) > sizeofPtr {
word := *((*uintptr)(unsafe.Pointer(&data[0])))
- errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
- if errno != 0 {
- return n, errno
+ err = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if err != nil {
+ return n, err
}
n += sizeofPtr
data = data[sizeofPtr:]
@@ -653,61 +684,61 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Trailing edge.
if len(data) > 0 {
var buf [sizeofPtr]byte
- errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return n, errno
+ err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return n, err
}
copy(buf[0:], data)
word := *((*uintptr)(unsafe.Pointer(&buf[0])))
- errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
- if errno != 0 {
- return n, errno
+ err = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if err != nil {
+ return n, err
}
n += len(data)
}
- return n, 0
+ return n, nil
}
-func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data)
}
-func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data)
}
-func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
}
-func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}
-func PtraceSetOptions(pid int, options int) (errno int) {
+func PtraceSetOptions(pid int, options int) (err error) {
return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options))
}
-func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+func PtraceGetEventMsg(pid int) (msg uint, err error) {
var data _C_long
- errno = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
+ err = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
msg = uint(data)
return
}
-func PtraceCont(pid int, signal int) (errno int) {
+func PtraceCont(pid int, signal int) (err error) {
return ptrace(PTRACE_CONT, pid, 0, uintptr(signal))
}
-func PtraceSingleStep(pid int) (errno int) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
+func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
-func PtraceAttach(pid int) (errno int) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
+func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
-func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
+func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
-//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int)
-func Reboot(cmd int) (errno int) {
+//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error)
+func Reboot(cmd int) (err error) {
return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
}
@@ -720,7 +751,7 @@ func clen(n []byte) int {
return len(n)
}
-func ReadDirent(fd int, buf []byte) (n int, errno int) {
+func ReadDirent(fd int, buf []byte) (n int, err error) {
return Getdents(fd, buf)
}
@@ -745,6 +776,16 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
return origlen - len(buf), count, names
}
+//sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error)
+func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
+ // Certain file systems get rather angry and EINVAL if you give
+ // them an empty string of data, rather than NULL.
+ if data == "" {
+ return mount(source, target, fstype, flags, nil)
+ }
+ return mount(source, target, fstype, flags, StringBytePtr(data))
+}
+
// Sendto
// Recvfrom
// Socketpair
@@ -752,86 +793,86 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
/*
* Direct access
*/
-//sys Access(path string, mode uint32) (errno int)
-//sys Acct(path string) (errno int)
-//sys Adjtimex(buf *Timex) (state int, errno int)
-//sys Chdir(path string) (errno int)
-//sys Chmod(path string, mode uint32) (errno int)
-//sys Chroot(path string) (errno int)
-//sys Close(fd int) (errno int)
-//sys Creat(path string, mode uint32) (fd int, errno int)
-//sysnb Dup(oldfd int) (fd int, errno int)
-//sysnb Dup2(oldfd int, newfd int) (fd int, errno int)
-//sysnb EpollCreate(size int) (fd int, errno int)
-//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int)
+//sys Access(path string, mode uint32) (err error)
+//sys Acct(path string) (err error)
+//sys Adjtimex(buf *Timex) (state int, err error)
+//sys Chdir(path string) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sys Creat(path string, mode uint32) (fd int, err error)
+//sysnb Dup(oldfd int) (fd int, err error)
+//sysnb Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
+//sysnb EpollCreate1(flag int) (fd int, err error)
+//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Exit(code int) = SYS_EXIT_GROUP
-//sys Faccessat(dirfd int, path string, mode uint32, flags int) (errno int)
-//sys Fallocate(fd int, mode uint32, off int64, len int64) (errno int)
-//sys Fchdir(fd int) (errno int)
-//sys Fchmod(fd int, mode uint32) (errno int)
-//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int)
-//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int)
-//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
-//sys Fdatasync(fd int) (errno int)
-//sys Flock(fd int, how int) (errno int)
-//sys Fsync(fd int) (errno int)
-//sys Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64
-//sysnb Getpgid(pid int) (pgid int, errno int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
+//sys Fchdir(fd int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+//sys Fdatasync(fd int) (err error)
+//sys Flock(fd int, how int) (err error)
+//sys Fsync(fd int) (err error)
+//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
+//sysnb Getpgid(pid int) (pgid int, err error)
//sysnb Getpgrp() (pid int)
//sysnb Getpid() (pid int)
//sysnb Getppid() (ppid int)
-//sysnb Getrlimit(resource int, rlim *Rlimit) (errno int)
-//sysnb Getrusage(who int, rusage *Rusage) (errno int)
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
//sysnb Gettid() (tid int)
-//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int)
-//sysnb InotifyInit() (fd int, errno int)
-//sysnb InotifyInit1(flags int) (fd int, errno int)
-//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int)
-//sysnb Kill(pid int, sig int) (errno int)
-//sys Klogctl(typ int, buf []byte) (n int, errno int) = SYS_SYSLOG
-//sys Link(oldpath string, newpath string) (errno int)
-//sys Mkdir(path string, mode uint32) (errno int)
-//sys Mkdirat(dirfd int, path string, mode uint32) (errno int)
-//sys Mknod(path string, mode uint32, dev int) (errno int)
-//sys Mknodat(dirfd int, path string, mode uint32, dev int) (errno int)
-//sys Mount(source string, target string, fstype string, flags int, data string) (errno int)
-//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int)
-//sys Pause() (errno int)
-//sys PivotRoot(newroot string, putold string) (errno int) = SYS_PIVOT_ROOT
-//sys Read(fd int, p []byte) (n int, errno int)
-//sys Readlink(path string, buf []byte) (n int, errno int)
-//sys Rename(oldpath string, newpath string) (errno int)
-//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int)
-//sys Rmdir(path string) (errno int)
-//sys Setdomainname(p []byte) (errno int)
-//sys Sethostname(p []byte) (errno int)
-//sysnb Setpgid(pid int, pgid int) (errno int)
-//sysnb Setrlimit(resource int, rlim *Rlimit) (errno int)
-//sysnb Setsid() (pid int, errno int)
-//sysnb Settimeofday(tv *Timeval) (errno int)
-//sysnb Setuid(uid int) (errno int)
-//sys Symlink(oldpath string, newpath string) (errno int)
+//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
+//sysnb InotifyInit() (fd int, err error)
+//sysnb InotifyInit1(flags int) (fd int, err error)
+//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
+//sysnb Kill(pid int, sig Signal) (err error)
+//sys Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG
+//sys Link(oldpath string, newpath string) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Pause() (err error)
+//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
+//sys Read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(oldpath string, newpath string) (err error)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Setdomainname(p []byte) (err error)
+//sys Sethostname(p []byte) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tv *Timeval) (err error)
+//sysnb Setuid(uid int) (err error)
+//sys Symlink(oldpath string, newpath string) (err error)
//sys Sync()
-//sysnb Sysinfo(info *Sysinfo_t) (errno int)
-//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int)
-//sysnb Tgkill(tgid int, tid int, sig int) (errno int)
-//sysnb Times(tms *Tms) (ticks uintptr, errno int)
+//sysnb Sysinfo(info *Sysinfo_t) (err error)
+//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
+//sysnb Tgkill(tgid int, tid int, sig Signal) (err error)
+//sysnb Times(tms *Tms) (ticks uintptr, err error)
//sysnb Umask(mask int) (oldmask int)
-//sysnb Uname(buf *Utsname) (errno int)
-//sys Unlink(path string) (errno int)
-//sys Unlinkat(dirfd int, path string) (errno int)
-//sys Unmount(target string, flags int) (errno int) = SYS_UMOUNT2
-//sys Unshare(flags int) (errno int)
-//sys Ustat(dev int, ubuf *Ustat_t) (errno int)
-//sys Utime(path string, buf *Utimbuf) (errno int)
-//sys Write(fd int, p []byte) (n int, errno int)
-//sys exitThread(code int) (errno int) = SYS_EXIT
-//sys read(fd int, p *byte, np int) (n int, errno int)
-//sys write(fd int, p *byte, np int) (n int, errno int)
+//sysnb Uname(buf *Utsname) (err error)
+//sys Unlink(path string) (err error)
+//sys Unlinkat(dirfd int, path string) (err error)
+//sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2
+//sys Unshare(flags int) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
+//sys Utime(path string, buf *Utimbuf) (err error)
+//sys Write(fd int, p []byte) (n int, err error)
+//sys exitThread(code int) (err error) = SYS_EXIT
+//sys read(fd int, p *byte, np int) (n int, err error)
+//sys write(fd int, p *byte, np int) (n int, err error)
// mmap varies by architecture; see syscall_linux_*.go.
-//sys munmap(addr uintptr, length uintptr) (errno int)
+//sys munmap(addr uintptr, length uintptr) (err error)
var mapper = &mmapper{
active: make(map[*byte][]byte),
@@ -839,20 +880,20 @@ var mapper = &mmapper{
munmap: munmap,
}
-func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
return mapper.Mmap(fd, offset, length, prot, flags)
}
-func Munmap(b []byte) (errno int) {
+func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}
-//sys Madvise(b []byte, advice int) (errno int)
-//sys Mprotect(b []byte, prot int) (errno int)
-//sys Mlock(b []byte) (errno int)
-//sys Munlock(b []byte) (errno int)
-//sys Mlockall(flags int) (errno int)
-//sys Munlockall() (errno int)
+//sys Madvise(b []byte, advice int) (err error)
+//sys Mprotect(b []byte, prot int) (err error)
+//sys Mlock(b []byte) (err error)
+//sys Munlock(b []byte) (err error)
+//sys Mlockall(flags int) (err error)
+//sys Munlockall() (err error)
/*
* Unimplemented
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index 44891de87..b833db8a7 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -27,39 +27,39 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
-//sys Chown(path string, uid int, gid int) (errno int) = SYS_CHOWN32
-//sys Fchown(fd int, uid int, gid int) (errno int) = SYS_FCHOWN32
-//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
-//sys Ftruncate(fd int, length int64) (errno int) = SYS_FTRUNCATE64
+//sys Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
+//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
//sysnb Getegid() (egid int) = SYS_GETEGID32
//sysnb Geteuid() (euid int) = SYS_GETEUID32
//sysnb Getgid() (gid int) = SYS_GETGID32
//sysnb Getuid() (uid int) = SYS_GETUID32
-//sys Ioperm(from int, num int, on int) (errno int)
-//sys Iopl(level int) (errno int)
-//sys Lchown(path string, uid int, gid int) (errno int) = SYS_LCHOWN32
-//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64
-//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) = SYS_SENDFILE64
-//sys Setfsgid(gid int) (errno int) = SYS_SETFSGID32
-//sys Setfsuid(uid int) (errno int) = SYS_SETFSUID32
-//sysnb Setgid(gid int) (errno int) = SYS_SETGID32
-//sysnb Setregid(rgid int, egid int) (errno int) = SYS_SETREGID32
-//sysnb Setresgid(rgid int, egid int, sgid int) (errno int) = SYS_SETRESGID32
-//sysnb Setresuid(ruid int, euid int, suid int) (errno int) = SYS_SETRESUID32
-//sysnb Setreuid(ruid int, euid int) (errno int) = SYS_SETREUID32
-//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int)
-//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
-//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
-//sys Truncate(path string, length int64) (errno int) = SYS_TRUNCATE64
-//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
-//sysnb setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT
-
-//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int)
-
-func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+//sys Ioperm(from int, num int, on int) (err error)
+//sys Iopl(level int) (err error)
+//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
+//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
+//sys Setfsuid(uid int) (err error) = SYS_SETFSUID32
+//sysnb Setgid(gid int) (err error) = SYS_SETGID32
+//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
+//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
+//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
+//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
+//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
+
+//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
page := uintptr(offset / 4096)
if offset != int64(page)*4096 {
return 0, EINVAL
@@ -69,11 +69,11 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
// Vsyscalls on amd64.
-//sysnb Gettimeofday(tv *Timeval) (errno int)
-//sysnb Time(t *Time_t) (tt Time_t, errno int)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Time(t *Time_t) (tt Time_t, err error)
// On x86 Linux, all the socket calls go through an extra indirection,
// I think because the 5-register system call interface can't handle
@@ -103,101 +103,150 @@ const (
_RECVMSG = 17
)
-func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
-func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
- fd, errno = socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
- _, errno = rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, e := rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
- _, errno = rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, e := rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func socketpair(domain int, typ int, flags int, fd *[2]int) (errno int) {
- _, errno = rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
+func socketpair(domain int, typ int, flags int, fd *[2]int) (err error) {
+ _, e := rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
- _, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
- _, errno = socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func socket(domain int, typ int, proto int) (fd int, errno int) {
- fd, errno = rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ fd, e := rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
- _, errno = socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+ _, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
- _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+ _, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var base uintptr
if len(p) > 0 {
base = uintptr(unsafe.Pointer(&p[0]))
}
- n, errno = socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n, e := socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ if e != 0 {
+ err = e
+ }
return
}
-func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var base uintptr
if len(p) > 0 {
base = uintptr(unsafe.Pointer(&p[0]))
}
- _, errno = socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+ _, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+ if e != 0 {
+ err = e
+ }
return
}
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
- n, errno = socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ n, e := socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
- _, errno = socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
+ _, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func Listen(s int, n int) (errno int) {
- _, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
+func Listen(s int, n int) (err error) {
+ _, e := socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func Shutdown(s, how int) (errno int) {
- _, errno = socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
+func Shutdown(s, how int) (err error) {
+ _, e := socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
+ if e != 0 {
+ err = e
+ }
return
}
-func Fstatfs(fd int, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
- errno = int(e1)
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
+ _, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
+ if e != 0 {
+ err = e
+ }
return
}
-func Statfs(path string, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
- errno = int(e1)
+func Statfs(path string, buf *Statfs_t) (err error) {
+ _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
+ if e != 0 {
+ err = e
+ }
return
}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index 8b206ad0a..18b36b78e 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -4,59 +4,59 @@
package syscall
-//sys Chown(path string, uid int, gid int) (errno int)
-//sys Fchown(fd int, uid int, gid int) (errno int)
-//sys Fstat(fd int, stat *Stat_t) (errno int)
-//sys Fstatfs(fd int, buf *Statfs_t) (errno int)
-//sys Ftruncate(fd int, length int64) (errno int)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (euid int)
//sysnb Getgid() (gid int)
//sysnb Getuid() (uid int)
-//sys Ioperm(from int, num int, on int) (errno int)
-//sys Iopl(level int) (errno int)
-//sys Lchown(path string, uid int, gid int) (errno int)
-//sys Listen(s int, n int) (errno int)
-//sys Lstat(path string, stat *Stat_t) (errno int)
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64
-//sys Seek(fd int, offset int64, whence int) (off int64, errno int) = SYS_LSEEK
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int)
-//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int)
-//sys Setfsgid(gid int) (errno int)
-//sys Setfsuid(uid int) (errno int)
-//sysnb Setgid(gid int) (errno int)
-//sysnb Setregid(rgid int, egid int) (errno int)
-//sysnb Setresgid(rgid int, egid int, sgid int) (errno int)
-//sysnb Setresuid(ruid int, euid int, suid int) (errno int)
-//sysnb Setreuid(ruid int, euid int) (errno int)
-//sys Shutdown(fd int, how int) (errno int)
-//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int)
-//sys Stat(path string, stat *Stat_t) (errno int)
-//sys Statfs(path string, buf *Statfs_t) (errno int)
-//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
-//sys Truncate(path string, length int64) (errno int)
-//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int)
-//sysnb setgroups(n int, list *_Gid_t) (errno int)
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
-//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
-//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
-//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
-//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
-//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
-//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int)
+//sys Ioperm(from int, num int, on int) (err error)
+//sys Iopl(level int) (err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Listen(s int, n int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
+//sys Setfsgid(gid int) (err error)
+//sys Setfsuid(uid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
func Getpagesize() int { return 4096 }
-func Gettimeofday(tv *Timeval) (errno int)
-func Time(t *Time_t) (tt Time_t, errno int)
+func Gettimeofday(tv *Timeval) (err error)
+func Time(t *Time_t) (tt Time_t, err error)
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 8c03c765c..48b5d31d7 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -4,8 +4,6 @@
package syscall
-import "unsafe"
-
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -23,96 +21,63 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-// Pread and Pwrite are special: they insert padding before the int64.
-
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- }
- r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- }
- r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Ftruncate(fd int, length int64) (errno int) {
- // ARM EABI requires 64-bit arguments should be put in a pair
- // of registers from an even register number.
- _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
- errno = int(e1)
- return
-}
-
-func Truncate(path string, length int64) (errno int) {
- _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
- errno = int(e1)
- return
-}
-
// Seek is defined in assembly.
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
-
-//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int)
-//sys bind(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
-//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
-//sysnb setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
-//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
-//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
-//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
-//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int)
-//sysnb socketpair(domain int, typ int, flags int, fd *[2]int) (errno int)
-//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
-//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
-
-//sys Chown(path string, uid int, gid int) (errno int)
-//sys Fchown(fd int, uid int, gid int) (errno int)
-//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
-//sys Fstatfs(fd int, buf *Statfs_t) (errno int) = SYS_FSTATFS64
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys bind(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
+//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
+//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sysnb socketpair(domain int, typ int, flags int, fd *[2]int) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
+
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatfs(fd int, buf *Statfs_t) (err error) = SYS_FSTATFS64
//sysnb Getegid() (egid int)
//sysnb Geteuid() (euid int)
//sysnb Getgid() (gid int)
//sysnb Getuid() (uid int)
-//sys Lchown(path string, uid int, gid int) (errno int)
-//sys Listen(s int, n int) (errno int)
-//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
-//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) = SYS_SENDFILE64
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) = SYS__NEWSELECT
-//sys Setfsgid(gid int) (errno int)
-//sys Setfsuid(uid int) (errno int)
-//sysnb Setgid(gid int) (errno int)
-//sysnb Setregid(rgid int, egid int) (errno int)
-//sysnb Setresgid(rgid int, egid int, sgid int) (errno int)
-//sysnb Setresuid(ruid int, euid int, suid int) (errno int)
-//sysnb Setreuid(ruid int, euid int) (errno int)
-//sys Shutdown(fd int, how int) (errno int)
-//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int)
-//sys Stat(path string, stat *Stat_t) (errno int) = SYS_STAT64
-//sys Statfs(path string, buf *Statfs_t) (errno int) = SYS_STATFS64
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Listen(s int, n int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
+//sys Setfsgid(gid int) (err error)
+//sys Setfsuid(uid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys Statfs(path string, buf *Statfs_t) (err error) = SYS_STATFS64
// Vsyscalls on amd64.
-//sysnb Gettimeofday(tv *Timeval) (errno int)
-//sysnb Time(t *Time_t) (tt Time_t, errno int)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Time(t *Time_t) (tt Time_t, err error)
+
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
-//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int)
+//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
-func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
page := uintptr(offset / 4096)
if offset != int64(page)*4096 {
return 0, EINVAL
diff --git a/src/pkg/syscall/syscall_netbsd.go b/src/pkg/syscall/syscall_netbsd.go
new file mode 100644
index 000000000..3f6d16f56
--- /dev/null
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -0,0 +1,434 @@
+// Copyright 2009,2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// NetBSD system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_bsd.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+ raw RawSockaddrDatalink
+}
+
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+
+func nametomib(name string) (mib []_C_int, err error) {
+ return nil, EINVAL
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Fileno == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:dirent.Namlen])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe2(&pp, 0)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys getdents(fd int, buf []byte) (n int, err error)
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return getdents(fd, buf)
+}
+
+// TODO
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return -1, ENOSYS
+}
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chflags(path string, flags int) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sysnb Dup(fd int) (nfd int, err error)
+//sysnb Dup2(from int, to int) (err error)
+//sys Exit(code int)
+//sys Fchdir(fd int) (err error)
+//sys Fchflags(path string, flags int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Flock(fd int, how int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (uid int)
+//sysnb Getgid() (gid int)
+//sysnb Getpgid(pid int) (pgid int, err error)
+//sysnb Getpgrp() (pgrp int)
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sys Getpriority(which int, who int) (prio int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
+//sysnb Getsid(pid int) (sid int, err error)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Getuid() (uid int)
+//sys Issetugid() (tainted bool)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Kqueue() (fd int, err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Revoke(path string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tp *Timeval) (err error)
+//sysnb Setuid(uid int) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys Umask(newmask int) (oldmask int)
+//sys Unlink(path string) (err error)
+//sys Unmount(path string, flags int) (err error)
+//sys Write(fd int, p []byte) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys read(fd int, buf *byte, nbuf int) (n int, err error)
+//sys write(fd int, buf *byte, nbuf int) (n int, err error)
+
+/*
+ * Unimplemented
+ */
+// ____semctl13
+// __clone
+// __fhopen40
+// __fhstat40
+// __fhstatvfs140
+// __fstat30
+// __getcwd
+// __getfh30
+// __getlogin
+// __lstat30
+// __mount50
+// __msgctl13
+// __msync13
+// __ntp_gettime30
+// __posix_chown
+// __posix_fadvise50
+// __posix_fchown
+// __posix_lchown
+// __posix_rename
+// __setlogin
+// __shmctl13
+// __sigaction_sigtramp
+// __sigaltstack14
+// __sigpending14
+// __sigprocmask14
+// __sigsuspend14
+// __sigtimedwait
+// __stat30
+// __syscall
+// __vfork14
+// _ksem_close
+// _ksem_destroy
+// _ksem_getvalue
+// _ksem_init
+// _ksem_open
+// _ksem_post
+// _ksem_trywait
+// _ksem_unlink
+// _ksem_wait
+// _lwp_continue
+// _lwp_create
+// _lwp_ctl
+// _lwp_detach
+// _lwp_exit
+// _lwp_getname
+// _lwp_getprivate
+// _lwp_kill
+// _lwp_park
+// _lwp_self
+// _lwp_setname
+// _lwp_setprivate
+// _lwp_suspend
+// _lwp_unpark
+// _lwp_unpark_all
+// _lwp_wait
+// _lwp_wakeup
+// _pset_bind
+// _sched_getaffinity
+// _sched_getparam
+// _sched_setaffinity
+// _sched_setparam
+// acct
+// aio_cancel
+// aio_error
+// aio_fsync
+// aio_read
+// aio_return
+// aio_suspend
+// aio_write
+// break
+// clock_getres
+// clock_gettime
+// clock_settime
+// compat_09_ogetdomainname
+// compat_09_osetdomainname
+// compat_09_ouname
+// compat_10_omsgsys
+// compat_10_osemsys
+// compat_10_oshmsys
+// compat_12_fstat12
+// compat_12_getdirentries
+// compat_12_lstat12
+// compat_12_msync
+// compat_12_oreboot
+// compat_12_oswapon
+// compat_12_stat12
+// compat_13_sigaction13
+// compat_13_sigaltstack13
+// compat_13_sigpending13
+// compat_13_sigprocmask13
+// compat_13_sigreturn13
+// compat_13_sigsuspend13
+// compat_14___semctl
+// compat_14_msgctl
+// compat_14_shmctl
+// compat_16___sigaction14
+// compat_16___sigreturn14
+// compat_20_fhstatfs
+// compat_20_fstatfs
+// compat_20_getfsstat
+// compat_20_statfs
+// compat_30___fhstat30
+// compat_30___fstat13
+// compat_30___lstat13
+// compat_30___stat13
+// compat_30_fhopen
+// compat_30_fhstat
+// compat_30_fhstatvfs1
+// compat_30_getdents
+// compat_30_getfh
+// compat_30_ntp_gettime
+// compat_30_socket
+// compat_40_mount
+// compat_43_fstat43
+// compat_43_lstat43
+// compat_43_oaccept
+// compat_43_ocreat
+// compat_43_oftruncate
+// compat_43_ogetdirentries
+// compat_43_ogetdtablesize
+// compat_43_ogethostid
+// compat_43_ogethostname
+// compat_43_ogetkerninfo
+// compat_43_ogetpagesize
+// compat_43_ogetpeername
+// compat_43_ogetrlimit
+// compat_43_ogetsockname
+// compat_43_okillpg
+// compat_43_olseek
+// compat_43_ommap
+// compat_43_oquota
+// compat_43_orecv
+// compat_43_orecvfrom
+// compat_43_orecvmsg
+// compat_43_osend
+// compat_43_osendmsg
+// compat_43_osethostid
+// compat_43_osethostname
+// compat_43_osetrlimit
+// compat_43_osigblock
+// compat_43_osigsetmask
+// compat_43_osigstack
+// compat_43_osigvec
+// compat_43_otruncate
+// compat_43_owait
+// compat_43_stat43
+// execve
+// extattr_delete_fd
+// extattr_delete_file
+// extattr_delete_link
+// extattr_get_fd
+// extattr_get_file
+// extattr_get_link
+// extattr_list_fd
+// extattr_list_file
+// extattr_list_link
+// extattr_set_fd
+// extattr_set_file
+// extattr_set_link
+// extattrctl
+// fchroot
+// fdatasync
+// fgetxattr
+// fktrace
+// flistxattr
+// fork
+// fremovexattr
+// fsetxattr
+// fstatvfs1
+// fsync_range
+// getcontext
+// getitimer
+// getvfsstat
+// getxattr
+// ioctl
+// ktrace
+// lchflags
+// lchmod
+// lfs_bmapv
+// lfs_markv
+// lfs_segclean
+// lfs_segwait
+// lgetxattr
+// lio_listio
+// listxattr
+// llistxattr
+// lremovexattr
+// lseek
+// lsetxattr
+// lutimes
+// madvise
+// mincore
+// minherit
+// mlock
+// mlockall
+// modctl
+// mprotect
+// mq_close
+// mq_getattr
+// mq_notify
+// mq_open
+// mq_receive
+// mq_send
+// mq_setattr
+// mq_timedreceive
+// mq_timedsend
+// mq_unlink
+// mremap
+// msgget
+// msgrcv
+// msgsnd
+// munlock
+// munlockall
+// nfssvc
+// ntp_adjtime
+// pmc_control
+// pmc_get_info
+// poll
+// pollts
+// preadv
+// profil
+// pselect
+// pset_assign
+// pset_create
+// pset_destroy
+// ptrace
+// pwritev
+// quotactl
+// rasctl
+// readv
+// reboot
+// removexattr
+// sa_enable
+// sa_preempt
+// sa_register
+// sa_setconcurrency
+// sa_stacks
+// sa_yield
+// sbrk
+// sched_yield
+// semconfig
+// semget
+// semop
+// setcontext
+// setitimer
+// setxattr
+// shmat
+// shmdt
+// shmget
+// sstk
+// statvfs1
+// swapctl
+// sysarch
+// syscall
+// timer_create
+// timer_delete
+// timer_getoverrun
+// timer_gettime
+// timer_settime
+// undelete
+// utrace
+// uuidgen
+// vadvise
+// vfork
+// writev
diff --git a/src/pkg/syscall/syscall_netbsd_386.go b/src/pkg/syscall/syscall_netbsd_386.go
new file mode 100644
index 000000000..3c4c693c9
--- /dev/null
+++ b/src/pkg/syscall/syscall_netbsd_386.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_netbsd_amd64.go b/src/pkg/syscall/syscall_netbsd_amd64.go
new file mode 100644
index 000000000..17485b12c
--- /dev/null
+++ b/src/pkg/syscall/syscall_netbsd_amd64.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = nsec % 1e9 / 1e3
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_openbsd.go b/src/pkg/syscall/syscall_openbsd.go
new file mode 100644
index 000000000..7cd119108
--- /dev/null
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -0,0 +1,281 @@
+// Copyright 2009,2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenBSD system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_bsd.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+type SockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+ raw RawSockaddrDatalink
+}
+
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+
+func nametomib(name string) (mib []_C_int, err error) {
+
+ // Perform lookup via a binary search
+ left := 0
+ right := len(sysctlMib) - 1
+ for {
+ idx := left + (right-left)/2
+ switch {
+ case name == sysctlMib[idx].ctlname:
+ return sysctlMib[idx].ctloid, nil
+ case name > sysctlMib[idx].ctlname:
+ left = idx + 1
+ default:
+ right = idx - 1
+ }
+ if left > right {
+ break
+ }
+ }
+ return nil, EINVAL
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ for max != 0 && len(buf) > 0 {
+ dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+ if dirent.Reclen == 0 {
+ buf = nil
+ break
+ }
+ buf = buf[dirent.Reclen:]
+ if dirent.Fileno == 0 { // File absent in directory.
+ continue
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+ var name = string(bytes[0:dirent.Namlen])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ max--
+ count++
+ names = append(names, name)
+ }
+ return origlen - len(buf), count, names
+}
+
+//sysnb pipe(p *[2]_C_int) (err error)
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+// TODO
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return -1, ENOSYS
+}
+
+/*
+ * Exposed directly
+ */
+//sys Access(path string, mode uint32) (err error)
+//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys Chdir(path string) (err error)
+//sys Chflags(path string, flags int) (err error)
+//sys Chmod(path string, mode uint32) (err error)
+//sys Chown(path string, uid int, gid int) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sysnb Dup(fd int) (nfd int, err error)
+//sysnb Dup2(from int, to int) (err error)
+//sys Exit(code int)
+//sys Fchdir(fd int) (err error)
+//sys Fchflags(path string, flags int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Flock(fd int, how int) (err error)
+//sys Fpathconf(fd int, name int) (val int, err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys Fsync(fd int) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (uid int)
+//sys Getfsstat(buf []Statfs_t, flags int) (n int, err error)
+//sysnb Getgid() (gid int)
+//sysnb Getpgid(pid int) (pgid int, err error)
+//sysnb Getpgrp() (pgrp int)
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sys Getpriority(which int, who int) (prio int, err error)
+//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
+//sysnb Getsid(pid int) (sid int, err error)
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Getuid() (uid int)
+//sys Issetugid() (tainted bool)
+//sys Kill(pid int, signum Signal) (err error)
+//sys Kqueue() (fd int, err error)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Link(path string, link string) (err error)
+//sys Listen(s int, backlog int) (err error)
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Pathconf(path string, name int) (val int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Rename(from string, to string) (err error)
+//sys Revoke(path string) (err error)
+//sys Rmdir(path string) (err error)
+//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
+//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sysnb Setegid(egid int) (err error)
+//sysnb Seteuid(euid int) (err error)
+//sysnb Setgid(gid int) (err error)
+//sys Setlogin(name string) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sys Setpriority(which int, who int, prio int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tp *Timeval) (err error)
+//sysnb Setuid(uid int) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, stat *Statfs_t) (err error)
+//sys Symlink(path string, link string) (err error)
+//sys Sync() (err error)
+//sys Truncate(path string, length int64) (err error)
+//sys Umask(newmask int) (oldmask int)
+//sys Unlink(path string) (err error)
+//sys Unmount(path string, flags int) (err error)
+//sys Write(fd int, p []byte) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys munmap(addr uintptr, length uintptr) (err error)
+//sys read(fd int, buf *byte, nbuf int) (n int, err error)
+//sys write(fd int, buf *byte, nbuf int) (n int, err error)
+
+/*
+ * Unimplemented
+ */
+// __getcwd
+// __semctl
+// __syscall
+// __sysctl
+// adjfreq
+// break
+// clock_getres
+// clock_gettime
+// clock_settime
+// closefrom
+// execve
+// faccessat
+// fchmodat
+// fchownat
+// fcntl
+// fhopen
+// fhstat
+// fhstatfs
+// fork
+// fstatat
+// futimens
+// getfh
+// getgid
+// getitimer
+// getlogin
+// getresgid
+// getresuid
+// getrtable
+// getthrid
+// ioctl
+// ktrace
+// lfs_bmapv
+// lfs_markv
+// lfs_segclean
+// lfs_segwait
+// linkat
+// mincore
+// minherit
+// mkdirat
+// mkfifoat
+// mknodat
+// mlock
+// mlockall
+// mount
+// mquery
+// msgctl
+// msgget
+// msgrcv
+// msgsnd
+// munlock
+// munlockall
+// nfssvc
+// nnpfspioctl
+// openat
+// poll
+// preadv
+// profil
+// pwritev
+// quotactl
+// readlinkat
+// readv
+// reboot
+// renameat
+// rfork
+// sched_yield
+// semget
+// semop
+// setgroups
+// setitimer
+// setresgid
+// setresuid
+// setrtable
+// setsockopt
+// shmat
+// shmctl
+// shmdt
+// shmget
+// sigaction
+// sigaltstack
+// sigpending
+// sigprocmask
+// sigreturn
+// sigsuspend
+// symlinkat
+// sysarch
+// syscall
+// threxit
+// thrsigdivert
+// thrsleep
+// thrwakeup
+// unlinkat
+// utimensat
+// vfork
+// writev
diff --git a/src/pkg/syscall/syscall_openbsd_386.go b/src/pkg/syscall/syscall_openbsd_386.go
new file mode 100644
index 000000000..3c4c693c9
--- /dev/null
+++ b/src/pkg/syscall/syscall_openbsd_386.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = int32(nsec % 1e9)
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_openbsd_amd64.go b/src/pkg/syscall/syscall_openbsd_amd64.go
new file mode 100644
index 000000000..c356ad4fa
--- /dev/null
+++ b/src/pkg/syscall/syscall_openbsd_amd64.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = int32(nsec / 1e9)
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = nsec % 1e9 / 1e3
+ tv.Sec = int64(nsec / 1e9)
+ return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint32(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index eacdd93c9..122a96f26 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -13,22 +13,15 @@ package syscall
import "unsafe"
-const OS = "plan9"
-
const ImplementsGetwd = true
-// An Error can represent any printable error condition.
-type Error interface {
- String() string
-}
-
// ErrorString implements Error's String method by returning itself.
type ErrorString string
-func (e ErrorString) String() string { return string(e) }
+func (e ErrorString) Error() string { return string(e) }
// NewError converts s to an ErrorString, which satisfies the Error interface.
-func NewError(s string) Error { return ErrorString(s) }
+func NewError(s string) error { return ErrorString(s) }
var (
Stdin = 0
@@ -43,8 +36,8 @@ var (
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
-func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
-func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
@@ -94,7 +87,7 @@ func Exit(code int) {
Exits(&msg)
}
-func readnum(path string) (uint, Error) {
+func readnum(path string) (uint, error) {
var b [12]byte
fd, e := Open(path, O_RDONLY)
@@ -126,15 +119,15 @@ func Getppid() (ppid int) {
return int(n)
}
-func Read(fd int, p []byte) (n int, err Error) {
+func Read(fd int, p []byte) (n int, err error) {
return Pread(fd, p, -1)
}
-func Write(fd int, p []byte) (n int, err Error) {
+func Write(fd int, p []byte) (n int, err error) {
return Pwrite(fd, p, -1)
}
-func Getwd() (wd string, err Error) {
+func Getwd() (wd string, err error) {
fd, e := Open(".", O_RDONLY)
if e != nil {
@@ -145,8 +138,8 @@ func Getwd() (wd string, err Error) {
return Fd2path(fd)
}
-//sys fd2path(fd int, buf []byte) (err Error)
-func Fd2path(fd int) (path string, err Error) {
+//sys fd2path(fd int, buf []byte) (err error)
+func Fd2path(fd int) (path string, err error) {
var buf [512]byte
e := fd2path(fd, buf[:])
@@ -156,8 +149,8 @@ func Fd2path(fd int) (path string, err Error) {
return cstring(buf[:]), nil
}
-//sys pipe(p *[2]_C_int) (err Error)
-func Pipe(p []int) (err Error) {
+//sys pipe(p *[2]_C_int) (err error)
+func Pipe(p []int) (err error) {
if len(p) != 2 {
return NewError("bad arg in system call")
}
@@ -168,26 +161,20 @@ func Pipe(p []int) (err Error) {
return
}
-//sys sleep(millisecs int32) (err Error)
-func Sleep(nsec int64) (err Error) {
- return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
-}
-
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-func Seek(fd int, offset int64, whence int) (newoffset int64, err Error) {
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
newoffset, e := seek(0, fd, offset, whence)
- err = nil
if newoffset == -1 {
err = NewError(e)
}
return
}
-func Mkdir(path string, mode uint32) (err Error) {
+func Mkdir(path string, mode uint32) (err error) {
fd, err := Create(path, O_RDONLY, DMDIR|mode)
if fd != -1 {
@@ -214,8 +201,8 @@ func (w Waitmsg) ExitStatus() int {
return 1
}
-//sys await(s []byte) (n int, err Error)
-func Await(w *Waitmsg) (err Error) {
+//sys await(s []byte) (n int, err error)
+func Await(w *Waitmsg) (err error) {
var buf [512]byte
var f [5][]byte
@@ -245,14 +232,18 @@ func Await(w *Waitmsg) (err Error) {
w.Time[1] = uint32(atoi(f[2]))
w.Time[2] = uint32(atoi(f[3]))
w.Msg = cstring(f[4])
+ if w.Msg == "''" {
+ // await() returns '' for no error
+ w.Msg = ""
+ }
return
}
-func Unmount(name, old string) (err Error) {
+func Unmount(name, old string) (err error) {
oldp := uintptr(unsafe.Pointer(StringBytePtr(old)))
var r0 uintptr
- var e string
+ var e ErrorString
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
if name == "" {
@@ -261,14 +252,13 @@ func Unmount(name, old string) (err Error) {
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0)
}
- err = nil
if int(r0) == -1 {
- err = NewError(e)
+ err = e
}
return
}
-func Fchdir(fd int) (err Error) {
+func Fchdir(fd int) (err error) {
path, err := Fd2path(fd)
if err != nil {
@@ -278,6 +268,11 @@ func Fchdir(fd int) (err Error) {
return Chdir(path)
}
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
type Timeval struct {
Sec int32
Usec int32
@@ -290,11 +285,10 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-func DecodeBintime(b []byte) (nsec int64, err Error) {
+func DecodeBintime(b []byte) (nsec int64, err error) {
if len(b) != 8 {
return -1, NewError("bad /dev/bintime format")
}
- err = nil
nsec = int64(b[0])<<56 |
int64(b[1])<<48 |
int64(b[2])<<40 |
@@ -306,7 +300,7 @@ func DecodeBintime(b []byte) (nsec int64, err Error) {
return
}
-func Gettimeofday(tv *Timeval) (err Error) {
+func Gettimeofday(tv *Timeval) (err error) {
// TODO(paulzhol):
// avoid reopening a file descriptor for /dev/bintime on each call,
// use lower-level calls to avoid allocation.
@@ -337,21 +331,29 @@ func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
func Getuid() (uid int) { return -1 }
-func Getgroups() (gids []int, err Error) {
+func Getgroups() (gids []int, err error) {
return make([]int, 0), nil
}
-//sys Dup(oldfd int, newfd int) (fd int, err Error)
-//sys Open(path string, mode int) (fd int, err Error)
-//sys Create(path string, mode int, perm uint32) (fd int, err Error)
-//sys Remove(path string) (err Error)
-//sys Pread(fd int, p []byte, offset int64) (n int, err Error)
-//sys Pwrite(fd int, p []byte, offset int64) (n int, err Error)
-//sys Close(fd int) (err Error)
-//sys Chdir(path string) (err Error)
-//sys Bind(name string, old string, flag int) (err Error)
-//sys Mount(fd int, afd int, old string, flag int, aname string) (err Error)
-//sys Stat(path string, edir []byte) (n int, err Error)
-//sys Fstat(fd int, edir []byte) (n int, err Error)
-//sys Wstat(path string, edir []byte) (err Error)
-//sys Fwstat(fd int, edir []byte) (err Error)
+type Signal int
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ return ""
+}
+
+//sys Dup(oldfd int, newfd int) (fd int, err error)
+//sys Open(path string, mode int) (fd int, err error)
+//sys Create(path string, mode int, perm uint32) (fd int, err error)
+//sys Remove(path string) (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Close(fd int) (err error)
+//sys Chdir(path string) (err error)
+//sys Bind(name string, old string, flag int) (err error)
+//sys Mount(fd int, afd int, old string, flag int, aname string) (err error)
+//sys Stat(path string, edir []byte) (n int, err error)
+//sys Fstat(fd int, edir []byte) (n int, err error)
+//sys Wstat(path string, edir []byte) (err error)
+//sys Fwstat(fd int, edir []byte) (err error)
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index c298b91b4..d4e02f68a 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build darwin freebsd linux netbsd openbsd
+
package syscall
import (
+ "runtime"
"sync"
"unsafe"
)
@@ -15,37 +18,30 @@ var (
Stderr = 2
)
-const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
-
-func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
-func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
-func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
-func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+const darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64"
-func Errstr(errno int) string {
- if errno < 0 || errno >= int(len(errors)) {
- return "error " + itoa(errno)
- }
- return errors[errno]
-}
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
// Mmap manager, for use by operating system-specific implementations.
type mmapper struct {
sync.Mutex
active map[*byte][]byte // active mappings; key is last byte in mapping
- mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
- munmap func(addr uintptr, length uintptr) int
+ mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
+ munmap func(addr uintptr, length uintptr) error
}
-func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
if length <= 0 {
return nil, EINVAL
}
// Map the requested memory.
addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
- if errno != 0 {
+ if errno != nil {
return nil, errno
}
@@ -64,10 +60,10 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
m.Lock()
defer m.Unlock()
m.active[p] = b
- return b, 0
+ return b, nil
}
-func (m *mmapper) Munmap(data []byte) (errno int) {
+func (m *mmapper) Munmap(data []byte) (err error) {
if len(data) == 0 || len(data) != cap(data) {
return EINVAL
}
@@ -82,9 +78,52 @@ func (m *mmapper) Munmap(data []byte) (errno int) {
}
// Unmap the memory and update m.
- if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
+ if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
return errno
}
- m.active[p] = nil, false
- return 0
+ delete(m.active, p)
+ return nil
+}
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface. The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+// err = nil
+// if errno != 0 {
+// err = errno
+// }
+type Errno uintptr
+
+func (e Errno) Error() string {
+ if 0 <= int(e) && int(e) < len(errors) {
+ s := errors[e]
+ if s != "" {
+ return s
+ }
+ }
+ return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+ return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ if 0 <= s && int(s) < len(signals) {
+ str := signals[s]
+ if str != "" {
+ return str
+ }
+ }
+ return "signal " + itoa(int(s))
}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 19c6587f5..47209da8f 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -7,13 +7,10 @@
package syscall
import (
- "sync"
+ "unicode/utf16"
"unsafe"
- "utf16"
)
-const OS = "windows"
-
type Handle uintptr
const InvalidHandle = ^Handle(0)
@@ -28,8 +25,8 @@ import (
"syscall"
)
-func abort(funcname string, err int) {
- panic(funcname + " failed: " + syscall.Errstr(err))
+func abort(funcname string, err error) {
+ panic(funcname + " failed: " + err.Error())
}
func print_version(v uint32) {
@@ -41,12 +38,12 @@ func print_version(v uint32) {
func main() {
h, err := syscall.LoadLibrary("kernel32.dll")
- if err != 0 {
+ if err != nil {
abort("LoadLibrary", err)
}
defer syscall.FreeLibrary(h)
proc, err := syscall.GetProcAddress(h, "GetVersion")
- if err != 0 {
+ if err != nil {
abort("GetProcAddress", err)
}
r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
@@ -57,7 +54,7 @@ func main() {
// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
// with a terminating NUL added.
-func StringToUTF16(s string) []uint16 { return utf16.Encode([]int(s + "\x00")) }
+func StringToUTF16(s string) []uint16 { return utf16.Encode([]rune(s + "\x00")) }
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed.
@@ -75,77 +72,39 @@ func UTF16ToString(s []uint16) string {
// the UTF-8 string s, with a terminating NUL added.
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
-// dll helpers
+func Getpagesize() int { return 4096 }
-// Implemented in ../runtime/windows/syscall.goc
-func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr)
-func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
-func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr)
-func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr)
-func loadlibraryex(filename uintptr) (handle uintptr)
-func getprocaddress(handle uintptr, procname uintptr) (proc uintptr)
-
-// A LazyDLL implements access to a single DLL.
-// It will delay the load of the DLL until the first
-// call to its Handle method or to one of its
-// LazyProc's Addr method.
-type LazyDLL struct {
- mu sync.Mutex
- Name string
- h uintptr // module handle once dll is loaded
-}
-
-// Handle returns d's module handle.
-func (d *LazyDLL) Handle() uintptr {
- if d.h == 0 {
- d.mu.Lock()
- defer d.mu.Unlock()
- if d.h == 0 {
- d.h = loadlibraryex(uintptr(unsafe.Pointer(StringBytePtr(d.Name))))
- if d.h == 0 {
- panic("syscall: could not LoadLibraryEx " + d.Name)
- }
- }
- }
- return d.h
-}
+// Errno is the Windows error number.
+type Errno uintptr
-// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
-func (d *LazyDLL) NewProc(name string) *LazyProc {
- return &LazyProc{dll: d, Name: name}
-}
+func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) }
-// NewLazyDLL creates new LazyDLL associated with dll file.
-func NewLazyDLL(name string) *LazyDLL {
- return &LazyDLL{Name: name}
+func (e Errno) Error() string {
+ // deal with special go errors
+ idx := int(e - APPLICATION_ERROR)
+ if 0 <= idx && idx < len(errors) {
+ return errors[idx]
+ }
+ // ask windows for the remaining errors
+ var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
+ b := make([]uint16, 300)
+ n, err := FormatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
+ if err != nil {
+ return "error " + itoa(int(e)) + " (FormatMessage failed with err=" + itoa(int(err.(Errno))) + ")"
+ }
+ // trim terminating \r and \n
+ for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
+ }
+ return string(utf16.Decode(b[:n]))
}
-// A LazyProc implements access to a procedure inside a LazyDLL.
-// It delays the lookup until the Addr method is called.
-type LazyProc struct {
- mu sync.Mutex
- Name string
- dll *LazyDLL
- addr uintptr
-}
-
-// Addr returns the address of the procedure represented by s.
-// The return value can be passed to Syscall to run the procedure.
-func (s *LazyProc) Addr() uintptr {
- if s.addr == 0 {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.addr == 0 {
- s.addr = getprocaddress(s.dll.Handle(), uintptr(unsafe.Pointer(StringBytePtr(s.Name))))
- if s.addr == 0 {
- panic("syscall: could not GetProcAddress for " + s.Name)
- }
- }
- }
- return s.addr
+func (e Errno) Temporary() bool {
+ return e == EINTR || e == EMFILE || e.Timeout()
}
-func Getpagesize() int { return 4096 }
+func (e Errno) Timeout() bool {
+ return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
// Converts a Go function to a function pointer conforming
// to the stdcall calling convention. This is useful when
@@ -155,93 +114,94 @@ func NewCallback(fn interface{}) uintptr
// windows api calls
-//sys GetLastError() (lasterrno int)
-//sys LoadLibrary(libname string) (handle Handle, errno int) = LoadLibraryW
-//sys FreeLibrary(handle Handle) (errno int)
-//sys GetProcAddress(module Handle, procname string) (proc Handle, errno int)
-//sys GetVersion() (ver uint32, errno int)
-//sys FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) = FormatMessageW
+//sys GetLastError() (lasterr error)
+//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
+//sys FreeLibrary(handle Handle) (err error)
+//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
+//sys GetVersion() (ver uint32, err error)
+//sys FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32)
-//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) [failretval==InvalidHandle] = CreateFileW
-//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
-//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int)
-//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
-//sys CloseHandle(handle Handle) (errno int)
-//sys GetStdHandle(stdhandle int) (handle Handle, errno int) [failretval==InvalidHandle]
-//sys FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) [failretval==InvalidHandle] = FindFirstFileW
-//sys FindNextFile(handle Handle, data *Win32finddata) (errno int) = FindNextFileW
-//sys FindClose(handle Handle) (errno int)
-//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int)
-//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) = GetCurrentDirectoryW
-//sys SetCurrentDirectory(path *uint16) (errno int) = SetCurrentDirectoryW
-//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) = CreateDirectoryW
-//sys RemoveDirectory(path *uint16) (errno int) = RemoveDirectoryW
-//sys DeleteFile(path *uint16) (errno int) = DeleteFileW
-//sys MoveFile(from *uint16, to *uint16) (errno int) = MoveFileW
-//sys GetComputerName(buf *uint16, n *uint32) (errno int) = GetComputerNameW
-//sys SetEndOfFile(handle Handle) (errno int)
+//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
+//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
+//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
+//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
+//sys CloseHandle(handle Handle) (err error)
+//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle]
+//sys FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW
+//sys FindNextFile(handle Handle, data *Win32finddata) (err error) = FindNextFileW
+//sys FindClose(handle Handle) (err error)
+//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
+//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
+//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
+//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
+//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW
+//sys DeleteFile(path *uint16) (err error) = DeleteFileW
+//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
+//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
+//sys SetEndOfFile(handle Handle) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime)
-//sys sleep(msec uint32) = Sleep
-//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff]
-//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int)
-//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int)
-//sys CancelIo(s Handle) (errno int)
-//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW
-//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int)
-//sys TerminateProcess(handle Handle, exitcode uint32) (errno int)
-//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int)
-//sys GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW
-//sys GetCurrentProcess() (pseudoHandle Handle, errno int)
-//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int)
-//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
-//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
-//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int)
-//sys GetFileType(filehandle Handle) (n uint32, errno int)
-//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) = advapi32.CryptAcquireContextW
-//sys CryptReleaseContext(provhandle Handle, flags uint32) (errno int) = advapi32.CryptReleaseContext
-//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) = advapi32.CryptGenRandom
-//sys GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
-//sys FreeEnvironmentStrings(envs *uint16) (errno int) = kernel32.FreeEnvironmentStringsW
-//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
-//sys SetEnvironmentVariable(name *uint16, value *uint16) (errno int) = kernel32.SetEnvironmentVariableW
-//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int)
-//sys GetFileAttributes(name *uint16) (attrs uint32, errno int) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
-//sys SetFileAttributes(name *uint16, attrs uint32) (errno int) = kernel32.SetFileAttributesW
+//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
+//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
+//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
+//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
+//sys CancelIo(s Handle) (err error)
+//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
+//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
+//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
+//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
+//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
+//sys GetCurrentProcess() (pseudoHandle Handle, err error)
+//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
+//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
+//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
+//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
+//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
+//sys GetFileType(filehandle Handle) (n uint32, err error)
+//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
+//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
+//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
+//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
+//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
+//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
+//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
+//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
+//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
+//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
+//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
-//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) [failretval==nil] = shell32.CommandLineToArgvW
-//sys LocalFree(hmem Handle) (handle Handle, errno int) [failretval!=0]
-//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int)
-//sys FlushFileBuffers(handle Handle) (errno int)
-//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) = kernel32.GetFullPathNameW
-//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) = kernel32.CreateFileMappingW
-//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int)
-//sys UnmapViewOfFile(addr uintptr) (errno int)
-//sys FlushViewOfFile(addr uintptr, length uintptr) (errno int)
-//sys VirtualLock(addr uintptr, length uintptr) (errno int)
-//sys VirtualUnlock(addr uintptr, length uintptr) (errno int)
-//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile
+//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
+//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
+//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
+//sys FlushFileBuffers(handle Handle) (err error)
+//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
+//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
+//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
+//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
+//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
+//sys UnmapViewOfFile(addr uintptr) (err error)
+//sys FlushViewOfFile(addr uintptr, length uintptr) (err error)
+//sys VirtualLock(addr uintptr, length uintptr) (err error)
+//sys VirtualUnlock(addr uintptr, length uintptr) (err error)
+//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
+//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
+//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
+//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
+//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
+//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
+//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
+//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
+//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
+//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
+//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
+//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
+//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
+//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
+//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
+//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
+//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
// syscall interface implementation for other packages
-func Errstr(errno int) string {
- // deal with special go errors
- e := errno - APPLICATION_ERROR
- if 0 <= e && e < len(errors) {
- return errors[e]
- }
- // ask windows for the remaining errors
- var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
- b := make([]uint16, 300)
- n, err := FormatMessage(flags, 0, uint32(errno), 0, b, nil)
- if err != 0 {
- return "error " + itoa(errno) + " (FormatMessage failed with err=" + itoa(err) + ")"
- }
- // trim terminating \r and \n
- for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
- }
- return string(utf16.Decode(b[:n]))
-}
-
func Exit(code int) { ExitProcess(uint32(code)) }
func makeInheritSa() *SecurityAttributes {
@@ -251,7 +211,7 @@ func makeInheritSa() *SecurityAttributes {
return &sa
}
-func Open(path string, mode int, perm uint32) (fd Handle, errno int) {
+func Open(path string, mode int, perm uint32) (fd Handle, err error) {
if len(path) == 0 {
return InvalidHandle, ERROR_FILE_NOT_FOUND
}
@@ -290,32 +250,32 @@ func Open(path string, mode int, perm uint32) (fd Handle, errno int) {
createmode = OPEN_EXISTING
}
h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
- return h, int(e)
+ return h, e
}
-func Read(fd Handle, p []byte) (n int, errno int) {
+func Read(fd Handle, p []byte) (n int, err error) {
var done uint32
e := ReadFile(fd, p, &done, nil)
- if e != 0 {
+ if e != nil {
if e == ERROR_BROKEN_PIPE {
// NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
- return 0, 0
+ return 0, nil
}
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
-func Write(fd Handle, p []byte) (n int, errno int) {
+func Write(fd Handle, p []byte) (n int, err error) {
var done uint32
e := WriteFile(fd, p, &done, nil)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int(done), 0
+ return int(done), nil
}
-func Seek(fd Handle, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
var w uint32
switch whence {
case 0:
@@ -333,13 +293,13 @@ func Seek(fd Handle, offset int64, whence int) (newoffset int64, errno int) {
return 0, EPIPE
}
rlo, e := SetFilePointer(fd, lo, &hi, w)
- if e != 0 {
+ if e != nil {
return 0, e
}
- return int64(hi)<<32 + int64(rlo), 0
+ return int64(hi)<<32 + int64(rlo), nil
}
-func Close(fd Handle) (errno int) {
+func Close(fd Handle) (err error) {
return CloseHandle(fd)
}
@@ -351,136 +311,99 @@ var (
func getStdHandle(h int) (fd Handle) {
r, _ := GetStdHandle(h)
+ CloseOnExec(r)
return r
}
-func Stat(path string, stat *Stat_t) (errno int) {
- if len(path) == 0 {
- return ERROR_PATH_NOT_FOUND
- }
- // Remove trailing slash.
- if path[len(path)-1] == '/' || path[len(path)-1] == '\\' {
- // Check if we're given root directory ("\" or "c:\").
- if len(path) == 1 || (len(path) == 3 && path[1] == ':') {
- // TODO(brainman): Perhaps should fetch other fields, not just FileAttributes.
- stat.Windata = Win32finddata{}
- a, e := GetFileAttributes(StringToUTF16Ptr(path))
- if e != 0 {
- return e
- }
- stat.Windata.FileAttributes = a
- return 0
- }
- path = path[:len(path)-1]
- }
- h, e := FindFirstFile(StringToUTF16Ptr(path), &stat.Windata)
- if e != 0 {
- return e
- }
- defer FindClose(h)
- stat.Mode = 0
- return 0
-}
-
-func Lstat(path string, stat *Stat_t) (errno int) {
- // no links on windows, just call Stat
- return Stat(path, stat)
-}
-
const ImplementsGetwd = true
-func Getwd() (wd string, errno int) {
+func Getwd() (wd string, err error) {
b := make([]uint16, 300)
n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
- if e != 0 {
+ if e != nil {
return "", e
}
- return string(utf16.Decode(b[0:n])), 0
+ return string(utf16.Decode(b[0:n])), nil
}
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
return SetCurrentDirectory(&StringToUTF16(path)[0])
}
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
return CreateDirectory(&StringToUTF16(path)[0], nil)
}
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
return RemoveDirectory(&StringToUTF16(path)[0])
}
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
return DeleteFile(&StringToUTF16(path)[0])
}
-func Rename(oldpath, newpath string) (errno int) {
+func Rename(oldpath, newpath string) (err error) {
from := &StringToUTF16(oldpath)[0]
to := &StringToUTF16(newpath)[0]
return MoveFile(from, to)
}
-func ComputerName() (name string, errno int) {
+func ComputerName() (name string, err error) {
var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
b := make([]uint16, n)
e := GetComputerName(&b[0], &n)
- if e != 0 {
+ if e != nil {
return "", e
}
- return string(utf16.Decode(b[0:n])), 0
+ return string(utf16.Decode(b[0:n])), nil
}
-func Ftruncate(fd Handle, length int64) (errno int) {
+func Ftruncate(fd Handle, length int64) (err error) {
curoffset, e := Seek(fd, 0, 1)
- if e != 0 {
+ if e != nil {
return e
}
defer Seek(fd, curoffset, 0)
_, e = Seek(fd, length, 0)
- if e != 0 {
+ if e != nil {
return e
}
e = SetEndOfFile(fd)
- if e != 0 {
+ if e != nil {
return e
}
- return 0
+ return nil
}
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
var ft Filetime
GetSystemTimeAsFileTime(&ft)
*tv = NsecToTimeval(ft.Nanoseconds())
- return 0
+ return nil
}
-func Sleep(nsec int64) (errno int) {
- sleep(uint32((nsec + 1e6 - 1) / 1e6)) // round up to milliseconds
- return 0
-}
-
-func Pipe(p []Handle) (errno int) {
+func Pipe(p []Handle) (err error) {
if len(p) != 2 {
return EINVAL
}
var r, w Handle
e := CreatePipe(&r, &w, makeInheritSa(), 0)
- if e != 0 {
+ if e != nil {
return e
}
p[0] = r
p[1] = w
- return 0
+ return nil
}
-func Utimes(path string, tv []Timeval) (errno int) {
+func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
h, e := CreateFile(StringToUTF16Ptr(path),
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
- if e != 0 {
+ if e != nil {
return e
}
defer Close(h)
@@ -489,17 +412,17 @@ func Utimes(path string, tv []Timeval) (errno int) {
return SetFileTime(h, nil, &a, &w)
}
-func Fsync(fd Handle) (errno int) {
+func Fsync(fd Handle) (err error) {
return FlushFileBuffers(fd)
}
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
if mode == 0 {
return EINVAL
}
p := StringToUTF16Ptr(path)
attrs, e := GetFileAttributes(p)
- if e != 0 {
+ if e != nil {
return e
}
if mode&S_IWRITE != 0 {
@@ -512,31 +435,32 @@ func Chmod(path string, mode uint32) (errno int) {
// net api calls
-//sys WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
-//sys WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
-//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
-//sys socket(af int32, typ int32, protocol int32) (handle Handle, errno int) [failretval==InvalidHandle] = wsock32.socket
-//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
-//sys bind(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
-//sys connect(s Handle, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
-//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
-//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getpeername
-//sys listen(s Handle, backlog int32) (errno int) [failretval==-1] = wsock32.listen
-//sys shutdown(s Handle, how int32) (errno int) [failretval==-1] = wsock32.shutdown
-//sys Closesocket(s Handle) (errno int) [failretval==-1] = wsock32.closesocket
-//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) = wsock32.AcceptEx
-//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = wsock32.GetAcceptExSockaddrs
-//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
-//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
-//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecvFrom
-//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASendTo
-//sys GetHostByName(name string) (h *Hostent, errno int) [failretval==nil] = ws2_32.gethostbyname
-//sys GetServByName(name string, proto string) (s *Servent, errno int) [failretval==nil] = ws2_32.getservbyname
+//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
+//sys WSACleanup() (err error) [failretval==-1] = ws2_32.WSACleanup
+//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==-1] = ws2_32.WSAIoctl
+//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
+//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==-1] = ws2_32.setsockopt
+//sys bind(s Handle, name uintptr, namelen int32) (err error) [failretval==-1] = ws2_32.bind
+//sys connect(s Handle, name uintptr, namelen int32) (err error) [failretval==-1] = ws2_32.connect
+//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==-1] = ws2_32.getsockname
+//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==-1] = ws2_32.getpeername
+//sys listen(s Handle, backlog int32) (err error) [failretval==-1] = ws2_32.listen
+//sys shutdown(s Handle, how int32) (err error) [failretval==-1] = ws2_32.shutdown
+//sys Closesocket(s Handle) (err error) [failretval==-1] = ws2_32.closesocket
+//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
+//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
+//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSARecv
+//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSASend
+//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSARecvFrom
+//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSASendTo
+//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
+//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
-//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
+//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
+//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
-//sys GetIfEntry(pIfRow *MibIfRow) (errcode int) = iphlpapi.GetIfEntry
-//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) = iphlpapi.GetAdaptersInfo
+//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
+//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
@@ -560,7 +484,7 @@ type RawSockaddrAny struct {
}
type Sockaddr interface {
- sockaddr() (ptr uintptr, len int32, errno int) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr uintptr, len int32, err error) // lowercase; only we can define Sockaddrs
}
type SockaddrInet4 struct {
@@ -569,7 +493,7 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (uintptr, int32, int) {
+func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return 0, 0, EINVAL
}
@@ -580,7 +504,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, int32, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), 0
+ return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
}
type SockaddrInet6 struct {
@@ -589,7 +513,7 @@ type SockaddrInet6 struct {
Addr [16]byte
}
-func (sa *SockaddrInet6) sockaddr() (uintptr, int32, int) {
+func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
// TODO(brainman): implement SockaddrInet6.sockaddr()
return 0, 0, EWINDOWS
}
@@ -598,12 +522,12 @@ type SockaddrUnix struct {
Name string
}
-func (sa *SockaddrUnix) sockaddr() (uintptr, int32, int) {
+func (sa *SockaddrUnix) sockaddr() (uintptr, int32, error) {
// TODO(brainman): implement SockaddrUnix.sockaddr()
return 0, 0, EWINDOWS
}
-func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
+func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
return nil, EWINDOWS
@@ -616,7 +540,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
case AF_INET6:
return nil, EWINDOWS
@@ -624,75 +548,77 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
return nil, EAFNOSUPPORT
}
-func Socket(domain, typ, proto int) (fd Handle, errno int) {
+func Socket(domain, typ, proto int) (fd Handle, err error) {
if domain == AF_INET6 && SocketDisableIPv6 {
return InvalidHandle, EAFNOSUPPORT
}
- h, e := socket(int32(domain), int32(typ), int32(proto))
- return h, int(e)
+ return socket(int32(domain), int32(typ), int32(proto))
}
-func SetsockoptInt(fd Handle, level, opt int, value int) (errno int) {
+func SetsockoptInt(fd Handle, level, opt int, value int) (err error) {
v := int32(value)
- return int(Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v)))
}
-func Bind(fd Handle, sa Sockaddr) (errno int) {
+func Bind(fd Handle, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return bind(fd, ptr, n)
}
-func Connect(fd Handle, sa Sockaddr) (errno int) {
+func Connect(fd Handle, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return connect(fd, ptr, n)
}
-func Getsockname(fd Handle) (sa Sockaddr, errno int) {
+func Getsockname(fd Handle) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
l := int32(unsafe.Sizeof(rsa))
- if errno = getsockname(fd, &rsa, &l); errno != 0 {
+ if err = getsockname(fd, &rsa, &l); err != nil {
return
}
return rsa.Sockaddr()
}
-func Getpeername(fd Handle) (sa Sockaddr, errno int) {
+func Getpeername(fd Handle) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
l := int32(unsafe.Sizeof(rsa))
- if errno = getpeername(fd, &rsa, &l); errno != 0 {
+ if err = getpeername(fd, &rsa, &l); err != nil {
return
}
return rsa.Sockaddr()
}
-func Listen(s Handle, n int) (errno int) {
- return int(listen(s, int32(n)))
+func Listen(s Handle, n int) (err error) {
+ return listen(s, int32(n))
}
-func Shutdown(fd Handle, how int) (errno int) {
- return int(shutdown(fd, int32(how)))
+func Shutdown(fd Handle, how int) (err error) {
+ return shutdown(fd, int32(how))
}
-func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) {
rsa, l, err := to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
- errno = WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
- return
+ return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
}
// Invented structures to support what package os expects.
-type Rusage struct{}
+type Rusage struct {
+ CreationTime Filetime
+ ExitTime Filetime
+ KernelTime Filetime
+ UserTime Filetime
+}
type WaitStatus struct {
- Status uint32
ExitCode uint32
}
@@ -700,7 +626,7 @@ func (w WaitStatus) Exited() bool { return true }
func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
-func (w WaitStatus) Signal() int { return -1 }
+func (w WaitStatus) Signal() Signal { return -1 }
func (w WaitStatus) CoreDump() bool { return false }
@@ -708,31 +634,33 @@ func (w WaitStatus) Stopped() bool { return false }
func (w WaitStatus) Continued() bool { return false }
-func (w WaitStatus) StopSignal() int { return -1 }
+func (w WaitStatus) StopSignal() Signal { return -1 }
func (w WaitStatus) Signaled() bool { return false }
func (w WaitStatus) TrapCause() int { return -1 }
+// Timespec is an invented structure on Windows, but here for
+// consistency with the syscall package for other operating systems.
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
// TODO(brainman): fix all needed for net
-func Accept(fd Handle) (nfd Handle, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
-func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, errno int) {
+func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, EWINDOWS }
+func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
return 0, nil, EWINDOWS
}
-func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (errno int) { return EWINDOWS }
-func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (errno int) { return EWINDOWS }
+func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return EWINDOWS }
+func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return EWINDOWS }
type Linger struct {
Onoff int32
Linger int32
}
-const (
- IP_ADD_MEMBERSHIP = iota
- IP_DROP_MEMBERSHIP
-)
-
type IPMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
@@ -743,28 +671,47 @@ type IPv6Mreq struct {
Interface uint32
}
-func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (errno int) { return EWINDOWS }
-func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (errno int) { return EWINDOWS }
-func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (errno int) { return EWINDOWS }
-func BindToDevice(fd Handle, device string) (errno int) { return EWINDOWS }
+func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS }
+func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { return EWINDOWS }
+func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
+}
+func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
+}
+func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) { return EWINDOWS }
// TODO(brainman): fix all needed for os
func Getpid() (pid int) { return -1 }
func Getppid() (ppid int) { return -1 }
-func Fchdir(fd Handle) (errno int) { return EWINDOWS }
-func Link(oldpath, newpath string) (errno int) { return EWINDOWS }
-func Symlink(path, link string) (errno int) { return EWINDOWS }
-func Readlink(path string, buf []byte) (n int, errno int) { return 0, EWINDOWS }
+func Fchdir(fd Handle) (err error) { return EWINDOWS }
+func Link(oldpath, newpath string) (err error) { return EWINDOWS }
+func Symlink(path, link string) (err error) { return EWINDOWS }
+func Readlink(path string, buf []byte) (n int, err error) { return 0, EWINDOWS }
-func Fchmod(fd Handle, mode uint32) (errno int) { return EWINDOWS }
-func Chown(path string, uid int, gid int) (errno int) { return EWINDOWS }
-func Lchown(path string, uid int, gid int) (errno int) { return EWINDOWS }
-func Fchown(fd Handle, uid int, gid int) (errno int) { return EWINDOWS }
+func Fchmod(fd Handle, mode uint32) (err error) { return EWINDOWS }
+func Chown(path string, uid int, gid int) (err error) { return EWINDOWS }
+func Lchown(path string, uid int, gid int) (err error) { return EWINDOWS }
+func Fchown(fd Handle, uid int, gid int) (err error) { return EWINDOWS }
func Getuid() (uid int) { return -1 }
func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
func Getegid() (egid int) { return -1 }
-func Getgroups() (gids []int, errno int) { return nil, EWINDOWS }
+func Getgroups() (gids []int, err error) { return nil, EWINDOWS }
+
+type Signal int
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ if 0 <= s && int(s) < len(signals) {
+ str := signals[s]
+ if str != "" {
+ return str
+ }
+ }
+ return "signal " + itoa(int(s))
+}
diff --git a/src/pkg/syscall/types_darwin.c b/src/pkg/syscall/types_darwin.c
deleted file mode 100644
index 730d7f7b6..000000000
--- a/src/pkg/syscall/types_darwin.c
+++ /dev/null
@@ -1,180 +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.
-
-/*
-Input to godefs. See also mkerrors.sh and mkall.sh
- */
-
-#define __DARWIN_UNIX03 0
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
-#include <dirent.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <unistd.h>
-#include <mach/mach.h>
-#include <mach/message.h>
-#include <sys/event.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/ptrace.h>
-#include <sys/resource.h>
-#include <sys/select.h>
-#include <sys/signal.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/wait.h>
-#include <net/bpf.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_var.h>
-#include <net/route.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-// Machine characteristics; for internal use.
-
-enum {
- $sizeofPtr = sizeof(void*),
- $sizeofShort = sizeof(short),
- $sizeofInt = sizeof(int),
- $sizeofLong = sizeof(long),
- $sizeofLongLong = sizeof(long long),
-};
-
-// Basic types
-
-typedef short $_C_short;
-typedef int $_C_int;
-typedef long $_C_long;
-typedef long long $_C_long_long;
-
-// Time
-
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-typedef struct timeval32 $Timeval32;
-
-// Processes
-
-typedef struct rusage $Rusage;
-typedef struct rlimit $Rlimit;
-
-typedef gid_t $_Gid_t;
-
-// Files
-
-enum {
- $O_CLOEXEC = 0, // not supported
-};
-
-typedef struct stat64 $Stat_t;
-typedef struct statfs64 $Statfs_t;
-typedef struct flock $Flock_t;
-typedef struct fstore $Fstore_t;
-typedef struct radvisory $Radvisory_t;
-typedef struct fbootstraptransfer $Fbootstraptransfer_t;
-typedef struct log2phys $Log2phys_t;
-
-typedef struct dirent $Dirent;
-
-// Sockets
-
-union sockaddr_all {
- struct sockaddr s1; // this one gets used for fields
- struct sockaddr_in s2; // these pad it out
- struct sockaddr_in6 s3;
- struct sockaddr_un s4;
- struct sockaddr_dl s5;
-};
-
-struct sockaddr_any {
- struct sockaddr addr;
- char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
-};
-
-typedef struct sockaddr_in $RawSockaddrInet4;
-typedef struct sockaddr_in6 $RawSockaddrInet6;
-typedef struct sockaddr_un $RawSockaddrUnix;
-typedef struct sockaddr_dl $RawSockaddrDatalink;
-typedef struct sockaddr $RawSockaddr;
-typedef struct sockaddr_any $RawSockaddrAny;
-typedef socklen_t $_Socklen;
-typedef struct linger $Linger;
-typedef struct iovec $Iovec;
-typedef struct ip_mreq $IPMreq;
-typedef struct ipv6_mreq $IPv6Mreq;
-typedef struct msghdr $Msghdr;
-typedef struct cmsghdr $Cmsghdr;
-typedef struct in6_pktinfo $Inet6Pktinfo;
-
-enum {
- $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
- $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
- $SizeofSockaddrAny = sizeof(struct sockaddr_any),
- $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
- $SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
- $SizeofLinger = sizeof(struct linger),
- $SizeofIPMreq = sizeof(struct ip_mreq),
- $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
- $SizeofMsghdr = sizeof(struct msghdr),
- $SizeofCmsghdr = sizeof(struct cmsghdr),
- $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
-};
-
-// Ptrace requests
-
-enum {
- $PTRACE_TRACEME = PT_TRACE_ME,
- $PTRACE_CONT = PT_CONTINUE,
- $PTRACE_KILL = PT_KILL,
-};
-
-// Events (kqueue, kevent)
-
-typedef struct kevent $Kevent_t;
-
-// Select
-
-typedef fd_set $FdSet;
-
-// Routing and interface messages
-
-enum {
- $SizeofIfMsghdr = sizeof(struct if_msghdr),
- $SizeofIfData = sizeof(struct if_data),
- $SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
- $SizeofIfmaMsghdr = sizeof(struct ifma_msghdr),
- $SizeofIfmaMsghdr2 = sizeof(struct ifma_msghdr2),
- $SizeofRtMsghdr = sizeof(struct rt_msghdr),
- $SizeofRtMetrics = sizeof(struct rt_metrics),
-};
-
-typedef struct if_msghdr $IfMsghdr;
-typedef struct if_data $IfData;
-typedef struct ifa_msghdr $IfaMsghdr;
-typedef struct ifma_msghdr $IfmaMsghdr;
-typedef struct ifma_msghdr2 $IfmaMsghdr2;
-typedef struct rt_msghdr $RtMsghdr;
-typedef struct rt_metrics $RtMetrics;
-
-// Berkeley packet filter
-
-enum {
- $SizeofBpfVersion = sizeof(struct bpf_version),
- $SizeofBpfStat = sizeof(struct bpf_stat),
- $SizeofBpfProgram = sizeof(struct bpf_program),
- $SizeofBpfInsn = sizeof(struct bpf_insn),
- $SizeofBpfHdr = sizeof(struct bpf_hdr),
-};
-
-typedef struct bpf_version $BpfVersion;
-typedef struct bpf_stat $BpfStat;
-typedef struct bpf_program $BpfProgram;
-typedef struct bpf_insn $BpfInsn;
-typedef struct bpf_hdr $BpfHdr;
diff --git a/src/pkg/syscall/types_darwin.go b/src/pkg/syscall/types_darwin.go
new file mode 100644
index 000000000..b9c65e3c7
--- /dev/null
+++ b/src/pkg/syscall/types_darwin.go
@@ -0,0 +1,228 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define __DARWIN_UNIX03 0
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timeval32 C.struct_timeval32
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+type Stat_t C.struct_stat64
+
+type Statfs_t C.struct_statfs64
+
+type Flock_t C.struct_flock
+
+type Fstore_t C.struct_fstore
+
+type Radvisory_t C.struct_radvisory
+
+type Fbootstraptransfer_t C.struct_fbootstraptransfer
+
+type Log2phys_t C.struct_log2phys
+
+type Fsid C.struct_fsid
+
+type Dirent C.struct_dirent
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+)
+
+// Ptrace requests
+
+const (
+ PTRACE_TRACEME = C.PT_TRACE_ME
+ PTRACE_CONT = C.PT_CONTINUE
+ PTRACE_KILL = C.PT_KILL
+)
+
+// Events (kqueue, kevent)
+
+type Kevent_t C.struct_kevent
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofIfmaMsghdr = C.sizeof_struct_ifma_msghdr
+ SizeofIfmaMsghdr2 = C.sizeof_struct_ifma_msghdr2
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type IfmaMsghdr C.struct_ifma_msghdr
+
+type IfmaMsghdr2 C.struct_ifma_msghdr2
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfHdr C.struct_bpf_hdr
diff --git a/src/pkg/syscall/types_freebsd.c b/src/pkg/syscall/types_freebsd.c
deleted file mode 100644
index 1494661cf..000000000
--- a/src/pkg/syscall/types_freebsd.c
+++ /dev/null
@@ -1,190 +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.
-
-/*
-Input to godefs. See also mkerrors.sh and mkall.sh
- */
-
-#define KERNEL
-#include <dirent.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/event.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/ptrace.h>
-#include <sys/resource.h>
-#include <sys/select.h>
-#include <sys/signal.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/wait.h>
-#include <net/bpf.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/route.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-// Machine characteristics; for internal use.
-
-enum {
- $sizeofPtr = sizeof(void*),
- $sizeofShort = sizeof(short),
- $sizeofInt = sizeof(int),
- $sizeofLong = sizeof(long),
- $sizeofLongLong = sizeof(long long),
-};
-
-// Basic types
-
-typedef short $_C_short;
-typedef int $_C_int;
-typedef long $_C_long;
-typedef long long $_C_long_long;
-
-// Time
-
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-
-// Processes
-
-typedef struct rusage $Rusage;
-typedef struct rlimit $Rlimit;
-
-typedef gid_t $_Gid_t;
-
-// Files
-
-enum {
- $O_CLOEXEC = 0, // not supported
-};
-
-enum { // Directory mode bits
- $S_IFMT = S_IFMT,
- $S_IFIFO = S_IFIFO,
- $S_IFCHR = S_IFCHR,
- $S_IFDIR = S_IFDIR,
- $S_IFBLK = S_IFBLK,
- $S_IFREG = S_IFREG,
- $S_IFLNK = S_IFLNK,
- $S_IFSOCK = S_IFSOCK,
- $S_ISUID = S_ISUID,
- $S_ISGID = S_ISGID,
- $S_ISVTX = S_ISVTX,
- $S_IRUSR = S_IRUSR,
- $S_IWUSR = S_IWUSR,
- $S_IXUSR = S_IXUSR,
-};
-
-typedef struct stat $Stat_t;
-typedef struct statfs $Statfs_t;
-typedef struct flock $Flock_t;
-
-typedef struct dirent $Dirent;
-
-// Sockets
-
-union sockaddr_all {
- struct sockaddr s1; // this one gets used for fields
- struct sockaddr_in s2; // these pad it out
- struct sockaddr_in6 s3;
- struct sockaddr_un s4;
- struct sockaddr_dl s5;
-};
-
-struct sockaddr_any {
- struct sockaddr addr;
- char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
-};
-
-typedef struct sockaddr_in $RawSockaddrInet4;
-typedef struct sockaddr_in6 $RawSockaddrInet6;
-typedef struct sockaddr_un $RawSockaddrUnix;
-typedef struct sockaddr_dl $RawSockaddrDatalink;
-typedef struct sockaddr $RawSockaddr;
-typedef struct sockaddr_any $RawSockaddrAny;
-typedef socklen_t $_Socklen;
-typedef struct linger $Linger;
-typedef struct iovec $Iovec;
-typedef struct ip_mreq $IPMreq;
-typedef struct ipv6_mreq $IPv6Mreq;
-typedef struct msghdr $Msghdr;
-typedef struct cmsghdr $Cmsghdr;
-typedef struct in6_pktinfo $Inet6Pktinfo;
-
-enum {
- $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
- $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
- $SizeofSockaddrAny = sizeof(struct sockaddr_any),
- $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
- $SizeofSockaddrDatalink = sizeof(struct sockaddr_dl),
- $SizeofLinger = sizeof(struct linger),
- $SizeofIPMreq = sizeof(struct ip_mreq),
- $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
- $SizeofMsghdr = sizeof(struct msghdr),
- $SizeofCmsghdr = sizeof(struct cmsghdr),
- $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
-};
-
-// Ptrace requests
-
-enum {
- $PTRACE_TRACEME = PT_TRACE_ME,
- $PTRACE_CONT = PT_CONTINUE,
- $PTRACE_KILL = PT_KILL,
-};
-
-// Events (kqueue, kevent)
-
-typedef struct kevent $Kevent_t;
-
-// Select
-
-typedef fd_set $FdSet;
-
-// Routing and interface messages
-
-enum {
- $SizeofIfMsghdr = sizeof(struct if_msghdr),
- $SizeofIfData = sizeof(struct if_data),
- $SizeofIfaMsghdr = sizeof(struct ifa_msghdr),
- $SizeofIfmaMsghdr = sizeof(struct ifma_msghdr),
- $SizeofRtMsghdr = sizeof(struct rt_msghdr),
- $SizeofRtMetrics = sizeof(struct rt_metrics),
-};
-
-typedef struct if_msghdr $IfMsghdr;
-typedef struct if_data $IfData;
-typedef struct ifa_msghdr $IfaMsghdr;
-typedef struct ifma_msghdr $IfmaMsghdr;
-typedef struct rt_msghdr $RtMsghdr;
-typedef struct rt_metrics $RtMetrics;
-
-// Berkeley packet filter
-
-enum {
- $SizeofBpfVersion = sizeof(struct bpf_version),
- $SizeofBpfStat = sizeof(struct bpf_stat),
- $SizeofBpfZbuf = sizeof(struct bpf_zbuf),
- $SizeofBpfProgram = sizeof(struct bpf_program),
- $SizeofBpfInsn = sizeof(struct bpf_insn),
- $SizeofBpfHdr = sizeof(struct bpf_hdr),
- $SizeofBpfZbufHeader = sizeof(struct bpf_zbuf_header),
-};
-
-typedef struct bpf_version $BpfVersion;
-typedef struct bpf_stat $BpfStat;
-typedef struct bpf_zbuf $BpfZbuf;
-typedef struct bpf_program $BpfProgram;
-typedef struct bpf_insn $BpfInsn;
-typedef struct bpf_hdr $BpfHdr;
-typedef struct bpf_zbuf_header $BpfZbufHeader;
diff --git a/src/pkg/syscall/types_freebsd.go b/src/pkg/syscall/types_freebsd.go
new file mode 100644
index 000000000..6e1dd4310
--- /dev/null
+++ b/src/pkg/syscall/types_freebsd.go
@@ -0,0 +1,240 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const (
+ O_CLOEXEC = 0 // not supported
+)
+
+const ( // Directory mode bits
+ S_IFMT = C.S_IFMT
+ S_IFIFO = C.S_IFIFO
+ S_IFCHR = C.S_IFCHR
+ S_IFDIR = C.S_IFDIR
+ S_IFBLK = C.S_IFBLK
+ S_IFREG = C.S_IFREG
+ S_IFLNK = C.S_IFLNK
+ S_IFSOCK = C.S_IFSOCK
+ S_ISUID = C.S_ISUID
+ S_ISGID = C.S_ISGID
+ S_ISVTX = C.S_ISVTX
+ S_IRUSR = C.S_IRUSR
+ S_IWUSR = C.S_IWUSR
+ S_IXUSR = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Statfs_t C.struct_statfs
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+type Fsid C.struct_fsid
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPMreqn C.struct_ip_mreqn
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPMreqn = C.sizeof_struct_ip_mreqn
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+)
+
+// Ptrace requests
+
+const (
+ PTRACE_TRACEME = C.PT_TRACE_ME
+ PTRACE_CONT = C.PT_CONTINUE
+ PTRACE_KILL = C.PT_KILL
+)
+
+// Events (kqueue, kevent)
+
+type Kevent_t C.struct_kevent
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofIfmaMsghdr = C.sizeof_struct_ifma_msghdr
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type IfmaMsghdr C.struct_ifma_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfZbuf = C.sizeof_struct_bpf_zbuf
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+ SizeofBpfZbufHeader = C.sizeof_struct_bpf_zbuf_header
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfZbuf C.struct_bpf_zbuf
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfHdr C.struct_bpf_hdr
+
+type BpfZbufHeader C.struct_bpf_zbuf_header
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
deleted file mode 100644
index abb2a91a7..000000000
--- a/src/pkg/syscall/types_linux.c
+++ /dev/null
@@ -1,266 +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.
-
-/*
-Input to godefs. See also mkerrors.sh and mkall.sh
- */
-
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netpacket/packet.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/epoll.h>
-#include <sys/inotify.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/ptrace.h>
-#include <sys/resource.h>
-#include <sys/select.h>
-#include <sys/signal.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/sysinfo.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/timex.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <sys/user.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#include <linux/filter.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <time.h>
-#include <unistd.h>
-#include <ustat.h>
-#include <utime.h>
-
-// Machine characteristics; for internal use.
-
-enum {
- $sizeofPtr = sizeof(void*),
- $sizeofShort = sizeof(short),
- $sizeofInt = sizeof(int),
- $sizeofLong = sizeof(long),
- $sizeofLongLong = sizeof(long long),
- $PathMax = PATH_MAX,
-};
-
-// Basic types
-
-typedef short $_C_short;
-typedef int $_C_int;
-typedef long $_C_long;
-typedef long long $_C_long_long;
-
-// Time
-
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-typedef struct timex $Timex;
-typedef time_t $Time_t;
-typedef struct tms $Tms;
-typedef struct utimbuf $Utimbuf;
-
-// Processes
-
-typedef struct rusage $Rusage;
-typedef struct rlimit $Rlimit;
-
-typedef gid_t $_Gid_t;
-
-// Files
-
-typedef struct stat $Stat_t;
-typedef struct statfs $Statfs_t;
-
-typedef struct dirent $Dirent;
-
-// Sockets
-
-union sockaddr_all {
- struct sockaddr s1; // this one gets used for fields
- struct sockaddr_in s2; // these pad it out
- struct sockaddr_in6 s3;
- struct sockaddr_un s4;
- struct sockaddr_ll s5;
- struct sockaddr_nl s6;
-};
-
-struct sockaddr_any {
- struct sockaddr addr;
- char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
-};
-
-typedef struct sockaddr_in $RawSockaddrInet4;
-typedef struct sockaddr_in6 $RawSockaddrInet6;
-typedef struct sockaddr_un $RawSockaddrUnix;
-typedef struct sockaddr_ll $RawSockaddrLinklayer;
-typedef struct sockaddr_nl $RawSockaddrNetlink;
-typedef struct sockaddr $RawSockaddr;
-typedef struct sockaddr_any $RawSockaddrAny;
-typedef socklen_t $_Socklen;
-typedef struct linger $Linger;
-typedef struct iovec $Iovec;
-typedef struct ip_mreq $IPMreq;
-typedef struct ipv6_mreq $IPv6Mreq;
-typedef struct msghdr $Msghdr;
-typedef struct cmsghdr $Cmsghdr;
-typedef struct in6_pktinfo $Inet6Pktinfo;
-typedef struct ucred $Ucred;
-
-enum {
- $SizeofSockaddrInet4 = sizeof(struct sockaddr_in),
- $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6),
- $SizeofSockaddrAny = sizeof(struct sockaddr_any),
- $SizeofSockaddrUnix = sizeof(struct sockaddr_un),
- $SizeofSockaddrLinklayer = sizeof(struct sockaddr_ll),
- $SizeofSockaddrNetlink = sizeof(struct sockaddr_nl),
- $SizeofLinger = sizeof(struct linger),
- $SizeofIPMreq = sizeof(struct ip_mreq),
- $SizeofIPv6Mreq = sizeof(struct ipv6_mreq),
- $SizeofMsghdr = sizeof(struct msghdr),
- $SizeofCmsghdr = sizeof(struct cmsghdr),
- $SizeofInet6Pktinfo = sizeof(struct in6_pktinfo),
- $SizeofUcred = sizeof(struct ucred),
-};
-
-// Netlink routing and interface messages
-
-enum {
- $IFA_UNSPEC = IFA_UNSPEC,
- $IFA_ADDRESS = IFA_ADDRESS,
- $IFA_LOCAL = IFA_LOCAL,
- $IFA_LABEL = IFA_LABEL,
- $IFA_BROADCAST = IFA_BROADCAST,
- $IFA_ANYCAST = IFA_ANYCAST,
- $IFA_CACHEINFO = IFA_CACHEINFO,
- $IFA_MULTICAST = IFA_MULTICAST,
- $IFLA_UNSPEC = IFLA_UNSPEC,
- $IFLA_ADDRESS = IFLA_ADDRESS,
- $IFLA_BROADCAST = IFLA_BROADCAST,
- $IFLA_IFNAME = IFLA_IFNAME,
- $IFLA_MTU = IFLA_MTU,
- $IFLA_LINK = IFLA_LINK,
- $IFLA_QDISC = IFLA_QDISC,
- $IFLA_STATS = IFLA_STATS,
- $IFLA_COST = IFLA_COST,
- $IFLA_PRIORITY = IFLA_PRIORITY,
- $IFLA_MASTER = IFLA_MASTER,
- $IFLA_WIRELESS = IFLA_WIRELESS,
- $IFLA_PROTINFO = IFLA_PROTINFO,
- $IFLA_TXQLEN = IFLA_TXQLEN,
- $IFLA_MAP = IFLA_MAP,
- $IFLA_WEIGHT = IFLA_WEIGHT,
- $IFLA_OPERSTATE = IFLA_OPERSTATE,
- $IFLA_LINKMODE = IFLA_LINKMODE,
- $IFLA_LINKINFO = IFLA_LINKINFO,
- $IFLA_NET_NS_PID = IFLA_NET_NS_PID,
- $IFLA_IFALIAS = IFLA_IFALIAS,
- $IFLA_MAX = IFLA_MAX,
- $RT_SCOPE_UNIVERSE = RT_SCOPE_UNIVERSE,
- $RT_SCOPE_SITE = RT_SCOPE_SITE,
- $RT_SCOPE_LINK = RT_SCOPE_LINK,
- $RT_SCOPE_HOST = RT_SCOPE_HOST,
- $RT_SCOPE_NOWHERE = RT_SCOPE_NOWHERE,
- $RT_TABLE_UNSPEC = RT_TABLE_UNSPEC,
- $RT_TABLE_COMPAT = RT_TABLE_COMPAT,
- $RT_TABLE_DEFAULT = RT_TABLE_DEFAULT,
- $RT_TABLE_MAIN = RT_TABLE_MAIN,
- $RT_TABLE_LOCAL = RT_TABLE_LOCAL,
- $RT_TABLE_MAX = RT_TABLE_MAX,
- $RTA_UNSPEC = RTA_UNSPEC,
- $RTA_DST = RTA_DST,
- $RTA_SRC = RTA_SRC,
- $RTA_IIF = RTA_IIF,
- $RTA_OIF = RTA_OIF,
- $RTA_GATEWAY = RTA_GATEWAY,
- $RTA_PRIORITY = RTA_PRIORITY,
- $RTA_PREFSRC = RTA_PREFSRC,
- $RTA_METRICS = RTA_METRICS,
- $RTA_MULTIPATH = RTA_MULTIPATH,
- $RTA_FLOW = RTA_FLOW,
- $RTA_CACHEINFO = RTA_CACHEINFO,
- $RTA_TABLE = RTA_TABLE,
- $RTN_UNSPEC = RTN_UNSPEC,
- $RTN_UNICAST = RTN_UNICAST,
- $RTN_LOCAL = RTN_LOCAL,
- $RTN_BROADCAST = RTN_BROADCAST,
- $RTN_ANYCAST = RTN_ANYCAST,
- $RTN_MULTICAST = RTN_MULTICAST,
- $RTN_BLACKHOLE = RTN_BLACKHOLE,
- $RTN_UNREACHABLE = RTN_UNREACHABLE,
- $RTN_PROHIBIT = RTN_PROHIBIT,
- $RTN_THROW = RTN_THROW,
- $RTN_NAT = RTN_NAT,
- $RTN_XRESOLVE = RTN_XRESOLVE,
- $SizeofNlMsghdr = sizeof(struct nlmsghdr),
- $SizeofNlMsgerr = sizeof(struct nlmsgerr),
- $SizeofRtGenmsg = sizeof(struct rtgenmsg),
- $SizeofNlAttr = sizeof(struct nlattr),
- $SizeofRtAttr = sizeof(struct rtattr),
- $SizeofIfInfomsg = sizeof(struct ifinfomsg),
- $SizeofIfAddrmsg = sizeof(struct ifaddrmsg),
- $SizeofRtmsg = sizeof(struct rtmsg),
- $SizeofRtNexthop = sizeof(struct rtnexthop),
-};
-
-typedef struct nlmsghdr $NlMsghdr;
-typedef struct nlmsgerr $NlMsgerr;
-typedef struct rtgenmsg $RtGenmsg;
-typedef struct nlattr $NlAttr;
-typedef struct rtattr $RtAttr;
-typedef struct ifinfomsg $IfInfomsg;
-typedef struct ifaddrmsg $IfAddrmsg;
-typedef struct rtmsg $RtMsg;
-typedef struct rtnexthop $RtNexthop;
-
-// Linux socket filter
-
-enum {
- $SizeofSockFilter = sizeof(struct sock_filter),
- $SizeofSockFprog = sizeof(struct sock_fprog),
-};
-
-typedef struct sock_filter $SockFilter;
-typedef struct sock_fprog $SockFprog;
-
-// Inotify
-
-typedef struct inotify_event $InotifyEvent;
-
-enum {
- $SizeofInotifyEvent = sizeof(struct inotify_event)
-};
-
-// Ptrace
-
-// Register structures
-typedef struct user_regs_struct $PtraceRegs;
-
-// Misc
-
-typedef fd_set $FdSet;
-typedef struct sysinfo $Sysinfo_t;
-typedef struct utsname $Utsname;
-typedef struct ustat $Ustat_t;
-
-// The real epoll_event is a union, and godefs doesn't handle it well.
-struct my_epoll_event {
- uint32_t events;
- int32_t fd;
- int32_t pad;
-};
-
-typedef struct my_epoll_event $EpollEvent;
diff --git a/src/pkg/syscall/types_linux.go b/src/pkg/syscall/types_linux.go
new file mode 100644
index 000000000..0030960b5
--- /dev/null
+++ b/src/pkg/syscall/types_linux.go
@@ -0,0 +1,452 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netpacket/packet.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/user.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <ustat.h>
+#include <utime.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_ll s5;
+ struct sockaddr_nl s6;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+// copied from /usr/include/linux/un.h
+struct my_sockaddr_un {
+ sa_family_t sun_family;
+#ifdef __ARM_EABI__
+ // on ARM char is by default unsigned
+ signed char sun_path[108];
+#else
+ char sun_path[108];
+#endif
+};
+
+#ifdef __ARM_EABI__
+typedef struct user_regs PtraceRegs;
+#else
+typedef struct user_regs_struct PtraceRegs;
+#endif
+
+// The real epoll_event is a union, and godefs doesn't handle it well.
+struct my_epoll_event {
+ uint32_t events;
+#ifdef __ARM_EABI__
+ // padding is not specified in linux/eventpoll.h but added to conform to the
+ // alignment requirements of EABI
+ int32_t padFd;
+#endif
+ int32_t fd;
+ int32_t pad;
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+ PathMax = C.PATH_MAX
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timex C.struct_timex
+
+type Time_t C.time_t
+
+type Tms C.struct_tms
+
+type Utimbuf C.struct_utimbuf
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+type Stat_t C.struct_stat
+
+type Statfs_t C.struct_statfs
+
+type Dirent C.struct_dirent
+
+type Fsid C.fsid_t
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_my_sockaddr_un
+
+type RawSockaddrLinklayer C.struct_sockaddr_ll
+
+type RawSockaddrNetlink C.struct_sockaddr_nl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPMreqn C.struct_ip_mreqn
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet4Pktinfo C.struct_in_pktinfo
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+type Ucred C.struct_ucred
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrLinklayer = C.sizeof_struct_sockaddr_ll
+ SizeofSockaddrNetlink = C.sizeof_struct_sockaddr_nl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPMreqn = C.sizeof_struct_ip_mreqn
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet4Pktinfo = C.sizeof_struct_in_pktinfo
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+ SizeofUcred = C.sizeof_struct_ucred
+)
+
+// Netlink routing and interface messages
+
+const (
+ IFA_UNSPEC = C.IFA_UNSPEC
+ IFA_ADDRESS = C.IFA_ADDRESS
+ IFA_LOCAL = C.IFA_LOCAL
+ IFA_LABEL = C.IFA_LABEL
+ IFA_BROADCAST = C.IFA_BROADCAST
+ IFA_ANYCAST = C.IFA_ANYCAST
+ IFA_CACHEINFO = C.IFA_CACHEINFO
+ IFA_MULTICAST = C.IFA_MULTICAST
+ IFLA_UNSPEC = C.IFLA_UNSPEC
+ IFLA_ADDRESS = C.IFLA_ADDRESS
+ IFLA_BROADCAST = C.IFLA_BROADCAST
+ IFLA_IFNAME = C.IFLA_IFNAME
+ IFLA_MTU = C.IFLA_MTU
+ IFLA_LINK = C.IFLA_LINK
+ IFLA_QDISC = C.IFLA_QDISC
+ IFLA_STATS = C.IFLA_STATS
+ IFLA_COST = C.IFLA_COST
+ IFLA_PRIORITY = C.IFLA_PRIORITY
+ IFLA_MASTER = C.IFLA_MASTER
+ IFLA_WIRELESS = C.IFLA_WIRELESS
+ IFLA_PROTINFO = C.IFLA_PROTINFO
+ IFLA_TXQLEN = C.IFLA_TXQLEN
+ IFLA_MAP = C.IFLA_MAP
+ IFLA_WEIGHT = C.IFLA_WEIGHT
+ IFLA_OPERSTATE = C.IFLA_OPERSTATE
+ IFLA_LINKMODE = C.IFLA_LINKMODE
+ IFLA_LINKINFO = C.IFLA_LINKINFO
+ IFLA_NET_NS_PID = C.IFLA_NET_NS_PID
+ IFLA_IFALIAS = C.IFLA_IFALIAS
+ IFLA_MAX = C.IFLA_MAX
+ RT_SCOPE_UNIVERSE = C.RT_SCOPE_UNIVERSE
+ RT_SCOPE_SITE = C.RT_SCOPE_SITE
+ RT_SCOPE_LINK = C.RT_SCOPE_LINK
+ RT_SCOPE_HOST = C.RT_SCOPE_HOST
+ RT_SCOPE_NOWHERE = C.RT_SCOPE_NOWHERE
+ RT_TABLE_UNSPEC = C.RT_TABLE_UNSPEC
+ RT_TABLE_COMPAT = C.RT_TABLE_COMPAT
+ RT_TABLE_DEFAULT = C.RT_TABLE_DEFAULT
+ RT_TABLE_MAIN = C.RT_TABLE_MAIN
+ RT_TABLE_LOCAL = C.RT_TABLE_LOCAL
+ RT_TABLE_MAX = C.RT_TABLE_MAX
+ RTA_UNSPEC = C.RTA_UNSPEC
+ RTA_DST = C.RTA_DST
+ RTA_SRC = C.RTA_SRC
+ RTA_IIF = C.RTA_IIF
+ RTA_OIF = C.RTA_OIF
+ RTA_GATEWAY = C.RTA_GATEWAY
+ RTA_PRIORITY = C.RTA_PRIORITY
+ RTA_PREFSRC = C.RTA_PREFSRC
+ RTA_METRICS = C.RTA_METRICS
+ RTA_MULTIPATH = C.RTA_MULTIPATH
+ RTA_FLOW = C.RTA_FLOW
+ RTA_CACHEINFO = C.RTA_CACHEINFO
+ RTA_TABLE = C.RTA_TABLE
+ RTN_UNSPEC = C.RTN_UNSPEC
+ RTN_UNICAST = C.RTN_UNICAST
+ RTN_LOCAL = C.RTN_LOCAL
+ RTN_BROADCAST = C.RTN_BROADCAST
+ RTN_ANYCAST = C.RTN_ANYCAST
+ RTN_MULTICAST = C.RTN_MULTICAST
+ RTN_BLACKHOLE = C.RTN_BLACKHOLE
+ RTN_UNREACHABLE = C.RTN_UNREACHABLE
+ RTN_PROHIBIT = C.RTN_PROHIBIT
+ RTN_THROW = C.RTN_THROW
+ RTN_NAT = C.RTN_NAT
+ RTN_XRESOLVE = C.RTN_XRESOLVE
+ SizeofNlMsghdr = C.sizeof_struct_nlmsghdr
+ SizeofNlMsgerr = C.sizeof_struct_nlmsgerr
+ SizeofRtGenmsg = C.sizeof_struct_rtgenmsg
+ SizeofNlAttr = C.sizeof_struct_nlattr
+ SizeofRtAttr = C.sizeof_struct_rtattr
+ SizeofIfInfomsg = C.sizeof_struct_ifinfomsg
+ SizeofIfAddrmsg = C.sizeof_struct_ifaddrmsg
+ SizeofRtMsg = C.sizeof_struct_rtmsg
+ SizeofRtNexthop = C.sizeof_struct_rtnexthop
+)
+
+type NlMsghdr C.struct_nlmsghdr
+
+type NlMsgerr C.struct_nlmsgerr
+
+type RtGenmsg C.struct_rtgenmsg
+
+type NlAttr C.struct_nlattr
+
+type RtAttr C.struct_rtattr
+
+type IfInfomsg C.struct_ifinfomsg
+
+type IfAddrmsg C.struct_ifaddrmsg
+
+type RtMsg C.struct_rtmsg
+
+type RtNexthop C.struct_rtnexthop
+
+// Linux socket filter
+
+const (
+ SizeofSockFilter = C.sizeof_struct_sock_filter
+ SizeofSockFprog = C.sizeof_struct_sock_fprog
+)
+
+type SockFilter C.struct_sock_filter
+
+type SockFprog C.struct_sock_fprog
+
+// Inotify
+
+type InotifyEvent C.struct_inotify_event
+
+const SizeofInotifyEvent = C.sizeof_struct_inotify_event
+
+// Ptrace
+
+// Register structures
+type PtraceRegs C.PtraceRegs
+
+// Misc
+
+type FdSet C.fd_set
+
+type Sysinfo_t C.struct_sysinfo
+
+type Utsname C.struct_utsname
+
+type Ustat_t C.struct_ustat
+
+type EpollEvent C.struct_my_epoll_event
+
+// Terminal handling
+
+type Termios C.struct_termios
+
+const (
+ VINTR = C.VINTR
+ VQUIT = C.VQUIT
+ VERASE = C.VERASE
+ VKILL = C.VKILL
+ VEOF = C.VEOF
+ VTIME = C.VTIME
+ VMIN = C.VMIN
+ VSWTC = C.VSWTC
+ VSTART = C.VSTART
+ VSTOP = C.VSTOP
+ VSUSP = C.VSUSP
+ VEOL = C.VEOL
+ VREPRINT = C.VREPRINT
+ VDISCARD = C.VDISCARD
+ VWERASE = C.VWERASE
+ VLNEXT = C.VLNEXT
+ VEOL2 = C.VEOL2
+ IGNBRK = C.IGNBRK
+ BRKINT = C.BRKINT
+ IGNPAR = C.IGNPAR
+ PARMRK = C.PARMRK
+ INPCK = C.INPCK
+ ISTRIP = C.ISTRIP
+ INLCR = C.INLCR
+ IGNCR = C.IGNCR
+ ICRNL = C.ICRNL
+ IUCLC = C.IUCLC
+ IXON = C.IXON
+ IXANY = C.IXANY
+ IXOFF = C.IXOFF
+ IMAXBEL = C.IMAXBEL
+ IUTF8 = C.IUTF8
+ OPOST = C.OPOST
+ OLCUC = C.OLCUC
+ ONLCR = C.ONLCR
+ OCRNL = C.OCRNL
+ ONOCR = C.ONOCR
+ ONLRET = C.ONLRET
+ OFILL = C.OFILL
+ OFDEL = C.OFDEL
+ B0 = C.B0
+ B50 = C.B50
+ B75 = C.B75
+ B110 = C.B110
+ B134 = C.B134
+ B150 = C.B150
+ B200 = C.B200
+ B300 = C.B300
+ B600 = C.B600
+ B1200 = C.B1200
+ B1800 = C.B1800
+ B2400 = C.B2400
+ B4800 = C.B4800
+ B9600 = C.B9600
+ B19200 = C.B19200
+ B38400 = C.B38400
+ CSIZE = C.CSIZE
+ CS5 = C.CS5
+ CS6 = C.CS6
+ CS7 = C.CS7
+ CS8 = C.CS8
+ CSTOPB = C.CSTOPB
+ CREAD = C.CREAD
+ PARENB = C.PARENB
+ PARODD = C.PARODD
+ HUPCL = C.HUPCL
+ CLOCAL = C.CLOCAL
+ B57600 = C.B57600
+ B115200 = C.B115200
+ B230400 = C.B230400
+ B460800 = C.B460800
+ B500000 = C.B500000
+ B576000 = C.B576000
+ B921600 = C.B921600
+ B1000000 = C.B1000000
+ B1152000 = C.B1152000
+ B1500000 = C.B1500000
+ B2000000 = C.B2000000
+ B2500000 = C.B2500000
+ B3000000 = C.B3000000
+ B3500000 = C.B3500000
+ B4000000 = C.B4000000
+ ISIG = C.ISIG
+ ICANON = C.ICANON
+ XCASE = C.XCASE
+ ECHO = C.ECHO
+ ECHOE = C.ECHOE
+ ECHOK = C.ECHOK
+ ECHONL = C.ECHONL
+ NOFLSH = C.NOFLSH
+ TOSTOP = C.TOSTOP
+ ECHOCTL = C.ECHOCTL
+ ECHOPRT = C.ECHOPRT
+ ECHOKE = C.ECHOKE
+ FLUSHO = C.FLUSHO
+ PENDIN = C.PENDIN
+ IEXTEN = C.IEXTEN
+ TCGETS = C.TCGETS
+ TCSETS = C.TCSETS
+)
diff --git a/src/pkg/syscall/types_netbsd.go b/src/pkg/syscall/types_netbsd.go
new file mode 100644
index 000000000..518688833
--- /dev/null
+++ b/src/pkg/syscall/types_netbsd.go
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const ( // Directory mode bits
+ S_IFMT = C.S_IFMT
+ S_IFIFO = C.S_IFIFO
+ S_IFCHR = C.S_IFCHR
+ S_IFDIR = C.S_IFDIR
+ S_IFBLK = C.S_IFBLK
+ S_IFREG = C.S_IFREG
+ S_IFLNK = C.S_IFLNK
+ S_IFSOCK = C.S_IFSOCK
+ S_ISUID = C.S_ISUID
+ S_ISGID = C.S_ISGID
+ S_ISVTX = C.S_ISVTX
+ S_IRUSR = C.S_IRUSR
+ S_IWUSR = C.S_IWUSR
+ S_IXUSR = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Statfs_t C.struct_statfs
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+type Fsid C.fsid_t
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+)
+
+// Ptrace requests
+
+const (
+ PTRACE_TRACEME = C.PT_TRACE_ME
+ PTRACE_CONT = C.PT_CONTINUE
+ PTRACE_KILL = C.PT_KILL
+)
+
+// Events (kqueue, kevent)
+
+type Kevent_t C.struct_kevent
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+type Mclpool C.struct_mclpool
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfHdr C.struct_bpf_hdr
+
+type BpfTimeval C.struct_bpf_timeval
diff --git a/src/pkg/syscall/types_openbsd.go b/src/pkg/syscall/types_openbsd.go
new file mode 100644
index 000000000..518688833
--- /dev/null
+++ b/src/pkg/syscall/types_openbsd.go
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+Input to cgo -godefs. See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+enum {
+ sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+ struct sockaddr s1; // this one gets used for fields
+ struct sockaddr_in s2; // these pad it out
+ struct sockaddr_in6 s3;
+ struct sockaddr_un s4;
+ struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+ struct sockaddr addr;
+ char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+ sizeofPtr = C.sizeofPtr
+ sizeofShort = C.sizeof_short
+ sizeofInt = C.sizeof_int
+ sizeofLong = C.sizeof_long
+ sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+ _C_short C.short
+ _C_int C.int
+ _C_long C.long
+ _C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const ( // Directory mode bits
+ S_IFMT = C.S_IFMT
+ S_IFIFO = C.S_IFIFO
+ S_IFCHR = C.S_IFCHR
+ S_IFDIR = C.S_IFDIR
+ S_IFBLK = C.S_IFBLK
+ S_IFREG = C.S_IFREG
+ S_IFLNK = C.S_IFLNK
+ S_IFSOCK = C.S_IFSOCK
+ S_ISUID = C.S_ISUID
+ S_ISGID = C.S_ISGID
+ S_ISVTX = C.S_ISVTX
+ S_IRUSR = C.S_IRUSR
+ S_IWUSR = C.S_IWUSR
+ S_IXUSR = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Statfs_t C.struct_statfs
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+type Fsid C.fsid_t
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+const (
+ SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
+ SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
+ SizeofSockaddrAny = C.sizeof_struct_sockaddr_any
+ SizeofSockaddrUnix = C.sizeof_struct_sockaddr_un
+ SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+ SizeofLinger = C.sizeof_struct_linger
+ SizeofIPMreq = C.sizeof_struct_ip_mreq
+ SizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq
+ SizeofMsghdr = C.sizeof_struct_msghdr
+ SizeofCmsghdr = C.sizeof_struct_cmsghdr
+ SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
+)
+
+// Ptrace requests
+
+const (
+ PTRACE_TRACEME = C.PT_TRACE_ME
+ PTRACE_CONT = C.PT_CONTINUE
+ PTRACE_KILL = C.PT_KILL
+)
+
+// Events (kqueue, kevent)
+
+type Kevent_t C.struct_kevent
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+ SizeofIfMsghdr = C.sizeof_struct_if_msghdr
+ SizeofIfData = C.sizeof_struct_if_data
+ SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+ SizeofRtMsghdr = C.sizeof_struct_rt_msghdr
+ SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+type Mclpool C.struct_mclpool
+
+// Berkeley packet filter
+
+const (
+ SizeofBpfVersion = C.sizeof_struct_bpf_version
+ SizeofBpfStat = C.sizeof_struct_bpf_stat
+ SizeofBpfProgram = C.sizeof_struct_bpf_program
+ SizeofBpfInsn = C.sizeof_struct_bpf_insn
+ SizeofBpfHdr = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfHdr C.struct_bpf_hdr
+
+type BpfTimeval C.struct_bpf_timeval
diff --git a/src/pkg/syscall/types_plan9.c b/src/pkg/syscall/types_plan9.c
index 1da9d377c..cd9e15fa8 100644
--- a/src/pkg/syscall/types_plan9.c
+++ b/src/pkg/syscall/types_plan9.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+
/*
Input to godefs. See also mkerrors.sh and mkall.sh
*/
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index a769fd3a2..09d7b0fe9 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -1,1091 +1,1183 @@
-// mkerrors.sh -f -m32
+// mkerrors.sh -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
package syscall
-// Constants
const (
- AF_APPLETALK = 0x10
- AF_CCITT = 0xa
- AF_CHAOS = 0x5
- AF_CNT = 0x15
- AF_COIP = 0x14
- AF_DATAKIT = 0x9
- AF_DECnet = 0xc
- AF_DLI = 0xd
- AF_E164 = 0x1c
- AF_ECMA = 0x8
- AF_HYLINK = 0xf
- AF_IEEE80211 = 0x25
- AF_IMPLINK = 0x3
- AF_INET = 0x2
- AF_INET6 = 0x1e
- AF_IPX = 0x17
- AF_ISDN = 0x1c
- AF_ISO = 0x7
- AF_LAT = 0xe
- AF_LINK = 0x12
- AF_LOCAL = 0x1
- AF_MAX = 0x26
- AF_NATM = 0x1f
- AF_NDRV = 0x1b
- AF_NETBIOS = 0x21
- AF_NS = 0x6
- AF_OSI = 0x7
- AF_PPP = 0x22
- AF_PUP = 0x4
- AF_RESERVED_36 = 0x24
- AF_ROUTE = 0x11
- AF_SIP = 0x18
- AF_SNA = 0xb
- AF_SYSTEM = 0x20
- AF_UNIX = 0x1
- AF_UNSPEC = 0
- BIOCFLUSH = 0x20004268
- BIOCGBLEN = 0x40044266
- BIOCGDLT = 0x4004426a
- BIOCGDLTLIST = 0xc00c4279
- BIOCGETIF = 0x4020426b
- BIOCGHDRCMPLT = 0x40044274
- BIOCGRSIG = 0x40044272
- BIOCGRTIMEOUT = 0x4008426e
- BIOCGSEESENT = 0x40044276
- BIOCGSTATS = 0x4008426f
- BIOCIMMEDIATE = 0x80044270
- BIOCPROMISC = 0x20004269
- BIOCSBLEN = 0xc0044266
- BIOCSDLT = 0x80044278
- BIOCSETF = 0x80084267
- BIOCSETIF = 0x8020426c
- BIOCSHDRCMPLT = 0x80044275
- BIOCSRSIG = 0x80044273
- BIOCSRTIMEOUT = 0x8008426d
- BIOCSSEESENT = 0x80044277
- BIOCVERSION = 0x40044271
- BPF_A = 0x10
- BPF_ABS = 0x20
- BPF_ADD = 0
- BPF_ALIGNMENT = 0x4
- BPF_ALU = 0x4
- BPF_AND = 0x50
- BPF_B = 0x10
- BPF_DIV = 0x30
- BPF_H = 0x8
- BPF_IMM = 0
- BPF_IND = 0x40
- BPF_JA = 0
- BPF_JEQ = 0x10
- BPF_JGE = 0x30
- BPF_JGT = 0x20
- BPF_JMP = 0x5
- BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
- BPF_LDX = 0x1
- BPF_LEN = 0x80
- BPF_LSH = 0x60
- BPF_MAJOR_VERSION = 0x1
- BPF_MAXBUFSIZE = 0x80000
- BPF_MAXINSNS = 0x200
- BPF_MEM = 0x60
- BPF_MEMWORDS = 0x10
- BPF_MINBUFSIZE = 0x20
- BPF_MINOR_VERSION = 0x1
- BPF_MISC = 0x7
- BPF_MSH = 0xa0
- BPF_MUL = 0x20
- BPF_NEG = 0x80
- BPF_OR = 0x40
- BPF_RELEASE = 0x30bb6
- BPF_RET = 0x6
- BPF_RSH = 0x70
- BPF_ST = 0x2
- BPF_STX = 0x3
- BPF_SUB = 0x10
- BPF_TAX = 0
- BPF_TXA = 0x80
- BPF_W = 0
- BPF_X = 0x8
- CTL_MAXNAME = 0xc
- CTL_NET = 0x4
- DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
- DLT_ARCNET = 0x7
- DLT_ATM_CLIP = 0x13
- DLT_ATM_RFC1483 = 0xb
- DLT_AX25 = 0x3
- DLT_CHAOS = 0x5
- DLT_CHDLC = 0x68
- DLT_C_HDLC = 0x68
- DLT_EN10MB = 0x1
- DLT_EN3MB = 0x2
- DLT_FDDI = 0xa
- DLT_IEEE802 = 0x6
- DLT_IEEE802_11 = 0x69
- DLT_IEEE802_11_RADIO = 0x7f
- DLT_IEEE802_11_RADIO_AVS = 0xa3
- DLT_LINUX_SLL = 0x71
- DLT_LOOP = 0x6c
- DLT_NULL = 0
- DLT_PFLOG = 0x75
- DLT_PFSYNC = 0x12
- DLT_PPP = 0x9
- DLT_PPP_BSDOS = 0x10
- DLT_PPP_SERIAL = 0x32
- DLT_PRONET = 0x4
- DLT_RAW = 0xc
- DLT_SLIP = 0x8
- DLT_SLIP_BSDOS = 0xf
- DT_BLK = 0x6
- DT_CHR = 0x2
- DT_DIR = 0x4
- DT_FIFO = 0x1
- DT_LNK = 0xa
- DT_REG = 0x8
- DT_SOCK = 0xc
- DT_UNKNOWN = 0
- DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x30
- EADDRNOTAVAIL = 0x31
- EAFNOSUPPORT = 0x2f
- EAGAIN = 0x23
- EALREADY = 0x25
- EAUTH = 0x50
- EBADARCH = 0x56
- EBADEXEC = 0x55
- EBADF = 0x9
- EBADMACHO = 0x58
- EBADMSG = 0x5e
- EBADRPC = 0x48
- EBUSY = 0x10
- ECANCELED = 0x59
- ECHILD = 0xa
- ECHO = 0x8
- ECHOCTL = 0x40
- ECHOE = 0x2
- ECHOK = 0x4
- ECHOKE = 0x1
- ECHONL = 0x10
- ECHOPRT = 0x20
- ECONNABORTED = 0x35
- ECONNREFUSED = 0x3d
- ECONNRESET = 0x36
- EDEADLK = 0xb
- EDESTADDRREQ = 0x27
- EDEVERR = 0x53
- EDOM = 0x21
- EDQUOT = 0x45
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EFTYPE = 0x4f
- EHOSTDOWN = 0x40
- EHOSTUNREACH = 0x41
- EIDRM = 0x5a
- EILSEQ = 0x5c
- EINPROGRESS = 0x24
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x38
- EISDIR = 0x15
- ELAST = 0x67
- ELOOP = 0x3e
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x28
- EMULTIHOP = 0x5f
- ENAMETOOLONG = 0x3f
- ENEEDAUTH = 0x51
- ENETDOWN = 0x32
- ENETRESET = 0x34
- ENETUNREACH = 0x33
- ENFILE = 0x17
- ENOATTR = 0x5d
- ENOBUFS = 0x37
- ENODATA = 0x60
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOLCK = 0x4d
- ENOLINK = 0x61
- ENOMEM = 0xc
- ENOMSG = 0x5b
- ENOPOLICY = 0x67
- ENOPROTOOPT = 0x2a
- ENOSPC = 0x1c
- ENOSR = 0x62
- ENOSTR = 0x63
- ENOSYS = 0x4e
- ENOTBLK = 0xf
- ENOTCONN = 0x39
- ENOTDIR = 0x14
- ENOTEMPTY = 0x42
- ENOTSOCK = 0x26
- ENOTSUP = 0x2d
- ENOTTY = 0x19
- ENXIO = 0x6
- EOPNOTSUPP = 0x66
- EOVERFLOW = 0x54
- EPERM = 0x1
- EPFNOSUPPORT = 0x2e
- EPIPE = 0x20
- EPROCLIM = 0x43
- EPROCUNAVAIL = 0x4c
- EPROGMISMATCH = 0x4b
- EPROGUNAVAIL = 0x4a
- EPROTO = 0x64
- EPROTONOSUPPORT = 0x2b
- EPROTOTYPE = 0x29
- EPWROFF = 0x52
- ERANGE = 0x22
- EREMOTE = 0x47
- EROFS = 0x1e
- ERPCMISMATCH = 0x49
- ESHLIBVERS = 0x57
- ESHUTDOWN = 0x3a
- ESOCKTNOSUPPORT = 0x2c
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESTALE = 0x46
- ETIME = 0x65
- ETIMEDOUT = 0x3c
- ETOOMANYREFS = 0x3b
- ETXTBSY = 0x1a
- EUSERS = 0x44
- EVFILT_AIO = -0x3
- EVFILT_FS = -0x9
- EVFILT_MACHPORT = -0x8
- EVFILT_PROC = -0x5
- EVFILT_READ = -0x1
- EVFILT_SESSION = -0xb
- EVFILT_SIGNAL = -0x6
- EVFILT_SYSCOUNT = 0xb
- EVFILT_THREADMARKER = 0xb
- EVFILT_TIMER = -0x7
- EVFILT_USER = -0xa
- EVFILT_VNODE = -0x4
- EVFILT_WRITE = -0x2
- EV_ADD = 0x1
- EV_CLEAR = 0x20
- EV_DELETE = 0x2
- EV_DISABLE = 0x8
- EV_DISPATCH = 0x80
- EV_ENABLE = 0x4
- EV_EOF = 0x8000
- EV_ERROR = 0x4000
- EV_FLAG0 = 0x1000
- EV_FLAG1 = 0x2000
- EV_ONESHOT = 0x10
- EV_OOBAND = 0x2000
- EV_POLL = 0x1000
- EV_RECEIPT = 0x40
- EV_SYSFLAGS = 0xf000
- EV_TRIGGER = 0x100
- EWOULDBLOCK = 0x23
- EXDEV = 0x12
- EXTA = 0x4b00
- EXTB = 0x9600
- EXTPROC = 0x800
- FD_CLOEXEC = 0x1
- FD_SETSIZE = 0x400
- F_ADDFILESIGS = 0x3d
- F_ADDSIGS = 0x3b
- F_ALLOCATEALL = 0x4
- F_ALLOCATECONTIG = 0x2
- F_CHKCLEAN = 0x29
- F_DUPFD = 0
- F_FREEZE_FS = 0x35
- F_FULLFSYNC = 0x33
- F_GETFD = 0x1
- F_GETFL = 0x3
- F_GETLK = 0x7
- F_GETOWN = 0x5
- F_GETPATH = 0x32
- F_GETPROTECTIONCLASS = 0x3e
- F_GLOBAL_NOCACHE = 0x37
- F_LOG2PHYS = 0x31
- F_MARKDEPENDENCY = 0x3c
- F_NOCACHE = 0x30
- F_PATHPKG_CHECK = 0x34
- F_PEOFPOSMODE = 0x3
- F_PREALLOCATE = 0x2a
- F_RDADVISE = 0x2c
- F_RDAHEAD = 0x2d
- F_RDLCK = 0x1
- F_READBOOTSTRAP = 0x2e
- F_SETFD = 0x2
- F_SETFL = 0x4
- F_SETLK = 0x8
- F_SETLKW = 0x9
- F_SETOWN = 0x6
- F_SETPROTECTIONCLASS = 0x3f
- F_SETSIZE = 0x2b
- F_THAW_FS = 0x36
- F_UNLCK = 0x2
- F_VOLPOSMODE = 0x4
- F_WRITEBOOTSTRAP = 0x2f
- F_WRLCK = 0x3
- IFF_ALLMULTI = 0x200
- IFF_ALTPHYS = 0x4000
- IFF_BROADCAST = 0x2
- IFF_DEBUG = 0x4
- IFF_LINK0 = 0x1000
- IFF_LINK1 = 0x2000
- IFF_LINK2 = 0x4000
- IFF_LOOPBACK = 0x8
- IFF_MULTICAST = 0x8000
- IFF_NOARP = 0x80
- IFF_NOTRAILERS = 0x20
- IFF_OACTIVE = 0x400
- IFF_POINTOPOINT = 0x10
- IFF_PROMISC = 0x100
- IFF_RUNNING = 0x40
- IFF_SIMPLEX = 0x800
- IFF_UP = 0x1
- IFNAMSIZ = 0x10
- IFT_1822 = 0x2
- IFT_AAL5 = 0x31
- IFT_ARCNET = 0x23
- IFT_ARCNETPLUS = 0x24
- IFT_ATM = 0x25
- IFT_BRIDGE = 0xd1
- IFT_CARP = 0xf8
- IFT_CEPT = 0x13
- IFT_DS3 = 0x1e
- IFT_ENC = 0xf4
- IFT_EON = 0x19
- IFT_ETHER = 0x6
- IFT_FAITH = 0x38
- IFT_FDDI = 0xf
- IFT_FRELAY = 0x20
- IFT_FRELAYDCE = 0x2c
- IFT_GIF = 0x37
- IFT_HDH1822 = 0x3
- IFT_HIPPI = 0x2f
- IFT_HSSI = 0x2e
- IFT_HY = 0xe
- IFT_IEEE1394 = 0x90
- IFT_IEEE8023ADLAG = 0x88
- IFT_ISDNBASIC = 0x14
- IFT_ISDNPRIMARY = 0x15
- IFT_ISO88022LLC = 0x29
- IFT_ISO88023 = 0x7
- IFT_ISO88024 = 0x8
- IFT_ISO88025 = 0x9
- IFT_ISO88026 = 0xa
- IFT_L2VLAN = 0x87
- IFT_LAPB = 0x10
- IFT_LOCALTALK = 0x2a
- IFT_LOOP = 0x18
- IFT_MIOX25 = 0x26
- IFT_MODEM = 0x30
- IFT_NSIP = 0x1b
- IFT_OTHER = 0x1
- IFT_P10 = 0xc
- IFT_P80 = 0xd
- IFT_PARA = 0x22
- IFT_PDP = 0xff
- IFT_PFLOG = 0xf5
- IFT_PFSYNC = 0xf6
- IFT_PPP = 0x17
- IFT_PROPMUX = 0x36
- IFT_PROPVIRTUAL = 0x35
- IFT_PTPSERIAL = 0x16
- IFT_RS232 = 0x21
- IFT_SDLC = 0x11
- IFT_SIP = 0x1f
- IFT_SLIP = 0x1c
- IFT_SMDSDXI = 0x2b
- IFT_SMDSICIP = 0x34
- IFT_SONET = 0x27
- IFT_SONETPATH = 0x32
- IFT_SONETVT = 0x33
- IFT_STARLAN = 0xb
- IFT_STF = 0x39
- IFT_T1 = 0x12
- IFT_ULTRA = 0x1d
- IFT_V35 = 0x2d
- IFT_X25 = 0x5
- IFT_X25DDN = 0x4
- IFT_X25PLE = 0x28
- IFT_XETHER = 0x1a
- IN_CLASSA_HOST = 0xffffff
- IN_CLASSA_MAX = 0x80
- IN_CLASSA_NET = 0xff000000
- IN_CLASSA_NSHIFT = 0x18
- IN_CLASSB_HOST = 0xffff
- IN_CLASSB_MAX = 0x10000
- IN_CLASSB_NET = 0xffff0000
- IN_CLASSB_NSHIFT = 0x10
- IN_CLASSC_HOST = 0xff
- IN_CLASSC_NET = 0xffffff00
- IN_CLASSC_NSHIFT = 0x8
- IN_CLASSD_HOST = 0xfffffff
- IN_CLASSD_NET = 0xf0000000
- IN_CLASSD_NSHIFT = 0x1c
- IN_LINKLOCALNETNUM = 0xa9fe0000
- IN_LOOPBACKNET = 0x7f
- IPPROTO_3PC = 0x22
- IPPROTO_ADFS = 0x44
- IPPROTO_AH = 0x33
- IPPROTO_AHIP = 0x3d
- IPPROTO_APES = 0x63
- IPPROTO_ARGUS = 0xd
- IPPROTO_AX25 = 0x5d
- IPPROTO_BHA = 0x31
- IPPROTO_BLT = 0x1e
- IPPROTO_BRSATMON = 0x4c
- IPPROTO_CFTP = 0x3e
- IPPROTO_CHAOS = 0x10
- IPPROTO_CMTP = 0x26
- IPPROTO_CPHB = 0x49
- IPPROTO_CPNX = 0x48
- IPPROTO_DDP = 0x25
- IPPROTO_DGP = 0x56
- IPPROTO_DIVERT = 0xfe
- IPPROTO_DONE = 0x101
- IPPROTO_DSTOPTS = 0x3c
- IPPROTO_EGP = 0x8
- IPPROTO_EMCON = 0xe
- IPPROTO_ENCAP = 0x62
- IPPROTO_EON = 0x50
- IPPROTO_ESP = 0x32
- IPPROTO_ETHERIP = 0x61
- IPPROTO_FRAGMENT = 0x2c
- IPPROTO_GGP = 0x3
- IPPROTO_GMTP = 0x64
- IPPROTO_GRE = 0x2f
- IPPROTO_HELLO = 0x3f
- IPPROTO_HMP = 0x14
- IPPROTO_HOPOPTS = 0
- IPPROTO_ICMP = 0x1
- IPPROTO_ICMPV6 = 0x3a
- IPPROTO_IDP = 0x16
- IPPROTO_IDPR = 0x23
- IPPROTO_IDRP = 0x2d
- IPPROTO_IGMP = 0x2
- IPPROTO_IGP = 0x55
- IPPROTO_IGRP = 0x58
- IPPROTO_IL = 0x28
- IPPROTO_INLSP = 0x34
- IPPROTO_INP = 0x20
- IPPROTO_IP = 0
- IPPROTO_IPCOMP = 0x6c
- IPPROTO_IPCV = 0x47
- IPPROTO_IPEIP = 0x5e
- IPPROTO_IPIP = 0x4
- IPPROTO_IPPC = 0x43
- IPPROTO_IPV4 = 0x4
- IPPROTO_IPV6 = 0x29
- IPPROTO_IRTP = 0x1c
- IPPROTO_KRYPTOLAN = 0x41
- IPPROTO_LARP = 0x5b
- IPPROTO_LEAF1 = 0x19
- IPPROTO_LEAF2 = 0x1a
- IPPROTO_MAX = 0x100
- IPPROTO_MAXID = 0x34
- IPPROTO_MEAS = 0x13
- IPPROTO_MHRP = 0x30
- IPPROTO_MICP = 0x5f
- IPPROTO_MTP = 0x5c
- IPPROTO_MUX = 0x12
- IPPROTO_ND = 0x4d
- IPPROTO_NHRP = 0x36
- IPPROTO_NONE = 0x3b
- IPPROTO_NSP = 0x1f
- IPPROTO_NVPII = 0xb
- IPPROTO_OSPFIGP = 0x59
- IPPROTO_PGM = 0x71
- IPPROTO_PIGP = 0x9
- IPPROTO_PIM = 0x67
- IPPROTO_PRM = 0x15
- IPPROTO_PUP = 0xc
- IPPROTO_PVP = 0x4b
- IPPROTO_RAW = 0xff
- IPPROTO_RCCMON = 0xa
- IPPROTO_RDP = 0x1b
- IPPROTO_ROUTING = 0x2b
- IPPROTO_RSVP = 0x2e
- IPPROTO_RVD = 0x42
- IPPROTO_SATEXPAK = 0x40
- IPPROTO_SATMON = 0x45
- IPPROTO_SCCSP = 0x60
- IPPROTO_SDRP = 0x2a
- IPPROTO_SEP = 0x21
- IPPROTO_SRPC = 0x5a
- IPPROTO_ST = 0x7
- IPPROTO_SVMTP = 0x52
- IPPROTO_SWIPE = 0x35
- IPPROTO_TCF = 0x57
- IPPROTO_TCP = 0x6
- IPPROTO_TP = 0x1d
- IPPROTO_TPXX = 0x27
- IPPROTO_TRUNK1 = 0x17
- IPPROTO_TRUNK2 = 0x18
- IPPROTO_TTP = 0x54
- IPPROTO_UDP = 0x11
- IPPROTO_VINES = 0x53
- IPPROTO_VISA = 0x46
- IPPROTO_VMTP = 0x51
- IPPROTO_WBEXPAK = 0x4f
- IPPROTO_WBMON = 0x4e
- IPPROTO_WSN = 0x4a
- IPPROTO_XNET = 0xf
- IPPROTO_XTP = 0x24
- IPV6_BINDV6ONLY = 0x1b
- IPV6_CHECKSUM = 0x1a
- IPV6_DEFAULT_MULTICAST_HOPS = 0x1
- IPV6_DEFAULT_MULTICAST_LOOP = 0x1
- IPV6_DEFHLIM = 0x40
- IPV6_DSTOPTS = 0x17
- IPV6_FAITH = 0x1d
- IPV6_FLOWINFO_MASK = 0xffffff0f
- IPV6_FLOWLABEL_MASK = 0xffff0f00
- IPV6_FRAGTTL = 0x78
- IPV6_FW_ADD = 0x1e
- IPV6_FW_DEL = 0x1f
- IPV6_FW_FLUSH = 0x20
- IPV6_FW_GET = 0x22
- IPV6_FW_ZERO = 0x21
- IPV6_HLIMDEC = 0x1
- IPV6_HOPLIMIT = 0x14
- IPV6_HOPOPTS = 0x16
- IPV6_IPSEC_POLICY = 0x1c
- IPV6_JOIN_GROUP = 0xc
- IPV6_LEAVE_GROUP = 0xd
- IPV6_MAXHLIM = 0xff
- IPV6_MAXPACKET = 0xffff
- IPV6_MMTU = 0x500
- IPV6_MULTICAST_HOPS = 0xa
- IPV6_MULTICAST_IF = 0x9
- IPV6_MULTICAST_LOOP = 0xb
- IPV6_NEXTHOP = 0x15
- IPV6_PKTINFO = 0x13
- IPV6_PKTOPTIONS = 0x19
- IPV6_PORTRANGE = 0xe
- IPV6_PORTRANGE_DEFAULT = 0
- IPV6_PORTRANGE_HIGH = 0x1
- IPV6_PORTRANGE_LOW = 0x2
- IPV6_RECVTCLASS = 0x23
- IPV6_RTHDR = 0x18
- IPV6_RTHDR_LOOSE = 0
- IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
- IPV6_SOCKOPT_RESERVED1 = 0x3
- IPV6_TCLASS = 0x24
- IPV6_UNICAST_HOPS = 0x4
- IPV6_V6ONLY = 0x1b
- IPV6_VERSION = 0x60
- IPV6_VERSION_MASK = 0xf0
- IP_ADD_MEMBERSHIP = 0xc
- IP_BOUND_IF = 0x19
- IP_DEFAULT_MULTICAST_LOOP = 0x1
- IP_DEFAULT_MULTICAST_TTL = 0x1
- IP_DF = 0x4000
- IP_DROP_MEMBERSHIP = 0xd
- IP_DUMMYNET_CONFIGURE = 0x3c
- IP_DUMMYNET_DEL = 0x3d
- IP_DUMMYNET_FLUSH = 0x3e
- IP_DUMMYNET_GET = 0x40
- IP_FAITH = 0x16
- IP_FW_ADD = 0x28
- IP_FW_DEL = 0x29
- IP_FW_FLUSH = 0x2a
- IP_FW_GET = 0x2c
- IP_FW_RESETLOG = 0x2d
- IP_FW_ZERO = 0x2b
- IP_HDRINCL = 0x2
- IP_IPSEC_POLICY = 0x15
- IP_MAXPACKET = 0xffff
- IP_MAX_MEMBERSHIPS = 0x14
- IP_MF = 0x2000
- IP_MSS = 0x240
- IP_MULTICAST_IF = 0x9
- IP_MULTICAST_LOOP = 0xb
- IP_MULTICAST_TTL = 0xa
- IP_MULTICAST_VIF = 0xe
- IP_NAT__XXX = 0x37
- IP_OFFMASK = 0x1fff
- IP_OLD_FW_ADD = 0x32
- IP_OLD_FW_DEL = 0x33
- IP_OLD_FW_FLUSH = 0x34
- IP_OLD_FW_GET = 0x36
- IP_OLD_FW_RESETLOG = 0x38
- IP_OLD_FW_ZERO = 0x35
- IP_OPTIONS = 0x1
- IP_PORTRANGE = 0x13
- IP_PORTRANGE_DEFAULT = 0
- IP_PORTRANGE_HIGH = 0x1
- IP_PORTRANGE_LOW = 0x2
- IP_RECVDSTADDR = 0x7
- IP_RECVIF = 0x14
- IP_RECVOPTS = 0x5
- IP_RECVRETOPTS = 0x6
- IP_RECVTTL = 0x18
- IP_RETOPTS = 0x8
- IP_RF = 0x8000
- IP_RSVP_OFF = 0x10
- IP_RSVP_ON = 0xf
- IP_RSVP_VIF_OFF = 0x12
- IP_RSVP_VIF_ON = 0x11
- IP_STRIPHDR = 0x17
- IP_TOS = 0x3
- IP_TRAFFIC_MGT_BACKGROUND = 0x41
- IP_TTL = 0x4
- MADV_CAN_REUSE = 0x9
- MADV_DONTNEED = 0x4
- MADV_FREE = 0x5
- MADV_FREE_REUSABLE = 0x7
- MADV_FREE_REUSE = 0x8
- MADV_NORMAL = 0
- MADV_RANDOM = 0x1
- MADV_SEQUENTIAL = 0x2
- MADV_WILLNEED = 0x3
- MADV_ZERO_WIRED_PAGES = 0x6
- MAP_ANON = 0x1000
- MAP_COPY = 0x2
- MAP_FILE = 0
- MAP_FIXED = 0x10
- MAP_HASSEMAPHORE = 0x200
- MAP_NOCACHE = 0x400
- MAP_NOEXTEND = 0x100
- MAP_NORESERVE = 0x40
- MAP_PRIVATE = 0x2
- MAP_RENAME = 0x20
- MAP_RESERVED0080 = 0x80
- MAP_SHARED = 0x1
- MCL_CURRENT = 0x1
- MCL_FUTURE = 0x2
- MSG_CTRUNC = 0x20
- MSG_DONTROUTE = 0x4
- MSG_DONTWAIT = 0x80
- MSG_EOF = 0x100
- MSG_EOR = 0x8
- MSG_FLUSH = 0x400
- MSG_HAVEMORE = 0x2000
- MSG_HOLD = 0x800
- MSG_NEEDSA = 0x10000
- MSG_OOB = 0x1
- MSG_PEEK = 0x2
- MSG_RCVMORE = 0x4000
- MSG_SEND = 0x1000
- MSG_TRUNC = 0x10
- MSG_WAITALL = 0x40
- MSG_WAITSTREAM = 0x200
- MS_ASYNC = 0x1
- MS_DEACTIVATE = 0x8
- MS_INVALIDATE = 0x2
- MS_KILLPAGES = 0x4
- MS_SYNC = 0x10
- NAME_MAX = 0xff
- NET_RT_DUMP = 0x1
- NET_RT_DUMP2 = 0x7
- NET_RT_FLAGS = 0x2
- NET_RT_IFLIST = 0x3
- NET_RT_IFLIST2 = 0x6
- NET_RT_MAXID = 0x8
- NET_RT_STAT = 0x4
- NET_RT_TRASH = 0x5
- O_ACCMODE = 0x3
- O_ALERT = 0x20000000
- O_APPEND = 0x8
- O_ASYNC = 0x40
- O_CREAT = 0x200
- O_DIRECTORY = 0x100000
- O_DSYNC = 0x400000
- O_EVTONLY = 0x8000
- O_EXCL = 0x800
- O_EXLOCK = 0x20
- O_FSYNC = 0x80
- O_NDELAY = 0x4
- O_NOCTTY = 0x20000
- O_NOFOLLOW = 0x100
- O_NONBLOCK = 0x4
- O_POPUP = 0x80000000
- O_RDONLY = 0
- O_RDWR = 0x2
- O_SHLOCK = 0x10
- O_SYMLINK = 0x200000
- O_SYNC = 0x80
- O_TRUNC = 0x400
- O_WRONLY = 0x1
- PROT_EXEC = 0x4
- PROT_NONE = 0
- PROT_READ = 0x1
- PROT_WRITE = 0x2
- PT_ATTACH = 0xa
- PT_ATTACHEXC = 0xe
- PT_CONTINUE = 0x7
- PT_DENY_ATTACH = 0x1f
- PT_DETACH = 0xb
- PT_FIRSTMACH = 0x20
- PT_FORCEQUOTA = 0x1e
- PT_KILL = 0x8
- PT_READ_D = 0x2
- PT_READ_I = 0x1
- PT_READ_U = 0x3
- PT_SIGEXC = 0xc
- PT_STEP = 0x9
- PT_THUPDATE = 0xd
- PT_TRACE_ME = 0
- PT_WRITE_D = 0x5
- PT_WRITE_I = 0x4
- PT_WRITE_U = 0x6
- RTAX_AUTHOR = 0x6
- RTAX_BRD = 0x7
- RTAX_DST = 0
- RTAX_GATEWAY = 0x1
- RTAX_GENMASK = 0x3
- RTAX_IFA = 0x5
- RTAX_IFP = 0x4
- RTAX_MAX = 0x8
- RTAX_NETMASK = 0x2
- RTA_AUTHOR = 0x40
- RTA_BRD = 0x80
- RTA_DST = 0x1
- RTA_GATEWAY = 0x2
- RTA_GENMASK = 0x8
- RTA_IFA = 0x20
- RTA_IFP = 0x10
- RTA_NETMASK = 0x4
- RTF_BLACKHOLE = 0x1000
- RTF_BROADCAST = 0x400000
- RTF_CLONING = 0x100
- RTF_CONDEMNED = 0x2000000
- RTF_DELCLONE = 0x80
- RTF_DONE = 0x40
- RTF_DYNAMIC = 0x10
- RTF_GATEWAY = 0x2
- RTF_HOST = 0x4
- RTF_IFREF = 0x4000000
- RTF_IFSCOPE = 0x1000000
- RTF_LLINFO = 0x400
- RTF_LOCAL = 0x200000
- RTF_MODIFIED = 0x20
- RTF_MULTICAST = 0x800000
- RTF_PINNED = 0x100000
- RTF_PRCLONING = 0x10000
- RTF_PROTO1 = 0x8000
- RTF_PROTO2 = 0x4000
- RTF_PROTO3 = 0x40000
- RTF_REJECT = 0x8
- RTF_STATIC = 0x800
- RTF_UP = 0x1
- RTF_WASCLONED = 0x20000
- RTF_XRESOLVE = 0x200
- RTM_ADD = 0x1
- RTM_CHANGE = 0x3
- RTM_DELADDR = 0xd
- RTM_DELETE = 0x2
- RTM_DELMADDR = 0x10
- RTM_GET = 0x4
- RTM_GET2 = 0x14
- RTM_IFINFO = 0xe
- RTM_IFINFO2 = 0x12
- RTM_LOCK = 0x8
- RTM_LOSING = 0x5
- RTM_MISS = 0x7
- RTM_NEWADDR = 0xc
- RTM_NEWMADDR = 0xf
- RTM_NEWMADDR2 = 0x13
- RTM_OLDADD = 0x9
- RTM_OLDDEL = 0xa
- RTM_REDIRECT = 0x6
- RTM_RESOLVE = 0xb
- RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x5
- RTV_EXPIRE = 0x4
- RTV_HOPCOUNT = 0x2
- RTV_MTU = 0x1
- RTV_RPIPE = 0x8
- RTV_RTT = 0x40
- RTV_RTTVAR = 0x80
- RTV_SPIPE = 0x10
- RTV_SSTHRESH = 0x20
- SCM_CREDS = 0x3
- SCM_RIGHTS = 0x1
- SCM_TIMESTAMP = 0x2
- SHUT_RD = 0
- SHUT_RDWR = 0x2
- SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0xa
- SIGCHLD = 0x14
- SIGCONT = 0x13
- SIGEMT = 0x7
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINFO = 0x1d
- SIGINT = 0x2
- SIGIO = 0x17
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGPIPE = 0xd
- SIGPROF = 0x1b
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTOP = 0x11
- SIGSYS = 0xc
- SIGTERM = 0xf
- SIGTRAP = 0x5
- SIGTSTP = 0x12
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGURG = 0x10
- SIGUSR1 = 0x1e
- SIGUSR2 = 0x1f
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
- SIOCADDMULTI = 0x80206931
- SIOCAIFADDR = 0x8040691a
- SIOCALIFADDR = 0x8118691d
- SIOCARPIPLL = 0xc0206928
- SIOCATMARK = 0x40047307
- SIOCAUTOADDR = 0xc0206926
- SIOCAUTONETMASK = 0x80206927
- SIOCDELMULTI = 0x80206932
- SIOCDIFADDR = 0x80206919
- SIOCDIFPHYADDR = 0x80206941
- SIOCDLIFADDR = 0x8118691f
- SIOCGDRVSPEC = 0xc01c697b
- SIOCGETSGCNT = 0xc014721c
- SIOCGETVIFCNT = 0xc014721b
- SIOCGETVLAN = 0xc020697f
- SIOCGHIWAT = 0x40047301
- SIOCGIFADDR = 0xc0206921
- SIOCGIFALTMTU = 0xc0206948
- SIOCGIFASYNCMAP = 0xc020697c
- SIOCGIFBOND = 0xc0206947
- SIOCGIFBRDADDR = 0xc0206923
- SIOCGIFCONF = 0xc0086924
- SIOCGIFDEVMTU = 0xc0206944
- SIOCGIFDSTADDR = 0xc0206922
- SIOCGIFFLAGS = 0xc0206911
- SIOCGIFGENERIC = 0xc020693a
- SIOCGIFKPI = 0xc0206987
- SIOCGIFMAC = 0xc0206982
- SIOCGIFMEDIA = 0xc0286938
- SIOCGIFMETRIC = 0xc0206917
- SIOCGIFMTU = 0xc0206933
- SIOCGIFNETMASK = 0xc0206925
- SIOCGIFPDSTADDR = 0xc0206940
- SIOCGIFPHYS = 0xc0206935
- SIOCGIFPSRCADDR = 0xc020693f
- SIOCGIFSTATUS = 0xc331693d
- SIOCGIFVLAN = 0xc020697f
- SIOCGIFWAKEFLAGS = 0xc0206988
- SIOCGLIFADDR = 0xc118691e
- SIOCGLIFPHYADDR = 0xc1186943
- SIOCGLOWAT = 0x40047303
- SIOCGPGRP = 0x40047309
- SIOCIFCREATE = 0xc0206978
- SIOCIFCREATE2 = 0xc020697a
- SIOCIFDESTROY = 0x80206979
- SIOCRSLVMULTI = 0xc008693b
- SIOCSDRVSPEC = 0x801c697b
- SIOCSETVLAN = 0x8020697e
- SIOCSHIWAT = 0x80047300
- SIOCSIFADDR = 0x8020690c
- SIOCSIFALTMTU = 0x80206945
- SIOCSIFASYNCMAP = 0x8020697d
- SIOCSIFBOND = 0x80206946
- SIOCSIFBRDADDR = 0x80206913
- SIOCSIFDSTADDR = 0x8020690e
- SIOCSIFFLAGS = 0x80206910
- SIOCSIFGENERIC = 0x80206939
- SIOCSIFKPI = 0x80206986
- SIOCSIFLLADDR = 0x8020693c
- SIOCSIFMAC = 0x80206983
- SIOCSIFMEDIA = 0xc0206937
- SIOCSIFMETRIC = 0x80206918
- SIOCSIFMTU = 0x80206934
- SIOCSIFNETMASK = 0x80206916
- SIOCSIFPHYADDR = 0x8040693e
- SIOCSIFPHYS = 0x80206936
- SIOCSIFVLAN = 0x8020697e
- SIOCSLIFPHYADDR = 0x81186942
- SIOCSLOWAT = 0x80047302
- SIOCSPGRP = 0x80047308
- SOCK_DGRAM = 0x2
- SOCK_MAXADDRLEN = 0xff
- SOCK_RAW = 0x3
- SOCK_RDM = 0x4
- SOCK_SEQPACKET = 0x5
- SOCK_STREAM = 0x1
- SOL_SOCKET = 0xffff
- SOMAXCONN = 0x80
- SO_ACCEPTCONN = 0x2
- SO_BROADCAST = 0x20
- SO_DEBUG = 0x1
- SO_DONTROUTE = 0x10
- SO_DONTTRUNC = 0x2000
- SO_ERROR = 0x1007
- SO_KEEPALIVE = 0x8
- SO_LABEL = 0x1010
- SO_LINGER = 0x80
- SO_LINGER_SEC = 0x1080
- SO_NKE = 0x1021
- SO_NOADDRERR = 0x1023
- SO_NOSIGPIPE = 0x1022
- SO_NOTIFYCONFLICT = 0x1026
- SO_NP_EXTENSIONS = 0x1083
- SO_NREAD = 0x1020
- SO_NWRITE = 0x1024
- SO_OOBINLINE = 0x100
- SO_PEERLABEL = 0x1011
- SO_RANDOMPORT = 0x1082
- SO_RCVBUF = 0x1002
- SO_RCVLOWAT = 0x1004
- SO_RCVTIMEO = 0x1006
- SO_RESTRICTIONS = 0x1081
- SO_RESTRICT_DENYIN = 0x1
- SO_RESTRICT_DENYOUT = 0x2
- SO_RESTRICT_DENYSET = 0x80000000
- SO_REUSEADDR = 0x4
- SO_REUSEPORT = 0x200
- SO_REUSESHAREUID = 0x1025
- SO_SNDBUF = 0x1001
- SO_SNDLOWAT = 0x1003
- SO_SNDTIMEO = 0x1005
- SO_TIMESTAMP = 0x400
- SO_TYPE = 0x1008
- SO_UPCALLCLOSEWAIT = 0x1027
- SO_USELOOPBACK = 0x40
- SO_WANTMORE = 0x4000
- SO_WANTOOBFLAG = 0x8000
- S_IEXEC = 0x40
- S_IFBLK = 0x6000
- S_IFCHR = 0x2000
- S_IFDIR = 0x4000
- S_IFIFO = 0x1000
- S_IFLNK = 0xa000
- S_IFMT = 0xf000
- S_IFREG = 0x8000
- S_IFSOCK = 0xc000
- S_IFWHT = 0xe000
- S_IREAD = 0x100
- S_IRGRP = 0x20
- S_IROTH = 0x4
- S_IRUSR = 0x100
- S_IRWXG = 0x38
- S_IRWXO = 0x7
- S_IRWXU = 0x1c0
- S_ISGID = 0x400
- S_ISTXT = 0x200
- S_ISUID = 0x800
- S_ISVTX = 0x200
- S_IWGRP = 0x10
- S_IWOTH = 0x2
- S_IWRITE = 0x80
- S_IWUSR = 0x80
- S_IXGRP = 0x8
- S_IXOTH = 0x1
- S_IXUSR = 0x40
- TCP_CONNECTIONTIMEOUT = 0x20
- TCP_KEEPALIVE = 0x10
- TCP_MAXBURST = 0x4
- TCP_MAXHLEN = 0x3c
- TCP_MAXOLEN = 0x28
- TCP_MAXSEG = 0x2
- TCP_MAXWIN = 0xffff
- TCP_MAX_SACK = 0x3
- TCP_MAX_WINSHIFT = 0xe
- TCP_MINMSS = 0xd8
- TCP_MINMSSOVERLOAD = 0x3e8
- TCP_MSS = 0x200
- TCP_NODELAY = 0x1
- TCP_NOOPT = 0x8
- TCP_NOPUSH = 0x4
- TIOCCBRK = 0x2000747a
- TIOCCDTR = 0x20007478
- TIOCCONS = 0x80047462
- TIOCDCDTIMESTAMP = 0x40087458
- TIOCDRAIN = 0x2000745e
- TIOCDSIMICROCODE = 0x20007455
- TIOCEXCL = 0x2000740d
- TIOCEXT = 0x80047460
- TIOCFLUSH = 0x80047410
- TIOCGDRAINWAIT = 0x40047456
- TIOCGETA = 0x402c7413
- TIOCGETD = 0x4004741a
- TIOCGPGRP = 0x40047477
- TIOCGWINSZ = 0x40087468
- TIOCIXOFF = 0x20007480
- TIOCIXON = 0x20007481
- TIOCMBIC = 0x8004746b
- TIOCMBIS = 0x8004746c
- TIOCMGDTRWAIT = 0x4004745a
- TIOCMGET = 0x4004746a
- TIOCMODG = 0x40047403
- TIOCMODS = 0x80047404
- TIOCMSDTRWAIT = 0x8004745b
- TIOCMSET = 0x8004746d
- TIOCM_CAR = 0x40
- TIOCM_CD = 0x40
- TIOCM_CTS = 0x20
- TIOCM_DSR = 0x100
- TIOCM_DTR = 0x2
- TIOCM_LE = 0x1
- TIOCM_RI = 0x80
- TIOCM_RNG = 0x80
- TIOCM_RTS = 0x4
- TIOCM_SR = 0x10
- TIOCM_ST = 0x8
- TIOCNOTTY = 0x20007471
- TIOCNXCL = 0x2000740e
- TIOCOUTQ = 0x40047473
- TIOCPKT = 0x80047470
- TIOCPKT_DATA = 0
- TIOCPKT_DOSTOP = 0x20
- TIOCPKT_FLUSHREAD = 0x1
- TIOCPKT_FLUSHWRITE = 0x2
- TIOCPKT_IOCTL = 0x40
- TIOCPKT_NOSTOP = 0x10
- TIOCPKT_START = 0x8
- TIOCPKT_STOP = 0x4
- TIOCPTYGNAME = 0x40807453
- TIOCPTYGRANT = 0x20007454
- TIOCPTYUNLK = 0x20007452
- TIOCREMOTE = 0x80047469
- TIOCSBRK = 0x2000747b
- TIOCSCONS = 0x20007463
- TIOCSCTTY = 0x20007461
- TIOCSDRAINWAIT = 0x80047457
- TIOCSDTR = 0x20007479
- TIOCSETA = 0x802c7414
- TIOCSETAF = 0x802c7416
- TIOCSETAW = 0x802c7415
- TIOCSETD = 0x8004741b
- TIOCSIG = 0x2000745f
- TIOCSPGRP = 0x80047476
- TIOCSTART = 0x2000746e
- TIOCSTAT = 0x20007465
- TIOCSTI = 0x80017472
- TIOCSTOP = 0x2000746f
- TIOCSWINSZ = 0x80087467
- TIOCTIMESTAMP = 0x40087459
- TIOCUCNTL = 0x80047466
- WCONTINUED = 0x10
- WCOREFLAG = 0x80
- WEXITED = 0x4
- WNOHANG = 0x1
- WNOWAIT = 0x20
- WORDSIZE = 0x20
- WSTOPPED = 0x8
- WUNTRACED = 0x2
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1c
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IEEE80211 = 0x25
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1e
+ AF_IPX = 0x17
+ AF_ISDN = 0x1c
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x26
+ AF_NATM = 0x1f
+ AF_NDRV = 0x1b
+ AF_NETBIOS = 0x21
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PPP = 0x22
+ AF_PUP = 0x4
+ AF_RESERVED_36 = 0x24
+ AF_ROUTE = 0x11
+ AF_SIP = 0x18
+ AF_SNA = 0xb
+ AF_SYSTEM = 0x20
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc00c4279
+ BIOCGETIF = 0x4020426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDLT = 0x80044278
+ BIOCSETF = 0x80084267
+ BIOCSETIF = 0x8020426c
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_C_HDLC = 0x68
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_SERIAL = 0x32
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_MACHPORT = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xc
+ EVFILT_THREADMARKER = 0xc
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xa
+ EVFILT_VM = -0xc
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG0 = 0x1000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_OOBAND = 0x2000
+ EV_POLL = 0x1000
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_ADDFILESIGS = 0x3d
+ F_ADDSIGS = 0x3b
+ F_ALLOCATEALL = 0x4
+ F_ALLOCATECONTIG = 0x2
+ F_CHKCLEAN = 0x29
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x43
+ F_FLUSH_DATA = 0x28
+ F_FREEZE_FS = 0x35
+ F_FULLFSYNC = 0x33
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETLKPID = 0x42
+ F_GETNOSIGPIPE = 0x4a
+ F_GETOWN = 0x5
+ F_GETPATH = 0x32
+ F_GETPATH_MTMINFO = 0x47
+ F_GETPROTECTIONCLASS = 0x3f
+ F_GLOBAL_NOCACHE = 0x37
+ F_LOG2PHYS = 0x31
+ F_LOG2PHYS_EXT = 0x41
+ F_MARKDEPENDENCY = 0x3c
+ F_NOCACHE = 0x30
+ F_NODIRECT = 0x3e
+ F_OK = 0x0
+ F_PATHPKG_CHECK = 0x34
+ F_PEOFPOSMODE = 0x3
+ F_PREALLOCATE = 0x2a
+ F_RDADVISE = 0x2c
+ F_RDAHEAD = 0x2d
+ F_RDLCK = 0x1
+ F_READBOOTSTRAP = 0x2e
+ F_SETBACKINGSTORE = 0x46
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETNOSIGPIPE = 0x49
+ F_SETOWN = 0x6
+ F_SETPROTECTIONCLASS = 0x40
+ F_SETSIZE = 0x2b
+ F_THAW_FS = 0x36
+ F_UNLCK = 0x2
+ F_VOLPOSMODE = 0x4
+ F_WRITEBOOTSTRAP = 0x2f
+ F_WRLCK = 0x3
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_BRIDGE = 0xd1
+ IFT_CARP = 0xf8
+ IFT_CELLULAR = 0xff
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0x38
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIF = 0x37
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE8023ADLAG = 0x88
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_L2VLAN = 0x87
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PDP = 0xff
+ IFT_PFLOG = 0xf5
+ IFT_PFSYNC = 0xf6
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_STF = 0x39
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LINKLOCALNETNUM = 0xa9fe0000
+ IN_LOOPBACKNET = 0x7f
+ IPPROTO_3PC = 0x22
+ IPPROTO_ADFS = 0x44
+ IPPROTO_AH = 0x33
+ IPPROTO_AHIP = 0x3d
+ IPPROTO_APES = 0x63
+ IPPROTO_ARGUS = 0xd
+ IPPROTO_AX25 = 0x5d
+ IPPROTO_BHA = 0x31
+ IPPROTO_BLT = 0x1e
+ IPPROTO_BRSATMON = 0x4c
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0xfe
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EMCON = 0xe
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GMTP = 0x64
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HMP = 0x14
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IDPR = 0x23
+ IPPROTO_IDRP = 0x2d
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IGP = 0x55
+ IPPROTO_IGRP = 0x58
+ IPPROTO_IL = 0x28
+ IPPROTO_INLSP = 0x34
+ IPPROTO_INP = 0x20
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPCV = 0x47
+ IPPROTO_IPEIP = 0x5e
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPPC = 0x43
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_IRTP = 0x1c
+ IPPROTO_KRYPTOLAN = 0x41
+ IPPROTO_LARP = 0x5b
+ IPPROTO_LEAF1 = 0x19
+ IPPROTO_LEAF2 = 0x1a
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x34
+ IPPROTO_MEAS = 0x13
+ IPPROTO_MHRP = 0x30
+ IPPROTO_MICP = 0x5f
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PGM = 0x71
+ IPPROTO_PIGP = 0x9
+ IPPROTO_PIM = 0x67
+ IPPROTO_PRM = 0x15
+ IPPROTO_PUP = 0xc
+ IPPROTO_PVP = 0x4b
+ IPPROTO_RAW = 0xff
+ IPPROTO_RCCMON = 0xa
+ IPPROTO_RDP = 0x1b
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_RVD = 0x42
+ IPPROTO_SATEXPAK = 0x40
+ IPPROTO_SATMON = 0x45
+ IPPROTO_SCCSP = 0x60
+ IPPROTO_SCTP = 0x84
+ IPPROTO_SDRP = 0x2a
+ IPPROTO_SEP = 0x21
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_TPXX = 0x27
+ IPPROTO_TRUNK1 = 0x17
+ IPPROTO_TRUNK2 = 0x18
+ IPPROTO_TTP = 0x54
+ IPPROTO_UDP = 0x11
+ IPPROTO_VINES = 0x53
+ IPPROTO_VISA = 0x46
+ IPPROTO_VMTP = 0x51
+ IPPROTO_WBEXPAK = 0x4f
+ IPPROTO_WBMON = 0x4e
+ IPPROTO_WSN = 0x4a
+ IPPROTO_XNET = 0xf
+ IPPROTO_XTP = 0x24
+ IPV6_2292DSTOPTS = 0x17
+ IPV6_2292HOPLIMIT = 0x14
+ IPV6_2292HOPOPTS = 0x16
+ IPV6_2292NEXTHOP = 0x15
+ IPV6_2292PKTINFO = 0x13
+ IPV6_2292PKTOPTIONS = 0x19
+ IPV6_2292RTHDR = 0x18
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_BOUND_IF = 0x7d
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_FW_ADD = 0x1e
+ IPV6_FW_DEL = 0x1f
+ IPV6_FW_FLUSH = 0x20
+ IPV6_FW_GET = 0x22
+ IPV6_FW_ZERO = 0x21
+ IPV6_HLIMDEC = 0x1
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXOPTHDR = 0x800
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MAX_GROUP_SRC_FILTER = 0x200
+ IPV6_MAX_MEMBERSHIPS = 0xfff
+ IPV6_MAX_SOCK_SRC_FILTER = 0x80
+ IPV6_MIN_MEMBERSHIPS = 0x1f
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVTCLASS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x24
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_ADD_SOURCE_MEMBERSHIP = 0x46
+ IP_BLOCK_SOURCE = 0x48
+ IP_BOUND_IF = 0x19
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DROP_SOURCE_MEMBERSHIP = 0x47
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW_ADD = 0x28
+ IP_FW_DEL = 0x29
+ IP_FW_FLUSH = 0x2a
+ IP_FW_GET = 0x2c
+ IP_FW_RESETLOG = 0x2d
+ IP_FW_ZERO = 0x2b
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_GROUP_SRC_FILTER = 0x200
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MAX_SOCK_MUTE_FILTER = 0x80
+ IP_MAX_SOCK_SRC_FILTER = 0x80
+ IP_MF = 0x2000
+ IP_MIN_MEMBERSHIPS = 0x1f
+ IP_MSFILTER = 0x4a
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_IFINDEX = 0x42
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_NAT__XXX = 0x37
+ IP_OFFMASK = 0x1fff
+ IP_OLD_FW_ADD = 0x32
+ IP_OLD_FW_DEL = 0x33
+ IP_OLD_FW_FLUSH = 0x34
+ IP_OLD_FW_GET = 0x36
+ IP_OLD_FW_RESETLOG = 0x38
+ IP_OLD_FW_ZERO = 0x35
+ IP_OPTIONS = 0x1
+ IP_PKTINFO = 0x1a
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVOPTS = 0x5
+ IP_RECVPKTINFO = 0x1a
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x18
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RSVP_OFF = 0x10
+ IP_RSVP_ON = 0xf
+ IP_RSVP_VIF_OFF = 0x12
+ IP_RSVP_VIF_ON = 0x11
+ IP_STRIPHDR = 0x17
+ IP_TOS = 0x3
+ IP_TRAFFIC_MGT_BACKGROUND = 0x41
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x49
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_CAN_REUSE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_FREE_REUSABLE = 0x7
+ MADV_FREE_REUSE = 0x8
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MADV_ZERO_WIRED_PAGES = 0x6
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_JIT = 0x800
+ MAP_NOCACHE = 0x400
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_SHARED = 0x1
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_FLUSH = 0x400
+ MSG_HAVEMORE = 0x2000
+ MSG_HOLD = 0x800
+ MSG_NEEDSA = 0x10000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_RCVMORE = 0x4000
+ MSG_SEND = 0x1000
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITSTREAM = 0x200
+ MS_ASYNC = 0x1
+ MS_DEACTIVATE = 0x8
+ MS_INVALIDATE = 0x2
+ MS_KILLPAGES = 0x4
+ MS_SYNC = 0x10
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_DUMP2 = 0x7
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFLIST2 = 0x6
+ NET_RT_MAXID = 0xa
+ NET_RT_STAT = 0x4
+ NET_RT_TRASH = 0x5
+ NOTE_ABSOLUTE = 0x8
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXITSTATUS = 0x4000000
+ NOTE_EXTEND = 0x4
+ NOTE_FFAND = 0x40000000
+ NOTE_FFCOPY = 0xc0000000
+ NOTE_FFCTRLMASK = 0xc0000000
+ NOTE_FFLAGSMASK = 0xffffff
+ NOTE_FFNOP = 0x0
+ NOTE_FFOR = 0x80000000
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_NONE = 0x80
+ NOTE_NSECONDS = 0x4
+ NOTE_PCTRLMASK = -0x100000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_REAP = 0x10000000
+ NOTE_RENAME = 0x20
+ NOTE_RESOURCEEND = 0x2000000
+ NOTE_REVOKE = 0x40
+ NOTE_SECONDS = 0x1
+ NOTE_SIGNAL = 0x8000000
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRIGGER = 0x1000000
+ NOTE_USECONDS = 0x2
+ NOTE_VM_ERROR = 0x10000000
+ NOTE_VM_PRESSURE = 0x80000000
+ NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
+ NOTE_VM_PRESSURE_TERMINATE = 0x40000000
+ NOTE_WRITE = 0x2
+ O_ACCMODE = 0x3
+ O_ALERT = 0x20000000
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x1000000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x100000
+ O_DSYNC = 0x400000
+ O_EVTONLY = 0x8000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x20000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_POPUP = 0x80000000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYMLINK = 0x200000
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0x0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
+ RLIMIT_AS = 0x5
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_CLONING = 0x100
+ RTF_CONDEMNED = 0x2000000
+ RTF_DELCLONE = 0x80
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_IFREF = 0x4000000
+ RTF_IFSCOPE = 0x1000000
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_WASCLONED = 0x20000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_GET2 = 0x14
+ RTM_IFINFO = 0xe
+ RTM_IFINFO2 = 0x12
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_NEWMADDR2 = 0x13
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SCM_TIMESTAMP_MONOTONIC = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCALIFADDR = 0x8118691d
+ SIOCARPIPLL = 0xc0206928
+ SIOCATMARK = 0x40047307
+ SIOCAUTOADDR = 0xc0206926
+ SIOCAUTONETMASK = 0x80206927
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFPHYADDR = 0x80206941
+ SIOCDLIFADDR = 0x8118691f
+ SIOCGDRVSPEC = 0xc01c697b
+ SIOCGETSGCNT = 0xc014721c
+ SIOCGETVIFCNT = 0xc014721b
+ SIOCGETVLAN = 0xc020697f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFALTMTU = 0xc0206948
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBOND = 0xc0206947
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCAP = 0xc020695b
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDEVMTU = 0xc0206944
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFKPI = 0xc0206987
+ SIOCGIFMAC = 0xc0206982
+ SIOCGIFMEDIA = 0xc0286938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206940
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc020693f
+ SIOCGIFSTATUS = 0xc331693d
+ SIOCGIFVLAN = 0xc020697f
+ SIOCGIFWAKEFLAGS = 0xc0206988
+ SIOCGLIFADDR = 0xc118691e
+ SIOCGLIFPHYADDR = 0xc1186943
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCIFCREATE = 0xc0206978
+ SIOCIFCREATE2 = 0xc020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCRSLVMULTI = 0xc008693b
+ SIOCSDRVSPEC = 0x801c697b
+ SIOCSETVLAN = 0x8020697e
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFALTMTU = 0x80206945
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBOND = 0x80206946
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFCAP = 0x8020695a
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFKPI = 0x80206986
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206983
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x8040693e
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFVLAN = 0x8020697e
+ SIOCSLIFPHYADDR = 0x81186942
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_DONTTRUNC = 0x2000
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1010
+ SO_LINGER = 0x80
+ SO_LINGER_SEC = 0x1080
+ SO_NKE = 0x1021
+ SO_NOADDRERR = 0x1023
+ SO_NOSIGPIPE = 0x1022
+ SO_NOTIFYCONFLICT = 0x1026
+ SO_NP_EXTENSIONS = 0x1083
+ SO_NREAD = 0x1020
+ SO_NWRITE = 0x1024
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1011
+ SO_RANDOMPORT = 0x1082
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_RESTRICTIONS = 0x1081
+ SO_RESTRICT_DENYIN = 0x1
+ SO_RESTRICT_DENYOUT = 0x2
+ SO_RESTRICT_DENYSET = 0x80000000
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_REUSESHAREUID = 0x1025
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TIMESTAMP_MONOTONIC = 0x800
+ SO_TYPE = 0x1008
+ SO_UPCALLCLOSEWAIT = 0x1027
+ SO_USELOOPBACK = 0x40
+ SO_WANTMORE = 0x4000
+ SO_WANTOOBFLAG = 0x8000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCP_CONNECTIONTIMEOUT = 0x20
+ TCP_KEEPALIVE = 0x10
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MINMSS = 0xd8
+ TCP_MINMSSOVERLOAD = 0x3e8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ TCP_RXT_CONNDROPTIME = 0x80
+ TCP_RXT_FINDROP = 0x100
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDCDTIMESTAMP = 0x40087458
+ TIOCDRAIN = 0x2000745e
+ TIOCDSIMICROCODE = 0x20007455
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGWINSZ = 0x40087468
+ TIOCIXOFF = 0x20007480
+ TIOCIXON = 0x20007481
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0x80047404
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTYGNAME = 0x40807453
+ TIOCPTYGRANT = 0x20007454
+ TIOCPTYUNLK = 0x20007452
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCONS = 0x20007463
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2000745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40087459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x10
+ WCOREFLAG = 0x80
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOWAIT = 0x20
+ WORDSIZE = 0x20
+ WSTOPPED = 0x8
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADARCH = Errno(0x56)
+ EBADEXEC = Errno(0x55)
+ EBADF = Errno(0x9)
+ EBADMACHO = Errno(0x58)
+ EBADMSG = Errno(0x5e)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x59)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDEVERR = Errno(0x53)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x5a)
+ EILSEQ = Errno(0x5c)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x69)
+ ELOOP = Errno(0x3e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ EMULTIHOP = Errno(0x5f)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x5d)
+ ENOBUFS = Errno(0x37)
+ ENODATA = Errno(0x60)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOLINK = Errno(0x61)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5b)
+ ENOPOLICY = Errno(0x67)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x62)
+ ENOSTR = Errno(0x63)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x68)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x2d)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x66)
+ EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x69)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTO = Errno(0x64)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ EPWROFF = Errno(0x52)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHLIBVERS = Errno(0x57)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIME = Errno(0x65)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
)
-// Types
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1192,4 +1284,41 @@ var errors = [...]string{
101: "STREAM ioctl timeout",
102: "operation not supported on socket",
103: "policy not found",
+ 104: "state not recoverable",
+ 105: "previous owner died",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "suspended (signal)",
+ 18: "suspended",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
}
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index 3165feea2..7fa5cfcd2 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -1,1091 +1,1183 @@
-// mkerrors.sh -f -m64
+// mkerrors.sh -m64
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
package syscall
-// Constants
const (
- AF_APPLETALK = 0x10
- AF_CCITT = 0xa
- AF_CHAOS = 0x5
- AF_CNT = 0x15
- AF_COIP = 0x14
- AF_DATAKIT = 0x9
- AF_DECnet = 0xc
- AF_DLI = 0xd
- AF_E164 = 0x1c
- AF_ECMA = 0x8
- AF_HYLINK = 0xf
- AF_IEEE80211 = 0x25
- AF_IMPLINK = 0x3
- AF_INET = 0x2
- AF_INET6 = 0x1e
- AF_IPX = 0x17
- AF_ISDN = 0x1c
- AF_ISO = 0x7
- AF_LAT = 0xe
- AF_LINK = 0x12
- AF_LOCAL = 0x1
- AF_MAX = 0x26
- AF_NATM = 0x1f
- AF_NDRV = 0x1b
- AF_NETBIOS = 0x21
- AF_NS = 0x6
- AF_OSI = 0x7
- AF_PPP = 0x22
- AF_PUP = 0x4
- AF_RESERVED_36 = 0x24
- AF_ROUTE = 0x11
- AF_SIP = 0x18
- AF_SNA = 0xb
- AF_SYSTEM = 0x20
- AF_UNIX = 0x1
- AF_UNSPEC = 0
- BIOCFLUSH = 0x20004268
- BIOCGBLEN = 0x40044266
- BIOCGDLT = 0x4004426a
- BIOCGDLTLIST = 0xc00c4279
- BIOCGETIF = 0x4020426b
- BIOCGHDRCMPLT = 0x40044274
- BIOCGRSIG = 0x40044272
- BIOCGRTIMEOUT = 0x4008426e
- BIOCGSEESENT = 0x40044276
- BIOCGSTATS = 0x4008426f
- BIOCIMMEDIATE = 0x80044270
- BIOCPROMISC = 0x20004269
- BIOCSBLEN = 0xc0044266
- BIOCSDLT = 0x80044278
- BIOCSETF = 0x80104267
- BIOCSETIF = 0x8020426c
- BIOCSHDRCMPLT = 0x80044275
- BIOCSRSIG = 0x80044273
- BIOCSRTIMEOUT = 0x8008426d
- BIOCSSEESENT = 0x80044277
- BIOCVERSION = 0x40044271
- BPF_A = 0x10
- BPF_ABS = 0x20
- BPF_ADD = 0
- BPF_ALIGNMENT = 0x4
- BPF_ALU = 0x4
- BPF_AND = 0x50
- BPF_B = 0x10
- BPF_DIV = 0x30
- BPF_H = 0x8
- BPF_IMM = 0
- BPF_IND = 0x40
- BPF_JA = 0
- BPF_JEQ = 0x10
- BPF_JGE = 0x30
- BPF_JGT = 0x20
- BPF_JMP = 0x5
- BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
- BPF_LDX = 0x1
- BPF_LEN = 0x80
- BPF_LSH = 0x60
- BPF_MAJOR_VERSION = 0x1
- BPF_MAXBUFSIZE = 0x80000
- BPF_MAXINSNS = 0x200
- BPF_MEM = 0x60
- BPF_MEMWORDS = 0x10
- BPF_MINBUFSIZE = 0x20
- BPF_MINOR_VERSION = 0x1
- BPF_MISC = 0x7
- BPF_MSH = 0xa0
- BPF_MUL = 0x20
- BPF_NEG = 0x80
- BPF_OR = 0x40
- BPF_RELEASE = 0x30bb6
- BPF_RET = 0x6
- BPF_RSH = 0x70
- BPF_ST = 0x2
- BPF_STX = 0x3
- BPF_SUB = 0x10
- BPF_TAX = 0
- BPF_TXA = 0x80
- BPF_W = 0
- BPF_X = 0x8
- CTL_MAXNAME = 0xc
- CTL_NET = 0x4
- DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
- DLT_ARCNET = 0x7
- DLT_ATM_CLIP = 0x13
- DLT_ATM_RFC1483 = 0xb
- DLT_AX25 = 0x3
- DLT_CHAOS = 0x5
- DLT_CHDLC = 0x68
- DLT_C_HDLC = 0x68
- DLT_EN10MB = 0x1
- DLT_EN3MB = 0x2
- DLT_FDDI = 0xa
- DLT_IEEE802 = 0x6
- DLT_IEEE802_11 = 0x69
- DLT_IEEE802_11_RADIO = 0x7f
- DLT_IEEE802_11_RADIO_AVS = 0xa3
- DLT_LINUX_SLL = 0x71
- DLT_LOOP = 0x6c
- DLT_NULL = 0
- DLT_PFLOG = 0x75
- DLT_PFSYNC = 0x12
- DLT_PPP = 0x9
- DLT_PPP_BSDOS = 0x10
- DLT_PPP_SERIAL = 0x32
- DLT_PRONET = 0x4
- DLT_RAW = 0xc
- DLT_SLIP = 0x8
- DLT_SLIP_BSDOS = 0xf
- DT_BLK = 0x6
- DT_CHR = 0x2
- DT_DIR = 0x4
- DT_FIFO = 0x1
- DT_LNK = 0xa
- DT_REG = 0x8
- DT_SOCK = 0xc
- DT_UNKNOWN = 0
- DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x30
- EADDRNOTAVAIL = 0x31
- EAFNOSUPPORT = 0x2f
- EAGAIN = 0x23
- EALREADY = 0x25
- EAUTH = 0x50
- EBADARCH = 0x56
- EBADEXEC = 0x55
- EBADF = 0x9
- EBADMACHO = 0x58
- EBADMSG = 0x5e
- EBADRPC = 0x48
- EBUSY = 0x10
- ECANCELED = 0x59
- ECHILD = 0xa
- ECHO = 0x8
- ECHOCTL = 0x40
- ECHOE = 0x2
- ECHOK = 0x4
- ECHOKE = 0x1
- ECHONL = 0x10
- ECHOPRT = 0x20
- ECONNABORTED = 0x35
- ECONNREFUSED = 0x3d
- ECONNRESET = 0x36
- EDEADLK = 0xb
- EDESTADDRREQ = 0x27
- EDEVERR = 0x53
- EDOM = 0x21
- EDQUOT = 0x45
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EFTYPE = 0x4f
- EHOSTDOWN = 0x40
- EHOSTUNREACH = 0x41
- EIDRM = 0x5a
- EILSEQ = 0x5c
- EINPROGRESS = 0x24
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x38
- EISDIR = 0x15
- ELAST = 0x67
- ELOOP = 0x3e
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x28
- EMULTIHOP = 0x5f
- ENAMETOOLONG = 0x3f
- ENEEDAUTH = 0x51
- ENETDOWN = 0x32
- ENETRESET = 0x34
- ENETUNREACH = 0x33
- ENFILE = 0x17
- ENOATTR = 0x5d
- ENOBUFS = 0x37
- ENODATA = 0x60
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOLCK = 0x4d
- ENOLINK = 0x61
- ENOMEM = 0xc
- ENOMSG = 0x5b
- ENOPOLICY = 0x67
- ENOPROTOOPT = 0x2a
- ENOSPC = 0x1c
- ENOSR = 0x62
- ENOSTR = 0x63
- ENOSYS = 0x4e
- ENOTBLK = 0xf
- ENOTCONN = 0x39
- ENOTDIR = 0x14
- ENOTEMPTY = 0x42
- ENOTSOCK = 0x26
- ENOTSUP = 0x2d
- ENOTTY = 0x19
- ENXIO = 0x6
- EOPNOTSUPP = 0x66
- EOVERFLOW = 0x54
- EPERM = 0x1
- EPFNOSUPPORT = 0x2e
- EPIPE = 0x20
- EPROCLIM = 0x43
- EPROCUNAVAIL = 0x4c
- EPROGMISMATCH = 0x4b
- EPROGUNAVAIL = 0x4a
- EPROTO = 0x64
- EPROTONOSUPPORT = 0x2b
- EPROTOTYPE = 0x29
- EPWROFF = 0x52
- ERANGE = 0x22
- EREMOTE = 0x47
- EROFS = 0x1e
- ERPCMISMATCH = 0x49
- ESHLIBVERS = 0x57
- ESHUTDOWN = 0x3a
- ESOCKTNOSUPPORT = 0x2c
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESTALE = 0x46
- ETIME = 0x65
- ETIMEDOUT = 0x3c
- ETOOMANYREFS = 0x3b
- ETXTBSY = 0x1a
- EUSERS = 0x44
- EVFILT_AIO = -0x3
- EVFILT_FS = -0x9
- EVFILT_MACHPORT = -0x8
- EVFILT_PROC = -0x5
- EVFILT_READ = -0x1
- EVFILT_SESSION = -0xb
- EVFILT_SIGNAL = -0x6
- EVFILT_SYSCOUNT = 0xb
- EVFILT_THREADMARKER = 0xb
- EVFILT_TIMER = -0x7
- EVFILT_USER = -0xa
- EVFILT_VNODE = -0x4
- EVFILT_WRITE = -0x2
- EV_ADD = 0x1
- EV_CLEAR = 0x20
- EV_DELETE = 0x2
- EV_DISABLE = 0x8
- EV_DISPATCH = 0x80
- EV_ENABLE = 0x4
- EV_EOF = 0x8000
- EV_ERROR = 0x4000
- EV_FLAG0 = 0x1000
- EV_FLAG1 = 0x2000
- EV_ONESHOT = 0x10
- EV_OOBAND = 0x2000
- EV_POLL = 0x1000
- EV_RECEIPT = 0x40
- EV_SYSFLAGS = 0xf000
- EV_TRIGGER = 0x100
- EWOULDBLOCK = 0x23
- EXDEV = 0x12
- EXTA = 0x4b00
- EXTB = 0x9600
- EXTPROC = 0x800
- FD_CLOEXEC = 0x1
- FD_SETSIZE = 0x400
- F_ADDFILESIGS = 0x3d
- F_ADDSIGS = 0x3b
- F_ALLOCATEALL = 0x4
- F_ALLOCATECONTIG = 0x2
- F_CHKCLEAN = 0x29
- F_DUPFD = 0
- F_FREEZE_FS = 0x35
- F_FULLFSYNC = 0x33
- F_GETFD = 0x1
- F_GETFL = 0x3
- F_GETLK = 0x7
- F_GETOWN = 0x5
- F_GETPATH = 0x32
- F_GETPROTECTIONCLASS = 0x3e
- F_GLOBAL_NOCACHE = 0x37
- F_LOG2PHYS = 0x31
- F_MARKDEPENDENCY = 0x3c
- F_NOCACHE = 0x30
- F_PATHPKG_CHECK = 0x34
- F_PEOFPOSMODE = 0x3
- F_PREALLOCATE = 0x2a
- F_RDADVISE = 0x2c
- F_RDAHEAD = 0x2d
- F_RDLCK = 0x1
- F_READBOOTSTRAP = 0x2e
- F_SETFD = 0x2
- F_SETFL = 0x4
- F_SETLK = 0x8
- F_SETLKW = 0x9
- F_SETOWN = 0x6
- F_SETPROTECTIONCLASS = 0x3f
- F_SETSIZE = 0x2b
- F_THAW_FS = 0x36
- F_UNLCK = 0x2
- F_VOLPOSMODE = 0x4
- F_WRITEBOOTSTRAP = 0x2f
- F_WRLCK = 0x3
- IFF_ALLMULTI = 0x200
- IFF_ALTPHYS = 0x4000
- IFF_BROADCAST = 0x2
- IFF_DEBUG = 0x4
- IFF_LINK0 = 0x1000
- IFF_LINK1 = 0x2000
- IFF_LINK2 = 0x4000
- IFF_LOOPBACK = 0x8
- IFF_MULTICAST = 0x8000
- IFF_NOARP = 0x80
- IFF_NOTRAILERS = 0x20
- IFF_OACTIVE = 0x400
- IFF_POINTOPOINT = 0x10
- IFF_PROMISC = 0x100
- IFF_RUNNING = 0x40
- IFF_SIMPLEX = 0x800
- IFF_UP = 0x1
- IFNAMSIZ = 0x10
- IFT_1822 = 0x2
- IFT_AAL5 = 0x31
- IFT_ARCNET = 0x23
- IFT_ARCNETPLUS = 0x24
- IFT_ATM = 0x25
- IFT_BRIDGE = 0xd1
- IFT_CARP = 0xf8
- IFT_CEPT = 0x13
- IFT_DS3 = 0x1e
- IFT_ENC = 0xf4
- IFT_EON = 0x19
- IFT_ETHER = 0x6
- IFT_FAITH = 0x38
- IFT_FDDI = 0xf
- IFT_FRELAY = 0x20
- IFT_FRELAYDCE = 0x2c
- IFT_GIF = 0x37
- IFT_HDH1822 = 0x3
- IFT_HIPPI = 0x2f
- IFT_HSSI = 0x2e
- IFT_HY = 0xe
- IFT_IEEE1394 = 0x90
- IFT_IEEE8023ADLAG = 0x88
- IFT_ISDNBASIC = 0x14
- IFT_ISDNPRIMARY = 0x15
- IFT_ISO88022LLC = 0x29
- IFT_ISO88023 = 0x7
- IFT_ISO88024 = 0x8
- IFT_ISO88025 = 0x9
- IFT_ISO88026 = 0xa
- IFT_L2VLAN = 0x87
- IFT_LAPB = 0x10
- IFT_LOCALTALK = 0x2a
- IFT_LOOP = 0x18
- IFT_MIOX25 = 0x26
- IFT_MODEM = 0x30
- IFT_NSIP = 0x1b
- IFT_OTHER = 0x1
- IFT_P10 = 0xc
- IFT_P80 = 0xd
- IFT_PARA = 0x22
- IFT_PDP = 0xff
- IFT_PFLOG = 0xf5
- IFT_PFSYNC = 0xf6
- IFT_PPP = 0x17
- IFT_PROPMUX = 0x36
- IFT_PROPVIRTUAL = 0x35
- IFT_PTPSERIAL = 0x16
- IFT_RS232 = 0x21
- IFT_SDLC = 0x11
- IFT_SIP = 0x1f
- IFT_SLIP = 0x1c
- IFT_SMDSDXI = 0x2b
- IFT_SMDSICIP = 0x34
- IFT_SONET = 0x27
- IFT_SONETPATH = 0x32
- IFT_SONETVT = 0x33
- IFT_STARLAN = 0xb
- IFT_STF = 0x39
- IFT_T1 = 0x12
- IFT_ULTRA = 0x1d
- IFT_V35 = 0x2d
- IFT_X25 = 0x5
- IFT_X25DDN = 0x4
- IFT_X25PLE = 0x28
- IFT_XETHER = 0x1a
- IN_CLASSA_HOST = 0xffffff
- IN_CLASSA_MAX = 0x80
- IN_CLASSA_NET = 0xff000000
- IN_CLASSA_NSHIFT = 0x18
- IN_CLASSB_HOST = 0xffff
- IN_CLASSB_MAX = 0x10000
- IN_CLASSB_NET = 0xffff0000
- IN_CLASSB_NSHIFT = 0x10
- IN_CLASSC_HOST = 0xff
- IN_CLASSC_NET = 0xffffff00
- IN_CLASSC_NSHIFT = 0x8
- IN_CLASSD_HOST = 0xfffffff
- IN_CLASSD_NET = 0xf0000000
- IN_CLASSD_NSHIFT = 0x1c
- IN_LINKLOCALNETNUM = 0xa9fe0000
- IN_LOOPBACKNET = 0x7f
- IPPROTO_3PC = 0x22
- IPPROTO_ADFS = 0x44
- IPPROTO_AH = 0x33
- IPPROTO_AHIP = 0x3d
- IPPROTO_APES = 0x63
- IPPROTO_ARGUS = 0xd
- IPPROTO_AX25 = 0x5d
- IPPROTO_BHA = 0x31
- IPPROTO_BLT = 0x1e
- IPPROTO_BRSATMON = 0x4c
- IPPROTO_CFTP = 0x3e
- IPPROTO_CHAOS = 0x10
- IPPROTO_CMTP = 0x26
- IPPROTO_CPHB = 0x49
- IPPROTO_CPNX = 0x48
- IPPROTO_DDP = 0x25
- IPPROTO_DGP = 0x56
- IPPROTO_DIVERT = 0xfe
- IPPROTO_DONE = 0x101
- IPPROTO_DSTOPTS = 0x3c
- IPPROTO_EGP = 0x8
- IPPROTO_EMCON = 0xe
- IPPROTO_ENCAP = 0x62
- IPPROTO_EON = 0x50
- IPPROTO_ESP = 0x32
- IPPROTO_ETHERIP = 0x61
- IPPROTO_FRAGMENT = 0x2c
- IPPROTO_GGP = 0x3
- IPPROTO_GMTP = 0x64
- IPPROTO_GRE = 0x2f
- IPPROTO_HELLO = 0x3f
- IPPROTO_HMP = 0x14
- IPPROTO_HOPOPTS = 0
- IPPROTO_ICMP = 0x1
- IPPROTO_ICMPV6 = 0x3a
- IPPROTO_IDP = 0x16
- IPPROTO_IDPR = 0x23
- IPPROTO_IDRP = 0x2d
- IPPROTO_IGMP = 0x2
- IPPROTO_IGP = 0x55
- IPPROTO_IGRP = 0x58
- IPPROTO_IL = 0x28
- IPPROTO_INLSP = 0x34
- IPPROTO_INP = 0x20
- IPPROTO_IP = 0
- IPPROTO_IPCOMP = 0x6c
- IPPROTO_IPCV = 0x47
- IPPROTO_IPEIP = 0x5e
- IPPROTO_IPIP = 0x4
- IPPROTO_IPPC = 0x43
- IPPROTO_IPV4 = 0x4
- IPPROTO_IPV6 = 0x29
- IPPROTO_IRTP = 0x1c
- IPPROTO_KRYPTOLAN = 0x41
- IPPROTO_LARP = 0x5b
- IPPROTO_LEAF1 = 0x19
- IPPROTO_LEAF2 = 0x1a
- IPPROTO_MAX = 0x100
- IPPROTO_MAXID = 0x34
- IPPROTO_MEAS = 0x13
- IPPROTO_MHRP = 0x30
- IPPROTO_MICP = 0x5f
- IPPROTO_MTP = 0x5c
- IPPROTO_MUX = 0x12
- IPPROTO_ND = 0x4d
- IPPROTO_NHRP = 0x36
- IPPROTO_NONE = 0x3b
- IPPROTO_NSP = 0x1f
- IPPROTO_NVPII = 0xb
- IPPROTO_OSPFIGP = 0x59
- IPPROTO_PGM = 0x71
- IPPROTO_PIGP = 0x9
- IPPROTO_PIM = 0x67
- IPPROTO_PRM = 0x15
- IPPROTO_PUP = 0xc
- IPPROTO_PVP = 0x4b
- IPPROTO_RAW = 0xff
- IPPROTO_RCCMON = 0xa
- IPPROTO_RDP = 0x1b
- IPPROTO_ROUTING = 0x2b
- IPPROTO_RSVP = 0x2e
- IPPROTO_RVD = 0x42
- IPPROTO_SATEXPAK = 0x40
- IPPROTO_SATMON = 0x45
- IPPROTO_SCCSP = 0x60
- IPPROTO_SDRP = 0x2a
- IPPROTO_SEP = 0x21
- IPPROTO_SRPC = 0x5a
- IPPROTO_ST = 0x7
- IPPROTO_SVMTP = 0x52
- IPPROTO_SWIPE = 0x35
- IPPROTO_TCF = 0x57
- IPPROTO_TCP = 0x6
- IPPROTO_TP = 0x1d
- IPPROTO_TPXX = 0x27
- IPPROTO_TRUNK1 = 0x17
- IPPROTO_TRUNK2 = 0x18
- IPPROTO_TTP = 0x54
- IPPROTO_UDP = 0x11
- IPPROTO_VINES = 0x53
- IPPROTO_VISA = 0x46
- IPPROTO_VMTP = 0x51
- IPPROTO_WBEXPAK = 0x4f
- IPPROTO_WBMON = 0x4e
- IPPROTO_WSN = 0x4a
- IPPROTO_XNET = 0xf
- IPPROTO_XTP = 0x24
- IPV6_BINDV6ONLY = 0x1b
- IPV6_CHECKSUM = 0x1a
- IPV6_DEFAULT_MULTICAST_HOPS = 0x1
- IPV6_DEFAULT_MULTICAST_LOOP = 0x1
- IPV6_DEFHLIM = 0x40
- IPV6_DSTOPTS = 0x17
- IPV6_FAITH = 0x1d
- IPV6_FLOWINFO_MASK = 0xffffff0f
- IPV6_FLOWLABEL_MASK = 0xffff0f00
- IPV6_FRAGTTL = 0x78
- IPV6_FW_ADD = 0x1e
- IPV6_FW_DEL = 0x1f
- IPV6_FW_FLUSH = 0x20
- IPV6_FW_GET = 0x22
- IPV6_FW_ZERO = 0x21
- IPV6_HLIMDEC = 0x1
- IPV6_HOPLIMIT = 0x14
- IPV6_HOPOPTS = 0x16
- IPV6_IPSEC_POLICY = 0x1c
- IPV6_JOIN_GROUP = 0xc
- IPV6_LEAVE_GROUP = 0xd
- IPV6_MAXHLIM = 0xff
- IPV6_MAXPACKET = 0xffff
- IPV6_MMTU = 0x500
- IPV6_MULTICAST_HOPS = 0xa
- IPV6_MULTICAST_IF = 0x9
- IPV6_MULTICAST_LOOP = 0xb
- IPV6_NEXTHOP = 0x15
- IPV6_PKTINFO = 0x13
- IPV6_PKTOPTIONS = 0x19
- IPV6_PORTRANGE = 0xe
- IPV6_PORTRANGE_DEFAULT = 0
- IPV6_PORTRANGE_HIGH = 0x1
- IPV6_PORTRANGE_LOW = 0x2
- IPV6_RECVTCLASS = 0x23
- IPV6_RTHDR = 0x18
- IPV6_RTHDR_LOOSE = 0
- IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
- IPV6_SOCKOPT_RESERVED1 = 0x3
- IPV6_TCLASS = 0x24
- IPV6_UNICAST_HOPS = 0x4
- IPV6_V6ONLY = 0x1b
- IPV6_VERSION = 0x60
- IPV6_VERSION_MASK = 0xf0
- IP_ADD_MEMBERSHIP = 0xc
- IP_BOUND_IF = 0x19
- IP_DEFAULT_MULTICAST_LOOP = 0x1
- IP_DEFAULT_MULTICAST_TTL = 0x1
- IP_DF = 0x4000
- IP_DROP_MEMBERSHIP = 0xd
- IP_DUMMYNET_CONFIGURE = 0x3c
- IP_DUMMYNET_DEL = 0x3d
- IP_DUMMYNET_FLUSH = 0x3e
- IP_DUMMYNET_GET = 0x40
- IP_FAITH = 0x16
- IP_FW_ADD = 0x28
- IP_FW_DEL = 0x29
- IP_FW_FLUSH = 0x2a
- IP_FW_GET = 0x2c
- IP_FW_RESETLOG = 0x2d
- IP_FW_ZERO = 0x2b
- IP_HDRINCL = 0x2
- IP_IPSEC_POLICY = 0x15
- IP_MAXPACKET = 0xffff
- IP_MAX_MEMBERSHIPS = 0x14
- IP_MF = 0x2000
- IP_MSS = 0x240
- IP_MULTICAST_IF = 0x9
- IP_MULTICAST_LOOP = 0xb
- IP_MULTICAST_TTL = 0xa
- IP_MULTICAST_VIF = 0xe
- IP_NAT__XXX = 0x37
- IP_OFFMASK = 0x1fff
- IP_OLD_FW_ADD = 0x32
- IP_OLD_FW_DEL = 0x33
- IP_OLD_FW_FLUSH = 0x34
- IP_OLD_FW_GET = 0x36
- IP_OLD_FW_RESETLOG = 0x38
- IP_OLD_FW_ZERO = 0x35
- IP_OPTIONS = 0x1
- IP_PORTRANGE = 0x13
- IP_PORTRANGE_DEFAULT = 0
- IP_PORTRANGE_HIGH = 0x1
- IP_PORTRANGE_LOW = 0x2
- IP_RECVDSTADDR = 0x7
- IP_RECVIF = 0x14
- IP_RECVOPTS = 0x5
- IP_RECVRETOPTS = 0x6
- IP_RECVTTL = 0x18
- IP_RETOPTS = 0x8
- IP_RF = 0x8000
- IP_RSVP_OFF = 0x10
- IP_RSVP_ON = 0xf
- IP_RSVP_VIF_OFF = 0x12
- IP_RSVP_VIF_ON = 0x11
- IP_STRIPHDR = 0x17
- IP_TOS = 0x3
- IP_TRAFFIC_MGT_BACKGROUND = 0x41
- IP_TTL = 0x4
- MADV_CAN_REUSE = 0x9
- MADV_DONTNEED = 0x4
- MADV_FREE = 0x5
- MADV_FREE_REUSABLE = 0x7
- MADV_FREE_REUSE = 0x8
- MADV_NORMAL = 0
- MADV_RANDOM = 0x1
- MADV_SEQUENTIAL = 0x2
- MADV_WILLNEED = 0x3
- MADV_ZERO_WIRED_PAGES = 0x6
- MAP_ANON = 0x1000
- MAP_COPY = 0x2
- MAP_FILE = 0
- MAP_FIXED = 0x10
- MAP_HASSEMAPHORE = 0x200
- MAP_NOCACHE = 0x400
- MAP_NOEXTEND = 0x100
- MAP_NORESERVE = 0x40
- MAP_PRIVATE = 0x2
- MAP_RENAME = 0x20
- MAP_RESERVED0080 = 0x80
- MAP_SHARED = 0x1
- MCL_CURRENT = 0x1
- MCL_FUTURE = 0x2
- MSG_CTRUNC = 0x20
- MSG_DONTROUTE = 0x4
- MSG_DONTWAIT = 0x80
- MSG_EOF = 0x100
- MSG_EOR = 0x8
- MSG_FLUSH = 0x400
- MSG_HAVEMORE = 0x2000
- MSG_HOLD = 0x800
- MSG_NEEDSA = 0x10000
- MSG_OOB = 0x1
- MSG_PEEK = 0x2
- MSG_RCVMORE = 0x4000
- MSG_SEND = 0x1000
- MSG_TRUNC = 0x10
- MSG_WAITALL = 0x40
- MSG_WAITSTREAM = 0x200
- MS_ASYNC = 0x1
- MS_DEACTIVATE = 0x8
- MS_INVALIDATE = 0x2
- MS_KILLPAGES = 0x4
- MS_SYNC = 0x10
- NAME_MAX = 0xff
- NET_RT_DUMP = 0x1
- NET_RT_DUMP2 = 0x7
- NET_RT_FLAGS = 0x2
- NET_RT_IFLIST = 0x3
- NET_RT_IFLIST2 = 0x6
- NET_RT_MAXID = 0x8
- NET_RT_STAT = 0x4
- NET_RT_TRASH = 0x5
- O_ACCMODE = 0x3
- O_ALERT = 0x20000000
- O_APPEND = 0x8
- O_ASYNC = 0x40
- O_CREAT = 0x200
- O_DIRECTORY = 0x100000
- O_DSYNC = 0x400000
- O_EVTONLY = 0x8000
- O_EXCL = 0x800
- O_EXLOCK = 0x20
- O_FSYNC = 0x80
- O_NDELAY = 0x4
- O_NOCTTY = 0x20000
- O_NOFOLLOW = 0x100
- O_NONBLOCK = 0x4
- O_POPUP = 0x80000000
- O_RDONLY = 0
- O_RDWR = 0x2
- O_SHLOCK = 0x10
- O_SYMLINK = 0x200000
- O_SYNC = 0x80
- O_TRUNC = 0x400
- O_WRONLY = 0x1
- PROT_EXEC = 0x4
- PROT_NONE = 0
- PROT_READ = 0x1
- PROT_WRITE = 0x2
- PT_ATTACH = 0xa
- PT_ATTACHEXC = 0xe
- PT_CONTINUE = 0x7
- PT_DENY_ATTACH = 0x1f
- PT_DETACH = 0xb
- PT_FIRSTMACH = 0x20
- PT_FORCEQUOTA = 0x1e
- PT_KILL = 0x8
- PT_READ_D = 0x2
- PT_READ_I = 0x1
- PT_READ_U = 0x3
- PT_SIGEXC = 0xc
- PT_STEP = 0x9
- PT_THUPDATE = 0xd
- PT_TRACE_ME = 0
- PT_WRITE_D = 0x5
- PT_WRITE_I = 0x4
- PT_WRITE_U = 0x6
- RTAX_AUTHOR = 0x6
- RTAX_BRD = 0x7
- RTAX_DST = 0
- RTAX_GATEWAY = 0x1
- RTAX_GENMASK = 0x3
- RTAX_IFA = 0x5
- RTAX_IFP = 0x4
- RTAX_MAX = 0x8
- RTAX_NETMASK = 0x2
- RTA_AUTHOR = 0x40
- RTA_BRD = 0x80
- RTA_DST = 0x1
- RTA_GATEWAY = 0x2
- RTA_GENMASK = 0x8
- RTA_IFA = 0x20
- RTA_IFP = 0x10
- RTA_NETMASK = 0x4
- RTF_BLACKHOLE = 0x1000
- RTF_BROADCAST = 0x400000
- RTF_CLONING = 0x100
- RTF_CONDEMNED = 0x2000000
- RTF_DELCLONE = 0x80
- RTF_DONE = 0x40
- RTF_DYNAMIC = 0x10
- RTF_GATEWAY = 0x2
- RTF_HOST = 0x4
- RTF_IFREF = 0x4000000
- RTF_IFSCOPE = 0x1000000
- RTF_LLINFO = 0x400
- RTF_LOCAL = 0x200000
- RTF_MODIFIED = 0x20
- RTF_MULTICAST = 0x800000
- RTF_PINNED = 0x100000
- RTF_PRCLONING = 0x10000
- RTF_PROTO1 = 0x8000
- RTF_PROTO2 = 0x4000
- RTF_PROTO3 = 0x40000
- RTF_REJECT = 0x8
- RTF_STATIC = 0x800
- RTF_UP = 0x1
- RTF_WASCLONED = 0x20000
- RTF_XRESOLVE = 0x200
- RTM_ADD = 0x1
- RTM_CHANGE = 0x3
- RTM_DELADDR = 0xd
- RTM_DELETE = 0x2
- RTM_DELMADDR = 0x10
- RTM_GET = 0x4
- RTM_GET2 = 0x14
- RTM_IFINFO = 0xe
- RTM_IFINFO2 = 0x12
- RTM_LOCK = 0x8
- RTM_LOSING = 0x5
- RTM_MISS = 0x7
- RTM_NEWADDR = 0xc
- RTM_NEWMADDR = 0xf
- RTM_NEWMADDR2 = 0x13
- RTM_OLDADD = 0x9
- RTM_OLDDEL = 0xa
- RTM_REDIRECT = 0x6
- RTM_RESOLVE = 0xb
- RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x5
- RTV_EXPIRE = 0x4
- RTV_HOPCOUNT = 0x2
- RTV_MTU = 0x1
- RTV_RPIPE = 0x8
- RTV_RTT = 0x40
- RTV_RTTVAR = 0x80
- RTV_SPIPE = 0x10
- RTV_SSTHRESH = 0x20
- SCM_CREDS = 0x3
- SCM_RIGHTS = 0x1
- SCM_TIMESTAMP = 0x2
- SHUT_RD = 0
- SHUT_RDWR = 0x2
- SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0xa
- SIGCHLD = 0x14
- SIGCONT = 0x13
- SIGEMT = 0x7
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINFO = 0x1d
- SIGINT = 0x2
- SIGIO = 0x17
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGPIPE = 0xd
- SIGPROF = 0x1b
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTOP = 0x11
- SIGSYS = 0xc
- SIGTERM = 0xf
- SIGTRAP = 0x5
- SIGTSTP = 0x12
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGURG = 0x10
- SIGUSR1 = 0x1e
- SIGUSR2 = 0x1f
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
- SIOCADDMULTI = 0x80206931
- SIOCAIFADDR = 0x8040691a
- SIOCALIFADDR = 0x8118691d
- SIOCARPIPLL = 0xc0206928
- SIOCATMARK = 0x40047307
- SIOCAUTOADDR = 0xc0206926
- SIOCAUTONETMASK = 0x80206927
- SIOCDELMULTI = 0x80206932
- SIOCDIFADDR = 0x80206919
- SIOCDIFPHYADDR = 0x80206941
- SIOCDLIFADDR = 0x8118691f
- SIOCGDRVSPEC = 0xc028697b
- SIOCGETSGCNT = 0xc014721c
- SIOCGETVIFCNT = 0xc014721b
- SIOCGETVLAN = 0xc020697f
- SIOCGHIWAT = 0x40047301
- SIOCGIFADDR = 0xc0206921
- SIOCGIFALTMTU = 0xc0206948
- SIOCGIFASYNCMAP = 0xc020697c
- SIOCGIFBOND = 0xc0206947
- SIOCGIFBRDADDR = 0xc0206923
- SIOCGIFCONF = 0xc00c6924
- SIOCGIFDEVMTU = 0xc0206944
- SIOCGIFDSTADDR = 0xc0206922
- SIOCGIFFLAGS = 0xc0206911
- SIOCGIFGENERIC = 0xc020693a
- SIOCGIFKPI = 0xc0206987
- SIOCGIFMAC = 0xc0206982
- SIOCGIFMEDIA = 0xc02c6938
- SIOCGIFMETRIC = 0xc0206917
- SIOCGIFMTU = 0xc0206933
- SIOCGIFNETMASK = 0xc0206925
- SIOCGIFPDSTADDR = 0xc0206940
- SIOCGIFPHYS = 0xc0206935
- SIOCGIFPSRCADDR = 0xc020693f
- SIOCGIFSTATUS = 0xc331693d
- SIOCGIFVLAN = 0xc020697f
- SIOCGIFWAKEFLAGS = 0xc0206988
- SIOCGLIFADDR = 0xc118691e
- SIOCGLIFPHYADDR = 0xc1186943
- SIOCGLOWAT = 0x40047303
- SIOCGPGRP = 0x40047309
- SIOCIFCREATE = 0xc0206978
- SIOCIFCREATE2 = 0xc020697a
- SIOCIFDESTROY = 0x80206979
- SIOCRSLVMULTI = 0xc010693b
- SIOCSDRVSPEC = 0x8028697b
- SIOCSETVLAN = 0x8020697e
- SIOCSHIWAT = 0x80047300
- SIOCSIFADDR = 0x8020690c
- SIOCSIFALTMTU = 0x80206945
- SIOCSIFASYNCMAP = 0x8020697d
- SIOCSIFBOND = 0x80206946
- SIOCSIFBRDADDR = 0x80206913
- SIOCSIFDSTADDR = 0x8020690e
- SIOCSIFFLAGS = 0x80206910
- SIOCSIFGENERIC = 0x80206939
- SIOCSIFKPI = 0x80206986
- SIOCSIFLLADDR = 0x8020693c
- SIOCSIFMAC = 0x80206983
- SIOCSIFMEDIA = 0xc0206937
- SIOCSIFMETRIC = 0x80206918
- SIOCSIFMTU = 0x80206934
- SIOCSIFNETMASK = 0x80206916
- SIOCSIFPHYADDR = 0x8040693e
- SIOCSIFPHYS = 0x80206936
- SIOCSIFVLAN = 0x8020697e
- SIOCSLIFPHYADDR = 0x81186942
- SIOCSLOWAT = 0x80047302
- SIOCSPGRP = 0x80047308
- SOCK_DGRAM = 0x2
- SOCK_MAXADDRLEN = 0xff
- SOCK_RAW = 0x3
- SOCK_RDM = 0x4
- SOCK_SEQPACKET = 0x5
- SOCK_STREAM = 0x1
- SOL_SOCKET = 0xffff
- SOMAXCONN = 0x80
- SO_ACCEPTCONN = 0x2
- SO_BROADCAST = 0x20
- SO_DEBUG = 0x1
- SO_DONTROUTE = 0x10
- SO_DONTTRUNC = 0x2000
- SO_ERROR = 0x1007
- SO_KEEPALIVE = 0x8
- SO_LABEL = 0x1010
- SO_LINGER = 0x80
- SO_LINGER_SEC = 0x1080
- SO_NKE = 0x1021
- SO_NOADDRERR = 0x1023
- SO_NOSIGPIPE = 0x1022
- SO_NOTIFYCONFLICT = 0x1026
- SO_NP_EXTENSIONS = 0x1083
- SO_NREAD = 0x1020
- SO_NWRITE = 0x1024
- SO_OOBINLINE = 0x100
- SO_PEERLABEL = 0x1011
- SO_RANDOMPORT = 0x1082
- SO_RCVBUF = 0x1002
- SO_RCVLOWAT = 0x1004
- SO_RCVTIMEO = 0x1006
- SO_RESTRICTIONS = 0x1081
- SO_RESTRICT_DENYIN = 0x1
- SO_RESTRICT_DENYOUT = 0x2
- SO_RESTRICT_DENYSET = 0x80000000
- SO_REUSEADDR = 0x4
- SO_REUSEPORT = 0x200
- SO_REUSESHAREUID = 0x1025
- SO_SNDBUF = 0x1001
- SO_SNDLOWAT = 0x1003
- SO_SNDTIMEO = 0x1005
- SO_TIMESTAMP = 0x400
- SO_TYPE = 0x1008
- SO_UPCALLCLOSEWAIT = 0x1027
- SO_USELOOPBACK = 0x40
- SO_WANTMORE = 0x4000
- SO_WANTOOBFLAG = 0x8000
- S_IEXEC = 0x40
- S_IFBLK = 0x6000
- S_IFCHR = 0x2000
- S_IFDIR = 0x4000
- S_IFIFO = 0x1000
- S_IFLNK = 0xa000
- S_IFMT = 0xf000
- S_IFREG = 0x8000
- S_IFSOCK = 0xc000
- S_IFWHT = 0xe000
- S_IREAD = 0x100
- S_IRGRP = 0x20
- S_IROTH = 0x4
- S_IRUSR = 0x100
- S_IRWXG = 0x38
- S_IRWXO = 0x7
- S_IRWXU = 0x1c0
- S_ISGID = 0x400
- S_ISTXT = 0x200
- S_ISUID = 0x800
- S_ISVTX = 0x200
- S_IWGRP = 0x10
- S_IWOTH = 0x2
- S_IWRITE = 0x80
- S_IWUSR = 0x80
- S_IXGRP = 0x8
- S_IXOTH = 0x1
- S_IXUSR = 0x40
- TCP_CONNECTIONTIMEOUT = 0x20
- TCP_KEEPALIVE = 0x10
- TCP_MAXBURST = 0x4
- TCP_MAXHLEN = 0x3c
- TCP_MAXOLEN = 0x28
- TCP_MAXSEG = 0x2
- TCP_MAXWIN = 0xffff
- TCP_MAX_SACK = 0x3
- TCP_MAX_WINSHIFT = 0xe
- TCP_MINMSS = 0xd8
- TCP_MINMSSOVERLOAD = 0x3e8
- TCP_MSS = 0x200
- TCP_NODELAY = 0x1
- TCP_NOOPT = 0x8
- TCP_NOPUSH = 0x4
- TIOCCBRK = 0x2000747a
- TIOCCDTR = 0x20007478
- TIOCCONS = 0x80047462
- TIOCDCDTIMESTAMP = 0x40107458
- TIOCDRAIN = 0x2000745e
- TIOCDSIMICROCODE = 0x20007455
- TIOCEXCL = 0x2000740d
- TIOCEXT = 0x80047460
- TIOCFLUSH = 0x80047410
- TIOCGDRAINWAIT = 0x40047456
- TIOCGETA = 0x40487413
- TIOCGETD = 0x4004741a
- TIOCGPGRP = 0x40047477
- TIOCGWINSZ = 0x40087468
- TIOCIXOFF = 0x20007480
- TIOCIXON = 0x20007481
- TIOCMBIC = 0x8004746b
- TIOCMBIS = 0x8004746c
- TIOCMGDTRWAIT = 0x4004745a
- TIOCMGET = 0x4004746a
- TIOCMODG = 0x40047403
- TIOCMODS = 0x80047404
- TIOCMSDTRWAIT = 0x8004745b
- TIOCMSET = 0x8004746d
- TIOCM_CAR = 0x40
- TIOCM_CD = 0x40
- TIOCM_CTS = 0x20
- TIOCM_DSR = 0x100
- TIOCM_DTR = 0x2
- TIOCM_LE = 0x1
- TIOCM_RI = 0x80
- TIOCM_RNG = 0x80
- TIOCM_RTS = 0x4
- TIOCM_SR = 0x10
- TIOCM_ST = 0x8
- TIOCNOTTY = 0x20007471
- TIOCNXCL = 0x2000740e
- TIOCOUTQ = 0x40047473
- TIOCPKT = 0x80047470
- TIOCPKT_DATA = 0
- TIOCPKT_DOSTOP = 0x20
- TIOCPKT_FLUSHREAD = 0x1
- TIOCPKT_FLUSHWRITE = 0x2
- TIOCPKT_IOCTL = 0x40
- TIOCPKT_NOSTOP = 0x10
- TIOCPKT_START = 0x8
- TIOCPKT_STOP = 0x4
- TIOCPTYGNAME = 0x40807453
- TIOCPTYGRANT = 0x20007454
- TIOCPTYUNLK = 0x20007452
- TIOCREMOTE = 0x80047469
- TIOCSBRK = 0x2000747b
- TIOCSCONS = 0x20007463
- TIOCSCTTY = 0x20007461
- TIOCSDRAINWAIT = 0x80047457
- TIOCSDTR = 0x20007479
- TIOCSETA = 0x80487414
- TIOCSETAF = 0x80487416
- TIOCSETAW = 0x80487415
- TIOCSETD = 0x8004741b
- TIOCSIG = 0x2000745f
- TIOCSPGRP = 0x80047476
- TIOCSTART = 0x2000746e
- TIOCSTAT = 0x20007465
- TIOCSTI = 0x80017472
- TIOCSTOP = 0x2000746f
- TIOCSWINSZ = 0x80087467
- TIOCTIMESTAMP = 0x40107459
- TIOCUCNTL = 0x80047466
- WCONTINUED = 0x10
- WCOREFLAG = 0x80
- WEXITED = 0x4
- WNOHANG = 0x1
- WNOWAIT = 0x20
- WORDSIZE = 0x40
- WSTOPPED = 0x8
- WUNTRACED = 0x2
+ AF_APPLETALK = 0x10
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1c
+ AF_ECMA = 0x8
+ AF_HYLINK = 0xf
+ AF_IEEE80211 = 0x25
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1e
+ AF_IPX = 0x17
+ AF_ISDN = 0x1c
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x26
+ AF_NATM = 0x1f
+ AF_NDRV = 0x1b
+ AF_NETBIOS = 0x21
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PPP = 0x22
+ AF_PUP = 0x4
+ AF_RESERVED_36 = 0x24
+ AF_ROUTE = 0x11
+ AF_SIP = 0x18
+ AF_SNA = 0xb
+ AF_SYSTEM = 0x20
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc00c4279
+ BIOCGETIF = 0x4020426b
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044272
+ BIOCGRTIMEOUT = 0x4010426e
+ BIOCGSEESENT = 0x40044276
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDLT = 0x80044278
+ BIOCSETF = 0x80104267
+ BIOCSETIF = 0x8020426c
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044273
+ BIOCSRTIMEOUT = 0x8010426d
+ BIOCSSEESENT = 0x80044277
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x80000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
+ DLT_ARCNET = 0x7
+ DLT_ATM_CLIP = 0x13
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_CHDLC = 0x68
+ DLT_C_HDLC = 0x68
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_IEEE802_11_RADIO_AVS = 0xa3
+ DLT_LINUX_SLL = 0x71
+ DLT_LOOP = 0x6c
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_SERIAL = 0x32
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xc
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ EVFILT_AIO = -0x3
+ EVFILT_FS = -0x9
+ EVFILT_MACHPORT = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xc
+ EVFILT_THREADMARKER = 0xc
+ EVFILT_TIMER = -0x7
+ EVFILT_USER = -0xa
+ EVFILT_VM = -0xc
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_DISPATCH = 0x80
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG0 = 0x1000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_OOBAND = 0x2000
+ EV_POLL = 0x1000
+ EV_RECEIPT = 0x40
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_ADDFILESIGS = 0x3d
+ F_ADDSIGS = 0x3b
+ F_ALLOCATEALL = 0x4
+ F_ALLOCATECONTIG = 0x2
+ F_CHKCLEAN = 0x29
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x43
+ F_FLUSH_DATA = 0x28
+ F_FREEZE_FS = 0x35
+ F_FULLFSYNC = 0x33
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETLKPID = 0x42
+ F_GETNOSIGPIPE = 0x4a
+ F_GETOWN = 0x5
+ F_GETPATH = 0x32
+ F_GETPATH_MTMINFO = 0x47
+ F_GETPROTECTIONCLASS = 0x3f
+ F_GLOBAL_NOCACHE = 0x37
+ F_LOG2PHYS = 0x31
+ F_LOG2PHYS_EXT = 0x41
+ F_MARKDEPENDENCY = 0x3c
+ F_NOCACHE = 0x30
+ F_NODIRECT = 0x3e
+ F_OK = 0x0
+ F_PATHPKG_CHECK = 0x34
+ F_PEOFPOSMODE = 0x3
+ F_PREALLOCATE = 0x2a
+ F_RDADVISE = 0x2c
+ F_RDAHEAD = 0x2d
+ F_RDLCK = 0x1
+ F_READBOOTSTRAP = 0x2e
+ F_SETBACKINGSTORE = 0x46
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETNOSIGPIPE = 0x49
+ F_SETOWN = 0x6
+ F_SETPROTECTIONCLASS = 0x40
+ F_SETSIZE = 0x2b
+ F_THAW_FS = 0x36
+ F_UNLCK = 0x2
+ F_VOLPOSMODE = 0x4
+ F_WRITEBOOTSTRAP = 0x2f
+ F_WRLCK = 0x3
+ IFF_ALLMULTI = 0x200
+ IFF_ALTPHYS = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_AAL5 = 0x31
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ATM = 0x25
+ IFT_BRIDGE = 0xd1
+ IFT_CARP = 0xf8
+ IFT_CELLULAR = 0xff
+ IFT_CEPT = 0x13
+ IFT_DS3 = 0x1e
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0x38
+ IFT_FDDI = 0xf
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_GIF = 0x37
+ IFT_HDH1822 = 0x3
+ IFT_HIPPI = 0x2f
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE8023ADLAG = 0x88
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88026 = 0xa
+ IFT_L2VLAN = 0x87
+ IFT_LAPB = 0x10
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_NSIP = 0x1b
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PDP = 0xff
+ IFT_PFLOG = 0xf5
+ IFT_PFSYNC = 0xf6
+ IFT_PPP = 0x17
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PTPSERIAL = 0x16
+ IFT_RS232 = 0x21
+ IFT_SDLC = 0x11
+ IFT_SIP = 0x1f
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_STARLAN = 0xb
+ IFT_STF = 0x39
+ IFT_T1 = 0x12
+ IFT_ULTRA = 0x1d
+ IFT_V35 = 0x2d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LINKLOCALNETNUM = 0xa9fe0000
+ IN_LOOPBACKNET = 0x7f
+ IPPROTO_3PC = 0x22
+ IPPROTO_ADFS = 0x44
+ IPPROTO_AH = 0x33
+ IPPROTO_AHIP = 0x3d
+ IPPROTO_APES = 0x63
+ IPPROTO_ARGUS = 0xd
+ IPPROTO_AX25 = 0x5d
+ IPPROTO_BHA = 0x31
+ IPPROTO_BLT = 0x1e
+ IPPROTO_BRSATMON = 0x4c
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0xfe
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_EMCON = 0xe
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GMTP = 0x64
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HELLO = 0x3f
+ IPPROTO_HMP = 0x14
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IDPR = 0x23
+ IPPROTO_IDRP = 0x2d
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IGP = 0x55
+ IPPROTO_IGRP = 0x58
+ IPPROTO_IL = 0x28
+ IPPROTO_INLSP = 0x34
+ IPPROTO_INP = 0x20
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPCV = 0x47
+ IPPROTO_IPEIP = 0x5e
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPPC = 0x43
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_IRTP = 0x1c
+ IPPROTO_KRYPTOLAN = 0x41
+ IPPROTO_LARP = 0x5b
+ IPPROTO_LEAF1 = 0x19
+ IPPROTO_LEAF2 = 0x1a
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x34
+ IPPROTO_MEAS = 0x13
+ IPPROTO_MHRP = 0x30
+ IPPROTO_MICP = 0x5f
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PGM = 0x71
+ IPPROTO_PIGP = 0x9
+ IPPROTO_PIM = 0x67
+ IPPROTO_PRM = 0x15
+ IPPROTO_PUP = 0xc
+ IPPROTO_PVP = 0x4b
+ IPPROTO_RAW = 0xff
+ IPPROTO_RCCMON = 0xa
+ IPPROTO_RDP = 0x1b
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_RVD = 0x42
+ IPPROTO_SATEXPAK = 0x40
+ IPPROTO_SATMON = 0x45
+ IPPROTO_SCCSP = 0x60
+ IPPROTO_SCTP = 0x84
+ IPPROTO_SDRP = 0x2a
+ IPPROTO_SEP = 0x21
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_TPXX = 0x27
+ IPPROTO_TRUNK1 = 0x17
+ IPPROTO_TRUNK2 = 0x18
+ IPPROTO_TTP = 0x54
+ IPPROTO_UDP = 0x11
+ IPPROTO_VINES = 0x53
+ IPPROTO_VISA = 0x46
+ IPPROTO_VMTP = 0x51
+ IPPROTO_WBEXPAK = 0x4f
+ IPPROTO_WBMON = 0x4e
+ IPPROTO_WSN = 0x4a
+ IPPROTO_XNET = 0xf
+ IPPROTO_XTP = 0x24
+ IPV6_2292DSTOPTS = 0x17
+ IPV6_2292HOPLIMIT = 0x14
+ IPV6_2292HOPOPTS = 0x16
+ IPV6_2292NEXTHOP = 0x15
+ IPV6_2292PKTINFO = 0x13
+ IPV6_2292PKTOPTIONS = 0x19
+ IPV6_2292RTHDR = 0x18
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_BOUND_IF = 0x7d
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_FW_ADD = 0x1e
+ IPV6_FW_DEL = 0x1f
+ IPV6_FW_FLUSH = 0x20
+ IPV6_FW_GET = 0x22
+ IPV6_FW_ZERO = 0x21
+ IPV6_HLIMDEC = 0x1
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXOPTHDR = 0x800
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MAX_GROUP_SRC_FILTER = 0x200
+ IPV6_MAX_MEMBERSHIPS = 0xfff
+ IPV6_MAX_SOCK_SRC_FILTER = 0x80
+ IPV6_MIN_MEMBERSHIPS = 0x1f
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVTCLASS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x24
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_ADD_SOURCE_MEMBERSHIP = 0x46
+ IP_BLOCK_SOURCE = 0x48
+ IP_BOUND_IF = 0x19
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DROP_SOURCE_MEMBERSHIP = 0x47
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW_ADD = 0x28
+ IP_FW_DEL = 0x29
+ IP_FW_FLUSH = 0x2a
+ IP_FW_GET = 0x2c
+ IP_FW_RESETLOG = 0x2d
+ IP_FW_ZERO = 0x2b
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_GROUP_SRC_FILTER = 0x200
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MAX_SOCK_MUTE_FILTER = 0x80
+ IP_MAX_SOCK_SRC_FILTER = 0x80
+ IP_MF = 0x2000
+ IP_MIN_MEMBERSHIPS = 0x1f
+ IP_MSFILTER = 0x4a
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_IFINDEX = 0x42
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_NAT__XXX = 0x37
+ IP_OFFMASK = 0x1fff
+ IP_OLD_FW_ADD = 0x32
+ IP_OLD_FW_DEL = 0x33
+ IP_OLD_FW_FLUSH = 0x34
+ IP_OLD_FW_GET = 0x36
+ IP_OLD_FW_RESETLOG = 0x38
+ IP_OLD_FW_ZERO = 0x35
+ IP_OPTIONS = 0x1
+ IP_PKTINFO = 0x1a
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVIF = 0x14
+ IP_RECVOPTS = 0x5
+ IP_RECVPKTINFO = 0x1a
+ IP_RECVRETOPTS = 0x6
+ IP_RECVTTL = 0x18
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RSVP_OFF = 0x10
+ IP_RSVP_ON = 0xf
+ IP_RSVP_VIF_OFF = 0x12
+ IP_RSVP_VIF_ON = 0x11
+ IP_STRIPHDR = 0x17
+ IP_TOS = 0x3
+ IP_TRAFFIC_MGT_BACKGROUND = 0x41
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x49
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_CAN_REUSE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_FREE_REUSABLE = 0x7
+ MADV_FREE_REUSE = 0x8
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MADV_ZERO_WIRED_PAGES = 0x6
+ MAP_ANON = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_JIT = 0x800
+ MAP_NOCACHE = 0x400
+ MAP_NOEXTEND = 0x100
+ MAP_NORESERVE = 0x40
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_SHARED = 0x1
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOF = 0x100
+ MSG_EOR = 0x8
+ MSG_FLUSH = 0x400
+ MSG_HAVEMORE = 0x2000
+ MSG_HOLD = 0x800
+ MSG_NEEDSA = 0x10000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_RCVMORE = 0x4000
+ MSG_SEND = 0x1000
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ MSG_WAITSTREAM = 0x200
+ MS_ASYNC = 0x1
+ MS_DEACTIVATE = 0x8
+ MS_INVALIDATE = 0x2
+ MS_KILLPAGES = 0x4
+ MS_SYNC = 0x10
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_DUMP2 = 0x7
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_IFLIST2 = 0x6
+ NET_RT_MAXID = 0xa
+ NET_RT_STAT = 0x4
+ NET_RT_TRASH = 0x5
+ NOTE_ABSOLUTE = 0x8
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXITSTATUS = 0x4000000
+ NOTE_EXTEND = 0x4
+ NOTE_FFAND = 0x40000000
+ NOTE_FFCOPY = 0xc0000000
+ NOTE_FFCTRLMASK = 0xc0000000
+ NOTE_FFLAGSMASK = 0xffffff
+ NOTE_FFNOP = 0x0
+ NOTE_FFOR = 0x80000000
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_NONE = 0x80
+ NOTE_NSECONDS = 0x4
+ NOTE_PCTRLMASK = -0x100000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_REAP = 0x10000000
+ NOTE_RENAME = 0x20
+ NOTE_RESOURCEEND = 0x2000000
+ NOTE_REVOKE = 0x40
+ NOTE_SECONDS = 0x1
+ NOTE_SIGNAL = 0x8000000
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRIGGER = 0x1000000
+ NOTE_USECONDS = 0x2
+ NOTE_VM_ERROR = 0x10000000
+ NOTE_VM_PRESSURE = 0x80000000
+ NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
+ NOTE_VM_PRESSURE_TERMINATE = 0x40000000
+ NOTE_WRITE = 0x2
+ O_ACCMODE = 0x3
+ O_ALERT = 0x20000000
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x1000000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x100000
+ O_DSYNC = 0x400000
+ O_EVTONLY = 0x8000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x20000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_POPUP = 0x80000000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYMLINK = 0x200000
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0x0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
+ RLIMIT_AS = 0x5
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_MAX = 0x8
+ RTAX_NETMASK = 0x2
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_NETMASK = 0x4
+ RTF_BLACKHOLE = 0x1000
+ RTF_BROADCAST = 0x400000
+ RTF_CLONING = 0x100
+ RTF_CONDEMNED = 0x2000000
+ RTF_DELCLONE = 0x80
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_IFREF = 0x4000000
+ RTF_IFSCOPE = 0x1000000
+ RTF_LLINFO = 0x400
+ RTF_LOCAL = 0x200000
+ RTF_MODIFIED = 0x20
+ RTF_MULTICAST = 0x800000
+ RTF_PINNED = 0x100000
+ RTF_PRCLONING = 0x10000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x40000
+ RTF_REJECT = 0x8
+ RTF_STATIC = 0x800
+ RTF_UP = 0x1
+ RTF_WASCLONED = 0x20000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DELMADDR = 0x10
+ RTM_GET = 0x4
+ RTM_GET2 = 0x14
+ RTM_IFINFO = 0xe
+ RTM_IFINFO2 = 0x12
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_NEWMADDR = 0xf
+ RTM_NEWMADDR2 = 0x13
+ RTM_OLDADD = 0x9
+ RTM_OLDDEL = 0xa
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x5
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ SCM_CREDS = 0x3
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x2
+ SCM_TIMESTAMP_MONOTONIC = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCALIFADDR = 0x8118691d
+ SIOCARPIPLL = 0xc0206928
+ SIOCATMARK = 0x40047307
+ SIOCAUTOADDR = 0xc0206926
+ SIOCAUTONETMASK = 0x80206927
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFPHYADDR = 0x80206941
+ SIOCDLIFADDR = 0x8118691f
+ SIOCGDRVSPEC = 0xc028697b
+ SIOCGETSGCNT = 0xc014721c
+ SIOCGETVIFCNT = 0xc014721b
+ SIOCGETVLAN = 0xc020697f
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFALTMTU = 0xc0206948
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBOND = 0xc0206947
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCAP = 0xc020695b
+ SIOCGIFCONF = 0xc00c6924
+ SIOCGIFDEVMTU = 0xc0206944
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFKPI = 0xc0206987
+ SIOCGIFMAC = 0xc0206982
+ SIOCGIFMEDIA = 0xc02c6938
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc0206933
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206940
+ SIOCGIFPHYS = 0xc0206935
+ SIOCGIFPSRCADDR = 0xc020693f
+ SIOCGIFSTATUS = 0xc331693d
+ SIOCGIFVLAN = 0xc020697f
+ SIOCGIFWAKEFLAGS = 0xc0206988
+ SIOCGLIFADDR = 0xc118691e
+ SIOCGLIFPHYADDR = 0xc1186943
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCIFCREATE = 0xc0206978
+ SIOCIFCREATE2 = 0xc020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCRSLVMULTI = 0xc010693b
+ SIOCSDRVSPEC = 0x8028697b
+ SIOCSETVLAN = 0x8020697e
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFALTMTU = 0x80206945
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBOND = 0x80206946
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFCAP = 0x8020695a
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFKPI = 0x80206986
+ SIOCSIFLLADDR = 0x8020693c
+ SIOCSIFMAC = 0x80206983
+ SIOCSIFMEDIA = 0xc0206937
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x80206934
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x8040693e
+ SIOCSIFPHYS = 0x80206936
+ SIOCSIFVLAN = 0x8020697e
+ SIOCSLIFPHYADDR = 0x81186942
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SOCK_DGRAM = 0x2
+ SOCK_MAXADDRLEN = 0xff
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_DONTTRUNC = 0x2000
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1010
+ SO_LINGER = 0x80
+ SO_LINGER_SEC = 0x1080
+ SO_NKE = 0x1021
+ SO_NOADDRERR = 0x1023
+ SO_NOSIGPIPE = 0x1022
+ SO_NOTIFYCONFLICT = 0x1026
+ SO_NP_EXTENSIONS = 0x1083
+ SO_NREAD = 0x1020
+ SO_NWRITE = 0x1024
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1011
+ SO_RANDOMPORT = 0x1082
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_RESTRICTIONS = 0x1081
+ SO_RESTRICT_DENYIN = 0x1
+ SO_RESTRICT_DENYOUT = 0x2
+ SO_RESTRICT_DENYSET = 0x80000000
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_REUSESHAREUID = 0x1025
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TIMESTAMP_MONOTONIC = 0x800
+ SO_TYPE = 0x1008
+ SO_UPCALLCLOSEWAIT = 0x1027
+ SO_USELOOPBACK = 0x40
+ SO_WANTMORE = 0x4000
+ SO_WANTOOBFLAG = 0x8000
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCP_CONNECTIONTIMEOUT = 0x20
+ TCP_KEEPALIVE = 0x10
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MINMSS = 0xd8
+ TCP_MINMSSOVERLOAD = 0x3e8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ TCP_RXT_CONNDROPTIME = 0x80
+ TCP_RXT_FINDROP = 0x100
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDCDTIMESTAMP = 0x40107458
+ TIOCDRAIN = 0x2000745e
+ TIOCDSIMICROCODE = 0x20007455
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLUSH = 0x80047410
+ TIOCGDRAINWAIT = 0x40047456
+ TIOCGETA = 0x40487413
+ TIOCGETD = 0x4004741a
+ TIOCGPGRP = 0x40047477
+ TIOCGWINSZ = 0x40087468
+ TIOCIXOFF = 0x20007480
+ TIOCIXON = 0x20007481
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGDTRWAIT = 0x4004745a
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x40047403
+ TIOCMODS = 0x80047404
+ TIOCMSDTRWAIT = 0x8004745b
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCPTYGNAME = 0x40807453
+ TIOCPTYGRANT = 0x20007454
+ TIOCPTYUNLK = 0x20007452
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCONS = 0x20007463
+ TIOCSCTTY = 0x20007461
+ TIOCSDRAINWAIT = 0x80047457
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x80487414
+ TIOCSETAF = 0x80487416
+ TIOCSETAW = 0x80487415
+ TIOCSETD = 0x8004741b
+ TIOCSIG = 0x2000745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x20007465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSWINSZ = 0x80087467
+ TIOCTIMESTAMP = 0x40107459
+ TIOCUCNTL = 0x80047466
+ WCONTINUED = 0x10
+ WCOREFLAG = 0x80
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOWAIT = 0x20
+ WORDSIZE = 0x40
+ WSTOPPED = 0x8
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADARCH = Errno(0x56)
+ EBADEXEC = Errno(0x55)
+ EBADF = Errno(0x9)
+ EBADMACHO = Errno(0x58)
+ EBADMSG = Errno(0x5e)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x59)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDEVERR = Errno(0x53)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x5a)
+ EILSEQ = Errno(0x5c)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x69)
+ ELOOP = Errno(0x3e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ EMULTIHOP = Errno(0x5f)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x5d)
+ ENOBUFS = Errno(0x37)
+ ENODATA = Errno(0x60)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOLINK = Errno(0x61)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5b)
+ ENOPOLICY = Errno(0x67)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x62)
+ ENOSTR = Errno(0x63)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTRECOVERABLE = Errno(0x68)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x2d)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x66)
+ EOVERFLOW = Errno(0x54)
+ EOWNERDEAD = Errno(0x69)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTO = Errno(0x64)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ EPWROFF = Errno(0x52)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHLIBVERS = Errno(0x57)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIME = Errno(0x65)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
)
-// Types
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1192,4 +1284,41 @@ var errors = [...]string{
101: "STREAM ioctl timeout",
102: "operation not supported on socket",
103: "policy not found",
+ 104: "state not recoverable",
+ 105: "previous owner died",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "suspended (signal)",
+ 18: "suspended",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index a77e264e2..cc00f0dcf 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -1,13 +1,11 @@
-// mkerrors.sh -f -m32
+// mkerrors.sh -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
package syscall
-// Constants
const (
AF_APPLETALK = 0x10
AF_ARP = 0x23
@@ -45,7 +43,7 @@ const (
AF_SLOW = 0x21
AF_SNA = 0xb
AF_UNIX = 0x1
- AF_UNSPEC = 0
+ AF_UNSPEC = 0x0
AF_VENDOR00 = 0x27
AF_VENDOR01 = 0x29
AF_VENDOR02 = 0x2b
@@ -128,7 +126,7 @@ const (
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
- BPF_ADD = 0
+ BPF_ADD = 0x0
BPF_ALIGNMENT = 0x4
BPF_ALU = 0x4
BPF_AND = 0x50
@@ -137,16 +135,16 @@ const (
BPF_BUFMODE_ZBUF = 0x2
BPF_DIV = 0x30
BPF_H = 0x8
- BPF_IMM = 0
+ BPF_IMM = 0x0
BPF_IND = 0x40
- BPF_JA = 0
+ BPF_JA = 0x0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
BPF_JMP = 0x5
BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
+ BPF_K = 0x0
+ BPF_LD = 0x0
BPF_LDX = 0x1
BPF_LEN = 0x80
BPF_LSH = 0x60
@@ -168,9 +166,9 @@ const (
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
- BPF_TAX = 0
+ BPF_TAX = 0x0
BPF_TXA = 0x80
- BPF_W = 0
+ BPF_W = 0x0
BPF_X = 0x8
CTL_MAXNAME = 0x18
CTL_NET = 0x4
@@ -260,7 +258,7 @@ const (
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
DLT_MTP3 = 0x8d
- DLT_NULL = 0
+ DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
DLT_PFSYNC = 0x79
@@ -311,22 +309,8 @@ const (
DT_LNK = 0xa
DT_REG = 0x8
DT_SOCK = 0xc
- DT_UNKNOWN = 0
+ DT_UNKNOWN = 0x0
DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x30
- EADDRNOTAVAIL = 0x31
- EAFNOSUPPORT = 0x2f
- EAGAIN = 0x23
- EALREADY = 0x25
- EAUTH = 0x50
- EBADF = 0x9
- EBADMSG = 0x59
- EBADRPC = 0x48
- EBUSY = 0x10
- ECANCELED = 0x55
- ECHILD = 0xa
ECHO = 0x8
ECHOCTL = 0x40
ECHOE = 0x2
@@ -334,86 +318,6 @@ const (
ECHOKE = 0x1
ECHONL = 0x10
ECHOPRT = 0x20
- ECONNABORTED = 0x35
- ECONNREFUSED = 0x3d
- ECONNRESET = 0x36
- EDEADLK = 0xb
- EDESTADDRREQ = 0x27
- EDOM = 0x21
- EDOOFUS = 0x58
- EDQUOT = 0x45
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EFTYPE = 0x4f
- EHOSTDOWN = 0x40
- EHOSTUNREACH = 0x41
- EIDRM = 0x52
- EILSEQ = 0x56
- EINPROGRESS = 0x24
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x38
- EISDIR = 0x15
- ELAST = 0x5d
- ELOOP = 0x3e
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x28
- EMULTIHOP = 0x5a
- ENAMETOOLONG = 0x3f
- ENEEDAUTH = 0x51
- ENETDOWN = 0x32
- ENETRESET = 0x34
- ENETUNREACH = 0x33
- ENFILE = 0x17
- ENOATTR = 0x57
- ENOBUFS = 0x37
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOLCK = 0x4d
- ENOLINK = 0x5b
- ENOMEM = 0xc
- ENOMSG = 0x53
- ENOPROTOOPT = 0x2a
- ENOSPC = 0x1c
- ENOSYS = 0x4e
- ENOTBLK = 0xf
- ENOTCAPABLE = 0x5d
- ENOTCONN = 0x39
- ENOTDIR = 0x14
- ENOTEMPTY = 0x42
- ENOTSOCK = 0x26
- ENOTSUP = 0x2d
- ENOTTY = 0x19
- ENXIO = 0x6
- EOPNOTSUPP = 0x2d
- EOVERFLOW = 0x54
- EPERM = 0x1
- EPFNOSUPPORT = 0x2e
- EPIPE = 0x20
- EPROCLIM = 0x43
- EPROCUNAVAIL = 0x4c
- EPROGMISMATCH = 0x4b
- EPROGUNAVAIL = 0x4a
- EPROTO = 0x5c
- EPROTONOSUPPORT = 0x2b
- EPROTOTYPE = 0x29
- ERANGE = 0x22
- EREMOTE = 0x47
- EROFS = 0x1e
- ERPCMISMATCH = 0x49
- ESHUTDOWN = 0x3a
- ESOCKTNOSUPPORT = 0x2c
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESTALE = 0x46
- ETIMEDOUT = 0x3c
- ETOOMANYREFS = 0x3b
- ETXTBSY = 0x1a
- EUSERS = 0x44
EVFILT_AIO = -0x3
EVFILT_FS = -0x9
EVFILT_LIO = -0xa
@@ -437,8 +341,6 @@ const (
EV_ONESHOT = 0x10
EV_RECEIPT = 0x40
EV_SYSFLAGS = 0xf000
- EWOULDBLOCK = 0x23
- EXDEV = 0x12
EXTA = 0x4b00
EXTB = 0x9600
EXTPROC = 0x800
@@ -446,12 +348,13 @@ const (
FD_SETSIZE = 0x400
F_CANCEL = 0x5
F_DUP2FD = 0xa
- F_DUPFD = 0
+ F_DUPFD = 0x0
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0xb
F_GETOWN = 0x5
F_OGETLK = 0x7
+ F_OK = 0x0
F_OSETLK = 0x8
F_OSETLKW = 0x9
F_RDAHEAD = 0x10
@@ -746,7 +649,7 @@ const (
IPPROTO_GRE = 0x2f
IPPROTO_HELLO = 0x3f
IPPROTO_HMP = 0x14
- IPPROTO_HOPOPTS = 0
+ IPPROTO_HOPOPTS = 0x0
IPPROTO_ICMP = 0x1
IPPROTO_ICMPV6 = 0x3a
IPPROTO_IDP = 0x16
@@ -758,7 +661,7 @@ const (
IPPROTO_IL = 0x28
IPPROTO_INLSP = 0x34
IPPROTO_INP = 0x20
- IPPROTO_IP = 0
+ IPPROTO_IP = 0x0
IPPROTO_IPCOMP = 0x6c
IPPROTO_IPCV = 0x47
IPPROTO_IPEIP = 0x5e
@@ -868,7 +771,7 @@ const (
IPV6_PATHMTU = 0x2c
IPV6_PKTINFO = 0x2e
IPV6_PORTRANGE = 0xe
- IPV6_PORTRANGE_DEFAULT = 0
+ IPV6_PORTRANGE_DEFAULT = 0x0
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_PREFER_TEMPADDR = 0x3f
@@ -881,9 +784,9 @@ const (
IPV6_RECVTCLASS = 0x39
IPV6_RTHDR = 0x33
IPV6_RTHDRDSTOPTS = 0x23
- IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_LOOSE = 0x0
IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
+ IPV6_RTHDR_TYPE_0 = 0x0
IPV6_SOCKOPT_RESERVED1 = 0x3
IPV6_TCLASS = 0x3d
IPV6_UNICAST_HOPS = 0x4
@@ -944,7 +847,7 @@ const (
IP_ONESBCAST = 0x17
IP_OPTIONS = 0x1
IP_PORTRANGE = 0x13
- IP_PORTRANGE_DEFAULT = 0
+ IP_PORTRANGE_DEFAULT = 0x0
IP_PORTRANGE_HIGH = 0x1
IP_PORTRANGE_LOW = 0x2
IP_RECVDSTADDR = 0x7
@@ -962,6 +865,10 @@ const (
IP_TOS = 0x3
IP_TTL = 0x4
IP_UNBLOCK_SOURCE = 0x49
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -980,6 +887,29 @@ const (
NET_RT_IFLIST = 0x3
NET_RT_IFMALIST = 0x4
NET_RT_MAXID = 0x5
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXTEND = 0x4
+ NOTE_FFAND = 0x40000000
+ NOTE_FFCOPY = 0xc0000000
+ NOTE_FFCTRLMASK = 0xc0000000
+ NOTE_FFLAGSMASK = 0xffffff
+ NOTE_FFNOP = 0x0
+ NOTE_FFOR = 0x80000000
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_PCTRLMASK = 0xf0000000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_RENAME = 0x20
+ NOTE_REVOKE = 0x40
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRIGGER = 0x1000000
+ NOTE_WRITE = 0x2
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
@@ -994,16 +924,24 @@ const (
O_NOCTTY = 0x8000
O_NOFOLLOW = 0x100
O_NONBLOCK = 0x4
- O_RDONLY = 0
+ O_RDONLY = 0x0
O_RDWR = 0x2
O_SHLOCK = 0x10
O_SYNC = 0x80
O_TRUNC = 0x400
O_TTY_INIT = 0x80000
O_WRONLY = 0x1
+ RLIMIT_AS = 0xa
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
RTAX_AUTHOR = 0x6
RTAX_BRD = 0x7
- RTAX_DST = 0
+ RTAX_DST = 0x0
RTAX_GATEWAY = 0x1
RTAX_GENMASK = 0x3
RTAX_IFA = 0x5
@@ -1070,47 +1008,16 @@ const (
RTV_SPIPE = 0x10
RTV_SSTHRESH = 0x20
RTV_WEIGHT = 0x100
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
SCM_BINTIME = 0x4
SCM_CREDS = 0x3
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
- SHUT_RD = 0
+ SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0xa
- SIGCHLD = 0x14
- SIGCONT = 0x13
- SIGEMT = 0x7
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINFO = 0x1d
- SIGINT = 0x2
- SIGIO = 0x17
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGLWP = 0x20
- SIGPIPE = 0xd
- SIGPROF = 0x1b
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTOP = 0x11
- SIGSYS = 0xc
- SIGTERM = 0xf
- SIGTHR = 0x20
- SIGTRAP = 0x5
- SIGTSTP = 0x12
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGURG = 0x10
- SIGUSR1 = 0x1e
- SIGUSR2 = 0x1f
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
SIOCADDMULTI = 0x80206931
SIOCADDRT = 0x8030720a
SIOCAIFADDR = 0x8040691a
@@ -1270,7 +1177,7 @@ const (
TIOCNXCL = 0x2000740e
TIOCOUTQ = 0x40047473
TIOCPKT = 0x80047470
- TIOCPKT_DATA = 0
+ TIOCPKT_DATA = 0x0
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
@@ -1305,7 +1212,143 @@ const (
WUNTRACED = 0x2
)
-// Types
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADMSG = Errno(0x59)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x55)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDOOFUS = Errno(0x58)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x52)
+ EILSEQ = Errno(0x56)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5d)
+ ELOOP = Errno(0x3e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ EMULTIHOP = Errno(0x5a)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x57)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOLINK = Errno(0x5b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x53)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCAPABLE = Errno(0x5d)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x2d)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x54)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTO = Errno(0x5c)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGLWP = Signal(0x20)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHR = Signal(0x20)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1403,3 +1446,39 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "suspended (signal)",
+ 18: "suspended",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+ 32: "unknown signal",
+}
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index ce3c7dd34..b7b27b56f 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -1,13 +1,11 @@
-// mkerrors.sh -f -m64
+// mkerrors.sh -m64
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
package syscall
-// Constants
const (
AF_APPLETALK = 0x10
AF_ARP = 0x23
@@ -45,7 +43,7 @@ const (
AF_SLOW = 0x21
AF_SNA = 0xb
AF_UNIX = 0x1
- AF_UNSPEC = 0
+ AF_UNSPEC = 0x0
AF_VENDOR00 = 0x27
AF_VENDOR01 = 0x29
AF_VENDOR02 = 0x2b
@@ -128,7 +126,7 @@ const (
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
- BPF_ADD = 0
+ BPF_ADD = 0x0
BPF_ALIGNMENT = 0x8
BPF_ALU = 0x4
BPF_AND = 0x50
@@ -137,16 +135,16 @@ const (
BPF_BUFMODE_ZBUF = 0x2
BPF_DIV = 0x30
BPF_H = 0x8
- BPF_IMM = 0
+ BPF_IMM = 0x0
BPF_IND = 0x40
- BPF_JA = 0
+ BPF_JA = 0x0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
BPF_JMP = 0x5
BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
+ BPF_K = 0x0
+ BPF_LD = 0x0
BPF_LDX = 0x1
BPF_LEN = 0x80
BPF_LSH = 0x60
@@ -168,9 +166,9 @@ const (
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
- BPF_TAX = 0
+ BPF_TAX = 0x0
BPF_TXA = 0x80
- BPF_W = 0
+ BPF_W = 0x0
BPF_X = 0x8
CTL_MAXNAME = 0x18
CTL_NET = 0x4
@@ -260,7 +258,7 @@ const (
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
DLT_MTP3 = 0x8d
- DLT_NULL = 0
+ DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
DLT_PFSYNC = 0x79
@@ -311,22 +309,8 @@ const (
DT_LNK = 0xa
DT_REG = 0x8
DT_SOCK = 0xc
- DT_UNKNOWN = 0
+ DT_UNKNOWN = 0x0
DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x30
- EADDRNOTAVAIL = 0x31
- EAFNOSUPPORT = 0x2f
- EAGAIN = 0x23
- EALREADY = 0x25
- EAUTH = 0x50
- EBADF = 0x9
- EBADMSG = 0x59
- EBADRPC = 0x48
- EBUSY = 0x10
- ECANCELED = 0x55
- ECHILD = 0xa
ECHO = 0x8
ECHOCTL = 0x40
ECHOE = 0x2
@@ -334,86 +318,6 @@ const (
ECHOKE = 0x1
ECHONL = 0x10
ECHOPRT = 0x20
- ECONNABORTED = 0x35
- ECONNREFUSED = 0x3d
- ECONNRESET = 0x36
- EDEADLK = 0xb
- EDESTADDRREQ = 0x27
- EDOM = 0x21
- EDOOFUS = 0x58
- EDQUOT = 0x45
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EFTYPE = 0x4f
- EHOSTDOWN = 0x40
- EHOSTUNREACH = 0x41
- EIDRM = 0x52
- EILSEQ = 0x56
- EINPROGRESS = 0x24
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x38
- EISDIR = 0x15
- ELAST = 0x5d
- ELOOP = 0x3e
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x28
- EMULTIHOP = 0x5a
- ENAMETOOLONG = 0x3f
- ENEEDAUTH = 0x51
- ENETDOWN = 0x32
- ENETRESET = 0x34
- ENETUNREACH = 0x33
- ENFILE = 0x17
- ENOATTR = 0x57
- ENOBUFS = 0x37
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOLCK = 0x4d
- ENOLINK = 0x5b
- ENOMEM = 0xc
- ENOMSG = 0x53
- ENOPROTOOPT = 0x2a
- ENOSPC = 0x1c
- ENOSYS = 0x4e
- ENOTBLK = 0xf
- ENOTCAPABLE = 0x5d
- ENOTCONN = 0x39
- ENOTDIR = 0x14
- ENOTEMPTY = 0x42
- ENOTSOCK = 0x26
- ENOTSUP = 0x2d
- ENOTTY = 0x19
- ENXIO = 0x6
- EOPNOTSUPP = 0x2d
- EOVERFLOW = 0x54
- EPERM = 0x1
- EPFNOSUPPORT = 0x2e
- EPIPE = 0x20
- EPROCLIM = 0x43
- EPROCUNAVAIL = 0x4c
- EPROGMISMATCH = 0x4b
- EPROGUNAVAIL = 0x4a
- EPROTO = 0x5c
- EPROTONOSUPPORT = 0x2b
- EPROTOTYPE = 0x29
- ERANGE = 0x22
- EREMOTE = 0x47
- EROFS = 0x1e
- ERPCMISMATCH = 0x49
- ESHUTDOWN = 0x3a
- ESOCKTNOSUPPORT = 0x2c
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESTALE = 0x46
- ETIMEDOUT = 0x3c
- ETOOMANYREFS = 0x3b
- ETXTBSY = 0x1a
- EUSERS = 0x44
EVFILT_AIO = -0x3
EVFILT_FS = -0x9
EVFILT_LIO = -0xa
@@ -437,8 +341,6 @@ const (
EV_ONESHOT = 0x10
EV_RECEIPT = 0x40
EV_SYSFLAGS = 0xf000
- EWOULDBLOCK = 0x23
- EXDEV = 0x12
EXTA = 0x4b00
EXTB = 0x9600
EXTPROC = 0x800
@@ -446,12 +348,13 @@ const (
FD_SETSIZE = 0x400
F_CANCEL = 0x5
F_DUP2FD = 0xa
- F_DUPFD = 0
+ F_DUPFD = 0x0
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0xb
F_GETOWN = 0x5
F_OGETLK = 0x7
+ F_OK = 0x0
F_OSETLK = 0x8
F_OSETLKW = 0x9
F_RDAHEAD = 0x10
@@ -746,7 +649,7 @@ const (
IPPROTO_GRE = 0x2f
IPPROTO_HELLO = 0x3f
IPPROTO_HMP = 0x14
- IPPROTO_HOPOPTS = 0
+ IPPROTO_HOPOPTS = 0x0
IPPROTO_ICMP = 0x1
IPPROTO_ICMPV6 = 0x3a
IPPROTO_IDP = 0x16
@@ -758,7 +661,7 @@ const (
IPPROTO_IL = 0x28
IPPROTO_INLSP = 0x34
IPPROTO_INP = 0x20
- IPPROTO_IP = 0
+ IPPROTO_IP = 0x0
IPPROTO_IPCOMP = 0x6c
IPPROTO_IPCV = 0x47
IPPROTO_IPEIP = 0x5e
@@ -868,7 +771,7 @@ const (
IPV6_PATHMTU = 0x2c
IPV6_PKTINFO = 0x2e
IPV6_PORTRANGE = 0xe
- IPV6_PORTRANGE_DEFAULT = 0
+ IPV6_PORTRANGE_DEFAULT = 0x0
IPV6_PORTRANGE_HIGH = 0x1
IPV6_PORTRANGE_LOW = 0x2
IPV6_PREFER_TEMPADDR = 0x3f
@@ -881,9 +784,9 @@ const (
IPV6_RECVTCLASS = 0x39
IPV6_RTHDR = 0x33
IPV6_RTHDRDSTOPTS = 0x23
- IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_LOOSE = 0x0
IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
+ IPV6_RTHDR_TYPE_0 = 0x0
IPV6_SOCKOPT_RESERVED1 = 0x3
IPV6_TCLASS = 0x3d
IPV6_UNICAST_HOPS = 0x4
@@ -944,7 +847,7 @@ const (
IP_ONESBCAST = 0x17
IP_OPTIONS = 0x1
IP_PORTRANGE = 0x13
- IP_PORTRANGE_DEFAULT = 0
+ IP_PORTRANGE_DEFAULT = 0x0
IP_PORTRANGE_HIGH = 0x1
IP_PORTRANGE_LOW = 0x2
IP_RECVDSTADDR = 0x7
@@ -962,6 +865,10 @@ const (
IP_TOS = 0x3
IP_TTL = 0x4
IP_UNBLOCK_SOURCE = 0x49
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -980,6 +887,29 @@ const (
NET_RT_IFLIST = 0x3
NET_RT_IFMALIST = 0x4
NET_RT_MAXID = 0x5
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXTEND = 0x4
+ NOTE_FFAND = 0x40000000
+ NOTE_FFCOPY = 0xc0000000
+ NOTE_FFCTRLMASK = 0xc0000000
+ NOTE_FFLAGSMASK = 0xffffff
+ NOTE_FFNOP = 0x0
+ NOTE_FFOR = 0x80000000
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_PCTRLMASK = 0xf0000000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_RENAME = 0x20
+ NOTE_REVOKE = 0x40
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRIGGER = 0x1000000
+ NOTE_WRITE = 0x2
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
@@ -994,16 +924,24 @@ const (
O_NOCTTY = 0x8000
O_NOFOLLOW = 0x100
O_NONBLOCK = 0x4
- O_RDONLY = 0
+ O_RDONLY = 0x0
O_RDWR = 0x2
O_SHLOCK = 0x10
O_SYNC = 0x80
O_TRUNC = 0x400
O_TTY_INIT = 0x80000
O_WRONLY = 0x1
+ RLIMIT_AS = 0xa
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
RTAX_AUTHOR = 0x6
RTAX_BRD = 0x7
- RTAX_DST = 0
+ RTAX_DST = 0x0
RTAX_GATEWAY = 0x1
RTAX_GENMASK = 0x3
RTAX_IFA = 0x5
@@ -1070,47 +1008,16 @@ const (
RTV_SPIPE = 0x10
RTV_SSTHRESH = 0x20
RTV_WEIGHT = 0x100
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
SCM_BINTIME = 0x4
SCM_CREDS = 0x3
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x2
- SHUT_RD = 0
+ SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0xa
- SIGCHLD = 0x14
- SIGCONT = 0x13
- SIGEMT = 0x7
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINFO = 0x1d
- SIGINT = 0x2
- SIGIO = 0x17
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGLWP = 0x20
- SIGPIPE = 0xd
- SIGPROF = 0x1b
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTOP = 0x11
- SIGSYS = 0xc
- SIGTERM = 0xf
- SIGTHR = 0x20
- SIGTRAP = 0x5
- SIGTSTP = 0x12
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGURG = 0x10
- SIGUSR1 = 0x1e
- SIGUSR2 = 0x1f
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
SIOCADDMULTI = 0x80206931
SIOCADDRT = 0x8040720a
SIOCAIFADDR = 0x8040691a
@@ -1270,7 +1177,7 @@ const (
TIOCNXCL = 0x2000740e
TIOCOUTQ = 0x40047473
TIOCPKT = 0x80047470
- TIOCPKT_DATA = 0
+ TIOCPKT_DATA = 0x0
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
@@ -1305,7 +1212,143 @@ const (
WUNTRACED = 0x2
)
-// Types
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADMSG = Errno(0x59)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x55)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDOOFUS = Errno(0x58)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x52)
+ EILSEQ = Errno(0x56)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5d)
+ ELOOP = Errno(0x3e)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ EMULTIHOP = Errno(0x5a)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x57)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOLINK = Errno(0x5b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x53)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCAPABLE = Errno(0x5d)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x2d)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x54)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTO = Errno(0x5c)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGLWP = Signal(0x20)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHR = Signal(0x20)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1403,3 +1446,39 @@ var errors = [...]string{
92: "protocol error",
93: "capabilities insufficient",
}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "suspended (signal)",
+ 18: "suspended",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+ 32: "unknown signal",
+}
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index f482096e0..065da8f45 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -1,14 +1,17 @@
-// mkerrors.sh -f -m32
+// mkerrors.sh -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
+//line _const.go:1
package syscall
-// Constants
+//line _const.go:51
+
+//line _const.go:50
const (
+ AF_ALG = 0x26
AF_APPLETALK = 0x5
AF_ASH = 0x12
AF_ATMPVC = 0x8
@@ -16,6 +19,7 @@ const (
AF_AX25 = 0x3
AF_BLUETOOTH = 0x1f
AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
AF_CAN = 0x1d
AF_DECnet = 0xc
AF_ECONET = 0x13
@@ -30,7 +34,7 @@ const (
AF_KEY = 0xf
AF_LLC = 0x1a
AF_LOCAL = 0x1
- AF_MAX = 0x25
+ AF_MAX = 0x27
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
@@ -45,7 +49,7 @@ const (
AF_SNA = 0x16
AF_TIPC = 0x1e
AF_UNIX = 0x1
- AF_UNSPEC = 0
+ AF_UNSPEC = 0x0
AF_WANPIPE = 0x19
AF_X25 = 0x9
ARPHRD_ADAPT = 0x108
@@ -90,7 +94,7 @@ const (
ARPHRD_LOCALTLK = 0x305
ARPHRD_LOOPBACK = 0x304
ARPHRD_METRICOM = 0x17
- ARPHRD_NETROM = 0
+ ARPHRD_NETROM = 0x0
ARPHRD_NONE = 0xfffe
ARPHRD_PIMREG = 0x30b
ARPHRD_PPP = 0x200
@@ -108,22 +112,22 @@ const (
ARPHRD_X25 = 0x10f
BPF_A = 0x10
BPF_ABS = 0x20
- BPF_ADD = 0
+ BPF_ADD = 0x0
BPF_ALU = 0x4
BPF_AND = 0x50
BPF_B = 0x10
BPF_DIV = 0x30
BPF_H = 0x8
- BPF_IMM = 0
+ BPF_IMM = 0x0
BPF_IND = 0x40
- BPF_JA = 0
+ BPF_JA = 0x0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
BPF_JMP = 0x5
BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
+ BPF_K = 0x0
+ BPF_LD = 0x0
BPF_LDX = 0x1
BPF_LEN = 0x80
BPF_LSH = 0x60
@@ -142,9 +146,9 @@ const (
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
- BPF_TAX = 0
+ BPF_TAX = 0x0
BPF_TXA = 0x80
- BPF_W = 0
+ BPF_W = 0x0
BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
@@ -153,114 +157,8 @@ const (
DT_LNK = 0xa
DT_REG = 0x8
DT_SOCK = 0xc
- DT_UNKNOWN = 0
+ DT_UNKNOWN = 0x0
DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x62
- EADDRNOTAVAIL = 0x63
- EADV = 0x44
- EAFNOSUPPORT = 0x61
- EAGAIN = 0xb
- EALREADY = 0x72
- EBADE = 0x34
- EBADF = 0x9
- EBADFD = 0x4d
- EBADMSG = 0x4a
- EBADR = 0x35
- EBADRQC = 0x38
- EBADSLT = 0x39
- EBFONT = 0x3b
- EBUSY = 0x10
- ECANCELED = 0x7d
- ECHILD = 0xa
- ECHRNG = 0x2c
- ECOMM = 0x46
- ECONNABORTED = 0x67
- ECONNREFUSED = 0x6f
- ECONNRESET = 0x68
- EDEADLK = 0x23
- EDEADLOCK = 0x23
- EDESTADDRREQ = 0x59
- EDOM = 0x21
- EDOTDOT = 0x49
- EDQUOT = 0x7a
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EHOSTDOWN = 0x70
- EHOSTUNREACH = 0x71
- EIDRM = 0x2b
- EILSEQ = 0x54
- EINPROGRESS = 0x73
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x6a
- EISDIR = 0x15
- EISNAM = 0x78
- EKEYEXPIRED = 0x7f
- EKEYREJECTED = 0x81
- EKEYREVOKED = 0x80
- EL2HLT = 0x33
- EL2NSYNC = 0x2d
- EL3HLT = 0x2e
- EL3RST = 0x2f
- ELIBACC = 0x4f
- ELIBBAD = 0x50
- ELIBEXEC = 0x53
- ELIBMAX = 0x52
- ELIBSCN = 0x51
- ELNRNG = 0x30
- ELOOP = 0x28
- EMEDIUMTYPE = 0x7c
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x5a
- EMULTIHOP = 0x48
- ENAMETOOLONG = 0x24
- ENAVAIL = 0x77
- ENETDOWN = 0x64
- ENETRESET = 0x66
- ENETUNREACH = 0x65
- ENFILE = 0x17
- ENOANO = 0x37
- ENOBUFS = 0x69
- ENOCSI = 0x32
- ENODATA = 0x3d
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOKEY = 0x7e
- ENOLCK = 0x25
- ENOLINK = 0x43
- ENOMEDIUM = 0x7b
- ENOMEM = 0xc
- ENOMSG = 0x2a
- ENONET = 0x40
- ENOPKG = 0x41
- ENOPROTOOPT = 0x5c
- ENOSPC = 0x1c
- ENOSR = 0x3f
- ENOSTR = 0x3c
- ENOSYS = 0x26
- ENOTBLK = 0xf
- ENOTCONN = 0x6b
- ENOTDIR = 0x14
- ENOTEMPTY = 0x27
- ENOTNAM = 0x76
- ENOTRECOVERABLE = 0x83
- ENOTSOCK = 0x58
- ENOTSUP = 0x5f
- ENOTTY = 0x19
- ENOTUNIQ = 0x4c
- ENXIO = 0x6
- EOPNOTSUPP = 0x5f
- EOVERFLOW = 0x4b
- EOWNERDEAD = 0x82
- EPERM = 0x1
- EPFNOSUPPORT = 0x60
- EPIPE = 0x20
EPOLLERR = 0x8
EPOLLET = -0x80000000
EPOLLHUP = 0x10
@@ -279,23 +177,6 @@ const (
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
EPOLL_NONBLOCK = 0x800
- EPROTO = 0x47
- EPROTONOSUPPORT = 0x5d
- EPROTOTYPE = 0x5b
- ERANGE = 0x22
- EREMCHG = 0x4e
- EREMOTE = 0x42
- EREMOTEIO = 0x79
- ERESTART = 0x55
- ERFKILL = 0x84
- EROFS = 0x1e
- ESHUTDOWN = 0x6c
- ESOCKTNOSUPPORT = 0x5e
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESRMNT = 0x45
- ESTALE = 0x74
- ESTRPIPE = 0x56
ETH_P_1588 = 0x88f7
ETH_P_8021Q = 0x8100
ETH_P_802_2 = 0x4
@@ -310,6 +191,7 @@ const (
ETH_P_ATMMPOA = 0x884c
ETH_P_AX25 = 0x2
ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
ETH_P_CAN = 0xc
ETH_P_CONTROL = 0x16
ETH_P_CUST = 0x6006
@@ -333,6 +215,7 @@ const (
ETH_P_IPX = 0x8137
ETH_P_IRDA = 0x17
ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
ETH_P_LOCALTALK = 0x9
ETH_P_LOOP = 0x60
ETH_P_MOBITEX = 0x15
@@ -358,19 +241,9 @@ const (
ETH_P_WAN_PPP = 0x7
ETH_P_WCCP = 0x883e
ETH_P_X25 = 0x805
- ETIME = 0x3e
- ETIMEDOUT = 0x6e
- ETOOMANYREFS = 0x6d
- ETXTBSY = 0x1a
- EUCLEAN = 0x75
- EUNATCH = 0x31
- EUSERS = 0x57
- EWOULDBLOCK = 0xb
- EXDEV = 0x12
- EXFULL = 0x36
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
- F_DUPFD = 0
+ F_DUPFD = 0x0
F_DUPFD_CLOEXEC = 0x406
F_EXLCK = 0x4
F_GETFD = 0x1
@@ -380,11 +253,12 @@ const (
F_GETLK64 = 0xc
F_GETOWN = 0x9
F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
- F_OK = 0
- F_RDLCK = 0
+ F_OK = 0x0
+ F_RDLCK = 0x0
F_SETFD = 0x2
F_SETFL = 0x4
F_SETLEASE = 0x400
@@ -394,11 +268,12 @@ const (
F_SETLKW64 = 0xe
F_SETOWN = 0x8
F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
F_TLOCK = 0x2
- F_ULOCK = 0
+ F_ULOCK = 0x0
F_UNLCK = 0x2
F_WRLCK = 0x1
IFA_F_DADFAILED = 0x8
@@ -456,6 +331,7 @@ const (
IN_DELETE = 0x200
IN_DELETE_SELF = 0x400
IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
IN_IGNORED = 0x8000
IN_ISDIR = 0x40000000
IN_LOOPBACKNET = 0x7f
@@ -480,12 +356,12 @@ const (
IPPROTO_ESP = 0x32
IPPROTO_FRAGMENT = 0x2c
IPPROTO_GRE = 0x2f
- IPPROTO_HOPOPTS = 0
+ IPPROTO_HOPOPTS = 0x0
IPPROTO_ICMP = 0x1
IPPROTO_ICMPV6 = 0x3a
IPPROTO_IDP = 0x16
IPPROTO_IGMP = 0x2
- IPPROTO_IP = 0
+ IPPROTO_IP = 0x0
IPPROTO_IPIP = 0x4
IPPROTO_IPV6 = 0x29
IPPROTO_MTP = 0x5c
@@ -527,7 +403,7 @@ const (
IPV6_NEXTHOP = 0x9
IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
- IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_DONT = 0x0
IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
IPV6_RECVDSTOPTS = 0x3a
@@ -540,9 +416,9 @@ const (
IPV6_ROUTER_ALERT = 0x16
IPV6_RTHDR = 0x39
IPV6_RTHDRDSTOPTS = 0x37
- IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_LOOSE = 0x0
IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
+ IPV6_RTHDR_TYPE_0 = 0x0
IPV6_RXDSTOPTS = 0x3b
IPV6_RXHOPOPTS = 0x36
IPV6_TCLASS = 0x43
@@ -557,27 +433,34 @@ const (
IP_DF = 0x4000
IP_DROP_MEMBERSHIP = 0x24
IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
+ IP_MINTTL = 0x15
IP_MSFILTER = 0x29
IP_MSS = 0x240
+ IP_MTU = 0xe
IP_MTU_DISCOVER = 0xa
IP_MULTICAST_IF = 0x20
IP_MULTICAST_LOOP = 0x22
IP_MULTICAST_TTL = 0x21
IP_OFFMASK = 0x1fff
IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
IP_PKTINFO = 0x8
IP_PKTOPTIONS = 0x9
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
- IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_DONT = 0x0
IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
IP_RECVRETOPTS = 0x7
IP_RECVTOS = 0xd
IP_RECVTTL = 0xc
@@ -585,9 +468,11 @@ const (
IP_RF = 0x8000
IP_ROUTER_ALERT = 0x5
IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
- LINUX_REBOOT_CMD_CAD_OFF = 0
+ IP_XFRM_POLICY = 0x11
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
LINUX_REBOOT_CMD_HALT = 0xcdef0123
LINUX_REBOOT_CMD_KEXEC = 0x45584543
@@ -597,12 +482,18 @@ const (
LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
LINUX_REBOOT_MAGIC1 = 0xfee1dead
LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
MADV_DOFORK = 0xb
MADV_DONTFORK = 0xa
MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
MADV_HWPOISON = 0x64
MADV_MERGEABLE = 0xc
- MADV_NORMAL = 0
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
MADV_RANDOM = 0x1
MADV_REMOVE = 0x9
MADV_SEQUENTIAL = 0x2
@@ -613,9 +504,10 @@ const (
MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800
MAP_EXECUTABLE = 0x1000
- MAP_FILE = 0
+ MAP_FILE = 0x0
MAP_FIXED = 0x10
MAP_GROWSDOWN = 0x100
+ MAP_HUGETLB = 0x40000
MAP_LOCKED = 0x2000
MAP_NONBLOCK = 0x10000
MAP_NORESERVE = 0x4000
@@ -647,22 +539,38 @@ const (
MSG_TRUNC = 0x20
MSG_TRYHARD = 0x4
MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
MS_ASYNC = 0x1
MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
MS_MANDLOCK = 0x40
MS_MGC_MSK = 0xffff0000
MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
MS_NOATIME = 0x400
MS_NODEV = 0x4
MS_NODIRATIME = 0x800
MS_NOEXEC = 0x8
MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
MS_REMOUNT = 0x20
- MS_RMT_MASK = 0xc51
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
MS_SYNC = 0x4
MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
NAME_MAX = 0xff
NETLINK_ADD_MEMBERSHIP = 0x1
NETLINK_AUDIT = 0x9
@@ -682,7 +590,7 @@ const (
NETLINK_NFLOG = 0x5
NETLINK_NO_ENOBUFS = 0x5
NETLINK_PKTINFO = 0x3
- NETLINK_ROUTE = 0
+ NETLINK_ROUTE = 0x0
NETLINK_SCSITRANSPORT = 0x12
NETLINK_SELINUX = 0x7
NETLINK_UNUSED = 0x1
@@ -720,27 +628,27 @@ const (
O_DIRECTORY = 0x10000
O_DSYNC = 0x1000
O_EXCL = 0x80
- O_FSYNC = 0x1000
+ O_FSYNC = 0x101000
O_LARGEFILE = 0x8000
O_NDELAY = 0x800
O_NOATIME = 0x40000
O_NOCTTY = 0x100
O_NOFOLLOW = 0x20000
O_NONBLOCK = 0x800
- O_RDONLY = 0
+ O_RDONLY = 0x0
O_RDWR = 0x2
- O_RSYNC = 0x1000
- O_SYNC = 0x1000
+ O_RSYNC = 0x101000
+ O_SYNC = 0x101000
O_TRUNC = 0x200
O_WRONLY = 0x1
PACKET_ADD_MEMBERSHIP = 0x1
PACKET_BROADCAST = 0x1
PACKET_DROP_MEMBERSHIP = 0x2
PACKET_FASTROUTE = 0x6
- PACKET_HOST = 0
+ PACKET_HOST = 0x0
PACKET_LOOPBACK = 0x5
PACKET_MR_ALLMULTI = 0x2
- PACKET_MR_MULTICAST = 0
+ PACKET_MR_MULTICAST = 0x0
PACKET_MR_PROMISC = 0x1
PACKET_MULTICAST = 0x2
PACKET_OTHERHOST = 0x3
@@ -751,20 +659,69 @@ const (
PROT_EXEC = 0x4
PROT_GROWSDOWN = 0x1000000
PROT_GROWSUP = 0x2000000
- PROT_NONE = 0
+ PROT_NONE = 0x0
PROT_READ = 0x1
PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_NAME = 0xf
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
PTRACE_ATTACH = 0x10
- PTRACE_BTS_CLEAR = 0x2c
- PTRACE_BTS_CONFIG = 0x28
- PTRACE_BTS_DRAIN = 0x2d
- PTRACE_BTS_GET = 0x2b
- PTRACE_BTS_O_ALLOC = 0x8
- PTRACE_BTS_O_SCHED = 0x2
- PTRACE_BTS_O_SIGNAL = 0x4
- PTRACE_BTS_O_TRACE = 0x1
- PTRACE_BTS_SIZE = 0x2a
- PTRACE_BTS_STATUS = 0x29
PTRACE_CONT = 0x7
PTRACE_DETACH = 0x11
PTRACE_EVENT_CLONE = 0x3
@@ -777,6 +734,7 @@ const (
PTRACE_GETFPREGS = 0xe
PTRACE_GETFPXREGS = 0x12
PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
PTRACE_GETSIGINFO = 0x4202
PTRACE_GET_THREAD_AREA = 0x19
PTRACE_KILL = 0x8
@@ -799,6 +757,7 @@ const (
PTRACE_SETFPXREGS = 0x13
PTRACE_SETOPTIONS = 0x4200
PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203
PTRACE_SET_THREAD_AREA = 0x1a
PTRACE_SINGLEBLOCK = 0x21
@@ -806,7 +765,15 @@ const (
PTRACE_SYSCALL = 0x18
PTRACE_SYSEMU = 0x1f
PTRACE_SYSEMU_SINGLESTEP = 0x20
- PTRACE_TRACEME = 0
+ PTRACE_TRACEME = 0x0
+ RLIMIT_AS = 0x9
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
RTAX_ADVMSS = 0x8
RTAX_CWND = 0x7
RTAX_FEATURES = 0xc
@@ -816,18 +783,55 @@ const (
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
RTAX_LOCK = 0x1
- RTAX_MAX = 0xd
+ RTAX_MAX = 0xe
RTAX_MTU = 0x2
RTAX_REORDERING = 0x9
RTAX_RTO_MIN = 0xd
RTAX_RTT = 0x4
RTAX_RTTVAR = 0x5
RTAX_SSTHRESH = 0x6
- RTAX_UNSPEC = 0
+ RTAX_UNSPEC = 0x0
RTAX_WINDOW = 0x3
RTA_ALIGNTO = 0x4
- RTA_MAX = 0xf
+ RTA_MAX = 0x10
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
RTM_BASE = 0x10
RTM_DELACTION = 0x31
RTM_DELADDR = 0x15
@@ -892,52 +896,25 @@ const (
RTPROT_RA = 0x9
RTPROT_REDIRECT = 0x1
RTPROT_STATIC = 0x4
- RTPROT_UNSPEC = 0
+ RTPROT_UNSPEC = 0x0
RTPROT_XORP = 0xe
RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
SCM_CREDENTIALS = 0x2
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SCM_TIMESTAMPING = 0x25
SCM_TIMESTAMPNS = 0x23
- SHUT_RD = 0
+ SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0x7
- SIGCHLD = 0x11
- SIGCLD = 0x11
- SIGCONT = 0x12
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINT = 0x2
- SIGIO = 0x1d
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGPIPE = 0xd
- SIGPOLL = 0x1d
- SIGPROF = 0x1b
- SIGPWR = 0x1e
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTKFLT = 0x10
- SIGSTOP = 0x13
- SIGSYS = 0x1f
- SIGTERM = 0xf
- SIGTRAP = 0x5
- SIGTSTP = 0x14
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGUNUSED = 0x1f
- SIGURG = 0x17
- SIGUSR1 = 0xa
- SIGUSR2 = 0xc
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
SIOCADDDLCI = 0x8980
SIOCADDMULTI = 0x8931
SIOCADDRT = 0x890b
@@ -1009,7 +986,7 @@ const (
SOL_ATM = 0x108
SOL_DECNET = 0x105
SOL_ICMPV6 = 0x3a
- SOL_IP = 0
+ SOL_IP = 0x0
SOL_IPV6 = 0x29
SOL_IRDA = 0x10a
SOL_PACKET = 0x107
@@ -1045,6 +1022,7 @@ const (
SO_RCVLOWAT = 0x12
SO_RCVTIMEO = 0x14
SO_REUSEADDR = 0x2
+ SO_RXQ_OVFL = 0x28
SO_SECURITY_AUTHENTICATION = 0x16
SO_SECURITY_ENCRYPTION_NETWORK = 0x18
SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
@@ -1056,7 +1034,6 @@ const (
SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
- S_APPEND = 0x100
S_BLKSIZE = 0x200
S_IEXEC = 0x40
S_IFBLK = 0x6000
@@ -1067,7 +1044,6 @@ const (
S_IFMT = 0xf000
S_IFREG = 0x8000
S_IFSOCK = 0xc000
- S_IMMUTABLE = 0x200
S_IREAD = 0x100
S_IRGRP = 0x20
S_IROTH = 0x4
@@ -1085,7 +1061,6 @@ const (
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40
- S_WRITE = 0x80
TCP_CONGESTION = 0xd
TCP_CORK = 0x3
TCP_DEFER_ACCEPT = 0x9
@@ -1107,8 +1082,8 @@ const (
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
+ TIOCGDEV = 0x80045432
TIOCGETD = 0x5424
- TIOCGHAYESESP = 0x545e
TIOCGICOUNT = 0x545d
TIOCGLCKTRMIOS = 0x5456
TIOCGPGRP = 0x540f
@@ -1140,10 +1115,11 @@ const (
TIOCNXCL = 0x540d
TIOCOUTQ = 0x5411
TIOCPKT = 0x5420
- TIOCPKT_DATA = 0
+ TIOCPKT_DATA = 0x0
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
TIOCPKT_NOSTOP = 0x10
TIOCPKT_START = 0x8
TIOCPKT_STOP = 0x4
@@ -1158,7 +1134,7 @@ const (
TIOCSERSWILD = 0x5455
TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
- TIOCSHAYESESP = 0x545f
+ TIOCSIG = 0x40045436
TIOCSLCKTRMIOS = 0x5457
TIOCSPGRP = 0x5410
TIOCSPTLCK = 0x40045431
@@ -1167,9 +1143,12 @@ const (
TIOCSSOFTCAR = 0x541a
TIOCSTI = 0x5412
TIOCSWINSZ = 0x5414
+ TUNATTACHFILTER = 0x400854d5
+ TUNDETACHFILTER = 0x400854d6
TUNGETFEATURES = 0x800454cf
TUNGETIFF = 0x800454d2
TUNGETSNDBUF = 0x800454d3
+ TUNGETVNETHDRSZ = 0x800454d7
TUNSETDEBUG = 0x400454c9
TUNSETGROUP = 0x400454ce
TUNSETIFF = 0x400454ca
@@ -1180,6 +1159,7 @@ const (
TUNSETPERSIST = 0x400454cb
TUNSETSNDBUF = 0x400454d4
TUNSETTXFILTER = 0x400454d1
+ TUNSETVNETHDRSZ = 0x400454d8
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -1192,7 +1172,181 @@ const (
WUNTRACED = 0x2
)
-// Types
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x61)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x72)
+ EBADE = Errno(0x34)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x4d)
+ EBADMSG = Errno(0x4a)
+ EBADR = Errno(0x35)
+ EBADRQC = Errno(0x38)
+ EBADSLT = Errno(0x39)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x7d)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x2c)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x67)
+ ECONNREFUSED = Errno(0x6f)
+ ECONNRESET = Errno(0x68)
+ EDEADLK = Errno(0x23)
+ EDEADLOCK = Errno(0x23)
+ EDESTADDRREQ = Errno(0x59)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x7a)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x70)
+ EHOSTUNREACH = Errno(0x71)
+ EIDRM = Errno(0x2b)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x73)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x6a)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x78)
+ EKEYEXPIRED = Errno(0x7f)
+ EKEYREJECTED = Errno(0x81)
+ EKEYREVOKED = Errno(0x80)
+ EL2HLT = Errno(0x33)
+ EL2NSYNC = Errno(0x2d)
+ EL3HLT = Errno(0x2e)
+ EL3RST = Errno(0x2f)
+ ELIBACC = Errno(0x4f)
+ ELIBBAD = Errno(0x50)
+ ELIBEXEC = Errno(0x53)
+ ELIBMAX = Errno(0x52)
+ ELIBSCN = Errno(0x51)
+ ELNRNG = Errno(0x30)
+ ELOOP = Errno(0x28)
+ EMEDIUMTYPE = Errno(0x7c)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x5a)
+ EMULTIHOP = Errno(0x48)
+ ENAMETOOLONG = Errno(0x24)
+ ENAVAIL = Errno(0x77)
+ ENETDOWN = Errno(0x64)
+ ENETRESET = Errno(0x66)
+ ENETUNREACH = Errno(0x65)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x37)
+ ENOBUFS = Errno(0x69)
+ ENOCSI = Errno(0x32)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0x7e)
+ ENOLCK = Errno(0x25)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x7b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x2a)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x5c)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x26)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x6b)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x27)
+ ENOTNAM = Errno(0x76)
+ ENOTRECOVERABLE = Errno(0x83)
+ ENOTSOCK = Errno(0x58)
+ ENOTSUP = Errno(0x5f)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x4c)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x5f)
+ EOVERFLOW = Errno(0x4b)
+ EOWNERDEAD = Errno(0x82)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x60)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x5d)
+ EPROTOTYPE = Errno(0x5b)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x4e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x79)
+ ERESTART = Errno(0x55)
+ ERFKILL = Errno(0x84)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x6c)
+ ESOCKTNOSUPPORT = Errno(0x5e)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x74)
+ ESTRPIPE = Errno(0x56)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x6e)
+ ETOOMANYREFS = Errno(0x6d)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x75)
+ EUNATCH = Errno(0x31)
+ EUSERS = Errno(0x57)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x36)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0x7)
+ SIGCHLD = Signal(0x11)
+ SIGCLD = Signal(0x11)
+ SIGCONT = Signal(0x12)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x1d)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x1d)
+ SIGPROF = Signal(0x1b)
+ SIGPWR = Signal(0x1e)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTKFLT = Signal(0x10)
+ SIGSTOP = Signal(0x13)
+ SIGSYS = Signal(0x1f)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x14)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGUNUSED = Signal(0x1f)
+ SIGURG = Signal(0x17)
+ SIGUSR1 = Signal(0xa)
+ SIGUSR2 = Signal(0xc)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1325,5 +1479,40 @@ var errors = [...]string{
129: "key was rejected by service",
130: "owner died",
131: "state not recoverable",
- 132: "unknown error 132",
+ 132: "operation not possible due to RF-kill",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "stack fault",
+ 17: "child exited",
+ 18: "continued",
+ 19: "stopped (signal)",
+ 20: "stopped",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "urgent I/O condition",
+ 24: "CPU time limit exceeded",
+ 25: "file size limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window changed",
+ 29: "I/O possible",
+ 30: "power failure",
+ 31: "bad system call",
}
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index 5d1f31079..4e4918452 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -1,14 +1,17 @@
-// mkerrors.sh -f -m64
+// mkerrors.sh -m64
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+//line _const.go:1
package syscall
-// Constants
+//line _const.go:51
+
+//line _const.go:50
const (
+ AF_ALG = 0x26
AF_APPLETALK = 0x5
AF_ASH = 0x12
AF_ATMPVC = 0x8
@@ -16,6 +19,7 @@ const (
AF_AX25 = 0x3
AF_BLUETOOTH = 0x1f
AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
AF_CAN = 0x1d
AF_DECnet = 0xc
AF_ECONET = 0x13
@@ -30,7 +34,7 @@ const (
AF_KEY = 0xf
AF_LLC = 0x1a
AF_LOCAL = 0x1
- AF_MAX = 0x25
+ AF_MAX = 0x27
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
@@ -45,7 +49,7 @@ const (
AF_SNA = 0x16
AF_TIPC = 0x1e
AF_UNIX = 0x1
- AF_UNSPEC = 0
+ AF_UNSPEC = 0x0
AF_WANPIPE = 0x19
AF_X25 = 0x9
ARPHRD_ADAPT = 0x108
@@ -90,7 +94,7 @@ const (
ARPHRD_LOCALTLK = 0x305
ARPHRD_LOOPBACK = 0x304
ARPHRD_METRICOM = 0x17
- ARPHRD_NETROM = 0
+ ARPHRD_NETROM = 0x0
ARPHRD_NONE = 0xfffe
ARPHRD_PIMREG = 0x30b
ARPHRD_PPP = 0x200
@@ -108,22 +112,22 @@ const (
ARPHRD_X25 = 0x10f
BPF_A = 0x10
BPF_ABS = 0x20
- BPF_ADD = 0
+ BPF_ADD = 0x0
BPF_ALU = 0x4
BPF_AND = 0x50
BPF_B = 0x10
BPF_DIV = 0x30
BPF_H = 0x8
- BPF_IMM = 0
+ BPF_IMM = 0x0
BPF_IND = 0x40
- BPF_JA = 0
+ BPF_JA = 0x0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
BPF_JMP = 0x5
BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
+ BPF_K = 0x0
+ BPF_LD = 0x0
BPF_LDX = 0x1
BPF_LEN = 0x80
BPF_LSH = 0x60
@@ -142,9 +146,9 @@ const (
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
- BPF_TAX = 0
+ BPF_TAX = 0x0
BPF_TXA = 0x80
- BPF_W = 0
+ BPF_W = 0x0
BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
@@ -153,114 +157,8 @@ const (
DT_LNK = 0xa
DT_REG = 0x8
DT_SOCK = 0xc
- DT_UNKNOWN = 0
+ DT_UNKNOWN = 0x0
DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x62
- EADDRNOTAVAIL = 0x63
- EADV = 0x44
- EAFNOSUPPORT = 0x61
- EAGAIN = 0xb
- EALREADY = 0x72
- EBADE = 0x34
- EBADF = 0x9
- EBADFD = 0x4d
- EBADMSG = 0x4a
- EBADR = 0x35
- EBADRQC = 0x38
- EBADSLT = 0x39
- EBFONT = 0x3b
- EBUSY = 0x10
- ECANCELED = 0x7d
- ECHILD = 0xa
- ECHRNG = 0x2c
- ECOMM = 0x46
- ECONNABORTED = 0x67
- ECONNREFUSED = 0x6f
- ECONNRESET = 0x68
- EDEADLK = 0x23
- EDEADLOCK = 0x23
- EDESTADDRREQ = 0x59
- EDOM = 0x21
- EDOTDOT = 0x49
- EDQUOT = 0x7a
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EHOSTDOWN = 0x70
- EHOSTUNREACH = 0x71
- EIDRM = 0x2b
- EILSEQ = 0x54
- EINPROGRESS = 0x73
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x6a
- EISDIR = 0x15
- EISNAM = 0x78
- EKEYEXPIRED = 0x7f
- EKEYREJECTED = 0x81
- EKEYREVOKED = 0x80
- EL2HLT = 0x33
- EL2NSYNC = 0x2d
- EL3HLT = 0x2e
- EL3RST = 0x2f
- ELIBACC = 0x4f
- ELIBBAD = 0x50
- ELIBEXEC = 0x53
- ELIBMAX = 0x52
- ELIBSCN = 0x51
- ELNRNG = 0x30
- ELOOP = 0x28
- EMEDIUMTYPE = 0x7c
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x5a
- EMULTIHOP = 0x48
- ENAMETOOLONG = 0x24
- ENAVAIL = 0x77
- ENETDOWN = 0x64
- ENETRESET = 0x66
- ENETUNREACH = 0x65
- ENFILE = 0x17
- ENOANO = 0x37
- ENOBUFS = 0x69
- ENOCSI = 0x32
- ENODATA = 0x3d
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOKEY = 0x7e
- ENOLCK = 0x25
- ENOLINK = 0x43
- ENOMEDIUM = 0x7b
- ENOMEM = 0xc
- ENOMSG = 0x2a
- ENONET = 0x40
- ENOPKG = 0x41
- ENOPROTOOPT = 0x5c
- ENOSPC = 0x1c
- ENOSR = 0x3f
- ENOSTR = 0x3c
- ENOSYS = 0x26
- ENOTBLK = 0xf
- ENOTCONN = 0x6b
- ENOTDIR = 0x14
- ENOTEMPTY = 0x27
- ENOTNAM = 0x76
- ENOTRECOVERABLE = 0x83
- ENOTSOCK = 0x58
- ENOTSUP = 0x5f
- ENOTTY = 0x19
- ENOTUNIQ = 0x4c
- ENXIO = 0x6
- EOPNOTSUPP = 0x5f
- EOVERFLOW = 0x4b
- EOWNERDEAD = 0x82
- EPERM = 0x1
- EPFNOSUPPORT = 0x60
- EPIPE = 0x20
EPOLLERR = 0x8
EPOLLET = -0x80000000
EPOLLHUP = 0x10
@@ -279,23 +177,6 @@ const (
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
EPOLL_NONBLOCK = 0x800
- EPROTO = 0x47
- EPROTONOSUPPORT = 0x5d
- EPROTOTYPE = 0x5b
- ERANGE = 0x22
- EREMCHG = 0x4e
- EREMOTE = 0x42
- EREMOTEIO = 0x79
- ERESTART = 0x55
- ERFKILL = 0x84
- EROFS = 0x1e
- ESHUTDOWN = 0x6c
- ESOCKTNOSUPPORT = 0x5e
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESRMNT = 0x45
- ESTALE = 0x74
- ESTRPIPE = 0x56
ETH_P_1588 = 0x88f7
ETH_P_8021Q = 0x8100
ETH_P_802_2 = 0x4
@@ -310,6 +191,7 @@ const (
ETH_P_ATMMPOA = 0x884c
ETH_P_AX25 = 0x2
ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
ETH_P_CAN = 0xc
ETH_P_CONTROL = 0x16
ETH_P_CUST = 0x6006
@@ -333,6 +215,7 @@ const (
ETH_P_IPX = 0x8137
ETH_P_IRDA = 0x17
ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
ETH_P_LOCALTALK = 0x9
ETH_P_LOOP = 0x60
ETH_P_MOBITEX = 0x15
@@ -358,19 +241,9 @@ const (
ETH_P_WAN_PPP = 0x7
ETH_P_WCCP = 0x883e
ETH_P_X25 = 0x805
- ETIME = 0x3e
- ETIMEDOUT = 0x6e
- ETOOMANYREFS = 0x6d
- ETXTBSY = 0x1a
- EUCLEAN = 0x75
- EUNATCH = 0x31
- EUSERS = 0x57
- EWOULDBLOCK = 0xb
- EXDEV = 0x12
- EXFULL = 0x36
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
- F_DUPFD = 0
+ F_DUPFD = 0x0
F_DUPFD_CLOEXEC = 0x406
F_EXLCK = 0x4
F_GETFD = 0x1
@@ -380,11 +253,12 @@ const (
F_GETLK64 = 0x5
F_GETOWN = 0x9
F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
- F_OK = 0
- F_RDLCK = 0
+ F_OK = 0x0
+ F_RDLCK = 0x0
F_SETFD = 0x2
F_SETFL = 0x4
F_SETLEASE = 0x400
@@ -394,11 +268,12 @@ const (
F_SETLKW64 = 0x7
F_SETOWN = 0x8
F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
F_TLOCK = 0x2
- F_ULOCK = 0
+ F_ULOCK = 0x0
F_UNLCK = 0x2
F_WRLCK = 0x1
IFA_F_DADFAILED = 0x8
@@ -456,6 +331,7 @@ const (
IN_DELETE = 0x200
IN_DELETE_SELF = 0x400
IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
IN_IGNORED = 0x8000
IN_ISDIR = 0x40000000
IN_LOOPBACKNET = 0x7f
@@ -480,12 +356,12 @@ const (
IPPROTO_ESP = 0x32
IPPROTO_FRAGMENT = 0x2c
IPPROTO_GRE = 0x2f
- IPPROTO_HOPOPTS = 0
+ IPPROTO_HOPOPTS = 0x0
IPPROTO_ICMP = 0x1
IPPROTO_ICMPV6 = 0x3a
IPPROTO_IDP = 0x16
IPPROTO_IGMP = 0x2
- IPPROTO_IP = 0
+ IPPROTO_IP = 0x0
IPPROTO_IPIP = 0x4
IPPROTO_IPV6 = 0x29
IPPROTO_MTP = 0x5c
@@ -527,7 +403,7 @@ const (
IPV6_NEXTHOP = 0x9
IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
- IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_DONT = 0x0
IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
IPV6_RECVDSTOPTS = 0x3a
@@ -540,9 +416,9 @@ const (
IPV6_ROUTER_ALERT = 0x16
IPV6_RTHDR = 0x39
IPV6_RTHDRDSTOPTS = 0x37
- IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_LOOSE = 0x0
IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
+ IPV6_RTHDR_TYPE_0 = 0x0
IPV6_RXDSTOPTS = 0x3b
IPV6_RXHOPOPTS = 0x36
IPV6_TCLASS = 0x43
@@ -557,27 +433,34 @@ const (
IP_DF = 0x4000
IP_DROP_MEMBERSHIP = 0x24
IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
+ IP_MINTTL = 0x15
IP_MSFILTER = 0x29
IP_MSS = 0x240
+ IP_MTU = 0xe
IP_MTU_DISCOVER = 0xa
IP_MULTICAST_IF = 0x20
IP_MULTICAST_LOOP = 0x22
IP_MULTICAST_TTL = 0x21
IP_OFFMASK = 0x1fff
IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
IP_PKTINFO = 0x8
IP_PKTOPTIONS = 0x9
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
- IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_DONT = 0x0
IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
IP_RECVRETOPTS = 0x7
IP_RECVTOS = 0xd
IP_RECVTTL = 0xc
@@ -585,9 +468,11 @@ const (
IP_RF = 0x8000
IP_ROUTER_ALERT = 0x5
IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
- LINUX_REBOOT_CMD_CAD_OFF = 0
+ IP_XFRM_POLICY = 0x11
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
LINUX_REBOOT_CMD_HALT = 0xcdef0123
LINUX_REBOOT_CMD_KEXEC = 0x45584543
@@ -597,12 +482,18 @@ const (
LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
LINUX_REBOOT_MAGIC1 = 0xfee1dead
LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
MADV_DOFORK = 0xb
MADV_DONTFORK = 0xa
MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
MADV_HWPOISON = 0x64
MADV_MERGEABLE = 0xc
- MADV_NORMAL = 0
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
MADV_RANDOM = 0x1
MADV_REMOVE = 0x9
MADV_SEQUENTIAL = 0x2
@@ -613,9 +504,10 @@ const (
MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800
MAP_EXECUTABLE = 0x1000
- MAP_FILE = 0
+ MAP_FILE = 0x0
MAP_FIXED = 0x10
MAP_GROWSDOWN = 0x100
+ MAP_HUGETLB = 0x40000
MAP_LOCKED = 0x2000
MAP_NONBLOCK = 0x10000
MAP_NORESERVE = 0x4000
@@ -647,22 +539,38 @@ const (
MSG_TRUNC = 0x20
MSG_TRYHARD = 0x4
MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
MS_ASYNC = 0x1
MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
MS_MANDLOCK = 0x40
MS_MGC_MSK = 0xffff0000
MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
MS_NOATIME = 0x400
MS_NODEV = 0x4
MS_NODIRATIME = 0x800
MS_NOEXEC = 0x8
MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
MS_REMOUNT = 0x20
- MS_RMT_MASK = 0xc51
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
MS_SYNC = 0x4
MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
NAME_MAX = 0xff
NETLINK_ADD_MEMBERSHIP = 0x1
NETLINK_AUDIT = 0x9
@@ -682,7 +590,7 @@ const (
NETLINK_NFLOG = 0x5
NETLINK_NO_ENOBUFS = 0x5
NETLINK_PKTINFO = 0x3
- NETLINK_ROUTE = 0
+ NETLINK_ROUTE = 0x0
NETLINK_SCSITRANSPORT = 0x12
NETLINK_SELINUX = 0x7
NETLINK_UNUSED = 0x1
@@ -720,27 +628,27 @@ const (
O_DIRECTORY = 0x10000
O_DSYNC = 0x1000
O_EXCL = 0x80
- O_FSYNC = 0x1000
- O_LARGEFILE = 0
+ O_FSYNC = 0x101000
+ O_LARGEFILE = 0x0
O_NDELAY = 0x800
O_NOATIME = 0x40000
O_NOCTTY = 0x100
O_NOFOLLOW = 0x20000
O_NONBLOCK = 0x800
- O_RDONLY = 0
+ O_RDONLY = 0x0
O_RDWR = 0x2
- O_RSYNC = 0x1000
- O_SYNC = 0x1000
+ O_RSYNC = 0x101000
+ O_SYNC = 0x101000
O_TRUNC = 0x200
O_WRONLY = 0x1
PACKET_ADD_MEMBERSHIP = 0x1
PACKET_BROADCAST = 0x1
PACKET_DROP_MEMBERSHIP = 0x2
PACKET_FASTROUTE = 0x6
- PACKET_HOST = 0
+ PACKET_HOST = 0x0
PACKET_LOOPBACK = 0x5
PACKET_MR_ALLMULTI = 0x2
- PACKET_MR_MULTICAST = 0
+ PACKET_MR_MULTICAST = 0x0
PACKET_MR_PROMISC = 0x1
PACKET_MULTICAST = 0x2
PACKET_OTHERHOST = 0x3
@@ -751,21 +659,70 @@ const (
PROT_EXEC = 0x4
PROT_GROWSDOWN = 0x1000000
PROT_GROWSUP = 0x2000000
- PROT_NONE = 0
+ PROT_NONE = 0x0
PROT_READ = 0x1
PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_NAME = 0xf
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
PTRACE_ARCH_PRCTL = 0x1e
PTRACE_ATTACH = 0x10
- PTRACE_BTS_CLEAR = 0x2c
- PTRACE_BTS_CONFIG = 0x28
- PTRACE_BTS_DRAIN = 0x2d
- PTRACE_BTS_GET = 0x2b
- PTRACE_BTS_O_ALLOC = 0x8
- PTRACE_BTS_O_SCHED = 0x2
- PTRACE_BTS_O_SIGNAL = 0x4
- PTRACE_BTS_O_TRACE = 0x1
- PTRACE_BTS_SIZE = 0x2a
- PTRACE_BTS_STATUS = 0x29
PTRACE_CONT = 0x7
PTRACE_DETACH = 0x11
PTRACE_EVENT_CLONE = 0x3
@@ -778,6 +735,7 @@ const (
PTRACE_GETFPREGS = 0xe
PTRACE_GETFPXREGS = 0x12
PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
PTRACE_GETSIGINFO = 0x4202
PTRACE_GET_THREAD_AREA = 0x19
PTRACE_KILL = 0x8
@@ -800,6 +758,7 @@ const (
PTRACE_SETFPXREGS = 0x13
PTRACE_SETOPTIONS = 0x4200
PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203
PTRACE_SET_THREAD_AREA = 0x1a
PTRACE_SINGLEBLOCK = 0x21
@@ -807,7 +766,15 @@ const (
PTRACE_SYSCALL = 0x18
PTRACE_SYSEMU = 0x1f
PTRACE_SYSEMU_SINGLESTEP = 0x20
- PTRACE_TRACEME = 0
+ PTRACE_TRACEME = 0x0
+ RLIMIT_AS = 0x9
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
RTAX_ADVMSS = 0x8
RTAX_CWND = 0x7
RTAX_FEATURES = 0xc
@@ -817,18 +784,55 @@ const (
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
RTAX_LOCK = 0x1
- RTAX_MAX = 0xd
+ RTAX_MAX = 0xe
RTAX_MTU = 0x2
RTAX_REORDERING = 0x9
RTAX_RTO_MIN = 0xd
RTAX_RTT = 0x4
RTAX_RTTVAR = 0x5
RTAX_SSTHRESH = 0x6
- RTAX_UNSPEC = 0
+ RTAX_UNSPEC = 0x0
RTAX_WINDOW = 0x3
RTA_ALIGNTO = 0x4
- RTA_MAX = 0xf
+ RTA_MAX = 0x10
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
RTM_BASE = 0x10
RTM_DELACTION = 0x31
RTM_DELADDR = 0x15
@@ -893,52 +897,25 @@ const (
RTPROT_RA = 0x9
RTPROT_REDIRECT = 0x1
RTPROT_STATIC = 0x4
- RTPROT_UNSPEC = 0
+ RTPROT_UNSPEC = 0x0
RTPROT_XORP = 0xe
RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
SCM_CREDENTIALS = 0x2
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SCM_TIMESTAMPING = 0x25
SCM_TIMESTAMPNS = 0x23
- SHUT_RD = 0
+ SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0x7
- SIGCHLD = 0x11
- SIGCLD = 0x11
- SIGCONT = 0x12
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINT = 0x2
- SIGIO = 0x1d
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGPIPE = 0xd
- SIGPOLL = 0x1d
- SIGPROF = 0x1b
- SIGPWR = 0x1e
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTKFLT = 0x10
- SIGSTOP = 0x13
- SIGSYS = 0x1f
- SIGTERM = 0xf
- SIGTRAP = 0x5
- SIGTSTP = 0x14
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGUNUSED = 0x1f
- SIGURG = 0x17
- SIGUSR1 = 0xa
- SIGUSR2 = 0xc
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
SIOCADDDLCI = 0x8980
SIOCADDMULTI = 0x8931
SIOCADDRT = 0x890b
@@ -1010,7 +987,7 @@ const (
SOL_ATM = 0x108
SOL_DECNET = 0x105
SOL_ICMPV6 = 0x3a
- SOL_IP = 0
+ SOL_IP = 0x0
SOL_IPV6 = 0x29
SOL_IRDA = 0x10a
SOL_PACKET = 0x107
@@ -1046,6 +1023,7 @@ const (
SO_RCVLOWAT = 0x12
SO_RCVTIMEO = 0x14
SO_REUSEADDR = 0x2
+ SO_RXQ_OVFL = 0x28
SO_SECURITY_AUTHENTICATION = 0x16
SO_SECURITY_ENCRYPTION_NETWORK = 0x18
SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
@@ -1057,7 +1035,6 @@ const (
SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
- S_APPEND = 0x100
S_BLKSIZE = 0x200
S_IEXEC = 0x40
S_IFBLK = 0x6000
@@ -1068,7 +1045,6 @@ const (
S_IFMT = 0xf000
S_IFREG = 0x8000
S_IFSOCK = 0xc000
- S_IMMUTABLE = 0x200
S_IREAD = 0x100
S_IRGRP = 0x20
S_IROTH = 0x4
@@ -1086,7 +1062,6 @@ const (
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40
- S_WRITE = 0x80
TCP_CONGESTION = 0xd
TCP_CORK = 0x3
TCP_DEFER_ACCEPT = 0x9
@@ -1108,8 +1083,8 @@ const (
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
+ TIOCGDEV = 0x80045432
TIOCGETD = 0x5424
- TIOCGHAYESESP = 0x545e
TIOCGICOUNT = 0x545d
TIOCGLCKTRMIOS = 0x5456
TIOCGPGRP = 0x540f
@@ -1141,10 +1116,11 @@ const (
TIOCNXCL = 0x540d
TIOCOUTQ = 0x5411
TIOCPKT = 0x5420
- TIOCPKT_DATA = 0
+ TIOCPKT_DATA = 0x0
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
TIOCPKT_NOSTOP = 0x10
TIOCPKT_START = 0x8
TIOCPKT_STOP = 0x4
@@ -1159,7 +1135,7 @@ const (
TIOCSERSWILD = 0x5455
TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
- TIOCSHAYESESP = 0x545f
+ TIOCSIG = 0x40045436
TIOCSLCKTRMIOS = 0x5457
TIOCSPGRP = 0x5410
TIOCSPTLCK = 0x40045431
@@ -1168,9 +1144,12 @@ const (
TIOCSSOFTCAR = 0x541a
TIOCSTI = 0x5412
TIOCSWINSZ = 0x5414
+ TUNATTACHFILTER = 0x401054d5
+ TUNDETACHFILTER = 0x401054d6
TUNGETFEATURES = 0x800454cf
TUNGETIFF = 0x800454d2
TUNGETSNDBUF = 0x800454d3
+ TUNGETVNETHDRSZ = 0x800454d7
TUNSETDEBUG = 0x400454c9
TUNSETGROUP = 0x400454ce
TUNSETIFF = 0x400454ca
@@ -1181,6 +1160,7 @@ const (
TUNSETPERSIST = 0x400454cb
TUNSETSNDBUF = 0x400454d4
TUNSETTXFILTER = 0x400454d1
+ TUNSETVNETHDRSZ = 0x400454d8
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -1193,7 +1173,181 @@ const (
WUNTRACED = 0x2
)
-// Types
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x61)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x72)
+ EBADE = Errno(0x34)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x4d)
+ EBADMSG = Errno(0x4a)
+ EBADR = Errno(0x35)
+ EBADRQC = Errno(0x38)
+ EBADSLT = Errno(0x39)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x7d)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x2c)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x67)
+ ECONNREFUSED = Errno(0x6f)
+ ECONNRESET = Errno(0x68)
+ EDEADLK = Errno(0x23)
+ EDEADLOCK = Errno(0x23)
+ EDESTADDRREQ = Errno(0x59)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x7a)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x70)
+ EHOSTUNREACH = Errno(0x71)
+ EIDRM = Errno(0x2b)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x73)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x6a)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x78)
+ EKEYEXPIRED = Errno(0x7f)
+ EKEYREJECTED = Errno(0x81)
+ EKEYREVOKED = Errno(0x80)
+ EL2HLT = Errno(0x33)
+ EL2NSYNC = Errno(0x2d)
+ EL3HLT = Errno(0x2e)
+ EL3RST = Errno(0x2f)
+ ELIBACC = Errno(0x4f)
+ ELIBBAD = Errno(0x50)
+ ELIBEXEC = Errno(0x53)
+ ELIBMAX = Errno(0x52)
+ ELIBSCN = Errno(0x51)
+ ELNRNG = Errno(0x30)
+ ELOOP = Errno(0x28)
+ EMEDIUMTYPE = Errno(0x7c)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x5a)
+ EMULTIHOP = Errno(0x48)
+ ENAMETOOLONG = Errno(0x24)
+ ENAVAIL = Errno(0x77)
+ ENETDOWN = Errno(0x64)
+ ENETRESET = Errno(0x66)
+ ENETUNREACH = Errno(0x65)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x37)
+ ENOBUFS = Errno(0x69)
+ ENOCSI = Errno(0x32)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0x7e)
+ ENOLCK = Errno(0x25)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x7b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x2a)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x5c)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x26)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x6b)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x27)
+ ENOTNAM = Errno(0x76)
+ ENOTRECOVERABLE = Errno(0x83)
+ ENOTSOCK = Errno(0x58)
+ ENOTSUP = Errno(0x5f)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x4c)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x5f)
+ EOVERFLOW = Errno(0x4b)
+ EOWNERDEAD = Errno(0x82)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x60)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x5d)
+ EPROTOTYPE = Errno(0x5b)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x4e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x79)
+ ERESTART = Errno(0x55)
+ ERFKILL = Errno(0x84)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x6c)
+ ESOCKTNOSUPPORT = Errno(0x5e)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x74)
+ ESTRPIPE = Errno(0x56)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x6e)
+ ETOOMANYREFS = Errno(0x6d)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x75)
+ EUNATCH = Errno(0x31)
+ EUSERS = Errno(0x57)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x36)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0x7)
+ SIGCHLD = Signal(0x11)
+ SIGCLD = Signal(0x11)
+ SIGCONT = Signal(0x12)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x1d)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x1d)
+ SIGPROF = Signal(0x1b)
+ SIGPWR = Signal(0x1e)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTKFLT = Signal(0x10)
+ SIGSTOP = Signal(0x13)
+ SIGSYS = Signal(0x1f)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x14)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGUNUSED = Signal(0x1f)
+ SIGURG = Signal(0x17)
+ SIGUSR1 = Signal(0xa)
+ SIGUSR2 = Signal(0xc)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1326,5 +1480,40 @@ var errors = [...]string{
129: "key was rejected by service",
130: "owner died",
131: "state not recoverable",
- 132: "unknown error 132",
+ 132: "operation not possible due to RF-kill",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "stack fault",
+ 17: "child exited",
+ 18: "continued",
+ 19: "stopped (signal)",
+ 20: "stopped",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "urgent I/O condition",
+ 24: "CPU time limit exceeded",
+ 25: "file size limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window changed",
+ 29: "I/O possible",
+ 30: "power failure",
+ 31: "bad system call",
}
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index bebc00a4c..9b99cf83f 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -1,14 +1,13 @@
// mkerrors.sh
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -gsyscall _const.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
package syscall
-// Constants
const (
+ AF_ALG = 0x26
AF_APPLETALK = 0x5
AF_ASH = 0x12
AF_ATMPVC = 0x8
@@ -16,6 +15,7 @@ const (
AF_AX25 = 0x3
AF_BLUETOOTH = 0x1f
AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
AF_CAN = 0x1d
AF_DECnet = 0xc
AF_ECONET = 0x13
@@ -30,7 +30,7 @@ const (
AF_KEY = 0xf
AF_LLC = 0x1a
AF_LOCAL = 0x1
- AF_MAX = 0x25
+ AF_MAX = 0x27
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
@@ -45,7 +45,7 @@ const (
AF_SNA = 0x16
AF_TIPC = 0x1e
AF_UNIX = 0x1
- AF_UNSPEC = 0
+ AF_UNSPEC = 0x0
AF_WANPIPE = 0x19
AF_X25 = 0x9
ARPHRD_ADAPT = 0x108
@@ -90,7 +90,7 @@ const (
ARPHRD_LOCALTLK = 0x305
ARPHRD_LOOPBACK = 0x304
ARPHRD_METRICOM = 0x17
- ARPHRD_NETROM = 0
+ ARPHRD_NETROM = 0x0
ARPHRD_NONE = 0xfffe
ARPHRD_PIMREG = 0x30b
ARPHRD_PPP = 0x200
@@ -108,22 +108,22 @@ const (
ARPHRD_X25 = 0x10f
BPF_A = 0x10
BPF_ABS = 0x20
- BPF_ADD = 0
+ BPF_ADD = 0x0
BPF_ALU = 0x4
BPF_AND = 0x50
BPF_B = 0x10
BPF_DIV = 0x30
BPF_H = 0x8
- BPF_IMM = 0
+ BPF_IMM = 0x0
BPF_IND = 0x40
- BPF_JA = 0
+ BPF_JA = 0x0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
BPF_JMP = 0x5
BPF_JSET = 0x40
- BPF_K = 0
- BPF_LD = 0
+ BPF_K = 0x0
+ BPF_LD = 0x0
BPF_LDX = 0x1
BPF_LEN = 0x80
BPF_LSH = 0x60
@@ -142,9 +142,9 @@ const (
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
- BPF_TAX = 0
+ BPF_TAX = 0x0
BPF_TXA = 0x80
- BPF_W = 0
+ BPF_W = 0x0
BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
@@ -153,116 +153,10 @@ const (
DT_LNK = 0xa
DT_REG = 0x8
DT_SOCK = 0xc
- DT_UNKNOWN = 0
+ DT_UNKNOWN = 0x0
DT_WHT = 0xe
- E2BIG = 0x7
- EACCES = 0xd
- EADDRINUSE = 0x62
- EADDRNOTAVAIL = 0x63
- EADV = 0x44
- EAFNOSUPPORT = 0x61
- EAGAIN = 0xb
- EALREADY = 0x72
- EBADE = 0x34
- EBADF = 0x9
- EBADFD = 0x4d
- EBADMSG = 0x4a
- EBADR = 0x35
- EBADRQC = 0x38
- EBADSLT = 0x39
- EBFONT = 0x3b
- EBUSY = 0x10
- ECANCELED = 0x7d
- ECHILD = 0xa
- ECHRNG = 0x2c
- ECOMM = 0x46
- ECONNABORTED = 0x67
- ECONNREFUSED = 0x6f
- ECONNRESET = 0x68
- EDEADLK = 0x23
- EDEADLOCK = 0x23
- EDESTADDRREQ = 0x59
- EDOM = 0x21
- EDOTDOT = 0x49
- EDQUOT = 0x7a
- EEXIST = 0x11
- EFAULT = 0xe
- EFBIG = 0x1b
- EHOSTDOWN = 0x70
- EHOSTUNREACH = 0x71
- EIDRM = 0x2b
- EILSEQ = 0x54
- EINPROGRESS = 0x73
- EINTR = 0x4
- EINVAL = 0x16
- EIO = 0x5
- EISCONN = 0x6a
- EISDIR = 0x15
- EISNAM = 0x78
- EKEYEXPIRED = 0x7f
- EKEYREJECTED = 0x81
- EKEYREVOKED = 0x80
- EL2HLT = 0x33
- EL2NSYNC = 0x2d
- EL3HLT = 0x2e
- EL3RST = 0x2f
ELF_NGREG = 0x12
ELF_PRARGSZ = 0x50
- ELIBACC = 0x4f
- ELIBBAD = 0x50
- ELIBEXEC = 0x53
- ELIBMAX = 0x52
- ELIBSCN = 0x51
- ELNRNG = 0x30
- ELOOP = 0x28
- EMEDIUMTYPE = 0x7c
- EMFILE = 0x18
- EMLINK = 0x1f
- EMSGSIZE = 0x5a
- EMULTIHOP = 0x48
- ENAMETOOLONG = 0x24
- ENAVAIL = 0x77
- ENETDOWN = 0x64
- ENETRESET = 0x66
- ENETUNREACH = 0x65
- ENFILE = 0x17
- ENOANO = 0x37
- ENOBUFS = 0x69
- ENOCSI = 0x32
- ENODATA = 0x3d
- ENODEV = 0x13
- ENOENT = 0x2
- ENOEXEC = 0x8
- ENOKEY = 0x7e
- ENOLCK = 0x25
- ENOLINK = 0x43
- ENOMEDIUM = 0x7b
- ENOMEM = 0xc
- ENOMSG = 0x2a
- ENONET = 0x40
- ENOPKG = 0x41
- ENOPROTOOPT = 0x5c
- ENOSPC = 0x1c
- ENOSR = 0x3f
- ENOSTR = 0x3c
- ENOSYS = 0x26
- ENOTBLK = 0xf
- ENOTCONN = 0x6b
- ENOTDIR = 0x14
- ENOTEMPTY = 0x27
- ENOTNAM = 0x76
- ENOTRECOVERABLE = 0x83
- ENOTSOCK = 0x58
- ENOTSUP = 0x5f
- ENOTTY = 0x19
- ENOTUNIQ = 0x4c
- ENXIO = 0x6
- EOPNOTSUPP = 0x5f
- EOVERFLOW = 0x4b
- EOWNERDEAD = 0x82
- EPERM = 0x1
- EPFNOSUPPORT = 0x60
- EPIPE = 0x20
EPOLLERR = 0x8
EPOLLET = -0x80000000
EPOLLHUP = 0x10
@@ -281,23 +175,6 @@ const (
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
EPOLL_NONBLOCK = 0x800
- EPROTO = 0x47
- EPROTONOSUPPORT = 0x5d
- EPROTOTYPE = 0x5b
- ERANGE = 0x22
- EREMCHG = 0x4e
- EREMOTE = 0x42
- EREMOTEIO = 0x79
- ERESTART = 0x55
- ERFKILL = 0x84
- EROFS = 0x1e
- ESHUTDOWN = 0x6c
- ESOCKTNOSUPPORT = 0x5e
- ESPIPE = 0x1d
- ESRCH = 0x3
- ESRMNT = 0x45
- ESTALE = 0x74
- ESTRPIPE = 0x56
ETH_P_1588 = 0x88f7
ETH_P_8021Q = 0x8100
ETH_P_802_2 = 0x4
@@ -312,6 +189,7 @@ const (
ETH_P_ATMMPOA = 0x884c
ETH_P_AX25 = 0x2
ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
ETH_P_CAN = 0xc
ETH_P_CONTROL = 0x16
ETH_P_CUST = 0x6006
@@ -335,6 +213,7 @@ const (
ETH_P_IPX = 0x8137
ETH_P_IRDA = 0x17
ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
ETH_P_LOCALTALK = 0x9
ETH_P_LOOP = 0x60
ETH_P_MOBITEX = 0x15
@@ -360,19 +239,9 @@ const (
ETH_P_WAN_PPP = 0x7
ETH_P_WCCP = 0x883e
ETH_P_X25 = 0x805
- ETIME = 0x3e
- ETIMEDOUT = 0x6e
- ETOOMANYREFS = 0x6d
- ETXTBSY = 0x1a
- EUCLEAN = 0x75
- EUNATCH = 0x31
- EUSERS = 0x57
- EWOULDBLOCK = 0xb
- EXDEV = 0x12
- EXFULL = 0x36
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
- F_DUPFD = 0
+ F_DUPFD = 0x0
F_DUPFD_CLOEXEC = 0x406
F_EXLCK = 0x4
F_GETFD = 0x1
@@ -382,11 +251,12 @@ const (
F_GETLK64 = 0xc
F_GETOWN = 0x9
F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
- F_OK = 0
- F_RDLCK = 0
+ F_OK = 0x0
+ F_RDLCK = 0x0
F_SETFD = 0x2
F_SETFL = 0x4
F_SETLEASE = 0x400
@@ -396,11 +266,12 @@ const (
F_SETLKW64 = 0xe
F_SETOWN = 0x8
F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
F_TLOCK = 0x2
- F_ULOCK = 0
+ F_ULOCK = 0x0
F_UNLCK = 0x2
F_WRLCK = 0x1
IFA_F_DADFAILED = 0x8
@@ -458,6 +329,7 @@ const (
IN_DELETE = 0x200
IN_DELETE_SELF = 0x400
IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
IN_IGNORED = 0x8000
IN_ISDIR = 0x40000000
IN_LOOPBACKNET = 0x7f
@@ -482,12 +354,12 @@ const (
IPPROTO_ESP = 0x32
IPPROTO_FRAGMENT = 0x2c
IPPROTO_GRE = 0x2f
- IPPROTO_HOPOPTS = 0
+ IPPROTO_HOPOPTS = 0x0
IPPROTO_ICMP = 0x1
IPPROTO_ICMPV6 = 0x3a
IPPROTO_IDP = 0x16
IPPROTO_IGMP = 0x2
- IPPROTO_IP = 0
+ IPPROTO_IP = 0x0
IPPROTO_IPIP = 0x4
IPPROTO_IPV6 = 0x29
IPPROTO_MTP = 0x5c
@@ -529,7 +401,7 @@ const (
IPV6_NEXTHOP = 0x9
IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
- IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_DONT = 0x0
IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
IPV6_RECVDSTOPTS = 0x3a
@@ -542,9 +414,9 @@ const (
IPV6_ROUTER_ALERT = 0x16
IPV6_RTHDR = 0x39
IPV6_RTHDRDSTOPTS = 0x37
- IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_LOOSE = 0x0
IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0
+ IPV6_RTHDR_TYPE_0 = 0x0
IPV6_RXDSTOPTS = 0x3b
IPV6_RXHOPOPTS = 0x36
IPV6_TCLASS = 0x43
@@ -559,27 +431,34 @@ const (
IP_DF = 0x4000
IP_DROP_MEMBERSHIP = 0x24
IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
+ IP_MINTTL = 0x15
IP_MSFILTER = 0x29
IP_MSS = 0x240
+ IP_MTU = 0xe
IP_MTU_DISCOVER = 0xa
IP_MULTICAST_IF = 0x20
IP_MULTICAST_LOOP = 0x22
IP_MULTICAST_TTL = 0x21
IP_OFFMASK = 0x1fff
IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
IP_PKTINFO = 0x8
IP_PKTOPTIONS = 0x9
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
- IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_DONT = 0x0
IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
IP_RECVRETOPTS = 0x7
IP_RECVTOS = 0xd
IP_RECVTTL = 0xc
@@ -587,9 +466,11 @@ const (
IP_RF = 0x8000
IP_ROUTER_ALERT = 0x5
IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
- LINUX_REBOOT_CMD_CAD_OFF = 0
+ IP_XFRM_POLICY = 0x11
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
LINUX_REBOOT_CMD_HALT = 0xcdef0123
LINUX_REBOOT_CMD_KEXEC = 0x45584543
@@ -599,12 +480,18 @@ const (
LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
LINUX_REBOOT_MAGIC1 = 0xfee1dead
LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
MADV_DOFORK = 0xb
MADV_DONTFORK = 0xa
MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
MADV_HWPOISON = 0x64
MADV_MERGEABLE = 0xc
- MADV_NORMAL = 0
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
MADV_RANDOM = 0x1
MADV_REMOVE = 0x9
MADV_SEQUENTIAL = 0x2
@@ -614,7 +501,7 @@ const (
MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800
MAP_EXECUTABLE = 0x1000
- MAP_FILE = 0
+ MAP_FILE = 0x0
MAP_FIXED = 0x10
MAP_GROWSDOWN = 0x100
MAP_LOCKED = 0x2000
@@ -647,22 +534,38 @@ const (
MSG_TRUNC = 0x20
MSG_TRYHARD = 0x4
MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
MS_ASYNC = 0x1
MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
MS_MANDLOCK = 0x40
MS_MGC_MSK = 0xffff0000
MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
MS_NOATIME = 0x400
MS_NODEV = 0x4
MS_NODIRATIME = 0x800
MS_NOEXEC = 0x8
MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
MS_REMOUNT = 0x20
- MS_RMT_MASK = 0xc51
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
MS_SYNC = 0x4
MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
NAME_MAX = 0xff
NETLINK_ADD_MEMBERSHIP = 0x1
NETLINK_AUDIT = 0x9
@@ -682,7 +585,8 @@ const (
NETLINK_NFLOG = 0x5
NETLINK_NO_ENOBUFS = 0x5
NETLINK_PKTINFO = 0x3
- NETLINK_ROUTE = 0
+ NETLINK_RDMA = 0x14
+ NETLINK_ROUTE = 0x0
NETLINK_SCSITRANSPORT = 0x12
NETLINK_SELINUX = 0x7
NETLINK_UNUSED = 0x1
@@ -727,7 +631,7 @@ const (
O_NOCTTY = 0x100
O_NOFOLLOW = 0x8000
O_NONBLOCK = 0x800
- O_RDONLY = 0
+ O_RDONLY = 0x0
O_RDWR = 0x2
O_RSYNC = 0x1000
O_SYNC = 0x1000
@@ -737,10 +641,10 @@ const (
PACKET_BROADCAST = 0x1
PACKET_DROP_MEMBERSHIP = 0x2
PACKET_FASTROUTE = 0x6
- PACKET_HOST = 0
+ PACKET_HOST = 0x0
PACKET_LOOPBACK = 0x5
PACKET_MR_ALLMULTI = 0x2
- PACKET_MR_MULTICAST = 0
+ PACKET_MR_MULTICAST = 0x0
PACKET_MR_PROMISC = 0x1
PACKET_MULTICAST = 0x2
PACKET_OTHERHOST = 0x3
@@ -751,9 +655,73 @@ const (
PROT_EXEC = 0x4
PROT_GROWSDOWN = 0x1000000
PROT_GROWSUP = 0x2000000
- PROT_NONE = 0
+ PROT_NONE = 0x0
PROT_READ = 0x1
PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_CLEAR_SECCOMP_FILTER = 0x25
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECCOMP_FILTER = 0x23
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SECCOMP_FILTER_EVENT = 0x1
+ PR_SECCOMP_FILTER_SYSCALL = 0x0
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_NAME = 0xf
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECCOMP_FILTER = 0x24
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
PTRACE_ATTACH = 0x10
PTRACE_CONT = 0x7
PTRACE_DETACH = 0x11
@@ -766,7 +734,9 @@ const (
PTRACE_GETCRUNCHREGS = 0x19
PTRACE_GETEVENTMSG = 0x4201
PTRACE_GETFPREGS = 0xe
+ PTRACE_GETHBPREGS = 0x1d
PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
PTRACE_GETSIGINFO = 0x4202
PTRACE_GETVFPREGS = 0x1b
PTRACE_GETWMMXREGS = 0x12
@@ -789,18 +759,28 @@ const (
PTRACE_POKEUSR = 0x6
PTRACE_SETCRUNCHREGS = 0x1a
PTRACE_SETFPREGS = 0xf
+ PTRACE_SETHBPREGS = 0x1e
PTRACE_SETOPTIONS = 0x4200
PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203
PTRACE_SETVFPREGS = 0x1c
PTRACE_SETWMMXREGS = 0x13
PTRACE_SET_SYSCALL = 0x17
PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18
- PTRACE_TRACEME = 0
+ PTRACE_TRACEME = 0x0
PT_DATA_ADDR = 0x10004
PT_TEXT_ADDR = 0x10000
PT_TEXT_END_ADDR = 0x10008
+ RLIMIT_AS = 0x9
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x7
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
RTAX_ADVMSS = 0x8
RTAX_CWND = 0x7
RTAX_FEATURES = 0xc
@@ -810,18 +790,55 @@ const (
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
RTAX_LOCK = 0x1
- RTAX_MAX = 0xd
+ RTAX_MAX = 0xe
RTAX_MTU = 0x2
RTAX_REORDERING = 0x9
RTAX_RTO_MIN = 0xd
RTAX_RTT = 0x4
RTAX_RTTVAR = 0x5
RTAX_SSTHRESH = 0x6
- RTAX_UNSPEC = 0
+ RTAX_UNSPEC = 0x0
RTAX_WINDOW = 0x3
RTA_ALIGNTO = 0x4
- RTA_MAX = 0xf
+ RTA_MAX = 0x10
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
RTM_BASE = 0x10
RTM_DELACTION = 0x31
RTM_DELADDR = 0x15
@@ -886,52 +903,25 @@ const (
RTPROT_RA = 0x9
RTPROT_REDIRECT = 0x1
RTPROT_STATIC = 0x4
- RTPROT_UNSPEC = 0
+ RTPROT_UNSPEC = 0x0
RTPROT_XORP = 0xe
RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
SCM_CREDENTIALS = 0x2
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SCM_TIMESTAMPING = 0x25
SCM_TIMESTAMPNS = 0x23
- SHUT_RD = 0
+ SHUT_RD = 0x0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
- SIGABRT = 0x6
- SIGALRM = 0xe
- SIGBUS = 0x7
- SIGCHLD = 0x11
- SIGCLD = 0x11
- SIGCONT = 0x12
- SIGFPE = 0x8
- SIGHUP = 0x1
- SIGILL = 0x4
- SIGINT = 0x2
- SIGIO = 0x1d
- SIGIOT = 0x6
- SIGKILL = 0x9
- SIGPIPE = 0xd
- SIGPOLL = 0x1d
- SIGPROF = 0x1b
- SIGPWR = 0x1e
- SIGQUIT = 0x3
- SIGSEGV = 0xb
- SIGSTKFLT = 0x10
- SIGSTOP = 0x13
- SIGSYS = 0x1f
- SIGTERM = 0xf
- SIGTRAP = 0x5
- SIGTSTP = 0x14
- SIGTTIN = 0x15
- SIGTTOU = 0x16
- SIGUNUSED = 0x1f
- SIGURG = 0x17
- SIGUSR1 = 0xa
- SIGUSR2 = 0xc
- SIGVTALRM = 0x1a
- SIGWINCH = 0x1c
- SIGXCPU = 0x18
- SIGXFSZ = 0x19
SIOCADDDLCI = 0x8980
SIOCADDMULTI = 0x8931
SIOCADDRT = 0x890b
@@ -1003,7 +993,7 @@ const (
SOL_ATM = 0x108
SOL_DECNET = 0x105
SOL_ICMPV6 = 0x3a
- SOL_IP = 0
+ SOL_IP = 0x0
SOL_IPV6 = 0x29
SOL_IRDA = 0x10a
SOL_PACKET = 0x107
@@ -1039,6 +1029,7 @@ const (
SO_RCVLOWAT = 0x12
SO_RCVTIMEO = 0x14
SO_REUSEADDR = 0x2
+ SO_RXQ_OVFL = 0x28
SO_SECURITY_AUTHENTICATION = 0x16
SO_SECURITY_ENCRYPTION_NETWORK = 0x18
SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
@@ -1050,7 +1041,6 @@ const (
SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
- S_APPEND = 0x100
S_BLKSIZE = 0x200
S_IEXEC = 0x40
S_IFBLK = 0x6000
@@ -1061,7 +1051,6 @@ const (
S_IFMT = 0xf000
S_IFREG = 0x8000
S_IFSOCK = 0xc000
- S_IMMUTABLE = 0x200
S_IREAD = 0x100
S_IRGRP = 0x20
S_IROTH = 0x4
@@ -1079,7 +1068,6 @@ const (
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40
- S_WRITE = 0x80
TCP_CONGESTION = 0xd
TCP_CORK = 0x3
TCP_DEFER_ACCEPT = 0x9
@@ -1101,11 +1089,13 @@ const (
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
+ TIOCGDEV = 0x80045432
TIOCGETD = 0x5424
TIOCGICOUNT = 0x545d
TIOCGLCKTRMIOS = 0x5456
TIOCGPGRP = 0x540f
TIOCGPTN = 0x80045430
+ TIOCGRS485 = 0x542e
TIOCGSERIAL = 0x541e
TIOCGSID = 0x5429
TIOCGSOFTCAR = 0x5419
@@ -1132,10 +1122,11 @@ const (
TIOCNXCL = 0x540d
TIOCOUTQ = 0x5411
TIOCPKT = 0x5420
- TIOCPKT_DATA = 0
+ TIOCPKT_DATA = 0x0
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
TIOCPKT_NOSTOP = 0x10
TIOCPKT_START = 0x8
TIOCPKT_STOP = 0x4
@@ -1150,16 +1141,22 @@ const (
TIOCSERSWILD = 0x5455
TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
+ TIOCSIG = 0x40045436
TIOCSLCKTRMIOS = 0x5457
TIOCSPGRP = 0x5410
TIOCSPTLCK = 0x40045431
+ TIOCSRS485 = 0x542f
TIOCSSERIAL = 0x541f
TIOCSSOFTCAR = 0x541a
TIOCSTI = 0x5412
TIOCSWINSZ = 0x5414
+ TIOCVHANGUP = 0x5437
+ TUNATTACHFILTER = 0x400854d5
+ TUNDETACHFILTER = 0x400854d6
TUNGETFEATURES = 0x800454cf
TUNGETIFF = 0x800454d2
TUNGETSNDBUF = 0x800454d3
+ TUNGETVNETHDRSZ = 0x800454d7
TUNSETDEBUG = 0x400454c9
TUNSETGROUP = 0x400454ce
TUNSETIFF = 0x400454ca
@@ -1170,6 +1167,7 @@ const (
TUNSETPERSIST = 0x400454cb
TUNSETSNDBUF = 0x400454d4
TUNSETTXFILTER = 0x400454d1
+ TUNSETVNETHDRSZ = 0x400454d8
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -1182,7 +1180,182 @@ const (
WUNTRACED = 0x2
)
-// Types
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x62)
+ EADDRNOTAVAIL = Errno(0x63)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x61)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x72)
+ EBADE = Errno(0x34)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x4d)
+ EBADMSG = Errno(0x4a)
+ EBADR = Errno(0x35)
+ EBADRQC = Errno(0x38)
+ EBADSLT = Errno(0x39)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x7d)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x2c)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x67)
+ ECONNREFUSED = Errno(0x6f)
+ ECONNRESET = Errno(0x68)
+ EDEADLK = Errno(0x23)
+ EDEADLOCK = Errno(0x23)
+ EDESTADDRREQ = Errno(0x59)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x7a)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x70)
+ EHOSTUNREACH = Errno(0x71)
+ EHWPOISON = Errno(0x85)
+ EIDRM = Errno(0x2b)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x73)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x6a)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x78)
+ EKEYEXPIRED = Errno(0x7f)
+ EKEYREJECTED = Errno(0x81)
+ EKEYREVOKED = Errno(0x80)
+ EL2HLT = Errno(0x33)
+ EL2NSYNC = Errno(0x2d)
+ EL3HLT = Errno(0x2e)
+ EL3RST = Errno(0x2f)
+ ELIBACC = Errno(0x4f)
+ ELIBBAD = Errno(0x50)
+ ELIBEXEC = Errno(0x53)
+ ELIBMAX = Errno(0x52)
+ ELIBSCN = Errno(0x51)
+ ELNRNG = Errno(0x30)
+ ELOOP = Errno(0x28)
+ EMEDIUMTYPE = Errno(0x7c)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x5a)
+ EMULTIHOP = Errno(0x48)
+ ENAMETOOLONG = Errno(0x24)
+ ENAVAIL = Errno(0x77)
+ ENETDOWN = Errno(0x64)
+ ENETRESET = Errno(0x66)
+ ENETUNREACH = Errno(0x65)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x37)
+ ENOBUFS = Errno(0x69)
+ ENOCSI = Errno(0x32)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0x7e)
+ ENOLCK = Errno(0x25)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x7b)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x2a)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x5c)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x26)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x6b)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x27)
+ ENOTNAM = Errno(0x76)
+ ENOTRECOVERABLE = Errno(0x83)
+ ENOTSOCK = Errno(0x58)
+ ENOTSUP = Errno(0x5f)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x4c)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x5f)
+ EOVERFLOW = Errno(0x4b)
+ EOWNERDEAD = Errno(0x82)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x60)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x5d)
+ EPROTOTYPE = Errno(0x5b)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x4e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x79)
+ ERESTART = Errno(0x55)
+ ERFKILL = Errno(0x84)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x6c)
+ ESOCKTNOSUPPORT = Errno(0x5e)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x74)
+ ESTRPIPE = Errno(0x56)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x6e)
+ ETOOMANYREFS = Errno(0x6d)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x75)
+ EUNATCH = Errno(0x31)
+ EUSERS = Errno(0x57)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x36)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0x7)
+ SIGCHLD = Signal(0x11)
+ SIGCLD = Signal(0x11)
+ SIGCONT = Signal(0x12)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x1d)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x1d)
+ SIGPROF = Signal(0x1b)
+ SIGPWR = Signal(0x1e)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTKFLT = Signal(0x10)
+ SIGSTOP = Signal(0x13)
+ SIGSYS = Signal(0x1f)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x14)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGUNUSED = Signal(0x1f)
+ SIGURG = Signal(0x17)
+ SIGUSR1 = Signal(0xa)
+ SIGUSR2 = Signal(0xc)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
// Error table
var errors = [...]string{
@@ -1315,5 +1488,41 @@ var errors = [...]string{
129: "key was rejected by service",
130: "owner died",
131: "state not recoverable",
- 132: "unknown error 132",
+ 132: "operation not possible due to RF-kill",
+ 133: "unknown error 133",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "stack fault",
+ 17: "child exited",
+ 18: "continued",
+ 19: "stopped (signal)",
+ 20: "stopped",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "urgent I/O condition",
+ 24: "CPU time limit exceeded",
+ 25: "file size limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window changed",
+ 29: "I/O possible",
+ 30: "power failure",
+ 31: "bad system call",
}
diff --git a/src/pkg/syscall/zerrors_netbsd_386.go b/src/pkg/syscall/zerrors_netbsd_386.go
new file mode 100644
index 000000000..52dc69a64
--- /dev/null
+++ b/src/pkg/syscall/zerrors_netbsd_386.go
@@ -0,0 +1,1368 @@
+// mkerrors.sh -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_BLUETOOTH = 0x20
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1a
+ AF_ECMA = 0x8
+ AF_ENCAP = 0x1c
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x18
+ AF_IPX = 0x17
+ AF_ISDN = 0x1a
+ AF_ISO = 0x7
+ AF_KEY = 0x1e
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x24
+ AF_MPLS = 0x21
+ AF_NATM = 0x1b
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_ROUTE = 0x11
+ AF_SIP = 0x1d
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FRELAY = 0xf
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRFILT = 0x4004427c
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc008427b
+ BIOCGETIF = 0x4020426b
+ BIOCGFILDROP = 0x40044278
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044273
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x20004276
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRFILT = 0x8004427d
+ BIOCSDLT = 0x8004427a
+ BIOCSETF = 0x80084267
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x80084277
+ BIOCSFILDROP = 0x80044279
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044272
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIRECTION_IN = 0x1
+ BPF_DIRECTION_OUT = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x200000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_ARCNET = 0x7
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0xd
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_LOOP = 0xc
+ DLT_MPLS = 0xdb
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xe
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ EFER_LMA = 0x400
+ EFER_LME = 0x100
+ EFER_NXE = 0x800
+ EFER_SCE = 0x1
+ EMT_TAGOVF = 0x1
+ EMUL_ENABLED = 0x1
+ EMUL_NATIVE = 0x2
+ ETHERMIN = 0x2e
+ ETHERMTU = 0x5dc
+ ETHERTYPE_8023 = 0x4
+ ETHERTYPE_AARP = 0x80f3
+ ETHERTYPE_ACCTON = 0x8390
+ ETHERTYPE_AEONIC = 0x8036
+ ETHERTYPE_ALPHA = 0x814a
+ ETHERTYPE_AMBER = 0x6008
+ ETHERTYPE_AMOEBA = 0x8145
+ ETHERTYPE_AOE = 0x88a2
+ ETHERTYPE_APOLLO = 0x80f7
+ ETHERTYPE_APOLLODOMAIN = 0x8019
+ ETHERTYPE_APPLETALK = 0x809b
+ ETHERTYPE_APPLITEK = 0x80c7
+ ETHERTYPE_ARGONAUT = 0x803a
+ ETHERTYPE_ARP = 0x806
+ ETHERTYPE_AT = 0x809b
+ ETHERTYPE_ATALK = 0x809b
+ ETHERTYPE_ATOMIC = 0x86df
+ ETHERTYPE_ATT = 0x8069
+ ETHERTYPE_ATTSTANFORD = 0x8008
+ ETHERTYPE_AUTOPHON = 0x806a
+ ETHERTYPE_AXIS = 0x8856
+ ETHERTYPE_BCLOOP = 0x9003
+ ETHERTYPE_BOFL = 0x8102
+ ETHERTYPE_CABLETRON = 0x7034
+ ETHERTYPE_CHAOS = 0x804
+ ETHERTYPE_COMDESIGN = 0x806c
+ ETHERTYPE_COMPUGRAPHIC = 0x806d
+ ETHERTYPE_COUNTERPOINT = 0x8062
+ ETHERTYPE_CRONUS = 0x8004
+ ETHERTYPE_CRONUSVLN = 0x8003
+ ETHERTYPE_DCA = 0x1234
+ ETHERTYPE_DDE = 0x807b
+ ETHERTYPE_DEBNI = 0xaaaa
+ ETHERTYPE_DECAM = 0x8048
+ ETHERTYPE_DECCUST = 0x6006
+ ETHERTYPE_DECDIAG = 0x6005
+ ETHERTYPE_DECDNS = 0x803c
+ ETHERTYPE_DECDTS = 0x803e
+ ETHERTYPE_DECEXPER = 0x6000
+ ETHERTYPE_DECLAST = 0x8041
+ ETHERTYPE_DECLTM = 0x803f
+ ETHERTYPE_DECMUMPS = 0x6009
+ ETHERTYPE_DECNETBIOS = 0x8040
+ ETHERTYPE_DELTACON = 0x86de
+ ETHERTYPE_DIDDLE = 0x4321
+ ETHERTYPE_DLOG1 = 0x660
+ ETHERTYPE_DLOG2 = 0x661
+ ETHERTYPE_DN = 0x6003
+ ETHERTYPE_DOGFIGHT = 0x1989
+ ETHERTYPE_DSMD = 0x8039
+ ETHERTYPE_ECMA = 0x803
+ ETHERTYPE_ENCRYPT = 0x803d
+ ETHERTYPE_ES = 0x805d
+ ETHERTYPE_EXCELAN = 0x8010
+ ETHERTYPE_EXPERDATA = 0x8049
+ ETHERTYPE_FLIP = 0x8146
+ ETHERTYPE_FLOWCONTROL = 0x8808
+ ETHERTYPE_FRARP = 0x808
+ ETHERTYPE_GENDYN = 0x8068
+ ETHERTYPE_HAYES = 0x8130
+ ETHERTYPE_HIPPI_FP = 0x8180
+ ETHERTYPE_HITACHI = 0x8820
+ ETHERTYPE_HP = 0x8005
+ ETHERTYPE_IEEEPUP = 0xa00
+ ETHERTYPE_IEEEPUPAT = 0xa01
+ ETHERTYPE_IMLBL = 0x4c42
+ ETHERTYPE_IMLBLDIAG = 0x424c
+ ETHERTYPE_IP = 0x800
+ ETHERTYPE_IPAS = 0x876c
+ ETHERTYPE_IPV6 = 0x86dd
+ ETHERTYPE_IPX = 0x8137
+ ETHERTYPE_IPXNEW = 0x8037
+ ETHERTYPE_KALPANA = 0x8582
+ ETHERTYPE_LANBRIDGE = 0x8038
+ ETHERTYPE_LANPROBE = 0x8888
+ ETHERTYPE_LAT = 0x6004
+ ETHERTYPE_LBACK = 0x9000
+ ETHERTYPE_LITTLE = 0x8060
+ ETHERTYPE_LLDP = 0x88cc
+ ETHERTYPE_LOGICRAFT = 0x8148
+ ETHERTYPE_LOOPBACK = 0x9000
+ ETHERTYPE_MATRA = 0x807a
+ ETHERTYPE_MAX = 0xffff
+ ETHERTYPE_MERIT = 0x807c
+ ETHERTYPE_MICP = 0x873a
+ ETHERTYPE_MOPDL = 0x6001
+ ETHERTYPE_MOPRC = 0x6002
+ ETHERTYPE_MOTOROLA = 0x818d
+ ETHERTYPE_MPLS = 0x8847
+ ETHERTYPE_MPLS_MCAST = 0x8848
+ ETHERTYPE_MUMPS = 0x813f
+ ETHERTYPE_NBPCC = 0x3c04
+ ETHERTYPE_NBPCLAIM = 0x3c09
+ ETHERTYPE_NBPCLREQ = 0x3c05
+ ETHERTYPE_NBPCLRSP = 0x3c06
+ ETHERTYPE_NBPCREQ = 0x3c02
+ ETHERTYPE_NBPCRSP = 0x3c03
+ ETHERTYPE_NBPDG = 0x3c07
+ ETHERTYPE_NBPDGB = 0x3c08
+ ETHERTYPE_NBPDLTE = 0x3c0a
+ ETHERTYPE_NBPRAR = 0x3c0c
+ ETHERTYPE_NBPRAS = 0x3c0b
+ ETHERTYPE_NBPRST = 0x3c0d
+ ETHERTYPE_NBPSCD = 0x3c01
+ ETHERTYPE_NBPVCD = 0x3c00
+ ETHERTYPE_NBS = 0x802
+ ETHERTYPE_NCD = 0x8149
+ ETHERTYPE_NESTAR = 0x8006
+ ETHERTYPE_NETBEUI = 0x8191
+ ETHERTYPE_NOVELL = 0x8138
+ ETHERTYPE_NS = 0x600
+ ETHERTYPE_NSAT = 0x601
+ ETHERTYPE_NSCOMPAT = 0x807
+ ETHERTYPE_NTRAILER = 0x10
+ ETHERTYPE_OS9 = 0x7007
+ ETHERTYPE_OS9NET = 0x7009
+ ETHERTYPE_PACER = 0x80c6
+ ETHERTYPE_PAE = 0x888e
+ ETHERTYPE_PCS = 0x4242
+ ETHERTYPE_PLANNING = 0x8044
+ ETHERTYPE_PPP = 0x880b
+ ETHERTYPE_PPPOE = 0x8864
+ ETHERTYPE_PPPOEDISC = 0x8863
+ ETHERTYPE_PRIMENTS = 0x7031
+ ETHERTYPE_PUP = 0x200
+ ETHERTYPE_PUPAT = 0x200
+ ETHERTYPE_QINQ = 0x88a8
+ ETHERTYPE_RACAL = 0x7030
+ ETHERTYPE_RATIONAL = 0x8150
+ ETHERTYPE_RAWFR = 0x6559
+ ETHERTYPE_RCL = 0x1995
+ ETHERTYPE_RDP = 0x8739
+ ETHERTYPE_RETIX = 0x80f2
+ ETHERTYPE_REVARP = 0x8035
+ ETHERTYPE_SCA = 0x6007
+ ETHERTYPE_SECTRA = 0x86db
+ ETHERTYPE_SECUREDATA = 0x876d
+ ETHERTYPE_SGITW = 0x817e
+ ETHERTYPE_SG_BOUNCE = 0x8016
+ ETHERTYPE_SG_DIAG = 0x8013
+ ETHERTYPE_SG_NETGAMES = 0x8014
+ ETHERTYPE_SG_RESV = 0x8015
+ ETHERTYPE_SIMNET = 0x5208
+ ETHERTYPE_SLOW = 0x8809
+ ETHERTYPE_SNA = 0x80d5
+ ETHERTYPE_SNMP = 0x814c
+ ETHERTYPE_SONIX = 0xfaf5
+ ETHERTYPE_SPIDER = 0x809f
+ ETHERTYPE_SPRITE = 0x500
+ ETHERTYPE_STP = 0x8181
+ ETHERTYPE_TALARIS = 0x812b
+ ETHERTYPE_TALARISMC = 0x852b
+ ETHERTYPE_TCPCOMP = 0x876b
+ ETHERTYPE_TCPSM = 0x9002
+ ETHERTYPE_TEC = 0x814f
+ ETHERTYPE_TIGAN = 0x802f
+ ETHERTYPE_TRAIL = 0x1000
+ ETHERTYPE_TRANSETHER = 0x6558
+ ETHERTYPE_TYMSHARE = 0x802e
+ ETHERTYPE_UBBST = 0x7005
+ ETHERTYPE_UBDEBUG = 0x900
+ ETHERTYPE_UBDIAGLOOP = 0x7002
+ ETHERTYPE_UBDL = 0x7000
+ ETHERTYPE_UBNIU = 0x7001
+ ETHERTYPE_UBNMC = 0x7003
+ ETHERTYPE_VALID = 0x1600
+ ETHERTYPE_VARIAN = 0x80dd
+ ETHERTYPE_VAXELN = 0x803b
+ ETHERTYPE_VEECO = 0x8067
+ ETHERTYPE_VEXP = 0x805b
+ ETHERTYPE_VGLAB = 0x8131
+ ETHERTYPE_VINES = 0xbad
+ ETHERTYPE_VINESECHO = 0xbaf
+ ETHERTYPE_VINESLOOP = 0xbae
+ ETHERTYPE_VITAL = 0xff00
+ ETHERTYPE_VLAN = 0x8100
+ ETHERTYPE_VLTLMAN = 0x8080
+ ETHERTYPE_VPROD = 0x805c
+ ETHERTYPE_VURESERVED = 0x8147
+ ETHERTYPE_WATERLOO = 0x8130
+ ETHERTYPE_WELLFLEET = 0x8103
+ ETHERTYPE_X25 = 0x805
+ ETHERTYPE_X75 = 0x801
+ ETHERTYPE_XNSSM = 0x9001
+ ETHERTYPE_XTP = 0x817d
+ ETHER_ADDR_LEN = 0x6
+ ETHER_ALIGN = 0x2
+ ETHER_CRC_LEN = 0x4
+ ETHER_CRC_POLY_BE = 0x4c11db6
+ ETHER_CRC_POLY_LE = 0xedb88320
+ ETHER_HDR_LEN = 0xe
+ ETHER_MAX_DIX_LEN = 0x600
+ ETHER_MAX_LEN = 0x5ee
+ ETHER_MIN_LEN = 0x40
+ ETHER_TYPE_LEN = 0x2
+ ETHER_VLAN_ENCAP_LEN = 0x4
+ EVFILT_AIO = -0x3
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0x7
+ EVFILT_TIMER = -0x7
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0xa
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_UNLCK = 0x2
+ F_WRLCK = 0x3
+ IFA_ROUTE = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x8e52
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BLUETOOTH = 0xf8
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf7
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DOCSCABLEUPSTREAMCHANNEL = 0xcd
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DUMMY = 0xf1
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ECONET = 0xce
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf3
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LINEGROUP = 0xd2
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf5
+ IFT_PFLOW = 0xf9
+ IFT_PFSYNC = 0xf6
+ IFT_PLC = 0xae
+ IFT_PON155 = 0xcf
+ IFT_PON622 = 0xd0
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPATM = 0xc5
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf2
+ IFT_Q2931 = 0xc9
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SIPSIG = 0xcc
+ IFT_SIPTG = 0xcb
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TELINK = 0xc8
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VIRTUALTG = 0xca
+ IFT_VOICEDID = 0xd5
+ IFT_VOICEEM = 0x64
+ IFT_VOICEEMFGD = 0xd3
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFGDEANA = 0xd4
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERCABLE = 0xc6
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_HOST = 0x1
+ IN_RFC3021_NET = 0xfffffffe
+ IN_RFC3021_NSHIFT = 0x1f
+ IPPROTO_AH = 0x33
+ IPPROTO_CARP = 0x70
+ IPPROTO_DIVERT = 0x102
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x103
+ IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PFSYNC = 0xf0
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPV6_AUTH_LEVEL = 0x35
+ IPV6_AUTOFLOWLABEL = 0x3b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DONTFRAG = 0x3e
+ IPV6_DSTOPTS = 0x32
+ IPV6_ESP_NETWORK_LEVEL = 0x37
+ IPV6_ESP_TRANS_LEVEL = 0x36
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x2f
+ IPV6_HOPOPTS = 0x31
+ IPV6_IPCOMP_LEVEL = 0x3c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_OPTIONS = 0x1
+ IPV6_PATHMTU = 0x2c
+ IPV6_PIPEX = 0x3f
+ IPV6_PKTINFO = 0x2e
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x25
+ IPV6_RECVHOPOPTS = 0x27
+ IPV6_RECVPATHMTU = 0x2b
+ IPV6_RECVPKTINFO = 0x24
+ IPV6_RECVRTHDR = 0x26
+ IPV6_RECVTCLASS = 0x39
+ IPV6_RTABLE = 0x1021
+ IPV6_RTHDR = 0x33
+ IPV6_RTHDRDSTOPTS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x3d
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_USE_MIN_MTU = 0x2a
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_AUTH_LEVEL = 0x14
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_ESP_NETWORK_LEVEL = 0x16
+ IP_ESP_TRANS_LEVEL = 0x15
+ IP_HDRINCL = 0x2
+ IP_IPCOMP_LEVEL = 0x1d
+ IP_IPSEC_LOCAL_AUTH = 0x1b
+ IP_IPSEC_LOCAL_CRED = 0x19
+ IP_IPSEC_LOCAL_ID = 0x17
+ IP_IPSEC_REMOTE_AUTH = 0x1c
+ IP_IPSEC_REMOTE_CRED = 0x1a
+ IP_IPSEC_REMOTE_ID = 0x18
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MF = 0x2000
+ IP_MINTTL = 0x20
+ IP_MIN_MEMBERSHIPS = 0xf
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x1
+ IP_PIPEX = 0x22
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVDSTPORT = 0x21
+ IP_RECVIF = 0x1e
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVRTABLE = 0x23
+ IP_RECVTTL = 0x1f
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RTABLE = 0x1021
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ MAP_ET_KVAGUARD = 0x10
+ MSG_BCAST = 0x100
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOR = 0x8
+ MSG_MCAST = 0x200
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_MAXID = 0x6
+ NET_RT_STATS = 0x4
+ NET_RT_TABLE = 0x5
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x10000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x20000
+ O_DSYNC = 0x80
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x8000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x80
+ O_SHLOCK = 0x10
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_LABEL = 0xa
+ RTAX_MAX = 0xb
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTAX_SRCMASK = 0x9
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_LABEL = 0x400
+ RTA_NETMASK = 0x4
+ RTA_SRC = 0x100
+ RTA_SRCMASK = 0x200
+ RTF_ANNOUNCE = 0x4000
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONED = 0x10000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x8f808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_JUMBO = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MPATH = 0x40000
+ RTF_MPLS = 0x100000
+ RTF_PERMANENT_ARP = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x2000
+ RTF_REJECT = 0x8
+ RTF_SOURCE = 0x20000
+ RTF_STATIC = 0x800
+ RTF_TUNNEL = 0x100000
+ RTF_UP = 0x1
+ RTF_USETRAILERS = 0x8000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DESYNC = 0x10
+ RTM_GET = 0x4
+ RTM_IFANNOUNCE = 0xf
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MAXSIZE = 0x800
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x4
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_TABLEID_MAX = 0xff
+ SCM_CREDS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTHR = 0x20
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80246987
+ SIOCALIFADDR = 0x8218691c
+ SIOCATMARK = 0x40047307
+ SIOCBRDGADD = 0x8054693c
+ SIOCBRDGADDS = 0x80546941
+ SIOCBRDGARL = 0x806e694d
+ SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDEL = 0x8054693d
+ SIOCBRDGDELS = 0x80546942
+ SIOCBRDGFLUSH = 0x80546948
+ SIOCBRDGFRL = 0x806e694e
+ SIOCBRDGGCACHE = 0xc0146941
+ SIOCBRDGGFD = 0xc0146952
+ SIOCBRDGGHT = 0xc0146951
+ SIOCBRDGGIFFLGS = 0xc054693e
+ SIOCBRDGGMA = 0xc0146953
+ SIOCBRDGGPARAM = 0xc0386958
+ SIOCBRDGGPRI = 0xc0146950
+ SIOCBRDGGRL = 0xc028694f
+ SIOCBRDGGSIFS = 0xc054693c
+ SIOCBRDGGTO = 0xc0146946
+ SIOCBRDGIFS = 0xc0546942
+ SIOCBRDGRTS = 0xc0186943
+ SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSCACHE = 0x80146940
+ SIOCBRDGSFD = 0x80146952
+ SIOCBRDGSHT = 0x80146951
+ SIOCBRDGSIFCOST = 0x80546955
+ SIOCBRDGSIFFLGS = 0x8054693f
+ SIOCBRDGSIFPRIO = 0x80546954
+ SIOCBRDGSMA = 0x80146953
+ SIOCBRDGSPRI = 0x80146950
+ SIOCBRDGSPROTO = 0x8014695a
+ SIOCBRDGSTO = 0x80146945
+ SIOCBRDGSTXHC = 0x80146959
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80246989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8218691e
+ SIOCGETKALIVE = 0xc01869a4
+ SIOCGETLABEL = 0x8020699a
+ SIOCGETPFLOW = 0xc02069fe
+ SIOCGETPFSYNC = 0xc02069f8
+ SIOCGETSGCNT = 0xc0147534
+ SIOCGETVIFCNT = 0xc0147533
+ SIOCGETVLANPRIO = 0xc0206990
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDATA = 0xc020691b
+ SIOCGIFDESCR = 0xc0206981
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGATTR = 0xc024698b
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc024698a
+ SIOCGIFGROUP = 0xc0246988
+ SIOCGIFMEDIA = 0xc0286936
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc020697e
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPRIORITY = 0xc020699c
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFRDOMAIN = 0xc02069a0
+ SIOCGIFRTLABEL = 0xc0206983
+ SIOCGIFTIMESLOT = 0xc0206986
+ SIOCGIFXFLAGS = 0xc020699e
+ SIOCGLIFADDR = 0xc218691d
+ SIOCGLIFPHYADDR = 0xc218694b
+ SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGVH = 0xc02069f6
+ SIOCIFCREATE = 0x8020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc00c6978
+ SIOCSETKALIVE = 0x801869a3
+ SIOCSETLABEL = 0x80206999
+ SIOCSETPFLOW = 0x802069fd
+ SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLANPRIO = 0x8020698f
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDESCR = 0x80206980
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGATTR = 0x8024698c
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020691f
+ SIOCSIFMEDIA = 0xc0206935
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x8020697f
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPRIORITY = 0x8020699b
+ SIOCSIFRDOMAIN = 0x8020699f
+ SIOCSIFRTLABEL = 0x80206982
+ SIOCSIFTIMESLOT = 0x80206985
+ SIOCSIFXFLAGS = 0x8020699d
+ SIOCSLIFPHYADDR = 0x8218694a
+ SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SIOCSVH = 0xc02069f5
+ SOCK_DGRAM = 0x2
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BINDANY = 0x1000
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_JUMBO = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_NETPROC = 0x1020
+ SO_OOBINLINE = 0x100
+ SO_PEERCRED = 0x1022
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RTABLE = 0x1021
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_SPLICE = 0x1023
+ SO_TIMESTAMP = 0x800
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ TCP_MAXBURST = 0x4
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0x4
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NSTATES = 0xb
+ TCP_SACK_ENABLE = 0x8
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLAG_CLOCAL = 0x2
+ TIOCFLAG_CRTSCTS = 0x4
+ TIOCFLAG_MDMBUF = 0x8
+ TIOCFLAG_PPS = 0x10
+ TIOCFLAG_SOFTCAR = 0x1
+ TIOCFLUSH = 0x80047410
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGFLAGS = 0x4004745d
+ TIOCGPGRP = 0x40047477
+ TIOCGTSTAMP = 0x4008745b
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x4004746a
+ TIOCMODS = 0x8004746d
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSFLAGS = 0x8004745c
+ TIOCSIG = 0x8004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x80047465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSTSTAMP = 0x8008745a
+ TIOCSWINSZ = 0x80087467
+ TIOCUCNTL = 0x80047466
+ WALTSIG = 0x4
+ WCONTINUED = 0x8
+ WCOREFLAG = 0x80
+ WNOHANG = 0x1
+ WSTOPPED = 0x7f
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x58)
+ ECHILD = Errno(0xa)
+ ECHO = Errno(0x8)
+ ECHOCTL = Errno(0x40)
+ ECHOE = Errno(0x2)
+ ECHOK = Errno(0x4)
+ ECHOKE = Errno(0x1)
+ ECHONL = Errno(0x10)
+ ECHOPRT = Errno(0x20)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x59)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EIPSEC = Errno(0x52)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5b)
+ ELOOP = Errno(0x3e)
+ EMEDIUMTYPE = Errno(0x56)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ ENAMETOOLONG = Errno(0x3f)
+ ENDRUNDISC = Errno(0x9)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x53)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOMEDIUM = Errno(0x55)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5a)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x5b)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x57)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "connection timed out",
+ 61: "connection refused",
+ 62: "too many levels of symbolic links",
+ 63: "file name too long",
+ 64: "host is down",
+ 65: "no route to host",
+ 66: "directory not empty",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "IPsec processing failure",
+ 83: "attribute not found",
+ 84: "illegal byte sequence",
+ 85: "no medium found",
+ 86: "wrong medium type",
+ 87: "value too large to be stored in data type",
+ 88: "operation canceled",
+ 89: "identifier removed",
+ 90: "no message of desired type",
+ 91: "not supported",
+}
diff --git a/src/pkg/syscall/zerrors_netbsd_amd64.go b/src/pkg/syscall/zerrors_netbsd_amd64.go
new file mode 100644
index 000000000..c6367fbbc
--- /dev/null
+++ b/src/pkg/syscall/zerrors_netbsd_amd64.go
@@ -0,0 +1,1368 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_BLUETOOTH = 0x20
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1a
+ AF_ECMA = 0x8
+ AF_ENCAP = 0x1c
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x18
+ AF_IPX = 0x17
+ AF_ISDN = 0x1a
+ AF_ISO = 0x7
+ AF_KEY = 0x1e
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x24
+ AF_MPLS = 0x21
+ AF_NATM = 0x1b
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_ROUTE = 0x11
+ AF_SIP = 0x1d
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FRELAY = 0xf
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRFILT = 0x4004427c
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc010427b
+ BIOCGETIF = 0x4020426b
+ BIOCGFILDROP = 0x40044278
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044273
+ BIOCGRTIMEOUT = 0x4010426e
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x20004276
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRFILT = 0x8004427d
+ BIOCSDLT = 0x8004427a
+ BIOCSETF = 0x80104267
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x80104277
+ BIOCSFILDROP = 0x80044279
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044272
+ BIOCSRTIMEOUT = 0x8010426d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIRECTION_IN = 0x1
+ BPF_DIRECTION_OUT = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x200000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_ARCNET = 0x7
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0xd
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_LOOP = 0xc
+ DLT_MPLS = 0xdb
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xe
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ EFER_LMA = 0x400
+ EFER_LME = 0x100
+ EFER_NXE = 0x800
+ EFER_SCE = 0x1
+ EMT_TAGOVF = 0x1
+ EMUL_ENABLED = 0x1
+ EMUL_NATIVE = 0x2
+ ETHERMIN = 0x2e
+ ETHERMTU = 0x5dc
+ ETHERTYPE_8023 = 0x4
+ ETHERTYPE_AARP = 0x80f3
+ ETHERTYPE_ACCTON = 0x8390
+ ETHERTYPE_AEONIC = 0x8036
+ ETHERTYPE_ALPHA = 0x814a
+ ETHERTYPE_AMBER = 0x6008
+ ETHERTYPE_AMOEBA = 0x8145
+ ETHERTYPE_AOE = 0x88a2
+ ETHERTYPE_APOLLO = 0x80f7
+ ETHERTYPE_APOLLODOMAIN = 0x8019
+ ETHERTYPE_APPLETALK = 0x809b
+ ETHERTYPE_APPLITEK = 0x80c7
+ ETHERTYPE_ARGONAUT = 0x803a
+ ETHERTYPE_ARP = 0x806
+ ETHERTYPE_AT = 0x809b
+ ETHERTYPE_ATALK = 0x809b
+ ETHERTYPE_ATOMIC = 0x86df
+ ETHERTYPE_ATT = 0x8069
+ ETHERTYPE_ATTSTANFORD = 0x8008
+ ETHERTYPE_AUTOPHON = 0x806a
+ ETHERTYPE_AXIS = 0x8856
+ ETHERTYPE_BCLOOP = 0x9003
+ ETHERTYPE_BOFL = 0x8102
+ ETHERTYPE_CABLETRON = 0x7034
+ ETHERTYPE_CHAOS = 0x804
+ ETHERTYPE_COMDESIGN = 0x806c
+ ETHERTYPE_COMPUGRAPHIC = 0x806d
+ ETHERTYPE_COUNTERPOINT = 0x8062
+ ETHERTYPE_CRONUS = 0x8004
+ ETHERTYPE_CRONUSVLN = 0x8003
+ ETHERTYPE_DCA = 0x1234
+ ETHERTYPE_DDE = 0x807b
+ ETHERTYPE_DEBNI = 0xaaaa
+ ETHERTYPE_DECAM = 0x8048
+ ETHERTYPE_DECCUST = 0x6006
+ ETHERTYPE_DECDIAG = 0x6005
+ ETHERTYPE_DECDNS = 0x803c
+ ETHERTYPE_DECDTS = 0x803e
+ ETHERTYPE_DECEXPER = 0x6000
+ ETHERTYPE_DECLAST = 0x8041
+ ETHERTYPE_DECLTM = 0x803f
+ ETHERTYPE_DECMUMPS = 0x6009
+ ETHERTYPE_DECNETBIOS = 0x8040
+ ETHERTYPE_DELTACON = 0x86de
+ ETHERTYPE_DIDDLE = 0x4321
+ ETHERTYPE_DLOG1 = 0x660
+ ETHERTYPE_DLOG2 = 0x661
+ ETHERTYPE_DN = 0x6003
+ ETHERTYPE_DOGFIGHT = 0x1989
+ ETHERTYPE_DSMD = 0x8039
+ ETHERTYPE_ECMA = 0x803
+ ETHERTYPE_ENCRYPT = 0x803d
+ ETHERTYPE_ES = 0x805d
+ ETHERTYPE_EXCELAN = 0x8010
+ ETHERTYPE_EXPERDATA = 0x8049
+ ETHERTYPE_FLIP = 0x8146
+ ETHERTYPE_FLOWCONTROL = 0x8808
+ ETHERTYPE_FRARP = 0x808
+ ETHERTYPE_GENDYN = 0x8068
+ ETHERTYPE_HAYES = 0x8130
+ ETHERTYPE_HIPPI_FP = 0x8180
+ ETHERTYPE_HITACHI = 0x8820
+ ETHERTYPE_HP = 0x8005
+ ETHERTYPE_IEEEPUP = 0xa00
+ ETHERTYPE_IEEEPUPAT = 0xa01
+ ETHERTYPE_IMLBL = 0x4c42
+ ETHERTYPE_IMLBLDIAG = 0x424c
+ ETHERTYPE_IP = 0x800
+ ETHERTYPE_IPAS = 0x876c
+ ETHERTYPE_IPV6 = 0x86dd
+ ETHERTYPE_IPX = 0x8137
+ ETHERTYPE_IPXNEW = 0x8037
+ ETHERTYPE_KALPANA = 0x8582
+ ETHERTYPE_LANBRIDGE = 0x8038
+ ETHERTYPE_LANPROBE = 0x8888
+ ETHERTYPE_LAT = 0x6004
+ ETHERTYPE_LBACK = 0x9000
+ ETHERTYPE_LITTLE = 0x8060
+ ETHERTYPE_LLDP = 0x88cc
+ ETHERTYPE_LOGICRAFT = 0x8148
+ ETHERTYPE_LOOPBACK = 0x9000
+ ETHERTYPE_MATRA = 0x807a
+ ETHERTYPE_MAX = 0xffff
+ ETHERTYPE_MERIT = 0x807c
+ ETHERTYPE_MICP = 0x873a
+ ETHERTYPE_MOPDL = 0x6001
+ ETHERTYPE_MOPRC = 0x6002
+ ETHERTYPE_MOTOROLA = 0x818d
+ ETHERTYPE_MPLS = 0x8847
+ ETHERTYPE_MPLS_MCAST = 0x8848
+ ETHERTYPE_MUMPS = 0x813f
+ ETHERTYPE_NBPCC = 0x3c04
+ ETHERTYPE_NBPCLAIM = 0x3c09
+ ETHERTYPE_NBPCLREQ = 0x3c05
+ ETHERTYPE_NBPCLRSP = 0x3c06
+ ETHERTYPE_NBPCREQ = 0x3c02
+ ETHERTYPE_NBPCRSP = 0x3c03
+ ETHERTYPE_NBPDG = 0x3c07
+ ETHERTYPE_NBPDGB = 0x3c08
+ ETHERTYPE_NBPDLTE = 0x3c0a
+ ETHERTYPE_NBPRAR = 0x3c0c
+ ETHERTYPE_NBPRAS = 0x3c0b
+ ETHERTYPE_NBPRST = 0x3c0d
+ ETHERTYPE_NBPSCD = 0x3c01
+ ETHERTYPE_NBPVCD = 0x3c00
+ ETHERTYPE_NBS = 0x802
+ ETHERTYPE_NCD = 0x8149
+ ETHERTYPE_NESTAR = 0x8006
+ ETHERTYPE_NETBEUI = 0x8191
+ ETHERTYPE_NOVELL = 0x8138
+ ETHERTYPE_NS = 0x600
+ ETHERTYPE_NSAT = 0x601
+ ETHERTYPE_NSCOMPAT = 0x807
+ ETHERTYPE_NTRAILER = 0x10
+ ETHERTYPE_OS9 = 0x7007
+ ETHERTYPE_OS9NET = 0x7009
+ ETHERTYPE_PACER = 0x80c6
+ ETHERTYPE_PAE = 0x888e
+ ETHERTYPE_PCS = 0x4242
+ ETHERTYPE_PLANNING = 0x8044
+ ETHERTYPE_PPP = 0x880b
+ ETHERTYPE_PPPOE = 0x8864
+ ETHERTYPE_PPPOEDISC = 0x8863
+ ETHERTYPE_PRIMENTS = 0x7031
+ ETHERTYPE_PUP = 0x200
+ ETHERTYPE_PUPAT = 0x200
+ ETHERTYPE_QINQ = 0x88a8
+ ETHERTYPE_RACAL = 0x7030
+ ETHERTYPE_RATIONAL = 0x8150
+ ETHERTYPE_RAWFR = 0x6559
+ ETHERTYPE_RCL = 0x1995
+ ETHERTYPE_RDP = 0x8739
+ ETHERTYPE_RETIX = 0x80f2
+ ETHERTYPE_REVARP = 0x8035
+ ETHERTYPE_SCA = 0x6007
+ ETHERTYPE_SECTRA = 0x86db
+ ETHERTYPE_SECUREDATA = 0x876d
+ ETHERTYPE_SGITW = 0x817e
+ ETHERTYPE_SG_BOUNCE = 0x8016
+ ETHERTYPE_SG_DIAG = 0x8013
+ ETHERTYPE_SG_NETGAMES = 0x8014
+ ETHERTYPE_SG_RESV = 0x8015
+ ETHERTYPE_SIMNET = 0x5208
+ ETHERTYPE_SLOW = 0x8809
+ ETHERTYPE_SNA = 0x80d5
+ ETHERTYPE_SNMP = 0x814c
+ ETHERTYPE_SONIX = 0xfaf5
+ ETHERTYPE_SPIDER = 0x809f
+ ETHERTYPE_SPRITE = 0x500
+ ETHERTYPE_STP = 0x8181
+ ETHERTYPE_TALARIS = 0x812b
+ ETHERTYPE_TALARISMC = 0x852b
+ ETHERTYPE_TCPCOMP = 0x876b
+ ETHERTYPE_TCPSM = 0x9002
+ ETHERTYPE_TEC = 0x814f
+ ETHERTYPE_TIGAN = 0x802f
+ ETHERTYPE_TRAIL = 0x1000
+ ETHERTYPE_TRANSETHER = 0x6558
+ ETHERTYPE_TYMSHARE = 0x802e
+ ETHERTYPE_UBBST = 0x7005
+ ETHERTYPE_UBDEBUG = 0x900
+ ETHERTYPE_UBDIAGLOOP = 0x7002
+ ETHERTYPE_UBDL = 0x7000
+ ETHERTYPE_UBNIU = 0x7001
+ ETHERTYPE_UBNMC = 0x7003
+ ETHERTYPE_VALID = 0x1600
+ ETHERTYPE_VARIAN = 0x80dd
+ ETHERTYPE_VAXELN = 0x803b
+ ETHERTYPE_VEECO = 0x8067
+ ETHERTYPE_VEXP = 0x805b
+ ETHERTYPE_VGLAB = 0x8131
+ ETHERTYPE_VINES = 0xbad
+ ETHERTYPE_VINESECHO = 0xbaf
+ ETHERTYPE_VINESLOOP = 0xbae
+ ETHERTYPE_VITAL = 0xff00
+ ETHERTYPE_VLAN = 0x8100
+ ETHERTYPE_VLTLMAN = 0x8080
+ ETHERTYPE_VPROD = 0x805c
+ ETHERTYPE_VURESERVED = 0x8147
+ ETHERTYPE_WATERLOO = 0x8130
+ ETHERTYPE_WELLFLEET = 0x8103
+ ETHERTYPE_X25 = 0x805
+ ETHERTYPE_X75 = 0x801
+ ETHERTYPE_XNSSM = 0x9001
+ ETHERTYPE_XTP = 0x817d
+ ETHER_ADDR_LEN = 0x6
+ ETHER_ALIGN = 0x2
+ ETHER_CRC_LEN = 0x4
+ ETHER_CRC_POLY_BE = 0x4c11db6
+ ETHER_CRC_POLY_LE = 0xedb88320
+ ETHER_HDR_LEN = 0xe
+ ETHER_MAX_DIX_LEN = 0x600
+ ETHER_MAX_LEN = 0x5ee
+ ETHER_MIN_LEN = 0x40
+ ETHER_TYPE_LEN = 0x2
+ ETHER_VLAN_ENCAP_LEN = 0x4
+ EVFILT_AIO = -0x3
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0x7
+ EVFILT_TIMER = -0x7
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0xa
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_UNLCK = 0x2
+ F_WRLCK = 0x3
+ IFA_ROUTE = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x8e52
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BLUETOOTH = 0xf8
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf7
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DOCSCABLEUPSTREAMCHANNEL = 0xcd
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DUMMY = 0xf1
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ECONET = 0xce
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf3
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LINEGROUP = 0xd2
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf5
+ IFT_PFLOW = 0xf9
+ IFT_PFSYNC = 0xf6
+ IFT_PLC = 0xae
+ IFT_PON155 = 0xcf
+ IFT_PON622 = 0xd0
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPATM = 0xc5
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf2
+ IFT_Q2931 = 0xc9
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SIPSIG = 0xcc
+ IFT_SIPTG = 0xcb
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TELINK = 0xc8
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VIRTUALTG = 0xca
+ IFT_VOICEDID = 0xd5
+ IFT_VOICEEM = 0x64
+ IFT_VOICEEMFGD = 0xd3
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFGDEANA = 0xd4
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERCABLE = 0xc6
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_HOST = 0x1
+ IN_RFC3021_NET = 0xfffffffe
+ IN_RFC3021_NSHIFT = 0x1f
+ IPPROTO_AH = 0x33
+ IPPROTO_CARP = 0x70
+ IPPROTO_DIVERT = 0x102
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x103
+ IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PFSYNC = 0xf0
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPV6_AUTH_LEVEL = 0x35
+ IPV6_AUTOFLOWLABEL = 0x3b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DONTFRAG = 0x3e
+ IPV6_DSTOPTS = 0x32
+ IPV6_ESP_NETWORK_LEVEL = 0x37
+ IPV6_ESP_TRANS_LEVEL = 0x36
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x2f
+ IPV6_HOPOPTS = 0x31
+ IPV6_IPCOMP_LEVEL = 0x3c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_OPTIONS = 0x1
+ IPV6_PATHMTU = 0x2c
+ IPV6_PIPEX = 0x3f
+ IPV6_PKTINFO = 0x2e
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x25
+ IPV6_RECVHOPOPTS = 0x27
+ IPV6_RECVPATHMTU = 0x2b
+ IPV6_RECVPKTINFO = 0x24
+ IPV6_RECVRTHDR = 0x26
+ IPV6_RECVTCLASS = 0x39
+ IPV6_RTABLE = 0x1021
+ IPV6_RTHDR = 0x33
+ IPV6_RTHDRDSTOPTS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x3d
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_USE_MIN_MTU = 0x2a
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_AUTH_LEVEL = 0x14
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_ESP_NETWORK_LEVEL = 0x16
+ IP_ESP_TRANS_LEVEL = 0x15
+ IP_HDRINCL = 0x2
+ IP_IPCOMP_LEVEL = 0x1d
+ IP_IPSEC_LOCAL_AUTH = 0x1b
+ IP_IPSEC_LOCAL_CRED = 0x19
+ IP_IPSEC_LOCAL_ID = 0x17
+ IP_IPSEC_REMOTE_AUTH = 0x1c
+ IP_IPSEC_REMOTE_CRED = 0x1a
+ IP_IPSEC_REMOTE_ID = 0x18
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MF = 0x2000
+ IP_MINTTL = 0x20
+ IP_MIN_MEMBERSHIPS = 0xf
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x1
+ IP_PIPEX = 0x22
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVDSTPORT = 0x21
+ IP_RECVIF = 0x1e
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVRTABLE = 0x23
+ IP_RECVTTL = 0x1f
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RTABLE = 0x1021
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ MAP_ET_KVAGUARD = 0x10
+ MSG_BCAST = 0x100
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOR = 0x8
+ MSG_MCAST = 0x200
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_MAXID = 0x6
+ NET_RT_STATS = 0x4
+ NET_RT_TABLE = 0x5
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x10000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x20000
+ O_DSYNC = 0x80
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x8000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x80
+ O_SHLOCK = 0x10
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_LABEL = 0xa
+ RTAX_MAX = 0xb
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTAX_SRCMASK = 0x9
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_LABEL = 0x400
+ RTA_NETMASK = 0x4
+ RTA_SRC = 0x100
+ RTA_SRCMASK = 0x200
+ RTF_ANNOUNCE = 0x4000
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONED = 0x10000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x8f808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_JUMBO = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MPATH = 0x40000
+ RTF_MPLS = 0x100000
+ RTF_PERMANENT_ARP = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x2000
+ RTF_REJECT = 0x8
+ RTF_SOURCE = 0x20000
+ RTF_STATIC = 0x800
+ RTF_TUNNEL = 0x100000
+ RTF_UP = 0x1
+ RTF_USETRAILERS = 0x8000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DESYNC = 0x10
+ RTM_GET = 0x4
+ RTM_IFANNOUNCE = 0xf
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MAXSIZE = 0x800
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x4
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_TABLEID_MAX = 0xff
+ SCM_CREDS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIGABRT = 0x6
+ SIGALRM = 0xe
+ SIGBUS = 0xa
+ SIGCHLD = 0x14
+ SIGCONT = 0x13
+ SIGEMT = 0x7
+ SIGFPE = 0x8
+ SIGHUP = 0x1
+ SIGILL = 0x4
+ SIGINFO = 0x1d
+ SIGINT = 0x2
+ SIGIO = 0x17
+ SIGIOT = 0x6
+ SIGKILL = 0x9
+ SIGPIPE = 0xd
+ SIGPROF = 0x1b
+ SIGQUIT = 0x3
+ SIGSEGV = 0xb
+ SIGSTOP = 0x11
+ SIGSYS = 0xc
+ SIGTERM = 0xf
+ SIGTHR = 0x20
+ SIGTRAP = 0x5
+ SIGTSTP = 0x12
+ SIGTTIN = 0x15
+ SIGTTOU = 0x16
+ SIGURG = 0x10
+ SIGUSR1 = 0x1e
+ SIGUSR2 = 0x1f
+ SIGVTALRM = 0x1a
+ SIGWINCH = 0x1c
+ SIGXCPU = 0x18
+ SIGXFSZ = 0x19
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80286987
+ SIOCALIFADDR = 0x8218691c
+ SIOCATMARK = 0x40047307
+ SIOCBRDGADD = 0x8058693c
+ SIOCBRDGADDS = 0x80586941
+ SIOCBRDGARL = 0x806e694d
+ SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDEL = 0x8058693d
+ SIOCBRDGDELS = 0x80586942
+ SIOCBRDGFLUSH = 0x80586948
+ SIOCBRDGFRL = 0x806e694e
+ SIOCBRDGGCACHE = 0xc0146941
+ SIOCBRDGGFD = 0xc0146952
+ SIOCBRDGGHT = 0xc0146951
+ SIOCBRDGGIFFLGS = 0xc058693e
+ SIOCBRDGGMA = 0xc0146953
+ SIOCBRDGGPARAM = 0xc0406958
+ SIOCBRDGGPRI = 0xc0146950
+ SIOCBRDGGRL = 0xc030694f
+ SIOCBRDGGSIFS = 0xc058693c
+ SIOCBRDGGTO = 0xc0146946
+ SIOCBRDGIFS = 0xc0586942
+ SIOCBRDGRTS = 0xc0206943
+ SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSCACHE = 0x80146940
+ SIOCBRDGSFD = 0x80146952
+ SIOCBRDGSHT = 0x80146951
+ SIOCBRDGSIFCOST = 0x80586955
+ SIOCBRDGSIFFLGS = 0x8058693f
+ SIOCBRDGSIFPRIO = 0x80586954
+ SIOCBRDGSMA = 0x80146953
+ SIOCBRDGSPRI = 0x80146950
+ SIOCBRDGSPROTO = 0x8014695a
+ SIOCBRDGSTO = 0x80146945
+ SIOCBRDGSTXHC = 0x80146959
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80286989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8218691e
+ SIOCGETKALIVE = 0xc01869a4
+ SIOCGETLABEL = 0x8020699a
+ SIOCGETPFLOW = 0xc02069fe
+ SIOCGETPFSYNC = 0xc02069f8
+ SIOCGETSGCNT = 0xc0207534
+ SIOCGETVIFCNT = 0xc0287533
+ SIOCGETVLANPRIO = 0xc0206990
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0106924
+ SIOCGIFDATA = 0xc020691b
+ SIOCGIFDESCR = 0xc0206981
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGATTR = 0xc028698b
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc028698a
+ SIOCGIFGROUP = 0xc0286988
+ SIOCGIFMEDIA = 0xc0306936
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc020697e
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPRIORITY = 0xc020699c
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFRDOMAIN = 0xc02069a0
+ SIOCGIFRTLABEL = 0xc0206983
+ SIOCGIFTIMESLOT = 0xc0206986
+ SIOCGIFXFLAGS = 0xc020699e
+ SIOCGLIFADDR = 0xc218691d
+ SIOCGLIFPHYADDR = 0xc218694b
+ SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGVH = 0xc02069f6
+ SIOCIFCREATE = 0x8020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc0106978
+ SIOCSETKALIVE = 0x801869a3
+ SIOCSETLABEL = 0x80206999
+ SIOCSETPFLOW = 0x802069fd
+ SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLANPRIO = 0x8020698f
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDESCR = 0x80206980
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGATTR = 0x8028698c
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020691f
+ SIOCSIFMEDIA = 0xc0206935
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x8020697f
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPRIORITY = 0x8020699b
+ SIOCSIFRDOMAIN = 0x8020699f
+ SIOCSIFRTLABEL = 0x80206982
+ SIOCSIFTIMESLOT = 0x80206985
+ SIOCSIFXFLAGS = 0x8020699d
+ SIOCSLIFPHYADDR = 0x8218694a
+ SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SIOCSVH = 0xc02069f5
+ SOCK_DGRAM = 0x2
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BINDANY = 0x1000
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_JUMBO = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_NETPROC = 0x1020
+ SO_OOBINLINE = 0x100
+ SO_PEERCRED = 0x1022
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RTABLE = 0x1021
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_SPLICE = 0x1023
+ SO_TIMESTAMP = 0x800
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ TCP_MAXBURST = 0x4
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0x4
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NSTATES = 0xb
+ TCP_SACK_ENABLE = 0x8
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLAG_CLOCAL = 0x2
+ TIOCFLAG_CRTSCTS = 0x4
+ TIOCFLAG_MDMBUF = 0x8
+ TIOCFLAG_PPS = 0x10
+ TIOCFLAG_SOFTCAR = 0x1
+ TIOCFLUSH = 0x80047410
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGFLAGS = 0x4004745d
+ TIOCGPGRP = 0x40047477
+ TIOCGTSTAMP = 0x4010745b
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x4004746a
+ TIOCMODS = 0x8004746d
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSFLAGS = 0x8004745c
+ TIOCSIG = 0x8004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x80047465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSTSTAMP = 0x8008745a
+ TIOCSWINSZ = 0x80087467
+ TIOCUCNTL = 0x80047466
+ WALTSIG = 0x4
+ WCONTINUED = 0x8
+ WCOREFLAG = 0x80
+ WNOHANG = 0x1
+ WSTOPPED = 0x7f
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x58)
+ ECHILD = Errno(0xa)
+ ECHO = Errno(0x8)
+ ECHOCTL = Errno(0x40)
+ ECHOE = Errno(0x2)
+ ECHOK = Errno(0x4)
+ ECHOKE = Errno(0x1)
+ ECHONL = Errno(0x10)
+ ECHOPRT = Errno(0x20)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x59)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EIPSEC = Errno(0x52)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5b)
+ ELOOP = Errno(0x3e)
+ EMEDIUMTYPE = Errno(0x56)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ ENAMETOOLONG = Errno(0x3f)
+ ENDRUNDISC = Errno(0x9)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x53)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOMEDIUM = Errno(0x55)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5a)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x5b)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x57)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "connection timed out",
+ 61: "connection refused",
+ 62: "too many levels of symbolic links",
+ 63: "file name too long",
+ 64: "host is down",
+ 65: "no route to host",
+ 66: "directory not empty",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "IPsec processing failure",
+ 83: "attribute not found",
+ 84: "illegal byte sequence",
+ 85: "no medium found",
+ 86: "wrong medium type",
+ 87: "value too large to be stored in data type",
+ 88: "operation canceled",
+ 89: "identifier removed",
+ 90: "no message of desired type",
+ 91: "not supported",
+}
diff --git a/src/pkg/syscall/zerrors_openbsd_386.go b/src/pkg/syscall/zerrors_openbsd_386.go
new file mode 100644
index 000000000..11074d5f5
--- /dev/null
+++ b/src/pkg/syscall/zerrors_openbsd_386.go
@@ -0,0 +1,1441 @@
+// mkerrors.sh -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_BLUETOOTH = 0x20
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1a
+ AF_ECMA = 0x8
+ AF_ENCAP = 0x1c
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x18
+ AF_IPX = 0x17
+ AF_ISDN = 0x1a
+ AF_ISO = 0x7
+ AF_KEY = 0x1e
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x24
+ AF_MPLS = 0x21
+ AF_NATM = 0x1b
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_ROUTE = 0x11
+ AF_SIP = 0x1d
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FRELAY = 0xf
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRFILT = 0x4004427c
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc008427b
+ BIOCGETIF = 0x4020426b
+ BIOCGFILDROP = 0x40044278
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044273
+ BIOCGRTIMEOUT = 0x4008426e
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x20004276
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRFILT = 0x8004427d
+ BIOCSDLT = 0x8004427a
+ BIOCSETF = 0x80084267
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x80084277
+ BIOCSFILDROP = 0x80044279
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044272
+ BIOCSRTIMEOUT = 0x8008426d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIRECTION_IN = 0x1
+ BPF_DIRECTION_OUT = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x200000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_ARCNET = 0x7
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0xd
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_LOOP = 0xc
+ DLT_MPLS = 0xdb
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xe
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ EFER_LMA = 0x400
+ EFER_LME = 0x100
+ EFER_NXE = 0x800
+ EFER_SCE = 0x1
+ EMT_TAGOVF = 0x1
+ EMUL_ENABLED = 0x1
+ EMUL_NATIVE = 0x2
+ ENDRUNDISC = 0x9
+ ETHERMIN = 0x2e
+ ETHERMTU = 0x5dc
+ ETHERTYPE_8023 = 0x4
+ ETHERTYPE_AARP = 0x80f3
+ ETHERTYPE_ACCTON = 0x8390
+ ETHERTYPE_AEONIC = 0x8036
+ ETHERTYPE_ALPHA = 0x814a
+ ETHERTYPE_AMBER = 0x6008
+ ETHERTYPE_AMOEBA = 0x8145
+ ETHERTYPE_AOE = 0x88a2
+ ETHERTYPE_APOLLO = 0x80f7
+ ETHERTYPE_APOLLODOMAIN = 0x8019
+ ETHERTYPE_APPLETALK = 0x809b
+ ETHERTYPE_APPLITEK = 0x80c7
+ ETHERTYPE_ARGONAUT = 0x803a
+ ETHERTYPE_ARP = 0x806
+ ETHERTYPE_AT = 0x809b
+ ETHERTYPE_ATALK = 0x809b
+ ETHERTYPE_ATOMIC = 0x86df
+ ETHERTYPE_ATT = 0x8069
+ ETHERTYPE_ATTSTANFORD = 0x8008
+ ETHERTYPE_AUTOPHON = 0x806a
+ ETHERTYPE_AXIS = 0x8856
+ ETHERTYPE_BCLOOP = 0x9003
+ ETHERTYPE_BOFL = 0x8102
+ ETHERTYPE_CABLETRON = 0x7034
+ ETHERTYPE_CHAOS = 0x804
+ ETHERTYPE_COMDESIGN = 0x806c
+ ETHERTYPE_COMPUGRAPHIC = 0x806d
+ ETHERTYPE_COUNTERPOINT = 0x8062
+ ETHERTYPE_CRONUS = 0x8004
+ ETHERTYPE_CRONUSVLN = 0x8003
+ ETHERTYPE_DCA = 0x1234
+ ETHERTYPE_DDE = 0x807b
+ ETHERTYPE_DEBNI = 0xaaaa
+ ETHERTYPE_DECAM = 0x8048
+ ETHERTYPE_DECCUST = 0x6006
+ ETHERTYPE_DECDIAG = 0x6005
+ ETHERTYPE_DECDNS = 0x803c
+ ETHERTYPE_DECDTS = 0x803e
+ ETHERTYPE_DECEXPER = 0x6000
+ ETHERTYPE_DECLAST = 0x8041
+ ETHERTYPE_DECLTM = 0x803f
+ ETHERTYPE_DECMUMPS = 0x6009
+ ETHERTYPE_DECNETBIOS = 0x8040
+ ETHERTYPE_DELTACON = 0x86de
+ ETHERTYPE_DIDDLE = 0x4321
+ ETHERTYPE_DLOG1 = 0x660
+ ETHERTYPE_DLOG2 = 0x661
+ ETHERTYPE_DN = 0x6003
+ ETHERTYPE_DOGFIGHT = 0x1989
+ ETHERTYPE_DSMD = 0x8039
+ ETHERTYPE_ECMA = 0x803
+ ETHERTYPE_ENCRYPT = 0x803d
+ ETHERTYPE_ES = 0x805d
+ ETHERTYPE_EXCELAN = 0x8010
+ ETHERTYPE_EXPERDATA = 0x8049
+ ETHERTYPE_FLIP = 0x8146
+ ETHERTYPE_FLOWCONTROL = 0x8808
+ ETHERTYPE_FRARP = 0x808
+ ETHERTYPE_GENDYN = 0x8068
+ ETHERTYPE_HAYES = 0x8130
+ ETHERTYPE_HIPPI_FP = 0x8180
+ ETHERTYPE_HITACHI = 0x8820
+ ETHERTYPE_HP = 0x8005
+ ETHERTYPE_IEEEPUP = 0xa00
+ ETHERTYPE_IEEEPUPAT = 0xa01
+ ETHERTYPE_IMLBL = 0x4c42
+ ETHERTYPE_IMLBLDIAG = 0x424c
+ ETHERTYPE_IP = 0x800
+ ETHERTYPE_IPAS = 0x876c
+ ETHERTYPE_IPV6 = 0x86dd
+ ETHERTYPE_IPX = 0x8137
+ ETHERTYPE_IPXNEW = 0x8037
+ ETHERTYPE_KALPANA = 0x8582
+ ETHERTYPE_LANBRIDGE = 0x8038
+ ETHERTYPE_LANPROBE = 0x8888
+ ETHERTYPE_LAT = 0x6004
+ ETHERTYPE_LBACK = 0x9000
+ ETHERTYPE_LITTLE = 0x8060
+ ETHERTYPE_LLDP = 0x88cc
+ ETHERTYPE_LOGICRAFT = 0x8148
+ ETHERTYPE_LOOPBACK = 0x9000
+ ETHERTYPE_MATRA = 0x807a
+ ETHERTYPE_MAX = 0xffff
+ ETHERTYPE_MERIT = 0x807c
+ ETHERTYPE_MICP = 0x873a
+ ETHERTYPE_MOPDL = 0x6001
+ ETHERTYPE_MOPRC = 0x6002
+ ETHERTYPE_MOTOROLA = 0x818d
+ ETHERTYPE_MPLS = 0x8847
+ ETHERTYPE_MPLS_MCAST = 0x8848
+ ETHERTYPE_MUMPS = 0x813f
+ ETHERTYPE_NBPCC = 0x3c04
+ ETHERTYPE_NBPCLAIM = 0x3c09
+ ETHERTYPE_NBPCLREQ = 0x3c05
+ ETHERTYPE_NBPCLRSP = 0x3c06
+ ETHERTYPE_NBPCREQ = 0x3c02
+ ETHERTYPE_NBPCRSP = 0x3c03
+ ETHERTYPE_NBPDG = 0x3c07
+ ETHERTYPE_NBPDGB = 0x3c08
+ ETHERTYPE_NBPDLTE = 0x3c0a
+ ETHERTYPE_NBPRAR = 0x3c0c
+ ETHERTYPE_NBPRAS = 0x3c0b
+ ETHERTYPE_NBPRST = 0x3c0d
+ ETHERTYPE_NBPSCD = 0x3c01
+ ETHERTYPE_NBPVCD = 0x3c00
+ ETHERTYPE_NBS = 0x802
+ ETHERTYPE_NCD = 0x8149
+ ETHERTYPE_NESTAR = 0x8006
+ ETHERTYPE_NETBEUI = 0x8191
+ ETHERTYPE_NOVELL = 0x8138
+ ETHERTYPE_NS = 0x600
+ ETHERTYPE_NSAT = 0x601
+ ETHERTYPE_NSCOMPAT = 0x807
+ ETHERTYPE_NTRAILER = 0x10
+ ETHERTYPE_OS9 = 0x7007
+ ETHERTYPE_OS9NET = 0x7009
+ ETHERTYPE_PACER = 0x80c6
+ ETHERTYPE_PAE = 0x888e
+ ETHERTYPE_PCS = 0x4242
+ ETHERTYPE_PLANNING = 0x8044
+ ETHERTYPE_PPP = 0x880b
+ ETHERTYPE_PPPOE = 0x8864
+ ETHERTYPE_PPPOEDISC = 0x8863
+ ETHERTYPE_PRIMENTS = 0x7031
+ ETHERTYPE_PUP = 0x200
+ ETHERTYPE_PUPAT = 0x200
+ ETHERTYPE_QINQ = 0x88a8
+ ETHERTYPE_RACAL = 0x7030
+ ETHERTYPE_RATIONAL = 0x8150
+ ETHERTYPE_RAWFR = 0x6559
+ ETHERTYPE_RCL = 0x1995
+ ETHERTYPE_RDP = 0x8739
+ ETHERTYPE_RETIX = 0x80f2
+ ETHERTYPE_REVARP = 0x8035
+ ETHERTYPE_SCA = 0x6007
+ ETHERTYPE_SECTRA = 0x86db
+ ETHERTYPE_SECUREDATA = 0x876d
+ ETHERTYPE_SGITW = 0x817e
+ ETHERTYPE_SG_BOUNCE = 0x8016
+ ETHERTYPE_SG_DIAG = 0x8013
+ ETHERTYPE_SG_NETGAMES = 0x8014
+ ETHERTYPE_SG_RESV = 0x8015
+ ETHERTYPE_SIMNET = 0x5208
+ ETHERTYPE_SLOW = 0x8809
+ ETHERTYPE_SNA = 0x80d5
+ ETHERTYPE_SNMP = 0x814c
+ ETHERTYPE_SONIX = 0xfaf5
+ ETHERTYPE_SPIDER = 0x809f
+ ETHERTYPE_SPRITE = 0x500
+ ETHERTYPE_STP = 0x8181
+ ETHERTYPE_TALARIS = 0x812b
+ ETHERTYPE_TALARISMC = 0x852b
+ ETHERTYPE_TCPCOMP = 0x876b
+ ETHERTYPE_TCPSM = 0x9002
+ ETHERTYPE_TEC = 0x814f
+ ETHERTYPE_TIGAN = 0x802f
+ ETHERTYPE_TRAIL = 0x1000
+ ETHERTYPE_TRANSETHER = 0x6558
+ ETHERTYPE_TYMSHARE = 0x802e
+ ETHERTYPE_UBBST = 0x7005
+ ETHERTYPE_UBDEBUG = 0x900
+ ETHERTYPE_UBDIAGLOOP = 0x7002
+ ETHERTYPE_UBDL = 0x7000
+ ETHERTYPE_UBNIU = 0x7001
+ ETHERTYPE_UBNMC = 0x7003
+ ETHERTYPE_VALID = 0x1600
+ ETHERTYPE_VARIAN = 0x80dd
+ ETHERTYPE_VAXELN = 0x803b
+ ETHERTYPE_VEECO = 0x8067
+ ETHERTYPE_VEXP = 0x805b
+ ETHERTYPE_VGLAB = 0x8131
+ ETHERTYPE_VINES = 0xbad
+ ETHERTYPE_VINESECHO = 0xbaf
+ ETHERTYPE_VINESLOOP = 0xbae
+ ETHERTYPE_VITAL = 0xff00
+ ETHERTYPE_VLAN = 0x8100
+ ETHERTYPE_VLTLMAN = 0x8080
+ ETHERTYPE_VPROD = 0x805c
+ ETHERTYPE_VURESERVED = 0x8147
+ ETHERTYPE_WATERLOO = 0x8130
+ ETHERTYPE_WELLFLEET = 0x8103
+ ETHERTYPE_X25 = 0x805
+ ETHERTYPE_X75 = 0x801
+ ETHERTYPE_XNSSM = 0x9001
+ ETHERTYPE_XTP = 0x817d
+ ETHER_ADDR_LEN = 0x6
+ ETHER_ALIGN = 0x2
+ ETHER_CRC_LEN = 0x4
+ ETHER_CRC_POLY_BE = 0x4c11db6
+ ETHER_CRC_POLY_LE = 0xedb88320
+ ETHER_HDR_LEN = 0xe
+ ETHER_MAX_DIX_LEN = 0x600
+ ETHER_MAX_LEN = 0x5ee
+ ETHER_MIN_LEN = 0x40
+ ETHER_TYPE_LEN = 0x2
+ ETHER_VLAN_ENCAP_LEN = 0x4
+ EVFILT_AIO = -0x3
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0x7
+ EVFILT_TIMER = -0x7
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0xa
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_OK = 0x0
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_UNLCK = 0x2
+ F_WRLCK = 0x3
+ IFA_ROUTE = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x8e52
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BLUETOOTH = 0xf8
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf7
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DOCSCABLEUPSTREAMCHANNEL = 0xcd
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DUMMY = 0xf1
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ECONET = 0xce
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf3
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LINEGROUP = 0xd2
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf5
+ IFT_PFLOW = 0xf9
+ IFT_PFSYNC = 0xf6
+ IFT_PLC = 0xae
+ IFT_PON155 = 0xcf
+ IFT_PON622 = 0xd0
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPATM = 0xc5
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf2
+ IFT_Q2931 = 0xc9
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SIPSIG = 0xcc
+ IFT_SIPTG = 0xcb
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TELINK = 0xc8
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VIRTUALTG = 0xca
+ IFT_VOICEDID = 0xd5
+ IFT_VOICEEM = 0x64
+ IFT_VOICEEMFGD = 0xd3
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFGDEANA = 0xd4
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERCABLE = 0xc6
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_HOST = 0x1
+ IN_RFC3021_NET = 0xfffffffe
+ IN_RFC3021_NSHIFT = 0x1f
+ IPPROTO_AH = 0x33
+ IPPROTO_CARP = 0x70
+ IPPROTO_DIVERT = 0x102
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x103
+ IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PFSYNC = 0xf0
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPV6_AUTH_LEVEL = 0x35
+ IPV6_AUTOFLOWLABEL = 0x3b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DONTFRAG = 0x3e
+ IPV6_DSTOPTS = 0x32
+ IPV6_ESP_NETWORK_LEVEL = 0x37
+ IPV6_ESP_TRANS_LEVEL = 0x36
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x2f
+ IPV6_HOPOPTS = 0x31
+ IPV6_IPCOMP_LEVEL = 0x3c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_OPTIONS = 0x1
+ IPV6_PATHMTU = 0x2c
+ IPV6_PIPEX = 0x3f
+ IPV6_PKTINFO = 0x2e
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x25
+ IPV6_RECVHOPOPTS = 0x27
+ IPV6_RECVPATHMTU = 0x2b
+ IPV6_RECVPKTINFO = 0x24
+ IPV6_RECVRTHDR = 0x26
+ IPV6_RECVTCLASS = 0x39
+ IPV6_RTABLE = 0x1021
+ IPV6_RTHDR = 0x33
+ IPV6_RTHDRDSTOPTS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x3d
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_USE_MIN_MTU = 0x2a
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_AUTH_LEVEL = 0x14
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_ESP_NETWORK_LEVEL = 0x16
+ IP_ESP_TRANS_LEVEL = 0x15
+ IP_HDRINCL = 0x2
+ IP_IPCOMP_LEVEL = 0x1d
+ IP_IPSEC_LOCAL_AUTH = 0x1b
+ IP_IPSEC_LOCAL_CRED = 0x19
+ IP_IPSEC_LOCAL_ID = 0x17
+ IP_IPSEC_REMOTE_AUTH = 0x1c
+ IP_IPSEC_REMOTE_CRED = 0x1a
+ IP_IPSEC_REMOTE_ID = 0x18
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MF = 0x2000
+ IP_MINTTL = 0x20
+ IP_MIN_MEMBERSHIPS = 0xf
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x1
+ IP_PIPEX = 0x22
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVDSTPORT = 0x21
+ IP_RECVIF = 0x1e
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVRTABLE = 0x23
+ IP_RECVTTL = 0x1f
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RTABLE = 0x1021
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MAP_ET_KVAGUARD = 0x10
+ MSG_BCAST = 0x100
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOR = 0x8
+ MSG_MCAST = 0x200
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_MAXID = 0x6
+ NET_RT_STATS = 0x4
+ NET_RT_TABLE = 0x5
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EOF = 0x2
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXTEND = 0x4
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_PCTRLMASK = 0xf0000000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_RENAME = 0x20
+ NOTE_REVOKE = 0x40
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRUNCATE = 0x80
+ NOTE_WRITE = 0x2
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x10000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x20000
+ O_DSYNC = 0x80
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x8000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x80
+ O_SHLOCK = 0x10
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_LABEL = 0xa
+ RTAX_MAX = 0xb
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTAX_SRCMASK = 0x9
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_LABEL = 0x400
+ RTA_NETMASK = 0x4
+ RTA_SRC = 0x100
+ RTA_SRCMASK = 0x200
+ RTF_ANNOUNCE = 0x4000
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONED = 0x10000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x8f808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_JUMBO = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MPATH = 0x40000
+ RTF_MPLS = 0x100000
+ RTF_PERMANENT_ARP = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x2000
+ RTF_REJECT = 0x8
+ RTF_SOURCE = 0x20000
+ RTF_STATIC = 0x800
+ RTF_TUNNEL = 0x100000
+ RTF_UP = 0x1
+ RTF_USETRAILERS = 0x8000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DESYNC = 0x10
+ RTM_GET = 0x4
+ RTM_IFANNOUNCE = 0xf
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MAXSIZE = 0x800
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x4
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_TABLEID_MAX = 0xff
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80246987
+ SIOCALIFADDR = 0x8218691c
+ SIOCATMARK = 0x40047307
+ SIOCBRDGADD = 0x8054693c
+ SIOCBRDGADDS = 0x80546941
+ SIOCBRDGARL = 0x806e694d
+ SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDEL = 0x8054693d
+ SIOCBRDGDELS = 0x80546942
+ SIOCBRDGFLUSH = 0x80546948
+ SIOCBRDGFRL = 0x806e694e
+ SIOCBRDGGCACHE = 0xc0146941
+ SIOCBRDGGFD = 0xc0146952
+ SIOCBRDGGHT = 0xc0146951
+ SIOCBRDGGIFFLGS = 0xc054693e
+ SIOCBRDGGMA = 0xc0146953
+ SIOCBRDGGPARAM = 0xc0386958
+ SIOCBRDGGPRI = 0xc0146950
+ SIOCBRDGGRL = 0xc028694f
+ SIOCBRDGGSIFS = 0xc054693c
+ SIOCBRDGGTO = 0xc0146946
+ SIOCBRDGIFS = 0xc0546942
+ SIOCBRDGRTS = 0xc0186943
+ SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSCACHE = 0x80146940
+ SIOCBRDGSFD = 0x80146952
+ SIOCBRDGSHT = 0x80146951
+ SIOCBRDGSIFCOST = 0x80546955
+ SIOCBRDGSIFFLGS = 0x8054693f
+ SIOCBRDGSIFPRIO = 0x80546954
+ SIOCBRDGSMA = 0x80146953
+ SIOCBRDGSPRI = 0x80146950
+ SIOCBRDGSPROTO = 0x8014695a
+ SIOCBRDGSTO = 0x80146945
+ SIOCBRDGSTXHC = 0x80146959
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80246989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8218691e
+ SIOCGETKALIVE = 0xc01869a4
+ SIOCGETLABEL = 0x8020699a
+ SIOCGETPFLOW = 0xc02069fe
+ SIOCGETPFSYNC = 0xc02069f8
+ SIOCGETSGCNT = 0xc0147534
+ SIOCGETVIFCNT = 0xc0147533
+ SIOCGETVLANPRIO = 0xc0206990
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0086924
+ SIOCGIFDATA = 0xc020691b
+ SIOCGIFDESCR = 0xc0206981
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGATTR = 0xc024698b
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc024698a
+ SIOCGIFGROUP = 0xc0246988
+ SIOCGIFMEDIA = 0xc0286936
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc020697e
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPRIORITY = 0xc020699c
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFRDOMAIN = 0xc02069a0
+ SIOCGIFRTLABEL = 0xc0206983
+ SIOCGIFTIMESLOT = 0xc0206986
+ SIOCGIFXFLAGS = 0xc020699e
+ SIOCGLIFADDR = 0xc218691d
+ SIOCGLIFPHYADDR = 0xc218694b
+ SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGVH = 0xc02069f6
+ SIOCIFCREATE = 0x8020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc00c6978
+ SIOCSETKALIVE = 0x801869a3
+ SIOCSETLABEL = 0x80206999
+ SIOCSETPFLOW = 0x802069fd
+ SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLANPRIO = 0x8020698f
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDESCR = 0x80206980
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGATTR = 0x8024698c
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020691f
+ SIOCSIFMEDIA = 0xc0206935
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x8020697f
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPRIORITY = 0x8020699b
+ SIOCSIFRDOMAIN = 0x8020699f
+ SIOCSIFRTLABEL = 0x80206982
+ SIOCSIFTIMESLOT = 0x80206985
+ SIOCSIFXFLAGS = 0x8020699d
+ SIOCSLIFPHYADDR = 0x8218694a
+ SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SIOCSVH = 0xc02069f5
+ SOCK_DGRAM = 0x2
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BINDANY = 0x1000
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_JUMBO = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_NETPROC = 0x1020
+ SO_OOBINLINE = 0x100
+ SO_PEERCRED = 0x1022
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RTABLE = 0x1021
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_SPLICE = 0x1023
+ SO_TIMESTAMP = 0x800
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ TCP_MAXBURST = 0x4
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0x4
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NSTATES = 0xb
+ TCP_SACK_ENABLE = 0x8
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLAG_CLOCAL = 0x2
+ TIOCFLAG_CRTSCTS = 0x4
+ TIOCFLAG_MDMBUF = 0x8
+ TIOCFLAG_PPS = 0x10
+ TIOCFLAG_SOFTCAR = 0x1
+ TIOCFLUSH = 0x80047410
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGFLAGS = 0x4004745d
+ TIOCGPGRP = 0x40047477
+ TIOCGTSTAMP = 0x4008745b
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x4004746a
+ TIOCMODS = 0x8004746d
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSFLAGS = 0x8004745c
+ TIOCSIG = 0x8004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x80047465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSTSTAMP = 0x8008745a
+ TIOCSWINSZ = 0x80087467
+ TIOCUCNTL = 0x80047466
+ WALTSIG = 0x4
+ WCONTINUED = 0x8
+ WCOREFLAG = 0x80
+ WNOHANG = 0x1
+ WSTOPPED = 0x7f
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x58)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x59)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EIPSEC = Errno(0x52)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5b)
+ ELOOP = Errno(0x3e)
+ EMEDIUMTYPE = Errno(0x56)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x53)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOMEDIUM = Errno(0x55)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5a)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x5b)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x57)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHR = Signal(0x20)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "connection timed out",
+ 61: "connection refused",
+ 62: "too many levels of symbolic links",
+ 63: "file name too long",
+ 64: "host is down",
+ 65: "no route to host",
+ 66: "directory not empty",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "IPsec processing failure",
+ 83: "attribute not found",
+ 84: "illegal byte sequence",
+ 85: "no medium found",
+ 86: "wrong medium type",
+ 87: "value too large to be stored in data type",
+ 88: "operation canceled",
+ 89: "identifier removed",
+ 90: "no message of desired type",
+ 91: "not supported",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "stopped (signal)",
+ 18: "stopped",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+ 32: "thread AST",
+}
diff --git a/src/pkg/syscall/zerrors_openbsd_amd64.go b/src/pkg/syscall/zerrors_openbsd_amd64.go
new file mode 100644
index 000000000..91ea06553
--- /dev/null
+++ b/src/pkg/syscall/zerrors_openbsd_amd64.go
@@ -0,0 +1,1441 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+ AF_APPLETALK = 0x10
+ AF_BLUETOOTH = 0x20
+ AF_CCITT = 0xa
+ AF_CHAOS = 0x5
+ AF_CNT = 0x15
+ AF_COIP = 0x14
+ AF_DATAKIT = 0x9
+ AF_DECnet = 0xc
+ AF_DLI = 0xd
+ AF_E164 = 0x1a
+ AF_ECMA = 0x8
+ AF_ENCAP = 0x1c
+ AF_HYLINK = 0xf
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x18
+ AF_IPX = 0x17
+ AF_ISDN = 0x1a
+ AF_ISO = 0x7
+ AF_KEY = 0x1e
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x24
+ AF_MPLS = 0x21
+ AF_NATM = 0x1b
+ AF_NS = 0x6
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_ROUTE = 0x11
+ AF_SIP = 0x1d
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ ARPHRD_ETHER = 0x1
+ ARPHRD_FRELAY = 0xf
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ BIOCFLUSH = 0x20004268
+ BIOCGBLEN = 0x40044266
+ BIOCGDIRFILT = 0x4004427c
+ BIOCGDLT = 0x4004426a
+ BIOCGDLTLIST = 0xc010427b
+ BIOCGETIF = 0x4020426b
+ BIOCGFILDROP = 0x40044278
+ BIOCGHDRCMPLT = 0x40044274
+ BIOCGRSIG = 0x40044273
+ BIOCGRTIMEOUT = 0x4010426e
+ BIOCGSTATS = 0x4008426f
+ BIOCIMMEDIATE = 0x80044270
+ BIOCLOCK = 0x20004276
+ BIOCPROMISC = 0x20004269
+ BIOCSBLEN = 0xc0044266
+ BIOCSDIRFILT = 0x8004427d
+ BIOCSDLT = 0x8004427a
+ BIOCSETF = 0x80104267
+ BIOCSETIF = 0x8020426c
+ BIOCSETWF = 0x80104277
+ BIOCSFILDROP = 0x80044279
+ BIOCSHDRCMPLT = 0x80044275
+ BIOCSRSIG = 0x80044272
+ BIOCSRTIMEOUT = 0x8010426d
+ BIOCVERSION = 0x40044271
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALIGNMENT = 0x4
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIRECTION_IN = 0x1
+ BPF_DIRECTION_OUT = 0x2
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXBUFSIZE = 0x200000
+ BPF_MAXINSNS = 0x200
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINBUFSIZE = 0x20
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RELEASE = 0x30bb6
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ CTL_MAXNAME = 0xc
+ CTL_NET = 0x4
+ DLT_ARCNET = 0x7
+ DLT_ATM_RFC1483 = 0xb
+ DLT_AX25 = 0x3
+ DLT_CHAOS = 0x5
+ DLT_EN10MB = 0x1
+ DLT_EN3MB = 0x2
+ DLT_ENC = 0xd
+ DLT_FDDI = 0xa
+ DLT_IEEE802 = 0x6
+ DLT_IEEE802_11 = 0x69
+ DLT_IEEE802_11_RADIO = 0x7f
+ DLT_LOOP = 0xc
+ DLT_MPLS = 0xdb
+ DLT_NULL = 0x0
+ DLT_PFLOG = 0x75
+ DLT_PFSYNC = 0x12
+ DLT_PPP = 0x9
+ DLT_PPP_BSDOS = 0x10
+ DLT_PPP_ETHER = 0x33
+ DLT_PRONET = 0x4
+ DLT_RAW = 0xe
+ DLT_SLIP = 0x8
+ DLT_SLIP_BSDOS = 0xf
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ ECHO = 0x8
+ ECHOCTL = 0x40
+ ECHOE = 0x2
+ ECHOK = 0x4
+ ECHOKE = 0x1
+ ECHONL = 0x10
+ ECHOPRT = 0x20
+ EFER_LMA = 0x400
+ EFER_LME = 0x100
+ EFER_NXE = 0x800
+ EFER_SCE = 0x1
+ EMT_TAGOVF = 0x1
+ EMUL_ENABLED = 0x1
+ EMUL_NATIVE = 0x2
+ ENDRUNDISC = 0x9
+ ETHERMIN = 0x2e
+ ETHERMTU = 0x5dc
+ ETHERTYPE_8023 = 0x4
+ ETHERTYPE_AARP = 0x80f3
+ ETHERTYPE_ACCTON = 0x8390
+ ETHERTYPE_AEONIC = 0x8036
+ ETHERTYPE_ALPHA = 0x814a
+ ETHERTYPE_AMBER = 0x6008
+ ETHERTYPE_AMOEBA = 0x8145
+ ETHERTYPE_AOE = 0x88a2
+ ETHERTYPE_APOLLO = 0x80f7
+ ETHERTYPE_APOLLODOMAIN = 0x8019
+ ETHERTYPE_APPLETALK = 0x809b
+ ETHERTYPE_APPLITEK = 0x80c7
+ ETHERTYPE_ARGONAUT = 0x803a
+ ETHERTYPE_ARP = 0x806
+ ETHERTYPE_AT = 0x809b
+ ETHERTYPE_ATALK = 0x809b
+ ETHERTYPE_ATOMIC = 0x86df
+ ETHERTYPE_ATT = 0x8069
+ ETHERTYPE_ATTSTANFORD = 0x8008
+ ETHERTYPE_AUTOPHON = 0x806a
+ ETHERTYPE_AXIS = 0x8856
+ ETHERTYPE_BCLOOP = 0x9003
+ ETHERTYPE_BOFL = 0x8102
+ ETHERTYPE_CABLETRON = 0x7034
+ ETHERTYPE_CHAOS = 0x804
+ ETHERTYPE_COMDESIGN = 0x806c
+ ETHERTYPE_COMPUGRAPHIC = 0x806d
+ ETHERTYPE_COUNTERPOINT = 0x8062
+ ETHERTYPE_CRONUS = 0x8004
+ ETHERTYPE_CRONUSVLN = 0x8003
+ ETHERTYPE_DCA = 0x1234
+ ETHERTYPE_DDE = 0x807b
+ ETHERTYPE_DEBNI = 0xaaaa
+ ETHERTYPE_DECAM = 0x8048
+ ETHERTYPE_DECCUST = 0x6006
+ ETHERTYPE_DECDIAG = 0x6005
+ ETHERTYPE_DECDNS = 0x803c
+ ETHERTYPE_DECDTS = 0x803e
+ ETHERTYPE_DECEXPER = 0x6000
+ ETHERTYPE_DECLAST = 0x8041
+ ETHERTYPE_DECLTM = 0x803f
+ ETHERTYPE_DECMUMPS = 0x6009
+ ETHERTYPE_DECNETBIOS = 0x8040
+ ETHERTYPE_DELTACON = 0x86de
+ ETHERTYPE_DIDDLE = 0x4321
+ ETHERTYPE_DLOG1 = 0x660
+ ETHERTYPE_DLOG2 = 0x661
+ ETHERTYPE_DN = 0x6003
+ ETHERTYPE_DOGFIGHT = 0x1989
+ ETHERTYPE_DSMD = 0x8039
+ ETHERTYPE_ECMA = 0x803
+ ETHERTYPE_ENCRYPT = 0x803d
+ ETHERTYPE_ES = 0x805d
+ ETHERTYPE_EXCELAN = 0x8010
+ ETHERTYPE_EXPERDATA = 0x8049
+ ETHERTYPE_FLIP = 0x8146
+ ETHERTYPE_FLOWCONTROL = 0x8808
+ ETHERTYPE_FRARP = 0x808
+ ETHERTYPE_GENDYN = 0x8068
+ ETHERTYPE_HAYES = 0x8130
+ ETHERTYPE_HIPPI_FP = 0x8180
+ ETHERTYPE_HITACHI = 0x8820
+ ETHERTYPE_HP = 0x8005
+ ETHERTYPE_IEEEPUP = 0xa00
+ ETHERTYPE_IEEEPUPAT = 0xa01
+ ETHERTYPE_IMLBL = 0x4c42
+ ETHERTYPE_IMLBLDIAG = 0x424c
+ ETHERTYPE_IP = 0x800
+ ETHERTYPE_IPAS = 0x876c
+ ETHERTYPE_IPV6 = 0x86dd
+ ETHERTYPE_IPX = 0x8137
+ ETHERTYPE_IPXNEW = 0x8037
+ ETHERTYPE_KALPANA = 0x8582
+ ETHERTYPE_LANBRIDGE = 0x8038
+ ETHERTYPE_LANPROBE = 0x8888
+ ETHERTYPE_LAT = 0x6004
+ ETHERTYPE_LBACK = 0x9000
+ ETHERTYPE_LITTLE = 0x8060
+ ETHERTYPE_LLDP = 0x88cc
+ ETHERTYPE_LOGICRAFT = 0x8148
+ ETHERTYPE_LOOPBACK = 0x9000
+ ETHERTYPE_MATRA = 0x807a
+ ETHERTYPE_MAX = 0xffff
+ ETHERTYPE_MERIT = 0x807c
+ ETHERTYPE_MICP = 0x873a
+ ETHERTYPE_MOPDL = 0x6001
+ ETHERTYPE_MOPRC = 0x6002
+ ETHERTYPE_MOTOROLA = 0x818d
+ ETHERTYPE_MPLS = 0x8847
+ ETHERTYPE_MPLS_MCAST = 0x8848
+ ETHERTYPE_MUMPS = 0x813f
+ ETHERTYPE_NBPCC = 0x3c04
+ ETHERTYPE_NBPCLAIM = 0x3c09
+ ETHERTYPE_NBPCLREQ = 0x3c05
+ ETHERTYPE_NBPCLRSP = 0x3c06
+ ETHERTYPE_NBPCREQ = 0x3c02
+ ETHERTYPE_NBPCRSP = 0x3c03
+ ETHERTYPE_NBPDG = 0x3c07
+ ETHERTYPE_NBPDGB = 0x3c08
+ ETHERTYPE_NBPDLTE = 0x3c0a
+ ETHERTYPE_NBPRAR = 0x3c0c
+ ETHERTYPE_NBPRAS = 0x3c0b
+ ETHERTYPE_NBPRST = 0x3c0d
+ ETHERTYPE_NBPSCD = 0x3c01
+ ETHERTYPE_NBPVCD = 0x3c00
+ ETHERTYPE_NBS = 0x802
+ ETHERTYPE_NCD = 0x8149
+ ETHERTYPE_NESTAR = 0x8006
+ ETHERTYPE_NETBEUI = 0x8191
+ ETHERTYPE_NOVELL = 0x8138
+ ETHERTYPE_NS = 0x600
+ ETHERTYPE_NSAT = 0x601
+ ETHERTYPE_NSCOMPAT = 0x807
+ ETHERTYPE_NTRAILER = 0x10
+ ETHERTYPE_OS9 = 0x7007
+ ETHERTYPE_OS9NET = 0x7009
+ ETHERTYPE_PACER = 0x80c6
+ ETHERTYPE_PAE = 0x888e
+ ETHERTYPE_PCS = 0x4242
+ ETHERTYPE_PLANNING = 0x8044
+ ETHERTYPE_PPP = 0x880b
+ ETHERTYPE_PPPOE = 0x8864
+ ETHERTYPE_PPPOEDISC = 0x8863
+ ETHERTYPE_PRIMENTS = 0x7031
+ ETHERTYPE_PUP = 0x200
+ ETHERTYPE_PUPAT = 0x200
+ ETHERTYPE_QINQ = 0x88a8
+ ETHERTYPE_RACAL = 0x7030
+ ETHERTYPE_RATIONAL = 0x8150
+ ETHERTYPE_RAWFR = 0x6559
+ ETHERTYPE_RCL = 0x1995
+ ETHERTYPE_RDP = 0x8739
+ ETHERTYPE_RETIX = 0x80f2
+ ETHERTYPE_REVARP = 0x8035
+ ETHERTYPE_SCA = 0x6007
+ ETHERTYPE_SECTRA = 0x86db
+ ETHERTYPE_SECUREDATA = 0x876d
+ ETHERTYPE_SGITW = 0x817e
+ ETHERTYPE_SG_BOUNCE = 0x8016
+ ETHERTYPE_SG_DIAG = 0x8013
+ ETHERTYPE_SG_NETGAMES = 0x8014
+ ETHERTYPE_SG_RESV = 0x8015
+ ETHERTYPE_SIMNET = 0x5208
+ ETHERTYPE_SLOW = 0x8809
+ ETHERTYPE_SNA = 0x80d5
+ ETHERTYPE_SNMP = 0x814c
+ ETHERTYPE_SONIX = 0xfaf5
+ ETHERTYPE_SPIDER = 0x809f
+ ETHERTYPE_SPRITE = 0x500
+ ETHERTYPE_STP = 0x8181
+ ETHERTYPE_TALARIS = 0x812b
+ ETHERTYPE_TALARISMC = 0x852b
+ ETHERTYPE_TCPCOMP = 0x876b
+ ETHERTYPE_TCPSM = 0x9002
+ ETHERTYPE_TEC = 0x814f
+ ETHERTYPE_TIGAN = 0x802f
+ ETHERTYPE_TRAIL = 0x1000
+ ETHERTYPE_TRANSETHER = 0x6558
+ ETHERTYPE_TYMSHARE = 0x802e
+ ETHERTYPE_UBBST = 0x7005
+ ETHERTYPE_UBDEBUG = 0x900
+ ETHERTYPE_UBDIAGLOOP = 0x7002
+ ETHERTYPE_UBDL = 0x7000
+ ETHERTYPE_UBNIU = 0x7001
+ ETHERTYPE_UBNMC = 0x7003
+ ETHERTYPE_VALID = 0x1600
+ ETHERTYPE_VARIAN = 0x80dd
+ ETHERTYPE_VAXELN = 0x803b
+ ETHERTYPE_VEECO = 0x8067
+ ETHERTYPE_VEXP = 0x805b
+ ETHERTYPE_VGLAB = 0x8131
+ ETHERTYPE_VINES = 0xbad
+ ETHERTYPE_VINESECHO = 0xbaf
+ ETHERTYPE_VINESLOOP = 0xbae
+ ETHERTYPE_VITAL = 0xff00
+ ETHERTYPE_VLAN = 0x8100
+ ETHERTYPE_VLTLMAN = 0x8080
+ ETHERTYPE_VPROD = 0x805c
+ ETHERTYPE_VURESERVED = 0x8147
+ ETHERTYPE_WATERLOO = 0x8130
+ ETHERTYPE_WELLFLEET = 0x8103
+ ETHERTYPE_X25 = 0x805
+ ETHERTYPE_X75 = 0x801
+ ETHERTYPE_XNSSM = 0x9001
+ ETHERTYPE_XTP = 0x817d
+ ETHER_ADDR_LEN = 0x6
+ ETHER_ALIGN = 0x2
+ ETHER_CRC_LEN = 0x4
+ ETHER_CRC_POLY_BE = 0x4c11db6
+ ETHER_CRC_POLY_LE = 0xedb88320
+ ETHER_HDR_LEN = 0xe
+ ETHER_MAX_DIX_LEN = 0x600
+ ETHER_MAX_LEN = 0x5ee
+ ETHER_MIN_LEN = 0x40
+ ETHER_TYPE_LEN = 0x2
+ ETHER_VLAN_ENCAP_LEN = 0x4
+ EVFILT_AIO = -0x3
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0x7
+ EVFILT_TIMER = -0x7
+ EVFILT_VNODE = -0x4
+ EVFILT_WRITE = -0x2
+ EV_ADD = 0x1
+ EV_CLEAR = 0x20
+ EV_DELETE = 0x2
+ EV_DISABLE = 0x8
+ EV_ENABLE = 0x4
+ EV_EOF = 0x8000
+ EV_ERROR = 0x4000
+ EV_FLAG1 = 0x2000
+ EV_ONESHOT = 0x10
+ EV_SYSFLAGS = 0xf000
+ EXTA = 0x4b00
+ EXTB = 0x9600
+ EXTPROC = 0x800
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0xa
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0x7
+ F_GETOWN = 0x5
+ F_OK = 0x0
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0x8
+ F_SETLKW = 0x9
+ F_SETOWN = 0x6
+ F_UNLCK = 0x2
+ F_WRLCK = 0x3
+ IFA_ROUTE = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_BROADCAST = 0x2
+ IFF_CANTCHANGE = 0x8e52
+ IFF_DEBUG = 0x4
+ IFF_LINK0 = 0x1000
+ IFF_LINK1 = 0x2000
+ IFF_LINK2 = 0x4000
+ IFF_LOOPBACK = 0x8
+ IFF_MULTICAST = 0x8000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_OACTIVE = 0x400
+ IFF_POINTOPOINT = 0x10
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SIMPLEX = 0x800
+ IFF_UP = 0x1
+ IFNAMSIZ = 0x10
+ IFT_1822 = 0x2
+ IFT_A12MPPSWITCH = 0x82
+ IFT_AAL2 = 0xbb
+ IFT_AAL5 = 0x31
+ IFT_ADSL = 0x5e
+ IFT_AFLANE8023 = 0x3b
+ IFT_AFLANE8025 = 0x3c
+ IFT_ARAP = 0x58
+ IFT_ARCNET = 0x23
+ IFT_ARCNETPLUS = 0x24
+ IFT_ASYNC = 0x54
+ IFT_ATM = 0x25
+ IFT_ATMDXI = 0x69
+ IFT_ATMFUNI = 0x6a
+ IFT_ATMIMA = 0x6b
+ IFT_ATMLOGICAL = 0x50
+ IFT_ATMRADIO = 0xbd
+ IFT_ATMSUBINTERFACE = 0x86
+ IFT_ATMVCIENDPT = 0xc2
+ IFT_ATMVIRTUAL = 0x95
+ IFT_BGPPOLICYACCOUNTING = 0xa2
+ IFT_BLUETOOTH = 0xf8
+ IFT_BRIDGE = 0xd1
+ IFT_BSC = 0x53
+ IFT_CARP = 0xf7
+ IFT_CCTEMUL = 0x3d
+ IFT_CEPT = 0x13
+ IFT_CES = 0x85
+ IFT_CHANNEL = 0x46
+ IFT_CNR = 0x55
+ IFT_COFFEE = 0x84
+ IFT_COMPOSITELINK = 0x9b
+ IFT_DCN = 0x8d
+ IFT_DIGITALPOWERLINE = 0x8a
+ IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+ IFT_DLSW = 0x4a
+ IFT_DOCSCABLEDOWNSTREAM = 0x80
+ IFT_DOCSCABLEMACLAYER = 0x7f
+ IFT_DOCSCABLEUPSTREAM = 0x81
+ IFT_DOCSCABLEUPSTREAMCHANNEL = 0xcd
+ IFT_DS0 = 0x51
+ IFT_DS0BUNDLE = 0x52
+ IFT_DS1FDL = 0xaa
+ IFT_DS3 = 0x1e
+ IFT_DTM = 0x8c
+ IFT_DUMMY = 0xf1
+ IFT_DVBASILN = 0xac
+ IFT_DVBASIOUT = 0xad
+ IFT_DVBRCCDOWNSTREAM = 0x93
+ IFT_DVBRCCMACLAYER = 0x92
+ IFT_DVBRCCUPSTREAM = 0x94
+ IFT_ECONET = 0xce
+ IFT_ENC = 0xf4
+ IFT_EON = 0x19
+ IFT_EPLRS = 0x57
+ IFT_ESCON = 0x49
+ IFT_ETHER = 0x6
+ IFT_FAITH = 0xf3
+ IFT_FAST = 0x7d
+ IFT_FASTETHER = 0x3e
+ IFT_FASTETHERFX = 0x45
+ IFT_FDDI = 0xf
+ IFT_FIBRECHANNEL = 0x38
+ IFT_FRAMERELAYINTERCONNECT = 0x3a
+ IFT_FRAMERELAYMPI = 0x5c
+ IFT_FRDLCIENDPT = 0xc1
+ IFT_FRELAY = 0x20
+ IFT_FRELAYDCE = 0x2c
+ IFT_FRF16MFRBUNDLE = 0xa3
+ IFT_FRFORWARD = 0x9e
+ IFT_G703AT2MB = 0x43
+ IFT_G703AT64K = 0x42
+ IFT_GIF = 0xf0
+ IFT_GIGABITETHERNET = 0x75
+ IFT_GR303IDT = 0xb2
+ IFT_GR303RDT = 0xb1
+ IFT_H323GATEKEEPER = 0xa4
+ IFT_H323PROXY = 0xa5
+ IFT_HDH1822 = 0x3
+ IFT_HDLC = 0x76
+ IFT_HDSL2 = 0xa8
+ IFT_HIPERLAN2 = 0xb7
+ IFT_HIPPI = 0x2f
+ IFT_HIPPIINTERFACE = 0x39
+ IFT_HOSTPAD = 0x5a
+ IFT_HSSI = 0x2e
+ IFT_HY = 0xe
+ IFT_IBM370PARCHAN = 0x48
+ IFT_IDSL = 0x9a
+ IFT_IEEE1394 = 0x90
+ IFT_IEEE80211 = 0x47
+ IFT_IEEE80212 = 0x37
+ IFT_IEEE8023ADLAG = 0xa1
+ IFT_IFGSN = 0x91
+ IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
+ IFT_INTERLEAVE = 0x7c
+ IFT_IP = 0x7e
+ IFT_IPFORWARD = 0x8e
+ IFT_IPOVERATM = 0x72
+ IFT_IPOVERCDLC = 0x6d
+ IFT_IPOVERCLAW = 0x6e
+ IFT_IPSWITCH = 0x4e
+ IFT_ISDN = 0x3f
+ IFT_ISDNBASIC = 0x14
+ IFT_ISDNPRIMARY = 0x15
+ IFT_ISDNS = 0x4b
+ IFT_ISDNU = 0x4c
+ IFT_ISO88022LLC = 0x29
+ IFT_ISO88023 = 0x7
+ IFT_ISO88024 = 0x8
+ IFT_ISO88025 = 0x9
+ IFT_ISO88025CRFPINT = 0x62
+ IFT_ISO88025DTR = 0x56
+ IFT_ISO88025FIBER = 0x73
+ IFT_ISO88026 = 0xa
+ IFT_ISUP = 0xb3
+ IFT_L2VLAN = 0x87
+ IFT_L3IPVLAN = 0x88
+ IFT_L3IPXVLAN = 0x89
+ IFT_LAPB = 0x10
+ IFT_LAPD = 0x4d
+ IFT_LAPF = 0x77
+ IFT_LINEGROUP = 0xd2
+ IFT_LOCALTALK = 0x2a
+ IFT_LOOP = 0x18
+ IFT_MEDIAMAILOVERIP = 0x8b
+ IFT_MFSIGLINK = 0xa7
+ IFT_MIOX25 = 0x26
+ IFT_MODEM = 0x30
+ IFT_MPC = 0x71
+ IFT_MPLS = 0xa6
+ IFT_MPLSTUNNEL = 0x96
+ IFT_MSDSL = 0x8f
+ IFT_MVL = 0xbf
+ IFT_MYRINET = 0x63
+ IFT_NFAS = 0xaf
+ IFT_NSIP = 0x1b
+ IFT_OPTICALCHANNEL = 0xc3
+ IFT_OPTICALTRANSPORT = 0xc4
+ IFT_OTHER = 0x1
+ IFT_P10 = 0xc
+ IFT_P80 = 0xd
+ IFT_PARA = 0x22
+ IFT_PFLOG = 0xf5
+ IFT_PFLOW = 0xf9
+ IFT_PFSYNC = 0xf6
+ IFT_PLC = 0xae
+ IFT_PON155 = 0xcf
+ IFT_PON622 = 0xd0
+ IFT_POS = 0xab
+ IFT_PPP = 0x17
+ IFT_PPPMULTILINKBUNDLE = 0x6c
+ IFT_PROPATM = 0xc5
+ IFT_PROPBWAP2MP = 0xb8
+ IFT_PROPCNLS = 0x59
+ IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
+ IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
+ IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
+ IFT_PROPMUX = 0x36
+ IFT_PROPVIRTUAL = 0x35
+ IFT_PROPWIRELESSP2P = 0x9d
+ IFT_PTPSERIAL = 0x16
+ IFT_PVC = 0xf2
+ IFT_Q2931 = 0xc9
+ IFT_QLLC = 0x44
+ IFT_RADIOMAC = 0xbc
+ IFT_RADSL = 0x5f
+ IFT_REACHDSL = 0xc0
+ IFT_RFC1483 = 0x9f
+ IFT_RS232 = 0x21
+ IFT_RSRB = 0x4f
+ IFT_SDLC = 0x11
+ IFT_SDSL = 0x60
+ IFT_SHDSL = 0xa9
+ IFT_SIP = 0x1f
+ IFT_SIPSIG = 0xcc
+ IFT_SIPTG = 0xcb
+ IFT_SLIP = 0x1c
+ IFT_SMDSDXI = 0x2b
+ IFT_SMDSICIP = 0x34
+ IFT_SONET = 0x27
+ IFT_SONETOVERHEADCHANNEL = 0xb9
+ IFT_SONETPATH = 0x32
+ IFT_SONETVT = 0x33
+ IFT_SRP = 0x97
+ IFT_SS7SIGLINK = 0x9c
+ IFT_STACKTOSTACK = 0x6f
+ IFT_STARLAN = 0xb
+ IFT_T1 = 0x12
+ IFT_TDLC = 0x74
+ IFT_TELINK = 0xc8
+ IFT_TERMPAD = 0x5b
+ IFT_TR008 = 0xb0
+ IFT_TRANSPHDLC = 0x7b
+ IFT_TUNNEL = 0x83
+ IFT_ULTRA = 0x1d
+ IFT_USB = 0xa0
+ IFT_V11 = 0x40
+ IFT_V35 = 0x2d
+ IFT_V36 = 0x41
+ IFT_V37 = 0x78
+ IFT_VDSL = 0x61
+ IFT_VIRTUALIPADDRESS = 0x70
+ IFT_VIRTUALTG = 0xca
+ IFT_VOICEDID = 0xd5
+ IFT_VOICEEM = 0x64
+ IFT_VOICEEMFGD = 0xd3
+ IFT_VOICEENCAP = 0x67
+ IFT_VOICEFGDEANA = 0xd4
+ IFT_VOICEFXO = 0x65
+ IFT_VOICEFXS = 0x66
+ IFT_VOICEOVERATM = 0x98
+ IFT_VOICEOVERCABLE = 0xc6
+ IFT_VOICEOVERFRAMERELAY = 0x99
+ IFT_VOICEOVERIP = 0x68
+ IFT_X213 = 0x5d
+ IFT_X25 = 0x5
+ IFT_X25DDN = 0x4
+ IFT_X25HUNTGROUP = 0x7a
+ IFT_X25MLP = 0x79
+ IFT_X25PLE = 0x28
+ IFT_XETHER = 0x1a
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLASSD_HOST = 0xfffffff
+ IN_CLASSD_NET = 0xf0000000
+ IN_CLASSD_NSHIFT = 0x1c
+ IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_HOST = 0x1
+ IN_RFC3021_NET = 0xfffffffe
+ IN_RFC3021_NSHIFT = 0x1f
+ IPPROTO_AH = 0x33
+ IPPROTO_CARP = 0x70
+ IPPROTO_DIVERT = 0x102
+ IPPROTO_DONE = 0x101
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_EON = 0x50
+ IPPROTO_ESP = 0x32
+ IPPROTO_ETHERIP = 0x61
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GGP = 0x3
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPCOMP = 0x6c
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV4 = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MAX = 0x100
+ IPPROTO_MAXID = 0x103
+ IPPROTO_MOBILE = 0x37
+ IPPROTO_MPLS = 0x89
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PFSYNC = 0xf0
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPV6_AUTH_LEVEL = 0x35
+ IPV6_AUTOFLOWLABEL = 0x3b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DONTFRAG = 0x3e
+ IPV6_DSTOPTS = 0x32
+ IPV6_ESP_NETWORK_LEVEL = 0x37
+ IPV6_ESP_TRANS_LEVEL = 0x36
+ IPV6_FAITH = 0x1d
+ IPV6_FLOWINFO_MASK = 0xffffff0f
+ IPV6_FLOWLABEL_MASK = 0xffff0f00
+ IPV6_FRAGTTL = 0x78
+ IPV6_HLIMDEC = 0x1
+ IPV6_HOPLIMIT = 0x2f
+ IPV6_HOPOPTS = 0x31
+ IPV6_IPCOMP_LEVEL = 0x3c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_OPTIONS = 0x1
+ IPV6_PATHMTU = 0x2c
+ IPV6_PIPEX = 0x3f
+ IPV6_PKTINFO = 0x2e
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0x0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x25
+ IPV6_RECVHOPOPTS = 0x27
+ IPV6_RECVPATHMTU = 0x2b
+ IPV6_RECVPKTINFO = 0x24
+ IPV6_RECVRTHDR = 0x26
+ IPV6_RECVTCLASS = 0x39
+ IPV6_RTABLE = 0x1021
+ IPV6_RTHDR = 0x33
+ IPV6_RTHDRDSTOPTS = 0x23
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_SOCKOPT_RESERVED1 = 0x3
+ IPV6_TCLASS = 0x3d
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_USE_MIN_MTU = 0x2a
+ IPV6_V6ONLY = 0x1b
+ IPV6_VERSION = 0x60
+ IPV6_VERSION_MASK = 0xf0
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_AUTH_LEVEL = 0x14
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_ESP_NETWORK_LEVEL = 0x16
+ IP_ESP_TRANS_LEVEL = 0x15
+ IP_HDRINCL = 0x2
+ IP_IPCOMP_LEVEL = 0x1d
+ IP_IPSEC_LOCAL_AUTH = 0x1b
+ IP_IPSEC_LOCAL_CRED = 0x19
+ IP_IPSEC_LOCAL_ID = 0x17
+ IP_IPSEC_REMOTE_AUTH = 0x1c
+ IP_IPSEC_REMOTE_CRED = 0x1a
+ IP_IPSEC_REMOTE_ID = 0x18
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MF = 0x2000
+ IP_MINTTL = 0x20
+ IP_MIN_MEMBERSHIPS = 0xf
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x1
+ IP_PIPEX = 0x22
+ IP_PORTRANGE = 0x13
+ IP_PORTRANGE_DEFAULT = 0x0
+ IP_PORTRANGE_HIGH = 0x1
+ IP_PORTRANGE_LOW = 0x2
+ IP_RECVDSTADDR = 0x7
+ IP_RECVDSTPORT = 0x21
+ IP_RECVIF = 0x1e
+ IP_RECVOPTS = 0x5
+ IP_RECVRETOPTS = 0x6
+ IP_RECVRTABLE = 0x23
+ IP_RECVTTL = 0x1f
+ IP_RETOPTS = 0x8
+ IP_RF = 0x8000
+ IP_RTABLE = 0x1021
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MAP_ET_KVAGUARD = 0x10
+ MSG_BCAST = 0x100
+ MSG_CTRUNC = 0x20
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x80
+ MSG_EOR = 0x8
+ MSG_MCAST = 0x200
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_TRUNC = 0x10
+ MSG_WAITALL = 0x40
+ NAME_MAX = 0xff
+ NET_RT_DUMP = 0x1
+ NET_RT_FLAGS = 0x2
+ NET_RT_IFLIST = 0x3
+ NET_RT_MAXID = 0x6
+ NET_RT_STATS = 0x4
+ NET_RT_TABLE = 0x5
+ NOTE_ATTRIB = 0x8
+ NOTE_CHILD = 0x4
+ NOTE_DELETE = 0x1
+ NOTE_EOF = 0x2
+ NOTE_EXEC = 0x20000000
+ NOTE_EXIT = 0x80000000
+ NOTE_EXTEND = 0x4
+ NOTE_FORK = 0x40000000
+ NOTE_LINK = 0x10
+ NOTE_LOWAT = 0x1
+ NOTE_PCTRLMASK = 0xf0000000
+ NOTE_PDATAMASK = 0xfffff
+ NOTE_RENAME = 0x20
+ NOTE_REVOKE = 0x40
+ NOTE_TRACK = 0x1
+ NOTE_TRACKERR = 0x2
+ NOTE_TRUNCATE = 0x80
+ NOTE_WRITE = 0x2
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CLOEXEC = 0x10000
+ O_CREAT = 0x200
+ O_DIRECTORY = 0x20000
+ O_DSYNC = 0x80
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x8000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x80
+ O_SHLOCK = 0x10
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x8
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = 0x7fffffffffffffff
+ RTAX_AUTHOR = 0x6
+ RTAX_BRD = 0x7
+ RTAX_DST = 0x0
+ RTAX_GATEWAY = 0x1
+ RTAX_GENMASK = 0x3
+ RTAX_IFA = 0x5
+ RTAX_IFP = 0x4
+ RTAX_LABEL = 0xa
+ RTAX_MAX = 0xb
+ RTAX_NETMASK = 0x2
+ RTAX_SRC = 0x8
+ RTAX_SRCMASK = 0x9
+ RTA_AUTHOR = 0x40
+ RTA_BRD = 0x80
+ RTA_DST = 0x1
+ RTA_GATEWAY = 0x2
+ RTA_GENMASK = 0x8
+ RTA_IFA = 0x20
+ RTA_IFP = 0x10
+ RTA_LABEL = 0x400
+ RTA_NETMASK = 0x4
+ RTA_SRC = 0x100
+ RTA_SRCMASK = 0x200
+ RTF_ANNOUNCE = 0x4000
+ RTF_BLACKHOLE = 0x1000
+ RTF_CLONED = 0x10000
+ RTF_CLONING = 0x100
+ RTF_DONE = 0x40
+ RTF_DYNAMIC = 0x10
+ RTF_FMASK = 0x8f808
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_JUMBO = 0x80000
+ RTF_LLINFO = 0x400
+ RTF_MASK = 0x80
+ RTF_MODIFIED = 0x20
+ RTF_MPATH = 0x40000
+ RTF_MPLS = 0x100000
+ RTF_PERMANENT_ARP = 0x2000
+ RTF_PROTO1 = 0x8000
+ RTF_PROTO2 = 0x4000
+ RTF_PROTO3 = 0x2000
+ RTF_REJECT = 0x8
+ RTF_SOURCE = 0x20000
+ RTF_STATIC = 0x800
+ RTF_TUNNEL = 0x100000
+ RTF_UP = 0x1
+ RTF_USETRAILERS = 0x8000
+ RTF_XRESOLVE = 0x200
+ RTM_ADD = 0x1
+ RTM_CHANGE = 0x3
+ RTM_DELADDR = 0xd
+ RTM_DELETE = 0x2
+ RTM_DESYNC = 0x10
+ RTM_GET = 0x4
+ RTM_IFANNOUNCE = 0xf
+ RTM_IFINFO = 0xe
+ RTM_LOCK = 0x8
+ RTM_LOSING = 0x5
+ RTM_MAXSIZE = 0x800
+ RTM_MISS = 0x7
+ RTM_NEWADDR = 0xc
+ RTM_REDIRECT = 0x6
+ RTM_RESOLVE = 0xb
+ RTM_RTTUNIT = 0xf4240
+ RTM_VERSION = 0x4
+ RTV_EXPIRE = 0x4
+ RTV_HOPCOUNT = 0x2
+ RTV_MTU = 0x1
+ RTV_RPIPE = 0x8
+ RTV_RTT = 0x40
+ RTV_RTTVAR = 0x80
+ RTV_SPIPE = 0x10
+ RTV_SSTHRESH = 0x20
+ RT_TABLEID_MAX = 0xff
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x4
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDMULTI = 0x80206931
+ SIOCAIFADDR = 0x8040691a
+ SIOCAIFGROUP = 0x80286987
+ SIOCALIFADDR = 0x8218691c
+ SIOCATMARK = 0x40047307
+ SIOCBRDGADD = 0x8058693c
+ SIOCBRDGADDS = 0x80586941
+ SIOCBRDGARL = 0x806e694d
+ SIOCBRDGDADDR = 0x80286947
+ SIOCBRDGDEL = 0x8058693d
+ SIOCBRDGDELS = 0x80586942
+ SIOCBRDGFLUSH = 0x80586948
+ SIOCBRDGFRL = 0x806e694e
+ SIOCBRDGGCACHE = 0xc0146941
+ SIOCBRDGGFD = 0xc0146952
+ SIOCBRDGGHT = 0xc0146951
+ SIOCBRDGGIFFLGS = 0xc058693e
+ SIOCBRDGGMA = 0xc0146953
+ SIOCBRDGGPARAM = 0xc0406958
+ SIOCBRDGGPRI = 0xc0146950
+ SIOCBRDGGRL = 0xc030694f
+ SIOCBRDGGSIFS = 0xc058693c
+ SIOCBRDGGTO = 0xc0146946
+ SIOCBRDGIFS = 0xc0586942
+ SIOCBRDGRTS = 0xc0206943
+ SIOCBRDGSADDR = 0xc0286944
+ SIOCBRDGSCACHE = 0x80146940
+ SIOCBRDGSFD = 0x80146952
+ SIOCBRDGSHT = 0x80146951
+ SIOCBRDGSIFCOST = 0x80586955
+ SIOCBRDGSIFFLGS = 0x8058693f
+ SIOCBRDGSIFPRIO = 0x80586954
+ SIOCBRDGSMA = 0x80146953
+ SIOCBRDGSPRI = 0x80146950
+ SIOCBRDGSPROTO = 0x8014695a
+ SIOCBRDGSTO = 0x80146945
+ SIOCBRDGSTXHC = 0x80146959
+ SIOCDELMULTI = 0x80206932
+ SIOCDIFADDR = 0x80206919
+ SIOCDIFGROUP = 0x80286989
+ SIOCDIFPHYADDR = 0x80206949
+ SIOCDLIFADDR = 0x8218691e
+ SIOCGETKALIVE = 0xc01869a4
+ SIOCGETLABEL = 0x8020699a
+ SIOCGETPFLOW = 0xc02069fe
+ SIOCGETPFSYNC = 0xc02069f8
+ SIOCGETSGCNT = 0xc0207534
+ SIOCGETVIFCNT = 0xc0287533
+ SIOCGETVLANPRIO = 0xc0206990
+ SIOCGHIWAT = 0x40047301
+ SIOCGIFADDR = 0xc0206921
+ SIOCGIFASYNCMAP = 0xc020697c
+ SIOCGIFBRDADDR = 0xc0206923
+ SIOCGIFCONF = 0xc0106924
+ SIOCGIFDATA = 0xc020691b
+ SIOCGIFDESCR = 0xc0206981
+ SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFLAGS = 0xc0206911
+ SIOCGIFGATTR = 0xc028698b
+ SIOCGIFGENERIC = 0xc020693a
+ SIOCGIFGMEMB = 0xc028698a
+ SIOCGIFGROUP = 0xc0286988
+ SIOCGIFMEDIA = 0xc0306936
+ SIOCGIFMETRIC = 0xc0206917
+ SIOCGIFMTU = 0xc020697e
+ SIOCGIFNETMASK = 0xc0206925
+ SIOCGIFPDSTADDR = 0xc0206948
+ SIOCGIFPRIORITY = 0xc020699c
+ SIOCGIFPSRCADDR = 0xc0206947
+ SIOCGIFRDOMAIN = 0xc02069a0
+ SIOCGIFRTLABEL = 0xc0206983
+ SIOCGIFTIMESLOT = 0xc0206986
+ SIOCGIFXFLAGS = 0xc020699e
+ SIOCGLIFADDR = 0xc218691d
+ SIOCGLIFPHYADDR = 0xc218694b
+ SIOCGLIFPHYRTABLE = 0xc02069a2
+ SIOCGLOWAT = 0x40047303
+ SIOCGPGRP = 0x40047309
+ SIOCGVH = 0xc02069f6
+ SIOCIFCREATE = 0x8020697a
+ SIOCIFDESTROY = 0x80206979
+ SIOCIFGCLONERS = 0xc0106978
+ SIOCSETKALIVE = 0x801869a3
+ SIOCSETLABEL = 0x80206999
+ SIOCSETPFLOW = 0x802069fd
+ SIOCSETPFSYNC = 0x802069f7
+ SIOCSETVLANPRIO = 0x8020698f
+ SIOCSHIWAT = 0x80047300
+ SIOCSIFADDR = 0x8020690c
+ SIOCSIFASYNCMAP = 0x8020697d
+ SIOCSIFBRDADDR = 0x80206913
+ SIOCSIFDESCR = 0x80206980
+ SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFLAGS = 0x80206910
+ SIOCSIFGATTR = 0x8028698c
+ SIOCSIFGENERIC = 0x80206939
+ SIOCSIFLLADDR = 0x8020691f
+ SIOCSIFMEDIA = 0xc0206935
+ SIOCSIFMETRIC = 0x80206918
+ SIOCSIFMTU = 0x8020697f
+ SIOCSIFNETMASK = 0x80206916
+ SIOCSIFPHYADDR = 0x80406946
+ SIOCSIFPRIORITY = 0x8020699b
+ SIOCSIFRDOMAIN = 0x8020699f
+ SIOCSIFRTLABEL = 0x80206982
+ SIOCSIFTIMESLOT = 0x80206985
+ SIOCSIFXFLAGS = 0x8020699d
+ SIOCSLIFPHYADDR = 0x8218694a
+ SIOCSLIFPHYRTABLE = 0x802069a1
+ SIOCSLOWAT = 0x80047302
+ SIOCSPGRP = 0x80047308
+ SIOCSVH = 0xc02069f5
+ SOCK_DGRAM = 0x2
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x1
+ SOL_SOCKET = 0xffff
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x2
+ SO_BINDANY = 0x1000
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_JUMBO = 0x400
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_NETPROC = 0x1020
+ SO_OOBINLINE = 0x100
+ SO_PEERCRED = 0x1022
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RTABLE = 0x1021
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_SPLICE = 0x1023
+ SO_TIMESTAMP = 0x800
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ TCP_MAXBURST = 0x4
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x3
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0x4
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NSTATES = 0xb
+ TCP_SACK_ENABLE = 0x8
+ TIOCCBRK = 0x2000747a
+ TIOCCDTR = 0x20007478
+ TIOCCONS = 0x80047462
+ TIOCDRAIN = 0x2000745e
+ TIOCEXCL = 0x2000740d
+ TIOCEXT = 0x80047460
+ TIOCFLAG_CLOCAL = 0x2
+ TIOCFLAG_CRTSCTS = 0x4
+ TIOCFLAG_MDMBUF = 0x8
+ TIOCFLAG_PPS = 0x10
+ TIOCFLAG_SOFTCAR = 0x1
+ TIOCFLUSH = 0x80047410
+ TIOCGETA = 0x402c7413
+ TIOCGETD = 0x4004741a
+ TIOCGFLAGS = 0x4004745d
+ TIOCGPGRP = 0x40047477
+ TIOCGTSTAMP = 0x4010745b
+ TIOCGWINSZ = 0x40087468
+ TIOCMBIC = 0x8004746b
+ TIOCMBIS = 0x8004746c
+ TIOCMGET = 0x4004746a
+ TIOCMODG = 0x4004746a
+ TIOCMODS = 0x8004746d
+ TIOCMSET = 0x8004746d
+ TIOCM_CAR = 0x40
+ TIOCM_CD = 0x40
+ TIOCM_CTS = 0x20
+ TIOCM_DSR = 0x100
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x80
+ TIOCM_RNG = 0x80
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x10
+ TIOCM_ST = 0x8
+ TIOCNOTTY = 0x20007471
+ TIOCNXCL = 0x2000740e
+ TIOCOUTQ = 0x40047473
+ TIOCPKT = 0x80047470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCREMOTE = 0x80047469
+ TIOCSBRK = 0x2000747b
+ TIOCSCTTY = 0x20007461
+ TIOCSDTR = 0x20007479
+ TIOCSETA = 0x802c7414
+ TIOCSETAF = 0x802c7416
+ TIOCSETAW = 0x802c7415
+ TIOCSETD = 0x8004741b
+ TIOCSFLAGS = 0x8004745c
+ TIOCSIG = 0x8004745f
+ TIOCSPGRP = 0x80047476
+ TIOCSTART = 0x2000746e
+ TIOCSTAT = 0x80047465
+ TIOCSTI = 0x80017472
+ TIOCSTOP = 0x2000746f
+ TIOCSTSTAMP = 0x8008745a
+ TIOCSWINSZ = 0x80087467
+ TIOCUCNTL = 0x80047466
+ WALTSIG = 0x4
+ WCONTINUED = 0x8
+ WCOREFLAG = 0x80
+ WNOHANG = 0x1
+ WSTOPPED = 0x7f
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x30)
+ EADDRNOTAVAIL = Errno(0x31)
+ EAFNOSUPPORT = Errno(0x2f)
+ EAGAIN = Errno(0x23)
+ EALREADY = Errno(0x25)
+ EAUTH = Errno(0x50)
+ EBADF = Errno(0x9)
+ EBADRPC = Errno(0x48)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x58)
+ ECHILD = Errno(0xa)
+ ECONNABORTED = Errno(0x35)
+ ECONNREFUSED = Errno(0x3d)
+ ECONNRESET = Errno(0x36)
+ EDEADLK = Errno(0xb)
+ EDESTADDRREQ = Errno(0x27)
+ EDOM = Errno(0x21)
+ EDQUOT = Errno(0x45)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EFTYPE = Errno(0x4f)
+ EHOSTDOWN = Errno(0x40)
+ EHOSTUNREACH = Errno(0x41)
+ EIDRM = Errno(0x59)
+ EILSEQ = Errno(0x54)
+ EINPROGRESS = Errno(0x24)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EIPSEC = Errno(0x52)
+ EISCONN = Errno(0x38)
+ EISDIR = Errno(0x15)
+ ELAST = Errno(0x5b)
+ ELOOP = Errno(0x3e)
+ EMEDIUMTYPE = Errno(0x56)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x28)
+ ENAMETOOLONG = Errno(0x3f)
+ ENEEDAUTH = Errno(0x51)
+ ENETDOWN = Errno(0x32)
+ ENETRESET = Errno(0x34)
+ ENETUNREACH = Errno(0x33)
+ ENFILE = Errno(0x17)
+ ENOATTR = Errno(0x53)
+ ENOBUFS = Errno(0x37)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOLCK = Errno(0x4d)
+ ENOMEDIUM = Errno(0x55)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x5a)
+ ENOPROTOOPT = Errno(0x2a)
+ ENOSPC = Errno(0x1c)
+ ENOSYS = Errno(0x4e)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x39)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x42)
+ ENOTSOCK = Errno(0x26)
+ ENOTSUP = Errno(0x5b)
+ ENOTTY = Errno(0x19)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x2d)
+ EOVERFLOW = Errno(0x57)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x2e)
+ EPIPE = Errno(0x20)
+ EPROCLIM = Errno(0x43)
+ EPROCUNAVAIL = Errno(0x4c)
+ EPROGMISMATCH = Errno(0x4b)
+ EPROGUNAVAIL = Errno(0x4a)
+ EPROTONOSUPPORT = Errno(0x2b)
+ EPROTOTYPE = Errno(0x29)
+ ERANGE = Errno(0x22)
+ EREMOTE = Errno(0x47)
+ EROFS = Errno(0x1e)
+ ERPCMISMATCH = Errno(0x49)
+ ESHUTDOWN = Errno(0x3a)
+ ESOCKTNOSUPPORT = Errno(0x2c)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESTALE = Errno(0x46)
+ ETIMEDOUT = Errno(0x3c)
+ ETOOMANYREFS = Errno(0x3b)
+ ETXTBSY = Errno(0x1a)
+ EUSERS = Errno(0x44)
+ EWOULDBLOCK = Errno(0x23)
+ EXDEV = Errno(0x12)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x14)
+ SIGCONT = Signal(0x13)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINFO = Signal(0x1d)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x17)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPROF = Signal(0x1b)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x11)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTHR = Signal(0x20)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x12)
+ SIGTTIN = Signal(0x15)
+ SIGTTOU = Signal(0x16)
+ SIGURG = Signal(0x10)
+ SIGUSR1 = Signal(0x1e)
+ SIGUSR2 = Signal(0x1f)
+ SIGVTALRM = Signal(0x1a)
+ SIGWINCH = Signal(0x1c)
+ SIGXCPU = Signal(0x18)
+ SIGXFSZ = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "device not configured",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource deadlock avoided",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "result too large",
+ 35: "resource temporarily unavailable",
+ 36: "operation now in progress",
+ 37: "operation already in progress",
+ 38: "socket operation on non-socket",
+ 39: "destination address required",
+ 40: "message too long",
+ 41: "protocol wrong type for socket",
+ 42: "protocol not available",
+ 43: "protocol not supported",
+ 44: "socket type not supported",
+ 45: "operation not supported",
+ 46: "protocol family not supported",
+ 47: "address family not supported by protocol family",
+ 48: "address already in use",
+ 49: "can't assign requested address",
+ 50: "network is down",
+ 51: "network is unreachable",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
+ 55: "no buffer space available",
+ 56: "socket is already connected",
+ 57: "socket is not connected",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "connection timed out",
+ 61: "connection refused",
+ 62: "too many levels of symbolic links",
+ 63: "file name too long",
+ 64: "host is down",
+ 65: "no route to host",
+ 66: "directory not empty",
+ 67: "too many processes",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
+ 71: "too many levels of remote in path",
+ 72: "RPC struct is bad",
+ 73: "RPC version wrong",
+ 74: "RPC prog. not avail",
+ 75: "program version wrong",
+ 76: "bad procedure for program",
+ 77: "no locks available",
+ 78: "function not implemented",
+ 79: "inappropriate file type or format",
+ 80: "authentication error",
+ 81: "need authenticator",
+ 82: "IPsec processing failure",
+ 83: "attribute not found",
+ 84: "illegal byte sequence",
+ 85: "no medium found",
+ 86: "wrong medium type",
+ 87: "value too large to be stored in data type",
+ 88: "operation canceled",
+ 89: "identifier removed",
+ 90: "no message of desired type",
+ 91: "not supported",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/BPT trap",
+ 6: "abort trap",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "urgent I/O condition",
+ 17: "stopped (signal)",
+ 18: "stopped",
+ 19: "continued",
+ 20: "child exited",
+ 21: "stopped (tty input)",
+ 22: "stopped (tty output)",
+ 23: "I/O possible",
+ 24: "cputime limit exceeded",
+ 25: "filesize limit exceeded",
+ 26: "virtual timer expired",
+ 27: "profiling timer expired",
+ 28: "window size changes",
+ 29: "information request",
+ 30: "user defined signal 1",
+ 31: "user defined signal 2",
+ 32: "thread AST",
+}
diff --git a/src/pkg/syscall/zerrors_plan9_386.go b/src/pkg/syscall/zerrors_plan9_386.go
index 65198c3ad..e7c993c0f 100644
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -1,5 +1,11 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package syscall
+import "errors"
+
// Constants
const (
// Invented values to support what package os expects.
@@ -18,6 +24,19 @@ const (
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
+
+ SIGINT = Signal(0x2)
+ SIGKILL = Signal(0x9)
)
-// Error table
+// Errors
+var (
+ EINVAL = errors.New("bad arg in system call")
+ ENOTDIR = errors.New("not a directory")
+ ENOENT = errors.New("file does not exist")
+ EEXIST = errors.New("file already exists")
+ EIO = errors.New("i/o error")
+ ENAMETOOLONG = errors.New("file name too long")
+ EPERM = errors.New("permission denied")
+ EPLAN9 = errors.New("not supported by plan 9")
+)
diff --git a/src/pkg/syscall/zerrors_windows.go b/src/pkg/syscall/zerrors_windows.go
index ae4506fac..afdeae2bc 100644
--- a/src/pkg/syscall/zerrors_windows.go
+++ b/src/pkg/syscall/zerrors_windows.go
@@ -1,12 +1,12 @@
-// mkerrors_windows.sh -f -m32
+// mkerrors_windows.sh -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
// Go names for Windows errors.
const (
- ENOENT = ERROR_FILE_NOT_FOUND
- ENOTDIR = ERROR_DIRECTORY
+ ENOENT Errno = ERROR_FILE_NOT_FOUND
+ ENOTDIR Errno = ERROR_PATH_NOT_FOUND
)
// Windows reserves errors >= 1<<29 for application use.
@@ -14,7 +14,7 @@ const APPLICATION_ERROR = 1 << 29
// Invented values to support what package os and others expects.
const (
- E2BIG = APPLICATION_ERROR + iota
+ E2BIG Errno = APPLICATION_ERROR + iota
EACCES
EADDRINUSE
EADDRNOTAVAIL
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 6d611e8ff..b952ac47c 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -7,115 +7,141 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(ngid int, gid *_Gid_t) (errno int) {
+func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(s int, how int) (errno int) {
+func Shutdown(s int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, proto int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -124,13 +150,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -138,39 +166,47 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
@@ -178,147 +214,183 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, timeval *[2]Timeval) (errno int) {
+func utimes(path string, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimes(fd int, timeval *[2]Timeval) (errno int) {
+func futimes(fd int, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe() (r int, w int, errno int) {
+func pipe() (r int, w int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
w = int(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kill(pid int, signum int, posix int) (errno int) {
+func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chflags(path string, flags int) (errno int) {
+func Chflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(fd int) (nfd int, errno int) {
+func Dup(fd int) (nfd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(from int, to int) (errno int) {
+func Dup2(from int, to int) (err error) {
_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Exchangedata(path1 string, path2 string, options int) (errno int) {
+func Exchangedata(path1 string, path2 string, options int) (err error) {
_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -331,88 +403,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (errno int) {
+func Fchflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fpathconf(fd int, name int) (val int, errno int) {
+func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (errno int) {
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -421,7 +513,9 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -451,7 +545,7 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -460,7 +554,9 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -474,10 +570,12 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -507,35 +605,43 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpriority(which int, who int) (prio int, errno int) {
+func Getpriority(which int, who int) (prio int, err error) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(which int, lim *Rlimit) (errno int) {
+func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getsid(pid int) (sid int, errno int) {
+func Getsid(pid int) (sid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -557,90 +663,110 @@ func Issetugid() (tainted bool) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kqueue() (fd int, errno int) {
+func Kqueue() (fd int, err error) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(path string, link string) (errno int) {
+func Link(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, backlog int) (errno int) {
+func Listen(s int, backlog int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkfifo(path string, mode uint32) (errno int) {
+func Mkfifo(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pathconf(path string, name int) (val int, errno int) {
+func Pathconf(path string, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -649,13 +775,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -664,13 +792,15 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -679,13 +809,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -694,193 +826,241 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(from string, to string) (errno int) {
+func Rename(from string, to string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Revoke(path string) (errno int) {
+func Revoke(path string) (err error) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setegid(egid int) (errno int) {
+func Setegid(egid int) (err error) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seteuid(euid int) (errno int) {
+func Seteuid(euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setlogin(name string) (errno int) {
+func Setlogin(name string) (err error) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpriority(which int, who int, prio int) (errno int) {
+func Setpriority(which int, who int, prio int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setprivexec(flag int) (errno int) {
+func Setprivexec(flag int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (errno int) {
+func Setrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tp *Timeval) (errno int) {
+func Settimeofday(tp *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (errno int) {
+func Statfs(path string, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(path string, link string) (errno int) {
+func Symlink(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sync() (errno int) {
+func Sync() (err error) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -894,31 +1074,37 @@ func Umask(newmask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Undelete(path string) (errno int) {
+func Undelete(path string) (err error) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(path string, flags int) (errno int) {
+func Unmount(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -927,51 +1113,63 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
ret = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func gettimeofday(tp *Timeval) (sec int32, usec int32, errno int) {
+func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) {
r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
sec = int32(r0)
usec = int32(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index e26fed46f..104ee5513 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -7,115 +7,141 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(ngid int, gid *_Gid_t) (errno int) {
+func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(s int, how int) (errno int) {
+func Shutdown(s int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, proto int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -124,13 +150,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -138,39 +166,47 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
@@ -178,147 +214,183 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, timeval *[2]Timeval) (errno int) {
+func utimes(path string, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimes(fd int, timeval *[2]Timeval) (errno int) {
+func futimes(fd int, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe() (r int, w int, errno int) {
+func pipe() (r int, w int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
w = int(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kill(pid int, signum int, posix int) (errno int) {
+func kill(pid int, signum int, posix int) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chflags(path string, flags int) (errno int) {
+func Chflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(fd int) (nfd int, errno int) {
+func Dup(fd int) (nfd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(from int, to int) (errno int) {
+func Dup2(from int, to int) (err error) {
_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Exchangedata(path1 string, path2 string, options int) (errno int) {
+func Exchangedata(path1 string, path2 string, options int) (err error) {
_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -331,88 +403,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (errno int) {
+func Fchflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fpathconf(fd int, name int) (val int, errno int) {
+func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (errno int) {
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -421,7 +513,9 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -451,7 +545,7 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -460,7 +554,9 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -474,10 +570,12 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -507,35 +605,43 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpriority(which int, who int) (prio int, errno int) {
+func Getpriority(which int, who int) (prio int, err error) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(which int, lim *Rlimit) (errno int) {
+func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getsid(pid int) (sid int, errno int) {
+func Getsid(pid int) (sid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -557,90 +663,110 @@ func Issetugid() (tainted bool) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kqueue() (fd int, errno int) {
+func Kqueue() (fd int, err error) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(path string, link string) (errno int) {
+func Link(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, backlog int) (errno int) {
+func Listen(s int, backlog int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkfifo(path string, mode uint32) (errno int) {
+func Mkfifo(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pathconf(path string, name int) (val int, errno int) {
+func Pathconf(path string, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -649,13 +775,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -664,13 +792,15 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -679,13 +809,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -694,193 +826,241 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(from string, to string) (errno int) {
+func Rename(from string, to string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Revoke(path string) (errno int) {
+func Revoke(path string) (err error) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
newoffset = int64(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setegid(egid int) (errno int) {
+func Setegid(egid int) (err error) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seteuid(euid int) (errno int) {
+func Seteuid(euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setlogin(name string) (errno int) {
+func Setlogin(name string) (err error) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpriority(which int, who int, prio int) (errno int) {
+func Setpriority(which int, who int, prio int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setprivexec(flag int) (errno int) {
+func Setprivexec(flag int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (errno int) {
+func Setrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tp *Timeval) (errno int) {
+func Settimeofday(tp *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (errno int) {
+func Statfs(path string, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(path string, link string) (errno int) {
+func Symlink(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sync() (errno int) {
+func Sync() (err error) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -894,31 +1074,37 @@ func Umask(newmask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Undelete(path string) (errno int) {
+func Undelete(path string) (err error) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(path string, flags int) (errno int) {
+func Unmount(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -927,51 +1113,63 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
ret = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) {
+func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
sec = int64(r0)
usec = int32(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 2cf6cbac6..455575467 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -7,115 +7,141 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(ngid int, gid *_Gid_t) (errno int) {
+func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(s int, how int) (errno int) {
+func Shutdown(s int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, proto int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -124,13 +150,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -138,39 +166,47 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
@@ -178,123 +214,153 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, timeval *[2]Timeval) (errno int) {
+func utimes(path string, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimes(fd int, timeval *[2]Timeval) (errno int) {
+func futimes(fd int, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe() (r int, w int, errno int) {
+func pipe() (r int, w int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
w = int(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chflags(path string, flags int) (errno int) {
+func Chflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(fd int) (nfd int, errno int) {
+func Dup(fd int) (nfd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(from int, to int) (errno int) {
+func Dup2(from int, to int) (err error) {
_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -307,88 +373,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (errno int) {
+func Fchflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fpathconf(fd int, name int) (val int, errno int) {
+func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (errno int) {
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -397,7 +483,9 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -427,7 +515,7 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -436,7 +524,9 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -450,10 +540,12 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -483,43 +575,53 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpriority(which int, who int) (prio int, errno int) {
+func Getpriority(which int, who int) (prio int, err error) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(which int, lim *Rlimit) (errno int) {
+func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getsid(pid int) (sid int, errno int) {
+func Getsid(pid int) (sid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -541,106 +643,130 @@ func Issetugid() (tainted bool) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kill(pid int, signum int) (errno int) {
+func Kill(pid int, signum Signal) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kqueue() (fd int, errno int) {
+func Kqueue() (fd int, err error) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(path string, link string) (errno int) {
+func Link(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, backlog int) (errno int) {
+func Listen(s int, backlog int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkfifo(path string, mode uint32) (errno int) {
+func Mkfifo(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pathconf(path string, name int) (val int, errno int) {
+func Pathconf(path string, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -649,13 +775,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -664,13 +792,15 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -679,13 +809,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -694,185 +826,231 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(from string, to string) (errno int) {
+func Rename(from string, to string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Revoke(path string) (errno int) {
+func Revoke(path string) (err error) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setegid(egid int) (errno int) {
+func Setegid(egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seteuid(euid int) (errno int) {
+func Seteuid(euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setlogin(name string) (errno int) {
+func Setlogin(name string) (err error) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpriority(which int, who int, prio int) (errno int) {
+func Setpriority(which int, who int, prio int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (errno int) {
+func Setrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tp *Timeval) (errno int) {
+func Settimeofday(tp *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (errno int) {
+func Statfs(path string, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(path string, link string) (errno int) {
+func Symlink(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sync() (errno int) {
+func Sync() (err error) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -886,31 +1064,37 @@ func Umask(newmask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Undelete(path string) (errno int) {
+func Undelete(path string) (err error) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(path string, flags int) (errno int) {
+func Unmount(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -919,41 +1103,51 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
ret = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index bdbfae952..33b71b9eb 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -7,115 +7,141 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(ngid int, gid *_Gid_t) (errno int) {
+func setgroups(ngid int, gid *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(s int, how int) (errno int) {
+func Shutdown(s int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, proto int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -124,13 +150,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -138,39 +166,47 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (errno int) {
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
var _p0 unsafe.Pointer
if len(mib) > 0 {
_p0 = unsafe.Pointer(&mib[0])
@@ -178,123 +214,153 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, timeval *[2]Timeval) (errno int) {
+func utimes(path string, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimes(fd int, timeval *[2]Timeval) (errno int) {
+func futimes(fd int, timeval *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe() (r int, w int, errno int) {
+func pipe() (r int, w int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
w = int(r1)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chflags(path string, flags int) (errno int) {
+func Chflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(fd int) (nfd int, errno int) {
+func Dup(fd int) (nfd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(from int, to int) (errno int) {
+func Dup2(from int, to int) (err error) {
_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -307,88 +373,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (errno int) {
+func Fchflags(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fpathconf(fd int, name int) (val int, errno int) {
+func Fpathconf(fd int, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, stat *Statfs_t) (errno int) {
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -397,7 +483,9 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -427,7 +515,7 @@ func Geteuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -436,7 +524,9 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -450,10 +540,12 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -483,43 +575,53 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpriority(which int, who int) (prio int, errno int) {
+func Getpriority(which int, who int) (prio int, err error) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(which int, lim *Rlimit) (errno int) {
+func Getrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getsid(pid int) (sid int, errno int) {
+func Getsid(pid int) (sid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -541,106 +643,130 @@ func Issetugid() (tainted bool) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kill(pid int, signum int) (errno int) {
+func Kill(pid int, signum Signal) (err error) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kqueue() (fd int, errno int) {
+func Kqueue() (fd int, err error) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(path string, link string) (errno int) {
+func Link(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, backlog int) (errno int) {
+func Listen(s int, backlog int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkfifo(path string, mode uint32) (errno int) {
+func Mkfifo(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Open(path string, mode int, perm uint32) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pathconf(path string, name int) (val int, errno int) {
+func Pathconf(path string, name int) (val int, err error) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -649,13 +775,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -664,13 +792,15 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -679,13 +809,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -694,185 +826,231 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(from string, to string) (errno int) {
+func Rename(from string, to string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Revoke(path string) (errno int) {
+func Revoke(path string) (err error) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
newoffset = int64(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) {
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setegid(egid int) (errno int) {
+func Setegid(egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seteuid(euid int) (errno int) {
+func Seteuid(euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setlogin(name string) (errno int) {
+func Setlogin(name string) (err error) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpriority(which int, who int, prio int) (errno int) {
+func Setpriority(which int, who int, prio int) (err error) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(which int, lim *Rlimit) (errno int) {
+func Setrlimit(which int, lim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tp *Timeval) (errno int) {
+func Settimeofday(tp *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, stat *Statfs_t) (errno int) {
+func Statfs(path string, stat *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(path string, link string) (errno int) {
+func Symlink(path string, link string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sync() (errno int) {
+func Sync() (err error) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -886,31 +1064,37 @@ func Umask(newmask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Undelete(path string) (errno int) {
+func Undelete(path string) (err error) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(path string, flags int) (errno int) {
+func Unmount(path string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -919,41 +1103,51 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
ret = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, buf *byte, nbuf int) (n int, errno int) {
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_linux_386.go b/src/pkg/syscall/zsyscall_linux_386.go
index 4eb522ad9..1752fe462 100644
--- a/src/pkg/syscall/zsyscall_linux_386.go
+++ b/src/pkg/syscall/zsyscall_linux_386.go
@@ -7,49 +7,59 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func open(path string, mode int, perm uint32) (fd int, errno int) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int) {
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe(p *[2]_C_int) (errno int) {
+func pipe(p *[2]_C_int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, times *[2]Timeval) (errno int) {
+func utimes(path string, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int) {
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getcwd(buf []byte) (n int, errno int) {
+func Getcwd(buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -58,139 +68,191 @@ func Getcwd(buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Acct(path string) (errno int) {
+func Acct(path string) (err error) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtimex(buf *Timex) (state int, errno int) {
+func Adjtimex(buf *Timex) (state int, err error) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Creat(path string, mode uint32) (fd int, errno int) {
+func Creat(path string, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(oldfd int) (fd int, errno int) {
+func Dup(oldfd int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(oldfd int, newfd int) (fd int, errno int) {
- r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
- fd = int(r0)
- errno = int(e1)
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCreate(size int) (fd int, errno int) {
+func EpollCreate(size int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
var _p0 unsafe.Pointer
if len(events) > 0 {
_p0 = unsafe.Pointer(&events[0])
@@ -199,7 +261,9 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -212,88 +276,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fallocate(fd int, mode uint32, off int64, len int64) (errno int) {
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) {
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fdatasync(fd int) (errno int) {
+func Fdatasync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdents(fd int, buf []byte) (n int, errno int) {
+func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -302,16 +386,20 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -341,17 +429,21 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -365,51 +457,61 @@ func Gettid() (tid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int) {
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
watchdesc = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit() (fd int, errno int) {
+func InotifyInit() (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit1(flags int) (fd int, errno int) {
+func InotifyInit1(flags int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int) {
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
success = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kill(pid int, sig int) (errno int) {
+func Kill(pid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Klogctl(typ int, buf []byte) (n int, errno int) {
+func Klogctl(typ int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -418,85 +520,95 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(oldpath string, newpath string) (errno int) {
+func Link(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknodat(dirfd int, path string, mode uint32, dev int) (errno int) {
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0)
- errno = int(e1)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mount(source string, target string, fstype string, flags int, data string) (errno int) {
- _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pause() (errno int) {
+func Pause() (err error) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func PivotRoot(newroot string, putold string) (errno int) {
+func PivotRoot(newroot string, putold string) (err error) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -505,13 +617,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,37 +634,45 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(oldpath string, newpath string) (errno int) {
+func Rename(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) {
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setdomainname(p []byte) (errno int) {
+func Setdomainname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -558,13 +680,15 @@ func Setdomainname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sethostname(p []byte) (errno int) {
+func Sethostname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -572,56 +696,70 @@ func Sethostname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (errno int) {
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tv *Timeval) (errno int) {
+func Settimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(oldpath string, newpath string) (errno int) {
+func Symlink(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -634,35 +772,43 @@ func Sync() {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sysinfo(info *Sysinfo_t) (errno int) {
+func Sysinfo(info *Sysinfo_t) (err error) {
_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) {
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
n = int64(int64(r1)<<32 | int64(r0))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tgkill(tgid int, tid int, sig int) (errno int) {
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Times(tms *Tms) (ticks uintptr, errno int) {
+func Times(tms *Tms) (ticks uintptr, err error) {
r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
ticks = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -676,63 +822,77 @@ func Umask(mask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Uname(buf *Utsname) (errno int) {
+func Uname(buf *Utsname) (err error) {
_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlinkat(dirfd int, path string) (errno int) {
+func Unlinkat(dirfd int, path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(target string, flags int) (errno int) {
+func Unmount(target string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unshare(flags int) (errno int) {
+func Unshare(flags int) (err error) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ustat(dev int, ubuf *Ustat_t) (errno int) {
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Utime(path string, buf *Utimbuf) (errno int) {
+func Utime(path string, buf *Utimbuf) (err error) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -741,47 +901,57 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func exitThread(code int) (errno int) {
+func exitThread(code int) (err error) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, p *byte, np int) (n int, errno int) {
+func read(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, p *byte, np int) (n int, errno int) {
+func write(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Madvise(b []byte, advice int) (errno int) {
+func Madvise(b []byte, advice int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -789,13 +959,15 @@ func Madvise(b []byte, advice int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mprotect(b []byte, prot int) (errno int) {
+func Mprotect(b []byte, prot int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -803,13 +975,15 @@ func Mprotect(b []byte, prot int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlock(b []byte) (errno int) {
+func Mlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -817,13 +991,15 @@ func Mlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlock(b []byte) (errno int) {
+func Munlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -831,55 +1007,69 @@ func Munlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlockall(flags int) (errno int) {
+func Mlockall(flags int) (err error) {
_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlockall() (errno int) {
+func Munlockall() (err error) {
_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -917,39 +1107,47 @@ func Getuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ioperm(from int, num int, on int) (errno int) {
+func Ioperm(from int, num int, on int) (err error) {
_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Iopl(level int) (errno int) {
+func Iopl(level int) (err error) {
_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -958,13 +1156,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -973,156 +1173,194 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
written = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsgid(gid int) (errno int) {
+func Setfsgid(gid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsuid(uid int) (errno int) {
+func Setfsuid(uid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID32, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresgid(rgid int, egid int, sgid int) (errno int) {
+func Setresgid(rgid int, egid int, sgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresuid(ruid int, euid int, suid int) (errno int) {
+func Setresuid(ruid int, euid int, suid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int) {
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) {
r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) {
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(n int, list *_Gid_t) (nn int, errno int) {
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(n int, list *_Gid_t) (errno int) {
+func setgroups(n int, list *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) {
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int) {
+func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
xaddr = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Time(t *Time_t) (tt Time_t, errno int) {
+func Time(t *Time_t) (tt Time_t, err error) {
r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
tt = Time_t(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index 999ed64a1..d27346f7f 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -7,49 +7,59 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func open(path string, mode int, perm uint32) (fd int, errno int) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int) {
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe(p *[2]_C_int) (errno int) {
+func pipe(p *[2]_C_int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, times *[2]Timeval) (errno int) {
+func utimes(path string, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int) {
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getcwd(buf []byte) (n int, errno int) {
+func Getcwd(buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -58,139 +68,191 @@ func Getcwd(buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Acct(path string) (errno int) {
+func Acct(path string) (err error) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtimex(buf *Timex) (state int, errno int) {
+func Adjtimex(buf *Timex) (state int, err error) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Creat(path string, mode uint32) (fd int, errno int) {
+func Creat(path string, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(oldfd int) (fd int, errno int) {
+func Dup(oldfd int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(oldfd int, newfd int) (fd int, errno int) {
- r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
- fd = int(r0)
- errno = int(e1)
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCreate(size int) (fd int, errno int) {
+func EpollCreate(size int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
var _p0 unsafe.Pointer
if len(events) > 0 {
_p0 = unsafe.Pointer(&events[0])
@@ -199,7 +261,9 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -212,88 +276,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fallocate(fd int, mode uint32, off int64, len int64) (errno int) {
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) {
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fdatasync(fd int) (errno int) {
+func Fdatasync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdents(fd int, buf []byte) (n int, errno int) {
+func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -302,16 +386,20 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -341,17 +429,21 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -365,51 +457,61 @@ func Gettid() (tid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int) {
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
watchdesc = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit() (fd int, errno int) {
+func InotifyInit() (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit1(flags int) (fd int, errno int) {
+func InotifyInit1(flags int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int) {
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
success = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kill(pid int, sig int) (errno int) {
+func Kill(pid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Klogctl(typ int, buf []byte) (n int, errno int) {
+func Klogctl(typ int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -418,85 +520,95 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(oldpath string, newpath string) (errno int) {
+func Link(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknodat(dirfd int, path string, mode uint32, dev int) (errno int) {
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0)
- errno = int(e1)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mount(source string, target string, fstype string, flags int, data string) (errno int) {
- _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pause() (errno int) {
+func Pause() (err error) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func PivotRoot(newroot string, putold string) (errno int) {
+func PivotRoot(newroot string, putold string) (err error) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -505,13 +617,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,37 +634,45 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(oldpath string, newpath string) (errno int) {
+func Rename(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) {
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setdomainname(p []byte) (errno int) {
+func Setdomainname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -558,13 +680,15 @@ func Setdomainname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sethostname(p []byte) (errno int) {
+func Sethostname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -572,56 +696,70 @@ func Sethostname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (errno int) {
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tv *Timeval) (errno int) {
+func Settimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(oldpath string, newpath string) (errno int) {
+func Symlink(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -634,35 +772,43 @@ func Sync() {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sysinfo(info *Sysinfo_t) (errno int) {
+func Sysinfo(info *Sysinfo_t) (err error) {
_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) {
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
n = int64(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tgkill(tgid int, tid int, sig int) (errno int) {
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Times(tms *Tms) (ticks uintptr, errno int) {
+func Times(tms *Tms) (ticks uintptr, err error) {
r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
ticks = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -676,63 +822,77 @@ func Umask(mask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Uname(buf *Utsname) (errno int) {
+func Uname(buf *Utsname) (err error) {
_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlinkat(dirfd int, path string) (errno int) {
+func Unlinkat(dirfd int, path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(target string, flags int) (errno int) {
+func Unmount(target string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unshare(flags int) (errno int) {
+func Unshare(flags int) (err error) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ustat(dev int, ubuf *Ustat_t) (errno int) {
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Utime(path string, buf *Utimbuf) (errno int) {
+func Utime(path string, buf *Utimbuf) (err error) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -741,47 +901,57 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func exitThread(code int) (errno int) {
+func exitThread(code int) (err error) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, p *byte, np int) (n int, errno int) {
+func read(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, p *byte, np int) (n int, errno int) {
+func write(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Madvise(b []byte, advice int) (errno int) {
+func Madvise(b []byte, advice int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -789,13 +959,15 @@ func Madvise(b []byte, advice int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mprotect(b []byte, prot int) (errno int) {
+func Mprotect(b []byte, prot int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -803,13 +975,15 @@ func Mprotect(b []byte, prot int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlock(b []byte) (errno int) {
+func Mlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -817,13 +991,15 @@ func Mlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlock(b []byte) (errno int) {
+func Munlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -831,63 +1007,79 @@ func Munlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlockall(flags int) (errno int) {
+func Mlockall(flags int) (err error) {
_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlockall() (errno int) {
+func Munlockall() (err error) {
_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, buf *Statfs_t) (errno int) {
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ftruncate(fd int, length int64) (errno int) {
+func Ftruncate(fd int, length int64) (err error) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -925,47 +1117,57 @@ func Getuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ioperm(from int, num int, on int) (errno int) {
+func Ioperm(from int, num int, on int) (err error) {
_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Iopl(level int) (errno int) {
+func Iopl(level int) (err error) {
_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, n int) (errno int) {
+func Listen(s int, n int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -974,13 +1176,15 @@ func Pread(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -989,236 +1193,292 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Seek(fd int, offset int64, whence int) (off int64, errno int) {
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
off = int64(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) {
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
written = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsgid(gid int) (errno int) {
+func Setfsgid(gid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsuid(uid int) (errno int) {
+func Setfsuid(uid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresgid(rgid int, egid int, sgid int) (errno int) {
+func Setresgid(rgid int, egid int, sgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresuid(ruid int, euid int, suid int) (errno int) {
+func Setresuid(ruid int, euid int, suid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(fd int, how int) (errno int) {
+func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
n = int64(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, buf *Statfs_t) (errno int) {
+func Statfs(path string, buf *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) {
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Truncate(path string, length int64) (errno int) {
+func Truncate(path string, length int64) (err error) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(n int, list *_Gid_t) (nn int, errno int) {
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(n int, list *_Gid_t) (errno int) {
+func setgroups(n int, list *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, proto int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -1227,13 +1487,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -1241,32 +1503,40 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int) {
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
xaddr = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index cd49dabed..1e86d3b7f 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -b32 syscall_linux.go syscall_linux_arm.go
+// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -7,49 +7,59 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func open(path string, mode int, perm uint32) (fd int, errno int) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int) {
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe(p *[2]_C_int) (errno int) {
+func pipe(p *[2]_C_int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func utimes(path string, times *[2]Timeval) (errno int) {
+func utimes(path string, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int) {
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getcwd(buf []byte) (n int, errno int) {
+func Getcwd(buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -58,139 +68,191 @@ func Getcwd(buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) {
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int) {
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(StringBytePtr(arg))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Access(path string, mode uint32) (errno int) {
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Acct(path string) (errno int) {
+func Acct(path string) (err error) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Adjtimex(buf *Timex) (state int, errno int) {
+func Adjtimex(buf *Timex) (state int, err error) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (errno int) {
+func Chdir(path string) (err error) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chmod(path string, mode uint32) (errno int) {
+func Chmod(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chroot(path string) (errno int) {
+func Chroot(path string) (err error) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (errno int) {
+func Close(fd int) (err error) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Creat(path string, mode uint32) (fd int, errno int) {
+func Creat(path string, mode uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(oldfd int) (fd int, errno int) {
+func Dup(oldfd int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup2(oldfd int, newfd int) (fd int, errno int) {
- r0, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
- fd = int(r0)
- errno = int(e1)
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCreate(size int) (fd int, errno int) {
+func EpollCreate(size int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) {
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
var _p0 unsafe.Pointer
if len(events) > 0 {
_p0 = unsafe.Pointer(&events[0])
@@ -199,7 +261,9 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) {
}
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -212,88 +276,108 @@ func Exit(code int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fallocate(fd int, mode uint32, off int64, len int64) (errno int) {
- _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))
- errno = int(e1)
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchdir(fd int) (errno int) {
+func Fchdir(fd int) (err error) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmod(fd int, mode uint32) (errno int) {
+func Fchmod(fd int, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int) {
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) {
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fcntl(fd int, cmd int, arg int) (val int, errno int) {
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fdatasync(fd int) (errno int) {
+func Fdatasync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Flock(fd int, how int) (errno int) {
+func Flock(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fsync(fd int) (errno int) {
+func Fsync(fd int) (err error) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getdents(fd int, buf []byte) (n int, errno int) {
+func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -302,16 +386,20 @@ func Getdents(fd int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getpgid(pid int) (pgid int, errno int) {
+func Getpgid(pid int) (pgid int, err error) {
r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -341,17 +429,21 @@ func Getppid() (ppid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrlimit(resource int, rlim *Rlimit) (errno int) {
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Getrusage(who int, rusage *Rusage) (errno int) {
+func Getrusage(who int, rusage *Rusage) (err error) {
_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -365,51 +457,61 @@ func Gettid() (tid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int) {
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
watchdesc = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit() (fd int, errno int) {
+func InotifyInit() (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyInit1(flags int) (fd int, errno int) {
+func InotifyInit1(flags int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int) {
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
success = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Kill(pid int, sig int) (errno int) {
+func Kill(pid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Klogctl(typ int, buf []byte) (n int, errno int) {
+func Klogctl(typ int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -418,85 +520,95 @@ func Klogctl(typ int, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Link(oldpath string, newpath string) (errno int) {
+func Link(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdir(path string, mode uint32) (errno int) {
+func Mkdir(path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknod(path string, mode uint32, dev int) (errno int) {
+func Mknod(path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mknodat(dirfd int, path string, mode uint32, dev int) (errno int) {
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0)
- errno = int(e1)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mount(source string, target string, fstype string, flags int, data string) (errno int) {
- _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(StringBytePtr(source))), uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(unsafe.Pointer(StringBytePtr(fstype))), uintptr(flags), uintptr(unsafe.Pointer(StringBytePtr(data))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pause() (errno int) {
+func Pause() (err error) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func PivotRoot(newroot string, putold string) (errno int) {
+func PivotRoot(newroot string, putold string) (err error) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Read(fd int, p []byte) (n int, errno int) {
+func Read(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -505,13 +617,15 @@ func Read(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Readlink(path string, buf []byte) (n int, errno int) {
+func Readlink(path string, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -520,37 +634,45 @@ func Readlink(path string, buf []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rename(oldpath string, newpath string) (errno int) {
+func Rename(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) {
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Rmdir(path string) (errno int) {
+func Rmdir(path string) (err error) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setdomainname(p []byte) (errno int) {
+func Setdomainname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -558,13 +680,15 @@ func Setdomainname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sethostname(p []byte) (errno int) {
+func Sethostname(p []byte) (err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -572,56 +696,70 @@ func Sethostname(p []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setpgid(pid int, pgid int) (errno int) {
+func Setpgid(pid int, pgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setrlimit(resource int, rlim *Rlimit) (errno int) {
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setsid() (pid int, errno int) {
+func Setsid() (pid int, err error) {
r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Settimeofday(tv *Timeval) (errno int) {
+func Settimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setuid(uid int) (errno int) {
+func Setuid(uid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Symlink(oldpath string, newpath string) (errno int) {
+func Symlink(oldpath string, newpath string) (err error) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -634,35 +772,43 @@ func Sync() {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sysinfo(info *Sysinfo_t) (errno int) {
+func Sysinfo(info *Sysinfo_t) (err error) {
_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) {
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
- n = int64(int64(r0)<<32 | int64(r1))
- errno = int(e1)
+ n = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Tgkill(tgid int, tid int, sig int) (errno int) {
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Times(tms *Tms) (ticks uintptr, errno int) {
+func Times(tms *Tms) (ticks uintptr, err error) {
r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
ticks = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -676,63 +822,77 @@ func Umask(mask int) (oldmask int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Uname(buf *Utsname) (errno int) {
+func Uname(buf *Utsname) (err error) {
_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlink(path string) (errno int) {
+func Unlink(path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unlinkat(dirfd int, path string) (errno int) {
+func Unlinkat(dirfd int, path string) (err error) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unmount(target string, flags int) (errno int) {
+func Unmount(target string, flags int) (err error) {
_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(StringBytePtr(target))), uintptr(flags), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Unshare(flags int) (errno int) {
+func Unshare(flags int) (err error) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Ustat(dev int, ubuf *Ustat_t) (errno int) {
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Utime(path string, buf *Utimbuf) (errno int) {
+func Utime(path string, buf *Utimbuf) (err error) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Write(fd int, p []byte) (n int, errno int) {
+func Write(fd int, p []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -741,47 +901,57 @@ func Write(fd int, p []byte) (n int, errno int) {
}
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func exitThread(code int) (errno int) {
+func exitThread(code int) (err error) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func read(fd int, p *byte, np int) (n int, errno int) {
+func read(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func write(fd int, p *byte, np int) (n int, errno int) {
+func write(fd int, p *byte, np int) (n int, err error) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func munmap(addr uintptr, length uintptr) (errno int) {
+func munmap(addr uintptr, length uintptr) (err error) {
_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Madvise(b []byte, advice int) (errno int) {
+func Madvise(b []byte, advice int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -789,13 +959,15 @@ func Madvise(b []byte, advice int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mprotect(b []byte, prot int) (errno int) {
+func Mprotect(b []byte, prot int) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -803,13 +975,15 @@ func Mprotect(b []byte, prot int) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlock(b []byte) (errno int) {
+func Mlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -817,13 +991,15 @@ func Mlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlock(b []byte) (errno int) {
+func Munlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
@@ -831,112 +1007,138 @@ func Munlock(b []byte) (errno int) {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mlockall(flags int) (errno int) {
+func Mlockall(flags int) (err error) {
_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Munlockall() (errno int) {
+func Munlockall() (err error) {
_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func connect(s int, addr uintptr, addrlen _Socklen) (errno int) {
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getgroups(n int, list *_Gid_t) (nn int, errno int) {
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setgroups(n int, list *_Gid_t) (errno int) {
+func setgroups(n int, list *_Gid_t) (err error) {
_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int) {
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socket(domain int, typ int, proto int) (fd int, errno int) {
+func socket(domain int, typ int, proto int) (fd int, err error) {
r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int) {
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -945,13 +1147,15 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno int) {
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -959,64 +1163,80 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func socketpair(domain int, typ int, flags int, fd *[2]int) (errno int) {
+func socketpair(domain int, typ int, flags int, fd *[2]int) (err error) {
_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chown(path string, uid int, gid int) (errno int) {
+func Chown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchown(fd int, uid int, gid int) (errno int) {
+func Fchown(fd int, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, stat *Stat_t) (errno int) {
+func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstatfs(fd int, buf *Statfs_t) (errno int) {
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
@@ -1054,157 +1274,249 @@ func Getuid() (uid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lchown(path string, uid int, gid int) (errno int) {
+func Lchown(path string, uid int, gid int) (err error) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Listen(s int, n int) (errno int) {
+func Listen(s int, n int) (err error) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Lstat(path string, stat *Stat_t) (errno int) {
+func Lstat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
written = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) {
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsgid(gid int) (errno int) {
+func Setfsgid(gid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setfsuid(uid int) (errno int) {
+func Setfsuid(uid int) (err error) {
_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setgid(gid int) (errno int) {
+func Setgid(gid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setregid(rgid int, egid int) (errno int) {
+func Setregid(rgid int, egid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresgid(rgid int, egid int, sgid int) (errno int) {
+func Setresgid(rgid int, egid int, sgid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setresuid(ruid int, euid int, suid int) (errno int) {
+func Setresuid(ruid int, euid int, suid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Setreuid(ruid int, euid int) (errno int) {
+func Setreuid(ruid int, euid int) (err error) {
_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Shutdown(fd int, how int) (errno int) {
+func Shutdown(fd int, how int) (err error) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, errno int) {
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) {
r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
n = int(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, stat *Stat_t) (errno int) {
+func Stat(path string, stat *Stat_t) (err error) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Statfs(path string, buf *Statfs_t) (errno int) {
+func Statfs(path string, buf *Statfs_t) (err error) {
_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Time(t *Time_t) (tt Time_t, errno int) {
+func Time(t *Time_t) (tt Time_t, err error) {
r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
tt = Time_t(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, errno int) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
xaddr = uintptr(r0)
- errno = int(e1)
+ if e1 != 0 {
+ err = e1
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_netbsd_386.go b/src/pkg/syscall/zsyscall_netbsd_386.go
new file mode 100644
index 000000000..6155a1687
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -0,0 +1,1086 @@
+// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe2(p *[2]_C_int, flags _C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum int) (err error) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+ _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
+ newoffset = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+ _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+ _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_netbsd_amd64.go b/src/pkg/syscall/zsyscall_netbsd_amd64.go
new file mode 100644
index 000000000..d68cd86d8
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_netbsd_amd64.go
@@ -0,0 +1,1086 @@
+// mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe2(p *[2]_C_int, flags _C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum int) (err error) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+ _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
+ newoffset = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+ _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+ _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_openbsd_386.go b/src/pkg/syscall/zsyscall_openbsd_386.go
new file mode 100644
index 000000000..c88492329
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_openbsd_386.go
@@ -0,0 +1,1133 @@
+// mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum Signal) (err error) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+ _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
+ newoffset = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+ _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+ _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+ _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_openbsd_amd64.go b/src/pkg/syscall/zsyscall_openbsd_amd64.go
new file mode 100644
index 000000000..7775646c4
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_openbsd_amd64.go
@@ -0,0 +1,1133 @@
+// mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+ var _p0 unsafe.Pointer
+ if len(mib) > 0 {
+ _p0 = unsafe.Pointer(&mib[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err error) {
+ _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(fd int) (nfd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+ nfd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+ _, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+ sid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+ r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+ tainted = bool(r0 != 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum Signal) (err error) {
+ _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+ _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
+ fd = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
+ val = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+ _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+ _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+ _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
+ newoffset = int64(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+ _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+ _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+ _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(path string, link string) (err error) {
+ _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+ _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+ r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+ _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+ r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
+ ret = uintptr(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, buf *byte, nbuf int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_plan9_386.go b/src/pkg/syscall/zsyscall_plan9_386.go
index 75c411ad6..913c28fa2 100644
--- a/src/pkg/syscall/zsyscall_plan9_386.go
+++ b/src/pkg/syscall/zsyscall_plan9_386.go
@@ -14,7 +14,7 @@ func exits(msg *byte) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func fd2path(fd int, buf []byte) (err Error) {
+func fd2path(fd int, buf []byte) (err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
@@ -22,38 +22,25 @@ func fd2path(fd int, buf []byte) (err Error) {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe(p *[2]_C_int) (err Error) {
+func pipe(p *[2]_C_int) (err error) {
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func sleep(millisecs int32) (err Error) {
- r0, _, e1 := Syscall(SYS_SLEEP, uintptr(millisecs), 0, 0)
- err = nil
- if int(r0) == -1 {
- err = NewError(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func await(s []byte) (n int, err Error) {
+func await(s []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(s) > 0 {
_p0 = unsafe.Pointer(&s[0])
@@ -62,63 +49,58 @@ func await(s []byte) (n int, err Error) {
}
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
n = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Dup(oldfd int, newfd int) (fd int, err Error) {
+func Dup(oldfd int, newfd int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Open(path string, mode int) (fd int, err Error) {
+func Open(path string, mode int) (fd int, err error) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Create(path string, mode int, perm uint32) (fd int, err Error) {
+func Create(path string, mode int, perm uint32) (fd int, err error) {
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Remove(path string) (err Error) {
+func Remove(path string) (err error) {
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pread(fd int, p []byte, offset int64) (n int, err Error) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -127,16 +109,15 @@ func Pread(fd int, p []byte, offset int64) (n int, err Error) {
}
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Pwrite(fd int, p []byte, offset int64) (n int, err Error) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
var _p0 unsafe.Pointer
if len(p) > 0 {
_p0 = unsafe.Pointer(&p[0])
@@ -145,60 +126,55 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err Error) {
}
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Close(fd int) (err Error) {
+func Close(fd int) (err error) {
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Chdir(path string) (err Error) {
+func Chdir(path string) (err error) {
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Bind(name string, old string, flag int) (err Error) {
+func Bind(name string, old string, flag int) (err error) {
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag))
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Mount(fd int, afd int, old string, flag int, aname string) (err Error) {
+func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(StringBytePtr(old))), uintptr(flag), uintptr(unsafe.Pointer(StringBytePtr(aname))), 0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Stat(path string, edir []byte) (n int, err Error) {
+func Stat(path string, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
@@ -207,16 +183,15 @@ func Stat(path string, edir []byte) (n int, err Error) {
}
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fstat(fd int, edir []byte) (n int, err Error) {
+func Fstat(fd int, edir []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
@@ -225,16 +200,15 @@ func Fstat(fd int, edir []byte) (n int, err Error) {
}
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
n = int(r0)
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Wstat(path string, edir []byte) (err Error) {
+func Wstat(path string, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
@@ -242,16 +216,15 @@ func Wstat(path string, edir []byte) (err Error) {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(edir)))
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fwstat(fd int, edir []byte) (err Error) {
+func Fwstat(fd int, edir []byte) (err error) {
var _p0 unsafe.Pointer
if len(edir) > 0 {
_p0 = unsafe.Pointer(&edir[0])
@@ -259,9 +232,8 @@ func Fwstat(fd int, edir []byte) (err Error) {
_p0 = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
- err = nil
if int(r0) == -1 {
- err = NewError(e1)
+ err = e1
}
return
}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index b46493f8d..8e6afcf0a 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl -l32 syscall_windows.go syscall_windows_386.go
+// mksyscall_windows.pl -l32 syscall_windows.go security_windows.go syscall_windows_386.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -9,169 +9,201 @@ var (
modkernel32 = NewLazyDLL("kernel32.dll")
modadvapi32 = NewLazyDLL("advapi32.dll")
modshell32 = NewLazyDLL("shell32.dll")
- modwsock32 = NewLazyDLL("wsock32.dll")
+ modmswsock = NewLazyDLL("mswsock.dll")
+ modcrypt32 = NewLazyDLL("crypt32.dll")
modws2_32 = NewLazyDLL("ws2_32.dll")
moddnsapi = NewLazyDLL("dnsapi.dll")
modiphlpapi = NewLazyDLL("iphlpapi.dll")
-
- procGetLastError = modkernel32.NewProc("GetLastError")
- procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
- procFreeLibrary = modkernel32.NewProc("FreeLibrary")
- procGetProcAddress = modkernel32.NewProc("GetProcAddress")
- procGetVersion = modkernel32.NewProc("GetVersion")
- procFormatMessageW = modkernel32.NewProc("FormatMessageW")
- procExitProcess = modkernel32.NewProc("ExitProcess")
- procCreateFileW = modkernel32.NewProc("CreateFileW")
- procReadFile = modkernel32.NewProc("ReadFile")
- procWriteFile = modkernel32.NewProc("WriteFile")
- procSetFilePointer = modkernel32.NewProc("SetFilePointer")
- procCloseHandle = modkernel32.NewProc("CloseHandle")
- procGetStdHandle = modkernel32.NewProc("GetStdHandle")
- procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
- procFindNextFileW = modkernel32.NewProc("FindNextFileW")
- procFindClose = modkernel32.NewProc("FindClose")
- procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
- procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
- procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
- procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
- procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
- procDeleteFileW = modkernel32.NewProc("DeleteFileW")
- procMoveFileW = modkernel32.NewProc("MoveFileW")
- procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
- procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
- procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
- procSleep = modkernel32.NewProc("Sleep")
- procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
- procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
- procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
- procCancelIo = modkernel32.NewProc("CancelIo")
- procCreateProcessW = modkernel32.NewProc("CreateProcessW")
- procOpenProcess = modkernel32.NewProc("OpenProcess")
- procTerminateProcess = modkernel32.NewProc("TerminateProcess")
- procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
- procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
- procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
- procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
- procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
- procGetTempPathW = modkernel32.NewProc("GetTempPathW")
- procCreatePipe = modkernel32.NewProc("CreatePipe")
- procGetFileType = modkernel32.NewProc("GetFileType")
- procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
- procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
- procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
- procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
- procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
- procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
- procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
- procSetFileTime = modkernel32.NewProc("SetFileTime")
- procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
- procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
- procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
- procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
- procLocalFree = modkernel32.NewProc("LocalFree")
- procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
- procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
- procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
- procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
- procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
- procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
- procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
- procVirtualLock = modkernel32.NewProc("VirtualLock")
- procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
- procTransmitFile = modwsock32.NewProc("TransmitFile")
- procWSAStartup = modwsock32.NewProc("WSAStartup")
- procWSACleanup = modwsock32.NewProc("WSACleanup")
- procWSAIoctl = modws2_32.NewProc("WSAIoctl")
- procsocket = modwsock32.NewProc("socket")
- procsetsockopt = modwsock32.NewProc("setsockopt")
- procbind = modwsock32.NewProc("bind")
- procconnect = modwsock32.NewProc("connect")
- procgetsockname = modwsock32.NewProc("getsockname")
- procgetpeername = modwsock32.NewProc("getpeername")
- proclisten = modwsock32.NewProc("listen")
- procshutdown = modwsock32.NewProc("shutdown")
- procclosesocket = modwsock32.NewProc("closesocket")
- procAcceptEx = modwsock32.NewProc("AcceptEx")
- procGetAcceptExSockaddrs = modwsock32.NewProc("GetAcceptExSockaddrs")
- procWSARecv = modws2_32.NewProc("WSARecv")
- procWSASend = modws2_32.NewProc("WSASend")
- procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
- procWSASendTo = modws2_32.NewProc("WSASendTo")
- procgethostbyname = modws2_32.NewProc("gethostbyname")
- procgetservbyname = modws2_32.NewProc("getservbyname")
- procntohs = modws2_32.NewProc("ntohs")
- procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
- procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
- procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
- procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ modsecur32 = NewLazyDLL("secur32.dll")
+ modnetapi32 = NewLazyDLL("netapi32.dll")
+ moduserenv = NewLazyDLL("userenv.dll")
+
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
+ procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modmswsock.NewProc("TransmitFile")
+ procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
+ procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
+ procCertOpenStore = modcrypt32.NewProc("CertOpenStore")
+ procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
+ procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore")
+ procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
+ procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
+ procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
+ procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext")
+ procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
+ procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
+ procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
+ procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
+ procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
+ procWSAStartup = modws2_32.NewProc("WSAStartup")
+ procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modws2_32.NewProc("socket")
+ procsetsockopt = modws2_32.NewProc("setsockopt")
+ procbind = modws2_32.NewProc("bind")
+ procconnect = modws2_32.NewProc("connect")
+ procgetsockname = modws2_32.NewProc("getsockname")
+ procgetpeername = modws2_32.NewProc("getpeername")
+ proclisten = modws2_32.NewProc("listen")
+ procshutdown = modws2_32.NewProc("shutdown")
+ procclosesocket = modws2_32.NewProc("closesocket")
+ procAcceptEx = modmswsock.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procgetprotobyname = modws2_32.NewProc("getprotobyname")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ procTranslateNameW = modsecur32.NewProc("TranslateNameW")
+ procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
+ procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
+ procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
+ procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
+ procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
+ procCopySid = modadvapi32.NewProc("CopySid")
+ procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
+ procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
+ procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
)
-func GetLastError() (lasterrno int) {
+func GetLastError() (lasterr error) {
r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
- lasterrno = int(r0)
+ if r0 != 0 {
+ lasterr = Errno(r0)
+ }
return
}
-func LoadLibrary(libname string) (handle Handle, errno int) {
+func LoadLibrary(libname string) (handle Handle, err error) {
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FreeLibrary(handle Handle) (errno int) {
+func FreeLibrary(handle Handle) (err error) {
r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
+func GetProcAddress(module Handle, procname string) (proc uintptr, err error) {
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
- proc = Handle(r0)
+ proc = uintptr(r0)
if proc == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetVersion() (ver uint32, errno int) {
+func GetVersion() (ver uint32, err error) {
r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0)
ver = uint32(r0)
if ver == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) {
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
var _p0 *uint16
if len(buf) > 0 {
_p0 = &buf[0]
@@ -180,12 +212,10 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -195,22 +225,20 @@ func ExitProcess(exitcode uint32) {
return
}
-func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
@@ -218,17 +246,15 @@ func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (
r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
@@ -236,226 +262,194 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped)
r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) {
r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
newlowoffset = uint32(r0)
if newlowoffset == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CloseHandle(handle Handle) (errno int) {
+func CloseHandle(handle Handle) (err error) {
r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetStdHandle(stdhandle int) (handle Handle, errno int) {
+func GetStdHandle(stdhandle int) (handle Handle, err error) {
r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
+func FindNextFile(handle Handle, data *Win32finddata) (err error) {
r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindClose(handle Handle) (errno int) {
+func FindClose(handle Handle) (err error) {
r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) {
r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) {
r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetCurrentDirectory(path *uint16) (errno int) {
+func SetCurrentDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) {
r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func RemoveDirectory(path *uint16) (errno int) {
+func RemoveDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func DeleteFile(path *uint16) (errno int) {
+func DeleteFile(path *uint16) (err error) {
r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func MoveFile(from *uint16, to *uint16) (errno int) {
+func MoveFile(from *uint16, to *uint16) (err error) {
r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetComputerName(buf *uint16, n *uint32) (errno int) {
+func GetComputerName(buf *uint16, n *uint32) (err error) {
r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetEndOfFile(handle Handle) (errno int) {
+func SetEndOfFile(handle Handle) (err error) {
r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -465,70 +459,69 @@ func GetSystemTimeAsFileTime(time *Filetime) {
return
}
-func sleep(msec uint32) {
- Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
- return
-}
-
-func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
rc = uint32(r0)
if rc == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) {
r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CancelIo(s Handle) (errno int) {
+func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CancelIo(s Handle) (err error) {
r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) {
var _p0 uint32
if inheritHandles {
_p0 = 1
@@ -538,17 +531,15 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) {
var _p0 uint32
if inheritHandle {
_p0 = 1
@@ -559,74 +550,76 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errn
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
+func TerminateProcess(handle Handle, exitcode uint32) (err error) {
r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) {
r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+func GetStartupInfo(startupInfo *StartupInfo) (err error) {
r1, _, e1 := Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetCurrentProcess() (pseudoHandle Handle, errno int) {
+func GetCurrentProcess() (pseudoHandle Handle, err error) {
r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0)
pseudoHandle = Handle(r0)
if pseudoHandle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) {
+ r1, _, e1 := Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
var _p0 uint32
if bInheritHandle {
_p0 = 1
@@ -636,214 +629,196 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) {
r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0)
event = uint32(r0)
if event == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) {
r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) {
r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileType(filehandle Handle) (n uint32, errno int) {
+func GetFileType(filehandle Handle) (n uint32, err error) {
r0, _, e1 := Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) {
r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
+func CryptReleaseContext(provhandle Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) {
r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetEnvironmentStrings() (envs *uint16, errno int) {
+func GetEnvironmentStrings() (envs *uint16, err error) {
r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0)
envs = (*uint16)(unsafe.Pointer(r0))
if envs == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FreeEnvironmentStrings(envs *uint16) (errno int) {
+func FreeEnvironmentStrings(envs *uint16) (err error) {
r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) {
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) {
r0, _, e1 := Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetEnvironmentVariable(name *uint16, value *uint16) (errno int) {
+func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) {
r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+func GetFileAttributes(name *uint16) (attrs uint32, err error) {
r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
attrs = uint32(r0)
if attrs == INVALID_FILE_ATTRIBUTES {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFileAttributes(name *uint16, attrs uint32) (errno int) {
+func SetFileAttributes(name *uint16, attrs uint32) (err error) {
r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) {
+ r1, _, e1 := Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -854,350 +829,505 @@ func GetCommandLine() (cmd *uint16) {
return
}
-func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) {
+func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
r0, _, e1 := Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
if argv == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func LocalFree(hmem Handle) (handle Handle, errno int) {
+func LocalFree(hmem Handle) (handle Handle, err error) {
r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0)
handle = Handle(r0)
if handle != 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FlushFileBuffers(handle Handle) (errno int) {
+func FlushFileBuffers(handle Handle) (err error) {
r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) {
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) {
r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) {
r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
addr = uintptr(r0)
if addr == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func UnmapViewOfFile(addr uintptr) (errno int) {
+func UnmapViewOfFile(addr uintptr) (err error) {
r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FlushViewOfFile(addr uintptr, length uintptr) (errno int) {
+func FlushViewOfFile(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func VirtualLock(addr uintptr, length uintptr) (errno int) {
+func VirtualLock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
+func VirtualUnlock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) {
r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
+ }
+ return
+}
+
+func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ var _p0 uint32
+ if watchSubTree {
+ _p0 = 1
} else {
- errno = 0
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
+ r0, _, e1 := Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0)
+ store = Handle(r0)
+ if store == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
+ r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0)
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) {
+ r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertCloseStore(store Handle, flags uint32) (err error) {
+ r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) {
+ r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
}
return
}
-func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
+func CertFreeCertificateChain(ctx *CertChainContext) {
+ Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ return
+}
+
+func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen))
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateContext(ctx *CertContext) (err error) {
+ r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) {
+ r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) {
+ r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegCloseKey(key Handle) (regerrno error) {
+ r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime)))
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+ r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)))
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
- sockerrno = int(r0)
+ if r0 != 0 {
+ sockerr = Errno(r0)
+ }
return
}
-func WSACleanup() (errno int) {
+func WSACleanup() (err error) {
r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
+func socket(af int32, typ int32, protocol int32) (handle Handle, err error) {
r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol))
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) {
r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func bind(s Handle, name uintptr, namelen int32) (errno int) {
+func bind(s Handle, name uintptr, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func connect(s Handle, name uintptr, namelen int32) (errno int) {
+func connect(s Handle, name uintptr, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func listen(s Handle, backlog int32) (errno int) {
+func listen(s Handle, backlog int32) (err error) {
r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func shutdown(s Handle, how int32) (errno int) {
+func shutdown(s Handle, how int32) (err error) {
r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func Closesocket(s Handle) (errno int) {
+func Closesocket(s Handle) (err error) {
r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) {
r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -1207,88 +1337,76 @@ func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen
return
}
-func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetHostByName(name string) (h *Hostent, errno int) {
+func GetHostByName(name string) (h *Hostent, err error) {
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
h = (*Hostent)(unsafe.Pointer(r0))
if h == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetServByName(name string, proto string) (s *Servent, errno int) {
+func GetServByName(name string, proto string) (s *Servent, err error) {
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
s = (*Servent)(unsafe.Pointer(r0))
if s == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -1299,9 +1417,24 @@ func Ntohs(netshort uint16) (u uint16) {
return
}
-func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
+func GetProtoByName(name string) (p *Protoent, err error) {
+ r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ p = (*Protoent)(unsafe.Pointer(r0))
+ if p == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
- status = uint32(r0)
+ if r0 != 0 {
+ status = Errno(r0)
+ }
return
}
@@ -1310,14 +1443,160 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
return
}
-func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
- errcode = int(r0)
+ if r0 != 0 {
+ errcode = Errno(r0)
+ }
return
}
-func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) {
r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
- errcode = int(r0)
+ if r0 != 0 {
+ errcode = Errno(r0)
+ }
+ return
+}
+
+func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
+ if int(r1)&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
+ if int(r1)&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
+ r0, _, _ := Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = Errno(r0)
+ }
+ return
+}
+
+func NetApiBufferFree(buf *byte) (neterr error) {
+ r0, _, _ := Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = Errno(r0)
+ }
+ return
+}
+
+func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) {
+ r1, _, e1 := Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) {
+ r1, _, e1 := Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetLengthSid(sid *SID) (len uint32) {
+ r0, _, _ := Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ len = uint32(r0)
+ return
+}
+
+func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) {
+ r1, _, e1 := Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func OpenProcessToken(h Handle, access uint32, token *Token) (err error) {
+ r1, _, e1 := Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) {
+ r1, _, e1 := Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
+ r1, _, e1 := Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
return
}
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index ca087bb69..c6ff6fe02 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl syscall_windows.go syscall_windows_amd64.go
+// mksyscall_windows.pl syscall_windows.go security_windows.go syscall_windows_amd64.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -9,169 +9,201 @@ var (
modkernel32 = NewLazyDLL("kernel32.dll")
modadvapi32 = NewLazyDLL("advapi32.dll")
modshell32 = NewLazyDLL("shell32.dll")
- modwsock32 = NewLazyDLL("wsock32.dll")
+ modmswsock = NewLazyDLL("mswsock.dll")
+ modcrypt32 = NewLazyDLL("crypt32.dll")
modws2_32 = NewLazyDLL("ws2_32.dll")
moddnsapi = NewLazyDLL("dnsapi.dll")
modiphlpapi = NewLazyDLL("iphlpapi.dll")
-
- procGetLastError = modkernel32.NewProc("GetLastError")
- procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
- procFreeLibrary = modkernel32.NewProc("FreeLibrary")
- procGetProcAddress = modkernel32.NewProc("GetProcAddress")
- procGetVersion = modkernel32.NewProc("GetVersion")
- procFormatMessageW = modkernel32.NewProc("FormatMessageW")
- procExitProcess = modkernel32.NewProc("ExitProcess")
- procCreateFileW = modkernel32.NewProc("CreateFileW")
- procReadFile = modkernel32.NewProc("ReadFile")
- procWriteFile = modkernel32.NewProc("WriteFile")
- procSetFilePointer = modkernel32.NewProc("SetFilePointer")
- procCloseHandle = modkernel32.NewProc("CloseHandle")
- procGetStdHandle = modkernel32.NewProc("GetStdHandle")
- procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
- procFindNextFileW = modkernel32.NewProc("FindNextFileW")
- procFindClose = modkernel32.NewProc("FindClose")
- procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
- procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
- procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
- procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
- procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
- procDeleteFileW = modkernel32.NewProc("DeleteFileW")
- procMoveFileW = modkernel32.NewProc("MoveFileW")
- procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
- procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
- procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
- procSleep = modkernel32.NewProc("Sleep")
- procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
- procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
- procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
- procCancelIo = modkernel32.NewProc("CancelIo")
- procCreateProcessW = modkernel32.NewProc("CreateProcessW")
- procOpenProcess = modkernel32.NewProc("OpenProcess")
- procTerminateProcess = modkernel32.NewProc("TerminateProcess")
- procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
- procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
- procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
- procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
- procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
- procGetTempPathW = modkernel32.NewProc("GetTempPathW")
- procCreatePipe = modkernel32.NewProc("CreatePipe")
- procGetFileType = modkernel32.NewProc("GetFileType")
- procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
- procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
- procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
- procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
- procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
- procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
- procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
- procSetFileTime = modkernel32.NewProc("SetFileTime")
- procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
- procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
- procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
- procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
- procLocalFree = modkernel32.NewProc("LocalFree")
- procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
- procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
- procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
- procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
- procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
- procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
- procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
- procVirtualLock = modkernel32.NewProc("VirtualLock")
- procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
- procTransmitFile = modwsock32.NewProc("TransmitFile")
- procWSAStartup = modwsock32.NewProc("WSAStartup")
- procWSACleanup = modwsock32.NewProc("WSACleanup")
- procWSAIoctl = modws2_32.NewProc("WSAIoctl")
- procsocket = modwsock32.NewProc("socket")
- procsetsockopt = modwsock32.NewProc("setsockopt")
- procbind = modwsock32.NewProc("bind")
- procconnect = modwsock32.NewProc("connect")
- procgetsockname = modwsock32.NewProc("getsockname")
- procgetpeername = modwsock32.NewProc("getpeername")
- proclisten = modwsock32.NewProc("listen")
- procshutdown = modwsock32.NewProc("shutdown")
- procclosesocket = modwsock32.NewProc("closesocket")
- procAcceptEx = modwsock32.NewProc("AcceptEx")
- procGetAcceptExSockaddrs = modwsock32.NewProc("GetAcceptExSockaddrs")
- procWSARecv = modws2_32.NewProc("WSARecv")
- procWSASend = modws2_32.NewProc("WSASend")
- procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
- procWSASendTo = modws2_32.NewProc("WSASendTo")
- procgethostbyname = modws2_32.NewProc("gethostbyname")
- procgetservbyname = modws2_32.NewProc("getservbyname")
- procntohs = modws2_32.NewProc("ntohs")
- procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
- procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
- procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
- procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ modsecur32 = NewLazyDLL("secur32.dll")
+ modnetapi32 = NewLazyDLL("netapi32.dll")
+ moduserenv = NewLazyDLL("userenv.dll")
+
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
+ procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modmswsock.NewProc("TransmitFile")
+ procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
+ procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
+ procCertOpenStore = modcrypt32.NewProc("CertOpenStore")
+ procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
+ procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore")
+ procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
+ procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
+ procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
+ procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext")
+ procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
+ procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
+ procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
+ procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
+ procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
+ procWSAStartup = modws2_32.NewProc("WSAStartup")
+ procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modws2_32.NewProc("socket")
+ procsetsockopt = modws2_32.NewProc("setsockopt")
+ procbind = modws2_32.NewProc("bind")
+ procconnect = modws2_32.NewProc("connect")
+ procgetsockname = modws2_32.NewProc("getsockname")
+ procgetpeername = modws2_32.NewProc("getpeername")
+ proclisten = modws2_32.NewProc("listen")
+ procshutdown = modws2_32.NewProc("shutdown")
+ procclosesocket = modws2_32.NewProc("closesocket")
+ procAcceptEx = modmswsock.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procgetprotobyname = modws2_32.NewProc("getprotobyname")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ procTranslateNameW = modsecur32.NewProc("TranslateNameW")
+ procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
+ procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
+ procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
+ procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
+ procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
+ procCopySid = modadvapi32.NewProc("CopySid")
+ procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
+ procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
+ procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
)
-func GetLastError() (lasterrno int) {
+func GetLastError() (lasterr error) {
r0, _, _ := Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
- lasterrno = int(r0)
+ if r0 != 0 {
+ lasterr = Errno(r0)
+ }
return
}
-func LoadLibrary(libname string) (handle Handle, errno int) {
+func LoadLibrary(libname string) (handle Handle, err error) {
r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FreeLibrary(handle Handle) (errno int) {
+func FreeLibrary(handle Handle) (err error) {
r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetProcAddress(module Handle, procname string) (proc Handle, errno int) {
+func GetProcAddress(module Handle, procname string) (proc uintptr, err error) {
r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
- proc = Handle(r0)
+ proc = uintptr(r0)
if proc == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetVersion() (ver uint32, errno int) {
+func GetVersion() (ver uint32, err error) {
r0, _, e1 := Syscall(procGetVersion.Addr(), 0, 0, 0, 0)
ver = uint32(r0)
if ver == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, errno int) {
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
var _p0 *uint16
if len(buf) > 0 {
_p0 = &buf[0]
@@ -180,12 +212,10 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -195,22 +225,20 @@ func ExitProcess(exitcode uint32) {
return
}
-func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, errno int) {
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
r0, _, e1 := Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
@@ -218,17 +246,15 @@ func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (
r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (errno int) {
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
var _p0 *byte
if len(buf) > 0 {
_p0 = &buf[0]
@@ -236,226 +262,194 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped)
r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) {
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) {
r0, _, e1 := Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
newlowoffset = uint32(r0)
if newlowoffset == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CloseHandle(handle Handle) (errno int) {
+func CloseHandle(handle Handle) (err error) {
r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetStdHandle(stdhandle int) (handle Handle, errno int) {
+func GetStdHandle(stdhandle int) (handle Handle, err error) {
r0, _, e1 := Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, errno int) {
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
r0, _, e1 := Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindNextFile(handle Handle, data *Win32finddata) (errno int) {
+func FindNextFile(handle Handle, data *Win32finddata) (err error) {
r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FindClose(handle Handle) (errno int) {
+func FindClose(handle Handle) (err error) {
r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (errno int) {
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) {
r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) {
r0, _, e1 := Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetCurrentDirectory(path *uint16) (errno int) {
+func SetCurrentDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateDirectory(path *uint16, sa *SecurityAttributes) (errno int) {
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) {
r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func RemoveDirectory(path *uint16) (errno int) {
+func RemoveDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func DeleteFile(path *uint16) (errno int) {
+func DeleteFile(path *uint16) (err error) {
r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func MoveFile(from *uint16, to *uint16) (errno int) {
+func MoveFile(from *uint16, to *uint16) (err error) {
r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetComputerName(buf *uint16, n *uint32) (errno int) {
+func GetComputerName(buf *uint16, n *uint32) (err error) {
r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetEndOfFile(handle Handle) (errno int) {
+func SetEndOfFile(handle Handle) (err error) {
r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -465,70 +459,69 @@ func GetSystemTimeAsFileTime(time *Filetime) {
return
}
-func sleep(msec uint32) {
- Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
- return
-}
-
-func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
rc = uint32(r0)
if rc == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, errno int) {
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) {
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) {
r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CancelIo(s Handle) (errno int) {
+func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CancelIo(s Handle) (err error) {
r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) {
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) {
var _p0 uint32
if inheritHandles {
_p0 = 1
@@ -538,17 +531,15 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errno int) {
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) {
var _p0 uint32
if inheritHandle {
_p0 = 1
@@ -559,74 +550,76 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, errn
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func TerminateProcess(handle Handle, exitcode uint32) (errno int) {
+func TerminateProcess(handle Handle, exitcode uint32) (err error) {
r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetExitCodeProcess(handle Handle, exitcode *uint32) (errno int) {
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) {
r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetStartupInfo(startupInfo *StartupInfo) (errno int) {
+func GetStartupInfo(startupInfo *StartupInfo) (err error) {
r1, _, e1 := Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetCurrentProcess() (pseudoHandle Handle, errno int) {
+func GetCurrentProcess() (pseudoHandle Handle, err error) {
r0, _, e1 := Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0)
pseudoHandle = Handle(r0)
if pseudoHandle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) {
+func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) {
+ r1, _, e1 := Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
var _p0 uint32
if bInheritHandle {
_p0 = 1
@@ -636,214 +629,196 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, errno int) {
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) {
r0, _, e1 := Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0)
event = uint32(r0)
if event == 0xffffffff {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) {
r0, _, e1 := Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (errno int) {
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) {
r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileType(filehandle Handle) (n uint32, errno int) {
+func GetFileType(filehandle Handle) (n uint32, err error) {
r0, _, e1 := Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (errno int) {
+func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) {
r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptReleaseContext(provhandle Handle, flags uint32) (errno int) {
+func CryptReleaseContext(provhandle Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (errno int) {
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) {
r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetEnvironmentStrings() (envs *uint16, errno int) {
+func GetEnvironmentStrings() (envs *uint16, err error) {
r0, _, e1 := Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0)
envs = (*uint16)(unsafe.Pointer(r0))
if envs == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FreeEnvironmentStrings(envs *uint16) (errno int) {
+func FreeEnvironmentStrings(envs *uint16) (err error) {
r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) {
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) {
r0, _, e1 := Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetEnvironmentVariable(name *uint16, value *uint16) (errno int) {
+func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (errno int) {
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) {
r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+func GetFileAttributes(name *uint16) (attrs uint32, err error) {
r0, _, e1 := Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
attrs = uint32(r0)
if attrs == INVALID_FILE_ATTRIBUTES {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetFileAttributes(name *uint16, attrs uint32) (errno int) {
+func SetFileAttributes(name *uint16, attrs uint32) (err error) {
r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) {
+ r1, _, e1 := Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -854,350 +829,505 @@ func GetCommandLine() (cmd *uint16) {
return
}
-func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) {
+func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
r0, _, e1 := Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
if argv == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func LocalFree(hmem Handle) (handle Handle, errno int) {
+func LocalFree(hmem Handle) (handle Handle, err error) {
r0, _, e1 := Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0)
handle = Handle(r0)
if handle != 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func SetHandleInformation(handle Handle, mask uint32, flags uint32) (errno int) {
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FlushFileBuffers(handle Handle) (errno int) {
+func FlushFileBuffers(handle Handle) (err error) {
r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, errno int) {
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) {
r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, errno int) {
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, errno int) {
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) {
r0, _, e1 := Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
addr = uintptr(r0)
if addr == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func UnmapViewOfFile(addr uintptr) (errno int) {
+func UnmapViewOfFile(addr uintptr) (err error) {
r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func FlushViewOfFile(addr uintptr, length uintptr) (errno int) {
+func FlushViewOfFile(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func VirtualLock(addr uintptr, length uintptr) (errno int) {
+func VirtualLock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
+func VirtualUnlock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) {
r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
+ }
+ return
+}
+
+func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ var _p0 uint32
+ if watchSubTree {
+ _p0 = 1
} else {
- errno = 0
+ _p0 = 0
+ }
+ r1, _, e1 := Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
+ r0, _, e1 := Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0)
+ store = Handle(r0)
+ if store == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
+ r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0)
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) {
+ r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertCloseStore(store Handle, flags uint32) (err error) {
+ r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) {
+ r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
}
return
}
-func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
+func CertFreeCertificateChain(ctx *CertChainContext) {
+ Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ return
+}
+
+func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen))
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateContext(ctx *CertContext) (err error) {
+ r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) {
+ r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) {
+ r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegCloseKey(key Handle) (regerrno error) {
+ r0, _, _ := Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime)))
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+ r0, _, _ := Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)))
+ if r0 != 0 {
+ regerrno = Errno(r0)
+ }
+ return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
- sockerrno = int(r0)
+ if r0 != 0 {
+ sockerr = Errno(r0)
+ }
return
}
-func WSACleanup() (errno int) {
+func WSACleanup() (err error) {
r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func socket(af int32, typ int32, protocol int32) (handle Handle, errno int) {
+func socket(af int32, typ int32, protocol int32) (handle Handle, err error) {
r0, _, e1 := Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol))
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (errno int) {
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) {
r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func bind(s Handle, name uintptr, namelen int32) (errno int) {
+func bind(s Handle, name uintptr, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func connect(s Handle, name uintptr, namelen int32) (errno int) {
+func connect(s Handle, name uintptr, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func listen(s Handle, backlog int32) (errno int) {
+func listen(s Handle, backlog int32) (err error) {
r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func shutdown(s Handle, how int32) (errno int) {
+func shutdown(s Handle, how int32) (err error) {
r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func Closesocket(s Handle) (errno int) {
+func Closesocket(s Handle) (err error) {
r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (errno int) {
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) {
r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
if int(r1) == 0 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -1207,88 +1337,76 @@ func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen
return
}
-func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) {
r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if int(r1) == -1 {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetHostByName(name string) (h *Hostent, errno int) {
+func GetHostByName(name string) (h *Hostent, err error) {
r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
h = (*Hostent)(unsafe.Pointer(r0))
if h == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
-func GetServByName(name string, proto string) (s *Servent, errno int) {
+func GetServByName(name string, proto string) (s *Servent, err error) {
r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0)
s = (*Servent)(unsafe.Pointer(r0))
if s == nil {
if e1 != 0 {
- errno = int(e1)
+ err = error(e1)
} else {
- errno = EINVAL
+ err = EINVAL
}
- } else {
- errno = 0
}
return
}
@@ -1299,9 +1417,24 @@ func Ntohs(netshort uint16) (u uint16) {
return
}
-func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
+func GetProtoByName(name string) (p *Protoent, err error) {
+ r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ p = (*Protoent)(unsafe.Pointer(r0))
+ if p == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
- status = uint32(r0)
+ if r0 != 0 {
+ status = Errno(r0)
+ }
return
}
@@ -1310,14 +1443,160 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
return
}
-func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
r0, _, _ := Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
- errcode = int(r0)
+ if r0 != 0 {
+ errcode = Errno(r0)
+ }
return
}
-func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) {
r0, _, _ := Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
- errcode = int(r0)
+ if r0 != 0 {
+ errcode = Errno(r0)
+ }
+ return
+}
+
+func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
+ if int(r1)&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
+ if int(r1)&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
+ r0, _, _ := Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = Errno(r0)
+ }
+ return
+}
+
+func NetApiBufferFree(buf *byte) (neterr error) {
+ r0, _, _ := Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = Errno(r0)
+ }
+ return
+}
+
+func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) {
+ r1, _, e1 := Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) {
+ r1, _, e1 := Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetLengthSid(sid *SID) (len uint32) {
+ r0, _, _ := Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ len = uint32(r0)
+ return
+}
+
+func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) {
+ r1, _, e1 := Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func OpenProcessToken(h Handle, access uint32, token *Token) (err error) {
+ r1, _, e1 := Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) {
+ r1, _, e1 := Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
+ r1, _, e1 := Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)))
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
return
}
diff --git a/src/pkg/syscall/zsysctl_openbsd.go b/src/pkg/syscall/zsysctl_openbsd.go
new file mode 100644
index 000000000..fb1342290
--- /dev/null
+++ b/src/pkg/syscall/zsysctl_openbsd.go
@@ -0,0 +1,292 @@
+// mksysctl_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+type mibentry struct {
+ ctlname string
+ ctloid []_C_int
+}
+
+var sysctlMib = []mibentry{
+ {"ddb.console", []_C_int{9, 6}},
+ {"ddb.log", []_C_int{9, 7}},
+ {"ddb.max_line", []_C_int{9, 3}},
+ {"ddb.max_width", []_C_int{9, 2}},
+ {"ddb.panic", []_C_int{9, 5}},
+ {"ddb.radix", []_C_int{9, 1}},
+ {"ddb.tab_stop_width", []_C_int{9, 4}},
+ {"ddb.trigger", []_C_int{9, 8}},
+ {"fs.posix.setuid", []_C_int{3, 1, 1}},
+ {"hw.allowpowerdown", []_C_int{6, 22}},
+ {"hw.byteorder", []_C_int{6, 4}},
+ {"hw.cpuspeed", []_C_int{6, 12}},
+ {"hw.diskcount", []_C_int{6, 10}},
+ {"hw.disknames", []_C_int{6, 8}},
+ {"hw.diskstats", []_C_int{6, 9}},
+ {"hw.machine", []_C_int{6, 1}},
+ {"hw.model", []_C_int{6, 2}},
+ {"hw.ncpu", []_C_int{6, 3}},
+ {"hw.ncpufound", []_C_int{6, 21}},
+ {"hw.pagesize", []_C_int{6, 7}},
+ {"hw.physmem", []_C_int{6, 19}},
+ {"hw.product", []_C_int{6, 15}},
+ {"hw.serialno", []_C_int{6, 17}},
+ {"hw.setperf", []_C_int{6, 13}},
+ {"hw.usermem", []_C_int{6, 20}},
+ {"hw.uuid", []_C_int{6, 18}},
+ {"hw.vendor", []_C_int{6, 14}},
+ {"hw.version", []_C_int{6, 16}},
+ {"kern.arandom", []_C_int{1, 37}},
+ {"kern.argmax", []_C_int{1, 8}},
+ {"kern.boottime", []_C_int{1, 21}},
+ {"kern.bufcachepercent", []_C_int{1, 72}},
+ {"kern.ccpu", []_C_int{1, 45}},
+ {"kern.clockrate", []_C_int{1, 12}},
+ {"kern.consdev", []_C_int{1, 75}},
+ {"kern.cp_time", []_C_int{1, 40}},
+ {"kern.cp_time2", []_C_int{1, 71}},
+ {"kern.cryptodevallowsoft", []_C_int{1, 53}},
+ {"kern.domainname", []_C_int{1, 22}},
+ {"kern.file", []_C_int{1, 15}},
+ {"kern.file2", []_C_int{1, 73}},
+ {"kern.forkstat", []_C_int{1, 42}},
+ {"kern.fscale", []_C_int{1, 46}},
+ {"kern.fsync", []_C_int{1, 33}},
+ {"kern.hostid", []_C_int{1, 11}},
+ {"kern.hostname", []_C_int{1, 10}},
+ {"kern.intrcnt.nintrcnt", []_C_int{1, 63, 1}},
+ {"kern.job_control", []_C_int{1, 19}},
+ {"kern.malloc.buckets", []_C_int{1, 39, 1}},
+ {"kern.malloc.kmemnames", []_C_int{1, 39, 3}},
+ {"kern.maxclusters", []_C_int{1, 67}},
+ {"kern.maxfiles", []_C_int{1, 7}},
+ {"kern.maxlocksperuid", []_C_int{1, 70}},
+ {"kern.maxpartitions", []_C_int{1, 23}},
+ {"kern.maxproc", []_C_int{1, 6}},
+ {"kern.maxvnodes", []_C_int{1, 5}},
+ {"kern.mbstat", []_C_int{1, 59}},
+ {"kern.msgbuf", []_C_int{1, 48}},
+ {"kern.msgbufsize", []_C_int{1, 38}},
+ {"kern.nchstats", []_C_int{1, 41}},
+ {"kern.netlivelocks", []_C_int{1, 76}},
+ {"kern.nfiles", []_C_int{1, 56}},
+ {"kern.ngroups", []_C_int{1, 18}},
+ {"kern.nosuidcoredump", []_C_int{1, 32}},
+ {"kern.nprocs", []_C_int{1, 47}},
+ {"kern.nselcoll", []_C_int{1, 43}},
+ {"kern.numvnodes", []_C_int{1, 58}},
+ {"kern.osrelease", []_C_int{1, 2}},
+ {"kern.osrevision", []_C_int{1, 3}},
+ {"kern.ostype", []_C_int{1, 1}},
+ {"kern.osversion", []_C_int{1, 27}},
+ {"kern.pool_debug", []_C_int{1, 77}},
+ {"kern.posix1version", []_C_int{1, 17}},
+ {"kern.proc", []_C_int{1, 66}},
+ {"kern.random", []_C_int{1, 31}},
+ {"kern.rawpartition", []_C_int{1, 24}},
+ {"kern.rthreads", []_C_int{1, 74}},
+ {"kern.saved_ids", []_C_int{1, 20}},
+ {"kern.securelevel", []_C_int{1, 9}},
+ {"kern.seminfo", []_C_int{1, 61}},
+ {"kern.shminfo", []_C_int{1, 62}},
+ {"kern.somaxconn", []_C_int{1, 28}},
+ {"kern.sominconn", []_C_int{1, 29}},
+ {"kern.splassert", []_C_int{1, 54}},
+ {"kern.stackgap_random", []_C_int{1, 50}},
+ {"kern.sysvipc_info", []_C_int{1, 51}},
+ {"kern.sysvmsg", []_C_int{1, 34}},
+ {"kern.sysvsem", []_C_int{1, 35}},
+ {"kern.sysvshm", []_C_int{1, 36}},
+ {"kern.timecounter.choice", []_C_int{1, 69, 4}},
+ {"kern.timecounter.hardware", []_C_int{1, 69, 3}},
+ {"kern.timecounter.tick", []_C_int{1, 69, 1}},
+ {"kern.timecounter.timestepwarnings", []_C_int{1, 69, 2}},
+ {"kern.tty.maxptys", []_C_int{1, 44, 6}},
+ {"kern.tty.nptys", []_C_int{1, 44, 7}},
+ {"kern.tty.tk_cancc", []_C_int{1, 44, 4}},
+ {"kern.tty.tk_nin", []_C_int{1, 44, 1}},
+ {"kern.tty.tk_nout", []_C_int{1, 44, 2}},
+ {"kern.tty.tk_rawcc", []_C_int{1, 44, 3}},
+ {"kern.tty.ttyinfo", []_C_int{1, 44, 5}},
+ {"kern.ttycount", []_C_int{1, 57}},
+ {"kern.userasymcrypto", []_C_int{1, 60}},
+ {"kern.usercrypto", []_C_int{1, 52}},
+ {"kern.usermount", []_C_int{1, 30}},
+ {"kern.version", []_C_int{1, 4}},
+ {"kern.vnode", []_C_int{1, 13}},
+ {"kern.watchdog.auto", []_C_int{1, 64, 2}},
+ {"kern.watchdog.period", []_C_int{1, 64, 1}},
+ {"net.bpf.bufsize", []_C_int{4, 31, 1}},
+ {"net.bpf.maxbufsize", []_C_int{4, 31, 2}},
+ {"net.inet.ah.enable", []_C_int{4, 2, 51, 1}},
+ {"net.inet.ah.stats", []_C_int{4, 2, 51, 2}},
+ {"net.inet.carp.allow", []_C_int{4, 2, 112, 1}},
+ {"net.inet.carp.log", []_C_int{4, 2, 112, 3}},
+ {"net.inet.carp.preempt", []_C_int{4, 2, 112, 2}},
+ {"net.inet.carp.stats", []_C_int{4, 2, 112, 4}},
+ {"net.inet.divert.recvspace", []_C_int{4, 2, 258, 1}},
+ {"net.inet.divert.sendspace", []_C_int{4, 2, 258, 2}},
+ {"net.inet.divert.stats", []_C_int{4, 2, 258, 3}},
+ {"net.inet.esp.enable", []_C_int{4, 2, 50, 1}},
+ {"net.inet.esp.stats", []_C_int{4, 2, 50, 4}},
+ {"net.inet.esp.udpencap", []_C_int{4, 2, 50, 2}},
+ {"net.inet.esp.udpencap_port", []_C_int{4, 2, 50, 3}},
+ {"net.inet.etherip.allow", []_C_int{4, 2, 97, 1}},
+ {"net.inet.etherip.stats", []_C_int{4, 2, 97, 2}},
+ {"net.inet.gre.allow", []_C_int{4, 2, 47, 1}},
+ {"net.inet.gre.wccp", []_C_int{4, 2, 47, 2}},
+ {"net.inet.icmp.bmcastecho", []_C_int{4, 2, 1, 2}},
+ {"net.inet.icmp.errppslimit", []_C_int{4, 2, 1, 3}},
+ {"net.inet.icmp.maskrepl", []_C_int{4, 2, 1, 1}},
+ {"net.inet.icmp.rediraccept", []_C_int{4, 2, 1, 4}},
+ {"net.inet.icmp.redirtimeout", []_C_int{4, 2, 1, 5}},
+ {"net.inet.icmp.stats", []_C_int{4, 2, 1, 7}},
+ {"net.inet.icmp.tstamprepl", []_C_int{4, 2, 1, 6}},
+ {"net.inet.igmp.stats", []_C_int{4, 2, 2, 1}},
+ {"net.inet.ip.arpqueued", []_C_int{4, 2, 0, 36}},
+ {"net.inet.ip.encdebug", []_C_int{4, 2, 0, 12}},
+ {"net.inet.ip.forwarding", []_C_int{4, 2, 0, 1}},
+ {"net.inet.ip.ifq.congestion", []_C_int{4, 2, 0, 30, 4}},
+ {"net.inet.ip.ifq.drops", []_C_int{4, 2, 0, 30, 3}},
+ {"net.inet.ip.ifq.len", []_C_int{4, 2, 0, 30, 1}},
+ {"net.inet.ip.ifq.maxlen", []_C_int{4, 2, 0, 30, 2}},
+ {"net.inet.ip.maxqueue", []_C_int{4, 2, 0, 11}},
+ {"net.inet.ip.mforwarding", []_C_int{4, 2, 0, 31}},
+ {"net.inet.ip.mrtproto", []_C_int{4, 2, 0, 34}},
+ {"net.inet.ip.mrtstats", []_C_int{4, 2, 0, 35}},
+ {"net.inet.ip.mtu", []_C_int{4, 2, 0, 4}},
+ {"net.inet.ip.mtudisc", []_C_int{4, 2, 0, 27}},
+ {"net.inet.ip.mtudisctimeout", []_C_int{4, 2, 0, 28}},
+ {"net.inet.ip.multipath", []_C_int{4, 2, 0, 32}},
+ {"net.inet.ip.portfirst", []_C_int{4, 2, 0, 7}},
+ {"net.inet.ip.porthifirst", []_C_int{4, 2, 0, 9}},
+ {"net.inet.ip.porthilast", []_C_int{4, 2, 0, 10}},
+ {"net.inet.ip.portlast", []_C_int{4, 2, 0, 8}},
+ {"net.inet.ip.redirect", []_C_int{4, 2, 0, 2}},
+ {"net.inet.ip.sourceroute", []_C_int{4, 2, 0, 5}},
+ {"net.inet.ip.stats", []_C_int{4, 2, 0, 33}},
+ {"net.inet.ip.ttl", []_C_int{4, 2, 0, 3}},
+ {"net.inet.ipcomp.enable", []_C_int{4, 2, 108, 1}},
+ {"net.inet.ipcomp.stats", []_C_int{4, 2, 108, 2}},
+ {"net.inet.ipip.allow", []_C_int{4, 2, 4, 1}},
+ {"net.inet.ipip.stats", []_C_int{4, 2, 4, 2}},
+ {"net.inet.mobileip.allow", []_C_int{4, 2, 55, 1}},
+ {"net.inet.pfsync.stats", []_C_int{4, 2, 240, 1}},
+ {"net.inet.pim.stats", []_C_int{4, 2, 103, 1}},
+ {"net.inet.tcp.ackonpush", []_C_int{4, 2, 6, 13}},
+ {"net.inet.tcp.always_keepalive", []_C_int{4, 2, 6, 22}},
+ {"net.inet.tcp.baddynamic", []_C_int{4, 2, 6, 6}},
+ {"net.inet.tcp.drop", []_C_int{4, 2, 6, 19}},
+ {"net.inet.tcp.ecn", []_C_int{4, 2, 6, 14}},
+ {"net.inet.tcp.ident", []_C_int{4, 2, 6, 9}},
+ {"net.inet.tcp.keepidle", []_C_int{4, 2, 6, 3}},
+ {"net.inet.tcp.keepinittime", []_C_int{4, 2, 6, 2}},
+ {"net.inet.tcp.keepintvl", []_C_int{4, 2, 6, 4}},
+ {"net.inet.tcp.mssdflt", []_C_int{4, 2, 6, 11}},
+ {"net.inet.tcp.reasslimit", []_C_int{4, 2, 6, 18}},
+ {"net.inet.tcp.rfc1323", []_C_int{4, 2, 6, 1}},
+ {"net.inet.tcp.rfc3390", []_C_int{4, 2, 6, 17}},
+ {"net.inet.tcp.rstppslimit", []_C_int{4, 2, 6, 12}},
+ {"net.inet.tcp.sack", []_C_int{4, 2, 6, 10}},
+ {"net.inet.tcp.sackholelimit", []_C_int{4, 2, 6, 20}},
+ {"net.inet.tcp.slowhz", []_C_int{4, 2, 6, 5}},
+ {"net.inet.tcp.stats", []_C_int{4, 2, 6, 21}},
+ {"net.inet.tcp.synbucketlimit", []_C_int{4, 2, 6, 16}},
+ {"net.inet.tcp.syncachelimit", []_C_int{4, 2, 6, 15}},
+ {"net.inet.udp.baddynamic", []_C_int{4, 2, 17, 2}},
+ {"net.inet.udp.checksum", []_C_int{4, 2, 17, 1}},
+ {"net.inet.udp.recvspace", []_C_int{4, 2, 17, 3}},
+ {"net.inet.udp.sendspace", []_C_int{4, 2, 17, 4}},
+ {"net.inet.udp.stats", []_C_int{4, 2, 17, 5}},
+ {"net.inet6.divert.recvspace", []_C_int{4, 24, 86, 1}},
+ {"net.inet6.divert.sendspace", []_C_int{4, 24, 86, 2}},
+ {"net.inet6.divert.stats", []_C_int{4, 24, 86, 3}},
+ {"net.inet6.icmp6.errppslimit", []_C_int{4, 24, 30, 14}},
+ {"net.inet6.icmp6.mtudisc_hiwat", []_C_int{4, 24, 30, 16}},
+ {"net.inet6.icmp6.mtudisc_lowat", []_C_int{4, 24, 30, 17}},
+ {"net.inet6.icmp6.nd6_debug", []_C_int{4, 24, 30, 18}},
+ {"net.inet6.icmp6.nd6_delay", []_C_int{4, 24, 30, 8}},
+ {"net.inet6.icmp6.nd6_maxnudhint", []_C_int{4, 24, 30, 15}},
+ {"net.inet6.icmp6.nd6_mmaxtries", []_C_int{4, 24, 30, 10}},
+ {"net.inet6.icmp6.nd6_prune", []_C_int{4, 24, 30, 6}},
+ {"net.inet6.icmp6.nd6_umaxtries", []_C_int{4, 24, 30, 9}},
+ {"net.inet6.icmp6.nd6_useloopback", []_C_int{4, 24, 30, 11}},
+ {"net.inet6.icmp6.nodeinfo", []_C_int{4, 24, 30, 13}},
+ {"net.inet6.icmp6.rediraccept", []_C_int{4, 24, 30, 2}},
+ {"net.inet6.icmp6.redirtimeout", []_C_int{4, 24, 30, 3}},
+ {"net.inet6.ip6.accept_rtadv", []_C_int{4, 24, 17, 12}},
+ {"net.inet6.ip6.auto_flowlabel", []_C_int{4, 24, 17, 17}},
+ {"net.inet6.ip6.dad_count", []_C_int{4, 24, 17, 16}},
+ {"net.inet6.ip6.dad_pending", []_C_int{4, 24, 17, 49}},
+ {"net.inet6.ip6.defmcasthlim", []_C_int{4, 24, 17, 18}},
+ {"net.inet6.ip6.forwarding", []_C_int{4, 24, 17, 1}},
+ {"net.inet6.ip6.forwsrcrt", []_C_int{4, 24, 17, 5}},
+ {"net.inet6.ip6.hdrnestlimit", []_C_int{4, 24, 17, 15}},
+ {"net.inet6.ip6.hlim", []_C_int{4, 24, 17, 3}},
+ {"net.inet6.ip6.kame_version", []_C_int{4, 24, 17, 20}},
+ {"net.inet6.ip6.keepfaith", []_C_int{4, 24, 17, 13}},
+ {"net.inet6.ip6.log_interval", []_C_int{4, 24, 17, 14}},
+ {"net.inet6.ip6.maxdynroutes", []_C_int{4, 24, 17, 48}},
+ {"net.inet6.ip6.maxfragpackets", []_C_int{4, 24, 17, 9}},
+ {"net.inet6.ip6.maxfrags", []_C_int{4, 24, 17, 41}},
+ {"net.inet6.ip6.maxifdefrouters", []_C_int{4, 24, 17, 47}},
+ {"net.inet6.ip6.maxifprefixes", []_C_int{4, 24, 17, 46}},
+ {"net.inet6.ip6.mforwarding", []_C_int{4, 24, 17, 42}},
+ {"net.inet6.ip6.mrtproto", []_C_int{4, 24, 17, 8}},
+ {"net.inet6.ip6.mtu", []_C_int{4, 24, 17, 4}},
+ {"net.inet6.ip6.multicast_mtudisc", []_C_int{4, 24, 17, 44}},
+ {"net.inet6.ip6.multipath", []_C_int{4, 24, 17, 43}},
+ {"net.inet6.ip6.neighborgcthresh", []_C_int{4, 24, 17, 45}},
+ {"net.inet6.ip6.redirect", []_C_int{4, 24, 17, 2}},
+ {"net.inet6.ip6.rr_prune", []_C_int{4, 24, 17, 22}},
+ {"net.inet6.ip6.sourcecheck", []_C_int{4, 24, 17, 10}},
+ {"net.inet6.ip6.sourcecheck_logint", []_C_int{4, 24, 17, 11}},
+ {"net.inet6.ip6.use_deprecated", []_C_int{4, 24, 17, 21}},
+ {"net.inet6.ip6.v6only", []_C_int{4, 24, 17, 24}},
+ {"net.key.sadb_dump", []_C_int{4, 30, 1}},
+ {"net.key.spd_dump", []_C_int{4, 30, 2}},
+ {"net.mpls.ifq.congestion", []_C_int{4, 33, 3, 4}},
+ {"net.mpls.ifq.drops", []_C_int{4, 33, 3, 3}},
+ {"net.mpls.ifq.len", []_C_int{4, 33, 3, 1}},
+ {"net.mpls.ifq.maxlen", []_C_int{4, 33, 3, 2}},
+ {"net.mpls.mapttl_ip", []_C_int{4, 33, 5}},
+ {"net.mpls.mapttl_ip6", []_C_int{4, 33, 6}},
+ {"net.mpls.maxloop_inkernel", []_C_int{4, 33, 4}},
+ {"net.mpls.ttl", []_C_int{4, 33, 2}},
+ {"net.pflow.stats", []_C_int{4, 34, 1}},
+ {"net.pipex.enable", []_C_int{4, 35, 1}},
+ {"user.bc_base_max", []_C_int{8, 2}},
+ {"user.bc_dim_max", []_C_int{8, 3}},
+ {"user.bc_scale_max", []_C_int{8, 4}},
+ {"user.bc_string_max", []_C_int{8, 5}},
+ {"user.coll_weights_max", []_C_int{8, 6}},
+ {"user.cs_path", []_C_int{8, 1}},
+ {"user.expr_nest_max", []_C_int{8, 7}},
+ {"user.line_max", []_C_int{8, 8}},
+ {"user.posix2_c_bind", []_C_int{8, 11}},
+ {"user.posix2_c_dev", []_C_int{8, 12}},
+ {"user.posix2_char_term", []_C_int{8, 13}},
+ {"user.posix2_fort_dev", []_C_int{8, 14}},
+ {"user.posix2_fort_run", []_C_int{8, 15}},
+ {"user.posix2_localedef", []_C_int{8, 16}},
+ {"user.posix2_sw_dev", []_C_int{8, 17}},
+ {"user.posix2_upe", []_C_int{8, 18}},
+ {"user.posix2_version", []_C_int{8, 10}},
+ {"user.re_dup_max", []_C_int{8, 9}},
+ {"user.stream_max", []_C_int{8, 19}},
+ {"user.tzname_max", []_C_int{8, 20}},
+ {"vm.anonmin", []_C_int{2, 7}},
+ {"vm.loadavg", []_C_int{2, 2}},
+ {"vm.maxslp", []_C_int{2, 10}},
+ {"vm.nkmempages", []_C_int{2, 6}},
+ {"vm.psstrings", []_C_int{2, 3}},
+ {"vm.swapencrypt.enable", []_C_int{2, 5, 0}},
+ {"vm.swapencrypt.keyscreated", []_C_int{2, 5, 1}},
+ {"vm.swapencrypt.keysdeleted", []_C_int{2, 5, 2}},
+ {"vm.uspace", []_C_int{2, 11}},
+ {"vm.uvmexp", []_C_int{2, 4}},
+ {"vm.vmmeter", []_C_int{2, 1}},
+ {"vm.vnodemin", []_C_int{2, 9}},
+ {"vm.vtextmin", []_C_int{2, 8}},
+}
diff --git a/src/pkg/syscall/zsysnum_darwin_386.go b/src/pkg/syscall/zsysnum_darwin_386.go
index 50aec39f1..abdef7743 100644
--- a/src/pkg/syscall/zsysnum_darwin_386.go
+++ b/src/pkg/syscall/zsysnum_darwin_386.go
@@ -4,352 +4,357 @@
package syscall
const (
- SYS_SYSCALL = 0
- SYS_EXIT = 1
- SYS_FORK = 2
- SYS_READ = 3
- SYS_WRITE = 4
- SYS_OPEN = 5
- SYS_CLOSE = 6
- SYS_WAIT4 = 7
- SYS_LINK = 9
- SYS_UNLINK = 10
- SYS_CHDIR = 12
- SYS_FCHDIR = 13
- SYS_MKNOD = 14
- SYS_CHMOD = 15
- SYS_CHOWN = 16
- SYS_GETFSSTAT = 18
- SYS_GETPID = 20
- SYS_SETUID = 23
- SYS_GETUID = 24
- SYS_GETEUID = 25
- SYS_PTRACE = 26
- SYS_RECVMSG = 27
- SYS_SENDMSG = 28
- SYS_RECVFROM = 29
- SYS_ACCEPT = 30
- SYS_GETPEERNAME = 31
- SYS_GETSOCKNAME = 32
- SYS_ACCESS = 33
- SYS_CHFLAGS = 34
- SYS_FCHFLAGS = 35
- SYS_SYNC = 36
- SYS_KILL = 37
- SYS_GETPPID = 39
- SYS_DUP = 41
- SYS_PIPE = 42
- SYS_GETEGID = 43
- SYS_PROFIL = 44
- SYS_SIGACTION = 46
- SYS_GETGID = 47
- SYS_SIGPROCMASK = 48
- SYS_GETLOGIN = 49
- SYS_SETLOGIN = 50
- SYS_ACCT = 51
- SYS_SIGPENDING = 52
- SYS_SIGALTSTACK = 53
- SYS_IOCTL = 54
- SYS_REBOOT = 55
- SYS_REVOKE = 56
- SYS_SYMLINK = 57
- SYS_READLINK = 58
- SYS_EXECVE = 59
- SYS_UMASK = 60
- SYS_CHROOT = 61
- SYS_MSYNC = 65
- SYS_VFORK = 66
- SYS_MUNMAP = 73
- SYS_MPROTECT = 74
- SYS_MADVISE = 75
- SYS_MINCORE = 78
- SYS_GETGROUPS = 79
- SYS_SETGROUPS = 80
- SYS_GETPGRP = 81
- SYS_SETPGID = 82
- SYS_SETITIMER = 83
- SYS_SWAPON = 85
- SYS_GETITIMER = 86
- SYS_GETDTABLESIZE = 89
- SYS_DUP2 = 90
- SYS_FCNTL = 92
- SYS_SELECT = 93
- SYS_FSYNC = 95
- SYS_SETPRIORITY = 96
- SYS_SOCKET = 97
- SYS_CONNECT = 98
- SYS_GETPRIORITY = 100
- SYS_BIND = 104
- SYS_SETSOCKOPT = 105
- SYS_LISTEN = 106
- SYS_SIGSUSPEND = 111
- SYS_GETTIMEOFDAY = 116
- SYS_GETRUSAGE = 117
- SYS_GETSOCKOPT = 118
- SYS_READV = 120
- SYS_WRITEV = 121
- SYS_SETTIMEOFDAY = 122
- SYS_FCHOWN = 123
- SYS_FCHMOD = 124
- SYS_SETREUID = 126
- SYS_SETREGID = 127
- SYS_RENAME = 128
- SYS_FLOCK = 131
- SYS_MKFIFO = 132
- SYS_SENDTO = 133
- SYS_SHUTDOWN = 134
- SYS_SOCKETPAIR = 135
- SYS_MKDIR = 136
- SYS_RMDIR = 137
- SYS_UTIMES = 138
- SYS_FUTIMES = 139
- SYS_ADJTIME = 140
- SYS_GETHOSTUUID = 142
- SYS_SETSID = 147
- SYS_GETPGID = 151
- SYS_SETPRIVEXEC = 152
- SYS_PREAD = 153
- SYS_PWRITE = 154
- SYS_NFSSVC = 155
- SYS_STATFS = 157
- SYS_FSTATFS = 158
- SYS_UNMOUNT = 159
- SYS_GETFH = 161
- SYS_QUOTACTL = 165
- SYS_MOUNT = 167
- SYS_CSOPS = 169
- SYS_WAITID = 173
- SYS_ADD_PROFIL = 176
- SYS_KDEBUG_TRACE = 180
- SYS_SETGID = 181
- SYS_SETEGID = 182
- SYS_SETEUID = 183
- SYS_SIGRETURN = 184
- SYS_CHUD = 185
- SYS_FDATASYNC = 187
- SYS_STAT = 188
- SYS_FSTAT = 189
- SYS_LSTAT = 190
- SYS_PATHCONF = 191
- SYS_FPATHCONF = 192
- SYS_GETRLIMIT = 194
- SYS_SETRLIMIT = 195
- SYS_GETDIRENTRIES = 196
- SYS_MMAP = 197
- SYS_LSEEK = 199
- SYS_TRUNCATE = 200
- SYS_FTRUNCATE = 201
- SYS___SYSCTL = 202
- SYS_MLOCK = 203
- SYS_MUNLOCK = 204
- SYS_UNDELETE = 205
- SYS_ATSOCKET = 206
- SYS_ATGETMSG = 207
- SYS_ATPUTMSG = 208
- SYS_ATPSNDREQ = 209
- SYS_ATPSNDRSP = 210
- SYS_ATPGETREQ = 211
- SYS_ATPGETRSP = 212
- SYS_MKCOMPLEX = 216
- SYS_STATV = 217
- SYS_LSTATV = 218
- SYS_FSTATV = 219
- SYS_GETATTRLIST = 220
- SYS_SETATTRLIST = 221
- SYS_GETDIRENTRIESATTR = 222
- SYS_EXCHANGEDATA = 223
- SYS_SEARCHFS = 225
- SYS_DELETE = 226
- SYS_COPYFILE = 227
- SYS_FGETATTRLIST = 228
- SYS_FSETATTRLIST = 229
- SYS_POLL = 230
- SYS_WATCHEVENT = 231
- SYS_WAITEVENT = 232
- SYS_MODWATCH = 233
- SYS_GETXATTR = 234
- SYS_FGETXATTR = 235
- SYS_SETXATTR = 236
- SYS_FSETXATTR = 237
- SYS_REMOVEXATTR = 238
- SYS_FREMOVEXATTR = 239
- SYS_LISTXATTR = 240
- SYS_FLISTXATTR = 241
- SYS_FSCTL = 242
- SYS_INITGROUPS = 243
- SYS_POSIX_SPAWN = 244
- SYS_FFSCTL = 245
- SYS_NFSCLNT = 247
- SYS_FHOPEN = 248
- SYS_MINHERIT = 250
- SYS_SEMSYS = 251
- SYS_MSGSYS = 252
- SYS_SHMSYS = 253
- SYS_SEMCTL = 254
- SYS_SEMGET = 255
- SYS_SEMOP = 256
- SYS_MSGCTL = 258
- SYS_MSGGET = 259
- SYS_MSGSND = 260
- SYS_MSGRCV = 261
- SYS_SHMAT = 262
- SYS_SHMCTL = 263
- SYS_SHMDT = 264
- SYS_SHMGET = 265
- SYS_SHM_OPEN = 266
- SYS_SHM_UNLINK = 267
- SYS_SEM_OPEN = 268
- SYS_SEM_CLOSE = 269
- SYS_SEM_UNLINK = 270
- SYS_SEM_WAIT = 271
- SYS_SEM_TRYWAIT = 272
- SYS_SEM_POST = 273
- SYS_SEM_GETVALUE = 274
- SYS_SEM_INIT = 275
- SYS_SEM_DESTROY = 276
- SYS_OPEN_EXTENDED = 277
- SYS_UMASK_EXTENDED = 278
- SYS_STAT_EXTENDED = 279
- SYS_LSTAT_EXTENDED = 280
- SYS_FSTAT_EXTENDED = 281
- SYS_CHMOD_EXTENDED = 282
- SYS_FCHMOD_EXTENDED = 283
- SYS_ACCESS_EXTENDED = 284
- SYS_SETTID = 285
- SYS_GETTID = 286
- SYS_SETSGROUPS = 287
- SYS_GETSGROUPS = 288
- SYS_SETWGROUPS = 289
- SYS_GETWGROUPS = 290
- SYS_MKFIFO_EXTENDED = 291
- SYS_MKDIR_EXTENDED = 292
- SYS_IDENTITYSVC = 293
- SYS_SHARED_REGION_CHECK_NP = 294
- SYS_SHARED_REGION_MAP_NP = 295
- SYS_VM_PRESSURE_MONITOR = 296
- SYS_PSYNCH_RW_LONGRDLOCK = 297
- SYS_PSYNCH_RW_YIELDWRLOCK = 298
- SYS_PSYNCH_RW_DOWNGRADE = 299
- SYS_PSYNCH_RW_UPGRADE = 300
- SYS_PSYNCH_MUTEXWAIT = 301
- SYS_PSYNCH_MUTEXDROP = 302
- SYS_PSYNCH_CVBROAD = 303
- SYS_PSYNCH_CVSIGNAL = 304
- SYS_PSYNCH_CVWAIT = 305
- SYS_PSYNCH_RW_RDLOCK = 306
- SYS_PSYNCH_RW_WRLOCK = 307
- SYS_PSYNCH_RW_UNLOCK = 308
- SYS_PSYNCH_RW_UNLOCK2 = 309
- SYS_GETSID = 310
- SYS_SETTID_WITH_PID = 311
- SYS_AIO_FSYNC = 313
- SYS_AIO_RETURN = 314
- SYS_AIO_SUSPEND = 315
- SYS_AIO_CANCEL = 316
- SYS_AIO_ERROR = 317
- SYS_AIO_READ = 318
- SYS_AIO_WRITE = 319
- SYS_LIO_LISTIO = 320
- SYS_IOPOLICYSYS = 322
- SYS_MLOCKALL = 324
- SYS_MUNLOCKALL = 325
- SYS_ISSETUGID = 327
- SYS___PTHREAD_KILL = 328
- SYS___PTHREAD_SIGMASK = 329
- SYS___SIGWAIT = 330
- SYS___DISABLE_THREADSIGNAL = 331
- SYS___PTHREAD_MARKCANCEL = 332
- SYS___PTHREAD_CANCELED = 333
- SYS___SEMWAIT_SIGNAL = 334
- SYS_PROC_INFO = 336
- SYS_SENDFILE = 337
- SYS_STAT64 = 338
- SYS_FSTAT64 = 339
- SYS_LSTAT64 = 340
- SYS_STAT64_EXTENDED = 341
- SYS_LSTAT64_EXTENDED = 342
- SYS_FSTAT64_EXTENDED = 343
- SYS_GETDIRENTRIES64 = 344
- SYS_STATFS64 = 345
- SYS_FSTATFS64 = 346
- SYS_GETFSSTAT64 = 347
- SYS___PTHREAD_CHDIR = 348
- SYS___PTHREAD_FCHDIR = 349
- SYS_AUDIT = 350
- SYS_AUDITON = 351
- SYS_GETAUID = 353
- SYS_SETAUID = 354
- SYS_GETAUDIT = 355
- SYS_SETAUDIT = 356
- SYS_GETAUDIT_ADDR = 357
- SYS_SETAUDIT_ADDR = 358
- SYS_AUDITCTL = 359
- SYS_BSDTHREAD_CREATE = 360
- SYS_BSDTHREAD_TERMINATE = 361
- SYS_KQUEUE = 362
- SYS_KEVENT = 363
- SYS_LCHOWN = 364
- SYS_STACK_SNAPSHOT = 365
- SYS_BSDTHREAD_REGISTER = 366
- SYS_WORKQ_OPEN = 367
- SYS_WORKQ_KERNRETURN = 368
- SYS_KEVENT64 = 369
- SYS___OLD_SEMWAIT_SIGNAL = 370
- SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
- SYS_THREAD_SELFID = 372
- SYS___MAC_EXECVE = 380
- SYS___MAC_SYSCALL = 381
- SYS___MAC_GET_FILE = 382
- SYS___MAC_SET_FILE = 383
- SYS___MAC_GET_LINK = 384
- SYS___MAC_SET_LINK = 385
- SYS___MAC_GET_PROC = 386
- SYS___MAC_SET_PROC = 387
- SYS___MAC_GET_FD = 388
- SYS___MAC_SET_FD = 389
- SYS___MAC_GET_PID = 390
- SYS___MAC_GET_LCID = 391
- SYS___MAC_GET_LCTX = 392
- SYS___MAC_SET_LCTX = 393
- SYS_SETLCID = 394
- SYS_GETLCID = 395
- SYS_READ_NOCANCEL = 396
- SYS_WRITE_NOCANCEL = 397
- SYS_OPEN_NOCANCEL = 398
- SYS_CLOSE_NOCANCEL = 399
- SYS_WAIT4_NOCANCEL = 400
- SYS_RECVMSG_NOCANCEL = 401
- SYS_SENDMSG_NOCANCEL = 402
- SYS_RECVFROM_NOCANCEL = 403
- SYS_ACCEPT_NOCANCEL = 404
- SYS_MSYNC_NOCANCEL = 405
- SYS_FCNTL_NOCANCEL = 406
- SYS_SELECT_NOCANCEL = 407
- SYS_FSYNC_NOCANCEL = 408
- SYS_CONNECT_NOCANCEL = 409
- SYS_SIGSUSPEND_NOCANCEL = 410
- SYS_READV_NOCANCEL = 411
- SYS_WRITEV_NOCANCEL = 412
- SYS_SENDTO_NOCANCEL = 413
- SYS_PREAD_NOCANCEL = 414
- SYS_PWRITE_NOCANCEL = 415
- SYS_WAITID_NOCANCEL = 416
- SYS_POLL_NOCANCEL = 417
- SYS_MSGSND_NOCANCEL = 418
- SYS_MSGRCV_NOCANCEL = 419
- SYS_SEM_WAIT_NOCANCEL = 420
- SYS_AIO_SUSPEND_NOCANCEL = 421
- SYS___SIGWAIT_NOCANCEL = 422
- SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
- SYS___MAC_MOUNT = 424
- SYS___MAC_GET_MOUNT = 425
- SYS___MAC_GETFSSTAT = 426
- SYS_FSGETPATH = 427
- SYS_AUDIT_SESSION_SELF = 428
- SYS_AUDIT_SESSION_JOIN = 429
- SYS_PID_SUSPEND = 430
- SYS_PID_RESUME = 431
- SYS_FILEPORT_MAKEPORT = 432
- SYS_FILEPORT_MAKEFD = 433
- SYS_MAXSYSCALL = 434
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_PSYNCH_CVCLRPREPOST = 312
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_PROCESS_POLICY = 323
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_FILEPORT_MAKEPORT = 430
+ SYS_FILEPORT_MAKEFD = 431
+ SYS_AUDIT_SESSION_PORT = 432
+ SYS_PID_SUSPEND = 433
+ SYS_PID_RESUME = 434
+ SYS_PID_HIBERNATE = 435
+ SYS_PID_SHUTDOWN_SOCKETS = 436
+ SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438
+ SYS_MAXSYSCALL = 439
)
diff --git a/src/pkg/syscall/zsysnum_darwin_amd64.go b/src/pkg/syscall/zsysnum_darwin_amd64.go
index 50aec39f1..abdef7743 100644
--- a/src/pkg/syscall/zsysnum_darwin_amd64.go
+++ b/src/pkg/syscall/zsysnum_darwin_amd64.go
@@ -4,352 +4,357 @@
package syscall
const (
- SYS_SYSCALL = 0
- SYS_EXIT = 1
- SYS_FORK = 2
- SYS_READ = 3
- SYS_WRITE = 4
- SYS_OPEN = 5
- SYS_CLOSE = 6
- SYS_WAIT4 = 7
- SYS_LINK = 9
- SYS_UNLINK = 10
- SYS_CHDIR = 12
- SYS_FCHDIR = 13
- SYS_MKNOD = 14
- SYS_CHMOD = 15
- SYS_CHOWN = 16
- SYS_GETFSSTAT = 18
- SYS_GETPID = 20
- SYS_SETUID = 23
- SYS_GETUID = 24
- SYS_GETEUID = 25
- SYS_PTRACE = 26
- SYS_RECVMSG = 27
- SYS_SENDMSG = 28
- SYS_RECVFROM = 29
- SYS_ACCEPT = 30
- SYS_GETPEERNAME = 31
- SYS_GETSOCKNAME = 32
- SYS_ACCESS = 33
- SYS_CHFLAGS = 34
- SYS_FCHFLAGS = 35
- SYS_SYNC = 36
- SYS_KILL = 37
- SYS_GETPPID = 39
- SYS_DUP = 41
- SYS_PIPE = 42
- SYS_GETEGID = 43
- SYS_PROFIL = 44
- SYS_SIGACTION = 46
- SYS_GETGID = 47
- SYS_SIGPROCMASK = 48
- SYS_GETLOGIN = 49
- SYS_SETLOGIN = 50
- SYS_ACCT = 51
- SYS_SIGPENDING = 52
- SYS_SIGALTSTACK = 53
- SYS_IOCTL = 54
- SYS_REBOOT = 55
- SYS_REVOKE = 56
- SYS_SYMLINK = 57
- SYS_READLINK = 58
- SYS_EXECVE = 59
- SYS_UMASK = 60
- SYS_CHROOT = 61
- SYS_MSYNC = 65
- SYS_VFORK = 66
- SYS_MUNMAP = 73
- SYS_MPROTECT = 74
- SYS_MADVISE = 75
- SYS_MINCORE = 78
- SYS_GETGROUPS = 79
- SYS_SETGROUPS = 80
- SYS_GETPGRP = 81
- SYS_SETPGID = 82
- SYS_SETITIMER = 83
- SYS_SWAPON = 85
- SYS_GETITIMER = 86
- SYS_GETDTABLESIZE = 89
- SYS_DUP2 = 90
- SYS_FCNTL = 92
- SYS_SELECT = 93
- SYS_FSYNC = 95
- SYS_SETPRIORITY = 96
- SYS_SOCKET = 97
- SYS_CONNECT = 98
- SYS_GETPRIORITY = 100
- SYS_BIND = 104
- SYS_SETSOCKOPT = 105
- SYS_LISTEN = 106
- SYS_SIGSUSPEND = 111
- SYS_GETTIMEOFDAY = 116
- SYS_GETRUSAGE = 117
- SYS_GETSOCKOPT = 118
- SYS_READV = 120
- SYS_WRITEV = 121
- SYS_SETTIMEOFDAY = 122
- SYS_FCHOWN = 123
- SYS_FCHMOD = 124
- SYS_SETREUID = 126
- SYS_SETREGID = 127
- SYS_RENAME = 128
- SYS_FLOCK = 131
- SYS_MKFIFO = 132
- SYS_SENDTO = 133
- SYS_SHUTDOWN = 134
- SYS_SOCKETPAIR = 135
- SYS_MKDIR = 136
- SYS_RMDIR = 137
- SYS_UTIMES = 138
- SYS_FUTIMES = 139
- SYS_ADJTIME = 140
- SYS_GETHOSTUUID = 142
- SYS_SETSID = 147
- SYS_GETPGID = 151
- SYS_SETPRIVEXEC = 152
- SYS_PREAD = 153
- SYS_PWRITE = 154
- SYS_NFSSVC = 155
- SYS_STATFS = 157
- SYS_FSTATFS = 158
- SYS_UNMOUNT = 159
- SYS_GETFH = 161
- SYS_QUOTACTL = 165
- SYS_MOUNT = 167
- SYS_CSOPS = 169
- SYS_WAITID = 173
- SYS_ADD_PROFIL = 176
- SYS_KDEBUG_TRACE = 180
- SYS_SETGID = 181
- SYS_SETEGID = 182
- SYS_SETEUID = 183
- SYS_SIGRETURN = 184
- SYS_CHUD = 185
- SYS_FDATASYNC = 187
- SYS_STAT = 188
- SYS_FSTAT = 189
- SYS_LSTAT = 190
- SYS_PATHCONF = 191
- SYS_FPATHCONF = 192
- SYS_GETRLIMIT = 194
- SYS_SETRLIMIT = 195
- SYS_GETDIRENTRIES = 196
- SYS_MMAP = 197
- SYS_LSEEK = 199
- SYS_TRUNCATE = 200
- SYS_FTRUNCATE = 201
- SYS___SYSCTL = 202
- SYS_MLOCK = 203
- SYS_MUNLOCK = 204
- SYS_UNDELETE = 205
- SYS_ATSOCKET = 206
- SYS_ATGETMSG = 207
- SYS_ATPUTMSG = 208
- SYS_ATPSNDREQ = 209
- SYS_ATPSNDRSP = 210
- SYS_ATPGETREQ = 211
- SYS_ATPGETRSP = 212
- SYS_MKCOMPLEX = 216
- SYS_STATV = 217
- SYS_LSTATV = 218
- SYS_FSTATV = 219
- SYS_GETATTRLIST = 220
- SYS_SETATTRLIST = 221
- SYS_GETDIRENTRIESATTR = 222
- SYS_EXCHANGEDATA = 223
- SYS_SEARCHFS = 225
- SYS_DELETE = 226
- SYS_COPYFILE = 227
- SYS_FGETATTRLIST = 228
- SYS_FSETATTRLIST = 229
- SYS_POLL = 230
- SYS_WATCHEVENT = 231
- SYS_WAITEVENT = 232
- SYS_MODWATCH = 233
- SYS_GETXATTR = 234
- SYS_FGETXATTR = 235
- SYS_SETXATTR = 236
- SYS_FSETXATTR = 237
- SYS_REMOVEXATTR = 238
- SYS_FREMOVEXATTR = 239
- SYS_LISTXATTR = 240
- SYS_FLISTXATTR = 241
- SYS_FSCTL = 242
- SYS_INITGROUPS = 243
- SYS_POSIX_SPAWN = 244
- SYS_FFSCTL = 245
- SYS_NFSCLNT = 247
- SYS_FHOPEN = 248
- SYS_MINHERIT = 250
- SYS_SEMSYS = 251
- SYS_MSGSYS = 252
- SYS_SHMSYS = 253
- SYS_SEMCTL = 254
- SYS_SEMGET = 255
- SYS_SEMOP = 256
- SYS_MSGCTL = 258
- SYS_MSGGET = 259
- SYS_MSGSND = 260
- SYS_MSGRCV = 261
- SYS_SHMAT = 262
- SYS_SHMCTL = 263
- SYS_SHMDT = 264
- SYS_SHMGET = 265
- SYS_SHM_OPEN = 266
- SYS_SHM_UNLINK = 267
- SYS_SEM_OPEN = 268
- SYS_SEM_CLOSE = 269
- SYS_SEM_UNLINK = 270
- SYS_SEM_WAIT = 271
- SYS_SEM_TRYWAIT = 272
- SYS_SEM_POST = 273
- SYS_SEM_GETVALUE = 274
- SYS_SEM_INIT = 275
- SYS_SEM_DESTROY = 276
- SYS_OPEN_EXTENDED = 277
- SYS_UMASK_EXTENDED = 278
- SYS_STAT_EXTENDED = 279
- SYS_LSTAT_EXTENDED = 280
- SYS_FSTAT_EXTENDED = 281
- SYS_CHMOD_EXTENDED = 282
- SYS_FCHMOD_EXTENDED = 283
- SYS_ACCESS_EXTENDED = 284
- SYS_SETTID = 285
- SYS_GETTID = 286
- SYS_SETSGROUPS = 287
- SYS_GETSGROUPS = 288
- SYS_SETWGROUPS = 289
- SYS_GETWGROUPS = 290
- SYS_MKFIFO_EXTENDED = 291
- SYS_MKDIR_EXTENDED = 292
- SYS_IDENTITYSVC = 293
- SYS_SHARED_REGION_CHECK_NP = 294
- SYS_SHARED_REGION_MAP_NP = 295
- SYS_VM_PRESSURE_MONITOR = 296
- SYS_PSYNCH_RW_LONGRDLOCK = 297
- SYS_PSYNCH_RW_YIELDWRLOCK = 298
- SYS_PSYNCH_RW_DOWNGRADE = 299
- SYS_PSYNCH_RW_UPGRADE = 300
- SYS_PSYNCH_MUTEXWAIT = 301
- SYS_PSYNCH_MUTEXDROP = 302
- SYS_PSYNCH_CVBROAD = 303
- SYS_PSYNCH_CVSIGNAL = 304
- SYS_PSYNCH_CVWAIT = 305
- SYS_PSYNCH_RW_RDLOCK = 306
- SYS_PSYNCH_RW_WRLOCK = 307
- SYS_PSYNCH_RW_UNLOCK = 308
- SYS_PSYNCH_RW_UNLOCK2 = 309
- SYS_GETSID = 310
- SYS_SETTID_WITH_PID = 311
- SYS_AIO_FSYNC = 313
- SYS_AIO_RETURN = 314
- SYS_AIO_SUSPEND = 315
- SYS_AIO_CANCEL = 316
- SYS_AIO_ERROR = 317
- SYS_AIO_READ = 318
- SYS_AIO_WRITE = 319
- SYS_LIO_LISTIO = 320
- SYS_IOPOLICYSYS = 322
- SYS_MLOCKALL = 324
- SYS_MUNLOCKALL = 325
- SYS_ISSETUGID = 327
- SYS___PTHREAD_KILL = 328
- SYS___PTHREAD_SIGMASK = 329
- SYS___SIGWAIT = 330
- SYS___DISABLE_THREADSIGNAL = 331
- SYS___PTHREAD_MARKCANCEL = 332
- SYS___PTHREAD_CANCELED = 333
- SYS___SEMWAIT_SIGNAL = 334
- SYS_PROC_INFO = 336
- SYS_SENDFILE = 337
- SYS_STAT64 = 338
- SYS_FSTAT64 = 339
- SYS_LSTAT64 = 340
- SYS_STAT64_EXTENDED = 341
- SYS_LSTAT64_EXTENDED = 342
- SYS_FSTAT64_EXTENDED = 343
- SYS_GETDIRENTRIES64 = 344
- SYS_STATFS64 = 345
- SYS_FSTATFS64 = 346
- SYS_GETFSSTAT64 = 347
- SYS___PTHREAD_CHDIR = 348
- SYS___PTHREAD_FCHDIR = 349
- SYS_AUDIT = 350
- SYS_AUDITON = 351
- SYS_GETAUID = 353
- SYS_SETAUID = 354
- SYS_GETAUDIT = 355
- SYS_SETAUDIT = 356
- SYS_GETAUDIT_ADDR = 357
- SYS_SETAUDIT_ADDR = 358
- SYS_AUDITCTL = 359
- SYS_BSDTHREAD_CREATE = 360
- SYS_BSDTHREAD_TERMINATE = 361
- SYS_KQUEUE = 362
- SYS_KEVENT = 363
- SYS_LCHOWN = 364
- SYS_STACK_SNAPSHOT = 365
- SYS_BSDTHREAD_REGISTER = 366
- SYS_WORKQ_OPEN = 367
- SYS_WORKQ_KERNRETURN = 368
- SYS_KEVENT64 = 369
- SYS___OLD_SEMWAIT_SIGNAL = 370
- SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
- SYS_THREAD_SELFID = 372
- SYS___MAC_EXECVE = 380
- SYS___MAC_SYSCALL = 381
- SYS___MAC_GET_FILE = 382
- SYS___MAC_SET_FILE = 383
- SYS___MAC_GET_LINK = 384
- SYS___MAC_SET_LINK = 385
- SYS___MAC_GET_PROC = 386
- SYS___MAC_SET_PROC = 387
- SYS___MAC_GET_FD = 388
- SYS___MAC_SET_FD = 389
- SYS___MAC_GET_PID = 390
- SYS___MAC_GET_LCID = 391
- SYS___MAC_GET_LCTX = 392
- SYS___MAC_SET_LCTX = 393
- SYS_SETLCID = 394
- SYS_GETLCID = 395
- SYS_READ_NOCANCEL = 396
- SYS_WRITE_NOCANCEL = 397
- SYS_OPEN_NOCANCEL = 398
- SYS_CLOSE_NOCANCEL = 399
- SYS_WAIT4_NOCANCEL = 400
- SYS_RECVMSG_NOCANCEL = 401
- SYS_SENDMSG_NOCANCEL = 402
- SYS_RECVFROM_NOCANCEL = 403
- SYS_ACCEPT_NOCANCEL = 404
- SYS_MSYNC_NOCANCEL = 405
- SYS_FCNTL_NOCANCEL = 406
- SYS_SELECT_NOCANCEL = 407
- SYS_FSYNC_NOCANCEL = 408
- SYS_CONNECT_NOCANCEL = 409
- SYS_SIGSUSPEND_NOCANCEL = 410
- SYS_READV_NOCANCEL = 411
- SYS_WRITEV_NOCANCEL = 412
- SYS_SENDTO_NOCANCEL = 413
- SYS_PREAD_NOCANCEL = 414
- SYS_PWRITE_NOCANCEL = 415
- SYS_WAITID_NOCANCEL = 416
- SYS_POLL_NOCANCEL = 417
- SYS_MSGSND_NOCANCEL = 418
- SYS_MSGRCV_NOCANCEL = 419
- SYS_SEM_WAIT_NOCANCEL = 420
- SYS_AIO_SUSPEND_NOCANCEL = 421
- SYS___SIGWAIT_NOCANCEL = 422
- SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
- SYS___MAC_MOUNT = 424
- SYS___MAC_GET_MOUNT = 425
- SYS___MAC_GETFSSTAT = 426
- SYS_FSGETPATH = 427
- SYS_AUDIT_SESSION_SELF = 428
- SYS_AUDIT_SESSION_JOIN = 429
- SYS_PID_SUSPEND = 430
- SYS_PID_RESUME = 431
- SYS_FILEPORT_MAKEPORT = 432
- SYS_FILEPORT_MAKEFD = 433
- SYS_MAXSYSCALL = 434
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_PSYNCH_CVCLRPREPOST = 312
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_PROCESS_POLICY = 323
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_FILEPORT_MAKEPORT = 430
+ SYS_FILEPORT_MAKEFD = 431
+ SYS_AUDIT_SESSION_PORT = 432
+ SYS_PID_SUSPEND = 433
+ SYS_PID_RESUME = 434
+ SYS_PID_HIBERNATE = 435
+ SYS_PID_SHUTDOWN_SOCKETS = 436
+ SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438
+ SYS_MAXSYSCALL = 439
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index a5b7b664f..e986abac5 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -1,4 +1,4 @@
-// mksysnum_freebsd.sh
+// mksysnum_freebsd.pl
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
@@ -33,7 +33,7 @@ const (
SYS_ACCEPT = 30 // { int accept(int s, \
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
- SYS_ACCESS = 33 // { int access(char *path, int flags); }
+ SYS_ACCESS = 33 // { int access(char *path, int amode); }
SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
SYS_SYNC = 36 // { int sync(void); }
@@ -146,6 +146,9 @@ const (
SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \
SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); }
SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \
+ SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
+ SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \
+ SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
SYS_RFORK = 251 // { int rfork(int flags); }
@@ -215,7 +218,7 @@ const (
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
- SYS_EACCESS = 376 // { int eaccess(char *path, int flags); }
+ SYS_EACCESS = 376 // { int eaccess(char *path, int amode); }
SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \
SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); }
SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); }
@@ -296,7 +299,7 @@ const (
SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \
SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \
SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \
- SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int mode, \
+ SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \
SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \
SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \
SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \
@@ -317,5 +320,21 @@ const (
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
+ SYS_CAP_NEW = 514 // { int cap_new(int fd, u_int64_t rights); }
+ SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
+ SYS_CAP_ENTER = 516 // { int cap_enter(void); }
+ SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
+ SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
+ SYS_PDKILL = 519 // { int pdkill(int fd, int signum); }
+ SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); }
SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \
+ SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \
+ SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); }
+ SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \
+ SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \
+ SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \
+ SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \
+ SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
+ SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
+ SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index a5b7b664f..e986abac5 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -1,4 +1,4 @@
-// mksysnum_freebsd.sh
+// mksysnum_freebsd.pl
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
@@ -33,7 +33,7 @@ const (
SYS_ACCEPT = 30 // { int accept(int s, \
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \
- SYS_ACCESS = 33 // { int access(char *path, int flags); }
+ SYS_ACCESS = 33 // { int access(char *path, int amode); }
SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
SYS_SYNC = 36 // { int sync(void); }
@@ -146,6 +146,9 @@ const (
SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \
SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); }
SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \
+ SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
+ SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \
+ SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
SYS_RFORK = 251 // { int rfork(int flags); }
@@ -215,7 +218,7 @@ const (
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \
SYS___SETUGID = 374 // { int __setugid(int flag); }
- SYS_EACCESS = 376 // { int eaccess(char *path, int flags); }
+ SYS_EACCESS = 376 // { int eaccess(char *path, int amode); }
SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \
SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); }
SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); }
@@ -296,7 +299,7 @@ const (
SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \
SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \
SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \
- SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int mode, \
+ SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \
SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \
SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \
SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \
@@ -317,5 +320,21 @@ const (
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
+ SYS_CAP_NEW = 514 // { int cap_new(int fd, u_int64_t rights); }
+ SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
+ SYS_CAP_ENTER = 516 // { int cap_enter(void); }
+ SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
+ SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
+ SYS_PDKILL = 519 // { int pdkill(int fd, int signum); }
+ SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); }
SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \
+ SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \
+ SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); }
+ SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \
+ SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \
+ SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \
+ SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \
+ SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
+ SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
+ SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
)
diff --git a/src/pkg/syscall/zsysnum_linux_386.go b/src/pkg/syscall/zsysnum_linux_386.go
index 71e21c7a5..c40b5f1ac 100644
--- a/src/pkg/syscall/zsysnum_linux_386.go
+++ b/src/pkg/syscall/zsysnum_linux_386.go
@@ -338,4 +338,8 @@ const (
SYS_PWRITEV = 334
SYS_RT_TGSIGQUEUEINFO = 335
SYS_PERF_EVENT_OPEN = 336
+ SYS_RECVMMSG = 337
+ SYS_FANOTIFY_INIT = 338
+ SYS_FANOTIFY_MARK = 339
+ SYS_PRLIMIT64 = 340
)
diff --git a/src/pkg/syscall/zsysnum_linux_amd64.go b/src/pkg/syscall/zsysnum_linux_amd64.go
index 77d4eea9e..7cf70a4d8 100644
--- a/src/pkg/syscall/zsysnum_linux_amd64.go
+++ b/src/pkg/syscall/zsysnum_linux_amd64.go
@@ -303,4 +303,8 @@ const (
SYS_PWRITEV = 296
SYS_RT_TGSIGQUEUEINFO = 297
SYS_PERF_EVENT_OPEN = 298
+ SYS_RECVMMSG = 299
+ SYS_FANOTIFY_INIT = 300
+ SYS_FANOTIFY_MARK = 301
+ SYS_PRLIMIT64 = 302
)
diff --git a/src/pkg/syscall/zsysnum_linux_arm.go b/src/pkg/syscall/zsysnum_linux_arm.go
index 8d22929ef..7f5d9498c 100644
--- a/src/pkg/syscall/zsysnum_linux_arm.go
+++ b/src/pkg/syscall/zsysnum_linux_arm.go
@@ -1,336 +1,354 @@
-// hand generated
+// mksysnum_linux.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
const (
- SYS_SYSCALL_BASE = 0
-
- SYS_RESTART_SYSCALL = (SYS_SYSCALL_BASE + 0)
- SYS_EXIT = (SYS_SYSCALL_BASE + 1)
- SYS_FORK = (SYS_SYSCALL_BASE + 2)
- SYS_READ = (SYS_SYSCALL_BASE + 3)
- SYS_WRITE = (SYS_SYSCALL_BASE + 4)
- SYS_OPEN = (SYS_SYSCALL_BASE + 5)
- SYS_CLOSE = (SYS_SYSCALL_BASE + 6)
- SYS_CREAT = (SYS_SYSCALL_BASE + 8)
- SYS_LINK = (SYS_SYSCALL_BASE + 9)
- SYS_UNLINK = (SYS_SYSCALL_BASE + 10)
- SYS_EXECVE = (SYS_SYSCALL_BASE + 11)
- SYS_CHDIR = (SYS_SYSCALL_BASE + 12)
- SYS_TIME = (SYS_SYSCALL_BASE + 13)
- SYS_MKNOD = (SYS_SYSCALL_BASE + 14)
- SYS_CHMOD = (SYS_SYSCALL_BASE + 15)
- SYS_LCHOWN = (SYS_SYSCALL_BASE + 16)
- SYS_LSEEK = (SYS_SYSCALL_BASE + 19)
- SYS_GETPID = (SYS_SYSCALL_BASE + 20)
- SYS_MOUNT = (SYS_SYSCALL_BASE + 21)
- SYS_UMOUNT = (SYS_SYSCALL_BASE + 22)
- SYS_SETUID = (SYS_SYSCALL_BASE + 23)
- SYS_GETUID = (SYS_SYSCALL_BASE + 24)
- SYS_STIME = (SYS_SYSCALL_BASE + 25)
- SYS_PTRACE = (SYS_SYSCALL_BASE + 26)
- SYS_ALARM = (SYS_SYSCALL_BASE + 27)
- SYS_PAUSE = (SYS_SYSCALL_BASE + 29)
- SYS_UTIME = (SYS_SYSCALL_BASE + 30)
- SYS_ACCESS = (SYS_SYSCALL_BASE + 33)
- SYS_NICE = (SYS_SYSCALL_BASE + 34)
- SYS_SYNC = (SYS_SYSCALL_BASE + 36)
- SYS_KILL = (SYS_SYSCALL_BASE + 37)
- SYS_RENAME = (SYS_SYSCALL_BASE + 38)
- SYS_MKDIR = (SYS_SYSCALL_BASE + 39)
- SYS_RMDIR = (SYS_SYSCALL_BASE + 40)
- SYS_DUP = (SYS_SYSCALL_BASE + 41)
- SYS_PIPE = (SYS_SYSCALL_BASE + 42)
- SYS_TIMES = (SYS_SYSCALL_BASE + 43)
- SYS_BRK = (SYS_SYSCALL_BASE + 45)
- SYS_SETGID = (SYS_SYSCALL_BASE + 46)
- SYS_GETGID = (SYS_SYSCALL_BASE + 47)
- SYS_GETEUID = (SYS_SYSCALL_BASE + 49)
- SYS_GETEGID = (SYS_SYSCALL_BASE + 50)
- SYS_ACCT = (SYS_SYSCALL_BASE + 51)
- SYS_UMOUNT2 = (SYS_SYSCALL_BASE + 52)
- SYS_IOCTL = (SYS_SYSCALL_BASE + 54)
- SYS_FCNTL = (SYS_SYSCALL_BASE + 55)
- SYS_SETPGID = (SYS_SYSCALL_BASE + 57)
- SYS_UMASK = (SYS_SYSCALL_BASE + 60)
- SYS_CHROOT = (SYS_SYSCALL_BASE + 61)
- SYS_USTAT = (SYS_SYSCALL_BASE + 62)
- SYS_DUP2 = (SYS_SYSCALL_BASE + 63)
- SYS_GETPPID = (SYS_SYSCALL_BASE + 64)
- SYS_GETPGRP = (SYS_SYSCALL_BASE + 65)
- SYS_SETSID = (SYS_SYSCALL_BASE + 66)
- SYS_SIGACTION = (SYS_SYSCALL_BASE + 67)
- SYS_SETREUID = (SYS_SYSCALL_BASE + 70)
- SYS_SETREGID = (SYS_SYSCALL_BASE + 71)
- SYS_SIGSUSPEND = (SYS_SYSCALL_BASE + 72)
- SYS_SIGPENDING = (SYS_SYSCALL_BASE + 73)
- SYS_SETHOSTNAME = (SYS_SYSCALL_BASE + 74)
- SYS_SETRLIMIT = (SYS_SYSCALL_BASE + 75)
- SYS_GETRLIMIT = (SYS_SYSCALL_BASE + 76)
- SYS_GETRUSAGE = (SYS_SYSCALL_BASE + 77)
- SYS_GETTIMEOFDAY = (SYS_SYSCALL_BASE + 78)
- SYS_SETTIMEOFDAY = (SYS_SYSCALL_BASE + 79)
- SYS_GETGROUPS = (SYS_SYSCALL_BASE + 80)
- SYS_SETGROUPS = (SYS_SYSCALL_BASE + 81)
- SYS_SELECT = (SYS_SYSCALL_BASE + 82)
- SYS_SYMLINK = (SYS_SYSCALL_BASE + 83)
- SYS_READLINK = (SYS_SYSCALL_BASE + 85)
- SYS_USELIB = (SYS_SYSCALL_BASE + 86)
- SYS_SWAPON = (SYS_SYSCALL_BASE + 87)
- SYS_REBOOT = (SYS_SYSCALL_BASE + 88)
- SYS_READDIR = (SYS_SYSCALL_BASE + 89)
- SYS_MMAP = (SYS_SYSCALL_BASE + 90)
- SYS_MUNMAP = (SYS_SYSCALL_BASE + 91)
- SYS_TRUNCATE = (SYS_SYSCALL_BASE + 92)
- SYS_FTRUNCATE = (SYS_SYSCALL_BASE + 93)
- SYS_FCHMOD = (SYS_SYSCALL_BASE + 94)
- SYS_FCHOWN = (SYS_SYSCALL_BASE + 95)
- SYS_GETPRIORITY = (SYS_SYSCALL_BASE + 96)
- SYS_SETPRIORITY = (SYS_SYSCALL_BASE + 97)
- SYS_STATFS = (SYS_SYSCALL_BASE + 99)
- SYS_FSTATFS = (SYS_SYSCALL_BASE + 100)
- SYS_SOCKETCALL = (SYS_SYSCALL_BASE + 102)
- SYS_SYSLOG = (SYS_SYSCALL_BASE + 103)
- SYS_SETITIMER = (SYS_SYSCALL_BASE + 104)
- SYS_GETITIMER = (SYS_SYSCALL_BASE + 105)
- SYS_STAT = (SYS_SYSCALL_BASE + 106)
- SYS_LSTAT = (SYS_SYSCALL_BASE + 107)
- SYS_FSTAT = (SYS_SYSCALL_BASE + 108)
- SYS_VHANGUP = (SYS_SYSCALL_BASE + 111)
- SYS_SYSCALL = (SYS_SYSCALL_BASE + 113)
- SYS_WAIT4 = (SYS_SYSCALL_BASE + 114)
- SYS_SWAPOFF = (SYS_SYSCALL_BASE + 115)
- SYS_SYSINFO = (SYS_SYSCALL_BASE + 116)
- SYS_IPC = (SYS_SYSCALL_BASE + 117)
- SYS_FSYNC = (SYS_SYSCALL_BASE + 118)
- SYS_SIGRETURN = (SYS_SYSCALL_BASE + 119)
- SYS_CLONE = (SYS_SYSCALL_BASE + 120)
- SYS_SETDOMAINNAME = (SYS_SYSCALL_BASE + 121)
- SYS_UNAME = (SYS_SYSCALL_BASE + 122)
- SYS_ADJTIMEX = (SYS_SYSCALL_BASE + 124)
- SYS_MPROTECT = (SYS_SYSCALL_BASE + 125)
- SYS_SIGPROCMASK = (SYS_SYSCALL_BASE + 126)
- SYS_INIT_MODULE = (SYS_SYSCALL_BASE + 128)
- SYS_DELETE_MODULE = (SYS_SYSCALL_BASE + 129)
- SYS_QUOTACTL = (SYS_SYSCALL_BASE + 131)
- SYS_GETPGID = (SYS_SYSCALL_BASE + 132)
- SYS_FCHDIR = (SYS_SYSCALL_BASE + 133)
- SYS_BDFLUSH = (SYS_SYSCALL_BASE + 134)
- SYS_SYSFS = (SYS_SYSCALL_BASE + 135)
- SYS_PERSONALITY = (SYS_SYSCALL_BASE + 136)
- SYS_SETFSUID = (SYS_SYSCALL_BASE + 138)
- SYS_SETFSGID = (SYS_SYSCALL_BASE + 139)
- SYS__LLSEEK = (SYS_SYSCALL_BASE + 140)
- SYS_GETDENTS = (SYS_SYSCALL_BASE + 141)
- SYS__NEWSELECT = (SYS_SYSCALL_BASE + 142)
- SYS_FLOCK = (SYS_SYSCALL_BASE + 143)
- SYS_MSYNC = (SYS_SYSCALL_BASE + 144)
- SYS_READV = (SYS_SYSCALL_BASE + 145)
- SYS_WRITEV = (SYS_SYSCALL_BASE + 146)
- SYS_GETSID = (SYS_SYSCALL_BASE + 147)
- SYS_FDATASYNC = (SYS_SYSCALL_BASE + 148)
- SYS__SYSCTL = (SYS_SYSCALL_BASE + 149)
- SYS_MLOCK = (SYS_SYSCALL_BASE + 150)
- SYS_MUNLOCK = (SYS_SYSCALL_BASE + 151)
- SYS_MLOCKALL = (SYS_SYSCALL_BASE + 152)
- SYS_MUNLOCKALL = (SYS_SYSCALL_BASE + 153)
- SYS_SCHED_SETPARAM = (SYS_SYSCALL_BASE + 154)
- SYS_SCHED_GETPARAM = (SYS_SYSCALL_BASE + 155)
- SYS_SCHED_SETSCHEDULER = (SYS_SYSCALL_BASE + 156)
- SYS_SCHED_GETSCHEDULER = (SYS_SYSCALL_BASE + 157)
- SYS_SCHED_YIELD = (SYS_SYSCALL_BASE + 158)
- SYS_SCHED_GET_PRIORITY_MAX = (SYS_SYSCALL_BASE + 159)
- SYS_SCHED_GET_PRIORITY_MIN = (SYS_SYSCALL_BASE + 160)
- SYS_SCHED_RR_GET_INTERVAL = (SYS_SYSCALL_BASE + 161)
- SYS_NANOSLEEP = (SYS_SYSCALL_BASE + 162)
- SYS_MREMAP = (SYS_SYSCALL_BASE + 163)
- SYS_SETRESUID = (SYS_SYSCALL_BASE + 164)
- SYS_GETRESUID = (SYS_SYSCALL_BASE + 165)
- SYS_POLL = (SYS_SYSCALL_BASE + 168)
- SYS_NFSSERVCTL = (SYS_SYSCALL_BASE + 169)
- SYS_SETRESGID = (SYS_SYSCALL_BASE + 170)
- SYS_GETRESGID = (SYS_SYSCALL_BASE + 171)
- SYS_PRCTL = (SYS_SYSCALL_BASE + 172)
- SYS_RT_SIGRETURN = (SYS_SYSCALL_BASE + 173)
- SYS_RT_SIGACTION = (SYS_SYSCALL_BASE + 174)
- SYS_RT_SIGPROCMASK = (SYS_SYSCALL_BASE + 175)
- SYS_RT_SIGPENDING = (SYS_SYSCALL_BASE + 176)
- SYS_RT_SIGTIMEDWAIT = (SYS_SYSCALL_BASE + 177)
- SYS_RT_SIGQUEUEINFO = (SYS_SYSCALL_BASE + 178)
- SYS_RT_SIGSUSPEND = (SYS_SYSCALL_BASE + 179)
- SYS_PREAD64 = (SYS_SYSCALL_BASE + 180)
- SYS_PWRITE64 = (SYS_SYSCALL_BASE + 181)
- SYS_CHOWN = (SYS_SYSCALL_BASE + 182)
- SYS_GETCWD = (SYS_SYSCALL_BASE + 183)
- SYS_CAPGET = (SYS_SYSCALL_BASE + 184)
- SYS_CAPSET = (SYS_SYSCALL_BASE + 185)
- SYS_SIGALTSTACK = (SYS_SYSCALL_BASE + 186)
- SYS_SENDFILE = (SYS_SYSCALL_BASE + 187)
- SYS_VFORK = (SYS_SYSCALL_BASE + 190)
- SYS_UGETRLIMIT = (SYS_SYSCALL_BASE + 191)
- SYS_MMAP2 = (SYS_SYSCALL_BASE + 192)
- SYS_TRUNCATE64 = (SYS_SYSCALL_BASE + 193)
- SYS_FTRUNCATE64 = (SYS_SYSCALL_BASE + 194)
- SYS_STAT64 = (SYS_SYSCALL_BASE + 195)
- SYS_LSTAT64 = (SYS_SYSCALL_BASE + 196)
- SYS_FSTAT64 = (SYS_SYSCALL_BASE + 197)
- SYS_LCHOWN32 = (SYS_SYSCALL_BASE + 198)
- SYS_GETUID32 = (SYS_SYSCALL_BASE + 199)
- SYS_GETGID32 = (SYS_SYSCALL_BASE + 200)
- SYS_GETEUID32 = (SYS_SYSCALL_BASE + 201)
- SYS_GETEGID32 = (SYS_SYSCALL_BASE + 202)
- SYS_SETREUID32 = (SYS_SYSCALL_BASE + 203)
- SYS_SETREGID32 = (SYS_SYSCALL_BASE + 204)
- SYS_GETGROUPS32 = (SYS_SYSCALL_BASE + 205)
- SYS_SETGROUPS32 = (SYS_SYSCALL_BASE + 206)
- SYS_FCHOWN32 = (SYS_SYSCALL_BASE + 207)
- SYS_SETRESUID32 = (SYS_SYSCALL_BASE + 208)
- SYS_GETRESUID32 = (SYS_SYSCALL_BASE + 209)
- SYS_SETRESGID32 = (SYS_SYSCALL_BASE + 210)
- SYS_GETRESGID32 = (SYS_SYSCALL_BASE + 211)
- SYS_CHOWN32 = (SYS_SYSCALL_BASE + 212)
- SYS_SETUID32 = (SYS_SYSCALL_BASE + 213)
- SYS_SETGID32 = (SYS_SYSCALL_BASE + 214)
- SYS_SETFSUID32 = (SYS_SYSCALL_BASE + 215)
- SYS_SETFSGID32 = (SYS_SYSCALL_BASE + 216)
- SYS_GETDENTS64 = (SYS_SYSCALL_BASE + 217)
- SYS_PIVOT_ROOT = (SYS_SYSCALL_BASE + 218)
- SYS_MINCORE = (SYS_SYSCALL_BASE + 219)
- SYS_MADVISE = (SYS_SYSCALL_BASE + 220)
- SYS_FCNTL64 = (SYS_SYSCALL_BASE + 221)
- SYS_GETTID = (SYS_SYSCALL_BASE + 224)
- SYS_READAHEAD = (SYS_SYSCALL_BASE + 225)
- SYS_SETXATTR = (SYS_SYSCALL_BASE + 226)
- SYS_LSETXATTR = (SYS_SYSCALL_BASE + 227)
- SYS_FSETXATTR = (SYS_SYSCALL_BASE + 228)
- SYS_GETXATTR = (SYS_SYSCALL_BASE + 229)
- SYS_LGETXATTR = (SYS_SYSCALL_BASE + 230)
- SYS_FGETXATTR = (SYS_SYSCALL_BASE + 231)
- SYS_LISTXATTR = (SYS_SYSCALL_BASE + 232)
- SYS_LLISTXATTR = (SYS_SYSCALL_BASE + 233)
- SYS_FLISTXATTR = (SYS_SYSCALL_BASE + 234)
- SYS_REMOVEXATTR = (SYS_SYSCALL_BASE + 235)
- SYS_LREMOVEXATTR = (SYS_SYSCALL_BASE + 236)
- SYS_FREMOVEXATTR = (SYS_SYSCALL_BASE + 237)
- SYS_TKILL = (SYS_SYSCALL_BASE + 238)
- SYS_SENDFILE64 = (SYS_SYSCALL_BASE + 239)
- SYS_FUTEX = (SYS_SYSCALL_BASE + 240)
- SYS_SCHED_SETAFFINITY = (SYS_SYSCALL_BASE + 241)
- SYS_SCHED_GETAFFINITY = (SYS_SYSCALL_BASE + 242)
- SYS_IO_SETUP = (SYS_SYSCALL_BASE + 243)
- SYS_IO_DESTROY = (SYS_SYSCALL_BASE + 244)
- SYS_IO_GETEVENTS = (SYS_SYSCALL_BASE + 245)
- SYS_IO_SUBMIT = (SYS_SYSCALL_BASE + 246)
- SYS_IO_CANCEL = (SYS_SYSCALL_BASE + 247)
- SYS_EXIT_GROUP = (SYS_SYSCALL_BASE + 248)
- SYS_LOOKUP_DCOOKIE = (SYS_SYSCALL_BASE + 249)
- SYS_EPOLL_CREATE = (SYS_SYSCALL_BASE + 250)
- SYS_EPOLL_CTL = (SYS_SYSCALL_BASE + 251)
- SYS_EPOLL_WAIT = (SYS_SYSCALL_BASE + 252)
- SYS_REMAP_FILE_PAGES = (SYS_SYSCALL_BASE + 253)
- SYS_SET_TID_ADDRESS = (SYS_SYSCALL_BASE + 256)
- SYS_TIMER_CREATE = (SYS_SYSCALL_BASE + 257)
- SYS_TIMER_SETTIME = (SYS_SYSCALL_BASE + 258)
- SYS_TIMER_GETTIME = (SYS_SYSCALL_BASE + 259)
- SYS_TIMER_GETOVERRUN = (SYS_SYSCALL_BASE + 260)
- SYS_TIMER_DELETE = (SYS_SYSCALL_BASE + 261)
- SYS_CLOCK_SETTIME = (SYS_SYSCALL_BASE + 262)
- SYS_CLOCK_GETTIME = (SYS_SYSCALL_BASE + 263)
- SYS_CLOCK_GETRES = (SYS_SYSCALL_BASE + 264)
- SYS_CLOCK_NANOSLEEP = (SYS_SYSCALL_BASE + 265)
- SYS_STATFS64 = (SYS_SYSCALL_BASE + 266)
- SYS_FSTATFS64 = (SYS_SYSCALL_BASE + 267)
- SYS_TGKILL = (SYS_SYSCALL_BASE + 268)
- SYS_UTIMES = (SYS_SYSCALL_BASE + 269)
- SYS_ARM_FADVISE64_64 = (SYS_SYSCALL_BASE + 270)
- SYS_PCICONFIG_IOBASE = (SYS_SYSCALL_BASE + 271)
- SYS_PCICONFIG_READ = (SYS_SYSCALL_BASE + 272)
- SYS_PCICONFIG_WRITE = (SYS_SYSCALL_BASE + 273)
- SYS_MQ_OPEN = (SYS_SYSCALL_BASE + 274)
- SYS_MQ_UNLINK = (SYS_SYSCALL_BASE + 275)
- SYS_MQ_TIMEDSEND = (SYS_SYSCALL_BASE + 276)
- SYS_MQ_TIMEDRECEIVE = (SYS_SYSCALL_BASE + 277)
- SYS_MQ_NOTIFY = (SYS_SYSCALL_BASE + 278)
- SYS_MQ_GETSETATTR = (SYS_SYSCALL_BASE + 279)
- SYS_WAITID = (SYS_SYSCALL_BASE + 280)
- SYS_SOCKET = (SYS_SYSCALL_BASE + 281)
- SYS_BIND = (SYS_SYSCALL_BASE + 282)
- SYS_CONNECT = (SYS_SYSCALL_BASE + 283)
- SYS_LISTEN = (SYS_SYSCALL_BASE + 284)
- SYS_ACCEPT = (SYS_SYSCALL_BASE + 285)
- SYS_GETSOCKNAME = (SYS_SYSCALL_BASE + 286)
- SYS_GETPEERNAME = (SYS_SYSCALL_BASE + 287)
- SYS_SOCKETPAIR = (SYS_SYSCALL_BASE + 288)
- SYS_SEND = (SYS_SYSCALL_BASE + 289)
- SYS_SENDTO = (SYS_SYSCALL_BASE + 290)
- SYS_RECV = (SYS_SYSCALL_BASE + 291)
- SYS_RECVFROM = (SYS_SYSCALL_BASE + 292)
- SYS_SHUTDOWN = (SYS_SYSCALL_BASE + 293)
- SYS_SETSOCKOPT = (SYS_SYSCALL_BASE + 294)
- SYS_GETSOCKOPT = (SYS_SYSCALL_BASE + 295)
- SYS_SENDMSG = (SYS_SYSCALL_BASE + 296)
- SYS_RECVMSG = (SYS_SYSCALL_BASE + 297)
- SYS_SEMOP = (SYS_SYSCALL_BASE + 298)
- SYS_SEMGET = (SYS_SYSCALL_BASE + 299)
- SYS_SEMCTL = (SYS_SYSCALL_BASE + 300)
- SYS_MSGSND = (SYS_SYSCALL_BASE + 301)
- SYS_MSGRCV = (SYS_SYSCALL_BASE + 302)
- SYS_MSGGET = (SYS_SYSCALL_BASE + 303)
- SYS_MSGCTL = (SYS_SYSCALL_BASE + 304)
- SYS_SHMAT = (SYS_SYSCALL_BASE + 305)
- SYS_SHMDT = (SYS_SYSCALL_BASE + 306)
- SYS_SHMGET = (SYS_SYSCALL_BASE + 307)
- SYS_SHMCTL = (SYS_SYSCALL_BASE + 308)
- SYS_ADD_KEY = (SYS_SYSCALL_BASE + 309)
- SYS_REQUEST_KEY = (SYS_SYSCALL_BASE + 310)
- SYS_KEYCTL = (SYS_SYSCALL_BASE + 311)
- SYS_SEMTIMEDOP = (SYS_SYSCALL_BASE + 312)
- SYS_VSERVER = (SYS_SYSCALL_BASE + 313)
- SYS_IOPRIO_SET = (SYS_SYSCALL_BASE + 314)
- SYS_IOPRIO_GET = (SYS_SYSCALL_BASE + 315)
- SYS_INOTIFY_INIT = (SYS_SYSCALL_BASE + 316)
- SYS_INOTIFY_ADD_WATCH = (SYS_SYSCALL_BASE + 317)
- SYS_INOTIFY_RM_WATCH = (SYS_SYSCALL_BASE + 318)
- SYS_MBIND = (SYS_SYSCALL_BASE + 319)
- SYS_GET_MEMPOLICY = (SYS_SYSCALL_BASE + 320)
- SYS_SET_MEMPOLICY = (SYS_SYSCALL_BASE + 321)
- SYS_OPENAT = (SYS_SYSCALL_BASE + 322)
- SYS_MKDIRAT = (SYS_SYSCALL_BASE + 323)
- SYS_MKNODAT = (SYS_SYSCALL_BASE + 324)
- SYS_FCHOWNAT = (SYS_SYSCALL_BASE + 325)
- SYS_FUTIMESAT = (SYS_SYSCALL_BASE + 326)
- SYS_FSTATAT64 = (SYS_SYSCALL_BASE + 327)
- SYS_UNLINKAT = (SYS_SYSCALL_BASE + 328)
- SYS_RENAMEAT = (SYS_SYSCALL_BASE + 329)
- SYS_LINKAT = (SYS_SYSCALL_BASE + 330)
- SYS_SYMLINKAT = (SYS_SYSCALL_BASE + 331)
- SYS_READLINKAT = (SYS_SYSCALL_BASE + 332)
- SYS_FCHMODAT = (SYS_SYSCALL_BASE + 333)
- SYS_FACCESSAT = (SYS_SYSCALL_BASE + 334)
- SYS_UNSHARE = (SYS_SYSCALL_BASE + 337)
- SYS_SET_ROBUST_LIST = (SYS_SYSCALL_BASE + 338)
- SYS_GET_ROBUST_LIST = (SYS_SYSCALL_BASE + 339)
- SYS_SPLICE = (SYS_SYSCALL_BASE + 340)
- SYS_ARM_SYNC_FILE_RANGE = (SYS_SYSCALL_BASE + 341)
- SYS_SYNC_FILE_RANGE2 = SYS_ARM_SYNC_FILE_RANGE
- SYS_TEE = (SYS_SYSCALL_BASE + 342)
- SYS_VMSPLICE = (SYS_SYSCALL_BASE + 343)
- SYS_MOVE_PAGES = (SYS_SYSCALL_BASE + 344)
- SYS_GETCPU = (SYS_SYSCALL_BASE + 345)
- SYS_KEXEC_LOAD = (SYS_SYSCALL_BASE + 347)
- SYS_UTIMENSAT = (SYS_SYSCALL_BASE + 348)
- SYS_SIGNALFD = (SYS_SYSCALL_BASE + 349)
- SYS_TIMERFD_CREATE = (SYS_SYSCALL_BASE + 350)
- SYS_EVENTFD = (SYS_SYSCALL_BASE + 351)
- SYS_FALLOCATE = (SYS_SYSCALL_BASE + 352)
- SYS_TIMERFD_SETTIME = (SYS_SYSCALL_BASE + 353)
- SYS_TIMERFD_GETTIME = (SYS_SYSCALL_BASE + 354)
- SYS_SIGNALFD4 = (SYS_SYSCALL_BASE + 355)
- SYS_EVENTFD2 = (SYS_SYSCALL_BASE + 356)
- SYS_EPOLL_CREATE1 = (SYS_SYSCALL_BASE + 357)
- SYS_DUP3 = (SYS_SYSCALL_BASE + 358)
- SYS_PIPE2 = (SYS_SYSCALL_BASE + 359)
- SYS_INOTIFY_INIT1 = (SYS_SYSCALL_BASE + 360)
+ SYS_OABI_SYSCALL_BASE = 0
+ SYS_SYSCALL_BASE = 0
+ SYS_RESTART_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_CREAT = 8
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_EXECVE = 11
+ SYS_CHDIR = 12
+ SYS_TIME = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_LCHOWN = 16
+ SYS_LSEEK = 19
+ SYS_GETPID = 20
+ SYS_MOUNT = 21
+ SYS_UMOUNT = 22
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_STIME = 25
+ SYS_PTRACE = 26
+ SYS_ALARM = 27
+ SYS_PAUSE = 29
+ SYS_UTIME = 30
+ SYS_ACCESS = 33
+ SYS_NICE = 34
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_RENAME = 38
+ SYS_MKDIR = 39
+ SYS_RMDIR = 40
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_TIMES = 43
+ SYS_BRK = 45
+ SYS_SETGID = 46
+ SYS_GETGID = 47
+ SYS_GETEUID = 49
+ SYS_GETEGID = 50
+ SYS_ACCT = 51
+ SYS_UMOUNT2 = 52
+ SYS_IOCTL = 54
+ SYS_FCNTL = 55
+ SYS_SETPGID = 57
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_USTAT = 62
+ SYS_DUP2 = 63
+ SYS_GETPPID = 64
+ SYS_GETPGRP = 65
+ SYS_SETSID = 66
+ SYS_SIGACTION = 67
+ SYS_SETREUID = 70
+ SYS_SETREGID = 71
+ SYS_SIGSUSPEND = 72
+ SYS_SIGPENDING = 73
+ SYS_SETHOSTNAME = 74
+ SYS_SETRLIMIT = 75
+ SYS_GETRLIMIT = 76
+ SYS_GETRUSAGE = 77
+ SYS_GETTIMEOFDAY = 78
+ SYS_SETTIMEOFDAY = 79
+ SYS_GETGROUPS = 80
+ SYS_SETGROUPS = 81
+ SYS_SELECT = 82
+ SYS_SYMLINK = 83
+ SYS_READLINK = 85
+ SYS_USELIB = 86
+ SYS_SWAPON = 87
+ SYS_REBOOT = 88
+ SYS_READDIR = 89
+ SYS_MMAP = 90
+ SYS_MUNMAP = 91
+ SYS_TRUNCATE = 92
+ SYS_FTRUNCATE = 93
+ SYS_FCHMOD = 94
+ SYS_FCHOWN = 95
+ SYS_GETPRIORITY = 96
+ SYS_SETPRIORITY = 97
+ SYS_STATFS = 99
+ SYS_FSTATFS = 100
+ SYS_SOCKETCALL = 102
+ SYS_SYSLOG = 103
+ SYS_SETITIMER = 104
+ SYS_GETITIMER = 105
+ SYS_STAT = 106
+ SYS_LSTAT = 107
+ SYS_FSTAT = 108
+ SYS_VHANGUP = 111
+ SYS_SYSCALL = 113
+ SYS_WAIT4 = 114
+ SYS_SWAPOFF = 115
+ SYS_SYSINFO = 116
+ SYS_IPC = 117
+ SYS_FSYNC = 118
+ SYS_SIGRETURN = 119
+ SYS_CLONE = 120
+ SYS_SETDOMAINNAME = 121
+ SYS_UNAME = 122
+ SYS_ADJTIMEX = 124
+ SYS_MPROTECT = 125
+ SYS_SIGPROCMASK = 126
+ SYS_INIT_MODULE = 128
+ SYS_DELETE_MODULE = 129
+ SYS_QUOTACTL = 131
+ SYS_GETPGID = 132
+ SYS_FCHDIR = 133
+ SYS_BDFLUSH = 134
+ SYS_SYSFS = 135
+ SYS_PERSONALITY = 136
+ SYS_SETFSUID = 138
+ SYS_SETFSGID = 139
+ SYS__LLSEEK = 140
+ SYS_GETDENTS = 141
+ SYS__NEWSELECT = 142
+ SYS_FLOCK = 143
+ SYS_MSYNC = 144
+ SYS_READV = 145
+ SYS_WRITEV = 146
+ SYS_GETSID = 147
+ SYS_FDATASYNC = 148
+ SYS__SYSCTL = 149
+ SYS_MLOCK = 150
+ SYS_MUNLOCK = 151
+ SYS_MLOCKALL = 152
+ SYS_MUNLOCKALL = 153
+ SYS_SCHED_SETPARAM = 154
+ SYS_SCHED_GETPARAM = 155
+ SYS_SCHED_SETSCHEDULER = 156
+ SYS_SCHED_GETSCHEDULER = 157
+ SYS_SCHED_YIELD = 158
+ SYS_SCHED_GET_PRIORITY_MAX = 159
+ SYS_SCHED_GET_PRIORITY_MIN = 160
+ SYS_SCHED_RR_GET_INTERVAL = 161
+ SYS_NANOSLEEP = 162
+ SYS_MREMAP = 163
+ SYS_SETRESUID = 164
+ SYS_GETRESUID = 165
+ SYS_POLL = 168
+ SYS_NFSSERVCTL = 169
+ SYS_SETRESGID = 170
+ SYS_GETRESGID = 171
+ SYS_PRCTL = 172
+ SYS_RT_SIGRETURN = 173
+ SYS_RT_SIGACTION = 174
+ SYS_RT_SIGPROCMASK = 175
+ SYS_RT_SIGPENDING = 176
+ SYS_RT_SIGTIMEDWAIT = 177
+ SYS_RT_SIGQUEUEINFO = 178
+ SYS_RT_SIGSUSPEND = 179
+ SYS_PREAD64 = 180
+ SYS_PWRITE64 = 181
+ SYS_CHOWN = 182
+ SYS_GETCWD = 183
+ SYS_CAPGET = 184
+ SYS_CAPSET = 185
+ SYS_SIGALTSTACK = 186
+ SYS_SENDFILE = 187
+ SYS_VFORK = 190
+ SYS_UGETRLIMIT = 191
+ SYS_MMAP2 = 192
+ SYS_TRUNCATE64 = 193
+ SYS_FTRUNCATE64 = 194
+ SYS_STAT64 = 195
+ SYS_LSTAT64 = 196
+ SYS_FSTAT64 = 197
+ SYS_LCHOWN32 = 198
+ SYS_GETUID32 = 199
+ SYS_GETGID32 = 200
+ SYS_GETEUID32 = 201
+ SYS_GETEGID32 = 202
+ SYS_SETREUID32 = 203
+ SYS_SETREGID32 = 204
+ SYS_GETGROUPS32 = 205
+ SYS_SETGROUPS32 = 206
+ SYS_FCHOWN32 = 207
+ SYS_SETRESUID32 = 208
+ SYS_GETRESUID32 = 209
+ SYS_SETRESGID32 = 210
+ SYS_GETRESGID32 = 211
+ SYS_CHOWN32 = 212
+ SYS_SETUID32 = 213
+ SYS_SETGID32 = 214
+ SYS_SETFSUID32 = 215
+ SYS_SETFSGID32 = 216
+ SYS_GETDENTS64 = 217
+ SYS_PIVOT_ROOT = 218
+ SYS_MINCORE = 219
+ SYS_MADVISE = 220
+ SYS_FCNTL64 = 221
+ SYS_GETTID = 224
+ SYS_READAHEAD = 225
+ SYS_SETXATTR = 226
+ SYS_LSETXATTR = 227
+ SYS_FSETXATTR = 228
+ SYS_GETXATTR = 229
+ SYS_LGETXATTR = 230
+ SYS_FGETXATTR = 231
+ SYS_LISTXATTR = 232
+ SYS_LLISTXATTR = 233
+ SYS_FLISTXATTR = 234
+ SYS_REMOVEXATTR = 235
+ SYS_LREMOVEXATTR = 236
+ SYS_FREMOVEXATTR = 237
+ SYS_TKILL = 238
+ SYS_SENDFILE64 = 239
+ SYS_FUTEX = 240
+ SYS_SCHED_SETAFFINITY = 241
+ SYS_SCHED_GETAFFINITY = 242
+ SYS_IO_SETUP = 243
+ SYS_IO_DESTROY = 244
+ SYS_IO_GETEVENTS = 245
+ SYS_IO_SUBMIT = 246
+ SYS_IO_CANCEL = 247
+ SYS_EXIT_GROUP = 248
+ SYS_LOOKUP_DCOOKIE = 249
+ SYS_EPOLL_CREATE = 250
+ SYS_EPOLL_CTL = 251
+ SYS_EPOLL_WAIT = 252
+ SYS_REMAP_FILE_PAGES = 253
+ SYS_SET_TID_ADDRESS = 256
+ SYS_TIMER_CREATE = 257
+ SYS_TIMER_SETTIME = 258
+ SYS_TIMER_GETTIME = 259
+ SYS_TIMER_GETOVERRUN = 260
+ SYS_TIMER_DELETE = 261
+ SYS_CLOCK_SETTIME = 262
+ SYS_CLOCK_GETTIME = 263
+ SYS_CLOCK_GETRES = 264
+ SYS_CLOCK_NANOSLEEP = 265
+ SYS_STATFS64 = 266
+ SYS_FSTATFS64 = 267
+ SYS_TGKILL = 268
+ SYS_UTIMES = 269
+ SYS_ARM_FADVISE64_64 = 270
+ SYS_PCICONFIG_IOBASE = 271
+ SYS_PCICONFIG_READ = 272
+ SYS_PCICONFIG_WRITE = 273
+ SYS_MQ_OPEN = 274
+ SYS_MQ_UNLINK = 275
+ SYS_MQ_TIMEDSEND = 276
+ SYS_MQ_TIMEDRECEIVE = 277
+ SYS_MQ_NOTIFY = 278
+ SYS_MQ_GETSETATTR = 279
+ SYS_WAITID = 280
+ SYS_SOCKET = 281
+ SYS_BIND = 282
+ SYS_CONNECT = 283
+ SYS_LISTEN = 284
+ SYS_ACCEPT = 285
+ SYS_GETSOCKNAME = 286
+ SYS_GETPEERNAME = 287
+ SYS_SOCKETPAIR = 288
+ SYS_SEND = 289
+ SYS_SENDTO = 290
+ SYS_RECV = 291
+ SYS_RECVFROM = 292
+ SYS_SHUTDOWN = 293
+ SYS_SETSOCKOPT = 294
+ SYS_GETSOCKOPT = 295
+ SYS_SENDMSG = 296
+ SYS_RECVMSG = 297
+ SYS_SEMOP = 298
+ SYS_SEMGET = 299
+ SYS_SEMCTL = 300
+ SYS_MSGSND = 301
+ SYS_MSGRCV = 302
+ SYS_MSGGET = 303
+ SYS_MSGCTL = 304
+ SYS_SHMAT = 305
+ SYS_SHMDT = 306
+ SYS_SHMGET = 307
+ SYS_SHMCTL = 308
+ SYS_ADD_KEY = 309
+ SYS_REQUEST_KEY = 310
+ SYS_KEYCTL = 311
+ SYS_SEMTIMEDOP = 312
+ SYS_VSERVER = 313
+ SYS_IOPRIO_SET = 314
+ SYS_IOPRIO_GET = 315
+ SYS_INOTIFY_INIT = 316
+ SYS_INOTIFY_ADD_WATCH = 317
+ SYS_INOTIFY_RM_WATCH = 318
+ SYS_MBIND = 319
+ SYS_GET_MEMPOLICY = 320
+ SYS_SET_MEMPOLICY = 321
+ SYS_OPENAT = 322
+ SYS_MKDIRAT = 323
+ SYS_MKNODAT = 324
+ SYS_FCHOWNAT = 325
+ SYS_FUTIMESAT = 326
+ SYS_FSTATAT64 = 327
+ SYS_UNLINKAT = 328
+ SYS_RENAMEAT = 329
+ SYS_LINKAT = 330
+ SYS_SYMLINKAT = 331
+ SYS_READLINKAT = 332
+ SYS_FCHMODAT = 333
+ SYS_FACCESSAT = 334
+ SYS_PSELECT6 = 335
+ SYS_PPOLL = 336
+ SYS_UNSHARE = 337
+ SYS_SET_ROBUST_LIST = 338
+ SYS_GET_ROBUST_LIST = 339
+ SYS_SPLICE = 340
+ SYS_ARM_SYNC_FILE_RANGE = 341
+ SYS_TEE = 342
+ SYS_VMSPLICE = 343
+ SYS_MOVE_PAGES = 344
+ SYS_GETCPU = 345
+ SYS_EPOLL_PWAIT = 346
+ SYS_KEXEC_LOAD = 347
+ SYS_UTIMENSAT = 348
+ SYS_SIGNALFD = 349
+ SYS_TIMERFD_CREATE = 350
+ SYS_EVENTFD = 351
+ SYS_FALLOCATE = 352
+ SYS_TIMERFD_SETTIME = 353
+ SYS_TIMERFD_GETTIME = 354
+ SYS_SIGNALFD4 = 355
+ SYS_EVENTFD2 = 356
+ SYS_EPOLL_CREATE1 = 357
+ SYS_DUP3 = 358
+ SYS_PIPE2 = 359
+ SYS_INOTIFY_INIT1 = 360
+ SYS_PREADV = 361
+ SYS_PWRITEV = 362
+ SYS_RT_TGSIGQUEUEINFO = 363
+ SYS_PERF_EVENT_OPEN = 364
+ SYS_RECVMMSG = 365
+ SYS_ACCEPT4 = 366
+ SYS_FANOTIFY_INIT = 367
+ SYS_FANOTIFY_MARK = 368
+ SYS_PRLIMIT64 = 369
+ SYS_NAME_TO_HANDLE_AT = 370
+ SYS_OPEN_BY_HANDLE_AT = 371
+ SYS_CLOCK_ADJTIME = 372
+ SYS_SYNCFS = 373
+ SYS_SENDMMSG = 374
+ SYS_SETNS = 375
+ SYS_PROCESS_VM_READV = 376
+ SYS_PROCESS_VM_WRITEV = 377
)
-
-func _darwin_system_call_conflict() {}
diff --git a/src/pkg/syscall/zsysnum_netbsd_386.go b/src/pkg/syscall/zsysnum_netbsd_386.go
new file mode 100644
index 000000000..e9a0bcfb1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_netbsd_386.go
@@ -0,0 +1,274 @@
+// mksysnum_netbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_EXIT = 1 // { void|sys||exit(int rval); }
+ SYS_FORK = 2 // { int|sys||fork(void); }
+ SYS_READ = 3 // { ssize_t|sys||read(int fd, void *buf, size_t nbyte); }
+ SYS_WRITE = 4 // { ssize_t|sys||write(int fd, const void *buf, size_t nbyte); }
+ SYS_OPEN = 5 // { int|sys||open(const char *path, int flags, ... mode_t mode); }
+ SYS_CLOSE = 6 // { int|sys||close(int fd); }
+ SYS_LINK = 9 // { int|sys||link(const char *path, const char *link); }
+ SYS_UNLINK = 10 // { int|sys||unlink(const char *path); }
+ SYS_CHDIR = 12 // { int|sys||chdir(const char *path); }
+ SYS_FCHDIR = 13 // { int|sys||fchdir(int fd); }
+ SYS_CHMOD = 15 // { int|sys||chmod(const char *path, mode_t mode); }
+ SYS_CHOWN = 16 // { int|sys||chown(const char *path, uid_t uid, gid_t gid); }
+ SYS_BREAK = 17 // { int|sys||obreak(char *nsize); }
+ SYS_GETPID = 20 // { pid_t|sys||getpid_with_ppid(void); }
+ SYS_UNMOUNT = 22 // { int|sys||unmount(const char *path, int flags); }
+ SYS_SETUID = 23 // { int|sys||setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t|sys||getuid_with_euid(void); }
+ SYS_GETEUID = 25 // { uid_t|sys||geteuid(void); }
+ SYS_PTRACE = 26 // { int|sys||ptrace(int req, pid_t pid, void *addr, int data); }
+ SYS_RECVMSG = 27 // { ssize_t|sys||recvmsg(int s, struct msghdr *msg, int flags); }
+ SYS_SENDMSG = 28 // { ssize_t|sys||sendmsg(int s, const struct msghdr *msg, int flags); }
+ SYS_RECVFROM = 29 // { ssize_t|sys||recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); }
+ SYS_ACCEPT = 30 // { int|sys||accept(int s, struct sockaddr *name, socklen_t *anamelen); }
+ SYS_GETPEERNAME = 31 // { int|sys||getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); }
+ SYS_GETSOCKNAME = 32 // { int|sys||getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); }
+ SYS_ACCESS = 33 // { int|sys||access(const char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int|sys||chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int|sys||fchflags(int fd, u_long flags); }
+ SYS_SYNC = 36 // { void|sys||sync(void); }
+ SYS_KILL = 37 // { int|sys||kill(pid_t pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t|sys||getppid(void); }
+ SYS_DUP = 41 // { int|sys||dup(int fd); }
+ SYS_PIPE = 42 // { int|sys||pipe(void); }
+ SYS_GETEGID = 43 // { gid_t|sys||getegid(void); }
+ SYS_PROFIL = 44 // { int|sys||profil(char *samples, size_t size, u_long offset, u_int scale); }
+ SYS_KTRACE = 45 // { int|sys||ktrace(const char *fname, int ops, int facs, pid_t pid); }
+ SYS_GETGID = 47 // { gid_t|sys||getgid_with_egid(void); }
+ SYS___GETLOGIN = 49 // { int|sys||__getlogin(char *namebuf, size_t namelen); }
+ SYS___SETLOGIN = 50 // { int|sys||__setlogin(const char *namebuf); }
+ SYS_ACCT = 51 // { int|sys||acct(const char *path); }
+ SYS_IOCTL = 54 // { int|sys||ioctl(int fd, u_long com, ... void *data); }
+ SYS_REVOKE = 56 // { int|sys||revoke(const char *path); }
+ SYS_SYMLINK = 57 // { int|sys||symlink(const char *path, const char *link); }
+ SYS_READLINK = 58 // { ssize_t|sys||readlink(const char *path, char *buf, size_t count); }
+ SYS_EXECVE = 59 // { int|sys||execve(const char *path, char * const *argp, char * const *envp); }
+ SYS_UMASK = 60 // { mode_t|sys||umask(mode_t newmask); }
+ SYS_CHROOT = 61 // { int|sys||chroot(const char *path); }
+ SYS_VFORK = 66 // { int|sys||vfork(void); }
+ SYS_SBRK = 69 // { int|sys||sbrk(intptr_t incr); }
+ SYS_SSTK = 70 // { int|sys||sstk(int incr); }
+ SYS_VADVISE = 72 // { int|sys||ovadvise(int anom); }
+ SYS_MUNMAP = 73 // { int|sys||munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int|sys||mprotect(void *addr, size_t len, int prot); }
+ SYS_MADVISE = 75 // { int|sys||madvise(void *addr, size_t len, int behav); }
+ SYS_MINCORE = 78 // { int|sys||mincore(void *addr, size_t len, char *vec); }
+ SYS_GETGROUPS = 79 // { int|sys||getgroups(int gidsetsize, gid_t *gidset); }
+ SYS_SETGROUPS = 80 // { int|sys||setgroups(int gidsetsize, const gid_t *gidset); }
+ SYS_GETPGRP = 81 // { int|sys||getpgrp(void); }
+ SYS_SETPGID = 82 // { int|sys||setpgid(pid_t pid, pid_t pgid); }
+ SYS_DUP2 = 90 // { int|sys||dup2(int from, int to); }
+ SYS_FCNTL = 92 // { int|sys||fcntl(int fd, int cmd, ... void *arg); }
+ SYS_FSYNC = 95 // { int|sys||fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int|sys||setpriority(int which, id_t who, int prio); }
+ SYS_CONNECT = 98 // { int|sys||connect(int s, const struct sockaddr *name, socklen_t namelen); }
+ SYS_GETPRIORITY = 100 // { int|sys||getpriority(int which, id_t who); }
+ SYS_BIND = 104 // { int|sys||bind(int s, const struct sockaddr *name, socklen_t namelen); }
+ SYS_SETSOCKOPT = 105 // { int|sys||setsockopt(int s, int level, int name, const void *val, socklen_t valsize); }
+ SYS_LISTEN = 106 // { int|sys||listen(int s, int backlog); }
+ SYS_GETSOCKOPT = 118 // { int|sys||getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); }
+ SYS_READV = 120 // { ssize_t|sys||readv(int fd, const struct iovec *iovp, int iovcnt); }
+ SYS_WRITEV = 121 // { ssize_t|sys||writev(int fd, const struct iovec *iovp, int iovcnt); }
+ SYS_FCHOWN = 123 // { int|sys||fchown(int fd, uid_t uid, gid_t gid); }
+ SYS_FCHMOD = 124 // { int|sys||fchmod(int fd, mode_t mode); }
+ SYS_SETREUID = 126 // { int|sys||setreuid(uid_t ruid, uid_t euid); }
+ SYS_SETREGID = 127 // { int|sys||setregid(gid_t rgid, gid_t egid); }
+ SYS_RENAME = 128 // { int|sys||rename(const char *from, const char *to); }
+ SYS_FLOCK = 131 // { int|sys||flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int|sys||mkfifo(const char *path, mode_t mode); }
+ SYS_SENDTO = 133 // { ssize_t|sys||sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); }
+ SYS_SHUTDOWN = 134 // { int|sys||shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int|sys||socketpair(int domain, int type, int protocol, int *rsv); }
+ SYS_MKDIR = 136 // { int|sys||mkdir(const char *path, mode_t mode); }
+ SYS_RMDIR = 137 // { int|sys||rmdir(const char *path); }
+ SYS_SETSID = 147 // { int|sys||setsid(void); }
+ SYS_SYSARCH = 165 // { int|sys||sysarch(int op, void *parms); }
+ SYS_PREAD = 173 // { ssize_t|sys||pread(int fd, void *buf, size_t nbyte, int PAD, off_t offset); }
+ SYS_PWRITE = 174 // { ssize_t|sys||pwrite(int fd, const void *buf, size_t nbyte, int PAD, off_t offset); }
+ SYS_NTP_ADJTIME = 176 // { int|sys||ntp_adjtime(struct timex *tp); }
+ SYS_SETGID = 181 // { int|sys||setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int|sys||setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int|sys||seteuid(uid_t euid); }
+ SYS_PATHCONF = 191 // { long|sys||pathconf(const char *path, int name); }
+ SYS_FPATHCONF = 192 // { long|sys||fpathconf(int fd, int name); }
+ SYS_GETRLIMIT = 194 // { int|sys||getrlimit(int which, struct rlimit *rlp); }
+ SYS_SETRLIMIT = 195 // { int|sys||setrlimit(int which, const struct rlimit *rlp); }
+ SYS_MMAP = 197 // { void *|sys||mmap(void *addr, size_t len, int prot, int flags, int fd, long PAD, off_t pos); }
+ SYS_LSEEK = 199 // { off_t|sys||lseek(int fd, int PAD, off_t offset, int whence); }
+ SYS_TRUNCATE = 200 // { int|sys||truncate(const char *path, int PAD, off_t length); }
+ SYS_FTRUNCATE = 201 // { int|sys||ftruncate(int fd, int PAD, off_t length); }
+ SYS___SYSCTL = 202 // { int|sys||__sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, const void *new, size_t newlen); }
+ SYS_MLOCK = 203 // { int|sys||mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int|sys||munlock(const void *addr, size_t len); }
+ SYS_UNDELETE = 205 // { int|sys||undelete(const char *path); }
+ SYS_GETPGID = 207 // { pid_t|sys||getpgid(pid_t pid); }
+ SYS_REBOOT = 208 // { int|sys||reboot(int opt, char *bootstr); }
+ SYS_POLL = 209 // { int|sys||poll(struct pollfd *fds, u_int nfds, int timeout); }
+ SYS_SEMGET = 221 // { int|sys||semget(key_t key, int nsems, int semflg); }
+ SYS_SEMOP = 222 // { int|sys||semop(int semid, struct sembuf *sops, size_t nsops); }
+ SYS_SEMCONFIG = 223 // { int|sys||semconfig(int flag); }
+ SYS_MSGGET = 225 // { int|sys||msgget(key_t key, int msgflg); }
+ SYS_MSGSND = 226 // { int|sys||msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); }
+ SYS_MSGRCV = 227 // { ssize_t|sys||msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); }
+ SYS_SHMAT = 228 // { void *|sys||shmat(int shmid, const void *shmaddr, int shmflg); }
+ SYS_SHMDT = 230 // { int|sys||shmdt(const void *shmaddr); }
+ SYS_SHMGET = 231 // { int|sys||shmget(key_t key, size_t size, int shmflg); }
+ SYS_TIMER_CREATE = 235 // { int|sys||timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid); }
+ SYS_TIMER_DELETE = 236 // { int|sys||timer_delete(timer_t timerid); }
+ SYS_TIMER_GETOVERRUN = 239 // { int|sys||timer_getoverrun(timer_t timerid); }
+ SYS_FDATASYNC = 241 // { int|sys||fdatasync(int fd); }
+ SYS_MLOCKALL = 242 // { int|sys||mlockall(int flags); }
+ SYS_MUNLOCKALL = 243 // { int|sys||munlockall(void); }
+ SYS_SIGQUEUEINFO = 245 // { int|sys||sigqueueinfo(pid_t pid, const siginfo_t *info); }
+ SYS_MODCTL = 246 // { int|sys||modctl(int cmd, void *arg); }
+ SYS___POSIX_RENAME = 270 // { int|sys||__posix_rename(const char *from, const char *to); }
+ SYS_SWAPCTL = 271 // { int|sys||swapctl(int cmd, void *arg, int misc); }
+ SYS_MINHERIT = 273 // { int|sys||minherit(void *addr, size_t len, int inherit); }
+ SYS_LCHMOD = 274 // { int|sys||lchmod(const char *path, mode_t mode); }
+ SYS_LCHOWN = 275 // { int|sys||lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS___POSIX_CHOWN = 283 // { int|sys||__posix_chown(const char *path, uid_t uid, gid_t gid); }
+ SYS___POSIX_FCHOWN = 284 // { int|sys||__posix_fchown(int fd, uid_t uid, gid_t gid); }
+ SYS___POSIX_LCHOWN = 285 // { int|sys||__posix_lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS_GETSID = 286 // { pid_t|sys||getsid(pid_t pid); }
+ SYS___CLONE = 287 // { pid_t|sys||__clone(int flags, void *stack); }
+ SYS_FKTRACE = 288 // { int|sys||fktrace(int fd, int ops, int facs, pid_t pid); }
+ SYS_PREADV = 289 // { ssize_t|sys||preadv(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); }
+ SYS_PWRITEV = 290 // { ssize_t|sys||pwritev(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); }
+ SYS___GETCWD = 296 // { int|sys||__getcwd(char *bufp, size_t length); }
+ SYS_FCHROOT = 297 // { int|sys||fchroot(int fd); }
+ SYS_LCHFLAGS = 304 // { int|sys||lchflags(const char *path, u_long flags); }
+ SYS_ISSETUGID = 305 // { int|sys||issetugid(void); }
+ SYS_UTRACE = 306 // { int|sys||utrace(const char *label, void *addr, size_t len); }
+ SYS_GETCONTEXT = 307 // { int|sys||getcontext(struct __ucontext *ucp); }
+ SYS_SETCONTEXT = 308 // { int|sys||setcontext(const struct __ucontext *ucp); }
+ SYS__LWP_CREATE = 309 // { int|sys||_lwp_create(const struct __ucontext *ucp, u_long flags, lwpid_t *new_lwp); }
+ SYS__LWP_EXIT = 310 // { int|sys||_lwp_exit(void); }
+ SYS__LWP_SELF = 311 // { lwpid_t|sys||_lwp_self(void); }
+ SYS__LWP_WAIT = 312 // { int|sys||_lwp_wait(lwpid_t wait_for, lwpid_t *departed); }
+ SYS__LWP_SUSPEND = 313 // { int|sys||_lwp_suspend(lwpid_t target); }
+ SYS__LWP_CONTINUE = 314 // { int|sys||_lwp_continue(lwpid_t target); }
+ SYS__LWP_WAKEUP = 315 // { int|sys||_lwp_wakeup(lwpid_t target); }
+ SYS__LWP_GETPRIVATE = 316 // { void *|sys||_lwp_getprivate(void); }
+ SYS__LWP_SETPRIVATE = 317 // { void|sys||_lwp_setprivate(void *ptr); }
+ SYS__LWP_KILL = 318 // { int|sys||_lwp_kill(lwpid_t target, int signo); }
+ SYS__LWP_DETACH = 319 // { int|sys||_lwp_detach(lwpid_t target); }
+ SYS__LWP_UNPARK = 321 // { int|sys||_lwp_unpark(lwpid_t target, const void *hint); }
+ SYS__LWP_UNPARK_ALL = 322 // { ssize_t|sys||_lwp_unpark_all(const lwpid_t *targets, size_t ntargets, const void *hint); }
+ SYS__LWP_SETNAME = 323 // { int|sys||_lwp_setname(lwpid_t target, const char *name); }
+ SYS__LWP_GETNAME = 324 // { int|sys||_lwp_getname(lwpid_t target, char *name, size_t len); }
+ SYS__LWP_CTL = 325 // { int|sys||_lwp_ctl(int features, struct lwpctl **address); }
+ SYS_SA_REGISTER = 330 // { int|sys||sa_register(sa_upcall_t new, sa_upcall_t *old, int flags, ssize_t stackinfo_offset); }
+ SYS_SA_STACKS = 331 // { int|sys||sa_stacks(int num, stack_t *stacks); }
+ SYS_SA_ENABLE = 332 // { int|sys||sa_enable(void); }
+ SYS_SA_SETCONCURRENCY = 333 // { int|sys||sa_setconcurrency(int concurrency); }
+ SYS_SA_YIELD = 334 // { int|sys||sa_yield(void); }
+ SYS_SA_PREEMPT = 335 // { int|sys||sa_preempt(int sa_id); }
+ SYS___SIGACTION_SIGTRAMP = 340 // { int|sys||__sigaction_sigtramp(int signum, const struct sigaction *nsa, struct sigaction *osa, const void *tramp, int vers); }
+ SYS_PMC_GET_INFO = 341 // { int|sys||pmc_get_info(int ctr, int op, void *args); }
+ SYS_PMC_CONTROL = 342 // { int|sys||pmc_control(int ctr, int op, void *args); }
+ SYS_RASCTL = 343 // { int|sys||rasctl(void *addr, size_t len, int op); }
+ SYS_KQUEUE = 344 // { int|sys||kqueue(void); }
+ SYS__SCHED_SETPARAM = 346 // { int|sys||_sched_setparam(pid_t pid, lwpid_t lid, int policy, const struct sched_param *params); }
+ SYS__SCHED_GETPARAM = 347 // { int|sys||_sched_getparam(pid_t pid, lwpid_t lid, int *policy, struct sched_param *params); }
+ SYS__SCHED_SETAFFINITY = 348 // { int|sys||_sched_setaffinity(pid_t pid, lwpid_t lid, size_t size, const cpuset_t *cpuset); }
+ SYS__SCHED_GETAFFINITY = 349 // { int|sys||_sched_getaffinity(pid_t pid, lwpid_t lid, size_t size, cpuset_t *cpuset); }
+ SYS_SCHED_YIELD = 350 // { int|sys||sched_yield(void); }
+ SYS_FSYNC_RANGE = 354 // { int|sys||fsync_range(int fd, int flags, off_t start, off_t length); }
+ SYS_UUIDGEN = 355 // { int|sys||uuidgen(struct uuid *store, int count); }
+ SYS_GETVFSSTAT = 356 // { int|sys||getvfsstat(struct statvfs *buf, size_t bufsize, int flags); }
+ SYS_STATVFS1 = 357 // { int|sys||statvfs1(const char *path, struct statvfs *buf, int flags); }
+ SYS_FSTATVFS1 = 358 // { int|sys||fstatvfs1(int fd, struct statvfs *buf, int flags); }
+ SYS_EXTATTRCTL = 360 // { int|sys||extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_FILE = 361 // { int|sys||extattr_set_file(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_FILE = 362 // { ssize_t|sys||extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_FILE = 363 // { int|sys||extattr_delete_file(const char *path, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_FD = 364 // { int|sys||extattr_set_fd(int fd, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_FD = 365 // { ssize_t|sys||extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_FD = 366 // { int|sys||extattr_delete_fd(int fd, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_LINK = 367 // { int|sys||extattr_set_link(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_LINK = 368 // { ssize_t|sys||extattr_get_link(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_LINK = 369 // { int|sys||extattr_delete_link(const char *path, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_LIST_FD = 370 // { ssize_t|sys||extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); }
+ SYS_EXTATTR_LIST_FILE = 371 // { ssize_t|sys||extattr_list_file(const char *path, int attrnamespace, void *data, size_t nbytes); }
+ SYS_EXTATTR_LIST_LINK = 372 // { ssize_t|sys||extattr_list_link(const char *path, int attrnamespace, void *data, size_t nbytes); }
+ SYS_SETXATTR = 375 // { int|sys||setxattr(const char *path, const char *name, const void *value, size_t size, int flags); }
+ SYS_LSETXATTR = 376 // { int|sys||lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); }
+ SYS_FSETXATTR = 377 // { int|sys||fsetxattr(int fd, const char *name, const void *value, size_t size, int flags); }
+ SYS_GETXATTR = 378 // { int|sys||getxattr(const char *path, const char *name, void *value, size_t size); }
+ SYS_LGETXATTR = 379 // { int|sys||lgetxattr(const char *path, const char *name, void *value, size_t size); }
+ SYS_FGETXATTR = 380 // { int|sys||fgetxattr(int fd, const char *name, void *value, size_t size); }
+ SYS_LISTXATTR = 381 // { int|sys||listxattr(const char *path, char *list, size_t size); }
+ SYS_LLISTXATTR = 382 // { int|sys||llistxattr(const char *path, char *list, size_t size); }
+ SYS_FLISTXATTR = 383 // { int|sys||flistxattr(int fd, char *list, size_t size); }
+ SYS_REMOVEXATTR = 384 // { int|sys||removexattr(const char *path, const char *name); }
+ SYS_LREMOVEXATTR = 385 // { int|sys||lremovexattr(const char *path, const char *name); }
+ SYS_FREMOVEXATTR = 386 // { int|sys||fremovexattr(int fd, const char *name); }
+ SYS_GETDENTS = 390 // { int|sys|30|getdents(int fd, char *buf, size_t count); }
+ SYS_SOCKET = 394 // { int|sys|30|socket(int domain, int type, int protocol); }
+ SYS_GETFH = 395 // { int|sys|30|getfh(const char *fname, void *fhp, size_t *fh_size); }
+ SYS_MOUNT = 410 // { int|sys|50|mount(const char *type, const char *path, int flags, void *data, size_t data_len); }
+ SYS_MREMAP = 411 // { void *|sys||mremap(void *old_address, size_t old_size, void *new_address, size_t new_size, int flags); }
+ SYS_PSET_CREATE = 412 // { int|sys||pset_create(psetid_t *psid); }
+ SYS_PSET_DESTROY = 413 // { int|sys||pset_destroy(psetid_t psid); }
+ SYS_PSET_ASSIGN = 414 // { int|sys||pset_assign(psetid_t psid, cpuid_t cpuid, psetid_t *opsid); }
+ SYS__PSET_BIND = 415 // { int|sys||_pset_bind(idtype_t idtype, id_t first_id, id_t second_id, psetid_t psid, psetid_t *opsid); }
+ SYS_POSIX_FADVISE = 416 // { int|sys|50|posix_fadvise(int fd, int PAD, off_t offset, off_t len, int advice); }
+ SYS_SELECT = 417 // { int|sys|50|select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); }
+ SYS_GETTIMEOFDAY = 418 // { int|sys|50|gettimeofday(struct timeval *tp, void *tzp); }
+ SYS_SETTIMEOFDAY = 419 // { int|sys|50|settimeofday(const struct timeval *tv, const void *tzp); }
+ SYS_UTIMES = 420 // { int|sys|50|utimes(const char *path, const struct timeval *tptr); }
+ SYS_ADJTIME = 421 // { int|sys|50|adjtime(const struct timeval *delta, struct timeval *olddelta); }
+ SYS_FUTIMES = 423 // { int|sys|50|futimes(int fd, const struct timeval *tptr); }
+ SYS_LUTIMES = 424 // { int|sys|50|lutimes(const char *path, const struct timeval *tptr); }
+ SYS_SETITIMER = 425 // { int|sys|50|setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); }
+ SYS_GETITIMER = 426 // { int|sys|50|getitimer(int which, struct itimerval *itv); }
+ SYS_CLOCK_GETTIME = 427 // { int|sys|50|clock_gettime(clockid_t clock_id, struct timespec *tp); }
+ SYS_CLOCK_SETTIME = 428 // { int|sys|50|clock_settime(clockid_t clock_id, const struct timespec *tp); }
+ SYS_CLOCK_GETRES = 429 // { int|sys|50|clock_getres(clockid_t clock_id, struct timespec *tp); }
+ SYS_NANOSLEEP = 430 // { int|sys|50|nanosleep(const struct timespec *rqtp, struct timespec *rmtp); }
+ SYS___SIGTIMEDWAIT = 431 // { int|sys|50|__sigtimedwait(const sigset_t *set, siginfo_t *info, struct timespec *timeout); }
+ SYS__LWP_PARK = 434 // { int|sys|50|_lwp_park(const struct timespec *ts, lwpid_t unpark, const void *hint, const void *unparkhint); }
+ SYS_KEVENT = 435 // { int|sys|50|kevent(int fd, const struct kevent *changelist, size_t nchanges, struct kevent *eventlist, size_t nevents, const struct timespec *timeout); }
+ SYS_PSELECT = 436 // { int|sys|50|pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); }
+ SYS_POLLTS = 437 // { int|sys|50|pollts(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); }
+ SYS_STAT = 439 // { int|sys|50|stat(const char *path, struct stat *ub); }
+ SYS_FSTAT = 440 // { int|sys|50|fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 441 // { int|sys|50|lstat(const char *path, struct stat *ub); }
+ SYS___SEMCTL = 442 // { int|sys|50|__semctl(int semid, int semnum, int cmd, ... union __semun *arg); }
+ SYS_SHMCTL = 443 // { int|sys|50|shmctl(int shmid, int cmd, struct shmid_ds *buf); }
+ SYS_MSGCTL = 444 // { int|sys|50|msgctl(int msqid, int cmd, struct msqid_ds *buf); }
+ SYS_GETRUSAGE = 445 // { int|sys|50|getrusage(int who, struct rusage *rusage); }
+ SYS_TIMER_SETTIME = 446 // { int|sys|50|timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); }
+ SYS_TIMER_GETTIME = 447 // { int|sys|50|timer_gettime(timer_t timerid, struct itimerspec *value); }
+ SYS_NTP_GETTIME = 448 // { int|sys|50|ntp_gettime(struct ntptimeval *ntvp); }
+ SYS_WAIT4 = 449 // { int|sys|50|wait4(pid_t pid, int *status, int options, struct rusage *rusage); }
+ SYS_MKNOD = 450 // { int|sys|50|mknod(const char *path, mode_t mode, dev_t dev); }
+ SYS_FHSTAT = 451 // { int|sys|50|fhstat(const void *fhp, size_t fh_size, struct stat *sb); }
+ SYS_QUOTACTL = 452 // { int|sys|50|quotactl(const char *path, struct plistref *pref); }
+ SYS_PIPE2 = 453 // { int|sys||pipe2(int *fildes, int flags); }
+ SYS_DUP3 = 454 // { int|sys||dup3(int from, int to, int flags); }
+ SYS_KQUEUE1 = 455 // { int|sys||kqueue1(int flags); }
+ SYS_PACCEPT = 456 // { int|sys||paccept(int s, struct sockaddr *name, socklen_t *anamelen, const sigset_t *mask, int flags); }
+ SYS_LINKAT = 457 // { int|sys||linkat(int fd1, const char *name1, int fd2, const char *name2, int flags); }
+ SYS_RENAMEAT = 458 // { int|sys||renameat(int fromfd, const char *from, int tofd, const char *to); }
+ SYS_MKFIFOAT = 459 // { int|sys||mkfifoat(int fd, const char *path, mode_t mode); }
+ SYS_MKNODAT = 460 // { int|sys||mknodat(int fd, const char *path, mode_t mode, uint32_t dev); }
+ SYS_MKDIRAT = 461 // { int|sys||mkdirat(int fd, const char *path, mode_t mode); }
+ SYS_FACCESSAT = 462 // { int|sys||faccessat(int fd, const char *path, int amode, int flag); }
+ SYS_FCHMODAT = 463 // { int|sys||fchmodat(int fd, const char *path, mode_t mode, int flag); }
+ SYS_FCHOWNAT = 464 // { int|sys||fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag); }
+ SYS_FEXECVE = 465 // { int|sys||fexecve(int fd, char * const *argp, char * const *envp); }
+ SYS_FSTATAT = 466 // { int|sys||fstatat(int fd, const char *path, struct stat *buf, int flag); }
+ SYS_UTIMENSAT = 467 // { int|sys||utimensat(int fd, const char *path, const struct timespec *tptr, int flag); }
+ SYS_OPENAT = 468 // { int|sys||openat(int fd, const char *path, int oflags, ... mode_t mode); }
+ SYS_READLINKAT = 469 // { int|sys||readlinkat(int fd, const char *path, char *buf, size_t bufsize); }
+ SYS_SYMLINKAT = 470 // { int|sys||symlinkat(const char *path1, int fd, const char *path2); }
+ SYS_UNLINKAT = 471 // { int|sys||unlinkat(int fd, const char *path, int flag); }
+ SYS_FUTIMENS = 472 // { int|sys||futimens(int fd, const struct timespec *tptr); }
+)
diff --git a/src/pkg/syscall/zsysnum_netbsd_amd64.go b/src/pkg/syscall/zsysnum_netbsd_amd64.go
new file mode 100644
index 000000000..e9a0bcfb1
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_netbsd_amd64.go
@@ -0,0 +1,274 @@
+// mksysnum_netbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_EXIT = 1 // { void|sys||exit(int rval); }
+ SYS_FORK = 2 // { int|sys||fork(void); }
+ SYS_READ = 3 // { ssize_t|sys||read(int fd, void *buf, size_t nbyte); }
+ SYS_WRITE = 4 // { ssize_t|sys||write(int fd, const void *buf, size_t nbyte); }
+ SYS_OPEN = 5 // { int|sys||open(const char *path, int flags, ... mode_t mode); }
+ SYS_CLOSE = 6 // { int|sys||close(int fd); }
+ SYS_LINK = 9 // { int|sys||link(const char *path, const char *link); }
+ SYS_UNLINK = 10 // { int|sys||unlink(const char *path); }
+ SYS_CHDIR = 12 // { int|sys||chdir(const char *path); }
+ SYS_FCHDIR = 13 // { int|sys||fchdir(int fd); }
+ SYS_CHMOD = 15 // { int|sys||chmod(const char *path, mode_t mode); }
+ SYS_CHOWN = 16 // { int|sys||chown(const char *path, uid_t uid, gid_t gid); }
+ SYS_BREAK = 17 // { int|sys||obreak(char *nsize); }
+ SYS_GETPID = 20 // { pid_t|sys||getpid_with_ppid(void); }
+ SYS_UNMOUNT = 22 // { int|sys||unmount(const char *path, int flags); }
+ SYS_SETUID = 23 // { int|sys||setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t|sys||getuid_with_euid(void); }
+ SYS_GETEUID = 25 // { uid_t|sys||geteuid(void); }
+ SYS_PTRACE = 26 // { int|sys||ptrace(int req, pid_t pid, void *addr, int data); }
+ SYS_RECVMSG = 27 // { ssize_t|sys||recvmsg(int s, struct msghdr *msg, int flags); }
+ SYS_SENDMSG = 28 // { ssize_t|sys||sendmsg(int s, const struct msghdr *msg, int flags); }
+ SYS_RECVFROM = 29 // { ssize_t|sys||recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlenaddr); }
+ SYS_ACCEPT = 30 // { int|sys||accept(int s, struct sockaddr *name, socklen_t *anamelen); }
+ SYS_GETPEERNAME = 31 // { int|sys||getpeername(int fdes, struct sockaddr *asa, socklen_t *alen); }
+ SYS_GETSOCKNAME = 32 // { int|sys||getsockname(int fdes, struct sockaddr *asa, socklen_t *alen); }
+ SYS_ACCESS = 33 // { int|sys||access(const char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int|sys||chflags(const char *path, u_long flags); }
+ SYS_FCHFLAGS = 35 // { int|sys||fchflags(int fd, u_long flags); }
+ SYS_SYNC = 36 // { void|sys||sync(void); }
+ SYS_KILL = 37 // { int|sys||kill(pid_t pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t|sys||getppid(void); }
+ SYS_DUP = 41 // { int|sys||dup(int fd); }
+ SYS_PIPE = 42 // { int|sys||pipe(void); }
+ SYS_GETEGID = 43 // { gid_t|sys||getegid(void); }
+ SYS_PROFIL = 44 // { int|sys||profil(char *samples, size_t size, u_long offset, u_int scale); }
+ SYS_KTRACE = 45 // { int|sys||ktrace(const char *fname, int ops, int facs, pid_t pid); }
+ SYS_GETGID = 47 // { gid_t|sys||getgid_with_egid(void); }
+ SYS___GETLOGIN = 49 // { int|sys||__getlogin(char *namebuf, size_t namelen); }
+ SYS___SETLOGIN = 50 // { int|sys||__setlogin(const char *namebuf); }
+ SYS_ACCT = 51 // { int|sys||acct(const char *path); }
+ SYS_IOCTL = 54 // { int|sys||ioctl(int fd, u_long com, ... void *data); }
+ SYS_REVOKE = 56 // { int|sys||revoke(const char *path); }
+ SYS_SYMLINK = 57 // { int|sys||symlink(const char *path, const char *link); }
+ SYS_READLINK = 58 // { ssize_t|sys||readlink(const char *path, char *buf, size_t count); }
+ SYS_EXECVE = 59 // { int|sys||execve(const char *path, char * const *argp, char * const *envp); }
+ SYS_UMASK = 60 // { mode_t|sys||umask(mode_t newmask); }
+ SYS_CHROOT = 61 // { int|sys||chroot(const char *path); }
+ SYS_VFORK = 66 // { int|sys||vfork(void); }
+ SYS_SBRK = 69 // { int|sys||sbrk(intptr_t incr); }
+ SYS_SSTK = 70 // { int|sys||sstk(int incr); }
+ SYS_VADVISE = 72 // { int|sys||ovadvise(int anom); }
+ SYS_MUNMAP = 73 // { int|sys||munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int|sys||mprotect(void *addr, size_t len, int prot); }
+ SYS_MADVISE = 75 // { int|sys||madvise(void *addr, size_t len, int behav); }
+ SYS_MINCORE = 78 // { int|sys||mincore(void *addr, size_t len, char *vec); }
+ SYS_GETGROUPS = 79 // { int|sys||getgroups(int gidsetsize, gid_t *gidset); }
+ SYS_SETGROUPS = 80 // { int|sys||setgroups(int gidsetsize, const gid_t *gidset); }
+ SYS_GETPGRP = 81 // { int|sys||getpgrp(void); }
+ SYS_SETPGID = 82 // { int|sys||setpgid(pid_t pid, pid_t pgid); }
+ SYS_DUP2 = 90 // { int|sys||dup2(int from, int to); }
+ SYS_FCNTL = 92 // { int|sys||fcntl(int fd, int cmd, ... void *arg); }
+ SYS_FSYNC = 95 // { int|sys||fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int|sys||setpriority(int which, id_t who, int prio); }
+ SYS_CONNECT = 98 // { int|sys||connect(int s, const struct sockaddr *name, socklen_t namelen); }
+ SYS_GETPRIORITY = 100 // { int|sys||getpriority(int which, id_t who); }
+ SYS_BIND = 104 // { int|sys||bind(int s, const struct sockaddr *name, socklen_t namelen); }
+ SYS_SETSOCKOPT = 105 // { int|sys||setsockopt(int s, int level, int name, const void *val, socklen_t valsize); }
+ SYS_LISTEN = 106 // { int|sys||listen(int s, int backlog); }
+ SYS_GETSOCKOPT = 118 // { int|sys||getsockopt(int s, int level, int name, void *val, socklen_t *avalsize); }
+ SYS_READV = 120 // { ssize_t|sys||readv(int fd, const struct iovec *iovp, int iovcnt); }
+ SYS_WRITEV = 121 // { ssize_t|sys||writev(int fd, const struct iovec *iovp, int iovcnt); }
+ SYS_FCHOWN = 123 // { int|sys||fchown(int fd, uid_t uid, gid_t gid); }
+ SYS_FCHMOD = 124 // { int|sys||fchmod(int fd, mode_t mode); }
+ SYS_SETREUID = 126 // { int|sys||setreuid(uid_t ruid, uid_t euid); }
+ SYS_SETREGID = 127 // { int|sys||setregid(gid_t rgid, gid_t egid); }
+ SYS_RENAME = 128 // { int|sys||rename(const char *from, const char *to); }
+ SYS_FLOCK = 131 // { int|sys||flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int|sys||mkfifo(const char *path, mode_t mode); }
+ SYS_SENDTO = 133 // { ssize_t|sys||sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); }
+ SYS_SHUTDOWN = 134 // { int|sys||shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int|sys||socketpair(int domain, int type, int protocol, int *rsv); }
+ SYS_MKDIR = 136 // { int|sys||mkdir(const char *path, mode_t mode); }
+ SYS_RMDIR = 137 // { int|sys||rmdir(const char *path); }
+ SYS_SETSID = 147 // { int|sys||setsid(void); }
+ SYS_SYSARCH = 165 // { int|sys||sysarch(int op, void *parms); }
+ SYS_PREAD = 173 // { ssize_t|sys||pread(int fd, void *buf, size_t nbyte, int PAD, off_t offset); }
+ SYS_PWRITE = 174 // { ssize_t|sys||pwrite(int fd, const void *buf, size_t nbyte, int PAD, off_t offset); }
+ SYS_NTP_ADJTIME = 176 // { int|sys||ntp_adjtime(struct timex *tp); }
+ SYS_SETGID = 181 // { int|sys||setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int|sys||setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int|sys||seteuid(uid_t euid); }
+ SYS_PATHCONF = 191 // { long|sys||pathconf(const char *path, int name); }
+ SYS_FPATHCONF = 192 // { long|sys||fpathconf(int fd, int name); }
+ SYS_GETRLIMIT = 194 // { int|sys||getrlimit(int which, struct rlimit *rlp); }
+ SYS_SETRLIMIT = 195 // { int|sys||setrlimit(int which, const struct rlimit *rlp); }
+ SYS_MMAP = 197 // { void *|sys||mmap(void *addr, size_t len, int prot, int flags, int fd, long PAD, off_t pos); }
+ SYS_LSEEK = 199 // { off_t|sys||lseek(int fd, int PAD, off_t offset, int whence); }
+ SYS_TRUNCATE = 200 // { int|sys||truncate(const char *path, int PAD, off_t length); }
+ SYS_FTRUNCATE = 201 // { int|sys||ftruncate(int fd, int PAD, off_t length); }
+ SYS___SYSCTL = 202 // { int|sys||__sysctl(const int *name, u_int namelen, void *old, size_t *oldlenp, const void *new, size_t newlen); }
+ SYS_MLOCK = 203 // { int|sys||mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int|sys||munlock(const void *addr, size_t len); }
+ SYS_UNDELETE = 205 // { int|sys||undelete(const char *path); }
+ SYS_GETPGID = 207 // { pid_t|sys||getpgid(pid_t pid); }
+ SYS_REBOOT = 208 // { int|sys||reboot(int opt, char *bootstr); }
+ SYS_POLL = 209 // { int|sys||poll(struct pollfd *fds, u_int nfds, int timeout); }
+ SYS_SEMGET = 221 // { int|sys||semget(key_t key, int nsems, int semflg); }
+ SYS_SEMOP = 222 // { int|sys||semop(int semid, struct sembuf *sops, size_t nsops); }
+ SYS_SEMCONFIG = 223 // { int|sys||semconfig(int flag); }
+ SYS_MSGGET = 225 // { int|sys||msgget(key_t key, int msgflg); }
+ SYS_MSGSND = 226 // { int|sys||msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); }
+ SYS_MSGRCV = 227 // { ssize_t|sys||msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); }
+ SYS_SHMAT = 228 // { void *|sys||shmat(int shmid, const void *shmaddr, int shmflg); }
+ SYS_SHMDT = 230 // { int|sys||shmdt(const void *shmaddr); }
+ SYS_SHMGET = 231 // { int|sys||shmget(key_t key, size_t size, int shmflg); }
+ SYS_TIMER_CREATE = 235 // { int|sys||timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid); }
+ SYS_TIMER_DELETE = 236 // { int|sys||timer_delete(timer_t timerid); }
+ SYS_TIMER_GETOVERRUN = 239 // { int|sys||timer_getoverrun(timer_t timerid); }
+ SYS_FDATASYNC = 241 // { int|sys||fdatasync(int fd); }
+ SYS_MLOCKALL = 242 // { int|sys||mlockall(int flags); }
+ SYS_MUNLOCKALL = 243 // { int|sys||munlockall(void); }
+ SYS_SIGQUEUEINFO = 245 // { int|sys||sigqueueinfo(pid_t pid, const siginfo_t *info); }
+ SYS_MODCTL = 246 // { int|sys||modctl(int cmd, void *arg); }
+ SYS___POSIX_RENAME = 270 // { int|sys||__posix_rename(const char *from, const char *to); }
+ SYS_SWAPCTL = 271 // { int|sys||swapctl(int cmd, void *arg, int misc); }
+ SYS_MINHERIT = 273 // { int|sys||minherit(void *addr, size_t len, int inherit); }
+ SYS_LCHMOD = 274 // { int|sys||lchmod(const char *path, mode_t mode); }
+ SYS_LCHOWN = 275 // { int|sys||lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS___POSIX_CHOWN = 283 // { int|sys||__posix_chown(const char *path, uid_t uid, gid_t gid); }
+ SYS___POSIX_FCHOWN = 284 // { int|sys||__posix_fchown(int fd, uid_t uid, gid_t gid); }
+ SYS___POSIX_LCHOWN = 285 // { int|sys||__posix_lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS_GETSID = 286 // { pid_t|sys||getsid(pid_t pid); }
+ SYS___CLONE = 287 // { pid_t|sys||__clone(int flags, void *stack); }
+ SYS_FKTRACE = 288 // { int|sys||fktrace(int fd, int ops, int facs, pid_t pid); }
+ SYS_PREADV = 289 // { ssize_t|sys||preadv(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); }
+ SYS_PWRITEV = 290 // { ssize_t|sys||pwritev(int fd, const struct iovec *iovp, int iovcnt, int PAD, off_t offset); }
+ SYS___GETCWD = 296 // { int|sys||__getcwd(char *bufp, size_t length); }
+ SYS_FCHROOT = 297 // { int|sys||fchroot(int fd); }
+ SYS_LCHFLAGS = 304 // { int|sys||lchflags(const char *path, u_long flags); }
+ SYS_ISSETUGID = 305 // { int|sys||issetugid(void); }
+ SYS_UTRACE = 306 // { int|sys||utrace(const char *label, void *addr, size_t len); }
+ SYS_GETCONTEXT = 307 // { int|sys||getcontext(struct __ucontext *ucp); }
+ SYS_SETCONTEXT = 308 // { int|sys||setcontext(const struct __ucontext *ucp); }
+ SYS__LWP_CREATE = 309 // { int|sys||_lwp_create(const struct __ucontext *ucp, u_long flags, lwpid_t *new_lwp); }
+ SYS__LWP_EXIT = 310 // { int|sys||_lwp_exit(void); }
+ SYS__LWP_SELF = 311 // { lwpid_t|sys||_lwp_self(void); }
+ SYS__LWP_WAIT = 312 // { int|sys||_lwp_wait(lwpid_t wait_for, lwpid_t *departed); }
+ SYS__LWP_SUSPEND = 313 // { int|sys||_lwp_suspend(lwpid_t target); }
+ SYS__LWP_CONTINUE = 314 // { int|sys||_lwp_continue(lwpid_t target); }
+ SYS__LWP_WAKEUP = 315 // { int|sys||_lwp_wakeup(lwpid_t target); }
+ SYS__LWP_GETPRIVATE = 316 // { void *|sys||_lwp_getprivate(void); }
+ SYS__LWP_SETPRIVATE = 317 // { void|sys||_lwp_setprivate(void *ptr); }
+ SYS__LWP_KILL = 318 // { int|sys||_lwp_kill(lwpid_t target, int signo); }
+ SYS__LWP_DETACH = 319 // { int|sys||_lwp_detach(lwpid_t target); }
+ SYS__LWP_UNPARK = 321 // { int|sys||_lwp_unpark(lwpid_t target, const void *hint); }
+ SYS__LWP_UNPARK_ALL = 322 // { ssize_t|sys||_lwp_unpark_all(const lwpid_t *targets, size_t ntargets, const void *hint); }
+ SYS__LWP_SETNAME = 323 // { int|sys||_lwp_setname(lwpid_t target, const char *name); }
+ SYS__LWP_GETNAME = 324 // { int|sys||_lwp_getname(lwpid_t target, char *name, size_t len); }
+ SYS__LWP_CTL = 325 // { int|sys||_lwp_ctl(int features, struct lwpctl **address); }
+ SYS_SA_REGISTER = 330 // { int|sys||sa_register(sa_upcall_t new, sa_upcall_t *old, int flags, ssize_t stackinfo_offset); }
+ SYS_SA_STACKS = 331 // { int|sys||sa_stacks(int num, stack_t *stacks); }
+ SYS_SA_ENABLE = 332 // { int|sys||sa_enable(void); }
+ SYS_SA_SETCONCURRENCY = 333 // { int|sys||sa_setconcurrency(int concurrency); }
+ SYS_SA_YIELD = 334 // { int|sys||sa_yield(void); }
+ SYS_SA_PREEMPT = 335 // { int|sys||sa_preempt(int sa_id); }
+ SYS___SIGACTION_SIGTRAMP = 340 // { int|sys||__sigaction_sigtramp(int signum, const struct sigaction *nsa, struct sigaction *osa, const void *tramp, int vers); }
+ SYS_PMC_GET_INFO = 341 // { int|sys||pmc_get_info(int ctr, int op, void *args); }
+ SYS_PMC_CONTROL = 342 // { int|sys||pmc_control(int ctr, int op, void *args); }
+ SYS_RASCTL = 343 // { int|sys||rasctl(void *addr, size_t len, int op); }
+ SYS_KQUEUE = 344 // { int|sys||kqueue(void); }
+ SYS__SCHED_SETPARAM = 346 // { int|sys||_sched_setparam(pid_t pid, lwpid_t lid, int policy, const struct sched_param *params); }
+ SYS__SCHED_GETPARAM = 347 // { int|sys||_sched_getparam(pid_t pid, lwpid_t lid, int *policy, struct sched_param *params); }
+ SYS__SCHED_SETAFFINITY = 348 // { int|sys||_sched_setaffinity(pid_t pid, lwpid_t lid, size_t size, const cpuset_t *cpuset); }
+ SYS__SCHED_GETAFFINITY = 349 // { int|sys||_sched_getaffinity(pid_t pid, lwpid_t lid, size_t size, cpuset_t *cpuset); }
+ SYS_SCHED_YIELD = 350 // { int|sys||sched_yield(void); }
+ SYS_FSYNC_RANGE = 354 // { int|sys||fsync_range(int fd, int flags, off_t start, off_t length); }
+ SYS_UUIDGEN = 355 // { int|sys||uuidgen(struct uuid *store, int count); }
+ SYS_GETVFSSTAT = 356 // { int|sys||getvfsstat(struct statvfs *buf, size_t bufsize, int flags); }
+ SYS_STATVFS1 = 357 // { int|sys||statvfs1(const char *path, struct statvfs *buf, int flags); }
+ SYS_FSTATVFS1 = 358 // { int|sys||fstatvfs1(int fd, struct statvfs *buf, int flags); }
+ SYS_EXTATTRCTL = 360 // { int|sys||extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_FILE = 361 // { int|sys||extattr_set_file(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_FILE = 362 // { ssize_t|sys||extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_FILE = 363 // { int|sys||extattr_delete_file(const char *path, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_FD = 364 // { int|sys||extattr_set_fd(int fd, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_FD = 365 // { ssize_t|sys||extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_FD = 366 // { int|sys||extattr_delete_fd(int fd, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_SET_LINK = 367 // { int|sys||extattr_set_link(const char *path, int attrnamespace, const char *attrname, const void *data, size_t nbytes); }
+ SYS_EXTATTR_GET_LINK = 368 // { ssize_t|sys||extattr_get_link(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
+ SYS_EXTATTR_DELETE_LINK = 369 // { int|sys||extattr_delete_link(const char *path, int attrnamespace, const char *attrname); }
+ SYS_EXTATTR_LIST_FD = 370 // { ssize_t|sys||extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); }
+ SYS_EXTATTR_LIST_FILE = 371 // { ssize_t|sys||extattr_list_file(const char *path, int attrnamespace, void *data, size_t nbytes); }
+ SYS_EXTATTR_LIST_LINK = 372 // { ssize_t|sys||extattr_list_link(const char *path, int attrnamespace, void *data, size_t nbytes); }
+ SYS_SETXATTR = 375 // { int|sys||setxattr(const char *path, const char *name, const void *value, size_t size, int flags); }
+ SYS_LSETXATTR = 376 // { int|sys||lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags); }
+ SYS_FSETXATTR = 377 // { int|sys||fsetxattr(int fd, const char *name, const void *value, size_t size, int flags); }
+ SYS_GETXATTR = 378 // { int|sys||getxattr(const char *path, const char *name, void *value, size_t size); }
+ SYS_LGETXATTR = 379 // { int|sys||lgetxattr(const char *path, const char *name, void *value, size_t size); }
+ SYS_FGETXATTR = 380 // { int|sys||fgetxattr(int fd, const char *name, void *value, size_t size); }
+ SYS_LISTXATTR = 381 // { int|sys||listxattr(const char *path, char *list, size_t size); }
+ SYS_LLISTXATTR = 382 // { int|sys||llistxattr(const char *path, char *list, size_t size); }
+ SYS_FLISTXATTR = 383 // { int|sys||flistxattr(int fd, char *list, size_t size); }
+ SYS_REMOVEXATTR = 384 // { int|sys||removexattr(const char *path, const char *name); }
+ SYS_LREMOVEXATTR = 385 // { int|sys||lremovexattr(const char *path, const char *name); }
+ SYS_FREMOVEXATTR = 386 // { int|sys||fremovexattr(int fd, const char *name); }
+ SYS_GETDENTS = 390 // { int|sys|30|getdents(int fd, char *buf, size_t count); }
+ SYS_SOCKET = 394 // { int|sys|30|socket(int domain, int type, int protocol); }
+ SYS_GETFH = 395 // { int|sys|30|getfh(const char *fname, void *fhp, size_t *fh_size); }
+ SYS_MOUNT = 410 // { int|sys|50|mount(const char *type, const char *path, int flags, void *data, size_t data_len); }
+ SYS_MREMAP = 411 // { void *|sys||mremap(void *old_address, size_t old_size, void *new_address, size_t new_size, int flags); }
+ SYS_PSET_CREATE = 412 // { int|sys||pset_create(psetid_t *psid); }
+ SYS_PSET_DESTROY = 413 // { int|sys||pset_destroy(psetid_t psid); }
+ SYS_PSET_ASSIGN = 414 // { int|sys||pset_assign(psetid_t psid, cpuid_t cpuid, psetid_t *opsid); }
+ SYS__PSET_BIND = 415 // { int|sys||_pset_bind(idtype_t idtype, id_t first_id, id_t second_id, psetid_t psid, psetid_t *opsid); }
+ SYS_POSIX_FADVISE = 416 // { int|sys|50|posix_fadvise(int fd, int PAD, off_t offset, off_t len, int advice); }
+ SYS_SELECT = 417 // { int|sys|50|select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); }
+ SYS_GETTIMEOFDAY = 418 // { int|sys|50|gettimeofday(struct timeval *tp, void *tzp); }
+ SYS_SETTIMEOFDAY = 419 // { int|sys|50|settimeofday(const struct timeval *tv, const void *tzp); }
+ SYS_UTIMES = 420 // { int|sys|50|utimes(const char *path, const struct timeval *tptr); }
+ SYS_ADJTIME = 421 // { int|sys|50|adjtime(const struct timeval *delta, struct timeval *olddelta); }
+ SYS_FUTIMES = 423 // { int|sys|50|futimes(int fd, const struct timeval *tptr); }
+ SYS_LUTIMES = 424 // { int|sys|50|lutimes(const char *path, const struct timeval *tptr); }
+ SYS_SETITIMER = 425 // { int|sys|50|setitimer(int which, const struct itimerval *itv, struct itimerval *oitv); }
+ SYS_GETITIMER = 426 // { int|sys|50|getitimer(int which, struct itimerval *itv); }
+ SYS_CLOCK_GETTIME = 427 // { int|sys|50|clock_gettime(clockid_t clock_id, struct timespec *tp); }
+ SYS_CLOCK_SETTIME = 428 // { int|sys|50|clock_settime(clockid_t clock_id, const struct timespec *tp); }
+ SYS_CLOCK_GETRES = 429 // { int|sys|50|clock_getres(clockid_t clock_id, struct timespec *tp); }
+ SYS_NANOSLEEP = 430 // { int|sys|50|nanosleep(const struct timespec *rqtp, struct timespec *rmtp); }
+ SYS___SIGTIMEDWAIT = 431 // { int|sys|50|__sigtimedwait(const sigset_t *set, siginfo_t *info, struct timespec *timeout); }
+ SYS__LWP_PARK = 434 // { int|sys|50|_lwp_park(const struct timespec *ts, lwpid_t unpark, const void *hint, const void *unparkhint); }
+ SYS_KEVENT = 435 // { int|sys|50|kevent(int fd, const struct kevent *changelist, size_t nchanges, struct kevent *eventlist, size_t nevents, const struct timespec *timeout); }
+ SYS_PSELECT = 436 // { int|sys|50|pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *mask); }
+ SYS_POLLTS = 437 // { int|sys|50|pollts(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *mask); }
+ SYS_STAT = 439 // { int|sys|50|stat(const char *path, struct stat *ub); }
+ SYS_FSTAT = 440 // { int|sys|50|fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 441 // { int|sys|50|lstat(const char *path, struct stat *ub); }
+ SYS___SEMCTL = 442 // { int|sys|50|__semctl(int semid, int semnum, int cmd, ... union __semun *arg); }
+ SYS_SHMCTL = 443 // { int|sys|50|shmctl(int shmid, int cmd, struct shmid_ds *buf); }
+ SYS_MSGCTL = 444 // { int|sys|50|msgctl(int msqid, int cmd, struct msqid_ds *buf); }
+ SYS_GETRUSAGE = 445 // { int|sys|50|getrusage(int who, struct rusage *rusage); }
+ SYS_TIMER_SETTIME = 446 // { int|sys|50|timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); }
+ SYS_TIMER_GETTIME = 447 // { int|sys|50|timer_gettime(timer_t timerid, struct itimerspec *value); }
+ SYS_NTP_GETTIME = 448 // { int|sys|50|ntp_gettime(struct ntptimeval *ntvp); }
+ SYS_WAIT4 = 449 // { int|sys|50|wait4(pid_t pid, int *status, int options, struct rusage *rusage); }
+ SYS_MKNOD = 450 // { int|sys|50|mknod(const char *path, mode_t mode, dev_t dev); }
+ SYS_FHSTAT = 451 // { int|sys|50|fhstat(const void *fhp, size_t fh_size, struct stat *sb); }
+ SYS_QUOTACTL = 452 // { int|sys|50|quotactl(const char *path, struct plistref *pref); }
+ SYS_PIPE2 = 453 // { int|sys||pipe2(int *fildes, int flags); }
+ SYS_DUP3 = 454 // { int|sys||dup3(int from, int to, int flags); }
+ SYS_KQUEUE1 = 455 // { int|sys||kqueue1(int flags); }
+ SYS_PACCEPT = 456 // { int|sys||paccept(int s, struct sockaddr *name, socklen_t *anamelen, const sigset_t *mask, int flags); }
+ SYS_LINKAT = 457 // { int|sys||linkat(int fd1, const char *name1, int fd2, const char *name2, int flags); }
+ SYS_RENAMEAT = 458 // { int|sys||renameat(int fromfd, const char *from, int tofd, const char *to); }
+ SYS_MKFIFOAT = 459 // { int|sys||mkfifoat(int fd, const char *path, mode_t mode); }
+ SYS_MKNODAT = 460 // { int|sys||mknodat(int fd, const char *path, mode_t mode, uint32_t dev); }
+ SYS_MKDIRAT = 461 // { int|sys||mkdirat(int fd, const char *path, mode_t mode); }
+ SYS_FACCESSAT = 462 // { int|sys||faccessat(int fd, const char *path, int amode, int flag); }
+ SYS_FCHMODAT = 463 // { int|sys||fchmodat(int fd, const char *path, mode_t mode, int flag); }
+ SYS_FCHOWNAT = 464 // { int|sys||fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag); }
+ SYS_FEXECVE = 465 // { int|sys||fexecve(int fd, char * const *argp, char * const *envp); }
+ SYS_FSTATAT = 466 // { int|sys||fstatat(int fd, const char *path, struct stat *buf, int flag); }
+ SYS_UTIMENSAT = 467 // { int|sys||utimensat(int fd, const char *path, const struct timespec *tptr, int flag); }
+ SYS_OPENAT = 468 // { int|sys||openat(int fd, const char *path, int oflags, ... mode_t mode); }
+ SYS_READLINKAT = 469 // { int|sys||readlinkat(int fd, const char *path, char *buf, size_t bufsize); }
+ SYS_SYMLINKAT = 470 // { int|sys||symlinkat(const char *path1, int fd, const char *path2); }
+ SYS_UNLINKAT = 471 // { int|sys||unlinkat(int fd, const char *path, int flag); }
+ SYS_FUTIMENS = 472 // { int|sys||futimens(int fd, const struct timespec *tptr); }
+)
diff --git a/src/pkg/syscall/zsysnum_openbsd_386.go b/src/pkg/syscall/zsysnum_openbsd_386.go
new file mode 100644
index 000000000..1d97fe0db
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_openbsd_386.go
@@ -0,0 +1,207 @@
+// mksysnum_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_EXIT = 1 // { void sys_exit(int rval); }
+ SYS_FORK = 2 // { int sys_fork(void); }
+ SYS_READ = 3 // { ssize_t sys_read(int fd, void *buf, size_t nbyte); }
+ SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
+ SYS_OPEN = 5 // { int sys_open(const char *path, \
+ SYS_CLOSE = 6 // { int sys_close(int fd); }
+ SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
+ SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
+ SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
+ SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
+ SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
+ SYS_CHMOD = 15 // { int sys_chmod(const char *path, mode_t mode); }
+ SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
+ SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
+ SYS_GETPID = 20 // { pid_t sys_getpid(void); }
+ SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
+ SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
+ SYS_SETUID = 23 // { int sys_setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t sys_getuid(void); }
+ SYS_GETEUID = 25 // { uid_t sys_geteuid(void); }
+ SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \
+ SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \
+ SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, \
+ SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \
+ SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, \
+ SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, \
+ SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, \
+ SYS_ACCESS = 33 // { int sys_access(const char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int sys_chflags(const char *path, u_int flags); }
+ SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
+ SYS_SYNC = 36 // { void sys_sync(void); }
+ SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
+ SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
+ SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
+ SYS_SIGACTION = 46 // { int sys_sigaction(int signum, \
+ SYS_GETGID = 47 // { gid_t sys_getgid(void); }
+ SYS_SIGPROCMASK = 48 // { int sys_sigprocmask(int how, sigset_t mask); }
+ SYS_GETLOGIN = 49 // { int sys_getlogin(char *namebuf, u_int namelen); }
+ SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
+ SYS_ACCT = 51 // { int sys_acct(const char *path); }
+ SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
+ SYS_REBOOT = 55 // { int sys_reboot(int opt); }
+ SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
+ SYS_SYMLINK = 57 // { int sys_symlink(const char *path, \
+ SYS_READLINK = 58 // { int sys_readlink(const char *path, char *buf, \
+ SYS_EXECVE = 59 // { int sys_execve(const char *path, \
+ SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
+ SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
+ SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
+ SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
+ SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
+ SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
+ SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
+ SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
+ SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_FSYNC = 95 // { int sys_fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
+ SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
+ SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
+ SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
+ SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
+ SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
+ SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
+ SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
+ SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
+ SYS_READV = 120 // { ssize_t sys_readv(int fd, \
+ SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
+ SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
+ SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
+ SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
+ SYS_SETREGID = 127 // { int sys_setregid(gid_t rgid, gid_t egid); }
+ SYS_RENAME = 128 // { int sys_rename(const char *from, const char *to); }
+ SYS_FLOCK = 131 // { int sys_flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int sys_mkfifo(const char *path, mode_t mode); }
+ SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, \
+ SYS_SHUTDOWN = 134 // { int sys_shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
+ SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
+ SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
+ SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
+ SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
+ SYS_SETSID = 147 // { int sys_setsid(void); }
+ SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
+ SYS_NFSSVC = 155 // { int sys_nfssvc(int flag, void *argp); }
+ SYS_GETFH = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); }
+ SYS_SYSARCH = 165 // { int sys_sysarch(int op, void *parms); }
+ SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, \
+ SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \
+ SYS_SETGID = 181 // { int sys_setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int sys_setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int sys_seteuid(uid_t euid); }
+ LFS_BMAPV = 184 // { int lfs_bmapv(fsid_t *fsidp, \
+ LFS_MARKV = 185 // { int lfs_markv(fsid_t *fsidp, \
+ LFS_SEGCLEAN = 186 // { int lfs_segclean(fsid_t *fsidp, u_long segment); }
+ LFS_SEGWAIT = 187 // { int lfs_segwait(fsid_t *fsidp, struct timeval *tv); }
+ SYS_PATHCONF = 191 // { long sys_pathconf(const char *path, int name); }
+ SYS_FPATHCONF = 192 // { long sys_fpathconf(int fd, int name); }
+ SYS_SWAPCTL = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); }
+ SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, \
+ SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, \
+ SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \
+ SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
+ SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
+ SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
+ SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
+ SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
+ SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_NNPFSPIOCTL = 208 // { int sys_nnpfspioctl(int operation, char *a_pathP, \
+ SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
+ SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
+ SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
+ SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
+ SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
+ SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
+ SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
+ SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
+ SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
+ SYS_RFORK = 251 // { int sys_rfork(int flags); }
+ SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
+ SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
+ SYS_LCHOWN = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS_GETSID = 255 // { pid_t sys_getsid(pid_t pid); }
+ SYS_MSYNC = 256 // { int sys_msync(void *addr, size_t len, int flags); }
+ SYS_PIPE = 263 // { int sys_pipe(int *fdp); }
+ SYS_FHOPEN = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); }
+ SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
+ SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
+ SYS_KQUEUE = 269 // { int sys_kqueue(void); }
+ SYS_KEVENT = 270 // { int sys_kevent(int fd, \
+ SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
+ SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
+ SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
+ SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \
+ SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \
+ SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \
+ SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \
+ SYS_CLOSEFROM = 287 // { int sys_closefrom(int fd); }
+ SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
+ SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
+ SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
+ SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
+ SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
+ SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
+ SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
+ SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
+ SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
+ SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
+ SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
+ SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
+ SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
+ SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
+ SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
+ SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
+ SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
+ SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 307 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
+ SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
+ SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
+ SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
+ SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
+ SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
+ SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
+ SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
+ SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
+ SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
+ SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
+ SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, \
+ SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, \
+ SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \
+ SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
+ SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
+ SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
+ SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
+ SYS___TFORK = 328 // { int sys___tfork(struct __tfork *param); }
+ SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
+ SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
+)
diff --git a/src/pkg/syscall/zsysnum_openbsd_amd64.go b/src/pkg/syscall/zsysnum_openbsd_amd64.go
new file mode 100644
index 000000000..1d97fe0db
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_openbsd_amd64.go
@@ -0,0 +1,207 @@
+// mksysnum_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_EXIT = 1 // { void sys_exit(int rval); }
+ SYS_FORK = 2 // { int sys_fork(void); }
+ SYS_READ = 3 // { ssize_t sys_read(int fd, void *buf, size_t nbyte); }
+ SYS_WRITE = 4 // { ssize_t sys_write(int fd, const void *buf, \
+ SYS_OPEN = 5 // { int sys_open(const char *path, \
+ SYS_CLOSE = 6 // { int sys_close(int fd); }
+ SYS_WAIT4 = 7 // { pid_t sys_wait4(pid_t pid, int *status, int options, \
+ SYS_LINK = 9 // { int sys_link(const char *path, const char *link); }
+ SYS_UNLINK = 10 // { int sys_unlink(const char *path); }
+ SYS_CHDIR = 12 // { int sys_chdir(const char *path); }
+ SYS_FCHDIR = 13 // { int sys_fchdir(int fd); }
+ SYS_MKNOD = 14 // { int sys_mknod(const char *path, mode_t mode, \
+ SYS_CHMOD = 15 // { int sys_chmod(const char *path, mode_t mode); }
+ SYS_CHOWN = 16 // { int sys_chown(const char *path, uid_t uid, \
+ SYS_OBREAK = 17 // { int sys_obreak(char *nsize); } break
+ SYS_GETPID = 20 // { pid_t sys_getpid(void); }
+ SYS_MOUNT = 21 // { int sys_mount(const char *type, const char *path, \
+ SYS_UNMOUNT = 22 // { int sys_unmount(const char *path, int flags); }
+ SYS_SETUID = 23 // { int sys_setuid(uid_t uid); }
+ SYS_GETUID = 24 // { uid_t sys_getuid(void); }
+ SYS_GETEUID = 25 // { uid_t sys_geteuid(void); }
+ SYS_PTRACE = 26 // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \
+ SYS_RECVMSG = 27 // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \
+ SYS_SENDMSG = 28 // { ssize_t sys_sendmsg(int s, \
+ SYS_RECVFROM = 29 // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \
+ SYS_ACCEPT = 30 // { int sys_accept(int s, struct sockaddr *name, \
+ SYS_GETPEERNAME = 31 // { int sys_getpeername(int fdes, struct sockaddr *asa, \
+ SYS_GETSOCKNAME = 32 // { int sys_getsockname(int fdes, struct sockaddr *asa, \
+ SYS_ACCESS = 33 // { int sys_access(const char *path, int flags); }
+ SYS_CHFLAGS = 34 // { int sys_chflags(const char *path, u_int flags); }
+ SYS_FCHFLAGS = 35 // { int sys_fchflags(int fd, u_int flags); }
+ SYS_SYNC = 36 // { void sys_sync(void); }
+ SYS_KILL = 37 // { int sys_kill(int pid, int signum); }
+ SYS_GETPPID = 39 // { pid_t sys_getppid(void); }
+ SYS_DUP = 41 // { int sys_dup(int fd); }
+ SYS_GETEGID = 43 // { gid_t sys_getegid(void); }
+ SYS_PROFIL = 44 // { int sys_profil(caddr_t samples, size_t size, \
+ SYS_KTRACE = 45 // { int sys_ktrace(const char *fname, int ops, \
+ SYS_SIGACTION = 46 // { int sys_sigaction(int signum, \
+ SYS_GETGID = 47 // { gid_t sys_getgid(void); }
+ SYS_SIGPROCMASK = 48 // { int sys_sigprocmask(int how, sigset_t mask); }
+ SYS_GETLOGIN = 49 // { int sys_getlogin(char *namebuf, u_int namelen); }
+ SYS_SETLOGIN = 50 // { int sys_setlogin(const char *namebuf); }
+ SYS_ACCT = 51 // { int sys_acct(const char *path); }
+ SYS_SIGPENDING = 52 // { int sys_sigpending(void); }
+ SYS_IOCTL = 54 // { int sys_ioctl(int fd, \
+ SYS_REBOOT = 55 // { int sys_reboot(int opt); }
+ SYS_REVOKE = 56 // { int sys_revoke(const char *path); }
+ SYS_SYMLINK = 57 // { int sys_symlink(const char *path, \
+ SYS_READLINK = 58 // { int sys_readlink(const char *path, char *buf, \
+ SYS_EXECVE = 59 // { int sys_execve(const char *path, \
+ SYS_UMASK = 60 // { mode_t sys_umask(mode_t newmask); }
+ SYS_CHROOT = 61 // { int sys_chroot(const char *path); }
+ SYS_VFORK = 66 // { int sys_vfork(void); }
+ SYS_MUNMAP = 73 // { int sys_munmap(void *addr, size_t len); }
+ SYS_MPROTECT = 74 // { int sys_mprotect(void *addr, size_t len, \
+ SYS_MADVISE = 75 // { int sys_madvise(void *addr, size_t len, \
+ SYS_MINCORE = 78 // { int sys_mincore(void *addr, size_t len, \
+ SYS_GETGROUPS = 79 // { int sys_getgroups(int gidsetsize, \
+ SYS_SETGROUPS = 80 // { int sys_setgroups(int gidsetsize, \
+ SYS_GETPGRP = 81 // { int sys_getpgrp(void); }
+ SYS_SETPGID = 82 // { int sys_setpgid(pid_t pid, int pgid); }
+ SYS_SETITIMER = 83 // { int sys_setitimer(int which, \
+ SYS_GETITIMER = 86 // { int sys_getitimer(int which, \
+ SYS_DUP2 = 90 // { int sys_dup2(int from, int to); }
+ SYS_FCNTL = 92 // { int sys_fcntl(int fd, int cmd, ... void *arg); }
+ SYS_SELECT = 93 // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+ SYS_FSYNC = 95 // { int sys_fsync(int fd); }
+ SYS_SETPRIORITY = 96 // { int sys_setpriority(int which, id_t who, int prio); }
+ SYS_SOCKET = 97 // { int sys_socket(int domain, int type, int protocol); }
+ SYS_CONNECT = 98 // { int sys_connect(int s, const struct sockaddr *name, \
+ SYS_GETPRIORITY = 100 // { int sys_getpriority(int which, id_t who); }
+ SYS_SIGRETURN = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
+ SYS_BIND = 104 // { int sys_bind(int s, const struct sockaddr *name, \
+ SYS_SETSOCKOPT = 105 // { int sys_setsockopt(int s, int level, int name, \
+ SYS_LISTEN = 106 // { int sys_listen(int s, int backlog); }
+ SYS_SIGSUSPEND = 111 // { int sys_sigsuspend(int mask); }
+ SYS_GETTIMEOFDAY = 116 // { int sys_gettimeofday(struct timeval *tp, \
+ SYS_GETRUSAGE = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
+ SYS_GETSOCKOPT = 118 // { int sys_getsockopt(int s, int level, int name, \
+ SYS_READV = 120 // { ssize_t sys_readv(int fd, \
+ SYS_WRITEV = 121 // { ssize_t sys_writev(int fd, \
+ SYS_SETTIMEOFDAY = 122 // { int sys_settimeofday(const struct timeval *tv, \
+ SYS_FCHOWN = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
+ SYS_FCHMOD = 124 // { int sys_fchmod(int fd, mode_t mode); }
+ SYS_SETREUID = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
+ SYS_SETREGID = 127 // { int sys_setregid(gid_t rgid, gid_t egid); }
+ SYS_RENAME = 128 // { int sys_rename(const char *from, const char *to); }
+ SYS_FLOCK = 131 // { int sys_flock(int fd, int how); }
+ SYS_MKFIFO = 132 // { int sys_mkfifo(const char *path, mode_t mode); }
+ SYS_SENDTO = 133 // { ssize_t sys_sendto(int s, const void *buf, \
+ SYS_SHUTDOWN = 134 // { int sys_shutdown(int s, int how); }
+ SYS_SOCKETPAIR = 135 // { int sys_socketpair(int domain, int type, \
+ SYS_MKDIR = 136 // { int sys_mkdir(const char *path, mode_t mode); }
+ SYS_RMDIR = 137 // { int sys_rmdir(const char *path); }
+ SYS_UTIMES = 138 // { int sys_utimes(const char *path, \
+ SYS_ADJTIME = 140 // { int sys_adjtime(const struct timeval *delta, \
+ SYS_SETSID = 147 // { int sys_setsid(void); }
+ SYS_QUOTACTL = 148 // { int sys_quotactl(const char *path, int cmd, \
+ SYS_NFSSVC = 155 // { int sys_nfssvc(int flag, void *argp); }
+ SYS_GETFH = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); }
+ SYS_SYSARCH = 165 // { int sys_sysarch(int op, void *parms); }
+ SYS_PREAD = 173 // { ssize_t sys_pread(int fd, void *buf, \
+ SYS_PWRITE = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \
+ SYS_SETGID = 181 // { int sys_setgid(gid_t gid); }
+ SYS_SETEGID = 182 // { int sys_setegid(gid_t egid); }
+ SYS_SETEUID = 183 // { int sys_seteuid(uid_t euid); }
+ LFS_BMAPV = 184 // { int lfs_bmapv(fsid_t *fsidp, \
+ LFS_MARKV = 185 // { int lfs_markv(fsid_t *fsidp, \
+ LFS_SEGCLEAN = 186 // { int lfs_segclean(fsid_t *fsidp, u_long segment); }
+ LFS_SEGWAIT = 187 // { int lfs_segwait(fsid_t *fsidp, struct timeval *tv); }
+ SYS_PATHCONF = 191 // { long sys_pathconf(const char *path, int name); }
+ SYS_FPATHCONF = 192 // { long sys_fpathconf(int fd, int name); }
+ SYS_SWAPCTL = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); }
+ SYS_GETRLIMIT = 194 // { int sys_getrlimit(int which, \
+ SYS_SETRLIMIT = 195 // { int sys_setrlimit(int which, \
+ SYS_MMAP = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \
+ SYS_LSEEK = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
+ SYS_TRUNCATE = 200 // { int sys_truncate(const char *path, int pad, \
+ SYS_FTRUNCATE = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
+ SYS___SYSCTL = 202 // { int sys___sysctl(int *name, u_int namelen, \
+ SYS_MLOCK = 203 // { int sys_mlock(const void *addr, size_t len); }
+ SYS_MUNLOCK = 204 // { int sys_munlock(const void *addr, size_t len); }
+ SYS_FUTIMES = 206 // { int sys_futimes(int fd, \
+ SYS_GETPGID = 207 // { pid_t sys_getpgid(pid_t pid); }
+ SYS_NNPFSPIOCTL = 208 // { int sys_nnpfspioctl(int operation, char *a_pathP, \
+ SYS_SEMGET = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
+ SYS_MSGGET = 225 // { int sys_msgget(key_t key, int msgflg); }
+ SYS_MSGSND = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
+ SYS_MSGRCV = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
+ SYS_SHMAT = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
+ SYS_SHMDT = 230 // { int sys_shmdt(const void *shmaddr); }
+ SYS_CLOCK_GETTIME = 232 // { int sys_clock_gettime(clockid_t clock_id, \
+ SYS_CLOCK_SETTIME = 233 // { int sys_clock_settime(clockid_t clock_id, \
+ SYS_CLOCK_GETRES = 234 // { int sys_clock_getres(clockid_t clock_id, \
+ SYS_NANOSLEEP = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
+ SYS_MINHERIT = 250 // { int sys_minherit(void *addr, size_t len, \
+ SYS_RFORK = 251 // { int sys_rfork(int flags); }
+ SYS_POLL = 252 // { int sys_poll(struct pollfd *fds, \
+ SYS_ISSETUGID = 253 // { int sys_issetugid(void); }
+ SYS_LCHOWN = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); }
+ SYS_GETSID = 255 // { pid_t sys_getsid(pid_t pid); }
+ SYS_MSYNC = 256 // { int sys_msync(void *addr, size_t len, int flags); }
+ SYS_PIPE = 263 // { int sys_pipe(int *fdp); }
+ SYS_FHOPEN = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); }
+ SYS_PREADV = 267 // { ssize_t sys_preadv(int fd, \
+ SYS_PWRITEV = 268 // { ssize_t sys_pwritev(int fd, \
+ SYS_KQUEUE = 269 // { int sys_kqueue(void); }
+ SYS_KEVENT = 270 // { int sys_kevent(int fd, \
+ SYS_MLOCKALL = 271 // { int sys_mlockall(int flags); }
+ SYS_MUNLOCKALL = 272 // { int sys_munlockall(void); }
+ SYS_GETRESUID = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
+ SYS_SETRESUID = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \
+ SYS_GETRESGID = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \
+ SYS_SETRESGID = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \
+ SYS_MQUERY = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \
+ SYS_CLOSEFROM = 287 // { int sys_closefrom(int fd); }
+ SYS_SIGALTSTACK = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
+ SYS_SHMGET = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
+ SYS_SEMOP = 290 // { int sys_semop(int semid, struct sembuf *sops, \
+ SYS_STAT = 291 // { int sys_stat(const char *path, struct stat *ub); }
+ SYS_FSTAT = 292 // { int sys_fstat(int fd, struct stat *sb); }
+ SYS_LSTAT = 293 // { int sys_lstat(const char *path, struct stat *ub); }
+ SYS_FHSTAT = 294 // { int sys_fhstat(const fhandle_t *fhp, \
+ SYS___SEMCTL = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
+ SYS_SHMCTL = 296 // { int sys_shmctl(int shmid, int cmd, \
+ SYS_MSGCTL = 297 // { int sys_msgctl(int msqid, int cmd, \
+ SYS_SCHED_YIELD = 298 // { int sys_sched_yield(void); }
+ SYS_GETTHRID = 299 // { pid_t sys_getthrid(void); }
+ SYS___THRSLEEP = 300 // { int sys___thrsleep(const volatile void *ident, \
+ SYS___THRWAKEUP = 301 // { int sys___thrwakeup(const volatile void *ident, \
+ SYS___THREXIT = 302 // { void sys___threxit(pid_t *notdead); }
+ SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
+ SYS___GETCWD = 304 // { int sys___getcwd(char *buf, size_t len); }
+ SYS_ADJFREQ = 305 // { int sys_adjfreq(const int64_t *freq, \
+ SYS_GETFSSTAT = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+ SYS_STATFS = 307 // { int sys_statfs(const char *path, \
+ SYS_FSTATFS = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
+ SYS_FHSTATFS = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
+ SYS_SETRTABLE = 310 // { int sys_setrtable(int rtableid); }
+ SYS_GETRTABLE = 311 // { int sys_getrtable(void); }
+ SYS_GETDIRENTRIES = 312 // { int sys_getdirentries(int fd, char *buf, \
+ SYS_FACCESSAT = 313 // { int sys_faccessat(int fd, const char *path, \
+ SYS_FCHMODAT = 314 // { int sys_fchmodat(int fd, const char *path, \
+ SYS_FCHOWNAT = 315 // { int sys_fchownat(int fd, const char *path, \
+ SYS_FSTATAT = 316 // { int sys_fstatat(int fd, const char *path, \
+ SYS_LINKAT = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
+ SYS_MKDIRAT = 318 // { int sys_mkdirat(int fd, const char *path, \
+ SYS_MKFIFOAT = 319 // { int sys_mkfifoat(int fd, const char *path, \
+ SYS_MKNODAT = 320 // { int sys_mknodat(int fd, const char *path, \
+ SYS_OPENAT = 321 // { int sys_openat(int fd, const char *path, int flags, \
+ SYS_READLINKAT = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \
+ SYS_RENAMEAT = 323 // { int sys_renameat(int fromfd, const char *from, \
+ SYS_SYMLINKAT = 324 // { int sys_symlinkat(const char *path, int fd, \
+ SYS_UNLINKAT = 325 // { int sys_unlinkat(int fd, const char *path, \
+ SYS_UTIMENSAT = 326 // { int sys_utimensat(int fd, const char *path, \
+ SYS_FUTIMENS = 327 // { int sys_futimens(int fd, \
+ SYS___TFORK = 328 // { int sys___tfork(struct __tfork *param); }
+ SYS___SET_TCB = 329 // { void sys___set_tcb(void *tcb); }
+ SYS___GET_TCB = 330 // { void *sys___get_tcb(void); }
+)
diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go
index 0ec74f379..566b02195 100644
--- a/src/pkg/syscall/ztypes_darwin_386.go
+++ b/src/pkg/syscall/ztypes_darwin_386.go
@@ -1,54 +1,22 @@
-// godefs -gsyscall -f-m32 types_darwin.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
package syscall
-// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- O_CLOEXEC = 0
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6a
- SizeofSockaddrDatalink = 0x14
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- PTRACE_TRACEME = 0
- PTRACE_CONT = 0x7
- PTRACE_KILL = 0x8
- SizeofIfMsghdr = 0x70
- SizeofIfData = 0x60
- SizeofIfaMsghdr = 0x14
- SizeofIfmaMsghdr = 0x10
- SizeofIfmaMsghdr2 = 0x14
- SizeofRtMsghdr = 0x5c
- SizeofRtMetrics = 0x38
- SizeofBpfVersion = 0x4
- SizeofBpfStat = 0x8
- SizeofBpfProgram = 0x8
- SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x14
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
type Timespec struct {
Sec int32
@@ -60,6 +28,8 @@ type Timeval struct {
Usec int32
}
+type Timeval32 [0]byte
+
type Rusage struct {
Utime Timeval
Stime Timeval
@@ -115,7 +85,7 @@ type Statfs_t struct {
Bavail uint64
Files uint64
Ffree uint64
- Fsid [8]byte /* fsid */
+ Fsid Fsid
Owner uint32
Type uint32
Flags uint32
@@ -159,14 +129,18 @@ type Log2phys_t struct {
Devoffset int64
}
+type Fsid struct {
+ Val [2]int32
+}
+
type Dirent struct {
- Ino uint64
- Seekoff uint64
- Reclen uint16
- Namlen uint16
- Type uint8
- Name [1024]int8
- Pad_godefs_0 [3]byte
+ Ino uint64
+ Seekoff uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [1024]int8
+ Pad_cgo_0 [3]byte
}
type RawSockaddrInet4 struct {
@@ -257,6 +231,26 @@ type Inet6Pktinfo struct {
Ifindex uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x14
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
type Kevent_t struct {
Ident uint32
Filter int16
@@ -270,15 +264,25 @@ type FdSet struct {
Bits [32]int32
}
+const (
+ SizeofIfMsghdr = 0x70
+ SizeofIfData = 0x60
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofIfmaMsghdr2 = 0x14
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+)
+
type IfMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Data IfData
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
}
type IfData struct {
@@ -314,51 +318,51 @@ type IfData struct {
}
type IfaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Metric int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
}
type IfmaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
}
type IfmaMsghdr2 struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Refcount int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Refcount int32
}
type RtMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Pad_godefs_0 [2]byte
- Flags int32
- Addrs int32
- Pid int32
- Seq int32
- Errno int32
- Use int32
- Inits uint32
- Rmx RtMetrics
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
}
type RtMetrics struct {
@@ -375,6 +379,14 @@ type RtMetrics struct {
Filler [4]uint32
}
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
type BpfVersion struct {
Major uint16
Minor uint16
@@ -398,9 +410,9 @@ type BpfInsn struct {
}
type BpfHdr struct {
- Tstamp Timeval
- Caplen uint32
- Datalen uint32
- Hdrlen uint16
- Pad_godefs_0 [2]byte
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
}
diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go
index f0e8a9248..2c6531158 100644
--- a/src/pkg/syscall/ztypes_darwin_amd64.go
+++ b/src/pkg/syscall/ztypes_darwin_amd64.go
@@ -1,54 +1,22 @@
-// godefs -gsyscall -f-m64 types_darwin.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
package syscall
-// Constants
const (
- sizeofPtr = 0x8
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x8
- sizeofLongLong = 0x8
- O_CLOEXEC = 0
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6a
- SizeofSockaddrDatalink = 0x14
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x30
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- PTRACE_TRACEME = 0
- PTRACE_CONT = 0x7
- PTRACE_KILL = 0x8
- SizeofIfMsghdr = 0x70
- SizeofIfData = 0x60
- SizeofIfaMsghdr = 0x14
- SizeofIfmaMsghdr = 0x10
- SizeofIfmaMsghdr2 = 0x14
- SizeofRtMsghdr = 0x5c
- SizeofRtMetrics = 0x38
- SizeofBpfVersion = 0x4
- SizeofBpfStat = 0x8
- SizeofBpfProgram = 0x10
- SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x14
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int64
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
type Timespec struct {
Sec int64
@@ -56,9 +24,9 @@ type Timespec struct {
}
type Timeval struct {
- Sec int64
- Usec int32
- Pad_godefs_0 [4]byte
+ Sec int64
+ Usec int32
+ Pad_cgo_0 [4]byte
}
type Timeval32 struct {
@@ -100,7 +68,7 @@ type Stat_t struct {
Uid uint32
Gid uint32
Rdev int32
- Pad_godefs_0 [4]byte
+ Pad_cgo_0 [4]byte
Atimespec Timespec
Mtimespec Timespec
Ctimespec Timespec
@@ -122,7 +90,7 @@ type Statfs_t struct {
Bavail uint64
Files uint64
Ffree uint64
- Fsid [8]byte /* fsid */
+ Fsid Fsid
Owner uint32
Type uint32
Flags uint32
@@ -150,9 +118,9 @@ type Fstore_t struct {
}
type Radvisory_t struct {
- Offset int64
- Count int32
- Pad_godefs_0 [4]byte
+ Offset int64
+ Count int32
+ Pad_cgo_0 [4]byte
}
type Fbootstraptransfer_t struct {
@@ -167,14 +135,18 @@ type Log2phys_t struct {
Devoffset int64
}
+type Fsid struct {
+ Val [2]int32
+}
+
type Dirent struct {
- Ino uint64
- Seekoff uint64
- Reclen uint16
- Namlen uint16
- Type uint8
- Name [1024]int8
- Pad_godefs_0 [3]byte
+ Ino uint64
+ Seekoff uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [1024]int8
+ Pad_cgo_0 [3]byte
}
type RawSockaddrInet4 struct {
@@ -245,15 +217,15 @@ type IPv6Mreq struct {
}
type Msghdr struct {
- Name *byte
- Namelen uint32
- Pad_godefs_0 [4]byte
- Iov *Iovec
- Iovlen int32
- Pad_godefs_1 [4]byte
- Control *byte
- Controllen uint32
- Flags int32
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_cgo_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
}
type Cmsghdr struct {
@@ -267,6 +239,26 @@ type Inet6Pktinfo struct {
Ifindex uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x14
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
type Kevent_t struct {
Ident uint64
Filter int16
@@ -280,15 +272,25 @@ type FdSet struct {
Bits [32]int32
}
+const (
+ SizeofIfMsghdr = 0x70
+ SizeofIfData = 0x60
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofIfmaMsghdr2 = 0x14
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+)
+
type IfMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Data IfData
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
}
type IfData struct {
@@ -324,51 +326,51 @@ type IfData struct {
}
type IfaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Metric int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
}
type IfmaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
}
type IfmaMsghdr2 struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Refcount int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Refcount int32
}
type RtMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Pad_godefs_0 [2]byte
- Flags int32
- Addrs int32
- Pid int32
- Seq int32
- Errno int32
- Use int32
- Inits uint32
- Rmx RtMetrics
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Use int32
+ Inits uint32
+ Rmx RtMetrics
}
type RtMetrics struct {
@@ -385,6 +387,14 @@ type RtMetrics struct {
Filler [4]uint32
}
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
type BpfVersion struct {
Major uint16
Minor uint16
@@ -396,9 +406,9 @@ type BpfStat struct {
}
type BpfProgram struct {
- Len uint32
- Pad_godefs_0 [4]byte
- Insns *BpfInsn
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
}
type BpfInsn struct {
@@ -409,9 +419,9 @@ type BpfInsn struct {
}
type BpfHdr struct {
- Tstamp Timeval32
- Caplen uint32
- Datalen uint32
- Hdrlen uint16
- Pad_godefs_0 [2]byte
+ Tstamp Timeval32
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
index 01cf2fbda..4149948c5 100644
--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -1,69 +1,22 @@
-// godefs -gsyscall -f-m32 types_freebsd.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
package syscall
-// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- O_CLOEXEC = 0
- S_IFMT = 0xf000
- S_IFIFO = 0x1000
- S_IFCHR = 0x2000
- S_IFDIR = 0x4000
- S_IFBLK = 0x6000
- S_IFREG = 0x8000
- S_IFLNK = 0xa000
- S_IFSOCK = 0xc000
- S_ISUID = 0x800
- S_ISGID = 0x400
- S_ISVTX = 0x200
- S_IRUSR = 0x100
- S_IWUSR = 0x80
- S_IXUSR = 0x40
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6a
- SizeofSockaddrDatalink = 0x36
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- PTRACE_TRACEME = 0
- PTRACE_CONT = 0x7
- PTRACE_KILL = 0x8
- SizeofIfMsghdr = 0x60
- SizeofIfData = 0x50
- SizeofIfaMsghdr = 0x14
- SizeofIfmaMsghdr = 0x10
- SizeofRtMsghdr = 0x5c
- SizeofRtMetrics = 0x38
- SizeofBpfVersion = 0x4
- SizeofBpfStat = 0x8
- SizeofBpfZbuf = 0xc
- SizeofBpfProgram = 0x8
- SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x14
- SizeofBpfZbufHeader = 0x20
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
type Timespec struct {
Sec int32
@@ -101,6 +54,27 @@ type Rlimit struct {
type _Gid_t uint32
+const (
+ O_CLOEXEC = 0
+)
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
type Stat_t struct {
Dev uint32
Ino uint32
@@ -119,8 +93,7 @@ type Stat_t struct {
Gen uint32
Lspare int32
Birthtimespec Timespec
- Pad_godefs_0 uint32
- Pad_godefs_1 uint32
+ Pad_cgo_0 [8]byte
}
type Statfs_t struct {
@@ -141,7 +114,7 @@ type Statfs_t struct {
Spare [10]uint64
Namemax uint32
Owner uint32
- Fsid [8]byte /* fsid */
+ Fsid Fsid
Charspare [80]int8
Fstypename [16]int8
Mntfromname [88]int8
@@ -165,6 +138,10 @@ type Dirent struct {
Name [256]int8
}
+type Fsid struct {
+ Val [2]int32
+}
+
type RawSockaddrInet4 struct {
Len uint8
Family uint8
@@ -227,6 +204,12 @@ type IPMreq struct {
Interface [4]byte /* in_addr */
}
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
@@ -253,6 +236,27 @@ type Inet6Pktinfo struct {
Ifindex uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
type Kevent_t struct {
Ident uint32
Filter int16
@@ -266,15 +270,24 @@ type FdSet struct {
X__fds_bits [32]uint32
}
+const (
+ SizeofIfMsghdr = 0x60
+ SizeofIfData = 0x50
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofRtMsghdr = 0x5c
+ SizeofRtMetrics = 0x38
+)
+
type IfMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Data IfData
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
}
type IfData struct {
@@ -306,40 +319,40 @@ type IfData struct {
}
type IfaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Metric int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
}
type IfmaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
}
type RtMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Pad_godefs_0 [2]byte
- Flags int32
- Addrs int32
- Pid int32
- Seq int32
- Errno int32
- Fmask int32
- Inits uint32
- Rmx RtMetrics
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Fmask int32
+ Inits uint32
+ Rmx RtMetrics
}
type RtMetrics struct {
@@ -357,6 +370,16 @@ type RtMetrics struct {
Filler [3]uint32
}
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfZbuf = 0xc
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+ SizeofBpfZbufHeader = 0x20
+)
+
type BpfVersion struct {
Major uint16
Minor uint16
@@ -386,11 +409,11 @@ type BpfInsn struct {
}
type BpfHdr struct {
- Tstamp Timeval
- Caplen uint32
- Datalen uint32
- Hdrlen uint16
- Pad_godefs_0 [2]byte
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
}
type BpfZbufHeader struct {
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
index d6a05ae68..80c12f607 100644
--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -1,69 +1,22 @@
-// godefs -gsyscall -f-m64 types_freebsd.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_freebsd.go
package syscall
-// Constants
const (
- sizeofPtr = 0x8
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x8
- sizeofLongLong = 0x8
- O_CLOEXEC = 0
- S_IFMT = 0xf000
- S_IFIFO = 0x1000
- S_IFCHR = 0x2000
- S_IFDIR = 0x4000
- S_IFBLK = 0x6000
- S_IFREG = 0x8000
- S_IFLNK = 0xa000
- S_IFSOCK = 0xc000
- S_ISUID = 0x800
- S_ISGID = 0x400
- S_ISVTX = 0x200
- S_IRUSR = 0x100
- S_IWUSR = 0x80
- S_IXUSR = 0x40
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6a
- SizeofSockaddrDatalink = 0x36
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x30
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- PTRACE_TRACEME = 0
- PTRACE_CONT = 0x7
- PTRACE_KILL = 0x8
- SizeofIfMsghdr = 0xa8
- SizeofIfData = 0x98
- SizeofIfaMsghdr = 0x14
- SizeofIfmaMsghdr = 0x10
- SizeofRtMsghdr = 0x98
- SizeofRtMetrics = 0x70
- SizeofBpfVersion = 0x4
- SizeofBpfStat = 0x8
- SizeofBpfZbuf = 0x18
- SizeofBpfProgram = 0x10
- SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x20
- SizeofBpfZbufHeader = 0x20
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int64
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
type Timespec struct {
Sec int64
@@ -101,6 +54,27 @@ type Rlimit struct {
type _Gid_t uint32
+const (
+ O_CLOEXEC = 0
+)
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
type Stat_t struct {
Dev uint32
Ino uint32
@@ -119,8 +93,6 @@ type Stat_t struct {
Gen uint32
Lspare int32
Birthtimespec Timespec
- Pad_godefs_0 uint8
- Pad_godefs_1 uint8
}
type Statfs_t struct {
@@ -141,7 +113,7 @@ type Statfs_t struct {
Spare [10]uint64
Namemax uint32
Owner uint32
- Fsid [8]byte /* fsid */
+ Fsid Fsid
Charspare [80]int8
Fstypename [16]int8
Mntfromname [88]int8
@@ -149,13 +121,13 @@ type Statfs_t struct {
}
type Flock_t struct {
- Start int64
- Len int64
- Pid int32
- Type int16
- Whence int16
- Sysid int32
- Pad_godefs_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+ Sysid int32
+ Pad_cgo_0 [4]byte
}
type Dirent struct {
@@ -166,6 +138,10 @@ type Dirent struct {
Name [256]int8
}
+type Fsid struct {
+ Val [2]int32
+}
+
type RawSockaddrInet4 struct {
Len uint8
Family uint8
@@ -228,21 +204,27 @@ type IPMreq struct {
Interface [4]byte /* in_addr */
}
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type Msghdr struct {
- Name *byte
- Namelen uint32
- Pad_godefs_0 [4]byte
- Iov *Iovec
- Iovlen int32
- Pad_godefs_1 [4]byte
- Control *byte
- Controllen uint32
- Flags int32
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen int32
+ Pad_cgo_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
}
type Cmsghdr struct {
@@ -256,6 +238,27 @@ type Inet6Pktinfo struct {
Ifindex uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x36
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
type Kevent_t struct {
Ident uint64
Filter int16
@@ -269,15 +272,24 @@ type FdSet struct {
X__fds_bits [16]uint64
}
+const (
+ SizeofIfMsghdr = 0xa8
+ SizeofIfData = 0x98
+ SizeofIfaMsghdr = 0x14
+ SizeofIfmaMsghdr = 0x10
+ SizeofRtMsghdr = 0x98
+ SizeofRtMetrics = 0x70
+)
+
type IfMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Data IfData
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Data IfData
}
type IfData struct {
@@ -309,40 +321,40 @@ type IfData struct {
}
type IfaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
- Metric int32
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Metric int32
}
type IfmaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_godefs_0 [2]byte
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Addrs int32
+ Flags int32
+ Index uint16
+ Pad_cgo_0 [2]byte
}
type RtMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Pad_godefs_0 [2]byte
- Flags int32
- Addrs int32
- Pid int32
- Seq int32
- Errno int32
- Fmask int32
- Inits uint64
- Rmx RtMetrics
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Index uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Addrs int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Fmask int32
+ Inits uint64
+ Rmx RtMetrics
}
type RtMetrics struct {
@@ -360,6 +372,16 @@ type RtMetrics struct {
Filler [3]uint64
}
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfZbuf = 0x18
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x20
+ SizeofBpfZbufHeader = 0x20
+)
+
type BpfVersion struct {
Major uint16
Minor uint16
@@ -377,9 +399,9 @@ type BpfZbuf struct {
}
type BpfProgram struct {
- Len uint32
- Pad_godefs_0 [4]byte
- Insns *BpfInsn
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
}
type BpfInsn struct {
@@ -390,11 +412,11 @@ type BpfInsn struct {
}
type BpfHdr struct {
- Tstamp Timeval
- Caplen uint32
- Datalen uint32
- Hdrlen uint16
- Pad_godefs_0 [6]byte
+ Tstamp Timeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [6]byte
}
type BpfZbufHeader struct {
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 252fbff74..fcead2f97 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -1,119 +1,23 @@
-// godefs -gsyscall -f-m32 types_linux.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
package syscall
-// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x70
- SizeofSockaddrUnix = 0x6e
- SizeofSockaddrLinklayer = 0x14
- SizeofSockaddrNetlink = 0xc
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- SizeofUcred = 0xc
- IFA_UNSPEC = 0
- IFA_ADDRESS = 0x1
- IFA_LOCAL = 0x2
- IFA_LABEL = 0x3
- IFA_BROADCAST = 0x4
- IFA_ANYCAST = 0x5
- IFA_CACHEINFO = 0x6
- IFA_MULTICAST = 0x7
- IFLA_UNSPEC = 0
- IFLA_ADDRESS = 0x1
- IFLA_BROADCAST = 0x2
- IFLA_IFNAME = 0x3
- IFLA_MTU = 0x4
- IFLA_LINK = 0x5
- IFLA_QDISC = 0x6
- IFLA_STATS = 0x7
- IFLA_COST = 0x8
- IFLA_PRIORITY = 0x9
- IFLA_MASTER = 0xa
- IFLA_WIRELESS = 0xb
- IFLA_PROTINFO = 0xc
- IFLA_TXQLEN = 0xd
- IFLA_MAP = 0xe
- IFLA_WEIGHT = 0xf
- IFLA_OPERSTATE = 0x10
- IFLA_LINKMODE = 0x11
- IFLA_LINKINFO = 0x12
- IFLA_NET_NS_PID = 0x13
- IFLA_IFALIAS = 0x14
- IFLA_MAX = 0x14
- RT_SCOPE_UNIVERSE = 0
- RT_SCOPE_SITE = 0xc8
- RT_SCOPE_LINK = 0xfd
- RT_SCOPE_HOST = 0xfe
- RT_SCOPE_NOWHERE = 0xff
- RT_TABLE_UNSPEC = 0
- RT_TABLE_COMPAT = 0xfc
- RT_TABLE_DEFAULT = 0xfd
- RT_TABLE_MAIN = 0xfe
- RT_TABLE_LOCAL = 0xff
- RT_TABLE_MAX = 0xffffffff
- RTA_UNSPEC = 0
- RTA_DST = 0x1
- RTA_SRC = 0x2
- RTA_IIF = 0x3
- RTA_OIF = 0x4
- RTA_GATEWAY = 0x5
- RTA_PRIORITY = 0x6
- RTA_PREFSRC = 0x7
- RTA_METRICS = 0x8
- RTA_MULTIPATH = 0x9
- RTA_FLOW = 0xb
- RTA_CACHEINFO = 0xc
- RTA_TABLE = 0xf
- RTN_UNSPEC = 0
- RTN_UNICAST = 0x1
- RTN_LOCAL = 0x2
- RTN_BROADCAST = 0x3
- RTN_ANYCAST = 0x4
- RTN_MULTICAST = 0x5
- RTN_BLACKHOLE = 0x6
- RTN_UNREACHABLE = 0x7
- RTN_PROHIBIT = 0x8
- RTN_THROW = 0x9
- RTN_NAT = 0xa
- RTN_XRESOLVE = 0xb
- SizeofNlMsghdr = 0x10
- SizeofNlMsgerr = 0x14
- SizeofRtGenmsg = 0x1
- SizeofNlAttr = 0x4
- SizeofRtAttr = 0x4
- SizeofIfInfomsg = 0x10
- SizeofIfAddrmsg = 0x8
- SizeofRtmsg = 0xc
- SizeofRtNexthop = 0x8
- SizeofSockFilter = 0x8
- SizeofSockFprog = 0x8
- SizeofInotifyEvent = 0x10
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
type Timespec struct {
Sec int32
@@ -126,37 +30,27 @@ type Timeval struct {
}
type Timex struct {
- Modes uint32
- Offset int32
- Freq int32
- Maxerror int32
- Esterror int32
- Status int32
- Constant int32
- Precision int32
- Tolerance int32
- Time Timeval
- Tick int32
- Ppsfreq int32
- Jitter int32
- Shift int32
- Stabil int32
- Jitcnt int32
- Calcnt int32
- Errcnt int32
- Stbcnt int32
- Tai int32
- Pad_godefs_0 int32
- Pad_godefs_1 int32
- Pad_godefs_2 int32
- Pad_godefs_3 int32
- Pad_godefs_4 int32
- Pad_godefs_5 int32
- Pad_godefs_6 int32
- Pad_godefs_7 int32
- Pad_godefs_8 int32
- Pad_godefs_9 int32
- Pad_godefs_10 int32
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_cgo_0 [44]byte
}
type Time_t int32
@@ -200,24 +94,24 @@ type Rlimit struct {
type _Gid_t uint32
type Stat_t struct {
- Dev uint64
- X__pad1 uint16
- Pad_godefs_0 [2]byte
- X__st_ino uint32
- Mode uint32
- Nlink uint32
- Uid uint32
- Gid uint32
- Rdev uint64
- X__pad2 uint16
- Pad_godefs_1 [2]byte
- Size int64
- Blksize int32
- Blocks int64
- Atim Timespec
- Mtim Timespec
- Ctim Timespec
- Ino uint64
+ Dev uint64
+ X__pad1 uint16
+ Pad_cgo_0 [2]byte
+ X__st_ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ X__pad2 uint16
+ Pad_cgo_1 [2]byte
+ Size int64
+ Blksize int32
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Ino uint64
}
type Statfs_t struct {
@@ -228,19 +122,24 @@ type Statfs_t struct {
Bavail uint64
Files uint64
Ffree uint64
- Fsid [8]byte /* __fsid_t */
+ Fsid Fsid
Namelen int32
Frsize int32
- Spare [5]int32
+ Flags int32
+ Spare [4]int32
}
type Dirent struct {
- Ino uint64
- Off int64
- Reclen uint16
- Type uint8
- Name [256]int8
- Pad_godefs_0 [1]byte
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_cgo_0 [1]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
}
type RawSockaddrInet4 struct {
@@ -307,6 +206,12 @@ type IPMreq struct {
Interface [4]byte /* in_addr */
}
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
@@ -323,9 +228,16 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint32
- Level int32
- Type int32
+ Len uint32
+ Level int32
+ Type int32
+ X__cmsg_data [0]byte
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
}
type Inet6Pktinfo struct {
@@ -339,6 +251,102 @@ type Ucred struct {
Gid uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x1c
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
type NlMsghdr struct {
Len uint32
Type uint16
@@ -402,6 +410,11 @@ type RtNexthop struct {
Ifindex int32
}
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+)
+
type SockFilter struct {
Code uint16
Jt uint8
@@ -410,9 +423,9 @@ type SockFilter struct {
}
type SockFprog struct {
- Len uint16
- Pad_godefs_0 [2]byte
- Filter *SockFilter
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *SockFilter
}
type InotifyEvent struct {
@@ -420,8 +433,11 @@ type InotifyEvent struct {
Mask uint32
Cookie uint32
Len uint32
+ Name [0]byte
}
+const SizeofInotifyEvent = 0x10
+
type PtraceRegs struct {
Ebx int32
Ecx int32
@@ -484,3 +500,117 @@ type EpollEvent struct {
Fd int32
Pad int32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ VINTR = 0x0
+ VQUIT = 0x1
+ VERASE = 0x2
+ VKILL = 0x3
+ VEOF = 0x4
+ VTIME = 0x5
+ VMIN = 0x6
+ VSWTC = 0x7
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VEOL = 0xb
+ VREPRINT = 0xc
+ VDISCARD = 0xd
+ VWERASE = 0xe
+ VLNEXT = 0xf
+ VEOL2 = 0x10
+ IGNBRK = 0x1
+ BRKINT = 0x2
+ IGNPAR = 0x4
+ PARMRK = 0x8
+ INPCK = 0x10
+ ISTRIP = 0x20
+ INLCR = 0x40
+ IGNCR = 0x80
+ ICRNL = 0x100
+ IUCLC = 0x200
+ IXON = 0x400
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IMAXBEL = 0x2000
+ IUTF8 = 0x4000
+ OPOST = 0x1
+ OLCUC = 0x2
+ ONLCR = 0x4
+ OCRNL = 0x8
+ ONOCR = 0x10
+ ONLRET = 0x20
+ OFILL = 0x40
+ OFDEL = 0x80
+ B0 = 0x0
+ B50 = 0x1
+ B75 = 0x2
+ B110 = 0x3
+ B134 = 0x4
+ B150 = 0x5
+ B200 = 0x6
+ B300 = 0x7
+ B600 = 0x8
+ B1200 = 0x9
+ B1800 = 0xa
+ B2400 = 0xb
+ B4800 = 0xc
+ B9600 = 0xd
+ B19200 = 0xe
+ B38400 = 0xf
+ CSIZE = 0x30
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSTOPB = 0x40
+ CREAD = 0x80
+ PARENB = 0x100
+ PARODD = 0x200
+ HUPCL = 0x400
+ CLOCAL = 0x800
+ B57600 = 0x1001
+ B115200 = 0x1002
+ B230400 = 0x1003
+ B460800 = 0x1004
+ B500000 = 0x1005
+ B576000 = 0x1006
+ B921600 = 0x1007
+ B1000000 = 0x1008
+ B1152000 = 0x1009
+ B1500000 = 0x100a
+ B2000000 = 0x100b
+ B2500000 = 0x100c
+ B3000000 = 0x100d
+ B3500000 = 0x100e
+ B4000000 = 0x100f
+ ISIG = 0x1
+ ICANON = 0x2
+ XCASE = 0x4
+ ECHO = 0x8
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHONL = 0x40
+ NOFLSH = 0x80
+ TOSTOP = 0x100
+ ECHOCTL = 0x200
+ ECHOPRT = 0x400
+ ECHOKE = 0x800
+ FLUSHO = 0x1000
+ PENDIN = 0x4000
+ IEXTEN = 0x8000
+ TCGETS = 0x5401
+ TCSETS = 0x5402
+)
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index 520ba963a..d5583a7c2 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -1,119 +1,23 @@
-// godefs -gsyscall -f-m64 types_linux.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
package syscall
-// Constants
const (
- sizeofPtr = 0x8
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x8
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x70
- SizeofSockaddrUnix = 0x6e
- SizeofSockaddrLinklayer = 0x14
- SizeofSockaddrNetlink = 0xc
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x38
- SizeofCmsghdr = 0x10
- SizeofInet6Pktinfo = 0x14
- SizeofUcred = 0xc
- IFA_UNSPEC = 0
- IFA_ADDRESS = 0x1
- IFA_LOCAL = 0x2
- IFA_LABEL = 0x3
- IFA_BROADCAST = 0x4
- IFA_ANYCAST = 0x5
- IFA_CACHEINFO = 0x6
- IFA_MULTICAST = 0x7
- IFLA_UNSPEC = 0
- IFLA_ADDRESS = 0x1
- IFLA_BROADCAST = 0x2
- IFLA_IFNAME = 0x3
- IFLA_MTU = 0x4
- IFLA_LINK = 0x5
- IFLA_QDISC = 0x6
- IFLA_STATS = 0x7
- IFLA_COST = 0x8
- IFLA_PRIORITY = 0x9
- IFLA_MASTER = 0xa
- IFLA_WIRELESS = 0xb
- IFLA_PROTINFO = 0xc
- IFLA_TXQLEN = 0xd
- IFLA_MAP = 0xe
- IFLA_WEIGHT = 0xf
- IFLA_OPERSTATE = 0x10
- IFLA_LINKMODE = 0x11
- IFLA_LINKINFO = 0x12
- IFLA_NET_NS_PID = 0x13
- IFLA_IFALIAS = 0x14
- IFLA_MAX = 0x14
- RT_SCOPE_UNIVERSE = 0
- RT_SCOPE_SITE = 0xc8
- RT_SCOPE_LINK = 0xfd
- RT_SCOPE_HOST = 0xfe
- RT_SCOPE_NOWHERE = 0xff
- RT_TABLE_UNSPEC = 0
- RT_TABLE_COMPAT = 0xfc
- RT_TABLE_DEFAULT = 0xfd
- RT_TABLE_MAIN = 0xfe
- RT_TABLE_LOCAL = 0xff
- RT_TABLE_MAX = 0xffffffff
- RTA_UNSPEC = 0
- RTA_DST = 0x1
- RTA_SRC = 0x2
- RTA_IIF = 0x3
- RTA_OIF = 0x4
- RTA_GATEWAY = 0x5
- RTA_PRIORITY = 0x6
- RTA_PREFSRC = 0x7
- RTA_METRICS = 0x8
- RTA_MULTIPATH = 0x9
- RTA_FLOW = 0xb
- RTA_CACHEINFO = 0xc
- RTA_TABLE = 0xf
- RTN_UNSPEC = 0
- RTN_UNICAST = 0x1
- RTN_LOCAL = 0x2
- RTN_BROADCAST = 0x3
- RTN_ANYCAST = 0x4
- RTN_MULTICAST = 0x5
- RTN_BLACKHOLE = 0x6
- RTN_UNREACHABLE = 0x7
- RTN_PROHIBIT = 0x8
- RTN_THROW = 0x9
- RTN_NAT = 0xa
- RTN_XRESOLVE = 0xb
- SizeofNlMsghdr = 0x10
- SizeofNlMsgerr = 0x14
- SizeofRtGenmsg = 0x1
- SizeofNlAttr = 0x4
- SizeofRtAttr = 0x4
- SizeofIfInfomsg = 0x10
- SizeofIfAddrmsg = 0x8
- SizeofRtmsg = 0xc
- SizeofRtNexthop = 0x8
- SizeofSockFilter = 0x8
- SizeofSockFprog = 0x10
- SizeofInotifyEvent = 0x10
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int64
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
type Timespec struct {
Sec int64
@@ -126,40 +30,30 @@ type Timeval struct {
}
type Timex struct {
- Modes uint32
- Pad_godefs_0 [4]byte
- Offset int64
- Freq int64
- Maxerror int64
- Esterror int64
- Status int32
- Pad_godefs_1 [4]byte
- Constant int64
- Precision int64
- Tolerance int64
- Time Timeval
- Tick int64
- Ppsfreq int64
- Jitter int64
- Shift int32
- Pad_godefs_2 [4]byte
- Stabil int64
- Jitcnt int64
- Calcnt int64
- Errcnt int64
- Stbcnt int64
- Tai int32
- Pad_godefs_3 int32
- Pad_godefs_4 int32
- Pad_godefs_5 int32
- Pad_godefs_6 int32
- Pad_godefs_7 int32
- Pad_godefs_8 int32
- Pad_godefs_9 int32
- Pad_godefs_10 int32
- Pad_godefs_11 int32
- Pad_godefs_12 int32
- Pad_godefs_13 int32
+ Modes uint32
+ Pad_cgo_0 [4]byte
+ Offset int64
+ Freq int64
+ Maxerror int64
+ Esterror int64
+ Status int32
+ Pad_cgo_1 [4]byte
+ Constant int64
+ Precision int64
+ Tolerance int64
+ Time Timeval
+ Tick int64
+ Ppsfreq int64
+ Jitter int64
+ Shift int32
+ Pad_cgo_2 [4]byte
+ Stabil int64
+ Jitcnt int64
+ Calcnt int64
+ Errcnt int64
+ Stbcnt int64
+ Tai int32
+ Pad_cgo_3 [44]byte
}
type Time_t int64
@@ -228,19 +122,24 @@ type Statfs_t struct {
Bavail uint64
Files uint64
Ffree uint64
- Fsid [8]byte /* __fsid_t */
+ Fsid Fsid
Namelen int64
Frsize int64
- Spare [5]int64
+ Flags int64
+ Spare [4]int64
}
type Dirent struct {
- Ino uint64
- Off int64
- Reclen uint16
- Type uint8
- Name [256]int8
- Pad_godefs_0 [5]byte
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
}
type RawSockaddrInet4 struct {
@@ -307,27 +206,40 @@ type IPMreq struct {
Interface [4]byte /* in_addr */
}
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type Msghdr struct {
- Name *byte
- Namelen uint32
- Pad_godefs_0 [4]byte
- Iov *Iovec
- Iovlen uint64
- Control *byte
- Controllen uint64
- Flags int32
- Pad_godefs_1 [4]byte
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen uint64
+ Control *byte
+ Controllen uint64
+ Flags int32
+ Pad_cgo_1 [4]byte
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
+ Len uint64
+ Level int32
+ Type int32
+ X__cmsg_data [0]byte
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
}
type Inet6Pktinfo struct {
@@ -341,6 +253,102 @@ type Ucred struct {
Gid uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x38
+ SizeofCmsghdr = 0x10
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x1c
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
type NlMsghdr struct {
Len uint32
Type uint16
@@ -404,6 +412,11 @@ type RtNexthop struct {
Ifindex int32
}
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x10
+)
+
type SockFilter struct {
Code uint16
Jt uint8
@@ -412,9 +425,9 @@ type SockFilter struct {
}
type SockFprog struct {
- Len uint16
- Pad_godefs_0 [6]byte
- Filter *SockFilter
+ Len uint16
+ Pad_cgo_0 [6]byte
+ Filter *SockFilter
}
type InotifyEvent struct {
@@ -422,8 +435,11 @@ type InotifyEvent struct {
Mask uint32
Cookie uint32
Len uint32
+ Name [0]byte
}
+const SizeofInotifyEvent = 0x10
+
type PtraceRegs struct {
R15 uint64
R14 uint64
@@ -459,22 +475,22 @@ type FdSet struct {
}
type Sysinfo_t struct {
- Uptime int64
- Loads [3]uint64
- Totalram uint64
- Freeram uint64
- Sharedram uint64
- Bufferram uint64
- Totalswap uint64
- Freeswap uint64
- Procs uint16
- Pad uint16
- Pad_godefs_0 [4]byte
- Totalhigh uint64
- Freehigh uint64
- Unit uint32
- X_f [0]int8
- Pad_godefs_1 [4]byte
+ Uptime int64
+ Loads [3]uint64
+ Totalram uint64
+ Freeram uint64
+ Sharedram uint64
+ Bufferram uint64
+ Totalswap uint64
+ Freeswap uint64
+ Procs uint16
+ Pad uint16
+ Pad_cgo_0 [4]byte
+ Totalhigh uint64
+ Freehigh uint64
+ Unit uint32
+ X_f [0]byte
+ Pad_cgo_1 [4]byte
}
type Utsname struct {
@@ -487,12 +503,12 @@ type Utsname struct {
}
type Ustat_t struct {
- Tfree int32
- Pad_godefs_0 [4]byte
- Tinode uint64
- Fname [6]int8
- Fpack [6]int8
- Pad_godefs_1 [4]byte
+ Tfree int32
+ Pad_cgo_0 [4]byte
+ Tinode uint64
+ Fname [6]int8
+ Fpack [6]int8
+ Pad_cgo_1 [4]byte
}
type EpollEvent struct {
@@ -500,3 +516,117 @@ type EpollEvent struct {
Fd int32
Pad int32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ VINTR = 0x0
+ VQUIT = 0x1
+ VERASE = 0x2
+ VKILL = 0x3
+ VEOF = 0x4
+ VTIME = 0x5
+ VMIN = 0x6
+ VSWTC = 0x7
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VEOL = 0xb
+ VREPRINT = 0xc
+ VDISCARD = 0xd
+ VWERASE = 0xe
+ VLNEXT = 0xf
+ VEOL2 = 0x10
+ IGNBRK = 0x1
+ BRKINT = 0x2
+ IGNPAR = 0x4
+ PARMRK = 0x8
+ INPCK = 0x10
+ ISTRIP = 0x20
+ INLCR = 0x40
+ IGNCR = 0x80
+ ICRNL = 0x100
+ IUCLC = 0x200
+ IXON = 0x400
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IMAXBEL = 0x2000
+ IUTF8 = 0x4000
+ OPOST = 0x1
+ OLCUC = 0x2
+ ONLCR = 0x4
+ OCRNL = 0x8
+ ONOCR = 0x10
+ ONLRET = 0x20
+ OFILL = 0x40
+ OFDEL = 0x80
+ B0 = 0x0
+ B50 = 0x1
+ B75 = 0x2
+ B110 = 0x3
+ B134 = 0x4
+ B150 = 0x5
+ B200 = 0x6
+ B300 = 0x7
+ B600 = 0x8
+ B1200 = 0x9
+ B1800 = 0xa
+ B2400 = 0xb
+ B4800 = 0xc
+ B9600 = 0xd
+ B19200 = 0xe
+ B38400 = 0xf
+ CSIZE = 0x30
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSTOPB = 0x40
+ CREAD = 0x80
+ PARENB = 0x100
+ PARODD = 0x200
+ HUPCL = 0x400
+ CLOCAL = 0x800
+ B57600 = 0x1001
+ B115200 = 0x1002
+ B230400 = 0x1003
+ B460800 = 0x1004
+ B500000 = 0x1005
+ B576000 = 0x1006
+ B921600 = 0x1007
+ B1000000 = 0x1008
+ B1152000 = 0x1009
+ B1500000 = 0x100a
+ B2000000 = 0x100b
+ B2500000 = 0x100c
+ B3000000 = 0x100d
+ B3500000 = 0x100e
+ B4000000 = 0x100f
+ ISIG = 0x1
+ ICANON = 0x2
+ XCASE = 0x4
+ ECHO = 0x8
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHONL = 0x40
+ NOFLSH = 0x80
+ TOSTOP = 0x100
+ ECHOCTL = 0x200
+ ECHOPRT = 0x400
+ ECHOKE = 0x800
+ FLUSHO = 0x1000
+ PENDIN = 0x4000
+ IEXTEN = 0x8000
+ TCGETS = 0x5401
+ TCSETS = 0x5402
+)
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 2421df081..cd680c3ad 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -1,124 +1,23 @@
-// godefs -gsyscall types_linux.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-// Manual corrections: TODO(rsc): need to fix godefs
-// remove duplicate PtraceRegs type
-// change RawSockaddrUnix field to Path [108]int8 (was uint8)
-// add padding to EpollEvent
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
package syscall
-// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x70
- SizeofSockaddrUnix = 0x6e
- SizeofSockaddrLinklayer = 0x14
- SizeofSockaddrNetlink = 0xc
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- SizeofUcred = 0xc
- IFA_UNSPEC = 0
- IFA_ADDRESS = 0x1
- IFA_LOCAL = 0x2
- IFA_LABEL = 0x3
- IFA_BROADCAST = 0x4
- IFA_ANYCAST = 0x5
- IFA_CACHEINFO = 0x6
- IFA_MULTICAST = 0x7
- IFLA_UNSPEC = 0
- IFLA_ADDRESS = 0x1
- IFLA_BROADCAST = 0x2
- IFLA_IFNAME = 0x3
- IFLA_MTU = 0x4
- IFLA_LINK = 0x5
- IFLA_QDISC = 0x6
- IFLA_STATS = 0x7
- IFLA_COST = 0x8
- IFLA_PRIORITY = 0x9
- IFLA_MASTER = 0xa
- IFLA_WIRELESS = 0xb
- IFLA_PROTINFO = 0xc
- IFLA_TXQLEN = 0xd
- IFLA_MAP = 0xe
- IFLA_WEIGHT = 0xf
- IFLA_OPERSTATE = 0x10
- IFLA_LINKMODE = 0x11
- IFLA_LINKINFO = 0x12
- IFLA_NET_NS_PID = 0x13
- IFLA_IFALIAS = 0x14
- IFLA_MAX = 0x14
- RT_SCOPE_UNIVERSE = 0
- RT_SCOPE_SITE = 0xc8
- RT_SCOPE_LINK = 0xfd
- RT_SCOPE_HOST = 0xfe
- RT_SCOPE_NOWHERE = 0xff
- RT_TABLE_UNSPEC = 0
- RT_TABLE_COMPAT = 0xfc
- RT_TABLE_DEFAULT = 0xfd
- RT_TABLE_MAIN = 0xfe
- RT_TABLE_LOCAL = 0xff
- RT_TABLE_MAX = 0xffffffff
- RTA_UNSPEC = 0
- RTA_DST = 0x1
- RTA_SRC = 0x2
- RTA_IIF = 0x3
- RTA_OIF = 0x4
- RTA_GATEWAY = 0x5
- RTA_PRIORITY = 0x6
- RTA_PREFSRC = 0x7
- RTA_METRICS = 0x8
- RTA_MULTIPATH = 0x9
- RTA_FLOW = 0xb
- RTA_CACHEINFO = 0xc
- RTA_TABLE = 0xf
- RTN_UNSPEC = 0
- RTN_UNICAST = 0x1
- RTN_LOCAL = 0x2
- RTN_BROADCAST = 0x3
- RTN_ANYCAST = 0x4
- RTN_MULTICAST = 0x5
- RTN_BLACKHOLE = 0x6
- RTN_UNREACHABLE = 0x7
- RTN_PROHIBIT = 0x8
- RTN_THROW = 0x9
- RTN_NAT = 0xa
- RTN_XRESOLVE = 0xb
- SizeofNlMsghdr = 0x10
- SizeofNlMsgerr = 0x14
- SizeofRtGenmsg = 0x1
- SizeofNlAttr = 0x4
- SizeofRtAttr = 0x4
- SizeofIfInfomsg = 0x10
- SizeofIfAddrmsg = 0x8
- SizeofRtmsg = 0xc
- SizeofRtNexthop = 0x8
- SizeofSockFilter = 0x8
- SizeofSockFprog = 0x8
- SizeofInotifyEvent = 0x10
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
)
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
type Timespec struct {
Sec int32
@@ -131,37 +30,27 @@ type Timeval struct {
}
type Timex struct {
- Modes uint32
- Offset int32
- Freq int32
- Maxerror int32
- Esterror int32
- Status int32
- Constant int32
- Precision int32
- Tolerance int32
- Time Timeval
- Tick int32
- Ppsfreq int32
- Jitter int32
- Shift int32
- Stabil int32
- Jitcnt int32
- Calcnt int32
- Errcnt int32
- Stbcnt int32
- Tai int32
- Pad_godefs_0 int32
- Pad_godefs_1 int32
- Pad_godefs_2 int32
- Pad_godefs_3 int32
- Pad_godefs_4 int32
- Pad_godefs_5 int32
- Pad_godefs_6 int32
- Pad_godefs_7 int32
- Pad_godefs_8 int32
- Pad_godefs_9 int32
- Pad_godefs_10 int32
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_cgo_0 [44]byte
}
type Time_t int32
@@ -205,49 +94,54 @@ type Rlimit struct {
type _Gid_t uint32
type Stat_t struct {
- Dev uint64
- X__pad1 uint16
- Pad_godefs_0 [2]byte
- X__st_ino uint32
- Mode uint32
- Nlink uint32
- Uid uint32
- Gid uint32
- Rdev uint64
- X__pad2 uint16
- Pad_godefs_1 [6]byte
- Size int64
- Blksize int32
- Pad_godefs_2 [4]byte
- Blocks int64
- Atim Timespec
- Mtim Timespec
- Ctim Timespec
- Ino uint64
+ Dev uint64
+ X__pad1 uint16
+ Pad_cgo_0 [2]byte
+ X__st_ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ X__pad2 uint16
+ Pad_cgo_1 [6]byte
+ Size int64
+ Blksize int32
+ Pad_cgo_2 [4]byte
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Ino uint64
}
type Statfs_t struct {
- Type int32
- Bsize int32
- Blocks uint64
- Bfree uint64
- Bavail uint64
- Files uint64
- Ffree uint64
- Fsid [8]byte /* __fsid_t */
- Namelen int32
- Frsize int32
- Spare [5]int32
- Pad_godefs_0 [4]byte
+ Type int32
+ Bsize int32
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Fsid Fsid
+ Namelen int32
+ Frsize int32
+ Flags int32
+ Spare [4]int32
+ Pad_cgo_0 [4]byte
}
type Dirent struct {
- Ino uint64
- Off int64
- Reclen uint16
- Type uint8
- Name [256]uint8
- Pad_godefs_0 [5]byte
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]uint8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
}
type RawSockaddrInet4 struct {
@@ -314,6 +208,12 @@ type IPMreq struct {
Interface [4]byte /* in_addr */
}
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
@@ -330,9 +230,16 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint32
- Level int32
- Type int32
+ Len uint32
+ Level int32
+ Type int32
+ X__cmsg_data [0]uint8
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
}
type Inet6Pktinfo struct {
@@ -346,6 +253,102 @@ type Ucred struct {
Gid uint32
}
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofUcred = 0xc
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x1c
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
type NlMsghdr struct {
Len uint32
Type uint16
@@ -409,6 +412,11 @@ type RtNexthop struct {
Ifindex int32
}
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+)
+
type SockFilter struct {
Code uint16
Jt uint8
@@ -417,9 +425,9 @@ type SockFilter struct {
}
type SockFprog struct {
- Len uint16
- Pad_godefs_0 [2]byte
- Filter *SockFilter
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *SockFilter
}
type InotifyEvent struct {
@@ -427,9 +435,14 @@ type InotifyEvent struct {
Mask uint32
Cookie uint32
Len uint32
+ Name [0]uint8
}
-type PtraceRegs struct{}
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+ Uregs [18]uint32
+}
type FdSet struct {
Bits [32]int32
@@ -474,3 +487,117 @@ type EpollEvent struct {
Fd int32
Pad int32
}
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ VINTR = 0x0
+ VQUIT = 0x1
+ VERASE = 0x2
+ VKILL = 0x3
+ VEOF = 0x4
+ VTIME = 0x5
+ VMIN = 0x6
+ VSWTC = 0x7
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VEOL = 0xb
+ VREPRINT = 0xc
+ VDISCARD = 0xd
+ VWERASE = 0xe
+ VLNEXT = 0xf
+ VEOL2 = 0x10
+ IGNBRK = 0x1
+ BRKINT = 0x2
+ IGNPAR = 0x4
+ PARMRK = 0x8
+ INPCK = 0x10
+ ISTRIP = 0x20
+ INLCR = 0x40
+ IGNCR = 0x80
+ ICRNL = 0x100
+ IUCLC = 0x200
+ IXON = 0x400
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IMAXBEL = 0x2000
+ IUTF8 = 0x4000
+ OPOST = 0x1
+ OLCUC = 0x2
+ ONLCR = 0x4
+ OCRNL = 0x8
+ ONOCR = 0x10
+ ONLRET = 0x20
+ OFILL = 0x40
+ OFDEL = 0x80
+ B0 = 0x0
+ B50 = 0x1
+ B75 = 0x2
+ B110 = 0x3
+ B134 = 0x4
+ B150 = 0x5
+ B200 = 0x6
+ B300 = 0x7
+ B600 = 0x8
+ B1200 = 0x9
+ B1800 = 0xa
+ B2400 = 0xb
+ B4800 = 0xc
+ B9600 = 0xd
+ B19200 = 0xe
+ B38400 = 0xf
+ CSIZE = 0x30
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSTOPB = 0x40
+ CREAD = 0x80
+ PARENB = 0x100
+ PARODD = 0x200
+ HUPCL = 0x400
+ CLOCAL = 0x800
+ B57600 = 0x1001
+ B115200 = 0x1002
+ B230400 = 0x1003
+ B460800 = 0x1004
+ B500000 = 0x1005
+ B576000 = 0x1006
+ B921600 = 0x1007
+ B1000000 = 0x1008
+ B1152000 = 0x1009
+ B1500000 = 0x100a
+ B2000000 = 0x100b
+ B2500000 = 0x100c
+ B3000000 = 0x100d
+ B3500000 = 0x100e
+ B4000000 = 0x100f
+ ISIG = 0x1
+ ICANON = 0x2
+ XCASE = 0x4
+ ECHO = 0x8
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHONL = 0x40
+ NOFLSH = 0x80
+ TOSTOP = 0x100
+ ECHOCTL = 0x200
+ ECHOPRT = 0x400
+ ECHOKE = 0x800
+ FLUSHO = 0x1000
+ PENDIN = 0x4000
+ IEXTEN = 0x8000
+ TCGETS = 0x5401
+ TCSETS = 0x5402
+)
diff --git a/src/pkg/syscall/ztypes_netbsd_386.go b/src/pkg/syscall/ztypes_netbsd_386.go
new file mode 100644
index 000000000..ef9f33aeb
--- /dev/null
+++ b/src/pkg/syscall/ztypes_netbsd_386.go
@@ -0,0 +1,406 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_netbsd.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev int32
+ Ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Lspare0 int32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare1 int32
+ X__st_birthtim Timespec
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ F_flags uint32
+ F_bsize uint32
+ F_iosize uint32
+ F_blocks uint64
+ F_bfree uint64
+ F_bavail int64
+ F_files uint64
+ F_ffree uint64
+ F_favail int64
+ F_syncwrites uint64
+ F_syncreads uint64
+ F_asyncwrites uint64
+ F_asyncreads uint64
+ F_fsid Fsid
+ F_namemax uint32
+ F_owner uint32
+ F_ctime uint32
+ F_spare [3]uint32
+ F_fstypename [16]int8
+ F_mntonname [90]int8
+ F_mntfromname [90]int8
+ Mount_info [160]byte
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Dirent struct {
+ Fileno uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [512]int8
+}
+
+type Fsid struct {
+ Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x20
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+const (
+ SizeofIfMsghdr = 0xe8
+ SizeofIfData = 0xd0
+ SizeofIfaMsghdr = 0x18
+ SizeofRtMsghdr = 0x58
+ SizeofRtMetrics = 0x30
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Xflags int32
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Mtu uint32
+ Metric uint32
+ Pad uint32
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Capabilities uint32
+ Lastchange Timeval
+ Mclpool [7]Mclpool
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Priority uint8
+ Mpls uint8
+ Addrs int32
+ Flags int32
+ Fmask int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Pksent uint64
+ Locks uint32
+ Mtu uint32
+ Expire uint32
+ Refcnt uint32
+ Hopcount uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+}
+
+type Mclpool struct {
+ Grown uint32
+ Alive uint16
+ Hwm uint16
+ Cwm uint16
+ Lwm uint16
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type BpfTimeval struct {
+ Sec uint32
+ Usec uint32
+}
diff --git a/src/pkg/syscall/ztypes_netbsd_amd64.go b/src/pkg/syscall/ztypes_netbsd_amd64.go
new file mode 100644
index 000000000..3979d54de
--- /dev/null
+++ b/src/pkg/syscall/ztypes_netbsd_amd64.go
@@ -0,0 +1,412 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_netbsd.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Pad_cgo_0 [4]byte
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev int32
+ Ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Lspare0 int32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare1 int32
+ X__st_birthtim Timespec
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ F_flags uint32
+ F_bsize uint32
+ F_iosize uint32
+ Pad_cgo_0 [4]byte
+ F_blocks uint64
+ F_bfree uint64
+ F_bavail int64
+ F_files uint64
+ F_ffree uint64
+ F_favail int64
+ F_syncwrites uint64
+ F_syncreads uint64
+ F_asyncwrites uint64
+ F_asyncreads uint64
+ F_fsid Fsid
+ F_namemax uint32
+ F_owner uint32
+ F_ctime uint32
+ F_spare [3]uint32
+ F_fstypename [16]int8
+ F_mntonname [90]int8
+ F_mntfromname [90]int8
+ Pad_cgo_1 [4]byte
+ Mount_info [160]byte
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Dirent struct {
+ Fileno uint64
+ Reclen uint16
+ Namlen uint16
+ Type uint8
+ Name [512]int8
+}
+
+type Fsid struct {
+ Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen uint32
+ Pad_cgo_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x20
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+type Kevent_t struct {
+ Ident uint64
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+const (
+ SizeofIfMsghdr = 0xf0
+ SizeofIfData = 0xd8
+ SizeofIfaMsghdr = 0x18
+ SizeofRtMsghdr = 0x58
+ SizeofRtMetrics = 0x30
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Xflags int32
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Mtu uint32
+ Metric uint32
+ Pad uint32
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Lastchange Timeval
+ Mclpool [7]Mclpool
+ Pad_cgo_0 [4]byte
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Priority uint8
+ Mpls uint8
+ Addrs int32
+ Flags int32
+ Fmask int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Pksent uint64
+ Locks uint32
+ Mtu uint32
+ Expire uint32
+ Refcnt uint32
+ Hopcount uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+}
+
+type Mclpool struct {
+ Grown uint32
+ Alive uint16
+ Hwm uint16
+ Cwm uint16
+ Lwm uint16
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type BpfTimeval struct {
+ Sec uint32
+ Usec uint32
+}
diff --git a/src/pkg/syscall/ztypes_openbsd_386.go b/src/pkg/syscall/ztypes_openbsd_386.go
new file mode 100644
index 000000000..6c21e39b0
--- /dev/null
+++ b/src/pkg/syscall/ztypes_openbsd_386.go
@@ -0,0 +1,405 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev int32
+ Ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Lspare0 int32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare1 int32
+ X__st_birthtim Timespec
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ F_flags uint32
+ F_bsize uint32
+ F_iosize uint32
+ F_blocks uint64
+ F_bfree uint64
+ F_bavail int64
+ F_files uint64
+ F_ffree uint64
+ F_favail int64
+ F_syncwrites uint64
+ F_syncreads uint64
+ F_asyncwrites uint64
+ F_asyncreads uint64
+ F_fsid Fsid
+ F_namemax uint32
+ F_owner uint32
+ F_ctime uint32
+ F_spare [3]uint32
+ F_fstypename [16]int8
+ F_mntonname [90]int8
+ F_mntfromname [90]int8
+ Mount_info [160]byte
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Dirent struct {
+ Fileno uint32
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ Name [256]int8
+}
+
+type Fsid struct {
+ Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x20
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+const (
+ SizeofIfMsghdr = 0xe4
+ SizeofIfData = 0xcc
+ SizeofIfaMsghdr = 0x18
+ SizeofRtMsghdr = 0x58
+ SizeofRtMetrics = 0x30
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Xflags int32
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Mtu uint32
+ Metric uint32
+ Pad uint32
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Lastchange Timeval
+ Mclpool [7]Mclpool
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Priority uint8
+ Mpls uint8
+ Addrs int32
+ Flags int32
+ Fmask int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Pksent uint64
+ Locks uint32
+ Mtu uint32
+ Expire uint32
+ Refcnt uint32
+ Hopcount uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+}
+
+type Mclpool struct {
+ Grown uint32
+ Alive uint16
+ Hwm uint16
+ Cwm uint16
+ Lwm uint16
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x8
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type BpfTimeval struct {
+ Sec uint32
+ Usec uint32
+}
diff --git a/src/pkg/syscall/ztypes_openbsd_amd64.go b/src/pkg/syscall/ztypes_openbsd_amd64.go
new file mode 100644
index 000000000..4d01578fc
--- /dev/null
+++ b/src/pkg/syscall/ztypes_openbsd_amd64.go
@@ -0,0 +1,412 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int64
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Pad_cgo_0 [4]byte
+ Nsec int64
+}
+
+type Timeval struct {
+ Sec int64
+ Usec int64
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int64
+ Ixrss int64
+ Idrss int64
+ Isrss int64
+ Minflt int64
+ Majflt int64
+ Nswap int64
+ Inblock int64
+ Oublock int64
+ Msgsnd int64
+ Msgrcv int64
+ Nsignals int64
+ Nvcsw int64
+ Nivcsw int64
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+ S_IFMT = 0xf000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+type Stat_t struct {
+ Dev int32
+ Ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev int32
+ Lspare0 int32
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Size int64
+ Blocks int64
+ Blksize uint32
+ Flags uint32
+ Gen uint32
+ Lspare1 int32
+ X__st_birthtim Timespec
+ Qspare [2]int64
+}
+
+type Statfs_t struct {
+ F_flags uint32
+ F_bsize uint32
+ F_iosize uint32
+ Pad_cgo_0 [4]byte
+ F_blocks uint64
+ F_bfree uint64
+ F_bavail int64
+ F_files uint64
+ F_ffree uint64
+ F_favail int64
+ F_syncwrites uint64
+ F_syncreads uint64
+ F_asyncwrites uint64
+ F_asyncreads uint64
+ F_fsid Fsid
+ F_namemax uint32
+ F_owner uint32
+ F_ctime uint32
+ F_spare [3]uint32
+ F_fstypename [16]int8
+ F_mntonname [90]int8
+ F_mntfromname [90]int8
+ Pad_cgo_1 [4]byte
+ Mount_info [160]byte
+}
+
+type Flock_t struct {
+ Start int64
+ Len int64
+ Pid int32
+ Type int16
+ Whence int16
+}
+
+type Dirent struct {
+ Fileno uint32
+ Reclen uint16
+ Type uint8
+ Namlen uint8
+ Name [256]int8
+}
+
+type Fsid struct {
+ Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]int8
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [104]int8
+}
+
+type RawSockaddrDatalink struct {
+ Len uint8
+ Family uint8
+ Index uint16
+ Type uint8
+ Nlen uint8
+ Alen uint8
+ Slen uint8
+ Data [24]int8
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint64
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Pad_cgo_0 [4]byte
+ Iov *Iovec
+ Iovlen uint32
+ Pad_cgo_1 [4]byte
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x6c
+ SizeofSockaddrUnix = 0x6a
+ SizeofSockaddrDatalink = 0x20
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x30
+ SizeofCmsghdr = 0xc
+ SizeofInet6Pktinfo = 0x14
+)
+
+const (
+ PTRACE_TRACEME = 0x0
+ PTRACE_CONT = 0x7
+ PTRACE_KILL = 0x8
+)
+
+type Kevent_t struct {
+ Ident uint32
+ Filter int16
+ Flags uint16
+ Fflags uint32
+ Data int32
+ Udata *byte
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+const (
+ SizeofIfMsghdr = 0xf0
+ SizeofIfData = 0xd8
+ SizeofIfaMsghdr = 0x18
+ SizeofRtMsghdr = 0x58
+ SizeofRtMetrics = 0x30
+)
+
+type IfMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Xflags int32
+ Data IfData
+}
+
+type IfData struct {
+ Type uint8
+ Addrlen uint8
+ Hdrlen uint8
+ Link_state uint8
+ Mtu uint32
+ Metric uint32
+ Pad uint32
+ Baudrate uint64
+ Ipackets uint64
+ Ierrors uint64
+ Opackets uint64
+ Oerrors uint64
+ Collisions uint64
+ Ibytes uint64
+ Obytes uint64
+ Imcasts uint64
+ Omcasts uint64
+ Iqdrops uint64
+ Noproto uint64
+ Lastchange Timeval
+ Mclpool [7]Mclpool
+ Pad_cgo_0 [4]byte
+}
+
+type IfaMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Pad1 uint8
+ Pad2 uint8
+ Addrs int32
+ Flags int32
+ Metric int32
+}
+
+type RtMsghdr struct {
+ Msglen uint16
+ Version uint8
+ Type uint8
+ Hdrlen uint16
+ Index uint16
+ Tableid uint16
+ Priority uint8
+ Mpls uint8
+ Addrs int32
+ Flags int32
+ Fmask int32
+ Pid int32
+ Seq int32
+ Errno int32
+ Inits uint32
+ Rmx RtMetrics
+}
+
+type RtMetrics struct {
+ Pksent uint64
+ Locks uint32
+ Mtu uint32
+ Expire uint32
+ Refcnt uint32
+ Hopcount uint32
+ Recvpipe uint32
+ Sendpipe uint32
+ Ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+}
+
+type Mclpool struct {
+ Grown uint32
+ Alive uint16
+ Hwm uint16
+ Cwm uint16
+ Lwm uint16
+}
+
+const (
+ SizeofBpfVersion = 0x4
+ SizeofBpfStat = 0x8
+ SizeofBpfProgram = 0x10
+ SizeofBpfInsn = 0x8
+ SizeofBpfHdr = 0x14
+)
+
+type BpfVersion struct {
+ Major uint16
+ Minor uint16
+}
+
+type BpfStat struct {
+ Recv uint32
+ Drop uint32
+}
+
+type BpfProgram struct {
+ Len uint32
+ Pad_cgo_0 [4]byte
+ Insns *BpfInsn
+}
+
+type BpfInsn struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type BpfHdr struct {
+ Tstamp BpfTimeval
+ Caplen uint32
+ Datalen uint32
+ Hdrlen uint16
+ Pad_cgo_0 [2]byte
+}
+
+type BpfTimeval struct {
+ Sec uint32
+ Usec uint32
+}
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index 07f2b85f0..54168bb98 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -1,19 +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 syscall
const (
// Windows errors.
- ERROR_FILE_NOT_FOUND = 2
- ERROR_PATH_NOT_FOUND = 3
- ERROR_NO_MORE_FILES = 18
- ERROR_BROKEN_PIPE = 109
- ERROR_BUFFER_OVERFLOW = 111
- ERROR_INSUFFICIENT_BUFFER = 122
- ERROR_MOD_NOT_FOUND = 126
- ERROR_PROC_NOT_FOUND = 127
- ERROR_ENVVAR_NOT_FOUND = 203
- ERROR_DIRECTORY = 267
- ERROR_OPERATION_ABORTED = 995
- ERROR_IO_PENDING = 997
+ ERROR_FILE_NOT_FOUND Errno = 2
+ ERROR_PATH_NOT_FOUND Errno = 3
+ ERROR_ACCESS_DENIED Errno = 5
+ ERROR_NO_MORE_FILES Errno = 18
+ ERROR_FILE_EXISTS Errno = 80
+ ERROR_BROKEN_PIPE Errno = 109
+ ERROR_BUFFER_OVERFLOW Errno = 111
+ ERROR_INSUFFICIENT_BUFFER Errno = 122
+ ERROR_MOD_NOT_FOUND Errno = 126
+ ERROR_PROC_NOT_FOUND Errno = 127
+ ERROR_ALREADY_EXISTS Errno = 183
+ ERROR_ENVVAR_NOT_FOUND Errno = 203
+ ERROR_OPERATION_ABORTED Errno = 995
+ ERROR_IO_PENDING Errno = 997
)
const (
@@ -34,27 +40,46 @@ const (
const (
// More invented values for signals
- SIGHUP = 0x1
- SIGINT = 0x2
- SIGQUIT = 0x3
- SIGILL = 0x4
- SIGTRAP = 0x5
- SIGABRT = 0x6
- SIGBUS = 0x7
- SIGFPE = 0x8
- SIGKILL = 0x9
- SIGSEGV = 0xb
- SIGPIPE = 0xd
- SIGALRM = 0xe
- SIGTERM = 0xf
+ SIGHUP = Signal(0x1)
+ SIGINT = Signal(0x2)
+ SIGQUIT = Signal(0x3)
+ SIGILL = Signal(0x4)
+ SIGTRAP = Signal(0x5)
+ SIGABRT = Signal(0x6)
+ SIGBUS = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGKILL = Signal(0x9)
+ SIGSEGV = Signal(0xb)
+ SIGPIPE = Signal(0xd)
+ SIGALRM = Signal(0xe)
+ SIGTERM = Signal(0xf)
)
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+}
+
const (
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
+ FILE_LIST_DIRECTORY = 0x00000001
FILE_APPEND_DATA = 0x00000004
FILE_WRITE_ATTRIBUTES = 0x00000100
@@ -76,6 +101,9 @@ const (
OPEN_ALWAYS = 4
TRUNCATE_EXISTING = 5
+ FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
+ FILE_FLAG_OVERLAPPED = 0x40000000
+
HANDLE_FLAG_INHERIT = 0x00000001
STARTF_USESTDHANDLES = 0x00000100
STARTF_USESHOWWINDOW = 0x00000001
@@ -90,6 +118,9 @@ const (
FILE_CURRENT = 1
FILE_END = 2
+ LANG_ENGLISH = 0x09
+ SUBLANG_ENGLISH_US = 0x01
+
FORMAT_MESSAGE_ALLOCATE_BUFFER = 256
FORMAT_MESSAGE_IGNORE_INSERTS = 512
FORMAT_MESSAGE_FROM_STRING = 1024
@@ -117,7 +148,6 @@ const (
CREATE_UNICODE_ENVIRONMENT = 0x00000400
- STANDARD_RIGHTS_READ = 0x00020000
PROCESS_QUERY_INFORMATION = 0x00000400
SYNCHRONIZE = 0x00100000
@@ -135,6 +165,26 @@ const (
)
const (
+ // do not reorder
+ FILE_NOTIFY_CHANGE_FILE_NAME = 1 << iota
+ FILE_NOTIFY_CHANGE_DIR_NAME
+ FILE_NOTIFY_CHANGE_ATTRIBUTES
+ FILE_NOTIFY_CHANGE_SIZE
+ FILE_NOTIFY_CHANGE_LAST_WRITE
+ FILE_NOTIFY_CHANGE_LAST_ACCESS
+ FILE_NOTIFY_CHANGE_CREATION
+)
+
+const (
+ // do not reorder
+ FILE_ACTION_ADDED = iota + 1
+ FILE_ACTION_REMOVED
+ FILE_ACTION_MODIFIED
+ FILE_ACTION_RENAMED_OLD_NAME
+ FILE_ACTION_RENAMED_NEW_NAME
+)
+
+const (
// wincrypt.h
PROV_RSA_FULL = 1
PROV_RSA_SIG = 2
@@ -160,6 +210,63 @@ const (
CRYPT_MACHINE_KEYSET = 0x00000020
CRYPT_SILENT = 0x00000040
CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
+
+ USAGE_MATCH_TYPE_AND = 0
+ USAGE_MATCH_TYPE_OR = 1
+
+ X509_ASN_ENCODING = 0x00000001
+ PKCS_7_ASN_ENCODING = 0x00010000
+
+ CERT_STORE_PROV_MEMORY = 2
+
+ CERT_STORE_ADD_ALWAYS = 4
+
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004
+
+ CERT_TRUST_NO_ERROR = 0x00000000
+ CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001
+ CERT_TRUST_IS_REVOKED = 0x00000004
+ CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010
+ CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040
+ CERT_TRUST_IS_CYCLIC = 0x00000080
+ CERT_TRUST_INVALID_EXTENSION = 0x00000100
+ CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400
+ CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800
+ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000
+ CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000
+ CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000
+ CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000
+ CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000
+ CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000
+
+ CERT_CHAIN_POLICY_BASE = 1
+ CERT_CHAIN_POLICY_AUTHENTICODE = 2
+ CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3
+ CERT_CHAIN_POLICY_SSL = 4
+ CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5
+ CERT_CHAIN_POLICY_NT_AUTH = 6
+ CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7
+ CERT_CHAIN_POLICY_EV = 8
+
+ CERT_E_EXPIRED = 0x800B0101
+ CERT_E_ROLE = 0x800B0103
+ CERT_E_PURPOSE = 0x800B0106
+ CERT_E_UNTRUSTEDROOT = 0x800B0109
+ CERT_E_CN_NO_MATCH = 0x800B010F
+
+ AUTHTYPE_CLIENT = 1
+ AUTHTYPE_SERVER = 2
+)
+
+var (
+ OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00")
+ OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00")
+ OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00")
)
// Invented values to support what package os expects.
@@ -192,11 +299,20 @@ type Overlapped struct {
HEvent Handle
}
+type FileNotifyInformation struct {
+ NextEntryOffset uint32
+ Action uint32
+ FileNameLength uint32
+ FileName uint16
+}
+
type Filetime struct {
LowDateTime uint32
HighDateTime uint32
}
+// Nanoseconds returns Filetime ft in nanoseconds
+// since Epoch (00:00:00 UTC, January 1, 1970).
func (ft *Filetime) Nanoseconds() int64 {
// 100-nanosecond intervals since January 1, 1601
nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
@@ -244,6 +360,20 @@ type ByHandleFileInformation struct {
FileIndexLow uint32
}
+const (
+ GetFileExInfoStandard = 0
+ GetFileExMaxInfoLevel = 1
+)
+
+type Win32FileAttributeData struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ FileSizeHigh uint32
+ FileSizeLow uint32
+}
+
// ShowWindow constants
const (
// winuser.h
@@ -291,12 +421,6 @@ type ProcessInformation struct {
ThreadId uint32
}
-// Invented values to support what package os expects.
-type Stat_t struct {
- Windata Win32finddata
- Mode uint32
-}
-
type Systemtime struct {
Year uint16
Month uint16
@@ -332,9 +456,10 @@ const (
SOCK_RAW = 3
SOCK_SEQPACKET = 5
- IPPROTO_IP = 0
- IPPROTO_TCP = 6
- IPPROTO_UDP = 17
+ IPPROTO_IP = 0
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 17
SOL_SOCKET = 0xffff
SO_REUSEADDR = 4
@@ -346,10 +471,25 @@ const (
SO_SNDBUF = 0x1001
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
- IPPROTO_IPV6 = 0x29
- IPV6_V6ONLY = 0x1b
+ // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
+
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_LOOP = 0xb
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_DROP_MEMBERSHIP = 0xd
+
+ IPV6_V6ONLY = 0x1b
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
- SOMAXCONN = 5
+ SOMAXCONN = 0x7fffffff
TCP_NODELAY = 1
@@ -401,6 +541,12 @@ type Hostent struct {
AddrList **byte
}
+type Protoent struct {
+ Name *byte
+ Aliases **byte
+ Proto uint16
+}
+
const (
DNS_TYPE_A = 0x0001
DNS_TYPE_NS = 0x0002
@@ -484,6 +630,11 @@ type DNSMXData struct {
Pad uint16
}
+type DNSTXTData struct {
+ StringCount uint16
+ StringArray [1]*uint16
+}
+
type DNSRecord struct {
Next *DNSRecord
Name *uint16
@@ -601,3 +752,140 @@ type MibIfRow struct {
DescrLen uint32
Descr [MAXLEN_IFDESCR]byte
}
+
+type CertContext struct {
+ EncodingType uint32
+ EncodedCert *byte
+ Length uint32
+ CertInfo uintptr
+ Store Handle
+}
+
+type CertChainContext struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ ChainCount uint32
+ Chains **CertSimpleChain
+ LowerQualityChainCount uint32
+ LowerQualityChains **CertChainContext
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertSimpleChain struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ NumElements uint32
+ Elements **CertChainElement
+ TrustListInfo uintptr
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertChainElement struct {
+ Size uint32
+ CertContext *CertContext
+ TrustStatus CertTrustStatus
+ RevocationInfo *CertRevocationInfo
+ IssuanceUsage *CertEnhKeyUsage
+ ApplicationUsage *CertEnhKeyUsage
+ ExtendedErrorInfo *uint16
+}
+
+type CertRevocationInfo struct {
+ Size uint32
+ RevocationResult uint32
+ RevocationOid *byte
+ OidSpecificInfo uintptr
+ HasFreshnessTime uint32
+ FreshnessTime uint32
+ CrlInfo uintptr // *CertRevocationCrlInfo
+}
+
+type CertTrustStatus struct {
+ ErrorStatus uint32
+ InfoStatus uint32
+}
+
+type CertUsageMatch struct {
+ Type uint32
+ Usage CertEnhKeyUsage
+}
+
+type CertEnhKeyUsage struct {
+ Length uint32
+ UsageIdentifiers **byte
+}
+
+type CertChainPara struct {
+ Size uint32
+ RequestedUsage CertUsageMatch
+ RequstedIssuancePolicy CertUsageMatch
+ URLRetrievalTimeout uint32
+ CheckRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+ CacheResync *Filetime
+}
+
+type CertChainPolicyPara struct {
+ Size uint32
+ Flags uint32
+ ExtraPolicyPara uintptr
+}
+
+type SSLExtraCertChainPolicyPara struct {
+ Size uint32
+ AuthType uint32
+ Checks uint32
+ ServerName *uint16
+}
+
+type CertChainPolicyStatus struct {
+ Size uint32
+ Error uint32
+ ChainIndex uint32
+ ElementIndex uint32
+ ExtraPolicyStatus uintptr
+}
+
+const (
+ // do not reorder
+ HKEY_CLASSES_ROOT = 0x80000000 + iota
+ HKEY_CURRENT_USER
+ HKEY_LOCAL_MACHINE
+ HKEY_USERS
+ HKEY_PERFORMANCE_DATA
+ HKEY_CURRENT_CONFIG
+ HKEY_DYN_DATA
+
+ KEY_QUERY_VALUE = 1
+ KEY_SET_VALUE = 2
+ KEY_CREATE_SUB_KEY = 4
+ KEY_ENUMERATE_SUB_KEYS = 8
+ KEY_NOTIFY = 16
+ KEY_CREATE_LINK = 32
+ KEY_WRITE = 0x20006
+ KEY_EXECUTE = 0x20019
+ KEY_READ = 0x20019
+ KEY_WOW64_64KEY = 0x0100
+ KEY_WOW64_32KEY = 0x0200
+ KEY_ALL_ACCESS = 0xf003f
+)
+
+const (
+ // do not reorder
+ REG_NONE = iota
+ REG_SZ
+ REG_EXPAND_SZ
+ REG_BINARY
+ REG_DWORD_LITTLE_ENDIAN
+ REG_DWORD_BIG_ENDIAN
+ REG_LINK
+ REG_MULTI_SZ
+ REG_RESOURCE_LIST
+ REG_FULL_RESOURCE_DESCRIPTOR
+ REG_RESOURCE_REQUIREMENTS_LIST
+ REG_QWORD_LITTLE_ENDIAN
+ REG_DWORD = REG_DWORD_LITTLE_ENDIAN
+ REG_QWORD = REG_QWORD_LITTLE_ENDIAN
+)
diff --git a/src/pkg/syslog/Makefile b/src/pkg/syslog/Makefile
deleted file mode 100644
index 82baf7253..000000000
--- a/src/pkg/syslog/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=syslog
-GOFILES=\
- syslog.go\
- syslog_unix.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/tabwriter/Makefile b/src/pkg/tabwriter/Makefile
deleted file mode 100644
index bdc888784..000000000
--- a/src/pkg/tabwriter/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=tabwriter
-GOFILES=\
- tabwriter.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/template/Makefile b/src/pkg/template/Makefile
deleted file mode 100644
index 3ed3b0330..000000000
--- a/src/pkg/template/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2011 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.inc
-
-TARG=template
-GOFILES=\
- exec.go\
- funcs.go\
- helper.go\
- parse.go\
- set.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/template/helper.go b/src/pkg/template/helper.go
deleted file mode 100644
index c9b099856..000000000
--- a/src/pkg/template/helper.go
+++ /dev/null
@@ -1,238 +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.
-
-// 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/src/pkg/template/parse.go b/src/pkg/template/parse.go
deleted file mode 100644
index b089c599a..000000000
--- a/src/pkg/template/parse.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package template
-
-import (
- "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/src/pkg/template/parse/Makefile b/src/pkg/template/parse/Makefile
deleted file mode 100644
index fe6585809..000000000
--- a/src/pkg/template/parse/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../../Make.inc
-
-TARG=template/parse
-GOFILES=\
- lex.go\
- node.go\
- parse.go\
- set.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/template/parse/set.go b/src/pkg/template/parse/set.go
deleted file mode 100644
index dca41ea76..000000000
--- a/src/pkg/template/parse/set.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 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/src/pkg/template/set.go b/src/pkg/template/set.go
deleted file mode 100644
index f778fd169..000000000
--- a/src/pkg/template/set.go
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package template
-
-import (
- "fmt"
- "io"
- "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/src/pkg/template/set_test.go b/src/pkg/template/set_test.go
deleted file mode 100644
index f437bc779..000000000
--- a/src/pkg/template/set_test.go
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package template
-
-import (
- "fmt"
- "testing"
-)
-
-const (
- noError = true
- hasError = false
-)
-
-type setParseTest struct {
- name string
- input string
- ok bool
- names []string
- results []string
-}
-
-var setParseTests = []setParseTest{
- {"empty", "", noError,
- nil,
- nil},
- {"one", `{{define "foo"}} FOO {{end}}`, noError,
- []string{"foo"},
- []string{`[(text: " FOO ")]`}},
- {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
- []string{"foo", "bar"},
- []string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
- // errors
- {"missing end", `{{define "foo"}} FOO `, hasError,
- nil,
- nil},
- {"malformed name", `{{define "foo}} FOO `, hasError,
- nil,
- nil},
-}
-
-func TestSetParse(t *testing.T) {
- for _, test := range setParseTests {
- set, err := new(Set).Parse(test.input)
- switch {
- case err == nil && !test.ok:
- t.Errorf("%q: expected error; got none", test.name)
- continue
- case err != nil && test.ok:
- t.Errorf("%q: unexpected error: %v", test.name, err)
- continue
- case err != nil && !test.ok:
- // expected error, got one
- if *debug {
- fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
- }
- continue
- }
- if set == nil {
- continue
- }
- if len(set.tmpl) != len(test.names) {
- t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
- continue
- }
- for i, name := range test.names {
- tmpl, ok := set.tmpl[name]
- if !ok {
- t.Errorf("%s: can't find template %q", test.name, name)
- continue
- }
- result := tmpl.Root.String()
- if result != test.results[i] {
- t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
- }
- }
- }
-}
-
-var setExecTests = []execTest{
- {"empty", "", "", nil, true},
- {"text", "some text", "some text", nil, true},
- {"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
- {"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
- {"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
- {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
- {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
- {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
- {"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
-
- // User-defined function: test argument evaluator.
- {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
- {"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
-}
-
-// These strings are also in testdata/*.
-const setText1 = `
- {{define "x"}}TEXT{{end}}
- {{define "dotV"}}{{.V}}{{end}}
-`
-
-const setText2 = `
- {{define "dot"}}{{.}}{{end}}
- {{define "nested"}}{{template "dot" .}}{{end}}
-`
-
-func TestSetExecute(t *testing.T) {
- // Declare a set with a couple of templates first.
- set := new(Set)
- _, err := set.Parse(setText1)
- if err != nil {
- t.Fatalf("error parsing set: %s", err)
- }
- _, err = set.Parse(setText2)
- if err != nil {
- t.Fatalf("error parsing set: %s", err)
- }
- testExecute(setExecTests, set, t)
-}
-
-func TestSetParseFiles(t *testing.T) {
- set := new(Set)
- _, err := set.ParseFiles("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- _, err = set.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(setExecTests, set, t)
-}
-
-func TestParseSetFiles(t *testing.T) {
- set := new(Set)
- _, err := ParseSetFiles("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- set, err = ParseSetFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(setExecTests, set, t)
-}
-
-func TestSetParseGlob(t *testing.T) {
- _, err := new(Set).ParseGlob("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- _, err = new(Set).ParseGlob("[x")
- if err == nil {
- t.Error("expected error for bad pattern; got none")
- }
- set, err := new(Set).ParseGlob("testdata/file*.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(setExecTests, set, t)
-}
-
-func TestParseSetGlob(t *testing.T) {
- _, err := ParseSetGlob("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- _, err = ParseSetGlob("[x")
- if err == nil {
- t.Error("expected error for bad pattern; got none")
- }
- set, err := ParseSetGlob("testdata/file*.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(setExecTests, set, t)
-}
-
-var templateFileExecTests = []execTest{
- {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
-}
-
-func TestSetParseTemplateFiles(t *testing.T) {
- _, err := ParseTemplateFiles("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(templateFileExecTests, set, t)
-}
-
-func TestParseTemplateFiles(t *testing.T) {
- _, err := ParseTemplateFiles("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(templateFileExecTests, set, t)
-}
-
-func TestSetParseTemplateGlob(t *testing.T) {
- _, err := ParseTemplateGlob("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- _, err = new(Set).ParseTemplateGlob("[x")
- if err == nil {
- t.Error("expected error for bad pattern; got none")
- }
- set, err := new(Set).ParseTemplateGlob("testdata/tmpl*.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(templateFileExecTests, set, t)
-}
-
-func TestParseTemplateGlob(t *testing.T) {
- _, err := ParseTemplateGlob("DOES NOT EXIST")
- if err == nil {
- t.Error("expected error for non-existent file; got none")
- }
- _, err = ParseTemplateGlob("[x")
- if err == nil {
- t.Error("expected error for bad pattern; got none")
- }
- set, err := ParseTemplateGlob("testdata/tmpl*.tmpl")
- if err != nil {
- t.Fatalf("error parsing files: %v", err)
- }
- testExecute(templateFileExecTests, set, t)
-}
diff --git a/src/pkg/template/testdata/tmpl1.tmpl b/src/pkg/template/testdata/tmpl1.tmpl
deleted file mode 100644
index 3d15b8173..000000000
--- a/src/pkg/template/testdata/tmpl1.tmpl
+++ /dev/null
@@ -1 +0,0 @@
-template1
diff --git a/src/pkg/template/testdata/tmpl2.tmpl b/src/pkg/template/testdata/tmpl2.tmpl
deleted file mode 100644
index a374d2fe7..000000000
--- a/src/pkg/template/testdata/tmpl2.tmpl
+++ /dev/null
@@ -1 +0,0 @@
-template2
diff --git a/src/pkg/testing/Makefile b/src/pkg/testing/Makefile
deleted file mode 100644
index 9e8bd1756..000000000
--- a/src/pkg/testing/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=testing
-GOFILES=\
- benchmark.go\
- testing.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index fd0bd8665..41290594e 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -16,7 +16,7 @@ var matchBenchmarks = flag.String("test.bench", "", "regular expression to selec
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.
+// of the "go test" command.
type InternalBenchmark struct {
Name string
F func(b *B)
@@ -25,19 +25,21 @@ type InternalBenchmark struct {
// B is a type passed to Benchmark functions to manage benchmark
// timing and to specify the number of iterations to run.
type B struct {
+ common
N int
benchmark InternalBenchmark
- ns int64
bytes int64
- start int64
+ timerOn bool
+ result BenchmarkResult
}
// StartTimer starts timing a test. This function is called automatically
// before a benchmark starts, but it can also used to resume timing after
// a call to StopTimer.
func (b *B) StartTimer() {
- if b.start == 0 {
- b.start = time.Nanoseconds()
+ if !b.timerOn {
+ b.start = time.Now()
+ b.timerOn = true
}
}
@@ -45,19 +47,19 @@ func (b *B) StartTimer() {
// while performing complex initialization that you don't
// want to measure.
func (b *B) StopTimer() {
- if b.start > 0 {
- b.ns += time.Nanoseconds() - b.start
+ if b.timerOn {
+ b.duration += time.Now().Sub(b.start)
+ b.timerOn = false
}
- b.start = 0
}
// ResetTimer sets the elapsed benchmark time to zero.
// It does not affect whether the timer is running.
func (b *B) ResetTimer() {
- if b.start > 0 {
- b.start = time.Nanoseconds()
+ if b.timerOn {
+ b.start = time.Now()
}
- b.ns = 0
+ b.duration = 0
}
// SetBytes records the number of bytes processed in a single operation.
@@ -68,7 +70,7 @@ func (b *B) nsPerOp() int64 {
if b.N <= 0 {
return 0
}
- return b.ns / int64(b.N)
+ return b.duration.Nanoseconds() / int64(b.N)
}
// runN runs a single benchmark for the specified number of iterations.
@@ -125,23 +127,38 @@ func roundUp(n int) int {
return 10 * base
}
-// run times the benchmark function. It gradually increases the number
+// run times the benchmark function in a separate goroutine.
+func (b *B) run() BenchmarkResult {
+ go b.launch()
+ <-b.signal
+ return b.result
+}
+
+// launch launches the benchmark function. It gradually increases the number
// of benchmark iterations until the benchmark runs for a second in order
// to get a reasonable measurement. It prints timing information in this form
// testing.BenchmarkHello 100000 19 ns/op
-func (b *B) run() BenchmarkResult {
+// launch is run by the fun function as a separate goroutine.
+func (b *B) launch() {
// Run the benchmark for a single iteration in case it's expensive.
n := 1
+
+ // Signal that we're done whether we return normally
+ // or by FailNow's runtime.Goexit.
+ defer func() {
+ b.signal <- b
+ }()
+
b.runN(n)
// Run the benchmark for at least the specified amount of time.
- time := int64(*benchTime * 1e9)
- for b.ns < time && n < 1e9 {
+ d := time.Duration(*benchTime * float64(time.Second))
+ for !b.failed && b.duration < d && n < 1e9 {
last := n
// Predict iterations/sec.
if b.nsPerOp() == 0 {
n = 1e9
} else {
- n = int(time / b.nsPerOp())
+ n = int(d.Nanoseconds() / b.nsPerOp())
}
// Run more iterations than we think we'll need for a second (1.5x).
// Don't grow too fast in case we had timing errors previously.
@@ -151,28 +168,28 @@ func (b *B) run() BenchmarkResult {
n = roundUp(n)
b.runN(n)
}
- return BenchmarkResult{b.N, b.ns, b.bytes}
+ b.result = BenchmarkResult{b.N, b.duration, 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 // Bytes processed in one iteration.
+ N int // The number of iterations.
+ T time.Duration // The total time taken.
+ Bytes int64 // Bytes processed in one iteration.
}
func (r BenchmarkResult) NsPerOp() int64 {
if r.N <= 0 {
return 0
}
- return r.Ns / int64(r.N)
+ return r.T.Nanoseconds() / int64(r.N)
}
func (r BenchmarkResult) mbPerSec() float64 {
- if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 {
+ if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 {
return 0
}
- return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3
+ return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
}
func (r BenchmarkResult) String() string {
@@ -187,17 +204,17 @@ func (r BenchmarkResult) String() string {
// The format specifiers here make sure that
// the ones digits line up for all three possible formats.
if nsop < 10 {
- ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N))
+ ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
} else {
- ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
+ ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
}
}
return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
}
// An internal function but exported because it is cross-package; part of the implementation
-// of gotest.
-func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmarks []InternalBenchmark) {
+// of the "go test" command.
+func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
// If no flag was specified, don't run benchmarks.
if len(*matchBenchmarks) == 0 {
return
@@ -205,7 +222,7 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
for _, Benchmark := range benchmarks {
matched, err := matchString(*matchBenchmarks, Benchmark.Name)
if err != nil {
- println("invalid regexp for -test.bench:", err.String())
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
os.Exit(1)
}
if !matched {
@@ -213,24 +230,64 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
}
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
- b := &B{benchmark: Benchmark}
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: Benchmark,
+ }
benchName := Benchmark.Name
if procs != 1 {
benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
}
- print(fmt.Sprintf("%s\t", benchName))
+ fmt.Printf("%s\t", benchName)
r := b.run()
- print(fmt.Sprintf("%v\n", r))
+ if b.failed {
+ // The output could be very long here, but probably isn't.
+ // We print it all, regardless, because we don't want to trim the reason
+ // the benchmark failed.
+ fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
+ continue
+ }
+ fmt.Printf("%v\n", r)
+ // Unlike with tests, we ignore the -chatty flag and always print output for
+ // benchmarks since the output generation time will skew the results.
+ if len(b.output) > 0 {
+ b.trimOutput()
+ fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
+ }
if p := runtime.GOMAXPROCS(-1); p != procs {
- print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+ fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
+ }
+ }
+ }
+}
+
+// trimOutput shortens the output from a benchmark, which can be very long.
+func (b *B) trimOutput() {
+ // The output is likely to appear multiple times because the benchmark
+ // is run multiple times, but at least it will be seen. This is not a big deal
+ // because benchmarks rarely print, but just in case, we trim it if it's too long.
+ const maxNewlines = 10
+ for nlCount, j := 0, 0; j < len(b.output); j++ {
+ if b.output[j] == '\n' {
+ nlCount++
+ if nlCount >= maxNewlines {
+ b.output = append(b.output[:j], "\n\t... [output truncated]\n"...)
+ break
}
}
}
}
// Benchmark benchmarks a single function. Useful for creating
-// custom benchmarks that do not use gotest.
+// custom benchmarks that do not use the "go test" command.
func Benchmark(f func(b *B)) BenchmarkResult {
- b := &B{benchmark: InternalBenchmark{"", f}}
+ b := &B{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ benchmark: InternalBenchmark{"", f},
+ }
return b.run()
}
diff --git a/src/pkg/testing/example.go b/src/pkg/testing/example.go
new file mode 100644
index 000000000..671c79876
--- /dev/null
+++ b/src/pkg/testing/example.go
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "time"
+)
+
+type InternalExample struct {
+ Name string
+ F func()
+ Output string
+}
+
+func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
+ ok = true
+
+ var eg InternalExample
+
+ stdout, stderr := os.Stdout, os.Stderr
+
+ for _, eg = range examples {
+ matched, err := matchString(*match, eg.Name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
+ if *chatty {
+ fmt.Printf("=== RUN: %s\n", eg.Name)
+ }
+
+ // capture stdout and stderr
+ r, w, err := os.Pipe()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ os.Stdout, os.Stderr = w, w
+ outC := make(chan string)
+ go func() {
+ buf := new(bytes.Buffer)
+ _, err := io.Copy(buf, r)
+ if err != nil {
+ fmt.Fprintf(stderr, "testing: copying pipe: %v\n", err)
+ os.Exit(1)
+ }
+ outC <- buf.String()
+ }()
+
+ // run example
+ t0 := time.Now()
+ eg.F()
+ dt := time.Now().Sub(t0)
+
+ // close pipe, restore stdout/stderr, get output
+ w.Close()
+ os.Stdout, os.Stderr = stdout, stderr
+ out := <-outC
+
+ // report any errors
+ tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
+ if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
+ fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
+ eg.Name, tstr, g, e)
+ ok = false
+ } else if *chatty {
+ fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
+ }
+ }
+
+ return
+}
diff --git a/src/pkg/testing/iotest/Makefile b/src/pkg/testing/iotest/Makefile
deleted file mode 100644
index 43a047cc9..000000000
--- a/src/pkg/testing/iotest/Makefile
+++ /dev/null
@@ -1,13 +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.
-
-include ../../../Make.inc
-
-TARG=testing/iotest
-GOFILES=\
- logger.go\
- reader.go\
- writer.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/testing/iotest/logger.go b/src/pkg/testing/iotest/logger.go
index c3bf5df3c..1475d9b0c 100644
--- a/src/pkg/testing/iotest/logger.go
+++ b/src/pkg/testing/iotest/logger.go
@@ -7,7 +7,6 @@ package iotest
import (
"io"
"log"
- "os"
)
type writeLogger struct {
@@ -15,7 +14,7 @@ type writeLogger struct {
w io.Writer
}
-func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
+func (l *writeLogger) Write(p []byte) (n int, err error) {
n, err = l.w.Write(p)
if err != nil {
log.Printf("%s %x: %v", l.prefix, p[0:n], err)
@@ -37,7 +36,7 @@ type readLogger struct {
r io.Reader
}
-func (l *readLogger) Read(p []byte) (n int, err os.Error) {
+func (l *readLogger) Read(p []byte) (n int, err error) {
n, err = l.r.Read(p)
if err != nil {
log.Printf("%s %x: %v", l.prefix, p[0:n], err)
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
index dcf5565e0..441b9102d 100644
--- a/src/pkg/testing/iotest/reader.go
+++ b/src/pkg/testing/iotest/reader.go
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package iotest implements Readers and Writers useful only for testing.
+// Package iotest implements Readers and Writers useful mainly for testing.
package iotest
import (
+ "errors"
"io"
- "os"
)
// OneByteReader returns a Reader that implements
@@ -18,7 +18,7 @@ type oneByteReader struct {
r io.Reader
}
-func (r *oneByteReader) Read(p []byte) (int, os.Error) {
+func (r *oneByteReader) Read(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}
@@ -33,7 +33,7 @@ type halfReader struct {
r io.Reader
}
-func (r *halfReader) Read(p []byte) (int, os.Error) {
+func (r *halfReader) Read(p []byte) (int, error) {
return r.r.Read(p[0 : (len(p)+1)/2])
}
@@ -48,7 +48,7 @@ type dataErrReader struct {
data []byte
}
-func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
+func (r *dataErrReader) Read(p []byte) (n int, err error) {
// loop because first call needs two reads:
// one to get data and a second to look for an error.
for {
@@ -66,7 +66,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
return
}
-var ErrTimeout = os.NewError("timeout")
+var ErrTimeout = errors.New("timeout")
// TimeoutReader returns ErrTimeout on the second read
// with no data. Subsequent calls to read succeed.
@@ -77,7 +77,7 @@ type timeoutReader struct {
count int
}
-func (r *timeoutReader) Read(p []byte) (int, os.Error) {
+func (r *timeoutReader) Read(p []byte) (int, error) {
r.count++
if r.count == 2 {
return 0, ErrTimeout
diff --git a/src/pkg/testing/iotest/writer.go b/src/pkg/testing/iotest/writer.go
index 71f504ce2..af61ab858 100644
--- a/src/pkg/testing/iotest/writer.go
+++ b/src/pkg/testing/iotest/writer.go
@@ -4,10 +4,7 @@
package iotest
-import (
- "io"
- "os"
-)
+import "io"
// TruncateWriter returns a Writer that writes to w
// but stops silently after n bytes.
@@ -20,7 +17,7 @@ type truncateWriter struct {
n int64
}
-func (t *truncateWriter) Write(p []byte) (n int, err os.Error) {
+func (t *truncateWriter) Write(p []byte) (n int, err error) {
if t.n <= 0 {
return len(p), nil
}
diff --git a/src/pkg/testing/quick/Makefile b/src/pkg/testing/quick/Makefile
deleted file mode 100644
index 6d3b736b0..000000000
--- a/src/pkg/testing/quick/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=testing/quick
-GOFILES=\
- quick.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/testing/quick/quick.go b/src/pkg/testing/quick/quick.go
index 756a60e13..242709822 100644
--- a/src/pkg/testing/quick/quick.go
+++ b/src/pkg/testing/quick/quick.go
@@ -9,8 +9,7 @@ import (
"flag"
"fmt"
"math"
- "os"
- "rand"
+ "math/rand"
"reflect"
"strings"
)
@@ -51,7 +50,7 @@ const complexSize = 50
// Value returns an arbitrary value of the given type.
// If the type implements the Generator interface, that will be used.
-// Note: in order to create arbitrary values for structs, all the members must be public.
+// Note: To create arbitrary values for structs, all the fields must be exported.
func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
if m, ok := reflect.Zero(t).Interface().(Generator); ok {
return m.Generate(rand, complexSize), true
@@ -123,9 +122,9 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
return s, true
case reflect.String:
numChars := rand.Intn(complexSize)
- codePoints := make([]int, numChars)
+ codePoints := make([]rune, numChars)
for i := 0; i < numChars; i++ {
- codePoints[i] = rand.Intn(0x10ffff)
+ codePoints[i] = rune(rand.Intn(0x10ffff))
}
return reflect.ValueOf(string(codePoints)), true
case reflect.Struct:
@@ -156,9 +155,10 @@ type Config struct {
// If non-nil, rand is a source of random numbers. Otherwise a default
// pseudo-random source will be used.
Rand *rand.Rand
- // If non-nil, Values is a function which generates a slice of arbitrary
- // Values that are congruent with the arguments to the function being
- // tested. Otherwise, Values is used to generate the values.
+ // If non-nil, the Values function generates a slice of arbitrary
+ // reflect.Values that are congruent with the arguments to the function
+ // being tested. Otherwise, the top-level Values function is used
+ // to generate them.
Values func([]reflect.Value, *rand.Rand)
}
@@ -191,7 +191,7 @@ func (c *Config) getMaxCount() (maxCount int) {
// used, independent of the functions being tested.
type SetupError string
-func (s SetupError) String() string { return string(s) }
+func (s SetupError) Error() string { return string(s) }
// A CheckError is the result of Check finding an error.
type CheckError struct {
@@ -199,7 +199,7 @@ type CheckError struct {
In []interface{}
}
-func (s *CheckError) String() string {
+func (s *CheckError) Error() string {
return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
}
@@ -210,7 +210,7 @@ type CheckEqualError struct {
Out2 []interface{}
}
-func (s *CheckEqualError) String() string {
+func (s *CheckEqualError) Error() string {
return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
}
@@ -229,7 +229,7 @@ func (s *CheckEqualError) String() string {
// t.Error(err)
// }
// }
-func Check(function interface{}, config *Config) (err os.Error) {
+func Check(function interface{}, config *Config) (err error) {
if config == nil {
config = &defaultConfig
}
@@ -272,7 +272,7 @@ func Check(function interface{}, config *Config) (err os.Error) {
// It calls f and g repeatedly with arbitrary values for each argument.
// If f and g return different answers, CheckEqual returns a *CheckEqualError
// describing the input and the outputs.
-func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
+func CheckEqual(f, g interface{}, config *Config) (err error) {
if config == nil {
config = &defaultConfig
}
@@ -317,7 +317,7 @@ func CheckEqual(f, g interface{}, config *Config) (err os.Error) {
// arbitraryValues writes Values to args such that args contains Values
// suitable for calling f.
-func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err os.Error) {
+func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err error) {
if config.Values != nil {
config.Values(args, rand)
return
diff --git a/src/pkg/testing/quick/quick_test.go b/src/pkg/testing/quick/quick_test.go
index f2618c3c2..a6cf0dc39 100644
--- a/src/pkg/testing/quick/quick_test.go
+++ b/src/pkg/testing/quick/quick_test.go
@@ -5,10 +5,9 @@
package quick
import (
- "rand"
+ "math/rand"
"reflect"
"testing"
- "os"
)
func fBool(a bool) bool { return a }
@@ -63,7 +62,7 @@ func fIntptr(a *int) *int {
return &b
}
-func reportError(property string, err os.Error, t *testing.T) {
+func reportError(property string, err error, t *testing.T) {
if err != nil {
t.Errorf("%s: %s", property, err)
}
diff --git a/src/pkg/testing/script/Makefile b/src/pkg/testing/script/Makefile
deleted file mode 100644
index 9388d972b..000000000
--- a/src/pkg/testing/script/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../../Make.inc
-
-TARG=testing/script
-GOFILES=\
- script.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/testing/script/script.go b/src/pkg/testing/script/script.go
deleted file mode 100644
index afb286f5b..000000000
--- a/src/pkg/testing/script/script.go
+++ /dev/null
@@ -1,359 +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 script aids in the testing of code that uses channels.
-package script
-
-import (
- "fmt"
- "os"
- "rand"
- "reflect"
- "strings"
-)
-
-// An Event is an element in a partially ordered set that either sends a value
-// to a channel or expects a value from a channel.
-type Event struct {
- name string
- occurred bool
- predecessors []*Event
- action action
-}
-
-type action interface {
- // getSend returns nil if the action is not a send action.
- getSend() sendAction
- // getRecv returns nil if the action is not a receive action.
- getRecv() recvAction
- // getChannel returns the channel that the action operates on.
- getChannel() interface{}
-}
-
-type recvAction interface {
- recvMatch(interface{}) bool
-}
-
-type sendAction interface {
- send()
-}
-
-// isReady returns true if all the predecessors of an Event have occurred.
-func (e Event) isReady() bool {
- for _, predecessor := range e.predecessors {
- if !predecessor.occurred {
- return false
- }
- }
-
- return true
-}
-
-// A Recv action reads a value from a channel and uses reflect.DeepMatch to
-// compare it with an expected value.
-type Recv struct {
- Channel interface{}
- Expected interface{}
-}
-
-func (r Recv) getRecv() recvAction { return r }
-
-func (Recv) getSend() sendAction { return nil }
-
-func (r Recv) getChannel() interface{} { return r.Channel }
-
-func (r Recv) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return reflect.DeepEqual(c.value, r.Expected)
-}
-
-// A RecvMatch action reads a value from a channel and calls a function to
-// determine if the value matches.
-type RecvMatch struct {
- Channel interface{}
- Match func(interface{}) bool
-}
-
-func (r RecvMatch) getRecv() recvAction { return r }
-
-func (RecvMatch) getSend() sendAction { return nil }
-
-func (r RecvMatch) getChannel() interface{} { return r.Channel }
-
-func (r RecvMatch) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelRecv)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return r.Match(c.value)
-}
-
-// A Closed action matches if the given channel is closed. The closing is
-// treated as an event, not a state, thus Closed will only match once for a
-// given channel.
-type Closed struct {
- Channel interface{}
-}
-
-func (r Closed) getRecv() recvAction { return r }
-
-func (Closed) getSend() sendAction { return nil }
-
-func (r Closed) getChannel() interface{} { return r.Channel }
-
-func (r Closed) recvMatch(chanEvent interface{}) bool {
- c, ok := chanEvent.(channelClosed)
- if !ok || c.channel != r.Channel {
- return false
- }
-
- return true
-}
-
-// A Send action sends a value to a channel. The value must match the
-// type of the channel exactly unless the channel if of type chan interface{}.
-type Send struct {
- Channel interface{}
- Value interface{}
-}
-
-func (Send) getRecv() recvAction { return nil }
-
-func (s Send) getSend() sendAction { return s }
-
-func (s Send) getChannel() interface{} { return s.Channel }
-
-type empty struct {
- x interface{}
-}
-
-func newEmptyInterface(e empty) reflect.Value {
- return reflect.ValueOf(e).Field(0)
-}
-
-func (s Send) send() {
- // With reflect.ChanValue.Send, we must match the types exactly. So, if
- // s.Channel is a chan interface{} we convert s.Value to an interface{}
- // first.
- c := reflect.ValueOf(s.Channel)
- var v reflect.Value
- if iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 {
- v = newEmptyInterface(empty{s.Value})
- } else {
- v = reflect.ValueOf(s.Value)
- }
- c.Send(v)
-}
-
-// A Close action closes the given channel.
-type Close struct {
- Channel interface{}
-}
-
-func (Close) getRecv() recvAction { return nil }
-
-func (s Close) getSend() sendAction { return s }
-
-func (s Close) getChannel() interface{} { return s.Channel }
-
-func (s Close) send() { reflect.ValueOf(s.Channel).Close() }
-
-// A ReceivedUnexpected error results if no active Events match a value
-// received from a channel.
-type ReceivedUnexpected struct {
- Value interface{}
- ready []*Event
-}
-
-func (r ReceivedUnexpected) String() string {
- names := make([]string, len(r.ready))
- for i, v := range r.ready {
- names[i] = v.name
- }
- return fmt.Sprintf("received unexpected value on one of the channels: %#v. Runnable events: %s", r.Value, strings.Join(names, ", "))
-}
-
-// A SetupError results if there is a error with the configuration of a set of
-// Events.
-type SetupError string
-
-func (s SetupError) String() string { return string(s) }
-
-func NewEvent(name string, predecessors []*Event, action action) *Event {
- e := &Event{name, false, predecessors, action}
- return e
-}
-
-// Given a set of Events, Perform repeatedly iterates over the set and finds the
-// subset of ready Events (that is, all of their predecessors have
-// occurred). From that subset, it pseudo-randomly selects an Event to perform.
-// If the Event is a send event, the send occurs and Perform recalculates the ready
-// set. If the event is a receive event, Perform waits for a value from any of the
-// channels that are contained in any of the events. That value is then matched
-// against the ready events. The first event that matches is considered to
-// have occurred and Perform recalculates the ready set.
-//
-// Perform continues this until all Events have occurred.
-//
-// Note that uncollected goroutines may still be reading from any of the
-// channels read from after Perform returns.
-//
-// For example, consider the problem of testing a function that reads values on
-// one channel and echos them to two output channels. To test this we would
-// create three events: a send event and two receive events. Each of the
-// receive events must list the send event as a predecessor but there is no
-// ordering between the receive events.
-//
-// send := NewEvent("send", nil, Send{c, 1})
-// recv1 := NewEvent("recv 1", []*Event{send}, Recv{c, 1})
-// recv2 := NewEvent("recv 2", []*Event{send}, Recv{c, 1})
-// Perform(0, []*Event{send, recv1, recv2})
-//
-// At first, only the send event would be in the ready set and thus Perform will
-// send a value to the input channel. Now the two receive events are ready and
-// Perform will match each of them against the values read from the output channels.
-//
-// It would be invalid to list one of the receive events as a predecessor of
-// the other. At each receive step, all the receive channels are considered,
-// thus Perform may see a value from a channel that is not in the current ready
-// set and fail.
-func Perform(seed int64, events []*Event) (err os.Error) {
- r := rand.New(rand.NewSource(seed))
-
- channels, err := getChannels(events)
- if err != nil {
- return
- }
- multiplex := make(chan interface{})
- for _, channel := range channels {
- go recvValues(multiplex, channel)
- }
-
-Outer:
- for {
- ready, err := readyEvents(events)
- if err != nil {
- return err
- }
-
- if len(ready) == 0 {
- // All events occurred.
- break
- }
-
- event := ready[r.Intn(len(ready))]
- if send := event.action.getSend(); send != nil {
- send.send()
- event.occurred = true
- continue
- }
-
- v := <-multiplex
- for _, event := range ready {
- if recv := event.action.getRecv(); recv != nil && recv.recvMatch(v) {
- event.occurred = true
- continue Outer
- }
- }
-
- return ReceivedUnexpected{v, ready}
- }
-
- return nil
-}
-
-// getChannels returns all the channels listed in any receive events.
-func getChannels(events []*Event) ([]interface{}, os.Error) {
- channels := make([]interface{}, len(events))
-
- j := 0
- for _, event := range events {
- if recv := event.action.getRecv(); recv == nil {
- continue
- }
- c := event.action.getChannel()
- if reflect.ValueOf(c).Kind() != reflect.Chan {
- return nil, SetupError("one of the channel values is not a channel")
- }
-
- duplicate := false
- for _, other := range channels[0:j] {
- if c == other {
- duplicate = true
- break
- }
- }
-
- if !duplicate {
- channels[j] = c
- j++
- }
- }
-
- return channels[0:j], nil
-}
-
-// recvValues is a multiplexing helper function. It reads values from the given
-// channel repeatedly, wrapping them up as either a channelRecv or
-// channelClosed structure, and forwards them to the multiplex channel.
-func recvValues(multiplex chan<- interface{}, channel interface{}) {
- c := reflect.ValueOf(channel)
-
- for {
- v, ok := c.Recv()
- if !ok {
- multiplex <- channelClosed{channel}
- return
- }
-
- multiplex <- channelRecv{channel, v.Interface()}
- }
-}
-
-type channelClosed struct {
- channel interface{}
-}
-
-type channelRecv struct {
- channel interface{}
- value interface{}
-}
-
-// readyEvents returns the subset of events that are ready.
-func readyEvents(events []*Event) ([]*Event, os.Error) {
- ready := make([]*Event, len(events))
-
- j := 0
- eventsWaiting := false
- for _, event := range events {
- if event.occurred {
- continue
- }
-
- eventsWaiting = true
- if event.isReady() {
- ready[j] = event
- j++
- }
- }
-
- if j == 0 && eventsWaiting {
- names := make([]string, len(events))
- for _, event := range events {
- if event.occurred {
- continue
- }
- names[j] = event.name
- }
-
- return nil, SetupError("dependency cycle in events. These events are waiting to run but cannot: " + strings.Join(names, ", "))
- }
-
- return ready[0:j], nil
-}
diff --git a/src/pkg/testing/script/script_test.go b/src/pkg/testing/script/script_test.go
deleted file mode 100644
index e9ab142c2..000000000
--- a/src/pkg/testing/script/script_test.go
+++ /dev/null
@@ -1,75 +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 script
-
-import (
- "testing"
-)
-
-func TestNoop(t *testing.T) {
- err := Perform(0, nil)
- if err != nil {
- t.Errorf("Got error: %s", err)
- }
-}
-
-func TestSimple(t *testing.T) {
- c := make(chan int)
- defer close(c)
-
- a := NewEvent("send", nil, Send{c, 1})
- b := NewEvent("recv", []*Event{a}, Recv{c, 1})
-
- err := Perform(0, []*Event{a, b})
- if err != nil {
- t.Errorf("Got error: %s", err)
- }
-}
-
-func TestFail(t *testing.T) {
- c := make(chan int)
- defer close(c)
-
- a := NewEvent("send", nil, Send{c, 2})
- b := NewEvent("recv", []*Event{a}, Recv{c, 1})
-
- err := Perform(0, []*Event{a, b})
- if err == nil {
- t.Errorf("Failed to get expected error")
- } else if _, ok := err.(ReceivedUnexpected); !ok {
- t.Errorf("Error returned was of the wrong type: %s", err)
- }
-}
-
-func TestClose(t *testing.T) {
- c := make(chan int)
-
- a := NewEvent("close", nil, Close{c})
- b := NewEvent("closed", []*Event{a}, Closed{c})
-
- err := Perform(0, []*Event{a, b})
- if err != nil {
- t.Errorf("Got error: %s", err)
- }
-}
-
-func matchOne(v interface{}) bool {
- if i, ok := v.(int); ok && i == 1 {
- return true
- }
- return false
-}
-
-func TestRecvMatch(t *testing.T) {
- c := make(chan int)
-
- a := NewEvent("send", nil, Send{c, 1})
- b := NewEvent("recv", []*Event{a}, RecvMatch{c, matchOne})
-
- err := Perform(0, []*Event{a, b})
- if err != nil {
- t.Errorf("Got error: %s", err)
- }
-}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index ec4a45371..f59ce8ed6 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package testing provides support for automated testing of Go packages.
-// It is intended to be used in concert with the ``gotest'' utility, which automates
+// It is intended to be used in concert with the ``go test'' command, which automates
// execution of any function of the form
// func TestXxx(*testing.T)
// where Xxx can be any alphanumeric string (but the first letter must not be in
@@ -12,8 +12,8 @@
//
// Functions of the form
// func BenchmarkXxx(*testing.B)
-// are considered benchmarks, and are executed by gotest when the -test.bench
-// flag is provided.
+// are considered benchmarks, and are executed by the "go test" command when
+// the -test.bench flag is provided.
//
// A sample benchmark function looks like this:
// func BenchmarkHello(b *testing.B) {
@@ -21,10 +21,11 @@
// fmt.Sprintf("hello")
// }
// }
+//
// The benchmark package will vary b.N until the benchmark function lasts
// long enough to be timed reliably. The output
-// testing.BenchmarkHello 500000 4076 ns/op
-// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+// testing.BenchmarkHello 10000000 282 ns/op
+// means that the loop ran 10000000 times at a speed of 282 ns per loop.
//
// If a benchmark needs some expensive setup before running, the timer
// may be stopped:
@@ -36,6 +37,45 @@
// big.Len()
// }
// }
+//
+// The package also runs and verifies example code. Example functions may
+// include a concluding comment that begins with "Output:" and is compared with
+// the standard output of the function when the tests are run, as in these
+// examples of an example:
+//
+// func ExampleHello() {
+// fmt.Println("hello")
+// // Output: hello
+// }
+//
+// func ExampleSalutations() {
+// fmt.Println("hello, and")
+// fmt.Println("goodbye")
+// // Output:
+// // hello, and
+// // goodbye
+// }
+//
+// Example functions without output comments are compiled but not executed.
+//
+// The naming convention to declare examples for a function F, a type T and
+// method M on type T are:
+//
+// func ExampleF() { ... }
+// func ExampleT() { ... }
+// func ExampleT_M() { ... }
+//
+// Multiple example functions for a type/function/method may be provided by
+// appending a distinct suffix to the name. The suffix must start with a
+// lower-case letter.
+//
+// func ExampleF_suffix() { ... }
+// func ExampleT_suffix() { ... }
+// func ExampleT_M_suffix() { ... }
+//
+// The entire test file is presented as the example when it contains a single
+// example function, at least one other function, type, variable, or constant
+// declaration, and no test or benchmark functions.
package testing
import (
@@ -44,8 +84,8 @@ import (
"os"
"runtime"
"runtime/pprof"
- "strings"
"strconv"
+ "strings"
"time"
)
@@ -53,29 +93,60 @@ var (
// The short flag requests that tests run more quickly, but its functionality
// is provided by test writers themselves. The testing package is just its
// home. The all.bash installation script sets it to make installation more
- // efficient, but by default the flag is off so a plain "gotest" will do a
+ // efficient, but by default the flag is off so a plain "go test" will do a
// full test of the package.
short = flag.Bool("test.short", false, "run smaller test suite to save time")
// Report as tests are run; default is silent for success.
chatty = flag.Bool("test.v", false, "verbose: print additional output")
- match = flag.String("test.run", "", "regular expression to select tests to run")
+ match = flag.String("test.run", "", "regular expression to select tests and examples to run")
memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
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")
+ timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+ parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+
+ haveExamples bool // are there examples?
cpuList []int
)
+// common holds the elements common between T and B and
+// captures common methods such as Errorf.
+type common struct {
+ output []byte // Output generated by test or benchmark.
+ failed bool // Test or benchmark has failed.
+ start time.Time // Time test or benchmark started
+ duration time.Duration
+ self interface{} // To be sent on signal channel when done.
+ signal chan interface{} // Output for serial tests.
+}
+
// Short reports whether the -test.short flag is set.
func Short() bool {
return *short
}
-// Insert final newline if needed and tabs after internal newlines.
-func tabify(s string) string {
+// decorate inserts the final newline if needed and indentation tabs for formatting.
+// If addFileLine is true, it also prefixes the string with the file and line of the call site.
+func decorate(s string, addFileLine bool) string {
+ if addFileLine {
+ _, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+ if ok {
+ // Truncate file name at last file name separator.
+ if index := strings.LastIndex(file, "/"); index >= 0 {
+ file = file[index+1:]
+ } else if index = strings.LastIndex(file, "\\"); index >= 0 {
+ file = file[index+1:]
+ }
+ } else {
+ file = "???"
+ line = 1
+ }
+ s = fmt.Sprintf("%s:%d: %s", file, line, s)
+ }
+ s = "\t" + s // Every line is indented at least one tab.
n := len(s)
if n > 0 && s[n-1] != '\n' {
s += "\n"
@@ -83,7 +154,8 @@ func tabify(s string) string {
}
for i := 0; i < n-1; i++ { // -1 to avoid final newline
if s[i] == '\n' {
- return s[0:i+1] + "\t" + tabify(s[i+1:n])
+ // Second and subsequent lines are indented an extra tab.
+ return s[0:i+1] + "\t" + decorate(s[i+1:n], false)
}
}
return s
@@ -92,134 +164,216 @@ func tabify(s string) string {
// T is a type passed to Test functions to manage test state and support formatted test logs.
// Logs are accumulated during execution and dumped to standard error when done.
type T struct {
- errors string
- failed bool
- ch chan *T
+ common
+ name string // Name of test.
+ startParallel chan bool // Parallel tests will wait on this.
}
-// Fail marks the Test function as having failed but continues execution.
-func (t *T) Fail() { t.failed = true }
+// Fail marks the function as having failed but continues execution.
+func (c *common) Fail() { c.failed = true }
+
+// Failed returns whether the function has failed.
+func (c *common) Failed() bool { return c.failed }
-// Failed returns whether the Test function has failed.
-func (t *T) Failed() bool { return t.failed }
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next test or benchmark.
+func (c *common) FailNow() {
+ c.Fail()
-// FailNow marks the Test function as having failed and stops its execution.
-// Execution will continue at the next Test.
-func (t *T) FailNow() {
- t.Fail()
- t.ch <- t
+ // Calling runtime.Goexit will exit the goroutine, which
+ // will run the deferred functions in this goroutine,
+ // which will eventually run the deferred lines in tRunner,
+ // which will signal to the test loop that this test is done.
+ //
+ // A previous version of this code said:
+ //
+ // c.duration = ...
+ // c.signal <- c.self
+ // runtime.Goexit()
+ //
+ // This previous version duplicated code (those lines are in
+ // tRunner no matter what), but worse the goroutine teardown
+ // implicit in runtime.Goexit was not guaranteed to complete
+ // before the test exited. If a test deferred an important cleanup
+ // function (like removing temporary files), there was no guarantee
+ // it would run on a test failure. Because we send on c.signal during
+ // a top-of-stack deferred function now, we know that the send
+ // only happens after any other stacked defers have completed.
runtime.Goexit()
}
-// Log formats its arguments using default formatting, analogous to Print(),
+// log generates the output. It's always at the same stack depth.
+func (c *common) log(s string) {
+ c.output = append(c.output, decorate(s, true)...)
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
// and records the text in the error log.
-func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
+func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
// Logf formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
-func (t *T) Logf(format string, args ...interface{}) {
- t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
-}
+func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log() followed by Fail().
-func (t *T) Error(args ...interface{}) {
- t.Log(args...)
- t.Fail()
+func (c *common) Error(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.Fail()
}
// Errorf is equivalent to Logf() followed by Fail().
-func (t *T) Errorf(format string, args ...interface{}) {
- t.Logf(format, args...)
- t.Fail()
+func (c *common) Errorf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.Fail()
}
// Fatal is equivalent to Log() followed by FailNow().
-func (t *T) Fatal(args ...interface{}) {
- t.Log(args...)
- t.FailNow()
+func (c *common) Fatal(args ...interface{}) {
+ c.log(fmt.Sprintln(args...))
+ c.FailNow()
}
// Fatalf is equivalent to Logf() followed by FailNow().
-func (t *T) Fatalf(format string, args ...interface{}) {
- t.Logf(format, args...)
- t.FailNow()
+func (c *common) Fatalf(format string, args ...interface{}) {
+ c.log(fmt.Sprintf(format, args...))
+ c.FailNow()
+}
+
+// Parallel signals that this test is to be run in parallel with (and only with)
+// other parallel tests in this CPU group.
+func (t *T) Parallel() {
+ t.signal <- (*T)(nil) // Release main testing loop
+ <-t.startParallel // Wait for serial tests to finish
}
// An internal type but exported because it is cross-package; part of the implementation
-// of gotest.
+// of the "go test" command.
type InternalTest struct {
Name string
F func(*T)
}
func tRunner(t *T, test *InternalTest) {
+ t.start = time.Now()
+
+ // When this goroutine is done, either because test.F(t)
+ // returned normally or because a test failure triggered
+ // a call to runtime.Goexit, record the duration and send
+ // a signal saying that the test is done.
+ defer func() {
+ t.duration = time.Now().Sub(t.start)
+ // If the test panicked, print any test output before dying.
+ if err := recover(); err != nil {
+ t.report()
+ panic(err)
+ }
+ t.signal <- t
+ }()
+
test.F(t)
- t.ch <- t
}
// An internal function but exported because it is cross-package; part of the implementation
-// of gotest.
-func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) {
+// of the "go test" command.
+func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
flag.Parse()
parseCpuList()
before()
startAlarm()
- RunTests(matchString, tests)
+ haveExamples = len(examples) > 0
+ testOk := RunTests(matchString, tests)
+ exampleOk := RunExamples(matchString, examples)
+ if !testOk || !exampleOk {
+ fmt.Println("FAIL")
+ os.Exit(1)
+ }
+ fmt.Println("PASS")
stopAlarm()
RunBenchmarks(matchString, benchmarks)
after()
}
-func RunTests(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) {
- ok := true
- if len(tests) == 0 {
- println("testing: warning: no tests to run")
+func (t *T) report() {
+ tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
+ format := "--- %s: %s %s\n%s"
+ if t.failed {
+ fmt.Printf(format, "FAIL", t.name, tstr, t.output)
+ } else if *chatty {
+ fmt.Printf(format, "PASS", t.name, tstr, t.output)
}
- for i := 0; i < len(tests); i++ {
- matched, err := matchString(*match, tests[i].Name)
- if err != nil {
- println("invalid regexp for -test.run:", err.String())
- os.Exit(1)
- }
- if !matched {
- continue
- }
- for _, procs := range cpuList {
- runtime.GOMAXPROCS(procs)
+}
+
+func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
+ ok = true
+ if len(tests) == 0 && !haveExamples {
+ fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
+ return
+ }
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ // We build a new channel tree for each run of the loop.
+ // collector merges in one channel all the upstream signals from parallel tests.
+ // If all tests pump to the same channel, a bug can occur where a test
+ // kicks off a goroutine that Fails, yet the test still delivers a completion signal,
+ // which skews the counting.
+ var collector = make(chan interface{})
+
+ numParallel := 0
+ startParallel := make(chan bool)
+
+ for i := 0; i < len(tests); i++ {
+ matched, err := matchString(*match, tests[i].Name)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
+ os.Exit(1)
+ }
+ if !matched {
+ continue
+ }
testName := tests[i].Name
if procs != 1 {
testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
}
+ t := &T{
+ common: common{
+ signal: make(chan interface{}),
+ },
+ name: testName,
+ startParallel: startParallel,
+ }
+ t.self = t
if *chatty {
- println("=== RUN ", testName)
+ fmt.Printf("=== RUN %s\n", t.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 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)
+ out := (<-t.signal).(*T)
+ if out == nil { // Parallel run.
+ go func() {
+ collector <- <-t.signal
+ }()
+ numParallel++
+ continue
}
- if t.failed {
- println("--- FAIL:", testName, tstr)
- print(t.errors)
- ok = false
- } else if *chatty {
- println("--- PASS:", testName, tstr)
- print(t.errors)
+ t.report()
+ ok = ok && !out.failed
+ }
+
+ running := 0
+ for numParallel+running > 0 {
+ if running < *parallel && numParallel > 0 {
+ startParallel <- true
+ running++
+ numParallel--
+ continue
}
+ t := (<-collector).(*T)
+ t.report()
+ ok = ok && !t.failed
+ running--
}
}
- if !ok {
- println("FAIL")
- os.Exit(1)
- }
- println("PASS")
+ return
}
// before runs before all testing.
@@ -266,7 +420,7 @@ var timer *time.Timer
// startAlarm starts an alarm if requested.
func startAlarm() {
if *timeout > 0 {
- timer = time.AfterFunc(*timeout*1e9, alarm)
+ timer = time.AfterFunc(*timeout, alarm)
}
}
@@ -289,7 +443,7 @@ func parseCpuList() {
for _, val := range strings.Split(*cpuListStr, ",") {
cpu, err := strconv.Atoi(val)
if err != nil || cpu <= 0 {
- println("invalid value for -test.cpu")
+ fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val)
os.Exit(1)
}
cpuList = append(cpuList, cpu)
diff --git a/src/pkg/scanner/scanner.go b/src/pkg/text/scanner/scanner.go
index 8fbcb9c11..565650edf 100644
--- a/src/pkg/scanner/scanner.go
+++ b/src/pkg/text/scanner/scanner.go
@@ -5,8 +5,7 @@
// Package scanner provides a scanner and tokenizer for UTF-8-encoded text.
// It takes an io.Reader providing the source, which then can be tokenized
// through repeated calls to the Scan function. For compatibility with
-// existing tools, the NUL character is not allowed (implementation
-// restriction).
+// existing tools, the NUL character is not allowed.
//
// By default, a Scanner skips white space and Go comments and recognizes all
// literals as defined by the Go language specification. It may be
@@ -31,7 +30,7 @@ import (
"io"
"os"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// TODO(gri): Consider changing this to use the new (token) Position package.
@@ -93,7 +92,7 @@ const (
skipComment
)
-var tokenString = map[int]string{
+var tokenString = map[rune]string{
EOF: "EOF",
Ident: "Ident",
Int: "Int",
@@ -104,8 +103,8 @@ var tokenString = map[int]string{
Comment: "Comment",
}
-// TokenString returns a (visible) string for a token or Unicode character.
-func TokenString(tok int) string {
+// TokenString returns a printable string for a token or Unicode character.
+func TokenString(tok rune) string {
if s, found := tokenString[tok]; found {
return s
}
@@ -144,7 +143,7 @@ type Scanner struct {
tokEnd int // token text tail end (srcBuf index)
// One character look-ahead
- ch int // character before current srcPos
+ ch rune // character before current srcPos
// Error is called for each error encountered. If no Error
// function is set, the error is reported to os.Stderr.
@@ -164,9 +163,12 @@ type Scanner struct {
// for values ch > ' '). The field may be changed at any time.
Whitespace uint64
- // Current token position. The Offset, Line, and Column fields
- // are set by Scan(); the Filename field is left untouched by the
- // Scanner.
+ // Start position of most recently scanned token; set by Scan.
+ // Calling Init or Next invalidates the position (Line == 0).
+ // The Filename field is always left untouched by the Scanner.
+ // If an error is reported (via Error) and Position is invalid,
+ // the scanner is not inside a token. Call Pos to obtain an error
+ // position in that case.
Position
}
@@ -201,6 +203,7 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
s.ErrorCount = 0
s.Mode = GoTokens
s.Whitespace = GoWhitespace
+ s.Line = 0 // invalidate token position
return s
}
@@ -214,8 +217,8 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
// that only a minimal amount of work needs to be done in the common ASCII
// case (one test to check for both ASCII and end-of-buffer, and one test
// to check for newlines).
-func (s *Scanner) next() int {
- ch, width := int(s.srcBuf[s.srcPos]), 1
+func (s *Scanner) next() rune {
+ ch, width := rune(s.srcBuf[s.srcPos]), 1
if ch >= utf8.RuneSelf {
// uncommon case: not ASCII or not enough bytes
@@ -231,7 +234,7 @@ func (s *Scanner) next() int {
copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd])
s.srcBufOffset += s.srcPos
// read more bytes
- // (an io.Reader must return os.EOF when it reaches
+ // (an io.Reader must return io.EOF when it reaches
// the end of what it is reading - simply returning
// n == 0 will make this loop retry forever; but the
// error is in the reader implementation in that case)
@@ -249,8 +252,8 @@ func (s *Scanner) next() int {
s.lastCharLen = 0
return EOF
}
- if err != os.EOF {
- s.error(err.String())
+ if err != io.EOF {
+ s.error(err.Error())
}
// If err == EOF, we won't be getting more
// bytes; break to avoid infinite loop. If
@@ -260,7 +263,7 @@ func (s *Scanner) next() int {
}
}
// at least one byte
- ch = int(s.srcBuf[s.srcPos])
+ ch = rune(s.srcBuf[s.srcPos])
if ch >= utf8.RuneSelf {
// uncommon case: not ASCII
ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd])
@@ -283,7 +286,7 @@ func (s *Scanner) next() int {
// special situations
switch ch {
case 0:
- // implementation restriction for compatibility with other tools
+ // for compatibility with other tools
s.error("illegal character NUL")
case '\n':
s.line++
@@ -300,8 +303,9 @@ func (s *Scanner) next() int {
// it prints an error message to os.Stderr. Next does not
// update the Scanner's Position field; use Pos() to
// get the current position.
-func (s *Scanner) Next() int {
+func (s *Scanner) Next() rune {
s.tokPos = -1 // don't collect token text
+ s.Line = 0 // invalidate token position
ch := s.Peek()
s.ch = s.next()
return ch
@@ -310,7 +314,7 @@ func (s *Scanner) Next() int {
// Peek returns the next Unicode character in the source without advancing
// the scanner. It returns EOF if the scanner's position is at the last
// character of the source.
-func (s *Scanner) Peek() int {
+func (s *Scanner) Peek() rune {
if s.ch < 0 {
s.ch = s.next()
}
@@ -323,10 +327,14 @@ func (s *Scanner) error(msg string) {
s.Error(s, msg)
return
}
- fmt.Fprintf(os.Stderr, "%s: %s\n", s.Position, msg)
+ pos := s.Position
+ if !pos.IsValid() {
+ pos = s.Pos()
+ }
+ fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg)
}
-func (s *Scanner) scanIdentifier() int {
+func (s *Scanner) scanIdentifier() rune {
ch := s.next() // read character after first '_' or letter
for ch == '_' || unicode.IsLetter(ch) || unicode.IsDigit(ch) {
ch = s.next()
@@ -334,35 +342,35 @@ func (s *Scanner) scanIdentifier() int {
return ch
}
-func digitVal(ch int) int {
+func digitVal(ch rune) int {
switch {
case '0' <= ch && ch <= '9':
- return ch - '0'
+ return int(ch - '0')
case 'a' <= ch && ch <= 'f':
- return ch - 'a' + 10
+ return int(ch - 'a' + 10)
case 'A' <= ch && ch <= 'F':
- return ch - 'A' + 10
+ return int(ch - 'A' + 10)
}
return 16 // larger than any legal digit val
}
-func isDecimal(ch int) bool { return '0' <= ch && ch <= '9' }
+func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' }
-func (s *Scanner) scanMantissa(ch int) int {
+func (s *Scanner) scanMantissa(ch rune) rune {
for isDecimal(ch) {
ch = s.next()
}
return ch
}
-func (s *Scanner) scanFraction(ch int) int {
+func (s *Scanner) scanFraction(ch rune) rune {
if ch == '.' {
ch = s.scanMantissa(s.next())
}
return ch
}
-func (s *Scanner) scanExponent(ch int) int {
+func (s *Scanner) scanExponent(ch rune) rune {
if ch == 'e' || ch == 'E' {
ch = s.next()
if ch == '-' || ch == '+' {
@@ -373,7 +381,7 @@ func (s *Scanner) scanExponent(ch int) int {
return ch
}
-func (s *Scanner) scanNumber(ch int) (int, int) {
+func (s *Scanner) scanNumber(ch rune) (rune, rune) {
// isDecimal(ch)
if ch == '0' {
// int or float
@@ -417,7 +425,7 @@ func (s *Scanner) scanNumber(ch int) (int, int) {
return Int, ch
}
-func (s *Scanner) scanDigits(ch, base, n int) int {
+func (s *Scanner) scanDigits(ch rune, base, n int) rune {
for n > 0 && digitVal(ch) < base {
ch = s.next()
n--
@@ -428,7 +436,7 @@ func (s *Scanner) scanDigits(ch, base, n int) int {
return ch
}
-func (s *Scanner) scanEscape(quote int) int {
+func (s *Scanner) scanEscape(quote rune) rune {
ch := s.next() // read character after '/'
switch ch {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
@@ -448,7 +456,7 @@ func (s *Scanner) scanEscape(quote int) int {
return ch
}
-func (s *Scanner) scanString(quote int) (n int) {
+func (s *Scanner) scanString(quote rune) (n int) {
ch := s.next() // read character after quote
for ch != quote {
if ch == '\n' || ch < 0 {
@@ -482,7 +490,7 @@ func (s *Scanner) scanChar() {
}
}
-func (s *Scanner) scanComment(ch int) int {
+func (s *Scanner) scanComment(ch rune) rune {
// ch == '/' || ch == '*'
if ch == '/' {
// line comment
@@ -515,11 +523,12 @@ func (s *Scanner) scanComment(ch int) int {
// It returns EOF at the end of the source. It reports scanner errors (read and
// token errors) by calling s.Error, if not nil; otherwise it prints an error
// message to os.Stderr.
-func (s *Scanner) Scan() int {
+func (s *Scanner) Scan() rune {
ch := s.Peek()
// reset token text position
s.tokPos = -1
+ s.Line = 0
redo:
// skip white space
diff --git a/src/pkg/scanner/scanner_test.go b/src/pkg/text/scanner/scanner_test.go
index 8403d6153..bb3adb55a 100644
--- a/src/pkg/scanner/scanner_test.go
+++ b/src/pkg/text/scanner/scanner_test.go
@@ -7,10 +7,10 @@ package scanner
import (
"bytes"
"fmt"
- "os"
+ "io"
"strings"
"testing"
- "utf8"
+ "unicode/utf8"
)
// A StringReader delivers its data one string segment at a time via Read.
@@ -19,13 +19,13 @@ type StringReader struct {
step int
}
-func (r *StringReader) Read(p []byte) (n int, err os.Error) {
+func (r *StringReader) Read(p []byte) (n int, err error) {
if r.step < len(r.data) {
s := r.data[r.step]
n = copy(p, s)
r.step++
} else {
- err = os.EOF
+ err = io.EOF
}
return
}
@@ -64,7 +64,7 @@ func TestNext(t *testing.T) {
}
type token struct {
- tok int
+ tok rune
text string
}
@@ -100,11 +100,8 @@ var tokenList = []token{
{Ident, "_abc_123_"},
{Ident, "_äöü"},
{Ident, "_本"},
- // TODO for unknown reasons these fail when checking the literals
- /*
- token{Ident, "äöü"},
- token{Ident, "本"},
- */
+ {Ident, "äöü"},
+ {Ident, "本"},
{Ident, "a۰۱۸"},
{Ident, "foo६४"},
{Ident, "bar9876"},
@@ -236,7 +233,7 @@ func makeSource(pattern string) *bytes.Buffer {
return &buf
}
-func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
+func checkTok(t *testing.T, s *Scanner, line int, got, want rune, text string) {
if got != want {
t.Fatalf("tok = %s, want %s for %q", TokenString(got), TokenString(want), text)
}
@@ -332,7 +329,7 @@ func TestScanZeroMode(t *testing.T) {
}
}
-func testScanSelectedMode(t *testing.T, mode uint, class int) {
+func testScanSelectedMode(t *testing.T, mode uint, class rune) {
src := makeSource("%s\n")
s := new(Scanner).Init(src)
s.Mode = mode
@@ -365,14 +362,14 @@ func TestScanNext(t *testing.T) {
checkTok(t, s, 1, s.Scan(), Ident, "if")
checkTok(t, s, 1, s.Scan(), Ident, "a")
checkTok(t, s, 1, s.Scan(), '=', "=")
- checkTok(t, s, 1, s.Next(), '=', "")
- checkTok(t, s, 1, s.Next(), ' ', "")
- checkTok(t, s, 1, s.Next(), 'b', "")
+ checkTok(t, s, 0, s.Next(), '=', "")
+ checkTok(t, s, 0, s.Next(), ' ', "")
+ checkTok(t, s, 0, s.Next(), 'b', "")
checkTok(t, s, 1, s.Scan(), Ident, "cd")
checkTok(t, s, 1, s.Scan(), '{', "{")
checkTok(t, s, 2, s.Scan(), Ident, "a")
checkTok(t, s, 2, s.Scan(), '+', "+")
- checkTok(t, s, 2, s.Next(), '=', "")
+ checkTok(t, s, 0, s.Next(), '=', "")
checkTok(t, s, 2, s.Scan(), Ident, "c")
checkTok(t, s, 3, s.Scan(), '}', "}")
checkTok(t, s, 3, s.Scan(), -1, "")
@@ -401,7 +398,7 @@ func TestScanWhitespace(t *testing.T) {
}
}
-func testError(t *testing.T, src, pos, msg string, tok int) {
+func testError(t *testing.T, src, pos, msg string, tok rune) {
s := new(Scanner).Init(bytes.NewBufferString(src))
errorCalled := false
s.Error = func(s *Scanner, m string) {
@@ -466,7 +463,7 @@ func checkPos(t *testing.T, got, want Position) {
}
}
-func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
+func checkNextPos(t *testing.T, s *Scanner, offset, line, column int, char rune) {
if ch := s.Next(); ch != char {
t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
}
@@ -474,7 +471,7 @@ 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) {
+func checkScanPos(t *testing.T, s *Scanner, offset, line, column int, char rune) {
want := Position{Offset: offset, Line: line, Column: column}
checkPos(t, s.Pos(), want)
if ch := s.Scan(); ch != char {
diff --git a/src/pkg/text/tabwriter/example_test.go b/src/pkg/text/tabwriter/example_test.go
new file mode 100644
index 000000000..20443cb1f
--- /dev/null
+++ b/src/pkg/text/tabwriter/example_test.go
@@ -0,0 +1,38 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tabwriter_test
+
+import (
+ "fmt"
+ "os"
+ "text/tabwriter"
+)
+
+func ExampleWriter_Init() {
+ w := new(tabwriter.Writer)
+
+ // Format in tab-separated columns with a tab stop of 8.
+ w.Init(os.Stdout, 0, 8, 0, '\t', 0)
+ fmt.Fprintln(w, "a\tb\tc\td\t.")
+ fmt.Fprintln(w, "123\t12345\t1234567\t123456789\t.")
+ fmt.Fprintln(w)
+ w.Flush()
+
+ // Format right-aligned in space-separated columns of minimal width 5
+ // and at least one blank of padding (so wider column entries do not
+ // touch each other).
+ w.Init(os.Stdout, 5, 0, 1, ' ', tabwriter.AlignRight)
+ fmt.Fprintln(w, "a\tb\tc\td\t.")
+ fmt.Fprintln(w, "123\t12345\t1234567\t123456789\t.")
+ fmt.Fprintln(w)
+ w.Flush()
+
+ // output:
+ // a b c d .
+ // 123 12345 1234567 123456789 .
+ //
+ // a b c d.
+ // 123 12345 1234567 123456789.
+}
diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/text/tabwriter/tabwriter.go
index 2f35d961e..ce84600d6 100644
--- a/src/pkg/tabwriter/tabwriter.go
+++ b/src/pkg/text/tabwriter/tabwriter.go
@@ -13,8 +13,7 @@ package tabwriter
import (
"bytes"
"io"
- "os"
- "utf8"
+ "unicode/utf8"
)
// ----------------------------------------------------------------------------
@@ -53,7 +52,7 @@ type cell struct {
// this flag.
//
// If a Writer is configured to filter HTML, HTML tags and entities
-// are simply passed through. The widths of tags and entities are
+// are passed through. The widths of tags and entities are
// assumed to be zero (tags) and one (entities) for formatting purposes.
//
// A segment of text may be escaped by bracketing it with Escape
@@ -170,12 +169,6 @@ const (
// to the tab width in the viewer displaying the result)
// flags formatting control
//
-// To format in tab-separated columns with a tab stop of 8:
-// b.Init(w, 8, 1, 8, '\t', 0);
-//
-// To format in space-separated columns with at least 4 spaces between columns:
-// b.Init(w, 0, 4, 8, ' ', 0);
-//
func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
if minwidth < 0 || tabwidth < 0 || padding < 0 {
panic("negative minwidth, tabwidth, or padding")
@@ -212,16 +205,16 @@ func (b *Writer) dump() {
print("\n")
}
-// local error wrapper so we can distinguish os.Errors we want to return
+// local error wrapper so we can distinguish errors we want to return
// as errors from genuine panics (which we don't want to return as errors)
type osError struct {
- err os.Error
+ err error
}
func (b *Writer) write0(buf []byte) {
n, err := b.output.Write(buf)
if n != len(buf) && err == nil {
- err = os.EIO
+ err = io.ErrShortWrite
}
if err != nil {
panic(osError{err})
@@ -441,7 +434,7 @@ func (b *Writer) terminateCell(htab bool) int {
return len(*line)
}
-func handlePanic(err *os.Error) {
+func handlePanic(err *error) {
if e := recover(); e != nil {
*err = e.(osError).err // re-panics if it's not a local osError
}
@@ -449,10 +442,10 @@ func handlePanic(err *os.Error) {
// Flush should be called after the last call to Write to ensure
// that any data buffered in the Writer is written to output. Any
-// incomplete escape sequence at the end is simply considered
+// incomplete escape sequence at the end is considered
// complete for formatting purposes.
//
-func (b *Writer) Flush() (err os.Error) {
+func (b *Writer) Flush() (err error) {
defer b.reset() // even in the presence of errors
defer handlePanic(&err)
@@ -477,7 +470,7 @@ var hbar = []byte("---\n")
// The only errors returned are ones encountered
// while writing to the underlying output stream.
//
-func (b *Writer) Write(buf []byte) (n int, err os.Error) {
+func (b *Writer) Write(buf []byte) (n int, err error) {
defer handlePanic(&err)
// split text into cells
diff --git a/src/pkg/tabwriter/tabwriter_test.go b/src/pkg/text/tabwriter/tabwriter_test.go
index 6ef7e808e..ace535647 100644
--- a/src/pkg/tabwriter/tabwriter_test.go
+++ b/src/pkg/text/tabwriter/tabwriter_test.go
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package tabwriter
+package tabwriter_test
import (
"io"
- "os"
"testing"
+ . "text/tabwriter"
)
type buffer struct {
@@ -18,7 +18,7 @@ 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) {
+func (b *buffer) Write(buf []byte) (written int, err error) {
n := len(b.a)
m := len(buf)
if n+m <= cap(b.a) {
diff --git a/src/pkg/template/doc.go b/src/pkg/text/template/doc.go
index a52f32d91..aa50ab97f 100644
--- a/src/pkg/template/doc.go
+++ b/src/pkg/text/template/doc.go
@@ -3,8 +3,10 @@
// license that can be found in the LICENSE file.
/*
-Package template implements data-driven templates for generating textual output
-such as HTML.
+Package template implements data-driven templates for generating textual output.
+
+To generate HTML output, see package html/template, which has the same interface
+as this package but automatically secures HTML output against certain attacks.
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
@@ -18,8 +20,21 @@ The input text for a template is UTF-8-encoded text in any format.
"{{" and "}}"; all text outside actions is copied to the output unchanged.
Actions may not span newlines, although comments can.
-Once constructed, templates and template sets can be executed safely in
-parallel.
+Once constructed, a template may be executed safely in parallel.
+
+Here is a trivial example that prints "17 items are made of wool".
+
+ type Inventory struct {
+ Material string
+ Count uint
+ }
+ sweaters := Inventory{"wool", 17}
+ tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
+ if err != nil { panic(err) }
+ err = tmpl.Execute(os.Stdout, sweaters)
+ if err != nil { panic(err) }
+
+More intricate examples appear below.
Actions
@@ -51,7 +66,9 @@ data, defined in detail below.
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.
+ slice, or map and T1 is executed. If the value is a map and the
+ keys are of basic type with a defined order ("comparable"), the
+ elements will be visited in sorted key order.
{{range pipeline}} T1 {{else}} T0 {{end}}
The value of the pipeline must be an array, slice, or map. If
@@ -117,7 +134,7 @@ An argument is a simple value, denoted by one of the following.
.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.
+ any type) or two return values, the second of which is an 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
@@ -133,6 +150,10 @@ An argument is a simple value, denoted by one of the following.
Arguments may evaluate to any type; if they are pointers the implementation
automatically indirects to the base type when required.
+If an evaluation yields a function value, such as a function-valued
+field of a struct, the function is not invoked automatically, but it
+can be used as a truth value for an if action and the like. To invoke
+it, use the call function, defined below.
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:
@@ -159,7 +180,7 @@ 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
+which has type error. If that second value is present and evaluates to
non-nil, execution terminates and the error is returned to the caller of
Execute.
@@ -221,10 +242,9 @@ All produce the quoted word "output":
Functions
-During execution functions are found in three function maps: first in the
-template, then in the "template set" (described below), and finally in the
-global function map. By default, no functions are defined in the template or
-the set but the Funcs methods can be used to add them.
+During execution functions are found in two function maps: first in the
+template, then in the global function map. By default, no functions are defined
+in the template but the Funcs method can be used to add them.
Predefined global functions are named as follows.
@@ -233,6 +253,17 @@ Predefined global functions are named as follows.
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.
+ call
+ Returns the result of calling the first argument, which
+ must be a function, with the remaining arguments as parameters.
+ Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
+ Y is a func-valued field, map entry, or the like.
+ The first argument must be the result of an evaluation
+ that yields a value of function type (as distinct from
+ a predefined function such as print). The function must
+ return either one or two result values, the second of which
+ is of type error. If the arguments don't match the function
+ or the returned error value is non-nil, execution stops.
html
Returns the escaped HTML equivalent of the textual
representation of its arguments.
@@ -265,49 +296,63 @@ Predefined global functions are named as follows.
The boolean functions take any zero value to be false and a non-zero value to
be true.
-Template sets
+Associated templates
+
+Each template is named by a string specified when it is created. Also, each
+template is associated with zero or more other templates that it may invoke by
+name; such associations are transitive and form a name space of templates.
-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.
+A template may use a template invocation to instantiate another associated
+template; see the explanation of the "template" action above. The name must be
+that of a template associated with the template that contains the invocation.
-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.
+Nested template definitions
-There are two ways to construct template sets.
+When parsing a template, another template may be defined and associated with the
+template being parsed. Template definitions must appear at the top level of the
+template, much like global variables in a Go program.
-The 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 syntax of such definitions is to surround each template declaration with a
+"define" and "end" action.
The define action names the template being created by providing a string
-constant. Here is a simple example of input to Set.Parse:
+constant. Here is a simple example:
- `{{define "T1"}} definition of template T1 {{end}}
- {{define "T2"}} definition of template T2 {{end}}
- {{define "T3"}} {{template "T1"}} {{template "T2"}} {{end}}`
+ `{{define "T1"}}ONE{{end}}
+ {{define "T2"}}TWO{{end}}
+ {{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
+ {{template "T3"}}`
This defines two templates, T1 and T2, and a third T3 that invokes the other two
-when it is executed.
+when it is executed. Finally it invokes T3. If executed this template will
+produce the text
+
+ ONE TWO
-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.
+By construction, a template may reside in only one association. If it's
+necessary to have a template addressable from multiple associations, the
+template definition must be parsed multiple times to create distinct *Template
+values, or must be copied with the Clone or AddParseTree method.
-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.
+Parse may be called multiple times to assemble the various associated templates;
+see the ParseFiles and ParseGlob functions and methods for simple ways to parse
+related templates stored in files.
-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,
+A template may be executed directly or through ExecuteTemplate, which executes
+an associated template identified by name. To invoke our example above, we
+might write,
- err := set.Execute(os.Stdout, "T3", "no data needed")
+ err := tmpl.Execute(os.Stdout, "no data needed")
if err != nil {
log.Fatalf("execution failed: %s", err)
}
+
+or to invoke a particular template explicitly by name,
+
+ err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
+ if err != nil {
+ log.Fatalf("execution failed: %s", err)
+ }
+
*/
package template
diff --git a/src/pkg/text/template/example_test.go b/src/pkg/text/template/example_test.go
new file mode 100644
index 000000000..ad49514a8
--- /dev/null
+++ b/src/pkg/text/template/example_test.go
@@ -0,0 +1,71 @@
+// 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_test
+
+import (
+ "log"
+ "os"
+ "text/template"
+)
+
+func ExampleTemplate() {
+ // Define a template.
+ const letter = `
+Dear {{.Name}},
+{{if .Attended}}
+It was a pleasure to see you at the wedding.{{else}}
+It is a shame you couldn't make it to the wedding.{{end}}
+{{with .Gift}}Thank you for the lovely {{.}}.
+{{end}}
+Best wishes,
+Josie
+`
+
+ // Prepare some data to insert into the template.
+ type Recipient struct {
+ Name, Gift string
+ Attended bool
+ }
+ var recipients = []Recipient{
+ {"Aunt Mildred", "bone china tea set", true},
+ {"Uncle John", "moleskin pants", false},
+ {"Cousin Rodney", "", false},
+ }
+
+ // Create a new template and parse the letter into it.
+ t := template.Must(template.New("letter").Parse(letter))
+
+ // Execute the template for each recipient.
+ for _, r := range recipients {
+ err := t.Execute(os.Stdout, r)
+ if err != nil {
+ log.Println("executing template:", err)
+ }
+ }
+
+ // Output:
+ // Dear Aunt Mildred,
+ //
+ // It was a pleasure to see you at the wedding.
+ // Thank you for the lovely bone china tea set.
+ //
+ // Best wishes,
+ // Josie
+ //
+ // Dear Uncle John,
+ //
+ // It is a shame you couldn't make it to the wedding.
+ // Thank you for the lovely moleskin pants.
+ //
+ // Best wishes,
+ // Josie
+ //
+ // Dear Cousin Rodney,
+ //
+ // It is a shame you couldn't make it to the wedding.
+ //
+ // Best wishes,
+ // Josie
+}
diff --git a/src/pkg/text/template/examplefiles_test.go b/src/pkg/text/template/examplefiles_test.go
new file mode 100644
index 000000000..a15c7a62a
--- /dev/null
+++ b/src/pkg/text/template/examplefiles_test.go
@@ -0,0 +1,182 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template_test
+
+import (
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "text/template"
+)
+
+// templateFile defines the contents of a template to be stored in a file, for testing.
+type templateFile struct {
+ name string
+ contents string
+}
+
+func createTestDir(files []templateFile) string {
+ dir, err := ioutil.TempDir("", "template")
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, file := range files {
+ f, err := os.Create(filepath.Join(dir, file.name))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ _, err = io.WriteString(f, file.contents)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ return dir
+}
+
+// Here we demonstrate loading a set of templates from a directory.
+func ExampleTemplate_glob() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T0.tmpl is a plain template file that just invokes T1.
+ {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
+ // T1.tmpl defines a template, T1 that invokes T2.
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ // T2.tmpl defines a template T2.
+ {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // T0.tmpl is the first name matched, so it becomes the starting template,
+ // the value returned by ParseGlob.
+ tmpl := template.Must(template.ParseGlob(pattern))
+
+ err := tmpl.Execute(os.Stdout, nil)
+ if err != nil {
+ log.Fatalf("template execution: %s", err)
+ }
+ // Output:
+ // T0 invokes T1: (T1 invokes T2: (This is T2))
+}
+
+// This example demonstrates one way to share some templates
+// and use them in different contexts. In this variant we add multiple driver
+// templates by hand to an existing bundle of templates.
+func ExampleTemplate_helpers() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T1.tmpl defines a template, T1 that invokes T2.
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ // T2.tmpl defines a template T2.
+ {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // Load the helpers.
+ templates := template.Must(template.ParseGlob(pattern))
+ // Add one driver template to the bunch; we do this with an explicit template definition.
+ _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
+ if err != nil {
+ log.Fatal("parsing driver1: ", err)
+ }
+ // Add another driver template.
+ _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
+ if err != nil {
+ log.Fatal("parsing driver2: ", err)
+ }
+ // We load all the templates before execution. This package does not require
+ // that behavior but html/template's escaping does, so it's a good habit.
+ err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
+ if err != nil {
+ log.Fatalf("driver1 execution: %s", err)
+ }
+ err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
+ if err != nil {
+ log.Fatalf("driver2 execution: %s", err)
+ }
+ // Output:
+ // Driver 1 calls T1: (T1 invokes T2: (This is T2))
+ // Driver 2 calls T2: (This is T2)
+}
+
+// This example demonstrates how to use one group of driver
+// templates with distinct sets of helper templates.
+func ExampleTemplate_share() {
+ // Here we create a temporary directory and populate it with our sample
+ // template definition files; usually the template files would already
+ // exist in some location known to the program.
+ dir := createTestDir([]templateFile{
+ // T0.tmpl is a plain template file that just invokes T1.
+ {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
+ // T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
+ {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+ })
+ // Clean up after the test; another quirk of running as an example.
+ defer os.RemoveAll(dir)
+
+ // pattern is the glob pattern used to find all the template files.
+ pattern := filepath.Join(dir, "*.tmpl")
+
+ // Here starts the example proper.
+ // Load the drivers.
+ drivers := template.Must(template.ParseGlob(pattern))
+
+ // We must define an implementation of the T2 template. First we clone
+ // the drivers, then add a definition of T2 to the template name space.
+
+ // 1. Clone the helper set to create a new name space from which to run them.
+ first, err := drivers.Clone()
+ if err != nil {
+ log.Fatal("cloning helpers: ", err)
+ }
+ // 2. Define T2, version A, and parse it.
+ _, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
+ if err != nil {
+ log.Fatal("parsing T2: ", err)
+ }
+
+ // Now repeat the whole thing, using a different version of T2.
+ // 1. Clone the drivers.
+ second, err := drivers.Clone()
+ if err != nil {
+ log.Fatal("cloning drivers: ", err)
+ }
+ // 2. Define T2, version B, and parse it.
+ _, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
+ if err != nil {
+ log.Fatal("parsing T2: ", err)
+ }
+
+ // Execute the templates in the reverse order to verify the
+ // first is unaffected by the second.
+ err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
+ if err != nil {
+ log.Fatalf("second execution: %s", err)
+ }
+ err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
+ if err != nil {
+ log.Fatalf("first: execution: %s", err)
+ }
+
+ // Output:
+ // T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
+ // T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
+}
diff --git a/src/pkg/text/template/examplefunc_test.go b/src/pkg/text/template/examplefunc_test.go
new file mode 100644
index 000000000..080b5e3a0
--- /dev/null
+++ b/src/pkg/text/template/examplefunc_test.go
@@ -0,0 +1,54 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template_test
+
+import (
+ "log"
+ "os"
+ "strings"
+ "text/template"
+)
+
+// This example demonstrates a custom function to process template text.
+// It installs the strings.Title function and uses it to
+// Make Title Text Look Good In Our Template's Output.
+func ExampleTemplate_func() {
+ // First we create a FuncMap with which to register the function.
+ funcMap := template.FuncMap{
+ // The name "title" is what the function will be called in the template text.
+ "title": strings.Title,
+ }
+
+ // A simple template definition to test our function.
+ // We print the input text several ways:
+ // - the original
+ // - title-cased
+ // - title-cased and then printed with %q
+ // - printed with %q and then title-cased.
+ const templateText = `
+Input: {{printf "%q" .}}
+Output 0: {{title .}}
+Output 1: {{title . | printf "%q"}}
+Output 2: {{printf "%q" . | title}}
+`
+
+ // Create a template, add the function map, and parse the text.
+ tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
+ if err != nil {
+ log.Fatalf("parsing: %s", err)
+ }
+
+ // Run the template to verify the output.
+ err = tmpl.Execute(os.Stdout, "the go programming language")
+ if err != nil {
+ log.Fatalf("execution: %s", err)
+ }
+
+ // Output:
+ // Input: "the go programming language"
+ // Output 0: The Go Programming Language
+ // Output 1: "The Go Programming Language"
+ // Output 2: "The Go Programming Language"
+}
diff --git a/src/pkg/template/exec.go b/src/pkg/text/template/exec.go
index f1590b3bb..9a720cf43 100644
--- a/src/pkg/template/exec.go
+++ b/src/pkg/text/template/exec.go
@@ -7,11 +7,11 @@ package template
import (
"fmt"
"io"
- "os"
"reflect"
"runtime"
+ "sort"
"strings"
- "template/parse"
+ "text/template/parse"
)
// state represents the state of an execution. It's not part of the
@@ -70,25 +70,39 @@ func (s *state) errorf(format string, args ...interface{}) {
}
// error terminates processing.
-func (s *state) error(err os.Error) {
+func (s *state) error(err 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) {
+func errRecover(errp *error) {
e := recover()
if e != nil {
- if _, ok := e.(runtime.Error); ok {
+ switch err := e.(type) {
+ case runtime.Error:
+ panic(e)
+ case error:
+ *errp = err
+ default:
panic(e)
}
- *errp = e.(os.Error)
}
}
+// ExecuteTemplate applies the template associated with t that has the given name
+// to the specified data object and writes the output to wr.
+func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
+ tmpl := t.tmpl[name]
+ if tmpl == nil {
+ return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
+ }
+ return tmpl.Execute(wr, data)
+}
+
// Execute applies a parsed template to the specified data object,
-// writing the output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+// and writes the output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
defer errRecover(&err)
value := reflect.ValueOf(data)
state := &state{
@@ -97,8 +111,8 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
line: 1,
vars: []variable{{"$", value}},
}
- if t.Root == nil {
- state.errorf("must be parsed before execution")
+ if t.Tree == nil || t.Root == nil {
+ state.errorf("%q is an incomplete or empty template", t.name)
}
state.walk(value, t.Root)
return
@@ -221,7 +235,7 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
if val.Len() == 0 {
break
}
- for _, key := range val.MapKeys() {
+ for _, key := range sortKeys(val.MapKeys()) {
oneIteration(key, val.MapIndex(key))
}
return
@@ -252,13 +266,9 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
}
func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
- set := s.tmpl.set
- if set == nil {
- s.errorf("no set defined in which to invoke template named %q", t.Name)
- }
- tmpl := set.tmpl[t.Name]
+ tmpl := s.tmpl.tmpl[t.Name]
if tmpl == nil {
- s.errorf("template %q not in set", t.Name)
+ s.errorf("template %q not defined", t.Name)
}
// Variables declared by the pipeline persist.
dot = s.evalPipeline(dot, t.Pipe)
@@ -359,6 +369,7 @@ func (s *state) evalVariableNode(dot reflect.Value, v *parse.VariableNode, args
// $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 {
+ s.notAFunction(args, final)
return value
}
return s.evalFieldChain(dot, value, v.Ident[1:], args, final)
@@ -377,7 +388,7 @@ func (s *state) evalFieldChain(dot, receiver reflect.Value, ident []string, args
}
func (s *state) evalFunction(dot reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
- function, ok := findFunction(name, s.tmpl, s.tmpl.set)
+ function, ok := findFunction(name, s.tmpl)
if !ok {
s.errorf("%q is not a defined function", name)
}
@@ -399,7 +410,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
ptr = ptr.Addr()
}
- if method, ok := methodByName(ptr, fieldName); ok {
+ if method := ptr.MethodByName(fieldName); method.IsValid() {
return s.evalCall(dot, method, fieldName, args, final)
}
hasArgs := len(args) > 1 || final.IsValid()
@@ -409,10 +420,11 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
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
+ // If it's a function, we must call it.
+ if hasArgs {
+ s.errorf("%s has arguments but cannot be invoked as function", fieldName)
+ }
return field
}
}
@@ -434,19 +446,8 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
panic("not reached")
}
-// TODO: delete when reflect's own MethodByName is released.
-func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
- typ := receiver.Type()
- for i := 0; i < typ.NumMethod(); i++ {
- if typ.Method(i).Name == name {
- return receiver.Method(i), true // This value includes the receiver.
- }
- }
- return zero, false
-}
-
var (
- osErrorType = reflect.TypeOf((*os.Error)(nil)).Elem()
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
)
@@ -493,9 +494,9 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node,
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 we have an 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))
+ s.errorf("error calling %s: %s", name, result[1].Interface().(error))
}
return result[0]
}
@@ -503,7 +504,13 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node,
// 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)
+ switch typ.Kind() {
+ case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Map, reflect.Slice, reflect.Func:
+ // An untyped nil interface{}. Accept as a proper nil value.
+ value = reflect.Zero(typ)
+ default:
+ s.errorf("invalid value; expected %s", typ)
+ }
}
if !value.Type().AssignableTo(typ) {
// Does one dereference or indirection work? We could do more, as we
@@ -511,7 +518,7 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
// 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):
+ case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
value = value.Elem()
case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
value = value.Addr()
@@ -660,8 +667,8 @@ func (s *state) printValue(n parse.Node, v reflect.Value) {
return
}
- if !v.Type().Implements(fmtStringerType) {
- if v.CanAddr() && reflect.PtrTo(v.Type()).Implements(fmtStringerType) {
+ if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
+ if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
v = v.Addr()
} else {
switch v.Kind() {
@@ -672,3 +679,44 @@ func (s *state) printValue(n parse.Node, v reflect.Value) {
}
fmt.Fprint(s.wr, v.Interface())
}
+
+// Types to help sort the keys in a map for reproducible output.
+
+type rvs []reflect.Value
+
+func (x rvs) Len() int { return len(x) }
+func (x rvs) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+type rvInts struct{ rvs }
+
+func (x rvInts) Less(i, j int) bool { return x.rvs[i].Int() < x.rvs[j].Int() }
+
+type rvUints struct{ rvs }
+
+func (x rvUints) Less(i, j int) bool { return x.rvs[i].Uint() < x.rvs[j].Uint() }
+
+type rvFloats struct{ rvs }
+
+func (x rvFloats) Less(i, j int) bool { return x.rvs[i].Float() < x.rvs[j].Float() }
+
+type rvStrings struct{ rvs }
+
+func (x rvStrings) Less(i, j int) bool { return x.rvs[i].String() < x.rvs[j].String() }
+
+// sortKeys sorts (if it can) the slice of reflect.Values, which is a slice of map keys.
+func sortKeys(v []reflect.Value) []reflect.Value {
+ if len(v) <= 1 {
+ return v
+ }
+ switch v[0].Kind() {
+ case reflect.Float32, reflect.Float64:
+ sort.Sort(rvFloats{v})
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ sort.Sort(rvInts{v})
+ case reflect.String:
+ sort.Sort(rvStrings{v})
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ sort.Sort(rvUints{v})
+ }
+ return v
+}
diff --git a/src/pkg/template/exec_test.go b/src/pkg/text/template/exec_test.go
index 8e1894ea0..5446027ff 100644
--- a/src/pkg/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -6,11 +6,10 @@ package template
import (
"bytes"
+ "errors"
"flag"
"fmt"
- "os"
"reflect"
- "sort"
"strings"
"testing"
)
@@ -31,6 +30,9 @@ type T struct {
// Struct with String method.
V0 V
V1, V2 *V
+ // Struct with Error method.
+ W0 W
+ W1, W2 *W
// Slices
SI []int
SIEmpty []int
@@ -52,10 +54,15 @@ type T struct {
NonEmptyInterface I
// Stringer.
Str fmt.Stringer
+ Err error
// Pointers
PI *int
PSI *[]int
NIL *int
+ // Function (not method)
+ BinaryFunc func(string, string) string
+ VariadicFunc func(...string) string
+ VariadicFuncInt func(int, ...string) string
// Template to test evaluation of templates.
Tmpl *Template
}
@@ -75,6 +82,17 @@ func (v *V) String() string {
return fmt.Sprintf("<%d>", v.j)
}
+type W struct {
+ k int
+}
+
+func (w *W) Error() string {
+ if w == nil {
+ return "nilW"
+ }
+ return fmt.Sprintf("[%d]", w.k)
+}
+
var tVal = &T{
True: true,
I: 17,
@@ -83,6 +101,8 @@ var tVal = &T{
U: &U{"v"},
V0: V{6666},
V1: &V{7777}, // leave V2 as nil
+ W0: W{888},
+ W1: &W{999}, // leave W2 as nil
SI: []int{3, 4, 5},
SB: []bool{true, false},
MSI: map[string]int{"one": 1, "two": 2, "three": 3},
@@ -98,9 +118,13 @@ var tVal = &T{
Empty3: []int{7, 8},
Empty4: &U{"UinEmpty"},
NonEmptyInterface: new(T),
- Str: os.NewError("foozle"),
+ Str: bytes.NewBuffer([]byte("foozle")),
+ Err: errors.New("erroozle"),
PI: newInt(23),
PSI: newIntSlice(21, 22, 23),
+ BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
+ VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
+ VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
}
@@ -138,6 +162,10 @@ func (t *T) Method2(a uint16, b string) string {
return fmt.Sprintf("Method2: %d %s", a, b)
}
+func (t *T) Method3(v interface{}) string {
+ return fmt.Sprintf("Method3: %v", v)
+}
+
func (t *T) MAdd(a int, b []int) []int {
v := make([]int, len(b))
for i, x := range b {
@@ -146,22 +174,12 @@ func (t *T) MAdd(a int, b []int) []int {
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
-}
+var myError = errors.New("my error")
-// EPERM returns a value and an os.Error according to its argument.
-func (t *T) EPERM(error bool) (bool, os.Error) {
+// MyError returns a value and an error according to its argument.
+func (t *T) MyError(error bool) (bool, error) {
if error {
- return true, os.EPERM
+ return true, myError
}
return false, nil
}
@@ -231,7 +249,7 @@ var execTests = []execTest{
{"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 map", "<{{.}}>", "<map[two:22]>", map[string]int{"two": 22}, true},
{"dot struct", "<{{.}}>", "<{7 seven}>", struct {
a int
b string
@@ -248,6 +266,11 @@ var execTests = []execTest{
{"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
{"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
+ // Type with Error method.
+ {"W{888}.Error()", "-{{.W0}}-", "-[888]-", tVal, true},
+ {"&W{999}.Error()", "-{{.W1}}-", "-[999]-", tVal, true},
+ {"(*W)(nil).Error()", "-{{.W2}}-", "-nilW-", tVal, true},
+
// Pointers.
{"*int", "{{.PI}}", "23", tVal, true},
{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
@@ -269,6 +292,7 @@ var execTests = []execTest{
{".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},
+ {".Method3(nil)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", 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}}",
@@ -280,8 +304,26 @@ var execTests = []execTest{
"{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
"true", tVal, true},
+ // Function call builtin.
+ {".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
+ {".VariadicFunc0", "{{call .VariadicFunc}}", "<>", tVal, true},
+ {".VariadicFunc2", "{{call .VariadicFunc `he` `llo`}}", "<he+llo>", tVal, true},
+ {".VariadicFuncInt", "{{call .VariadicFuncInt 33 `he` `llo`}}", "33=<he+llo>", tVal, true},
+ {"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true},
+ {"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
+
+ // Erroneous function calls (check args).
+ {".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
+ {".BinaryFuncTooMany", "{{call .BinaryFunc `1` `2` `3`}}", "", tVal, false},
+ {".BinaryFuncBad0", "{{call .BinaryFunc 1 3}}", "", tVal, false},
+ {".BinaryFuncBad1", "{{call .BinaryFunc `1` 3}}", "", tVal, false},
+ {".VariadicFuncBad0", "{{call .VariadicFunc 3}}", "", tVal, false},
+ {".VariadicFuncIntBad0", "{{call .VariadicFuncInt}}", "", tVal, false},
+ {".VariadicFuncIntBad`", "{{call .VariadicFuncInt `x`}}", "", tVal, false},
+
// Pipelines.
{"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
+ {"pipeline func", "-{{call .VariadicFunc `llo` | call .VariadicFunc `he` }}-", "-<he+<llo>>-", tVal, true},
// If.
{"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
@@ -298,6 +340,8 @@ var execTests = []execTest{
{"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 map unset", "{{if .MXI.none}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if map not unset", "{{if not .MXI.none}}ZERO{{else}}NON-ZERO{{end}}", "ZERO", 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},
@@ -379,9 +423,9 @@ var execTests = []execTest{
{"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 map", "{{range .MSI}}-{{.}}-{{end}}", "-1--3--2-", 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 map else", "{{range .MSI}}-{{.}}-{{else}}EMPTY{{end}}", "-1--3--2-", 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},
@@ -399,8 +443,8 @@ var execTests = []execTest{
{"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},
+ {"error method, error", "{{.MyError true}}", "", tVal, false},
+ {"error method, no error", "{{.MyError false}}", "false", tVal, true},
// Fixed bugs.
// Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
@@ -416,11 +460,16 @@ var execTests = []execTest{
{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
// Stringer.
{"bug5", "{{.Str}}", "foozle", tVal, true},
+ {"bug5a", "{{.Err}}", "erroozle", 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},
+ // Legal parse but illegal execution: non-function should have no arguments.
+ {"bug7a", "{{3 2}}", "", tVal, false},
+ {"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
+ {"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
}
func zeroArgs() string {
@@ -451,7 +500,7 @@ func vfunc(V, *V) string {
return "vfunc"
}
-func testExecute(execTests []execTest, set *Set, t *testing.T) {
+func testExecute(execTests []execTest, template *Template, t *testing.T) {
b := new(bytes.Buffer)
funcs := FuncMap{
"count": count,
@@ -461,8 +510,13 @@ func testExecute(execTests []execTest, set *Set, t *testing.T) {
"zeroArgs": zeroArgs,
}
for _, test := range execTests {
- tmpl := New(test.name).Funcs(funcs)
- _, err := tmpl.ParseInSet(test.input, set)
+ var tmpl *Template
+ var err error
+ if template == nil {
+ tmpl, err = New(test.name).Funcs(funcs).Parse(test.input)
+ } else {
+ tmpl, err = template.New(test.name).Funcs(funcs).Parse(test.input)
+ }
if err != nil {
t.Errorf("%s: parse error: %s", test.name, err)
continue
@@ -493,22 +547,66 @@ func TestExecute(t *testing.T) {
testExecute(execTests, nil, t)
}
+var delimPairs = []string{
+ "", "", // default
+ "{{", "}}", // same as default
+ "<<", ">>", // distinct
+ "|", "|", // same
+ "(日)", "(本)", // peculiar
+}
+
+func TestDelims(t *testing.T) {
+ const hello = "Hello, world"
+ var value = struct{ Str string }{hello}
+ for i := 0; i < len(delimPairs); i += 2 {
+ text := ".Str"
+ left := delimPairs[i+0]
+ trueLeft := left
+ right := delimPairs[i+1]
+ trueRight := right
+ if left == "" { // default case
+ trueLeft = "{{"
+ }
+ if right == "" { // default case
+ trueRight = "}}"
+ }
+ text = trueLeft + text + trueRight
+ // Now add a comment
+ text += trueLeft + "/*comment*/" + trueRight
+ // Now add an action containing a string.
+ text += trueLeft + `"` + trueLeft + `"` + trueRight
+ // At this point text looks like `{{.Str}}{{/*comment*/}}{{"{{"}}`.
+ tmpl, err := New("delims").Delims(left, right).Parse(text)
+ if err != nil {
+ t.Fatalf("delim %q text %q parse err %s", left, text, err)
+ }
+ var b = new(bytes.Buffer)
+ err = tmpl.Execute(b, value)
+ if err != nil {
+ t.Fatalf("delim %q exec err %s", left, err)
+ }
+ if b.String() != hello+trueLeft {
+ t.Errorf("expected %q got %q", hello+trueLeft, b.String())
+ }
+ }
+}
+
// 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}}")
+ _, err := tmpl.Parse("{{.MyError 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()) {
+ } else if !strings.Contains(err.Error(), myError.Error()) {
if *debug {
fmt.Printf("test execute error: %s\n", err)
}
- t.Errorf("expected os.EPERM; got %s", err)
+ t.Errorf("expected myError; got %s", err)
}
}
@@ -538,18 +636,19 @@ type Tree struct {
Left, Right *Tree
}
+// Use different delimiters to test Set.Delims.
const treeTemplate = `
- {{define "tree"}}
+ (define "tree")
[
- {{.Val}}
- {{with .Left}}
- {{template "tree" .}}
- {{end}}
- {{with .Right}}
- {{template "tree" .}}
- {{end}}
+ (.Val)
+ (with .Left)
+ (template "tree" .)
+ (end)
+ (with .Right)
+ (template "tree" .)
+ (end)
]
- {{end}}
+ (end)
`
func TestTree(t *testing.T) {
@@ -589,24 +688,34 @@ func TestTree(t *testing.T) {
},
},
}
- set := new(Set)
- _, err := set.Parse(treeTemplate)
+ tmpl, err := New("root").Delims("(", ")").Parse(treeTemplate)
if err != nil {
t.Fatal("parse error:", err)
}
var b bytes.Buffer
- err = set.Execute(&b, "tree", tree)
- if err != nil {
- t.Fatal("exec error:", err)
- }
- stripSpace := func(r int) int {
+ stripSpace := func(r rune) rune {
if r == '\t' || r == '\n' {
return -1
}
return r
}
- result := strings.Map(stripSpace, b.String())
const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
+ // First by looking up the template.
+ err = tmpl.Lookup("tree").Execute(&b, tree)
+ if err != nil {
+ t.Fatal("exec error:", err)
+ }
+ result := strings.Map(stripSpace, b.String())
+ if result != expect {
+ t.Errorf("expected %q got %q", expect, result)
+ }
+ // Then direct to execution.
+ b.Reset()
+ err = tmpl.ExecuteTemplate(&b, "tree", tree)
+ if err != nil {
+ t.Fatal("exec error:", err)
+ }
+ result = strings.Map(stripSpace, b.String())
if result != expect {
t.Errorf("expected %q got %q", expect, result)
}
diff --git a/src/pkg/template/funcs.go b/src/pkg/text/template/funcs.go
index feb1fd82c..525179cb4 100644
--- a/src/pkg/template/funcs.go
+++ b/src/pkg/text/template/funcs.go
@@ -8,22 +8,23 @@ import (
"bytes"
"fmt"
"io"
- "os"
+ "net/url"
"reflect"
"strings"
"unicode"
- "url"
- "utf8"
+ "unicode/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.
+// which the second has type error. In that case, if the second (error)
+// argument evaluates to non-nil during execution, execution terminates and
+// Execute returns that error.
type FuncMap map[string]interface{}
var builtins = FuncMap{
"and": and,
+ "call": call,
"html": HTMLEscaper,
"index": index,
"js": JSEscaper,
@@ -69,28 +70,23 @@ func addFuncs(out, in FuncMap) {
// 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.
+ // We allow functions with 1 result or 2 results where the second is an error.
switch {
case typ.NumOut() == 1:
return true
- case typ.NumOut() == 2 && typ.Out(1) == osErrorType:
+ case typ.NumOut() == 2 && typ.Out(1) == errorType:
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 {
+// findFunction looks for a function in the template, and global map.
+func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
+ if tmpl != nil && tmpl.common != nil {
if fn := tmpl.execFuncs[name]; fn.IsValid() {
return fn, true
}
}
- if set != nil {
- if fn := set.execFuncs[name]; fn.IsValid() {
- return fn, true
- }
- }
if fn := builtinFuncs[name]; fn.IsValid() {
return fn, true
}
@@ -102,7 +98,7 @@ func findFunction(name string, tmpl *Template, set *Set) (reflect.Value, bool) {
// 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) {
+func index(item interface{}, indices ...interface{}) (interface{}, error) {
v := reflect.ValueOf(item)
for _, i := range indices {
index := reflect.ValueOf(i)
@@ -144,7 +140,7 @@ func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
// Length
// length returns the length of the item, with an error if it has no defined length.
-func length(item interface{}) (int, os.Error) {
+func length(item interface{}) (int, error) {
v, isNil := indirect(reflect.ValueOf(item))
if isNil {
return 0, fmt.Errorf("len of nil pointer")
@@ -156,6 +152,53 @@ func length(item interface{}) (int, os.Error) {
return 0, fmt.Errorf("len of type %s", v.Type())
}
+// Function invocation
+
+// call returns the result of evaluating the the first argument as a function.
+// The function must return 1 result, or 2 results, the second of which is an error.
+func call(fn interface{}, args ...interface{}) (interface{}, error) {
+ v := reflect.ValueOf(fn)
+ typ := v.Type()
+ if typ.Kind() != reflect.Func {
+ return nil, fmt.Errorf("non-function of type %s", typ)
+ }
+ if !goodFunc(typ) {
+ return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
+ }
+ numIn := typ.NumIn()
+ var dddType reflect.Type
+ if typ.IsVariadic() {
+ if len(args) < numIn-1 {
+ return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
+ }
+ dddType = typ.In(numIn - 1).Elem()
+ } else {
+ if len(args) != numIn {
+ return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
+ }
+ }
+ argv := make([]reflect.Value, len(args))
+ for i, arg := range args {
+ value := reflect.ValueOf(arg)
+ // Compute the expected type. Clumsy because of variadics.
+ var argType reflect.Type
+ if !typ.IsVariadic() || i < numIn-1 {
+ argType = typ.In(i)
+ } else {
+ argType = dddType
+ }
+ if !value.Type().AssignableTo(argType) {
+ return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
+ }
+ argv[i] = reflect.ValueOf(arg)
+ }
+ result := v.Call(argv)
+ if len(result) == 2 {
+ return result[0].Interface(), result[1].Interface().(error)
+ }
+ return result[0].Interface(), nil
+}
+
// Boolean logic.
func truth(a interface{}) bool {
@@ -279,7 +322,7 @@ func JSEscape(w io.Writer, b []byte) {
for i := 0; i < len(b); i++ {
c := b[i]
- if !jsIsSpecial(int(c)) {
+ if !jsIsSpecial(rune(c)) {
// fast path: nothing to do
continue
}
@@ -307,12 +350,11 @@ func JSEscape(w io.Writer, b []byte) {
}
} else {
// Unicode rune.
- rune, size := utf8.DecodeRune(b[i:])
- if unicode.IsPrint(rune) {
+ r, size := utf8.DecodeRune(b[i:])
+ if unicode.IsPrint(r) {
w.Write(b[i : i+size])
} else {
- // TODO(dsymonds): Do this without fmt?
- fmt.Fprintf(w, "\\u%04X", rune)
+ fmt.Fprintf(w, "\\u%04X", r)
}
i += size - 1
}
@@ -332,12 +374,12 @@ func JSEscapeString(s string) string {
return b.String()
}
-func jsIsSpecial(rune int) bool {
- switch rune {
+func jsIsSpecial(r rune) bool {
+ switch r {
case '\\', '\'', '"', '<', '>':
return true
}
- return rune < ' ' || utf8.RuneSelf <= rune
+ return r < ' ' || utf8.RuneSelf <= r
}
// JSEscaper returns the escaped JavaScript equivalent of the textual
diff --git a/src/pkg/text/template/helper.go b/src/pkg/text/template/helper.go
new file mode 100644
index 000000000..3636fb54d
--- /dev/null
+++ b/src/pkg/text/template/helper.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.
+
+// Helper functions to make constructing templates easier.
+
+package template
+
+import (
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+)
+
+// Functions and methods to parse templates.
+
+// Must is a helper that wraps a call to a function returning (*Template, error)
+// and panics if the error is non-nil. It is intended for use in variable
+// initializations such as
+// var t = template.Must(template.New("name").Parse("text"))
+func Must(t *Template, err error) *Template {
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// ParseFiles creates a new Template and parses the template definitions from
+// the named files. The returned template's name will have the (base) name and
+// (parsed) contents of the first file. There must be at least one file.
+// If an error occurs, parsing stops and the returned *Template is nil.
+func ParseFiles(filenames ...string) (*Template, error) {
+ return parseFiles(nil, filenames...)
+}
+
+// ParseFiles parses the named files and associates the resulting templates with
+// t. If an error occurs, parsing stops and the returned template is nil;
+// otherwise it is t. There must be at least one file.
+func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
+ return parseFiles(t, filenames...)
+}
+
+// parseFiles is the helper for the method and function. If the argument
+// template is nil, it is created from the first file.
+func parseFiles(t *Template, filenames ...string) (*Template, error) {
+ if len(filenames) == 0 {
+ // Not really a problem, but be consistent.
+ return nil, fmt.Errorf("template: no files named in call to ParseFiles")
+ }
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ s := string(b)
+ name := filepath.Base(filename)
+ // First template becomes return value if not already defined,
+ // and we use that one for subsequent New calls to associate
+ // all the templates together. Also, if this file has the same name
+ // as t, this file becomes the contents of t, so
+ // t, err := New(name).Funcs(xxx).ParseFiles(name)
+ // works. Otherwise we create a new template associated with t.
+ var tmpl *Template
+ if t == nil {
+ t = New(name)
+ }
+ if name == t.Name() {
+ tmpl = t
+ } else {
+ tmpl = t.New(name)
+ }
+ _, err = tmpl.Parse(s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return t, nil
+}
+
+// ParseGlob creates a new Template and parses the template definitions from the
+// files identified by the pattern, which must match at least one file. The
+// returned template will have the (base) name and (parsed) contents of the
+// first file matched by the pattern. ParseGlob is equivalent to calling
+// ParseFiles with the list of files matched by the pattern.
+func ParseGlob(pattern string) (*Template, error) {
+ return parseGlob(nil, pattern)
+}
+
+// ParseGlob parses the template definitions in the files identified by the
+// pattern and associates the resulting templates with t. The pattern is
+// processed by filepath.Glob and must match at least one file. ParseGlob is
+// equivalent to calling t.ParseFiles with the list of files matched by the
+// pattern.
+func (t *Template) ParseGlob(pattern string) (*Template, error) {
+ return parseGlob(t, pattern)
+}
+
+// parseGlob is the implementation of the function and method ParseGlob.
+func parseGlob(t *Template, pattern string) (*Template, error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ if len(filenames) == 0 {
+ return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
+ }
+ return parseFiles(t, filenames...)
+}
diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go
new file mode 100644
index 000000000..bd98bd047
--- /dev/null
+++ b/src/pkg/text/template/multi_test.go
@@ -0,0 +1,280 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+// Tests for mulitple-template parsing and execution.
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "testing"
+ "text/template/parse"
+)
+
+const (
+ noError = true
+ hasError = false
+)
+
+type multiParseTest struct {
+ name string
+ input string
+ ok bool
+ names []string
+ results []string
+}
+
+var multiParseTests = []multiParseTest{
+ {"empty", "", noError,
+ nil,
+ nil},
+ {"one", `{{define "foo"}} FOO {{end}}`, noError,
+ []string{"foo"},
+ []string{`" FOO "`}},
+ {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
+ []string{"foo", "bar"},
+ []string{`" FOO "`, `" BAR "`}},
+ // errors
+ {"missing end", `{{define "foo"}} FOO `, hasError,
+ nil,
+ nil},
+ {"malformed name", `{{define "foo}} FOO `, hasError,
+ nil,
+ nil},
+}
+
+func TestMultiParse(t *testing.T) {
+ for _, test := range multiParseTests {
+ template, err := New("root").Parse(test.input)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ if template == nil {
+ continue
+ }
+ if len(template.tmpl) != len(test.names)+1 { // +1 for root
+ t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(template.tmpl))
+ continue
+ }
+ for i, name := range test.names {
+ tmpl, ok := template.tmpl[name]
+ if !ok {
+ t.Errorf("%s: can't find template %q", test.name, name)
+ continue
+ }
+ result := tmpl.Root.String()
+ if result != test.results[i] {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
+ }
+ }
+ }
+}
+
+var multiExecTests = []execTest{
+ {"empty", "", "", nil, true},
+ {"text", "some text", "some text", nil, true},
+ {"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
+ {"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
+ {"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
+ {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
+ {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
+ {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+ {"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+
+ // User-defined function: test argument evaluator.
+ {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
+ {"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
+}
+
+// These strings are also in testdata/*.
+const multiText1 = `
+ {{define "x"}}TEXT{{end}}
+ {{define "dotV"}}{{.V}}{{end}}
+`
+
+const multiText2 = `
+ {{define "dot"}}{{.}}{{end}}
+ {{define "nested"}}{{template "dot" .}}{{end}}
+`
+
+func TestMultiExecute(t *testing.T) {
+ // Declare a couple of templates first.
+ template, err := New("root").Parse(multiText1)
+ if err != nil {
+ t.Fatalf("parse error for 1: %s", err)
+ }
+ _, err = template.Parse(multiText2)
+ if err != nil {
+ t.Fatalf("parse error for 2: %s", err)
+ }
+ testExecute(multiExecTests, template, t)
+}
+
+func TestParseFiles(t *testing.T) {
+ _, err := ParseFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ template := New("root")
+ _, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(multiExecTests, template, t)
+}
+
+func TestParseGlob(t *testing.T) {
+ _, err := ParseGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = New("error").ParseGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ template := New("root")
+ _, err = template.ParseGlob("testdata/file*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(multiExecTests, template, t)
+}
+
+// In these tests, actual content (not just template definitions) comes from the parsed files.
+
+var templateFileExecTests = []execTest{
+ {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
+}
+
+func TestParseFilesWithData(t *testing.T) {
+ template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, template, t)
+}
+
+func TestParseGlobWithData(t *testing.T) {
+ template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, template, t)
+}
+
+const (
+ cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
+ cloneText2 = `{{define "b"}}b{{end}}`
+ cloneText3 = `{{define "c"}}root{{end}}`
+ cloneText4 = `{{define "c"}}clone{{end}}`
+)
+
+func TestClone(t *testing.T) {
+ // Create some templates and clone the root.
+ root, err := New("root").Parse(cloneText1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = root.Parse(cloneText2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ clone := Must(root.Clone())
+ // Add variants to both.
+ _, err = root.Parse(cloneText3)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = clone.Parse(cloneText4)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Verify that the clone is self-consistent.
+ for k, v := range clone.tmpl {
+ if k == clone.name && v.tmpl[k] != clone {
+ t.Error("clone does not contain root")
+ }
+ if v != v.tmpl[v.name] {
+ t.Errorf("clone does not contain self for %q", k)
+ }
+ }
+ // Execute root.
+ var b bytes.Buffer
+ err = root.ExecuteTemplate(&b, "a", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if b.String() != "broot" {
+ t.Errorf("expected %q got %q", "broot", b.String())
+ }
+ // Execute copy.
+ b.Reset()
+ err = clone.ExecuteTemplate(&b, "a", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if b.String() != "bclone" {
+ t.Errorf("expected %q got %q", "bclone", b.String())
+ }
+}
+
+func TestAddParseTree(t *testing.T) {
+ // Create some templates.
+ root, err := New("root").Parse(cloneText1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = root.Parse(cloneText2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Add a new parse tree.
+ tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins)
+ if err != nil {
+ t.Fatal(err)
+ }
+ added, err := root.AddParseTree("c", tree["c"])
+ // Execute.
+ var b bytes.Buffer
+ err = added.ExecuteTemplate(&b, "a", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if b.String() != "broot" {
+ t.Errorf("expected %q got %q", "broot", b.String())
+ }
+}
+
+func TestRedefinition(t *testing.T) {
+ var tmpl *Template
+ var err error
+ if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil {
+ t.Fatalf("parse 1: %v", err)
+ }
+ if _, err = tmpl.Parse(`{{define "test"}}bar{{end}}`); err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "redefinition") {
+ t.Fatalf("expected redefinition error; got %v", err)
+ }
+ if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "redefinition") {
+ t.Fatalf("expected redefinition error; got %v", err)
+ }
+}
diff --git a/src/pkg/template/parse/lex.go b/src/pkg/text/template/parse/lex.go
index 83ad6c628..7705c0b88 100644
--- a/src/pkg/template/parse/lex.go
+++ b/src/pkg/text/template/parse/lex.go
@@ -8,7 +8,7 @@ import (
"fmt"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// item represents a token or text string returned from the scanner.
@@ -119,31 +119,33 @@ 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.
+ name string // the name of the input; used only for error reports.
+ input string // the string being scanned.
+ leftDelim string // start of action.
+ rightDelim string // end of action.
+ 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) {
+func (l *lexer) next() (r rune) {
if l.pos >= len(l.input) {
l.width = 0
return eof
}
- rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+ r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
l.pos += l.width
- return rune
+ return r
}
// peek returns but does not consume the next rune in the input.
-func (l *lexer) peek() int {
- rune := l.next()
+func (l *lexer) peek() rune {
+ r := l.next()
l.backup()
- return rune
+ return r
}
// backup steps back one rune. Can only be called once per call of next.
@@ -185,7 +187,7 @@ func (l *lexer) lineNumber() int {
}
// error returns an error token and terminates the scan by passing
-// back a nil pointer that will be the next state, terminating l.run.
+// back a nil pointer that will be the next state, terminating l.nextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
l.items <- item{itemError, fmt.Sprintf(format, args...)}
return nil
@@ -205,12 +207,20 @@ func (l *lexer) nextItem() item {
}
// lex creates a new scanner for the input string.
-func lex(name, input string) *lexer {
+func lex(name, input, left, right string) *lexer {
+ if left == "" {
+ left = leftDelim
+ }
+ if right == "" {
+ right = rightDelim
+ }
l := &lexer{
- name: name,
- input: input,
- state: lexText,
- items: make(chan item, 2), // Two items of buffering is sufficient for all state functions
+ name: name,
+ input: input,
+ leftDelim: left,
+ rightDelim: right,
+ state: lexText,
+ items: make(chan item, 2), // Two items of buffering is sufficient for all state functions
}
return l
}
@@ -220,14 +230,14 @@ func lex(name, input string) *lexer {
const (
leftDelim = "{{"
rightDelim = "}}"
- leftComment = "{{/*"
- rightComment = "*/}}"
+ leftComment = "/*"
+ rightComment = "*/"
)
// lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn {
for {
- if strings.HasPrefix(l.input[l.pos:], leftDelim) {
+ if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
if l.pos > l.start {
l.emit(itemText)
}
@@ -247,28 +257,28 @@ func lexText(l *lexer) stateFn {
// lexLeftDelim scans the left delimiter, which is known to be present.
func lexLeftDelim(l *lexer) stateFn {
- if strings.HasPrefix(l.input[l.pos:], leftComment) {
+ if strings.HasPrefix(l.input[l.pos:], l.leftDelim+leftComment) {
return lexComment
}
- l.pos += len(leftDelim)
+ l.pos += len(l.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)
+ i := strings.Index(l.input[l.pos:], rightComment+l.rightDelim)
if i < 0 {
return l.errorf("unclosed comment")
}
- l.pos += i + len(rightComment)
+ l.pos += i + len(rightComment) + len(l.rightDelim)
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.pos += len(l.rightDelim)
l.emit(itemRightDelim)
return lexText
}
@@ -278,7 +288,7 @@ 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) {
+ if strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
return lexRightDelim
}
switch r := l.next(); {
@@ -337,6 +347,9 @@ Loop:
default:
l.backup()
word := l.input[l.start:l.pos]
+ if !l.atTerminator() {
+ return l.errorf("unexpected character %+U", r)
+ }
switch {
case key[word] > itemKeyword:
l.emit(key[word])
@@ -355,6 +368,28 @@ Loop:
return lexInsideAction
}
+// atTerminator reports whether the input is at valid termination character to
+// appear after an identifier. Mostly to catch cases like "$x+2" not being
+// acceptable without a space, in case we decide one day to implement
+// arithmetic.
+func (l *lexer) atTerminator() bool {
+ r := l.peek()
+ if isSpace(r) {
+ return true
+ }
+ switch r {
+ case eof, ',', '|', ':':
+ return true
+ }
+ // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
+ // succeed but should fail) but only in extremely rare cases caused by willfully
+ // bad choice of delimiter.
+ if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
+ return true
+ }
+ return false
+}
+
// lexChar scans a character constant. The initial quote is already
// scanned. Syntax checking is done by the parse.
func lexChar(l *lexer) stateFn {
@@ -458,7 +493,7 @@ Loop:
}
// isSpace reports whether r is a space character.
-func isSpace(r int) bool {
+func isSpace(r rune) bool {
switch r {
case ' ', '\t', '\n', '\r':
return true
@@ -467,6 +502,6 @@ func isSpace(r int) bool {
}
// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
-func isAlphaNumeric(r int) bool {
+func isAlphaNumeric(r rune) bool {
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
}
diff --git a/src/pkg/template/parse/lex_test.go b/src/pkg/text/template/parse/lex_test.go
index d71c8e66d..6ee1b4701 100644
--- a/src/pkg/template/parse/lex_test.go
+++ b/src/pkg/text/template/parse/lex_test.go
@@ -201,8 +201,8 @@ var lexTests = []lexTest{
}
// collect gathers the emitted items into a slice.
-func collect(t *lexTest) (items []item) {
- l := lex(t.name, t.input)
+func collect(t *lexTest, left, right string) (items []item) {
+ l := lex(t.name, t.input, left, right)
for {
item := l.nextItem()
items = append(items, item)
@@ -215,7 +215,41 @@ func collect(t *lexTest) (items []item) {
func TestLex(t *testing.T) {
for _, test := range lexTests {
- items := collect(&test)
+ 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)
+ }
+ }
+}
+
+// Some easy cases from above, but with delimiters $$ and @@
+var lexDelimTests = []lexTest{
+ {"punctuation", "$$,@%{{}}@@", []item{
+ tLeftDelim,
+ {itemChar, ","},
+ {itemChar, "@"},
+ {itemChar, "%"},
+ {itemChar, "{"},
+ {itemChar, "{"},
+ {itemChar, "}"},
+ {itemChar, "}"},
+ tRightDelim,
+ tEOF,
+ }},
+ {"empty action", `$$@@`, []item{tLeftDelim, tRightDelim, tEOF}},
+ {"for", `$$for @@`, []item{tLeftDelim, tFor, tRightDelim, tEOF}},
+ {"quote", `$$"abc \n\t\" "@@`, []item{tLeftDelim, tQuote, tRightDelim, tEOF}},
+ {"raw quote", "$$" + raw + "@@", []item{tLeftDelim, tRawQuote, tRightDelim, tEOF}},
+}
+
+var (
+ tLeftDelim = item{itemLeftDelim, "$$"}
+ tRightDelim = item{itemRightDelim, "@@"}
+)
+
+func TestDelims(t *testing.T) {
+ for _, test := range lexDelimTests {
+ items := collect(&test, "$$", "@@")
if !reflect.DeepEqual(items, test.items) {
t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
}
diff --git a/src/pkg/template/parse/node.go b/src/pkg/text/template/parse/node.go
index 6f0b429b9..db645624c 100644
--- a/src/pkg/template/parse/node.go
+++ b/src/pkg/text/template/parse/node.go
@@ -9,7 +9,6 @@ package parse
import (
"bytes"
"fmt"
- "os"
"strconv"
"strings"
)
@@ -18,6 +17,10 @@ import (
type Node interface {
Type() NodeType
String() string
+ // Copy does a deep copy of the Node and all its components.
+ // To avoid type assertions, some XxxNodes also have specialized
+ // CopyXxx methods that return *XxxNode.
+ Copy() Node
}
// NodeType identifies the type of a parse tree node.
@@ -68,14 +71,27 @@ func (l *ListNode) append(n Node) {
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()
}
+func (l *ListNode) CopyList() *ListNode {
+ if l == nil {
+ return l
+ }
+ n := newList()
+ for _, elem := range l.Nodes {
+ n.append(elem.Copy())
+ }
+ return n
+}
+
+func (l *ListNode) Copy() Node {
+ return l.CopyList()
+}
+
// TextNode holds plain text.
type TextNode struct {
NodeType
@@ -87,7 +103,11 @@ func newText(text string) *TextNode {
}
func (t *TextNode) String() string {
- return fmt.Sprintf("(text: %q)", t.Text)
+ return fmt.Sprintf("%q", t.Text)
+}
+
+func (t *TextNode) Copy() Node {
+ return &TextNode{NodeType: NodeText, Text: append([]byte{}, t.Text...)}
}
// PipeNode holds a pipeline with optional declaration
@@ -107,10 +127,42 @@ func (p *PipeNode) append(command *CommandNode) {
}
func (p *PipeNode) String() string {
- if p.Decl != nil {
- return fmt.Sprintf("%v := %v", p.Decl, p.Cmds)
+ s := ""
+ if len(p.Decl) > 0 {
+ for i, v := range p.Decl {
+ if i > 0 {
+ s += ", "
+ }
+ s += v.String()
+ }
+ s += " := "
+ }
+ for i, c := range p.Cmds {
+ if i > 0 {
+ s += " | "
+ }
+ s += c.String()
}
- return fmt.Sprintf("%v", p.Cmds)
+ return s
+}
+
+func (p *PipeNode) CopyPipe() *PipeNode {
+ if p == nil {
+ return p
+ }
+ var decl []*VariableNode
+ for _, d := range p.Decl {
+ decl = append(decl, d.Copy().(*VariableNode))
+ }
+ n := newPipeline(p.Line, decl)
+ for _, c := range p.Cmds {
+ n.append(c.Copy().(*CommandNode))
+ }
+ return n
+}
+
+func (p *PipeNode) Copy() Node {
+ return p.CopyPipe()
}
// ActionNode holds an action (something bounded by delimiters).
@@ -127,7 +179,13 @@ func newAction(line int, pipe *PipeNode) *ActionNode {
}
func (a *ActionNode) String() string {
- return fmt.Sprintf("(action: %v)", a.Pipe)
+ return fmt.Sprintf("{{%s}}", a.Pipe)
+
+}
+
+func (a *ActionNode) Copy() Node {
+ return newAction(a.Line, a.Pipe.CopyPipe())
+
}
// CommandNode holds a command (a pipeline inside an evaluating action).
@@ -145,7 +203,25 @@ func (c *CommandNode) append(arg Node) {
}
func (c *CommandNode) String() string {
- return fmt.Sprintf("(command: %v)", c.Args)
+ s := ""
+ for i, arg := range c.Args {
+ if i > 0 {
+ s += " "
+ }
+ s += arg.String()
+ }
+ return s
+}
+
+func (c *CommandNode) Copy() Node {
+ if c == nil {
+ return c
+ }
+ n := newCommand()
+ for _, c := range c.Args {
+ n.append(c.Copy())
+ }
+ return n
}
// IdentifierNode holds an identifier.
@@ -160,7 +236,11 @@ func NewIdentifier(ident string) *IdentifierNode {
}
func (i *IdentifierNode) String() string {
- return fmt.Sprintf("I=%s", i.Ident)
+ return i.Ident
+}
+
+func (i *IdentifierNode) Copy() Node {
+ return NewIdentifier(i.Ident)
}
// VariableNode holds a list of variable names. The dollar sign is
@@ -175,7 +255,18 @@ func newVariable(ident string) *VariableNode {
}
func (v *VariableNode) String() string {
- return fmt.Sprintf("V=%s", v.Ident)
+ s := ""
+ for i, id := range v.Ident {
+ if i > 0 {
+ s += "."
+ }
+ s += id
+ }
+ return s
+}
+
+func (v *VariableNode) Copy() Node {
+ return &VariableNode{NodeType: NodeVariable, Ident: append([]string{}, v.Ident...)}
}
// DotNode holds the special identifier '.'. It is represented by a nil pointer.
@@ -190,7 +281,11 @@ func (d *DotNode) Type() NodeType {
}
func (d *DotNode) String() string {
- return "{{<.>}}"
+ return "."
+}
+
+func (d *DotNode) Copy() Node {
+ return newDot()
}
// FieldNode holds a field (identifier starting with '.').
@@ -206,7 +301,15 @@ func newField(ident string) *FieldNode {
}
func (f *FieldNode) String() string {
- return fmt.Sprintf("F=%s", f.Ident)
+ s := ""
+ for _, id := range f.Ident {
+ s += "." + id
+ }
+ return s
+}
+
+func (f *FieldNode) Copy() Node {
+ return &FieldNode{NodeType: NodeField, Ident: append([]string{}, f.Ident...)}
}
// BoolNode holds a boolean constant.
@@ -220,7 +323,14 @@ func newBool(true bool) *BoolNode {
}
func (b *BoolNode) String() string {
- return fmt.Sprintf("B=%t", b.True)
+ if b.True {
+ return "true"
+ }
+ return "false"
+}
+
+func (b *BoolNode) Copy() Node {
+ return newBool(b.True)
}
// NumberNode holds a number: signed or unsigned integer, float, or complex.
@@ -239,7 +349,7 @@ type NumberNode struct {
Text string // The original textual representation from the input.
}
-func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
+func newNumber(text string, typ itemType) (*NumberNode, error) {
n := &NumberNode{NodeType: NodeNumber, Text: text}
switch typ {
case itemCharConstant:
@@ -268,7 +378,7 @@ func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
}
// 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])
+ f, err := strconv.ParseFloat(text[:len(text)-1], 64)
if err == nil {
n.IsComplex = true
n.Complex128 = complex(0, f)
@@ -277,12 +387,12 @@ func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
}
}
// Do integer test first so we get 0x123 etc.
- u, err := strconv.Btoui64(text, 0) // will fail for -0; fixed below.
+ u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
if err == nil {
n.IsUint = true
n.Uint64 = u
}
- i, err := strconv.Btoi64(text, 0)
+ i, err := strconv.ParseInt(text, 0, 64)
if err == nil {
n.IsInt = true
n.Int64 = i
@@ -299,7 +409,7 @@ func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
n.IsFloat = true
n.Float64 = float64(n.Uint64)
} else {
- f, err := strconv.Atof64(text)
+ f, err := strconv.ParseFloat(text, 64)
if err == nil {
n.IsFloat = true
n.Float64 = f
@@ -338,7 +448,13 @@ func (n *NumberNode) simplifyComplex() {
}
func (n *NumberNode) String() string {
- return fmt.Sprintf("N=%s", n.Text)
+ return n.Text
+}
+
+func (n *NumberNode) Copy() Node {
+ nn := new(NumberNode)
+ *nn = *n // Easy, fast, correct.
+ return nn
}
// StringNode holds a string constant. The value has been "unquoted".
@@ -353,7 +469,11 @@ func newString(orig, text string) *StringNode {
}
func (s *StringNode) String() string {
- return fmt.Sprintf("S=%#q", s.Text)
+ return s.Quoted
+}
+
+func (s *StringNode) Copy() Node {
+ return newString(s.Quoted, s.Text)
}
// endNode represents an {{end}} action. It is represented by a nil pointer.
@@ -372,6 +492,10 @@ func (e *endNode) String() string {
return "{{end}}"
}
+func (e *endNode) Copy() Node {
+ return newEnd()
+}
+
// elseNode represents an {{else}} action. Does not appear in the final tree.
type elseNode struct {
NodeType
@@ -390,8 +514,12 @@ func (e *elseNode) String() string {
return "{{else}}"
}
-// IfNode represents an {{if}} action and its commands.
-type IfNode struct {
+func (e *elseNode) Copy() Node {
+ return newElse(e.Line)
+}
+
+// BranchNode is the common representation of if, range, and with.
+type BranchNode struct {
NodeType
Line int // The line number in the input.
Pipe *PipeNode // The pipeline to be evaluated.
@@ -399,35 +527,61 @@ type IfNode struct {
ElseList *ListNode // What to execute if the value is empty (nil if absent).
}
+func (b *BranchNode) String() string {
+ name := ""
+ switch b.NodeType {
+ case NodeIf:
+ name = "if"
+ case NodeRange:
+ name = "range"
+ case NodeWith:
+ name = "with"
+ default:
+ panic("unknown branch type")
+ }
+ if b.ElseList != nil {
+ return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList)
+ }
+ return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
+}
+
+// IfNode represents an {{if}} action and its commands.
+type IfNode struct {
+ BranchNode
+}
+
func newIf(line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
- return &IfNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+ return &IfNode{BranchNode{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)
+func (i *IfNode) Copy() Node {
+ return newIf(i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
}
// 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).
+ BranchNode
}
func newRange(line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
- return &RangeNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+ return &RangeNode{BranchNode{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)
+func (r *RangeNode) Copy() Node {
+ return newRange(r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
+}
+
+// WithNode represents a {{with}} action and its commands.
+type WithNode struct {
+ BranchNode
+}
+
+func newWith(line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
+ return &WithNode{BranchNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
+}
+
+func (w *WithNode) Copy() Node {
+ return newWith(w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
}
// TemplateNode represents a {{template}} action.
@@ -449,22 +603,6 @@ func (t *TemplateNode) String() string {
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)
+func (t *TemplateNode) Copy() Node {
+ return newTemplate(t.Line, t.Name, t.Pipe.CopyPipe())
}
diff --git a/src/pkg/template/parse/parse.go b/src/pkg/text/template/parse/parse.go
index 691807466..c0087b278 100644
--- a/src/pkg/template/parse/parse.go
+++ b/src/pkg/text/template/parse/parse.go
@@ -2,22 +2,24 @@
// 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 builds parse trees for templates as defined by text/template
+// and html/template. Clients should use those packages to construct templates
+// rather than this one, which provides shared internal data structures not
+// intended for general use.
package parse
import (
+ "bytes"
"fmt"
- "os"
"runtime"
"strconv"
"unicode"
)
-// Tree is the representation of a parsed template.
+// Tree is the representation of a single parsed template.
type Tree struct {
- Name string // Name is the name of the template.
- Root *ListNode // Root is the top-level root of the parse tree.
+ Name string // name of the template represented by the tree.
+ Root *ListNode // top-level root of the tree.
// Parsing only; cleared after parse.
funcs []map[string]interface{}
lex *lexer
@@ -26,6 +28,16 @@ type Tree struct {
vars []string // variables defined at the moment.
}
+// Parse returns a map from template name to parse.Tree, created by parsing the
+// templates described in the argument string. The top-level template will be
+// given the specified name. If an error is encountered, parsing stops and an
+// empty map is returned with the error.
+func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
+ treeSet = make(map[string]*Tree)
+ _, err = New(name).Parse(text, leftDelim, rightDelim, treeSet, funcs...)
+ return
+}
+
// next returns the next token.
func (t *Tree) next() item {
if t.peekCount > 0 {
@@ -59,7 +71,7 @@ func (t *Tree) peek() item {
// Parsing.
-// New allocates a new template with the given name.
+// New allocates a new parse tree with the given name.
func New(name string, funcs ...map[string]interface{}) *Tree {
return &Tree{
Name: name,
@@ -75,7 +87,7 @@ func (t *Tree) errorf(format string, args ...interface{}) {
}
// error terminates processing.
-func (t *Tree) error(err os.Error) {
+func (t *Tree) error(err error) {
t.errorf("%s", err)
}
@@ -88,13 +100,22 @@ func (t *Tree) expect(expected itemType, context string) item {
return token
}
+// expectEither consumes the next token and guarantees it has one of the required types.
+func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
+ token := t.next()
+ if token.typ != expected1 && token.typ != expected2 {
+ t.errorf("expected %s or %s in %s; got %s", expected1, expected2, context, token)
+ }
+ return token
+}
+
// unexpected complains about the token and terminates processing.
func (t *Tree) unexpected(token item, context string) {
t.errorf("unexpected %s in %s", token, context)
}
// recover is the handler that turns panics into returns from the top level of Parse.
-func (t *Tree) recover(errp *os.Error) {
+func (t *Tree) recover(errp *error) {
e := recover()
if e != nil {
if _, ok := e.(runtime.Error); ok {
@@ -103,12 +124,12 @@ func (t *Tree) recover(errp *os.Error) {
if t != nil {
t.stopParse()
}
- *errp = e.(os.Error)
+ *errp = e.(error)
}
return
}
-// startParse starts the template parsing from the lexer.
+// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
t.Root = nil
t.lex = lex
@@ -144,31 +165,106 @@ func (t *Tree) atEOF() bool {
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) {
+// Parse parses the template definition string to construct a representation of
+// the template for execution. If either action delimiter string is empty, the
+// default ("{{" or "}}") is used. Embedded template definitions are added to
+// the treeSet map.
+func (t *Tree) Parse(s, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
defer t.recover(&err)
- t.startParse(funcs, lex(t.Name, s))
- t.parse(true)
+ t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
+ t.parse(treeSet)
+ t.add(treeSet)
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)
+// add adds tree to the treeSet.
+func (t *Tree) add(treeSet map[string]*Tree) {
+ tree := treeSet[t.Name]
+ if tree == nil || IsEmptyTree(tree.Root) {
+ treeSet[t.Name] = t
+ return
+ }
+ if !IsEmptyTree(t.Root) {
+ t.errorf("template: multiple definition of template %q", t.Name)
+ }
+}
+
+// IsEmptyTree reports whether this tree (node) is empty of everything but space.
+func IsEmptyTree(n Node) bool {
+ switch n := n.(type) {
+ case nil:
+ return true
+ case *ActionNode:
+ case *IfNode:
+ case *ListNode:
+ for _, node := range n.Nodes {
+ if !IsEmptyTree(node) {
+ return false
+ }
+ }
+ return true
+ case *RangeNode:
+ case *TemplateNode:
+ case *TextNode:
+ return len(bytes.TrimSpace(n.Text)) == 0
+ case *WithNode:
+ default:
+ panic("unknown node: " + n.String())
+ }
+ return false
+}
+
+// parse is the top-level parser for a template, essentially the same
+// as itemList except it also parses {{define}} actions.
+// It runs to EOF.
+func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
+ t.Root = newList()
+ for t.peek().typ != itemEOF {
+ if t.peek().typ == itemLeftDelim {
+ delim := t.next()
+ if t.next().typ == itemDefine {
+ newT := New("definition") // name will be updated once we know it.
+ newT.startParse(t.funcs, t.lex)
+ newT.parseDefinition(treeSet)
+ continue
+ }
+ t.backup2(delim)
+ }
+ n := t.textOrAction()
+ if n.Type() == nodeEnd {
+ t.errorf("unexpected %s", n)
+ }
+ t.Root.append(n)
+ }
+ return nil
+}
+
+// parseDefinition parses a {{define}} ... {{end}} template definition and
+// installs the definition in the treeSet map. The "define" keyword has already
+// been scanned.
+func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
+ const context = "define clause"
+ name := t.expectOneOf(itemString, itemRawString, context)
+ var err error
+ t.Name, err = strconv.Unquote(name.val)
+ if err != nil {
+ t.error(err)
}
- return next
+ t.expect(itemRightDelim, context)
+ var end Node
+ t.Root, end = t.itemList()
+ if end.Type() != nodeEnd {
+ t.errorf("unexpected %s in %s", end, context)
+ }
+ t.stopParse()
+ t.add(treeSet)
}
// 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) {
+// Terminates at {{end}} or {{else}}, returned separately.
+func (t *Tree) itemList() (list *ListNode, next Node) {
list = newList()
for t.peek().typ != itemEOF {
n := t.textOrAction()
@@ -178,10 +274,8 @@ func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
}
list.append(n)
}
- if !toEOF {
- t.unexpected(t.next(), "input")
- }
- return list, nil
+ t.errorf("unexpected EOF")
+ return
}
// textOrAction:
@@ -232,7 +326,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
for {
if v := t.peek(); v.typ == itemVariable {
t.next()
- if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
+ if next := t.peek(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
t.next()
variable := newVariable(v.val)
if len(variable.Ident) != 1 {
@@ -276,11 +370,11 @@ func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list,
defer t.popVars(len(t.vars))
pipe = t.pipeline(context)
var next Node
- list, next = t.itemList(false)
+ list, next = t.itemList()
switch next.Type() {
case nodeEnd: //done
case nodeElse:
- elseList, next = t.itemList(false)
+ elseList, next = t.itemList()
if next.Type() != nodeEnd {
t.errorf("expected end; found %s", next)
}
diff --git a/src/pkg/template/parse/parse_test.go b/src/pkg/text/template/parse/parse_test.go
index 1928c319d..b2e788238 100644
--- a/src/pkg/template/parse/parse_test.go
+++ b/src/pkg/text/template/parse/parse_test.go
@@ -150,7 +150,7 @@ type parseTest struct {
name string
input string
ok bool
- result string
+ result string // what the user would see in an error message.
}
const (
@@ -160,59 +160,61 @@ const (
var parseTests = []parseTest{
{"empty", "", noError,
- `[]`},
+ ``},
{"comment", "{{/*\n\n\n*/}}", noError,
- `[]`},
+ ``},
{"spaces", " \t\n", noError,
- `[(text: " \t\n")]`},
+ `" \t\n"`},
{"text", "some text", noError,
- `[(text: "some text")]`},
+ `"some text"`},
{"emptyAction", "{{}}", hasError,
- `[(action: [])]`},
+ `{{}}`},
{"field", "{{.X}}", noError,
- `[(action: [(command: [F=[X]])])]`},
+ `{{.X}}`},
{"simple command", "{{printf}}", noError,
- `[(action: [(command: [I=printf])])]`},
+ `{{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])])])]"},
+ "{{with $x := 3}}{{$x 23}}{{end}}"},
{"variable with fields", "{{$.I}}", noError,
- "[(action: [(command: [V=[$ I]])])]"},
+ "{{$.I}}"},
{"multi-word command", "{{printf `%d` 23}}", noError,
- "[(action: [(command: [I=printf S=`%d` N=23])])]"},
+ "{{printf `%d` 23}}"},
{"pipeline", "{{.X|.Y}}", noError,
- `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ `{{.X | .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]])])]`},
+ `{{$x := .X | .Y}}`},
{"simple if", "{{if .X}}hello{{end}}", noError,
- `[({{if [(command: [F=[X]])]}} [(text: "hello")])]`},
+ `{{if .X}}"hello"{{end}}`},
{"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
- `[({{if [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ `{{if .X}}"true"{{else}}"false"{{end}}`},
{"simple range", "{{range .X}}hello{{end}}", noError,
- `[({{range [(command: [F=[X]])]}} [(text: "hello")])]`},
+ `{{range .X}}"hello"{{end}}`},
{"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
- `[({{range [(command: [F=[X Y Z]])]}} [(text: "hello")])]`},
+ `{{range .X.Y.Z}}"hello"{{end}}`},
{"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
- `[({{range [(command: [F=[X]])]}} [(text: "hello")({{range [(command: [F=[Y]])]}} [(text: "goodbye")])])]`},
+ `{{range .X}}"hello"{{range .Y}}"goodbye"{{end}}{{end}}`},
{"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
- `[({{range [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ `{{range .X}}"true"{{else}}"false"{{end}}`},
{"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
- `[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ `{{range .X | .M}}"true"{{else}}"false"{{end}}`},
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
- `[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
+ `{{range .SI}}{{.}}{{end}}`},
+ {"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
+ `{{range $x := .SI}}{{.}}{{end}}`},
+ {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
+ `{{range $x, $y := .SI}}{{.}}{{end}}`},
{"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'])]}} [])]`},
+ `{{range .SI 1 -3.2i true false 'a'}}{{end}}`},
{"template", "{{template `x`}}", noError,
- `[{{template "x"}}]`},
+ `{{template "x"}}`},
{"template with arg", "{{template `x` .Y}}", noError,
- `[{{template "x" [(command: [F=[Y]])]}}]`},
+ `{{template "x" .Y}}`},
{"with", "{{with .X}}hello{{end}}", noError,
- `[({{with [(command: [F=[X]])]}} [(text: "hello")])]`},
+ `{{with .X}}"hello"{{end}}`},
{"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
- `[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`},
+ `{{with .X}}"hello"{{else}}"goodbye"{{end}}`},
// Errors.
{"unclosed action", "hello{{range", hasError, ""},
{"unmatched end", "{{end}}", hasError, ""},
@@ -228,15 +230,26 @@ var parseTests = []parseTest{
{"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, ""},
+ // Equals (and other chars) do not assignments make (yet).
+ {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
+ {"bug0b", "{{$x = 1}}{{$x}}", hasError, ""},
+ {"bug0c", "{{$x ! 2}}{{$x}}", hasError, ""},
+ {"bug0d", "{{$x % 3}}{{$x}}", hasError, ""},
+ // Check the parse fails for := rather than comma.
+ {"bug0e", "{{range $x := $y := 3}}{{end}}", hasError, ""},
+ // Another bug: variable read must ignore following punctuation.
+ {"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""}, // ! is just illegal here.
+ {"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""}, // $x+2 should not parse as ($x) (+2).
+ {"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
}
var builtins = map[string]interface{}{
"printf": fmt.Sprintf,
}
-func TestParse(t *testing.T) {
+func testParse(doCopy bool, t *testing.T) {
for _, test := range parseTests {
- tmpl, err := New(test.name).Parse(test.input, builtins)
+ tmpl, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree), builtins)
switch {
case err == nil && !test.ok:
t.Errorf("%q: expected error; got none", test.name)
@@ -251,9 +264,55 @@ func TestParse(t *testing.T) {
}
continue
}
- result := tmpl.Root.String()
+ var result string
+ if doCopy {
+ result = tmpl.Root.Copy().String()
+ } else {
+ 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)
}
}
}
+
+func TestParse(t *testing.T) {
+ testParse(false, t)
+}
+
+// Same as TestParse, but we copy the node first
+func TestParseCopy(t *testing.T) {
+ testParse(true, t)
+}
+
+type isEmptyTest struct {
+ name string
+ input string
+ empty bool
+}
+
+var isEmptyTests = []isEmptyTest{
+ {"empty", ``, true},
+ {"nonempty", `hello`, false},
+ {"spaces only", " \t\n \t\n", true},
+ {"definition", `{{define "x"}}something{{end}}`, true},
+ {"definitions and space", "{{define `x`}}something{{end}}\n\n{{define `y`}}something{{end}}\n\n", true},
+ {"definitions and text", "{{define `x`}}something{{end}}\nx\n{{define `y`}}something{{end}}\ny\n}}", false},
+ {"definition and action", "{{define `x`}}something{{end}}{{if 3}}foo{{end}}", false},
+}
+
+func TestIsEmpty(t *testing.T) {
+ if !IsEmptyTree(nil) {
+ t.Errorf("nil tree is not empty")
+ }
+ for _, test := range isEmptyTests {
+ tree, err := New("root").Parse(test.input, "", "", make(map[string]*Tree), nil)
+ if err != nil {
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ }
+ if empty := IsEmptyTree(tree.Root); empty != test.empty {
+ t.Errorf("%q: expected %t got %t", test.name, test.empty, empty)
+ }
+ }
+}
diff --git a/src/pkg/text/template/template.go b/src/pkg/text/template/template.go
new file mode 100644
index 000000000..82fc9e5e3
--- /dev/null
+++ b/src/pkg/text/template/template.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 template
+
+import (
+ "fmt"
+ "reflect"
+ "text/template/parse"
+)
+
+// common holds the information shared by related templates.
+type common struct {
+ tmpl map[string]*Template
+ // We use two maps, one for parsing and one for execution.
+ // This separation makes the API cleaner since it doesn't
+ // expose reflection to the client.
+ parseFuncs FuncMap
+ execFuncs map[string]reflect.Value
+}
+
+// Template is the representation of a parsed template. The *parse.Tree
+// field is exported only for use by html/template and should be treated
+// as unexported by all other clients.
+type Template struct {
+ name string
+ *parse.Tree
+ *common
+ leftDelim string
+ rightDelim string
+}
+
+// New allocates a new template with the given name.
+func New(name string) *Template {
+ return &Template{
+ name: name,
+ }
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+ return t.name
+}
+
+// New allocates a new template associated with the given one and with the same
+// delimiters. The association, which is transitive, allows one template to
+// invoke another with a {{template}} action.
+func (t *Template) New(name string) *Template {
+ t.init()
+ return &Template{
+ name: name,
+ common: t.common,
+ leftDelim: t.leftDelim,
+ rightDelim: t.rightDelim,
+ }
+}
+
+func (t *Template) init() {
+ if t.common == nil {
+ t.common = new(common)
+ t.tmpl = make(map[string]*Template)
+ t.parseFuncs = make(FuncMap)
+ t.execFuncs = make(map[string]reflect.Value)
+ }
+}
+
+// Clone returns a duplicate of the template, including all associated
+// templates. The actual representation is not copied, but the name space of
+// associated templates is, so further calls to Parse in the copy will add
+// templates to the copy but not to the original. Clone can be used to prepare
+// common templates and use them with variant definitions for other templates
+// by adding the variants after the clone is made.
+func (t *Template) Clone() (*Template, error) {
+ nt := t.copy(nil)
+ nt.init()
+ nt.tmpl[t.name] = nt
+ for k, v := range t.tmpl {
+ if k == t.name { // Already installed.
+ continue
+ }
+ // The associated templates share nt's common structure.
+ tmpl := v.copy(nt.common)
+ nt.tmpl[k] = tmpl
+ }
+ for k, v := range t.parseFuncs {
+ nt.parseFuncs[k] = v
+ }
+ for k, v := range t.execFuncs {
+ nt.execFuncs[k] = v
+ }
+ return nt, nil
+}
+
+// copy returns a shallow copy of t, with common set to the argument.
+func (t *Template) copy(c *common) *Template {
+ nt := New(t.name)
+ nt.Tree = t.Tree
+ nt.common = c
+ nt.leftDelim = t.leftDelim
+ nt.rightDelim = t.rightDelim
+ return nt
+}
+
+// AddParseTree creates a new template with the name and parse tree
+// and associates it with t.
+func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+ if t.tmpl[name] != nil {
+ return nil, fmt.Errorf("template: redefinition of template %q", name)
+ }
+ nt := t.New(name)
+ nt.Tree = tree
+ t.tmpl[name] = nt
+ return nt, nil
+}
+
+// Templates returns a slice of the templates associated with t, including t
+// itself.
+func (t *Template) Templates() []*Template {
+ // Return a slice so we don't expose the map.
+ m := make([]*Template, 0, len(t.tmpl))
+ for _, v := range t.tmpl {
+ m = append(m, v)
+ }
+ return m
+}
+
+// Delims sets the action delimiters to the specified strings, to be used in
+// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
+// definitions will inherit the settings. An empty delimiter stands for the
+// corresponding default: {{ or }}.
+// The return value is the template, so calls can be chained.
+func (t *Template) Delims(left, right string) *Template {
+ t.leftDelim = left
+ t.rightDelim = right
+ return t
+}
+
+// Funcs adds the elements of the argument map to the template's function map.
+// It panics if a value in the map is not a function with appropriate return
+// type. However, it is legal to overwrite elements of the map. The return
+// value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+ t.init()
+ addValueFuncs(t.execFuncs, funcMap)
+ addFuncs(t.parseFuncs, funcMap)
+ return t
+}
+
+// Lookup returns the template with the given name that is associated with t,
+// or nil if there is no such template.
+func (t *Template) Lookup(name string) *Template {
+ if t.common == nil {
+ return nil
+ }
+ return t.tmpl[name]
+}
+
+// Parse parses a string into a template. Nested template definitions will be
+// associated with the top-level template t. Parse may be called multiple times
+// to parse definitions of templates to associate with t. It is an error if a
+// resulting template is non-empty (contains content other than template
+// definitions) and would replace a non-empty template with the same name.
+// (In multiple calls to Parse with the same receiver template, only one call
+// can contain text other than space, comments, and template definitions.)
+func (t *Template) Parse(text string) (*Template, error) {
+ t.init()
+ trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ // Add the newly parsed trees, including the one for t, into our common structure.
+ for name, tree := range trees {
+ // If the name we parsed is the name of this template, overwrite this template.
+ // The associate method checks it's not a redefinition.
+ tmpl := t
+ if name != t.name {
+ tmpl = t.New(name)
+ }
+ // Even if t == tmpl, we need to install it in the common.tmpl map.
+ if replace, err := t.associate(tmpl, tree); err != nil {
+ return nil, err
+ } else if replace {
+ tmpl.Tree = tree
+ }
+ tmpl.leftDelim = t.leftDelim
+ tmpl.rightDelim = t.rightDelim
+ }
+ return t, nil
+}
+
+// associate installs the new template into the group of templates associated
+// with t. It is an error to reuse a name except to overwrite an empty
+// template. The two are already known to share the common structure.
+// The boolean return value reports wither to store this tree as t.Tree.
+func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
+ if new.common != t.common {
+ panic("internal error: associate not common")
+ }
+ name := new.name
+ if old := t.tmpl[name]; old != nil {
+ oldIsEmpty := parse.IsEmptyTree(old.Root)
+ newIsEmpty := parse.IsEmptyTree(tree.Root)
+ if newIsEmpty {
+ // Whether old is empty or not, new is empty; no reason to replace old.
+ return false, nil
+ }
+ if !oldIsEmpty {
+ return false, fmt.Errorf("template: redefinition of template %q", name)
+ }
+ }
+ t.tmpl[name] = new
+ return true, nil
+}
diff --git a/src/pkg/template/testdata/file1.tmpl b/src/pkg/text/template/testdata/file1.tmpl
index febf9d9f8..febf9d9f8 100644
--- a/src/pkg/template/testdata/file1.tmpl
+++ b/src/pkg/text/template/testdata/file1.tmpl
diff --git a/src/pkg/template/testdata/file2.tmpl b/src/pkg/text/template/testdata/file2.tmpl
index 39bf6fb9e..39bf6fb9e 100644
--- a/src/pkg/template/testdata/file2.tmpl
+++ b/src/pkg/text/template/testdata/file2.tmpl
diff --git a/src/pkg/text/template/testdata/tmpl1.tmpl b/src/pkg/text/template/testdata/tmpl1.tmpl
new file mode 100644
index 000000000..b72b3a340
--- /dev/null
+++ b/src/pkg/text/template/testdata/tmpl1.tmpl
@@ -0,0 +1,3 @@
+template1
+{{define "x"}}x{{end}}
+{{template "y"}}
diff --git a/src/pkg/text/template/testdata/tmpl2.tmpl b/src/pkg/text/template/testdata/tmpl2.tmpl
new file mode 100644
index 000000000..16beba6e7
--- /dev/null
+++ b/src/pkg/text/template/testdata/tmpl2.tmpl
@@ -0,0 +1,3 @@
+template2
+{{define "y"}}y{{end}}
+{{template "x"}}
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile
deleted file mode 100644
index a6fce3fa1..000000000
--- a/src/pkg/time/Makefile
+++ /dev/null
@@ -1,46 +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.
-
-include ../../Make.inc
-
-TARG=time
-GOFILES=\
- format.go\
- sleep.go\
- sys.go\
- tick.go\
- time.go\
-
-GOFILES_freebsd=\
- sys_posix.go\
- zoneinfo_posix.go\
- zoneinfo_unix.go\
-
-GOFILES_darwin=\
- sys_posix.go\
- zoneinfo_posix.go\
- zoneinfo_unix.go\
-
-GOFILES_linux=\
- sys_posix.go\
- zoneinfo_posix.go\
- zoneinfo_unix.go\
-
-GOFILES_openbsd=\
- sys_posix.go\
- zoneinfo_posix.go\
- zoneinfo_unix.go\
-
-GOFILES_windows=\
- sys_posix.go\
- zoneinfo_windows.go\
-
-GOFILES_plan9=\
- sys_plan9.go\
- zoneinfo_posix.go\
- zoneinfo_plan9.go\
-
-GOFILES+=$(GOFILES_$(GOOS))
-
-include ../../Make.pkg
diff --git a/src/pkg/time/example_test.go b/src/pkg/time/example_test.go
new file mode 100644
index 000000000..944cc789c
--- /dev/null
+++ b/src/pkg/time/example_test.go
@@ -0,0 +1,58 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "fmt"
+ "time"
+)
+
+func expensiveCall() {}
+
+func ExampleDuration() {
+ t0 := time.Now()
+ expensiveCall()
+ t1 := time.Now()
+ fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
+}
+
+var c chan int
+
+func handle(int) {}
+
+func ExampleAfter() {
+ select {
+ case m := <-c:
+ handle(m)
+ case <-time.After(5 * time.Minute):
+ fmt.Println("timed out")
+ }
+}
+
+func ExampleSleep() {
+ time.Sleep(100 * time.Millisecond)
+}
+
+func statusUpdate() string { return "" }
+
+func ExampleTick() {
+ c := time.Tick(1 * time.Minute)
+ for now := range c {
+ fmt.Printf("%v %s\n", now, statusUpdate())
+ }
+}
+
+func ExampleMonth() {
+ _, month, day := time.Now().Date()
+ if month == time.November && day == 10 {
+ fmt.Println("Happy Go day!")
+ }
+}
+
+func ExampleDate() {
+ t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+ fmt.Printf("Go launched at %s\n", t.Local())
+ // Output: Go launched at 2009-11-10 15:00:00 -0800 PST
+}
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 5ddd54812..ad52bab21 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -1,33 +1,30 @@
-package time
+// 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.
-import (
- "bytes"
- "os"
- "strconv"
-)
+package time
-const (
- numeric = iota
- alphabetic
- separator
- plus
- minus
-)
+import "errors"
// These are predefined layouts for use in Time.Format.
// The standard time used in the layouts is:
-// Mon Jan 2 15:04:05 MST 2006 (MST is GMT-0700)
-// which is Unix time 1136243045.
-// (Think of it as 01/02 03:04:05PM '06 -0700.)
-// To define your own format, write down what the standard
-// time would look like formatted your way.
+// Mon Jan 2 15:04:05 MST 2006
+// which is Unix time 1136243045. Since MST is GMT-0700,
+// the standard time can be thought of as
+// 01/02 03:04:05PM '06 -0700
+// To define your own format, write down what the standard time would look
+// like formatted your way; see the values of constants like ANSIC,
+// StampMicro or Kitchen for examples.
//
// Within the format string, an underscore _ represents a space that may be
// replaced by a digit if the following number (a day) has two digits; for
// compatibility with fixed-width Unix time formats.
//
// A decimal point followed by one or more zeros represents a fractional
-// second. When parsing (only), the input may contain a fractional second
+// second, printed to the given number of decimal places. A decimal point
+// followed by one or more nines represents a fractional second, printed to
+// the given number of decimal places, with trailing zeros removed.
+// 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.
@@ -41,16 +38,17 @@ const (
// Z0700 Z or ±hhmm
// Z07:00 Z or ±hh:mm
const (
- ANSIC = "Mon Jan _2 15:04:05 2006"
- UnixDate = "Mon Jan _2 15:04:05 MST 2006"
- RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
- RFC822 = "02 Jan 06 1504 MST"
- // RFC822 with Zulu time.
- RFC822Z = "02 Jan 06 1504 -0700"
- RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
- RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
- RFC3339 = "2006-01-02T15:04:05Z07:00"
- Kitchen = "3:04PM"
+ ANSIC = "Mon Jan _2 15:04:05 2006"
+ UnixDate = "Mon Jan _2 15:04:05 MST 2006"
+ RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
+ RFC822 = "02 Jan 06 1504 MST"
+ RFC822Z = "02 Jan 06 1504 -0700" // RFC822 with numeric zone
+ RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
+ RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
+ RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
+ RFC3339 = "2006-01-02T15:04:05Z07:00"
+ RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
+ Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
@@ -165,15 +163,17 @@ 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:]
+ case '.': // .000 or .999 - repeated digits for fractional seconds.
+ if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
+ ch := layout[i+1]
+ j := i + 1
+ for j < len(layout) && layout[j] == ch {
+ j++
+ }
+ // String of digits must end here - only fractional second is all digits.
+ if !isDigit(layout, j) {
+ return layout[0:i], layout[i:j], layout[j:]
+ }
}
}
}
@@ -232,17 +232,78 @@ var longMonthNames = []string{
"December",
}
-func lookup(tab []string, val string) (int, string, os.Error) {
+// match returns true if s1 and s2 match ignoring case.
+// It is assumed s1 and s2 are the same length.
+func match(s1, s2 string) bool {
+ for i := 0; i < len(s1); i++ {
+ c1 := s1[i]
+ c2 := s2[i]
+ if c1 != c2 {
+ // Switch to lower-case; 'a'-'A' is known to be a single bit.
+ c1 |= 'a' - 'A'
+ c2 |= 'a' - 'A'
+ if c1 != c2 || c1 < 'a' || c1 > 'z' {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func lookup(tab []string, val string) (int, string, error) {
for i, v := range tab {
- if len(val) >= len(v) && val[0:len(v)] == v {
+ if len(val) >= len(v) && match(val[0:len(v)], v) {
return i, val[len(v):], nil
}
}
return -1, val, errBad
}
+// Duplicates functionality in strconv, but avoids dependency.
+func itoa(x int) string {
+ var buf [32]byte
+ n := len(buf)
+ if x == 0 {
+ return "0"
+ }
+ u := uint(x)
+ if x < 0 {
+ u = -u
+ }
+ for u > 0 {
+ n--
+ buf[n] = byte(u%10 + '0')
+ u /= 10
+ }
+ if x < 0 {
+ n--
+ buf[n] = '-'
+ }
+ return string(buf[n:])
+}
+
+// Never printed, just needs to be non-nil for return by atoi.
+var atoiError = errors.New("time: invalid number")
+
+// Duplicates functionality in strconv, but avoids dependency.
+func atoi(s string) (x int, err error) {
+ neg := false
+ if s != "" && s[0] == '-' {
+ neg = true
+ s = s[1:]
+ }
+ x, rem, err := leadingInt(s)
+ if err != nil || rem != "" {
+ return 0, atoiError
+ }
+ if neg {
+ x = -x
+ }
+ return x, nil
+}
+
func pad(i int, padding string) string {
- s := strconv.Itoa(i)
+ s := itoa(i)
if i < 10 {
s = padding + s
}
@@ -252,10 +313,10 @@ 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 {
+func formatNano(nanosec, n int, trim bool) string {
// User might give us bad data. Make sure it's positive and in range.
// They'll get nonsense output but it will have the right format.
- s := strconv.Uitoa(uint(nanosec) % 1e9)
+ s := itoa(int(uint(nanosec) % 1e9))
// Zero pad left without fmt.
if len(s) < 9 {
s = "000000000"[:9-len(s)] + s
@@ -263,17 +324,51 @@ func formatNano(nanosec, n int) string {
if n > 9 {
n = 9
}
+ if trim {
+ for n > 0 && s[n-1] == '0' {
+ n--
+ }
+ if n == 0 {
+ return ""
+ }
+ }
return "." + s[:n]
}
+// String returns the time formatted using the format string
+// "2006-01-02 15:04:05.999999999 -0700 MST"
+func (t Time) String() string {
+ return t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
+}
+
+type buffer []byte
+
+func (b *buffer) WriteString(s string) {
+ *b = append(*b, s...)
+}
+
+func (b *buffer) String() string {
+ return string([]byte(*b))
+}
+
// Format returns a textual representation of the time value formatted
// according to layout. The layout defines the format by showing the
-// representation of a standard time, which is then used to describe
-// the time to be formatted. Predefined layouts ANSIC, UnixDate,
-// RFC3339 and others describe standard representations. For more
-// information about the formats, see the documentation for ANSIC.
-func (t *Time) Format(layout string) string {
- b := new(bytes.Buffer)
+// representation of the standard time,
+// Mon Jan 2 15:04:05 -0700 MST 2006
+// which is then used to describe the time to be formatted. Predefined
+// layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// representations. For more information about the formats and the
+// definition of the standard time, see the documentation for ANSIC.
+func (t Time) Format(layout string) string {
+ var (
+ year int = -1
+ month Month
+ day int
+ hour int = -1
+ min int
+ sec int
+ b buffer
+ )
// Each iteration generates one std value.
for {
prefix, std, suffix := nextStdChunk(layout)
@@ -281,62 +376,109 @@ func (t *Time) Format(layout string) string {
if std == "" {
break
}
+
+ // Compute year, month, day if needed.
+ if year < 0 {
+ // Jan 01 02 2006
+ if a, z := std[0], std[len(std)-1]; a == 'J' || a == 'j' || z == '1' || z == '2' || z == '6' {
+ year, month, day = t.Date()
+ }
+ }
+
+ // Compute hour, minute, second if needed.
+ if hour < 0 {
+ // 03 04 05 15 pm
+ if z := std[len(std)-1]; z == '3' || z == '4' || z == '5' || z == 'm' || z == 'M' {
+ hour, min, sec = t.Clock()
+ }
+ }
+
var p string
switch std {
case stdYear:
- p = zeroPad(int(t.Year % 100))
+ p = zeroPad(year % 100)
case stdLongYear:
- p = strconv.Itoa64(t.Year)
+ // Pad year to at least 4 digits.
+ p = itoa(year)
+ switch {
+ case year <= -1000:
+ // ok
+ case year <= -100:
+ p = p[:1] + "0" + p[1:]
+ case year <= -10:
+ p = p[:1] + "00" + p[1:]
+ case year < 0:
+ p = p[:1] + "000" + p[1:]
+ case year < 10:
+ p = "000" + p
+ case year < 100:
+ p = "00" + p
+ case year < 1000:
+ p = "0" + p
+ }
case stdMonth:
- p = shortMonthNames[t.Month]
+ p = month.String()[:3]
case stdLongMonth:
- p = longMonthNames[t.Month]
+ p = month.String()
case stdNumMonth:
- p = strconv.Itoa(t.Month)
+ p = itoa(int(month))
case stdZeroMonth:
- p = zeroPad(t.Month)
+ p = zeroPad(int(month))
case stdWeekDay:
- p = shortDayNames[t.Weekday]
+ p = t.Weekday().String()[:3]
case stdLongWeekDay:
- p = longDayNames[t.Weekday]
+ p = t.Weekday().String()
case stdDay:
- p = strconv.Itoa(t.Day)
+ p = itoa(day)
case stdUnderDay:
- p = pad(t.Day, " ")
+ p = pad(day, " ")
case stdZeroDay:
- p = zeroPad(t.Day)
+ p = zeroPad(day)
case stdHour:
- p = zeroPad(t.Hour)
+ p = zeroPad(hour)
case stdHour12:
// Noon is 12PM, midnight is 12AM.
- hr := t.Hour % 12
+ hr := hour % 12
if hr == 0 {
hr = 12
}
- p = strconv.Itoa(hr)
+ p = itoa(hr)
case stdZeroHour12:
// Noon is 12PM, midnight is 12AM.
- hr := t.Hour % 12
+ hr := hour % 12
if hr == 0 {
hr = 12
}
p = zeroPad(hr)
case stdMinute:
- p = strconv.Itoa(t.Minute)
+ p = itoa(min)
case stdZeroMinute:
- p = zeroPad(t.Minute)
+ p = zeroPad(min)
case stdSecond:
- p = strconv.Itoa(t.Second)
+ p = itoa(sec)
case stdZeroSecond:
- p = zeroPad(t.Second)
+ p = zeroPad(sec)
+ case stdPM:
+ if hour >= 12 {
+ p = "PM"
+ } else {
+ p = "AM"
+ }
+ case stdpm:
+ if hour >= 12 {
+ p = "pm"
+ } else {
+ p = "am"
+ }
case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
// Ugly special case. We cheat and take the "Z" variants
// to mean "the time zone as formatted for ISO 8601".
- if t.ZoneOffset == 0 && std[0] == 'Z' {
+ _, offset := t.Zone()
+ if offset == 0 && std[0] == 'Z' {
p = "Z"
break
}
- zone := t.ZoneOffset / 60 // convert to minutes
+ zone := offset / 60 // convert to minutes
if zone < 0 {
p = "-"
zone = -zone
@@ -348,25 +490,14 @@ func (t *Time) Format(layout string) string {
p += ":"
}
p += zeroPad(zone % 60)
- case stdPM:
- if t.Hour >= 12 {
- p = "PM"
- } else {
- p = "AM"
- }
- case stdpm:
- if t.Hour >= 12 {
- p = "pm"
- } else {
- p = "am"
- }
case stdTZ:
- if t.Zone != "" {
- p = t.Zone
+ name, offset := t.Zone()
+ if name != "" {
+ p = name
} else {
// No time zone known for this time, but we must print one.
// Use the -0700 format.
- zone := t.ZoneOffset / 60 // convert to minutes
+ zone := offset / 60 // convert to minutes
if zone < 0 {
p = "-"
zone = -zone
@@ -377,8 +508,8 @@ func (t *Time) Format(layout string) string {
p += zeroPad(zone % 60)
}
default:
- if len(std) >= 2 && std[0:2] == ".0" {
- p = formatNano(t.Nanosecond, len(std)-1)
+ if len(std) >= 2 && (std[0:2] == ".0" || std[0:2] == ".9") {
+ p = formatNano(t.Nanosecond(), len(std)-1, std[1] == '9')
}
}
b.WriteString(p)
@@ -387,15 +518,7 @@ func (t *Time) Format(layout string) string {
return b.String()
}
-// String returns a Unix-style representation of the time value.
-func (t *Time) String() string {
- if t == nil {
- return "<nil>"
- }
- return t.Format(UnixDate)
-}
-
-var errBad = os.NewError("bad value for field") // placeholder not passed to user
+var errBad = errors.New("bad value for field") // placeholder not passed to user
// ParseError describes a problem parsing a time string.
type ParseError struct {
@@ -406,17 +529,21 @@ type ParseError struct {
Message string
}
-// String is the string representation of a ParseError.
-func (e *ParseError) String() string {
+func quote(s string) string {
+ return "\"" + s + "\""
+}
+
+// Error returns the string representation of a ParseError.
+func (e *ParseError) Error() string {
if e.Message == "" {
return "parsing time " +
- strconv.Quote(e.Value) + " as " +
- strconv.Quote(e.Layout) + ": cannot parse " +
- strconv.Quote(e.ValueElem) + " as " +
- strconv.Quote(e.LayoutElem)
+ quote(e.Value) + " as " +
+ quote(e.Layout) + ": cannot parse " +
+ quote(e.ValueElem) + " as " +
+ quote(e.LayoutElem)
}
return "parsing time " +
- strconv.Quote(e.Value) + e.Message
+ quote(e.Value) + e.Message
}
// isDigit returns true if s[i] is a decimal digit, false if not or
@@ -432,7 +559,7 @@ func isDigit(s string, i int) bool {
// 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) {
+func getnum(s string, fixed bool) (int, string, error) {
if !isDigit(s, 0) {
return 0, s, errBad
}
@@ -454,7 +581,7 @@ func cutspace(s string) string {
// skip removes the given prefix from value,
// treating runs of space characters as equivalent.
-func skip(value, prefix string) (string, os.Error) {
+func skip(value, prefix string) (string, error) {
for len(prefix) > 0 {
if prefix[0] == ' ' {
if len(value) > 0 && value[0] != ' ' {
@@ -474,35 +601,50 @@ func skip(value, prefix string) (string, os.Error) {
}
// Parse parses a formatted string and returns the time value it represents.
-// The layout defines the format by showing the representation of a standard
-// time, which is then used to describe the string to be parsed. Predefined
-// layouts ANSIC, UnixDate, RFC3339 and others describe standard
-// representations.For more information about the formats, see the
-// documentation for ANSIC.
+// The layout defines the format by showing the representation of the
+// standard time,
+// Mon Jan 2 15:04:05 -0700 MST 2006
+// which is then used to describe the string to be parsed. Predefined layouts
+// ANSIC, UnixDate, RFC3339 and others describe standard representations. For
+// more information about the formats and the definition of the standard
+// time, see the documentation for ANSIC.
//
-// Only those elements present in the value will be set in the returned time
-// structure. Also, if the input string represents an inconsistent time
-// (such as having the wrong day of the week), the returned value will also
-// be inconsistent. In any case, the elements of the returned time will be
-// sane: hours in 0..23, minutes in 0..59, day of month in 1..31, etc.
-// Years must be in the range 0000..9999.
-func Parse(alayout, avalue string) (*Time, os.Error) {
- var t Time
+// Elements omitted from the value are assumed to be zero or, when
+// zero is impossible, one, so parsing "3:04pm" returns the time
+// corresponding to Jan 1, year 0, 15:04:00 UTC.
+// Years must be in the range 0000..9999. The day of the week is checked
+// for syntax but it is otherwise ignored.
+func Parse(layout, value string) (Time, error) {
+ alayout, avalue := layout, value
rangeErrString := "" // set if a value is out of range
amSet := false // do we need to subtract 12 from the hour for midnight?
pmSet := false // do we need to add 12 to the hour?
- layout, value := alayout, avalue
+
+ // Time being constructed.
+ var (
+ year int
+ month int = 1 // January
+ day int = 1
+ hour int
+ min int
+ sec int
+ nsec int
+ z *Location
+ zoneOffset int = -1
+ zoneName string
+ )
+
// Each iteration processes one std value.
for {
- var err os.Error
+ var err error
prefix, std, suffix := nextStdChunk(layout)
value, err = skip(value, prefix)
if err != nil {
- return nil, &ParseError{alayout, avalue, prefix, value, ""}
+ return Time{}, &ParseError{alayout, avalue, prefix, value, ""}
}
if len(std) == 0 {
if len(value) != 0 {
- return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
+ return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
}
break
}
@@ -515,11 +657,11 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
p, value = value[0:2], value[2:]
- t.Year, err = strconv.Atoi64(p)
- if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones
- t.Year += 1900
+ year, err = atoi(p)
+ if year >= 69 { // Unix time starts Dec 31 1969 in some time zones
+ year += 1900
} else {
- t.Year += 2000
+ year += 2000
}
case stdLongYear:
if len(value) < 4 || !isDigit(value, 0) {
@@ -527,47 +669,47 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
p, value = value[0:4], value[4:]
- t.Year, err = strconv.Atoi64(p)
+ year, err = atoi(p)
case stdMonth:
- t.Month, value, err = lookup(shortMonthNames, value)
+ month, value, err = lookup(shortMonthNames, value)
case stdLongMonth:
- t.Month, value, err = lookup(longMonthNames, value)
+ month, value, err = lookup(longMonthNames, value)
case stdNumMonth, stdZeroMonth:
- t.Month, value, err = getnum(value, std == stdZeroMonth)
- if t.Month <= 0 || 12 < t.Month {
+ month, value, err = getnum(value, std == stdZeroMonth)
+ if month <= 0 || 12 < month {
rangeErrString = "month"
}
case stdWeekDay:
- t.Weekday, value, err = lookup(shortDayNames, value)
+ // Ignore weekday except for error checking.
+ _, value, err = lookup(shortDayNames, value)
case stdLongWeekDay:
- t.Weekday, value, err = lookup(longDayNames, value)
+ _, value, err = lookup(longDayNames, value)
case stdDay, stdUnderDay, stdZeroDay:
if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
value = value[1:]
}
- t.Day, value, err = getnum(value, std == stdZeroDay)
- if t.Day < 0 || 31 < t.Day {
- // TODO: be more thorough in date check?
+ day, value, err = getnum(value, std == stdZeroDay)
+ if day < 0 || 31 < day {
rangeErrString = "day"
}
case stdHour:
- t.Hour, value, err = getnum(value, false)
- if t.Hour < 0 || 24 <= t.Hour {
+ hour, value, err = getnum(value, false)
+ if hour < 0 || 24 <= hour {
rangeErrString = "hour"
}
case stdHour12, stdZeroHour12:
- t.Hour, value, err = getnum(value, std == stdZeroHour12)
- if t.Hour < 0 || 12 < t.Hour {
+ hour, value, err = getnum(value, std == stdZeroHour12)
+ if hour < 0 || 12 < hour {
rangeErrString = "hour"
}
case stdMinute, stdZeroMinute:
- t.Minute, value, err = getnum(value, std == stdZeroMinute)
- if t.Minute < 0 || 60 <= t.Minute {
+ min, value, err = getnum(value, std == stdZeroMinute)
+ if min < 0 || 60 <= min {
rangeErrString = "minute"
}
case stdSecond, stdZeroSecond:
- t.Second, value, err = getnum(value, std == stdZeroSecond)
- if t.Second < 0 || 60 <= t.Second {
+ sec, value, err = getnum(value, std == stdZeroSecond)
+ if sec < 0 || 60 <= sec {
rangeErrString = "second"
}
// Special case: do we have a fractional second but no
@@ -582,16 +724,44 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
n := 2
for ; n < len(value) && isDigit(value, n); n++ {
}
- rangeErrString, err = t.parseNanoseconds(value, n)
+ nsec, rangeErrString, err = parseNanoseconds(value, n)
value = value[n:]
}
+ case stdPM:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ switch p {
+ case "PM":
+ pmSet = true
+ case "AM":
+ amSet = true
+ default:
+ err = errBad
+ }
+ case stdpm:
+ if len(value) < 2 {
+ err = errBad
+ break
+ }
+ p, value = value[0:2], value[2:]
+ switch p {
+ case "pm":
+ pmSet = true
+ case "am":
+ amSet = true
+ default:
+ err = errBad
+ }
case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
- t.Zone = "UTC"
+ z = UTC
break
}
- var sign, hh, mm string
+ var sign, hour, min string
if std == stdISO8601ColonTZ || std == stdNumColonTZ {
if len(value) < 6 {
err = errBad
@@ -601,65 +771,38 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
err = errBad
break
}
- sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
+ sign, hour, min, value = value[0:1], value[1:3], value[4:6], value[6:]
} else if std == stdNumShortTZ {
if len(value) < 3 {
err = errBad
break
}
- sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
+ sign, hour, min, value = value[0:1], value[1:3], "00", value[3:]
} else {
if len(value) < 5 {
err = errBad
break
}
- sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:]
+ sign, hour, min, value = value[0:1], value[1:3], value[3:5], value[5:]
}
- var hr, min int
- hr, err = strconv.Atoi(hh)
+ var hr, mm int
+ hr, err = atoi(hour)
if err == nil {
- min, err = strconv.Atoi(mm)
+ mm, err = atoi(min)
}
- t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
+ zoneOffset = (hr*60 + mm) * 60 // offset is in seconds
switch sign[0] {
case '+':
case '-':
- t.ZoneOffset = -t.ZoneOffset
- default:
- err = errBad
- }
- case stdPM:
- if len(value) < 2 {
- err = errBad
- break
- }
- p, value = value[0:2], value[2:]
- switch p {
- case "PM":
- pmSet = true
- case "AM":
- amSet = true
- default:
- err = errBad
- }
- case stdpm:
- if len(value) < 2 {
- err = errBad
- break
- }
- p, value = value[0:2], value[2:]
- switch p {
- case "pm":
- pmSet = true
- case "am":
- amSet = true
+ zoneOffset = -zoneOffset
default:
err = errBad
}
case stdTZ:
// Does it look like a time zone?
if len(value) >= 3 && value[0:3] == "UTC" {
- t.Zone, value = value[0:3], value[3:]
+ z = UTC
+ value = value[3:]
break
}
@@ -680,47 +823,86 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
// It's a valid format.
- t.Zone = p
- // Can we find its offset?
- if offset, found := lookupByName(p); found {
- t.ZoneOffset = offset
- }
+ zoneName = p
default:
if len(value) < len(std) {
err = errBad
break
}
if len(std) >= 2 && std[0:2] == ".0" {
- rangeErrString, err = t.parseNanoseconds(value, len(std))
+ nsec, rangeErrString, err = parseNanoseconds(value, len(std))
value = value[len(std):]
}
}
if rangeErrString != "" {
- return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
+ return Time{}, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
}
if err != nil {
- return nil, &ParseError{alayout, avalue, std, value, ""}
+ return Time{}, &ParseError{alayout, avalue, std, value, ""}
+ }
+ }
+ if pmSet && hour < 12 {
+ hour += 12
+ } else if amSet && hour == 12 {
+ hour = 0
+ }
+
+ // TODO: be more aggressive checking day?
+ if z != nil {
+ return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
+ }
+
+ t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
+ if zoneOffset != -1 {
+ t.sec -= int64(zoneOffset)
+
+ // Look for local zone with the given offset.
+ // If that zone was in effect at the given time, use it.
+ name, offset, _, _, _ := Local.lookup(t.sec + internalToUnix)
+ if offset == zoneOffset && (zoneName == "" || name == zoneName) {
+ t.loc = Local
+ return t, nil
}
+
+ // Otherwise create fake zone to record offset.
+ t.loc = FixedZone(zoneName, zoneOffset)
+ return t, nil
}
- if pmSet && t.Hour < 12 {
- t.Hour += 12
- } else if amSet && t.Hour == 12 {
- t.Hour = 0
+
+ if zoneName != "" {
+ // Look for local zone with the given offset.
+ // If that zone was in effect at the given time, use it.
+ offset, _, ok := Local.lookupName(zoneName)
+ if ok {
+ name, off, _, _, _ := Local.lookup(t.sec + internalToUnix - int64(offset))
+ if name == zoneName && off == offset {
+ t.sec -= int64(offset)
+ t.loc = Local
+ return t, nil
+ }
+ }
+
+ // Otherwise, create fake zone with unknown offset.
+ t.loc = FixedZone(zoneName, 0)
+ return t, nil
}
- return &t, nil
+
+ // Otherwise, fall back to UTC.
+ return t, nil
}
-func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string, err os.Error) {
+func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
if value[0] != '.' {
- return "", errBad
+ err = errBad
+ return
}
- var ns int
- ns, err = strconv.Atoi(value[1:nbytes])
+ ns, err = atoi(value[1:nbytes])
if err != nil {
- return "", err
+ return
}
if ns < 0 || 1e9 <= ns {
- return "fractional second", nil
+ rangeErrString = "fractional second"
+ return
}
// We need nanoseconds, which means scaling by the number
// of missing digits in the format, maximum length 10. If it's
@@ -729,6 +911,128 @@ func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string,
for i := 0; i < scaleDigits; i++ {
ns *= 10
}
- t.Nanosecond = ns
return
}
+
+var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
+
+// leadingInt consumes the leading [0-9]* from s.
+func leadingInt(s string) (x int, rem string, err error) {
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if x >= (1<<31-10)/10 {
+ // overflow
+ return 0, "", errLeadingInt
+ }
+ x = x*10 + int(c) - '0'
+ }
+ return x, s[i:], nil
+}
+
+var unitMap = map[string]float64{
+ "ns": float64(Nanosecond),
+ "us": float64(Microsecond),
+ "µs": float64(Microsecond), // U+00B5 = micro symbol
+ "μs": float64(Microsecond), // U+03BC = Greek letter mu
+ "ms": float64(Millisecond),
+ "s": float64(Second),
+ "m": float64(Minute),
+ "h": float64(Hour),
+}
+
+// ParseDuration parses a duration string.
+// A duration string is a possibly signed sequence of
+// decimal numbers, each with optional fraction and a unit suffix,
+// such as "300ms", "-1.5h" or "2h45m".
+// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
+func ParseDuration(s string) (Duration, error) {
+ // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
+ orig := s
+ f := float64(0)
+ neg := false
+
+ // Consume [-+]?
+ if s != "" {
+ c := s[0]
+ if c == '-' || c == '+' {
+ neg = c == '-'
+ s = s[1:]
+ }
+ }
+ // Special case: if all that is left is "0", this is zero.
+ if s == "0" {
+ return 0, nil
+ }
+ if s == "" {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ for s != "" {
+ g := float64(0) // this element of the sequence
+
+ var x int
+ var err error
+
+ // The next character must be [0-9.]
+ if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ // Consume [0-9]*
+ pl := len(s)
+ x, s, err = leadingInt(s)
+ if err != nil {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ g = float64(x)
+ pre := pl != len(s) // whether we consumed anything before a period
+
+ // Consume (\.[0-9]*)?
+ post := false
+ if s != "" && s[0] == '.' {
+ s = s[1:]
+ pl := len(s)
+ x, s, err = leadingInt(s)
+ if err != nil {
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+ scale := 1
+ for n := pl - len(s); n > 0; n-- {
+ scale *= 10
+ }
+ g += float64(x) / float64(scale)
+ post = pl != len(s)
+ }
+ if !pre && !post {
+ // no digits (e.g. ".s" or "-.s")
+ return 0, errors.New("time: invalid duration " + orig)
+ }
+
+ // Consume unit.
+ i := 0
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c == '.' || ('0' <= c && c <= '9') {
+ break
+ }
+ }
+ if i == 0 {
+ return 0, errors.New("time: missing unit in duration " + orig)
+ }
+ u := s[:i]
+ s = s[i:]
+ unit, ok := unitMap[u]
+ if !ok {
+ return 0, errors.New("time: unknown unit " + u + " in duration " + orig)
+ }
+
+ f += g * unit
+ }
+
+ if neg {
+ f = -f
+ }
+ return Duration(f), nil
+}
diff --git a/src/pkg/time/internal_test.go b/src/pkg/time/internal_test.go
new file mode 100644
index 000000000..b753896d7
--- /dev/null
+++ b/src/pkg/time/internal_test.go
@@ -0,0 +1,13 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func init() {
+ // force US/Pacific for time zone tests
+ localOnce.Do(initTestingZone)
+}
+
+var Interrupt = interrupt
+var DaysIn = daysIn
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
index 314622d0d..27820b0ea 100644
--- a/src/pkg/time/sleep.go
+++ b/src/pkg/time/sleep.go
@@ -4,174 +4,92 @@
package time
-import (
- "container/heap"
- "sync"
-)
+// Sleep pauses the current goroutine for the duration d.
+func Sleep(d Duration)
-// The Timer type represents a single event.
-// When the Timer expires, the current time will be sent on C
-// unless the Timer represents an AfterFunc event.
-type Timer struct {
- C <-chan int64
- t int64 // The absolute time that the event should fire.
- f func(int64) // The function to call when the event fires.
- i int // The event's index inside eventHeap.
-}
-
-type timerHeap []*Timer
-
-// forever is the absolute time (in ns) of an event that is forever away.
-const forever = 1 << 62
-
-// maxSleepTime is the maximum length of time that a sleeper
-// sleeps for before checking if it is defunct.
-const maxSleepTime = 1e9
-
-var (
- // timerMutex guards the variables inside this var group.
- timerMutex sync.Mutex
-
- // timers holds a binary heap of pending events, terminated with a sentinel.
- timers timerHeap
-
- // currentSleeper is an ever-incrementing counter which represents
- // the current sleeper. It allows older sleepers to detect that they are
- // defunct and exit.
- currentSleeper int64
-)
-
-func init() {
- timers.Push(&Timer{t: forever}) // sentinel
+func nano() int64 {
+ sec, nsec := now()
+ return sec*1e9 + int64(nsec)
}
-// NewTimer creates a new Timer that will send
-// the current time on its channel after at least ns nanoseconds.
-func NewTimer(ns int64) *Timer {
- c := make(chan int64, 1)
- e := after(ns, func(t int64) { c <- t })
- e.C = c
- return e
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+type runtimeTimer struct {
+ i int32
+ when int64
+ period int64
+ f func(int64, interface{})
+ arg interface{}
}
-// After waits at least ns nanoseconds before sending the current time
-// on the returned channel.
-// It is equivalent to NewTimer(ns).C.
-func After(ns int64) <-chan int64 {
- return NewTimer(ns).C
-}
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
-// AfterFunc waits at least ns nanoseconds before calling f
-// in its own goroutine. It returns a Timer that can
-// be used to cancel the call using its Stop method.
-func AfterFunc(ns int64, f func()) *Timer {
- return after(ns, func(_ int64) {
- go f()
- })
+// The Timer type represents a single event.
+// When the Timer expires, the current time will be sent on C,
+// unless the Timer was created by AfterFunc.
+type Timer struct {
+ C <-chan Time
+ r runtimeTimer
}
// Stop prevents the Timer from firing.
// It returns true if the call stops the timer, false if the timer has already
// expired or stopped.
-func (e *Timer) Stop() (ok bool) {
- timerMutex.Lock()
- // Avoid removing the first event in the queue so that
- // we don't start a new sleeper unnecessarily.
- if e.i > 0 {
- heap.Remove(timers, e.i)
- }
- ok = e.f != nil
- e.f = nil
- timerMutex.Unlock()
- return
+func (t *Timer) Stop() (ok bool) {
+ return stopTimer(&t.r)
}
-// after is the implementation of After and AfterFunc.
-// When the current time is after ns, it calls f with the current time.
-// It assumes that f will not block.
-func after(ns int64, f func(int64)) (e *Timer) {
- now := Nanoseconds()
- t := now + ns
- if ns > 0 && t < now {
- panic("time: time overflow")
- }
- timerMutex.Lock()
- t0 := timers[0].t
- e = &Timer{nil, t, f, -1}
- heap.Push(timers, e)
- // Start a new sleeper if the new event is before
- // the first event in the queue. If the length of time
- // until the new event is at least maxSleepTime,
- // then we're guaranteed that the sleeper will wake up
- // in time to service it, so no new sleeper is needed.
- if t0 > t && (t0 == forever || ns < maxSleepTime) {
- currentSleeper++
- go sleeper(currentSleeper)
+// NewTimer creates a new Timer that will send
+// the current time on its channel after at least duration d.
+func NewTimer(d Duration) *Timer {
+ c := make(chan Time, 1)
+ t := &Timer{
+ C: c,
+ r: runtimeTimer{
+ when: nano() + int64(d),
+ f: sendTime,
+ arg: c,
+ },
}
- timerMutex.Unlock()
- return
+ startTimer(&t.r)
+ return t
}
-// sleeper continually looks at the earliest event in the queue, waits until it happens,
-// then removes any events in the queue that are due. It stops when the queue
-// is empty or when another sleeper has been started.
-func sleeper(sleeperId int64) {
- timerMutex.Lock()
- e := timers[0]
- t := Nanoseconds()
- for e.t != forever {
- if dt := e.t - t; dt > 0 {
- if dt > maxSleepTime {
- dt = maxSleepTime
- }
- timerMutex.Unlock()
- sysSleep(dt)
- timerMutex.Lock()
- if currentSleeper != sleeperId {
- // Another sleeper has been started, making this one redundant.
- break
- }
- }
- e = timers[0]
- t = Nanoseconds()
- for t >= e.t {
- if e.f != nil {
- e.f(t)
- e.f = nil
- }
- heap.Pop(timers)
- e = timers[0]
- }
+func sendTime(now int64, c interface{}) {
+ // Non-blocking send of time on c.
+ // Used in NewTimer, it cannot block anyway (buffer).
+ // Used in NewTicker, dropping sends on the floor is
+ // the desired behavior when the reader gets behind,
+ // because the sends are periodic.
+ select {
+ case c.(chan Time) <- Unix(0, now):
+ default:
}
- timerMutex.Unlock()
-}
-
-func (timerHeap) Len() int {
- return len(timers)
-}
-
-func (timerHeap) Less(i, j int) bool {
- return timers[i].t < timers[j].t
}
-func (timerHeap) Swap(i, j int) {
- timers[i], timers[j] = timers[j], timers[i]
- timers[i].i = i
- timers[j].i = j
+// After waits for the duration to elapse and then sends the current time
+// on the returned channel.
+// It is equivalent to NewTimer(d).C.
+func After(d Duration) <-chan Time {
+ return NewTimer(d).C
}
-func (timerHeap) Push(x interface{}) {
- e := x.(*Timer)
- e.i = len(timers)
- timers = append(timers, e)
+// AfterFunc waits for the duration to elapse and then calls f
+// in its own goroutine. It returns a Timer that can
+// be used to cancel the call using its Stop method.
+func AfterFunc(d Duration, f func()) *Timer {
+ t := &Timer{
+ r: runtimeTimer{
+ when: nano() + int64(d),
+ f: goFunc,
+ arg: f,
+ },
+ }
+ startTimer(&t.r)
+ return t
}
-func (timerHeap) Pop() interface{} {
- // TODO: possibly shrink array.
- n := len(timers) - 1
- e := timers[n]
- timers[n] = nil
- timers = timers[0:n]
- e.i = -1
- return e
+func goFunc(now int64, arg interface{}) {
+ go arg.(func())()
}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index a4a1a429f..526d58d75 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -5,25 +5,26 @@
package time_test
import (
+ "errors"
"fmt"
- "os"
- "syscall"
- "testing"
+ "runtime"
"sort"
+ "sync/atomic"
+ "testing"
. "time"
)
func TestSleep(t *testing.T) {
- const delay = int64(100e6)
+ const delay = 100 * Millisecond
go func() {
Sleep(delay / 2)
- syscall.Kill(os.Getpid(), syscall.SIGCHLD)
+ Interrupt()
}()
- start := Nanoseconds()
+ start := Now()
Sleep(delay)
- duration := Nanoseconds() - start
+ duration := Now().Sub(start)
if duration < delay {
- t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
+ t.Fatalf("Sleep(%s) slept for only %s", delay, duration)
}
}
@@ -38,7 +39,7 @@ func TestAfterFunc(t *testing.T) {
i--
if i >= 0 {
AfterFunc(0, f)
- Sleep(1e9)
+ Sleep(1 * Second)
} else {
c <- true
}
@@ -48,6 +49,23 @@ func TestAfterFunc(t *testing.T) {
<-c
}
+func TestAfterStress(t *testing.T) {
+ stop := uint32(0)
+ go func() {
+ for atomic.LoadUint32(&stop) == 0 {
+ runtime.GC()
+ // Need to yield, because otherwise
+ // the main goroutine will never set the stop flag.
+ runtime.Gosched()
+ }
+ }()
+ c := Tick(1)
+ for i := 0; i < 100; i++ {
+ <-c
+ }
+ atomic.StoreUint32(&stop, 1)
+}
+
func BenchmarkAfterFunc(b *testing.B) {
i := b.N
c := make(chan bool)
@@ -73,47 +91,49 @@ func BenchmarkAfter(b *testing.B) {
func BenchmarkStop(b *testing.B) {
for i := 0; i < b.N; i++ {
- NewTimer(1e9).Stop()
+ NewTimer(1 * Second).Stop()
}
}
func TestAfter(t *testing.T) {
- const delay = int64(100e6)
- start := Nanoseconds()
+ const delay = 100 * Millisecond
+ start := Now()
end := <-After(delay)
- if duration := Nanoseconds() - start; duration < delay {
- t.Fatalf("After(%d) slept for only %d ns", delay, duration)
+ if duration := Now().Sub(start); duration < delay {
+ t.Fatalf("After(%s) slept for only %d ns", delay, duration)
}
- if min := start + delay; end < min {
- t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end)
+ if min := start.Add(delay); end.Before(min) {
+ t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end)
}
}
func TestAfterTick(t *testing.T) {
- const (
- Delta = 100 * 1e6
- Count = 10
- )
- t0 := Nanoseconds()
+ const Count = 10
+ Delta := 100 * Millisecond
+ if testing.Short() {
+ Delta = 10 * Millisecond
+ }
+ t0 := Now()
for i := 0; i < Count; i++ {
<-After(Delta)
}
- t1 := Nanoseconds()
- ns := t1 - t0
- target := int64(Delta * Count)
- slop := target * 2 / 10
- if ns < target-slop || ns > target+slop {
- t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ t1 := Now()
+ d := t1.Sub(t0)
+ target := Delta * Count
+ if d < target*9/10 {
+ t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target)
+ }
+ if !testing.Short() && d > target*30/10 {
+ t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target)
}
}
func TestAfterStop(t *testing.T) {
- const msec = 1e6
- AfterFunc(100*msec, func() {})
- t0 := NewTimer(50 * msec)
+ AfterFunc(100*Millisecond, func() {})
+ t0 := NewTimer(50 * Millisecond)
c1 := make(chan bool, 1)
- t1 := AfterFunc(150*msec, func() { c1 <- true })
- c2 := After(200 * msec)
+ t1 := AfterFunc(150*Millisecond, func() { c1 <- true })
+ c2 := After(200 * Millisecond)
if !t0.Stop() {
t.Fatalf("failed to stop event 0")
}
@@ -137,7 +157,7 @@ func TestAfterQueuing(t *testing.T) {
// This test flakes out on some systems,
// so we'll try it a few times before declaring it a failure.
const attempts = 3
- err := os.NewError("!=nil")
+ err := errors.New("!=nil")
for i := 0; i < attempts && err != nil; i++ {
if err = testAfterQueuing(t); err != nil {
t.Logf("attempt %v failed: %v", i, err)
@@ -152,38 +172,54 @@ var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
type afterResult struct {
slot int
- t int64
+ t Time
}
-func await(slot int, result chan<- afterResult, ac <-chan int64) {
+func await(slot int, result chan<- afterResult, ac <-chan Time) {
result <- afterResult{slot, <-ac}
}
-func testAfterQueuing(t *testing.T) os.Error {
- const (
- Delta = 100 * 1e6
- )
+func testAfterQueuing(t *testing.T) error {
+ Delta := 100 * Millisecond
+ if testing.Short() {
+ Delta = 20 * Millisecond
+ }
// make the result channel buffered because we don't want
// to depend on channel queueing semantics that might
// possibly change in the future.
result := make(chan afterResult, len(slots))
- t0 := Nanoseconds()
+ t0 := Now()
for _, slot := range slots {
- go await(slot, result, After(int64(slot)*Delta))
+ go await(slot, result, After(Duration(slot)*Delta))
}
sort.Ints(slots)
for _, slot := range slots {
r := <-result
if r.slot != slot {
- return fmt.Errorf("after queue got slot %d, expected %d", r.slot, slot)
+ return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
}
- ns := r.t - t0
- target := int64(slot * Delta)
- slop := int64(Delta) / 4
- if ns < target-slop || ns > target+slop {
- return fmt.Errorf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+ dt := r.t.Sub(t0)
+ target := Duration(slot) * Delta
+ if dt < target-Delta/2 || dt > target+Delta*10 {
+ return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10)
}
}
return nil
}
+
+func TestTimerStopStress(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+ for i := 0; i < 100; i++ {
+ go func(i int) {
+ timer := AfterFunc(2*Second, func() {
+ t.Fatalf("timer %d was not stopped", i)
+ })
+ Sleep(1 * Second)
+ timer.Stop()
+ }(i)
+ }
+ Sleep(3 * Second)
+}
diff --git a/src/pkg/time/sys.go b/src/pkg/time/sys.go
deleted file mode 100644
index 9fde3b3b6..000000000
--- a/src/pkg/time/sys.go
+++ /dev/null
@@ -1,51 +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 time
-
-import "os"
-
-// Seconds reports the number of seconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Seconds() int64 {
- sec, _, err := os.Time()
- if err != nil {
- panic(err)
- }
- return sec
-}
-
-// Nanoseconds reports the number of nanoseconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Nanoseconds() int64 {
- sec, nsec, err := os.Time()
- if err != nil {
- panic(err)
- }
- return sec*1e9 + nsec
-}
-
-// Sleep pauses the current goroutine for at least ns nanoseconds.
-// Higher resolution sleeping may be provided by syscall.Nanosleep
-// on some operating systems.
-func Sleep(ns int64) os.Error {
- _, err := sleep(Nanoseconds(), ns)
- return err
-}
-
-// sleep takes the current time and a duration,
-// pauses for at least ns nanoseconds, and
-// returns the current time and an error.
-func sleep(t, ns int64) (int64, os.Error) {
- // TODO(cw): use monotonic-time once it's available
- end := t + ns
- for t < end {
- err := sysSleep(end - t)
- if err != nil {
- return 0, err
- }
- t = Nanoseconds()
- }
- return t, nil
-}
diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go
index abe8649a2..848472944 100644
--- a/src/pkg/time/sys_plan9.go
+++ b/src/pkg/time/sys_plan9.go
@@ -2,17 +2,75 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build plan9
+
package time
import (
- "os"
+ "errors"
"syscall"
)
-func sysSleep(t int64) os.Error {
- err := syscall.Sleep(t)
+// for testing: whatever interrupts a sleep
+func interrupt() {
+ // cannot predict pid, don't want to kill group
+}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY)
if err != nil {
- return os.NewSyscallError("sleep", err)
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(int(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(int(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
}
return nil
}
diff --git a/src/pkg/time/sys_posix.go b/src/pkg/time/sys_posix.go
deleted file mode 100644
index 0d1eb72fc..000000000
--- a/src/pkg/time/sys_posix.go
+++ /dev/null
@@ -1,18 +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 time
-
-import (
- "os"
- "syscall"
-)
-
-func sysSleep(t int64) os.Error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go
new file mode 100644
index 000000000..7f69b492c
--- /dev/null
+++ b/src/pkg/time/sys_unix.go
@@ -0,0 +1,76 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux netbsd openbsd
+
+package time
+
+import (
+ "errors"
+ "syscall"
+)
+
+// for testing: whatever interrupts a sleep
+func interrupt() {
+ syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
+}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(int(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(int(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
+ }
+ return nil
+}
diff --git a/src/pkg/time/sys_windows.go b/src/pkg/time/sys_windows.go
new file mode 100644
index 000000000..de63b4bf4
--- /dev/null
+++ b/src/pkg/time/sys_windows.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 time
+
+import (
+ "errors"
+ "syscall"
+)
+
+// for testing: whatever interrupts a sleep
+func interrupt() {
+}
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+ f, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.Close(f)
+ var (
+ buf [4096]byte
+ ret []byte
+ n int
+ )
+ for {
+ n, err = syscall.Read(f, buf[:])
+ if n > 0 {
+ ret = append(ret, buf[:n]...)
+ }
+ if n == 0 || err != nil {
+ break
+ }
+ }
+ return ret, err
+}
+
+func open(name string) (uintptr, error) {
+ fd, err := syscall.Open(name, syscall.O_RDONLY, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uintptr(fd), nil
+}
+
+func closefd(fd uintptr) {
+ syscall.Close(syscall.Handle(fd))
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+ whence := 0
+ if off < 0 {
+ whence = 2
+ }
+ if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil {
+ return err
+ }
+ for len(buf) > 0 {
+ m, err := syscall.Read(syscall.Handle(fd), buf)
+ if m <= 0 {
+ if err == nil {
+ return errors.New("short read")
+ }
+ return err
+ }
+ buf = buf[m:]
+ }
+ return nil
+}
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index 852bae9c9..8c6b9bc3b 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -4,174 +4,50 @@
package time
-import (
- "os"
- "sync"
-)
+import "errors"
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
- C <-chan int64 // The channel on which the ticks are delivered.
- c chan<- int64 // The same channel, but the end we use.
- ns int64
- shutdown chan bool // Buffered channel used to signal shutdown.
- nextTick int64
- next *Ticker
+ C <-chan Time // The channel on which the ticks are delivered.
+ r runtimeTimer
+}
+
+// NewTicker returns a new Ticker containing a channel that will send the
+// time with a period specified by the duration argument.
+// It adjusts the intervals or drops ticks to make up for slow receivers.
+// The duration d must be greater than zero; if not, NewTicker will panic.
+func NewTicker(d Duration) *Ticker {
+ if d <= 0 {
+ panic(errors.New("non-positive interval for NewTicker"))
+ }
+ // Give the channel a 1-element time buffer.
+ // If the client falls behind while reading, we drop ticks
+ // on the floor until the client catches up.
+ c := make(chan Time, 1)
+ t := &Ticker{
+ C: c,
+ r: runtimeTimer{
+ when: nano() + int64(d),
+ period: int64(d),
+ f: sendTime,
+ arg: c,
+ },
+ }
+ startTimer(&t.r)
+ return t
}
// Stop turns off a ticker. After Stop, no more ticks will be sent.
func (t *Ticker) Stop() {
- select {
- case t.shutdown <- true:
- // ok
- default:
- // Stop in progress already
- }
+ stopTimer(&t.r)
}
// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only. Useful for clients that have no need to shut down the ticker.
-func Tick(ns int64) <-chan int64 {
- if ns <= 0 {
+func Tick(d Duration) <-chan Time {
+ if d <= 0 {
return nil
}
- return NewTicker(ns).C
-}
-
-type alarmer struct {
- wakeUp chan bool // wakeup signals sent/received here
- wakeMeAt chan int64
- wakeTime int64
-}
-
-// Set alarm to go off at time ns, if not already set earlier.
-func (a *alarmer) set(ns int64) {
- switch {
- case a.wakeTime > ns:
- // Next tick we expect is too late; shut down the late runner
- // and (after fallthrough) start a new wakeLoop.
- close(a.wakeMeAt)
- fallthrough
- case a.wakeMeAt == nil:
- // There's no wakeLoop, start one.
- a.wakeMeAt = make(chan int64)
- a.wakeUp = make(chan bool, 1)
- go wakeLoop(a.wakeMeAt, a.wakeUp)
- fallthrough
- case a.wakeTime == 0:
- // Nobody else is waiting; it's just us.
- a.wakeTime = ns
- a.wakeMeAt <- ns
- default:
- // There's already someone scheduled.
- }
-}
-
-// Channel to notify tickerLoop of new Tickers being created.
-var newTicker chan *Ticker
-
-func startTickerLoop() {
- newTicker = make(chan *Ticker)
- go tickerLoop()
-}
-
-// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
-// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
-// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
-func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
- for wakeAt := range wakeMeAt {
- Sleep(wakeAt - Nanoseconds())
- wakeUp <- true
- }
-}
-
-// A single tickerLoop serves all ticks to Tickers. It waits for two events:
-// either the creation of a new Ticker or a tick from the alarm,
-// signaling a time to wake up one or more Tickers.
-func tickerLoop() {
- // Represents the next alarm to be delivered.
- var alarm alarmer
- var now, wakeTime int64
- var tickers *Ticker
- for {
- select {
- case t := <-newTicker:
- // Add Ticker to list
- t.next = tickers
- tickers = t
- // Arrange for a new alarm if this one precedes the existing one.
- alarm.set(t.nextTick)
- case <-alarm.wakeUp:
- now = Nanoseconds()
- wakeTime = now + 1e15 // very long in the future
- var prev *Ticker = nil
- // Scan list of tickers, delivering updates to those
- // that need it and determining the next wake time.
- // TODO(r): list should be sorted in time order.
- for t := tickers; t != nil; t = t.next {
- select {
- case <-t.shutdown:
- // Ticker is done; remove it from list.
- if prev == nil {
- tickers = t.next
- } else {
- prev.next = t.next
- }
- continue
- default:
- }
- if t.nextTick <= now {
- if len(t.c) == 0 {
- // Only send if there's room. We must not block.
- // The channel is allocated with a one-element
- // buffer, which is sufficient: if he hasn't picked
- // up the last tick, no point in sending more.
- t.c <- now
- }
- t.nextTick += t.ns
- if t.nextTick <= now {
- // Still behind; advance in one big step.
- t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
- }
- }
- if t.nextTick < wakeTime {
- wakeTime = t.nextTick
- }
- prev = t
- }
- if tickers != nil {
- // Please send wakeup at earliest required time.
- // If there are no tickers, don't bother.
- alarm.wakeTime = wakeTime
- alarm.wakeMeAt <- wakeTime
- } else {
- alarm.wakeTime = 0
- }
- }
- }
-}
-
-var onceStartTickerLoop sync.Once
-
-// NewTicker returns a new Ticker containing a channel that will
-// send the time, in nanoseconds, every ns nanoseconds. It adjusts the
-// intervals to make up for pauses in delivery of the ticks. The value of
-// ns must be greater than zero; if not, NewTicker will panic.
-func NewTicker(ns int64) *Ticker {
- if ns <= 0 {
- panic(os.NewError("non-positive interval for NewTicker"))
- }
- c := make(chan int64, 1) // See comment on send in tickerLoop
- t := &Ticker{
- C: c,
- c: c,
- ns: ns,
- shutdown: make(chan bool, 1),
- nextTick: Nanoseconds() + ns,
- }
- onceStartTickerLoop.Do(startTickerLoop)
- // must be run in background so global Tickers can be created
- go func() { newTicker <- t }()
- return t
+ return NewTicker(d).C
}
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index 4dcb63956..d8a086ceb 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/time/tick_test.go
@@ -10,22 +10,20 @@ import (
)
func TestTicker(t *testing.T) {
- const (
- Delta = 100 * 1e6
- Count = 10
- )
+ const Count = 10
+ Delta := 100 * Millisecond
ticker := NewTicker(Delta)
- t0 := Nanoseconds()
+ t0 := Now()
for i := 0; i < Count; i++ {
<-ticker.C
}
ticker.Stop()
- t1 := Nanoseconds()
- ns := t1 - t0
- target := int64(Delta * Count)
+ t1 := Now()
+ dt := t1.Sub(t0)
+ target := Delta * Count
slop := target * 2 / 10
- if ns < target-slop || ns > target+slop {
- t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ if dt < target-slop || (!testing.Short() && dt > target+slop) {
+ t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
}
// Now test that the ticker stopped
Sleep(2 * Delta)
@@ -39,8 +37,12 @@ func TestTicker(t *testing.T) {
// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
func TestTeardown(t *testing.T) {
+ Delta := 100 * Millisecond
+ if testing.Short() {
+ Delta = 20 * Millisecond
+ }
for i := 0; i < 3; i++ {
- ticker := NewTicker(1e8)
+ ticker := NewTicker(Delta)
<-ticker.C
ticker.Stop()
}
diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
index 0e05da484..473bc2a45 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -3,11 +3,112 @@
// license that can be found in the LICENSE file.
// Package time provides functionality for measuring and displaying time.
+//
+// The calendrical calculations always assume a Gregorian calendar.
package time
-// Days of the week.
+import "errors"
+
+// A Time represents an instant in time with nanosecond precision.
+//
+// Programs using times should typically store and pass them as values,
+// not pointers. That is, time variables and struct fields should be of
+// type time.Time, not *time.Time. A Time value can be used by
+// multiple goroutines simultaneously.
+//
+// Time instants can be compared using the Before, After, and Equal methods.
+// The Sub method subtracts two instants, producing a Duration.
+// The Add method adds a Time and a Duration, producing a Time.
+//
+// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC.
+// As this time is unlikely to come up in practice, the IsZero method gives
+// a simple way of detecting a time that has not been initialized explicitly.
+//
+// Each Time has associated with it a Location, consulted when computing the
+// presentation form of the time, such as in the Format, Hour, and Year methods.
+// The methods Local, UTC, and In return a Time with a specific location.
+// Changing the location in this way changes only the presentation; it does not
+// change the instant in time being denoted and therefore does not affect the
+// computations described in earlier paragraphs.
+//
+type Time struct {
+ // sec gives the number of seconds elapsed since
+ // January 1, year 1 00:00:00 UTC.
+ sec int64
+
+ // nsec specifies a non-negative nanosecond
+ // offset within the second named by Seconds.
+ // It must be in the range [0, 999999999].
+ nsec int32
+
+ // loc specifies the Location that should be used to
+ // determine the minute, hour, month, day, and year
+ // that correspond to this Time.
+ // Only the zero Time has a nil Location.
+ // In that case it is interpreted to mean UTC.
+ loc *Location
+}
+
+// After reports whether the time instant t is after u.
+func (t Time) After(u Time) bool {
+ return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec
+}
+
+// Before reports whether the time instant t is before u.
+func (t Time) Before(u Time) bool {
+ return t.sec < u.sec || t.sec == u.sec && t.nsec < u.nsec
+}
+
+// Equal reports whether t and u represent the same time instant.
+// Two times can be equal even if they are in different locations.
+// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
+// This comparison is different from using t == u, which also compares
+// the locations.
+func (t Time) Equal(u Time) bool {
+ return t.sec == u.sec && t.nsec == u.nsec
+}
+
+// A Month specifies a month of the year (January = 1, ...).
+type Month int
+
const (
- Sunday = iota
+ January Month = 1 + iota
+ February
+ March
+ April
+ May
+ June
+ July
+ August
+ September
+ October
+ November
+ December
+)
+
+var months = [...]string{
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+}
+
+// String returns the English name of the month ("January", "February", ...).
+func (m Month) String() string { return months[m-1] }
+
+// A Weekday specifies a day of the week (Sunday = 0, ...).
+type Weekday int
+
+const (
+ Sunday Weekday = iota
Monday
Tuesday
Wednesday
@@ -16,215 +117,871 @@ const (
Saturday
)
-// Time is the struct representing a parsed time value.
-type Time struct {
- Year int64 // 2006 is 2006
- Month, Day int // Jan-2 is 1, 2
- Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
- Nanosecond int // Fractional second.
- Weekday int // Sunday, Monday, ...
- ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700
- Zone string // e.g., "MST"
+var days = [...]string{
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
}
-var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
-var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+// String returns the English name of the day ("Sunday", "Monday", ...).
+func (d Weekday) String() string { return days[d] }
+
+// Computations on time.
+//
+// The zero value for a Time is defined to be
+// January 1, year 1, 00:00:00.000000000 UTC
+// which (1) looks like a zero, or as close as you can get in a date
+// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to
+// be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a
+// non-negative year even in time zones west of UTC, unlike 1-1-0
+// 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York.
+//
+// The zero Time value does not force a specific epoch for the time
+// representation. For example, to use the Unix epoch internally, we
+// could define that to distinguish a zero value from Jan 1 1970, that
+// time would be represented by sec=-1, nsec=1e9. However, it does
+// suggest a representation, namely using 1-1-1 00:00:00 UTC as the
+// epoch, and that's what we do.
+//
+// The Add and Sub computations are oblivious to the choice of epoch.
+//
+// The presentation computations - year, month, minute, and so on - all
+// rely heavily on division and modulus by positive constants. For
+// calendrical calculations we want these divisions to round down, even
+// for negative values, so that the remainder is always positive, but
+// Go's division (like most hardware division instructions) rounds to
+// zero. We can still do those computations and then adjust the result
+// for a negative numerator, but it's annoying to write the adjustment
+// over and over. Instead, we can change to a different epoch so long
+// ago that all the times we care about will be positive, and then round
+// to zero and round down coincide. These presentation routines already
+// have to add the zone offset, so adding the translation to the
+// alternate epoch is cheap. For example, having a non-negative time t
+// means that we can write
+//
+// sec = t % 60
+//
+// instead of
+//
+// sec = t % 60
+// if sec < 0 {
+// sec += 60
+// }
+//
+// everywhere.
+//
+// The calendar runs on an exact 400 year cycle: a 400-year calendar
+// printed for 1970-2469 will apply as well to 2470-2869. Even the days
+// of the week match up. It simplifies the computations to choose the
+// cycle boundaries so that the exceptional years are always delayed as
+// long as possible. That means choosing a year equal to 1 mod 400, so
+// that the first leap year is the 4th year, the first missed leap year
+// is the 100th year, and the missed missed leap year is the 400th year.
+// So we'd prefer instead to print a calendar for 2001-2400 and reuse it
+// for 2401-2800.
+//
+// Finally, it's convenient if the delta between the Unix epoch and
+// long-ago epoch is representable by an int64 constant.
+//
+// These three considerations—choose an epoch as early as possible, that
+// uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds
+// earlier than 1970—bring us to the year -292277022399. We refer to
+// this year as the absolute zero year, and to times measured as a uint64
+// seconds since this year as absolute times.
+//
+// Times measured as an int64 seconds since the year 1—the representation
+// used for Time's sec field—are called internal times.
+//
+// Times measured as an int64 seconds since the year 1970 are called Unix
+// times.
+//
+// It is tempting to just use the year 1 as the absolute epoch, defining
+// that the routines are only valid for years >= 1. However, the
+// routines would then be invalid when displaying the epoch in time zones
+// west of UTC, since it is year 0. It doesn't seem tenable to say that
+// printing the zero time correctly isn't supported in half the time
+// zones. By comparison, it's reasonable to mishandle some times in
+// the year -292277022399.
+//
+// All this is opaque to clients of the API and can be changed if a
+// better implementation presents itself.
-func months(year int64) []int {
- if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
- return leapyear
+const (
+ // The unsigned zero year for internal calculations.
+ // Must be 1 mod 400, and times before it will not compute correctly,
+ // but otherwise can be changed at will.
+ absoluteZeroYear = -292277022399
+
+ // The year of the zero Time.
+ // Assumed by the unixToInternal computation below.
+ internalYear = 1
+
+ // The year of the zero Unix time.
+ unixYear = 1970
+
+ // Offsets to convert between internal and absolute or Unix times.
+ absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay
+ internalToAbsolute = -absoluteToInternal
+
+ unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
+ internalToUnix int64 = -unixToInternal
+)
+
+// IsZero reports whether t represents the zero time instant,
+// January 1, year 1, 00:00:00 UTC.
+func (t Time) IsZero() bool {
+ return t.sec == 0 && t.nsec == 0
+}
+
+// abs returns the time t as an absolute time, adjusted by the zone offset.
+// It is called when computing a presentation property like Month or Hour.
+func (t Time) abs() uint64 {
+ l := t.loc
+ if l == nil {
+ l = &utcLoc
}
- return nonleapyear
+ // Avoid function call if we hit the local time cache.
+ sec := t.sec + internalToUnix
+ if l != &utcLoc {
+ if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
+ sec += int64(l.cacheZone.offset)
+ } else {
+ _, offset, _, _, _ := l.lookup(sec)
+ sec += int64(offset)
+ }
+ }
+ return uint64(sec + (unixToInternal + internalToAbsolute))
+}
+
+// Date returns the year, month, and day in which t occurs.
+func (t Time) Date() (year int, month Month, day int) {
+ year, month, day, _ = t.date(true)
+ return
+}
+
+// Year returns the year in which t occurs.
+func (t Time) Year() int {
+ year, _, _, _ := t.date(false)
+ return year
+}
+
+// Month returns the month of the year specified by t.
+func (t Time) Month() Month {
+ _, month, _, _ := t.date(true)
+ return month
}
+// Day returns the day of the month specified by t.
+func (t Time) Day() int {
+ _, _, day, _ := t.date(true)
+ return day
+}
+
+// Weekday returns the day of the week specified by t.
+func (t Time) Weekday() Weekday {
+ // January 1 of the absolute year, like January 1 of 2001, was a Monday.
+ sec := (t.abs() + uint64(Monday)*secondsPerDay) % secondsPerWeek
+ return Weekday(int(sec) / secondsPerDay)
+}
+
+// ISOWeek returns the ISO 8601 year and week number in which t occurs.
+// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to
+// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1
+// of year n+1.
+func (t Time) ISOWeek() (year, week int) {
+ year, month, day, yday := t.date(true)
+ wday := int(t.Weekday()+6) % 7 // weekday but Monday = 0.
+ const (
+ Mon int = iota
+ Tue
+ Wed
+ Thu
+ Fri
+ Sat
+ Sun
+ )
+
+ // Calculate week as number of Mondays in year up to
+ // and including today, plus 1 because the first week is week 0.
+ // Putting the + 1 inside the numerator as a + 7 keeps the
+ // numerator from being negative, which would cause it to
+ // round incorrectly.
+ week = (yday - wday + 7) / 7
+
+ // The week number is now correct under the assumption
+ // that the first Monday of the year is in week 1.
+ // If Jan 1 is a Tuesday, Wednesday, or Thursday, the first Monday
+ // is actually in week 2.
+ jan1wday := (wday - yday + 7*53) % 7
+ if Tue <= jan1wday && jan1wday <= Thu {
+ week++
+ }
+
+ // If the week number is still 0, we're in early January but in
+ // the last week of last year.
+ if week == 0 {
+ year--
+ week = 52
+ // A year has 53 weeks when Jan 1 or Dec 31 is a Thursday,
+ // meaning Jan 1 of the next year is a Friday
+ // or it was a leap year and Jan 1 of the next year is a Saturday.
+ if jan1wday == Fri || (jan1wday == Sat && isLeap(year)) {
+ week++
+ }
+ }
+
+ // December 29 to 31 are in week 1 of next year if
+ // they are after the last Thursday of the year and
+ // December 31 is a Monday, Tuesday, or Wednesday.
+ if month == December && day >= 29 && wday < Thu {
+ if dec31wday := (wday + 31 - day) % 7; Mon <= dec31wday && dec31wday <= Wed {
+ year++
+ week = 1
+ }
+ }
+
+ return
+}
+
+// Clock returns the hour, minute, and second within the day specified by t.
+func (t Time) Clock() (hour, min, sec int) {
+ sec = int(t.abs() % secondsPerDay)
+ hour = sec / secondsPerHour
+ sec -= hour * secondsPerHour
+ min = sec / secondsPerMinute
+ sec -= min * secondsPerMinute
+ return
+}
+
+// Hour returns the hour within the day specified by t, in the range [0, 23].
+func (t Time) Hour() int {
+ return int(t.abs()%secondsPerDay) / secondsPerHour
+}
+
+// Minute returns the minute offset within the hour specified by t, in the range [0, 59].
+func (t Time) Minute() int {
+ return int(t.abs()%secondsPerHour) / secondsPerMinute
+}
+
+// Second returns the second offset within the minute specified by t, in the range [0, 59].
+func (t Time) Second() int {
+ return int(t.abs() % secondsPerMinute)
+}
+
+// Nanosecond returns the nanosecond offset within the second specified by t,
+// in the range [0, 999999999].
+func (t Time) Nanosecond() int {
+ return int(t.nsec)
+}
+
+// A Duration represents the elapsed time between two instants
+// as an int64 nanosecond count. The representation limits the
+// largest representable duration to approximately 290 years.
+type Duration int64
+
+// Common durations. There is no definition for units of Day or larger
+// to avoid confusion across daylight savings time zone transitions.
+//
+// To count the number of units in a Duration, divide:
+// second := time.Second
+// fmt.Print(int64(second/time.Millisecond)) // prints 1000
+//
+// To convert an integer number of units to a Duration, multiply:
+// seconds := 10
+// fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
+//
const (
- secondsPerDay = 24 * 60 * 60
- daysPer400Years = 365*400 + 97
- daysPer100Years = 365*100 + 24
- daysPer4Years = 365*4 + 1
- days1970To2001 = 31*365 + 8
+ Nanosecond Duration = 1
+ Microsecond = 1000 * Nanosecond
+ Millisecond = 1000 * Microsecond
+ Second = 1000 * Millisecond
+ Minute = 60 * Second
+ Hour = 60 * Minute
)
-// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the UTC time zone.
-func SecondsToUTC(sec int64) *Time {
- t := new(Time)
+// Duration returns a string representing the duration in the form "72h3m0.5s".
+// Leading zero units are omitted. As a special case, durations less than one
+// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
+// that the leading digit is non-zero. The zero duration formats as 0,
+// with no unit.
+func (d Duration) String() string {
+ // Largest time is 2540400h10m10.000000000s
+ var buf [32]byte
+ w := len(buf)
+
+ u := uint64(d)
+ neg := d < 0
+ if neg {
+ u = -u
+ }
- // Split into time and day.
- day := sec / secondsPerDay
- sec -= day * secondsPerDay
- if sec < 0 {
- day--
- sec += secondsPerDay
+ if u < uint64(Second) {
+ // Special case: if duration is smaller than a second,
+ // use smaller units, like 1.2ms
+ var (
+ prec int
+ unit byte
+ )
+ switch {
+ case u == 0:
+ return "0"
+ case u < uint64(Microsecond):
+ // print nanoseconds
+ prec = 0
+ unit = 'n'
+ case u < uint64(Millisecond):
+ // print microseconds
+ prec = 3
+ unit = 'u'
+ default:
+ // print milliseconds
+ prec = 6
+ unit = 'm'
+ }
+ w -= 2
+ buf[w] = unit
+ buf[w+1] = 's'
+ w, u = fmtFrac(buf[:w], u, prec)
+ w = fmtInt(buf[:w], u)
+ } else {
+ w--
+ buf[w] = 's'
+
+ w, u = fmtFrac(buf[:w], u, 9)
+
+ // u is now integer seconds
+ w = fmtInt(buf[:w], u%60)
+ u /= 60
+
+ // u is now integer minutes
+ if u > 0 {
+ w--
+ buf[w] = 'm'
+ w = fmtInt(buf[:w], u%60)
+ u /= 60
+
+ // u is now integer hours
+ // Stop at hours because days can be different lengths.
+ if u > 0 {
+ w--
+ buf[w] = 'h'
+ w = fmtInt(buf[:w], u)
+ }
+ }
+ }
+
+ if neg {
+ w--
+ buf[w] = '-'
}
- // Time
- t.Hour = int(sec / 3600)
- t.Minute = int((sec / 60) % 60)
- t.Second = int(sec % 60)
+ return string(buf[w:])
+}
- // Day 0 = January 1, 1970 was a Thursday
- t.Weekday = int((day + Thursday) % 7)
- if t.Weekday < 0 {
- t.Weekday += 7
+// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
+// tail of buf, omitting trailing zeros. it omits the decimal
+// point too when the fraction is 0. It returns the index where the
+// output bytes begin and the value v/10**prec.
+func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
+ // Omit trailing zeros up to and including decimal point.
+ w := len(buf)
+ print := false
+ for i := 0; i < prec; i++ {
+ digit := v % 10
+ print = print || digit != 0
+ if print {
+ w--
+ buf[w] = byte(digit) + '0'
+ }
+ v /= 10
}
+ if print {
+ w--
+ buf[w] = '.'
+ }
+ return w, v
+}
+
+// fmtInt formats v into the tail of buf.
+// It returns the index where the output begins.
+func fmtInt(buf []byte, v uint64) int {
+ w := len(buf)
+ if v == 0 {
+ w--
+ buf[w] = '0'
+ } else {
+ for v > 0 {
+ w--
+ buf[w] = byte(v%10) + '0'
+ v /= 10
+ }
+ }
+ return w
+}
+
+// Nanoseconds returns the duration as an integer nanosecond count.
+func (d Duration) Nanoseconds() int64 { return int64(d) }
+
+// These methods return float64 because the dominant
+// use case is for printing a floating point number like 1.5s, and
+// a truncation to integer would make them not useful in those cases.
+// Splitting the integer and fraction ourselves guarantees that
+// converting the returned float64 to an integer rounds the same
+// way that a pure integer conversion would have, even in cases
+// where, say, float64(d.Nanoseconds())/1e9 would have rounded
+// differently.
+
+// Seconds returns the duration as a floating point number of seconds.
+func (d Duration) Seconds() float64 {
+ sec := d / Second
+ nsec := d % Second
+ return float64(sec) + float64(nsec)*1e-9
+}
- // Change day from 0 = 1970 to 0 = 2001,
- // to make leap year calculations easier
- // (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
- day -= days1970To2001
+// Minutes returns the duration as a floating point number of minutes.
+func (d Duration) Minutes() float64 {
+ min := d / Minute
+ nsec := d % Minute
+ return float64(min) + float64(nsec)*(1e-9/60)
+}
- year := int64(2001)
- if day < 0 {
- // Go back enough 400 year cycles to make day positive.
- n := -day/daysPer400Years + 1
- year -= 400 * n
- day += daysPer400Years * n
+// Hours returns the duration as a floating point number of hours.
+func (d Duration) Hours() float64 {
+ hour := d / Hour
+ nsec := d % Hour
+ return float64(hour) + float64(nsec)*(1e-9/60/60)
+}
+
+// Add returns the time t+d.
+func (t Time) Add(d Duration) Time {
+ t.sec += int64(d / 1e9)
+ t.nsec += int32(d % 1e9)
+ if t.nsec >= 1e9 {
+ t.sec++
+ t.nsec -= 1e9
+ } else if t.nsec < 0 {
+ t.sec--
+ t.nsec += 1e9
}
+ return t
+}
- // Cut off 400 year cycles.
- n := day / daysPer400Years
- year += 400 * n
- day -= daysPer400Years * n
+// Sub returns the duration t-u.
+// To compute t-d for a duration d, use t.Add(-d).
+func (t Time) Sub(u Time) Duration {
+ return Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
+}
+
+// Since returns the time elapsed since t.
+// It is shorthand for time.Now().Sub(t).
+func Since(t Time) Duration {
+ return Now().Sub(t)
+}
+
+// AddDate returns the time corresponding to adding the
+// given number of years, months, and days to t.
+// For example, AddDate(-1, 2, 3) applied to January 1, 2011
+// returns March 4, 2010.
+//
+// AddDate normalizes its result in the same way that Date does,
+// so, for example, adding one month to October 31 yields
+// December 1, the normalized form for November 31.
+func (t Time) AddDate(years int, months int, days int) Time {
+ year, month, day := t.Date()
+ hour, min, sec := t.Clock()
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc)
+}
- // Cut off 100-year cycles
- n = day / daysPer100Years
- if n > 3 { // happens on last day of 400th year
- n = 3
+const (
+ secondsPerMinute = 60
+ secondsPerHour = 60 * 60
+ secondsPerDay = 24 * secondsPerHour
+ secondsPerWeek = 7 * secondsPerDay
+ daysPer400Years = 365*400 + 97
+ daysPer100Years = 365*100 + 24
+ daysPer4Years = 365*4 + 1
+ days1970To2001 = 31*365 + 8
+)
+
+// date computes the year and, only when full=true,
+// the month and day in which t occurs.
+func (t Time) date(full bool) (year int, month Month, day int, yday int) {
+ // Split into time and day.
+ d := t.abs() / secondsPerDay
+
+ // Account for 400 year cycles.
+ n := d / daysPer400Years
+ y := 400 * n
+ d -= daysPer400Years * n
+
+ // Cut off 100-year cycles.
+ // The last cycle has one extra leap year, so on the last day
+ // of that year, day / daysPer100Years will be 4 instead of 3.
+ // Cut it back down to 3 by subtracting n>>2.
+ n = d / daysPer100Years
+ n -= n >> 2
+ y += 100 * n
+ d -= daysPer100Years * n
+
+ // Cut off 4-year cycles.
+ // The last cycle has a missing leap year, which does not
+ // affect the computation.
+ n = d / daysPer4Years
+ y += 4 * n
+ d -= daysPer4Years * n
+
+ // Cut off years within a 4-year cycle.
+ // The last year is a leap year, so on the last day of that year,
+ // day / 365 will be 4 instead of 3. Cut it back down to 3
+ // by subtracting n>>2.
+ n = d / 365
+ n -= n >> 2
+ y += n
+ d -= 365 * n
+
+ year = int(int64(y) + absoluteZeroYear)
+ yday = int(d)
+
+ if !full {
+ return
}
- year += 100 * n
- day -= daysPer100Years * n
- // Cut off 4-year cycles
- n = day / daysPer4Years
- if n > 24 { // happens on last day of 100th year
- n = 24
+ day = yday
+ if isLeap(year) {
+ // Leap year
+ switch {
+ case day > 31+29-1:
+ // After leap day; pretend it wasn't there.
+ day--
+ case day == 31+29-1:
+ // Leap day.
+ month = February
+ day = 29
+ return
+ }
}
- year += 4 * n
- day -= daysPer4Years * n
- // Cut off non-leap years.
- n = day / 365
- if n > 3 { // happens on last day of 4th year
- n = 3
+ // Estimate month on assumption that every month has 31 days.
+ // The estimate may be too low by at most one month, so adjust.
+ month = Month(day / 31)
+ end := int(daysBefore[month+1])
+ var begin int
+ if day >= end {
+ month++
+ begin = end
+ } else {
+ begin = int(daysBefore[month])
}
- year += n
- day -= 365 * n
- t.Year = year
+ month++ // because January is 1
+ day = day - begin + 1
+ return
+}
- // If someone ever needs yearday,
- // tyearday = day (+1?)
+// daysBefore[m] counts the number of days in a non-leap year
+// before month m begins. There is an entry for m=12, counting
+// the number of days before January of next year (365).
+var daysBefore = [...]int32{
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
- months := months(year)
- var m int
- yday := int(day)
- for m = 0; m < 12 && yday >= months[m]; m++ {
- yday -= months[m]
+func daysIn(m Month, year int) int {
+ if m == February && isLeap(year) {
+ return 29
}
- t.Month = m + 1
- t.Day = yday + 1
- t.Zone = "UTC"
+ return int(daysBefore[m] - daysBefore[m-1])
+}
- return t
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// Now returns the current local time.
+func Now() Time {
+ sec, nsec := now()
+ return Time{sec + unixToInternal, nsec, Local}
}
-// 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)
+// UTC returns t with the location set to UTC.
+func (t Time) UTC() Time {
+ t.loc = UTC
return t
}
-// UTC returns the current time as a parsed Time value in the UTC time zone.
-func UTC() *Time { return NanosecondsToUTC(Nanoseconds()) }
-
-// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the local time zone.
-func SecondsToLocalTime(sec int64) *Time {
- z, offset := lookupTimezone(sec)
- t := SecondsToUTC(sec + int64(offset))
- t.Zone = z
- t.ZoneOffset = offset
+// Local returns t with the location set to local time.
+func (t Time) Local() Time {
+ t.loc = Local
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)
+// In returns t with the location information set to loc.
+//
+// In panics if loc is nil.
+func (t Time) In(loc *Location) Time {
+ if loc == nil {
+ panic("time: missing Location in call to Time.In")
+ }
+ t.loc = loc
return t
}
-// LocalTime returns the current time as a parsed Time value in the local time zone.
-func LocalTime() *Time { return NanosecondsToLocalTime(Nanoseconds()) }
+// Location returns the time zone information associated with t.
+func (t Time) Location() *Location {
+ l := t.loc
+ if l == nil {
+ l = UTC
+ }
+ return l
+}
+
+// Zone computes the time zone in effect at time t, returning the abbreviated
+// name of the zone (such as "CET") and its offset in seconds east of UTC.
+func (t Time) Zone() (name string, offset int) {
+ name, offset, _, _, _ = t.loc.lookup(t.sec + internalToUnix)
+ return
+}
+
+// Unix returns t as a Unix time, the number of seconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) Unix() int64 {
+ return t.sec + internalToUnix
+}
+
+// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) UnixNano() int64 {
+ return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
+}
+
+const timeGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (t Time) GobEncode() ([]byte, error) {
+ var offsetMin int16 // minutes east of UTC. -1 is UTC.
+
+ if t.Location() == &utcLoc {
+ offsetMin = -1
+ } else {
+ _, offset := t.Zone()
+ if offset%60 != 0 {
+ return nil, errors.New("Time.GobEncode: zone offset has fractional minute")
+ }
+ offset /= 60
+ if offset < -32768 || offset == -1 || offset > 32767 {
+ return nil, errors.New("Time.GobEncode: unexpected zone offset")
+ }
+ offsetMin = int16(offset)
+ }
+
+ enc := []byte{
+ timeGobVersion, // byte 0 : version
+ byte(t.sec >> 56), // bytes 1-8: seconds
+ byte(t.sec >> 48),
+ byte(t.sec >> 40),
+ byte(t.sec >> 32),
+ byte(t.sec >> 24),
+ byte(t.sec >> 16),
+ byte(t.sec >> 8),
+ byte(t.sec),
+ byte(t.nsec >> 24), // bytes 9-12: nanoseconds
+ byte(t.nsec >> 16),
+ byte(t.nsec >> 8),
+ byte(t.nsec),
+ byte(offsetMin >> 8), // bytes 13-14: zone offset in minutes
+ byte(offsetMin),
+ }
+
+ return enc, nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (t *Time) GobDecode(buf []byte) error {
+ if len(buf) == 0 {
+ return errors.New("Time.GobDecode: no data")
+ }
+
+ if buf[0] != timeGobVersion {
+ return errors.New("Time.GobDecode: unsupported version")
+ }
+
+ if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
+ return errors.New("Time.GobDecode: invalid length")
+ }
+
+ buf = buf[1:]
+ t.sec = int64(buf[7]) | int64(buf[6])<<8 | int64(buf[5])<<16 | int64(buf[4])<<24 |
+ int64(buf[3])<<32 | int64(buf[2])<<40 | int64(buf[1])<<48 | int64(buf[0])<<56
+
+ buf = buf[8:]
+ t.nsec = int32(buf[3]) | int32(buf[2])<<8 | int32(buf[1])<<16 | int32(buf[0])<<24
+
+ buf = buf[4:]
+ offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
+
+ if offset == -1*60 {
+ t.loc = &utcLoc
+ } else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
+ t.loc = Local
+ } else {
+ t.loc = FixedZone("", offset)
+ }
+
+ return nil
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+// Time is formatted as RFC3339.
+func (t Time) MarshalJSON() ([]byte, error) {
+ if y := t.Year(); y < 0 || y >= 10000 {
+ return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
+ }
+ return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+// Time is expected in RFC3339 format.
+func (t *Time) UnmarshalJSON(data []byte) (err error) {
+ // Fractional seconds are handled implicitly by Parse.
+ *t, err = Parse(`"`+RFC3339+`"`, string(data))
+ return
+}
-// Seconds returns the number of seconds since January 1, 1970 represented by the
-// parsed Time value.
-func (t *Time) Seconds() int64 {
- // First, accumulate days since January 1, 2001.
- // Using 2001 instead of 1970 makes the leap-year
- // handling easier (see SecondsToUTC), because
- // it is at the beginning of the 4-, 100-, and 400-year cycles.
- day := int64(0)
+// Unix returns the local Time corresponding to the given Unix time,
+// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
+// It is valid to pass nsec outside the range [0, 999999999].
+func Unix(sec int64, nsec int64) Time {
+ if nsec < 0 || nsec >= 1e9 {
+ n := nsec / 1e9
+ sec += n
+ nsec -= n * 1e9
+ if nsec < 0 {
+ nsec += 1e9
+ sec--
+ }
+ }
+ return Time{sec + unixToInternal, int32(nsec), Local}
+}
+
+func isLeap(year int) bool {
+ return year%4 == 0 && (year%100 != 0 || year%400 == 0)
+}
+
+// norm returns nhi, nlo such that
+// hi * base + lo == nhi * base + nlo
+// 0 <= nlo < base
+func norm(hi, lo, base int) (nhi, nlo int) {
+ if lo < 0 {
+ n := (-lo-1)/base + 1
+ hi -= n
+ lo += n * base
+ }
+ if lo >= base {
+ n := lo / base
+ hi += n
+ lo -= n * base
+ }
+ return hi, lo
+}
- // Rewrite year to be >= 2001.
- year := t.Year
- if year < 2001 {
- n := (2001-year)/400 + 1
- year += 400 * n
- day -= daysPer400Years * n
+// Date returns the Time corresponding to
+// yyyy-mm-dd hh:mm:ss + nsec nanoseconds
+// in the appropriate zone for that time in the given location.
+//
+// The month, day, hour, min, sec, and nsec values may be outside
+// their usual ranges and will be normalized during the conversion.
+// For example, October 32 converts to November 1.
+//
+// A daylight savings time transition skips or repeats times.
+// For example, in the United States, March 13, 2011 2:15am never occurred,
+// while November 6, 2011 1:15am occurred twice. In such cases, the
+// choice of time zone, and therefore the time, is not well-defined.
+// Date returns a time that is correct in one of the two zones involved
+// in the transition, but it does not guarantee which.
+//
+// Date panics if loc is nil.
+func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time {
+ if loc == nil {
+ panic("time: missing Location in call to Date")
}
+ // Normalize month, overflowing into year.
+ m := int(month) - 1
+ year, m = norm(year, m, 12)
+ month = Month(m) + 1
+
+ // Normalize nsec, sec, min, hour, overflowing into day.
+ sec, nsec = norm(sec, nsec, 1e9)
+ min, sec = norm(min, sec, 60)
+ hour, min = norm(hour, min, 60)
+ day, hour = norm(day, hour, 24)
+
+ y := uint64(int64(year) - absoluteZeroYear)
+
+ // Compute days since the absolute epoch.
+
// Add in days from 400-year cycles.
- n := (year - 2001) / 400
- year -= 400 * n
- day += daysPer400Years * n
+ n := y / 400
+ y -= 400 * n
+ d := daysPer400Years * n
// Add in 100-year cycles.
- n = (year - 2001) / 100
- year -= 100 * n
- day += daysPer100Years * n
+ n = y / 100
+ y -= 100 * n
+ d += daysPer100Years * n
// Add in 4-year cycles.
- n = (year - 2001) / 4
- year -= 4 * n
- day += daysPer4Years * n
+ n = y / 4
+ y -= 4 * n
+ d += daysPer4Years * n
// Add in non-leap years.
- n = year - 2001
- day += 365 * n
+ n = y
+ d += 365 * n
- // Add in days this year.
- months := months(t.Year)
- for m := 0; m < t.Month-1; m++ {
- day += int64(months[m])
+ // Add in days before this month.
+ d += uint64(daysBefore[month-1])
+ if isLeap(year) && month >= March {
+ d++ // February 29
}
- day += int64(t.Day - 1)
- // Convert days to seconds since January 1, 2001.
- sec := day * secondsPerDay
+ // Add in days before today.
+ d += uint64(day - 1)
// Add in time elapsed today.
- sec += int64(t.Hour) * 3600
- sec += int64(t.Minute) * 60
- sec += int64(t.Second)
-
- // Convert from seconds since 2001 to seconds since 1970.
- sec += days1970To2001 * secondsPerDay
-
- // Account for local time zone.
- sec -= int64(t.ZoneOffset)
- return sec
-}
+ abs := d * secondsPerDay
+ abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec)
+
+ unix := int64(abs) + (absoluteToInternal + internalToUnix)
+
+ // Look for zone offset for t, so we can adjust to UTC.
+ // The lookup function expects UTC, so we pass t in the
+ // hope that it will not be too close to a zone transition,
+ // and then adjust if it is.
+ _, offset, _, start, end := loc.lookup(unix)
+ if offset != 0 {
+ switch utc := unix - int64(offset); {
+ case utc < start:
+ _, offset, _, _, _ = loc.lookup(start - 1)
+ case utc >= end:
+ _, offset, _, _, _ = loc.lookup(end)
+ }
+ unix -= int64(offset)
+ }
-// 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)
+ return Time{unix + unixToInternal, int32(nsec), loc}
}
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index dceed491a..3430526b8 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -5,7 +5,11 @@
package time_test
import (
- "os"
+ "bytes"
+ "encoding/gob"
+ "encoding/json"
+ "fmt"
+ "math/rand"
"strconv"
"strings"
"testing"
@@ -13,84 +17,93 @@ import (
. "time"
)
-func init() {
- // Force US Pacific time for daylight-savings
- // tests below (localtests). Needs to be set
- // before the first call into the time library.
- os.Setenv("TZ", "America/Los_Angeles")
-}
-
// We should be in PST/PDT, but if the time zone files are missing we
// won't be. The purpose of this test is to at least explain why some of
// the subsequent tests fail.
func TestZoneData(t *testing.T) {
- lt := LocalTime()
+ lt := Now()
// PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique.
- if off := lt.ZoneOffset; off != -8*60*60 && off != -7*60*60 {
- t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", lt.Zone, off)
+ if name, off := lt.Zone(); off != -8*60*60 && off != -7*60*60 {
+ t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", name, off)
t.Error("Likely problem: the time zone files have not been installed.")
}
}
+// parsedTime is the struct representing a parsed time value.
+type parsedTime struct {
+ Year int
+ Month Month
+ Day int
+ Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
+ Nanosecond int // Fractional second.
+ Weekday Weekday
+ ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700
+ Zone string // e.g., "MST"
+}
+
type TimeTest struct {
seconds int64
- golden Time
+ golden parsedTime
}
var utctests = []TimeTest{
- {0, Time{1970, 1, 1, 0, 0, 0, 0, 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"}},
+ {0, parsedTime{1970, January, 1, 0, 0, 0, 0, Thursday, 0, "UTC"}},
+ {1221681866, parsedTime{2008, September, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}},
+ {-1221681866, parsedTime{1931, April, 16, 3, 55, 34, 0, Thursday, 0, "UTC"}},
+ {-11644473600, parsedTime{1601, January, 1, 0, 0, 0, 0, Monday, 0, "UTC"}},
+ {599529660, parsedTime{1988, December, 31, 0, 1, 0, 0, Saturday, 0, "UTC"}},
+ {978220860, parsedTime{2000, December, 31, 0, 1, 0, 0, Sunday, 0, "UTC"}},
}
var nanoutctests = []TimeTest{
- {0, Time{1970, 1, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}},
- {1221681866, Time{2008, 9, 17, 20, 4, 26, 2e8, Wednesday, 0, "UTC"}},
+ {0, parsedTime{1970, January, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}},
+ {1221681866, parsedTime{2008, September, 17, 20, 4, 26, 2e8, Wednesday, 0, "UTC"}},
}
var localtests = []TimeTest{
- {0, Time{1969, 12, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
- {1221681866, Time{2008, 9, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}},
+ {0, parsedTime{1969, December, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, parsedTime{2008, September, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}},
}
var nanolocaltests = []TimeTest{
- {0, Time{1969, 12, 31, 16, 0, 0, 1e8, 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 {
- return t.Year == u.Year &&
- t.Month == u.Month &&
- t.Day == u.Day &&
- t.Hour == u.Hour &&
- t.Minute == u.Minute &&
- t.Second == u.Second &&
- t.Nanosecond == u.Nanosecond &&
- t.Weekday == u.Weekday &&
- t.ZoneOffset == u.ZoneOffset &&
- t.Zone == u.Zone
+ {0, parsedTime{1969, December, 31, 16, 0, 0, 1e8, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, parsedTime{2008, September, 17, 13, 4, 26, 3e8, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+func same(t Time, u *parsedTime) bool {
+ // Check aggregates.
+ year, month, day := t.Date()
+ hour, min, sec := t.Clock()
+ name, offset := t.Zone()
+ if year != u.Year || month != u.Month || day != u.Day ||
+ hour != u.Hour || min != u.Minute || sec != u.Second ||
+ name != u.Zone || offset != u.ZoneOffset {
+ return false
+ }
+ // Check individual entries.
+ return t.Year() == u.Year &&
+ t.Month() == u.Month &&
+ t.Day() == u.Day &&
+ t.Hour() == u.Hour &&
+ t.Minute() == u.Minute &&
+ t.Second() == u.Second &&
+ t.Nanosecond() == u.Nanosecond &&
+ t.Weekday() == u.Weekday
}
func TestSecondsToUTC(t *testing.T) {
for _, test := range utctests {
sec := test.seconds
golden := &test.golden
- tm := SecondsToUTC(sec)
- newsec := tm.Seconds()
+ tm := Unix(sec, 0).UTC()
+ newsec := tm.Unix()
if newsec != sec {
t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
}
if !same(tm, golden) {
- t.Errorf("SecondsToUTC(%d):", sec)
+ t.Errorf("SecondsToUTC(%d): // %#v", sec, tm)
t.Errorf(" want=%+v", *golden)
- t.Errorf(" have=%+v", *tm)
+ t.Errorf(" have=%v", tm.Format(RFC3339+" MST"))
}
}
}
@@ -99,15 +112,15 @@ func TestNanosecondsToUTC(t *testing.T) {
for _, test := range nanoutctests {
golden := &test.golden
nsec := test.seconds*1e9 + int64(golden.Nanosecond)
- tm := NanosecondsToUTC(nsec)
- newnsec := tm.Nanoseconds()
+ tm := Unix(0, nsec).UTC()
+ newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
if newnsec != nsec {
t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec)
}
if !same(tm, golden) {
t.Errorf("NanosecondsToUTC(%d):", nsec)
t.Errorf(" want=%+v", *golden)
- t.Errorf(" have=%+v", *tm)
+ t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
}
}
@@ -116,38 +129,38 @@ func TestSecondsToLocalTime(t *testing.T) {
for _, test := range localtests {
sec := test.seconds
golden := &test.golden
- tm := SecondsToLocalTime(sec)
- newsec := tm.Seconds()
+ tm := Unix(sec, 0)
+ newsec := tm.Unix()
if newsec != sec {
t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
}
if !same(tm, golden) {
t.Errorf("SecondsToLocalTime(%d):", sec)
t.Errorf(" want=%+v", *golden)
- t.Errorf(" have=%+v", *tm)
+ t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
}
}
-func TestNanoecondsToLocalTime(t *testing.T) {
+func TestNanosecondsToLocalTime(t *testing.T) {
for _, test := range nanolocaltests {
golden := &test.golden
nsec := test.seconds*1e9 + int64(golden.Nanosecond)
- tm := NanosecondsToLocalTime(nsec)
- newnsec := tm.Nanoseconds()
+ tm := Unix(0, nsec)
+ newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
if newnsec != nsec {
t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec)
}
if !same(tm, golden) {
t.Errorf("NanosecondsToLocalTime(%d):", nsec)
t.Errorf(" want=%+v", *golden)
- t.Errorf(" have=%+v", *tm)
+ t.Errorf(" have=%+v", tm.Format(RFC3339+" MST"))
}
}
}
func TestSecondsToUTCAndBack(t *testing.T) {
- f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
+ f := func(sec int64) bool { return Unix(sec, 0).UTC().Unix() == sec }
f32 := func(sec int32) bool { return f(int64(sec)) }
cfg := &quick.Config{MaxCount: 10000}
@@ -161,7 +174,11 @@ func TestSecondsToUTCAndBack(t *testing.T) {
}
func TestNanosecondsToUTCAndBack(t *testing.T) {
- f := func(nsec int64) bool { return NanosecondsToUTC(nsec).Nanoseconds() == nsec }
+ f := func(nsec int64) bool {
+ t := Unix(0, nsec).UTC()
+ ns := t.Unix()*1e9 + int64(t.Nanosecond())
+ return ns == nsec
+ }
f32 := func(nsec int32) bool { return f(int64(nsec)) }
cfg := &quick.Config{MaxCount: 10000}
@@ -181,9 +198,9 @@ type TimeFormatTest struct {
}
var rfc3339Formats = []TimeFormatTest{
- {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"},
+ {Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+ {Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+ {Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
}
func TestRFC3339Conversion(t *testing.T) {
@@ -209,7 +226,9 @@ var formatTests = []FormatTest{
{"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"},
+ {"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+ {"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
{"Kitchen", Kitchen, "9:00PM"},
{"am/pm", "3pm", "9pm"},
{"AM/PM", "3PM", "9PM"},
@@ -218,12 +237,12 @@ var formatTests = []FormatTest{
{"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"},
+ {"StampNano", StampNano, "Feb 4 21:00:57.012345600"},
}
func TestFormat(t *testing.T) {
- // The numeric time represents Thu Feb 4 21:00:57.012345678 PST 2010
- time := NanosecondsToLocalTime(1233810057012345678)
+ // The numeric time represents Thu Feb 4 21:00:57.012345600 PST 2010
+ time := Unix(0, 1233810057012345600)
for _, test := range formatTests {
result := time.Format(test.format)
if result != test.result {
@@ -232,14 +251,46 @@ func TestFormat(t *testing.T) {
}
}
+func TestFormatShortYear(t *testing.T) {
+ years := []int{
+ -100001, -100000, -99999,
+ -10001, -10000, -9999,
+ -1001, -1000, -999,
+ -101, -100, -99,
+ -11, -10, -9,
+ -1, 0, 1,
+ 9, 10, 11,
+ 99, 100, 101,
+ 999, 1000, 1001,
+ 9999, 10000, 10001,
+ 99999, 100000, 100001,
+ }
+
+ for _, y := range years {
+ time := Date(y, January, 1, 0, 0, 0, 0, UTC)
+ result := time.Format("2006.01.02")
+ var want string
+ if y < 0 {
+ // The 4 in %04d counts the - sign, so print -y instead
+ // and introduce our own - sign.
+ want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
+ } else {
+ want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
+ }
+ if result != want {
+ t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
+ }
+ }
+}
+
type ParseTest struct {
name string
format string
value string
- hasTZ bool // contains a time zone
- hasWD bool // contains a weekday
- yearSign int64 // sign of year
- fracDigits int // number of digits of fractional second
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int // sign of year
+ fracDigits int // number of digits of fractional second
}
var parseTests = []ParseTest{
@@ -248,6 +299,7 @@ var parseTests = []ParseTest{
{"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},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", 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.
@@ -256,10 +308,14 @@ var parseTests = []ParseTest{
{"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},
+ {"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", 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, 0},
{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ // Case should not matter
+ {"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},
@@ -300,47 +356,48 @@ func TestRubyParse(t *testing.T) {
}
}
-func checkTime(time *Time, test *ParseTest, t *testing.T) {
+func checkTime(time Time, test *ParseTest, t *testing.T) {
// The time should be Thu Feb 4 21:00:57 PST 2010
- if test.yearSign*time.Year != 2010 {
- t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010)
+ if test.yearSign*time.Year() != 2010 {
+ t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
}
- if time.Month != 2 {
- t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
+ if time.Month() != February {
+ t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
}
- if time.Day != 4 {
- t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4)
+ if time.Day() != 4 {
+ t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
}
- if time.Hour != 21 {
- t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21)
+ if time.Hour() != 21 {
+ t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
}
- if time.Minute != 0 {
- t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0)
+ if time.Minute() != 0 {
+ t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
}
- if time.Second != 57 {
- t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
+ if time.Second() != 57 {
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
}
// Nanoseconds must be checked against the precision of the input.
- nanosec, err := strconv.Atoui("012345678"[:test.fracDigits] + "000000000"[:9-test.fracDigits])
+ nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
if err != nil {
panic(err)
}
- if time.Nanosecond != int(nanosec) {
- t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond, nanosec)
+ if time.Nanosecond() != int(nanosec) {
+ t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
}
- if test.hasTZ && time.ZoneOffset != -28800 {
- t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
+ name, offset := time.Zone()
+ if test.hasTZ && offset != -28800 {
+ t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
}
- if test.hasWD && time.Weekday != 4 {
- t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4)
+ if test.hasWD && time.Weekday() != Thursday {
+ t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
}
}
func TestFormatAndParse(t *testing.T) {
const fmt = "Mon MST " + RFC3339 // all fields
f := func(sec int64) bool {
- t1 := SecondsToLocalTime(sec)
- if t1.Year < 1000 || t1.Year > 9999 {
+ t1 := Unix(sec, 0)
+ if t1.Year() < 1000 || t1.Year() > 9999 {
// not required to work
return true
}
@@ -349,8 +406,8 @@ func TestFormatAndParse(t *testing.T) {
t.Errorf("error: %s", err)
return false
}
- if !same(t1, t2) {
- t.Errorf("different: %q %q", t1, t2)
+ if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
+ t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
return false
}
return true
@@ -389,14 +446,14 @@ func TestParseErrors(t *testing.T) {
_, err := Parse(test.format, test.value)
if err == nil {
t.Errorf("expected error for %q %q", test.format, test.value)
- } else if strings.Index(err.String(), test.expect) < 0 {
+ } else if strings.Index(err.Error(), test.expect) < 0 {
t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
}
}
}
func TestNoonIs12PM(t *testing.T) {
- noon := Time{Hour: 12}
+ noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
const expect = "12:00PM"
got := noon.Format("3:04PM")
if got != expect {
@@ -409,7 +466,7 @@ func TestNoonIs12PM(t *testing.T) {
}
func TestMidnightIs12AM(t *testing.T) {
- midnight := Time{Hour: 0}
+ midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
expect := "12:00AM"
got := midnight.Format("3:04PM")
if got != expect {
@@ -426,15 +483,15 @@ func Test12PMIsNoon(t *testing.T) {
if err != nil {
t.Fatal("error parsing date:", err)
}
- if noon.Hour != 12 {
- t.Errorf("got %d; expect 12", noon.Hour)
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
}
noon, err = Parse("03:04PM", "12:00PM")
if err != nil {
t.Fatal("error parsing date:", err)
}
- if noon.Hour != 12 {
- t.Errorf("got %d; expect 12", noon.Hour)
+ if noon.Hour() != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour())
}
}
@@ -443,29 +500,29 @@ func Test12AMIsMidnight(t *testing.T) {
if err != nil {
t.Fatal("error parsing date:", err)
}
- if midnight.Hour != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour)
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
}
midnight, err = Parse("03:04PM", "12:00AM")
if err != nil {
t.Fatal("error parsing date:", err)
}
- if midnight.Hour != 0 {
- t.Errorf("got %d; expect 0", midnight.Hour)
+ if midnight.Hour() != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour())
}
}
// Check that a time without a Zone still produces a (numeric) time zone
// when formatted with MST as a requested zone.
func TestMissingZone(t *testing.T) {
- time, err := Parse(RubyDate, "Tue Feb 02 16:10:03 -0500 2006")
+ time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
if err != nil {
t.Fatal("error parsing date:", err)
}
- expect := "Tue Feb 2 16:10:03 -0500 2006" // -0500 not EST
+ expect := "Thu Feb 2 16:10:03 -0500 2006" // -0500 not EST
str := time.Format(UnixDate) // uses MST as its time zone
if str != expect {
- t.Errorf("expected %q got %q", expect, str)
+ t.Errorf("got %s; expect %s", str, expect)
}
}
@@ -475,25 +532,409 @@ func TestMinutesInTimeZone(t *testing.T) {
t.Fatal("error parsing date:", err)
}
expected := (1*60 + 23) * 60
- if time.ZoneOffset != expected {
- t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+ _, offset := time.Zone()
+ if offset != expected {
+ t.Errorf("ZoneOffset = %d, want %d", offset, expected)
+ }
+}
+
+type ISOWeekTest struct {
+ year int // year
+ month, day int // month and day
+ yex int // expected year
+ wex int // expected week
+}
+
+var isoWeekTests = []ISOWeekTest{
+ {1981, 1, 1, 1981, 1}, {1982, 1, 1, 1981, 53}, {1983, 1, 1, 1982, 52},
+ {1984, 1, 1, 1983, 52}, {1985, 1, 1, 1985, 1}, {1986, 1, 1, 1986, 1},
+ {1987, 1, 1, 1987, 1}, {1988, 1, 1, 1987, 53}, {1989, 1, 1, 1988, 52},
+ {1990, 1, 1, 1990, 1}, {1991, 1, 1, 1991, 1}, {1992, 1, 1, 1992, 1},
+ {1993, 1, 1, 1992, 53}, {1994, 1, 1, 1993, 52}, {1995, 1, 2, 1995, 1},
+ {1996, 1, 1, 1996, 1}, {1996, 1, 7, 1996, 1}, {1996, 1, 8, 1996, 2},
+ {1997, 1, 1, 1997, 1}, {1998, 1, 1, 1998, 1}, {1999, 1, 1, 1998, 53},
+ {2000, 1, 1, 1999, 52}, {2001, 1, 1, 2001, 1}, {2002, 1, 1, 2002, 1},
+ {2003, 1, 1, 2003, 1}, {2004, 1, 1, 2004, 1}, {2005, 1, 1, 2004, 53},
+ {2006, 1, 1, 2005, 52}, {2007, 1, 1, 2007, 1}, {2008, 1, 1, 2008, 1},
+ {2009, 1, 1, 2009, 1}, {2010, 1, 1, 2009, 53}, {2010, 1, 1, 2009, 53},
+ {2011, 1, 1, 2010, 52}, {2011, 1, 2, 2010, 52}, {2011, 1, 3, 2011, 1},
+ {2011, 1, 4, 2011, 1}, {2011, 1, 5, 2011, 1}, {2011, 1, 6, 2011, 1},
+ {2011, 1, 7, 2011, 1}, {2011, 1, 8, 2011, 1}, {2011, 1, 9, 2011, 1},
+ {2011, 1, 10, 2011, 2}, {2011, 1, 11, 2011, 2}, {2011, 6, 12, 2011, 23},
+ {2011, 6, 13, 2011, 24}, {2011, 12, 25, 2011, 51}, {2011, 12, 26, 2011, 52},
+ {2011, 12, 27, 2011, 52}, {2011, 12, 28, 2011, 52}, {2011, 12, 29, 2011, 52},
+ {2011, 12, 30, 2011, 52}, {2011, 12, 31, 2011, 52}, {1995, 1, 1, 1994, 52},
+ {2012, 1, 1, 2011, 52}, {2012, 1, 2, 2012, 1}, {2012, 1, 8, 2012, 1},
+ {2012, 1, 9, 2012, 2}, {2012, 12, 23, 2012, 51}, {2012, 12, 24, 2012, 52},
+ {2012, 12, 30, 2012, 52}, {2012, 12, 31, 2013, 1}, {2013, 1, 1, 2013, 1},
+ {2013, 1, 6, 2013, 1}, {2013, 1, 7, 2013, 2}, {2013, 12, 22, 2013, 51},
+ {2013, 12, 23, 2013, 52}, {2013, 12, 29, 2013, 52}, {2013, 12, 30, 2014, 1},
+ {2014, 1, 1, 2014, 1}, {2014, 1, 5, 2014, 1}, {2014, 1, 6, 2014, 2},
+ {2015, 1, 1, 2015, 1}, {2016, 1, 1, 2015, 53}, {2017, 1, 1, 2016, 52},
+ {2018, 1, 1, 2018, 1}, {2019, 1, 1, 2019, 1}, {2020, 1, 1, 2020, 1},
+ {2021, 1, 1, 2020, 53}, {2022, 1, 1, 2021, 52}, {2023, 1, 1, 2022, 52},
+ {2024, 1, 1, 2024, 1}, {2025, 1, 1, 2025, 1}, {2026, 1, 1, 2026, 1},
+ {2027, 1, 1, 2026, 53}, {2028, 1, 1, 2027, 52}, {2029, 1, 1, 2029, 1},
+ {2030, 1, 1, 2030, 1}, {2031, 1, 1, 2031, 1}, {2032, 1, 1, 2032, 1},
+ {2033, 1, 1, 2032, 53}, {2034, 1, 1, 2033, 52}, {2035, 1, 1, 2035, 1},
+ {2036, 1, 1, 2036, 1}, {2037, 1, 1, 2037, 1}, {2038, 1, 1, 2037, 53},
+ {2039, 1, 1, 2038, 52}, {2040, 1, 1, 2039, 52},
+}
+
+func TestISOWeek(t *testing.T) {
+ // Selected dates and corner cases
+ for _, wt := range isoWeekTests {
+ dt := Date(wt.year, Month(wt.month), wt.day, 0, 0, 0, 0, UTC)
+ y, w := dt.ISOWeek()
+ if w != wt.wex || y != wt.yex {
+ t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d",
+ y, w, wt.yex, wt.wex, wt.year, wt.month, wt.day)
+ }
+ }
+
+ // The only real invariant: Jan 04 is in week 1
+ for year := 1950; year < 2100; year++ {
+ if y, w := Date(year, January, 4, 0, 0, 0, 0, UTC).ISOWeek(); y != year || w != 1 {
+ t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year)
+ }
}
}
-func BenchmarkSeconds(b *testing.B) {
- for i := 0; i < b.N; i++ {
- Seconds()
+var durationTests = []struct {
+ str string
+ d Duration
+}{
+ {"0", 0},
+ {"1ns", 1 * Nanosecond},
+ {"1.1us", 1100 * Nanosecond},
+ {"2.2ms", 2200 * Microsecond},
+ {"3.3s", 3300 * Millisecond},
+ {"4m5s", 4*Minute + 5*Second},
+ {"4m5.001s", 4*Minute + 5001*Millisecond},
+ {"5h6m7.001s", 5*Hour + 6*Minute + 7001*Millisecond},
+ {"8m0.000000001s", 8*Minute + 1*Nanosecond},
+ {"2562047h47m16.854775807s", 1<<63 - 1},
+ {"-2562047h47m16.854775808s", -1 << 63},
+}
+
+func TestDurationString(t *testing.T) {
+ for _, tt := range durationTests {
+ if str := tt.d.String(); str != tt.str {
+ t.Errorf("Duration(%d).String() = %s, want %s", int64(tt.d), str, tt.str)
+ }
+ if tt.d > 0 {
+ if str := (-tt.d).String(); str != "-"+tt.str {
+ t.Errorf("Duration(%d).String() = %s, want %s", int64(-tt.d), str, "-"+tt.str)
+ }
+ }
+ }
+}
+
+var dateTests = []struct {
+ year, month, day, hour, min, sec, nsec int
+ z *Location
+ unix int64
+}{
+ {2011, 11, 6, 1, 0, 0, 0, Local, 1320566400}, // 1:00:00 PDT
+ {2011, 11, 6, 1, 59, 59, 0, Local, 1320569999}, // 1:59:59 PDT
+ {2011, 11, 6, 2, 0, 0, 0, Local, 1320573600}, // 2:00:00 PST
+
+ {2011, 3, 13, 1, 0, 0, 0, Local, 1300006800}, // 1:00:00 PST
+ {2011, 3, 13, 1, 59, 59, 0, Local, 1300010399}, // 1:59:59 PST
+ {2011, 3, 13, 3, 0, 0, 0, Local, 1300010400}, // 3:00:00 PDT
+ {2011, 3, 13, 2, 30, 0, 0, Local, 1300008600}, // 2:30:00 PDT ≡ 1:30 PST
+
+ // Many names for Fri Nov 18 7:56:35 PST 2011
+ {2011, 11, 18, 7, 56, 35, 0, Local, 1321631795}, // Nov 18 7:56:35
+ {2011, 11, 19, -17, 56, 35, 0, Local, 1321631795}, // Nov 19 -17:56:35
+ {2011, 11, 17, 31, 56, 35, 0, Local, 1321631795}, // Nov 17 31:56:35
+ {2011, 11, 18, 6, 116, 35, 0, Local, 1321631795}, // Nov 18 6:116:35
+ {2011, 10, 49, 7, 56, 35, 0, Local, 1321631795}, // Oct 49 7:56:35
+ {2011, 11, 18, 7, 55, 95, 0, Local, 1321631795}, // Nov 18 7:55:95
+ {2011, 11, 18, 7, 56, 34, 1e9, Local, 1321631795}, // Nov 18 7:56:34 + 10⁹ns
+ {2011, 12, -12, 7, 56, 35, 0, Local, 1321631795}, // Dec -21 7:56:35
+ {2012, 1, -43, 7, 56, 35, 0, Local, 1321631795}, // Jan -52 7:56:35 2012
+ {2012, int(January - 2), 18, 7, 56, 35, 0, Local, 1321631795}, // (Jan-2) 18 7:56:35 2012
+ {2010, int(December + 11), 18, 7, 56, 35, 0, Local, 1321631795}, // (Dec+11) 18 7:56:35 2010
+}
+
+func TestDate(t *testing.T) {
+ for _, tt := range dateTests {
+ time := Date(tt.year, Month(tt.month), tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z)
+ want := Unix(tt.unix, 0)
+ if !time.Equal(want) {
+ t.Errorf("Date(%d, %d, %d, %d, %d, %d, %d, %s) = %v, want %v",
+ tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z,
+ time, want)
+ }
}
}
-func BenchmarkNanoseconds(b *testing.B) {
+// Several ways of getting from
+// Fri Nov 18 7:56:35 PST 2011
+// to
+// Thu Mar 19 7:56:35 PST 2016
+var addDateTests = []struct {
+ years, months, days int
+}{
+ {4, 4, 1},
+ {3, 16, 1},
+ {3, 15, 30},
+ {5, -6, -18 - 30 - 12},
+}
+
+func TestAddDate(t *testing.T) {
+ t0 := Date(2011, 11, 18, 7, 56, 35, 0, UTC)
+ t1 := Date(2016, 3, 19, 7, 56, 35, 0, UTC)
+ for _, at := range addDateTests {
+ time := t0.AddDate(at.years, at.months, at.days)
+ if !time.Equal(t1) {
+ t.Errorf("AddDate(%d, %d, %d) = %v, want %v",
+ at.years, at.months, at.days,
+ time, t1)
+ }
+ }
+}
+
+var daysInTests = []struct {
+ year, month, di int
+}{
+ {2011, 1, 31}, // January, first month, 31 days
+ {2011, 2, 28}, // February, non-leap year, 28 days
+ {2012, 2, 29}, // February, leap year, 29 days
+ {2011, 6, 30}, // June, 30 days
+ {2011, 12, 31}, // December, last month, 31 days
+}
+
+func TestDaysIn(t *testing.T) {
+ // The daysIn function is not exported.
+ // Test the daysIn function via the `var DaysIn = daysIn`
+ // statement in the internal_test.go file.
+ for _, tt := range daysInTests {
+ di := DaysIn(Month(tt.month), tt.year)
+ if di != tt.di {
+ t.Errorf("got %d; expected %d for %d-%02d",
+ di, tt.di, tt.year, tt.month)
+ }
+ }
+}
+
+func TestAddToExactSecond(t *testing.T) {
+ // Add an amount to the current time to round it up to the next exact second.
+ // This test checks that the nsec field still lies within the range [0, 999999999].
+ t1 := Now()
+ t2 := t1.Add(Second - Duration(t1.Nanosecond()))
+ sec := (t1.Second() + 1) % 60
+ if t2.Second() != sec || t2.Nanosecond() != 0 {
+ t.Errorf("sec = %d, nsec = %d, want sec = %d, nsec = 0", t2.Second(), t2.Nanosecond(), sec)
+ }
+}
+
+func equalTimeAndZone(a, b Time) bool {
+ aname, aoffset := a.Zone()
+ bname, boffset := b.Zone()
+ return a.Equal(b) && aoffset == boffset && aname == bname
+}
+
+var gobTests = []Time{
+ Date(0, 1, 2, 3, 4, 5, 6, UTC),
+ Date(7, 8, 9, 10, 11, 12, 13, FixedZone("", 0)),
+ Unix(81985467080890095, 0x76543210), // Time.sec: 0x0123456789ABCDEF
+ Time{}, // nil location
+ Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", 32767*60)),
+ Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", -32768*60)),
+}
+
+func TestTimeGob(t *testing.T) {
+ var b bytes.Buffer
+ enc := gob.NewEncoder(&b)
+ dec := gob.NewDecoder(&b)
+ for _, tt := range gobTests {
+ var gobtt Time
+ if err := enc.Encode(&tt); err != nil {
+ t.Errorf("%v gob Encode error = %q, want nil", tt, err)
+ } else if err := dec.Decode(&gobtt); err != nil {
+ t.Errorf("%v gob Decode error = %q, want nil", tt, err)
+ } else if !equalTimeAndZone(gobtt, tt) {
+ t.Errorf("Decoded time = %v, want %v", gobtt, tt)
+ }
+ b.Reset()
+ }
+}
+
+var invalidEncodingTests = []struct {
+ bytes []byte
+ want string
+}{
+ {[]byte{}, "Time.GobDecode: no data"},
+ {[]byte{0, 2, 3}, "Time.GobDecode: unsupported version"},
+ {[]byte{1, 2, 3}, "Time.GobDecode: invalid length"},
+}
+
+func TestInvalidTimeGob(t *testing.T) {
+ for _, tt := range invalidEncodingTests {
+ var ignored Time
+ err := ignored.GobDecode(tt.bytes)
+ if err == nil || err.Error() != tt.want {
+ t.Errorf("time.GobDecode(%#v) error = %v, want %v", tt.bytes, err, tt.want)
+ }
+ }
+}
+
+var notEncodableTimes = []struct {
+ time Time
+ want string
+}{
+ {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 1)), "Time.GobEncode: zone offset has fractional minute"},
+ {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -1*60)), "Time.GobEncode: unexpected zone offset"},
+ {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", -32769*60)), "Time.GobEncode: unexpected zone offset"},
+ {Date(0, 1, 2, 3, 4, 5, 6, FixedZone("", 32768*60)), "Time.GobEncode: unexpected zone offset"},
+}
+
+func TestNotGobEncodableTime(t *testing.T) {
+ for _, tt := range notEncodableTimes {
+ _, err := tt.time.GobEncode()
+ if err == nil || err.Error() != tt.want {
+ t.Errorf("%v GobEncode error = %v, want %v", tt.time, err, tt.want)
+ }
+ }
+}
+
+var jsonTests = []struct {
+ time Time
+ json string
+}{
+ {Date(9999, 4, 12, 23, 20, 50, .52*1e9, UTC), `"9999-04-12T23:20:50.52Z"`},
+ {Date(1996, 12, 19, 16, 39, 57, 0, Local), `"1996-12-19T16:39:57-08:00"`},
+ {Date(0, 1, 1, 0, 0, 0, 1, FixedZone("", 1*60)), `"0000-01-01T00:00:00.000000001+00:01"`},
+}
+
+func TestTimeJSON(t *testing.T) {
+ for _, tt := range jsonTests {
+ var jsonTime Time
+
+ if jsonBytes, err := json.Marshal(tt.time); err != nil {
+ t.Errorf("%v json.Marshal error = %v, want nil", tt.time, err)
+ } else if string(jsonBytes) != tt.json {
+ t.Errorf("%v JSON = %#q, want %#q", tt.time, string(jsonBytes), tt.json)
+ } else if err = json.Unmarshal(jsonBytes, &jsonTime); err != nil {
+ t.Errorf("%v json.Unmarshal error = %v, want nil", tt.time, err)
+ } else if !equalTimeAndZone(jsonTime, tt.time) {
+ t.Errorf("Unmarshaled time = %v, want %v", jsonTime, tt.time)
+ }
+ }
+}
+
+func TestInvalidTimeJSON(t *testing.T) {
+ var tt Time
+ err := json.Unmarshal([]byte(`{"now is the time":"buddy"}`), &tt)
+ _, isParseErr := err.(*ParseError)
+ if !isParseErr {
+ t.Errorf("expected *time.ParseError unmarshaling JSON, got %v", err)
+ }
+}
+
+var notJSONEncodableTimes = []struct {
+ time Time
+ want string
+}{
+ {Date(10000, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+ {Date(-1, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+}
+
+func TestNotJSONEncodableTime(t *testing.T) {
+ for _, tt := range notJSONEncodableTimes {
+ _, err := tt.time.MarshalJSON()
+ if err == nil || err.Error() != tt.want {
+ t.Errorf("%v MarshalJSON error = %v, want %v", tt.time, err, tt.want)
+ }
+ }
+}
+
+var parseDurationTests = []struct {
+ in string
+ ok bool
+ want Duration
+}{
+ // simple
+ {"0", true, 0},
+ {"5s", true, 5 * Second},
+ {"30s", true, 30 * Second},
+ {"1478s", true, 1478 * Second},
+ // sign
+ {"-5s", true, -5 * Second},
+ {"+5s", true, 5 * Second},
+ {"-0", true, 0},
+ {"+0", true, 0},
+ // decimal
+ {"5.0s", true, 5 * Second},
+ {"5.6s", true, 5*Second + 600*Millisecond},
+ {"5.s", true, 5 * Second},
+ {".5s", true, 500 * Millisecond},
+ {"1.0s", true, 1 * Second},
+ {"1.00s", true, 1 * Second},
+ {"1.004s", true, 1*Second + 4*Millisecond},
+ {"1.0040s", true, 1*Second + 4*Millisecond},
+ {"100.00100s", true, 100*Second + 1*Millisecond},
+ // different units
+ {"10ns", true, 10 * Nanosecond},
+ {"11us", true, 11 * Microsecond},
+ {"12µs", true, 12 * Microsecond}, // U+00B5
+ {"12μs", true, 12 * Microsecond}, // U+03BC
+ {"13ms", true, 13 * Millisecond},
+ {"14s", true, 14 * Second},
+ {"15m", true, 15 * Minute},
+ {"16h", true, 16 * Hour},
+ // composite durations
+ {"3h30m", true, 3*Hour + 30*Minute},
+ {"10.5s4m", true, 4*Minute + 10*Second + 500*Millisecond},
+ {"-2m3.4s", true, -(2*Minute + 3*Second + 400*Millisecond)},
+ {"1h2m3s4ms5us6ns", true, 1*Hour + 2*Minute + 3*Second + 4*Millisecond + 5*Microsecond + 6*Nanosecond},
+ {"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond},
+
+ // errors
+ {"", false, 0},
+ {"3", false, 0},
+ {"-", false, 0},
+ {"s", false, 0},
+ {".", false, 0},
+ {"-.", false, 0},
+ {".s", false, 0},
+ {"+.s", false, 0},
+}
+
+func TestParseDuration(t *testing.T) {
+ for _, tc := range parseDurationTests {
+ d, err := ParseDuration(tc.in)
+ if tc.ok && (err != nil || d != tc.want) {
+ t.Errorf("ParseDuration(%q) = %v, %v, want %v, nil", tc.in, d, err, tc.want)
+ } else if !tc.ok && err == nil {
+ t.Errorf("ParseDuration(%q) = _, nil, want _, non-nil", tc.in)
+ }
+ }
+}
+
+func TestParseDurationRoundTrip(t *testing.T) {
+ for i := 0; i < 100; i++ {
+ // Resolutions finer than milliseconds will result in
+ // imprecise round-trips.
+ d0 := Duration(rand.Int31()) * Millisecond
+ s := d0.String()
+ d1, err := ParseDuration(s)
+ if err != nil || d0 != d1 {
+ t.Errorf("round-trip failed: %d => %q => %d, %v", d0, s, d1, err)
+ }
+ }
+}
+
+func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
- Nanoseconds()
+ Now()
}
}
func BenchmarkFormat(b *testing.B) {
- time := SecondsToLocalTime(1265346057)
+ time := Unix(1265346057, 0)
for i := 0; i < b.N; i++ {
time.Format("Mon Jan 2 15:04:05 2006")
}
@@ -504,3 +945,31 @@ func BenchmarkParse(b *testing.B) {
Parse(ANSIC, "Mon Jan 2 15:04:05 2006")
}
}
+
+func BenchmarkHour(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ _ = t.Hour()
+ }
+}
+
+func BenchmarkSecond(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ _ = t.Second()
+ }
+}
+
+func BenchmarkYear(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ _ = t.Year()
+ }
+}
+
+func BenchmarkDay(b *testing.B) {
+ t := Now()
+ for i := 0; i < b.N; i++ {
+ _ = t.Day()
+ }
+}
diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go
new file mode 100644
index 000000000..3c5774404
--- /dev/null
+++ b/src/pkg/time/zoneinfo.go
@@ -0,0 +1,204 @@
+// 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"
+ "syscall"
+)
+
+// A Location maps time instants to the zone in use at that time.
+// Typically, the Location represents the collection of time offsets
+// in use in a geographical area, such as CEST and CET for central Europe.
+type Location struct {
+ name string
+ zone []zone
+ tx []zoneTrans
+
+ // Most lookups will be for the current time.
+ // To avoid the binary search through tx, keep a
+ // static one-element cache that gives the correct
+ // zone for the time when the Location was created.
+ // if cacheStart <= t <= cacheEnd,
+ // lookup can return cacheZone.
+ // The units for cacheStart and cacheEnd are seconds
+ // since January 1, 1970 UTC, to match the argument
+ // to lookup.
+ cacheStart int64
+ cacheEnd int64
+ cacheZone *zone
+}
+
+// A zone represents a single time zone such as CEST or CET.
+type zone struct {
+ name string // abbreviated name, "CET"
+ offset int // seconds east of UTC
+ isDST bool // is this zone Daylight Savings Time?
+}
+
+// A zoneTrans represents a single time zone transition.
+type zoneTrans struct {
+ when int64 // transition time, in seconds since 1970 GMT
+ index uint8 // the index of the zone that goes into effect at that time
+ isstd, isutc bool // ignored - no idea what these mean
+}
+
+// UTC represents Universal Coordinated Time (UTC).
+var UTC *Location = &utcLoc
+
+// utcLoc is separate so that get can refer to &utcLoc
+// and ensure that it never returns a nil *Location,
+// even if a badly behaved client has changed UTC.
+var utcLoc = Location{name: "UTC"}
+
+// Local represents the system's local time zone.
+var Local *Location = &localLoc
+
+// localLoc is separate so that initLocal can initialize
+// it even if a client has changed Local.
+var localLoc Location
+var localOnce sync.Once
+
+func (l *Location) get() *Location {
+ if l == nil {
+ return &utcLoc
+ }
+ if l == &localLoc {
+ localOnce.Do(initLocal)
+ }
+ return l
+}
+
+// String returns a descriptive name for the time zone information,
+// corresponding to the argument to LoadLocation.
+func (l *Location) String() string {
+ return l.get().name
+}
+
+// FixedZone returns a Location that always uses
+// the given zone name and offset (seconds east of UTC).
+func FixedZone(name string, offset int) *Location {
+ l := &Location{
+ name: name,
+ zone: []zone{{name, offset, false}},
+ tx: []zoneTrans{{-1 << 63, 0, false, false}},
+ cacheStart: -1 << 63,
+ cacheEnd: 1<<63 - 1,
+ }
+ l.cacheZone = &l.zone[0]
+ return l
+}
+
+// lookup returns information about the time zone in use at an
+// instant in time expressed as seconds since January 1, 1970 00:00:00 UTC.
+//
+// The returned information gives the name of the zone (such as "CET"),
+// the start and end times bracketing sec when that zone is in effect,
+// the offset in seconds east of UTC (such as -5*60*60), and whether
+// the daylight savings is being observed at that time.
+func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) {
+ l = l.get()
+
+ if len(l.tx) == 0 {
+ name = "UTC"
+ offset = 0
+ isDST = false
+ start = -1 << 63
+ end = 1<<63 - 1
+ return
+ }
+
+ if zone := l.cacheZone; zone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
+ name = zone.name
+ offset = zone.offset
+ isDST = zone.isDST
+ start = l.cacheStart
+ end = l.cacheEnd
+ return
+ }
+
+ // Binary search for entry with largest time <= sec.
+ // Not using sort.Search to avoid dependencies.
+ tx := l.tx
+ end = 1<<63 - 1
+ for len(tx) > 1 {
+ m := len(tx) / 2
+ lim := tx[m].when
+ if sec < lim {
+ end = lim
+ tx = tx[0:m]
+ } else {
+ tx = tx[m:]
+ }
+ }
+ zone := &l.zone[tx[0].index]
+ name = zone.name
+ offset = zone.offset
+ isDST = zone.isDST
+ start = tx[0].when
+ // end = maintained during the search
+ return
+}
+
+// lookupName returns information about the time zone with
+// the given name (such as "EST").
+func (l *Location) lookupName(name string) (offset int, isDST bool, ok bool) {
+ l = l.get()
+ for i := range l.zone {
+ zone := &l.zone[i]
+ if zone.name == name {
+ return zone.offset, zone.isDST, true
+ }
+ }
+ return
+}
+
+// lookupOffset returns information about the time zone with
+// the given offset (such as -5*60*60).
+func (l *Location) lookupOffset(offset int) (name string, isDST bool, ok bool) {
+ l = l.get()
+ for i := range l.zone {
+ zone := &l.zone[i]
+ if zone.offset == offset {
+ return zone.name, zone.isDST, true
+ }
+ }
+ return
+}
+
+// NOTE(rsc): Eventually we will need to accept the POSIX TZ environment
+// syntax too, but I don't feel like implementing it today.
+
+var zoneinfo, _ = syscall.Getenv("ZONEINFO")
+
+// LoadLocation returns the Location with the given name.
+//
+// If the name is "" or "UTC", LoadLocation returns UTC.
+// If the name is "Local", LoadLocation returns Local.
+//
+// Otherwise, the name is taken to be a location name corresponding to a file
+// in the IANA Time Zone database, such as "America/New_York".
+//
+// The time zone database needed by LoadLocation may not be
+// present on all systems, especially non-Unix systems.
+// LoadLocation looks in the directory or uncompressed zip file
+// named by the ZONEINFO environment variable, if any, then looks in
+// known installation locations on Unix systems,
+// and finally looks in $GOROOT/lib/time/zoneinfo.zip.
+func LoadLocation(name string) (*Location, error) {
+ if name == "" || name == "UTC" {
+ return UTC, nil
+ }
+ if name == "Local" {
+ return Local, nil
+ }
+ if zoneinfo != "" {
+ if z, err := loadZoneFile(zoneinfo, name); err == nil {
+ z.name = name
+ return z, nil
+ }
+ }
+ return loadLocation(name)
+}
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
index 3c3e7c424..6855238dc 100644
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -7,53 +7,150 @@
package time
import (
- "os"
- "strconv"
- "strings"
+ "errors"
+ "runtime"
+ "syscall"
)
-func parseZones(s string) (zt []zonetime) {
- f := strings.Fields(s)
+func isSpace(r rune) bool {
+ return r == ' ' || r == '\t' || r == '\n'
+}
+
+// Copied from strings to avoid a dependency.
+func fields(s string) []string {
+ // First count the fields.
+ n := 0
+ inField := false
+ for _, rune := range s {
+ wasInField := inField
+ inField = !isSpace(rune)
+ if inField && !wasInField {
+ n++
+ }
+ }
+
+ // Now create them.
+ a := make([]string, n)
+ na := 0
+ fieldStart := -1 // Set to -1 when looking for start of field.
+ for i, rune := range s {
+ if isSpace(rune) {
+ if fieldStart >= 0 {
+ a[na] = s[fieldStart:i]
+ na++
+ fieldStart = -1
+ }
+ } else if fieldStart == -1 {
+ fieldStart = i
+ }
+ }
+ if fieldStart >= 0 { // Last field might end at EOF.
+ a[na] = s[fieldStart:]
+ }
+ return a
+}
+
+func loadZoneDataPlan9(s string) (l *Location, err error) {
+ f := fields(s)
if len(f) < 4 {
- return
+ if len(f) == 2 && f[0] == "GMT" {
+ return UTC, nil
+ }
+ return nil, badData
}
+ var zones [2]zone
+
// standard timezone offset
- o, err := strconv.Atoi(f[1])
+ o, err := atoi(f[1])
if err != nil {
- return
+ return nil, badData
}
- std := &zone{name: f[0], utcoff: o, isdst: false}
+ zones[0] = zone{name: f[0], offset: o, isDST: false}
// alternate timezone offset
- o, err = strconv.Atoi(f[3])
+ o, err = atoi(f[3])
if err != nil {
- return
+ return nil, badData
}
- dst := &zone{name: f[2], utcoff: o, isdst: true}
+ zones[1] = zone{name: f[2], offset: o, isDST: true}
// transition time pairs
+ var tx []zoneTrans
f = f[4:]
for i := 0; i < len(f); i++ {
- z := std
+ zi := 0
if i%2 == 0 {
- z = dst
+ zi = 1
}
- t, err := strconv.Atoi(f[i])
+ t, err := atoi(f[i])
if err != nil {
- return nil
+ return nil, badData
+ }
+ t -= zones[0].offset
+ tx = append(tx, zoneTrans{when: int64(t), index: uint8(zi)})
+ }
+
+ // Committed to succeed.
+ l = &Location{zone: zones[:], tx: tx}
+
+ // Fill in the cache with information about right now,
+ // since that will be the most common lookup.
+ sec, _ := now()
+ for i := range tx {
+ if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
+ l.cacheStart = tx[i].when
+ l.cacheEnd = 1<<63 - 1
+ if i+1 < len(tx) {
+ l.cacheEnd = tx[i+1].when
+ }
+ l.cacheZone = &l.zone[tx[i].index]
}
- t -= std.utcoff
- zt = append(zt, zonetime{time: int32(t), zone: z})
}
- return
+
+ return l, nil
+}
+
+func loadZoneFilePlan9(name string) (*Location, error) {
+ b, err := readFile(name)
+ if err != nil {
+ return nil, err
+ }
+ return loadZoneDataPlan9(string(b))
}
-func setupZone() {
- t, err := os.Getenverror("timezone")
+func initTestingZone() {
+ z, err := loadLocation("America/Los_Angeles")
if err != nil {
- // do nothing: use UTC
- return
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
+ }
+ z.name = "Local"
+ localLoc = *z
+}
+
+func initLocal() {
+ t, ok := syscall.Getenv("timezone")
+ if ok {
+ if z, err := loadZoneDataPlan9(t); err == nil {
+ localLoc = *z
+ return
+ }
+ } else {
+ if z, err := loadZoneFilePlan9("/adm/timezone/local"); err == nil {
+ localLoc = *z
+ localLoc.name = "Local"
+ return
+ }
+ }
+
+ // Fall back to UTC.
+ localLoc.name = "UTC"
+}
+
+func loadLocation(name string) (*Location, error) {
+ if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
+ z.name = name
+ return z, nil
}
- zones = parseZones(t)
+ return nil, errors.New("unknown time zone " + name)
}
diff --git a/src/pkg/time/zoneinfo_posix.go b/src/pkg/time/zoneinfo_posix.go
deleted file mode 100644
index b49216410..000000000
--- a/src/pkg/time/zoneinfo_posix.go
+++ /dev/null
@@ -1,62 +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 time
-
-import "sync"
-
-// Parsed representation
-type zone struct {
- utcoff int
- isdst bool
- name string
-}
-
-type zonetime struct {
- time int32 // transition time, in seconds since 1970 GMT
- zone *zone // the zone that goes into effect at that time
- isstd, isutc bool // ignored - no idea what these mean
-}
-
-var zones []zonetime
-var onceSetupZone sync.Once
-
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
- onceSetupZone.Do(setupZone)
- if len(zones) == 0 {
- return "UTC", 0
- }
-
- // Binary search for entry with largest time <= sec
- tz := zones
- for len(tz) > 1 {
- m := len(tz) / 2
- if sec < int64(tz[m].time) {
- tz = tz[0:m]
- } else {
- tz = tz[m:]
- }
- }
- z := tz[0].zone
- return z.name, z.utcoff
-}
-
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-// For example, for a system configured as being in New York,
-// it only recognizes "EST" and "EDT".
-// For a system in San Francisco, "PST" and "PDT".
-// For a system in Sydney, "EST" and "EDT", though they have
-// different meanings than they do in New York.
-func lookupByName(name string) (off int, found bool) {
- onceSetupZone.Do(setupZone)
- for _, z := range zones {
- if name == z.zone.name {
- return z.zone.utcoff, true
- }
- }
- return 0, false
-}
diff --git a/src/pkg/time/zoneinfo_read.go b/src/pkg/time/zoneinfo_read.go
new file mode 100644
index 000000000..ebb4205a9
--- /dev/null
+++ b/src/pkg/time/zoneinfo_read.go
@@ -0,0 +1,341 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse "zoneinfo" time zone file.
+// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
+// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
+// and ftp://munnari.oz.au/pub/oldtz/
+
+package time
+
+import "errors"
+
+const (
+ headerSize = 4 + 16 + 4*7
+)
+
+// Simple I/O interface to binary blob of data.
+type data struct {
+ p []byte
+ error bool
+}
+
+func (d *data) read(n int) []byte {
+ if len(d.p) < n {
+ d.p = nil
+ d.error = true
+ return nil
+ }
+ p := d.p[0:n]
+ d.p = d.p[n:]
+ return p
+}
+
+func (d *data) big4() (n uint32, ok bool) {
+ p := d.read(4)
+ if len(p) < 4 {
+ d.error = true
+ return 0, false
+ }
+ return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
+}
+
+func (d *data) byte() (n byte, ok bool) {
+ p := d.read(1)
+ if len(p) < 1 {
+ d.error = true
+ return 0, false
+ }
+ return p[0], true
+}
+
+// Make a string by stopping at the first NUL
+func byteString(p []byte) string {
+ for i := 0; i < len(p); i++ {
+ if p[i] == 0 {
+ return string(p[0:i])
+ }
+ }
+ return string(p)
+}
+
+var badData = errors.New("malformed time zone information")
+
+func loadZoneData(bytes []byte) (l *Location, err error) {
+ d := data{bytes, false}
+
+ // 4-byte magic "TZif"
+ if magic := d.read(4); string(magic) != "TZif" {
+ return nil, badData
+ }
+
+ // 1-byte version, then 15 bytes of padding
+ var p []byte
+ if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+ return nil, badData
+ }
+
+ // six big-endian 32-bit integers:
+ // number of UTC/local indicators
+ // number of standard/wall indicators
+ // number of leap seconds
+ // number of transition times
+ // number of local time zones
+ // number of characters of time zone abbrev strings
+ const (
+ NUTCLocal = iota
+ NStdWall
+ NLeap
+ NTime
+ NZone
+ NChar
+ )
+ var n [6]int
+ for i := 0; i < 6; i++ {
+ nn, ok := d.big4()
+ if !ok {
+ return nil, badData
+ }
+ n[i] = int(nn)
+ }
+
+ // Transition times.
+ txtimes := data{d.read(n[NTime] * 4), false}
+
+ // Time zone indices for transition times.
+ txzones := d.read(n[NTime])
+
+ // Zone info structures
+ zonedata := data{d.read(n[NZone] * 6), false}
+
+ // Time zone abbreviations.
+ abbrev := d.read(n[NChar])
+
+ // Leap-second time pairs
+ d.read(n[NLeap] * 8)
+
+ // Whether tx times associated with local time types
+ // are specified as standard time or wall time.
+ isstd := d.read(n[NStdWall])
+
+ // Whether tx times associated with local time types
+ // are specified as UTC or local time.
+ isutc := d.read(n[NUTCLocal])
+
+ if d.error { // ran out of data
+ return nil, badData
+ }
+
+ // If version == 2, the entire file repeats, this time using
+ // 8-byte ints for txtimes and leap seconds.
+ // We won't need those until 2106.
+
+ // Now we can build up a useful data structure.
+ // First the zone information.
+ // utcoff[4] isdst[1] nameindex[1]
+ zone := make([]zone, n[NZone])
+ for i := range zone {
+ var ok bool
+ var n uint32
+ if n, ok = zonedata.big4(); !ok {
+ return nil, badData
+ }
+ zone[i].offset = int(n)
+ var b byte
+ if b, ok = zonedata.byte(); !ok {
+ return nil, badData
+ }
+ zone[i].isDST = b != 0
+ if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
+ return nil, badData
+ }
+ zone[i].name = byteString(abbrev[b:])
+ }
+
+ // Now the transition time info.
+ tx := make([]zoneTrans, n[NTime])
+ for i := range tx {
+ var ok bool
+ var n uint32
+ if n, ok = txtimes.big4(); !ok {
+ return nil, badData
+ }
+ tx[i].when = int64(int32(n))
+ if int(txzones[i]) >= len(zone) {
+ return nil, badData
+ }
+ tx[i].index = txzones[i]
+ if i < len(isstd) {
+ tx[i].isstd = isstd[i] != 0
+ }
+ if i < len(isutc) {
+ tx[i].isutc = isutc[i] != 0
+ }
+ }
+
+ // Commited to succeed.
+ l = &Location{zone: zone, tx: tx}
+
+ // Fill in the cache with information about right now,
+ // since that will be the most common lookup.
+ sec, _ := now()
+ for i := range tx {
+ if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
+ l.cacheStart = tx[i].when
+ l.cacheEnd = 1<<63 - 1
+ if i+1 < len(tx) {
+ l.cacheEnd = tx[i+1].when
+ }
+ l.cacheZone = &l.zone[tx[i].index]
+ }
+ }
+
+ return l, nil
+}
+
+func loadZoneFile(dir, name string) (l *Location, err error) {
+ if len(dir) > 4 && dir[len(dir)-4:] == ".zip" {
+ return loadZoneZip(dir, name)
+ }
+ if dir != "" {
+ name = dir + "/" + name
+ }
+ buf, err := readFile(name)
+ if err != nil {
+ return
+ }
+ return loadZoneData(buf)
+}
+
+// There are 500+ zoneinfo files. Rather than distribute them all
+// individually, we ship them in an uncompressed zip file.
+// Used this way, the zip file format serves as a commonly readable
+// container for the individual small files. We choose zip over tar
+// because zip files have a contiguous table of contents, making
+// individual file lookups faster, and because the per-file overhead
+// in a zip file is considerably less than tar's 512 bytes.
+
+// get4 returns the little-endian 32-bit value in b.
+func get4(b []byte) int {
+ if len(b) < 4 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func get2(b []byte) int {
+ if len(b) < 2 {
+ return 0
+ }
+ return int(b[0]) | int(b[1])<<8
+}
+
+func loadZoneZip(zipfile, name string) (l *Location, err error) {
+ fd, err := open(zipfile)
+ if err != nil {
+ return nil, errors.New("open " + zipfile + ": " + err.Error())
+ }
+ defer closefd(fd)
+
+ const (
+ zecheader = 0x06054b50
+ zcheader = 0x02014b50
+ ztailsize = 22
+
+ zheadersize = 30
+ zheader = 0x04034b50
+ )
+
+ buf := make([]byte, ztailsize)
+ if err := preadn(fd, buf, -ztailsize); err != nil || get4(buf) != zecheader {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+ n := get2(buf[10:])
+ size := get4(buf[12:])
+ off := get4(buf[16:])
+
+ buf = make([]byte, size)
+ if err := preadn(fd, buf, off); err != nil {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+
+ for i := 0; i < n; i++ {
+ // zip entry layout:
+ // 0 magic[4]
+ // 4 madevers[1]
+ // 5 madeos[1]
+ // 6 extvers[1]
+ // 7 extos[1]
+ // 8 flags[2]
+ // 10 meth[2]
+ // 12 modtime[2]
+ // 14 moddate[2]
+ // 16 crc[4]
+ // 20 csize[4]
+ // 24 uncsize[4]
+ // 28 namelen[2]
+ // 30 xlen[2]
+ // 32 fclen[2]
+ // 34 disknum[2]
+ // 36 iattr[2]
+ // 38 eattr[4]
+ // 42 off[4]
+ // 46 name[namelen]
+ // 46+namelen+xlen+fclen - next header
+ //
+ if get4(buf) != zcheader {
+ break
+ }
+ meth := get2(buf[10:])
+ size := get4(buf[24:])
+ namelen := get2(buf[28:])
+ xlen := get2(buf[30:])
+ fclen := get2(buf[32:])
+ off := get4(buf[42:])
+ zname := buf[46 : 46+namelen]
+ buf = buf[46+namelen+xlen+fclen:]
+ if string(zname) != name {
+ continue
+ }
+ if meth != 0 {
+ return nil, errors.New("unsupported compression for " + name + " in " + zipfile)
+ }
+
+ // zip per-file header layout:
+ // 0 magic[4]
+ // 4 extvers[1]
+ // 5 extos[1]
+ // 6 flags[2]
+ // 8 meth[2]
+ // 10 modtime[2]
+ // 12 moddate[2]
+ // 14 crc[4]
+ // 18 csize[4]
+ // 22 uncsize[4]
+ // 26 namelen[2]
+ // 28 xlen[2]
+ // 30 name[namelen]
+ // 30+namelen+xlen - file data
+ //
+ buf = make([]byte, zheadersize+namelen)
+ if err := preadn(fd, buf, off); err != nil ||
+ get4(buf) != zheader ||
+ get2(buf[8:]) != meth ||
+ get2(buf[26:]) != namelen ||
+ string(buf[30:30+namelen]) != name {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+ xlen = get2(buf[28:])
+
+ buf = make([]byte, size)
+ if err := preadn(fd, buf, off+30+namelen+xlen); err != nil {
+ return nil, errors.New("corrupt zip file " + zipfile)
+ }
+
+ return loadZoneData(buf)
+ }
+
+ return nil, errors.New("cannot find " + name + " in zip file " + zipfile)
+}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index f3ea7b6fd..2c951a983 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.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.
+// +build darwin freebsd linux netbsd openbsd
+
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
@@ -10,204 +12,61 @@
package time
import (
- "io/ioutil"
- "os"
-)
-
-const (
- headerSize = 4 + 16 + 4*7
+ "errors"
+ "runtime"
+ "syscall"
)
-// Simple I/O interface to binary blob of data.
-type data struct {
- p []byte
- error bool
-}
-
-func (d *data) read(n int) []byte {
- if len(d.p) < n {
- d.p = nil
- d.error = true
- return nil
- }
- p := d.p[0:n]
- d.p = d.p[n:]
- return p
-}
-
-func (d *data) big4() (n uint32, ok bool) {
- p := d.read(4)
- if len(p) < 4 {
- d.error = true
- return 0, false
- }
- return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
-}
-
-func (d *data) byte() (n byte, ok bool) {
- p := d.read(1)
- if len(p) < 1 {
- d.error = true
- return 0, false
+func initTestingZone() {
+ z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", "America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
}
- return p[0], true
+ z.name = "Local"
+ localLoc = *z
}
-// Make a string by stopping at the first NUL
-func byteString(p []byte) string {
- for i := 0; i < len(p); i++ {
- if p[i] == 0 {
- return string(p[0:i])
- }
- }
- return string(p)
+// Many systems use /usr/share/zoneinfo, Solaris 2 has
+// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
+var zoneDirs = []string{
+ "/usr/share/zoneinfo/",
+ "/usr/share/lib/zoneinfo/",
+ "/usr/lib/locale/TZ/",
+ runtime.GOROOT() + "/lib/time/zoneinfo/",
}
-func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
- d := data{bytes, false}
-
- // 4-byte magic "TZif"
- if magic := d.read(4); string(magic) != "TZif" {
- return nil, false
- }
-
- // 1-byte version, then 15 bytes of padding
- var p []byte
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
- return nil, false
- }
-
- // six big-endian 32-bit integers:
- // number of UTC/local indicators
- // number of standard/wall indicators
- // number of leap seconds
- // number of transition times
- // number of local time zones
- // number of characters of time zone abbrev strings
- const (
- NUTCLocal = iota
- NStdWall
- NLeap
- NTime
- NZone
- NChar
- )
- var n [6]int
- for i := 0; i < 6; i++ {
- nn, ok := d.big4()
- if !ok {
- return nil, false
- }
- n[i] = int(nn)
- }
-
- // Transition times.
- txtimes := data{d.read(n[NTime] * 4), false}
-
- // Time zone indices for transition times.
- txzones := d.read(n[NTime])
-
- // Zone info structures
- zonedata := data{d.read(n[NZone] * 6), false}
-
- // Time zone abbreviations.
- abbrev := d.read(n[NChar])
-
- // Leap-second time pairs
- d.read(n[NLeap] * 8)
-
- // Whether tx times associated with local time types
- // are specified as standard time or wall time.
- isstd := d.read(n[NStdWall])
-
- // Whether tx times associated with local time types
- // are specified as UTC or local time.
- isutc := d.read(n[NUTCLocal])
-
- if d.error { // ran out of data
- return nil, false
- }
-
- // If version == 2, the entire file repeats, this time using
- // 8-byte ints for txtimes and leap seconds.
- // We won't need those until 2106.
-
- // Now we can build up a useful data structure.
- // First the zone information.
- // utcoff[4] isdst[1] nameindex[1]
- z := make([]zone, n[NZone])
- for i := 0; i < len(z); i++ {
- var ok bool
- var n uint32
- if n, ok = zonedata.big4(); !ok {
- return nil, false
- }
- z[i].utcoff = int(n)
- var b byte
- if b, ok = zonedata.byte(); !ok {
- return nil, false
- }
- z[i].isdst = b != 0
- if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
- return nil, false
- }
- z[i].name = byteString(abbrev[b:])
- }
+func initLocal() {
+ // consult $TZ to find the time zone to use.
+ // no $TZ means use the system default /etc/localtime.
+ // $TZ="" means use UTC.
+ // $TZ="foo" means use /usr/share/zoneinfo/foo.
- // Now the transition time info.
- zt = make([]zonetime, n[NTime])
- for i := 0; i < len(zt); i++ {
- var ok bool
- var n uint32
- if n, ok = txtimes.big4(); !ok {
- return nil, false
- }
- zt[i].time = int32(n)
- if int(txzones[i]) >= len(z) {
- return nil, false
- }
- zt[i].zone = &z[txzones[i]]
- if i < len(isstd) {
- zt[i].isstd = isstd[i] != 0
+ tz, ok := syscall.Getenv("TZ")
+ switch {
+ case !ok:
+ z, err := loadZoneFile("", "/etc/localtime")
+ if err == nil {
+ localLoc = *z
+ localLoc.name = "Local"
+ return
}
- if i < len(isutc) {
- zt[i].isutc = isutc[i] != 0
+ case tz != "" && tz != "UTC":
+ if z, err := loadLocation(tz); err == nil {
+ localLoc = *z
+ return
}
}
- return zt, true
-}
-func readinfofile(name string) ([]zonetime, bool) {
- buf, err := ioutil.ReadFile(name)
- if err != nil {
- return nil, false
- }
- return parseinfo(buf)
+ // Fall back to UTC.
+ localLoc.name = "UTC"
}
-func setupZone() {
- // consult $TZ to find the time zone to use.
- // no $TZ means use the system default /etc/localtime.
- // $TZ="" means use UTC.
- // $TZ="foo" means use /usr/share/zoneinfo/foo.
- // Many systems use /usr/share/zoneinfo, Solaris 2 has
- // /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
- zoneDirs := []string{"/usr/share/zoneinfo/",
- "/usr/share/lib/zoneinfo/",
- "/usr/lib/locale/TZ/"}
-
- tz, err := os.Getenverror("TZ")
- switch {
- case err == os.ENOENV:
- zones, _ = readinfofile("/etc/localtime")
- case len(tz) > 0:
- for _, zoneDir := range zoneDirs {
- var ok bool
- if zones, ok = readinfofile(zoneDir + tz); ok {
- break
- }
+func loadLocation(name string) (*Location, error) {
+ for _, zoneDir := range zoneDirs {
+ if z, err := loadZoneFile(zoneDir, name); err == nil {
+ z.name = name
+ return z, nil
}
- case len(tz) == 0:
- // do nothing: use UTC
}
+ return nil, errors.New("unknown time zone " + name)
}
diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
index fabc00601..754e392de 100644
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -5,188 +5,157 @@
package time
import (
+ "errors"
+ "runtime"
"syscall"
- "sync"
- "os"
)
-// BUG(brainman): The Windows implementation assumes that
-// this year's rules for daylight savings time apply to all previous
-// and future years as well.
-
-// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
-// to improve on situation described in the bug above.
-
-type zone struct {
- name string
- offset int
- year int64
- month, day, dayofweek int
- hour, minute, second int
- abssec int64
- prev *zone
-}
+// TODO(rsc): Fall back to copy of zoneinfo files.
-// Populate zone struct with Windows supplied information. Returns true, if data is valid.
-func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
- z.name = syscall.UTF16ToString(name)
- z.offset = int(bias)
- z.year = int64(d.Year)
- z.month = int(d.Month)
- z.day = int(d.Day)
- z.dayofweek = int(d.DayOfWeek)
- z.hour = int(d.Hour)
- z.minute = int(d.Minute)
- z.second = int(d.Second)
- dateisgood = d.Month != 0
- if dateisgood {
- z.offset += int(biasdelta)
- }
- z.offset = -z.offset * 60
- return
-}
+// BUG(brainman,rsc): On Windows, the operating system does not provide complete
+// time zone information.
+// The implementation assumes that this year's rules for daylight savings
+// time apply to all previous and future years as well.
+// Also, time zone abbreviations are unavailable. The implementation constructs
+// them using the capital letters from a longer time zone description.
-// 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, 0, ""}).Seconds()
- // Time given is in "local" time. Adjust it for "utc".
- z.abssec -= int64(z.prev.offset)
+// abbrev returns the abbreviation to use for the given zone name.
+func abbrev(name []uint16) string {
+ // name is 'Pacific Standard Time' but we want 'PST'.
+ // Extract just capital letters. It's not perfect but the
+ // information we need is not available from the kernel.
+ // Because time zone abbreviations are not unique,
+ // Windows refuses to expose them.
+ //
+ // http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb
+ // http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net
+ var short []rune
+ for _, c := range name {
+ if 'A' <= c && c <= 'Z' {
+ short = append(short, rune(c))
+ }
}
+ return string(short)
}
-// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year.
-func (z *zone) cutoffSeconds(year int64) int64 {
+// pseudoUnix returns the pseudo-Unix time (seconds since Jan 1 1970 *LOCAL TIME*)
+// denoted by the system date+time d in the given year.
+// It is up to the caller to convert this local time into a UTC-based time.
+func pseudoUnix(year int, d *syscall.Systemtime) int64 {
// Windows specifies daylight savings information in "day in month" format:
- // z.month is month number (1-12)
- // z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
- // z.day is week within the month (1 to 5, where 5 is last week of the month)
- // z.hour, z.minute and z.second are absolute time
- t := &Time{year, 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
+ // d.Month is month number (1-12)
+ // d.DayOfWeek is appropriate weekday (Sunday=0 to Saturday=6)
+ // d.Day is week within the month (1 to 5, where 5 is last week of the month)
+ // d.Hour, d.Minute and d.Second are absolute time
+ day := 1
+ t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC)
+ i := int(d.DayOfWeek) - int(t.Weekday())
if i < 0 {
i += 7
}
- t.Day += i
- if week := int(z.day) - 1; week < 4 {
- t.Day += week * 7
+ day += i
+ if week := int(d.Day) - 1; week < 4 {
+ day += week * 7
} else {
// "Last" instance of the day.
- t.Day += 4 * 7
- if t.Day > months(year)[t.Month] {
- t.Day -= 7
+ day += 4 * 7
+ if day > daysIn(Month(d.Month), year) {
+ day -= 7
}
}
- // Result is in "local" time. Adjust it for "utc".
- return t.Seconds() - int64(z.prev.offset)
+ return t.sec + int64(day-1)*secondsPerDay + internalToUnix
}
-// Is t before the cutoff for switching to z?
-func (z *zone) isBeforeCutoff(t *Time) bool {
- var coff int64
- if z.year == 0 {
- // "day in month" format used
- coff = z.cutoffSeconds(t.Year)
- } else {
- // "absolute" format used
- coff = z.abssec
- }
- return t.Seconds() < coff
-}
+func initLocalFromTZI(i *syscall.Timezoneinformation) {
+ l := &localLoc
-type zoneinfo struct {
- disabled bool // daylight saving time is not used locally
- offsetIfDisabled int
- januaryIsStd bool // is january 1 standard time?
- std, dst zone
-}
+ nzone := 1
+ if i.StandardDate.Month > 0 {
+ nzone++
+ }
+ l.zone = make([]zone, nzone)
-// Pick zone (std or dst) t time belongs to.
-func (zi *zoneinfo) pickZone(t *Time) *zone {
- z := &zi.std
- if tz.januaryIsStd {
- if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
- // after switch to daylight time and before the switch back to standard
- z = &zi.dst
- }
- } else {
- if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
- // before switch to standard time or after the switch back to daylight
- z = &zi.dst
- }
+ std := &l.zone[0]
+ std.name = abbrev(i.StandardName[0:])
+ if nzone == 1 {
+ // No daylight savings.
+ std.offset = -int(i.Bias) * 60
+ l.cacheStart = -1 << 63
+ l.cacheEnd = 1<<63 - 1
+ l.cacheZone = std
+ return
}
- return z
-}
-var tz zoneinfo
-var initError os.Error
-var onceSetupZone sync.Once
+ // StandardBias must be ignored if StandardDate is not set,
+ // so this computation is delayed until after the nzone==1
+ // return above.
+ std.offset = -int(i.Bias+i.StandardBias) * 60
-func setupZone() {
- var i syscall.Timezoneinformation
- if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
- initError = os.NewSyscallError("GetTimeZoneInformation", e)
- return
+ dst := &l.zone[1]
+ dst.name = abbrev(i.DaylightName[0:])
+ dst.offset = -int(i.Bias+i.DaylightBias) * 60
+ dst.isDST = true
+
+ // Arrange so that d0 is first transition date, d1 second,
+ // i0 is index of zone after first transition, i1 second.
+ d0 := &i.StandardDate
+ d1 := &i.DaylightDate
+ i0 := 0
+ i1 := 1
+ if d0.Month > d1.Month {
+ d0, d1 = d1, d0
+ i0, i1 = i1, i0
}
- if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
- tz.disabled = true
- tz.offsetIfDisabled = tz.std.offset
- return
+
+ // 2 tx per year, 100 years on each side of this year
+ l.tx = make([]zoneTrans, 400)
+
+ t := Now().UTC()
+ year := t.Year()
+ txi := 0
+ for y := year - 100; y < year+100; y++ {
+ tx := &l.tx[txi]
+ tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset)
+ tx.index = uint8(i0)
+ txi++
+
+ tx = &l.tx[txi]
+ tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset)
+ tx.index = uint8(i1)
+ txi++
}
- tz.std.prev = &tz.dst
- tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
- tz.dst.prev = &tz.std
- tz.std.preCalculateAbsSec()
- tz.dst.preCalculateAbsSec()
- // Is january 1 standard time this year?
- t := UTC()
- tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
}
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
- onceSetupZone.Do(setupZone)
- if initError != nil {
- return "", 0
- }
- if tz.disabled {
- return "", tz.offsetIfDisabled
- }
- t := SecondsToUTC(sec)
- z := &tz.std
- if tz.std.year == 0 {
- // "day in month" format used
- z = tz.pickZone(t)
- } else {
- // "absolute" format used
- if tz.std.year == t.Year {
- // we have rule for the year in question
- z = tz.pickZone(t)
- } else {
- // we do not have any information for that year,
- // will assume standard offset all year around
- }
- }
- return z.name, z.offset
+var usPacific = syscall.Timezoneinformation{
+ Bias: 8 * 60,
+ StandardName: [32]uint16{
+ 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'S', 't', 'a', 'n', 'd', 'a', 'r', 'd', ' ', 'T', 'i', 'm', 'e',
+ },
+ StandardDate: syscall.Systemtime{Month: 11, Day: 1, Hour: 2},
+ DaylightName: [32]uint16{
+ 'P', 'a', 'c', 'i', 'f', 'i', 'c', ' ', 'D', 'a', 'y', 'l', 'i', 'g', 'h', 't', ' ', 'T', 'i', 'm', 'e',
+ },
+ DaylightDate: syscall.Systemtime{Month: 3, Day: 2, Hour: 2},
+ DaylightBias: -60,
}
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-func lookupByName(name string) (off int, found bool) {
- onceSetupZone.Do(setupZone)
- if initError != nil {
- return 0, false
- }
- if tz.disabled {
- return tz.offsetIfDisabled, false
+func initTestingZone() {
+ initLocalFromTZI(&usPacific)
+}
+
+func initLocal() {
+ var i syscall.Timezoneinformation
+ if _, err := syscall.GetTimeZoneInformation(&i); err != nil {
+ localLoc.name = "UTC"
+ return
}
- switch name {
- case tz.std.name:
- return tz.std.offset, true
- case tz.dst.name:
- return tz.dst.offset, true
+ initLocalFromTZI(&i)
+}
+
+func loadLocation(name string) (*Location, error) {
+ if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
+ z.name = name
+ return z, nil
}
- return 0, false
+ return nil, errors.New("unknown time zone " + name)
}
diff --git a/src/pkg/try/Makefile b/src/pkg/try/Makefile
deleted file mode 100644
index 06981a6fc..000000000
--- a/src/pkg/try/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=try
-GOFILES=\
- try.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/try/try.go b/src/pkg/try/try.go
deleted file mode 100644
index 2a3dbf987..000000000
--- a/src/pkg/try/try.go
+++ /dev/null
@@ -1,174 +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 try contains the executable part of the gotry command.
-// It is not intended for general use.
-package try
-
-import (
- "fmt"
- "io"
- "os"
- "reflect"
- "unicode"
-)
-
-var output io.Writer = os.Stdout // redirected when testing
-
-// Main is called directly from the gotry-generated Go source file to perform
-// the evaluations.
-func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) {
- switch len(args) {
- case 0:
- // Nothing to do.
- case 1:
- // Compiler has already evaluated the expression; just print the result.
- printSlice(firstArg, args)
- default:
- // See if methods satisfy the expressions.
- tryMethods(pkg, firstArg, args)
- // See if functions satisfy the expressions.
- for name, fn := range functions {
- tryFunction(pkg, name, fn, args)
- }
- }
-}
-
-// printSlice prints the zeroth element of the args slice, which should (by construction)
-// itself be a slice of interface{}.
-func printSlice(firstArg string, args []interface{}) {
- // Args should be length 1 and a slice.
- if len(args) != 1 {
- return
- }
- arg, ok := args[0].([]interface{})
- if !ok {
- return
- }
- fmt.Fprintf(output, "%s = ", firstArg)
- if len(arg) > 1 {
- fmt.Fprint(output, "(")
- }
- for i, a := range arg {
- if i > 0 {
- fmt.Fprint(output, ", ")
- }
- fmt.Fprintf(output, "%#v", a)
- }
- if len(arg) > 1 {
- fmt.Fprint(output, ")")
- }
- fmt.Fprint(output, "\n")
-}
-
-// tryMethods sees if the zeroth arg has methods, and if so treats them as potential
-// functions to satisfy the remaining arguments.
-func tryMethods(pkg, firstArg string, args []interface{}) {
- defer func() { recover() }()
- // Is the first argument something with methods?
- v := reflect.ValueOf(args[0])
- typ := v.Type()
- if typ.NumMethod() == 0 {
- return
- }
- for i := 0; i < typ.NumMethod(); i++ {
- if unicode.IsUpper(int(typ.Method(i).Name[0])) {
- tryMethod(pkg, firstArg, typ.Method(i), args)
- }
- }
-}
-
-// tryMethod converts a method to a function for tryOneFunction.
-func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
- rfn := method.Func
- typ := method.Type
- name := method.Name
- tryOneFunction(pkg, firstArg, name, typ, rfn, args)
-}
-
-// tryFunction sees if fn satisfies the arguments.
-func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
- defer func() { recover() }()
- rfn := reflect.ValueOf(fn)
- typ := rfn.Type()
- tryOneFunction(pkg, "", name, typ, rfn, args)
-}
-
-// tryOneFunction is the common code for tryMethod and tryFunction.
-func tryOneFunction(pkg, firstArg, name string, typ reflect.Type, rfn reflect.Value, args []interface{}) {
- // Any results?
- if typ.NumOut() == 0 {
- return // Nothing to do.
- }
- // Right number of arguments + results?
- if typ.NumIn()+typ.NumOut() != len(args) {
- return
- }
- // Right argument and result types?
- for i, a := range args {
- if i < typ.NumIn() {
- if !compatible(a, typ.In(i)) {
- return
- }
- } else {
- if !compatible(a, typ.Out(i-typ.NumIn())) {
- return
- }
- }
- }
- // Build the call args.
- argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
- for i, a := range args {
- argsVal[i] = reflect.ValueOf(a)
- }
- // Call the function and see if the results are as expected.
- resultVal := rfn.Call(argsVal[:typ.NumIn()])
- for i, v := range resultVal {
- if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
- return
- }
- }
- // Present the result including a godoc command to get more information.
- firstIndex := 0
- if firstArg != "" {
- fmt.Fprintf(output, "%s.%s(", firstArg, name)
- firstIndex = 1
- } else {
- fmt.Fprintf(output, "%s.%s(", pkg, name)
- }
- for i := firstIndex; i < typ.NumIn(); i++ {
- if i > firstIndex {
- fmt.Fprint(output, ", ")
- }
- fmt.Fprintf(output, "%#v", args[i])
- }
- fmt.Fprint(output, ") = ")
- if typ.NumOut() > 1 {
- fmt.Fprint(output, "(")
- }
- for i := 0; i < typ.NumOut(); i++ {
- if i > 0 {
- fmt.Fprint(output, ", ")
- }
- fmt.Fprintf(output, "%#v", resultVal[i].Interface())
- }
- if typ.NumOut() > 1 {
- fmt.Fprint(output, ")")
- }
- fmt.Fprintf(output, " // godoc %s %s\n", pkg, name)
-}
-
-// compatible reports whether the argument is compatible with the type.
-func compatible(arg interface{}, typ reflect.Type) bool {
- if reflect.TypeOf(arg) == typ {
- return true
- }
- if arg == nil {
- // nil is OK if the type is an interface.
- if typ.Kind() == reflect.Interface {
- return true
- }
- }
- return false
-}
diff --git a/src/pkg/try/try_test.go b/src/pkg/try/try_test.go
deleted file mode 100644
index 617b2c7c3..000000000
--- a/src/pkg/try/try_test.go
+++ /dev/null
@@ -1,60 +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 try
-
-import (
- "bytes"
- "regexp" // Used as the package to try.
- "testing"
-)
-
-// The global functions in package regexp at time of writing.
-// Doesn't need to be updated unless the entries in this list become invalid.
-var functions = map[string]interface{}{
- "Compile": regexp.Compile,
- "Match": regexp.Match,
- "MatchString": regexp.MatchString,
- "MustCompile": regexp.MustCompile,
- "QuoteMeta": regexp.QuoteMeta,
-}
-
-// A wraps arguments to make the test cases nicer to read.
-func A(args ...interface{}) []interface{} {
- return args
-}
-
-type Test struct {
- firstArg string // only needed if there is exactly one argument
- result string // minus final newline; might be just the godoc string
- args []interface{}
-}
-
-var testRE = regexp.MustCompile("a(.)(.)d")
-
-var tests = []Test{
- // A simple expression. The final value is a slice in case the expression is multivalue.
- {"3+4", "3+4 = 7", A([]interface{}{7})},
- // A search for a function.
- {"", "regexp QuoteMeta", A("([])", `\(\[\]\)`)},
- // A search for a function with multiple return values.
- {"", "regexp MatchString", A("abc", "xabcd", true, nil)},
- // Searches for methods.
- {"", "regexp MatchString", A(testRE, "xabcde", true)},
- {"", "regexp NumSubexp", A(testRE, 2)},
-}
-
-func TestAll(t *testing.T) {
- re := regexp.MustCompile(".*// godoc ")
- for _, test := range tests {
- b := new(bytes.Buffer)
- output = b
- Main("regexp", test.firstArg, functions, test.args)
- expect := test.result + "\n"
- got := re.ReplaceAllString(b.String(), "")
- if got != expect {
- t.Errorf("expected %q; got %q", expect, got)
- }
- }
-}
diff --git a/src/pkg/unicode/Makefile b/src/pkg/unicode/Makefile
index 55ed5b2d9..33b06ca10 100644
--- a/src/pkg/unicode/Makefile
+++ b/src/pkg/unicode/Makefile
@@ -2,35 +2,15 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-
-TARG=unicode
-GOFILES=\
- casetables.go\
- digit.go\
- graphic.go\
- letter.go\
- tables.go\
-
-include ../../Make.pkg
-
-CLEANFILES+=maketables
-
maketables: maketables.go
- $(GC) maketables.go
- $(LD) -o maketables maketables.$O
+ go build maketables.go
tables: maketables
./maketables --tables=all > tables.go
gofmt -w tables.go
-# Build (but do not run) maketables during testing,
-# just to make sure it still compiles.
-test: maketables
-testshort: maketables
-
# Downloads from www.unicode.org, so not part
# of standard test scripts.
testtables: maketables
- @echo '***' Be sure to make tables and make install first
+ @echo '***' Be sure to make tables and go install first
./maketables -test
diff --git a/src/pkg/unicode/casetables.go b/src/pkg/unicode/casetables.go
index 86336b1b9..29bf167e5 100644
--- a/src/pkg/unicode/casetables.go
+++ b/src/pkg/unicode/casetables.go
@@ -9,7 +9,7 @@
package unicode
-var TurkishCase = _TurkishCase
+var TurkishCase SpecialCase = _TurkishCase
var _TurkishCase = SpecialCase{
CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
CaseRange{0x0069, 0x0069, d{0x130 - 0x69, 0, 0x130 - 0x69}},
@@ -17,4 +17,4 @@ var _TurkishCase = SpecialCase{
CaseRange{0x0131, 0x0131, d{0x49 - 0x131, 0, 0x49 - 0x131}},
}
-var AzeriCase = _TurkishCase
+var AzeriCase SpecialCase = _TurkishCase
diff --git a/src/pkg/unicode/digit.go b/src/pkg/unicode/digit.go
index 6793fd7e5..4800bd6ea 100644
--- a/src/pkg/unicode/digit.go
+++ b/src/pkg/unicode/digit.go
@@ -5,9 +5,9 @@
package unicode
// IsDigit reports whether the rune is a decimal digit.
-func IsDigit(rune int) bool {
- if rune <= MaxLatin1 {
- return '0' <= rune && rune <= '9'
+func IsDigit(r rune) bool {
+ if r <= MaxLatin1 {
+ return '0' <= r && r <= '9'
}
- return Is(Digit, rune)
+ return Is(Digit, r)
}
diff --git a/src/pkg/unicode/digit_test.go b/src/pkg/unicode/digit_test.go
index ae3c0ece9..551c42a24 100644
--- a/src/pkg/unicode/digit_test.go
+++ b/src/pkg/unicode/digit_test.go
@@ -9,7 +9,7 @@ import (
. "unicode"
)
-var testDigit = []int{
+var testDigit = []rune{
0x0030,
0x0039,
0x0661,
@@ -68,7 +68,7 @@ var testDigit = []int{
0x1D7CE,
}
-var testLetter = []int{
+var testLetter = []rune{
0x0041,
0x0061,
0x00AA,
@@ -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 <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
if Is(Digit, i) != IsDigit(i) {
t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
}
diff --git a/src/pkg/unicode/graphic.go b/src/pkg/unicode/graphic.go
index d482aace2..0de90ebd8 100644
--- a/src/pkg/unicode/graphic.go
+++ b/src/pkg/unicode/graphic.go
@@ -31,13 +31,13 @@ var PrintRanges = []*RangeTable{
// 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
+func IsGraphic(r rune) bool {
+ // We convert to uint32 to avoid the extra test for negative,
+ // and in the index we convert to uint8 to avoid the range check.
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pg != 0
}
- return IsOneOf(GraphicRanges, rune)
+ return IsOneOf(GraphicRanges, r)
}
// IsPrint reports whether the rune is defined as printable by Go. Such
@@ -45,18 +45,17 @@ func IsGraphic(rune int) bool {
// 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
+func IsPrint(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pp != 0
}
- return IsOneOf(PrintRanges, rune)
+ return IsOneOf(PrintRanges, r)
}
// 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 {
+func IsOneOf(set []*RangeTable, r rune) bool {
for _, inside := range set {
- if Is(inside, rune) {
+ if Is(inside, r) {
return true
}
}
@@ -65,44 +64,44 @@ func IsOneOf(set []*RangeTable, rune int) bool {
// 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
+// such as surrogates; use Is(C, r) to test for them.
+func IsControl(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&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
+func IsLetter(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&(pLu|pLl) != 0
}
- return Is(Letter, rune)
+ return Is(Letter, r)
}
// IsMark reports whether the rune is a mark character (category M).
-func IsMark(rune int) bool {
+func IsMark(r rune) bool {
// There are no mark characters in Latin-1.
- return Is(Mark, rune)
+ return Is(Mark, r)
}
// 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
+func IsNumber(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pN != 0
}
- return Is(Number, rune)
+ return Is(Number, r)
}
// 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
+func IsPunct(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pP != 0
}
- return Is(Punct, rune)
+ return Is(Punct, r)
}
// IsSpace reports whether the rune is a space character as defined
@@ -111,22 +110,22 @@ func IsPunct(rune int) bool {
// '\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 {
+func IsSpace(r rune) bool {
// This property isn't the same as Z; special-case it.
- if uint32(rune) <= MaxLatin1 {
- switch rune {
+ if uint32(r) <= MaxLatin1 {
+ switch r {
case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
return true
}
return false
}
- return Is(White_Space, rune)
+ return Is(White_Space, r)
}
// IsSymbol reports whether the rune is a symbolic character.
-func IsSymbol(rune int) bool {
- if uint32(rune) <= MaxLatin1 {
- return properties[uint8(rune)]&pS != 0
+func IsSymbol(r rune) bool {
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pS != 0
}
- return Is(Symbol, rune)
+ return Is(Symbol, r)
}
diff --git a/src/pkg/unicode/graphic_test.go b/src/pkg/unicode/graphic_test.go
index 77c679f7c..7b1f6209e 100644
--- a/src/pkg/unicode/graphic_test.go
+++ b/src/pkg/unicode/graphic_test.go
@@ -13,7 +13,7 @@ import (
// in the Latin-1 range through the property table.
func TestIsControlLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsControl(i)
want := false
switch {
@@ -29,7 +29,7 @@ func TestIsControlLatin1(t *testing.T) {
}
func TestIsLetterLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsLetter(i)
want := Is(Letter, i)
if got != want {
@@ -39,7 +39,7 @@ func TestIsLetterLatin1(t *testing.T) {
}
func TestIsUpperLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsUpper(i)
want := Is(Upper, i)
if got != want {
@@ -49,7 +49,7 @@ func TestIsUpperLatin1(t *testing.T) {
}
func TestIsLowerLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsLower(i)
want := Is(Lower, i)
if got != want {
@@ -59,7 +59,7 @@ func TestIsLowerLatin1(t *testing.T) {
}
func TestNumberLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsNumber(i)
want := Is(Number, i)
if got != want {
@@ -69,7 +69,7 @@ func TestNumberLatin1(t *testing.T) {
}
func TestIsPrintLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsPrint(i)
want := IsOneOf(PrintRanges, i)
if i == ' ' {
@@ -82,7 +82,7 @@ func TestIsPrintLatin1(t *testing.T) {
}
func TestIsGraphicLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsGraphic(i)
want := IsOneOf(GraphicRanges, i)
if got != want {
@@ -92,7 +92,7 @@ func TestIsGraphicLatin1(t *testing.T) {
}
func TestIsPunctLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsPunct(i)
want := Is(Punct, i)
if got != want {
@@ -102,7 +102,7 @@ func TestIsPunctLatin1(t *testing.T) {
}
func TestIsSpaceLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsSpace(i)
want := Is(White_Space, i)
if got != want {
@@ -112,7 +112,7 @@ func TestIsSpaceLatin1(t *testing.T) {
}
func TestIsSymbolLatin1(t *testing.T) {
- for i := 0; i <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
got := IsSymbol(i)
want := Is(Symbol, i)
if got != want {
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index 38a11c42b..be484553d 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -7,10 +7,10 @@
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.
+ MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+ ReplacementChar = '\uFFFD' // Represents invalid code points.
+ MaxASCII = '\u007F' // maximum ASCII value.
+ MaxLatin1 = '\u00FF' // maximum Latin-1 value.
)
// RangeTable defines a set of Unicode code points by listing the ranges of
@@ -60,8 +60,8 @@ type CaseRange struct {
// Methods of SpecialCase customize (by overriding) the standard mappings.
type SpecialCase []CaseRange
-//BUG(r): Provide a mechanism for full case folding (those that involve
-// multiple runes in the input or output).
+// BUG(r): There is no mechanism for full case folding, that is, for
+// characters that involve multiple runes in the input or output.
// Indices into the Delta arrays inside CaseRanges for case mapping.
const (
@@ -71,7 +71,7 @@ const (
MaxCase
)
-type d [MaxCase]int32 // to make the CaseRanges text shorter
+type d [MaxCase]rune // to make the CaseRanges text shorter
// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
// this CaseRange represents a sequence of the form (say)
@@ -81,17 +81,17 @@ const (
)
// is16 uses binary search to test whether rune is in the specified slice of 16-bit ranges.
-func is16(ranges []Range16, rune uint16) bool {
+func is16(ranges []Range16, r 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
+ range_ := ranges[m]
+ if range_.Lo <= r && r <= range_.Hi {
+ return (r-range_.Lo)%range_.Stride == 0
}
- if rune < r.Lo {
+ if r < range_.Lo {
hi = m
} else {
lo = m + 1
@@ -101,17 +101,17 @@ func is16(ranges []Range16, rune uint16) bool {
}
// is32 uses binary search to test whether rune is in the specified slice of 32-bit ranges.
-func is32(ranges []Range32, rune uint32) bool {
+func is32(ranges []Range32, r uint32) 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
+ range_ := ranges[m]
+ if range_.Lo <= r && r <= range_.Hi {
+ return (r-range_.Lo)%range_.Stride == 0
}
- if rune < r.Lo {
+ if r < range_.Lo {
hi = m
} else {
lo = m + 1
@@ -121,11 +121,11 @@ func is32(ranges []Range32, rune uint32) bool {
}
// Is tests whether rune is in the specified table of ranges.
-func Is(rangeTab *RangeTable, rune int) bool {
+func Is(rangeTab *RangeTable, r rune) bool {
// common case: rune is ASCII or Latin-1.
- if uint32(rune) <= MaxLatin1 {
+ if uint32(r) <= MaxLatin1 {
// Only need to check R16, since R32 is always >= 1<<16.
- r16 := uint16(rune)
+ r16 := uint16(r)
for _, r := range rangeTab.R16 {
if r16 > r.Hi {
continue
@@ -138,44 +138,44 @@ func Is(rangeTab *RangeTable, rune int) bool {
return false
}
r16 := rangeTab.R16
- if len(r16) > 0 && rune <= int(r16[len(r16)-1].Hi) {
- return is16(r16, uint16(rune))
+ if len(r16) > 0 && r <= rune(r16[len(r16)-1].Hi) {
+ return is16(r16, uint16(r))
}
r32 := rangeTab.R32
- if len(r32) > 0 && rune >= int(r32[0].Lo) {
- return is32(r32, uint32(rune))
+ if len(r32) > 0 && r >= rune(r32[0].Lo) {
+ return is32(r32, uint32(r))
}
return false
}
// IsUpper reports whether the rune is an upper case letter.
-func IsUpper(rune int) bool {
+func IsUpper(r rune) bool {
// See comment in IsGraphic.
- if uint32(rune) <= MaxLatin1 {
- return properties[uint8(rune)]&pLu != 0
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pLu != 0
}
- return Is(Upper, rune)
+ return Is(Upper, r)
}
// IsLower reports whether the rune is a lower case letter.
-func IsLower(rune int) bool {
+func IsLower(r rune) bool {
// See comment in IsGraphic.
- if uint32(rune) <= MaxLatin1 {
- return properties[uint8(rune)]&pLl != 0
+ if uint32(r) <= MaxLatin1 {
+ return properties[uint8(r)]&pLl != 0
}
- return Is(Lower, rune)
+ return Is(Lower, r)
}
// IsTitle reports whether the rune is a title case letter.
-func IsTitle(rune int) bool {
- if rune <= MaxLatin1 {
+func IsTitle(r rune) bool {
+ if r <= MaxLatin1 {
return false
}
- return Is(Title, rune)
+ return Is(Title, r)
}
// to maps the rune using the specified case mapping.
-func to(_case int, rune int, caseRange []CaseRange) int {
+func to(_case int, r rune, caseRange []CaseRange) rune {
if _case < 0 || MaxCase <= _case {
return ReplacementChar // as reasonable an error as any
}
@@ -184,9 +184,9 @@ func to(_case int, rune int, caseRange []CaseRange) int {
hi := len(caseRange)
for lo < hi {
m := lo + (hi-lo)/2
- r := caseRange[m]
- if int(r.Lo) <= rune && rune <= int(r.Hi) {
- delta := int(r.Delta[_case])
+ cr := caseRange[m]
+ if rune(cr.Lo) <= r && r <= rune(cr.Hi) {
+ delta := rune(cr.Delta[_case])
if delta > MaxRune {
// In an Upper-Lower sequence, which always starts with
// an UpperCase letter, the real deltas always look like:
@@ -198,82 +198,82 @@ 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 int(r.Lo) + ((rune-int(r.Lo))&^1 | _case&1)
+ return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1))
}
- return rune + delta
+ return r + delta
}
- if rune < int(r.Lo) {
+ if r < rune(cr.Lo) {
hi = m
} else {
lo = m + 1
}
}
- return rune
+ return r
}
// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
-func To(_case int, rune int) int {
- return to(_case, rune, CaseRanges)
+func To(_case int, r rune) rune {
+ return to(_case, r, CaseRanges)
}
// ToUpper maps the rune to upper case.
-func ToUpper(rune int) int {
- if rune <= MaxASCII {
- if 'a' <= rune && rune <= 'z' {
- rune -= 'a' - 'A'
+func ToUpper(r rune) rune {
+ if r <= MaxASCII {
+ if 'a' <= r && r <= 'z' {
+ r -= 'a' - 'A'
}
- return rune
+ return r
}
- return To(UpperCase, rune)
+ return To(UpperCase, r)
}
// ToLower maps the rune to lower case.
-func ToLower(rune int) int {
- if rune <= MaxASCII {
- if 'A' <= rune && rune <= 'Z' {
- rune += 'a' - 'A'
+func ToLower(r rune) rune {
+ if r <= MaxASCII {
+ if 'A' <= r && r <= 'Z' {
+ r += 'a' - 'A'
}
- return rune
+ return r
}
- return To(LowerCase, rune)
+ return To(LowerCase, r)
}
// ToTitle maps the rune to title case.
-func ToTitle(rune int) int {
- if rune <= MaxASCII {
- if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
- rune -= 'a' - 'A'
+func ToTitle(r rune) rune {
+ if r <= MaxASCII {
+ if 'a' <= r && r <= 'z' { // title case is upper case for ASCII
+ r -= 'a' - 'A'
}
- return rune
+ return r
}
- return To(TitleCase, rune)
+ return To(TitleCase, r)
}
// ToUpper maps the rune to upper case giving priority to the special mapping.
-func (special SpecialCase) ToUpper(rune int) int {
- r := to(UpperCase, rune, []CaseRange(special))
- if r == rune {
- r = ToUpper(rune)
+func (special SpecialCase) ToUpper(r rune) rune {
+ r1 := to(UpperCase, r, []CaseRange(special))
+ if r1 == r {
+ r1 = ToUpper(r)
}
- return r
+ return r1
}
// ToTitle maps the rune to title case giving priority to the special mapping.
-func (special SpecialCase) ToTitle(rune int) int {
- r := to(TitleCase, rune, []CaseRange(special))
- if r == rune {
- r = ToTitle(rune)
+func (special SpecialCase) ToTitle(r rune) rune {
+ r1 := to(TitleCase, r, []CaseRange(special))
+ if r1 == r {
+ r1 = ToTitle(r)
}
- return r
+ return r1
}
// ToLower maps the rune to lower case giving priority to the special mapping.
-func (special SpecialCase) ToLower(rune int) int {
- r := to(LowerCase, rune, []CaseRange(special))
- if r == rune {
- r = ToLower(rune)
+func (special SpecialCase) ToLower(r rune) rune {
+ r1 := to(LowerCase, r, []CaseRange(special))
+ if r1 == r {
+ r1 = ToLower(r)
}
- return r
+ return r1
}
// caseOrbit is defined in tables.go as []foldPair. Right now all the
@@ -288,7 +288,7 @@ type foldPair struct {
// 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.
+// smallest rune >= r if one exists, or else the smallest rune >= 0.
//
// For example:
// SimpleFold('A') = 'a'
@@ -300,27 +300,27 @@ type foldPair struct {
//
// SimpleFold('1') = '1'
//
-func SimpleFold(rune int) int {
+func SimpleFold(r rune) rune {
// 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 {
+ if rune(caseOrbit[m].From) < r {
lo = m + 1
} else {
hi = m
}
}
- if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
- return int(caseOrbit[lo].To)
+ if lo < len(caseOrbit) && rune(caseOrbit[lo].From) == r {
+ return rune(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 {
+ if l := ToLower(r); l != r {
return l
}
- return ToUpper(rune)
+ return ToUpper(r)
}
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index 8d2665a44..2d8056218 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -9,7 +9,7 @@ import (
. "unicode"
)
-var upperTest = []int{
+var upperTest = []rune{
0x41,
0xc0,
0xd8,
@@ -33,7 +33,7 @@ var upperTest = []int{
0x1d7ca,
}
-var notupperTest = []int{
+var notupperTest = []rune{
0x40,
0x5b,
0x61,
@@ -46,7 +46,7 @@ var notupperTest = []int{
0x10000,
}
-var letterTest = []int{
+var letterTest = []rune{
0x41,
0x61,
0xaa,
@@ -82,7 +82,7 @@ var letterTest = []int{
0x2fa1d,
}
-var notletterTest = []int{
+var notletterTest = []rune{
0x20,
0x35,
0x375,
@@ -94,7 +94,7 @@ var notletterTest = []int{
}
// Contains all the special cased Latin-1 chars.
-var spaceTest = []int{
+var spaceTest = []rune{
0x09,
0x0a,
0x0b,
@@ -108,7 +108,8 @@ var spaceTest = []int{
}
type caseT struct {
- cas, in, out int
+ cas int
+ in, out rune
}
var caseTest = []caseT{
@@ -327,7 +328,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 <= MaxLatin1; i++ {
+ for i := rune(0); i <= MaxLatin1; i++ {
if Is(Letter, i) != IsLetter(i) {
t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
}
@@ -356,8 +357,8 @@ func TestLetterOptimizations(t *testing.T) {
}
func TestTurkishCase(t *testing.T) {
- lower := []int("abcçdefgğhıijklmnoöprsştuüvyz")
- upper := []int("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
+ lower := []rune("abcçdefgğhıijklmnoöprsştuüvyz")
+ upper := []rune("ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
for i, l := range lower {
u := upper[i]
if TurkishCase.ToLower(l) != l {
@@ -416,13 +417,13 @@ var simpleFoldTests = []string{
func TestSimpleFold(t *testing.T) {
for _, tt := range simpleFoldTests {
- cycle := []int(tt)
- rune := cycle[len(cycle)-1]
+ cycle := []rune(tt)
+ r := cycle[len(cycle)-1]
for _, out := range cycle {
- if r := SimpleFold(rune); r != out {
- t.Errorf("SimpleFold(%#U) = %#U, want %#U", rune, r, out)
+ if r := SimpleFold(r); r != out {
+ t.Errorf("SimpleFold(%#U) = %#U, want %#U", r, r, out)
}
- rune = out
+ r = out
}
}
}
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index b586bc655..16bc83cea 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.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.
+// +build ignore
+
// Unicode table generator.
// Data read from the web.
@@ -11,14 +13,15 @@ import (
"bufio"
"flag"
"fmt"
- "http"
+ "io"
"log"
+ "net/http"
"os"
"path/filepath"
+ "regexp"
"sort"
"strconv"
"strings"
- "regexp"
"unicode"
)
@@ -77,7 +80,7 @@ func open(url string) *reader {
}
return &reader{bufio.NewReader(fd), fd, nil}
}
- resp, err := http.Get(*dataURL)
+ resp, err := http.Get(url)
if err != nil {
logger.Fatal(err)
}
@@ -155,13 +158,13 @@ var fieldName = []string{
// This contains only the properties we're interested in.
type Char struct {
field []string // debugging only; could be deleted if we take out char.dump()
- codePoint uint32 // if zero, this index is not a valid code point.
+ codePoint rune // if zero, this index is not a valid code point.
category string
- upperCase int
- lowerCase int
- titleCase int
- foldCase int // simple case folding
- caseOrbit int // next in simple case folding orbit
+ upperCase rune
+ lowerCase rune
+ titleCase rune
+ foldCase rune // simple case folding
+ caseOrbit rune // next in simple case folding orbit
}
// Scripts.txt has form:
@@ -178,7 +181,7 @@ var chars = make([]Char, MaxChar+1)
var scripts = make(map[string][]Script)
var props = make(map[string][]Script) // a property looks like a script; can share the format
-var lastChar uint32 = 0
+var lastChar rune = 0
// In UnicodeData.txt, some ranges are marked like this:
// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
@@ -198,11 +201,11 @@ func parseCategory(line string) (state State) {
if len(field) != NumField {
logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
}
- point, err := strconv.Btoui64(field[FCodePoint], 16)
+ point, err := strconv.ParseUint(field[FCodePoint], 16, 64)
if err != nil {
logger.Fatalf("%.5s...: %s", line, err)
}
- lastChar = uint32(point)
+ lastChar = rune(point)
if point == 0 {
return // not interesting and we use 0 as unset
}
@@ -256,35 +259,42 @@ func (char *Char) letter(u, l, t string) {
char.titleCase = char.letterValue(t, "T")
}
-func (char *Char) letterValue(s string, cas string) int {
+func (char *Char) letterValue(s string, cas string) rune {
if s == "" {
return 0
}
- v, err := strconv.Btoui64(s, 16)
+ v, err := strconv.ParseUint(s, 16, 64)
if err != nil {
char.dump(cas)
logger.Fatalf("%U: bad letter(%s): %s", char.codePoint, s, err)
}
- return int(v)
+ return rune(v)
}
func allCategories() []string {
- a := make([]string, len(category))
- i := 0
+ a := make([]string, 0, len(category))
for k := range category {
- a[i] = k
- i++
+ a = append(a, k)
}
+ sort.Strings(a)
return a
}
func all(scripts map[string][]Script) []string {
- a := make([]string, len(scripts))
- i := 0
+ a := make([]string, 0, len(scripts))
for k := range scripts {
- a[i] = k
- i++
+ a = append(a, k)
+ }
+ sort.Strings(a)
+ return a
+}
+
+func allCatFold(m map[string]map[rune]bool) []string {
+ a := make([]string, 0, len(m))
+ for k := range m {
+ a = append(a, k)
}
+ sort.Strings(a)
return a
}
@@ -301,7 +311,7 @@ func version() string {
return "Unknown"
}
-func categoryOp(code int, class uint8) bool {
+func categoryOp(code rune, class uint8) bool {
category := chars[code].category
return len(category) > 0 && category[0] == class
}
@@ -311,11 +321,11 @@ func loadChars() {
flag.Set("data", *url+"UnicodeData.txt")
}
input := open(*dataURL)
- var first uint32 = 0
+ var first rune = 0
for {
line, err := input.ReadString('\n')
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
break
}
logger.Fatal(err)
@@ -352,7 +362,7 @@ func loadCasefold() {
for {
line, err := input.ReadString('\n')
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
break
}
logger.Fatal(err)
@@ -369,15 +379,15 @@ func loadCasefold() {
// Only care about 'common' and 'simple' foldings.
continue
}
- p1, err := strconv.Btoui64(field[0], 16)
+ p1, err := strconv.ParseUint(field[0], 16, 64)
if err != nil {
logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
}
- p2, err := strconv.Btoui64(field[2], 16)
+ p2, err := strconv.ParseUint(field[2], 16, 64)
if err != nil {
logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
}
- chars[p1].foldCase = int(p2)
+ chars[p1].foldCase = rune(p2)
}
input.close()
}
@@ -409,9 +419,9 @@ func printCategories() {
fmt.Printf("const Version = %q\n\n", version())
if *tablelist == "all" {
- fmt.Println("// Categories is the set of Unicode data tables.")
+ fmt.Println("// Categories is the set of Unicode category tables.")
fmt.Println("var Categories = map[string] *RangeTable {")
- for k := range category {
+ for _, k := range allCategories() {
fmt.Printf("\t%q: %s,\n", k, k)
}
fmt.Print("}\n\n")
@@ -470,14 +480,15 @@ func printCategories() {
decl := fmt.Sprintf("var _%s = &RangeTable{\n", name)
dumpRange(
decl,
- func(code int) bool { return categoryOp(code, name[0]) })
+ func(code rune) bool { return categoryOp(code, name[0]) })
continue
}
dumpRange(
fmt.Sprintf("var _%s = &RangeTable{\n", name),
- func(code int) bool { return chars[code].category == name })
+ func(code rune) bool { return chars[code].category == name })
}
decl.Sort()
+ fmt.Println("// The following variables are of type *RangeTable:")
fmt.Println("var (")
for _, d := range decl {
fmt.Print(d)
@@ -485,23 +496,23 @@ func printCategories() {
fmt.Print(")\n\n")
}
-type Op func(code int) bool
+type Op func(code rune) bool
const format = "\t\t{0x%04x, 0x%04x, %d},\n"
func dumpRange(header string, inCategory Op) {
fmt.Print(header)
- next := 0
+ next := rune(0)
fmt.Print("\tR16: []Range16{\n")
// one Range for each iteration
count := &range16Count
size := 16
for {
// look for start of range
- for next < len(chars) && !inCategory(next) {
+ for next < rune(len(chars)) && !inCategory(next) {
next++
}
- if next >= len(chars) {
+ if next >= rune(len(chars)) {
// no characters remain
break
}
@@ -509,14 +520,14 @@ func dumpRange(header string, inCategory Op) {
// start of range
lo := next
hi := next
- stride := 1
+ stride := rune(1)
// accept lo
next++
// look for another character to set the stride
- for next < len(chars) && !inCategory(next) {
+ for next < rune(len(chars)) && !inCategory(next) {
next++
}
- if next >= len(chars) {
+ if next >= rune(len(chars)) {
// no more characters
fmt.Printf(format, lo, hi, stride)
break
@@ -524,7 +535,7 @@ func dumpRange(header string, inCategory Op) {
// set stride
stride = next - lo
// check for length of run. next points to first jump in stride
- for i := next; i < len(chars); i++ {
+ for i := next; i < rune(len(chars)); i++ {
if inCategory(i) == (((i - lo) % stride) == 0) {
// accept
if inCategory(i) {
@@ -577,11 +588,11 @@ func fullCategoryTest(list []string) {
logger.Fatalf("unknown table %q", name)
}
if len(name) == 1 {
- verifyRange(name, func(code int) bool { return categoryOp(code, name[0]) }, r)
+ verifyRange(name, func(code rune) bool { return categoryOp(code, name[0]) }, r)
} else {
verifyRange(
name,
- func(code int) bool { return chars[code].category == name },
+ func(code rune) bool { return chars[code].category == name },
r)
}
}
@@ -589,7 +600,8 @@ func fullCategoryTest(list []string) {
func verifyRange(name string, inCategory Op, table *unicode.RangeTable) {
count := 0
- for i := range chars {
+ for j := range chars {
+ i := rune(j)
web := inCategory(i)
pkg := unicode.Is(table, i)
if web != pkg {
@@ -619,13 +631,13 @@ func parseScript(line string, scripts map[string][]Script) {
if len(matches) != 4 {
logger.Fatalf("%s: %d matches (expected 3)\n", line, len(matches))
}
- lo, err := strconv.Btoui64(matches[1], 16)
+ lo, err := strconv.ParseUint(matches[1], 16, 64)
if err != nil {
logger.Fatalf("%.5s...: %s", line, err)
}
hi := lo
if len(matches[2]) > 2 { // ignore leading ..
- hi, err = strconv.Btoui64(matches[2][2:], 16)
+ hi, err = strconv.ParseUint(matches[2][2:], 16, 64)
if err != nil {
logger.Fatalf("%.5s...: %s", line, err)
}
@@ -643,7 +655,11 @@ func foldAdjacent(r []Script) []unicode.Range32 {
s[j-1].Hi = r[i].hi
} else {
s = s[0 : j+1]
- s[j] = unicode.Range32{uint32(r[i].lo), uint32(r[i].hi), 1}
+ s[j] = unicode.Range32{
+ Lo: uint32(r[i].lo),
+ Hi: uint32(r[i].hi),
+ Stride: 1,
+ }
j++
}
}
@@ -661,7 +677,7 @@ func fullScriptTest(list []string, installed map[string]*unicode.RangeTable, scr
}
for _, script := range scripts[name] {
for r := script.lo; r <= script.hi; r++ {
- if !unicode.Is(installed[name], int(r)) {
+ if !unicode.Is(installed[name], rune(r)) {
fmt.Fprintf(os.Stderr, "%U: not in script %s\n", r, name)
}
}
@@ -690,7 +706,7 @@ func printScriptOrProperty(doProps bool) {
for {
line, err := input.ReadString('\n')
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
break
}
logger.Fatal(err)
@@ -724,7 +740,7 @@ func printScriptOrProperty(doProps bool) {
fmt.Println("// Scripts is the set of Unicode script tables.")
fmt.Println("var Scripts = map[string] *RangeTable{")
}
- for k := range table {
+ for _, k := range all(table) {
fmt.Printf("\t%q: %s,\n", k, k)
}
fmt.Print("}\n\n")
@@ -755,6 +771,7 @@ func printScriptOrProperty(doProps bool) {
fmt.Print("}\n\n")
}
decl.Sort()
+ fmt.Println("// The following variables are of type *RangeTable:")
fmt.Println("var (")
for _, d := range decl {
fmt.Print(d)
@@ -771,11 +788,11 @@ const (
)
type caseState struct {
- point int
+ point rune
_case int
- deltaToUpper int
- deltaToLower int
- deltaToTitle int
+ deltaToUpper rune
+ deltaToLower rune
+ deltaToTitle rune
}
// Is d a continuation of the state of c?
@@ -866,10 +883,10 @@ func (c *caseState) isLowerUpper() bool {
return true
}
-func getCaseState(i int) (c *caseState) {
+func getCaseState(i rune) (c *caseState) {
c = &caseState{point: i, _case: CaseNone}
ch := &chars[i]
- switch int(ch.codePoint) {
+ switch ch.codePoint {
case 0:
c._case = CaseMissing // Will get NUL wrong but that doesn't matter
return
@@ -923,7 +940,7 @@ func printCases() {
var startState *caseState // the start of a run; nil for not active
var prevState = &caseState{} // the state of the previous character
for i := range chars {
- state := getCaseState(i)
+ state := getCaseState(rune(i))
if state.adjacent(prevState) {
prevState = state
continue
@@ -963,15 +980,16 @@ func printCaseRange(lo, hi *caseState) {
}
// If the cased value in the Char is 0, it means use the rune itself.
-func caseIt(rune, cased int) int {
+func caseIt(r, cased rune) rune {
if cased == 0 {
- return rune
+ return r
}
return cased
}
func fullCaseTest() {
- for i, c := range chars {
+ for j, c := range chars {
+ i := rune(j)
lower := unicode.ToLower(i)
want := caseIt(i, c.lowerCase)
if lower != want {
@@ -1026,10 +1044,17 @@ func printLatinProperties() {
fmt.Printf("}\n\n")
}
+type runeSlice []rune
+
+func (p runeSlice) Len() int { return len(p) }
+func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+
func printCasefold() {
// Build list of case-folding groups attached to each canonical folded char (typically lower case).
- var caseOrbit = make([][]int, MaxChar+1)
- for i := range chars {
+ var caseOrbit = make([][]rune, MaxChar+1)
+ for j := range chars {
+ i := rune(j)
c := &chars[i]
if c.foldCase == 0 {
continue
@@ -1042,7 +1067,8 @@ func printCasefold() {
}
// Insert explicit 1-element groups when assuming [lower, upper] would be wrong.
- for i := range chars {
+ for j := range chars {
+ i := rune(j)
c := &chars[i]
f := c.foldCase
if f == 0 {
@@ -1051,7 +1077,7 @@ func printCasefold() {
orb := caseOrbit[f]
if orb == nil && (c.upperCase != 0 && c.upperCase != i || c.lowerCase != 0 && c.lowerCase != i) {
// Default assumption of [upper, lower] is wrong.
- caseOrbit[i] = []int{i}
+ caseOrbit[i] = []rune{i}
}
}
@@ -1067,7 +1093,7 @@ func printCasefold() {
if orb == nil {
continue
}
- sort.Ints(orb)
+ sort.Sort(runeSlice(orb))
c := orb[len(orb)-1]
for _, d := range orb {
chars[c].caseOrbit = d
@@ -1080,14 +1106,14 @@ func printCasefold() {
// Tables of category and script folding exceptions: code points
// that must be added when interpreting a particular category/script
// in a case-folding context.
- cat := make(map[string]map[int]bool)
+ cat := make(map[string]map[rune]bool)
for name := range category {
if x := foldExceptions(inCategory(name)); len(x) > 0 {
cat[name] = x
}
}
- scr := make(map[string]map[int]bool)
+ scr := make(map[string]map[rune]bool)
for name := range scripts {
if x := foldExceptions(inScript(name)); len(x) > 0 {
cat[name] = x
@@ -1099,9 +1125,10 @@ func printCasefold() {
}
// inCategory returns a list of all the runes in the category.
-func inCategory(name string) []int {
- var x []int
- for i := range chars {
+func inCategory(name string) []rune {
+ var x []rune
+ for j := range chars {
+ i := rune(j)
c := &chars[i]
if c.category == name || len(name) == 1 && len(c.category) > 1 && c.category[0] == name[0] {
x = append(x, i)
@@ -1111,11 +1138,11 @@ func inCategory(name string) []int {
}
// inScript returns a list of all the runes in the script.
-func inScript(name string) []int {
- var x []int
+func inScript(name string) []rune {
+ var x []rune
for _, s := range scripts[name] {
for c := s.lo; c <= s.hi; c++ {
- x = append(x, int(c))
+ x = append(x, rune(c))
}
}
return x
@@ -1123,9 +1150,9 @@ func inScript(name string) []int {
// foldExceptions returns a list of all the runes fold-equivalent
// to runes in class but not in class themselves.
-func foldExceptions(class []int) map[int]bool {
+func foldExceptions(class []rune) map[rune]bool {
// Create map containing class and all fold-equivalent chars.
- m := make(map[int]bool)
+ m := make(map[rune]bool)
for _, r := range class {
c := &chars[r]
if c.caseOrbit == 0 {
@@ -1152,7 +1179,7 @@ func foldExceptions(class []int) map[int]bool {
// Remove class itself.
for _, r := range class {
- m[r] = false, false
+ delete(m, r)
}
// What's left is the exceptions.
@@ -1173,7 +1200,8 @@ var comment = map[string]string{
func printCaseOrbit() {
if *test {
- for i := range chars {
+ for j := range chars {
+ i := rune(j)
c := &chars[i]
f := c.caseOrbit
if f == 0 {
@@ -1203,7 +1231,7 @@ func printCaseOrbit() {
fmt.Printf("}\n\n")
}
-func printCatFold(name string, m map[string]map[int]bool) {
+func printCatFold(name string, m map[string]map[rune]bool) {
if *test {
var pkgMap map[string]*unicode.RangeTable
if name == "FoldCategory" {
@@ -1223,7 +1251,7 @@ func printCatFold(name string, m map[string]map[int]bool) {
}
n := 0
for _, r := range t.R16 {
- for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ for c := rune(r.Lo); c <= rune(r.Hi); c += rune(r.Stride) {
if !v[c] {
fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
}
@@ -1231,7 +1259,7 @@ func printCatFold(name string, m map[string]map[int]bool) {
}
}
for _, r := range t.R32 {
- for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ for c := rune(r.Lo); c <= rune(r.Hi); c += rune(r.Stride) {
if !v[c] {
fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
}
@@ -1247,14 +1275,15 @@ func printCatFold(name string, m map[string]map[int]bool) {
fmt.Print(comment[name])
fmt.Printf("var %s = map[string]*RangeTable{\n", name)
- for name := range m {
+ for _, name := range allCatFold(m) {
fmt.Printf("\t%q: fold%s,\n", name, name)
}
fmt.Printf("}\n\n")
- for name, class := range m {
+ for _, name := range allCatFold(m) {
+ class := m[name]
dumpRange(
fmt.Sprintf("var fold%s = &RangeTable{\n", name),
- func(code int) bool { return class[code] })
+ func(code rune) bool { return class[code] })
}
}
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index b37ad1836..1c5b80142 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -10,7 +10,7 @@ import (
)
type T struct {
- rune int
+ rune rune
script string
}
@@ -206,7 +206,7 @@ func TestScripts(t *testing.T) {
if !Is(Scripts[test.script], test.rune) {
t.Errorf("IsScript(%U, %s) = false, want true", test.rune, test.script)
}
- notTested[test.script] = false, false
+ delete(notTested, test.script)
}
for _, test := range outTest {
if Is(Scripts[test.script], test.rune) {
@@ -230,7 +230,7 @@ func TestCategories(t *testing.T) {
if !Is(Categories[test.script], test.rune) {
t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
- notTested[test.script] = false, false
+ delete(notTested, test.script)
}
for k := range notTested {
t.Error("category not tested:", k)
@@ -249,7 +249,7 @@ func TestProperties(t *testing.T) {
if !Is(Properties[test.script], test.rune) {
t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
- notTested[test.script] = false, false
+ delete(notTested, test.script)
}
for k := range notTested {
t.Error("property not tested:", k)
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 88b5c0fba..5009e6b98 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -7,235 +7,81 @@ package unicode
// Version is the Unicode edition from which the tables are derived.
const Version = "6.0.0"
-// Categories is the set of Unicode data tables.
+// Categories is the set of Unicode category tables.
var Categories = map[string]*RangeTable{
- "Lm": Lm,
- "Ll": Ll,
"C": C,
- "M": M,
+ "Cc": Cc,
+ "Cf": Cf,
+ "Co": Co,
+ "Cs": Cs,
"L": L,
+ "Ll": Ll,
+ "Lm": Lm,
+ "Lo": Lo,
+ "Lt": Lt,
+ "Lu": Lu,
+ "M": M,
+ "Mc": Mc,
+ "Me": Me,
+ "Mn": Mn,
"N": N,
+ "Nd": Nd,
+ "Nl": Nl,
+ "No": No,
"P": P,
+ "Pc": Pc,
+ "Pd": Pd,
+ "Pe": Pe,
+ "Pf": Pf,
+ "Pi": Pi,
+ "Po": Po,
+ "Ps": Ps,
"S": S,
+ "Sc": Sc,
+ "Sk": Sk,
+ "Sm": Sm,
+ "So": So,
"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{
+var _C = &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},
+ {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{
- {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},
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
},
}
-var _C = &RangeTable{
+var _Cc = &RangeTable{
R16: []Range16{
{0x0001, 0x001f, 1},
{0x007f, 0x009f, 1},
+ },
+}
+
+var _Cf = &RangeTable{
+ R16: []Range16{
{0x00ad, 0x0600, 1363},
{0x0601, 0x0603, 1},
{0x06dd, 0x070f, 50},
@@ -244,7 +90,6 @@ var _C = &RangeTable{
{0x202a, 0x202e, 1},
{0x2060, 0x2064, 1},
{0x206a, 0x206f, 1},
- {0xd800, 0xf8ff, 1},
{0xfeff, 0xfff9, 250},
{0xfffa, 0xfffb, 1},
},
@@ -253,200 +98,22 @@ var _C = &RangeTable{
{0x1d174, 0x1d17a, 1},
{0xe0001, 0xe0020, 31},
{0xe0021, 0xe007f, 1},
- {0xf0000, 0xffffd, 1},
- {0x100000, 0x10fffd, 1},
},
}
-var _M = &RangeTable{
+var _Co = &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},
+ {0xe000, 0xf8ff, 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},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+ },
+}
+
+var _Cs = &RangeTable{
+ R16: []Range16{
+ {0xd800, 0xdfff, 1},
},
}
@@ -871,422 +538,845 @@ var _L = &RangeTable{
},
}
-var _N = &RangeTable{
+var _Ll = &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},
+ {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{
- {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},
+ {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 _P = &RangeTable{
+var _Lm = &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},
+ {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 _S = &RangeTable{
+var _Lo = &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},
+ {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{
- {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},
+ {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 _Z = &RangeTable{
+var _Lt = &RangeTable{
R16: []Range16{
- {0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
- {0x2028, 0x2029, 1},
- {0x202f, 0x205f, 48},
- {0x3000, 0x3000, 1},
+ {0x01c5, 0x01cb, 3},
+ {0x01f2, 0x1f88, 7574},
+ {0x1f89, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fbc, 0x1fcc, 16},
+ {0x1ffc, 0x1ffc, 1},
},
}
-var _Me = &RangeTable{
+var _Lu = &RangeTable{
R16: []Range16{
- {0x0488, 0x0489, 1},
- {0x20dd, 0x20e0, 1},
- {0x20e2, 0x20e4, 1},
- {0xa670, 0xa672, 1},
+ {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 _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},
},
}
@@ -1398,6 +1488,15 @@ var _Mc = &RangeTable{
},
}
+var _Me = &RangeTable{
+ R16: []Range16{
+ {0x0488, 0x0489, 1},
+ {0x20dd, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
+ },
+}
+
var _Mn = &RangeTable{
R16: []Range16{
{0x0300, 0x036f, 1},
@@ -1584,69 +1683,396 @@ var _Mn = &RangeTable{
},
}
-var _Zl = &RangeTable{
+var _N = &RangeTable{
R16: []Range16{
- {0x2028, 0x2028, 1},
+ {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 _Zp = &RangeTable{
+var _Nd = &RangeTable{
R16: []Range16{
- {0x2029, 0x2029, 1},
+ {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 _Zs = &RangeTable{
+var _Nl = &RangeTable{
R16: []Range16{
- {0x0020, 0x00a0, 128},
- {0x1680, 0x180e, 398},
- {0x2000, 0x200a, 1},
- {0x202f, 0x205f, 48},
- {0x3000, 0x3000, 1},
+ {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 _Cs = &RangeTable{
+var _No = &RangeTable{
R16: []Range16{
- {0xd800, 0xdfff, 1},
+ {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 _Co = &RangeTable{
+var _P = &RangeTable{
R16: []Range16{
- {0xe000, 0xf8ff, 1},
+ {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{
- {0xf0000, 0xffffd, 1},
- {0x100000, 0x10fffd, 1},
+ {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 _Cf = &RangeTable{
+var _Pc = &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},
+ {0x005f, 0x203f, 8160},
+ {0x2040, 0x2054, 20},
+ {0xfe33, 0xfe34, 1},
+ {0xfe4d, 0xfe4f, 1},
+ {0xff3f, 0xff3f, 1},
},
- R32: []Range32{
- {0x110bd, 0x1d173, 49334},
- {0x1d174, 0x1d17a, 1},
- {0xe0001, 0xe0020, 31},
- {0xe0021, 0xe007f, 1},
+}
+
+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 _Cc = &RangeTable{
+var _Pe = &RangeTable{
R16: []Range16{
- {0x0001, 0x001f, 1},
- {0x007f, 0x009f, 1},
+ {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 _Pf = &RangeTable{
+ R16: []Range16{
+ {0x00bb, 0x2019, 8030},
+ {0x201d, 0x203a, 29},
+ {0x2e03, 0x2e05, 2},
+ {0x2e0a, 0x2e0d, 3},
+ {0x2e1d, 0x2e21, 4},
+ },
+}
+
+var _Pi = &RangeTable{
+ R16: []Range16{
+ {0x00ab, 0x2018, 8045},
+ {0x201b, 0x201c, 1},
+ {0x201f, 0x2039, 26},
+ {0x2e02, 0x2e04, 2},
+ {0x2e09, 0x2e0c, 3},
+ {0x2e1c, 0x2e20, 4},
},
}
@@ -1770,77 +2196,6 @@ var _Po = &RangeTable{
},
}
-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},
@@ -1869,113 +2224,291 @@ var _Ps = &RangeTable{
},
}
-var _Nd = &RangeTable{
+var _S = &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},
+ {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{
- {0x104a0, 0x104a9, 1},
- {0x11066, 0x1106f, 1},
- {0x1d7ce, 0x1d7ff, 1},
+ {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 _Nl = &RangeTable{
+var _Sc = &RangeTable{
R16: []Range16{
- {0x16ee, 0x16f0, 1},
- {0x2160, 0x2182, 1},
- {0x2185, 0x2188, 1},
- {0x3007, 0x3021, 26},
- {0x3022, 0x3029, 1},
- {0x3038, 0x303a, 1},
- {0xa6e6, 0xa6ef, 1},
+ {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},
},
- R32: []Range32{
- {0x10140, 0x10174, 1},
- {0x10341, 0x1034a, 9},
- {0x103d1, 0x103d5, 1},
- {0x12400, 0x12462, 1},
+}
+
+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 _No = &RangeTable{
+var _Sm = &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},
+ {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{
- {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},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
},
}
@@ -2135,572 +2668,40 @@ var _So = &RangeTable{
},
}
-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{
+var _Z = &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},
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
},
}
-var _Lu = &RangeTable{
+var _Zl = &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},
+ {0x2028, 0x2028, 1},
},
}
-var _Lt = &RangeTable{
+var _Zp = &RangeTable{
R16: []Range16{
- {0x01c5, 0x01cb, 3},
- {0x01f2, 0x1f88, 7574},
- {0x1f89, 0x1f8f, 1},
- {0x1f98, 0x1f9f, 1},
- {0x1fa8, 0x1faf, 1},
- {0x1fbc, 0x1fcc, 16},
- {0x1ffc, 0x1ffc, 1},
+ {0x2029, 0x2029, 1},
},
}
-var _Lo = &RangeTable{
+var _Zs = &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},
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
},
}
+// The following variables are of type *RangeTable:
var (
Cc = _Cc // Cc is the set of Unicode characters in category Cc.
Cf = _Cf // Cf is the set of Unicode characters in category Cf.
@@ -2757,262 +2758,186 @@ var (
// Scripts is the set of Unicode script tables.
var Scripts = map[string]*RangeTable{
- "Katakana": Katakana,
- "Malayalam": Malayalam,
- "Phags_Pa": Phags_Pa,
- "Inscriptional_Parthian": Inscriptional_Parthian,
- "Latin": Latin,
- "Inscriptional_Pahlavi": Inscriptional_Pahlavi,
- "Osmanya": Osmanya,
- "Khmer": Khmer,
- "Inherited": Inherited,
- "Telugu": Telugu,
- "Samaritan": Samaritan,
+ "Arabic": Arabic,
+ "Armenian": Armenian,
+ "Avestan": Avestan,
+ "Balinese": Balinese,
+ "Bamum": Bamum,
+ "Batak": Batak,
+ "Bengali": Bengali,
"Bopomofo": Bopomofo,
- "Imperial_Aramaic": Imperial_Aramaic,
- "Kaithi": Kaithi,
- "Mandaic": Mandaic,
- "Old_South_Arabian": Old_South_Arabian,
- "Kayah_Li": Kayah_Li,
- "New_Tai_Lue": New_Tai_Lue,
- "Tai_Le": Tai_Le,
- "Kharoshthi": Kharoshthi,
- "Common": Common,
- "Kannada": Kannada,
- "Old_Turkic": Old_Turkic,
- "Tamil": Tamil,
- "Tagalog": Tagalog,
"Brahmi": Brahmi,
- "Arabic": Arabic,
- "Tagbanwa": Tagbanwa,
+ "Braille": Braille,
+ "Buginese": Buginese,
+ "Buhid": Buhid,
"Canadian_Aboriginal": Canadian_Aboriginal,
- "Tibetan": Tibetan,
+ "Carian": Carian,
+ "Cham": Cham,
+ "Cherokee": Cherokee,
+ "Common": Common,
"Coptic": Coptic,
- "Hiragana": Hiragana,
- "Limbu": Limbu,
+ "Cuneiform": Cuneiform,
+ "Cypriot": Cypriot,
+ "Cyrillic": Cyrillic,
+ "Deseret": Deseret,
+ "Devanagari": Devanagari,
"Egyptian_Hieroglyphs": Egyptian_Hieroglyphs,
- "Avestan": Avestan,
- "Myanmar": Myanmar,
- "Armenian": Armenian,
- "Sinhala": Sinhala,
- "Bengali": Bengali,
+ "Ethiopic": Ethiopic,
+ "Georgian": Georgian,
+ "Glagolitic": Glagolitic,
+ "Gothic": Gothic,
"Greek": Greek,
- "Cham": Cham,
- "Hebrew": Hebrew,
- "Meetei_Mayek": Meetei_Mayek,
- "Saurashtra": Saurashtra,
+ "Gujarati": Gujarati,
+ "Gurmukhi": Gurmukhi,
+ "Han": Han,
"Hangul": Hangul,
- "Runic": Runic,
- "Deseret": Deseret,
- "Lisu": Lisu,
- "Sundanese": Sundanese,
- "Glagolitic": Glagolitic,
- "Oriya": Oriya,
- "Buhid": Buhid,
- "Ethiopic": Ethiopic,
+ "Hanunoo": Hanunoo,
+ "Hebrew": Hebrew,
+ "Hiragana": Hiragana,
+ "Imperial_Aramaic": Imperial_Aramaic,
+ "Inherited": Inherited,
+ "Inscriptional_Pahlavi": Inscriptional_Pahlavi,
+ "Inscriptional_Parthian": Inscriptional_Parthian,
"Javanese": Javanese,
- "Syloti_Nagri": Syloti_Nagri,
- "Vai": Vai,
- "Cherokee": Cherokee,
+ "Kaithi": Kaithi,
+ "Kannada": Kannada,
+ "Katakana": Katakana,
+ "Kayah_Li": Kayah_Li,
+ "Kharoshthi": Kharoshthi,
+ "Khmer": Khmer,
+ "Lao": Lao,
+ "Latin": Latin,
+ "Lepcha": Lepcha,
+ "Limbu": Limbu,
+ "Linear_B": Linear_B,
+ "Lisu": Lisu,
+ "Lycian": Lycian,
+ "Lydian": Lydian,
+ "Malayalam": Malayalam,
+ "Mandaic": Mandaic,
+ "Meetei_Mayek": Meetei_Mayek,
+ "Mongolian": Mongolian,
+ "Myanmar": Myanmar,
+ "New_Tai_Lue": New_Tai_Lue,
+ "Nko": Nko,
"Ogham": Ogham,
- "Batak": Batak,
- "Syriac": Syriac,
- "Gurmukhi": Gurmukhi,
- "Tai_Tham": Tai_Tham,
"Ol_Chiki": Ol_Chiki,
- "Mongolian": Mongolian,
- "Hanunoo": Hanunoo,
- "Cypriot": Cypriot,
- "Buginese": Buginese,
- "Bamum": Bamum,
- "Lepcha": Lepcha,
- "Thaana": Thaana,
+ "Old_Italic": Old_Italic,
"Old_Persian": Old_Persian,
- "Cuneiform": Cuneiform,
+ "Old_South_Arabian": Old_South_Arabian,
+ "Old_Turkic": Old_Turkic,
+ "Oriya": Oriya,
+ "Osmanya": Osmanya,
+ "Phags_Pa": Phags_Pa,
+ "Phoenician": Phoenician,
"Rejang": Rejang,
- "Georgian": Georgian,
+ "Runic": Runic,
+ "Samaritan": Samaritan,
+ "Saurashtra": Saurashtra,
"Shavian": Shavian,
- "Lycian": Lycian,
- "Nko": Nko,
- "Yi": Yi,
- "Lao": Lao,
- "Linear_B": Linear_B,
- "Old_Italic": Old_Italic,
+ "Sinhala": Sinhala,
+ "Sundanese": Sundanese,
+ "Syloti_Nagri": Syloti_Nagri,
+ "Syriac": Syriac,
+ "Tagalog": Tagalog,
+ "Tagbanwa": Tagbanwa,
+ "Tai_Le": Tai_Le,
+ "Tai_Tham": Tai_Tham,
"Tai_Viet": Tai_Viet,
- "Devanagari": Devanagari,
- "Lydian": Lydian,
+ "Tamil": Tamil,
+ "Telugu": Telugu,
+ "Thaana": Thaana,
+ "Thai": Thai,
+ "Tibetan": Tibetan,
"Tifinagh": Tifinagh,
"Ugaritic": Ugaritic,
- "Thai": Thai,
- "Cyrillic": Cyrillic,
- "Gujarati": Gujarati,
- "Carian": Carian,
- "Phoenician": Phoenician,
- "Balinese": Balinese,
- "Braille": Braille,
- "Han": Han,
- "Gothic": Gothic,
-}
-
-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},
- },
+ "Vai": Vai,
+ "Yi": Yi,
}
-var _Phags_Pa = &RangeTable{
+var _Arabic = &RangeTable{
R16: []Range16{
- {0xa840, 0xa877, 1},
+ {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},
},
-}
-
-var _Inscriptional_Parthian = &RangeTable{
- R16: []Range16{},
R32: []Range32{
- {0x10b40, 0x10b55, 1},
- {0x10b58, 0x10b5f, 1},
+ {0x10e60, 0x10e7e, 1},
},
}
-var _Latin = &RangeTable{
+var _Armenian = &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},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x055f, 1},
+ {0x0561, 0x0587, 1},
+ {0x058a, 0x058a, 1},
+ {0xfb13, 0xfb17, 1},
},
}
-var _Osmanya = &RangeTable{
+var _Avestan = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10480, 0x1049d, 1},
- {0x104a0, 0x104a9, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b39, 0x10b3f, 1},
},
}
-var _Khmer = &RangeTable{
+var _Balinese = &RangeTable{
R16: []Range16{
- {0x1780, 0x17dd, 1},
- {0x17e0, 0x17e9, 1},
- {0x17f0, 0x17f9, 1},
- {0x19e0, 0x19ff, 1},
+ {0x1b00, 0x1b4b, 1},
+ {0x1b50, 0x1b7c, 1},
},
}
-var _Inherited = &RangeTable{
+var _Bamum = &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},
+ {0xa6a0, 0xa6f7, 1},
},
R32: []Range32{
- {0x101fd, 0x101fd, 1},
- {0x1d167, 0x1d169, 1},
- {0x1d17b, 0x1d182, 1},
- {0x1d185, 0x1d18b, 1},
- {0x1d1aa, 0x1d1ad, 1},
- {0xe0100, 0xe01ef, 1},
+ {0x16800, 0x16a38, 1},
},
}
-var _Telugu = &RangeTable{
+var _Batak = &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},
+ {0x1bc0, 0x1bf3, 1},
+ {0x1bfc, 0x1bff, 1},
},
}
-var _Samaritan = &RangeTable{
+var _Bengali = &RangeTable{
R16: []Range16{
- {0x0800, 0x082d, 1},
- {0x0830, 0x083e, 1},
+ {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},
},
}
@@ -3024,68 +2949,59 @@ var _Bopomofo = &RangeTable{
},
}
-var _Imperial_Aramaic = &RangeTable{
+var _Brahmi = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10840, 0x10855, 1},
- {0x10857, 0x1085f, 1},
+ {0x11000, 0x1104d, 1},
+ {0x11052, 0x1106f, 1},
},
}
-var _Kaithi = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x11080, 0x110c1, 1},
+var _Braille = &RangeTable{
+ R16: []Range16{
+ {0x2800, 0x28ff, 1},
},
}
-var _Mandaic = &RangeTable{
+var _Buginese = &RangeTable{
R16: []Range16{
- {0x0840, 0x085b, 1},
- {0x085e, 0x085e, 1},
+ {0x1a00, 0x1a1b, 1},
+ {0x1a1e, 0x1a1f, 1},
},
}
-var _Old_South_Arabian = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x10a60, 0x10a7f, 1},
+var _Buhid = &RangeTable{
+ R16: []Range16{
+ {0x1740, 0x1753, 1},
},
}
-var _Kayah_Li = &RangeTable{
+var _Canadian_Aboriginal = &RangeTable{
R16: []Range16{
- {0xa900, 0xa92f, 1},
+ {0x1400, 0x167f, 1},
+ {0x18b0, 0x18f5, 1},
},
}
-var _New_Tai_Lue = &RangeTable{
- R16: []Range16{
- {0x1980, 0x19ab, 1},
- {0x19b0, 0x19c9, 1},
- {0x19d0, 0x19da, 1},
- {0x19de, 0x19df, 1},
+var _Carian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x102a0, 0x102d0, 1},
},
}
-var _Tai_Le = &RangeTable{
+var _Cham = &RangeTable{
R16: []Range16{
- {0x1950, 0x196d, 1},
- {0x1970, 0x1974, 1},
+ {0xaa00, 0xaa36, 1},
+ {0xaa40, 0xaa4d, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xaa5c, 0xaa5f, 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 _Cherokee = &RangeTable{
+ R16: []Range16{
+ {0x13a0, 0x13f4, 1},
},
}
@@ -3265,147 +3181,62 @@ var _Common = &RangeTable{
},
}
-var _Kannada = &RangeTable{
+var _Coptic = &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},
+ {0x03e2, 0x03ef, 1},
+ {0x2c80, 0x2cf1, 1},
+ {0x2cf9, 0x2cff, 1},
},
}
-var _Old_Turkic = &RangeTable{
+var _Cuneiform = &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},
+ {0x12000, 0x1236e, 1},
+ {0x12400, 0x12462, 1},
+ {0x12470, 0x12473, 1},
},
}
-var _Brahmi = &RangeTable{
+var _Cypriot = &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},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x10808, 1},
+ {0x1080a, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083c, 1},
+ {0x1083f, 0x1083f, 1},
},
}
-var _Coptic = &RangeTable{
+var _Cyrillic = &RangeTable{
R16: []Range16{
- {0x03e2, 0x03ef, 1},
- {0x2c80, 0x2cf1, 1},
- {0x2cf9, 0x2cff, 1},
+ {0x0400, 0x0484, 1},
+ {0x0487, 0x0527, 1},
+ {0x1d2b, 0x1d2b, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa640, 0xa673, 1},
+ {0xa67c, 0xa697, 1},
},
}
-var _Hiragana = &RangeTable{
- R16: []Range16{
- {0x3041, 0x3096, 1},
- {0x309d, 0x309f, 1},
- },
+var _Deseret = &RangeTable{
+ R16: []Range16{},
R32: []Range32{
- {0x1b001, 0x1b001, 1},
- {0x1f200, 0x1f200, 1},
+ {0x10400, 0x1044f, 1},
},
}
-var _Limbu = &RangeTable{
+var _Devanagari = &RangeTable{
R16: []Range16{
- {0x1900, 0x191c, 1},
- {0x1920, 0x192b, 1},
- {0x1930, 0x193b, 1},
- {0x1940, 0x1940, 1},
- {0x1944, 0x194f, 1},
+ {0x0900, 0x0950, 1},
+ {0x0953, 0x0963, 1},
+ {0x0966, 0x096f, 1},
+ {0x0971, 0x0977, 1},
+ {0x0979, 0x097f, 1},
+ {0xa8e0, 0xa8fb, 1},
},
}
@@ -3416,63 +3247,63 @@ var _Egyptian_Hieroglyphs = &RangeTable{
},
}
-var _Avestan = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x10b00, 0x10b35, 1},
- {0x10b39, 0x10b3f, 1},
- },
-}
-
-var _Myanmar = &RangeTable{
+var _Ethiopic = &RangeTable{
R16: []Range16{
- {0x1000, 0x109f, 1},
- {0xaa60, 0xaa7b, 1},
+ {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 _Armenian = &RangeTable{
+var _Georgian = &RangeTable{
R16: []Range16{
- {0x0531, 0x0556, 1},
- {0x0559, 0x055f, 1},
- {0x0561, 0x0587, 1},
- {0x058a, 0x058a, 1},
- {0xfb13, 0xfb17, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x10fc, 1},
+ {0x2d00, 0x2d25, 1},
},
}
-var _Sinhala = &RangeTable{
+var _Glagolitic = &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},
+ {0x2c00, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 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 _Gothic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10330, 0x1034a, 1},
},
}
@@ -3516,40 +3347,66 @@ var _Greek = &RangeTable{
},
}
-var _Cham = &RangeTable{
+var _Gujarati = &RangeTable{
R16: []Range16{
- {0xaa00, 0xaa36, 1},
- {0xaa40, 0xaa4d, 1},
- {0xaa50, 0xaa59, 1},
- {0xaa5c, 0xaa5f, 1},
+ {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 _Hebrew = &RangeTable{
+var _Gurmukhi = &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},
+ {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 _Meetei_Mayek = &RangeTable{
+var _Han = &RangeTable{
R16: []Range16{
- {0xabc0, 0xabed, 1},
- {0xabf0, 0xabf9, 1},
+ {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},
},
-}
-
-var _Saurashtra = &RangeTable{
- R16: []Range16{
- {0xa880, 0xa8c4, 1},
- {0xa8ce, 0xa8d9, 1},
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
},
}
@@ -3572,183 +3429,307 @@ var _Hangul = &RangeTable{
},
}
-var _Runic = &RangeTable{
+var _Hanunoo = &RangeTable{
R16: []Range16{
- {0x16a0, 0x16ea, 1},
- {0x16ee, 0x16f0, 1},
+ {0x1720, 0x1734, 1},
},
}
-var _Deseret = &RangeTable{
+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 _Hiragana = &RangeTable{
+ R16: []Range16{
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ },
+ R32: []Range32{
+ {0x1b001, 0x1b001, 1},
+ {0x1f200, 0x1f200, 1},
+ },
+}
+
+var _Imperial_Aramaic = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10400, 0x1044f, 1},
+ {0x10840, 0x10855, 1},
+ {0x10857, 0x1085f, 1},
},
}
-var _Lisu = &RangeTable{
+var _Inherited = &RangeTable{
R16: []Range16{
- {0xa4d0, 0xa4ff, 1},
+ {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 _Sundanese = &RangeTable{
- R16: []Range16{
- {0x1b80, 0x1baa, 1},
- {0x1bae, 0x1bb9, 1},
+var _Inscriptional_Pahlavi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b60, 0x10b72, 1},
+ {0x10b78, 0x10b7f, 1},
},
}
-var _Glagolitic = &RangeTable{
- R16: []Range16{
- {0x2c00, 0x2c2e, 1},
- {0x2c30, 0x2c5e, 1},
+var _Inscriptional_Parthian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b40, 0x10b55, 1},
+ {0x10b58, 0x10b5f, 1},
},
}
-var _Oriya = &RangeTable{
+var _Javanese = &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},
+ {0xa980, 0xa9cd, 1},
+ {0xa9cf, 0xa9d9, 1},
+ {0xa9de, 0xa9df, 1},
},
}
-var _Buhid = &RangeTable{
+var _Kaithi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11080, 0x110c1, 1},
+ },
+}
+
+var _Kannada = &RangeTable{
R16: []Range16{
- {0x1740, 0x1753, 1},
+ {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 _Ethiopic = &RangeTable{
+var _Katakana = &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},
+ {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 _Javanese = &RangeTable{
+var _Kayah_Li = &RangeTable{
R16: []Range16{
- {0xa980, 0xa9cd, 1},
- {0xa9cf, 0xa9d9, 1},
- {0xa9de, 0xa9df, 1},
+ {0xa900, 0xa92f, 1},
},
}
-var _Syloti_Nagri = &RangeTable{
+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 _Khmer = &RangeTable{
R16: []Range16{
- {0xa800, 0xa82b, 1},
+ {0x1780, 0x17dd, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19e0, 0x19ff, 1},
},
}
-var _Vai = &RangeTable{
+var _Lao = &RangeTable{
R16: []Range16{
- {0xa500, 0xa62b, 1},
+ {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 _Cherokee = &RangeTable{
+var _Latin = &RangeTable{
R16: []Range16{
- {0x13a0, 0x13f4, 1},
+ {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 _Ogham = &RangeTable{
+var _Lepcha = &RangeTable{
R16: []Range16{
- {0x1680, 0x169c, 1},
+ {0x1c00, 0x1c37, 1},
+ {0x1c3b, 0x1c49, 1},
+ {0x1c4d, 0x1c4f, 1},
},
}
-var _Batak = &RangeTable{
+var _Limbu = &RangeTable{
R16: []Range16{
- {0x1bc0, 0x1bf3, 1},
- {0x1bfc, 0x1bff, 1},
+ {0x1900, 0x191c, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x1940, 0x1940, 1},
+ {0x1944, 0x194f, 1},
},
}
-var _Syriac = &RangeTable{
+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 _Lisu = &RangeTable{
R16: []Range16{
- {0x0700, 0x070d, 1},
- {0x070f, 0x074a, 1},
- {0x074d, 0x074f, 1},
+ {0xa4d0, 0xa4ff, 1},
},
}
-var _Gurmukhi = &RangeTable{
+var _Lycian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10280, 0x1029c, 1},
+ },
+}
+
+var _Lydian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10920, 0x10939, 1},
+ {0x1093f, 0x1093f, 1},
+ },
+}
+
+var _Malayalam = &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},
+ {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 _Tai_Tham = &RangeTable{
+var _Mandaic = &RangeTable{
R16: []Range16{
- {0x1a20, 0x1a5e, 1},
- {0x1a60, 0x1a7c, 1},
- {0x1a7f, 0x1a89, 1},
- {0x1a90, 0x1a99, 1},
- {0x1aa0, 0x1aad, 1},
+ {0x0840, 0x085b, 1},
+ {0x085e, 0x085e, 1},
},
}
-var _Ol_Chiki = &RangeTable{
+var _Meetei_Mayek = &RangeTable{
R16: []Range16{
- {0x1c50, 0x1c7f, 1},
+ {0xabc0, 0xabed, 1},
+ {0xabf0, 0xabf9, 1},
},
}
@@ -3763,51 +3744,45 @@ var _Mongolian = &RangeTable{
},
}
-var _Hanunoo = &RangeTable{
+var _Myanmar = &RangeTable{
R16: []Range16{
- {0x1720, 0x1734, 1},
+ {0x1000, 0x109f, 1},
+ {0xaa60, 0xaa7b, 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 _New_Tai_Lue = &RangeTable{
+ R16: []Range16{
+ {0x1980, 0x19ab, 1},
+ {0x19b0, 0x19c9, 1},
+ {0x19d0, 0x19da, 1},
+ {0x19de, 0x19df, 1},
},
}
-var _Buginese = &RangeTable{
+var _Nko = &RangeTable{
R16: []Range16{
- {0x1a00, 0x1a1b, 1},
- {0x1a1e, 0x1a1f, 1},
+ {0x07c0, 0x07fa, 1},
},
}
-var _Bamum = &RangeTable{
+var _Ogham = &RangeTable{
R16: []Range16{
- {0xa6a0, 0xa6f7, 1},
- },
- R32: []Range32{
- {0x16800, 0x16a38, 1},
+ {0x1680, 0x169c, 1},
},
}
-var _Lepcha = &RangeTable{
+var _Ol_Chiki = &RangeTable{
R16: []Range16{
- {0x1c00, 0x1c37, 1},
- {0x1c3b, 0x1c49, 1},
- {0x1c4d, 0x1c4f, 1},
+ {0x1c50, 0x1c7f, 1},
},
}
-var _Thaana = &RangeTable{
- R16: []Range16{
- {0x0780, 0x07b1, 1},
+var _Old_Italic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10300, 0x1031e, 1},
+ {0x10320, 0x10323, 1},
},
}
@@ -3819,240 +3794,267 @@ var _Old_Persian = &RangeTable{
},
}
-var _Cuneiform = &RangeTable{
+var _Old_South_Arabian = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x12000, 0x1236e, 1},
- {0x12400, 0x12462, 1},
- {0x12470, 0x12473, 1},
+ {0x10a60, 0x10a7f, 1},
},
}
-var _Rejang = &RangeTable{
- R16: []Range16{
- {0xa930, 0xa953, 1},
- {0xa95f, 0xa95f, 1},
+var _Old_Turkic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10c00, 0x10c48, 1},
},
}
-var _Georgian = &RangeTable{
+var _Oriya = &RangeTable{
R16: []Range16{
- {0x10a0, 0x10c5, 1},
- {0x10d0, 0x10fa, 1},
- {0x10fc, 0x10fc, 1},
- {0x2d00, 0x2d25, 1},
+ {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 _Shavian = &RangeTable{
+var _Osmanya = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10450, 0x1047f, 1},
+ {0x10480, 0x1049d, 1},
+ {0x104a0, 0x104a9, 1},
},
}
-var _Lycian = &RangeTable{
+var _Phags_Pa = &RangeTable{
+ R16: []Range16{
+ {0xa840, 0xa877, 1},
+ },
+}
+
+var _Phoenician = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10280, 0x1029c, 1},
+ {0x10900, 0x1091b, 1},
+ {0x1091f, 0x1091f, 1},
},
}
-var _Nko = &RangeTable{
+var _Rejang = &RangeTable{
R16: []Range16{
- {0x07c0, 0x07fa, 1},
+ {0xa930, 0xa953, 1},
+ {0xa95f, 0xa95f, 1},
},
}
-var _Yi = &RangeTable{
+var _Runic = &RangeTable{
R16: []Range16{
- {0xa000, 0xa48c, 1},
- {0xa490, 0xa4c6, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x16ee, 0x16f0, 1},
},
}
-var _Lao = &RangeTable{
+var _Samaritan = &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},
+ {0x0800, 0x082d, 1},
+ {0x0830, 0x083e, 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 _Saurashtra = &RangeTable{
+ R16: []Range16{
+ {0xa880, 0xa8c4, 1},
+ {0xa8ce, 0xa8d9, 1},
},
}
-var _Old_Italic = &RangeTable{
+var _Shavian = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10300, 0x1031e, 1},
- {0x10320, 0x10323, 1},
+ {0x10450, 0x1047f, 1},
},
}
-var _Tai_Viet = &RangeTable{
+var _Sinhala = &RangeTable{
R16: []Range16{
- {0xaa80, 0xaac2, 1},
- {0xaadb, 0xaadf, 1},
+ {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 _Devanagari = &RangeTable{
+var _Sundanese = &RangeTable{
R16: []Range16{
- {0x0900, 0x0950, 1},
- {0x0953, 0x0963, 1},
- {0x0966, 0x096f, 1},
- {0x0971, 0x0977, 1},
- {0x0979, 0x097f, 1},
- {0xa8e0, 0xa8fb, 1},
+ {0x1b80, 0x1baa, 1},
+ {0x1bae, 0x1bb9, 1},
},
}
-var _Lydian = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x10920, 0x10939, 1},
- {0x1093f, 0x1093f, 1},
+var _Syloti_Nagri = &RangeTable{
+ R16: []Range16{
+ {0xa800, 0xa82b, 1},
},
}
-var _Tifinagh = &RangeTable{
+var _Syriac = &RangeTable{
R16: []Range16{
- {0x2d30, 0x2d65, 1},
- {0x2d6f, 0x2d70, 1},
- {0x2d7f, 0x2d7f, 1},
+ {0x0700, 0x070d, 1},
+ {0x070f, 0x074a, 1},
+ {0x074d, 0x074f, 1},
},
}
-var _Ugaritic = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x10380, 0x1039d, 1},
- {0x1039f, 0x1039f, 1},
+var _Tagalog = &RangeTable{
+ R16: []Range16{
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1714, 1},
},
}
-var _Thai = &RangeTable{
+var _Tagbanwa = &RangeTable{
R16: []Range16{
- {0x0e01, 0x0e3a, 1},
- {0x0e40, 0x0e5b, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1772, 0x1773, 1},
},
}
-var _Cyrillic = &RangeTable{
+var _Tai_Le = &RangeTable{
R16: []Range16{
- {0x0400, 0x0484, 1},
- {0x0487, 0x0527, 1},
- {0x1d2b, 0x1d2b, 1},
- {0x1d78, 0x1d78, 1},
- {0x2de0, 0x2dff, 1},
- {0xa640, 0xa673, 1},
- {0xa67c, 0xa697, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
},
}
-var _Gujarati = &RangeTable{
+var _Tai_Tham = &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},
+ {0x1a20, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1aa0, 0x1aad, 1},
},
}
-var _Carian = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x102a0, 0x102d0, 1},
+var _Tai_Viet = &RangeTable{
+ R16: []Range16{
+ {0xaa80, 0xaac2, 1},
+ {0xaadb, 0xaadf, 1},
},
}
-var _Phoenician = &RangeTable{
- R16: []Range16{},
- R32: []Range32{
- {0x10900, 0x1091b, 1},
- {0x1091f, 0x1091f, 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 _Balinese = &RangeTable{
+var _Telugu = &RangeTable{
R16: []Range16{
- {0x1b00, 0x1b4b, 1},
- {0x1b50, 0x1b7c, 1},
+ {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 _Braille = &RangeTable{
+var _Thaana = &RangeTable{
R16: []Range16{
- {0x2800, 0x28ff, 1},
+ {0x0780, 0x07b1, 1},
},
}
-var _Han = &RangeTable{
+var _Thai = &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},
+ {0x0e01, 0x0e3a, 1},
+ {0x0e40, 0x0e5b, 1},
},
- R32: []Range32{
- {0x20000, 0x2a6d6, 1},
- {0x2a700, 0x2b734, 1},
- {0x2b740, 0x2b81d, 1},
- {0x2f800, 0x2fa1d, 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 _Gothic = &RangeTable{
+var _Tifinagh = &RangeTable{
+ R16: []Range16{
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d70, 1},
+ {0x2d7f, 0x2d7f, 1},
+ },
+}
+
+var _Ugaritic = &RangeTable{
R16: []Range16{},
R32: []Range32{
- {0x10330, 0x1034a, 1},
+ {0x10380, 0x1039d, 1},
+ {0x1039f, 0x1039f, 1},
},
}
+var _Vai = &RangeTable{
+ R16: []Range16{
+ {0xa500, 0xa62b, 1},
+ },
+}
+
+var _Yi = &RangeTable{
+ R16: []Range16{
+ {0xa000, 0xa48c, 1},
+ {0xa490, 0xa4c6, 1},
+ },
+}
+
+// The following variables are of type *RangeTable:
var (
Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic.
Armenian = _Armenian // Armenian is the set of Unicode characters in script Armenian.
@@ -4157,144 +4159,241 @@ var (
// Properties is the set of Unicode property tables.
var Properties = map[string]*RangeTable{
- "Pattern_Syntax": Pattern_Syntax,
- "Other_ID_Start": Other_ID_Start,
- "Pattern_White_Space": Pattern_White_Space,
- "Other_Lowercase": Other_Lowercase,
- "Soft_Dotted": Soft_Dotted,
- "Hex_Digit": Hex_Digit,
"ASCII_Hex_Digit": ASCII_Hex_Digit,
- "Deprecated": Deprecated,
- "Terminal_Punctuation": Terminal_Punctuation,
- "Quotation_Mark": Quotation_Mark,
- "Other_ID_Continue": Other_ID_Continue,
"Bidi_Control": Bidi_Control,
- "Variation_Selector": Variation_Selector,
- "Noncharacter_Code_Point": Noncharacter_Code_Point,
- "Other_Math": Other_Math,
- "Unified_Ideograph": Unified_Ideograph,
+ "Dash": Dash,
+ "Deprecated": Deprecated,
+ "Diacritic": Diacritic,
+ "Extender": Extender,
+ "Hex_Digit": Hex_Digit,
"Hyphen": Hyphen,
"IDS_Binary_Operator": IDS_Binary_Operator,
+ "IDS_Trinary_Operator": IDS_Trinary_Operator,
+ "Ideographic": Ideographic,
+ "Join_Control": Join_Control,
"Logical_Order_Exception": Logical_Order_Exception,
- "Radical": Radical,
- "Other_Uppercase": Other_Uppercase,
- "STerm": STerm,
+ "Noncharacter_Code_Point": Noncharacter_Code_Point,
"Other_Alphabetic": Other_Alphabetic,
- "Diacritic": Diacritic,
- "Extender": Extender,
- "Join_Control": Join_Control,
- "Ideographic": Ideographic,
- "Dash": Dash,
- "IDS_Trinary_Operator": IDS_Trinary_Operator,
- "Other_Grapheme_Extend": Other_Grapheme_Extend,
"Other_Default_Ignorable_Code_Point": Other_Default_Ignorable_Code_Point,
+ "Other_Grapheme_Extend": Other_Grapheme_Extend,
+ "Other_ID_Continue": Other_ID_Continue,
+ "Other_ID_Start": Other_ID_Start,
+ "Other_Lowercase": Other_Lowercase,
+ "Other_Math": Other_Math,
+ "Other_Uppercase": Other_Uppercase,
+ "Pattern_Syntax": Pattern_Syntax,
+ "Pattern_White_Space": Pattern_White_Space,
+ "Quotation_Mark": Quotation_Mark,
+ "Radical": Radical,
+ "STerm": STerm,
+ "Soft_Dotted": Soft_Dotted,
+ "Terminal_Punctuation": Terminal_Punctuation,
+ "Unified_Ideograph": Unified_Ideograph,
+ "Variation_Selector": Variation_Selector,
"White_Space": White_Space,
}
-var _Pattern_Syntax = &RangeTable{
+var _ASCII_Hex_Digit = &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},
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
},
}
-var _Other_ID_Start = &RangeTable{
+var _Bidi_Control = &RangeTable{
R16: []Range16{
- {0x2118, 0x2118, 1},
- {0x212e, 0x212e, 1},
- {0x309b, 0x309c, 1},
+ {0x200e, 0x200f, 1},
+ {0x202a, 0x202e, 1},
},
}
-var _Pattern_White_Space = &RangeTable{
+var _Dash = &RangeTable{
R16: []Range16{
- {0x0009, 0x000d, 1},
- {0x0020, 0x0020, 1},
- {0x0085, 0x0085, 1},
- {0x200e, 0x200f, 1},
- {0x2028, 0x2029, 1},
+ {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 _Other_Lowercase = &RangeTable{
+var _Deprecated = &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},
+ {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 _Soft_Dotted = &RangeTable{
+var _Diacritic = &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},
+ {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{
- {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},
+ {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},
},
}
@@ -4309,144 +4408,66 @@ var _Hex_Digit = &RangeTable{
},
}
-var _ASCII_Hex_Digit = &RangeTable{
+var _Hyphen = &RangeTable{
R16: []Range16{
- {0x0030, 0x0039, 1},
- {0x0041, 0x0046, 1},
- {0x0061, 0x0066, 1},
+ {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 _Deprecated = &RangeTable{
+var _IDS_Binary_Operator = &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},
+ {0x2ff0, 0x2ff1, 1},
+ {0x2ff4, 0x2ffb, 1},
},
}
-var _Terminal_Punctuation = &RangeTable{
+var _IDS_Trinary_Operator = &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},
+ {0x2ff2, 0x2ff3, 1},
},
}
-var _Quotation_Mark = &RangeTable{
+var _Ideographic = &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},
+ {0x3006, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
},
-}
-
-var _Other_ID_Continue = &RangeTable{
- R16: []Range16{
- {0x00b7, 0x00b7, 1},
- {0x0387, 0x0387, 1},
- {0x1369, 0x1371, 1},
- {0x19da, 0x19da, 1},
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
},
}
-var _Bidi_Control = &RangeTable{
+var _Join_Control = &RangeTable{
R16: []Range16{
- {0x200e, 0x200f, 1},
- {0x202a, 0x202e, 1},
+ {0x200c, 0x200d, 1},
},
}
-var _Variation_Selector = &RangeTable{
+var _Logical_Order_Exception = &RangeTable{
R16: []Range16{
- {0x180b, 0x180d, 1},
- {0xfe00, 0xfe0f, 1},
- },
- R32: []Range32{
- {0xe0100, 0xe01ef, 1},
+ {0x0e40, 0x0e44, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0xaab5, 0xaab6, 1},
+ {0xaab9, 0xaab9, 1},
+ {0xaabb, 0xaabc, 1},
},
}
@@ -4475,6 +4496,233 @@ var _Noncharacter_Code_Point = &RangeTable{
},
}
+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 _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 _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_ID_Continue = &RangeTable{
+ R16: []Range16{
+ {0x00b7, 0x00b7, 1},
+ {0x0387, 0x0387, 1},
+ {0x1369, 0x1371, 1},
+ {0x19da, 0x19da, 1},
+ },
+}
+
+var _Other_ID_Start = &RangeTable{
+ R16: []Range16{
+ {0x2118, 0x2118, 1},
+ {0x212e, 0x212e, 1},
+ {0x309b, 0x309c, 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 _Other_Math = &RangeTable{
R16: []Range16{
{0x005e, 0x005e, 1},
@@ -4582,54 +4830,70 @@ var _Other_Math = &RangeTable{
},
}
-var _Unified_Ideograph = &RangeTable{
+var _Other_Uppercase = &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},
+ {0x2160, 0x216f, 1},
+ {0x24b6, 0x24cf, 1},
},
}
-var _Hyphen = &RangeTable{
+var _Pattern_Syntax = &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},
+ {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 _IDS_Binary_Operator = &RangeTable{
+var _Pattern_White_Space = &RangeTable{
R16: []Range16{
- {0x2ff0, 0x2ff1, 1},
- {0x2ff4, 0x2ffb, 1},
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x200e, 0x200f, 1},
+ {0x2028, 0x2029, 1},
},
}
-var _Logical_Order_Exception = &RangeTable{
+var _Quotation_Mark = &RangeTable{
R16: []Range16{
- {0x0e40, 0x0e44, 1},
- {0x0ec0, 0x0ec4, 1},
- {0xaab5, 0xaab6, 1},
- {0xaab9, 0xaab9, 1},
- {0xaabb, 0xaabc, 1},
+ {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},
},
}
@@ -4641,13 +4905,6 @@ var _Radical = &RangeTable{
},
}
-var _Other_Uppercase = &RangeTable{
- R16: []Range16{
- {0x2160, 0x216f, 1},
- {0x24b6, 0x24cf, 1},
- },
-}
-
var _STerm = &RangeTable{
R16: []Range16{
{0x0021, 0x0021, 1},
@@ -4702,399 +4959,144 @@ var _STerm = &RangeTable{
},
}
-var _Other_Alphabetic = &RangeTable{
+var _Soft_Dotted = &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},
+ {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{
- {0x10a01, 0x10a03, 1},
- {0x10a05, 0x10a06, 1},
- {0x10a0c, 0x10a0f, 1},
- {0x11000, 0x11002, 1},
- {0x11038, 0x11045, 1},
- {0x11082, 0x11082, 1},
- {0x110b0, 0x110b8, 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 _Diacritic = &RangeTable{
+var _Terminal_Punctuation = &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},
+ {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{
- {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},
+ {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 _Ideographic = &RangeTable{
+var _Unified_Ideograph = &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},
+ {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},
- {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{
+var _Variation_Selector = &RangeTable{
R16: []Range16{
- {0x034f, 0x034f, 1},
- {0x115f, 0x1160, 1},
- {0x2065, 0x2069, 1},
- {0x3164, 0x3164, 1},
- {0xffa0, 0xffa0, 1},
- {0xfff0, 0xfff8, 1},
+ {0x180b, 0x180d, 1},
+ {0xfe00, 0xfe0f, 1},
},
R32: []Range32{
- {0xe0000, 0xe0000, 1},
- {0xe0002, 0xe001f, 1},
- {0xe0080, 0xe00ff, 1},
- {0xe01f0, 0xe0fff, 1},
+ {0xe0100, 0xe01ef, 1},
},
}
@@ -5114,6 +5116,7 @@ var _White_Space = &RangeTable{
},
}
+// The following variables are of type *RangeTable:
var (
ASCII_Hex_Digit = _ASCII_Hex_Digit // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
Bidi_Control = _Bidi_Control // Bidi_Control is the set of Unicode characters with property Bidi_Control.
@@ -5746,15 +5749,40 @@ var caseOrbit = []foldPair{
// 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,
+ "Inherited": foldInherited,
+ "L": foldL,
+ "Ll": foldLl,
"Lt": foldLt,
+ "Lu": foldLu,
+ "M": foldM,
+ "Mn": foldMn,
+}
+
+var foldCommon = &RangeTable{
+ R16: []Range16{
+ {0x039c, 0x03bc, 32},
+ },
+}
+
+var foldGreek = &RangeTable{
+ R16: []Range16{
+ {0x00b5, 0x0345, 656},
+ },
+}
+
+var foldInherited = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldL = &RangeTable{
+ R16: []Range16{
+ {0x0345, 0x0345, 1},
+ },
}
var foldLl = &RangeTable{
@@ -5861,42 +5889,17 @@ var foldLl = &RangeTable{
},
}
-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{
+var foldLt = &RangeTable{
R16: []Range16{
- {0x00b5, 0x0345, 656},
+ {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},
},
}
@@ -6000,17 +6003,17 @@ var foldLu = &RangeTable{
},
}
-var foldLt = &RangeTable{
+var foldM = &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},
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldMn = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
},
}
diff --git a/src/pkg/unicode/utf16/export_test.go b/src/pkg/unicode/utf16/export_test.go
new file mode 100644
index 000000000..306247e48
--- /dev/null
+++ b/src/pkg/unicode/utf16/export_test.go
@@ -0,0 +1,11 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf16
+
+// Extra names for constants so we can validate them during testing.
+const (
+ MaxRune = maxRune
+ ReplacementChar = replacementChar
+)
diff --git a/src/pkg/utf16/utf16.go b/src/pkg/unicode/utf16/utf16.go
index 372e38a71..903e4012a 100644
--- a/src/pkg/utf16/utf16.go
+++ b/src/pkg/unicode/utf16/utf16.go
@@ -5,7 +5,14 @@
// Package utf16 implements encoding and decoding of UTF-16 sequences.
package utf16
-import "unicode"
+// The conditions replacementChar==unicode.ReplacementChar and
+// maxRune==unicode.MaxRune are verified in the tests.
+// Defining them locally avoids this package depending on package unicode.
+
+const (
+ replacementChar = '\uFFFD' // Unicode replacement character
+ maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+)
const (
// 0xd800-0xdc00 encodes the high 10 bits of a pair.
@@ -20,33 +27,33 @@ const (
// IsSurrogate returns true if the specified Unicode code point
// can appear in a surrogate pair.
-func IsSurrogate(rune int) bool {
- return surr1 <= rune && rune < surr3
+func IsSurrogate(r rune) bool {
+ return surr1 <= r && r < surr3
}
// DecodeRune returns the UTF-16 decoding of a surrogate pair.
// If the pair is not a valid UTF-16 surrogate pair, DecodeRune returns
// the Unicode replacement code point U+FFFD.
-func DecodeRune(r1, r2 int) int {
+func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
- return (int(r1)-surr1)<<10 | (int(r2) - surr2) + 0x10000
+ return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000
}
- return unicode.ReplacementChar
+ return replacementChar
}
// EncodeRune returns the UTF-16 surrogate pair r1, r2 for the given rune.
// If the rune is not a valid Unicode code point or does not need encoding,
// EncodeRune returns U+FFFD, U+FFFD.
-func EncodeRune(rune int) (r1, r2 int) {
- if rune < surrSelf || rune > unicode.MaxRune || IsSurrogate(rune) {
- return unicode.ReplacementChar, unicode.ReplacementChar
+func EncodeRune(r rune) (r1, r2 rune) {
+ if r < surrSelf || r > maxRune || IsSurrogate(r) {
+ return replacementChar, replacementChar
}
- rune -= surrSelf
- return surr1 + (rune>>10)&0x3ff, surr2 + rune&0x3ff
+ r -= surrSelf
+ return surr1 + (r>>10)&0x3ff, surr2 + r&0x3ff
}
// Encode returns the UTF-16 encoding of the Unicode code point sequence s.
-func Encode(s []int) []uint16 {
+func Encode(s []rune) []uint16 {
n := len(s)
for _, v := range s {
if v >= surrSelf {
@@ -58,8 +65,8 @@ func Encode(s []int) []uint16 {
n = 0
for _, v := range s {
switch {
- case v < 0, surr1 <= v && v < surr3, v > unicode.MaxRune:
- v = unicode.ReplacementChar
+ case v < 0, surr1 <= v && v < surr3, v > maxRune:
+ v = replacementChar
fallthrough
case v < surrSelf:
a[n] = uint16(v)
@@ -76,24 +83,24 @@ func Encode(s []int) []uint16 {
// Decode returns the Unicode code point sequence represented
// by the UTF-16 encoding s.
-func Decode(s []uint16) []int {
- a := make([]int, len(s))
+func Decode(s []uint16) []rune {
+ a := make([]rune, len(s))
n := 0
for i := 0; i < len(s); i++ {
switch r := s[i]; {
case surr1 <= r && r < surr2 && i+1 < len(s) &&
surr2 <= s[i+1] && s[i+1] < surr3:
// valid surrogate sequence
- a[n] = DecodeRune(int(r), int(s[i+1]))
+ a[n] = DecodeRune(rune(r), rune(s[i+1]))
i++
n++
case surr1 <= r && r < surr3:
// invalid surrogate sequence
- a[n] = unicode.ReplacementChar
+ a[n] = replacementChar
n++
default:
// normal rune
- a[n] = int(r)
+ a[n] = rune(r)
n++
}
}
diff --git a/src/pkg/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index 2b9fb3d87..ee16a303d 100644
--- a/src/pkg/utf16/utf16_test.go
+++ b/src/pkg/unicode/utf16/utf16_test.go
@@ -5,23 +5,32 @@
package utf16_test
import (
- "fmt"
"reflect"
"testing"
"unicode"
- . "utf16"
+ . "unicode/utf16"
)
+// Validate the constants redefined from unicode.
+func TestConstants(t *testing.T) {
+ if MaxRune != unicode.MaxRune {
+ t.Errorf("utf16.maxRune is wrong: %x should be %x", MaxRune, unicode.MaxRune)
+ }
+ if ReplacementChar != unicode.ReplacementChar {
+ t.Errorf("utf16.replacementChar is wrong: %x should be %x", ReplacementChar, unicode.ReplacementChar)
+ }
+}
+
type encodeTest struct {
- in []int
+ in []rune
out []uint16
}
var encodeTests = []encodeTest{
- {[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
- {[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
+ {[]rune{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
+ {[]rune{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff}},
- {[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
+ {[]rune{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
[]uint16{'a', 'b', 0xd7ff, 0xfffd, 0xfffd, 0xe000, 0xfffd, 0xfffd}},
}
@@ -29,7 +38,7 @@ func TestEncode(t *testing.T) {
for _, tt := range encodeTests {
out := Encode(tt.in)
if !reflect.DeepEqual(out, tt.out) {
- t.Errorf("Encode(%v) = %v; want %v", hex(tt.in), hex16(out), hex16(tt.out))
+ t.Errorf("Encode(%x) = %x; want %x", tt.in, out, tt.out)
}
}
}
@@ -53,7 +62,7 @@ func TestEncodeRune(t *testing.T) {
t.Errorf("#%d: ran out of tt.out", i)
break
}
- if r1 != int(tt.out[j]) || r2 != int(tt.out[j+1]) {
+ if r1 != rune(tt.out[j]) || r2 != rune(tt.out[j+1]) {
t.Errorf("EncodeRune(%#x) = %#x, %#x; want %#x, %#x", r, r1, r2, tt.out[j], tt.out[j+1])
}
j += 2
@@ -71,48 +80,22 @@ func TestEncodeRune(t *testing.T) {
type decodeTest struct {
in []uint16
- out []int
+ out []rune
}
var decodeTests = []decodeTest{
- {[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
+ {[]uint16{1, 2, 3, 4}, []rune{1, 2, 3, 4}},
{[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
- []int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
- {[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
- {[]uint16{0xdfff}, []int{0xfffd}},
+ []rune{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
+ {[]uint16{0xd800, 'a'}, []rune{0xfffd, 'a'}},
+ {[]uint16{0xdfff}, []rune{0xfffd}},
}
func TestDecode(t *testing.T) {
for _, tt := range decodeTests {
out := Decode(tt.in)
if !reflect.DeepEqual(out, tt.out) {
- t.Errorf("Decode(%v) = %v; want %v", hex16(tt.in), hex(out), hex(tt.out))
- }
- }
-}
-
-type hex []int
-
-func (h hex) Format(f fmt.State, c int) {
- fmt.Fprint(f, "[")
- for i, v := range h {
- if i > 0 {
- fmt.Fprint(f, " ")
- }
- fmt.Fprintf(f, "%x", v)
- }
- fmt.Fprint(f, "]")
-}
-
-type hex16 []uint16
-
-func (h hex16) Format(f fmt.State, c int) {
- fmt.Fprint(f, "[")
- for i, v := range h {
- if i > 0 {
- fmt.Fprint(f, " ")
+ t.Errorf("Decode(%x) = %x; want %x", tt.in, out, tt.out)
}
- fmt.Fprintf(f, "%x", v)
}
- fmt.Fprint(f, "]")
}
diff --git a/src/pkg/utf8/utf8.go b/src/pkg/unicode/utf8/utf8.go
index 8910e17d7..57ea19e96 100644
--- a/src/pkg/utf8/utf8.go
+++ b/src/pkg/unicode/utf8/utf8.go
@@ -3,16 +3,19 @@
// license that can be found in the LICENSE file.
// Package utf8 implements functions and constants to support text encoded in
-// UTF-8. This package calls a Unicode character a rune for brevity.
+// UTF-8. It includes functions to translate between runes and UTF-8 byte sequences.
package utf8
-import "unicode" // only needed for a couple of constants
+// The conditions RuneError==unicode.ReplacementChar and
+// MaxRune==unicode.MaxRune are verified in the tests.
+// Defining them locally avoids this package depending on package unicode.
// Numbers fundamental to the encoding.
const (
- RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
- RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
- UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
+ RuneError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
+ RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+ UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
)
const (
@@ -34,7 +37,7 @@ const (
rune4Max = 1<<21 - 1
)
-func decodeRuneInternal(p []byte) (rune, size int, short bool) {
+func decodeRuneInternal(p []byte) (r rune, size int, short bool) {
n := len(p)
if n < 1 {
return RuneError, 0, true
@@ -43,7 +46,7 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
// 1-byte, 7-bit sequence?
if c0 < tx {
- return int(c0), 1, false
+ return rune(c0), 1, false
}
// unexpected continuation byte?
@@ -62,11 +65,11 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
// 2-byte, 11-bit sequence?
if c0 < t3 {
- rune = int(c0&mask2)<<6 | int(c1&maskx)
- if rune <= rune1Max {
+ r = rune(c0&mask2)<<6 | rune(c1&maskx)
+ if r <= rune1Max {
return RuneError, 1, false
}
- return rune, 2, false
+ return r, 2, false
}
// need second continuation byte
@@ -80,11 +83,11 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
// 3-byte, 16-bit sequence?
if c0 < t4 {
- rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
- if rune <= rune2Max {
+ r = rune(c0&mask3)<<12 | rune(c1&maskx)<<6 | rune(c2&maskx)
+ if r <= rune2Max {
return RuneError, 1, false
}
- return rune, 3, false
+ return r, 3, false
}
// need third continuation byte
@@ -98,18 +101,18 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
// 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 {
+ r = rune(c0&mask4)<<18 | rune(c1&maskx)<<12 | rune(c2&maskx)<<6 | rune(c3&maskx)
+ if r <= rune3Max {
return RuneError, 1, false
}
- return rune, 4, false
+ return r, 4, false
}
// error
return RuneError, 1, false
}
-func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
+func decodeRuneInStringInternal(s string) (r rune, size int, short bool) {
n := len(s)
if n < 1 {
return RuneError, 0, true
@@ -118,7 +121,7 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
// 1-byte, 7-bit sequence?
if c0 < tx {
- return int(c0), 1, false
+ return rune(c0), 1, false
}
// unexpected continuation byte?
@@ -137,11 +140,11 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
// 2-byte, 11-bit sequence?
if c0 < t3 {
- rune = int(c0&mask2)<<6 | int(c1&maskx)
- if rune <= rune1Max {
+ r = rune(c0&mask2)<<6 | rune(c1&maskx)
+ if r <= rune1Max {
return RuneError, 1, false
}
- return rune, 2, false
+ return r, 2, false
}
// need second continuation byte
@@ -155,11 +158,11 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
// 3-byte, 16-bit sequence?
if c0 < t4 {
- rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
- if rune <= rune2Max {
+ r = rune(c0&mask3)<<12 | rune(c1&maskx)<<6 | rune(c2&maskx)
+ if r <= rune2Max {
return RuneError, 1, false
}
- return rune, 3, false
+ return r, 3, false
}
// need third continuation byte
@@ -173,11 +176,11 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
// 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 {
+ r = rune(c0&mask4)<<18 | rune(c1&maskx)<<12 | rune(c2&maskx)<<6 | rune(c3&maskx)
+ if r <= rune3Max {
return RuneError, 1, false
}
- return rune, 4, false
+ return r, 4, false
}
// error
@@ -198,28 +201,30 @@ func FullRuneInString(s string) bool {
}
// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
-func DecodeRune(p []byte) (rune, size int) {
- rune, size, _ = decodeRuneInternal(p)
+// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+func DecodeRune(p []byte) (r rune, size int) {
+ r, size, _ = decodeRuneInternal(p)
return
}
// DecodeRuneInString is like DecodeRune but its input is a string.
-func DecodeRuneInString(s string) (rune, size int) {
- rune, size, _ = decodeRuneInStringInternal(s)
+// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+func DecodeRuneInString(s string) (r rune, size int) {
+ r, size, _ = decodeRuneInStringInternal(s)
return
}
-// DecodeLastRune unpacks the last UTF-8 encoding in p
-// and returns the rune and its width in bytes.
-func DecodeLastRune(p []byte) (rune, size int) {
+// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and its width in bytes.
+// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+func DecodeLastRune(p []byte) (r rune, size int) {
end := len(p)
if end == 0 {
return RuneError, 0
}
start := end - 1
- rune = int(p[start])
- if rune < RuneSelf {
- return rune, 1
+ r = rune(p[start])
+ if r < RuneSelf {
+ return r, 1
}
// guard against O(n^2) behavior when traversing
// backwards through strings with long sequences of
@@ -236,23 +241,24 @@ func DecodeLastRune(p []byte) (rune, size int) {
if start < 0 {
start = 0
}
- rune, size = DecodeRune(p[start:end])
+ r, size = DecodeRune(p[start:end])
if start+size != end {
return RuneError, 1
}
- return rune, size
+ return r, size
}
// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
-func DecodeLastRuneInString(s string) (rune, size int) {
+// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8.
+func DecodeLastRuneInString(s string) (r rune, size int) {
end := len(s)
if end == 0 {
return RuneError, 0
}
start := end - 1
- rune = int(s[start])
- if rune < RuneSelf {
- return rune, 1
+ r = rune(s[start])
+ if r < RuneSelf {
+ return r, 1
}
// guard against O(n^2) behavior when traversing
// backwards through strings with long sequences of
@@ -269,23 +275,23 @@ func DecodeLastRuneInString(s string) (rune, size int) {
if start < 0 {
start = 0
}
- rune, size = DecodeRuneInString(s[start:end])
+ r, size = DecodeRuneInString(s[start:end])
if start+size != end {
return RuneError, 1
}
- return rune, size
+ return r, size
}
// RuneLen returns the number of bytes required to encode the rune.
-func RuneLen(rune int) int {
+func RuneLen(r rune) int {
switch {
- case rune <= rune1Max:
+ case r <= rune1Max:
return 1
- case rune <= rune2Max:
+ case r <= rune2Max:
return 2
- case rune <= rune3Max:
+ case r <= rune3Max:
return 3
- case rune <= rune4Max:
+ case r <= rune4Max:
return 4
}
return -1
@@ -293,26 +299,24 @@ func RuneLen(rune int) int {
// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
-func EncodeRune(p []byte, rune int) int {
+func EncodeRune(p []byte, r rune) int {
// Negative values are erroneous. Making it unsigned addresses the problem.
- r := uint(rune)
-
- if r <= rune1Max {
+ if uint32(r) <= rune1Max {
p[0] = byte(r)
return 1
}
- if r <= rune2Max {
+ if uint32(r) <= rune2Max {
p[0] = t2 | byte(r>>6)
p[1] = tx | byte(r)&maskx
return 2
}
- if r > unicode.MaxRune {
+ if uint32(r) > MaxRune {
r = RuneError
}
- if r <= rune3Max {
+ if uint32(r) <= rune3Max {
p[0] = t3 | byte(r>>12)
p[1] = tx | byte(r>>6)&maskx
p[2] = tx | byte(r)&maskx
@@ -354,3 +358,40 @@ func RuneCountInString(s string) (n int) {
// an encoded rune. Second and subsequent bytes always have the top
// two bits set to 10.
func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
+
+// Valid reports whether p consists entirely of valid UTF-8-encoded runes.
+func Valid(p []byte) bool {
+ i := 0
+ for i < len(p) {
+ if p[i] < RuneSelf {
+ i++
+ } else {
+ _, size := DecodeRune(p[i:])
+ if size == 1 {
+ // All valid runes of size of 1 (those
+ // below RuneSelf) were handled above.
+ // This must be a RuneError.
+ return false
+ }
+ i += size
+ }
+ }
+ return true
+}
+
+// ValidString reports whether s consists entirely of valid UTF-8-encoded runes.
+func ValidString(s string) bool {
+ for i, r := range s {
+ if r == RuneError {
+ // The RuneError value can be an error
+ // sentinel value (if it's size 1) or the same
+ // value encoded properly. Decode it to see if
+ // it's the 1 byte sentinel value.
+ _, size := DecodeRuneInString(s[i:])
+ if size == 1 {
+ return false
+ }
+ }
+ }
+ return true
+}
diff --git a/src/pkg/utf8/utf8_test.go b/src/pkg/unicode/utf8/utf8_test.go
index 7a1db93e5..4f73c8fb8 100644
--- a/src/pkg/utf8/utf8_test.go
+++ b/src/pkg/unicode/utf8/utf8_test.go
@@ -7,12 +7,33 @@ package utf8_test
import (
"bytes"
"testing"
- . "utf8"
+ "unicode"
+ . "unicode/utf8"
)
+// Validate the constants redefined from unicode.
+func init() {
+ if MaxRune != unicode.MaxRune {
+ panic("utf8.MaxRune is wrong")
+ }
+ if RuneError != unicode.ReplacementChar {
+ panic("utf8.RuneError is wrong")
+ }
+}
+
+// Validate the constants redefined from unicode.
+func TestConstants(t *testing.T) {
+ if MaxRune != unicode.MaxRune {
+ t.Errorf("utf8.MaxRune is wrong: %x should be %x", MaxRune, unicode.MaxRune)
+ }
+ if RuneError != unicode.ReplacementChar {
+ t.Errorf("utf8.RuneError is wrong: %x should be %x", RuneError, unicode.ReplacementChar)
+ }
+}
+
type Utf8Map struct {
- rune int
- str string
+ r rune
+ str string
}
var utf8map = []Utf8Map{
@@ -58,11 +79,11 @@ func TestFullRune(t *testing.T) {
m := utf8map[i]
b := []byte(m.str)
if !FullRune(b) {
- t.Errorf("FullRune(%q) (%U) = false, want true", b, m.rune)
+ t.Errorf("FullRune(%q) (%U) = false, want true", b, m.r)
}
s := m.str
if !FullRuneInString(s) {
- t.Errorf("FullRuneInString(%q) (%U) = false, want true", s, m.rune)
+ t.Errorf("FullRuneInString(%q) (%U) = false, want true", s, m.r)
}
b1 := b[0 : len(b)-1]
if FullRune(b1) {
@@ -80,10 +101,10 @@ func TestEncodeRune(t *testing.T) {
m := utf8map[i]
b := []byte(m.str)
var buf [10]byte
- n := EncodeRune(buf[0:], m.rune)
+ n := EncodeRune(buf[0:], m.r)
b1 := buf[0:n]
if !bytes.Equal(b, b1) {
- t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
+ t.Errorf("EncodeRune(%#04x) = %q want %q", m.r, b1, b)
}
}
}
@@ -92,25 +113,25 @@ func TestDecodeRune(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i]
b := []byte(m.str)
- rune, size := DecodeRune(b)
- if rune != m.rune || size != len(b) {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ r, size := DecodeRune(b)
+ if r != m.r || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, r, size, m.r, len(b))
}
s := m.str
- rune, size = DecodeRuneInString(s)
- if rune != m.rune || size != len(b) {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ r, size = DecodeRuneInString(s)
+ if r != m.r || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, r, size, m.r, len(b))
}
// there's an extra byte that bytes left behind - make sure trailing byte works
- rune, size = DecodeRune(b[0:cap(b)])
- if rune != m.rune || size != len(b) {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, m.rune, len(b))
+ r, size = DecodeRune(b[0:cap(b)])
+ if r != m.r || size != len(b) {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, r, size, m.r, len(b))
}
s = m.str + "\x00"
- rune, size = DecodeRuneInString(s)
- if rune != m.rune || size != len(b) {
- t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, m.rune, len(b))
+ r, size = DecodeRuneInString(s)
+ if r != m.r || size != len(b) {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, r, size, m.r, len(b))
}
// make sure missing bytes fail
@@ -118,14 +139,14 @@ func TestDecodeRune(t *testing.T) {
if wantsize >= len(b) {
wantsize = 0
}
- rune, size = DecodeRune(b[0 : len(b)-1])
- if rune != RuneError || size != wantsize {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize)
+ r, size = DecodeRune(b[0 : len(b)-1])
+ if r != RuneError || size != wantsize {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b[0:len(b)-1], r, size, RuneError, wantsize)
}
s = m.str[0 : len(m.str)-1]
- rune, size = DecodeRuneInString(s)
- if rune != RuneError || size != wantsize {
- t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, wantsize)
+ r, size = DecodeRuneInString(s)
+ if r != RuneError || size != wantsize {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, r, size, RuneError, wantsize)
}
// make sure bad sequences fail
@@ -134,14 +155,14 @@ func TestDecodeRune(t *testing.T) {
} else {
b[len(b)-1] = 0x7F
}
- rune, size = DecodeRune(b)
- if rune != RuneError || size != 1 {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, rune, size, RuneError, 1)
+ r, size = DecodeRune(b)
+ if r != RuneError || size != 1 {
+ t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, r, size, RuneError, 1)
}
s = string(b)
- rune, size = DecodeRune(b)
- if rune != RuneError || size != 1 {
- t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
+ r, size = DecodeRune(b)
+ if r != RuneError || size != 1 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, r, size, RuneError, 1)
}
}
@@ -164,7 +185,7 @@ func TestSequencing(t *testing.T) {
// it's good to verify
func TestIntConversion(t *testing.T) {
for _, ts := range testStrings {
- runes := []int(ts)
+ runes := []rune(ts)
if RuneCountInString(ts) != len(runes) {
t.Errorf("%q: expected %d runes; got %d", ts, len(runes), RuneCountInString(ts))
break
@@ -182,7 +203,7 @@ func TestIntConversion(t *testing.T) {
func testSequence(t *testing.T, s string) {
type info struct {
index int
- rune int
+ r rune
}
index := make([]info, len(s))
b := []byte(s)
@@ -195,14 +216,14 @@ func testSequence(t *testing.T, s string) {
}
index[j] = info{i, r}
j++
- rune1, size1 := DecodeRune(b[i:])
- if r != rune1 {
- t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], rune1, r)
+ r1, size1 := DecodeRune(b[i:])
+ if r != r1 {
+ t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], r1, r)
return
}
- rune2, size2 := DecodeRuneInString(s[i:])
- if r != rune2 {
- t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], rune2, r)
+ r2, size2 := DecodeRuneInString(s[i:])
+ if r != r2 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], r2, r)
return
}
if size1 != size2 {
@@ -213,18 +234,18 @@ func testSequence(t *testing.T, s string) {
}
j--
for si = len(s); si > 0; {
- rune1, size1 := DecodeLastRune(b[0:si])
- rune2, size2 := DecodeLastRuneInString(s[0:si])
+ r1, size1 := DecodeLastRune(b[0:si])
+ r2, size2 := DecodeLastRuneInString(s[0:si])
if size1 != size2 {
t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
return
}
- if rune1 != index[j].rune {
- t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, rune1, index[j].rune)
+ if r1 != index[j].r {
+ t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, r1, index[j].r)
return
}
- if rune2 != index[j].rune {
- t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, rune2, index[j].rune)
+ if r2 != index[j].r {
+ t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, r2, index[j].r)
return
}
si -= size1
@@ -274,6 +295,35 @@ func TestRuneCount(t *testing.T) {
}
}
+type ValidTest struct {
+ in string
+ out bool
+}
+
+var validTests = []ValidTest{
+ {"", true},
+ {"a", true},
+ {"abc", true},
+ {"Ж", true},
+ {"ЖЖ", true},
+ {"брэд-ЛГТМ", true},
+ {"☺☻☹", true},
+ {string([]byte{66, 250}), false},
+ {string([]byte{66, 250, 67}), false},
+ {"a\uFFFDb", true},
+}
+
+func TestValid(t *testing.T) {
+ for i, tt := range validTests {
+ if Valid([]byte(tt.in)) != tt.out {
+ t.Errorf("%d. Valid(%q) = %v; want %v", i, tt.in, !tt.out, tt.out)
+ }
+ if ValidString(tt.in) != tt.out {
+ t.Errorf("%d. ValidString(%q) = %v; want %v", i, tt.in, !tt.out, tt.out)
+ }
+ }
+}
+
func BenchmarkRuneCountTenASCIIChars(b *testing.B) {
for i := 0; i < b.N; i++ {
RuneCountInString("0123456789")
diff --git a/src/pkg/unsafe/unsafe.go b/src/pkg/unsafe/unsafe.go
index a1257066e..024969b42 100644
--- a/src/pkg/unsafe/unsafe.go
+++ b/src/pkg/unsafe/unsafe.go
@@ -24,38 +24,14 @@ type Pointer *ArbitraryType
// Sizeof returns the size in bytes occupied by the value v. The size is that of the
// "top level" of the value only. For instance, if v is a slice, it returns the size of
// the slice descriptor, not the size of the memory referenced by the slice.
-func Sizeof(v ArbitraryType) int
+func Sizeof(v ArbitraryType) uintptr
// Offsetof returns the offset within the struct of the field represented by v,
-// which must be of the form struct_value.field. In other words, it returns the
+// which must be of the form structValue.field. In other words, it returns the
// number of bytes between the start of the struct and the start of the field.
-func Offsetof(v ArbitraryType) int
+func Offsetof(v ArbitraryType) uintptr
// Alignof returns the alignment of the value v. It is the maximum value m such
// that the address of a variable with the type of v will always always be zero mod m.
-// If v is of the form obj.f, it returns the alignment of field f within struct object obj.
-func Alignof(v ArbitraryType) int
-
-// Typeof returns the type of an interface value, a runtime.Type.
-func Typeof(i interface{}) (typ interface{})
-
-// Reflect unpacks an interface value into its type and the address of a copy of the
-// internal value.
-func Reflect(i interface{}) (typ interface{}, addr Pointer)
-
-// Unreflect inverts Reflect: Given a type and a pointer to a value, it returns an
-// empty interface value with contents the type and the value (not the pointer to
-// the value). The typ is assumed to contain a pointer to a runtime type; the type
-// information in the interface{} is ignored, so that, for example, both
-// *reflect.structType and *runtime.StructType can be passed for typ.
-func Unreflect(typ interface{}, addr Pointer) (ret interface{})
-
-// New allocates and returns a pointer to memory for a new value of the given type.
-// The typ is assumed to hold a pointer to a runtime type.
-// Callers should use reflect.MakeZero instead of invoking unsafe.New directly.
-func New(typ interface{}) Pointer
-
-// NewArray allocates and returns a pointer to an array of n elements of the given type.
-// The typ is assumed to hold a pointer to a runtime type.
-// Callers should use reflect.MakeSlice instead of invoking unsafe.NewArray directly.
-func NewArray(typ interface{}, n int) Pointer
+// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
+func Alignof(v ArbitraryType) uintptr
diff --git a/src/pkg/url/Makefile b/src/pkg/url/Makefile
deleted file mode 100644
index b9267bd08..000000000
--- a/src/pkg/url/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=url
-GOFILES=\
- url.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/utf16/Makefile b/src/pkg/utf16/Makefile
deleted file mode 100644
index 8a564fb0f..000000000
--- a/src/pkg/utf16/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-include ../../Make.inc
-
-TARG=utf16
-GOFILES=\
- utf16.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/utf8/Makefile b/src/pkg/utf8/Makefile
deleted file mode 100644
index b3574ba3b..000000000
--- a/src/pkg/utf8/Makefile
+++ /dev/null
@@ -1,12 +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.
-
-include ../../Make.inc
-
-TARG=utf8
-GOFILES=\
- string.go\
- utf8.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/utf8/string.go b/src/pkg/utf8/string.go
deleted file mode 100644
index 83b56b944..000000000
--- a/src/pkg/utf8/string.go
+++ /dev/null
@@ -1,211 +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 utf8
-
-// String wraps a regular string with a small structure that provides more
-// efficient indexing by code point index, as opposed to byte index.
-// Scanning incrementally forwards or backwards is O(1) per index operation
-// (although not as fast a range clause going forwards). Random access is
-// O(N) in the length of the string, but the overhead is less than always
-// scanning from the beginning.
-// If the string is ASCII, random access is O(1).
-// Unlike the built-in string type, String has internal mutable state and
-// is not thread-safe.
-type String struct {
- str string
- numRunes int
- // If width > 0, the rune at runePos starts at bytePos and has the specified width.
- width int
- bytePos int
- runePos int
- nonASCII int // byte index of the first non-ASCII rune.
-}
-
-// NewString returns a new UTF-8 string with the provided contents.
-func NewString(contents string) *String {
- return new(String).Init(contents)
-}
-
-// Init initializes an existing String to hold the provided contents.
-// It returns a pointer to the initialized String.
-func (s *String) Init(contents string) *String {
- s.str = contents
- s.bytePos = 0
- s.runePos = 0
- for i := 0; i < len(contents); i++ {
- if contents[i] >= RuneSelf {
- // Not ASCII.
- s.numRunes = RuneCountInString(contents)
- _, s.width = DecodeRuneInString(contents)
- s.nonASCII = i
- return s
- }
- }
- // ASCII is simple. Also, the empty string is ASCII.
- s.numRunes = len(contents)
- s.width = 0
- s.nonASCII = len(contents)
- return s
-}
-
-// String returns the contents of the String. This method also means the
-// String is directly printable by fmt.Print.
-func (s *String) String() string {
- return s.str
-}
-
-// RuneCount returns the number of runes (Unicode code points) in the String.
-func (s *String) RuneCount() int {
- return s.numRunes
-}
-
-// IsASCII returns a boolean indicating whether the String contains only ASCII bytes.
-func (s *String) IsASCII() bool {
- return s.width == 0
-}
-
-// Slice returns the string sliced at rune positions [i:j].
-func (s *String) Slice(i, j int) string {
- // ASCII is easy. Let the compiler catch the indexing error if there is one.
- if j < s.nonASCII {
- return s.str[i:j]
- }
- if i < 0 || j > s.numRunes || i > j {
- panic(sliceOutOfRange)
- }
- if i == j {
- return ""
- }
- // For non-ASCII, after At(i), bytePos is always the position of the indexed character.
- var low, high int
- switch {
- case i < s.nonASCII:
- low = i
- case i == s.numRunes:
- low = len(s.str)
- default:
- s.At(i)
- low = s.bytePos
- }
- switch {
- case j == s.numRunes:
- high = len(s.str)
- default:
- s.At(j)
- high = s.bytePos
- }
- return s.str[low:high]
-}
-
-// At returns the rune with index i in the String. The sequence of runes is the same
-// as iterating over the contents with a "for range" clause.
-func (s *String) At(i int) int {
- // ASCII is easy. Let the compiler catch the indexing error if there is one.
- if i < s.nonASCII {
- return int(s.str[i])
- }
-
- // Now we do need to know the index is valid.
- if i < 0 || i >= s.numRunes {
- panic(outOfRange)
- }
-
- var rune int
-
- // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end.
- // With these cases, all scans from beginning or end work in O(1) time per rune.
- switch {
-
- case i == s.runePos-1: // backing up one rune
- rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
- s.runePos = i
- s.bytePos -= s.width
- return rune
- case i == s.runePos+1: // moving ahead one rune
- s.runePos = i
- s.bytePos += s.width
- fallthrough
- case i == s.runePos:
- rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
- return rune
- case i == 0: // start of string
- rune, s.width = DecodeRuneInString(s.str)
- s.runePos = 0
- s.bytePos = 0
- return rune
-
- case i == s.numRunes-1: // last rune in string
- rune, s.width = DecodeLastRuneInString(s.str)
- s.runePos = i
- s.bytePos = len(s.str) - s.width
- return rune
- }
-
- // We need to do a linear scan. There are three places to start from:
- // 1) The beginning
- // 2) bytePos/runePos.
- // 3) The end
- // Choose the closest in rune count, scanning backwards if necessary.
- forward := true
- if i < s.runePos {
- // Between beginning and pos. Which is closer?
- // Since both i and runePos are guaranteed >= nonASCII, that's the
- // lowest location we need to start from.
- if i < (s.runePos-s.nonASCII)/2 {
- // Scan forward from beginning
- s.bytePos, s.runePos = s.nonASCII, s.nonASCII
- } else {
- // Scan backwards from where we are
- forward = false
- }
- } else {
- // Between pos and end. Which is closer?
- if i-s.runePos < (s.numRunes-s.runePos)/2 {
- // Scan forward from pos
- } else {
- // Scan backwards from end
- s.bytePos, s.runePos = len(s.str), s.numRunes
- forward = false
- }
- }
- if forward {
- // TODO: Is it much faster to use a range loop for this scan?
- for {
- rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
- if s.runePos == i {
- break
- }
- s.runePos++
- s.bytePos += s.width
- }
- } else {
- for {
- rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
- s.runePos--
- s.bytePos -= s.width
- if s.runePos == i {
- break
- }
- }
- }
- return rune
-}
-
-// We want the panic in At(i) to satisfy os.Error, because that's what
-// runtime panics satisfy, but we can't import os. This is our solution.
-
-// error is the type of the error returned if a user calls String.At(i) with i out of range.
-// It satisfies os.Error and runtime.Error.
-type error string
-
-func (err error) String() string {
- return string(err)
-}
-
-func (err error) RunTimeError() {
-}
-
-var outOfRange = error("utf8.String: index out of range")
-var sliceOutOfRange = error("utf8.String: slice index out of range")
diff --git a/src/pkg/utf8/string_test.go b/src/pkg/utf8/string_test.go
deleted file mode 100644
index f376b628c..000000000
--- a/src/pkg/utf8/string_test.go
+++ /dev/null
@@ -1,114 +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 utf8_test
-
-import (
- "rand"
- "testing"
- . "utf8"
-)
-
-func TestScanForwards(t *testing.T) {
- for _, s := range testStrings {
- runes := []int(s)
- str := NewString(s)
- if str.RuneCount() != len(runes) {
- t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
- break
- }
- for i, expect := range runes {
- got := str.At(i)
- if got != expect {
- t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
- }
- }
- }
-}
-
-func TestScanBackwards(t *testing.T) {
- for _, s := range testStrings {
- runes := []int(s)
- str := NewString(s)
- if str.RuneCount() != len(runes) {
- t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
- break
- }
- for i := len(runes) - 1; i >= 0; i-- {
- expect := runes[i]
- got := str.At(i)
- if got != expect {
- t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
- }
- }
- }
-}
-
-func randCount() int {
- if testing.Short() {
- return 100
- }
- return 100000
-}
-
-func TestRandomAccess(t *testing.T) {
- for _, s := range testStrings {
- if len(s) == 0 {
- continue
- }
- runes := []int(s)
- str := NewString(s)
- if str.RuneCount() != len(runes) {
- t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
- break
- }
- for j := 0; j < randCount(); j++ {
- i := rand.Intn(len(runes))
- expect := runes[i]
- got := str.At(i)
- if got != expect {
- t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
- }
- }
- }
-}
-
-func TestRandomSliceAccess(t *testing.T) {
- for _, s := range testStrings {
- if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
- continue
- }
- runes := []int(s)
- str := NewString(s)
- if str.RuneCount() != len(runes) {
- t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
- break
- }
- for k := 0; k < randCount(); k++ {
- i := rand.Intn(len(runes))
- j := rand.Intn(len(runes) + 1)
- if i > j { // include empty strings
- continue
- }
- expect := string(runes[i:j])
- got := str.Slice(i, j)
- if got != expect {
- t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
- }
- }
- }
-}
-
-func TestLimitSliceAccess(t *testing.T) {
- for _, s := range testStrings {
- str := NewString(s)
- if str.Slice(0, 0) != "" {
- t.Error("failure with empty slice at beginning")
- }
- nr := RuneCountInString(s)
- if str.Slice(nr, nr) != "" {
- t.Error("failure with empty slice at end")
- }
- }
-}
diff --git a/src/pkg/websocket/Makefile b/src/pkg/websocket/Makefile
deleted file mode 100644
index 6d3c9cbd1..000000000
--- a/src/pkg/websocket/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include ../../Make.inc
-
-TARG=websocket
-GOFILES=\
- client.go\
- server.go\
- websocket.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
deleted file mode 100644
index 74bede424..000000000
--- a/src/pkg/websocket/client.go
+++ /dev/null
@@ -1,323 +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 websocket
-
-import (
- "bufio"
- "bytes"
- "crypto/tls"
- "fmt"
- "http"
- "io"
- "net"
- "os"
- "rand"
- "strings"
- "url"
-)
-
-type ProtocolError struct {
- ErrorString string
-}
-
-func (err *ProtocolError) String() string { return string(err.ErrorString) }
-
-var (
- 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 challenge/response"}
- secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
-)
-
-type DialError struct {
- URL string
- Protocol string
- Origin string
- Error os.Error
-}
-
-func (e *DialError) String() string {
- return "websocket.Dial " + e.URL + ": " + e.Error.String()
-}
-
-func init() {
- i := 0
- for ch := byte(0x21); ch < 0x30; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
- for ch := byte(0x3a); ch < 0x7F; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
-}
-
-type handshaker func(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) os.Error
-
-// newClient creates a new Web Socket client connection.
-func newClient(resourceName, host, origin, location, protocol string, rwc io.ReadWriteCloser, handshake handshaker) (ws *Conn, err os.Error) {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- err = handshake(resourceName, host, origin, location, protocol, br, bw)
- if err != nil {
- return
- }
- buf := bufio.NewReadWriter(br, bw)
- ws = newConn(origin, location, protocol, buf, rwc)
- return
-}
-
-/*
-Dial opens a new client connection to a Web Socket.
-
-A trivial example client:
-
- package main
-
- import (
- "websocket"
- "strings"
- )
-
- func main() {
- ws, err := websocket.Dial("ws://localhost/ws", "", "http://localhost/");
- if err != nil {
- panic("Dial: " + err.String())
- }
- if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
- panic("Write: " + err.String())
- }
- var msg = make([]byte, 512);
- if n, err := ws.Read(msg); err != nil {
- panic("Read: " + err.String())
- }
- // use msg[0:n]
- }
-*/
-func Dial(url_, protocol, origin string) (ws *Conn, err os.Error) {
- var client net.Conn
-
- parsedUrl, err := url.Parse(url_)
- if err != nil {
- goto Error
- }
-
- switch parsedUrl.Scheme {
- case "ws":
- client, err = net.Dial("tcp", parsedUrl.Host)
-
- case "wss":
- client, err = tls.Dial("tcp", parsedUrl.Host, nil)
-
- default:
- err = ErrBadScheme
- }
- if err != nil {
- goto Error
- }
-
- ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url_, protocol, client, handshake)
- if err != nil {
- goto Error
- }
- return
-
-Error:
- return nil, &DialError{url_, protocol, origin, err}
-}
-
-/*
-Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
-cf. http://www.whatwg.org/specs/web-socket-protocol/
-*/
-func generateKeyNumber() (key string, number uint32) {
- // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
- spaces := rand.Intn(12) + 1
-
- // 17. Let /max_n/ be the largest integer not greater than
- // 4,294,967,295 divided by /spaces_n/
- max := int(4294967295 / uint32(spaces))
-
- // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
- number = uint32(rand.Intn(max + 1))
-
- // 19. Let /product_n/ be the result of multiplying /number_n/ and
- // /spaces_n/ together.
- product := number * uint32(spaces)
-
- // 20. Let /key_n/ be a string consisting of /product_n/, expressed
- // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
- // to U+0039 DIGIT NINE (9).
- key = fmt.Sprintf("%d", product)
-
- // 21. Insert between one and twelve random characters from the ranges
- // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
- // positions.
- n := rand.Intn(12) + 1
- for i := 0; i < n; i++ {
- pos := rand.Intn(len(key)) + 1
- ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
- key = key[0:pos] + string(ch) + key[pos:]
- }
-
- // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
- // positions other than the start or end of the string.
- for i := 0; i < spaces; i++ {
- pos := rand.Intn(len(key)-1) + 1
- key = key[0:pos] + " " + key[pos:]
- }
-
- return
-}
-
-/*
-Generates handshake key_3 as described in 4.1 Opening handshake step 26.
-cf. http://www.whatwg.org/specs/web-socket-protocol/
-*/
-func generateKey3() (key []byte) {
- // 26. Let /key3/ be a string consisting of eight random bytes (or
- // equivalently, a random 64 bit integer encoded in big-endian order).
- key = make([]byte, 8)
- for i := 0; i < 8; i++ {
- key[i] = byte(rand.Intn(256))
- }
- return
-}
-
-/*
-Web Socket protocol handshake based on
-http://www.whatwg.org/specs/web-socket-protocol/
-(draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
-*/
-func handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
- // 4.1. Opening handshake.
- // Step 5. send a request line.
- bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
-
- // Step 6-14. push request headers in fields.
- var fields []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 = 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 = 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++ {
- j := rand.Intn(i)
- fields[i], fields[j] = fields[j], fields[i]
- }
- for i := 0; i < len(fields); i++ {
- bw.WriteString(fields[i])
- }
- // Step 25. send CRLF.
- bw.WriteString("\r\n")
-
- // Step 26. generate 8 bytes random key.
- key3 := generateKey3()
- // Step 27. send it out.
- bw.Write(key3)
- if err = bw.Flush(); err != nil {
- return
- }
-
- // Step 28-29, 32-40. read response from server.
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return err
- }
- // Step 30. check response code is 101.
- if resp.StatusCode != 101 {
- return ErrBadStatus
- }
-
- // Step 41. check websocket headers.
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
- return ErrBadUpgrade
- }
-
- if resp.Header.Get("Sec-Websocket-Origin") != origin {
- return ErrBadWebSocketOrigin
- }
-
- if resp.Header.Get("Sec-Websocket-Location") != location {
- return ErrBadWebSocketLocation
- }
-
- if protocol != "" && resp.Header.Get("Sec-Websocket-Protocol") != protocol {
- return ErrBadWebSocketProtocol
- }
-
- // Step 42-43. get expected data from challenge data.
- expected, err := getChallengeResponse(number1, number2, key3)
- if err != nil {
- return err
- }
-
- // Step 44. read 16 bytes from server.
- reply := make([]byte, 16)
- if _, err = io.ReadFull(br, reply); err != nil {
- return err
- }
-
- // Step 45. check the reply equals to expected data.
- if !bytes.Equal(expected, reply) {
- return ErrChallengeResponse
- }
- // WebSocket connection is established.
- return
-}
-
-/*
-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) {
- bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
- bw.WriteString("Upgrade: WebSocket\r\n")
- bw.WriteString("Connection: Upgrade\r\n")
- bw.WriteString("Host: " + host + "\r\n")
- bw.WriteString("Origin: " + origin + "\r\n")
- if protocol != "" {
- bw.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
- }
- bw.WriteString("\r\n")
- bw.Flush()
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return
- }
- if resp.Status != "101 Web Socket Protocol Handshake" {
- return ErrBadStatus
- }
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- resp.Header.Get("Connection") != "Upgrade" {
- return ErrBadUpgrade
- }
- if resp.Header.Get("Websocket-Origin") != origin {
- return ErrBadWebSocketOrigin
- }
- if resp.Header.Get("Websocket-Location") != location {
- return ErrBadWebSocketLocation
- }
- if protocol != "" && resp.Header.Get("Websocket-Protocol") != protocol {
- return ErrBadWebSocketProtocol
- }
- return
-}
diff --git a/src/pkg/websocket/server.go b/src/pkg/websocket/server.go
deleted file mode 100644
index e0e7c872d..000000000
--- a/src/pkg/websocket/server.go
+++ /dev/null
@@ -1,219 +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 websocket
-
-import (
- "http"
- "io"
- "strings"
-)
-
-/*
-Handler is an interface to a WebSocket.
-
-A trivial example server:
-
- package main
-
- import (
- "http"
- "io"
- "websocket"
- )
-
- // Echo the data received on the Web Socket.
- func EchoServer(ws *websocket.Conn) {
- io.Copy(ws, ws);
- }
-
- func main() {
- http.Handle("/echo", websocket.Handler(EchoServer));
- err := http.ListenAndServe(":12345", nil);
- if err != nil {
- panic("ListenAndServe: " + err.String())
- }
- }
-*/
-type Handler func(*Conn)
-
-/*
-Gets key number from Sec-WebSocket-Key<n>: field as described
-in 5.2 Sending the server's opening handshake, 4.
-*/
-func getKeyNumber(s string) (r uint32) {
- // 4. Let /key-number_n/ be the digits (characters in the range
- // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
- // interpreted as a base ten integer, ignoring all other characters
- // in /key_n/.
- r = 0
- for i := 0; i < len(s); i++ {
- if s[i] >= '0' && s[i] <= '9' {
- r = r*10 + uint32(s[i]) - '0'
- }
- }
- return
-}
-
-// ServeHTTP implements the http.Handler interface for a Web Socket
-func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.String())
- return
- }
- // The server should abort the WebSocket connection if it finds
- // the client did not send a handshake that matches with protocol
- // specification.
- defer rwc.Close()
-
- if req.Method != "GET" {
- return
- }
- // HTTP version can be safely ignored.
-
- if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
- strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
- return
- }
-
- // TODO(ukai): check Host
- origin := req.Header.Get("Origin")
- if origin == "" {
- return
- }
-
- key1 := req.Header.Get("Sec-Websocket-Key1")
- if key1 == "" {
- return
- }
- key2 := req.Header.Get("Sec-Websocket-Key2")
- if key2 == "" {
- return
- }
- key3 := make([]byte, 8)
- if _, err := io.ReadFull(buf, key3); err != nil {
- return
- }
-
- var location string
- if req.TLS != nil {
- location = "wss://" + req.Host + req.URL.RawPath
- } else {
- location = "ws://" + req.Host + req.URL.RawPath
- }
-
- // Step 4. get key number in Sec-WebSocket-Key<n> fields.
- keyNumber1 := getKeyNumber(key1)
- keyNumber2 := getKeyNumber(key2)
-
- // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
- space1 := uint32(strings.Count(key1, " "))
- space2 := uint32(strings.Count(key2, " "))
- if space1 == 0 || space2 == 0 {
- return
- }
-
- // Step 6. key number must be an integral multiple of spaces.
- if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
- return
- }
-
- // Step 7. let part be key number divided by spaces.
- part1 := keyNumber1 / space1
- part2 := keyNumber2 / space2
-
- // Step 8. let challenge be concatenation of part1, part2 and key3.
- // Step 9. get MD5 fingerprint of challenge.
- response, err := getChallengeResponse(part1, part2, key3)
- if err != nil {
- return
- }
-
- // Step 10. send response status line.
- buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
- // Step 11. send response headers.
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
- buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
- protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
- if protocol != "" {
- buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
- }
- // Step 12. send CRLF.
- buf.WriteString("\r\n")
- // Step 13. send response data.
- buf.Write(response)
- if err := buf.Flush(); err != nil {
- return
- }
- ws := newConn(origin, location, protocol, buf, rwc)
- ws.Request = req
- f(ws)
-}
-
-/*
-Draft75Handler is an interface to a WebSocket based on the
-(soon obsolete) draft-hixie-thewebsocketprotocol-75.
-*/
-type Draft75Handler func(*Conn)
-
-// ServeHTTP implements the http.Handler interface for a Web Socket.
-func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- if req.Method != "GET" || req.Proto != "HTTP/1.1" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "Unexpected request")
- return
- }
- if req.Header.Get("Upgrade") != "WebSocket" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Upgrade: WebSocket header")
- return
- }
- if req.Header.Get("Connection") != "Upgrade" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Connection: Upgrade header")
- return
- }
- origin := strings.TrimSpace(req.Header.Get("Origin"))
- if origin == "" {
- w.WriteHeader(http.StatusBadRequest)
- io.WriteString(w, "missing Origin header")
- return
- }
-
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.String())
- return
- }
- defer rwc.Close()
-
- var location string
- if req.TLS != nil {
- location = "wss://" + req.Host + req.URL.RawPath
- } else {
- location = "ws://" + req.Host + req.URL.RawPath
- }
-
- // TODO(ukai): verify origin,location,protocol.
-
- buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("WebSocket-Origin: " + origin + "\r\n")
- buf.WriteString("WebSocket-Location: " + location + "\r\n")
- protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
- // canonical header key of WebSocket-Protocol.
- if protocol != "" {
- buf.WriteString("WebSocket-Protocol: " + protocol + "\r\n")
- }
- buf.WriteString("\r\n")
- if err := buf.Flush(); err != nil {
- return
- }
- ws := newConn(origin, location, protocol, buf, rwc)
- f(ws)
-}
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go
deleted file mode 100644
index 7447cf852..000000000
--- a/src/pkg/websocket/websocket.go
+++ /dev/null
@@ -1,192 +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 websocket implements a client and server for the Web Socket protocol.
-// The protocol is defined at http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
-package websocket
-
-// TODO(ukai):
-// better logging.
-
-import (
- "bufio"
- "crypto/md5"
- "encoding/binary"
- "http"
- "io"
- "net"
- "os"
-)
-
-// WebSocketAddr is an implementation of net.Addr for Web Sockets.
-type WebSocketAddr string
-
-// Network returns the network type for a Web Socket, "websocket".
-func (addr WebSocketAddr) Network() string { return "websocket" }
-
-// String returns the network address for a Web Socket.
-func (addr WebSocketAddr) String() string { return string(addr) }
-
-const (
- stateFrameByte = iota
- stateFrameLength
- stateFrameData
- stateFrameTextData
-)
-
-// Conn is a channel to communicate to a Web Socket.
-// It implements the net.Conn interface.
-type Conn struct {
- // The origin URI for the Web Socket.
- Origin string
- // The location URI for the Web Socket.
- Location string
- // The subprotocol for the Web Socket.
- Protocol string
- // The initial http Request (for the Server side only).
- Request *http.Request
-
- buf *bufio.ReadWriter
- rwc io.ReadWriteCloser
-
- // It holds text data in previous Read() that failed with small buffer.
- data []byte
- reading bool
-}
-
-// newConn creates a new Web Socket.
-func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
- if buf == nil {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- buf = bufio.NewReadWriter(br, bw)
- }
- ws := &Conn{Origin: origin, Location: location, Protocol: protocol, buf: buf, rwc: rwc}
- return ws
-}
-
-// Read implements the io.Reader interface for a Conn.
-func (ws *Conn) Read(msg []byte) (n int, err os.Error) {
-Frame:
- for !ws.reading && len(ws.data) == 0 {
- // Beginning of frame, possibly.
- b, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- if b&0x80 == 0x80 {
- // Skip length frame.
- length := 0
- for {
- c, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- length = length*128 + int(c&0x7f)
- if c&0x80 == 0 {
- break
- }
- }
- for length > 0 {
- _, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- }
- continue Frame
- }
- // In text mode
- if b != 0 {
- // Skip this frame
- for {
- c, err := ws.buf.ReadByte()
- if err != nil {
- return 0, err
- }
- if c == '\xff' {
- break
- }
- }
- continue Frame
- }
- ws.reading = true
- }
- if len(ws.data) == 0 {
- ws.data, err = ws.buf.ReadSlice('\xff')
- if err == nil {
- ws.reading = false
- ws.data = ws.data[:len(ws.data)-1] // trim \xff
- }
- }
- n = copy(msg, ws.data)
- ws.data = ws.data[n:]
- return n, err
-}
-
-// Write implements the io.Writer interface for a Conn.
-func (ws *Conn) Write(msg []byte) (n int, err os.Error) {
- ws.buf.WriteByte(0)
- ws.buf.Write(msg)
- ws.buf.WriteByte(0xff)
- err = ws.buf.Flush()
- return len(msg), err
-}
-
-// Close implements the io.Closer interface for a Conn.
-func (ws *Conn) Close() os.Error { return ws.rwc.Close() }
-
-// LocalAddr returns the WebSocket Origin for the connection.
-func (ws *Conn) LocalAddr() net.Addr { return WebSocketAddr(ws.Origin) }
-
-// RemoteAddr returns the WebSocket locations for the connection.
-func (ws *Conn) RemoteAddr() net.Addr { return WebSocketAddr(ws.Location) }
-
-// SetTimeout sets the connection's network timeout in nanoseconds.
-func (ws *Conn) SetTimeout(nsec int64) os.Error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetTimeout(nsec)
- }
- return os.EINVAL
-}
-
-// SetReadTimeout sets the connection's network read timeout in nanoseconds.
-func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetReadTimeout(nsec)
- }
- return os.EINVAL
-}
-
-// 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)
- }
- return os.EINVAL
-}
-
-// getChallengeResponse computes the expected response from the
-// challenge as described in section 5.1 Opening Handshake steps 42 to
-// 43 of http://www.whatwg.org/specs/web-socket-protocol/
-func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err os.Error) {
- // 41. Let /challenge/ be the concatenation of /number_1/, expressed
- // a big-endian 32 bit integer, /number_2/, expressed in a big-
- // endian 32 bit integer, and the eight bytes of /key_3/ in the
- // order they were sent to the wire.
- challenge := make([]byte, 16)
- binary.BigEndian.PutUint32(challenge[0:], number1)
- binary.BigEndian.PutUint32(challenge[4:], number2)
- copy(challenge[8:], key3)
-
- // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
- // endian 128 bit string.
- h := md5.New()
- if _, err = h.Write(challenge); err != nil {
- return
- }
- expected = h.Sum()
- return
-}
-
-var _ net.Conn = (*Conn)(nil) // compile-time check that *Conn implements net.Conn.
diff --git a/src/pkg/websocket/websocket_test.go b/src/pkg/websocket/websocket_test.go
deleted file mode 100644
index 71c3c8514..000000000
--- a/src/pkg/websocket/websocket_test.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 websocket
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "http"
- "http/httptest"
- "io"
- "log"
- "net"
- "sync"
- "testing"
- "url"
-)
-
-var serverAddr string
-var once sync.Once
-
-func echoServer(ws *Conn) { io.Copy(ws, ws) }
-
-func startServer() {
- http.Handle("/echo", Handler(echoServer))
- http.Handle("/echoDraft75", Draft75Handler(echoServer))
- server := httptest.NewServer(nil)
- serverAddr = server.Listener.Addr().String()
- log.Print("Test WebSocket server listening on ", serverAddr)
-}
-
-// Test the getChallengeResponse function with values from section
-// 5.1 of the specification steps 18, 26, and 43 from
-// http://www.whatwg.org/specs/web-socket-protocol/
-func TestChallenge(t *testing.T) {
- var part1 uint32 = 777007543
- var part2 uint32 = 114997259
- key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
- expected := []byte("0st3Rl&q-2ZU^weu")
-
- response, err := getChallengeResponse(part1, part2, key3)
- if err != nil {
- t.Errorf("getChallengeResponse: returned error %v", err)
- return
- }
- if !bytes.Equal(expected, response) {
- t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
- }
-}
-
-func TestEcho(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var actual_msg = make([]byte, 512)
- n, err := ws.Read(actual_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- actual_msg = actual_msg[0:n]
- if !bytes.Equal(msg, actual_msg) {
- t.Errorf("Echo: expected %q got %q", msg, actual_msg)
- }
- ws.Close()
-}
-
-func TestEchoDraft75(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- ws, err := newClient("/echoDraft75", "localhost", "http://localhost",
- "ws://localhost/echoDraft75", "", client, draft75handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: error %v", err)
- }
- var actual_msg = make([]byte, 512)
- n, err := ws.Read(actual_msg)
- if err != nil {
- t.Errorf("Read: error %v", err)
- }
- actual_msg = actual_msg[0:n]
- if !bytes.Equal(msg, actual_msg) {
- t.Errorf("Echo: expected %q got %q", msg, actual_msg)
- }
- ws.Close()
-}
-
-func TestWithQuery(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- ws, err := newClient("/echo?q=v", "localhost", "http://localhost",
- "ws://localhost/echo?q=v", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestWithProtocol(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "test", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestHTTP(t *testing.T) {
- once.Do(startServer)
-
- // If the client did not send a handshake that matches the protocol
- // specification, the server should abort the WebSocket connection.
- _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
- if err == nil {
- t.Error("Get: unexpected success")
- return
- }
- urlerr, ok := err.(*url.Error)
- if !ok {
- t.Errorf("Get: not url.Error %#v", err)
- return
- }
- if urlerr.Error != io.ErrUnexpectedEOF {
- t.Errorf("Get: error %#v", err)
- return
- }
-}
-
-func TestHTTPDraft75(t *testing.T) {
- once.Do(startServer)
-
- r, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
- if err != nil {
- t.Errorf("Get: error %#v", err)
- return
- }
- if r.StatusCode != http.StatusBadRequest {
- t.Errorf("Get: got status %d", r.StatusCode)
- }
-}
-
-func TestTrailingSpaces(t *testing.T) {
- // http://code.google.com/p/go/issues/detail?id=955
- // The last runs of this create keys with trailing spaces that should not be
- // generated by the client.
- once.Do(startServer)
- for i := 0; i < 30; i++ {
- // body
- ws, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "", "http://localhost/")
- if err != nil {
- t.Error("Dial failed:", err.String())
- break
- }
- ws.Close()
- }
-}
-
-func TestSmallBuffer(t *testing.T) {
- // http://code.google.com/p/go/issues/detail?id=1145
- // Read should be able to handle reading a fragment of a frame.
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- ws, err := newClient("/echo", "localhost", "http://localhost",
- "ws://localhost/echo", "", client, handshake)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := ws.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var small_msg = make([]byte, 8)
- n, err := ws.Read(small_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(msg[:len(small_msg)], small_msg) {
- t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
- }
- var second_msg = make([]byte, len(msg))
- n, err = ws.Read(second_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- second_msg = second_msg[0:n]
- if !bytes.Equal(msg[len(small_msg):], second_msg) {
- t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
- }
- ws.Close()
-
-}
-
-func testSkipLengthFrame(t *testing.T) {
- b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:8], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
- }
-}
-
-func testSkipNoUTF8Frame(t *testing.T) {
- b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:8], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
- }
-}
diff --git a/src/pkg/xml/Makefile b/src/pkg/xml/Makefile
deleted file mode 100644
index d66c4988a..000000000
--- a/src/pkg/xml/Makefile
+++ /dev/null
@@ -1,14 +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.
-
-include ../../Make.inc
-
-TARG=xml
-
-GOFILES=\
- marshal.go\
- read.go\
- xml.go\
-
-include ../../Make.pkg
diff --git a/src/pkg/xml/atom_test.go b/src/pkg/xml/atom_test.go
deleted file mode 100644
index d365510bf..000000000
--- a/src/pkg/xml/atom_test.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 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/src/pkg/xml/embed_test.go b/src/pkg/xml/embed_test.go
deleted file mode 100644
index ec7f478be..000000000
--- a/src/pkg/xml/embed_test.go
+++ /dev/null
@@ -1,124 +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 xml
-
-import "testing"
-
-type C struct {
- Name string
- Open bool
-}
-
-type A struct {
- XMLName Name `xml:"http://domain a"`
- C
- B B
- FieldA string
-}
-
-type B struct {
- XMLName Name `xml:"b"`
- C
- FieldB string
-}
-
-const _1a = `
-<?xml version="1.0" encoding="UTF-8"?>
-<a xmlns="http://domain">
- <name>KmlFile</name>
- <open>1</open>
- <b>
- <name>Absolute</name>
- <open>0</open>
- <fieldb>bar</fieldb>
- </b>
- <fielda>foo</fielda>
-</a>
-`
-
-// Tests that embedded structs are marshalled.
-func TestEmbedded1(t *testing.T) {
- var a A
- if e := Unmarshal(StringReader(_1a), &a); e != nil {
- t.Fatalf("Unmarshal: %s", e)
- }
- if a.FieldA != "foo" {
- t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.FieldA)
- }
- if a.Name != "KmlFile" {
- t.Fatalf("Unmarshal: expected 'KmlFile' but found '%s'", a.Name)
- }
- if !a.Open {
- t.Fatal("Unmarshal: expected 'true' but found otherwise")
- }
- if a.B.FieldB != "bar" {
- t.Fatalf("Unmarshal: expected 'bar' but found '%s'", a.B.FieldB)
- }
- if a.B.Name != "Absolute" {
- t.Fatalf("Unmarshal: expected 'Absolute' but found '%s'", a.B.Name)
- }
- if a.B.Open {
- t.Fatal("Unmarshal: expected 'false' but found otherwise")
- }
-}
-
-type A2 struct {
- XMLName Name `xml:"http://domain a"`
- XY string
- Xy string
-}
-
-const _2a = `
-<?xml version="1.0" encoding="UTF-8"?>
-<a xmlns="http://domain">
- <xy>foo</xy>
-</a>
-`
-
-// Tests that conflicting field names get excluded.
-func TestEmbedded2(t *testing.T) {
- var a A2
- if e := Unmarshal(StringReader(_2a), &a); e != nil {
- t.Fatalf("Unmarshal: %s", e)
- }
- if a.XY != "" {
- t.Fatalf("Unmarshal: expected empty string but found '%s'", a.XY)
- }
- if a.Xy != "" {
- t.Fatalf("Unmarshal: expected empty string but found '%s'", a.Xy)
- }
-}
-
-type A3 struct {
- XMLName Name `xml:"http://domain a"`
- xy string
-}
-
-// Tests that private fields are not set.
-func TestEmbedded3(t *testing.T) {
- var a A3
- if e := Unmarshal(StringReader(_2a), &a); e != nil {
- t.Fatalf("Unmarshal: %s", e)
- }
- if a.xy != "" {
- t.Fatalf("Unmarshal: expected empty string but found '%s'", a.xy)
- }
-}
-
-type A4 struct {
- XMLName Name `xml:"http://domain a"`
- Any string
-}
-
-// Tests that private fields are not set.
-func TestEmbedded4(t *testing.T) {
- var a A4
- if e := Unmarshal(StringReader(_2a), &a); e != nil {
- t.Fatalf("Unmarshal: %s", e)
- }
- if a.Any != "foo" {
- t.Fatalf("Unmarshal: expected 'foo' but found '%s'", a.Any)
- }
-}
diff --git a/src/pkg/xml/marshal.go b/src/pkg/xml/marshal.go
deleted file mode 100644
index ea421c1b1..000000000
--- a/src/pkg/xml/marshal.go
+++ /dev/null
@@ -1,228 +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 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/src/pkg/xml/marshal_test.go b/src/pkg/xml/marshal_test.go
deleted file mode 100644
index 5b972fafe..000000000
--- a/src/pkg/xml/marshal_test.go
+++ /dev/null
@@ -1,305 +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 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/src/pkg/xml/read.go b/src/pkg/xml/read.go
deleted file mode 100644
index 786b69f5a..000000000
--- a/src/pkg/xml/read.go
+++ /dev/null
@@ -1,631 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xml
-
-import (
- "bytes"
- "fmt"
- "io"
- "os"
- "reflect"
- "strconv"
- "strings"
- "unicode"
- "utf8"
-)
-
-// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
-// an XML element is an order-dependent collection of anonymous
-// values, while a data structure is an order-independent collection
-// of named values.
-// See package json for a textual representation more suitable
-// to data structures.
-
-// Unmarshal parses an XML element from r and uses the
-// reflect library to fill in an arbitrary struct, slice, or string
-// pointed at by val. Well-formed data that does not fit
-// into val is discarded.
-//
-// For example, given these definitions:
-//
-// type Email struct {
-// Where string `xml:"attr"`
-// Addr string
-// }
-//
-// type Result struct {
-// XMLName xml.Name `xml:"result"`
-// Name string
-// Phone string
-// Email []Email
-// Groups []string `xml:"group>value"`
-// }
-//
-// result := Result{Name: "name", Phone: "phone", Email: nil}
-//
-// unmarshalling the XML input
-//
-// <result>
-// <email where="home">
-// <addr>gre@example.com</addr>
-// </email>
-// <email where='work'>
-// <addr>gre@work.com</addr>
-// </email>
-// <name>Grace R. Emlin</name>
-// <group>
-// <value>Friends</value>
-// <value>Squash</value>
-// </group>
-// <address>123 Main Street</address>
-// </result>
-//
-// via Unmarshal(r, &result) is equivalent to assigning
-//
-// r = Result{xml.Name{"", "result"},
-// "Grace R. Emlin", // name
-// "phone", // no phone given
-// []Email{
-// Email{"home", "gre@example.com"},
-// Email{"work", "gre@work.com"},
-// },
-// []string{"Friends", "Squash"},
-// }
-//
-// Note that the field r.Phone has not been modified and
-// that the XML <address> element was discarded. Also, the field
-// Groups was assigned considering the element path provided in the
-// field tag.
-//
-// Because Unmarshal uses the reflect package, it can only assign
-// to 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.
-// 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
-// in that field. The rest of the rules still apply.
-//
-// * If the struct has a field named XMLName of type xml.Name,
-// Unmarshal records the element name in that field.
-//
-// * If the XMLName field has an associated tag 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
-// struct field of type string with tag "attr", Unmarshal records
-// the attribute value in that field.
-//
-// * If the XML element contains character data, that data is
-// accumulated in the first struct field that has tag "chardata".
-// The struct field may have type []byte or string.
-// If there is no such field, the character data is discarded.
-//
-// * If the XML element contains 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 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 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 field whose tag is neither "attr" nor "chardata",
-// Unmarshal maps the sub-element to that struct field.
-// Otherwise, if the struct has a field named Any, unmarshal
-// maps the sub-element to that struct field.
-//
-// Unmarshal maps an XML element to a string or []byte by saving the
-// concatenation of that element's character data in the string or
-// []byte.
-//
-// Unmarshal maps an 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 or attribute value to a bool by
-// setting it to the boolean value represented by the string.
-//
-// 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.
-//
-// Unmarshal maps an XML element to a pointer by setting the pointer
-// to a freshly allocated value and then mapping the element to that value.
-//
-func Unmarshal(r io.Reader, val interface{}) os.Error {
- v := reflect.ValueOf(val)
- if v.Kind() != reflect.Ptr {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- p := NewParser(r)
- elem := v.Elem()
- err := p.unmarshal(elem, nil)
- if err != nil {
- return err
- }
- return nil
-}
-
-// An UnmarshalError represents an error in the unmarshalling process.
-type UnmarshalError string
-
-func (e UnmarshalError) String() string { return string(e) }
-
-// A TagPathError represents an error in the unmarshalling process
-// caused by the use of field tags with conflicting paths.
-type TagPathError struct {
- Struct reflect.Type
- Field1, Tag1 string
- Field2, Tag2 string
-}
-
-func (e *TagPathError) String() string {
- return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
-}
-
-// The Parser's Unmarshal method is like xml.Unmarshal
-// except that it can be passed a pointer to the initial start element,
-// useful when a client reads some raw XML tokens itself
-// but also defers to Unmarshal for some elements.
-// Passing a nil start element indicates that Unmarshal should
-// read the token stream to find the start element.
-func (p *Parser) Unmarshal(val interface{}, start *StartElement) os.Error {
- v := reflect.ValueOf(val)
- if v.Kind() != reflect.Ptr {
- return os.NewError("non-pointer passed to Unmarshal")
- }
- return p.unmarshal(v.Elem(), start)
-}
-
-// fieldName strips invalid characters from an XML name
-// to create a valid Go struct name. It also converts the
-// name to lower case letters.
-func fieldName(original string) string {
-
- var i int
- //remove leading underscores
- for i = 0; i < len(original) && original[i] == '_'; i++ {
- }
-
- return strings.Map(
- func(x int) int {
- if x == '_' || unicode.IsDigit(x) || unicode.IsLetter(x) {
- return unicode.ToLower(x)
- }
- return -1
- },
- original[i:])
-}
-
-// Unmarshal a single XML element into val.
-func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
- // Find start element if we need it.
- if start == nil {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- if t, ok := tok.(StartElement); ok {
- start = &t
- break
- }
- }
- }
-
- if pv := val; pv.Kind() == reflect.Ptr {
- if pv.IsNil() {
- pv.Set(reflect.New(pv.Type().Elem()))
- }
- val = pv.Elem()
- }
-
- var (
- data []byte
- saveData reflect.Value
- comment []byte
- saveComment reflect.Value
- saveXML reflect.Value
- saveXMLIndex int
- saveXMLData []byte
- sv reflect.Value
- styp reflect.Type
- fieldPaths map[string]pathInfo
- )
-
- switch v := val; v.Kind() {
- default:
- return os.NewError("unknown type " + v.Type().String())
-
- case reflect.Slice:
- typ := v.Type()
- if typ.Elem().Kind() == reflect.Uint8 {
- // []byte
- saveData = v
- break
- }
-
- // Slice of element values.
- // Grow slice.
- n := v.Len()
- if n >= v.Cap() {
- ncap := 2 * n
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(typ, n, ncap)
- reflect.Copy(new, v)
- v.Set(new)
- }
- v.SetLen(n + 1)
-
- // Recur to read element into slice.
- if err := p.unmarshal(v.Index(n), start); err != nil {
- v.SetLen(n)
- return err
- }
- return nil
-
- case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
- saveData = v
-
- case reflect.Struct:
- if _, ok := v.Interface().(Name); ok {
- v.Set(reflect.ValueOf(start.Name))
- break
- }
-
- sv = v
- typ := sv.Type()
- styp = typ
- // Assign name.
- if f, ok := typ.FieldByName("XMLName"); ok {
- // Validate element name.
- if tag := f.Tag.Get("xml"); tag != "" {
- ns := ""
- i := strings.LastIndex(tag, " ")
- if i >= 0 {
- ns, tag = tag[0:i], tag[i+1:]
- }
- if tag != start.Name.Local {
- return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">")
- }
- if ns != "" && ns != start.Name.Space {
- e := "expected element <" + tag + "> in name space " + ns + " but have "
- if start.Name.Space == "" {
- e += "no name space"
- } else {
- e += start.Name.Space
- }
- return UnmarshalError(e)
- }
- }
-
- // Save
- v := sv.FieldByIndex(f.Index)
- if _, ok := v.Interface().(Name); !ok {
- return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
- }
- v.Set(reflect.ValueOf(start.Name))
- }
-
- // Assign attributes.
- // Also, determine whether we need to save character data or comments.
- for i, n := 0, typ.NumField(); i < n; i++ {
- f := typ.Field(i)
- switch f.Tag.Get("xml") {
- case "attr":
- strv := sv.FieldByIndex(f.Index)
- // Look for attribute.
- val := ""
- k := strings.ToLower(f.Name)
- for _, a := range start.Attr {
- if fieldName(a.Name.Local) == k {
- val = a.Value
- break
- }
- }
- copyValue(strv, []byte(val))
-
- case "comment":
- if !saveComment.IsValid() {
- saveComment = sv.FieldByIndex(f.Index)
- }
-
- case "chardata":
- if !saveData.IsValid() {
- saveData = sv.FieldByIndex(f.Index)
- }
-
- case "innerxml":
- if !saveXML.IsValid() {
- saveXML = sv.FieldByIndex(f.Index)
- if p.saved == nil {
- saveXMLIndex = 0
- p.saved = new(bytes.Buffer)
- } else {
- saveXMLIndex = p.savedOffset()
- }
- }
-
- default:
- if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") {
- if fieldPaths == nil {
- fieldPaths = make(map[string]pathInfo)
- }
- path := strings.ToLower(tag)
- if strings.HasPrefix(tag, ">") {
- path = strings.ToLower(f.Name) + path
- }
- if strings.HasSuffix(tag, ">") {
- path = path[:len(path)-1]
- }
- err := addFieldPath(sv, fieldPaths, path, f.Index)
- if err != nil {
- return err
- }
- }
- }
- }
- }
-
- // Find end element.
- // Process sub-elements along the way.
-Loop:
- for {
- var savedOffset int
- if saveXML.IsValid() {
- savedOffset = p.savedOffset()
- }
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- // Sub-element.
- // Look up by tag name.
- if sv.IsValid() {
- k := fieldName(t.Name.Local)
-
- if fieldPaths != nil {
- if _, found := fieldPaths[k]; found {
- if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil {
- return err
- }
- continue Loop
- }
- }
-
- match := func(s string) bool {
- // check if the name matches ignoring case
- if strings.ToLower(s) != k {
- return false
- }
- // now check that it's public
- c, _ := utf8.DecodeRuneInString(s)
- return unicode.IsUpper(c)
- }
-
- f, found := styp.FieldByNameFunc(match)
- if !found { // fall back to mop-up field named "Any"
- f, found = styp.FieldByName("Any")
- }
- if found {
- if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil {
- return err
- }
- continue Loop
- }
- }
- // Not saving sub-element but still have to skip over it.
- if err := p.Skip(); err != nil {
- return err
- }
-
- case EndElement:
- if saveXML.IsValid() {
- saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
- if saveXMLIndex == 0 {
- p.saved = nil
- }
- }
- break Loop
-
- case CharData:
- if saveData.IsValid() {
- data = append(data, t...)
- }
-
- case Comment:
- if saveComment.IsValid() {
- comment = append(comment, t...)
- }
- }
- }
-
- 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(src))
- // TODO: should check sizes
- return err == nil
- }
- var utmp uint64
- getUint64 := func() bool {
- utmp, err = strconv.Atoui64(string(src))
- // TODO: check for overflow?
- return err == nil
- }
- var ftmp float64
- getFloat64 := func() bool {
- ftmp, err = strconv.Atof64(string(src))
- // TODO: check for overflow?
- return err == nil
- }
-
- // Save accumulated data and comments
- switch t := dst; t.Kind() {
- case reflect.Invalid:
- // Probably a comment, handled below
- default:
- 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
- }
- t.SetInt(itmp)
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if !getUint64() {
- return err
- }
- t.SetUint(utmp)
- case reflect.Float32, reflect.Float64:
- if !getFloat64() {
- return err
- }
- t.SetFloat(ftmp)
- case reflect.Bool:
- value, err := strconv.Atob(strings.TrimSpace(string(src)))
- if err != nil {
- return err
- }
- t.SetBool(value)
- case reflect.String:
- t.SetString(string(src))
- case reflect.Slice:
- t.Set(reflect.ValueOf(src))
- }
- return nil
-}
-
-type pathInfo struct {
- fieldIdx []int
- complete bool
-}
-
-// addFieldPath takes an element path such as "a>b>c" and fills the
-// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
-// It is okay for paths to share a common, shorter prefix but not ok
-// for one path to itself be a prefix of another.
-func addFieldPath(sv reflect.Value, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
- if info, found := paths[path]; found {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- paths[path] = pathInfo{fieldIdx, true}
- for {
- i := strings.LastIndex(path, ">")
- if i < 0 {
- break
- }
- path = path[:i]
- if info, found := paths[path]; found {
- if info.complete {
- return tagError(sv, info.fieldIdx, fieldIdx)
- }
- } else {
- paths[path] = pathInfo{fieldIdx, false}
- }
- }
- return nil
-
-}
-
-func tagError(sv reflect.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.Get("xml"), f2.Name, f2.Tag.Get("xml")}
-}
-
-// unmarshalPaths walks down an XML structure looking for
-// wanted paths, and calls unmarshal on them.
-func (p *Parser) unmarshalPaths(sv reflect.Value, paths map[string]pathInfo, path string, start *StartElement) os.Error {
- if info, _ := paths[path]; info.complete {
- return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
- }
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- k := path + ">" + fieldName(t.Name.Local)
- if _, found := paths[k]; found {
- if err := p.unmarshalPaths(sv, paths, k, &t); err != nil {
- return err
- }
- continue
- }
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
-
-// Have already read a start element.
-// Read tokens until we find the end element.
-// Token is taking care of making sure the
-// end element matches the start element we saw.
-func (p *Parser) Skip() os.Error {
- for {
- tok, err := p.Token()
- if err != nil {
- return err
- }
- switch t := tok.(type) {
- case StartElement:
- if err := p.Skip(); err != nil {
- return err
- }
- case EndElement:
- return nil
- }
- }
- panic("unreachable")
-}
diff --git a/src/quietgcc.bash b/src/quietgcc.bash
deleted file mode 100755
index 759f6b407..000000000
--- a/src/quietgcc.bash
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# The master for this file is $GOROOT/src/quietgcc.bash
-# Changes made to $GOBIN/quietgcc will be overwritten.
-
-# Gcc output that we don't care to see.
-ignore=': error: .Each undeclared identifier'
-ignore=$ignore'|: error: for each function it appears'
-ignore=$ignore'|is dangerous, better use'
-ignore=$ignore'|is almost always misused'
-ignore=$ignore'|: In function '
-ignore=$ignore'|: At top level: '
-ignore=$ignore'|In file included from'
-ignore=$ignore'| from'
-
-# Figure out which cc to run; this is set by make.bash.
-gcc="@CC@"
-if test "$gcc" = "@C""C@"; then
- gcc=gcc
-fi
-
-# Build 64-bit binaries on 64-bit systems, unless GOHOSTARCH=386.
-case "$(uname -m -p)-$GOHOSTARCH" in
-*x86_64*-386 | *amd64*-386)
- gcc="$gcc -m32"
- ;;
-*x86_64* | *amd64*)
- gcc="$gcc -m64"
-esac
-
-# Run gcc, save error status, redisplay output without noise, exit with gcc status.
-tmp="${TMPDIR:-/tmp}/quietgcc.$$.$USER.out"
-$gcc -Wall -Wno-sign-compare -Wno-missing-braces \
- -Wno-parentheses -Wno-unknown-pragmas -Wno-switch -Wno-comment \
- -Werror \
- "$@" >"$tmp" 2>&1
-status=$?
-egrep -v "$ignore" "$tmp" | uniq | tee "$tmp.1"
-
-rm -f "$tmp" "$tmp.1"
-exit $status
diff --git a/src/run.bash b/src/run.bash
index a9689bf15..c2a52a078 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -4,69 +4,64 @@
# license that can be found in the LICENSE file.
set -e
-if [ "$1" = "--no-env" ]; then
- # caller has already run env.bash
- shift
-else
- . ./env.bash
-fi
-unset MAKEFLAGS # single-threaded make
+eval $(go env)
+
unset CDPATH # in case user has it set
+unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens
+ # to be under $GOPATH, then some tests below will fail
# no core files, please
ulimit -c 0
-# allow make.bash to avoid double-build of everything
+# allow all.bash to avoid double-build of everything
rebuild=true
if [ "$1" = "--no-rebuild" ]; then
- rebuild=false
shift
-fi
-
-xcd() {
+else
+ echo '# Building packages and commands.'
+ time go install -a -v std
echo
- echo --- cd $1
- builtin cd "$GOROOT"/src/$1
-}
-
-if $rebuild; then
- (xcd pkg
- gomake clean
- time gomake install
- ) || exit $?
fi
-(xcd pkg
-gomake testshort
-) || exit $?
+echo '# Testing packages.'
+time go test std -short -timeout=120s
+echo
-(xcd pkg/sync;
-GOMAXPROCS=10 gomake testshort
-) || exit $?
+echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
+GOMAXPROCS=2 go test runtime -short -timeout=240s -cpu=1,2,4
+echo
-(xcd cmd/ebnflint
-time gomake test
-) || exit $?
+echo '# sync -cpu=10'
+go test sync -short -timeout=120s -cpu=10
+
+xcd() {
+ echo
+ echo '#' $1
+ builtin cd "$GOROOT"/src/$1
+}
[ "$CGO_ENABLED" != 1 ] ||
[ "$GOHOSTOS" == windows ] ||
(xcd ../misc/cgo/stdio
-gomake clean
./test.bash
) || exit $?
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/life
-gomake clean
./test.bash
) || exit $?
[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == windows ] ||
(xcd ../misc/cgo/test
-gomake clean
-gotest
+go test
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+[ "$GOHOSTOS" == darwin ] ||
+(xcd ../misc/cgo/testso
+./test.bash
) || exit $?
(xcd ../doc/progs
@@ -74,29 +69,39 @@ time ./run
) || exit $?
[ "$GOARCH" == arm ] || # uses network, fails under QEMU
-(xcd ../doc/codelab/wiki
-gomake clean
-gomake
-gomake test
+(xcd ../doc/articles/wiki
+make clean
+./test.bash
) || exit $?
-for i in ../misc/dashboard/builder ../misc/goplay
-do
- (xcd $i
- gomake clean
- gomake
- ) || exit $?
-done
+(xcd ../doc/codewalk
+# TODO: test these too.
+set -e
+go build pig.go
+go build urlpoll.go
+rm -f pig urlpoll
+) || exit $?
+
+echo
+echo '#' ../misc/dashboard/builder ../misc/goplay
+go build ../misc/dashboard/builder ../misc/goplay
[ "$GOARCH" == arm ] ||
-(xcd ../test/bench
+(xcd ../test/bench/shootout
./timing.sh -test
) || exit $?
-[ "$GOHOSTOS" == windows ] ||
+echo
+echo '#' ../test/bench/go1
+go test ../test/bench/go1
+
(xcd ../test
-./run
+time go run run.go
) || exit $?
echo
+echo '# Checking API compatibility.'
+go tool api -c $GOROOT/api/go1.txt
+
+echo
echo ALL TESTS PASSED
diff --git a/src/run.bat b/src/run.bat
new file mode 100644
index 000000000..c7a157972
--- /dev/null
+++ b/src/run.bat
@@ -0,0 +1,76 @@
+:: Copyright 2012 The Go Authors. All rights reserved.
+:: Use of this source code is governed by a BSD-style
+:: license that can be found in the LICENSE file.
+@echo off
+
+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+setlocal
+:nolocal
+
+set GOBUILDFAIL=0
+
+:: we disallow local import for non-local packages, if %GOROOT% happens
+:: to be under %GOPATH%, then some tests below will fail
+set GOPATH=
+
+rem TODO avoid rebuild if possible
+
+if x%1==x--no-rebuild goto norebuild
+echo # Building packages and commands.
+go install -a -v std
+if errorlevel 1 goto fail
+echo.
+:norebuild
+
+echo # Testing packages.
+go test std -short -timeout=120s
+if errorlevel 1 goto fail
+echo.
+
+echo # runtime -cpu=1,2,4
+go test runtime -short -timeout=120s -cpu=1,2,4
+if errorlevel 1 goto fail
+echo.
+
+echo # sync -cpu=10
+go test sync -short -timeout=120s -cpu=10
+if errorlevel 1 goto fail
+echo.
+
+echo # ..\misc\dashboard\builder ..\misc\goplay
+go build ..\misc\dashboard\builder ..\misc\goplay
+if errorlevel 1 goto fail
+echo.
+
+:: TODO(brainman): disabled, because it fails with: mkdir C:\Users\ADMINI~1\AppData\Local\Temp\2.....\test\bench\: The filename or extension is too long.
+::echo # ..\test\bench\go1
+::go test ..\test\bench\go1
+::if errorlevel 1 goto fail
+::echo.
+
+:: TODO: The other tests in run.bash.
+
+echo # test
+cd ..\test
+set FAIL=0
+go run run.go
+if errorlevel 1 set FAIL=1
+cd ..\src
+echo.
+if %FAIL%==1 goto fail
+
+echo # Checking API compatibility.
+go tool api -c ..\api\go1.txt
+if errorlevel 1 goto fail
+echo.
+
+echo ALL TESTS PASSED
+goto end
+
+:fail
+set GOBUILDFAIL=1
+
+:end
diff --git a/src/sudo.bash b/src/sudo.bash
index 147e58f15..cccebd342 100755
--- a/src/sudo.bash
+++ b/src/sudo.bash
@@ -4,7 +4,6 @@
# license that can be found in the LICENSE file.
set -e
-. ./env.bash
case "`uname`" in
Darwin)
@@ -13,9 +12,19 @@ Darwin)
exit 0
esac
+if [[ ! -d /usr/local/bin ]]; then
+ echo 1>&2 'sudo.bash: problem with /usr/local/bin; cannot install tools.'
+ exit 2
+fi
+
+eval $(go env)
+cd $(dirname $0)
for i in prof cov
do
- sudo cp "$GOROOT"/src/cmd/$i/6$i /usr/local/bin/6$i
- sudo chgrp procmod /usr/local/bin/6$i
- sudo chmod g+s /usr/local/bin/6$i
+ # Remove old binaries if present
+ sudo rm -f /usr/local/bin/6$i
+ # Install new binaries
+ sudo cp $GOTOOLDIR/$i /usr/local/bin/go$i
+ sudo chgrp procmod /usr/local/bin/go$i
+ sudo chmod g+s /usr/local/bin/go$i
done
diff --git a/src/version.bash b/src/version.bash
deleted file mode 100755
index fc899e2e3..000000000
--- a/src/version.bash
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env bash
-# Copyright 2010 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-GOROOT=$(dirname $0)/..
-
-# If a version file created by -save is available, use it
-if [ -f "$GOROOT/VERSION" ]; then
- cat $GOROOT/VERSION
- exit 0
-fi
-
-# Otherwise, if hg doesn't work for whatever reason, fail
-if [ ! -d "$GOROOT/.hg" ] || ! hg version > /dev/null 2>&1; then
- echo 'Unable to report version: hg and VERSION file missing' 1>&2
- echo 'Generate VERSION with `src/version.bash -save` while hg is usable' 1>&2
- exit 2
-fi
-
-# Get numerical revision
-VERSION=$(hg identify -n 2>/dev/null)
-if [ $? != 0 ]; then
- OLD=$(hg identify | sed 1q)
- VERSION=$(echo $OLD | awk '{print $1}')
-fi
-
-# Get branch type
-BRANCH=release
-if [ "$(hg identify -b 2>/dev/null)" == "default" ]; then
- BRANCH=weekly
-fi
-
-# Find most recent known release or weekly tag.
-TAG=$(hg tags |
- grep $BRANCH |
- sed 's/:.*//' |
- sort -rn -k2 |
- awk -v ver=$VERSION '$2 <= ver && $1~/^(release|weekly)\./ {print $1}' |
- sed -n 1p)
-
-if [ "$TAG" != "" ]; then
- VERSION="$TAG $VERSION"
-fi
-
-if [ "$1" = "-save" ]; then
- echo $VERSION > $GOROOT/VERSION
-else
- echo $VERSION
-fi